~ubuntu-branches/debian/stretch/insubstantial/stretch

« back to all changes in this revision

Viewing changes to substance/src/main/java/org/pushingpixels/substance/api/SubstanceLookAndFeel.java

  • Committer: Package Import Robot
  • Author(s): Felix Natter
  • Date: 2016-01-18 20:58:45 UTC
  • Revision ID: package-import@ubuntu.com-20160118205845-crbmrkda61qsi5qa
Tags: upstream-7.3+dfsg2
ImportĀ upstreamĀ versionĀ 7.3+dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions are met:
 
6
 *
 
7
 *  o Redistributions of source code must retain the above copyright notice,
 
8
 *    this list of conditions and the following disclaimer.
 
9
 *
 
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.
 
13
 *
 
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.
 
17
 *
 
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.
 
29
 */
 
30
package org.pushingpixels.substance.api;
 
31
 
 
32
import java.awt.*;
 
33
import java.awt.image.BufferedImage;
 
34
import java.beans.PropertyChangeEvent;
 
35
import java.beans.PropertyChangeListener;
 
36
import java.lang.reflect.InvocationTargetException;
 
37
import java.util.*;
 
38
 
 
39
import javax.swing.*;
 
40
import javax.swing.plaf.IconUIResource;
 
41
import javax.swing.plaf.UIResource;
 
42
import javax.swing.plaf.basic.BasicLookAndFeel;
 
43
 
 
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.*;
 
66
 
 
67
/**
 
68
 * <p>
 
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.
 
72
 * </p>
 
73
 * 
 
74
 * <p>
 
75
 * Since version 5.0 this class is abstract. There are three options to use
 
76
 * Substance:
 
77
 * </p>
 
78
 * 
 
79
 * <ul>
 
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.
 
84
 * </li>
 
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>
 
88
 * </ul>
 
89
 * 
 
90
 * @author Kirill Grouchnikov
 
91
 */
 
