001package org.jdesktop.swingx.search;
002
003import java.awt.event.ActionListener;
004import java.beans.PropertyChangeEvent;
005
006import javax.swing.JPopupMenu;
007import javax.swing.JTextField;
008import javax.swing.UIManager;
009
010import org.jdesktop.swingx.plaf.AbstractUIChangeHandler;
011import org.jdesktop.swingx.util.OS;
012
013/**
014 * TODO: comment
015 * 
016 * @author Peter Weishapl <petw@gmx.net>
017 */
018public class NativeSearchFieldSupport {
019        public static final String FIND_POPUP_PROPERTY = "JTextField.Search.FindPopup";
020        public static final String FIND_ACTION_PROPERTY = "JTextField.Search.FindAction";
021        public static final String MAC_SEARCH_VARIANT = "search";
022        public static final String MAC_TEXT_FIELD_VARIANT_PROPERTY = "JTextField.variant";
023        public static final String CANCEL_ACTION_PROPERTY = "JTextField.Search.CancelAction";
024
025        /**
026         * @return <code>true</code> if we run Leopard and the Mac Look And Feel.
027         */
028        public static boolean isNativeSearchFieldSupported() {
029                try {
030                        String versionString = System.getProperty("os.version");
031                        // Mac versions have the format 10.x or 10.x.x
032                        if (versionString.length() < 4) {
033                                return false;
034                        }
035                        // only the part 10.x is important
036                        versionString = versionString.substring(0, 4);
037
038                        return OS.isMacOSX() && Float.parseFloat(versionString) >= 10.5
039                                        && UIManager.getLookAndFeel().getName().equals("Mac OS X");
040                } catch (Exception e) {
041                        // in case the os.version cannot be parsed, we are surely not
042                        // running mac os x.
043                        return false;
044                }
045        }
046
047        public static void setSearchField(JTextField txt, boolean isSearchField) {
048                // Leopard Hack: ensure property change event is triggered, if nothing
049                // changes.
050                if (isSearchField == isSearchField(txt)) {
051                        txt.putClientProperty(MAC_TEXT_FIELD_VARIANT_PROPERTY, "_triggerevent_");
052                } else if (isSearchField) {
053                        // if we have a search field here, register listener for ui changes
054                        // (leopard hack)
055                        uiChangeHandler.install(txt);
056                } else {
057                        // if we don't have a search field, we don't need to listen anymore.
058                        uiChangeHandler.uninstall(txt);
059                }
060
061                if (isSearchField) {
062                        txt.putClientProperty(MAC_TEXT_FIELD_VARIANT_PROPERTY, MAC_SEARCH_VARIANT);
063                        txt.putClientProperty("Quaqua.TextField.style", MAC_SEARCH_VARIANT);
064
065                } else {
066                        txt.putClientProperty(MAC_TEXT_FIELD_VARIANT_PROPERTY, "default");
067                        txt.putClientProperty("Quaqua.TextField.style", "default");
068                }
069        }
070
071        public static boolean isSearchField(JTextField txt) {
072                return MAC_SEARCH_VARIANT.equals(txt.getClientProperty(MAC_TEXT_FIELD_VARIANT_PROPERTY));
073        }
074
075        public static boolean isNativeSearchField(JTextField txt) {
076                return isSearchField(txt) && isNativeSearchFieldSupported();
077        }
078
079        public static void setFindPopupMenu(JTextField txt, JPopupMenu popupMenu) {
080                txt.putClientProperty(FIND_POPUP_PROPERTY, popupMenu);
081        }
082
083        public static JPopupMenu getFindPopupMenu(JTextField txt) {
084                return (JPopupMenu) txt.getClientProperty(FIND_POPUP_PROPERTY);
085        }
086
087        public static void setFindAction(JTextField txt, ActionListener findAction) {
088                txt.putClientProperty(FIND_ACTION_PROPERTY, findAction);
089        }
090
091        public static ActionListener getFindAction(JTextField txt) {
092                return (ActionListener) txt.getClientProperty(FIND_ACTION_PROPERTY);
093        }
094        
095        public static void setCancelAction(JTextField txt, ActionListener cancelAction) {
096                txt.putClientProperty(CANCEL_ACTION_PROPERTY, cancelAction);
097        }
098
099        public static ActionListener getCancelAction(JTextField txt) {
100                return (ActionListener) txt.getClientProperty(CANCEL_ACTION_PROPERTY);
101        }
102
103        private static final SearchFieldUIChangeHandler uiChangeHandler = new SearchFieldUIChangeHandler();
104
105        private static final class SearchFieldUIChangeHandler extends AbstractUIChangeHandler {
106                @Override
107        public void propertyChange(PropertyChangeEvent evt) {
108                        JTextField txt = (JTextField) evt.getSource();
109                        // Leopard hack to make appear correctly in search variant when
110                        // changing LnF.
111                        setSearchField(txt, isSearchField(txt));
112                }
113        }
114}