33 import java.text.*; 34 import java.util.*; 35 import javax.swing.*; 36 import javax.swing.plaf.*; 37 import javax.swing.plaf.basic.*; 38 39 import sun.awt.*; 40 import sun.security.action.*; 41 import sun.swing.*; 42 import sun.swing.plaf.synth.*; 43 44 /** 45 * SynthLookAndFeel provides the basis for creating a customized look and 46 * feel. SynthLookAndFeel does not directly provide a look, all painting is 47 * delegated. 48 * You need to either provide a configuration file, by way of the 49 * {@link #load} method, or provide your own {@link SynthStyleFactory} 50 * to {@link #setStyleFactory}. Refer to the 51 * <a href="package-summary.html">package summary</a> for an example of 52 * loading a file, and {@link javax.swing.plaf.synth.SynthStyleFactory} for 53 * an example of providing your own <code>SynthStyleFactory</code> to 54 * <code>setStyleFactory</code>. 55 * <p> 56 * <strong>Warning:</strong> 57 * This class implements {@link Serializable} as a side effect of it 58 * extending {@link BasicLookAndFeel}. It is not intended to be serialized. 59 * An attempt to serialize it will 60 * result in {@link NotSerializableException}. 61 * 62 * @serial exclude 63 * @since 1.5 64 * @author Scott Violet 65 */ 66 @SuppressWarnings("serial") // Per above comment, not actually serializable 67 public class SynthLookAndFeel extends BasicLookAndFeel { 68 /** 69 * Used in a handful of places where we need an empty Insets. 70 */ 71 static final Insets EMPTY_UIRESOURCE_INSETS = new InsetsUIResource( 72 0, 0, 0, 0); 73 74 /** 75 * AppContext key to get the current SynthStyleFactory. 76 */ 77 private static final Object STYLE_FACTORY_KEY = 78 new StringBuffer("com.sun.java.swing.plaf.gtk.StyleCache"); 79 80 /** 81 * AppContext key to get selectedUI. 82 */ 83 private static final Object SELECTED_UI_KEY = new StringBuilder("selectedUI"); 84 85 /** 86 * AppContext key to get selectedUIState. 87 */ 88 private static final Object SELECTED_UI_STATE_KEY = new StringBuilder("selectedUIState"); 89 90 /** 91 * The last SynthStyleFactory that was asked for from AppContext 92 * <code>lastContext</code>. 93 */ 94 private static SynthStyleFactory lastFactory; 95 /** 96 * AppContext lastLAF came from. 97 */ 98 private static AppContext lastContext; 99 100 /** 101 * SynthStyleFactory for the this SynthLookAndFeel. 102 */ 103 private SynthStyleFactory factory; 104 105 /** 106 * Map of defaults table entries. This is populated via the load 107 * method. 108 */ 109 private Map<String, Object> defaultsMap; 110 111 private Handler _handler; 112 113 static ComponentUI getSelectedUI() { 114 return (ComponentUI) AppContext.getAppContext().get(SELECTED_UI_KEY); 115 } 116 117 /** 118 * Used by the renderers. For the most part the renderers are implemented 119 * as Labels, which is problematic in so far as they are never selected. 120 * To accommodate this SynthLabelUI checks if the current 121 * UI matches that of <code>selectedUI</code> (which this methods sets), if 122 * it does, then a state as set by this method is returned. This provides 123 * a way for labels to have a state other than selected. 124 */ 125 static void setSelectedUI(ComponentUI uix, boolean selected, 126 boolean focused, boolean enabled, 127 boolean rollover) { 128 int selectedUIState = 0; 129 130 if (selected) { 131 selectedUIState = SynthConstants.SELECTED; 132 if (focused) { 133 selectedUIState |= SynthConstants.FOCUSED; 134 } 135 } 136 else if (rollover && enabled) { 137 selectedUIState |= 138 SynthConstants.MOUSE_OVER | SynthConstants.ENABLED; 139 if (focused) { 140 selectedUIState |= SynthConstants.FOCUSED; 141 } 222 } 223 return SynthUI.DISABLED; 224 } 225 226 /** 227 * Gets a SynthStyle for the specified region of the specified component. 228 * This is not for general consumption, only custom UIs should call this 229 * method. 230 * 231 * @param c JComponent to get the SynthStyle for 232 * @param region Identifies the region of the specified component 233 * @return SynthStyle to use. 234 */ 235 public static SynthStyle getStyle(JComponent c, Region region) { 236 return getStyleFactory().getStyle(c, region); 237 } 238 239 /** 240 * Returns true if the Style should be updated in response to the 241 * specified PropertyChangeEvent. This forwards to 242 * <code>shouldUpdateStyleOnAncestorChanged</code> as necessary. 243 */ 244 static boolean shouldUpdateStyle(PropertyChangeEvent event) { 245 LookAndFeel laf = UIManager.getLookAndFeel(); 246 return (laf instanceof SynthLookAndFeel && 247 ((SynthLookAndFeel) laf).shouldUpdateStyleOnEvent(event)); 248 } 249 250 /** 251 * A convience method that will reset the Style of StyleContext if 252 * necessary. 253 * 254 * @return newStyle 255 */ 256 static SynthStyle updateStyle(SynthContext context, SynthUI ui) { 257 SynthStyle newStyle = getStyle(context.getComponent(), 258 context.getRegion()); 259 SynthStyle oldStyle = context.getStyle(); 260 261 if (newStyle != oldStyle) { 262 if (oldStyle != null) { 263 oldStyle.uninstallDefaults(context); 264 } 265 context.setStyle(newStyle); 266 newStyle.installDefaults(context, ui); 267 } 268 return newStyle; 269 } 270 271 /** 272 * Updates the style associated with <code>c</code>, and all its children. 273 * This is a lighter version of 274 * <code>SwingUtilities.updateComponentTreeUI</code>. 275 * 276 * @param c Component to update style for. 277 */ 278 public static void updateStyles(Component c) { 279 if (c instanceof JComponent) { 280 // Yes, this is hacky. A better solution is to get the UI 281 // and cast, but JComponent doesn't expose a getter for the UI 282 // (each of the UIs do), making that approach impractical. 283 String name = c.getName(); 284 c.setName(null); 285 if (name != null) { 286 c.setName(name); 287 } 288 ((JComponent)c).revalidate(); 289 } 290 Component[] children = null; 291 if (c instanceof JMenu) { 292 children = ((JMenu)c).getMenuComponents(); 293 } 294 else if (c instanceof Container) { 295 children = ((Container)c).getComponents(); 296 } 297 if (children != null) { 298 for (Component child : children) { 299 updateStyles(child); 300 } 301 } 302 c.repaint(); 303 } 304 305 /** 306 * Returns the Region for the JComponent <code>c</code>. 307 * 308 * @param c JComponent to fetch the Region for 309 * @return Region corresponding to <code>c</code> 310 */ 311 public static Region getRegion(JComponent c) { 312 return Region.getRegion(c); 313 } 314 315 /** 316 * A convenience method to return where the foreground should be 317 * painted for the Component identified by the passed in 318 * AbstractSynthContext. 319 */ 320 static Insets getPaintingInsets(SynthContext state, Insets insets) { 321 if (state.isSubregion()) { 322 insets = state.getStyle().getInsets(state, insets); 323 } 324 else { 325 insets = state.getComponent().getInsets(insets); 326 } 327 return insets; 328 } 329 362 x = bounds.x; 363 y = bounds.y; 364 width = bounds.width; 365 height = bounds.height; 366 } 367 368 // Fill in the background, if necessary. 369 boolean subregion = state.isSubregion(); 370 if ((subregion && style.isOpaque(state)) || 371 (!subregion && c.isOpaque())) { 372 g.setColor(style.getColor(state, ColorType.BACKGROUND)); 373 g.fillRect(x, y, width, height); 374 } 375 } 376 377 static boolean isLeftToRight(Component c) { 378 return c.getComponentOrientation().isLeftToRight(); 379 } 380 381 /** 382 * Returns the ui that is of type <code>klass</code>, or null if 383 * one can not be found. 384 */ 385 static Object getUIOfType(ComponentUI ui, Class<?> klass) { 386 if (klass.isInstance(ui)) { 387 return ui; 388 } 389 return null; 390 } 391 392 /** 393 * Creates the Synth look and feel <code>ComponentUI</code> for 394 * the passed in <code>JComponent</code>. 395 * 396 * @param c JComponent to create the <code>ComponentUI</code> for 397 * @return ComponentUI to use for <code>c</code> 398 */ 399 public static ComponentUI createUI(JComponent c) { 400 String key = c.getUIClassID().intern(); 401 402 if (key == "ButtonUI") { 403 return SynthButtonUI.createUI(c); 404 } 405 else if (key == "CheckBoxUI") { 406 return SynthCheckBoxUI.createUI(c); 407 } 408 else if (key == "CheckBoxMenuItemUI") { 409 return SynthCheckBoxMenuItemUI.createUI(c); 410 } 411 else if (key == "ColorChooserUI") { 412 return SynthColorChooserUI.createUI(c); 413 } 414 else if (key == "ComboBoxUI") { 415 return SynthComboBoxUI.createUI(c); 416 } 417 else if (key == "DesktopPaneUI") { 518 } 519 else if (key == "ToolBarUI") { 520 return SynthToolBarUI.createUI(c); 521 } 522 else if (key == "ToolTipUI") { 523 return SynthToolTipUI.createUI(c); 524 } 525 else if (key == "TreeUI") { 526 return SynthTreeUI.createUI(c); 527 } 528 else if (key == "ViewportUI") { 529 return SynthViewportUI.createUI(c); 530 } 531 return null; 532 } 533 534 535 /** 536 * Creates a SynthLookAndFeel. 537 * <p> 538 * For the returned <code>SynthLookAndFeel</code> to be useful you need to 539 * invoke <code>load</code> to specify the set of 540 * <code>SynthStyle</code>s, or invoke <code>setStyleFactory</code>. 541 * 542 * @see #load 543 * @see #setStyleFactory 544 */ 545 public SynthLookAndFeel() { 546 factory = new DefaultSynthStyleFactory(); 547 _handler = new Handler(); 548 } 549 550 /** 551 * Loads the set of <code>SynthStyle</code>s that will be used by 552 * this <code>SynthLookAndFeel</code>. <code>resourceBase</code> is 553 * used to resolve any path based resources, for example an 554 * <code>Image</code> would be resolved by 555 * <code>resourceBase.getResource(path)</code>. Refer to 556 * <a href="doc-files/synthFileFormat.html">Synth File Format</a> 557 * for more information. 558 * 559 * @param input InputStream to load from 560 * @param resourceBase used to resolve any images or other resources 561 * @throws ParseException if there is an error in parsing 562 * @throws IllegalArgumentException if input or resourceBase is <code>null</code> 563 */ 564 public void load(InputStream input, Class<?> resourceBase) throws 565 ParseException { 566 if (resourceBase == null) { 567 throw new IllegalArgumentException( 568 "You must supply a valid resource base Class"); 569 } 570 571 if (defaultsMap == null) { 572 defaultsMap = new HashMap<String, Object>(); 573 } 574 575 new SynthParser().parse(input, (DefaultSynthStyleFactory) factory, 576 null, resourceBase, defaultsMap); 577 } 578 579 /** 580 * Loads the set of <code>SynthStyle</code>s that will be used by 581 * this <code>SynthLookAndFeel</code>. Path based resources are resolved 582 * relatively to the specified <code>URL</code> of the style. For example 583 * an <code>Image</code> would be resolved by 584 * <code>new URL(synthFile, path)</code>. Refer to 585 * <a href="doc-files/synthFileFormat.html">Synth File Format</a> for more 586 * information. 587 * 588 * @param url the <code>URL</code> to load the set of 589 * <code>SynthStyle</code> from 590 * @throws ParseException if there is an error in parsing 591 * @throws IllegalArgumentException if synthSet is <code>null</code> 592 * @throws IOException if synthSet cannot be opened as an <code>InputStream</code> 593 * @since 1.6 594 */ 595 public void load(URL url) throws ParseException, IOException { 596 if (url == null) { 597 throw new IllegalArgumentException( 598 "You must supply a valid Synth set URL"); 599 } 600 601 if (defaultsMap == null) { 602 defaultsMap = new HashMap<String, Object>(); 603 } 604 605 InputStream input = url.openStream(); 606 new SynthParser().parse(input, (DefaultSynthStyleFactory) factory, 607 url, null, defaultsMap); 608 } 609 610 /** 611 * Called by UIManager when this look and feel is installed. 612 */ 732 * 733 * @return a short string identifying this look and feel. 734 */ 735 @Override 736 public String getName() { 737 return "Synth look and feel"; 738 } 739 740 /** 741 * Return a string that identifies this look and feel. 742 * 743 * @return a short string identifying this look and feel. 744 */ 745 @Override 746 public String getID() { 747 return "Synth"; 748 } 749 750 /** 751 * Returns whether or not the UIs should update their 752 * <code>SynthStyles</code> from the <code>SynthStyleFactory</code> 753 * when the ancestor of the <code>JComponent</code> changes. A subclass 754 * that provided a <code>SynthStyleFactory</code> that based the 755 * return value from <code>getStyle</code> off the containment hierarchy 756 * would override this method to return true. 757 * 758 * @return whether or not the UIs should update their 759 * <code>SynthStyles</code> from the <code>SynthStyleFactory</code> 760 * when the ancestor changed. 761 */ 762 public boolean shouldUpdateStyleOnAncestorChanged() { 763 return false; 764 } 765 766 /** 767 * Returns whether or not the UIs should update their styles when a 768 * particular event occurs. 769 * 770 * @param ev a {@code PropertyChangeEvent} 771 * @return whether or not the UIs should update their styles 772 * @since 1.7 773 */ 774 protected boolean shouldUpdateStyleOnEvent(PropertyChangeEvent ev) { 775 String eName = ev.getPropertyName(); 776 if ("name" == eName || "componentOrientation" == eName) { 777 return true; 778 } 779 if ("ancestor" == eName && ev.getNewValue() != null) { | 33 import java.text.*; 34 import java.util.*; 35 import javax.swing.*; 36 import javax.swing.plaf.*; 37 import javax.swing.plaf.basic.*; 38 39 import sun.awt.*; 40 import sun.security.action.*; 41 import sun.swing.*; 42 import sun.swing.plaf.synth.*; 43 44 /** 45 * SynthLookAndFeel provides the basis for creating a customized look and 46 * feel. SynthLookAndFeel does not directly provide a look, all painting is 47 * delegated. 48 * You need to either provide a configuration file, by way of the 49 * {@link #load} method, or provide your own {@link SynthStyleFactory} 50 * to {@link #setStyleFactory}. Refer to the 51 * <a href="package-summary.html">package summary</a> for an example of 52 * loading a file, and {@link javax.swing.plaf.synth.SynthStyleFactory} for 53 * an example of providing your own {@code SynthStyleFactory} to 54 * {@code setStyleFactory}. 55 * <p> 56 * <strong>Warning:</strong> 57 * This class implements {@link Serializable} as a side effect of it 58 * extending {@link BasicLookAndFeel}. It is not intended to be serialized. 59 * An attempt to serialize it will 60 * result in {@link NotSerializableException}. 61 * 62 * @serial exclude 63 * @since 1.5 64 * @author Scott Violet 65 */ 66 @SuppressWarnings("serial") // Per above comment, not actually serializable 67 public class SynthLookAndFeel extends BasicLookAndFeel { 68 /** 69 * Used in a handful of places where we need an empty Insets. 70 */ 71 static final Insets EMPTY_UIRESOURCE_INSETS = new InsetsUIResource( 72 0, 0, 0, 0); 73 74 /** 75 * AppContext key to get the current SynthStyleFactory. 76 */ 77 private static final Object STYLE_FACTORY_KEY = 78 new StringBuffer("com.sun.java.swing.plaf.gtk.StyleCache"); 79 80 /** 81 * AppContext key to get selectedUI. 82 */ 83 private static final Object SELECTED_UI_KEY = new StringBuilder("selectedUI"); 84 85 /** 86 * AppContext key to get selectedUIState. 87 */ 88 private static final Object SELECTED_UI_STATE_KEY = new StringBuilder("selectedUIState"); 89 90 /** 91 * The last SynthStyleFactory that was asked for from AppContext 92 * {@code lastContext}. 93 */ 94 private static SynthStyleFactory lastFactory; 95 /** 96 * AppContext lastLAF came from. 97 */ 98 private static AppContext lastContext; 99 100 /** 101 * SynthStyleFactory for the this SynthLookAndFeel. 102 */ 103 private SynthStyleFactory factory; 104 105 /** 106 * Map of defaults table entries. This is populated via the load 107 * method. 108 */ 109 private Map<String, Object> defaultsMap; 110 111 private Handler _handler; 112 113 static ComponentUI getSelectedUI() { 114 return (ComponentUI) AppContext.getAppContext().get(SELECTED_UI_KEY); 115 } 116 117 /** 118 * Used by the renderers. For the most part the renderers are implemented 119 * as Labels, which is problematic in so far as they are never selected. 120 * To accommodate this SynthLabelUI checks if the current 121 * UI matches that of {@code selectedUI} (which this methods sets), if 122 * it does, then a state as set by this method is returned. This provides 123 * a way for labels to have a state other than selected. 124 */ 125 static void setSelectedUI(ComponentUI uix, boolean selected, 126 boolean focused, boolean enabled, 127 boolean rollover) { 128 int selectedUIState = 0; 129 130 if (selected) { 131 selectedUIState = SynthConstants.SELECTED; 132 if (focused) { 133 selectedUIState |= SynthConstants.FOCUSED; 134 } 135 } 136 else if (rollover && enabled) { 137 selectedUIState |= 138 SynthConstants.MOUSE_OVER | SynthConstants.ENABLED; 139 if (focused) { 140 selectedUIState |= SynthConstants.FOCUSED; 141 } 222 } 223 return SynthUI.DISABLED; 224 } 225 226 /** 227 * Gets a SynthStyle for the specified region of the specified component. 228 * This is not for general consumption, only custom UIs should call this 229 * method. 230 * 231 * @param c JComponent to get the SynthStyle for 232 * @param region Identifies the region of the specified component 233 * @return SynthStyle to use. 234 */ 235 public static SynthStyle getStyle(JComponent c, Region region) { 236 return getStyleFactory().getStyle(c, region); 237 } 238 239 /** 240 * Returns true if the Style should be updated in response to the 241 * specified PropertyChangeEvent. This forwards to 242 * {@code shouldUpdateStyleOnAncestorChanged} as necessary. 243 */ 244 static boolean shouldUpdateStyle(PropertyChangeEvent event) { 245 LookAndFeel laf = UIManager.getLookAndFeel(); 246 return (laf instanceof SynthLookAndFeel && 247 ((SynthLookAndFeel) laf).shouldUpdateStyleOnEvent(event)); 248 } 249 250 /** 251 * A convience method that will reset the Style of StyleContext if 252 * necessary. 253 * 254 * @return newStyle 255 */ 256 static SynthStyle updateStyle(SynthContext context, SynthUI ui) { 257 SynthStyle newStyle = getStyle(context.getComponent(), 258 context.getRegion()); 259 SynthStyle oldStyle = context.getStyle(); 260 261 if (newStyle != oldStyle) { 262 if (oldStyle != null) { 263 oldStyle.uninstallDefaults(context); 264 } 265 context.setStyle(newStyle); 266 newStyle.installDefaults(context, ui); 267 } 268 return newStyle; 269 } 270 271 /** 272 * Updates the style associated with {@code c}, and all its children. 273 * This is a lighter version of 274 * {@code SwingUtilities.updateComponentTreeUI}. 275 * 276 * @param c Component to update style for. 277 */ 278 public static void updateStyles(Component c) { 279 if (c instanceof JComponent) { 280 // Yes, this is hacky. A better solution is to get the UI 281 // and cast, but JComponent doesn't expose a getter for the UI 282 // (each of the UIs do), making that approach impractical. 283 String name = c.getName(); 284 c.setName(null); 285 if (name != null) { 286 c.setName(name); 287 } 288 ((JComponent)c).revalidate(); 289 } 290 Component[] children = null; 291 if (c instanceof JMenu) { 292 children = ((JMenu)c).getMenuComponents(); 293 } 294 else if (c instanceof Container) { 295 children = ((Container)c).getComponents(); 296 } 297 if (children != null) { 298 for (Component child : children) { 299 updateStyles(child); 300 } 301 } 302 c.repaint(); 303 } 304 305 /** 306 * Returns the Region for the JComponent {@code c}. 307 * 308 * @param c JComponent to fetch the Region for 309 * @return Region corresponding to {@code c} 310 */ 311 public static Region getRegion(JComponent c) { 312 return Region.getRegion(c); 313 } 314 315 /** 316 * A convenience method to return where the foreground should be 317 * painted for the Component identified by the passed in 318 * AbstractSynthContext. 319 */ 320 static Insets getPaintingInsets(SynthContext state, Insets insets) { 321 if (state.isSubregion()) { 322 insets = state.getStyle().getInsets(state, insets); 323 } 324 else { 325 insets = state.getComponent().getInsets(insets); 326 } 327 return insets; 328 } 329 362 x = bounds.x; 363 y = bounds.y; 364 width = bounds.width; 365 height = bounds.height; 366 } 367 368 // Fill in the background, if necessary. 369 boolean subregion = state.isSubregion(); 370 if ((subregion && style.isOpaque(state)) || 371 (!subregion && c.isOpaque())) { 372 g.setColor(style.getColor(state, ColorType.BACKGROUND)); 373 g.fillRect(x, y, width, height); 374 } 375 } 376 377 static boolean isLeftToRight(Component c) { 378 return c.getComponentOrientation().isLeftToRight(); 379 } 380 381 /** 382 * Returns the ui that is of type {@code klass}, or null if 383 * one can not be found. 384 */ 385 static Object getUIOfType(ComponentUI ui, Class<?> klass) { 386 if (klass.isInstance(ui)) { 387 return ui; 388 } 389 return null; 390 } 391 392 /** 393 * Creates the Synth look and feel {@code ComponentUI} for 394 * the passed in {@code JComponent}. 395 * 396 * @param c JComponent to create the {@code ComponentUI} for 397 * @return ComponentUI to use for {@code c} 398 */ 399 public static ComponentUI createUI(JComponent c) { 400 String key = c.getUIClassID().intern(); 401 402 if (key == "ButtonUI") { 403 return SynthButtonUI.createUI(c); 404 } 405 else if (key == "CheckBoxUI") { 406 return SynthCheckBoxUI.createUI(c); 407 } 408 else if (key == "CheckBoxMenuItemUI") { 409 return SynthCheckBoxMenuItemUI.createUI(c); 410 } 411 else if (key == "ColorChooserUI") { 412 return SynthColorChooserUI.createUI(c); 413 } 414 else if (key == "ComboBoxUI") { 415 return SynthComboBoxUI.createUI(c); 416 } 417 else if (key == "DesktopPaneUI") { 518 } 519 else if (key == "ToolBarUI") { 520 return SynthToolBarUI.createUI(c); 521 } 522 else if (key == "ToolTipUI") { 523 return SynthToolTipUI.createUI(c); 524 } 525 else if (key == "TreeUI") { 526 return SynthTreeUI.createUI(c); 527 } 528 else if (key == "ViewportUI") { 529 return SynthViewportUI.createUI(c); 530 } 531 return null; 532 } 533 534 535 /** 536 * Creates a SynthLookAndFeel. 537 * <p> 538 * For the returned {@code SynthLookAndFeel} to be useful you need to 539 * invoke {@code load} to specify the set of 540 * {@code SynthStyle}s, or invoke {@code setStyleFactory}. 541 * 542 * @see #load 543 * @see #setStyleFactory 544 */ 545 public SynthLookAndFeel() { 546 factory = new DefaultSynthStyleFactory(); 547 _handler = new Handler(); 548 } 549 550 /** 551 * Loads the set of {@code SynthStyle}s that will be used by 552 * this {@code SynthLookAndFeel}. {@code resourceBase} is 553 * used to resolve any path based resources, for example an 554 * {@code Image} would be resolved by 555 * {@code resourceBase.getResource(path)}. Refer to 556 * <a href="doc-files/synthFileFormat.html">Synth File Format</a> 557 * for more information. 558 * 559 * @param input InputStream to load from 560 * @param resourceBase used to resolve any images or other resources 561 * @throws ParseException if there is an error in parsing 562 * @throws IllegalArgumentException if input or resourceBase is {@code null} 563 */ 564 public void load(InputStream input, Class<?> resourceBase) throws 565 ParseException { 566 if (resourceBase == null) { 567 throw new IllegalArgumentException( 568 "You must supply a valid resource base Class"); 569 } 570 571 if (defaultsMap == null) { 572 defaultsMap = new HashMap<String, Object>(); 573 } 574 575 new SynthParser().parse(input, (DefaultSynthStyleFactory) factory, 576 null, resourceBase, defaultsMap); 577 } 578 579 /** 580 * Loads the set of {@code SynthStyle}s that will be used by 581 * this {@code SynthLookAndFeel}. Path based resources are resolved 582 * relatively to the specified {@code URL} of the style. For example 583 * an {@code Image} would be resolved by 584 * {@code new URL(synthFile, path)}. Refer to 585 * <a href="doc-files/synthFileFormat.html">Synth File Format</a> for more 586 * information. 587 * 588 * @param url the {@code URL} to load the set of 589 * {@code SynthStyle} from 590 * @throws ParseException if there is an error in parsing 591 * @throws IllegalArgumentException if synthSet is {@code null} 592 * @throws IOException if synthSet cannot be opened as an {@code InputStream} 593 * @since 1.6 594 */ 595 public void load(URL url) throws ParseException, IOException { 596 if (url == null) { 597 throw new IllegalArgumentException( 598 "You must supply a valid Synth set URL"); 599 } 600 601 if (defaultsMap == null) { 602 defaultsMap = new HashMap<String, Object>(); 603 } 604 605 InputStream input = url.openStream(); 606 new SynthParser().parse(input, (DefaultSynthStyleFactory) factory, 607 url, null, defaultsMap); 608 } 609 610 /** 611 * Called by UIManager when this look and feel is installed. 612 */ 732 * 733 * @return a short string identifying this look and feel. 734 */ 735 @Override 736 public String getName() { 737 return "Synth look and feel"; 738 } 739 740 /** 741 * Return a string that identifies this look and feel. 742 * 743 * @return a short string identifying this look and feel. 744 */ 745 @Override 746 public String getID() { 747 return "Synth"; 748 } 749 750 /** 751 * Returns whether or not the UIs should update their 752 * {@code SynthStyles} from the {@code SynthStyleFactory} 753 * when the ancestor of the {@code JComponent} changes. A subclass 754 * that provided a {@code SynthStyleFactory} that based the 755 * return value from {@code getStyle} off the containment hierarchy 756 * would override this method to return true. 757 * 758 * @return whether or not the UIs should update their 759 * {@code SynthStyles} from the {@code SynthStyleFactory} 760 * when the ancestor changed. 761 */ 762 public boolean shouldUpdateStyleOnAncestorChanged() { 763 return false; 764 } 765 766 /** 767 * Returns whether or not the UIs should update their styles when a 768 * particular event occurs. 769 * 770 * @param ev a {@code PropertyChangeEvent} 771 * @return whether or not the UIs should update their styles 772 * @since 1.7 773 */ 774 protected boolean shouldUpdateStyleOnEvent(PropertyChangeEvent ev) { 775 String eName = ev.getPropertyName(); 776 if ("name" == eName || "componentOrientation" == eName) { 777 return true; 778 } 779 if ("ancestor" == eName && ev.getNewValue() != null) { |