View Javadoc
1   /*
2    * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  package javax.swing.plaf.synth;
26  
27  import sun.awt.AppContext;
28  
29  import java.util.HashMap;
30  import java.util.Locale;
31  import java.util.Map;
32  import javax.swing.JComponent;
33  import javax.swing.UIDefaults;
34  
35  /**
36   * A distinct rendering area of a Swing component.  A component may
37   * support one or more regions.  Specific component regions are defined
38   * by the typesafe enumeration in this class.
39   * <p>
40   * Regions are typically used as a way to identify the <code>Component</code>s
41   * and areas a particular style is to apply to. Synth's file format allows you
42   * to bind styles based on the name of a <code>Region</code>.
43   * The name is derived from the field name of the constant:
44   * <ol>
45   *  <li>Map all characters to lowercase.
46   *  <li>Map the first character to uppercase.
47   *  <li>Map the first character after underscores to uppercase.
48   *  <li>Remove all underscores.
49   * </ol>
50   * For example, to identify the <code>SPLIT_PANE</code>
51   * <code>Region</code> you would use <code>SplitPane</code>.
52   * The following shows a custom <code>SynthStyleFactory</code>
53   * that returns a specific style for split panes:
54   * <pre>
55   *    public SynthStyle getStyle(JComponent c, Region id) {
56   *        if (id == Region.SPLIT_PANE) {
57   *            return splitPaneStyle;
58   *        }
59   *        ...
60   *    }
61   * </pre>
62   * The following <a href="doc-files/synthFileFormat.html">xml</a>
63   * accomplishes the same thing:
64   * <pre>
65   * &lt;style id="splitPaneStyle"&gt;
66   *   ...
67   * &lt;/style&gt;
68   * &lt;bind style="splitPaneStyle" type="region" key="SplitPane"/&gt;
69   * </pre>
70   *
71   * @since 1.5
72   * @author Scott Violet
73   */
74  public class Region {
75      private static final Object UI_TO_REGION_MAP_KEY = new Object();
76      private static final Object LOWER_CASE_NAME_MAP_KEY = new Object();
77  
78      /**
79       * ArrowButton's are special types of buttons that also render a
80       * directional indicator, typically an arrow. ArrowButtons are used by
81       * composite components, for example ScrollBar's contain ArrowButtons.
82       * To bind a style to this <code>Region</code> use the name
83       * <code>ArrowButton</code>.
84       */
85      public static final Region ARROW_BUTTON = new Region("ArrowButton", false);
86  
87      /**
88       * Button region. To bind a style to this <code>Region</code> use the name
89       * <code>Button</code>.
90       */
91      public static final Region BUTTON = new Region("Button", false);
92  
93      /**
94       * CheckBox region. To bind a style to this <code>Region</code> use the name
95       * <code>CheckBox</code>.
96       */
97      public static final Region CHECK_BOX = new Region("CheckBox", false);
98  
99      /**
100      * CheckBoxMenuItem region. To bind a style to this <code>Region</code> use
101      * the name <code>CheckBoxMenuItem</code>.
102      */
103     public static final Region CHECK_BOX_MENU_ITEM = new Region("CheckBoxMenuItem", false);
104 
105     /**
106      * ColorChooser region. To bind a style to this <code>Region</code> use
107      * the name <code>ColorChooser</code>.
108      */
109     public static final Region COLOR_CHOOSER = new Region("ColorChooser", false);
110 
111     /**
112      * ComboBox region. To bind a style to this <code>Region</code> use
113      * the name <code>ComboBox</code>.
114      */
115     public static final Region COMBO_BOX = new Region("ComboBox", false);
116 
117     /**
118      * DesktopPane region. To bind a style to this <code>Region</code> use
119      * the name <code>DesktopPane</code>.
120      */
121     public static final Region DESKTOP_PANE = new Region("DesktopPane", false);
122 
123     /**
124      * DesktopIcon region. To bind a style to this <code>Region</code> use
125      * the name <code>DesktopIcon</code>.
126      */
127     public static final Region DESKTOP_ICON = new Region("DesktopIcon", false);
128 
129     /**
130      * EditorPane region. To bind a style to this <code>Region</code> use
131      * the name <code>EditorPane</code>.
132      */
133     public static final Region EDITOR_PANE = new Region("EditorPane", false);
134 
135     /**
136      * FileChooser region. To bind a style to this <code>Region</code> use
137      * the name <code>FileChooser</code>.
138      */
139     public static final Region FILE_CHOOSER = new Region("FileChooser", false);
140 
141     /**
142      * FormattedTextField region. To bind a style to this <code>Region</code> use
143      * the name <code>FormattedTextField</code>.
144      */
145     public static final Region FORMATTED_TEXT_FIELD = new Region("FormattedTextField", false);
146 
147     /**
148      * InternalFrame region. To bind a style to this <code>Region</code> use
149      * the name <code>InternalFrame</code>.
150      */
151     public static final Region INTERNAL_FRAME = new Region("InternalFrame", false);
152 
153     /**
154      * TitlePane of an InternalFrame. The TitlePane typically
155      * shows a menu, title, widgets to manipulate the internal frame.
156      * To bind a style to this <code>Region</code> use the name
157      * <code>InternalFrameTitlePane</code>.
158      */
159     public static final Region INTERNAL_FRAME_TITLE_PANE = new Region("InternalFrameTitlePane", false);
160 
161     /**
162      * Label region. To bind a style to this <code>Region</code> use the name
163      * <code>Label</code>.
164      */
165     public static final Region LABEL = new Region("Label", false);
166 
167     /**
168      * List region. To bind a style to this <code>Region</code> use the name
169      * <code>List</code>.
170      */
171     public static final Region LIST = new Region("List", false);
172 
173     /**
174      * Menu region. To bind a style to this <code>Region</code> use the name
175      * <code>Menu</code>.
176      */
177     public static final Region MENU = new Region("Menu", false);
178 
179     /**
180      * MenuBar region. To bind a style to this <code>Region</code> use the name
181      * <code>MenuBar</code>.
182      */
183     public static final Region MENU_BAR = new Region("MenuBar", false);
184 
185     /**
186      * MenuItem region. To bind a style to this <code>Region</code> use the name
187      * <code>MenuItem</code>.
188      */
189     public static final Region MENU_ITEM = new Region("MenuItem", false);
190 
191     /**
192      * Accelerator region of a MenuItem. To bind a style to this
193      * <code>Region</code> use the name <code>MenuItemAccelerator</code>.
194      */
195     public static final Region MENU_ITEM_ACCELERATOR = new Region("MenuItemAccelerator", true);
196 
197     /**
198      * OptionPane region. To bind a style to this <code>Region</code> use
199      * the name <code>OptionPane</code>.
200      */
201     public static final Region OPTION_PANE = new Region("OptionPane", false);
202 
203     /**
204      * Panel region. To bind a style to this <code>Region</code> use the name
205      * <code>Panel</code>.
206      */
207     public static final Region PANEL = new Region("Panel", false);
208 
209     /**
210      * PasswordField region. To bind a style to this <code>Region</code> use
211      * the name <code>PasswordField</code>.
212      */
213     public static final Region PASSWORD_FIELD = new Region("PasswordField", false);
214 
215     /**
216      * PopupMenu region. To bind a style to this <code>Region</code> use
217      * the name <code>PopupMenu</code>.
218      */
219     public static final Region POPUP_MENU = new Region("PopupMenu", false);
220 
221     /**
222      * PopupMenuSeparator region. To bind a style to this <code>Region</code>
223      * use the name <code>PopupMenuSeparator</code>.
224      */
225     public static final Region POPUP_MENU_SEPARATOR = new Region("PopupMenuSeparator", false);
226 
227     /**
228      * ProgressBar region. To bind a style to this <code>Region</code>
229      * use the name <code>ProgressBar</code>.
230      */
231     public static final Region PROGRESS_BAR = new Region("ProgressBar", false);
232 
233     /**
234      * RadioButton region. To bind a style to this <code>Region</code>
235      * use the name <code>RadioButton</code>.
236      */
237     public static final Region RADIO_BUTTON = new Region("RadioButton", false);
238 
239     /**
240      * RegionButtonMenuItem region. To bind a style to this <code>Region</code>
241      * use the name <code>RadioButtonMenuItem</code>.
242      */
243     public static final Region RADIO_BUTTON_MENU_ITEM = new Region("RadioButtonMenuItem", false);
244 
245     /**
246      * RootPane region. To bind a style to this <code>Region</code> use
247      * the name <code>RootPane</code>.
248      */
249     public static final Region ROOT_PANE = new Region("RootPane", false);
250 
251     /**
252      * ScrollBar region. To bind a style to this <code>Region</code> use
253      * the name <code>ScrollBar</code>.
254      */
255     public static final Region SCROLL_BAR = new Region("ScrollBar", false);
256 
257     /**
258      * Track of the ScrollBar. To bind a style to this <code>Region</code> use
259      * the name <code>ScrollBarTrack</code>.
260      */
261     public static final Region SCROLL_BAR_TRACK = new Region("ScrollBarTrack", true);
262 
263     /**
264      * Thumb of the ScrollBar. The thumb is the region of the ScrollBar
265      * that gives a graphical depiction of what percentage of the View is
266      * currently visible. To bind a style to this <code>Region</code> use
267      * the name <code>ScrollBarThumb</code>.
268      */
269     public static final Region SCROLL_BAR_THUMB = new Region("ScrollBarThumb", true);
270 
271     /**
272      * ScrollPane region. To bind a style to this <code>Region</code> use
273      * the name <code>ScrollPane</code>.
274      */
275     public static final Region SCROLL_PANE = new Region("ScrollPane", false);
276 
277     /**
278      * Separator region. To bind a style to this <code>Region</code> use
279      * the name <code>Separator</code>.
280      */
281     public static final Region SEPARATOR = new Region("Separator", false);
282 
283     /**
284      * Slider region. To bind a style to this <code>Region</code> use
285      * the name <code>Slider</code>.
286      */
287     public static final Region SLIDER = new Region("Slider", false);
288 
289     /**
290      * Track of the Slider. To bind a style to this <code>Region</code> use
291      * the name <code>SliderTrack</code>.
292      */
293     public static final Region SLIDER_TRACK = new Region("SliderTrack", true);
294 
295     /**
296      * Thumb of the Slider. The thumb of the Slider identifies the current
297      * value. To bind a style to this <code>Region</code> use the name
298      * <code>SliderThumb</code>.
299      */
300     public static final Region SLIDER_THUMB = new Region("SliderThumb", true);
301 
302     /**
303      * Spinner region. To bind a style to this <code>Region</code> use the name
304      * <code>Spinner</code>.
305      */
306     public static final Region SPINNER = new Region("Spinner", false);
307 
308     /**
309      * SplitPane region. To bind a style to this <code>Region</code> use the name
310      * <code>SplitPane</code>.
311      */
312     public static final Region SPLIT_PANE = new Region("SplitPane", false);
313 
314     /**
315      * Divider of the SplitPane. To bind a style to this <code>Region</code>
316      * use the name <code>SplitPaneDivider</code>.
317      */
318     public static final Region SPLIT_PANE_DIVIDER = new Region("SplitPaneDivider", true);
319 
320     /**
321      * TabbedPane region. To bind a style to this <code>Region</code> use
322      * the name <code>TabbedPane</code>.
323      */
324     public static final Region TABBED_PANE = new Region("TabbedPane", false);
325 
326     /**
327      * Region of a TabbedPane for one tab. To bind a style to this
328      * <code>Region</code> use the name <code>TabbedPaneTab</code>.
329      */
330     public static final Region TABBED_PANE_TAB = new Region("TabbedPaneTab", true);
331 
332     /**
333      * Region of a TabbedPane containing the tabs. To bind a style to this
334      * <code>Region</code> use the name <code>TabbedPaneTabArea</code>.
335      */
336     public static final Region TABBED_PANE_TAB_AREA = new Region("TabbedPaneTabArea", true);
337 
338     /**
339      * Region of a TabbedPane containing the content. To bind a style to this
340      * <code>Region</code> use the name <code>TabbedPaneContent</code>.
341      */
342     public static final Region TABBED_PANE_CONTENT = new Region("TabbedPaneContent", true);
343 
344     /**
345      * Table region. To bind a style to this <code>Region</code> use
346      * the name <code>Table</code>.
347      */
348     public static final Region TABLE = new Region("Table", false);
349 
350     /**
351      * TableHeader region. To bind a style to this <code>Region</code> use
352      * the name <code>TableHeader</code>.
353      */
354     public static final Region TABLE_HEADER = new Region("TableHeader", false);
355 
356     /**
357      * TextArea region. To bind a style to this <code>Region</code> use
358      * the name <code>TextArea</code>.
359      */
360     public static final Region TEXT_AREA = new Region("TextArea", false);
361 
362     /**
363      * TextField region. To bind a style to this <code>Region</code> use
364      * the name <code>TextField</code>.
365      */
366     public static final Region TEXT_FIELD = new Region("TextField", false);
367 
368     /**
369      * TextPane region. To bind a style to this <code>Region</code> use
370      * the name <code>TextPane</code>.
371      */
372     public static final Region TEXT_PANE = new Region("TextPane", false);
373 
374     /**
375      * ToggleButton region. To bind a style to this <code>Region</code> use
376      * the name <code>ToggleButton</code>.
377      */
378     public static final Region TOGGLE_BUTTON = new Region("ToggleButton", false);
379 
380     /**
381      * ToolBar region. To bind a style to this <code>Region</code> use
382      * the name <code>ToolBar</code>.
383      */
384     public static final Region TOOL_BAR = new Region("ToolBar", false);
385 
386     /**
387      * Region of the ToolBar containing the content. To bind a style to this
388      * <code>Region</code> use the name <code>ToolBarContent</code>.
389      */
390     public static final Region TOOL_BAR_CONTENT = new Region("ToolBarContent", true);
391 
392     /**
393      * Region for the Window containing the ToolBar. To bind a style to this
394      * <code>Region</code> use the name <code>ToolBarDragWindow</code>.
395      */
396     public static final Region TOOL_BAR_DRAG_WINDOW = new Region("ToolBarDragWindow", false);
397 
398     /**
399      * ToolTip region. To bind a style to this <code>Region</code> use
400      * the name <code>ToolTip</code>.
401      */
402     public static final Region TOOL_TIP = new Region("ToolTip", false);
403 
404     /**
405      * ToolBar separator region. To bind a style to this <code>Region</code> use
406      * the name <code>ToolBarSeparator</code>.
407      */
408     public static final Region TOOL_BAR_SEPARATOR = new Region("ToolBarSeparator", false);
409 
410     /**
411      * Tree region. To bind a style to this <code>Region</code> use the name
412      * <code>Tree</code>.
413      */
414     public static final Region TREE = new Region("Tree", false);
415 
416     /**
417      * Region of the Tree for one cell. To bind a style to this
418      * <code>Region</code> use the name <code>TreeCell</code>.
419      */
420     public static final Region TREE_CELL = new Region("TreeCell", true);
421 
422     /**
423      * Viewport region. To bind a style to this <code>Region</code> use
424      * the name <code>Viewport</code>.
425      */
426     public static final Region VIEWPORT = new Region("Viewport", false);
427 
428     private static Map<String, Region> getUItoRegionMap() {
429         AppContext context = AppContext.getAppContext();
430         Map<String, Region> map = (Map<String, Region>) context.get(UI_TO_REGION_MAP_KEY);
431         if (map == null) {
432             map = new HashMap<String, Region>();
433             map.put("ArrowButtonUI", ARROW_BUTTON);
434             map.put("ButtonUI", BUTTON);
435             map.put("CheckBoxUI", CHECK_BOX);
436             map.put("CheckBoxMenuItemUI", CHECK_BOX_MENU_ITEM);
437             map.put("ColorChooserUI", COLOR_CHOOSER);
438             map.put("ComboBoxUI", COMBO_BOX);
439             map.put("DesktopPaneUI", DESKTOP_PANE);
440             map.put("DesktopIconUI", DESKTOP_ICON);
441             map.put("EditorPaneUI", EDITOR_PANE);
442             map.put("FileChooserUI", FILE_CHOOSER);
443             map.put("FormattedTextFieldUI", FORMATTED_TEXT_FIELD);
444             map.put("InternalFrameUI", INTERNAL_FRAME);
445             map.put("InternalFrameTitlePaneUI", INTERNAL_FRAME_TITLE_PANE);
446             map.put("LabelUI", LABEL);
447             map.put("ListUI", LIST);
448             map.put("MenuUI", MENU);
449             map.put("MenuBarUI", MENU_BAR);
450             map.put("MenuItemUI", MENU_ITEM);
451             map.put("OptionPaneUI", OPTION_PANE);
452             map.put("PanelUI", PANEL);
453             map.put("PasswordFieldUI", PASSWORD_FIELD);
454             map.put("PopupMenuUI", POPUP_MENU);
455             map.put("PopupMenuSeparatorUI", POPUP_MENU_SEPARATOR);
456             map.put("ProgressBarUI", PROGRESS_BAR);
457             map.put("RadioButtonUI", RADIO_BUTTON);
458             map.put("RadioButtonMenuItemUI", RADIO_BUTTON_MENU_ITEM);
459             map.put("RootPaneUI", ROOT_PANE);
460             map.put("ScrollBarUI", SCROLL_BAR);
461             map.put("ScrollPaneUI", SCROLL_PANE);
462             map.put("SeparatorUI", SEPARATOR);
463             map.put("SliderUI", SLIDER);
464             map.put("SpinnerUI", SPINNER);
465             map.put("SplitPaneUI", SPLIT_PANE);
466             map.put("TabbedPaneUI", TABBED_PANE);
467             map.put("TableUI", TABLE);
468             map.put("TableHeaderUI", TABLE_HEADER);
469             map.put("TextAreaUI", TEXT_AREA);
470             map.put("TextFieldUI", TEXT_FIELD);
471             map.put("TextPaneUI", TEXT_PANE);
472             map.put("ToggleButtonUI", TOGGLE_BUTTON);
473             map.put("ToolBarUI", TOOL_BAR);
474             map.put("ToolTipUI", TOOL_TIP);
475             map.put("ToolBarSeparatorUI", TOOL_BAR_SEPARATOR);
476             map.put("TreeUI", TREE);
477             map.put("ViewportUI", VIEWPORT);
478             context.put(UI_TO_REGION_MAP_KEY, map);
479         }
480         return map;
481     }
482 
483     private static Map<Region, String> getLowerCaseNameMap() {
484         AppContext context = AppContext.getAppContext();
485         Map<Region, String> map = (Map<Region, String>) context.get(LOWER_CASE_NAME_MAP_KEY);
486         if (map == null) {
487             map = new HashMap<Region, String>();
488             context.put(LOWER_CASE_NAME_MAP_KEY, map);
489         }
490         return map;
491     }
492 
493     static Region getRegion(JComponent c) {
494         return getUItoRegionMap().get(c.getUIClassID());
495     }
496 
497     static void registerUIs(UIDefaults table) {
498         for (Object key : getUItoRegionMap().keySet()) {
499             table.put(key, "javax.swing.plaf.synth.SynthLookAndFeel");
500         }
501     }
502 
503     private final String name;
504     private final boolean subregion;
505 
506     private Region(String name, boolean subregion) {
507         if (name == null) {
508             throw new NullPointerException("You must specify a non-null name");
509         }
510         this.name = name;
511         this.subregion = subregion;
512     }
513 
514     /**
515      * Creates a Region with the specified name. This should only be
516      * used if you are creating your own <code>JComponent</code> subclass
517      * with a custom <code>ComponentUI</code> class.
518      *
519      * @param name Name of the region
520      * @param ui String that will be returned from
521      *           <code>component.getUIClassID</code>. This will be null
522      *           if this is a subregion.
523      * @param subregion Whether or not this is a subregion.
524      */
525     protected Region(String name, String ui, boolean subregion) {
526         this(name, subregion);
527         if (ui != null) {
528             getUItoRegionMap().put(ui, this);
529         }
530     }
531 
532     /**
533      * Returns true if the Region is a subregion of a Component, otherwise
534      * false. For example, <code>Region.BUTTON</code> corresponds do a
535      * <code>Component</code> so that <code>Region.BUTTON.isSubregion()</code>
536      * returns false.
537      *
538      * @return true if the Region is a subregion of a Component.
539      */
540     public boolean isSubregion() {
541         return subregion;
542     }
543 
544     /**
545      * Returns the name of the region.
546      *
547      * @return name of the Region.
548      */
549     public String getName() {
550         return name;
551     }
552 
553     /**
554      * Returns the name, in lowercase.
555      *
556      * @return lower case representation of the name of the Region
557      */
558     String getLowerCaseName() {
559         Map<Region, String> lowerCaseNameMap = getLowerCaseNameMap();
560         String lowerCaseName = lowerCaseNameMap.get(this);
561         if (lowerCaseName == null) {
562             lowerCaseName = name.toLowerCase(Locale.ENGLISH);
563             lowerCaseNameMap.put(this, lowerCaseName);
564         }
565         return lowerCaseName;
566     }
567 
568     /**
569      * Returns the name of the Region.
570      *
571      * @return name of the Region.
572      */
573     @Override
574     public String toString() {
575         return name;
576     }
577 }