001: /*******************************************************************************
002: * Copyright (c) 2004, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.dnd;
011:
012: import org.eclipse.core.runtime.Assert;
013: import org.eclipse.swt.graphics.Point;
014: import org.eclipse.swt.graphics.Rectangle;
015: import org.eclipse.swt.widgets.Composite;
016: import org.eclipse.swt.widgets.Control;
017: import org.eclipse.swt.widgets.Display;
018: import org.eclipse.swt.widgets.Monitor;
019: import org.eclipse.swt.widgets.Shell;
020:
021: /**
022: * Contains static methods for manipulating SWT controls
023: *
024: * @since 3.0
025: */
026: public class SwtUtil {
027:
028: private SwtUtil() {
029:
030: }
031:
032: /**
033: * Returns true if the given control is null or has been disposed
034: *
035: * @param toTest the control to test
036: * @return false if it is safe to invoke methods on the given control
037: */
038: public static boolean isDisposed(Control toTest) {
039: return toTest == null || toTest.isDisposed();
040: }
041:
042: /**
043: * Returns the control that is covering the given control, or null if none.
044: *
045: * @param toTest control to test
046: * @return a control that obscures the test control or null if none
047: */
048: public static Control controlThatCovers(Control toTest) {
049: return controlThatCovers(toTest, DragUtil
050: .getDisplayBounds(toTest));
051: }
052:
053: private static Control controlThatCovers(Control toTest,
054: Rectangle testRegion) {
055: Composite parent = toTest.getParent();
056:
057: if (parent == null || toTest instanceof Shell) {
058: return null;
059: }
060:
061: Control[] children = parent.getChildren();
062: for (int i = 0; i < children.length; i++) {
063: Control control = children[i];
064:
065: if (control == toTest) {
066: break;
067: }
068:
069: if (!control.isVisible()) {
070: continue;
071: }
072:
073: Rectangle nextBounds = DragUtil.getDisplayBounds(control);
074:
075: if (nextBounds.intersects(testRegion)) {
076: return control;
077: }
078: }
079:
080: return controlThatCovers(parent, testRegion);
081: }
082:
083: /**
084: * Determines if one control is a child of another. Returns true iff the second
085: * argument is a child of the first (or the same object).
086: *
087: * @param potentialParent
088: * @param childToTest
089: * @return
090: */
091: public static boolean isChild(Control potentialParent,
092: Control childToTest) {
093: if (childToTest == null) {
094: return false;
095: }
096:
097: if (childToTest == potentialParent) {
098: return true;
099: }
100:
101: return isChild(potentialParent, childToTest.getParent());
102: }
103:
104: public static boolean isFocusAncestor(Control potentialParent) {
105: Assert.isNotNull(potentialParent);
106: Control focusControl = Display.getCurrent().getFocusControl();
107: if (focusControl == null) {
108: return false;
109: }
110: return isChild(potentialParent, focusControl);
111: }
112:
113: /**
114: * Finds and returns the most specific SWT control at the given location.
115: * (Note: this does a DFS on the SWT widget hierarchy, which is slow).
116: *
117: * @param displayToSearch
118: * @param locationToFind
119: * @return
120: */
121: public static Control findControl(Display displayToSearch,
122: Point locationToFind) {
123: Shell[] shells = displayToSearch.getShells();
124:
125: return findControl(shells, locationToFind);
126: }
127:
128: /**
129: * Searches the given list of controls for a control containing the given point.
130: * If the array contains any composites, those composites will be recursively
131: * searched to find the most specific child that contains the point.
132: *
133: * @param toSearch an array of composites
134: * @param locationToFind a point (in display coordinates)
135: * @return the most specific Control that overlaps the given point, or null if none
136: */
137: public static Control findControl(Control[] toSearch,
138: Point locationToFind) {
139: for (int idx = toSearch.length - 1; idx >= 0; idx--) {
140: Control next = toSearch[idx];
141:
142: if (!next.isDisposed() && next.isVisible()) {
143:
144: Rectangle bounds = DragUtil.getDisplayBounds(next);
145:
146: if (bounds.contains(locationToFind)) {
147: if (next instanceof Composite) {
148: Control result = findControl((Composite) next,
149: locationToFind);
150:
151: if (result != null) {
152: return result;
153: }
154: }
155:
156: return next;
157: }
158: }
159: }
160:
161: return null;
162: }
163:
164: public static Control[] getAncestors(Control theControl) {
165: return getAncestors(theControl, 1);
166: }
167:
168: private static Control[] getAncestors(Control theControl,
169: int children) {
170: Control[] result;
171:
172: if (theControl.getParent() == null) {
173: result = new Control[children];
174: } else {
175: result = getAncestors(theControl.getParent(), children + 1);
176: }
177:
178: result[result.length - children] = theControl;
179:
180: return result;
181: }
182:
183: public static Control findCommonAncestor(Control control1,
184: Control control2) {
185: Control[] control1Ancestors = getAncestors(control1);
186: Control[] control2Ancestors = getAncestors(control2);
187:
188: Control mostSpecific = null;
189:
190: for (int idx = 0; idx < Math.min(control1Ancestors.length,
191: control2Ancestors.length); idx++) {
192: Control control1Ancestor = control1Ancestors[idx];
193: if (control1Ancestor == control2Ancestors[idx]) {
194: mostSpecific = control1Ancestor;
195: } else {
196: break;
197: }
198: }
199:
200: return mostSpecific;
201: }
202:
203: /**
204: * Finds the control in the given location
205: *
206: * @param toSearch
207: * @param locationToFind location (in display coordinates)
208: * @return
209: */
210: public static Control findControl(Composite toSearch,
211: Point locationToFind) {
212: Control[] children = toSearch.getChildren();
213:
214: return findControl(children, locationToFind);
215: }
216:
217: /**
218: *
219: * Returns true iff the given rectangle is located in the client area of any
220: * monitor.
221: *
222: * @param someRectangle a rectangle in display coordinates (not null)
223: * @return true iff the given point can be seen on any monitor
224: */
225: public static boolean intersectsAnyMonitor(Display display,
226: Rectangle someRectangle) {
227: Monitor[] monitors = display.getMonitors();
228:
229: for (int idx = 0; idx < monitors.length; idx++) {
230: Monitor mon = monitors[idx];
231:
232: if (mon.getClientArea().intersects(someRectangle)) {
233: return true;
234: }
235: }
236:
237: return false;
238: }
239:
240: }
|