Package com.salas.bb.remixfeeds.editor

Source Code of com.salas.bb.remixfeeds.editor.PostEditorAdv$SyntheticCategoryProperty

// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software Foundation;
// either version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: PostEditorAdv.java,v 1.10 2007/03/23 12:40:53 spyromus Exp $
//

package com.salas.bb.remixfeeds.editor;

import com.jgoodies.binding.beans.PropertyAdapter;
import com.jgoodies.binding.list.ArrayListModel;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.uif.AbstractDialog;
import com.salas.bb.remixfeeds.api.WeblogPost;
import com.salas.bb.remixfeeds.prefs.TargetBlog;
import com.salas.bb.utils.i18n.Strings;
import com.salas.bb.utils.uif.BBFormBuilder;
import com.salas.bb.utils.uif.CheckBoxList;
import com.toedter.calendar.JDateChooser;
import com.toedter.calendar.JTextFieldDateEditor;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.*;
import java.util.List;

/**
* Advanced version of the post editor.
*/
public class PostEditorAdv extends AbstractPostEditor
{
    protected JButton           btnPostAndContinue;
    protected JEditorPane       tfExcerpt;
    protected JCheckBox         chAllowComments;
    protected JCheckBox         chAllowTrackbacks;
    private JDateChooser        pkDate;
    private JLabel              lbDate;

    private TargetBlog[]        targetBlogs;
    private JCheckBox[]         chTargetBlog;

    private CategoriesLabel[]   pcCategories;
    private ArrayListModel[]    categories;
    private TargetBlog.Category[][] category;
    private SyntheticCategoryProperty[] categoryProperties;

    /**
     * Creates advanced post editor.
     *
     * @param frame frame.
     * @param richText <code>TRUE</code> to show rich text editor.
     */
    public PostEditorAdv(Frame frame, boolean richText)
    {
        super(frame, richText);

        btnPostAndContinue = new JButton(new PostToBlogAction(true));
        tfExcerpt = new JEditorPane();
        chAllowComments = new JCheckBox(Strings.message("ptb.editor.allow.comments"), true);
        chAllowTrackbacks = new JCheckBox(Strings.message("ptb.editor.allow.trackbacks"), true);
    }

    /**
     * Sets the list of target blogs. Initializes their category lists and creates checkboxes for the
     * layout. This method must be called before opening the dialog.
     *
     * @param targetBlogs   the list of target blogs.
     * @param selected      the list of selected blogs.
     */
    public void setTargetBlogs(TargetBlog[] targetBlogs, TargetBlog[] selected)
    {
        int blogs = targetBlogs.length;
        this.targetBlogs = targetBlogs;
        java.util.List<TargetBlog> selBlogs = Arrays.asList(selected);

        // Initialize the arrays
        pcCategories = new CategoriesLabel[blogs];
        chTargetBlog = new JCheckBox[blogs];
        categories = new ArrayListModel[blogs];
        category = new TargetBlog.Category[blogs][];
        categoryProperties = new SyntheticCategoryProperty[blogs];

        for (int i = 0; i < targetBlogs.length; i++)
        {
            categoryProperties[i] = new SyntheticCategoryProperty(i);

            TargetBlog blog = targetBlogs[i];
            initCategories(blog, i, new TargetBlog.Category[] { blog.getDefaultCategory() });

            PropertyAdapter adapter = new PropertyAdapter(categoryProperties[i], SyntheticCategoryProperty.PROP, true);
            pcCategories[i] = new CategoriesLabel(categories[i], adapter);

            chTargetBlog[i] = new JCheckBox(blog.getTitle());

            if (selBlogs.contains(blog))
            {
                chTargetBlog[i].setSelected(true);
                setDraft(blog.isDraft());
            }
        }

        updateTitle(selected);
    }

