1 /* 2 * Copyright (c) 2011, 2014, 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 @SuppressWarnings("serial") // JDK implementation class 57 public class AquaInternalFrameManager extends DefaultDesktopManager { 58 // Variables 59 60 /* The frame which is currently selected/activated. 61 * We store this value to enforce Mac's single-selection model. 62 */ 63 JInternalFrame fCurrentFrame; 64 JInternalFrame fInitialFrame; 65 AquaInternalFramePaneUI fCurrentPaneUI; 66 67 /* The list of frames, sorted by order of creation. 68 * This list is necessary because by default the order of 69 * child frames in the JDesktopPane changes during frame 70 * activation (the activated frame is moved to index 0). 71 * We preserve the creation order so that "next" and "previous" 72 * frame actions make sense. 73 */ 74 Vector<JInternalFrame> fChildFrames = new Vector<JInternalFrame>(1); 75 76 public void closeFrame(final JInternalFrame f) { 77 if (f == fCurrentFrame) { 78 activateNextFrame(); 79 } 80 fChildFrames.removeElement(f); 81 super.closeFrame(f); 82 } 83 84 public void deiconifyFrame(final JInternalFrame f) { 85 JInternalFrame.JDesktopIcon desktopIcon; 86 87 desktopIcon = f.getDesktopIcon(); 88 // If the icon moved, move the frame to that spot before expanding it 89 // reshape does delta checks for us 90 f.reshape(desktopIcon.getX(), desktopIcon.getY(), f.getWidth(), f.getHeight()); 91 super.deiconifyFrame(f); 92 } 93 94 void addIcon(final Container c, final JInternalFrame.JDesktopIcon desktopIcon) { 95 c.add(desktopIcon); 96 } 97 98 /** Removes the frame from its parent and adds its desktopIcon to the parent. */ 99 public void iconifyFrame(final JInternalFrame f) { 100 // Same as super except doesn't deactivate it 101 JInternalFrame.JDesktopIcon desktopIcon; 102 Container c; 103 104 desktopIcon = f.getDesktopIcon(); 105 // Position depends on *current* position of frame, unlike super which reuses the first position 106 final Rectangle r = getBoundsForIconOf(f); 107 desktopIcon.setBounds(r.x, r.y, r.width, r.height); 108 109 c = f.getParent(); 110 if (c == null) return; 111 112 c.remove(f); 113 addIcon(c, desktopIcon); 114 c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight()); 115 } 116 117 // WindowsDesktopManager code 118 public void activateFrame(final JInternalFrame f) { 119 try { 120 if (f != null) super.activateFrame(f); 121 122 // If this is the first activation, add to child list. 123 if (fChildFrames.indexOf(f) == -1) { 124 fChildFrames.addElement(f); 125 } 126 127 if (fCurrentFrame != null && f != fCurrentFrame) { 128 if (fCurrentFrame.isSelected()) { 129 fCurrentFrame.setSelected(false); 130 } 131 } 132 133 if (f != null && !f.isSelected()) { 134 f.setSelected(true); 135 } 136 137 fCurrentFrame = f; 138 } catch(final PropertyVetoException e) {} 139 } 140 141 private void switchFrame(final boolean next) { 142 if (fCurrentFrame == null) { 143 // initialize first frame we find 144 if (fInitialFrame != null) activateFrame(fInitialFrame); 145 return; 146 } 147 148 final int count = fChildFrames.size(); 149 if (count <= 1) { 150 // No other child frames. 151 return; 152 } 153 154 final int currentIndex = fChildFrames.indexOf(fCurrentFrame); 155 if (currentIndex == -1) { 156 // the "current frame" is no longer in the list 157 fCurrentFrame = null; 158 return; 159 } 160 161 int nextIndex; 162 if (next) { 163 nextIndex = currentIndex + 1; 164 if (nextIndex == count) { 165 nextIndex = 0; 166 } 167 } else { 168 nextIndex = currentIndex - 1; 169 if (nextIndex == -1) { 170 nextIndex = count - 1; 171 } 172 } 173 final JInternalFrame f = fChildFrames.elementAt(nextIndex); 174 activateFrame(f); 175 fCurrentFrame = f; 176 } 177 178 /** 179 * Activate the next child JInternalFrame, as determined by 180 * the frames' Z-order. If there is only one child frame, it 181 * remains activated. If there are no child frames, nothing 182 * happens. 183 */ 184 public void activateNextFrame() { 185 switchFrame(true); 186 } 187 188 /** same as above but will activate a frame if none 189 * have been selected 190 */ 191 public void activateNextFrame(final JInternalFrame f) { 192 fInitialFrame = f; 193 switchFrame(true); 194 } 195 196 /** 197 * Activate the previous child JInternalFrame, as determined by 198 * the frames' Z-order. If there is only one child frame, it 199 * remains activated. If there are no child frames, nothing 200 * happens. 201 */ 202 public void activatePreviousFrame() { 203 switchFrame(false); 204 } 205 }