92
public abstract class SubstanceLookAndFeel extends BasicLookAndFeel {
 
93
        /**
 
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.
 
97
         */
 
98
        public static final String PLUGIN_XML = "META-INF/substance-plugin.xml";
 
99
 
 
100
        /**
 
101
         * Plugin manager for component plugins.
 
102
         */
 
103
        private static ComponentPluginManager componentPlugins;
 
104
 
 
105
        /**
 
106
         * Plugin manager for skin plugins.
 
107
         */
 
108
        private static PluginManager skinPlugins;
 
109
 
 
110
        /**
 
111
         * List of all listeners on skin changes.
 
112
         */
 
113
        protected final static Set<SkinChangeListener> skinChangeListeners = new HashSet<SkinChangeListener>();
 
114
 
 
115
        /**
 
116
         * List of all listeners on changing locales.
 
117
         */
 
118
        protected final static Set<LocaleChangeListener> localeChangeListeners = new HashSet<LocaleChangeListener>();
 
119
 
 
120
        /**
 
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>.
 
127
         * 
 
128
         * @see #isToUseConstantThemesOnDialogs()
 
129
         * @see #setToUseConstantThemesOnDialogs(boolean)
 
130
         */
 
131
        private static boolean toUseConstantThemesOnDialogs = true;
 
132
 
 
133
        /**
 
134
         * Change listener on keyboard focus manager - fix for defect 208.
 
135
         */
 
136
        protected PropertyChangeListener focusOwnerChangeListener;
 
137
 
 
138
        /**
 
139
         * The current keyboard focus manager - fix for defect 208.
 
140
         */
 
141
        protected KeyboardFocusManager currentKeyboardFocusManager;
 
142
 
 
143
        /**
 
144
         * Smart tree scroll animation facet. Disabled by default, use
 
145
         * {@link AnimationConfigurationManager#allowAnimations(AnimationFacet)} to
 
146
         * enable. </p>
 
147
         * 
 
148
         * <p>
 
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
 
152
         * narrow viewports).
 
153
         * </p>
 
154
         * 
 
155
         * @since 4.0
 
156
         */
 
157
        public final static AnimationFacet TREE_SMART_SCROLL_ANIMATION_KIND = new AnimationFacet(
 
158
                        "substancelaf.treeSmartScrollAnimationKind", false);
 
159
 
 
160
        /**
 
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}.
 
166
         * 
 
167
         * <p>
 
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).
 
174
         * </p>
 
175
         * 
 
176
         * <p>
 
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}.
 
181
         * </p>
 
182
         * 
 
183
         * @since version 5.0
 
184
         */
 
185
        public static final String WATERMARK_VISIBLE = "substancelaf.watermark.visible";
 
186
 
 
187
        /**
 
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}.
 
192
         * <p>
 
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
 
196
         * property.
 
197
         * </p>
 
198
         * 
 
199
         * <p>
 
200
         * Example of marking a button to ignore minimum dimension settings:
 
201
         * </p>
 
202
         * <code>
 
203
         * JButton button = new JButton("text");<br>
 
204
         * button.putClientProperty(SubstanceLookAndFeel.BUTTON_NO_MIN_SIZE_PROPERTY, <br>
 
205
         * &nbsp;&nbsp;Boolean.TRUE);
 
206
         * </code>
 
207
         * <p>
 
208
         * Example of marking all application buttons to ignore minimum dimension
 
209
         * settings:
 
210
         * </p>
 
211
         * <code>
 
212
         * UIManager.put(SubstanceLookAndFeel.BUTTON_NO_MIN_SIZE_PROPERTY, <br>
 
213
         * &nbsp;&nbsp;Boolean.TRUE);
 
214
         * </code>
 
215
         * 
 
216
         * @since version 2.1
 
217
         */
 
218
        public static final String BUTTON_NO_MIN_SIZE_PROPERTY = "substancelaf.buttonnominsize";
 
219
 
 
220
        /**
 
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).
 
228
         * 
 
229
         * <p>
 
230
         * Example of marking a button to never paint background:
 
231
         * </p>
 
232
         * <code>
 
233
         * JButton button = new JButton("text");<br>
 
234
         * button.putClientProperty(SubstanceLookAndFeel.BUTTON_PAINT_NEVER_PROPERTY, <br>
 
235
         * &nbsp;&nbsp;Boolean.TRUE);
 
236
         * </code>
 
237
         * 
 
238
         * <p>
 
239
         * Example of marking all application buttons to never paint background:
 
240
         * </p>
 
241
         * <code>
 
242
         * UIManager.put(SubstanceLookAndFeel.BUTTON_PAINT_NEVER_PROPERTY, <br>
 
243
         * &nbsp;&nbsp;Boolean.TRUE);
 
244
         * </code>
 
245
         * 
 
246
         * @since version 2.3
 
247
         * @see #FLAT_PROPERTY
 
248
         */
 
249
        public static final String BUTTON_PAINT_NEVER_PROPERTY = "substancelaf.buttonpaintnever";
 
250
 
 
251
        /**
 
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:
 
254
         * 
 
255
         * <p>
 
256
         * <ul>
 
257
         * <li>A value in {@link SubstanceConstants.Side} enum.
 
258
         * <li>Set of values in {@link SubstanceConstants.Side} enum.
 
259
         * </ul>
 
260
         * 
 
261
         * <p>
 
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
 
265
         * property.
 
266
         * </p>
 
267
         * 
 
268
         * <p>
 
269
         * Example of marking a button to have straight north side:
 
270
         * </p>
 
271
         * <code>
 
272
         * JButton button = new JButton("text");<br>
 
273
         * button.putClientProperty(SubstanceLookAndFeel.BUTTON_SIDE_PROPERTY,<br>
 
274
         * &nbsp;&nbsp;SubstanceConstants.Side.RIGHT);
 
275
         * </code>
 
276
         * 
 
277
         * @since version 2.1
 
278
         * @see #BUTTON_OPEN_SIDE_PROPERTY
 
279
         */
 
280
        public static final String BUTTON_SIDE_PROPERTY = "substancelaf.buttonside";
 
281
 
 
282
        /**
 
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:
 
285
         * 
 
286
         * <p>
 
287
         * <ul>
 
288
         * <li>A value in {@link SubstanceConstants.Side} enum.
 
289
         * <li>Set of values in {@link SubstanceConstants.Side} enum.
 
290
         * </ul>
 
291
         * </p>
 
292
         * <p>
 
293
         * Example of marking a button to have open top and west sides:
 
294
         * </p>
 
295
         * <code>
 
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
         * &nbsp;&nbsp;openSides);
 
300
         * </code>
 
301
         * 
 
302
         * @since version 3.1
 
303
         * @see #BUTTON_SIDE_PROPERTY
 
304
         */
 
305
        public static final String BUTTON_OPEN_SIDE_PROPERTY = "substancelaf.buttonopenSide";
 
306
 
 
307
        /**
 
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}.
 
313
         * 
 
314
         * <p>
 
315
         * Example of specifying a (toolbar) button to have corner radius of 5
 
316
         * pixels:
 
317
         * </p>
 
318
         * <code>
 
319
         * JButton button = new JButton("text");<br>
 
320
         * button.putClientProperty(SubstanceLookAndFeel.CORNER_RADIUS, <br>
 
321
         * &nbsp;&nbsp;Float.valueOf(5.0f));
 
322
         * </code>
 
323
         * 
 
324
         * <p>
 
325
         * Example of specifying all buttons of a toolbar to have corner radius of 3
 
326
         * pixels:
 
327
         * </p>
 
328
         * <code>
 
329
         * JToolBar toolbar = new JToolBar("toolbar");<br>
 
330
         * toolbar.putClientProperty(SubstanceLookAndFeel.CORNER_RADIUS, <br>
 
331
         * &nbsp;&nbsp;Float.valueOf(3.0f));
 
332
         * </code>
 
333
         * 
 
334
         * <p>
 
335
         * Example of specifying all toolbar buttons to have corner radius of 0
 
336
         * pixels:
 
337
         * </p>
 
338
         * <code>
 
339
         * UIManager.put(SubstanceLookAndFeel.CORNER_RADIUS, Float.valueOf(0.0f));
 
340
         * </code>
 
341
         * 
 
342
         * @since version 3.0
 
343
         */
 
344
        public static final String CORNER_RADIUS = "substancelaf.cornerRadius";
 
345
 
 
346
        /**
 
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.
 
351
         * 
 
352
         * <p>
 
353
         * Example how to mark a button to appear flat:
 
354
         * </p>
 
355
         * 
 
356
         * <code>
 
357
         * JButton button = new JButton("text");<br>
 
358
         * button.putClientProperty(SubstanceLookAndFeel.FLAT_PROPERTY, <br>
 
359
         * &nbsp;&nbsp;Boolean.TRUE);
 
360
         * </code>
 
361
         * 
 
362
         * @since version 3.0
 
363
         * @see #BUTTON_PAINT_NEVER_PROPERTY
 
364
         */
 
365
        public static final String FLAT_PROPERTY = "substancelaf.componentFlat";
 
366
 
 
367
        /**
 
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:
 
372
         * 
 
373
         * <p>
 
374
         * <code>
 
375
         * -Dsubstancelaf.heapStatusTraceFile=C:/temp/myApp.heap.log
 
376
         * </code>
 
377
         * </p>
 
378
         * 
 
379
         * @since version 5.0
 
380
         */
 
381
        public static final String HEAP_STATUS_TRACE_FILE = "substancelaf.heapStatusTraceFile";
 
382
 
 
383
        /**
 
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:
 
387
         * <p>
 
388
         * <ul>
 
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>
 
400
         * </ul>
 
401
         * </p>
 
402
         * <p>
 
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.
 
410
         * </p>
 
411
         * 
 
412
         * <p>
 
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.
 
418
         * </p>
 
419
         * 
 
420
         * <code>
 
421
         * public class Changer extends JFrame {<br>
 
422
         * &nbsp;&nbsp;public Changer() {<br>
 
423
         * &nbsp;&nbsp;&nbsp;&nbsp;super("Changer");<br>
 
424
         * <br>
 
425
         * &nbsp;&nbsp;&nbsp;&nbsp;this.setLayout(new BorderLayout());<br>
 
426
         * &nbsp;&nbsp;&nbsp;&nbsp;JTextPane textArea = new JTextPane();<br>
 
427
         * &nbsp;&nbsp;&nbsp;&nbsp;this.add(textArea, BorderLayout.CENTER);<br>
 
428
         * &nbsp;&nbsp;&nbsp;&nbsp;textArea.getDocument().addDocumentListener(new
 
429
         * DocumentListener() {<br>
 
430
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private void handleChange() {<br>
 
431
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getRootPane().putClientProperty(<br>
 
432
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SubstanceLookAndFeel.WINDOW_MODIFIED,
 
433
         * Boolean.TRUE);<br>
 
434
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
 
435
         * <br>
 
436
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void
 
437
         * changedUpdate(DocumentEvent e) {<br>
 
438
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handleChange();<br>
 
439
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
 
440
         * <br>
 
441
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void
 
442
         * insertUpdate(DocumentEvent e) {<br>
 
443
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handleChange();<br>
 
444
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
 
445
         * <br>
 
446
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void
 
447
         * removeUpdate(DocumentEvent e) {<br>
 
448
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handleChange();<br>
 
449
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
 
450
         * &nbsp;&nbsp;&nbsp;&nbsp;});<br>
 
451
         * &nbsp;&nbsp;&nbsp;&nbsp;<br>
 
452
         * &nbsp;&nbsp;&nbsp;&nbsp;JPanel buttons = new JPanel(new
 
453
         * FlowLayout(FlowLayout.RIGHT));<br>
 
454
         * &nbsp;&nbsp;&nbsp;&nbsp;JButton saveButton = new JButton("Save");<br>
 
455
         * &nbsp;&nbsp;&nbsp;&nbsp;saveButton.addActionListener(new ActionListener() {<br>
 
456
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void
 
457
         * actionPerformed(ActionEvent e) {<br>
 
458
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getRootPane().putClientProperty(<br>
 
459
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SubstanceLookAndFeel.WINDOW_MODIFIED,
 
460
         * Boolean.FALSE);<br>
 
461
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
 
462
         * &nbsp;&nbsp;&nbsp;&nbsp;});<br>
 
463
         * &nbsp;&nbsp;&nbsp;&nbsp;<br>
 
464
         * &nbsp;&nbsp;&nbsp;&nbsp;buttons.add(saveButton);<br>
 
465
         * &nbsp;&nbsp;&nbsp;&nbsp;this.add(buttons, BorderLayout.SOUTH);<br>
 
466
         * &nbsp;&nbsp;&nbsp;&nbsp;<br>
 
467
         * &nbsp;&nbsp;&nbsp;&nbsp;this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br>
 
468
         * &nbsp;&nbsp;}<br>
 
469
         * <br>
 
470
         * &nbsp;&nbsp;public static void main(String ... args) {<br>
 
471
         * &nbsp;&nbsp;&nbsp;&nbsp;try {<br>
 
472
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UIManager.setLookAndFeel(new
 
473
         * SubstanceLookAndFeel());<br>
 
474
         * &nbsp;&nbsp;&nbsp;&nbsp;}<br>
 
475
         * &nbsp;&nbsp;&nbsp;&nbsp;catch (Exception exc) {}<br>
 
476
         * &nbsp;&nbsp;&nbsp;&nbsp;JFrame.setDefaultLookAndFeelDecorated(true);<br>
 
477
         * &nbsp;&nbsp;&nbsp;&nbsp;Changer ch = new Changer();<br>
 
478
         * &nbsp;&nbsp;&nbsp;&nbsp;ch.setPreferredSize(new Dimension(200, 200));<br>
 
479
         * &nbsp;&nbsp;&nbsp;&nbsp;ch.setSize(ch.getPreferredSize());<br>
 
480
         * &nbsp;&nbsp;&nbsp;&nbsp;ch.setLocationRelativeTo(null);<br>
 
481
         * &nbsp;&nbsp;&nbsp;&nbsp;ch.setVisible(true);<br>
 
482
         * &nbsp;&nbsp;}<br> }
 
483
         * </code>
 
484
         * 
 
485
         * @since version 2.1
 
486
         */
 
487
        public final static String WINDOW_MODIFIED = "windowModified";
 
488
 
 
489
    /**
 
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.
 
496
     * </p>
 
497
     *
 
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
 
504
     * be toggled.</p>
 
505
     *
 
506
     * <code>
 
507
         * UIManager.put(SubstanceLookAndFeel.WINDOW_AUTO_DEACTIVATE, <br>
 
508
         * &nbsp;&nbsp;Boolean.TRUE);<br>
 
509
     * </code>
 
510
     *
 
511
     * @since version 6.3
 
512
     */
 
513
    public final static String WINDOW_AUTO_DEACTIVATE = "windowAutoDeactivate";
 
514
 
 
515
    /**
 
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.
 
525
     * </p>
 
526
     *
 
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.
 
529
     *
 
530
     * <p>
 
531
     * <code>
 
532
     * -Dsubstancelaf.windowRoundedCorners=False
 
533
     * </code>
 
534
     * </p>
 
535
     *
 
536
     * @since version 7.1
 
537
     */
 
538
    public final static String WINDOW_ROUNDED_CORNERS_PROPERTY = "substancelaf.windowRoundedCorners";
 
539
 
 
540
    /**
 
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.
 
548
     * </p>
 
549
     *
 
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.
 
552
     *
 
553
     * <code>
 
554
     * UIManager.put(SubstanceLookAndFeel.WINDOW_ROUNDED_CORNERS, <br>
 
555
     * &nbsp;&nbsp;Boolean.FALSE);<br>
 
556
     * // OR <br/>
 
557
     * someFrameOrDialog.putClientProperty(SubstanceLookAndFeel.WINDOW_ROUNDED_CORNERS, <br>
 
558
     * &nbsp;&nbsp;Boolean.FALSE);<br>
 
559
     * // for specific JInternalFrames, JFrames, or JDialogs
 
560
     *
 
561
     * </code>
 
562
     *
 
563
     * @since version 7.1
 
564
     */
 
565
    public final static String WINDOW_ROUNDED_CORNERS = "windowRoundedCorners";
 
566
 
 
567
        /**
 
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.
 
573
         * 
 
574
         * <p>
 
575
         * Example of setting that all tabs in the application will have close
 
576
         * buttons:
 
577
         * </p>
 
578
         * <code>
 
579
         * UIManager.put(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_PROPERTY, <br>
 
580
         * &nbsp;&nbsp;Boolean.TRUE);
 
581
         * </code>
 
582
         * 
 
583
         * <p>
 
584
         * A more complex example:
 
585
         * </p>
 
586
         * <code>
 
587
         * UIManager.put(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_PROPERTY, <br>
 
588
         * &nbsp;&nbsp;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
         * &nbsp;&nbsp;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
         * &nbsp;&nbsp;Boolean.TRUE);<br>
 
600
         * jtpSecondary.addTab(tab1);<br>
 
601
         * jtpSecondary.addTab(tab2);
 
602
         * </code>
 
603
         * 
 
604
         * <p>
 
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
 
612
         * parent setting).
 
613
         * </p>
 
614
         * 
 
615
         * @since version 2.1
 
616
         * @see #TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION
 
617
         * @see #TABBED_PANE_CLOSE_CALLBACK
 
618
         */
 
619
        public final static String TABBED_PANE_CLOSE_BUTTONS_PROPERTY = "substancelaf.tabbedpanehasclosebuttons";
 
620
 
 
621
        /**
 
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.
 
630
         * 
 
631
         * <p>
 
632
         * Example of setting that all tabs in the application will have modified
 
633
         * animation on close button:
 
634
         * </p>
 
635
         * <code>
 
636
         * UIManager.put(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION, <br>
 
637
         * &nbsp;&nbsp;Boolean.TRUE);
 
638
         * </code>
 
639
         * 
 
640
         * <p>
 
641
         * A more complex example:
 
642
         * </p>
 
643
         * <code>
 
644
         * UIManager.put(SubstanceLookAndFeel.TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION, <br>
 
645
         * &nbsp;&nbsp;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
         * &nbsp;&nbsp;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
         * &nbsp;&nbsp;Boolean.TRUE);<br>
 
657
         * jtpSecondary.addTab(tab1);<br>
 
658
         * jtpSecondary.addTab(tab2);
 
659
         * </code>
 
660
         * 
 
661
         * <p>
 
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).
 
670
         * </p>
 
671
         * 
 
672
         * @since version 2.2
 
673
         * @see #TABBED_PANE_CLOSE_BUTTONS_PROPERTY
 
674
         * @see #TABBED_PANE_CLOSE_CALLBACK
 
675
         */
 
676
        public final static String TABBED_PANE_CLOSE_BUTTONS_MODIFIED_ANIMATION = "substancelaf.tabbedpaneclosebuttonsmodifiedanimation";
 
677
 
 
678
        /**
 
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}
 
685
         * property.
 
686
         * 
 
687
         * <p>
 
688
         * Example of custom tab close callback set on a tabbed pane:
 
689
         * </p>
 
690
         * <code>
 
691
         * TabCloseCallback closeCallback = new TabCloseCallback() {<br>
 
692
         * &nbsp;&nbsp;public TabCloseKind onAreaClick(JTabbedPane tabbedPane,<br>
 
693
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int tabIndex, MouseEvent mouseEvent) {<br>
 
694
         * &nbsp;&nbsp;&nbsp;&nbsp;if (mouseEvent.getButton() != MouseEvent.BUTTON3)<br>
 
695
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return TabCloseKind.NONE;<br>
 
696
         * &nbsp;&nbsp;&nbsp;&nbsp;if (mouseEvent.isShiftDown()) {<br>
 
697
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return TabCloseKind.ALL;<br>
 
698
         * &nbsp;&nbsp;&nbsp;&nbsp;}<br>
 
699
         * &nbsp;&nbsp;&nbsp;&nbsp;return TabCloseKind.THIS;<br>
 
700
         * &nbsp;&nbsp;}<br>
 
701
         * <br>
 
702
         * &nbsp;&nbsp;public TabCloseKind onCloseButtonClick(JTabbedPane tabbedPane,<br>
 
703
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int tabIndex, MouseEvent mouseEvent) {<br>
 
704
         * &nbsp;&nbsp;&nbsp;&nbsp;if (mouseEvent.isAltDown()) {<br>
 
705
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return TabCloseKind.ALL_BUT_THIS;<br>
 
706
         * &nbsp;&nbsp;&nbsp;&nbsp;}<br>
 
707
         * &nbsp;&nbsp;&nbsp;&nbsp;if (mouseEvent.isShiftDown()) {<br>
 
708
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return TabCloseKind.ALL;<br>
 
709
         * &nbsp;&nbsp;&nbsp;&nbsp;}<br>
 
710
         * &nbsp;&nbsp;&nbsp;&nbsp;return TabCloseKind.THIS;<br>
 
711
         * &nbsp;&nbsp;}<br>
 
712
         * <br>
 
713
         * &nbsp;&nbsp;public String getAreaTooltip(JTabbedPane tabbedPane, int tabIndex) {<br>
 
714
         * &nbsp;&nbsp;&nbsp;&nbsp;return null;<br>
 
715
         * &nbsp;&nbsp;}<br>
 
716
         * <br>
 
717
         * &nbsp;&nbsp;public String getCloseButtonTooltip(JTabbedPane tabbedPane,<br>
 
718
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int tabIndex) {<br>
 
719
         * &nbsp;&nbsp;&nbsp;&nbsp;StringBuffer result = new StringBuffer();<br>
 
720
         * &nbsp;&nbsp;&nbsp;&nbsp;result.append("&lt;html&gt;&lt;body&gt;");<br>
 
721
         * &nbsp;&nbsp;&nbsp;&nbsp;result.append("Mouse click closes &lt;b&gt;"<br>
 
722
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ tabbedPane.getTitleAt(tabIndex) + "&lt;/b&gt; tab");<br>
 
723
         * &nbsp;&nbsp;&nbsp;&nbsp;result.append("&lt;br&gt;&lt;b&gt;Alt&lt;/b&gt;-Mouse click closes all tabs but &lt;b&gt;"<br>
 
724
         * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ tabbedPane.getTitleAt(tabIndex) + "&lt;/b&gt; tab");<br>
 
725
         * &nbsp;&nbsp;&nbsp;&nbsp;result.append("&lt;br&gt;&lt;b&gt;Shift&lt;/b&gt;-Mouse click closes all tabs");<br>
 
726
         * &nbsp;&nbsp;&nbsp;&nbsp;result.append("&lt;/body&gt;&lt;/html&gt;");<br>
 
727
         * &nbsp;&nbsp;&nbsp;&nbsp;return result.toString();<br>
 
728
         * &nbsp;&nbsp;}<br>
 
729
         * };<br>
 
730
         * 
 
731
         * JTabbedPane jtp = new JTabbedPane();<br>
 
732
         * jtp.putClientProperty(<br>
 
733
         * &nbsp;&nbsp;&nbsp;&nbsp;SubstanceLookAndFeel.TABBED_PANE_CLOSE_CALLBACK, <br>
 
734
         * &nbsp;&nbsp;&nbsp;&nbsp;closeCallback);
 
735
         * </code>
 
736
         * 
 
737
         * @since version 2.3
 
738
         */
 
739
        public final static String TABBED_PANE_CLOSE_CALLBACK = "substancelaf.tabbedpanecloseCallback";
 
740
 
 
741
        /**
 
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
 
746
         * border kind is
 
747
         * {@link SubstanceConstants.TabContentPaneBorderKind#DOUBLE_FULL}.
 
748
         * 
 
749
         * <p>
 
750
         * Example of setting that all tabbed panes in the application have single
 
751
         * full border (default setting prior to version 4.1):
 
752
         * </p>
 
753
         * <code>
 
754
         * UIManager.put(SubstanceLookAndFeel.TABBED_PANE_CONTENT_BORDER_KIND, <br>
 
755
         * &nbsp;&nbsp;TabContentPaneBorderKind.SINGLE_FULL);
 
756
         * </code>
 
757
         * 
 
758
         * <p>
 
759
         * Example of specifying that the specific tabbed pane has single full
 
760
         * border (default setting prior to version 4.1):
 
761
         * </p>
 
762
         * <code>
 
763
         * JTabbedPane jtpMain = new JTabbedPane();<br>
 
764
         * jtpMain.putClientProperty(SubstanceLookAndFeel.TABBED_PANE_CONTENT_BORDER_KIND, <br>
 
765
         * &nbsp;&nbsp;TabContentPaneBorderKind.SINGLE_FULL);
 
766
         * </code>
 
767
         * 
 
768
         * @since version 4.1
 
769
         */
 
770
        public final static String TABBED_PANE_CONTENT_BORDER_KIND = "substancelaf.tabbedPaneContentBorderKind";
 
771
 
 
772
 
 
773
        /**
 
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.
 
778
         * 
 
779
         * <p>
 
780
         * Example of setting that all tabbed panes should not rotate the tabs:
 
781
         * </p>
 
782
         * <code>
 
783
         * UIManager.put(SubstanceLookAndFeel.TABBED_PANE_ROTATE_SIDE_TABS, <br>
 
784
         * &nbsp;&nbsp;Boolean.FALSE);
 
785
         * </code>
 
786
         * 
 
787
         * <p>
 
788
         * Example of specifying that the specific tabbed pane tabbed panes should not rotate the tabs:
 
789
         * </p>
 
790
         * <code>
 
791
         * JTabbedPane jtpMain = new JTabbedPane();<br>
 
792
         * jtpMain.putClientProperty(SubstanceLookAndFeel.TABBED_PANE_ROTATE_SIDE_TABS, <br>
 
793
         * &nbsp;&nbsp;Boolean.FALSE);
 
794
         * </code>
 
795
         * 
 
796
         * @since version 7.2
 
797
         */
 
798
        public final static String TABBED_PANE_ROTATE_SIDE_TABS = "substancelaf.rotate";
 
799
 
 
800
        /**
 
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.
 
804
     *
 
805
     * <p>
 
806
     * <ul>
 
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.
 
810
     * </ul>
 
811
     * </p>
 
812
 
 
813
         * <code>
 
814
         * JTable jtable = new JTable();<br>
 
815
         * jtable.putClientProperty(SubstanceLookAndFeel.TABLE_LEADING_VERTICAL_LINE, <br>
 
816
         * &nbsp;&nbsp;false);
 
817
         * </code>
 
818
         *
 
819
         * @since version 7.2
 
820
         */
 
821
        public final static String TABLE_LEADING_VERTICAL_LINE = "substancelaf.tableLeadingVerticalLine";
 
822
 
 
823
        /**
 
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
 
827
     *
 
828
     * <p>
 
829
     * <ul>
 
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.
 
833
     * </ul>
 
834
     * </p>
 
835
 
 
836
         * <code>
 
837
         * JTable jtable = new JTable();<br>
 
838
         * jtable.putClientProperty(SubstanceLookAndFeel.TABLE_TRAILING_VERTICAL_LINE, <br>
 
839
         * &nbsp;&nbsp;false);
 
840
         * </code>
 
841
         *
 
842
         * @since version 7.2
 
843
         */
 
844
        public final static String TABLE_TRAILING_VERTICAL_LINE = "substancelaf.tableTrailingVerticalLine";
 
845
 
 
846
        /**
 
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:
 
850
         * 
 
851
         * <p>
 
852
         * <ul>
 
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.
 
863
         * </ul>
 
864
         * </p>
 
865
         * 
 
866
         * <p>
 
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
 
869
         * orientation:
 
870
         * </p>
 
871
         * <code>
 
872
         * JComboBox cb = new JComboBox(<br>
 
873
         * &nbsp;&nbsp;new Object[] { "Ester", "Jordi", "Jordina", "Jorge", "Sergi" });<br>
 
874
         * cb.putClientProperty(SubstanceLookAndFeel.COMBO_BOX_POPUP_FLYOUT_ORIENTATION, <br>
 
875
         * &nbsp;&nbsp;SwingConstants.CENTER);
 
876
         * </code>
 
877
         * 
 
878
         * @since version 2.3
 
879
         * @see #COMBO_POPUP_PROTOTYPE
 
880
         */
 
881
        public final static String COMBO_BOX_POPUP_FLYOUT_ORIENTATION = "substancelaf.comboboxpopupFlyoutOrientation";
 
882
 
 
883
        /**
 
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:
 
889
         * 
 
890
         * <p>
 
891
         * <code>
 
892
         * JScrollPane jsp = new JScrollPane(new JPanel());<br>
 
893
         * jsp.putClientProperty(SubstanceLookAndFeel.SCROLL_PANE_BUTTONS_POLICY,<br>
 
894
         * &nbsp;&nbsp;ScrollPaneButtonPolicyKind.MULTIPLE);
 
895
         * </code>
 
896
         * 
 
897
         * @since version 3.1
 
898
         */
 
899
        public final static String SCROLL_PANE_BUTTONS_POLICY = "substancelaf.scrollPaneButtonsPolicy";
 
900
 
 
901
        /**
 
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}.
 
907
         * 
 
908
         * <p>
 
909
         * Example of setting this property on {@link UIManager}:
 
910
         * </p>
 
911
         * <code>
 
912
         * UIManager.put(SubstanceLookAndFeel.SHOW_EXTRA_WIDGETS, Boolean.TRUE);
 
913
         * SwingUtilities.updateComponentTree(myFrame);
 
914
         * </code>
 
915
         * 
 
916
         * @since version 5.0
 
917
         */
 
918
        public final static String SHOW_EXTRA_WIDGETS = "substancelaf.addWidgets";
 
919
 
 
920
        /**
 
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}.
 
926
         * 
 
927
         * <p>
 
928
         * Example of setting soft fill kind:
 
929
         * </p>
 
930
         * <code>
 
931
         * UIManager.put(SubstanceLookAndFeel.MENU_GUTTER_FILL_KIND, MenuGutterFillKind.SOFT);
 
932
         * </code>
 
933
         * 
 
934
         * @since version 3.2
 
935
         */
 
936
        public final static String MENU_GUTTER_FILL_KIND = "substancelaf.menuGutterFillKind";
 
937
 
 
938
        /**
 
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
 
943
         * {@link UIManager}.
 
944
         * 
 
945
         * <p>
 
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:
 
953
         * </p>
 
954
         * 
 
955
         * <code>
 
956
         * &nbsp;&nbsp;JPanel topPanel = new JPanel();<br>
 
957
         * &nbsp;&nbsp;topPanel.putClientProperty(SubstanceLookAndFeel.FOCUS_KIND, FocusKind.UNDERLINE);<br>
 
958
         * &nbsp;&nbsp;JPanel panel1 = new JPanel();<br>
 
959
         * &nbsp;&nbsp;JButton b1 = new JButton("button1");<br>
 
960
         * &nbsp;&nbsp;b1.putClientProperty(SubstanceLookAndFeel.FOCUS_KIND, FocusKind.TEXT);<br>
 
961
         * &nbsp;&nbsp;JButton b2 = new JButton("button2");<br>
 
962
         * &nbsp;&nbsp;JButton b3 = new JButton("button3");<br>
 
963
         * &nbsp;&nbsp;b3.putClientProperty(SubstanceLookAndFeel.FOCUS_KIND, FocusKind.ALL_INNER);<br>
 
964
         * &nbsp;&nbsp;panel1.add(b1);<br>
 
965
         * &nbsp;&nbsp;panel1.add(b2);<br>
 
966
         * &nbsp;&nbsp;topPanel.add(panel1);<br>
 
967
         * &nbsp;&nbsp;topPanel.add(b3);<br>
 
968
         * </code>
 
969
         * 
 
970
         * <p>
 
971
         * In the code above:
 
972
         * </p>
 
973
         * <ul>
 
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.
 
982
         * </ul>
 
983
         * 
 
984
         * @since 2.2
 
985
         * @see SubstanceConstants.FocusKind
 
986
         */
 
987
        public final static String FOCUS_KIND = "substancelaf.focusKind";
 
988
 
 
989
        /**
 
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:
 
993
         * 
 
994
         * <p>
 
995
         * <ul>
 
996
         * <li>{@link ComboPopupPrototypeCallback} - will provide
 
997
         * application-specific logic at runtime.
 
998
         * <li>{@link Object} - will point to the prototype entry itself.
 
999
         * </ul>
 
1000
         * </p>
 
1001
         * 
 
1002
         * <p>
 
1003
         * This property can be set either on a specific {@link JComboBox} or
 
1004
         * globally on {@link UIManager}.
 
1005
         * </p>
 
1006
         * 
 
1007
         * <p>
 
1008
         * Here is an example of combo popup prototype set to a model element:
 
1009
         * </p>
 
1010
         * <code>
 
1011
         *      JComboBox comboProto1 = new JComboBox(new Object[] { "aa", "aaaaa",<br>
 
1012
         *      &nbsp;&nbsp;"aaaaaaaaaa", "this one is the one", "aaaaaaaaaaaaaaaaaaaaa" });<br>
 
1013
         *      comboProto1.setPrototypeDisplayValue("aaaaa");<br>
 
1014
         *      comboProto1.putClientProperty(SubstanceLookAndFeel.COMBO_POPUP_PROTOTYPE,<br>
 
1015
         *      &nbsp;&nbsp;"this one is the one");
 
1016
         * </code>
 
1017
         * 
 
1018
         * <p>
 
1019
         * Here is an example of combo popup prototype set to a dynamic callback.
 
1020
         * This callback always returns the last model element:
 
1021
         * </p>
 
1022
         * <code>
 
1023
         *  JComboBox comboProto3 = new JComboBox(new Object[] { "aa", "aaaaa",<br>
 
1024
         *      &nbsp;&nbsp;"this is not", "this one is not it",<br>
 
1025
         *      &nbsp;&nbsp;"this one is it that is for the popup" });<br>
 
1026
         *      comboProto3.setPrototypeDisplayValue("aaaaa");<br>
 
1027
         *      comboProto3.putClientProperty(SubstanceLookAndFeel.COMBO_POPUP_PROTOTYPE,<br>
 
1028
         *      &nbsp;&nbsp;new ComboPopupPrototypeCallback() {<br>
 
1029
         *      &nbsp;&nbsp;&nbsp;&nbsp;public Object getPopupPrototypeDisplayValue(JComboBox jc) {<br>
 
1030
         *      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return jc.getModel().getElementAt(<br>
 
1031
         *      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jc.getModel().getSize() - 1);<br>
 
1032
         *      &nbsp;&nbsp;&nbsp;&nbsp;}<br>
 
1033
         *      &nbsp;&nbsp;});
 
1034
         *  </code>
 
1035
         * 
 
1036
         * @since version 3.0
 
1037
         * @see #COMBO_BOX_POPUP_FLYOUT_ORIENTATION
 
1038
         */
 
1039
        public final static String COMBO_POPUP_PROTOTYPE = "substancelaf.comboPopupPrototype";
 
1040
 
 
1041
        /**
 
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:
 
1046
         * 
 
1047
         * <p>
 
1048
         * <code>
 
1049
         * -Dsubstancelaf.traceFile=C:/temp/myApp.substance.log
 
1050
         * </code>
 
1051
         * </p>
 
1052
         * 
 
1053
         * @since version 2.0
 
1054
         */
 
1055
        public final static String TRACE_FILE = "substancelaf.traceFile";
 
1056
 
 
1057
        /**
 
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}.
 
1063
         * 
 
1064
         * <p>
 
1065
         * Example of having all password fields echo 3 characters per each typed
 
1066
         * user character:
 
1067
         * </p>
 
1068
         * <code>
 
1069
         * UIManager.put(SubstanceLookAndFeel.PASSWORD_ECHO_PER_CHAR, <br>
 
1070
         * &nbsp;&nbsp;new Integer(3));
 
1071
         * </code>
 
1072
         * 
 
1073
         * <p>
 
1074
         * Example of having a specific password field echo 2 characters per each
 
1075
         * typed user character:
 
1076
         * </p>
 
1077
         * <code>
 
1078
         * JPasswordField jpf = new JPasswordField();<br>
 
1079
         * jpf.putClientProperty(SubstanceLookAndFeel.PASSWORD_ECHO_PER_CHAR, <br>
 
1080
         * &nbsp;&nbsp;new Integer(2));
 
1081
         * </code>
 
1082
         * 
 
1083
         * @since version 2.2
 
1084
         */
 
1085
        public final static String PASSWORD_ECHO_PER_CHAR = "substancelaf.passwordEchoPerChar";
 
1086
 
 
1087
        /**
 
1088
         * <p>
 
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}.
 
1096
         * </p>
 
1097
         * 
 
1098
         * @since version 3.3
 
1099
         */
 
1100
        public final static String USE_THEMED_DEFAULT_ICONS = "substancelaf.useThemedDefaultIcons";
 
1101
 
 
1102
        /**
 
1103
         * <p>
 
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.
 
1112
         * </p>
 
1113
         * 
 
1114
         * <p>
 
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
 
1121
         * check mark.
 
1122
         * </p>
 
1123
         * 
 
1124
         * <p>
 
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.
 
1133
         * </p>
 
1134
         * 
 
1135
         * <p>
 
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.
 
1140
         * </p>
 
1141
         * 
 
1142
         * <p>
 
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.
 
1147
         * </p>
 
1148
         * 
 
1149
         * <p>
 
1150
         * The value should be an instance of {@link Double} in 0.0-1.0 range.
 
1151
         * </p>
 
1152
         * 
 
1153
         * <p>
 
1154
         * Example of marking a button to have a custom background color and
 
1155
         * colorizing it with 40%:
 
1156
         * </p>
 
1157
         * <code>
 
1158
         * JButton jb = new JButton("sample", myIcon);<br>
 
1159
         * jb.setBackground(Color.red);<br>
 
1160
         * jb.putClientProperty(SubstanceLookAndFeel.COLORIZATION_FACTOR, <br>
 
1161
         * &nbsp;&nbsp;new Double(0.4));
 
1162
         * </code>
 
1163
         * 
 
1164
         * <p>
 
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.
 
1169
         * </p>
 
1170
         * 
 
1171
         * @since version 4.2
 
1172
         * @see Component#setBackground(Color)
 
1173
         * @see Component#setForeground(Color)
 
1174
         */
 
1175
        public final static String COLORIZATION_FACTOR = "substancelaf.colorizationFactor";
 
1176
 
 
1177
        /**
 
1178
         * Internal client property name for storing application-specific font
 
1179
         * policy.
 
1180
         * 
 
1181
         * @since version 3.3
 
1182
         * @see #setFontPolicy(FontPolicy)
 
1183
         * @see #getFontPolicy()
 
1184
         */
 
1185
        protected final static String SUBSTANCE_FONT_POLICY_KEY = "substancelaf.fontPolicyKey";
 
1186
 
 
1187
        /**
 
1188
         * Internal client property name for storing application-specific input map
 
1189
         * set.
 
1190
         * 
 
1191
         * @since version 6.1
 
1192
         * @see #setInputMapSet(InputMapSet)
 
1193
         * @see #getInputMapSet()
 
1194
         */
 
1195
        protected final static String SUBSTANCE_INPUT_MAP_SET_KEY = "substancelaf.inputMapSetKey";
 
1196
 
 
1197
        /**
 
1198
         * Property name for specifying outline shaper. This property is used a
 
1199
         * client property that can be set on a specific control.
 
1200
         * 
 
1201
         * <p>
 
1202
         * The value must be a {@link SubstanceButtonShaper} object.
 
1203
         * </p>
 
1204
         * 
 
1205
         * <p>
 
1206
         * Example of using a {@link SubstanceButtonShaper} object as client
 
1207
         * property value:
 
1208
         * </p>
 
1209
         * <code>
 
1210
         * JButton b = new JButton("text");<br>
 
1211
         * b.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, <br>
 
1212
         * &nbsp;&nbsp;new ClassicButtonShaper());
 
1213
         * </code>
 
1214
         * 
 
1215
         * @since version 2.1
 
1216
         */
 
1217
        public static final String BUTTON_SHAPER_PROPERTY = "substancelaf.buttonShaper";
 
1218
 
 
1219
        /**
 
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
 
1225
         * window.
 
1226
         * 
 
1227
         * @since version 5.0
 
1228
         * @see #getCurrentSkin(Component)
 
1229
         */
 
1230
        public static final String SKIN_PROPERTY = "substancelaf.skin";
 
1231
 
 
1232
        /**
 
1233
         * Resource bundle for <b>Substance</b> labels.
 
1234
         */
 
1235
        private static ResourceBundle LABEL_BUNDLE = null;
 
1236
 
 
1237
        /**
 
1238
         * Class loader for {@link #LABEL_BUNDLE}.
 
1239
         */
 
1240
        private static ClassLoader labelBundleClassLoader;
 
1241
 
 
1242
        /**
 
1243
         * The skin of this look-and-feel instance.
 
1244
         */
 
1245
        protected SubstanceSkin skin;
 
1246
 
 
1247
        /**
 
1248
         * The name of this look-and-feel instance.
 
1249
         */
 
1250
        protected String name;
 
1251
 
 
1252
        /**
 
1253
         * Creates a new skin-based Substance look-and-feel. This is the only way to
 
1254
         * create an instance of {@link SubstanceLookAndFeel} class.
 
1255
         * 
 
1256
         * @param skin
 
1257
         *            Skin.
 
1258
         */
 
1259
        protected SubstanceLookAndFeel(SubstanceSkin skin) {
 
1260
                this.skin = skin;
 
1261
                this.name = "Substance " + skin.getDisplayName();
 
1262
 
 
1263
                initPluginsIfNecessary();
 
1264
        }
 
1265
 
 
1266
        /**
 
1267
         * Initializes the plugins if necessary.
 
1268
         */
 
1269
        protected static void initPluginsIfNecessary() {
 
1270
                if (SubstanceLookAndFeel.skinPlugins != null)
 
1271
                        return;
 
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);
 
1277
        }
 
