Package com.salas.bb.dialogs

Source Code of com.salas.bb.dialogs.UserPreferencesDialog

// 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: UserPreferencesDialog.java,v 1.110 2008/10/23 08:14:25 spyromus Exp $
//

package com.salas.bb.dialogs;

import com.jgoodies.binding.adapter.BoundedRangeAdapter;
import com.jgoodies.binding.adapter.ComboBoxAdapter;
import com.jgoodies.binding.adapter.ToggleButtonAdapter;
import com.jgoodies.binding.beans.PropertyAdapter;
import com.jgoodies.binding.value.AbstractValueModel;
import com.jgoodies.binding.value.BufferedValueModel;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.factories.Borders;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.uif.AbstractDialog;
import com.jgoodies.uif.AbstractFrame;
import com.jgoodies.uif.util.SystemUtils;
import com.salas.bb.core.*;
import com.salas.bb.domain.FeedClass;
import com.salas.bb.domain.FeedsSortOrder;
import com.salas.bb.domain.GuideClass;
import com.salas.bb.domain.prefs.StarzPreferences;
import com.salas.bb.domain.prefs.UserPreferences;
import com.salas.bb.domain.prefs.ViewModePreferences;
import com.salas.bb.remixfeeds.prefs.BloggingPreferencesPanel;
import com.salas.bb.sentiments.SentimentsFeature;
import com.salas.bb.twitter.TwitterPreferencesPanel;
import com.salas.bb.utils.Constants;
import com.salas.bb.utils.ResourceID;
import com.salas.bb.utils.SpinnerModelAdapter;
import com.salas.bb.utils.i18n.Strings;
import com.salas.bb.utils.notification.NotificationArea;
import com.salas.bb.utils.uif.*;
import com.salas.bb.views.feeds.IFeedDisplay;
import com.salas.bb.views.feeds.IFeedDisplayConstants;
import com.salas.bb.views.mainframe.MainFrame;
import com.salas.bb.views.settings.FeedRenderingSettings;
import com.salas.bb.views.settings.RenderingSettingsNames;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* Builds the User Preferences dialog.
*/
public final class UserPreferencesDialog extends AbstractDialog
{
    private final GlobalModel   model;
    private final Pages         pages;
    private AdvancedPreferencesPanel pnlAdvanced;

    private final AtomicBoolean feedsFilterChanged = new AtomicBoolean(false);
    private final AtomicBoolean guidesFilterChanged = new AtomicBoolean(false);

    private static final ColorListCellRenderer colorListCellRenderer =
        new ColorListCellRenderer(Strings.message("userprefs.tab.feeds.filter.hidden"));

    private Class selectedPanelClass;

    /**
     * Creates user preferences dialog.
     *
     * @param owner owning frame.
     * @param aModel global Model of BlogBridge.
     */
    public UserPreferencesDialog(AbstractFrame owner, GlobalModel aModel)
    {
        super(owner);
        this.model = aModel;
        pages = new Pages();
    }

    // Building *************************************************************

    /**
     * Builds and answers the preference's header.
     *
     * @return JComponent header of dialog box
     */
    protected JComponent buildHeader()
    {
        return new HeaderPanelExt(
            Strings.message("userprefs.dialog.title"),
            Strings.message("userprefs.dialog.header"),
            IconSource.getIcon(ResourceID.ICON_PREFERENCES));
    }

    /**
     * Builds and answers the preference's content pane.
     *
     * @return JComponent of content part of the dialog box
     */
    protected JComponent buildContent()
    {
        JPanel content = new JPanel(new BorderLayout());
        content.add(buildNavPanel(), BorderLayout.NORTH);
        content.add(buildMainPane(), BorderLayout.CENTER);
        content.add(buildButtonsBar(), BorderLayout.SOUTH);
        return content;
    }

    private Component buildNavPanel()
    {
        JComboBox selector = pages.getSelector();
        JButton btnPrev = new JButton(Strings.message("userprefs.dialog.nav.prev"));
        btnPrev.addActionListener(new MoveSelection(selector, false));
        JButton btnNext = new JButton(Strings.message("userprefs.dialog.nav.next"));
        btnNext.addActionListener(new MoveSelection(selector, true));

        BBFormBuilder builder = new BBFormBuilder("p, 4dlu, p, 2dlu, p");

        builder.append(selector);
        builder.append(btnPrev);
        builder.append(btnNext);

        JPanel panel = builder.getPanel();
        Insets ins = Borders.DIALOG_BORDER.getBorderInsets(null);
        panel.setBorder(BorderFactory.createEmptyBorder(0, 0, ins.bottom, 0));
        return panel;
    }

