1 /* 2 * Copyright (c) 2011, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.apple.laf; 27 28 import java.awt.*; 29 import java.beans.PropertyVetoException; 30 import java.util.Vector; 31 32 import javax.swing.*; 33 34 /** 35 * Based on AquaInternalFrameManager 36 * 37 * DesktopManager implementation for Aqua 38 * 39 * Mac is more like Windows than it's like Motif/Basic 40 * 41 * From WindowsDesktopManager: 42 * 43 * This class implements a DesktopManager which more closely follows 44 * the MDI model than the DefaultDesktopManager. Unlike the 45 * DefaultDesktopManager policy, MDI requires that the selected 46 * and activated child frames are the same, and that that frame 47 * always be the top-most window. 48 * <p> 49 * The maximized state is managed by the DesktopManager with MDI, 50 * instead of just being a property of the individual child frame. 51 * This means that if the currently selected window is maximized 52 * and another window is selected, that new window will be maximized. 53 * 54 * @see com.sun.java.swing.plaf.windows.WindowsDesktopManager 55 */ 56 public class AquaInternalFrameManager extends DefaultDesktopManager { 57 // Variables 58 59 /* The frame which is currently selected/activated. 60 * We store this value to enforce Mac's single-selection model. 61 */ 62 JInternalFrame fCurrentFrame; 63 JInternalFrame fInitialFrame; 64 AquaInternalFramePaneUI fCurrentPaneUI; 65 66 /* The list of frames, sorted by order of creation. 67 * This list is necessary because by default the order of 68 * child frames in the JDesktopPane changes during frame 69 * activation (the activated frame is moved to index 0). 70 * We preserve the creation order so that "next" and "previous" 71 * frame actions make sense. 72 */ 73 Vector<JInternalFrame> fChildFrames = new Vector<JInternalFrame>(1); 74 75 public void closeFrame(final JInternalFrame f) { 76 if (f == fCurrentFrame) { 77 activateNextFrame(); 78 } 79 fChildFrames.removeElement(f); 80 super.closeFrame(f); 81 } 82 83 public void deiconifyFrame(final JInternalFrame f) { 84 JInternalFrame.JDesktopIcon desktopIcon; 85 86 desktopIcon = f.getDesktopIcon(); 87 // If the icon moved, move the frame to that spot before expanding it 88 // reshape does delta checks for us 89 f.reshape(desktopIcon.getX(), desktopIcon.getY(), f.getWidth(), f.getHeight()); 90 super.deiconifyFrame(f); 91 } 92 93 void addIcon(final Container c, final JInternalFrame.JDesktopIcon desktopIcon) { 94 c.add(desktopIcon); 95 } 96 97 /** Removes the frame from its parent and adds its desktopIcon to the parent. */ 98 public void iconifyFrame(final JInternalFrame f) { 99 // Same as super except doesn't deactivate it 100 JInternalFrame.JDesktopIcon desktopIcon; 101 Container c; 102 103 desktopIcon = f.getDesktopIcon(); 104 // Position depends on *current* position of frame, unlike super which reuses the first position 105 final Rectangle r = getBoundsForIconOf(f); 106 desktopIcon.setBounds(r.x, r.y, r.width, r.height); 107 108 c = f.getParent(); 109 if (c == null) return; 110 111 c.remove(f); 112 addIcon(c, desktopIcon); 113 c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight()); 114 } 115 116 // WindowsDesktopManager code 117 public void activateFrame(final JInternalFrame f) { 118 try { 119 if (f != null) super.activateFrame(f); 120 121 // If this is the first activation, add to child list. 122 if (fChildFrames.indexOf(f) == -1) { 123 fChildFrames.addElement(f); 124 } 125 126 if (fCurrentFrame != null && f != fCurrentFrame) { 127 if (fCurrentFrame.isSelected()) { 128 fCurrentFrame.setSelected(false); 129 } 130 } 131 132 if (f != null && !f.isSelected()) { 133 f.setSelected(true); 134 } 135 136 fCurrentFrame = f; 137 } catch(final PropertyVetoException e) {} 138 } 139 140 private void switchFrame(final boolean next) { 141 if (fCurrentFrame == null) { 142 // initialize first frame we find 143 if (fInitialFrame != null) activateFrame(fInitialFrame); 144 return; 145 } 146 147 final int count = fChildFrames.size(); 148 if (count <= 1) { 149 // No other child frames. 150 return; 151 } 152 153 final int currentIndex = fChildFrames.indexOf(fCurrentFrame); 154 if (currentIndex == -1) { 155 // the "current frame" is no longer in the list 156 fCurrentFrame = null; 157 return; 158 } 159 160 int nextIndex; 161 if (next) { 162 nextIndex = currentIndex + 1; 163 if (nextIndex == count) { 164 nextIndex = 0; 165 } 166 } else { 167 nextIndex = currentIndex - 1; 168 if (nextIndex == -1) { 169 nextIndex = count - 1; 170 } 171 } 172 final JInternalFrame f = fChildFrames.elementAt(nextIndex); 173 activateFrame(f); 174 fCurrentFrame = f; 175 } 176 177 /** 178 * Activate the next child JInternalFrame, as determined by 179 * the frames' Z-order. If there is only one child frame, it 180 * remains activated. If there are no child frames, nothing 181 * happens. 182 */ 183 public void activateNextFrame() { 184 switchFrame(true); 185 } 186 187 /** same as above but will activate a frame if none 188 * have been selected 189 */ 190 public void activateNextFrame(final JInternalFrame f) { 191 fInitialFrame = f; 192 switchFrame(true); 193 } 194 195 /** 196 * Activate the previous child JInternalFrame, as determined by 197 * the frames' Z-order. If there is only one child frame, it 198 * remains activated. If there are no child frames, nothing 199 * happens. 200 */ 201 public void activatePreviousFrame() { 202 switchFrame(false); 203 } 204 }