    /**
     * Initializes the list of categories for a given blog. If the categories aren't
     * available, loads them and then selects the given default.
     *
     * @param blog      blog to initialize.
     * @param index     index of the blog to locate the correct categories / category object.
     * @param cat       category to select.
     */
    private void initCategories(final TargetBlog blog, final int index, final TargetBlog.Category[] cat)
    {
        // If there are no categories in the blog object yet, let it be the default category.
        // We'll start loading them right away.
        TargetBlog.Category[] cats = blog.getCategories();
        boolean noCategories = cats.length == 0;
        if (noCategories) cats = cat;

        // Populate the list of categories with defaults
        ArrayListModel categories = this.categories[index];
        if (categories == null)
        {
            categories = new ArrayListModel();
            this.categories[index] = categories;
        }
        categories.clear();
        categories.addAll(Arrays.asList(cats));

        // Select the category
        setCategories(index, cat);

        if (noCategories)
        {
            // Load categories for this blog
            blog.loadCategories(new Runnable()
            {
                public void run()
                {
                    initCategories(blog, index, category[index]);
                }
            });
        }
    }

    /**
     * Sets the categories for a given blog.
     *
     * @param index blog index.
     * @param cat   categories.
     */
    private void setCategories(int index, TargetBlog.Category[] cat)
    {
        cat = findEqualCategories(categories[index], cat);

        // Set and fire
        TargetBlog.Category[] old = category[index];
        category[index] = cat;
        categoryProperties[index].fireChange(old, cat);
    }
    /**
     * Scans the list of given categories and returns the one which is like the given.
     *
     * @param categories    categories.
     * @param cat           category to find among these in the list.
     *
     * @return a category or <code>NULL</code>.
     */
    protected static TargetBlog.Category[] findEqualCategories(ArrayListModel categories, TargetBlog.Category[] cat)
    {
        List<TargetBlog.Category> newCats = new ArrayList<TargetBlog.Category>();

        if (cat != null)
        {
            List<TargetBlog.Category> cats = Arrays.asList(cat);

            for (Object o : categories)
            {
                TargetBlog.Category c = (TargetBlog.Category)o;
                if (c != null && cats.contains(c)) newCats.add(c);
            }
        }

        return newCats.toArray(new TargetBlog.Category[newCats.size()]);
    }


    /**
     * The hook to add more buttons.
     *
     * @param builder builder.
     */
    protected void addCustomButtons(ButtonBarBuilder builder)
    {
        builder.addFixed(btnPostAndContinue);
        builder.addRelatedGap();
    }

    /**
     * The hook to add more custom panels after the main part.
     *
     * @param builder builder.
     */
    protected void addCustomPanels(BBFormBuilder builder)
    {
        builder.appendRelatedComponentsGapRow(2);
        builder.appendRow("50dlu");
        builder.append(new JScrollPane(tfExcerpt), 2, CellConstraints.FILL, CellConstraints.FILL);

        builder.append(buildOptionsPanel(), 2);
    }

    /**
     * Builds the options panel for below the excerpt.
     *
     * @return options panel.
     */
    private Component buildOptionsPanel()
    {
        BBFormBuilder builder = new BBFormBuilder("p");
        for (int i = 0; i < targetBlogs.length; i++)
        {
            BBFormBuilder b = new BBFormBuilder("min(p;100dlu), 2dlu, min(p;100dlu)");
            b.append(chTargetBlog[i], pcCategories[i]);
            builder.append(b.getPanel());
        }
        JPanel pnlBlogs = builder.getPanel();

        builder = new BBFormBuilder("p");
        builder.append(chDraft);
        builder.append(chAllowComments);
        builder.append(chAllowTrackbacks);
        JPanel pnlOptions = builder.getPanel();

        builder = new BBFormBuilder(new FormLayout("p, 4dlu:grow, p", "top:p"));
        builder.append(pnlBlogs, pnlOptions);
        return builder.getPanel();
    }

    /**
     * The hook to add custom control elements to the toolbar.
     *
     * @param builder builder.
     */
    protected void addCustomControls(BBFormBuilder builder)
    {
        pkDate = new JDateChooser(new JTextFieldDateEditor("MM/dd/yyyy", "##/##/####", '_'));
        pkDate.setDate(new Date());

        Component[] cmps = pkDate.getComponents();
        for (Component cmp : cmps) if (cmp instanceof JButton) pkDate.remove(cmp);
       
        lbDate = new JLabel(Strings.message("ptb.editor.publication.date"));

        BBFormBuilder b = new BBFormBuilder("p, 2dlu, p");
        b.append(lbDate, pkDate);

        builder.append(b.getPanel());
    }

