2
* Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
10
* o Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
14
* o Neither the name of Substance Kirill Grouchnikov nor the names of
15
* its contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
package org.pushingpixels.substance.api;
33
import java.awt.image.BufferedImage;
34
import java.beans.PropertyChangeEvent;
35
import java.beans.PropertyChangeListener;
36
import java.lang.reflect.InvocationTargetException;
40
import javax.swing.plaf.IconUIResource;
41
import javax.swing.plaf.UIResource;
42
import javax.swing.plaf.basic.BasicLookAndFeel;
44
import org.pushingpixels.lafplugin.*;
45
import org.pushingpixels.lafwidget.LafWidgetRepository;
46
import org.pushingpixels.lafwidget.animation.AnimationConfigurationManager;
47
import org.pushingpixels.lafwidget.animation.AnimationFacet;
48
import org.pushingpixels.lafwidget.utils.LookUtils;
49
import org.pushingpixels.substance.api.SubstanceConstants.MenuGutterFillKind;
50
import org.pushingpixels.substance.api.SubstanceConstants.SubstanceWidgetType;
51
import org.pushingpixels.substance.api.combo.ComboPopupPrototypeCallback;
52
import org.pushingpixels.substance.api.fonts.*;
53
import org.pushingpixels.substance.api.inputmaps.InputMapSet;
54
import org.pushingpixels.substance.api.inputmaps.SubstanceInputMapUtilities;
55
import org.pushingpixels.substance.api.shaper.*;
56
import org.pushingpixels.substance.api.skin.SkinChangeListener;
57
import org.pushingpixels.substance.api.skin.SkinInfo;
58
import org.pushingpixels.substance.api.tabbed.BaseTabCloseListener;
59
import org.pushingpixels.substance.api.tabbed.TabCloseCallback;
60
import org.pushingpixels.substance.internal.contrib.jgoodies.looks.common.ShadowPopupFactory;
61
import org.pushingpixels.substance.internal.fonts.FontPolicies;
62
import org.pushingpixels.substance.internal.painter.DecorationPainterUtils;
63
import org.pushingpixels.substance.internal.plugin.SubstanceSkinPlugin;
64
import org.pushingpixels.substance.internal.ui.SubstanceRootPaneUI;
65
import org.pushingpixels.substance.internal.utils.*;
69
* Main class for <b>Substance </b> look and feel. <b>All</b> static methods in
70
* this class should be called when Substance is the currently set look and feel
71
* unless explicitly stated otherwise.
75
* Since version 5.0 this class is abstract. There are three options to use
80
* <li>Use one of the core skin-based look-and-feels in the
81
* <code>org.pushingpixels.substance.skin</code> package.</li>
82
* <li>Extend this class and pass a skin instance to the
83
* {@link SubstanceLookAndFeel#SubstanceLookAndFeel(SubstanceSkin)} constructor.
85
* <li>Call {@link SubstanceLookAndFeel#setSkin(String)} or
86
* {@link SubstanceLookAndFeel#setSkin(SubstanceSkin)} static methods. These
87
* methods do not require Substance to be the current look-and-feel.</li>
90
* @author Kirill Grouchnikov
92
public abstract class SubstanceLookAndFeel extends BasicLookAndFeel {
94
* The name of plugin configuration XML resource name. This is used for the
95
* <a href="https://laf-plugin.dev.java.net">laf-plugin</a> support layer of
96
* third-party components.
98
public static final String PLUGIN_XML = "META-INF/substance-plugin.xml";
101
* Plugin manager for component plugins.
103
private static ComponentPluginManager componentPlugins;
106
* Plugin manager for skin plugins.
108
private static PluginManager skinPlugins;
111
* List of all listeners on skin changes.
113
protected final static Set<SkinChangeListener> skinChangeListeners = new HashSet<SkinChangeListener>();
116
* List of all listeners on changing locales.
118
protected final static Set<LocaleChangeListener> localeChangeListeners = new HashSet<LocaleChangeListener>();
121
* Indicates whether option dialogs (error, question, warning, info) should
122
* use constant color schemes for icon coloring. Note that since version
123
* 4.0, the default setting is <code>true</code> (use constant color
124
* scheme). To use color scheme-consistent coloring, call
125
* {@link #setToUseConstantThemesOnDialogs(boolean)} and pass
126
* <code>false</code>.
128
* @see #isToUseConstantThemesOnDialogs()
129
* @see #setToUseConstantThemesOnDialogs(boolean)
131
private static boolean toUseConstantThemesOnDialogs = true;
134
* Change listener on keyboard focus manager - fix for defect 208.
136
protected PropertyChangeListener focusOwnerChangeListener;
139
* The current keyboard focus manager - fix for defect 208.
141
protected KeyboardFocusManager currentKeyboardFocusManager;
144
* Smart tree scroll animation facet. Disabled by default, use
145
* {@link AnimationConfigurationManager#allowAnimations(AnimationFacet)} to
149
* Smart tree scroll is relevant for scroll panes containing a tree. When
150
* enabled, it automatically scrolls the tree horizontally when the viewport
151
* shows mainly empty area (especially relevant for multi-level trees with
157
public final static AnimationFacet TREE_SMART_SCROLL_ANIMATION_KIND = new AnimationFacet(
158
"substancelaf.treeSmartScrollAnimationKind", false);
161
* Client property name for requesting that watermark should be painted on
162
* the component and its descendants. This property can be set either as
163
* client property on some component or as global property on
164
* {@link UIManager}. The value should be either {@link Boolean#TRUE} or
165
* {@link Boolean#FALSE}.
168
* In order to compute whether the current watermark should be painted on a
169
* given component, its hierarchy is traversed bottom up. The first
170
* component that has this property set defines the watermark visibility. If
171
* neither component nor its ancestors define this property, the global
172
* setting on {@link UIManager} is checked. If there is no global setting,
173
* the watermark is <b>not</b> ignored (it is painted).
177
* There is special default setting for trees, tables, lists and text
178
* components. These show watermark only when this property is explicitly
179
* set to {@link Boolean#TRUE} on the component itself, one of its ancestors
180
* or the {@link UIManager}.
185
public static final String WATERMARK_VISIBLE = "substancelaf.watermark.visible";
188
* Client property name for ignoring the default (minimum) dimension for a
189
* single button. This property can be set either on the specific button or
190
* as a global setting on {@link UIManager}. The value should be either
191
* {@link Boolean#TRUE} or {@link Boolean#FALSE}.
193
* Note that {@link SubstanceButtonShaper} implementations are not required
194
* to respect this property. The current implementations of the default
195
* {@link StandardButtonShaper} and {@link ClassicButtonShaper} respect this
200
* Example of marking a button to ignore minimum dimension settings:
203
* JButton button = new JButton("text");<br>
204
* button.putClientProperty(SubstanceLookAndFeel.BUTTON_NO_MIN_SIZE_PROPERTY, <br>
205
* Boolean.TRUE);
208
* Example of marking all application buttons to ignore minimum dimension
212
* UIManager.put(SubstanceLookAndFeel.BUTTON_NO_MIN_SIZE_PROPERTY, <br>
213
* Boolean.TRUE);
218
public static final String BUTTON_NO_MIN_SIZE_PROPERTY = "substancelaf.buttonnominsize";
221
* Client property name for specifying that a single button / all
222
* application buttons should not paint the background. This property can be
223
* set on the specific button, its parent or as a global setting on
224
* {@link UIManager}. The value should be either {@link Boolean#TRUE} or
225
* {@link Boolean#FALSE}. Note that unlike the {@link #FLAT_PROPERTY}, a
226
* button marked with this property will <b>never</b> show the background
227
* (will always be painted flat).
230
* Example of marking a button to never paint background:
233
* JButton button = new JButton("text");<br>
234
* button.putClientProperty(SubstanceLookAndFeel.BUTTON_PAINT_NEVER_PROPERTY, <br>
235
* Boolean.TRUE);
239
* Example of marking all application buttons to never paint background:
242
* UIManager.put(SubstanceLookAndFeel.BUTTON_PAINT_NEVER_PROPERTY, <br>
243
* Boolean.TRUE);
247
* @see #FLAT_PROPERTY
249
public static final String BUTTON_PAINT_NEVER_PROPERTY = "substancelaf.buttonpaintnever";
252
* Client property name for specifying a straight side for a single button.
253
* This property must be set on the specific button. The value can be:
257
* <li>A value in {@link SubstanceConstants.Side} enum.
258
* <li>Set of values in {@link SubstanceConstants.Side} enum.
262
* Note that the {@link SubstanceButtonShaper} implementations are not
263
* required to respect this property. The default
264
* {@link StandardButtonShaper} and {@link ClassicButtonShaper} respect this
269
* Example of marking a button to have straight north side:
272
* JButton button = new JButton("text");<br>
273
* button.putClientProperty(SubstanceLookAndFeel.BUTTON_SIDE_PROPERTY,<br>
274
* SubstanceConstants.Side.RIGHT);
278
* @see #BUTTON_OPEN_SIDE_PROPERTY
280
public static final String BUTTON_SIDE_PROPERTY = "substancelaf.buttonside";
283
* Client property name for specifying an open side for a single button.
284
* This property must be set on the specific button. The value can be:
288
* <li>A value in {@link SubstanceConstants.Side} enum.
289
* <li>Set of values in {@link SubstanceConstants.Side} enum.
293
* Example of marking a button to have open top and west sides:
296
* JButton button = new JButton("text");<br>
297
* Set<Side> openSides = EnumSet.of(Side.TOP, Side.WEST);<br>
298
* button.putClientProperty(SubstanceLookAndFeel.BUTTON_OPEN_SIDE_PROPERTY, <br>
299
* openSides);
303
* @see #BUTTON_SIDE_PROPERTY
305
public static final String BUTTON_OPEN_SIDE_PROPERTY = "substancelaf.buttonopenSide";
308
* Client property name for specifying the corner radius for buttons.
309
* Currently, this property is respected only on toolbar buttons. This
310
* property can be set on the specific toolbar button, on the specific
311
* toolbar (will hold for all buttons in the toolbar) or as a global setting
312
* on {@link UIManager}. The value should be a positive {@link Float}.
315
* Example of specifying a (toolbar) button to have corner radius of 5
319
* JButton button = new JButton("text");<br>
320
* button.putClientProperty(SubstanceLookAndFeel.CORNER_RADIUS, <br>
321
* Float.valueOf(5.0f));
325
* Example of specifying all buttons of a toolbar to have corner radius of 3
329
* JToolBar toolbar = new JToolBar("toolbar");<br>
330
* toolbar.putClientProperty(SubstanceLookAndFeel.CORNER_RADIUS, <br>
331
* Float.valueOf(3.0f));
335
* Example of specifying all toolbar buttons to have corner radius of 0
339
* UIManager.put(SubstanceLookAndFeel.CORNER_RADIUS, Float.valueOf(0.0f));
344
public static final String CORNER_RADIUS = "substancelaf.cornerRadius";
347
* Property name for specifying that the component should be painted flat
348
* (no background / border) when it's inactive. This property should be
349
* specified on a specific component or its parent and must have either
350
* {@link Boolean#TRUE} or {@link Boolean#FALSE} value.
353
* Example how to mark a button to appear flat:
357
* JButton button = new JButton("text");<br>
358
* button.putClientProperty(SubstanceLookAndFeel.FLAT_PROPERTY, <br>
359
* Boolean.TRUE);
363
* @see #BUTTON_PAINT_NEVER_PROPERTY
365
public static final String FLAT_PROPERTY = "substancelaf.componentFlat";
368
* VM property name for specifying the heap status trace file. The trace
369
* file will contain information on the status of heap. The property value
370
* is used as a filename for tracing the heap status. Example for specifying
371
* the trace file name:
375
* -Dsubstancelaf.heapStatusTraceFile=C:/temp/myApp.heap.log
381
public static final String HEAP_STATUS_TRACE_FILE = "substancelaf.heapStatusTraceFile";
384
* Client property name for specifying that contents of a frame, dialog,
385
* internal frame, desktop icon or tab have been modified and not saved. The
386
* property can be set on:
389
* <li>{@link JRootPane} - the <b>close</b> button of the title pane of the
390
* matching frame / dialog will be animated (in case that the frame / dialog
391
* have decorated title pane). In case the root pane belongs to a
392
* {@link JInternalFrame} and that frame is iconified (to a
393
* {@link javax.swing.JInternalFrame.JDesktopIcon}), the close button of the its desktop
394
* icon is animated as well.</li>
395
* <li>{@link JComponent} in a {@link JTabbedPane}. Based on the
396
* {@link #TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION} property presence,
397
* either the entire tab or its close button area is animated. In this case,
398
* this property must be set on the tab component itself, <b>not</b> on one
399
* of its child components.</li>
403
* The animation cycles between red, orange and yellow color schemes. In
404
* most cases (all but tabs not marked with
405
* {@link #TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION} property), the
406
* animation will be visible only when the mouse hovers over the close
407
* button of the matching container (frame, dialog, internal frame, desktop
408
* icon, tab). The tooltip of the close button is changed as well to reflect
409
* that the container contents are marked as modified.
413
* Here is a sample text editing application that illustrates the use of
414
* this property. Once the contents of the text pane are changed, the frame
415
* is marked as modified. The <b>Save</b> button marks the frame as
416
* not-modified. In the real application, the listener on this button will
417
* need to persist the changes as well.
421
* public class Changer extends JFrame {<br>
422
* public Changer() {<br>
423
* super("Changer");<br>
425
* this.setLayout(new BorderLayout());<br>
426
* JTextPane textArea = new JTextPane();<br>
427
* this.add(textArea, BorderLayout.CENTER);<br>
428
* textArea.getDocument().addDocumentListener(new
429
* DocumentListener() {<br>
430
* private void handleChange() {<br>
431
* getRootPane().putClientProperty(<br>
432
* SubstanceLookAndFeel.WINDOW_MODIFIED,
434
* }<br>
436
* public void
437
* changedUpdate(DocumentEvent e) {<br>
438
* handleChange();<br>
439
* }<br>
441
* public void
442
* insertUpdate(DocumentEvent e) {<br>
443
* handleChange();<br>
444
* }<br>
446
* public void
447
* removeUpdate(DocumentEvent e) {<br>
448
* handleChange();<br>
449
* }<br>
450
* });<br>
451
* <br>
452
* JPanel buttons = new JPanel(new
453
* FlowLayout(FlowLayout.RIGHT));<br>
454
* JButton saveButton = new JButton("Save");<br>
455
* saveButton.addActionListener(new ActionListener() {<br>
456
* public void
457
* actionPerformed(ActionEvent e) {<br>
458
* getRootPane().putClientProperty(<br>
459
* SubstanceLookAndFeel.WINDOW_MODIFIED,
460
* Boolean.FALSE);<br>
461
* }<br>
462
* });<br>
463
* <br>
464
* buttons.add(saveButton);<br>
465
* this.add(buttons, BorderLayout.SOUTH);<br>
466
* <br>
467
* this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br>
470
* public static void main(String ... args) {<br>
471
* try {<br>
472
* UIManager.setLookAndFeel(new
473
* SubstanceLookAndFeel());<br>
474
* }<br>
475
* catch (Exception exc) {}<br>
476
* JFrame.setDefaultLookAndFeelDecorated(true);<br>
477
* Changer ch = new Changer();<br>
478
* ch.setPreferredSize(new Dimension(200, 200));<br>
479
* ch.setSize(ch.getPreferredSize());<br>
480
* ch.setLocationRelativeTo(null);<br>
481
* ch.setVisible(true);<br>
482
* }<br> }
487
public final static String WINDOW_MODIFIED = "windowModified";
490
* <p>UIManager property name for specifying that whether any JRootPane with
491
* Substance window decorations should be attentive to the active or selected
492
* state of the respective JFrame or JInternalFrame. This property can only be
493
* specified in the {@link UIManager} for this release. The value should be
494
* either {@link Boolean#TRUE} or {@link Boolean#FALSE}. The initial value
495
* depends on the specific skin chosen and will be false if not specified.
498
* <p>When active this property will cause the title pane and borders of
499
* JFrames and JInternal frames to toggle between {DecorationAreaType#PRIMARY_TITLE_PANE}
500
* / {DecorationAreaType#PRIMARY_TITLE_PANE_INACTIVE} or {DecorationAreaType#SECONDARY_TITLE_PANE}
501
* / {DecorationAreaType#SECONDARY_TITLE_PANE_INACTIVE} respectively when the
502
* respective containers active or selected property changes. If the Title pane of the
503
* window decoration is change to any other DecorationAreaType, then the type will not
507
* UIManager.put(SubstanceLookAndFeel.WINDOW_AUTO_DEACTIVATE, <br>
508
* Boolean.TRUE);<br>
513
public final static String WINDOW_AUTO_DEACTIVATE = "windowAutoDeactivate";
516
* <p>VM property name for specifying that whether any JRootPane with
517
* Substance window decorations should be drawn with rounded corners in it's
518
* decoration frame. This property is specified globally in via a system property.
519
* The value will be parsed by {Boolean.valueOf}, unless it is unset or an empty
520
* string, then it will default to true. A true value only enables rounded windows,
521
* they can be turned off via the UIManager or client properties. A false value
522
* disables <i>all</i> rounded corners and is used to remove artifacts from legacy
523
* video cards. This value is read when the Substance look and feel is initialized,
524
* and is not consulted later.
527
* <p>When unset or set to true this property will cause the title pane and borders of
528
* JFrames and JInternal frames to be rounded.
532
* -Dsubstancelaf.windowRoundedCorners=False
538
public final static String WINDOW_ROUNDED_CORNERS_PROPERTY = "substancelaf.windowRoundedCorners";
541
* <p>Client property name for specifying that whether any JRootPane with
542
* Substance window decorations should be drawn with rounded corners in it's
543
* decoration frame. This property can be specified per-window or globally in
544
* the UIManager or via client properties. The value should be
545
* either {@link Boolean#TRUE} or {@link Boolean#FALSE}. This value is subject
546
* to being globally set to false if the system property is set to false. When unset
547
* it defauls to true.
550
* <p>When unset or set to true this property will cause the title pane and borders of
551
* JFrames and JInternal frames to be rounded.
554
* UIManager.put(SubstanceLookAndFeel.WINDOW_ROUNDED_CORNERS, <br>
555
* Boolean.FALSE);<br>
557
* someFrameOrDialog.putClientProperty(SubstanceLookAndFeel.WINDOW_ROUNDED_CORNERS, <br>
558
* Boolean.FALSE);<br>
559
* // for specific JInternalFrames, JFrames, or JDialogs
565
public final static String WINDOW_ROUNDED_CORNERS = "windowRoundedCorners";
568
* Client property name for adding close buttons on tabs. This property can
569
* be specified on a single tab component, on a {@link JTabbedPane} itself
570
* (will hold for all tab components that don't define this property) or on
571
* {@link UIManager}. The value should be either {@link Boolean#TRUE} or
572
* {@link Boolean#FALSE}. By default, the close buttons are not displayed.
575
* Example of setting that all tabs in the application will have close
579
* UIManager.put(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_PROPERTY, <br>
580
* Boolean.TRUE);
584
* A more complex example:
587
* UIManager.put(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_PROPERTY, <br>
588
* Boolean.TRUE);<br>
589
* JTabbedPane jtpMain = new JTabbedPane();<br>
590
* JTabbedPane jtpSecondary = new JTabbedPane();<br>
591
* jtpSecondary.putClientProperty(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_PROPERTY, <br>
592
* Boolean.FALSE);<br>
593
* JPanel panelSecondary = new JPanel();<br>
594
* jtpMain.addTab(jtpSecondary);<br>
595
* jtpMain.addTab(panelSecondary);<br>
596
* JPanel tab1 = new JPanel();<br>
597
* JPanel tab2 = new JPanel();<br>
598
* tab2.putClientProperty(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_PROPERTY, <br>
599
* Boolean.TRUE);<br>
600
* jtpSecondary.addTab(tab1);<br>
601
* jtpSecondary.addTab(tab2);
605
* In the example above, the first first-level child (<b>jtpSecondary</b>)
606
* doesn't have the close button (since it overrides the global setting).
607
* The second first-level child tab (<b>panelSecondary</b>) has close button
608
* (from the global <b>UIManager</b> setting). The first second-level tab
609
* doesn't have the close button (setting inherited from the parent
610
* <b>jtpSecondary</b> tab that overrides the global setting). The second
611
* second-level tab has the close button (since its setting overrides the
616
* @see #TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION
617
* @see #TABBED_PANE_CLOSE_CALLBACK
619
public final static String TABBED_PANE_CLOSE_BUTTONS_PROPERTY = "substancelaf.tabbedpanehasclosebuttons";
622
* Client property name for specifying that only the close button of a
623
* marked-as-modified tab component should pulsate. This property can be
624
* specified on a single tab component, on a {@link JTabbedPane} itself
625
* (will hold for all tab components that don't define this property) or on
626
* {@link UIManager}. The value should be either {@link Boolean#TRUE} or
627
* {@link Boolean#FALSE}. By default, the animation on modified tabs is on
628
* the entire tab rectangle. Note that this setting is only relevant for
629
* tabs marked with {@link #WINDOW_MODIFIED} property.
632
* Example of setting that all tabs in the application will have modified
633
* animation on close button:
636
* UIManager.put(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION, <br>
637
* Boolean.TRUE);
641
* A more complex example:
644
* UIManager.put(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION, <br>
645
* Boolean.TRUE);<br>
646
* JTabbedPane jtpMain = new JTabbedPane();<br>
647
* JTabbedPane jtpSecondary = new JTabbedPane();<br>
648
* jtpSecondary.putClientProperty(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION, <br>
649
* Boolean.FALSE);<br>
650
* JPanel panelSecondary = new JPanel();<br>
651
* jtpMain.addTab(jtpSecondary);<br>
652
* jtpMain.addTab(panelSecondary);<br>
653
* JPanel tab1 = new JPanel();<br>
654
* JPanel tab2 = new JPanel();<br>
655
* tab2.putClientProperty(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION, <br>
656
* Boolean.TRUE);<br>
657
* jtpSecondary.addTab(tab1);<br>
658
* jtpSecondary.addTab(tab2);
662
* In the example above, the first first-level child (<b>jtpSecondary</b>)
663
* has the animation on the entire tab (since it overrides the global
664
* setting). The second first-level child tab (<b>panelSecondary</b>) has
665
* animation on the close button (from the global <b>UIManager</b> setting).
666
* The first second-level tab has the animation on the entire tab (setting
667
* inherited from the parent <b>jtpSecondary</b> tab that overrides the
668
* global setting). The second second-level tab has animation on the close
669
* button (since its setting overrides the parent setting).
673
* @see #TABBED_PANE_CLOSE_BUTTONS_PROPERTY
674
* @see #TABBED_PANE_CLOSE_CALLBACK
676
public final static String TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION = "substancelaf.tabbedpaneclosebuttonsmodifiedanimation";
679
* Client property name for specifying the callback for deciding on the tab
680
* close type. This property can be specified on a single tab component, on
681
* a {@link JTabbedPane} itself (will hold for all tab components that don't
682
* define this property) or on {@link UIManager}. The value should be an
683
* instance of {@link TabCloseCallback}. Note that this setting is only
684
* relevant for tabs marked with {@link #TABBED_PANE_CLOSE_BUTTONS_PROPERTY}
688
* Example of custom tab close callback set on a tabbed pane:
691
* TabCloseCallback closeCallback = new TabCloseCallback() {<br>
692
* public TabCloseKind onAreaClick(JTabbedPane tabbedPane,<br>
693
* int tabIndex, MouseEvent mouseEvent) {<br>
694
* if (mouseEvent.getButton() != MouseEvent.BUTTON3)<br>
695
* return TabCloseKind.NONE;<br>
696
* if (mouseEvent.isShiftDown()) {<br>
697
* return TabCloseKind.ALL;<br>
698
* }<br>
699
* return TabCloseKind.THIS;<br>
702
* public TabCloseKind onCloseButtonClick(JTabbedPane tabbedPane,<br>
703
* int tabIndex, MouseEvent mouseEvent) {<br>
704
* if (mouseEvent.isAltDown()) {<br>
705
* return TabCloseKind.ALL_BUT_THIS;<br>
706
* }<br>
707
* if (mouseEvent.isShiftDown()) {<br>
708
* return TabCloseKind.ALL;<br>
709
* }<br>
710
* return TabCloseKind.THIS;<br>
713
* public String getAreaTooltip(JTabbedPane tabbedPane, int tabIndex) {<br>
714
* return null;<br>
717
* public String getCloseButtonTooltip(JTabbedPane tabbedPane,<br>
718
* int tabIndex) {<br>
719
* StringBuffer result = new StringBuffer();<br>
720
* result.append("<html><body>");<br>
721
* result.append("Mouse click closes <b>"<br>
722
* + tabbedPane.getTitleAt(tabIndex) + "</b> tab");<br>
723
* result.append("<br><b>Alt</b>-Mouse click closes all tabs but <b>"<br>
724
* + tabbedPane.getTitleAt(tabIndex) + "</b> tab");<br>
725
* result.append("<br><b>Shift</b>-Mouse click closes all tabs");<br>
726
* result.append("</body></html>");<br>
727
* return result.toString();<br>
731
* JTabbedPane jtp = new JTabbedPane();<br>
732
* jtp.putClientProperty(<br>
733
* SubstanceLookAndFeel.TABBED_PANE_CLOSE_CALLBACK, <br>
734
* closeCallback);
739
public final static String TABBED_PANE_CLOSE_CALLBACK = "substancelaf.tabbedpanecloseCallback";
742
* Client property name for specifying the content pane border kind. This
743
* property can be specified either on a single {@link JTabbedPane} or on
744
* {@link UIManager}. The value should be one of
745
* {@link SubstanceConstants.TabContentPaneBorderKind} enum. By default, the
747
* {@link SubstanceConstants.TabContentPaneBorderKind#DOUBLE_FULL}.
750
* Example of setting that all tabbed panes in the application have single
751
* full border (default setting prior to version 4.1):
754
* UIManager.put(SubstanceLookAndFeel.TABBED_PANE_CONTENT_BORDER_KIND, <br>
755
* TabContentPaneBorderKind.SINGLE_FULL);
759
* Example of specifying that the specific tabbed pane has single full
760
* border (default setting prior to version 4.1):
763
* JTabbedPane jtpMain = new JTabbedPane();<br>
764
* jtpMain.putClientProperty(SubstanceLookAndFeel.TABBED_PANE_CONTENT_BORDER_KIND, <br>
765
* TabContentPaneBorderKind.SINGLE_FULL);
770
public final static String TABBED_PANE_CONTENT_BORDER_KIND = "substancelaf.tabbedPaneContentBorderKind";
774
* Client property name for specifying wheter tabs shown on the left or right
775
* will be rotated vertically. This property can be specified either on a
776
* single {@link JTabbedPane} or on * {@link UIManager}. The value should a
777
* Boolean. By default, the rotation is enabled.
780
* Example of setting that all tabbed panes should not rotate the tabs:
783
* UIManager.put(SubstanceLookAndFeel.TABBED_PANE_ROTATE_SIDE_TABS, <br>
784
* Boolean.FALSE);
788
* Example of specifying that the specific tabbed pane tabbed panes should not rotate the tabs:
791
* JTabbedPane jtpMain = new JTabbedPane();<br>
792
* jtpMain.putClientProperty(SubstanceLookAndFeel.TABBED_PANE_ROTATE_SIDE_TABS, <br>
793
* Boolean.FALSE);
798
public final static String TABBED_PANE_ROTATE_SIDE_TABS = "substancelaf.rotate";
801
* Client property name for specifying the leading vertical line on a table.
802
* Normally the presence of the leading vertical line on a table is driven
803
* by the presence or absence of a row header.
807
* <li>The default <code>null</code> - The line is driven by the presence of row headers
808
* <li><code>true</code> - The line is always drawn.
809
* <li><code>false</code> - The line is never drawn.
814
* JTable jtable = new JTable();<br>
815
* jtable.putClientProperty(SubstanceLookAndFeel.TABLE_LEADING_VERTICAL_LINE, <br>
816
* false);
821
public final static String TABLE_LEADING_VERTICAL_LINE = "substancelaf.tableLeadingVerticalLine";
824
* Client property name for specifying the trailing verticle line on a table.
825
* Normally the presence of the leading vertical line on a table is driven
826
* by the width of the table and the width of the children
830
* <li>The default <code>null</code> - The line is driven by whether it fits within the view of the scroll pane (true) or not (false)
831
* <li><code>true</code> - The line is always drawn.
832
* <li><code>false</code> - The line is never drawn.
837
* JTable jtable = new JTable();<br>
838
* jtable.putClientProperty(SubstanceLookAndFeel.TABLE_TRAILING_VERTICAL_LINE, <br>
839
* false);
844
public final static String TABLE_TRAILING_VERTICAL_LINE = "substancelaf.tableTrailingVerticalLine";
847
* Client property name for specifying combo popup flyout orientation. This
848
* property can be set on either a specific {@link JComboBox} or globally on
849
* {@link UIManager}. The value should be one of the {@link Integer}s below:
853
* <li>The default {@link SwingConstants#SOUTH} - the popup is displayed
854
* directly below the combo aligned to the left.
855
* <li>{@link SwingConstants#NORTH} - the popup is displayed directly above
856
* the combo aligned to the left.
857
* <li>{@link SwingConstants#EAST} - the popup is displayed to the left of
858
* the combo aligned to the top.
859
* <li>{@link SwingConstants#WEST} - the popup is displayed to the right of
860
* the combo aligned to the top.
861
* <li>{@link SwingConstants#CENTER} - the popup is displayed centered
862
* vertically over the combo aligned to the left.
867
* Note that the combo arrow changes in accordance with the combo popup
868
* flyout orientation. Example of setting a combobox with a custom flyout
872
* JComboBox cb = new JComboBox(<br>
873
* new Object[] { "Ester", "Jordi", "Jordina", "Jorge", "Sergi" });<br>
874
* cb.putClientProperty(SubstanceLookAndFeel.COMBO_BOX_POPUP_FLYOUT_ORIENTATION, <br>
875
* SwingConstants.CENTER);
879
* @see #COMBO_POPUP_PROTOTYPE
881
public final static String COMBO_BOX_POPUP_FLYOUT_ORIENTATION = "substancelaf.comboboxpopupFlyoutOrientation";
884
* Client property name for specifying scroll pane button policy. This
885
* property can be set on either a specific {@link JScrollPane} or globally
886
* on {@link UIManager}. The value should be one of the
887
* {@link SubstanceConstants.ScrollPaneButtonPolicyKind} enum. Example of
888
* setting a scroll pane with a custom button policy:
892
* JScrollPane jsp = new JScrollPane(new JPanel());<br>
893
* jsp.putClientProperty(SubstanceLookAndFeel.SCROLL_PANE_BUTTONS_POLICY,<br>
894
* ScrollPaneButtonPolicyKind.MULTIPLE);
899
public final static String SCROLL_PANE_BUTTONS_POLICY = "substancelaf.scrollPaneButtonsPolicy";
902
* Property name for specifying that extra UI elements (such as menu items
903
* in system menu or lock borders) should be shown. This property can be set
904
* as a global setting on {@link UIManager} or as a client property on a
905
* specific component. The value should be either {@link Boolean#TRUE} or
906
* {@link Boolean#FALSE}.
909
* Example of setting this property on {@link UIManager}:
912
* UIManager.put(SubstanceLookAndFeel.SHOW_EXTRA_WIDGETS, Boolean.TRUE);
913
* SwingUtilities.updateComponentTree(myFrame);
918
public final static String SHOW_EXTRA_WIDGETS = "substancelaf.addWidgets";
921
* Property name for specifying menu gutter fill kind. Menu gutter is the
922
* part of the menu where checkmarks and icons are painted. The value should
923
* be one of {@link MenuGutterFillKind} enum. This property can be set
924
* globally on the {@link UIManager}. The default value is
925
* {@link MenuGutterFillKind#HARD}.
928
* Example of setting soft fill kind:
931
* UIManager.put(SubstanceLookAndFeel.MENU_GUTTER_FILL_KIND, MenuGutterFillKind.SOFT);
936
public final static String MENU_GUTTER_FILL_KIND = "substancelaf.menuGutterFillKind";
939
* Client property name for specifying the kind of focus indication on
940
* buttons, check boxes and radio buttons. The value should be one of
941
* {@link SubstanceConstants.FocusKind} enum. This property can be set
942
* either on the specific component or as global property on
946
* In order to compute the kind of focus indication for some component, the
947
* component's hierarchy is traversed bottom up. The first component that
948
* has this property set, defines the focus indication kind. If neither
949
* component nor its ancestors define this property, the global setting on
950
* {@link UIManager} is checked. If there is no global setting, the default
951
* {@link SubstanceConstants.FocusKind#ALL_INNER} is used. Here is an
952
* example to illustrate the above:
956
* JPanel topPanel = new JPanel();<br>
957
* topPanel.putClientProperty(SubstanceLookAndFeel.FOCUS_KIND, FocusKind.UNDERLINE);<br>
958
* JPanel panel1 = new JPanel();<br>
959
* JButton b1 = new JButton("button1");<br>
960
* b1.putClientProperty(SubstanceLookAndFeel.FOCUS_KIND, FocusKind.TEXT);<br>
961
* JButton b2 = new JButton("button2");<br>
962
* JButton b3 = new JButton("button3");<br>
963
* b3.putClientProperty(SubstanceLookAndFeel.FOCUS_KIND, FocusKind.ALL_INNER);<br>
964
* panel1.add(b1);<br>
965
* panel1.add(b2);<br>
966
* topPanel.add(panel1);<br>
967
* topPanel.add(b3);<br>
974
* <li>Button <b>b1</b> will have {@link SubstanceConstants.FocusKind#NONE}
975
* focus kind which is set directly on the button.
976
* <li>Button <b>b2</b> will have
977
* {@link SubstanceConstants.FocusKind#UNDERLINE} focus kind which is
978
* inherited from its <b>topPanel</b> parent.
979
* <li>Button <b>b3</b> will have
980
* {@link SubstanceConstants.FocusKind#ALL_INNER} focus kind which is set
981
* directly on the button.
985
* @see SubstanceConstants.FocusKind
987
public final static String FOCUS_KIND = "substancelaf.focusKind";
990
* Property name for specifying the combobox popup prototype display value
991
* which is used to compute the width of the popup at runtime. The property
992
* value should be one of:
996
* <li>{@link ComboPopupPrototypeCallback} - will provide
997
* application-specific logic at runtime.
998
* <li>{@link Object} - will point to the prototype entry itself.
1003
* This property can be set either on a specific {@link JComboBox} or
1004
* globally on {@link UIManager}.
1008
* Here is an example of combo popup prototype set to a model element:
1011
* JComboBox comboProto1 = new JComboBox(new Object[] { "aa", "aaaaa",<br>
1012
* "aaaaaaaaaa", "this one is the one", "aaaaaaaaaaaaaaaaaaaaa" });<br>
1013
* comboProto1.setPrototypeDisplayValue("aaaaa");<br>
1014
* comboProto1.putClientProperty(SubstanceLookAndFeel.COMBO_POPUP_PROTOTYPE,<br>
1015
* "this one is the one");
1019
* Here is an example of combo popup prototype set to a dynamic callback.
1020
* This callback always returns the last model element:
1023
* JComboBox comboProto3 = new JComboBox(new Object[] { "aa", "aaaaa",<br>
1024
* "this is not", "this one is not it",<br>
1025
* "this one is it that is for the popup" });<br>
1026
* comboProto3.setPrototypeDisplayValue("aaaaa");<br>
1027
* comboProto3.putClientProperty(SubstanceLookAndFeel.COMBO_POPUP_PROTOTYPE,<br>
1028
* new ComboPopupPrototypeCallback() {<br>
1029
* public Object getPopupPrototypeDisplayValue(JComboBox jc) {<br>
1030
* return jc.getModel().getElementAt(<br>
1031
* jc.getModel().getSize() - 1);<br>
1032
* }<br>
1036
* @since version 3.0
1037
* @see #COMBO_BOX_POPUP_FLYOUT_ORIENTATION
1039
public final static String COMBO_POPUP_PROTOTYPE = "substancelaf.comboPopupPrototype";
1042
* VM property name for specifying the trace file. The trace file will
1043
* contain output of the memory analyser which can be used to pinpoint the
1044
* memory leaks. The property value is used as a filename for tracing the
1045
* memory allocations. Example for specifying the trace file name:
1049
* -Dsubstancelaf.traceFile=C:/temp/myApp.substance.log
1053
* @since version 2.0
1055
public final static String TRACE_FILE = "substancelaf.traceFile";
1058
* Client property name for specifying the number of echo characters for
1059
* each password character. The value should be an instance of
1060
* {@link Integer}, otherwise will be ignored. This property can be set
1061
* either on a specific {@link JPasswordField} or globally on
1062
* {@link UIManager}.
1065
* Example of having all password fields echo 3 characters per each typed
1069
* UIManager.put(SubstanceLookAndFeel.PASSWORD_ECHO_PER_CHAR, <br>
1070
* new Integer(3));
1074
* Example of having a specific password field echo 2 characters per each
1075
* typed user character:
1078
* JPasswordField jpf = new JPasswordField();<br>
1079
* jpf.putClientProperty(SubstanceLookAndFeel.PASSWORD_ECHO_PER_CHAR, <br>
1080
* new Integer(2));
1083
* @since version 2.2
1085
public final static String PASSWORD_ECHO_PER_CHAR = "substancelaf.passwordEchoPerChar";
1089
* Client property name for specifying that icons on controls such as
1090
* buttons, toggle buttons, labels, tabs and menu items should match the
1091
* color of the current color scheme when they are in default state. The
1092
* control is in default state when it's not pressed, not selected, not
1093
* armed and not rolled over. The value should be an instance of
1094
* {@link Boolean}. By default, all controls show regular (full-color
1095
* original) icons. The value can be set globally on {@link UIManager}.
1098
* @since version 3.3
1100
public final static String USE_THEMED_DEFAULT_ICONS = "substancelaf.useThemedDefaultIcons";
1104
* Client property name for specifying the colorization amount applied to
1105
* the background and foreground of the current color scheme and the
1106
* specific control. By default, when the application does not use any
1107
* custom colors, all the controls are painted with the colors of the
1108
* current color scheme / skin. The colors coming from the look-and-feel
1109
* implement the marker {@link UIResource} interface which allows the UI
1110
* delegates to differentiate between application-specific colors which are
1111
* not changed, and the LAF-provide colors that are changed on LAF switch.
1115
* This new client property installs the "smart colorization" mode which
1116
* uses the colors of the current color scheme and the custom background /
1117
* foreground colors (when installed by application) to colorize the
1118
* relevant portions of the control. For example, on checkbox the custom
1119
* background color will be used to colorize the check box itself, while the
1120
* custom foreground color will be applied to the check box text and the
1125
* The value of this property specifies the actual colorization amount.
1126
* Value of 0.0 results in Substance completely <strong>ignoring</strong>
1127
* the custom application background and foreground colors set on the
1128
* components - no colorization. Values closer to 1.0 result in almost full
1129
* usage of the custom application background and foreground colors set on
1130
* the components. Note that in order to maintain the gradients (fill,
1131
* border, etc), even value of 1.0 does not result in full custom color
1132
* being applied to the relevant visuals of the control.
1136
* This property can be specified globally on {@link UIManager}, applying on
1137
* all controls, or on the specific component / container. In the later
1138
* case, the value will be applied to the component / container itself and
1139
* all its children that do not specify a custom value for this property.
1143
* The default colorization amount (when this property is not set at all) is
1144
* 0.5. This means that applications that install custom background /
1145
* foreground colors on their UI controls will see them colorized with 50%
1146
* "strength", even without setting this property.
1150
* The value should be an instance of {@link Double} in 0.0-1.0 range.
1154
* Example of marking a button to have a custom background color and
1155
* colorizing it with 40%:
1158
* JButton jb = new JButton("sample", myIcon);<br>
1159
* jb.setBackground(Color.red);<br>
1160
* jb.putClientProperty(SubstanceLookAndFeel.COLORIZATION_FACTOR, <br>
1161
* new Double(0.4));
1165
* Note that components in decoration areas registered on the current skin
1166
* will ignore the colorization on custom background color. The background
1167
* of such components is always painted by the skin's decoration painter to
1168
* ensure consistent background painting of the relevant decoration area.
1171
* @since version 4.2
1172
* @see Component#setBackground(Color)
1173
* @see Component#setForeground(Color)
1175
public final static String COLORIZATION_FACTOR = "substancelaf.colorizationFactor";
1178
* Internal client property name for storing application-specific font
1181
* @since version 3.3
1182
* @see #setFontPolicy(FontPolicy)
1183
* @see #getFontPolicy()
1185
protected final static String SUBSTANCE_FONT_POLICY_KEY = "substancelaf.fontPolicyKey";
1188
* Internal client property name for storing application-specific input map
1191
* @since version 6.1
1192
* @see #setInputMapSet(InputMapSet)
1193
* @see #getInputMapSet()
1195
protected final static String SUBSTANCE_INPUT_MAP_SET_KEY = "substancelaf.inputMapSetKey";
1198
* Property name for specifying outline shaper. This property is used a
1199
* client property that can be set on a specific control.
1202
* The value must be a {@link SubstanceButtonShaper} object.
1206
* Example of using a {@link SubstanceButtonShaper} object as client
1210
* JButton b = new JButton("text");<br>
1211
* b.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, <br>
1212
* new ClassicButtonShaper());
1215
* @since version 2.1
1217
public static final String BUTTON_SHAPER_PROPERTY = "substancelaf.buttonShaper";
1220
* Property name for specifying a skin to be used on the specific root pane.
1221
* This property can only be installed on a {@link JRootPane} and will
1222
* affect all the controls in that root pane. The value must be an instance
1223
* of {@link SubstanceSkin}. After setting this property, call
1224
* {@link SwingUtilities#updateComponentTreeUI(Component)} on the matching
1227
* @since version 5.0
1228
* @see #getCurrentSkin(Component)
1230
public static final String SKIN_PROPERTY = "substancelaf.skin";
1233
* Resource bundle for <b>Substance</b> labels.
1235
private static ResourceBundle LABEL_BUNDLE = null;
1238
* Class loader for {@link #LABEL_BUNDLE}.
1240
private static ClassLoader labelBundleClassLoader;
1243
* The skin of this look-and-feel instance.
1245
protected SubstanceSkin skin;
1248
* The name of this look-and-feel instance.
1250
protected String name;
1253
* Creates a new skin-based Substance look-and-feel. This is the only way to
1254
* create an instance of {@link SubstanceLookAndFeel} class.
1259
protected SubstanceLookAndFeel(SubstanceSkin skin) {
1261
this.name = "Substance " + skin.getDisplayName();
1263
initPluginsIfNecessary();
1267
* Initializes the plugins if necessary.
1269
protected static void initPluginsIfNecessary() {
1270
if (SubstanceLookAndFeel.skinPlugins != null)
1272
SubstanceLookAndFeel.skinPlugins = new PluginManager(
1273
SubstanceLookAndFeel.PLUGIN_XML, LafPlugin.TAG_MAIN,
1274
SubstanceSkinPlugin.TAG_SKIN_PLUGIN_CLASS);
1275
SubstanceLookAndFeel.componentPlugins = new ComponentPluginManager(
1276
SubstanceLookAndFeel.PLUGIN_XML);
1280
* Retrieves the current label bundle.
1282
* @return The current label bundle.
1283
* @see #resetLabelBundle()
1285
public static synchronized ResourceBundle getLabelBundle() {
1286
if (SubstanceLookAndFeel.LABEL_BUNDLE == null) {
1287
// fix for RFE 157 (allowing custom class loader for
1288
// resource bundles which can remove server calls
1290
if (SubstanceLookAndFeel.labelBundleClassLoader == null) {
1291
SubstanceLookAndFeel.LABEL_BUNDLE = ResourceBundle
1293
"org.pushingpixels.substance.internal.resources.Labels",
1294
Locale.getDefault());
1296
SubstanceLookAndFeel.LABEL_BUNDLE = ResourceBundle
1298
"org.pushingpixels.substance.internal.resources.Labels",
1299
Locale.getDefault(),
1300
SubstanceLookAndFeel.labelBundleClassLoader);
1302
for (LocaleChangeListener lcl : SubstanceLookAndFeel.localeChangeListeners)
1303
lcl.localeChanged();
1305
return SubstanceLookAndFeel.LABEL_BUNDLE;
1309
* Retrieves the label bundle for the specified locale.
1313
* @return The label bundle for the specified locale.
1315
public static synchronized ResourceBundle getLabelBundle(Locale locale) {
1316
// fix for RFE 157 (allowing custom class loader for
1317
// resource bundles which can remove server calls
1319
if (SubstanceLookAndFeel.labelBundleClassLoader == null) {
1320
return ResourceBundle.getBundle(
1321
"org.pushingpixels.substance.internal.resources.Labels",
1324
return ResourceBundle.getBundle(
1325
"org.pushingpixels.substance.internal.resources.Labels",
1326
locale, SubstanceLookAndFeel.labelBundleClassLoader);
1331
* Resets the current label bundle. Useful when the application changes
1332
* Locale at runtime.
1334
* @see #getLabelBundle()
1336
public static synchronized void resetLabelBundle() {
1337
SubstanceLookAndFeel.LABEL_BUNDLE = null;
1338
LafWidgetRepository.resetLabelBundle();
1342
* Returns the current global skin. If the current look-and-feel is not
1343
* Substance, this method returns <code>null</code>. This method is for
1344
* internal use only. Applications should use the
1345
* {@link #getCurrentSkin(Component)}.
1347
* @return Current global skin.
1348
* @see #getCurrentSkin(Component)
1350
public static SubstanceSkin getCurrentSkin() {
1351
LookAndFeel current = UIManager.getLookAndFeel();
1352
if (current instanceof SubstanceLookAndFeel) {
1359
* Returns the current skin for the specified component. If the current
1360
* look-and-feel is not Substance, this method returns <code>null</code>.
1363
* Component. May be <code>null</code> - in this case the global
1364
* current Substance skin will be returned.
1365
* @return Current skin for the specified component.
1366
* @see #SKIN_PROPERTY
1367
* @see #getCurrentSkin()
1369
public static SubstanceSkin getCurrentSkin(Component c) {
1370
return SubstanceCoreUtilities.getSkin(c);
1376
* @see javax.swing.LookAndFeel#getDescription()
1379
public String getDescription() {
1380
return "Substance Look and Feel by Kirill Grouchnikov";
1386
* @see javax.swing.LookAndFeel#getID()
1389
public String getID() {
1396
* @see javax.swing.LookAndFeel#getName()
1399
public String getName() {
1406
* @see javax.swing.LookAndFeel#isNativeLookAndFeel()
1409
public boolean isNativeLookAndFeel() {
1416
* @see javax.swing.LookAndFeel#isSupportedLookAndFeel()
1419
public boolean isSupportedLookAndFeel() {
1427
* javax.swing.plaf.basic.BasicLookAndFeel#initClassDefaults(javax.swing
1431
protected void initClassDefaults(UIDefaults table) {
1432
super.initClassDefaults(table);
1434
String UI_CLASSNAME_PREFIX = "org.pushingpixels.substance.internal.ui.Substance";
1435
Object[] uiDefaults = {
1437
"ButtonUI", UI_CLASSNAME_PREFIX + "ButtonUI",
1439
"CheckBoxUI", UI_CLASSNAME_PREFIX + "CheckBoxUI",
1441
"ComboBoxUI", UI_CLASSNAME_PREFIX + "ComboBoxUI",
1443
"CheckBoxMenuItemUI", UI_CLASSNAME_PREFIX + "CheckBoxMenuItemUI",
1445
"DesktopIconUI", UI_CLASSNAME_PREFIX + "DesktopIconUI",
1447
"DesktopPaneUI", UI_CLASSNAME_PREFIX + "DesktopPaneUI",
1450
UI_CLASSNAME_PREFIX + "EditorPaneUI",
1453
UI_CLASSNAME_PREFIX + "FileChooserUI",
1455
// "FileChooserUI", "javax.swing.plaf.metal.MetalFileChooserUI",
1457
"FormattedTextFieldUI",
1458
UI_CLASSNAME_PREFIX + "FormattedTextFieldUI",
1460
"InternalFrameUI", UI_CLASSNAME_PREFIX + "InternalFrameUI",
1462
"LabelUI", UI_CLASSNAME_PREFIX + "LabelUI",
1464
"ListUI", UI_CLASSNAME_PREFIX + "ListUI",
1466
"MenuUI", UI_CLASSNAME_PREFIX + "MenuUI",
1468
"MenuBarUI", UI_CLASSNAME_PREFIX + "MenuBarUI",
1470
"MenuItemUI", UI_CLASSNAME_PREFIX + "MenuItemUI",
1472
"OptionPaneUI", UI_CLASSNAME_PREFIX + "OptionPaneUI",
1474
"PanelUI", UI_CLASSNAME_PREFIX + "PanelUI",
1476
"PasswordFieldUI", UI_CLASSNAME_PREFIX + "PasswordFieldUI",
1478
"PopupMenuUI", UI_CLASSNAME_PREFIX + "PopupMenuUI",
1480
"PopupMenuSeparatorUI",
1481
UI_CLASSNAME_PREFIX + "PopupMenuSeparatorUI",
1483
"ProgressBarUI", UI_CLASSNAME_PREFIX + "ProgressBarUI",
1485
"RadioButtonUI", UI_CLASSNAME_PREFIX + "RadioButtonUI",
1487
"RadioButtonMenuItemUI",
1488
UI_CLASSNAME_PREFIX + "RadioButtonMenuItemUI",
1490
"RootPaneUI", UI_CLASSNAME_PREFIX + "RootPaneUI",
1492
"ScrollBarUI", UI_CLASSNAME_PREFIX + "ScrollBarUI",
1494
"ScrollPaneUI", UI_CLASSNAME_PREFIX + "ScrollPaneUI",
1496
"SeparatorUI", UI_CLASSNAME_PREFIX + "SeparatorUI",
1498
"SliderUI", UI_CLASSNAME_PREFIX + "SliderUI",
1500
"SpinnerUI", UI_CLASSNAME_PREFIX + "SpinnerUI",
1502
"SplitPaneUI", UI_CLASSNAME_PREFIX + "SplitPaneUI",
1504
"TabbedPaneUI", UI_CLASSNAME_PREFIX + "TabbedPaneUI",
1506
"TableUI", UI_CLASSNAME_PREFIX + "TableUI",
1508
"TableHeaderUI", UI_CLASSNAME_PREFIX + "TableHeaderUI",
1510
"TextAreaUI", UI_CLASSNAME_PREFIX + "TextAreaUI",
1512
"TextFieldUI", UI_CLASSNAME_PREFIX + "TextFieldUI",
1514
"TextPaneUI", UI_CLASSNAME_PREFIX + "TextPaneUI",
1516
"ToggleButtonUI", UI_CLASSNAME_PREFIX + "ToggleButtonUI",
1518
"ToolBarUI", UI_CLASSNAME_PREFIX + "ToolBarUI",
1520
"ToolBarSeparatorUI",
1521
UI_CLASSNAME_PREFIX + "ToolBarSeparatorUI",
1523
"ToolTipUI", UI_CLASSNAME_PREFIX + "ToolTipUI",
1525
"TreeUI", UI_CLASSNAME_PREFIX + "TreeUI",
1527
"ViewportUI", UI_CLASSNAME_PREFIX + "ViewportUI",
1530
table.putDefaults(uiDefaults);
1537
* javax.swing.plaf.basic.BasicLookAndFeel#initComponentDefaults(javax.swing
1541
protected void initComponentDefaults(UIDefaults table) {
1542
super.initComponentDefaults(table);
1544
initFontDefaults(table);
1545
this.skin.addCustomEntriesToTable(table);
1549
* Sets the {@link FontPolicy} to be used with Substance family. If the
1550
* specified policy is <code>null</code>, the default will be reset. This
1551
* method does not require Substance to be the current look-and-feel, and
1552
* will cause Substance to be set as the current application look-and-feel.
1555
* The {@link FontPolicy} to be used with Substance family, or
1556
* <code>null</code> to reset to the default
1558
* @see #getFontPolicy()
1559
* @see SubstanceLookAndFeel#SUBSTANCE_FONT_POLICY_KEY
1561
public static void setFontPolicy(FontPolicy fontPolicy) {
1562
UIManager.put(SUBSTANCE_FONT_POLICY_KEY, fontPolicy);
1563
SubstanceSizeUtils.setControlFontSize(-1);
1564
SubstanceSizeUtils.resetPointsToPixelsRatio(fontPolicy);
1565
SubstanceLookAndFeel.setSkin(SubstanceLookAndFeel.getCurrentSkin());
1569
* Looks up and retrieves the {@link FontPolicy} used by the Substance
1570
* family. If a {@link FontPolicy} has been set, it'll be returned.
1571
* Otherwise, this method checks if a {@link FontPolicy} or {@link FontSet}
1572
* is defined in the system properties or UIDefaults. If so, it is returned.
1573
* If no {@link FontPolicy} has been set for this look, in the system
1574
* properties or {@link UIDefaults}, the default Substance font policy will
1577
* @return the {@link FontPolicy} set for this Look&feel - if any, the
1578
* {@link FontPolicy} specified in the system properties or
1579
* {@link UIDefaults} - if any, or the default Substance font
1582
* @see #setFontPolicy(org.pushingpixels.substance.api.fonts.FontPolicy)
1584
* @see FontPolicies#customSettingsPolicy(FontPolicy)
1586
public static FontPolicy getFontPolicy() {
1587
FontPolicy policy = (FontPolicy) UIManager
1588
.get(SUBSTANCE_FONT_POLICY_KEY);
1592
// return default policy
1593
return SubstanceFontUtilities.getDefaultFontPolicy();
1597
* Sets the {@link InputMapSet} to be used with Substance family. If the
1598
* specified set is <code>null</code>, the default will be reset. This
1599
* method does not require Substance to be the current look-and-feel, and
1600
* will cause Substance to be set as the current application look-and-feel.
1602
* @param inputMapSet
1603
* The {@link InputMapSet} to be used with Substance family, or
1604
* <code>null</code> to reset to the default
1606
* @see #getInputMapSet()
1607
* @see SubstanceLookAndFeel#SUBSTANCE_INPUT_MAP_SET_KEY
1609
public static void setInputMapSet(InputMapSet inputMapSet) {
1610
UIManager.put(SUBSTANCE_INPUT_MAP_SET_KEY, inputMapSet);
1611
SubstanceLookAndFeel.setSkin(SubstanceLookAndFeel.getCurrentSkin());
1615
* Looks up and retrieves the {@link InputMapSet} used by the Substance
1616
* family. If a {@link InputMapSet} has been set, it'll be returned. If no
1617
* {@link InputMapSet} has been set for this look, the default Substance
1618
* input map set will be returned.
1620
* @return the {@link InputMapSet} set for this Look&feel - if any, or
1621
* the default Substance input map set.
1623
* @see #setInputMapSet(InputMapSet)
1625
public static InputMapSet getInputMapSet() {
1626
InputMapSet inputMapSet = (InputMapSet) UIManager
1627
.get(SUBSTANCE_INPUT_MAP_SET_KEY);
1628
if (inputMapSet != null)
1631
// return system input map set
1632
return SubstanceInputMapUtilities.getSystemInputMapSet();
1636
* Looks up the correct control font and sets it for all controls.
1639
* The UI defaults table.
1641
private void initFontDefaults(UIDefaults table) {
1642
FontSet substanceFontSet = getFontPolicy()
1643
.getFontSet("Substance", null);
1644
initFontDefaults(table, substanceFontSet);
1648
* Sets Fonts in the given FontSet as defaults for all known component types
1649
* in the given UIDefaults table.
1652
* the UIDefaults table used to set fonts
1654
* describes the set of Fonts to be installed
1656
private static void initFontDefaults(UIDefaults table, FontSet fontSet) {
1657
Font controlFont = fontSet.getControlFont();
1658
Font menuFont = fontSet.getMenuFont();
1659
Font messageFont = fontSet.getMessageFont();
1660
Font toolTipFont = fontSet.getSmallFont();
1661
Font titleFont = fontSet.getTitleFont();
1662
Font windowFont = fontSet.getWindowTitleFont();
1664
// System.out.println("Control: " + fontSet.getControlFont());
1665
// System.out.println("Menu: " + fontSet.getMenuFont());
1666
// System.out.println("Message: " + fontSet.getMessageFont());
1667
// System.out.println("Small: " + fontSet.getSmallFont());
1668
// System.out.println("Title: " + fontSet.getTitleFont());
1669
// System.out.println("Window title: " + fontSet.getWindowTitleFont());
1671
Object[] defaults = {
1673
"Button.font", controlFont,
1675
"CheckBox.font", controlFont,
1677
"ColorChooser.font", controlFont,
1679
"ComboBox.font", controlFont,
1681
"EditorPane.font", controlFont,
1683
"FormattedTextField.font", controlFont,
1685
"Label.font", controlFont,
1687
"List.font", controlFont,
1689
"Panel.font", controlFont,
1691
"PasswordField.font", controlFont,
1693
"ProgressBar.font", controlFont,
1695
"RadioButton.font", controlFont,
1697
"ScrollPane.font", controlFont,
1699
"Spinner.font", controlFont,
1701
"TabbedPane.font", controlFont,
1703
"Table.font", controlFont,
1705
"TableHeader.font", controlFont,
1707
"TextArea.font", controlFont,
1709
"TextField.font", controlFont,
1711
"TextPane.font", controlFont,
1713
"ToolBar.font", controlFont,
1715
"ToggleButton.font", controlFont,
1717
"Tree.font", controlFont,
1719
"Viewport.font", controlFont,
1721
"InternalFrame.titleFont", windowFont,
1723
"DesktopIcon.titleFont", windowFont,
1725
"OptionPane.font", messageFont,
1727
"OptionPane.messageFont", messageFont,
1729
"OptionPane.buttonFont", messageFont,
1731
"TitledBorder.font", titleFont,
1733
"ToolTip.font", toolTipFont,
1735
"CheckBoxMenuItem.font", menuFont,
1737
"CheckBoxMenuItem.acceleratorFont", menuFont,
1739
"Menu.font", menuFont,
1741
"Menu.acceleratorFont", menuFont,
1743
"MenuBar.font", menuFont,
1745
"MenuItem.font", menuFont,
1747
"MenuItem.acceleratorFont", menuFont,
1749
"PopupMenu.font", menuFont,
1751
"RadioButtonMenuItem.font", menuFont,
1753
"RadioButtonMenuItem.acceleratorFont", menuFont,
1756
table.putDefaults(defaults);
1762
* @see javax.swing.plaf.basic.BasicLookAndFeel#getDefaults()
1765
public UIDefaults getDefaults() {
1766
UIDefaults table = super.getDefaults();
1768
SubstanceLookAndFeel.componentPlugins.processAllDefaultsEntries(table,
1776
* @see javax.swing.plaf.basic.BasicLookAndFeel#initialize()
1779
public void initialize() {
1781
ShadowPopupFactory.install();
1783
setSkin(this.skin, false);
1785
// tracer for memory analysis
1786
String paramTraceFile = SubstanceCoreUtilities
1787
.getVmParameter(SubstanceLookAndFeel.TRACE_FILE);
1788
if (paramTraceFile != null) {
1789
MemoryAnalyzer.commence(1000, paramTraceFile);
1790
for (Object plugin : SubstanceLookAndFeel.componentPlugins
1791
.getAvailablePlugins(true))
1792
MemoryAnalyzer.enqueueUsage("Has plugin '"
1793
+ plugin.getClass().getName() + "'");
1796
// to show heap status panel in title pane?
1797
String heapStatusPanelParam = SubstanceCoreUtilities
1798
.getVmParameter(SubstanceLookAndFeel.HEAP_STATUS_TRACE_FILE);
1799
SubstanceTitlePane.setHeapStatusLogfileName(heapStatusPanelParam);
1801
// initialize component plugins
1802
SubstanceLookAndFeel.componentPlugins.initializeAll();
1804
// initialize widget support
1805
LafWidgetRepository.getRepository().setLafSupport(
1806
new SubstanceWidgetSupport());
1808
// fix for defect 208 - tracking changes to focus owner
1809
// and repainting the default button
1810
this.focusOwnerChangeListener = new PropertyChangeListener() {
1812
public void propertyChange(PropertyChangeEvent evt) {
1813
if ("focusOwner".equals(evt.getPropertyName())) {
1814
Component newFocusOwner = (Component) evt.getNewValue();
1815
if (newFocusOwner != null) {
1816
JRootPane rootPane = SwingUtilities
1817
.getRootPane(newFocusOwner);
1818
if (rootPane == null)
1820
JButton defaultButton = rootPane.getDefaultButton();
1821
if (defaultButton == null)
1823
defaultButton.repaint();
1826
if ("managingFocus".equals(evt.getPropertyName())) {
1827
if (Boolean.FALSE.equals(evt.getNewValue())) {
1828
// new keyboard focus manager has been installed
1829
currentKeyboardFocusManager
1830
.removePropertyChangeListener(focusOwnerChangeListener);
1831
currentKeyboardFocusManager = KeyboardFocusManager
1832
.getCurrentKeyboardFocusManager();
1833
currentKeyboardFocusManager
1834
.addPropertyChangeListener(focusOwnerChangeListener);
1839
this.currentKeyboardFocusManager = KeyboardFocusManager
1840
.getCurrentKeyboardFocusManager();
1841
this.currentKeyboardFocusManager
1842
.addPropertyChangeListener(this.focusOwnerChangeListener);
1843
if (!LookUtils.IS_OS_WINDOWS
1844
|| System.getProperty("java.version").compareTo("1.6.0_10") < 0) {
1845
UIManager.put(WINDOW_ROUNDED_CORNERS, Boolean.FALSE);
1853
* @see javax.swing.plaf.basic.BasicLookAndFeel#uninitialize()
1856
public void uninitialize() {
1857
super.uninitialize();
1859
SubstanceLookAndFeel.currentSkin = null;
1861
ShadowPopupFactory.uninstall();
1863
SubstanceCoreUtilities.stopThreads();
1865
// fix for defect 109 - memory leak on watermarks
1866
if (this.skin.getWatermark() != null)
1867
this.skin.getWatermark().dispose();
1869
// uninitialize component plugins
1870
SubstanceLookAndFeel.componentPlugins.uninitializeAll();
1872
// reset widget support
1873
LafWidgetRepository.getRepository().unsetLafSupport();
1876
LazyResettableHashMap.reset();
1878
this.currentKeyboardFocusManager
1879
.removePropertyChangeListener(this.focusOwnerChangeListener);
1880
this.focusOwnerChangeListener = null;
1881
this.currentKeyboardFocusManager = null;
1885
* Registers a new listener on skin change.
1887
* @param skinChangeListener
1888
* New listener on skin change.
1889
* @see #setSkin(String)
1890
* @see #setSkin(SubstanceSkin)
1891
* @see #unregisterSkinChangeListener(SkinChangeListener)
1893
public static void registerSkinChangeListener(
1894
SkinChangeListener skinChangeListener) {
1895
SubstanceLookAndFeel.skinChangeListeners.add(skinChangeListener);
1899
* Unregisters a listener on skin change.
1901
* @param skinChangeListener
1902
* The listener to unregister.
1903
* @see #setSkin(String)
1904
* @see #setSkin(SubstanceSkin)
1905
* @see #registerSkinChangeListener(SkinChangeListener)
1907
public static void unregisterSkinChangeListener(
1908
SkinChangeListener skinChangeListener) {
1909
SubstanceLookAndFeel.skinChangeListeners.remove(skinChangeListener);
1913
* Registers the specified listener on tab-close events on <b>all</b> tabbed
1916
* @param tabCloseListener
1917
* Listener to register.
1918
* @see #registerTabCloseChangeListener(JTabbedPane, BaseTabCloseListener)
1919
* @see #unregisterTabCloseChangeListener(BaseTabCloseListener)
1920
* @see #unregisterTabCloseChangeListener(JTabbedPane, BaseTabCloseListener)
1922
public static void registerTabCloseChangeListener(
1923
BaseTabCloseListener tabCloseListener) {
1924
TabCloseListenerManager.getInstance()
1925
.registerListener(tabCloseListener);
1929
* Registers the specified listener on tab-close events on <b>the
1930
* specified</b> tabbed pane.
1933
* Tabbed pane. If <code>null</code>, the tab close listener is
1934
* registered globally (for all tabbed panes).
1935
* @param tabCloseListener
1936
* Listener to register.
1937
* @see #registerTabCloseChangeListener(BaseTabCloseListener)
1938
* @see #unregisterTabCloseChangeListener(BaseTabCloseListener)
1939
* @see #unregisterTabCloseChangeListener(JTabbedPane, BaseTabCloseListener)
1941
public static void registerTabCloseChangeListener(JTabbedPane tabbedPane,
1942
BaseTabCloseListener tabCloseListener) {
1943
TabCloseListenerManager.getInstance().registerListener(tabbedPane,
1948
* Unregisters the specified listener on tab-close events on <b>all</b>
1951
* @param tabCloseListener
1952
* Listener to unregister.
1953
* @see #registerTabCloseChangeListener(BaseTabCloseListener)
1954
* @see #registerTabCloseChangeListener(JTabbedPane, BaseTabCloseListener)
1955
* @see #unregisterTabCloseChangeListener(JTabbedPane, BaseTabCloseListener)
1957
public static void unregisterTabCloseChangeListener(
1958
BaseTabCloseListener tabCloseListener) {
1959
TabCloseListenerManager.getInstance().unregisterListener(
1964
* Unregisters the specified listener on tab-close events on <b>the
1965
* specified</b> tabbed pane.
1968
* Tabbed pane. If <code>null</code>, the tab close listener is
1969
* unregistered globally (for all tabbed panes).
1970
* @param tabCloseListener
1971
* Listener to unregister.
1972
* @see #registerTabCloseChangeListener(BaseTabCloseListener)
1973
* @see #registerTabCloseChangeListener(JTabbedPane, BaseTabCloseListener)
1974
* @see #unregisterTabCloseChangeListener(BaseTabCloseListener)
1976
public static void unregisterTabCloseChangeListener(JTabbedPane tabbedPane,
1977
BaseTabCloseListener tabCloseListener) {
1978
TabCloseListenerManager.getInstance().unregisterListener(tabbedPane,
1983
* Returns the set of all listeners registered on tab-close events on
1984
* <b>all</b> tabbed panes.
1986
* @return Set of all listeners registered on tab-close events on <b>all</b>
1989
public static Set<BaseTabCloseListener> getAllTabCloseListeners() {
1990
return TabCloseListenerManager.getInstance().getListeners();
1994
* Returns all listeners registered on tab closing of the specified tabbed
1998
* A tabbed pane. If <code>null</code>, all globally registered
1999
* tab close listeners are returned.
2000
* @return All listeners registered on tab closing of the specified tabbed
2003
public static Set<BaseTabCloseListener> getAllTabCloseListeners(
2004
JTabbedPane tabbedPane) {
2005
return TabCloseListenerManager.getInstance().getListeners(tabbedPane);
2009
* Registers a new listener on locale change.
2011
* @param localeListener
2012
* New listener on locale change.
2014
public static void registerLocaleChangeListener(
2015
LocaleChangeListener localeListener) {
2016
SubstanceLookAndFeel.localeChangeListeners.add(localeListener);
2020
* Unregisters a listener on locale change.
2022
* @param localeListener
2023
* The listener to unregister.
2025
public static void unregisterLocaleChangeListener(
2026
LocaleChangeListener localeListener) {
2027
SubstanceLookAndFeel.localeChangeListeners.remove(localeListener);
2031
* Returns all listeners registered on locale change.
2033
* @return All listeners registered on locale change.
2035
public static Set<LocaleChangeListener> getLocaleListeners() {
2037
.unmodifiableSet(SubstanceLookAndFeel.localeChangeListeners);
2041
* Sets the visibility of the specified widget kind(s). If the first
2042
* <code>rootPane</code> parameter is <code>null</code>, this call applies
2043
* to all root panes. This method should not be called from inside the
2044
* initialization sequence of your window. If the specific widget needs to
2045
* be visible when the window is shown, wrap the call with
2046
* {@link SwingUtilities#invokeLater(Runnable)}.
2049
* Root pane. May be <code>null</code>.
2051
* Visibility indication.
2052
* @param substanceWidgets
2054
* @since version 5.0
2056
public static void setWidgetVisible(JRootPane rootPane, boolean visible,
2057
SubstanceWidgetType... substanceWidgets) {
2058
SubstanceWidgetManager.getInstance().register(rootPane, visible,
2060
if (rootPane != null) {
2061
SwingUtilities.updateComponentTreeUI(rootPane);
2063
for (Window window : Window.getWindows()) {
2064
JRootPane root = SwingUtilities.getRootPane(window);
2065
SwingUtilities.updateComponentTreeUI(root);
2071
* Checks whether the <code>JOptionPane</code>s created with predefined
2072
* message types should use constant color schemes for the icons.
2074
* @return <code>true</code> if the <code>JOptionPane</code>s created with
2075
* predefined message types should use constant color schemes for
2076
* the icons, <code>false</code> otherwise.
2077
* @see #setToUseConstantThemesOnDialogs(boolean)
2079
public static boolean isToUseConstantThemesOnDialogs() {
2080
return SubstanceLookAndFeel.toUseConstantThemesOnDialogs;
2084
* Sets the new setting for the icons of the <code>JOptionPane</code>s
2085
* created with predefined message types.
2087
* @param toUseConstantThemesOnDialogs
2088
* if <code>true</code>, the <code>JOptionPane</code>s created
2089
* with predefined message types should use constant color
2090
* schemes for the icons.
2091
* @see #isToUseConstantThemesOnDialogs()
2093
public static void setToUseConstantThemesOnDialogs(
2094
boolean toUseConstantThemesOnDialogs) {
2095
SubstanceLookAndFeel.toUseConstantThemesOnDialogs = toUseConstantThemesOnDialogs;
2096
SwingUtilities.invokeLater(new Runnable() {
2099
for (Window window : Window.getWindows()) {
2100
SwingUtilities.updateComponentTreeUI(window);
2107
* The current Substance skin.
2109
private static SubstanceSkin currentSkin = null;
2112
* Sets the specified skin. If the current look-and-feel is not Substance,
2113
* this method will create a new Substance look-and-feel based on the
2114
* specified skin and set it on {@link UIManager}. This method does not
2115
* require Substance to be the current look-and-feel.
2119
* @param toUpdateWindows
2120
* if <code>true</code>, the
2121
* {@link SwingUtilities#updateComponentTreeUI(Component)} is
2122
* called on all windows returned by {@link Window#getWindows()}
2124
* @return <code>true</code> if the specified skin has been set
2125
* successfully, <code>false</code> otherwise.
2126
* @see #setSkin(SubstanceSkin)
2128
private static boolean setSkin(final SubstanceSkin newSkin,
2129
final boolean toUpdateWindows) {
2130
if (!SwingUtilities.isEventDispatchThread()) {
2131
final boolean[] returnValue = new boolean[1];
2133
SwingUtilities.invokeAndWait(new Runnable() {
2136
returnValue[0] = setSkin(newSkin, toUpdateWindows);
2139
} catch (InvocationTargetException ite) {
2140
if (ite.getCause() instanceof RuntimeException) {
2141
throw (RuntimeException) ite.getCause();
2142
} else if (ite.getCause() instanceof Error) {
2143
throw (Error) ite.getCause();
2146
} catch (InterruptedException ignore) {}
2147
return returnValue[0];
2150
if (!newSkin.isValid())
2153
boolean isSubstance = (UIManager.getLookAndFeel() instanceof SubstanceLookAndFeel);
2155
class SkinDerivedLookAndFeel extends SubstanceLookAndFeel {
2156
public SkinDerivedLookAndFeel(SubstanceSkin newSkin) {
2161
LookAndFeel derived = new SkinDerivedLookAndFeel(newSkin);
2163
UIManager.setLookAndFeel(derived);
2164
} catch (UnsupportedLookAndFeelException ulafe) {
2167
if (!(UIManager.getLookAndFeel() instanceof SubstanceLookAndFeel)) {
2170
for (Window window : Window.getWindows()) {
2171
SwingUtilities.updateComponentTreeUI(window);
2177
// Required skin settings must be non-null
2178
if (!newSkin.isValid()) {
2182
// fix for defect 109 - memory leak on watermark switch
2183
if ((currentSkin != null) && (currentSkin.getWatermark() != null)) {
2184
currentSkin.getWatermark().dispose();
2186
if (newSkin.getWatermark() != null) {
2187
if (!newSkin.getWatermark().updateWatermarkImage(newSkin)) {
2192
UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults();
2193
// The table will be null when the skin is set using a custom
2195
if (lafDefaults != null) {
2196
initFontDefaults(lafDefaults, SubstanceLookAndFeel
2197
.getFontPolicy().getFontSet("Substance", null));
2198
newSkin.addCustomEntriesToTable(lafDefaults);
2199
SubstanceLookAndFeel.componentPlugins
2200
.processAllDefaultsEntries(lafDefaults, newSkin);
2203
// file chooser strings go to the main UIManager table
2204
for (ResourceBundle bundle : new ResourceBundle[] {
2205
ResourceBundle.getBundle("com.sun.swing.internal.plaf.metal.resources.metal"),
2206
SubstanceLookAndFeel.getLabelBundle()
2208
Enumeration<String> keyEn = bundle.getKeys();
2209
while (keyEn.hasMoreElements()) {
2210
String key = keyEn.nextElement();
2211
if (key.contains("FileChooser")) {
2212
String value = bundle.getString(key);
2213
UIManager.put(key, value);
2219
LazyResettableHashMap.reset();
2221
currentSkin = newSkin;
2223
if (toUpdateWindows) {
2224
for (Window window : Window.getWindows()) {
2225
SwingUtilities.updateComponentTreeUI(window);
2229
// SwingUtilities.invokeLater(new Runnable() {
2230
// public void run() {
2231
for (SkinChangeListener skinChangeListener : SubstanceLookAndFeel.skinChangeListeners)
2232
skinChangeListener.skinChanged();
2236
} catch (NoClassDefFoundError ncdfe) {
2237
// this may happen when a skin references some class
2238
// that can't be found in the classpath.
2240
} catch (Exception e) {
2246
* Sets the specified skin. If the current look-and-feel is not Substance,
2247
* this method will create a new Substance look-and-feel based on the
2248
* specified skin and set it on {@link UIManager}. This method does not
2249
* require Substance to be the current look-and-feel. Calling this method
2250
* will call {@link SwingUtilities#updateComponentTreeUI(Component)} on all
2251
* open top-level windows.
2255
* @return <code>true</code> if the specified skin has been set
2256
* successfully, <code>false</code> otherwise.
2257
* @throws IllegalStateException
2258
* When called outside the Event Dispatch Thread.
2259
* @see #registerSkinChangeListener(SkinChangeListener)
2260
* @see #unregisterSkinChangeListener(SkinChangeListener)
2261
* @see SubstanceSkin#isValid()
2263
public static boolean setSkin(SubstanceSkin newSkin) {
2264
return setSkin(newSkin, true);
2268
* Sets the specified skin. If the current look-and-feel is not Substance,
2269
* this method will create a new Substance look-and-feel based on the
2270
* specified skin and set it on {@link UIManager}. This method does not
2271
* require Substance to be the current look-and-feel. Calling this method
2272
* will call {@link SwingUtilities#updateComponentTreeUI(Component)} on all
2273
* open top-level windows.
2275
* @param skinClassName
2277
* @return <code>true</code> if the specified skin has been set
2278
* successfully, <code>false</code> otherwise.
2279
* @throws IllegalStateException
2280
* When called outside the Event Dispatch Thread.
2281
* @since version 3.1
2282
* @see #setSkin(SubstanceSkin)
2283
* @see #registerSkinChangeListener(SkinChangeListener)
2284
* @see #unregisterSkinChangeListener(SkinChangeListener)
2285
* @see SubstanceSkin#isValid()
2287
public static boolean setSkin(String skinClassName) {
2289
Class<?> skinClass = Class.forName(skinClassName);
2290
if (skinClass == null) {
2293
Object obj = skinClass.newInstance();
2297
if (!(obj instanceof SubstanceSkin)) {
2300
return SubstanceLookAndFeel.setSkin((SubstanceSkin) obj);
2301
} catch (Exception exc) {
2302
exc.printStackTrace();
2308
* Returns all available skins.
2310
* @return All available skins. Key - skin display name, value - skin
2313
public static Map<String, SkinInfo> getAllSkins() {
2314
initPluginsIfNecessary();
2315
Map<String, SkinInfo> result = new TreeMap<String, SkinInfo>();
2316
for (Object skinPlugin : SubstanceLookAndFeel.skinPlugins
2317
.getAvailablePlugins(true)) {
2318
for (SkinInfo skinInfo : ((SubstanceSkinPlugin) skinPlugin)
2320
result.put(skinInfo.getDisplayName(), skinInfo);
2329
* @see javax.swing.LookAndFeel#getSupportsWindowDecorations()
2332
public boolean getSupportsWindowDecorations() {
2337
* Sets the class loader for {@link #LABEL_BUNDLE}.
2339
* @param labelBundleClassLoader
2340
* Class loader for {@link #LABEL_BUNDLE}.
2341
* @since version 3.1
2343
public static void setLabelBundleClassLoader(
2344
ClassLoader labelBundleClassLoader) {
2345
SubstanceLookAndFeel.labelBundleClassLoader = labelBundleClassLoader;
2346
LafWidgetRepository.setLabelBundleClassLoader(labelBundleClassLoader);
2350
* Returns the title pane of the specified top-level window.
2354
* @return If the parameter is either {@link JFrame} or {@link JDialog} and
2355
* has custom decorations, the result is the title pane,
2356
* <code>null</code> otherwise.
2357
* @since version 3.1
2359
public static JComponent getTitlePaneComponent(Window window) {
2360
JRootPane rootPane = null;
2361
if (window instanceof JFrame) {
2362
JFrame f = (JFrame) window;
2363
rootPane = f.getRootPane();
2365
if (window instanceof JDialog) {
2366
JDialog d = (JDialog) window;
2367
rootPane = d.getRootPane();
2369
if (rootPane != null) {
2370
SubstanceRootPaneUI ui = (SubstanceRootPaneUI) rootPane.getUI();
2371
return ui.getTitlePane();
2377
* Sets the decoration type of the specified component and all its children.
2382
* Decoration type of the component and all its children.
2384
public static void setDecorationType(JComponent comp,
2385
DecorationAreaType type) {
2386
DecorationPainterUtils.setDecorationType(comp, type);
2390
* Returns the decoration area type of the specified component. The
2391
* component and its ancestor hierarchy are scanned for the registered
2392
* decoration area type. If
2393
* {@link #setDecorationType(JComponent, DecorationAreaType)} has been
2394
* called on the specified component, the matching decoration type is
2395
* returned. Otherwise, the component hierarchy is scanned to find the
2396
* closest ancestor that was passed to
2397
* {@link #setDecorationType(JComponent, DecorationAreaType)} - and its
2398
* decoration type is returned. If neither the component, nor any one of its
2399
* parent components has been passed to the setter method,
2400
* {@link DecorationAreaType#NONE} is returned.
2404
* @return Decoration area type of the component.
2406
public static DecorationAreaType getDecorationType(Component comp) {
2407
return DecorationPainterUtils.getDecorationType(comp);
2411
* Returns the immediate decoration area type of the specified component.
2412
* The component is checked for the registered decoration area type. If
2413
* {@link #setDecorationType(javax.swing.JComponent, DecorationAreaType)} was
2414
* not called on this component, this method returns <code>null</code>.
2418
* @return Immediate decoration area type of the component.
2420
public static DecorationAreaType getImmediateDecorationType(Component comp) {
2421
return DecorationPainterUtils.getImmediateDecorationType(comp);
2425
* Checks whether Substance is the current look-and-feel. This method is for
2426
* internal use only.
2428
* @return <code>true</code> if Substance is the current look-and-feel,
2429
* <code>false</code> otherwise.
2431
public static boolean isCurrentLookAndFeel() {
2432
return ((UIManager.getLookAndFeel() instanceof SubstanceLookAndFeel) && (currentSkin != null));
2438
* @see javax.swing.LookAndFeel#getDisabledIcon(javax.swing.JComponent,
2442
public Icon getDisabledIcon(JComponent component, Icon icon) {
2445
SubstanceColorScheme colorScheme = SubstanceColorSchemeUtilities
2446
.getColorScheme(component, ComponentState.DISABLED_UNSELECTED);
2447
BufferedImage result = SubstanceImageCreator.getColorSchemeImage(
2448
component, icon, colorScheme, 0.5f);
2449
float alpha = SubstanceColorSchemeUtilities.getAlpha(component,
2450
ComponentState.DISABLED_UNSELECTED);
2452
BufferedImage intermediate = SubstanceCoreUtilities.getBlankImage(
2453
result.getWidth(), result.getHeight());
2454
Graphics2D g2d = intermediate.createGraphics();
2455
g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
2456
g2d.drawImage(result, 0, 0, null);
2458
result = intermediate;
2461
return new IconUIResource(new ImageIcon(result));