< prev index next >

src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java

Print this page




  81 import java.beans.PropertyChangeEvent;
  82 
  83 
  84 /**
  85  * A base class to use in creating a look and feel for Swing.
  86  * <p>
  87  * Each of the {@code ComponentUI}s provided by {@code
  88  * BasicLookAndFeel} derives its behavior from the defaults
  89  * table. Unless otherwise noted each of the {@code ComponentUI}
  90  * implementations in this package document the set of defaults they
  91  * use. Unless otherwise noted the defaults are installed at the time
  92  * {@code installUI} is invoked, and follow the recommendations
  93  * outlined in {@code LookAndFeel} for installing defaults.
  94  * <p>
  95  * <strong>Warning:</strong>
  96  * Serialized objects of this class will not be compatible with
  97  * future Swing releases. The current serialization support is
  98  * appropriate for short term storage or RMI between applications running
  99  * the same version of Swing.  As of 1.4, support for long term storage
 100  * of all JavaBeans&trade;
 101  * has been added to the <code>java.beans</code> package.
 102  * Please see {@link java.beans.XMLEncoder}.
 103  *
 104  * @author unattributed
 105  */
 106 @SuppressWarnings("serial") // Same-version serialization only
 107 public abstract class BasicLookAndFeel extends LookAndFeel implements Serializable
 108 {
 109     /**
 110      * Whether or not the developer has created a JPopupMenu.
 111      */
 112     static boolean needsEventHelper;
 113 
 114     /**
 115      * Lock used when manipulating clipPlaying.
 116      */
 117     private transient Object audioLock = new Object();
 118     /**
 119      * The Clip that is currently playing (set in AudioAction).
 120      */
 121     private Clip clipPlaying;


 203             AccessController.doPrivileged(invocator);
 204             invocator = null;
 205         }
 206 
 207         if (disposer != null) {
 208             // Note that we're likely calling removePropertyChangeListener()
 209             // during the course of AppContext.firePropertyChange().
 210             // However, EventListenerAggreggate has code to safely modify
 211             // the list under such circumstances.
 212             context.removePropertyChangeListener(AppContext.GUI_DISPOSED,
 213                                                  disposer);
 214             disposer = null;
 215         }
 216     }
 217 
 218     /**
 219      * Populates {@code table} with mappings from {@code uiClassID} to the
 220      * fully qualified name of the ui class. The value for a
 221      * particular {@code uiClassID} is {@code
 222      * "javax.swing.plaf.basic.Basic + uiClassID"}. For example, the
 223      * value for the {@code uiClassID} {@code TreeUI} is {@code
 224      * "javax.swing.plaf.basic.BasicTreeUI"}.
 225      *
 226      * @param table the {@code UIDefaults} instance the entries are
 227      *        added to
 228      * @throws NullPointerException if {@code table} is {@code null}
 229      *
 230      * @see javax.swing.LookAndFeel
 231      * @see #getDefaults
 232      */
 233     protected void initClassDefaults(UIDefaults table)
 234     {
 235         final String basicPackageName = "javax.swing.plaf.basic.";
 236         Object[] uiDefaults = {
 237                    "ButtonUI", basicPackageName + "BasicButtonUI",
 238                  "CheckBoxUI", basicPackageName + "BasicCheckBoxUI",
 239              "ColorChooserUI", basicPackageName + "BasicColorChooserUI",
 240        "FormattedTextFieldUI", basicPackageName + "BasicFormattedTextFieldUI",
 241                   "MenuBarUI", basicPackageName + "BasicMenuBarUI",
 242                      "MenuUI", basicPackageName + "BasicMenuUI",
 243                  "MenuItemUI", basicPackageName + "BasicMenuItemUI",


1840                     "released ENTER", "release",
1841                         "ctrl ENTER", "press",
1842                "ctrl released ENTER", "release"
1843               },
1844         };
1845 
1846         table.putDefaults(defaults);
1847     }
1848 
1849     static int getFocusAcceleratorKeyMask() {
1850         Toolkit tk = Toolkit.getDefaultToolkit();
1851         if (tk instanceof SunToolkit) {
1852             return ((SunToolkit)tk).getFocusAcceleratorKeyMask();
1853         }
1854         return ActionEvent.ALT_MASK;
1855     }
1856 
1857 
1858 
1859     /**
1860      * Returns the ui that is of type <code>klass</code>, or null if
1861      * one can not be found.
1862      */
1863     static Object getUIOfType(ComponentUI ui, Class<?> klass) {
1864         if (klass.isInstance(ui)) {
1865             return ui;
1866         }
1867         return null;
1868     }
1869 
1870     // ********* Auditory Cue support methods and objects *********
1871     // also see the "AuditoryCues" section of the defaults table
1872 
1873     /**
1874      * Returns an <code>ActionMap</code> containing the audio actions
1875      * for this look and feel.
1876      * <P>
1877      * The returned <code>ActionMap</code> contains <code>Actions</code> that
1878      * embody the ability to render an auditory cue. These auditory
1879      * cues map onto user and system activities that may be useful
1880      * for an end user to know about (such as a dialog box appearing).
1881      * <P>
1882      * At the appropriate time,
1883      * the {@code ComponentUI} is responsible for obtaining an
1884      * <code>Action</code> out of the <code>ActionMap</code> and passing
1885      * it to <code>playSound</code>.
1886      * <P>
1887      * This method first looks up the {@code ActionMap} from the
1888      * defaults using the key {@code "AuditoryCues.actionMap"}.
1889      * <p>
1890      * If the value is {@code non-null}, it is returned. If the value
1891      * of the default {@code "AuditoryCues.actionMap"} is {@code null}
1892      * and the value of the default {@code "AuditoryCues.cueList"} is
1893      * {@code non-null}, an {@code ActionMapUIResource} is created and
1894      * populated. Population is done by iterating over each of the
1895      * elements of the {@code "AuditoryCues.cueList"} array, and
1896      * invoking {@code createAudioAction()} to create an {@code
1897      * Action} for each element.  The resulting {@code Action} is
1898      * placed in the {@code ActionMapUIResource}, using the array
1899      * element as the key.  For example, if the {@code
1900      * "AuditoryCues.cueList"} array contains a single-element, {@code
1901      * "audioKey"}, the {@code ActionMapUIResource} is created, then
1902      * populated by way of {@code actionMap.put(cueList[0],
1903      * createAudioAction(cueList[0]))}.
1904      * <p>
1905      * If the value of the default {@code "AuditoryCues.actionMap"} is


2026          */
2027         private void cancelCurrentSound(Clip clip) {
2028             Clip lastClip = null;
2029 
2030             synchronized(audioLock) {
2031                 if (clip == null || clip == clipPlaying) {
2032                     lastClip = clipPlaying;
2033                     clipPlaying = null;
2034                 }
2035             }
2036 
2037             if (lastClip != null) {
2038                 lastClip.removeLineListener(this);
2039                 lastClip.close();
2040             }
2041         }
2042     }
2043 
2044     /**
2045      * Utility method that loads audio bits for the specified
2046      * <code>soundFile</code> filename. If this method is unable to
2047      * build a viable path name from the <code>baseClass</code> and
2048      * <code>soundFile</code> passed into this method, it will
2049      * return <code>null</code>.
2050      *
2051      * @param soundFile    the name of the audio file to be retrieved
2052      *                     from disk
2053      * @return             A byte[] with audio data or null
2054      * @since 1.4
2055      */
2056     private byte[] loadAudioData(final String soundFile){
2057         if (soundFile == null) {
2058             return null;
2059         }
2060         /* Copy resource into a byte array.  This is
2061          * necessary because several browsers consider
2062          * Class.getResource a security risk since it
2063          * can be used to load additional classes.
2064          * Class.getResourceAsStream just returns raw
2065          * bytes, which we can convert to a sound.
2066          */
2067         byte[] buffer = AccessController.doPrivileged(
2068                                                  new PrivilegedAction<byte[]>() {
2069                 public byte[] run() {


2092                     }
2093                 }
2094             });
2095         if (buffer == null) {
2096             System.err.println(getClass().getName() + "/" +
2097                                soundFile + " not found.");
2098             return null;
2099         }
2100         if (buffer.length == 0) {
2101             System.err.println("warning: " + soundFile +
2102                                " is zero-length");
2103             return null;
2104         }
2105         return buffer;
2106     }
2107 
2108     /**
2109      * If necessary, invokes {@code actionPerformed} on
2110      * {@code audioAction} to play a sound.
2111      * The {@code actionPerformed} method is invoked if the value of
2112      * the {@code "AuditoryCues.playList"} default is a {@code
2113      * non-null} {@code Object[]} containing a {@code String} entry
2114      * equal to the name of the {@code audioAction}.
2115      *
2116      * @param audioAction an Action that knows how to render the audio
2117      *                    associated with the system or user activity
2118      *                    that is occurring; a value of {@code null}, is
2119      *                    ignored
2120      * @throws ClassCastException if {@code audioAction} is {@code non-null}
2121      *         and the value of the default {@code "AuditoryCues.playList"}
2122      *         is not an {@code Object[]}
2123      * @since 1.4
2124      */
2125     protected void playSound(Action audioAction) {
2126         if (audioAction != null) {
2127             Object[] audioStrings = (Object[])
2128                                     UIManager.get("AuditoryCues.playList");
2129             if (audioStrings != null) {
2130                 // create a HashSet to help us decide to play or not
2131                 HashSet<Object> audioCues = new HashSet<Object>();
2132                 for (Object audioString : audioStrings) {
2133                     audioCues.add(audioString);




  81 import java.beans.PropertyChangeEvent;
  82 
  83 
  84 /**
  85  * A base class to use in creating a look and feel for Swing.
  86  * <p>
  87  * Each of the {@code ComponentUI}s provided by {@code
  88  * BasicLookAndFeel} derives its behavior from the defaults
  89  * table. Unless otherwise noted each of the {@code ComponentUI}
  90  * implementations in this package document the set of defaults they
  91  * use. Unless otherwise noted the defaults are installed at the time
  92  * {@code installUI} is invoked, and follow the recommendations
  93  * outlined in {@code LookAndFeel} for installing defaults.
  94  * <p>
  95  * <strong>Warning:</strong>
  96  * Serialized objects of this class will not be compatible with
  97  * future Swing releases. The current serialization support is
  98  * appropriate for short term storage or RMI between applications running
  99  * the same version of Swing.  As of 1.4, support for long term storage
 100  * of all JavaBeans&trade;
 101  * has been added to the {@code java.beans} package.
 102  * Please see {@link java.beans.XMLEncoder}.
 103  *
 104  * @author unattributed
 105  */
 106 @SuppressWarnings("serial") // Same-version serialization only
 107 public abstract class BasicLookAndFeel extends LookAndFeel implements Serializable
 108 {
 109     /**
 110      * Whether or not the developer has created a JPopupMenu.
 111      */
 112     static boolean needsEventHelper;
 113 
 114     /**
 115      * Lock used when manipulating clipPlaying.
 116      */
 117     private transient Object audioLock = new Object();
 118     /**
 119      * The Clip that is currently playing (set in AudioAction).
 120      */
 121     private Clip clipPlaying;


 203             AccessController.doPrivileged(invocator);
 204             invocator = null;
 205         }
 206 
 207         if (disposer != null) {
 208             // Note that we're likely calling removePropertyChangeListener()
 209             // during the course of AppContext.firePropertyChange().
 210             // However, EventListenerAggreggate has code to safely modify
 211             // the list under such circumstances.
 212             context.removePropertyChangeListener(AppContext.GUI_DISPOSED,
 213                                                  disposer);
 214             disposer = null;
 215         }
 216     }
 217 
 218     /**
 219      * Populates {@code table} with mappings from {@code uiClassID} to the
 220      * fully qualified name of the ui class. The value for a
 221      * particular {@code uiClassID} is {@code
 222      * "javax.swing.plaf.basic.Basic + uiClassID"}. For example, the
 223      * value for the {@code uiClassID TreeUI} is {@code
 224      * "javax.swing.plaf.basic.BasicTreeUI"}.
 225      *
 226      * @param table the {@code UIDefaults} instance the entries are
 227      *        added to
 228      * @throws NullPointerException if {@code table} is {@code null}
 229      *
 230      * @see javax.swing.LookAndFeel
 231      * @see #getDefaults
 232      */
 233     protected void initClassDefaults(UIDefaults table)
 234     {
 235         final String basicPackageName = "javax.swing.plaf.basic.";
 236         Object[] uiDefaults = {
 237                    "ButtonUI", basicPackageName + "BasicButtonUI",
 238                  "CheckBoxUI", basicPackageName + "BasicCheckBoxUI",
 239              "ColorChooserUI", basicPackageName + "BasicColorChooserUI",
 240        "FormattedTextFieldUI", basicPackageName + "BasicFormattedTextFieldUI",
 241                   "MenuBarUI", basicPackageName + "BasicMenuBarUI",
 242                      "MenuUI", basicPackageName + "BasicMenuUI",
 243                  "MenuItemUI", basicPackageName + "BasicMenuItemUI",


1840                     "released ENTER", "release",
1841                         "ctrl ENTER", "press",
1842                "ctrl released ENTER", "release"
1843               },
1844         };
1845 
1846         table.putDefaults(defaults);
1847     }
1848 
1849     static int getFocusAcceleratorKeyMask() {
1850         Toolkit tk = Toolkit.getDefaultToolkit();
1851         if (tk instanceof SunToolkit) {
1852             return ((SunToolkit)tk).getFocusAcceleratorKeyMask();
1853         }
1854         return ActionEvent.ALT_MASK;
1855     }
1856 
1857 
1858 
1859     /**
1860      * Returns the ui that is of type {@code klass}, or null if
1861      * one can not be found.
1862      */
1863     static Object getUIOfType(ComponentUI ui, Class<?> klass) {
1864         if (klass.isInstance(ui)) {
1865             return ui;
1866         }
1867         return null;
1868     }
1869 
1870     // ********* Auditory Cue support methods and objects *********
1871     // also see the "AuditoryCues" section of the defaults table
1872 
1873     /**
1874      * Returns an {@code ActionMap} containing the audio actions
1875      * for this look and feel.
1876      * <P>
1877      * The returned {@code ActionMap} contains {@code Actions} that
1878      * embody the ability to render an auditory cue. These auditory
1879      * cues map onto user and system activities that may be useful
1880      * for an end user to know about (such as a dialog box appearing).
1881      * <P>
1882      * At the appropriate time,
1883      * the {@code ComponentUI} is responsible for obtaining an
1884      * {@code Action} out of the {@code ActionMap} and passing
1885      * it to {@code playSound}.
1886      * <P>
1887      * This method first looks up the {@code ActionMap} from the
1888      * defaults using the key {@code "AuditoryCues.actionMap"}.
1889      * <p>
1890      * If the value is {@code non-null}, it is returned. If the value
1891      * of the default {@code "AuditoryCues.actionMap"} is {@code null}
1892      * and the value of the default {@code "AuditoryCues.cueList"} is
1893      * {@code non-null}, an {@code ActionMapUIResource} is created and
1894      * populated. Population is done by iterating over each of the
1895      * elements of the {@code "AuditoryCues.cueList"} array, and
1896      * invoking {@code createAudioAction()} to create an {@code
1897      * Action} for each element.  The resulting {@code Action} is
1898      * placed in the {@code ActionMapUIResource}, using the array
1899      * element as the key.  For example, if the {@code
1900      * "AuditoryCues.cueList"} array contains a single-element, {@code
1901      * "audioKey"}, the {@code ActionMapUIResource} is created, then
1902      * populated by way of {@code actionMap.put(cueList[0],
1903      * createAudioAction(cueList[0]))}.
1904      * <p>
1905      * If the value of the default {@code "AuditoryCues.actionMap"} is


2026          */
2027         private void cancelCurrentSound(Clip clip) {
2028             Clip lastClip = null;
2029 
2030             synchronized(audioLock) {
2031                 if (clip == null || clip == clipPlaying) {
2032                     lastClip = clipPlaying;
2033                     clipPlaying = null;
2034                 }
2035             }
2036 
2037             if (lastClip != null) {
2038                 lastClip.removeLineListener(this);
2039                 lastClip.close();
2040             }
2041         }
2042     }
2043 
2044     /**
2045      * Utility method that loads audio bits for the specified
2046      * {@code soundFile} filename. If this method is unable to
2047      * build a viable path name from the {@code baseClass} and
2048      * {@code soundFile} passed into this method, it will
2049      * return {@code null}.
2050      *
2051      * @param soundFile    the name of the audio file to be retrieved
2052      *                     from disk
2053      * @return             A byte[] with audio data or null
2054      * @since 1.4
2055      */
2056     private byte[] loadAudioData(final String soundFile){
2057         if (soundFile == null) {
2058             return null;
2059         }
2060         /* Copy resource into a byte array.  This is
2061          * necessary because several browsers consider
2062          * Class.getResource a security risk since it
2063          * can be used to load additional classes.
2064          * Class.getResourceAsStream just returns raw
2065          * bytes, which we can convert to a sound.
2066          */
2067         byte[] buffer = AccessController.doPrivileged(
2068                                                  new PrivilegedAction<byte[]>() {
2069                 public byte[] run() {


2092                     }
2093                 }
2094             });
2095         if (buffer == null) {
2096             System.err.println(getClass().getName() + "/" +
2097                                soundFile + " not found.");
2098             return null;
2099         }
2100         if (buffer.length == 0) {
2101             System.err.println("warning: " + soundFile +
2102                                " is zero-length");
2103             return null;
2104         }
2105         return buffer;
2106     }
2107 
2108     /**
2109      * If necessary, invokes {@code actionPerformed} on
2110      * {@code audioAction} to play a sound.
2111      * The {@code actionPerformed} method is invoked if the value of
2112      * the {@code "AuditoryCues.playList"} default is a
2113      * {@code non-null Object[]} containing a {@code String} entry
2114      * equal to the name of the {@code audioAction}.
2115      *
2116      * @param audioAction an Action that knows how to render the audio
2117      *                    associated with the system or user activity
2118      *                    that is occurring; a value of {@code null}, is
2119      *                    ignored
2120      * @throws ClassCastException if {@code audioAction} is {@code non-null}
2121      *         and the value of the default {@code "AuditoryCues.playList"}
2122      *         is not an {@code Object[]}
2123      * @since 1.4
2124      */
2125     protected void playSound(Action audioAction) {
2126         if (audioAction != null) {
2127             Object[] audioStrings = (Object[])
2128                                     UIManager.get("AuditoryCues.playList");
2129             if (audioStrings != null) {
2130                 // create a HashSet to help us decide to play or not
2131                 HashSet<Object> audioCues = new HashSet<Object>();
2132                 for (Object audioString : audioStrings) {
2133                     audioCues.add(audioString);


< prev index next >