1278
 
 
1279
        /**
 
1280
         * Retrieves the current label bundle.
 
1281
         * 
 
1282
         * @return The current label bundle.
 
1283
         * @see #resetLabelBundle()
 
1284
         */
 
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
 
1289
                        // in applets)
 
1290
                        if (SubstanceLookAndFeel.labelBundleClassLoader == null) {
 
1291
                                SubstanceLookAndFeel.LABEL_BUNDLE = ResourceBundle
 
1292
                                                .getBundle(
 
1293
                                                                "org.pushingpixels.substance.internal.resources.Labels",
 
1294
                                                                Locale.getDefault());
 
1295
                        } else {
 
1296
                                SubstanceLookAndFeel.LABEL_BUNDLE = ResourceBundle
 
1297
                                                .getBundle(
 
1298
                                                                "org.pushingpixels.substance.internal.resources.Labels",
 
1299
                                                                Locale.getDefault(),
 
1300
                                                                SubstanceLookAndFeel.labelBundleClassLoader);
 
1301
                        }
 
1302
                        for (LocaleChangeListener lcl : SubstanceLookAndFeel.localeChangeListeners)
 
1303
                                lcl.localeChanged();
 
1304
                }
 
1305
                return SubstanceLookAndFeel.LABEL_BUNDLE;
 
