1 /*
2 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package javax.swing.plaf.basic;
27
28 import javax.swing;
29 import javax.swing.plaf;
30
31 import java.beans;
32
33 import java.awt.event;
34 import java.awt.Dimension;
35 import java.awt.Insets;
36 import java.awt.Graphics;
37 import java.awt.KeyboardFocusManager;
38 import java.awt;
39 import java.util.Vector;
40 import sun.swing.DefaultLookup;
41 import sun.swing.UIAction;
42 import sun.awt.AppContext;
43
44 /**
45 * Basic L&F for a desktop.
46 *
47 * @author Steve Wilson
48 */
49 public class BasicDesktopPaneUI extends DesktopPaneUI {
50 // Old actions forward to an instance of this.
51 private static final Actions SHARED_ACTION = new Actions();
52 private static Dimension minSize = new Dimension(0,0);
53 private static Dimension maxSize = new Dimension(Integer.MAX_VALUE,
54 Integer.MAX_VALUE);
55 private Handler handler;
56 private PropertyChangeListener pcl;
57
58 protected JDesktopPane desktop;
59 protected DesktopManager desktopManager;
60
61 /**
62 * As of Java 2 platform v1.3 this previously undocumented field is no
63 * longer used.
64 * Key bindings are now defined by the LookAndFeel, please refer to
65 * the key bindings specification for further details.
66 *
67 * @deprecated As of 1.3.
68 */
69 @Deprecated
70 protected KeyStroke minimizeKey;
71 /**
72 * As of Java 2 platform v1.3 this previously undocumented field is no
73 * longer used.
74 * Key bindings are now defined by the LookAndFeel, please refer to
75 * the key bindings specification for further details.
76 *
77 * @deprecated As of 1.3.
78 */
79 @Deprecated
80 protected KeyStroke maximizeKey;
81 /**
82 * As of Java 2 platform v1.3 this previously undocumented field is no
83 * longer used.
84 * Key bindings are now defined by the LookAndFeel, please refer to
85 * the key bindings specification for further details.
86 *
87 * @deprecated As of 1.3.
88 */
89 @Deprecated
90 protected KeyStroke closeKey;
91 /**
92 * As of Java 2 platform v1.3 this previously undocumented field is no
93 * longer used.
94 * Key bindings are now defined by the LookAndFeel, please refer to
95 * the key bindings specification for further details.
96 *
97 * @deprecated As of 1.3.
98 */
99 @Deprecated
100 protected KeyStroke navigateKey;
101 /**
102 * As of Java 2 platform v1.3 this previously undocumented field is no
103 * longer used.
104 * Key bindings are now defined by the LookAndFeel, please refer to
105 * the key bindings specification for further details.
106 *
107 * @deprecated As of 1.3.
108 */
109 @Deprecated
110 protected KeyStroke navigateKey2;
111
112 public static ComponentUI createUI(JComponent c) {
113 return new BasicDesktopPaneUI();
114 }
115
116 public BasicDesktopPaneUI() {
117 }
118
119 public void installUI(JComponent c) {
120 desktop = (JDesktopPane)c;
121 installDefaults();
122 installDesktopManager();
123 installListeners();
124 installKeyboardActions();
125 }
126
127 public void uninstallUI(JComponent c) {
128 uninstallKeyboardActions();
129 uninstallListeners();
130 uninstallDesktopManager();
131 uninstallDefaults();
132 desktop = null;
133 handler = null;
134 }
135
136 protected void installDefaults() {
137 if (desktop.getBackground() == null ||
138 desktop.getBackground() instanceof UIResource) {
139 desktop.setBackground(UIManager.getColor("Desktop.background"));
140 }
141 LookAndFeel.installProperty(desktop, "opaque", Boolean.TRUE);
142 }
143
144 protected void uninstallDefaults() { }
145
146 /**
147 * Installs the <code>PropertyChangeListener</code> returned from
148 * <code>createPropertyChangeListener</code> on the
149 * <code>JDesktopPane</code>.
150 *
151 * @since 1.5
152 * @see #createPropertyChangeListener
153 */
154 protected void installListeners() {
155 pcl = createPropertyChangeListener();
156 desktop.addPropertyChangeListener(pcl);
157 }
158
159 /**
160 * Uninstalls the <code>PropertyChangeListener</code> returned from
161 * <code>createPropertyChangeListener</code> from the
162 * <code>JDesktopPane</code>.
163 *
164 * @since 1.5
165 * @see #createPropertyChangeListener
166 */
167 protected void uninstallListeners() {
168 desktop.removePropertyChangeListener(pcl);
169 pcl = null;
170 }
171
172 protected void installDesktopManager() {
173 desktopManager = desktop.getDesktopManager();
174 if(desktopManager == null) {
175 desktopManager = new BasicDesktopManager();
176 desktop.setDesktopManager(desktopManager);
177 }
178 }
179
180 protected void uninstallDesktopManager() {
181 if(desktop.getDesktopManager() instanceof UIResource) {
182 desktop.setDesktopManager(null);
183 }
184 desktopManager = null;
185 }
186
187 protected void installKeyboardActions(){
188 InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
189 if (inputMap != null) {
190 SwingUtilities.replaceUIInputMap(desktop,
191 JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap);
192 }
193 inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
194 if (inputMap != null) {
195 SwingUtilities.replaceUIInputMap(desktop,
196 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
197 inputMap);
198 }
199
200 LazyActionMap.installLazyActionMap(desktop, BasicDesktopPaneUI.class,
201 "DesktopPane.actionMap");
202 registerKeyboardActions();
203 }
204
205 protected void registerKeyboardActions(){
206 }
207
208 protected void unregisterKeyboardActions(){
209 }
210
211 InputMap getInputMap(int condition) {
212 if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
213 return createInputMap(condition);
214 }
215 else if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
216 return (InputMap)DefaultLookup.get(desktop, this,
217 "Desktop.ancestorInputMap");
218 }
219 return null;
220 }
221
222 InputMap createInputMap(int condition) {
223 if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
224 Object[] bindings = (Object[])DefaultLookup.get(desktop,
225 this, "Desktop.windowBindings");
226
227 if (bindings != null) {
228 return LookAndFeel.makeComponentInputMap(desktop, bindings);
229 }
230 }
231 return null;
232 }
233
234 static void loadActionMap(LazyActionMap map) {
235 map.put(new Actions(Actions.RESTORE));
236 map.put(new Actions(Actions.CLOSE));
237 map.put(new Actions(Actions.MOVE));
238 map.put(new Actions(Actions.RESIZE));
239 map.put(new Actions(Actions.LEFT));
240 map.put(new Actions(Actions.SHRINK_LEFT));
241 map.put(new Actions(Actions.RIGHT));
242 map.put(new Actions(Actions.SHRINK_RIGHT));
243 map.put(new Actions(Actions.UP));
244 map.put(new Actions(Actions.SHRINK_UP));
245 map.put(new Actions(Actions.DOWN));
246 map.put(new Actions(Actions.SHRINK_DOWN));
247 map.put(new Actions(Actions.ESCAPE));
248 map.put(new Actions(Actions.MINIMIZE));
249 map.put(new Actions(Actions.MAXIMIZE));
250 map.put(new Actions(Actions.NEXT_FRAME));
251 map.put(new Actions(Actions.PREVIOUS_FRAME));
252 map.put(new Actions(Actions.NAVIGATE_NEXT));
253 map.put(new Actions(Actions.NAVIGATE_PREVIOUS));
254 }
255
256 protected void uninstallKeyboardActions(){
257 unregisterKeyboardActions();
258 SwingUtilities.replaceUIInputMap(desktop, JComponent.
259 WHEN_IN_FOCUSED_WINDOW, null);
260 SwingUtilities.replaceUIInputMap(desktop, JComponent.
261 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
262 SwingUtilities.replaceUIActionMap(desktop, null);
263 }
264
265 public void paint(Graphics g, JComponent c) {}
266
267 public Dimension getPreferredSize(JComponent c) {return null;}
268
269 public Dimension getMinimumSize(JComponent c) {
270 return minSize;
271 }
272 public Dimension getMaximumSize(JComponent c){
273 return maxSize;
274 }
275
276 /**
277 * Returns the <code>PropertyChangeListener</code> to install on
278 * the <code>JDesktopPane</code>.
279 *
280 * @since 1.5
281 * @return The PropertyChangeListener that will be added to track
282 * changes in the desktop pane.
283 */
284 protected PropertyChangeListener createPropertyChangeListener() {
285 return getHandler();
286 }
287
288 private Handler getHandler() {
289 if (handler == null) {
290 handler = new Handler();
291 }
292 return handler;
293 }
294
295 private class Handler implements PropertyChangeListener {
296 public void propertyChange(PropertyChangeEvent evt) {
297 String propertyName = evt.getPropertyName();
298 if ("desktopManager" == propertyName) {
299 installDesktopManager();
300 }
301 }
302 }
303
304 /**
305 * The default DesktopManager installed by the UI.
306 */
307 private class BasicDesktopManager extends DefaultDesktopManager
308 implements UIResource {
309 }
310
311 private static class Actions extends UIAction {
312 private static String CLOSE = "close";
313 private static String ESCAPE = "escape";
314 private static String MAXIMIZE = "maximize";
315 private static String MINIMIZE = "minimize";
316 private static String MOVE = "move";
317 private static String RESIZE = "resize";
318 private static String RESTORE = "restore";
319 private static String LEFT = "left";
320 private static String RIGHT = "right";
321 private static String UP = "up";
322 private static String DOWN = "down";
323 private static String SHRINK_LEFT = "shrinkLeft";
324 private static String SHRINK_RIGHT = "shrinkRight";
325 private static String SHRINK_UP = "shrinkUp";
326 private static String SHRINK_DOWN = "shrinkDown";
327 private static String NEXT_FRAME = "selectNextFrame";
328 private static String PREVIOUS_FRAME = "selectPreviousFrame";
329 private static String NAVIGATE_NEXT = "navigateNext";
330 private static String NAVIGATE_PREVIOUS = "navigatePrevious";
331 private final int MOVE_RESIZE_INCREMENT = 10;
332 private static boolean moving = false;
333 private static boolean resizing = false;
334 private static JInternalFrame sourceFrame = null;
335 private static Component focusOwner = null;
336
337 Actions() {
338 super(null);
339 }
340
341 Actions(String name) {
342 super(name);
343 }
344
345 public void actionPerformed(ActionEvent e) {
346 JDesktopPane dp = (JDesktopPane)e.getSource();
347 String key = getName();
348
349 if (CLOSE == key || MAXIMIZE == key || MINIMIZE == key ||
350 RESTORE == key) {
351 setState(dp, key);
352 }
353 else if (ESCAPE == key) {
354 if (sourceFrame == dp.getSelectedFrame() &&
355 focusOwner != null) {
356 focusOwner.requestFocus();
357 }
358 moving = false;
359 resizing = false;
360 sourceFrame = null;
361 focusOwner = null;
362 }
363 else if (MOVE == key || RESIZE == key) {
364 sourceFrame = dp.getSelectedFrame();
365 if (sourceFrame == null) {
366 return;
367 }
368 moving = (key == MOVE) ? true : false;
369 resizing = (key == RESIZE) ? true : false;
370
371 focusOwner = KeyboardFocusManager.
372 getCurrentKeyboardFocusManager().getFocusOwner();
373 if (!SwingUtilities.isDescendingFrom(focusOwner, sourceFrame)) {
374 focusOwner = null;
375 }
376 sourceFrame.requestFocus();
377 }
378 else if (LEFT == key ||
379 RIGHT == key ||
380 UP == key ||
381 DOWN == key ||
382 SHRINK_RIGHT == key ||
383 SHRINK_LEFT == key ||
384 SHRINK_UP == key ||
385 SHRINK_DOWN == key) {
386 JInternalFrame c = dp.getSelectedFrame();
387 if (sourceFrame == null || c != sourceFrame ||
388 KeyboardFocusManager.
389 getCurrentKeyboardFocusManager().getFocusOwner() !=
390 sourceFrame) {
391 return;
392 }
393 Insets minOnScreenInsets =
394 UIManager.getInsets("Desktop.minOnScreenInsets");
395 Dimension size = c.getSize();
396 Dimension minSize = c.getMinimumSize();
397 int dpWidth = dp.getWidth();
398 int dpHeight = dp.getHeight();
399 int delta;
400 Point loc = c.getLocation();
401 if (LEFT == key) {
402 if (moving) {
403 c.setLocation(
404 loc.x + size.width - MOVE_RESIZE_INCREMENT <
405 minOnScreenInsets.right ?
406 -size.width + minOnScreenInsets.right :
407 loc.x - MOVE_RESIZE_INCREMENT,
408 loc.y);
409 } else if (resizing) {
410 c.setLocation(loc.x - MOVE_RESIZE_INCREMENT, loc.y);
411 c.setSize(size.width + MOVE_RESIZE_INCREMENT,
412 size.height);
413 }
414 } else if (RIGHT == key) {
415 if (moving) {
416 c.setLocation(
417 loc.x + MOVE_RESIZE_INCREMENT >
418 dpWidth - minOnScreenInsets.left ?
419 dpWidth - minOnScreenInsets.left :
420 loc.x + MOVE_RESIZE_INCREMENT,
421 loc.y);
422 } else if (resizing) {
423 c.setSize(size.width + MOVE_RESIZE_INCREMENT,
424 size.height);
425 }
426 } else if (UP == key) {
427 if (moving) {
428 c.setLocation(loc.x,
429 loc.y + size.height - MOVE_RESIZE_INCREMENT <
430 minOnScreenInsets.bottom ?
431 -size.height +
432 minOnScreenInsets.bottom :
433 loc.y - MOVE_RESIZE_INCREMENT);
434 } else if (resizing) {
435 c.setLocation(loc.x, loc.y - MOVE_RESIZE_INCREMENT);
436 c.setSize(size.width,
437 size.height + MOVE_RESIZE_INCREMENT);
438 }
439 } else if (DOWN == key) {
440 if (moving) {
441 c.setLocation(loc.x,
442 loc.y + MOVE_RESIZE_INCREMENT >
443 dpHeight - minOnScreenInsets.top ?
444 dpHeight - minOnScreenInsets.top :
445 loc.y + MOVE_RESIZE_INCREMENT);
446 } else if (resizing) {
447 c.setSize(size.width,
448 size.height + MOVE_RESIZE_INCREMENT);
449 }
450 } else if (SHRINK_LEFT == key && resizing) {
451 // Make sure we don't resize less than minimum size.
452 if (minSize.width < (size.width - MOVE_RESIZE_INCREMENT)) {
453 delta = MOVE_RESIZE_INCREMENT;
454 } else {
455 delta = size.width - minSize.width;
456 }
457
458 // Ensure that we keep the internal frame on the desktop.
459 if (loc.x + size.width - delta < minOnScreenInsets.left) {
460 delta = loc.x + size.width - minOnScreenInsets.left;
461 }
462 c.setSize(size.width - delta, size.height);
463 } else if (SHRINK_RIGHT == key && resizing) {
464 // Make sure we don't resize less than minimum size.
465 if (minSize.width < (size.width - MOVE_RESIZE_INCREMENT)) {
466 delta = MOVE_RESIZE_INCREMENT;
467 } else {
468 delta = size.width - minSize.width;
469 }
470
471 // Ensure that we keep the internal frame on the desktop.
472 if (loc.x + delta > dpWidth - minOnScreenInsets.right) {
473 delta = (dpWidth - minOnScreenInsets.right) - loc.x;
474 }
475
476 c.setLocation(loc.x + delta, loc.y);
477 c.setSize(size.width - delta, size.height);
478 } else if (SHRINK_UP == key && resizing) {
479 // Make sure we don't resize less than minimum size.
480 if (minSize.height <
481 (size.height - MOVE_RESIZE_INCREMENT)) {
482 delta = MOVE_RESIZE_INCREMENT;
483 } else {
484 delta = size.height - minSize.height;
485 }
486
487 // Ensure that we keep the internal frame on the desktop.
488 if (loc.y + size.height - delta <
489 minOnScreenInsets.bottom) {
490 delta = loc.y + size.height - minOnScreenInsets.bottom;
491 }
492
493 c.setSize(size.width, size.height - delta);
494 } else if (SHRINK_DOWN == key && resizing) {
495 // Make sure we don't resize less than minimum size.
496 if (minSize.height <
497 (size.height - MOVE_RESIZE_INCREMENT)) {
498 delta = MOVE_RESIZE_INCREMENT;
499 } else {
500 delta = size.height - minSize.height;
501 }
502
503 // Ensure that we keep the internal frame on the desktop.
504 if (loc.y + delta > dpHeight - minOnScreenInsets.top) {
505 delta = (dpHeight - minOnScreenInsets.top) - loc.y;
506 }
507
508 c.setLocation(loc.x, loc.y + delta);
509 c.setSize(size.width, size.height - delta);
510 }
511 }
512 else if (NEXT_FRAME == key || PREVIOUS_FRAME == key) {
513 dp.selectFrame((key == NEXT_FRAME) ? true : false);
514 }
515 else if (NAVIGATE_NEXT == key ||
516 NAVIGATE_PREVIOUS == key) {
517 boolean moveForward = true;
518 if (NAVIGATE_PREVIOUS == key) {
519 moveForward = false;
520 }
521 Container cycleRoot = dp.getFocusCycleRootAncestor();
522
523 if (cycleRoot != null) {
524 FocusTraversalPolicy policy =
525 cycleRoot.getFocusTraversalPolicy();
526 if (policy != null && policy instanceof
527 SortingFocusTraversalPolicy) {
528 SortingFocusTraversalPolicy sPolicy =
529 (SortingFocusTraversalPolicy)policy;
530 boolean idc = sPolicy.getImplicitDownCycleTraversal();
531 try {
532 sPolicy.setImplicitDownCycleTraversal(false);
533 if (moveForward) {
534 KeyboardFocusManager.
535 getCurrentKeyboardFocusManager().
536 focusNextComponent(dp);
537 } else {
538 KeyboardFocusManager.
539 getCurrentKeyboardFocusManager().
540 focusPreviousComponent(dp);
541 }
542 } finally {
543 sPolicy.setImplicitDownCycleTraversal(idc);
544 }
545 }
546 }
547 }
548 }
549
550 private void setState(JDesktopPane dp, String state) {
551 if (state == CLOSE) {
552 JInternalFrame f = dp.getSelectedFrame();
553 if (f == null) {
554 return;
555 }
556 f.doDefaultCloseAction();
557 } else if (state == MAXIMIZE) {
558 // maximize the selected frame
559 JInternalFrame f = dp.getSelectedFrame();
560 if (f == null) {
561 return;
562 }
563 if (!f.isMaximum()) {
564 if (f.isIcon()) {
565 try {
566 f.setIcon(false);
567 f.setMaximum(true);
568 } catch (PropertyVetoException pve) {}
569 } else {
570 try {
571 f.setMaximum(true);
572 } catch (PropertyVetoException pve) {
573 }
574 }
575 }
576 } else if (state == MINIMIZE) {
577 // minimize the selected frame
578 JInternalFrame f = dp.getSelectedFrame();
579 if (f == null) {
580 return;
581 }
582 if (!f.isIcon()) {
583 try {
584 f.setIcon(true);
585 } catch (PropertyVetoException pve) {
586 }
587 }
588 } else if (state == RESTORE) {
589 // restore the selected minimized or maximized frame
590 JInternalFrame f = dp.getSelectedFrame();
591 if (f == null) {
592 return;
593 }
594 try {
595 if (f.isIcon()) {
596 f.setIcon(false);
597 } else if (f.isMaximum()) {
598 f.setMaximum(false);
599 }
600 f.setSelected(true);
601 } catch (PropertyVetoException pve) {
602 }
603 }
604 }
605
606 public boolean isEnabled(Object sender) {
607 if (sender instanceof JDesktopPane) {
608 JDesktopPane dp = (JDesktopPane)sender;
609 String action = getName();
610 if (action == Actions.NEXT_FRAME ||
611 action == Actions.PREVIOUS_FRAME) {
612 return true;
613 }
614 JInternalFrame iFrame = dp.getSelectedFrame();
615 if (iFrame == null) {
616 return false;
617 } else if (action == Actions.CLOSE) {
618 return iFrame.isClosable();
619 } else if (action == Actions.MINIMIZE) {
620 return iFrame.isIconifiable();
621 } else if (action == Actions.MAXIMIZE) {
622 return iFrame.isMaximizable();
623 }
624 return true;
625 }
626 return false;
627 }
628 }
629
630
631 /**
632 * Handles restoring a minimized or maximized internal frame.
633 * @since 1.3
634 */
635 protected class OpenAction extends AbstractAction {
636 public void actionPerformed(ActionEvent evt) {
637 JDesktopPane dp = (JDesktopPane)evt.getSource();
638 SHARED_ACTION.setState(dp, Actions.RESTORE);
639 }
640
641 public boolean isEnabled() {
642 return true;
643 }
644 }
645
646 /**
647 * Handles closing an internal frame.
648 */
649 protected class CloseAction extends AbstractAction {
650 public void actionPerformed(ActionEvent evt) {
651 JDesktopPane dp = (JDesktopPane)evt.getSource();
652 SHARED_ACTION.setState(dp, Actions.CLOSE);
653 }
654
655 public boolean isEnabled() {
656 JInternalFrame iFrame = desktop.getSelectedFrame();
657 if (iFrame != null) {
658 return iFrame.isClosable();
659 }
660 return false;
661 }
662 }
663
664 /**
665 * Handles minimizing an internal frame.
666 */
667 protected class MinimizeAction extends AbstractAction {
668 public void actionPerformed(ActionEvent evt) {
669 JDesktopPane dp = (JDesktopPane)evt.getSource();
670 SHARED_ACTION.setState(dp, Actions.MINIMIZE);
671 }
672
673 public boolean isEnabled() {
674 JInternalFrame iFrame = desktop.getSelectedFrame();
675 if (iFrame != null) {
676 return iFrame.isIconifiable();
677 }
678 return false;
679 }
680 }
681
682 /**
683 * Handles maximizing an internal frame.
684 */
685 protected class MaximizeAction extends AbstractAction {
686 public void actionPerformed(ActionEvent evt) {
687 JDesktopPane dp = (JDesktopPane)evt.getSource();
688 SHARED_ACTION.setState(dp, Actions.MAXIMIZE);
689 }
690
691 public boolean isEnabled() {
692 JInternalFrame iFrame = desktop.getSelectedFrame();
693 if (iFrame != null) {
694 return iFrame.isMaximizable();
695 }
696 return false;
697 }
698 }
699
700 /**
701 * Handles navigating to the next internal frame.
702 */
703 protected class NavigateAction extends AbstractAction {
704 public void actionPerformed(ActionEvent evt) {
705 JDesktopPane dp = (JDesktopPane)evt.getSource();
706 dp.selectFrame(true);
707 }
708
709 public boolean isEnabled() {
710 return true;
711 }
712 }
713 }