    /**
     * Returns the list of indices of all selected target blogs.
     *
     * @return list of indices.
     */
    public java.util.List<Integer> getSelectedBlogIndices()
    {
        java.util.List<Integer> sel = new ArrayList<Integer>();
        for (int i = 0; i < chTargetBlog.length; i++)
        {
            if (chTargetBlog[i].isSelected()) sel.add(i);
        }

        return sel;
    }


    /**
     * Adds more specific properties before sending.
     *
     * @param post post.
     */
    protected void addProperties(WeblogPost post)
    {
        post.excerpt = tfExcerpt.getText();
        post.allowComments = chAllowComments.isSelected();
        post.allowTrackbacks = chAllowTrackbacks.isSelected();
        post.dateCreated = pkDate.getDate();
    }

    /**
     * Returns a blog at a given index.
     *
     * @param i index.
     *
     * @return blog.
     */
    protected TargetBlog getBlogAt(int i)
    {
        return targetBlogs[i];
    }

    /**
     * Returns the list of categories selected for the given blog.
     *
     * @param blogIndex index of blog in list.
     *
     * @return categories.
     */
    protected java.util.List<TargetBlog.Category> getCategoriesForBlog(int blogIndex)
    {
        return Arrays.asList(category[blogIndex]);
    }

    /**
     * Enables / disables all controls during posting.
     *
     * @param en <code>TRUE</code> to enable.
     */
    protected void enableControls(boolean en)
    {
        super.enableControls(en);

        btnPostAndContinue.setEnabled(en);
        tfExcerpt.setEnabled(en);
        chAllowComments.setEnabled(en);
        chAllowTrackbacks.setEnabled(en);

        for (int i = 0; i < targetBlogs.length; i++)
        {
            chTargetBlog[i].setEnabled(en);
            pcCategories[i].setEnabled(en);
        }

        pkDate.setEnabled(en);
        lbDate.setEnabled(en);
    }

    /**
     * Synthetic property to watch categories in array.
     */
    public class SyntheticCategoryProperty
    {
        public static final String PROP = "value";

        private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
        private final int index;

        public SyntheticCategoryProperty(int index)
        {
            this.index = index;
        }

        public void addPropertyChangeListener(PropertyChangeListener x)
        {
            pcs.addPropertyChangeListener(x);
        }

        public void removePropertyChangeListener(PropertyChangeListener x)
        {
            pcs.removePropertyChangeListener(x);
        }

        public Object getValue()
        {
            return category[index];
        }

        public void setValue(Object c)
        {
            category[index] = (TargetBlog.Category[])c;
        }

        public void fireChange(TargetBlog.Category[] old, TargetBlog.Category[] cat)
        {
            pcs.firePropertyChange(PROP, old, cat);
        }
    }

    // ------------------------------------------------------------------------
    // Categories picker
    // ------------------------------------------------------------------------

    /**
     * The label with auto-updatable categories name.
     */
    private class CategoriesLabel extends JLabel
    {
        private final Color NORMAL = Color.BLUE;

        private final ArrayListModel allCategories;
        private final ValueModel     selCategories;

        /**
         * Creates a label for selected categories.
         *
         * @param allCategories all categories list model to pass to the picker.
         * @param selCategories selected categories to display and pass to the picker.
         */
        public CategoriesLabel(ArrayListModel allCategories, ValueModel selCategories)
        {
            this.allCategories = allCategories;
            this.selCategories = selCategories;

            setForeground(NORMAL);
            setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
           
            updateLabelText();
            enableEvents(AWTEvent.MOUSE_EVENT_MASK);
        }

        /** Updates the text according to what is selected. */
        private void updateLabelText()
        {
            String text;
            TargetBlog.Category[] cs = (TargetBlog.Category[])selCategories.getValue();
            if (cs == null || cs.length == 0)
            {
                text = "Uncategorized";
            } else if (cs.length == 1)
            {
                text = "category: " + cs[0].name;
            } else
            {
                text = cs.length + " categories";
            }

            setText("(" + text + ")");
        }

        @Override
        protected void processMouseEvent(MouseEvent e)
        {
            if (e.getID() == MouseEvent.MOUSE_CLICKED)
            {
                CategoriesPicker dlg = new CategoriesPicker(allCategories,
                    (TargetBlog.Category[])selCategories.getValue());

                dlg.open();
                if (!dlg.hasBeenCanceled())
                {
                    selCategories.setValue(dlg.getSelectedCategories());
                    updateLabelText();
                }
            }
        }
    }

