Package com.salas.bb.search

Source Code of com.salas.bb.search.SearchDialog$NavigationListener

// 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: SearchDialog.java,v 1.26 2007/07/20 16:51:27 spyromus Exp $
//

package com.salas.bb.search;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.uif.AbstractDialog;
import com.jgoodies.uif.util.Resizer;
import com.jgoodies.uif.util.ResourceUtils;
import com.jgoodies.uif.util.SystemUtils;
import com.salas.bb.utils.i18n.Strings;
import com.salas.bb.utils.uif.BBFormBuilder;
import com.salas.bb.utils.uif.ProgressSpinner;
import com.salas.bb.utils.uif.UifUtilities;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.text.MessageFormat;

/**
* Search dialog box.
*/
public class SearchDialog extends AbstractDialog
{
    /** Minimum dialog size. */
    private static final Dimension  MIN_SIZE = new Dimension(500, 350);

    private final SearchEngine      searchEngine;

    private ResultsList             itemsList;
    private JLabel                  lbResults;
    private ProgressSpinner         pgSpinner;
    private final SearchDialog.ResultsListener resultsListener;
    private SearchResultsListModel model;

    /**
     * Creates search dialog.
     *
     * @param owner     the dialog's parent frame.
     * @param engine    search engine to use.
     * @param listener  selection listener.
     */
    public SearchDialog(Frame owner, SearchEngine engine, ActionListener listener)
    {
        super(owner, Strings.message("search.dialog.title"));
        searchEngine = engine;

        model = new SearchResultsListModel();
        itemsList = new ResultsList(model);
        itemsList.addActionListener(listener);

        lbResults = new JLabel();
        UifUtilities.smallerFont(lbResults);

        pgSpinner = new ProgressSpinner();

        resultsListener = new ResultsListener();
        searchEngine.getResult().addChangesListener(resultsListener);

        setModal(false);
    }

    /** Release resources before closing. */
    public void close()
    {
        searchEngine.getResult().removeChangesListener(resultsListener);

        itemsList = null;
        super.close();
        getContentPane().removeAll();
    }

    /**
     * Sets the dialog's resizable state. By default dialogs are non-resizable; subclasses may
     * override.
     */
    protected void setResizable()
    {
        setResizable(true);
    }

    /**
     * Creates main content pane.
     *
     * @return the dialog's main content without header and border.
     */
    protected JComponent buildContent()
    {
        JPanel panel = new JPanel(new BorderLayout());

        panel.add(buildTopBar(), BorderLayout.NORTH);
        panel.add(buildResultsPanel(), BorderLayout.CENTER);

        return panel;
    }

    /**
     * Creates top bar with progress indicator, results count and search field.
     *
     * @return top bar component.
     */
    private Component buildTopBar()
    {
        final JLabel helpIcon = new JLabel(ResourceUtils.getIcon("search.ext.icon"));
        helpIcon.setToolTipText(Strings.message("search.ext.text"));
        helpIcon.setEnabled(false);

        final JCheckBox chPinnedArticlesOnly = new JCheckBox(Strings.message("search.pinned.articles.only"));
        UifUtilities.smallerFont(chPinnedArticlesOnly);
        if (SystemUtils.IS_OS_MAC) chPinnedArticlesOnly.setMargin(new Insets(0, 0, 2, 0));

        final SearchField tfSearch = new SearchField();
        tfSearch.addKeyListener(new NavigationListener());

        // Register changes monitor
        ActionListener monitor = new SearchCriteriaChangeMonitor(chPinnedArticlesOnly, tfSearch, helpIcon);
        tfSearch.addActionListener(monitor);
        chPinnedArticlesOnly.addActionListener(monitor);

        BBFormBuilder builder = new BBFormBuilder("p, 2dlu, 50dlu, 2dlu, p, 4dlu, p, 7dlu, p, 14dlu:grow, p");

        JLabel lbSearch = builder.append(Strings.message("search.prompt"), 1);
        lbSearch.setLabelFor(tfSearch);
        UifUtilities.smallerFont(lbSearch);
        UifUtilities.smallerFont(tfSearch);
        builder.append(tfSearch);
        builder.append(helpIcon);
        builder.append(chPinnedArticlesOnly, 1, CellConstraints.DEFAULT, CellConstraints.CENTER);
        builder.append(lbResults);
        builder.append(pgSpinner);
        builder.appendUnrelatedComponentsGapRow();

        return builder.getPanel();
    }

