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         @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 
 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 
 495     static Region getRegion(JComponent c) {
 496         return getUItoRegionMap().get(c.getUIClassID());
 497     }
 498 
 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 
 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      */
 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      */
 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      */
 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      */
 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
 576     public String toString() {
 577         return name;
 578     }
 579 }