    /**
     * Categories picker.
     */
    private class CategoriesPicker extends AbstractDialog
    {
        private CategoriesList lstCategories;

        /**
         * Creates categories picker component.
         *
         * @param categories    categories.
         * @param selected      selected categories.
         */
        public CategoriesPicker(ArrayListModel categories, TargetBlog.Category[] selected)
        {
            super(PostEditorAdv.this, Strings.message("ptb.editor.categories"));
            lstCategories = new CategoriesList(categories, selected);
        }

        /**
         * Builds the content pane.
         *
         * @return pane.
         */
        protected JComponent buildContent()
        {
            JPanel content = new JPanel(new BorderLayout());
            content.add(new JScrollPane(lstCategories), BorderLayout.CENTER);
            content.add(buildButtonBarWithOKCancel(), BorderLayout.SOUTH);
            return content;
        }

        /**
         * Returns the selected categories.
         *
         * @return selected.
         */
        public TargetBlog.Category[] getSelectedCategories()
        {
            return lstCategories.getChecked();
        }
    }

    /**
     * Categories list control.
     */
    private static class CategoriesList extends CheckBoxList
    {
        /**
         * Creates and initializes categories list.
         *
         * @param categories    the list of all known categories.
         * @param selected      the list of selected.
         */
        public CategoriesList(ArrayListModel categories, TargetBlog.Category[] selected)
        {
            populateList(categories, selected);
            check(selected);
        }

        /**
         * Returns the list of checked categories.
         *
         * @return checked categories.
         */
        public TargetBlog.Category[] getChecked()
        {
            java.util.List<TargetBlog.Category> cats = new ArrayList<TargetBlog.Category>();
            ListModel model = getModel();
            for (int i = 0; i < model.getSize(); i++)
            {
                CategoryCheckBox cb = (CategoryCheckBox)model.getElementAt(i);
                if (cb.isSelected()) cats.add(cb.getCategory());
            }

            return cats.toArray(new TargetBlog.Category[cats.size()]);
        }

        /**
         * Fetches all categories from the model and shows them.
         *
         * @param categories    categories.
         * @param selected      selected categories.
         */
        private void populateList(ArrayListModel categories, TargetBlog.Category[] selected)
        {
            Vector<CategoryCheckBox> wrappedCategories = new Vector<CategoryCheckBox>(categories.size());
            for (Object c : categories)
            {
                wrappedCategories.add(new CategoryCheckBox((TargetBlog.Category)c));
            }
            for (TargetBlog.Category c : selected)
            {
                TargetBlog.Category eqCat = findEqualCategory(categories, c);
                if (eqCat == null) wrappedCategories.add(new CategoryCheckBox(c));
            }
            setListData(wrappedCategories);
        }

        /**
         * Sets checkmarks for the given categories.
         *
         * @param selected the categories to be checked.
         */
        private void check(TargetBlog.Category[] selected)
        {
            java.util.List<TargetBlog.Category> cats = Arrays.asList(selected);
            ListModel model = getModel();
            for (int i = 0; i < model.getSize(); i++)
            {
                CategoryCheckBox cb = (CategoryCheckBox)model.getElementAt(i);
                TargetBlog.Category c = cb.getCategory();
                if (cats.contains(c)) cb.setSelected(true);
            }
        }

        /**
         * Custom checkbox for the category.
         */
        private static class CategoryCheckBox extends JCheckBox
        {
            private final TargetBlog.Category cat;

            /**
             * Creates a checkbox for the category.
             *
             * @param cat category.
             */
            public CategoryCheckBox(TargetBlog.Category cat)
            {
                this.cat = cat;
                setText(cat.name);
            }

            /**
             * Returns the assigned category.
             *
             * @return category.
             */
            public TargetBlog.Category getCategory()
            {
                return cat;
            }

            /**
             * Returns string representation.
             *
             * @return string representation.
             */
            public String toString()
            {
                return cat.name;
            }
        }
    }

}
TOP

Related Classes of com.salas.bb.remixfeeds.editor.PostEditorAdv$SyntheticCategoryProperty

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.