1306
        }
 
1307
 
 
1308
        /**
 
1309
         * Retrieves the label bundle for the specified locale.
 
1310
         * 
 
1311
         * @param locale
 
1312
         *            Locale.
 
1313
         * @return The label bundle for the specified locale.
 
1314
         */
 
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
 
1318
                // in applets)
 
1319
                if (SubstanceLookAndFeel.labelBundleClassLoader == null) {
 
1320
                        return ResourceBundle.getBundle(
 
1321
                                        "org.pushingpixels.substance.internal.resources.Labels",
 
1322
                                        locale);
 
1323
                } else {
 
1324
                        return ResourceBundle.getBundle(
 
1325
                                        "org.pushingpixels.substance.internal.resources.Labels",
 
1326
                                        locale, SubstanceLookAndFeel.labelBundleClassLoader);
 
1327
                }
 
1328
        }
 
1329
 
 
1330
        /**
 
1331
         * Resets the current label bundle. Useful when the application changes
 
1332
         * Locale at runtime.
 
1333
         * 
 
1334
         * @see #getLabelBundle()
 
1335
         */
 
1336
        public static synchronized void resetLabelBundle() {
 
1337
                SubstanceLookAndFeel.LABEL_BUNDLE = null;
 
1338
                LafWidgetRepository.resetLabelBundle();
 
1339
        }
 
