001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.core.windows.view.dnd;
043:
044: import java.awt.Component;
045: import java.awt.Point;
046: import java.awt.Window;
047: import java.awt.event.WindowAdapter;
048: import java.awt.event.WindowEvent;
049: import java.awt.event.WindowListener;
050: import java.lang.IllegalArgumentException;
051: import java.lang.ref.WeakReference;
052: import java.util.ArrayList;
053: import java.util.HashSet;
054: import java.util.Iterator;
055: import java.util.List;
056: import java.util.Set;
057: import java.util.logging.Logger;
058: import javax.swing.JComponent;
059: import javax.swing.RepaintManager;
060: import javax.swing.RootPaneContainer;
061: import javax.swing.SwingUtilities;
062: import org.openide.windows.WindowManager;
063:
064: /** Holds and manages z-order of attached windows.
065: *
066: * Note, manager is NetBeans specific, not general. It automatically attaches
067: * main window and expects that all registered zOrder are always above
068: * this main window.
069: *
070: * Not thread safe, must be called from EQT.
071: *
072: * @author Dafe Simonek
073: */
074: public final class ZOrderManager extends WindowAdapter {
075:
076: /** Singleton instance */
077: private static ZOrderManager instance;
078:
079: private static Logger logger = Logger
080: .getLogger("org.netbeans.core.windows.view.dnd");
081:
082: /** Z-order list of pane containers (windows) */
083: private List<WeakReference<RootPaneContainer>> zOrder = new ArrayList<WeakReference<RootPaneContainer>>();
084:
085: /** Set of pane containers to temporarily exclude from z-ordering. */
086: private Set<WeakReference<RootPaneContainer>> excludeSet = new HashSet<WeakReference<RootPaneContainer>>();
087:
088: /** Creates a new instance of ZOrderManager */
089: private ZOrderManager() {
090: }
091:
092: /** Returns singleton instance of ZOrderManager */
093: public static ZOrderManager getInstance() {
094: if (instance == null) {
095: instance = new ZOrderManager();
096: }
097: return instance;
098: }
099:
100: /** Adds given window (RootPaneContainer) to the set of windows which are tracked.
101: */
102: public void attachWindow(RootPaneContainer rpc) {
103: logger.entering(getClass().getName(), "attachWindow");
104:
105: if (!(rpc instanceof Window)) {
106: throw new IllegalArgumentException(
107: "Argument must be subclas of java.awt.Window: "
108: + rpc); //NOI18N
109: }
110: if (getWeak(rpc) != null) {
111: throw new IllegalArgumentException(
112: "Window already attached: " + rpc); //NOI18N
113: }
114:
115: zOrder.add(new WeakReference<RootPaneContainer>(rpc));
116: ((Window) rpc).addWindowListener(this );
117: }
118:
119: /** Stops to track given window (RootPaneContainer).
120: */
121: public boolean detachWindow(RootPaneContainer rpc) {
122: logger.entering(getClass().getName(), "detachWindow");
123:
124: if (!(rpc instanceof Window)) {
125: throw new IllegalArgumentException(
126: "Argument must be subclas of java.awt.Window: "
127: + rpc); //NOI18N
128: }
129:
130: WeakReference<RootPaneContainer> ww = getWeak(rpc);
131: if (ww == null) {
132: return false;
133: }
134:
135: ((Window) rpc).removeWindowListener(this );
136: return zOrder.remove(ww);
137: }
138:
139: /** Excludes/reincludes given RootPaneContainer from z-ordering. Excluded RootPaneContainer
140: * never returns true from isOnTop call, even if it is on top of window stack.
141: * RootPaneContainer that is second on top is returned in such situation.
142: *
143: * Used to distinguish RootPaneContainer that is being dragged.
144: *
145: * @param rpc Pane container to exlude or include back into rthe z-ordering.
146: * @param exclude true when exclusion is needed, false when normal default
147: * behaviour is desirable.
148: */
149: public void setExcludeFromOrder(RootPaneContainer rpc,
150: boolean exclude) {
151: if (exclude) {
152: excludeSet.add(new WeakReference<RootPaneContainer>(rpc));
153: } else {
154: WeakReference<RootPaneContainer> ww = getExcludedWeak(rpc);
155: if (ww != null) {
156: excludeSet.remove(ww);
157: }
158: }
159: }
160:
161: /* Stops to track all windows registered before.
162: */
163: public void clear() {
164: RootPaneContainer rpc;
165: for (WeakReference<RootPaneContainer> elem : zOrder) {
166: rpc = elem.get();
167: if (rpc != null) {
168: ((Window) rpc).removeWindowListener(this );
169: }
170: }
171: zOrder.clear();
172: }
173:
174: /** Finds out whether given pane container (window) is not under any other
175: * window registered in this manager at given screen point.
176: *
177: * @param rpc Pane container (window)
178: * @param screenLoc point relative to screen
179: * @return true when given window is on top of other registered windows at given point
180: */
181: public boolean isOnTop(RootPaneContainer rpc, Point screenLoc) {
182: logger.entering(getClass().getName(), "isOnTop");
183:
184: /*JComponent cp = (JComponent) rpc.getContentPane();
185: // false if point in dirty region - probably overlapped by other window
186: if (RepaintManager.currentManager(cp).getDirtyRegion(cp).contains(screenLoc)) {
187: return false;
188: }*/
189:
190: int size = zOrder.size();
191: WeakReference<RootPaneContainer> curWeakW = null;
192: RootPaneContainer curRpc = null;
193: for (int i = size - 1; i >= 0; i--) {
194: curWeakW = zOrder.get(i);
195: if (curWeakW == null) {
196: continue;
197: }
198: curRpc = curWeakW.get();
199: // ignore excluded ones
200: if (getExcludedWeak(curRpc) != null) {
201: continue;
202: }
203: // return top one
204: if (curRpc == rpc) {
205: return true;
206: }
207: // safe cast, assured by checks in attachWindow method
208: Window curW = (Window) curRpc;
209: Point loc = new Point(screenLoc);
210: SwingUtilities.convertPointFromScreen(loc, curW);
211: if (curW.contains(loc)) {
212: // && !RepaintManager.currentManager(curComp).getDirtyRegion(curComp).contains(screenLoc)) {
213: return false;
214: }
215: }
216:
217: // take main window automatically as last window to check
218: if (rpc == WindowManager.getDefault().getMainWindow()) {
219: return true;
220: }
221:
222: // not found
223: return false;
224: }
225:
226: /*** Implementation of WindowListener ******/
227:
228: public void windowOpened(WindowEvent e) {
229: }
230:
231: public void windowClosed(WindowEvent e) {
232: }
233:
234: public void windowActivated(WindowEvent e) {
235: logger.entering(getClass().getName(), "windowActivated");
236:
237: WeakReference<RootPaneContainer> ww = getWeak((RootPaneContainer) e
238: .getWindow());
239: if (ww != null) {
240: // place as last item in zOrder list
241: zOrder.remove(ww);
242: zOrder.add(ww);
243: } else {
244: throw new IllegalArgumentException("Window not attached: "
245: + e.getWindow()); //NOI18N
246: }
247: }
248:
249: public void windowDeactivated(WindowEvent e) {
250: }
251:
252: private WeakReference<RootPaneContainer> getWeak(
253: RootPaneContainer rpc) {
254: for (WeakReference<RootPaneContainer> elem : zOrder) {
255: if (elem.get() == rpc) {
256: return elem;
257: }
258: }
259: return null;
260: }
261:
262: private WeakReference<RootPaneContainer> getExcludedWeak(
263: RootPaneContainer rpc) {
264: for (WeakReference<RootPaneContainer> elem : excludeSet) {
265: if (elem.get() == rpc) {
266: return elem;
267: }
268: }
269: return null;
270: }
271:
272: }
|