    /**
     * Opens the dialog and chooses the panel.
     *
     * @param panelClass panel.
     */
    public void open(Class panelClass)
    {
        selectedPanelClass = panelClass;
        open();
    }

    /**
     * Moves selection in the combo-box forward/backwards.
     */
    private static class MoveSelection implements ActionListener
    {
        private JComboBox box;
        private boolean forward;

        /**
         * Creates action.
         *
         * @param box       box.
         * @param forward   direction.
         */
        public MoveSelection(JComboBox box, boolean forward)
        {
            this.box = box;
            this.forward = forward;
        }

        /**
         * Invoked when an action occurs.
         */
        public void actionPerformed(ActionEvent e)
        {
            int sel = box.getSelectedIndex();
            int siz = box.getItemCount();

            if (forward)
            {
                sel++;
                if (sel == siz) sel = 0;
            } else
            {
                sel--;
                if (sel < 0) sel = siz - 1;
            }

            box.setSelectedIndex(sel);
        }
    }
    private JComponent buildButtonsBar()
    {
        return buildButtonBarWithOKCancelApply();
    }

    /**
     * Builds content pane.
     *
     * @return pane.
     */
    private JComponent buildMainPane()
    {
        final UserPreferences prefs = model.getUserPreferences();
        final StarzPreferences starzPreferences = model.getStarzPreferences();
        final FeedRenderingSettings feedRS = model.getGlobalRenderingSettings();

        final ValueModel trigger = getTriggerChannel();

        GeneralPreferencesPanel generalPanel = new GeneralPreferencesPanel(prefs, feedRS, trigger);
        pnlAdvanced = new AdvancedPreferencesPanel(prefs, starzPreferences, feedRS, trigger);
        TagsPreferencesPanel tagsPanel = new TagsPreferencesPanel(prefs, model.getServicePreferences(), trigger);

        pages.addPage(Strings.message("userprefs.tab.general"), generalPanel);
        pages.addPage(Strings.message("userprefs.tab.guides"), new GuidesPanel(feedRS, trigger, guidesFilterChanged));
        pages.addPage(Strings.message("userprefs.tab.feeds"), new FeedsPanel(feedRS, prefs, trigger, feedsFilterChanged));
        pages.addPage(Strings.message("userprefs.tab.articles"), new ArticlesPanel(prefs, trigger));
        pages.addPage(Strings.message("userprefs.tab.tags"), tagsPanel);
        pages.addPage(Strings.message("userprefs.tab.readinglists"), new ReadingListsPanel(prefs, trigger));
        pages.addPage(Strings.message("userprefs.tab.blogs"),
            new BloggingPreferencesPanel(this, trigger, prefs.getBloggingPreferences()));
        pages.addPage(Strings.message("userprefs.tab.twitter"),
            new TwitterPreferencesPanel(this, trigger, prefs.getTwitterPreferences()));
        pages.addPage(Strings.message("userprefs.tab.notifications"), new NotificationsPanel(prefs, trigger));
        pages.addPage(Strings.message("userprefs.tab.advanced"), pnlAdvanced);

        pages.setBorder(BorderFactory.createEtchedBorder());

        // Restore last selected page
        if (!pages.selectPageByClass(selectedPanelClass))
        {
            int i = prefs.getSelectedPrefsPage();
            if (i > -1 && i < pages.getSelector().getItemCount()) pages.getSelector().setSelectedIndex(i);
        }

        return pages;
    }

    /**
     * Opens dialog. We intercept it to save the last visible page index.
     */
    public void open()
    {
        super.open();

        // Store last selected page
        model.getUserPreferences().setSelectedPrefsPage(pages.getSelector().getSelectedIndex());
    }

    protected void resizeHook(JComponent comp)
    {
        int width = SystemUtils.IS_OS_MAC ? 565 : (int)(460 * Constants.SIZE_FACTOR);
        int height = SystemUtils.IS_OS_MAC ? 600 : (int)(515 * Constants.SIZE_FACTOR);
        comp.setPreferredSize(new Dimension(width, height));
    }

    // Misc *****************************************************************