1340
 
 
1341
        /**
 
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)}.
 
1346
         * 
 
1347
         * @return Current global skin.
 
1348
         * @see #getCurrentSkin(Component)
 
1349
         */
 
1350
        public static SubstanceSkin getCurrentSkin() {
 
1351
                LookAndFeel current = UIManager.getLookAndFeel();
 
1352
                if (current instanceof SubstanceLookAndFeel) {
 
1353
                        return currentSkin;
 
1354
                }
 
1355
                return null;
 
1356
        }
 
1357
 
 
1358
        /**
 
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>.
 
1361
         * 
 
1362
         * @param c
 
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()
 
1368
         */
 
1369
        public static SubstanceSkin getCurrentSkin(Component c) {
 
1370
                return SubstanceCoreUtilities.getSkin(c);
 
1371
        }
 
1372
 
 
1373
        /*
 
1374
         * (non-Javadoc)
 
1375
         * 
 
1376
         * @see javax.swing.LookAndFeel#getDescription()
 
1377
         */
 
1378
        @Override
 
1379
        public String getDescription() {
 
1380
                return "Substance Look and Feel by Kirill Grouchnikov";
 
1381
        }
 
1382
 
 
1383
        /*
 
1384
         * (non-Javadoc)
 
1385
         * 
 
1386
         * @see javax.swing.LookAndFeel#getID()
 
1387
         */
 
1388
        @Override
 
1389
        public String getID() {
 
1390
                return this.name;
 
1391
        }
 
1392
 
 
1393
        /*
 
1394
         * (non-Javadoc)
 
1395
         * 
 
1396
         * @see javax.swing.LookAndFeel#getName()
 
1397
         */
 
1398
        @Override
 
1399
        public String getName() {
 
1400
                return this.name;
 
1401
        }
 
1402
 
 
1403
        /*
 
1404
         * (non-Javadoc)
 
1405
         * 
 
1406
         * @see javax.swing.LookAndFeel#isNativeLookAndFeel()
 
1407
         */
 
1408
        @Override
 
1409
        public boolean isNativeLookAndFeel() {
 
1410
                return false;
 
1411
        }
 
1412
 
 
1413
        /*
 
1414
         * (non-Javadoc)
 
1415
         * 
 
1416
         * @see javax.swing.LookAndFeel#isSupportedLookAndFeel()
 
1417
         */
 
1418
        @Override
 
1419
        public boolean isSupportedLookAndFeel() {
 
1420
                return true;
 
1421
        }
 
1422
 
 
1423
        /*
 
1424
         * (non-Javadoc)
 
1425
         * 
 
1426
         * @see
 
1427
         * javax.swing.plaf.basic.BasicLookAndFeel#initClassDefaults(javax.swing
 
1428
         * .UIDefaults)
 
1429
         */
 
1430
        @Override
 
1431
        protected void initClassDefaults(UIDefaults table) {
 
1432
                super.initClassDefaults(table);
 
1433
 
 
1434
                String UI_CLASSNAME_PREFIX = "org.pushingpixels.substance.internal.ui.Substance";
 
1435
                Object[] uiDefaults = {
 
1436
 
 
1437
                "ButtonUI", UI_CLASSNAME_PREFIX + "ButtonUI",
 
1438
 
 
1439
                "CheckBoxUI", UI_CLASSNAME_PREFIX + "CheckBoxUI",
 
1440
 
 
1441
                "ComboBoxUI", UI_CLASSNAME_PREFIX + "ComboBoxUI",
 
1442
 
 
1443
                "CheckBoxMenuItemUI", UI_CLASSNAME_PREFIX + "CheckBoxMenuItemUI",
 
1444
 
 
1445
                "DesktopIconUI", UI_CLASSNAME_PREFIX + "DesktopIconUI",
 
1446
 
 
1447
                "DesktopPaneUI", UI_CLASSNAME_PREFIX + "DesktopPaneUI",
 
1448
 
 
1449
                "EditorPaneUI",
 
1450
                                UI_CLASSNAME_PREFIX + "EditorPaneUI",
 
1451
 
 
1452
                                "FileChooserUI",
 
1453
                                UI_CLASSNAME_PREFIX + "FileChooserUI",
 
1454
 
 
1455
                                // "FileChooserUI", "javax.swing.plaf.metal.MetalFileChooserUI",
 
1456
 
 
1457
                                "FormattedTextFieldUI",
 
1458
                                UI_CLASSNAME_PREFIX + "FormattedTextFieldUI",
 
1459
 
 
1460
                                "InternalFrameUI", UI_CLASSNAME_PREFIX + "InternalFrameUI",
 
1461
 
 
1462
                                "LabelUI", UI_CLASSNAME_PREFIX + "LabelUI",
 
1463
 
 
1464
                                "ListUI", UI_CLASSNAME_PREFIX + "ListUI",
 
1465
 
 
1466
                                "MenuUI", UI_CLASSNAME_PREFIX + "MenuUI",
 
1467
 
 
1468
                                "MenuBarUI", UI_CLASSNAME_PREFIX + "MenuBarUI",
 
1469
 
 
1470
                                "MenuItemUI", UI_CLASSNAME_PREFIX + "MenuItemUI",
 
1471
 
 
1472
                                "OptionPaneUI", UI_CLASSNAME_PREFIX + "OptionPaneUI",
 
1473
 
 
1474
                                "PanelUI", UI_CLASSNAME_PREFIX + "PanelUI",
 
1475
 
 
1476
                                "PasswordFieldUI", UI_CLASSNAME_PREFIX + "PasswordFieldUI",
 
1477
 
 
1478
                                "PopupMenuUI", UI_CLASSNAME_PREFIX + "PopupMenuUI",
 
1479
 
 
1480
                                "PopupMenuSeparatorUI",
 
1481
                                UI_CLASSNAME_PREFIX + "PopupMenuSeparatorUI",
 
1482
 
 
1483
                                "ProgressBarUI", UI_CLASSNAME_PREFIX + "ProgressBarUI",
 
1484
 
 
1485
                                "RadioButtonUI", UI_CLASSNAME_PREFIX + "RadioButtonUI",
 
1486
 
 
1487
                                "RadioButtonMenuItemUI",
 
1488
                                UI_CLASSNAME_PREFIX + "RadioButtonMenuItemUI",
 
1489
 
 
1490
                                "RootPaneUI", UI_CLASSNAME_PREFIX + "RootPaneUI",
 
1491
 
 
1492
                                "ScrollBarUI", UI_CLASSNAME_PREFIX + "ScrollBarUI",
 
1493
 
 
1494
                                "ScrollPaneUI", UI_CLASSNAME_PREFIX + "ScrollPaneUI",
 
1495
 
 
1496
                                "SeparatorUI", UI_CLASSNAME_PREFIX + "SeparatorUI",
 
1497
 
 
1498
                                "SliderUI", UI_CLASSNAME_PREFIX + "SliderUI",
 
1499
 
 
1500
                                "SpinnerUI", UI_CLASSNAME_PREFIX + "SpinnerUI",
 
1501
 
 
1502
                                "SplitPaneUI", UI_CLASSNAME_PREFIX + "SplitPaneUI",
 
1503
 
 
1504
                                "TabbedPaneUI", UI_CLASSNAME_PREFIX + "TabbedPaneUI",
 
1505
 
 
1506
                                "TableUI", UI_CLASSNAME_PREFIX + "TableUI",
 
1507
 
 
1508
                                "TableHeaderUI", UI_CLASSNAME_PREFIX + "TableHeaderUI",
 
1509
 
 
1510
                                "TextAreaUI", UI_CLASSNAME_PREFIX + "TextAreaUI",
 
1511
 
 
1512
                                "TextFieldUI", UI_CLASSNAME_PREFIX + "TextFieldUI",
 
1513
 
 
1514
                                "TextPaneUI", UI_CLASSNAME_PREFIX + "TextPaneUI",
 
1515
 
 
1516
                                "ToggleButtonUI", UI_CLASSNAME_PREFIX + "ToggleButtonUI",
 
1517
 
 
1518
                                "ToolBarUI", UI_CLASSNAME_PREFIX + "ToolBarUI",
 
1519
 
 
1520
                                "ToolBarSeparatorUI",
 
1521
                                UI_CLASSNAME_PREFIX + "ToolBarSeparatorUI",
 
1522
 
 
1523
                                "ToolTipUI", UI_CLASSNAME_PREFIX + "ToolTipUI",
 
1524
 
 
1525
                                "TreeUI", UI_CLASSNAME_PREFIX + "TreeUI",
 
1526
 
 
1527
                                "ViewportUI", UI_CLASSNAME_PREFIX + "ViewportUI",
 
1528
 
 
1529
                };
 
1530
                table.putDefaults(uiDefaults);
 
1531
        }
 
