1. /*
  2. * @(#)SynthDesktopPaneUI.java 1.9 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 javax.swing.*;
  9. import javax.swing.plaf.*;
  10. import java.beans.*;
  11. import java.awt.event.*;
  12. import java.awt.Dimension;
  13. import java.awt.Insets;
  14. import java.awt.Graphics;
  15. import java.awt.KeyboardFocusManager;
  16. import java.awt.*;
  17. import java.util.Vector;
  18. /**
  19. * Synth L&F for a desktop.
  20. *
  21. * @version 1.9, 01/23/03 (originally from version 1.44 of BasicDesktopPaneUI)
  22. * @author Joshua Outwater
  23. * @author Steve Wilson
  24. */
  25. class SynthDesktopPaneUI extends DesktopPaneUI implements
  26. PropertyChangeListener, SynthUI, LazyActionMap.Loader {
  27. private static Dimension minSize = new Dimension(0,0);
  28. private static Dimension maxSize =
  29. new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  30. private SynthStyle style;
  31. protected JDesktopPane desktop;
  32. protected DesktopManager desktopManager;
  33. /**
  34. * As of Java 2 platform v1.3 this previously undocumented field is no
  35. * longer used.
  36. * Key bindings are now defined by the LookAndFeel, please refer to
  37. * the key bindings specification for further details.
  38. *
  39. * @deprecated As of 1.3.
  40. */
  41. protected KeyStroke minimizeKey;
  42. /**
  43. * As of Java 2 platform v1.3 this previously undocumented field is no
  44. * longer used.
  45. * Key bindings are now defined by the LookAndFeel, please refer to
  46. * the key bindings specification for further details.
  47. *
  48. * @deprecated As of 1.3.
  49. */
  50. protected KeyStroke maximizeKey;
  51. /**
  52. * As of Java 2 platform v1.3 this previously undocumented field is no
  53. * longer used.
  54. * Key bindings are now defined by the LookAndFeel, please refer to
  55. * the key bindings specification for further details.
  56. *
  57. * @deprecated As of 1.3.
  58. */
  59. protected KeyStroke closeKey;
  60. /**
  61. * As of Java 2 platform v1.3 this previously undocumented field is no
  62. * longer used.
  63. * Key bindings are now defined by the LookAndFeel, please refer to
  64. * the key bindings specification for further details.
  65. *
  66. * @deprecated As of 1.3.
  67. */
  68. protected KeyStroke navigateKey;
  69. /**
  70. * As of Java 2 platform v1.3 this previously undocumented field is no
  71. * longer used.
  72. * Key bindings are now defined by the LookAndFeel, please refer to
  73. * the key bindings specification for further details.
  74. *
  75. * @deprecated As of 1.3.
  76. */
  77. protected KeyStroke navigateKey2;
  78. public static ComponentUI createUI(JComponent c) {
  79. return new SynthDesktopPaneUI();
  80. }
  81. public SynthDesktopPaneUI() {
  82. }
  83. public void installUI(JComponent c) {
  84. desktop = (JDesktopPane)c;
  85. installDefaults();
  86. installDesktopManager();
  87. installKeyboardActions();
  88. installListeners();
  89. }
  90. public void uninstallUI(JComponent c) {
  91. uninstallKeyboardActions();
  92. uninstallDesktopManager();
  93. uninstallDefaults();
  94. uninstallListeners();
  95. desktop = null;
  96. }
  97. protected void installListeners() {
  98. desktop.addPropertyChangeListener(this);
  99. }
  100. protected void installDefaults() {
  101. fetchStyle(desktop);
  102. }
  103. private void fetchStyle(JDesktopPane c) {
  104. SynthContext context = getContext(c, ENABLED);
  105. style = SynthLookAndFeel.updateStyle(context, this);
  106. context.dispose();
  107. }
  108. protected void uninstallListeners() {
  109. desktop.removePropertyChangeListener(this);
  110. }
  111. protected void uninstallDefaults() {
  112. SynthContext context = getContext(desktop, ENABLED);
  113. style.uninstallDefaults(context);
  114. context.dispose();
  115. style = null;
  116. }
  117. protected void installDesktopManager() {
  118. if(desktop.getDesktopManager() == null) {
  119. desktopManager = new DefaultDesktopManager();
  120. desktop.setDesktopManager(desktopManager);
  121. }
  122. }
  123. protected void uninstallDesktopManager() {
  124. if(desktop.getDesktopManager() == desktopManager) {
  125. desktop.setDesktopManager(null);
  126. }
  127. desktopManager = null;
  128. }
  129. protected void installKeyboardActions(){
  130. InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
  131. if (inputMap != null) {
  132. SwingUtilities.replaceUIInputMap(desktop,
  133. JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap);
  134. }
  135. inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  136. if (inputMap != null) {
  137. SwingUtilities.replaceUIInputMap(desktop,
  138. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
  139. }
  140. LazyActionMap.installLazyActionMap(desktop, this);
  141. registerKeyboardActions();
  142. }
  143. protected void registerKeyboardActions(){
  144. }
  145. protected void unregisterKeyboardActions(){
  146. }
  147. InputMap getInputMap(int condition) {
  148. if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
  149. return createInputMap(condition);
  150. }
  151. else if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
  152. return (InputMap)UIManager.get("Desktop.ancestorInputMap");
  153. }
  154. return null;
  155. }
  156. InputMap createInputMap(int condition) {
  157. if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
  158. Object[] bindings =
  159. (Object[])UIManager.get("Desktop.windowBindings");
  160. if (bindings != null) {
  161. return LookAndFeel.makeComponentInputMap(desktop, bindings);
  162. }
  163. }
  164. return null;
  165. }
  166. public void loadActionMap(JComponent c, ActionMap map) {
  167. map.put("restore", new OpenAction());
  168. map.put("close", new CloseAction());
  169. map.put("move", new MoveResizeAction("move"));
  170. map.put("resize", new MoveResizeAction("resize"));
  171. map.put("left", new MoveResizeAction("left"));
  172. map.put("shrinkLeft", new MoveResizeAction("shrinkLeft"));
  173. map.put("right", new MoveResizeAction("right"));
  174. map.put("shrinkRight", new MoveResizeAction("shrinkRight"));
  175. map.put("up", new MoveResizeAction("up"));
  176. map.put("shrinkUp", new MoveResizeAction("shrinkUp"));
  177. map.put("down", new MoveResizeAction("down"));
  178. map.put("shrinkDown", new MoveResizeAction("shrinkDown"));
  179. map.put("escape", new MoveResizeAction("escape"));
  180. map.put("minimize", new MinimizeAction());
  181. map.put("maximize", new MaximizeAction());
  182. map.put("selectNextFrame", new NavigateAction());
  183. map.put("selectPreviousFrame", new PreviousAction());
  184. map.put("navigateNext", new NavigateOutAction(true));
  185. map.put("navigatePrevious", new NavigateOutAction(false));
  186. }
  187. protected void uninstallKeyboardActions() {
  188. unregisterKeyboardActions();
  189. SwingUtilities.replaceUIInputMap(
  190. desktop, JComponent.WHEN_IN_FOCUSED_WINDOW, null);
  191. SwingUtilities.replaceUIInputMap(
  192. desktop, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
  193. SwingUtilities.replaceUIActionMap(desktop, null);
  194. }
  195. public SynthContext getContext(JComponent c) {
  196. return getContext(c, getComponentState(c));
  197. }
  198. private SynthContext getContext(JComponent c, int state) {
  199. return SynthContext.getContext(SynthContext.class, c,
  200. SynthLookAndFeel.getRegion(c), style, state);
  201. }
  202. private Region getRegion(JComponent c) {
  203. return SynthLookAndFeel.getRegion(c);
  204. }
  205. private int getComponentState(JComponent c) {
  206. return SynthLookAndFeel.getComponentState(c);
  207. }
  208. public void update(Graphics g, JComponent c) {
  209. SynthContext context = getContext(c);
  210. SynthLookAndFeel.update(context, g);
  211. paint(context, g);
  212. context.dispose();
  213. }
  214. public void paint(Graphics g, JComponent c) {
  215. SynthContext context = getContext(c);
  216. paint(context, g);
  217. context.dispose();
  218. }
  219. protected void paint(SynthContext context, Graphics g) {
  220. }
  221. public Dimension getPreferredSize(JComponent c) {return null;}
  222. public Dimension getMinimumSize(JComponent c) {
  223. return minSize;
  224. }
  225. public Dimension getMaximumSize(JComponent c){
  226. return maxSize;
  227. }
  228. public void propertyChange(PropertyChangeEvent evt) {
  229. if (SynthLookAndFeel.shouldUpdateStyle(evt)) {
  230. fetchStyle((JDesktopPane)evt.getSource());
  231. }
  232. }
  233. /*
  234. * Key binding for accessibility -----------------
  235. */
  236. private static Vector framesCache;
  237. private boolean moving = false;
  238. private boolean resizing = false;
  239. private final int MOVE_RESIZE_INCREMENT = 10;
  240. /*
  241. * Handles restoring a minimized or maximized internal frame.
  242. */
  243. protected class OpenAction extends AbstractAction {
  244. public void actionPerformed(ActionEvent e) {
  245. // restore the selected minimized or maximized frame
  246. JInternalFrame f = desktop.getSelectedFrame();
  247. if (f == null) return;
  248. try {
  249. if (f.isIcon()) {
  250. f.setIcon(false);
  251. } else if (f.isMaximum()) {
  252. f.setMaximum(false);
  253. }
  254. f.setSelected(true);
  255. } catch (PropertyVetoException pve) {
  256. }
  257. }
  258. public boolean isEnabled() {
  259. return true;
  260. }
  261. }
  262. /*
  263. * Handles closing an internal frame
  264. */
  265. protected class CloseAction extends AbstractAction {
  266. public void actionPerformed(ActionEvent e) {
  267. JInternalFrame f = desktop.getSelectedFrame();
  268. if (f == null) {
  269. return;
  270. }
  271. if (f.isClosable()) {
  272. try {
  273. f.setClosed(true);
  274. } catch (PropertyVetoException pve) {
  275. }
  276. }
  277. }
  278. public boolean isEnabled() {
  279. return true;
  280. }
  281. }
  282. /*
  283. * Handles moving and resizing an internal frame
  284. */
  285. private class MoveResizeAction extends AbstractAction {
  286. private String command;
  287. public MoveResizeAction(String command) {
  288. this.command = command;
  289. }
  290. public void actionPerformed(ActionEvent e) {
  291. JInternalFrame c = desktop.getSelectedFrame();
  292. if (c == null) {
  293. return;
  294. }
  295. if ("move".equals(command)) {
  296. moving = true;
  297. resizing = false;
  298. return;
  299. } else if ("resize".equals(command)) {
  300. moving = false;
  301. resizing = true;
  302. return;
  303. } else if ("escape".equals(command)) {
  304. moving = resizing = false;
  305. return;
  306. }
  307. if (!moving && !resizing) {
  308. return;
  309. }
  310. Dimension size = c.getSize();
  311. Dimension minSize = c.getMinimumSize();
  312. Point loc = c.getLocation();
  313. if ("left".equals(command)) {
  314. if (moving) {
  315. c.setLocation(loc.x - MOVE_RESIZE_INCREMENT, loc.y);
  316. } else if (resizing) {
  317. c.setLocation(loc.x - MOVE_RESIZE_INCREMENT, loc.y);
  318. c.setSize(size.width + MOVE_RESIZE_INCREMENT, size.height);
  319. }
  320. } else if ("right".equals(command)) {
  321. if (moving) {
  322. c.setLocation(loc.x + MOVE_RESIZE_INCREMENT, loc.y);
  323. } else if (resizing) {
  324. c.setLocation(loc.x, loc.y);
  325. c.setSize(size.width + MOVE_RESIZE_INCREMENT, size.height);
  326. }
  327. } else if ("up".equals(command)) {
  328. if (moving) {
  329. c.setLocation(loc.x, loc.y - MOVE_RESIZE_INCREMENT);
  330. } else if (resizing) {
  331. c.setLocation(loc.x, loc.y - MOVE_RESIZE_INCREMENT);
  332. c.setSize(size.width, size.height + MOVE_RESIZE_INCREMENT);
  333. }
  334. } else if ("down".equals(command)) {
  335. if (moving) {
  336. c.setLocation(loc.x, loc.y + MOVE_RESIZE_INCREMENT);
  337. } else if (resizing) {
  338. c.setLocation(loc.x, loc.y);
  339. c.setSize(size.width, size.height + MOVE_RESIZE_INCREMENT);
  340. }
  341. } else if ("shrinkLeft".equals(command) && resizing) {
  342. if (minSize.width < (size.width - MOVE_RESIZE_INCREMENT)) {
  343. c.setLocation(loc.x, loc.y);
  344. c.setSize(size.width - MOVE_RESIZE_INCREMENT, size.height);
  345. } else {
  346. c.setSize(minSize.width, size.height);
  347. }
  348. } else if ("shrinkRight".equals(command) && resizing) {
  349. if (minSize.width < (size.width - MOVE_RESIZE_INCREMENT)) {
  350. c.setLocation(loc.x + MOVE_RESIZE_INCREMENT, loc.y);
  351. c.setSize(size.width - MOVE_RESIZE_INCREMENT, size.height);
  352. } else {
  353. c.setLocation(loc.x - minSize.width + size.width , loc.y);
  354. c.setSize(minSize.width, size.height);
  355. }
  356. } else if ("shrinkUp".equals(command) && resizing) {
  357. if (minSize.height < (size.height - MOVE_RESIZE_INCREMENT)) {
  358. c.setLocation(loc.x, loc.y);
  359. c.setSize(size.width, size.height - MOVE_RESIZE_INCREMENT);
  360. } else {
  361. c.setSize(size.width, minSize.height);
  362. }
  363. } else if ("shrinkDown".equals(command) && resizing) {
  364. if (minSize.height < (size.height - MOVE_RESIZE_INCREMENT)) {
  365. c.setLocation(loc.x, loc.y + MOVE_RESIZE_INCREMENT);
  366. c.setSize(size.width, size.height - MOVE_RESIZE_INCREMENT);
  367. } else {
  368. c.setLocation(loc.x, loc.y - minSize.height + size.height);
  369. c.setSize(size.width, minSize.height);
  370. }
  371. }
  372. }
  373. public boolean isEnabled() {
  374. return true;
  375. }
  376. }
  377. /*
  378. * Handles minimizing an internal frame
  379. */
  380. protected class MinimizeAction extends AbstractAction {
  381. public void actionPerformed(ActionEvent e) {
  382. // minimize the selected frame
  383. JInternalFrame f = desktop.getSelectedFrame();
  384. if (f == null) {
  385. return;
  386. }
  387. if (f.isIconifiable() && ! f.isIcon()) {
  388. try {
  389. f.setIcon(true);
  390. } catch (PropertyVetoException pve) {
  391. }
  392. }
  393. }
  394. public boolean isEnabled() {
  395. return true;
  396. }
  397. }
  398. /*
  399. * Handles maximizing an internal frame
  400. */
  401. protected class MaximizeAction extends AbstractAction {
  402. public void actionPerformed(ActionEvent e) {
  403. // maximize the selected frame
  404. JInternalFrame f = desktop.getSelectedFrame();
  405. if (f == null) {
  406. return;
  407. }
  408. if (f.isMaximizable() && !f.isMaximum()) {
  409. if (f.isIcon()) {
  410. try {
  411. f.setIcon(false);
  412. f.setMaximum(true);
  413. } catch (PropertyVetoException pve) {}
  414. } else
  415. try {
  416. f.setMaximum(true);
  417. } catch (PropertyVetoException pve) {
  418. }
  419. }
  420. }
  421. public boolean isEnabled() {
  422. return true;
  423. }
  424. }
  425. /*
  426. * Handles navigating to the next internal frame.
  427. */
  428. protected class NavigateAction extends AbstractAction {
  429. public void actionPerformed(ActionEvent e) {
  430. // navigate to the next frame
  431. int i = 0;
  432. verifyFramesCache();
  433. if (framesCache.size() == 0) {
  434. return;
  435. }
  436. JInternalFrame f = desktop.getSelectedFrame();
  437. if (f != null) {
  438. i = framesCache.indexOf(f);
  439. }
  440. if (i == -1) {
  441. /* if the frame is not there, its icon may be */
  442. i = framesCache.indexOf(f.getDesktopIcon());
  443. if (i == -1) {
  444. return; /* error */
  445. }
  446. }
  447. if (++i == framesCache.size()) {
  448. i = 0; /* wrap */
  449. }
  450. JComponent c = (JComponent) framesCache.elementAt(i);
  451. if (c instanceof JInternalFrame) {
  452. try {
  453. ((JInternalFrame) c).setSelected(true);
  454. desktopManager.activateFrame((JInternalFrame) c);
  455. }
  456. catch (PropertyVetoException pve) {}
  457. } else {
  458. /* it had better be an icon! */
  459. if (!(c instanceof JInternalFrame.JDesktopIcon)) {
  460. /* error */
  461. return;
  462. }
  463. try {
  464. ((JInternalFrame)((JInternalFrame.JDesktopIcon)c).
  465. getInternalFrame()).setSelected(true);
  466. desktopManager.activateFrame(
  467. ((JInternalFrame.JDesktopIcon) c).getInternalFrame());
  468. } catch (PropertyVetoException pve) {}
  469. }
  470. }
  471. public boolean isEnabled() {
  472. return true;
  473. }
  474. }
  475. /*
  476. * Handles navigating to the previous internal frame.
  477. */
  478. private class PreviousAction extends AbstractAction {
  479. public void actionPerformed(ActionEvent e) {
  480. // navigate to the previous internal frame
  481. int i = 0;
  482. verifyFramesCache();
  483. if (framesCache.size() == 0) return;
  484. JInternalFrame f = desktop.getSelectedFrame();
  485. if (f != null) i = framesCache.indexOf(f);
  486. if (i == -1) {
  487. /* if the frame is not there, its icon may be */
  488. i = framesCache.indexOf(f.getDesktopIcon());
  489. if (i == -1) {
  490. /* error */ return;
  491. }
  492. }
  493. if (--i == -1) /* wrap */ i = framesCache.size() - 1;
  494. JComponent c = (JComponent) framesCache.elementAt(i);
  495. if (c instanceof JInternalFrame) {
  496. try {
  497. ((JInternalFrame) c).setSelected(true);
  498. }
  499. catch (PropertyVetoException pve) {}
  500. } else {
  501. /* it had better be an icon! */
  502. if (!(c instanceof JInternalFrame.JDesktopIcon)){
  503. /* error */
  504. return;
  505. }
  506. try {
  507. ((JInternalFrame)((JInternalFrame.JDesktopIcon) c).getInternalFrame()).setSelected(true);
  508. }
  509. catch (PropertyVetoException pve) {}
  510. }
  511. }
  512. public boolean isEnabled() {
  513. return true;
  514. }
  515. }
  516. /**
  517. * Handles navigating to the component before or after the desktop.
  518. */
  519. private class NavigateOutAction extends AbstractAction {
  520. private boolean moveForward;
  521. public NavigateOutAction(boolean moveForward) {
  522. this.moveForward = moveForward;
  523. }
  524. public void actionPerformed(ActionEvent e) {
  525. Container cycleRoot = desktop.getFocusCycleRootAncestor();
  526. if (cycleRoot != null) {
  527. FocusTraversalPolicy policy =
  528. cycleRoot.getFocusTraversalPolicy();
  529. if (policy != null && policy instanceof
  530. SortingFocusTraversalPolicy) {
  531. SortingFocusTraversalPolicy sPolicy =
  532. (SortingFocusTraversalPolicy)policy;
  533. boolean idc = sPolicy.getImplicitDownCycleTraversal();
  534. try {
  535. sPolicy.setImplicitDownCycleTraversal(false);
  536. if (moveForward) {
  537. KeyboardFocusManager.
  538. getCurrentKeyboardFocusManager().
  539. focusNextComponent(desktop);
  540. } else {
  541. KeyboardFocusManager.
  542. getCurrentKeyboardFocusManager().
  543. focusPreviousComponent(desktop);
  544. }
  545. } finally {
  546. sPolicy.setImplicitDownCycleTraversal(idc);
  547. }
  548. }
  549. }
  550. }
  551. public boolean isEnabled() {
  552. return true;
  553. }
  554. }
  555. /*
  556. * Verifies the internal frames cache is up to date.
  557. */
  558. private void verifyFramesCache() {
  559. // Need to initialize?
  560. if (framesCache == null) {
  561. framesCache = new Vector();
  562. }
  563. // Check whether any internal frames have closed in
  564. // which case we have to refresh the frames cache.
  565. boolean framesHaveClosed = false;
  566. int len = framesCache.size();
  567. for (int i = 0; i < len; i++) {
  568. JComponent c =
  569. (JComponent)framesCache.elementAt(i);
  570. if (c instanceof JInternalFrame) {
  571. JInternalFrame f = (JInternalFrame)c;
  572. if (f.isClosed()) {
  573. framesHaveClosed = true;
  574. break;
  575. }
  576. }
  577. else if (c instanceof JInternalFrame.JDesktopIcon) {
  578. JInternalFrame.JDesktopIcon icon =
  579. (JInternalFrame.JDesktopIcon)c;
  580. JInternalFrame f = (JInternalFrame)icon.getInternalFrame();
  581. if (f.isClosed()) {
  582. framesHaveClosed = true;
  583. break;
  584. }
  585. }
  586. }
  587. JInternalFrame [] allFrames = desktop.getAllFrames();
  588. if (framesHaveClosed || allFrames.length != framesCache.size()) {
  589. // Cache frames starting at the lowest layer.
  590. framesCache.clear();
  591. int low = desktop.lowestLayer();
  592. int high = desktop.highestLayer();
  593. for (int i = high; i >= low; i--) {
  594. Component [] comp = desktop.getComponentsInLayer(i);
  595. if (comp.length > 0) {
  596. for (int j = 0; j < comp.length; j++) {
  597. framesCache.addElement(comp[j]);
  598. }
  599. }
  600. }
  601. }
  602. }
  603. // End of accessibility keybindings
  604. }