    /**
     * Creates results panel with results list and controls.
     *
     * @return results panel component.
     */
    private Component buildResultsPanel()
    {
        JPanel panel = new JPanel(new BorderLayout());

        JPanel panel2 = new JPanel(new BorderLayout());
        panel2.add(itemsList, BorderLayout.NORTH);
        panel2.setBackground(Color.WHITE);

        panel.add(panel2, BorderLayout.CENTER);
        panel.add(buildControlPanel(), BorderLayout.EAST);

        JScrollPane sp = new JScrollPane(panel);
        sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

        return sp;
    }

    /**
     * Returns currently selected item.
     *
     * @return item.
     */
    public ResultItem getSelectedItem()
    {
        return itemsList == null ? null : itemsList.getSelectedItem();
    }

    /**
     * Creates control panel with grouping, sorting and filtering options.
     *
     * @return control panel.
     */
    private JComponent buildControlPanel()
    {
        BBFormBuilder builder = new BBFormBuilder("5dlu, p, 5dlu");

        builder.appendRelatedComponentsGapRow();
        builder.setLeadingColumnOffset(1);
        builder.nextLine();

        // Grouping
        Action actGroup = new AbstractAction()
        {
            private ActionLabel selection;
            public void actionPerformed(ActionEvent e)
            {
                if (selection == e.getSource()) return;
                if (selection != null) selection.setSelected(false);
                onGroupingChange(e.getID());
                selection = (ActionLabel)e.getSource();
            }
        };
        ActionLabel albFlat = new ActionLabel(actGroup,
            Strings.message("search.groupping.flat"), SearchResultsListModel.GROUP_FLAT);
        ActionLabel albKind = new ActionLabel(actGroup,
            Strings.message("search.groupping.kind"), SearchResultsListModel.GROUP_KIND);
        ActionLabel albDate = new ActionLabel(actGroup,
            Strings.message("search.groupping.date"), SearchResultsListModel.GROUP_DATE);
        albKind.setSelected(true);

        // Filtering
        Action actFiltering = new AbstractAction()
        {
            private ActionLabel selection;
            public void actionPerformed(ActionEvent e)
            {
                if (selection == e.getSource()) return;
                if (selection != null) selection.setSelected(false);
                onFilteringChange(e.getID());
                selection = (ActionLabel)e.getSource();
            }
        };
        ActionLabel albAnyDate = new ActionLabel(actFiltering,
            Strings.message("search.when.any.date"),
            ResultsList.DATE_ANY);
        ActionLabel albToday = new ActionLabel(actFiltering,
            Strings.message("search.when.today"),
            ResultsList.DATE_TODAY);
        ActionLabel albYesterday =new ActionLabel(actFiltering,
            Strings.message("search.when.since.yesterday"),
            ResultsList.DATE_YESTERDAY);
        ActionLabel albThisWeek = new ActionLabel(actFiltering,
            Strings.message("search.when.this.week"),
            ResultsList.DATE_WEEK);
        ActionLabel albThisMonth = new ActionLabel(actFiltering,
            Strings.message("search.when.this.month"),
            ResultsList.DATE_MONTH);
        ActionLabel albThisYear = new ActionLabel(actFiltering,
            Strings.message("search.when.this.year"),
            ResultsList.DATE_YEAR);
        albAnyDate.setSelected(true);

        builder.append(smallLabel(Strings.message("search.groupping")));
        builder.nextLine();
        builder.append(albFlat);
        builder.nextLine();
        builder.append(albKind);
        builder.nextLine();
        builder.append(albDate);
//        builder.nextLine();

        builder.appendUnrelatedComponentsGapRow(2);
        builder.setLeadingColumnOffset(0);
        builder.append(new JLabel(), 3);
//        builder.append(new JPopupMenu.Separator(), 3);

        builder.setLeadingColumnOffset(1);
        builder.append(smallLabel(Strings.message("search.when")));
        builder.nextLine();
        builder.append(albAnyDate);
        builder.nextLine();
        builder.append(albToday);
        builder.nextLine();
        builder.append(albYesterday);
        builder.nextLine();
        builder.append(albThisWeek);
        builder.nextLine();
        builder.append(albThisMonth);
        builder.nextLine();
        builder.append(albThisYear);
        builder.nextLine();

        return builder.getPanel();
    }

    /**
     * Creates small label component.
     *
     * @param txt text.
     *
     * @return label component.
     */
    private static JComponent smallLabel(String txt)
    {
        JLabel label = new JLabel(txt);
        UifUtilities.smallerFont(label);

        return label;
    }

    /**
     * Inoked when grouping changes.
     *
     * @param grouping new grouping option.
     */
    private void onGroupingChange(int grouping)
    {
        model.setGroupBy(grouping);
    }

    /**
     * Invoked when filtering changes.
     *
     * @param filtering new filtering option.
     */
    private void onFilteringChange(int filtering)
    {
        itemsList.setDateRange(filtering);
    }