1532
 
 
1533
        /*
 
1534
         * (non-Javadoc)
 
1535
         * 
 
1536
         * @see
 
1537
         * javax.swing.plaf.basic.BasicLookAndFeel#initComponentDefaults(javax.swing
 
1538
         * .UIDefaults)
 
1539
         */
 
1540
        @Override
 
1541
        protected void initComponentDefaults(UIDefaults table) {
 
1542
                super.initComponentDefaults(table);
 
1543
 
 
1544
                initFontDefaults(table);
 
1545
                this.skin.addCustomEntriesToTable(table);
 
1546
        }
 
1547
 
 
1548
        /**
 
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.
 
1553
         * 
 
1554
         * @param fontPolicy
 
1555
         *            The {@link FontPolicy} to be used with Substance family, or
 
1556
         *            <code>null</code> to reset to the default
 
1557
         * 
 
1558
         * @see #getFontPolicy()
 
1559
         * @see SubstanceLookAndFeel#SUBSTANCE_FONT_POLICY_KEY
 
1560
         */
 
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());
 
1566
        }
 
1567
 
 
1568
        /**
 
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
 
1575
         * be returned.
 
1576
         * 
 
1577
         * @return the {@link FontPolicy} set for this Look&amp;feel - if any, the
 
1578
         *         {@link FontPolicy} specified in the system properties or
 
1579
         *         {@link UIDefaults} - if any, or the default Substance font
 
1580
         *         policy.
 
1581
         * 
 
1582
         * @see #setFontPolicy(org.pushingpixels.substance.api.fonts.FontPolicy)
 
1583
         * @see FontPolicies
 
1584
         * @see FontPolicies#customSettingsPolicy(FontPolicy)
 
1585
         */
 
1586
        public static FontPolicy getFontPolicy() {
 
1587
                FontPolicy policy = (FontPolicy) UIManager
 
1588
                                .get(SUBSTANCE_FONT_POLICY_KEY);
 
1589
                if (policy != null)
 
1590
                        return policy;
 
1591
 
 
1592
                // return default policy
 
1593
                return SubstanceFontUtilities.getDefaultFontPolicy();
 
1594
        }
 
1595
 
 
1596
        /**
 
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.
 
1601
         * 
 
1602
         * @param inputMapSet
 
1603
         *            The {@link InputMapSet} to be used with Substance family, or
 
1604
         *            <code>null</code> to reset to the default
 
1605
         * 
 
1606
         * @see #getInputMapSet()
 
1607
         * @see SubstanceLookAndFeel#SUBSTANCE_INPUT_MAP_SET_KEY
 
1608
         */
 
1609
        public static void setInputMapSet(InputMapSet inputMapSet) {
 
1610
                UIManager.put(SUBSTANCE_INPUT_MAP_SET_KEY, inputMapSet);
 
1611
                SubstanceLookAndFeel.setSkin(SubstanceLookAndFeel.getCurrentSkin());
 
1612
        }
 
1613
 
 
1614
        /**
 
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.
 
1619
         * 
 
1620
         * @return the {@link InputMapSet} set for this Look&amp;feel - if any, or
 
1621
         *         the default Substance input map set.
 
1622
         * 
 
1623
         * @see #setInputMapSet(InputMapSet)
 
1624
         */
 
1625
        public static InputMapSet getInputMapSet() {
 
1626
                InputMapSet inputMapSet = (InputMapSet) UIManager
 
1627
                                .get(SUBSTANCE_INPUT_MAP_SET_KEY);
 
1628
                if (inputMapSet != null)
 
1629
                        return inputMapSet;
 
1630
 
 
1631
                // return system input map set
 
1632
                return SubstanceInputMapUtilities.getSystemInputMapSet();
 
1633
        }
 
1634
 
 
1635
        /**
 
1636
         * Looks up the correct control font and sets it for all controls.
 
1637
         * 
 
1638
         * @param table
 
1639
         *            The UI defaults table.
 
1640
         */
 
1641
        private void initFontDefaults(UIDefaults table) {
 
1642
                FontSet substanceFontSet = getFontPolicy()
 
1643
                                .getFontSet("Substance", null);
 
1644
                initFontDefaults(table, substanceFontSet);
 
1645
        }
 
1646
 
 
1647
        /**
 
1648
         * Sets Fonts in the given FontSet as defaults for all known component types
 
1649
         * in the given UIDefaults table.
 
1650
         * 
 
1651
         * @param table
 
1652
         *            the UIDefaults table used to set fonts
 
1653
         * @param fontSet
 
1654
         *            describes the set of Fonts to be installed
 
1655
         */
 
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();
 
1663
 
 
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());
 
1670
 
 
1671
                Object[] defaults = {
 
1672
 
 
1673
                "Button.font", controlFont,
 
1674
 
 
1675
                "CheckBox.font", controlFont,
 
1676
 
 
1677
                "ColorChooser.font", controlFont,
 
1678
 
 
1679
                "ComboBox.font", controlFont,
 
1680
 
 
1681
                "EditorPane.font", controlFont,
 
1682
 
 
1683
                "FormattedTextField.font", controlFont,
 
1684
 
 
1685
                "Label.font", controlFont,
 
1686
 
 
1687
                "List.font", controlFont,
 
1688
 
 
1689
                "Panel.font", controlFont,
 
1690
 
 
1691
                "PasswordField.font", controlFont,
 
1692
 
 
1693
                "ProgressBar.font", controlFont,
 
1694
 
 
1695
                "RadioButton.font", controlFont,
 
1696
 
 
1697
                "ScrollPane.font", controlFont,
 
1698
 
 
1699
                "Spinner.font", controlFont,
 
1700
 
 
1701
                "TabbedPane.font", controlFont,
 
1702
 
 
1703
                "Table.font", controlFont,
 
1704
 
 
1705
                "TableHeader.font", controlFont,
 
1706
 
 
1707
                "TextArea.font", controlFont,
 
1708
 
 
1709
                "TextField.font", controlFont,
 
1710
 
 
1711
                "TextPane.font", controlFont,
 
1712
 
 
1713
                "ToolBar.font", controlFont,
 
1714
 
 
1715
                "ToggleButton.font", controlFont,
 
1716
 
 
1717
                "Tree.font", controlFont,
 
1718
 
 
1719
                "Viewport.font", controlFont,
 
1720
 
 
1721
                "InternalFrame.titleFont", windowFont,
 
1722
 
 
1723
                "DesktopIcon.titleFont", windowFont,
 
1724
 
 
1725
                "OptionPane.font", messageFont,
 
1726
 
 
1727
                "OptionPane.messageFont", messageFont,
 
1728
 
 
1729
                "OptionPane.buttonFont", messageFont,
 
1730
 
 
1731
                "TitledBorder.font", titleFont,
 
1732
 
 
1733
                "ToolTip.font", toolTipFont,
 
1734
 
 
1735
                "CheckBoxMenuItem.font", menuFont,
 
1736
 
 
1737
                "CheckBoxMenuItem.acceleratorFont", menuFont,
 
1738
 
 
1739
                "Menu.font", menuFont,
 
1740
 
 
1741
                "Menu.acceleratorFont", menuFont,
 
1742
 
 
1743
                "MenuBar.font", menuFont,
 
1744
 
 
1745
                "MenuItem.font", menuFont,
 
1746
 
 
1747
                "MenuItem.acceleratorFont", menuFont,
 
1748
 
 
1749
                "PopupMenu.font", menuFont,
 
1750
 
 
1751
                "RadioButtonMenuItem.font", menuFont,
 
1752
 
 
1753
                "RadioButtonMenuItem.acceleratorFont", menuFont,
 
1754
                // ?
 
1755
                };
 
1756
                table.putDefaults(defaults);
 
1757
        }
 
1758
 
 
1759
        /*
 
1760
         * (non-Javadoc)
 
1761
         * 
 
1762
         * @see javax.swing.plaf.basic.BasicLookAndFeel#getDefaults()
 
1763
         */
 
1764
        @Override
 
1765
        public UIDefaults getDefaults() {
 
1766
                UIDefaults table = super.getDefaults();
 
1767
 
 
1768
                SubstanceLookAndFeel.componentPlugins.processAllDefaultsEntries(table,
 
1769
                                this.skin);
 
1770
                return table;
 
1771
        }
 
1772
 
 
1773
        /*
 
1774
         * (non-Javadoc)
 
1775
         * 
 
1776
         * @see javax.swing.plaf.basic.BasicLookAndFeel#initialize()
 
1777
         */
 
1778
        @Override
 
1779
        public void initialize() {
 
1780
                super.initialize();
 
1781
                ShadowPopupFactory.install();
 
1782
 
 
1783
                setSkin(this.skin, false);
 
1784
 
 
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() + "'");
 
1794
                }
 
1795
 
 
1796
                // to show heap status panel in title pane?
 
1797
                String heapStatusPanelParam = SubstanceCoreUtilities
 
1798
                                .getVmParameter(SubstanceLookAndFeel.HEAP_STATUS_TRACE_FILE);
 
1799
                SubstanceTitlePane.setHeapStatusLogfileName(heapStatusPanelParam);
 
1800
 
 
1801
                // initialize component plugins
 
1802
                SubstanceLookAndFeel.componentPlugins.initializeAll();
 
1803
 
 
1804
                // initialize widget support
 
1805
                LafWidgetRepository.getRepository().setLafSupport(
 
1806
                                new SubstanceWidgetSupport());
 
