001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /**
019: * @author Vadim L. Bogdanov
020: * @version $Revision$
021: */package javax.swing.plaf.basic;
022:
023: import java.awt.Component;
024: import java.awt.Container;
025: import java.awt.Dimension;
026: import java.awt.FocusTraversalPolicy;
027: import java.awt.Graphics;
028: import java.awt.KeyboardFocusManager;
029: import java.awt.Rectangle;
030: import java.awt.event.ActionEvent;
031: import java.beans.PropertyChangeEvent;
032: import java.beans.PropertyChangeListener;
033: import java.beans.PropertyVetoException;
034: import java.util.Arrays;
035: import java.util.Comparator;
036:
037: import javax.swing.AbstractAction;
038: import javax.swing.ActionMap;
039: import javax.swing.DefaultDesktopManager;
040: import javax.swing.DesktopManager;
041: import javax.swing.InputMap;
042: import javax.swing.JComponent;
043: import javax.swing.JDesktopPane;
044: import javax.swing.JInternalFrame;
045: import javax.swing.KeyStroke;
046: import javax.swing.SortingFocusTraversalPolicy;
047: import javax.swing.SwingUtilities;
048: import javax.swing.UIManager;
049: import javax.swing.plaf.ActionMapUIResource;
050: import javax.swing.plaf.ComponentUI;
051: import javax.swing.plaf.DesktopPaneUI;
052: import javax.swing.plaf.UIResource;
053:
054: import org.apache.harmony.x.swing.Utilities;
055:
056: public class BasicDesktopPaneUI extends DesktopPaneUI {
057:
058: public static ComponentUI createUI(final JComponent c) {
059: return new BasicDesktopPaneUI();
060: }
061:
062: protected class CloseAction extends AbstractAction {
063: protected CloseAction() {
064: }
065:
066: public void actionPerformed(final ActionEvent e) {
067: try {
068: desktop.getSelectedFrame().setClosed(true);
069: } catch (PropertyVetoException e1) {
070: }
071: }
072:
073: public boolean isEnabled() {
074: return desktop.getSelectedFrame() != null
075: && desktop.getSelectedFrame().isClosable();
076: }
077: }
078:
079: protected class MaximizeAction extends AbstractAction {
080: protected MaximizeAction() {
081: }
082:
083: public void actionPerformed(final ActionEvent e) {
084: try {
085: desktop.getSelectedFrame().setMaximum(true);
086: } catch (PropertyVetoException e1) {
087: }
088: }
089:
090: public boolean isEnabled() {
091: return desktop.getSelectedFrame() != null
092: && desktop.getSelectedFrame().isMaximizable();
093: }
094: }
095:
096: protected class MinimizeAction extends AbstractAction {
097: protected MinimizeAction() {
098: }
099:
100: public void actionPerformed(final ActionEvent e) {
101: try {
102: desktop.getSelectedFrame().setIcon(true);
103: } catch (PropertyVetoException e1) {
104: }
105: }
106:
107: public boolean isEnabled() {
108: return desktop.getSelectedFrame() != null
109: && desktop.getSelectedFrame().isIconifiable();
110: }
111: }
112:
113: /**
114: * Implements <code>"navigateNext", "navigatePrevious"</code> actions.
115: */
116: protected class NavigateAction extends AbstractAction {
117: public void actionPerformed(final ActionEvent e) {
118: Container ancestor = desktop.getFocusCycleRootAncestor();
119: if (ancestor == null) {
120: return;
121: }
122:
123: FocusTraversalPolicy policy = ancestor
124: .getFocusTraversalPolicy();
125: if (!(policy instanceof SortingFocusTraversalPolicy)) {
126: return;
127: }
128:
129: SortingFocusTraversalPolicy sortingPolicy = (SortingFocusTraversalPolicy) policy;
130:
131: boolean implicitEnabled = sortingPolicy
132: .getImplicitDownCycleTraversal();
133: sortingPolicy.setImplicitDownCycleTraversal(false);
134:
135: Component result = null;
136: String action = (String) getValue(NAME);
137: if ("navigateNext".equals(action)) {
138: result = policy.getComponentAfter(ancestor, desktop);
139: } else if ("navigatePrevious".equals(action)) {
140: result = policy.getComponentBefore(ancestor, desktop);
141: }
142:
143: sortingPolicy
144: .setImplicitDownCycleTraversal(implicitEnabled);
145:
146: if (result != null) {
147: result.requestFocus();
148: }
149: }
150:
151: public boolean isEnabled() {
152: return true;
153: }
154: }
155:
156: /**
157: * Restores the selected frame from iconified or maximized states
158: * if it is not <code>null</code>.
159: */
160: protected class OpenAction extends AbstractAction {
161: protected OpenAction() {
162: }
163:
164: public void actionPerformed(final ActionEvent e) {
165: try {
166: if (desktop.getSelectedFrame().isMaximum()
167: && desktop.getSelectedFrame().isMaximizable()) {
168: desktop.getSelectedFrame().setMaximum(false);
169: } else if (desktop.getSelectedFrame().isIcon()
170: && desktop.getSelectedFrame().isIconifiable()) {
171: desktop.getSelectedFrame().setIcon(false);
172: }
173: } catch (PropertyVetoException e1) {
174: }
175: }
176:
177: public boolean isEnabled() {
178: return desktop.getSelectedFrame() != null
179: /*&& desktop.getSelectedFrame().isMaximizable()*/;
180: }
181: }
182:
183: /**
184: * Implements drag/move operations of the desktop icon.
185: */
186: private final class BoundsChangeAction extends AbstractAction {
187: private static final int BOUNDS_STEP = 10;
188:
189: private String command;
190:
191: public BoundsChangeAction(final String command) {
192: this .command = command;
193: }
194:
195: public void actionPerformed(final ActionEvent e) {
196: if (desktop.getSelectedFrame() == null) {
197: return;
198: }
199:
200: if ("move".equals(command)) {
201: frameOperation = DRAGGING;
202: moveFocusToFrame();
203:
204: } else if ("escape".equals(command)) {
205: frameOperation = NONE;
206: restoreFocusOwner();
207:
208: } else if ("resize".equals(command)) {
209: if (desktop.getSelectedFrame().isResizable()) {
210: frameOperation = RESIZING;
211: moveFocusToFrame();
212: }
213:
214: } else if (frameOperation != NONE) {
215: doBoundsChange();
216: }
217: }
218:
219: public boolean isEnabled() {
220: return desktop.getSelectedFrame() != null
221: && !desktop.getSelectedFrame().isMaximum();
222: }
223:
224: private JComponent getComponentForChangingBounds() {
225: JComponent comp;
226: if (desktop.getSelectedFrame().isIcon()) {
227: comp = desktop.getSelectedFrame().getDesktopIcon();
228: } else {
229: comp = desktop.getSelectedFrame();
230: }
231: return comp;
232: }
233:
234: private void doBoundsChange() {
235: Rectangle delta = new Rectangle();
236:
237: JComponent comp = getComponentForChangingBounds();
238: Dimension minSize = comp.getMinimumSize();
239: int shrinkX = Math.min(BOUNDS_STEP, comp.getWidth()
240: - minSize.width);
241: int shrinkY = Math.min(BOUNDS_STEP, comp.getHeight()
242: - minSize.height);
243:
244: if ("right".equals(command)) {
245: if (frameOperation == DRAGGING) {
246: delta.x = BOUNDS_STEP;
247: } else {
248: delta.width = BOUNDS_STEP;
249: }
250: } else if ("shrinkRight".equals(command)) {
251: if (frameOperation == RESIZING) {
252: delta.x = shrinkX;
253: delta.width = -shrinkX;
254: }
255: } else if ("left".equals(command)) {
256: if (frameOperation == RESIZING) {
257: delta.width = BOUNDS_STEP;
258: }
259: delta.x = -BOUNDS_STEP;
260: } else if ("shrinkLeft".equals(command)) {
261: if (frameOperation == RESIZING) {
262: delta.width = -shrinkX;
263: }
264: } else if ("up".equals(command)) {
265: delta.y = -BOUNDS_STEP;
266: if (frameOperation == RESIZING) {
267: delta.height = BOUNDS_STEP;
268: }
269: } else if ("shrinkUp".equals(command)) {
270: if (frameOperation == RESIZING) {
271: delta.height = -shrinkY;
272: }
273: } else if ("down".equals(command)) {
274: if (frameOperation == RESIZING) {
275: delta.height = BOUNDS_STEP;
276: } else {
277: delta.y = BOUNDS_STEP;
278: }
279: } else if ("shrinkDown".equals(command)) {
280: if (frameOperation == RESIZING) {
281: delta.y = shrinkY;
282: delta.height = -shrinkY;
283: }
284: }
285:
286: changeSelectedFrameBounds(comp, delta);
287: }
288:
289: private void changeSelectedFrameBounds(final JComponent comp,
290: final Rectangle delta) {
291: comp.setBounds(comp.getX() + delta.x,
292: comp.getY() + delta.y, comp.getWidth()
293: + delta.width, comp.getHeight()
294: + delta.height);
295: }
296:
297: private void moveFocusToFrame() {
298: saveFocusOwner();
299: desktop.getSelectedFrame().requestFocusInWindow();
300: }
301:
302: private void saveFocusOwner() {
303: savedFocusOwner = KeyboardFocusManager
304: .getCurrentKeyboardFocusManager().getFocusOwner();
305: }
306:
307: private void restoreFocusOwner() {
308: if (savedFocusOwner != null
309: && desktop.getSelectedFrame().isAncestorOf(
310: savedFocusOwner)) {
311: savedFocusOwner.requestFocusInWindow();
312: }
313: }
314: }
315:
316: private class SelectFrameAction extends AbstractAction {
317: private Comparator comparator;
318:
319: public SelectFrameAction() {
320: comparator = new Comparator() {
321: public int compare(final Object o1, final Object o2) {
322: return System.identityHashCode(o2)
323: - System.identityHashCode(o1);
324: }
325: };
326: }
327:
328: public void actionPerformed(final ActionEvent e) {
329: String action = (String) getValue(NAME);
330: JInternalFrame[] frames = getInternalFramesSorted();
331: int index = Arrays.binarySearch(frames, desktop
332: .getSelectedFrame(), comparator);
333:
334: if ("selectNextFrame".equals(action)) {
335: index = (index + 1) % frames.length;
336: } else if ("selectPreviousFrame".equals(action)) {
337: index = (index + frames.length - 1) % frames.length;
338: }
339:
340: try {
341: frames[index].setSelected(true);
342: } catch (PropertyVetoException e1) {
343: }
344: }
345:
346: private JInternalFrame[] getInternalFramesSorted() {
347: JInternalFrame[] frames = desktop.getAllFrames();
348: Arrays.sort(frames, comparator);
349: return frames;
350: }
351:
352: public boolean isEnabled() {
353: return true;
354: }
355: }
356:
357: private class PropertyChangeHandler implements
358: PropertyChangeListener {
359: public void propertyChange(final PropertyChangeEvent e) {
360: if ("desktopManager".equals(e.getPropertyName())) {
361: if (desktop.getDesktopManager() == null) {
362: installDesktopManager();
363: }
364: }
365: }
366: }
367:
368: /**
369: * @deprecated
370: */
371: protected KeyStroke closeKey;
372:
373: protected JDesktopPane desktop;
374:
375: protected DesktopManager desktopManager;
376:
377: /**
378: * @deprecated
379: */
380: protected KeyStroke maximizeKey;
381:
382: /**
383: * @deprecated
384: */
385: protected KeyStroke minimizeKey;
386:
387: /**
388: * @deprecated
389: */
390: protected KeyStroke navigateKey;
391:
392: /**
393: * @deprecated
394: */
395: protected KeyStroke navigateKey2;
396:
397: private ActionMap actionMap;
398: private DesktopManager oldDesktopManager;
399:
400: // these fields are also used in BasicInternalFrameTitlePane
401: static final int NONE = 0;
402: static final int DRAGGING = 1;
403: static final int RESIZING = 2;
404: int frameOperation = NONE;
405:
406: private Component savedFocusOwner;
407:
408: private PropertyChangeListener propertyChangeListener;
409:
410: public Dimension getMaximumSize(final JComponent c) {
411: return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
412: }
413:
414: public Dimension getMinimumSize(final JComponent c) {
415: return new Dimension(0, 0);
416: }
417:
418: public Dimension getPreferredSize(final JComponent c) {
419: return null;
420: }
421:
422: protected void installDefaults() {
423: if (Utilities.isUIResource(desktop.getBackground())) {
424: desktop.setBackground(UIManager
425: .getColor("Desktop.background"));
426: }
427: }
428:
429: protected void uninstallDefaults() {
430: if (desktop.getBackground() instanceof UIResource) {
431: desktop.setBackground(null);
432: }
433: }
434:
435: protected void installDesktopManager() {
436: oldDesktopManager = desktop.getDesktopManager();
437: if (desktop.getDesktopManager() != null) {
438: desktopManager = oldDesktopManager;
439: } else {
440: if (desktopManager == null) {
441: desktopManager = new DefaultDesktopManager();
442: }
443: desktop.setDesktopManager(desktopManager);
444: }
445: }
446:
447: protected void uninstallDesktopManager() {
448: if (desktop.getDesktopManager() == desktopManager
449: || desktop.getDesktopManager() == null) {
450: desktop.setDesktopManager(oldDesktopManager);
451: }
452: }
453:
454: private ActionMap getActionMap() {
455: if (actionMap == null) {
456: actionMap = new ActionMapUIResource();
457: actionMap.put("restore", new OpenAction()); // ctrl F5
458: actionMap.put("close", new CloseAction()); // ctrl F4
459: actionMap.put("move", new BoundsChangeAction("move")); // ctrl F7
460: actionMap.put("resize", new BoundsChangeAction("resize")); // ctrl F8
461: actionMap.put("right", new BoundsChangeAction("right")); // "RIGHT"
462: actionMap.put("shrinkRight", new BoundsChangeAction(
463: "shrinkRight")); // shift RIGHT
464: actionMap.put("left", new BoundsChangeAction("left")); // LEFT
465: actionMap.put("shrinkLeft", new BoundsChangeAction(
466: "shrinkLeft")); // shift LEFT
467: actionMap.put("up", new BoundsChangeAction("up")); // UP
468: actionMap.put("shrinkUp",
469: new BoundsChangeAction("shrinkUp")); // shift UP
470: actionMap.put("down", new BoundsChangeAction("down")); // DOWN
471: actionMap.put("shrinkDown", new BoundsChangeAction(
472: "shrinkDown")); // shift DOWN
473: actionMap.put("escape", new BoundsChangeAction("escape")); // ESCAPE
474: actionMap.put("minimize", new MinimizeAction()); // ctrl F9
475: actionMap.put("maximize", new MaximizeAction()); // ctrl F10
476:
477: putActionToActionMap("selectNextFrame",
478: new SelectFrameAction()); // ctrl F6
479: putActionToActionMap("selectPreviousFrame",
480: new SelectFrameAction()); // shift ctrl alt F6
481: putActionToActionMap("navigateNext", new NavigateAction()); // ctrl F12
482: putActionToActionMap("navigatePrevious",
483: new NavigateAction()); // shift ctrl F12
484: }
485:
486: return actionMap;
487: }
488:
489: private void putActionToActionMap(final String actionName,
490: final AbstractAction action) {
491: action.putValue(AbstractAction.NAME, actionName);
492: actionMap.put(actionName, action);
493: }
494:
495: protected void installKeyboardActions() {
496: SwingUtilities.replaceUIActionMap(desktop, getActionMap());
497:
498: SwingUtilities.replaceUIInputMap(desktop,
499: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
500: (InputMap) UIManager.get("Desktop.ancestorInputMap"));
501: }
502:
503: protected void uninstallKeyboardActions() {
504: SwingUtilities.replaceUIActionMap(desktop, null);
505:
506: SwingUtilities.replaceUIInputMap(desktop,
507: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
508: }
509:
510: protected PropertyChangeListener createPropertyChangeListener() {
511: return new PropertyChangeHandler();
512: }
513:
514: protected void installListeners() {
515: propertyChangeListener = createPropertyChangeListener();
516: if (propertyChangeListener != null) {
517: desktop.addPropertyChangeListener(propertyChangeListener);
518: }
519: }
520:
521: protected void uninstallListeners() {
522: if (propertyChangeListener != null) {
523: desktop
524: .removePropertyChangeListener(propertyChangeListener);
525: }
526: }
527:
528: public void installUI(final JComponent c) {
529: desktop = (JDesktopPane) c;
530:
531: installDefaults();
532: installListeners();
533: installKeyboardActions();
534: installDesktopManager();
535: }
536:
537: public void uninstallUI(final JComponent c) {
538: uninstallDefaults();
539: uninstallListeners();
540: uninstallKeyboardActions();
541: uninstallDesktopManager();
542: }
543:
544: public void paint(final Graphics g, final JComponent c) {
545: // no need to paint the background because
546: // it's already painted in ComponentUI.update()
547: }
548:
549: protected void registerKeyboardActions() {
550: // nothing to do
551: }
552:
553: protected void unregisterKeyboardActions() {
554: // nothing to do
555: }
556: }
|