    /**
     * Resizes the specified component. This method is called during the build process and enables
     * subclasses to achieve a better aspect ratio, by applying a resizer, e.g. the
     * <code>Resizer</code>.
     *
     * @param component the component to be resized
     */
    protected void resizeHook(JComponent component)
    {
        component.setPreferredSize(Resizer.ONE2ONE.fromWidth(MIN_SIZE.width));
    }

    // ---------------------------------------------------------------------------------------------

    /** Action label with selection indication and click handler. */
    private static class ActionLabel extends JLabel
    {
        private final Action action;
        private final int id;

        /**
         * Creates label.
         *
         * @param anAction action to call when clicked.
         * @param title    label title.
         * @param anID       ID.
         */
        public ActionLabel(Action anAction, String title, int anID)
        {
            super(title);
            UifUtilities.smallerFont(this);

            this.action = anAction;
            id = anID;

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

        /**
         * Selects / deselects item.
         *
         * @param aSelected <code>TRUE</code> to select.
         */
        public void setSelected(boolean aSelected)
        {
            Color cl = aSelected ? Color.BLUE : Color.BLACK;
            setForeground(cl);
            if (aSelected) action.actionPerformed(new ActionEvent(this, id, null));
        }

        /**
         * Processes clicks.
         *
         * @param e event.
         */
        protected void processMouseEvent(MouseEvent e)
        {
            if (e.getID() == MouseEvent.MOUSE_PRESSED)
            {
                setSelected(true);
            }
        }
    }

    /**
     * Listener for results updates.
     */
    private class ResultsListener implements ISearchResultListener
    {
        private int results = 0;

        /**
         * Invoked when new result item is added to the list.
         *
         * @param result results list object.
         * @param item   item added.
         * @param index  item index.
         */
        public void itemAdded(ISearchResult result, final ResultItem item, int index)
        {
            results++;

            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    lbResults.setText(MessageFormat.format(Strings.message("search.0.results"),
                        Integer.toString(results)));
                    model.add(item);
                }
            });
        }

        /**
         * Invoked when the result items are removed from the list.
         *
         * @param result results list object.
         */
        public void itemsRemoved(ISearchResult result)
        {
            results = 0;

            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    lbResults.setText(Strings.message("search.no.results"));
                    model.clear();
                }
            });
        }

        /**
         * Invoked when underlying search is finished.
         *
         * @param result results list object.
         */
        public void finished(ISearchResult result)
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    pgSpinner.stop();
                }
            });
        }
    }

    /**
     * Listens to key taps and passes them to the list component.
     */
    private class NavigationListener extends KeyAdapter
    {
        /**
         * Invoked when a key has been pressed.
         *
         * @param e event.
         */
        public void keyPressed(KeyEvent e)
        {
            switch (e.getKeyCode())
            {
                case KeyEvent.VK_UP:
                    itemsList.onPrevItemSelected();
                    break;
                case KeyEvent.VK_DOWN:
                    itemsList.onNextItemSelected();
                    break;
                case KeyEvent.VK_ESCAPE:
                    doCancel();
                    break;
            }
        }
    }

    private class SearchCriteriaChangeMonitor implements ActionListener
    {
        private String lastText;
        public boolean lastPinnedArticlesOnly;
        private final JCheckBox chPinnedArticlesOnly;
        private final JLabel    helpIcon;
        private final SearchField tfSearch;

        public SearchCriteriaChangeMonitor(JCheckBox chPinnedArticlesOnly, SearchField tfSearch, JLabel helpIcon)
        {
            this.chPinnedArticlesOnly = chPinnedArticlesOnly;
            this.helpIcon = helpIcon;
            this.tfSearch = tfSearch;
            lastPinnedArticlesOnly = chPinnedArticlesOnly.isSelected();
        }

        public void actionPerformed(ActionEvent e)
        {
            String text = tfSearch.getText();
            boolean pinnedArticlesOnly = chPinnedArticlesOnly.isSelected();

            showHelpIfNecessary(text);
            if (!text.equalsIgnoreCase(lastText) ||
                pinnedArticlesOnly != lastPinnedArticlesOnly)
            {
                pgSpinner.start();
                searchEngine.setSearchText(text, pinnedArticlesOnly);
                lastText = text;
                lastPinnedArticlesOnly = pinnedArticlesOnly;
            } else
            {
                itemsList.onItemFired();
            }
        }

        private void showHelpIfNecessary(String text)
        {
            helpIcon.setEnabled(SearchEngine.isComplexSeachPattern(text));
        }
    }
}
TOP

Related Classes of com.salas.bb.search.SearchDialog$NavigationListener

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.