1807
 
 
1808
                // fix for defect 208 - tracking changes to focus owner
 
1809
                // and repainting the default button
 
1810
                this.focusOwnerChangeListener = new PropertyChangeListener() {
 
1811
                        @Override
 
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)
 
1819
                                                        return;
 
1820
                                                JButton defaultButton = rootPane.getDefaultButton();
 
1821
                                                if (defaultButton == null)
 
1822
                                                        return;
 
1823
                                                defaultButton.repaint();
 
1824
                                        }
 
1825
                                }
 
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);
 
1835
                                        }
 
1836
                                }
 
1837
                        }
 
1838
                };
 
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);
 
1846
                }
 
1847
 
 
1848
        }
 
1849
 
 
1850
        /*
 
1851
         * (non-Javadoc)
 
1852
         * 
 
1853
         * @see javax.swing.plaf.basic.BasicLookAndFeel#uninitialize()
 
1854
         */
 
1855
        @Override
 
1856
        public void uninitialize() {
 
1857
                super.uninitialize();
 
1858
 
 
1859
                SubstanceLookAndFeel.currentSkin = null;
 
1860
 
 
1861
                ShadowPopupFactory.uninstall();
 
1862
 
 
1863
                SubstanceCoreUtilities.stopThreads();
 
1864
 
 
1865
                // fix for defect 109 - memory leak on watermarks
 
1866
                if (this.skin.getWatermark() != null)
 
1867
                        this.skin.getWatermark().dispose();
 
1868
 
 
1869
                // uninitialize component plugins
 
1870
                SubstanceLookAndFeel.componentPlugins.uninitializeAll();
 
1871
 
 
1872
                // reset widget support
 
1873
                LafWidgetRepository.getRepository().unsetLafSupport();
 
1874
 
 
1875
                // clear caches
 
1876
                LazyResettableHashMap.reset();
 
1877
 
 
1878
                this.currentKeyboardFocusManager
 
1879
                                .removePropertyChangeListener(this.focusOwnerChangeListener);
 
1880
                this.focusOwnerChangeListener = null;
 
1881
                this.currentKeyboardFocusManager = null;
 
1882
        }
 
1883
 
 
1884
        /**
 
1885
         * Registers a new listener on skin change.
 
1886
         * 
 
1887
         * @param skinChangeListener
 
1888
         *            New listener on skin change.
 
1889
         * @see #setSkin(String)
 
1890
         * @see #setSkin(SubstanceSkin)
 
1891
         * @see #unregisterSkinChangeListener(SkinChangeListener)
 
1892
         */
 
1893
        public static void registerSkinChangeListener(
 
1894
                        SkinChangeListener skinChangeListener) {
 
1895
                SubstanceLookAndFeel.skinChangeListeners.add(skinChangeListener);
 
1896
        }
 
1897
 
 
1898
        /**
 
1899
         * Unregisters a listener on skin change.
 
1900
         * 
 
1901
         * @param skinChangeListener
 
1902
         *            The listener to unregister.
 
1903
         * @see #setSkin(String)
 
1904
         * @see #setSkin(SubstanceSkin)
 
1905
         * @see #registerSkinChangeListener(SkinChangeListener)
 
1906
         */
 
1907
        public static void unregisterSkinChangeListener(
 
1908
                        SkinChangeListener skinChangeListener) {
 
1909
                SubstanceLookAndFeel.skinChangeListeners.remove(skinChangeListener);
 
1910
        }
 
1911
 
 
1912
        /**
 
1913
         * Registers the specified listener on tab-close events on <b>all</b> tabbed
 
1914
         * panes.
 
1915
         * 
 
1916
         * @param tabCloseListener
 
1917
         *            Listener to register.
 
1918
         * @see #registerTabCloseChangeListener(JTabbedPane, BaseTabCloseListener)
 
1919
         * @see #unregisterTabCloseChangeListener(BaseTabCloseListener)
 
1920
         * @see #unregisterTabCloseChangeListener(JTabbedPane, BaseTabCloseListener)
 
1921
         */
 
1922
        public static void registerTabCloseChangeListener(
 
1923
                        BaseTabCloseListener tabCloseListener) {
 
1924
                TabCloseListenerManager.getInstance()
 
1925
                                .registerListener(tabCloseListener);
 
1926
        }
 
1927
 
 
1928
        /**
 
1929
         * Registers the specified listener on tab-close events on <b>the
 
1930
         * specified</b> tabbed pane.
 
1931
         * 
 
1932
         * @param tabbedPane
 
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)
 
1940
         */
 
1941
        public static void registerTabCloseChangeListener(JTabbedPane tabbedPane,
 
1942
                        BaseTabCloseListener tabCloseListener) {
 
1943
                TabCloseListenerManager.getInstance().registerListener(tabbedPane,
 
1944
                                tabCloseListener);
 
1945
        }
 
1946
 
 
1947
        /**
 
1948
         * Unregisters the specified listener on tab-close events on <b>all</b>
 
1949
         * tabbed panes.
 
1950
         * 
 
1951
         * @param tabCloseListener
 
1952
         *            Listener to unregister.
 
1953
         * @see #registerTabCloseChangeListener(BaseTabCloseListener)
 
1954
         * @see #registerTabCloseChangeListener(JTabbedPane, BaseTabCloseListener)
 
1955
         * @see #unregisterTabCloseChangeListener(JTabbedPane, BaseTabCloseListener)
 
1956
         */
 
1957
        public static void unregisterTabCloseChangeListener(
 
1958
                        BaseTabCloseListener tabCloseListener) {
 
1959
                TabCloseListenerManager.getInstance().unregisterListener(
 
1960
                                tabCloseListener);
 
1961
        }
 
1962
 
 
1963
        /**
 
1964
         * Unregisters the specified listener on tab-close events on <b>the
 
1965
         * specified</b> tabbed pane.
 
1966
         * 
 
1967
         * @param tabbedPane
 
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)
 
1975
         */
 
1976
        public static void unregisterTabCloseChangeListener(JTabbedPane tabbedPane,
 
1977
                        BaseTabCloseListener tabCloseListener) {
 
1978
                TabCloseListenerManager.getInstance().unregisterListener(tabbedPane,
 
1979
                                tabCloseListener);
 
1980
        }
 
1981
 
 
1982
        /**
 
1983
         * Returns the set of all listeners registered on tab-close events on
 
1984
         * <b>all</b> tabbed panes.
 
1985
         * 
 
1986
         * @return Set of all listeners registered on tab-close events on <b>all</b>
 
1987
         *         tabbed panes.
 
1988
         */
 
1989
        public static Set<BaseTabCloseListener> getAllTabCloseListeners() {
 
1990
                return TabCloseListenerManager.getInstance().getListeners();
 
1991
        }
 
1992
 
 
1993
        /**
 
1994
         * Returns all listeners registered on tab closing of the specified tabbed
 
1995
         * pane.
 
1996
         * 
 
1997
         * @param tabbedPane
 
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
 
2001
         *         pane.
 
2002
         */
 
2003
        public static Set<BaseTabCloseListener> getAllTabCloseListeners(
 
2004
                        JTabbedPane tabbedPane) {
 
2005
                return TabCloseListenerManager.getInstance().getListeners(tabbedPane);
 
2006
        }
 
2007
 
 
2008
        /**
 
2009
         * Registers a new listener on locale change.
 
2010
         * 
 
2011
         * @param localeListener
 
2012
         *            New listener on locale change.
 
2013
         */
 
2014
        public static void registerLocaleChangeListener(
 
2015
                        LocaleChangeListener localeListener) {
 
2016
                SubstanceLookAndFeel.localeChangeListeners.add(localeListener);
 
2017
        }
 
2018
 
 
2019
        /**
 
2020
         * Unregisters a listener on locale change.
 
2021
         * 
 
2022
         * @param localeListener
 
2023
         *            The listener to unregister.
 
2024
         */
 
2025
        public static void unregisterLocaleChangeListener(
 
2026
                        LocaleChangeListener localeListener) {
 
2027
                SubstanceLookAndFeel.localeChangeListeners.remove(localeListener);
 
2028
        }
 
2029
 
 
2030
        /**
 
2031
         * Returns all listeners registered on locale change.
 
2032
         * 
 
2033
         * @return All listeners registered on locale change.
 
2034
         */
 
2035
        public static Set<LocaleChangeListener> getLocaleListeners() {
 
2036
                return Collections
 
2037
                                .unmodifiableSet(SubstanceLookAndFeel.localeChangeListeners);
 
2038
        }
 
2039
 
 
2040
        /**
 
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)}.
 
2047
         * 
 
2048
         * @param rootPane
 
2049
         *            Root pane. May be <code>null</code>.
 
2050
         * @param visible
 
2051
         *            Visibility indication.
 
2052
         * @param substanceWidgets
 
2053
         *            Widget types.
 
2054
         * @since version 5.0
 
2055
         */
 
2056
        public static void setWidgetVisible(JRootPane rootPane, boolean visible,
 
2057
                        SubstanceWidgetType... substanceWidgets) {
 
2058
                SubstanceWidgetManager.getInstance().register(rootPane, visible,
 
2059
                                substanceWidgets);
 
2060
                if (rootPane != null) {
 
2061
                        SwingUtilities.updateComponentTreeUI(rootPane);
 
2062
                } else {
 
2063
                        for (Window window : Window.getWindows()) {
 
2064
                                JRootPane root = SwingUtilities.getRootPane(window);
 
2065
                                SwingUtilities.updateComponentTreeUI(root);
 
2066
                        }
 
2067
                }
 
2068
        }
 
2069
 
 
2070
        /**
 
2071
         * Checks whether the <code>JOptionPane</code>s created with predefined
 
2072
         * message types should use constant color schemes for the icons.
 
2073
         * 
 
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)
 
2078
         */
 
2079
        public static boolean isToUseConstantThemesOnDialogs() {
 
2080
                return SubstanceLookAndFeel.toUseConstantThemesOnDialogs;
 
2081
        }
 
2082
 
 
2083
        /**
 
2084
         * Sets the new setting for the icons of the <code>JOptionPane</code>s
 
2085
         * created with predefined message types.
 
2086
         * 
 
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()
 
2092
         */
 
2093
        public static void setToUseConstantThemesOnDialogs(
 
2094
                        boolean toUseConstantThemesOnDialogs) {
 
2095
                SubstanceLookAndFeel.toUseConstantThemesOnDialogs = toUseConstantThemesOnDialogs;
 
2096
                SwingUtilities.invokeLater(new Runnable() {
 
2097
                        @Override
 
2098
            public void run() {
 
2099
                                for (Window window : Window.getWindows()) {
 
2100
                                        SwingUtilities.updateComponentTreeUI(window);
 
2101
                                }
 
2102
                        }
 
2103
                });
 
2104
        }
 
2105
 
 
2106
        /**
 
2107
         * The current Substance skin.
 
2108
         */
 
