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 closeFrame(final JInternalFrame f)76 public void closeFrame(final JInternalFrame f) { 77 if (f == fCurrentFrame) { 78 activateNextFrame(); 79 } 80 fChildFrames.removeElement(f); 81 super.closeFrame(f); 82 } 83 deiconifyFrame(final JInternalFrame f)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 addIcon(final Container c, final JInternalFrame.JDesktopIcon desktopIcon)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. */ iconifyFrame(final JInternalFrame f)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 if (!wasIcon(f)) { 109 setWasIcon(f, Boolean.TRUE); 110 } 111 c = f.getParent(); 112 if (c == null) return; 113 114 c.remove(f); 115 addIcon(c, desktopIcon); 116 c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight()); 117 } 118 119 // WindowsDesktopManager code activateFrame(final JInternalFrame f)120 public void activateFrame(final JInternalFrame f) { 121 try { 122 if (f != null) super.activateFrame(f); 123 124 // If this is the first activation, add to child list. 125 if (fChildFrames.indexOf(f) == -1) { 126 fChildFrames.addElement(f); 127 } 128 129 if (fCurrentFrame != null && f != fCurrentFrame) { 130 if (fCurrentFrame.isSelected()) { 131 fCurrentFrame.setSelected(false); 132 } 133 } 134 135 if (f != null && !f.isSelected()) { 136 f.setSelected(true); 137 } 138 139 fCurrentFrame = f; 140 } catch(final PropertyVetoException e) {} 141 } 142 switchFrame(final boolean next)143 private void switchFrame(final boolean next) { 144 if (fCurrentFrame == null) { 145 // initialize first frame we find 146 if (fInitialFrame != null) activateFrame(fInitialFrame); 147 return; 148 } 149 150 final int count = fChildFrames.size(); 151 if (count <= 1) { 152 // No other child frames. 153 return; 154 } 155 156 final int currentIndex = fChildFrames.indexOf(fCurrentFrame); 157 if (currentIndex == -1) { 158 // the "current frame" is no longer in the list 159 fCurrentFrame = null; 160 return; 161 } 162 163 int nextIndex; 164 if (next) { 165 nextIndex = currentIndex + 1; 166 if (nextIndex == count) { 167 nextIndex = 0; 168 } 169 } else { 170 nextIndex = currentIndex - 1; 171 if (nextIndex == -1) { 172 nextIndex = count - 1; 173 } 174 } 175 final JInternalFrame f = fChildFrames.elementAt(nextIndex); 176 activateFrame(f); 177 fCurrentFrame = f; 178 } 179 180 /** 181 * Activate the next child JInternalFrame, as determined by 182 * the frames' Z-order. If there is only one child frame, it 183 * remains activated. If there are no child frames, nothing 184 * happens. 185 */ activateNextFrame()186 public void activateNextFrame() { 187 switchFrame(true); 188 } 189 190 /** same as above but will activate a frame if none 191 * have been selected 192 */ activateNextFrame(final JInternalFrame f)193 public void activateNextFrame(final JInternalFrame f) { 194 fInitialFrame = f; 195 switchFrame(true); 196 } 197 198 /** 199 * Activate the previous child JInternalFrame, as determined by 200 * the frames' Z-order. If there is only one child frame, it 201 * remains activated. If there are no child frames, nothing 202 * happens. 203 */ activatePreviousFrame()204 public void activatePreviousFrame() { 205 switchFrame(false); 206 } 207 } 208