1 /*
2  * Copyright (c) 2002, 2014, 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 
getUItoRegionMap()428     private static Map<String, Region> getUItoRegionMap() {
429         AppContext context = AppContext.getAppContext();
430         @SuppressWarnings("unchecked")
431         Map<String, Region> map = (Map<String, Region>) context.get(UI_TO_REGION_MAP_KEY);
432         if (map == null) {
433             map = new HashMap<String, Region>();
434             map.put("ArrowButtonUI", ARROW_BUTTON);
435             map.put("ButtonUI", BUTTON);
436             map.put("CheckBoxUI", CHECK_BOX);
437             map.put("CheckBoxMenuItemUI", CHECK_BOX_MENU_ITEM);
438             map.put("ColorChooserUI", COLOR_CHOOSER);
439             map.put("ComboBoxUI", COMBO_BOX);
440             map.put("DesktopPaneUI", DESKTOP_PANE);
441             map.put("DesktopIconUI", DESKTOP_ICON);
442             map.put("EditorPaneUI", EDITOR_PANE);
443             map.put("FileChooserUI", FILE_CHOOSER);
444             map.put("FormattedTextFieldUI", FORMATTED_TEXT_FIELD);
445             map.put("InternalFrameUI", INTERNAL_FRAME);
446             map.put("InternalFrameTitlePaneUI", INTERNAL_FRAME_TITLE_PANE);
447             map.put("LabelUI", LABEL);
448             map.put("ListUI", LIST);
449             map.put("MenuUI", MENU);
450             map.put("MenuBarUI", MENU_BAR);
451             map.put("MenuItemUI", MENU_ITEM);
452             map.put("OptionPaneUI", OPTION_PANE);
453             map.put("PanelUI", PANEL);
454             map.put("PasswordFieldUI", PASSWORD_FIELD);
455             map.put("PopupMenuUI", POPUP_MENU);
456             map.put("PopupMenuSeparatorUI", POPUP_MENU_SEPARATOR);
457             map.put("ProgressBarUI", PROGRESS_BAR);
458             map.put("RadioButtonUI", RADIO_BUTTON);
459             map.put("RadioButtonMenuItemUI", RADIO_BUTTON_MENU_ITEM);
460             map.put("RootPaneUI", ROOT_PANE);
461             map.put("ScrollBarUI", SCROLL_BAR);
462             map.put("ScrollPaneUI", SCROLL_PANE);
463             map.put("SeparatorUI", SEPARATOR);
464             map.put("SliderUI", SLIDER);
465             map.put("SpinnerUI", SPINNER);
466             map.put("SplitPaneUI", SPLIT_PANE);
467             map.put("TabbedPaneUI", TABBED_PANE);
468             map.put("TableUI", TABLE);
469             map.put("TableHeaderUI", TABLE_HEADER);
470             map.put("TextAreaUI", TEXT_AREA);
471             map.put("TextFieldUI", TEXT_FIELD);
472             map.put("TextPaneUI", TEXT_PANE);
473             map.put("ToggleButtonUI", TOGGLE_BUTTON);
474             map.put("ToolBarUI", TOOL_BAR);
475             map.put("ToolTipUI", TOOL_TIP);
476             map.put("ToolBarSeparatorUI", TOOL_BAR_SEPARATOR);
477             map.put("TreeUI", TREE);
478             map.put("ViewportUI", VIEWPORT);
479             context.put(UI_TO_REGION_MAP_KEY, map);
480         }
481         return map;
482     }
483 
getLowerCaseNameMap()484     private static Map<Region, String> getLowerCaseNameMap() {
485         AppContext context = AppContext.getAppContext();
486         @SuppressWarnings("unchecked")
487         Map<Region, String> map = (Map<Region, String>) context.get(LOWER_CASE_NAME_MAP_KEY);
488         if (map == null) {
489             map = new HashMap<Region, String>();
490             context.put(LOWER_CASE_NAME_MAP_KEY, map);
491         }
492         return map;
493     }
494 
getRegion(JComponent c)495     static Region getRegion(JComponent c) {
496         return getUItoRegionMap().get(c.getUIClassID());
497     }
498 
registerUIs(UIDefaults table)499     static void registerUIs(UIDefaults table) {
500         for (Object key : getUItoRegionMap().keySet()) {
501             table.put(key, "javax.swing.plaf.synth.SynthLookAndFeel");
502         }
503     }
504 
505     private final String name;
506     private final boolean subregion;
507 
Region(String name, boolean subregion)508     private Region(String name, boolean subregion) {
509         if (name == null) {
510             throw new NullPointerException("You must specify a non-null name");
511         }
512         this.name = name;
513         this.subregion = subregion;
514     }
515 
516     /**
517      * Creates a Region with the specified name. This should only be
518      * used if you are creating your own <code>JComponent</code> subclass
519      * with a custom <code>ComponentUI</code> class.
520      *
521      * @param name Name of the region
522      * @param ui String that will be returned from
523      *           <code>component.getUIClassID</code>. This will be null
524      *           if this is a subregion.
525      * @param subregion Whether or not this is a subregion.
526      */
Region(String name, String ui, boolean subregion)527     protected Region(String name, String ui, boolean subregion) {
528         this(name, subregion);
529         if (ui != null) {
530             getUItoRegionMap().put(ui, this);
531         }
532     }
533 
534     /**
535      * Returns true if the Region is a subregion of a Component, otherwise
536      * false. For example, <code>Region.BUTTON</code> corresponds do a
537      * <code>Component</code> so that <code>Region.BUTTON.isSubregion()</code>
538      * returns false.
539      *
540      * @return true if the Region is a subregion of a Component.
541      */
isSubregion()542     public boolean isSubregion() {
543         return subregion;
544     }
545 
546     /**
547      * Returns the name of the region.
548      *
549      * @return name of the Region.
550      */
getName()551     public String getName() {
552         return name;
553     }
554 
555     /**
556      * Returns the name, in lowercase.
557      *
558      * @return lower case representation of the name of the Region
559      */
getLowerCaseName()560     String getLowerCaseName() {
561         Map<Region, String> lowerCaseNameMap = getLowerCaseNameMap();
562         String lowerCaseName = lowerCaseNameMap.get(this);
563         if (lowerCaseName == null) {
564             lowerCaseName = name.toLowerCase(Locale.ENGLISH);
565             lowerCaseNameMap.put(this, lowerCaseName);
566         }
567         return lowerCaseName;
568     }
569 
570     /**
571      * Returns the name of the Region.
572      *
573      * @return name of the Region.
574      */
575     @Override
toString()576     public String toString() {
577         return name;
578     }
579 }
580