2109
        private static SubstanceSkin currentSkin = null;
 
2110
 
 
2111
        /**
 
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.
 
2116
         * 
 
2117
         * @param newSkin
 
2118
         *            Skin to set.
 
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()}
 
2123
         *            API.
 
2124
         * @return <code>true</code> if the specified skin has been set
 
2125
         *         successfully, <code>false</code> otherwise.
 
2126
         * @see #setSkin(SubstanceSkin)
 
2127
         */
 
2128
        private static boolean setSkin(final SubstanceSkin newSkin,
 
2129
                        final boolean toUpdateWindows) {
 
2130
                if (!SwingUtilities.isEventDispatchThread()) {
 
2131
            final boolean[] returnValue = new boolean[1];
 
2132
            try {
 
2133
                SwingUtilities.invokeAndWait(new Runnable() {
 
2134
                    @Override
 
2135
                    public void run() {
 
2136
                        returnValue[0] = setSkin(newSkin, toUpdateWindows);
 
2137
                    }
 
2138
                });
 
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();
 
2144
                }
 
2145
                
 
2146
            } catch (InterruptedException ignore) {}
 
2147
            return returnValue[0];
 
2148
                }
 
2149
 
 
2150
                if (!newSkin.isValid())
 
2151
                        return false;
 
2152
 
 
2153
                boolean isSubstance = (UIManager.getLookAndFeel() instanceof SubstanceLookAndFeel);
 
2154
                if (!isSubstance) {
 
2155
                        class SkinDerivedLookAndFeel extends SubstanceLookAndFeel {
 
2156
                                public SkinDerivedLookAndFeel(SubstanceSkin newSkin) {
 
2157
                                        super(newSkin);
 
2158
                                }
 
2159
                        }
 
2160
 
 
2161
                        LookAndFeel derived = new SkinDerivedLookAndFeel(newSkin);
 
2162
                        try {
 
2163
                                UIManager.setLookAndFeel(derived);
 
2164
                        } catch (UnsupportedLookAndFeelException ulafe) {
 
2165
                                return false;
 
2166
                        }
 
2167
                        if (!(UIManager.getLookAndFeel() instanceof SubstanceLookAndFeel)) {
 
2168
                                return false;
 
2169
                        }
 
2170
                        for (Window window : Window.getWindows()) {
 
2171
                                SwingUtilities.updateComponentTreeUI(window);
 
2172
                        }
 
2173
                        return true;
 
2174
                }
 
2175
 
 
2176
                try {
 
2177
                        // Required skin settings must be non-null
 
2178
                        if (!newSkin.isValid()) {
 
2179
                                return false;
 
2180
                        }
 
2181
 
 
2182
                        // fix for defect 109 - memory leak on watermark switch
 
2183
                        if ((currentSkin != null) && (currentSkin.getWatermark() != null)) {
 
2184
                                currentSkin.getWatermark().dispose();
 
2185
                        }
 
2186
                        if (newSkin.getWatermark() != null) {
 
2187
                                if (!newSkin.getWatermark().updateWatermarkImage(newSkin)) {
 
2188
                                        return false;
 
2189
                                }
 
2190
                        }
 
2191
 
 
2192
                        UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults();
 
2193
                        // The table will be null when the skin is set using a custom
 
2194
                        // LAF
 
2195
                        if (lafDefaults != null) {
 
2196
                                initFontDefaults(lafDefaults, SubstanceLookAndFeel
 
2197
                                                .getFontPolicy().getFontSet("Substance", null));
 
2198
                                newSkin.addCustomEntriesToTable(lafDefaults);
 
2199
                                SubstanceLookAndFeel.componentPlugins
 
2200
                                                .processAllDefaultsEntries(lafDefaults, newSkin);
 
2201
                        }
 
2202
 
 
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()
 
2207
            }) {
 
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);
 
2214
                    }
 
2215
                }
 
2216
            }
 
2217
 
 
2218
                        if (isSubstance)
 
2219
                                LazyResettableHashMap.reset();
 
2220
 
 
2221
                        currentSkin = newSkin;
 
2222
 
 
2223
                        if (toUpdateWindows) {
 
2224
                                for (Window window : Window.getWindows()) {
 
2225
                                        SwingUtilities.updateComponentTreeUI(window);
 
2226
                                }
 
2227
                        }
 
2228
 
 
2229
                        // SwingUtilities.invokeLater(new Runnable() {
 
2230
                        // public void run() {
 
2231
                        for (SkinChangeListener skinChangeListener : SubstanceLookAndFeel.skinChangeListeners)
 
2232
                                skinChangeListener.skinChanged();
 
2233
                        // }
 
2234
                        // });
 
2235
                        return true;
 
2236
                } catch (NoClassDefFoundError ncdfe) {
 
2237
                        // this may happen when a skin references some class
 
2238
                        // that can't be found in the classpath.
 
2239
                        return false;
 
2240
                } catch (Exception e) {
 
2241
                        return false;
 
2242
                }
 
2243
        }
 
2244
 
 
2245
        /**
 
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.
 
2252
         * 
 
2253
         * @param newSkin
 
2254
         *            Skin to set.
 
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()
 
2262
         */
 
2263
        public static boolean setSkin(SubstanceSkin newSkin) {
 
2264
                return setSkin(newSkin, true);
 
2265
        }
 
2266
 
 
2267
        /**
 
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.
 
2274
         * 
 
2275
         * @param skinClassName
 
2276
         *            Skin to set.
 
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()
 
2286
         */
 
2287
        public static boolean setSkin(String skinClassName) {
 
2288
                try {
 
2289
                        Class<?> skinClass = Class.forName(skinClassName);
 
2290
                        if (skinClass == null) {
 
2291
                                return false;
 
2292
                        }
 
2293
                        Object obj = skinClass.newInstance();
 
2294
                        if (obj == null) {
 
2295
                                return false;
 
2296
                        }
 
2297
                        if (!(obj instanceof SubstanceSkin)) {
 
2298
                                return false;
 
2299
                        }
 
2300
                        return SubstanceLookAndFeel.setSkin((SubstanceSkin) obj);
 
2301
                } catch (Exception exc) {
 
2302
                        exc.printStackTrace();
 
2303
                        return false;
 
2304
                }
 
2305
        }
 
2306
 
 
2307
        /**
 
2308
         * Returns all available skins.
 
2309
         * 
 
2310
         * @return All available skins. Key - skin display name, value - skin
 
2311
         *         information.
 
2312
         */
 
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)
 
2319
                                        .getSkins()) {
 
2320
                                result.put(skinInfo.getDisplayName(), skinInfo);
 
2321
                        }
 
2322
                }
 
2323
                return result;
 
2324
        }
 
2325
 
 
2326
        /*
 
2327
         * (non-Javadoc)
 
2328
         * 
 
2329
         * @see javax.swing.LookAndFeel#getSupportsWindowDecorations()
 
2330
         */
 
2331
        @Override
 
2332
        public boolean getSupportsWindowDecorations() {
 
2333
                return true;
 
2334
        }
 
2335
 
 
2336
        /**
 
2337
         * Sets the class loader for {@link #LABEL_BUNDLE}.
 
2338
         * 
 
2339
         * @param labelBundleClassLoader
 
2340
         *            Class loader for {@link #LABEL_BUNDLE}.
 
2341
         * @since version 3.1
 
2342
         */
 
2343
        public static void setLabelBundleClassLoader(
 
2344
                        ClassLoader labelBundleClassLoader) {
 
2345
                SubstanceLookAndFeel.labelBundleClassLoader = labelBundleClassLoader;
 
2346
                LafWidgetRepository.setLabelBundleClassLoader(labelBundleClassLoader);
 
2347
        }
 
2348
 
 
2349
        /**
 
2350
         * Returns the title pane of the specified top-level window.
 
2351
         * 
 
2352
         * @param window
 
2353
         *            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
 
2358
         */
 
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();
 
2364
                }
 
2365
                if (window instanceof JDialog) {
 
2366
                        JDialog d = (JDialog) window;
 
2367
                        rootPane = d.getRootPane();
 
2368
                }
 
2369
                if (rootPane != null) {
 
2370
                        SubstanceRootPaneUI ui = (SubstanceRootPaneUI) rootPane.getUI();
 
2371
                        return ui.getTitlePane();
 
2372
                }
 
2373
                return null;
 
2374
        }
 
2375
 
 
2376
        /**
 
2377
         * Sets the decoration type of the specified component and all its children.
 
2378
         * 
 
2379
         * @param comp
 
2380
         *            Component.
 
2381
         * @param type
 
2382
         *            Decoration type of the component and all its children.
 
2383
         */
 
2384
        public static void setDecorationType(JComponent comp,
 
2385
                        DecorationAreaType type) {
 
2386
                DecorationPainterUtils.setDecorationType(comp, type);
 
2387
        }
 
2388
 
 
2389
        /**
 
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.
 
2401
         * 
 
2402
         * @param comp
 
2403
         *            Component.
 
2404
         * @return Decoration area type of the component.
 
2405
         */
 
2406
        public static DecorationAreaType getDecorationType(Component comp) {
 
2407
                return DecorationPainterUtils.getDecorationType(comp);
 
2408
        }
 
2409
 
 
2410
        /**
 
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>.
 
2415
         * 
 
2416
         * @param comp
 
2417
         *            Component.
 
2418
         * @return Immediate decoration area type of the component.
 
2419
         */
 
2420
        public static DecorationAreaType getImmediateDecorationType(Component comp) {
 
2421
                return DecorationPainterUtils.getImmediateDecorationType(comp);
 
2422
        }
 
2423
 
 
2424
        /**
 
2425
         * Checks whether Substance is the current look-and-feel. This method is for
 
2426
         * internal use only.
 
2427
         * 
 
2428
         * @return <code>true</code> if Substance is the current look-and-feel,
 
2429
         *         <code>false</code> otherwise.
 
2430
         */
 
2431
        public static boolean isCurrentLookAndFeel() {
 
2432
                return ((UIManager.getLookAndFeel() instanceof SubstanceLookAndFeel) && (currentSkin != null));
 
2433
        }
 
2434
 
 
2435
        /*
 
2436
         * (non-Javadoc)
 
2437
         * 
 
2438
         * @see javax.swing.LookAndFeel#getDisabledIcon(javax.swing.JComponent,
 
2439
         * javax.swing.Icon)
 
2440
         */
 
2441
        @Override
 
2442
        public Icon getDisabledIcon(JComponent component, Icon icon) {
 
2443
                if (icon == null)
 
2444
                        return null;
 
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);
 
2451
                if (alpha < 1.0f) {
 
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);
 
2457
                        g2d.dispose();
 
2458
                        result = intermediate;
 
2459
                }
 
2460
 
 
2461
                return new IconUIResource(new ImageIcon(result));
 
2462
        }
 
2463
}