SearchFactory.java
上传用户:zhengdagz
上传日期:2014-03-06
资源大小:1956k
文件大小:13k
源码类别:

xml/soap/webservice

开发平台:

Java

  1. /*
  2.  * $Id: SearchFactory.java,v 1.12 2005/10/12 11:26:58 kleopatra Exp $
  3.  *
  4.  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
  5.  * Santa Clara, California 95054, U.S.A. All rights reserved.
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  * 
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  * 
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  20.  */
  21. package org.jdesktop.swingx;
  22. import java.awt.Component;
  23. import java.awt.Container;
  24. import java.awt.Frame;
  25. import java.awt.KeyboardFocusManager;
  26. import java.awt.Point;
  27. import java.awt.Window;
  28. import java.awt.event.ActionEvent;
  29. import java.beans.PropertyChangeEvent;
  30. import java.beans.PropertyChangeListener;
  31. import java.util.HashSet;
  32. import java.util.Iterator;
  33. import java.util.Set;
  34. import javax.swing.AbstractAction;
  35. import javax.swing.Action;
  36. import javax.swing.JComponent;
  37. import javax.swing.JOptionPane;
  38. import javax.swing.JToolBar;
  39. import javax.swing.SwingUtilities;
  40. import org.jdesktop.swingx.plaf.LookAndFeelAddons;
  41. /**
  42.  * Factory to create, configure and show application consistent
  43.  * search and find widgets.
  44.  * 
  45.  * Typically a shared JXFindBar is used for incremental search, while
  46.  * a shared JXFindPanel is used for batch search. This implementation 
  47.  * 
  48.  * <ul>
  49.  *  <li> JXFindBar - adds and shows it in the target's toplevel container's
  50.  *    toolbar (assuming a JXRootPane)
  51.  *  <li> JXFindPanel - creates a JXDialog, adds and shows the findPanel in the
  52.  *    Dialog 
  53.  * </ul>
  54.  * 
  55.  * 
  56.  * PENDING: JW - update (?) views/wiring on focus change. Started brute force - 
  57.  * stop searching. This looks extreme confusing for findBars added to ToolBars 
  58.  * which are empty except for the findbar. Weird problem if triggered from 
  59.  * menu - find widget disappears after having been shown for an instance. 
  60.  * Where's the focus?
  61.  * 
  62.  * 
  63.  * PENDING: add methods to return JXSearchPanels (for use by PatternMatchers).
  64.  * 
  65.  * @author Jeanette Winzenburg
  66.  */
  67. public class SearchFactory {
  68.     // PENDING: rename methods to batch/incremental instead of dialog/toolbar
  69.     static {
  70.         // Hack to enforce loading of SwingX framework ResourceBundle
  71.         LookAndFeelAddons.getAddon();
  72.     }
  73.     private static SearchFactory searchFactory;
  74.    
  75.     /** the shared find widget for batch-find. */
  76.     protected JXFindPanel findPanel;
  77.    
  78.     /** the shared find widget for incremental-find. */
  79.     protected JXFindBar findBar;
  80.     private boolean useFindBar;
  81.     private Point lastFindDialogLocation;
  82.     private FindRemover findRemover;
  83.     
  84.     /** 
  85.      * returns the shared SearchFactory.
  86.      * 
  87.      * @return
  88.      */
  89.     public static SearchFactory getInstance() {
  90.           if (searchFactory == null) {
  91.               searchFactory = new SearchFactory();
  92.           }
  93.           return searchFactory;
  94.       }
  95.     
  96.     /**
  97.      * sets the shared SearchFactory.
  98.      * 
  99.      * @param factory
  100.      */
  101.     public static void setInstance(SearchFactory factory) {
  102.         searchFactory = factory;
  103.     }
  104.     
  105.     /**
  106.      * Shows an appropriate find widget targeted at the searchable.
  107.      * This implementation opens a batch-find or incremental-find 
  108.      * widget based on the showFindInToolBar property (which defaults
  109.      * to false).
  110.      *  
  111.      *  
  112.      * @param target - the component associated with the searchable
  113.      * @param searchable - the object to search.
  114.      */
  115.     public void showFindInput(JComponent target, Searchable searchable) {
  116.         if (isUseFindBar(target, searchable)) {
  117.             showFindBar(target, searchable);
  118.         } else {
  119.             showFindDialog(target, searchable);
  120.         }
  121.     }
  122.     /**
  123.      * Show a incremental-find widget targeted at the searchable.
  124.      * 
  125.      * This implementation uses a JXFindBar and inserts it into the
  126.      * target's toplevel container toolbar. 
  127.      * 
  128.      * PENDING: Nothing shown if there is no toolbar found. 
  129.      * 
  130.      * @param target - the component associated with the searchable
  131.      * @param searchable - the object to search.
  132.      */
  133.     public void showFindBar(JComponent target, Searchable searchable) {
  134.         if (target == null) return;
  135.         removeFromParent(getSharedFindBar());
  136.         Window topLevel = SwingUtilities.getWindowAncestor(target);
  137.         if (topLevel instanceof JXFrame) {
  138.             JXRootPane rootPane = ((JXFrame) topLevel).getRootPaneExt();
  139.             JToolBar toolBar = rootPane.getToolBar();
  140.             if (toolBar == null) {
  141.                 toolBar = new JToolBar();
  142.                 rootPane.setToolBar(toolBar);
  143.             }
  144.             toolBar.add(getSharedFindBar(), 0);
  145.             rootPane.revalidate();
  146.             KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(getSharedFindBar());
  147.             
  148.         }
  149.         target.putClientProperty(AbstractSearchable.MATCH_HIGHLIGHTER, Boolean.TRUE);
  150.         installFindRemover(target, getSharedFindBar());
  151.         getSharedFindBar().setSearchable(searchable);
  152.     }
  153.     protected void installFindRemover(Container target, Container findWidget) {
  154.         if (target != null) {
  155.             getFindRemover().addTarget(target);
  156.         }
  157.         getFindRemover().addTarget(findWidget);
  158.     }
  159.     private FindRemover getFindRemover() {
  160.         if (findRemover == null) {
  161.             findRemover = new FindRemover();
  162.         }
  163.         return findRemover;
  164.     }
  165.     /**
  166.      * convenience method to remove a component from its parent
  167.      * and revalidate the parent
  168.      */
  169.     protected void removeFromParent(JComponent component) {
  170.         Container oldParent = component.getParent();
  171.         if (oldParent != null) {
  172.             oldParent.remove(component);
  173.             if (oldParent instanceof JComponent) {
  174.                 ((JComponent) oldParent).revalidate();
  175.             } else {
  176.                 // not sure... never have non-j comps
  177.                 oldParent.invalidate();
  178.                 oldParent.validate();
  179.             }
  180.         }
  181.     }
  182.     /**
  183.      * returns the shared JXFindBar. Creates and configures on 
  184.      * first call.
  185.      * @return
  186.      */
  187.     public JXFindBar getSharedFindBar() {
  188.         if (findBar == null) {
  189.             findBar = createFindBar();
  190.             configureSharedFindBar();
  191.         }
  192.         return findBar;
  193.     }
  194.     
  195.     /**
  196.      * called after creation of shared FindBar.
  197.      * Subclasses can add configuration code. 
  198.      * Here: registers a custom action to remove the 
  199.      * findbar from its ancestor container.
  200.      * 
  201.      * PRE: findBar != null.
  202.      *
  203.      */
  204.     protected void configureSharedFindBar() {
  205.         Action removeAction = new AbstractAction() {
  206.             public void actionPerformed(ActionEvent e) {
  207.                 removeFromParent(findBar);
  208. //                stopSearching();
  209.                 
  210.             }
  211.             
  212.         };
  213.         findBar.getActionMap().put(JXDialog.CLOSE_ACTION_COMMAND, removeAction);
  214.     }
  215.     /**
  216.      * Factory method to create a JXFindBar.
  217.      * 
  218.      * @return
  219.      */
  220.     public JXFindBar createFindBar() {
  221.         return new JXFindBar();
  222.     }
  223.     /**
  224.      * returns the shared JXFindPanel. Creates and configures on 
  225.      * first call.
  226.      * @return
  227.      */
  228.     public JXFindPanel getSharedFindPanel() {
  229.         if (findPanel == null) {
  230.             findPanel = createFindPanel();
  231.             configureSharedFindPanel();
  232.         }
  233.         return findPanel;
  234.     }
  235.     
  236.     /**
  237.      * called after creation of shared FindPanel.
  238.      * Subclasses can add configuration code. 
  239.      * Here: no-op
  240.      * PRE: findPanel != null.
  241.      *
  242.      */
  243.     protected void configureSharedFindPanel() {
  244.     }
  245.     /**
  246.      * Factory method to create a JXFindPanel.
  247.      * 
  248.      * @return
  249.      */
  250.     public JXFindPanel createFindPanel() {
  251.         return new JXFindPanel();
  252.     }
  253.     /**
  254.      * Show a batch-find widget targeted at the given Searchable.
  255.      * 
  256.      * This implementation uses a shared JXFindPanel contained 
  257.      * JXDialog.
  258.      * 
  259.      * @param target -
  260.      *            the component associated with the searchable
  261.      * @param searchable -
  262.      *            the object to search.
  263.      */
  264.     public void showFindDialog(JComponent target, Searchable searchable) {
  265.         Frame frame = JOptionPane.getRootFrame();
  266.         if (target != null) {
  267.             target.putClientProperty(AbstractSearchable.MATCH_HIGHLIGHTER, Boolean.FALSE);
  268.             Window window = SwingUtilities.getWindowAncestor(target);
  269.             if (window instanceof Frame) {
  270.                 frame = (Frame) window;
  271.             }
  272.         }
  273.         JXDialog topLevel = getDialogForSharedFilePanel();
  274.         JXDialog findDialog;
  275.         if ((topLevel != null) && (topLevel.getOwner().equals(frame))) {
  276.             findDialog = topLevel;
  277.             KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(findDialog);
  278.         } else {
  279.             Point location = hideSharedFilePanel();
  280.             findDialog = new JXDialog(frame, getSharedFindPanel());
  281.             findDialog.setAlwaysOnTop(true);
  282.             findDialog.pack();
  283.             if (location == null) {
  284.                 findDialog.setLocationRelativeTo(frame);
  285.             } else {
  286.                 findDialog.setLocation(location);
  287.             }
  288.         } 
  289.         
  290.         findDialog.setVisible(true);
  291.         installFindRemover(target, findDialog);
  292.         getSharedFindPanel().setSearchable(searchable);
  293.     }
  294.     
  295.     private JXDialog getDialogForSharedFilePanel() {
  296.         if (findPanel == null) return null;
  297.         Window window = SwingUtilities.getWindowAncestor(findPanel);
  298.         return (window instanceof JXDialog) ? (JXDialog) window : null;
  299.     }
  300.     protected Point hideSharedFilePanel() {
  301.         if (findPanel == null) return null;
  302.         Window window = SwingUtilities.getWindowAncestor(findPanel);
  303.         Point location = lastFindDialogLocation;
  304.         if (window != null) {
  305.             findPanel.getParent().remove(findPanel);
  306.             if (window.isVisible()) {
  307.                 location = window.getLocationOnScreen();
  308.             }
  309.             window.dispose();
  310.         }
  311.         return location;
  312.     }
  313.     protected void stopSearching() {
  314.         if (findPanel != null) {
  315.             lastFindDialogLocation = hideSharedFilePanel();
  316.             findPanel.setSearchable(null);
  317.         }
  318.         if (findBar != null) {
  319.             removeFromParent(findBar);
  320.             findBar.setSearchable(null);
  321.         }
  322.         
  323.     }
  324.     /**
  325.      * Returns decision about using a batch- vs. incremental-find for the
  326.      * searchable. This implementation returns the useFindBar property
  327.      * directly.
  328.      * 
  329.      * @param target -
  330.      *            the component associated with the searchable
  331.      * @param searchable -
  332.      *            the object to search.
  333.      * @return true if a incremental-find should be used, false otherwise.
  334.      */
  335.     public boolean isUseFindBar(JComponent target, Searchable searchable) {
  336.         return useFindBar;
  337.     }
  338.  
  339.     /**
  340.      * 
  341.      * @param inToolBar
  342.      */
  343.     public void setUseFindBar(boolean inToolBar) {
  344.         if (inToolBar == useFindBar) return;
  345.         this.useFindBar = inToolBar;
  346.         getFindRemover().endSearching();
  347.     }
  348.     public class FindRemover implements PropertyChangeListener {
  349.         KeyboardFocusManager focusManager;
  350.         Set<Container> targets;
  351.         
  352.         public FindRemover() {
  353.             updateManager();
  354.         }
  355.         public void addTarget(Container target) {
  356.             getTargets().add(target);
  357.         }
  358.         
  359.         public void removeTarget(Container target) {
  360.             getTargets().remove(target);
  361.         }
  362.         
  363.         private Set<Container> getTargets() {
  364.             if (targets == null) {
  365.                 targets = new HashSet<Container>();
  366.             }
  367.             return targets;
  368.         }
  369.         /**
  370.          * 
  371.          */
  372.         private void updateManager() {
  373.             if (focusManager != null) {
  374.                 focusManager.removePropertyChangeListener("permanentFocusOwner", this);
  375.             }
  376.             this.focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
  377.             focusManager.addPropertyChangeListener("permanentFocusOwner", this);
  378.         }
  379.         public void propertyChange(PropertyChangeEvent ev) {
  380.             Component c = focusManager.getPermanentFocusOwner();
  381.             if (c == null) return;
  382.             for (Iterator<Container> iter = getTargets().iterator(); iter.hasNext();) {
  383.                 Container element = iter.next();
  384.                 if ((element == c) || (SwingUtilities.isDescendingFrom(c, element))) {
  385.                     return;
  386.                 }
  387.             }
  388.             endSearching();
  389.        }
  390.         /**
  391.          * 
  392.          */
  393.         public void endSearching() {
  394.             getTargets().clear();
  395.             stopSearching();
  396.         }
  397.     }
  398. }