    /**
     * Performs repacking of window on accept.
     */
    public void doApply()
    {
        String msg = checkValidity();

        if (msg == null)
        {
            super.doApply();

            if (feedsFilterChanged.get())
            {
                model.getGuidesSet().invalidateFeedVisibilityCaches();
                model.getGuideModel().filterChanged();
            }

            feedsFilterChanged.set(false);
            guidesFilterChanged.set(false);

            pack();

            GlobalModel.touchPreferences();
        } else
        {
            JOptionPane.showMessageDialog(getParent(), msg, getTitle(), JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * Checks the validity of the properties.
     *
     * @return the message or <code>NULL</code> if fine.
     */
    private String checkValidity()
    {
        return pnlAdvanced.checkValidity();
    }

    /**
     * Closes the window.
     */
    protected void doCloseWindow()
    {
        doCancel();
    }

    /**
     * Basic preferences panel.
     */
    private static class PreferencesPanel extends JPanel
    {
        final ValueModel trigger;

        /**
         * Creates the panel.
         *
         * @param aTrigger trigger.
         */
        public PreferencesPanel(ValueModel aTrigger)
        {
            trigger = aTrigger;
        }

    }

    /**
     * Pages component knows how to register and show titled pages. It has selector sub-component
     * based on combo-box (drop-down list).
     */
    private static class Pages extends JPanel
    {
        private JComboBox selector;

        /**
         * Creates pages control.
         */
        public Pages()
        {
            setLayout(new BorderLayout());

            selector = new JComboBox();
            selector.addItemListener(new PageSelectedListener());
        }

        /**
         * Returns page selector.
         *
         * @return page selector.
         */
        public JComboBox getSelector()
        {
            return selector;
        }

        /**
         * Adds page to the selector.
         *
         * @param title title.
         * @param page  page.
         */
        public void addPage(String title, JComponent page)
        {
            selector.addItem(new Page(title, page));
        }

        /**
         * Selects the page by its component class.
         *
         * @param pageClass class.
         *
         * @return TRUE if the page was found.
         */
        public boolean selectPageByClass(Class pageClass)
        {
            if (pageClass == null) return false;

            Page selectedPage = null;
            int count = selector.getItemCount();
            for (int i = 0; i < count && selectedPage == null; i++)
            {
                Page page = (Page)selector.getItemAt(i);
                if (page.page.getClass() == pageClass) selectedPage = page;
            }

            selector.setSelectedItem(selectedPage);

            return selectedPage != null;
        }

        /**
         * Invoked when the page gets selected.
         *
         * @param page page.
         */
        public void onPageSelected(JComponent page)
        {
            removeAll();
            add(page, BorderLayout.CENTER);

            validate();
            repaint();
        }

        /**
         * Listens to page selection events and sends them to the main class.
         */
        private class PageSelectedListener implements ItemListener
        {
            /**
             * Invoked when another page gets selected.
             *
             * @param e event.
             */
            public void itemStateChanged(ItemEvent e)
            {
                JComponent page = null;
                Page pageItem = (Page)selector.getSelectedItem();
                if (pageItem != null) page = pageItem.getPage();
                onPageSelected(page);
            }
        }

        /** Single titled page. */
        private static class Page
        {
            private String title;
            private JComponent page;

            /**
             * Creates titled page.
             *
             * @param title title.
             * @param page  page.
             */
            public Page(String title, JComponent page)
            {
                this.title = title;
                this.page = page;
            }

            /**
             * Returns page title.
             *
             * @return title.
             */
            public String toString()
            {
                return title;
            }

            /**
             * Returns page component.
             *
             * @return component.
             */
            public JComponent getPage()
            {
                return page;
            }
        }
    }
    /**
     * Guides preferences panel.
     */
    private static class GuidesPanel extends PreferencesPanel
    {
        /**
         * Creates panel.
         *
         * @param aFeedRS       feed rendering settings.
         * @param aTrigger      trigger.
         * @param filterChanged atomic boolean flag.
         */
        public GuidesPanel(FeedRenderingSettings aFeedRS, ValueModel aTrigger, AtomicBoolean filterChanged)
        {
            super(aTrigger);

            JCheckBox chBigIconInGuides = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.guides.use.large.icons"),
                aFeedRS, RenderingSettingsNames.IS_BIG_ICON_IN_GUIDES, trigger);
            JCheckBox chShowUnreadInGuides = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.guides.show.unread.counter"),
                aFeedRS, "showUnreadInGuides", trigger);
            JCheckBox chShowIconInGuides = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.guides.show.icon"),
                aFeedRS, RenderingSettingsNames.IS_ICON_IN_GUIDES_SHOWING, trigger);
            JCheckBox chShowTextInGuides = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.guides.show.name"),
                aFeedRS, RenderingSettingsNames.IS_TEXT_IN_GUIDES_SHOWING, trigger);

            new MandatoryCheckBoxController(chShowIconInGuides, chShowTextInGuides);

            GuideDisplayModeManager gdmm = GuideDisplayModeManager.getInstance();
            JComboBox cbFilterRead = createFilterComboBox(GuideClass.READ, gdmm, filterChanged, trigger);

            // Layout
            BBFormBuilder builder =
                new BBFormBuilder("7dlu, 7dlu, 35dlu, 40dlu, 2dlu, 90dlu, 2dlu, p:grow", this);
            builder.setDefaultDialogBorder();

            builder.setLeadingColumnOffset(1);
            builder.appendSeparator(Strings.message("userprefs.tab.feeds.filtering"));
            builder.append(Strings.message("userprefs.fully.read"), 3,
                CellConstraints.RIGHT, CellConstraints.DEFAULT).setLabelFor(cbFilterRead);
            builder.append(cbFilterRead);
            builder.nextLine();

            builder.appendSeparator(Strings.message("userprefs.tab.guides.show"));
            builder.setLeadingColumnOffset(1);
            builder.append(chShowIconInGuides, 7);
            builder.setLeadingColumnOffset(2);
            builder.append(chBigIconInGuides, 6);
            builder.setLeadingColumnOffset(1);
            builder.append(chShowTextInGuides, 7);
            builder.append(chShowUnreadInGuides, 7);
        }
    }

    /**
     * Feeds preferences panel.
     */
    private static class FeedsPanel extends PreferencesPanel
    {
        private static final Integer[] SORTING_ORDER = {
            FeedsSortOrder.ALPHABETICAL,
            FeedsSortOrder.RATING,
            FeedsSortOrder.READ,
            FeedsSortOrder.INVALIDNESS,
            FeedsSortOrder.VISITS
        };

        private static final String[] SORTING_CLASS_NAMES = {
            getFeedSortOrderName(FeedsSortOrder.ALPHABETICAL),
            getFeedSortOrderName(FeedsSortOrder.RATING),
            getFeedSortOrderName(FeedsSortOrder.READ),
            getFeedSortOrderName(FeedsSortOrder.INVALIDNESS),
            getFeedSortOrderName(FeedsSortOrder.VISITS)
        };

        private JLabel          lbSortFirstBy;
        private JLabel          lbSortThenBy;

        private JCheckBox       chSortingEnabled;
        private JComboBox       cbSortClass1;
        private JCheckBox       chReverseSort1;
        private JComboBox       cbSortClass2;
        private JCheckBox       chReverseSort2;

        /**
         * Creates the panel.
         *
         * @param aFeedRS       rendering settings.
         * @param aPrefs        user preferences.
         * @param aTrigger      trigger.
         * @param filterChanged atomic boolean flag.
         */
        public FeedsPanel(FeedRenderingSettings aFeedRS, UserPreferences aPrefs,
                          ValueModel aTrigger, AtomicBoolean filterChanged)
        {
            super(aTrigger);

            JCheckBox chShowStarz = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.feeds.show.starz"), aFeedRS, "showStarz", trigger);
            JCheckBox chShowUnreadInFeeds = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.feeds.show.number.of.unread.articles"),
                aFeedRS, "showUnreadInFeeds", trigger);
            JCheckBox chShowActivityChart = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.feeds.show.7.day.activity.chart"),
                aFeedRS, "showActivityChart", trigger);

            FeedDisplayModeManager fdmm = FeedDisplayModeManager.getInstance();
            JComboBox cbFilterLowRated = createFilterComboBox(FeedClass.LOW_RATED, fdmm, filterChanged, trigger);
            JComboBox cbFilterRead = createFilterComboBox(FeedClass.READ, fdmm, filterChanged, trigger);
            JComboBox cbFilterInvalid = createFilterComboBox(FeedClass.INVALID, fdmm, filterChanged, trigger);
            JComboBox cbFilterDisabled = createFilterComboBox(FeedClass.DISABLED, fdmm, filterChanged, trigger);

            chSortingEnabled = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.feeds.sort"), aPrefs, UserPreferences.PROP_SORTING_ENABLED, trigger);
            chSortingEnabled.addActionListener(new SortingEnabledListener());

            cbSortClass1 = new JComboBox(new SortClassesAdapter(new BufferedValueModel(
                new PropertyAdapter(aPrefs, UserPreferences.PROP_SORT_BY_CLASS_1), trigger)));
            cbSortClass2 = new JComboBox(new SortClassesAdapter(new BufferedValueModel(
                new PropertyAdapter(aPrefs, UserPreferences.PROP_SORT_BY_CLASS_2), trigger)));
            chReverseSort1 = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.feeds.sort.reverse.1"),
                aPrefs, UserPreferences.PROP_REVERSED_SORT_BY_CLASS_1, trigger);
            chReverseSort2 = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.feeds.sort.reverse.2"),
                aPrefs, UserPreferences.PROP_REVERSED_SORT_BY_CLASS_2, trigger);

            BBFormBuilder builder =
                new BBFormBuilder("7dlu, 40dlu, 2dlu, 40dlu, 2dlu, 90dlu, 2dlu, p:grow", this);
            builder.setDefaultDialogBorder();

            builder.appendSeparator(Strings.message("userprefs.tab.feeds.sorting"));
            builder.setLeadingColumnOffset(1);
            builder.append(chSortingEnabled);
            lbSortFirstBy = builder.append(Strings.message("userprefs.tab.feeds.sorting.first.by"), 1,
                CellConstraints.RIGHT, CellConstraints.DEFAULT);
            builder.append(cbSortClass1);
            builder.append(chReverseSort1);
            builder.nextLine();

            lbSortThenBy = builder.append(Strings.message("userprefs.tab.feeds.sorting.then.by"), 3,
                CellConstraints.RIGHT, CellConstraints.DEFAULT);
            builder.append(cbSortClass2);
            builder.append(chReverseSort2);

            builder.appendSeparator(Strings.message("userprefs.tab.feeds.filtering"));
            builder.append(Strings.message("userprefs.tab.feeds.invalid"), 3,
                CellConstraints.RIGHT, CellConstraints.DEFAULT).setLabelFor(cbFilterInvalid);
            builder.append(cbFilterInvalid);
            builder.nextLine();
            builder.append(Strings.message("userprefs.fully.read"), 3,
                CellConstraints.RIGHT, CellConstraints.DEFAULT).setLabelFor(cbFilterRead);
            builder.append(cbFilterRead);
            builder.nextLine();
            builder.append(Strings.message("userprefs.tab.feeds.below.starz.threshold"), 3,
                CellConstraints.RIGHT, CellConstraints.DEFAULT).setLabelFor(cbFilterLowRated);
            builder.append(cbFilterLowRated);
            builder.nextLine();
            builder.append(Strings.message("userprefs.tab.feeds.disabled"), 3,
                CellConstraints.RIGHT, CellConstraints.DEFAULT).setLabelFor(cbFilterDisabled);
            builder.append(cbFilterDisabled);

            builder.nextLine();
            builder.appendSeparator(Strings.message("userprefs.tab.feeds.show"));
            builder.append(chShowStarz, 5);
            builder.nextLine();

            builder.append(chShowUnreadInFeeds, 5);
            builder.nextLine();
            builder.append(chShowActivityChart, 5);

            setSortingEnabled(aPrefs.isSortingEnabled());
        }

        /**
         * Returns the name of the sorting class.
         *
         * @param clazz class id.
         *
         * @return the name.
         */
        private static String getFeedSortOrderName(int clazz)
        {
            return (String)FeedsSortOrder.SORTING_CLASS_NAMES.get(clazz);
        }

        /**
         * Enables and disables sorting components.
         *
         * @param enabled <code>TRUE</code> to enable.
         */
        private void setSortingEnabled(boolean enabled)
        {
            chReverseSort1.setEnabled(enabled);
            chReverseSort2.setEnabled(enabled);
            cbSortClass1.setEnabled(enabled);
            cbSortClass2.setEnabled(enabled);
            lbSortFirstBy.setEnabled(enabled);
            lbSortThenBy.setEnabled(enabled);
        }

        /** Listens to checkbox and updates enableness state of related controls. */
        private class SortingEnabledListener implements ActionListener
        {
            public void actionPerformed(ActionEvent e)
            {
                boolean enabled = chSortingEnabled.isSelected();
                setSortingEnabled(enabled);
            }
        }

        /** Writes class-mask into model, but displays textual names of class-masks. */
        private static class SortClassesAdapter extends ComboBoxAdapter
        {
            public SortClassesAdapter(ValueModel aValueModel)
            {
                super(SORTING_CLASS_NAMES, aValueModel);
            }

            public Object getSelectedItem()
            {
                int clazz = (Integer)super.getSelectedItem();
                int index = classToIndex(clazz);
                return SORTING_CLASS_NAMES[index];
            }

            public void setSelectedItem(Object o)
            {
                int index = classNameToIndex((String)o);
                super.setSelectedItem(SORTING_ORDER[index]);
            }

            private int classToIndex(int clazz)
            {
                int index = -1;
                for (int i = 0; index == -1 && i < SORTING_ORDER.length; i++)
                {
                    index = SORTING_ORDER[i] == clazz ? i : -1;
                }

                return index;
            }

            private int classNameToIndex(String className)
            {
                int index = -1;
                for (int i = 0; index == -1 && i < SORTING_CLASS_NAMES.length; i++)
                {
                    index = SORTING_CLASS_NAMES[i].equals(className) ? i : -1;
                }

                return index;
            }
        }
    }

    /**
     * Articles preferences panel.
     */
    private static class ArticlesPanel extends PreferencesPanel
    {
        private int oldBriefSentences;
        private int oldBriefMaxLength;

        /**
         * Creates articles panel.
         *
         * @param aPrefs    user preferences.
         * @param aTrigger  trigger.
         */
        public ArticlesPanel(final UserPreferences aPrefs, ValueModel aTrigger)
        {
            super(aTrigger);

            JCheckBox chAutoExpandMini = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.articles.autoexpand"), aPrefs,
                UserPreferences.PROP_AUTO_EXPAND_MINI, trigger);

            BBFormBuilder builder = new BBFormBuilder("7dlu, p, 4dlu, 15dlu, 17dlu, p:grow", this);
            builder.setDefaultDialogBorder();

            builder.appendSeparator(Strings.message("userprefs.tab.articles.what.to.display.in.each.mode"));
            builder.setLeadingColumnOffset(1);
            builder.append(buildViewModesPanel(aPrefs), 5);

            builder.setLeadingColumnOffset(0);
            builder.appendSeparator(Strings.message("userprefs.tab.articles.brief.mode"));
            builder.setLeadingColumnOffset(1);
            builder.append(buildBriefModePanel(aPrefs, aTrigger), 5);

            builder.setLeadingColumnOffset(0);
            builder.appendSeparator(Strings.message("userprefs.tab.articles.pagination"));
            builder.setLeadingColumnOffset(1);
            builder.append(buildPaginationPanel(aPrefs, aTrigger), 5);

            builder.setLeadingColumnOffset(0);
            builder.appendSeparator(Strings.message("userprefs.options"));
            builder.setLeadingColumnOffset(1);
            builder.append(chAutoExpandMini, 5);

            // This block must go after the initialization of the other controls because it depends
            // on the values being propagated upon triggering.
            oldBriefSentences = aPrefs.getBriefSentences();
            oldBriefMaxLength = aPrefs.getBriefMaxLength();
            aTrigger.addValueChangeListener(new PropertyChangeListener()
            {
                public void propertyChange(PropertyChangeEvent evt)
                {
                    if (Boolean.TRUE.equals(evt.getNewValue()) &&
                        (oldBriefMaxLength != aPrefs.getBriefMaxLength() ||
                         oldBriefSentences != aPrefs.getBriefSentences()))
                    {
                        oldBriefSentences = aPrefs.getBriefSentences();
                        oldBriefMaxLength = aPrefs.getBriefMaxLength();

                        MainFrame frame = GlobalController.SINGLETON.getMainFrame();
                        IFeedDisplay feedView = frame.getArticlesListPanel().getFeedView();
                        feedView.repaintIfInMode(true);
                    }
                }
            });
        }

        private Component buildBriefModePanel(UserPreferences prefs, ValueModel trigger)
        {
            SpinnerModelAdapter mdlSentences = new SpinnerModelAdapter(new BoundedRangeAdapter(
                new BufferedValueModel(new PropertyAdapter(prefs, UserPreferences.PROP_BRIEF_SENTENCES),
                    trigger), 0, 1, 10));
            JSpinner spSentences = new JSpinner(mdlSentences);

            SpinnerModelAdapter mdlMaxLength = new SpinnerModelAdapter(new BoundedRangeAdapter(
                new BufferedValueModel(new PropertyAdapter(prefs, UserPreferences.PROP_BRIEF_MAX_LENGTH),
                    trigger), 0, 100, 1000));
            mdlMaxLength.setStepSize(100);
            JSpinner spMaxLength = new JSpinner(mdlMaxLength);

            BBFormBuilder builder = new BBFormBuilder("p, 4dlu, 25dlu, 4dlu, p, 4dlu, 35dlu, 4dlu, p");

            String[] slices = Strings.slices("userprefs.tab.articles.brief.mode.settings");

            builder.append(slices[0], 1);
            builder.append(spSentences);
            builder.append(slices[1], 1);
            builder.append(spMaxLength);
            builder.append(slices[2], 1);

            return builder.getPanel();
        }

        private Component buildPaginationPanel(UserPreferences prefs, ValueModel trigger)
        {
            SpinnerModelAdapter mdlPageSize = new SpinnerModelAdapter(new BoundedRangeAdapter(
                new BufferedValueModel(new PropertyAdapter(prefs, UserPreferences.PROP_PAGE_SIZE),
                    trigger), 0, 10, 200));
            JSpinner spPageSize = new JSpinner(mdlPageSize);
            SpinnerNumberModel model = (SpinnerNumberModel)spPageSize.getModel();
            model.setStepSize(10);

            BBFormBuilder builder = new BBFormBuilder("p, 4dlu, 25dlu, 4dlu, p");

            String[] slices = Strings.slices("userprefs.tab.articles.pagination.settings");
            builder.append(slices[0], 1);
            builder.append(spPageSize);
            builder.append(slices[1], 1);

            return builder.getPanel();
        }

        /**
         * Creates view modes panel.
         *
         * @param aPrefs preferences.
         *
         * @return panel.
         */
        private Component buildViewModesPanel(UserPreferences aPrefs)
        {
            JCheckBox[][] checks = createCheckBoxes(aPrefs.getViewModePreferences());

            BBFormBuilder builder = new BBFormBuilder(
                "p, 4dlu, center:35dlu, 4dlu, center:35dlu, 4dlu, center:35dlu");

            builder.append("", 1);
            builder.append(Strings.message("viewmode.minimal"), 1);
            builder.append(Strings.message("viewmode.brief"), 1);
            builder.append(Strings.message("viewmode.full"), 1);

            String titles[] = {
                Strings.message("article.header.author"),
                Strings.message("article.header.categories"),
                Strings.message("article.header.date"),
                Strings.message("article.header.time"),
                Strings.message("article.header.pin"),
                Strings.message("article.header.colorCode"),
                Strings.message("article.header.url")
            };

            boolean enableness[] = {
                true,
                true,
                true,
                true,
                true,
                SentimentsFeature.isAvailable(),
                true
            };

            for (int i = 0; i < titles.length; i++)
            {
                boolean en = enableness[i];
                String title = titles[i];
                builder.append(title, 1).setEnabled(en);
                builder.append(checks[i][0], 1);
                builder.append(checks[i][1], 1);
                builder.append(checks[i][2], 1);

                for (int j = 0; j < 3; j++) checks[i][j].setEnabled(en);
            }

            // Make time checkboxes dependent on date
            int date = 3;
            int time = 4;
            for (int i = 0; i < 3; i++) UifUtilities.setDependency(checks[date][i], checks[time][i]);
           
            return builder.getPanel();
        }

        /**
         * Creates check boxes to use for the form.
         *
         * @param aPrefs preferences.
         *
         * @return check boxes.
         */
        private JCheckBox[][] createCheckBoxes(ViewModePreferences aPrefs)
        {
            ViewModePreferences.ViewModeBean[] modes = new ViewModePreferences.ViewModeBean[]
            {
                new ViewModePreferences.ViewModeBean(aPrefs, IFeedDisplayConstants.MODE_MINIMAL),
                new ViewModePreferences.ViewModeBean(aPrefs, IFeedDisplayConstants.MODE_BRIEF),
                new ViewModePreferences.ViewModeBean(aPrefs, IFeedDisplayConstants.MODE_FULL)
            };

            String[] properties = {
                ViewModePreferences.AUTHOR_VISIBLE,
                ViewModePreferences.CATEGORIES_VISIBLE,
                ViewModePreferences.DATE_VISIBLE,
                ViewModePreferences.TIME_VISIBLE,
                ViewModePreferences.PIN_VISIBLE,
                ViewModePreferences.COLOR_CODE_VISIBLE,
                ViewModePreferences.URL_VISIBLE
            };

            JCheckBox[][] checks = new JCheckBox[properties.length][modes.length];

            for (int i = 0; i < properties.length; i++)
            {
                String property = properties[i];
                for (int j = 0; j < modes.length; j++)
                {
                    ViewModePreferences.ViewModeBean mode = modes[j];

                    ButtonModel model = new ToggleButtonAdapter(new BufferedValueModel(
                        new PropertyAdapter(mode, property), trigger));
                    checks[i][j] = ComponentsFactory.createCheckBox(null, model);
                }
            }

            return checks;
        }
    }

    /**
     * Global notifications preferences.
     */
    private static class NotificationsPanel extends PreferencesPanel
    {
        /**
         * Creates panel.
         *
         * @param prefs     preferences.
         * @param trigger   trigger.
         */
        public NotificationsPanel(UserPreferences prefs, ValueModel trigger)
        {
            super(trigger);

            JComponent wording = ComponentsFactory.createWrappedMultilineLabel(
                Strings.message("userprefs.tab.notifications.wording"));

            JCheckBox chEnabled;
            if (NotificationArea.isSupported())
            {
                chEnabled = ComponentsFactory.createCheckBox(
                    Strings.message("userprefs.tab.notifications.enabled"),
                    prefs, UserPreferences.PROP_NOTIFICATIONS_ENABLED, this.trigger);
            } else
            {
                chEnabled = ComponentsFactory.createCheckBox(
                    Strings.message("userprefs.tab.notifications.enabled"));
                chEnabled.setEnabled(NotificationArea.isSupported());
            }

            JCheckBox chSoundOnNoUnread = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.notifications.sound.no.unread"),
                prefs, UserPreferences.PROP_SOUND_ON_NO_UNREAD, this.trigger);
            JCheckBox chSoundOnNewArticles = ComponentsFactory.createCheckBox(
                Strings.message("userprefs.tab.notifications.sound.new.article"),
                prefs, UserPreferences.PROP_SOUND_ON_NEW_ARTICLES, this.trigger);

            BBFormBuilder builder = new BBFormBuilder("7dlu, p:grow", this);
            builder.setDefaultDialogBorder();

            builder.append(wording, 2);
            builder.setLeadingColumnOffset(1);
            builder.appendUnrelatedComponentsGapRow(2);
            builder.append(chEnabled);

            builder.appendRelatedComponentsGapRow(2);
            builder.appendSeparator(Strings.message("userprefs.tab.notifications.sound"));
            builder.append(chSoundOnNoUnread);
            builder.append(chSoundOnNewArticles);
        }
    }

    /** Converts masked bits into states. */
    private static class FilterClassesAdapter extends ColorComboBoxAdapter
    {
        private static final Color[] COLORS = {
            Color.BLACK,
            Color.decode("#FF344E"), Color.decode("#FFAF2F"), Color.decode("#F6E12A"), Color.decode("#99DE26"),
            Color.decode("#24A4E0"), Color.decode("#F361B4"), Color.decode("#9E9E9E"),
            null };

        /**
         * Creates combo-box adapter for model.
         *
         * @param aModel model to adopt.
         */
        public FilterClassesAdapter(ValueModel aModel)
        {
            super(COLORS, aModel);
        }
    }

    /**
     * Reads and writes data directly to <code>ChannelDisplayModeManager</code>.
     */
    private static class DisplayModeModel extends AbstractValueModel
    {
        private int channelClass;
        private AbstractDisplayModeManager feedDMM;
        private final AtomicBoolean changedFlag;

        /**
         * Creates model adapter for the given class.
         *
         * @param cl            class.
         * @param dmm           display mode manager.
         * @param changedFlag   changed flag.
         */
        public DisplayModeModel(int cl, AbstractDisplayModeManager dmm,
                                AtomicBoolean changedFlag)
        {
            channelClass = cl;
            feedDMM = dmm;
            this.changedFlag = changedFlag;
        }

        /**
         * Takes the value of color from the display mode manager.
         *
         * @return color.
         */
        public Object getValue()
        {
            return feedDMM.getColor(channelClass);
        }

        /**
         * Sets the value of color to the display mode manager.
         *
         * @param object color.
         */
        public void setValue(Object object)
        {
            Color oldColor = feedDMM.getColor(channelClass);
            Color newColor = (Color)object;

            if ((oldColor == null && newColor != null) ||
                (oldColor != null && newColor == null)) changedFlag.set(true);

            feedDMM.setColor(channelClass, (Color)object);
        }
    }

    /**
     * Creates a filter combo-box for a given class.
     *
     * @param cl        class.
     * @param dmm       display mode manager to operate.
     * @param changed   changed atomic flag.
     * @param trigger   trigger to use for data commit.
     *
     * @return combo-box.
     */
    private static JComboBox createFilterComboBox(int cl, AbstractDisplayModeManager dmm, AtomicBoolean changed,
                                           ValueModel trigger)
    {
        JComboBox box = new JComboBox(new FilterClassesAdapter(new BufferedValueModel(
                        new DisplayModeModel(cl, dmm, changed),
                        trigger)));

        box.setRenderer(colorListCellRenderer);

        return box;
    }
}
TOP

Related Classes of com.salas.bb.dialogs.UserPreferencesDialog

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.