1. /*
  2. * @(#)SynthLookAndFeel.java 1.37 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.gtk;
  8. import java.awt.*;
  9. import java.awt.event.*;
  10. import java.beans.*;
  11. import java.lang.ref.*;
  12. import java.util.*;
  13. import javax.swing.*;
  14. import javax.swing.border.*;
  15. import javax.swing.plaf.*;
  16. import sun.awt.AppContext;
  17. /**
  18. * @version 1.37, 01/23/03
  19. */
  20. class SynthLookAndFeel extends LookAndFeel {
  21. static final Insets EMPTY_UIRESOURCE_INSETS = new InsetsUIResource(
  22. 0, 0, 0, 0);
  23. private static final Object STYLE_FACTORY_KEY =
  24. new StringBuffer("com.sun.java.swing.plaf.gtk.StyleCache");
  25. /**
  26. * The last SynthStyleFactory that was asked for from AppContext
  27. * <code>lastContext</code>.
  28. */
  29. private static SynthStyleFactory lastFactory;
  30. /**
  31. * If this is true it indicates there is more than one AppContext active
  32. * and that we need to make sure in getStyleCache the requesting
  33. * AppContext matches that of <code>lastContext</code> before returning
  34. * it.
  35. */
  36. private static boolean multipleApps;
  37. /**
  38. * AppContext lastLAF came from.
  39. */
  40. private static AppContext lastContext;
  41. /**
  42. * Sets the SynthStyleFactory for the current AppContext, null unsets
  43. * its for the current AppContext.
  44. */
  45. public static void setStyleFactory(SynthStyleFactory cache) {
  46. synchronized(SynthLookAndFeel.class) {
  47. if (lastFactory == null) {
  48. lastFactory = cache;
  49. lastContext = AppContext.getAppContext();
  50. }
  51. else if (cache == null) {
  52. AppContext context = AppContext.getAppContext();
  53. if (lastContext == context) {
  54. lastFactory = null;
  55. }
  56. AppContext.getAppContext().put(STYLE_FACTORY_KEY, null);
  57. }
  58. else {
  59. // More than one active
  60. multipleApps = true;
  61. AppContext.getAppContext().put(STYLE_FACTORY_KEY, cache);
  62. }
  63. }
  64. }
  65. /**
  66. * Returns the current SynthStyleFactory.
  67. */
  68. public static SynthStyleFactory getStyleFactory() {
  69. synchronized(SynthLookAndFeel.class) {
  70. if (!multipleApps) {
  71. return lastFactory;
  72. }
  73. AppContext context = AppContext.getAppContext();
  74. if (lastContext == context) {
  75. return lastFactory;
  76. }
  77. lastContext = context;
  78. lastFactory = (SynthStyleFactory)AppContext.getAppContext().get
  79. (STYLE_FACTORY_KEY);
  80. return lastFactory;
  81. }
  82. }
  83. public static int getComponentState(Component c) {
  84. if (c.isEnabled()) {
  85. if (c.isFocusOwner()) {
  86. return SynthUI.ENABLED | SynthUI.FOCUSED;
  87. }
  88. return SynthUI.ENABLED;
  89. }
  90. return SynthUI.DISABLED;
  91. }
  92. public static SynthStyle getStyle(JComponent c, Region region) {
  93. return getStyleFactory().getStyle(c, region);
  94. }
  95. /**
  96. * Returns the modifier to use in registering accelerators and the like.
  97. */
  98. public static int getAcceleratorModifier() {
  99. // PENDING: this should be an instance method.
  100. return InputEvent.ALT_MASK;
  101. }
  102. /**
  103. * Returns true if the MouseEvent represents a primary MouseButton.
  104. */
  105. public static boolean isPrimaryMouseButton(MouseEvent me) {
  106. // PENDING: this should be an instance method.
  107. return SwingUtilities.isLeftMouseButton(me);
  108. }
  109. /**
  110. * Returns true if the Style should be updated in response to the
  111. * specified PropertyChangeEvent.
  112. */
  113. static boolean shouldUpdateStyle(PropertyChangeEvent event) {
  114. // 'ancestor' will be interned in JComponent, making this safe.
  115. return ("ancestor" == event.getPropertyName() &&
  116. event.getNewValue() != null);
  117. }
  118. /**
  119. * A convience method that will reset the Style of StyleContext if
  120. * necessary.
  121. *
  122. * @return newStyle
  123. */
  124. static SynthStyle updateStyle(SynthContext context, SynthUI ui) {
  125. SynthStyle newStyle = getStyle(context.getComponent(),
  126. context.getRegion());
  127. SynthStyle oldStyle = context.getStyle();
  128. if (newStyle != oldStyle) {
  129. if (oldStyle != null) {
  130. oldStyle.uninstallDefaults(context);
  131. }
  132. context.setStyle(newStyle);
  133. newStyle.installDefaults(context, ui);
  134. }
  135. return newStyle;
  136. }
  137. static SynthEventListener getSynthEventListener(Component c) {
  138. PropertyChangeListener[] listeners = c.getPropertyChangeListeners();
  139. for (int counter = listeners.length - 1; counter >= 0; counter--) {
  140. if (listeners[counter] instanceof SynthEventListener) {
  141. return (SynthEventListener)listeners[counter];
  142. }
  143. }
  144. return null;
  145. }
  146. static void playSound(JComponent c, Object actionKey) {
  147. // PENDING: sounds
  148. /*
  149. ActionMap map = c.getActionMap();
  150. if (map != null) {
  151. Action audioAction = map.get(actionName);
  152. if (audioAction != null) {
  153. // pass off firing the Action to a utility method
  154. playSound(audioAction);
  155. }
  156. }
  157. */
  158. }
  159. /**
  160. * Returns the Region for c, or defaultRegion if a Region has
  161. * not been registered for c yet.
  162. */
  163. // PENDING(sky) - need to rethink this.
  164. // Made public so that DefaultSynthStyleFactory could access it
  165. public static Region getRegion(JComponent c) {
  166. return Region.getRegion(c);
  167. }
  168. /**
  169. * A convenience method to return where the foreground should be
  170. * painted for the Component identified by the passed in
  171. * AbstractSynthContext.
  172. */
  173. public static Insets getPaintingInsets(SynthContext state,
  174. Insets insets) {
  175. if (state.isSubregion()) {
  176. insets = state.getStyle().getInsets(state, insets);
  177. }
  178. else {
  179. insets = state.getComponent().getInsets(insets);
  180. }
  181. return insets;
  182. }
  183. /**
  184. * Convenience method to transfer focus to the next child of component.
  185. */
  186. // PENDING: remove this when a variant of this is added to awt.
  187. static void compositeRequestFocus(Component component) {
  188. if (component instanceof Container) {
  189. Container container = (Container)component;
  190. if (container.isFocusCycleRoot()) {
  191. FocusTraversalPolicy policy = container.
  192. getFocusTraversalPolicy();
  193. Component comp = policy.getDefaultComponent(container);
  194. if (comp!=null) {
  195. comp.requestFocus();
  196. return;
  197. }
  198. }
  199. Container rootAncestor = container.getFocusCycleRootAncestor();
  200. if (rootAncestor!=null) {
  201. FocusTraversalPolicy policy = rootAncestor.
  202. getFocusTraversalPolicy();
  203. Component comp = policy.getComponentAfter(rootAncestor,
  204. container);
  205. if (comp!=null && SwingUtilities.isDescendingFrom(comp,
  206. container)) {
  207. comp.requestFocus();
  208. return;
  209. }
  210. }
  211. }
  212. component.requestFocus();
  213. }
  214. /**
  215. * A convenience method that handles painting of the background.
  216. * All SynthUI implementations should override update and invoke
  217. * this method.
  218. */
  219. static void update(SynthContext state, Graphics g) {
  220. paintRegion(state, g, null);
  221. }
  222. /**
  223. * A convenience method that handles painting of the background for
  224. * subregions. All SynthUI's that have subregions should invoke
  225. * this method, than paint the foreground.
  226. */
  227. static void updateSubregion(SynthContext state, Graphics g,
  228. Rectangle bounds) {
  229. paintRegion(state, g, bounds);
  230. }
  231. /**
  232. * Obtains a foreground Painter from context's SynthStyle and
  233. * paints it.
  234. *
  235. * @param bounds region to paint in, if null the bounds of
  236. * the component are used.
  237. */
  238. static void paintForeground(SynthContext context, Graphics g,
  239. Rectangle bounds) {
  240. JComponent c = context.getComponent();
  241. SynthPainter painter = (SynthPainter)context.getStyle().get(
  242. context, "foreground");
  243. if (painter != null) {
  244. if (bounds == null) {
  245. // PENDING: Should this offset by the insets?
  246. /*
  247. Insets insets = c.getInsets();
  248. painter.paint(context, "foreground", g,
  249. insets.left, insets.top, c.getWidth() -
  250. (insets.left + insets.right),
  251. c.getHeight() - (insets.top + insets.bottom));
  252. */
  253. painter.paint(context, "foreground", g, 0, 0, c.getWidth(),
  254. c.getHeight());
  255. }
  256. else {
  257. painter.paint(context, "foreground", g,
  258. bounds.x, bounds.y, bounds.width, bounds.height);
  259. }
  260. }
  261. }
  262. private static void paintRegion(SynthContext state, Graphics g,
  263. Rectangle bounds) {
  264. JComponent c = state.getComponent();
  265. SynthStyle style = state.getStyle();
  266. int x, y, width, height;
  267. if (bounds == null) {
  268. x = 0;
  269. y = 0;
  270. width = c.getWidth();
  271. height = c.getHeight();
  272. }
  273. else {
  274. x = bounds.x;
  275. y = bounds.y;
  276. width = bounds.width;
  277. height = bounds.height;
  278. }
  279. // Fill in the background, if necessary.
  280. boolean subregion = state.isSubregion();
  281. if ((subregion && style.isOpaque(state)) ||
  282. (!subregion && c.isOpaque())) {
  283. g.setColor(style.getColor(state, ColorType.BACKGROUND));
  284. g.fillRect(x, y, width, height);
  285. }
  286. SynthPainter painter = style.getBackgroundPainter(state);
  287. // PENDING: may need to reorder these.
  288. // Paint the background, if necessary.
  289. if (painter != null) {
  290. // NOTE: This intentionally does not look at insets, it is
  291. // up to the painter to honor or ignore these.
  292. painter.paint(state, "background", g, x, y, width, height);
  293. }
  294. // And the border, if necessary.
  295. if (state.isSubregion()) {
  296. SynthPainter borderPainter = style.getBorderPainter(state);
  297. if (borderPainter != null) {
  298. borderPainter.paint(state, "border", g, x, y, width,
  299. height);
  300. }
  301. }
  302. }
  303. static boolean isLeftToRight(Component c) {
  304. return c.getComponentOrientation().isLeftToRight();
  305. }
  306. /**
  307. * Creates the Synth look and feel class for the passed in Component.
  308. */
  309. public static ComponentUI createUI(JComponent c) {
  310. String key = c.getUIClassID().intern();
  311. if (key == "ButtonUI") {
  312. return SynthButtonUI.createUI(c);
  313. }
  314. else if (key == "CheckBoxUI") {
  315. return SynthCheckBoxUI.createUI(c);
  316. }
  317. else if (key == "CheckBoxMenuItemUI") {
  318. return SynthCheckBoxMenuItemUI.createUI(c);
  319. }
  320. else if (key == "ColorChooserUI") {
  321. return SynthColorChooserUI.createUI(c);
  322. }
  323. else if (key == "ComboBoxUI") {
  324. return SynthComboBoxUI.createUI(c);
  325. }
  326. else if (key == "DesktopPaneUI") {
  327. return SynthDesktopPaneUI.createUI(c);
  328. }
  329. else if (key == "DesktopIconUI") {
  330. return SynthDesktopIconUI.createUI(c);
  331. }
  332. else if (key == "EditorPaneUI") {
  333. return SynthEditorPaneUI.createUI(c);
  334. }
  335. else if (key == "FormattedTextFieldUI") {
  336. return SynthFormattedTextFieldUI.createUI(c);
  337. }
  338. else if (key == "InternalFrameUI") {
  339. return SynthInternalFrameUI.createUI(c);
  340. }
  341. else if (key == "LabelUI") {
  342. return SynthLabelUI.createUI(c);
  343. }
  344. else if (key == "ListUI") {
  345. return SynthListUI.createUI(c);
  346. }
  347. else if (key == "MenuBarUI") {
  348. return SynthMenuBarUI.createUI(c);
  349. }
  350. else if (key == "MenuUI") {
  351. return SynthMenuUI.createUI(c);
  352. }
  353. else if (key == "MenuItemUI") {
  354. return SynthMenuItemUI.createUI(c);
  355. }
  356. else if (key == "OptionPaneUI") {
  357. return SynthOptionPaneUI.createUI(c);
  358. }
  359. else if (key == "PanelUI") {
  360. return SynthPanelUI.createUI(c);
  361. }
  362. else if (key == "PasswordFieldUI") {
  363. return SynthPasswordFieldUI.createUI(c);
  364. }
  365. else if (key == "PopupMenuSeparatorUI") {
  366. return SynthSeparatorUI.createUI(c);
  367. }
  368. else if (key == "PopupMenuUI") {
  369. return SynthPopupMenuUI.createUI(c);
  370. }
  371. else if (key == "ProgressBarUI") {
  372. return SynthProgressBarUI.createUI(c);
  373. }
  374. else if (key == "RadioButtonUI") {
  375. return SynthRadioButtonUI.createUI(c);
  376. }
  377. else if (key == "RadioButtonMenuItemUI") {
  378. return SynthRadioButtonMenuItemUI.createUI(c);
  379. }
  380. else if (key == "RootPaneUI") {
  381. return SynthRootPaneUI.createUI(c);
  382. }
  383. else if (key == "ScrollBarUI") {
  384. return SynthScrollBarUI.createUI(c);
  385. }
  386. else if (key == "ScrollPaneUI") {
  387. return SynthScrollPaneUI.createUI(c);
  388. }
  389. else if (key == "SeparatorUI") {
  390. return SynthSeparatorUI.createUI(c);
  391. }
  392. else if (key == "SliderUI") {
  393. return SynthSliderUI.createUI(c);
  394. }
  395. else if (key == "SpinnerUI") {
  396. return SynthSpinnerUI.createUI(c);
  397. }
  398. else if (key == "SplitPaneUI") {
  399. return SynthSplitPaneUI.createUI(c);
  400. }
  401. else if (key == "TabbedPaneUI") {
  402. return SynthTabbedPaneUI.createUI(c);
  403. }
  404. else if (key == "TableUI") {
  405. return SynthTableUI.createUI(c);
  406. }
  407. else if (key == "TableHeaderUI") {
  408. return SynthTableHeaderUI.createUI(c);
  409. }
  410. else if (key == "TextAreaUI") {
  411. return SynthTextAreaUI.createUI(c);
  412. }
  413. else if (key == "TextFieldUI") {
  414. return SynthTextFieldUI.createUI(c);
  415. }
  416. else if (key == "TextPaneUI") {
  417. return SynthTextPaneUI.createUI(c);
  418. }
  419. else if (key == "ToggleButtonUI") {
  420. return SynthToggleButtonUI.createUI(c);
  421. }
  422. else if (key == "ToolBarSeparatorUI") {
  423. return SynthSeparatorUI.createUI(c);
  424. }
  425. else if (key == "ToolBarUI") {
  426. return SynthToolBarUI.createUI(c);
  427. }
  428. else if (key == "ToolTipUI") {
  429. return SynthToolTipUI.createUI(c);
  430. }
  431. else if (key == "TreeUI") {
  432. return SynthTreeUI.createUI(c);
  433. }
  434. else if (key == "ViewportUI") {
  435. return SynthViewportUI.createUI(c);
  436. }
  437. return null;
  438. }
  439. public SynthLookAndFeel() {
  440. }
  441. public void initialize() {
  442. }
  443. public void uninitialize() {
  444. // PENDING: this should be possible, but unfortunately there are
  445. // a handful of things that retain references to the LookAndFeel
  446. // and expect things to work, these should all be fixed and this
  447. // uncommented.
  448. // setStyleFactory(null);
  449. super.uninitialize();
  450. }
  451. public UIDefaults getDefaults() {
  452. UIDefaults table = new UIDefaults();
  453. Region.registerUIs(table);
  454. table.setDefaultLocale(Locale.getDefault());
  455. table.addResourceBundle(
  456. "com.sun.swing.internal.plaf.basic.resources.basic" );
  457. // These need to be defined for JColorChooser to work.
  458. table.put("ColorChooser.swatchesRecentSwatchSize",
  459. new Dimension(10, 10));
  460. table.put("ColorChooser.swatchesDefaultRecentColor", Color.RED);
  461. table.put("ColorChooser.swatchesSwatchSize", new Dimension(10, 10));
  462. return table;
  463. }
  464. public boolean isSupportedLookAndFeel() {
  465. return true;
  466. }
  467. public boolean isNativeLookAndFeel() {
  468. return false;
  469. }
  470. public String getDescription() {
  471. return "Synth look and feel";
  472. }
  473. public String getName() {
  474. return "Synth look and feel";
  475. }
  476. public String getID() {
  477. return "Synth";
  478. }
  479. }