KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > presentations > util > ProxyControl


1 /*******************************************************************************
2  * Copyright (c) 2004, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal.presentations.util;
12
13 import org.eclipse.jface.util.Geometry;
14 import org.eclipse.swt.SWT;
15 import org.eclipse.swt.events.ControlEvent;
16 import org.eclipse.swt.events.ControlListener;
17 import org.eclipse.swt.events.DisposeEvent;
18 import org.eclipse.swt.events.DisposeListener;
19 import org.eclipse.swt.graphics.Point;
20 import org.eclipse.swt.graphics.Rectangle;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.swt.widgets.Control;
23 import org.eclipse.swt.widgets.Event;
24 import org.eclipse.swt.widgets.Layout;
25 import org.eclipse.swt.widgets.Listener;
26 import org.eclipse.ui.internal.dnd.DragUtil;
27 import org.eclipse.ui.internal.dnd.SwtUtil;
28 import org.eclipse.ui.internal.layout.SizeCache;
29
30 /**
31  * A ProxyControl is an invisible control whose size and position are linked
32  * with some target control. That is, when the dummy control is asked for its
33  * preferred size it returns the preferred size of the target. Changing the
34  * bounds of the dummy control also changes the bounds of the target. This allows
35  * any Composite to lay out a control that isn't one of its children.
36  *
37  * <p>
38  * For example, imagine you have a ViewForm and a ToolBar that share the same parent
39  * and you want the ToolBar to be located in the upper-right corner of the ViewForm.
40  * If the ToolBar were a child of the ViewForm, this could be done easily by calling
41  * viewForm.setTopRight(toolBar). However, this is impossible since ViewForm.setTopRight
42  * will only accept a child control. Instead, we create a ProxyControl as a child
43  * of the viewForm, and set the toolbar as its target. The ViewForm will treat
44  * the ProxyControl just like any other child, but it will actually be arranging the
45  * ToolBar.
46  * </p>
47  * <p>For example:
48  * </p>
49  * <code>
50  * // Create a ViewForm and a ToolBar that are siblings
51  * ViewForm viewForm = new ViewForm(parent, SWT.NONE);
52  * ToolBar toolBar = new ToolBar(parent, SWT.NONE);
53  *
54  * // Allow the ViewForm to control the position of the ToolBar by creating
55  * // a ProxyControl in the ViewForm that targets the ToolBar.
56  * ProxyControl toolBarProxy = new ProxyControl(viewForm);
57  * toolBarProxy.setTarget(toolBar);
58  * viewForm.setTopRight(toolBarProxy.getControl());
59  * </code>
60  *
61  * <p>
62  * This is intended to simplify management of view toolbars in the presentation API.
63  * Presentation objects have no control over where the view toolbars are created in
64  * the widget hierarchy, but they may wish to control the position of the view toolbars
65  * using traditional SWT layouts and composites.
66  * </p>
67  */

68 public class ProxyControl {
69     
70     /**
71      * Invisible dummy control
72      */

73     private Composite control;
74     
75     /**
76      * Target control (possibly null)
77      */

78     private Control target = null;
79     
80     /**
81      * Target cache (possibly null)
82      */

83     private SizeCache targetCache = null;
84     
85     /**
86      * Most specific common ancestor between the target and the proxy controls
87      */

88     private Control commonAncestor;
89     
90     /**
91      * Visibility state of the proxy control the last time it had a non-null target.
92      * Note: when the target is set to null, we force the proxy to become invisible
93      * and use this variable to remember the initial state when we get a new non-null
94      * target.
95      */

96     private boolean visible = true;
97     
98     /**
99      * Dispose listener. Breaks the link between the target and the proxy if either
100      * control is disposed.
101      */

102     private DisposeListener disposeListener = new DisposeListener() {
103         public void widgetDisposed(DisposeEvent e) {
104             if (e.widget == target || e.widget == control) {
105                 setTargetControl(null);
106             }
107         }
108     };
109     
110     private Listener visibilityListener = new Listener() {
111
112         public void handleEvent(Event event) {
113             if (target != null) {
114                 visible = control.getVisible();
115                 target.setVisible(visible);
116             }
117         }
118         
119     };
120     
121     /**
122      * Allow the visibility of the proxy control to be updated. When the target
123      * is not <code>null</code> it's visibility is tied to the listener. But
124      * in the case where some action causes the target to be populated while
125      * its visibility is <code>false</code>, it won't re-appear until its
126      * visibility is set to <code>true</code>.
127      *
128      * @param visible
129      * <code>true</code> - set it to visible
130      * @since 3.2
131      */

132     public void setVisible(boolean visible) {
133 // this.visible = visible;
134
}
135     
136     /**
137      * Movement listener. Updates the bounds of the target to match the
138      * bounds of the dummy control.
139      */

140     private ControlListener controlListener = new ControlListener() {
141
142         public void controlMoved(ControlEvent e) {
143             ProxyControl.this.layout();
144         }
145
146         public void controlResized(ControlEvent e) {
147             //if (e.widget == control) {
148
// ProxyControl.this.layout();
149
//}
150
}
151         
152     };
153     
154     /**
155      * Creates a new ProxyControl as a child of the given parent. This is an invisible dummy
156      * control. If given a target, the ProxyControl will update the bounds of the target to
157      * match the bounds of the dummy control.
158      *
159      * @param parent parent composite
160      */

161     public ProxyControl(Composite parent) {
162         // Create the invisible dummy composite
163
control = new Composite(parent, SWT.NO_BACKGROUND);
164         control.setVisible(false);
165         
166         // Attach a layout to the dummy composite. This is used to make the preferred
167
// size of the dummy match the preferred size of the target.
168
control.setLayout(new Layout() {
169             protected void layout (Composite composite, boolean flushCache) {
170                 ProxyControl.this.layout();
171                 // does nothing. The bounds of the target are updated by the controlListener
172
}
173             
174             protected Point computeSize (Composite composite, int wHint, int hHint, boolean flushCache) {
175                 if (targetCache == null) {
176                     if (target != null) {
177                         return target.computeSize(wHint, hHint, flushCache);
178                     }
179                     // Note: If we returned (0,0), SWT would ignore the result and use a default value.
180
return new Point(1,1);
181                 }
182                 
183                 return targetCache.computeSize(wHint, hHint);
184             }
185         });
186         
187         // Attach listeners to the dummy
188
control.addDisposeListener(disposeListener);
189         control.addListener(SWT.Show, visibilityListener);
190         control.addListener(SWT.Hide, visibilityListener);
191     }
192     
193     /**
194      * Sets the control whose position will be managed by this proxy
195      *
196      * @param target the control, or null if none
197      */

198     public void setTargetControl(Control target) {
199         targetCache = null;
200         internalSetTargetControl(target);
201     }
202     
203     private void internalSetTargetControl(Control target) {
204         if (this.target != target) {
205
206             if (this.target != null) {
207                 for (Control next = control; next != commonAncestor && next != null; next = next.getParent()) {
208                     next.removeControlListener(controlListener);
209                 }
210                 commonAncestor = null;
211                 
212                 // If we already had a target, detach the dispose listener
213
// (prevents memory leaks due to listeners)
214
if (!this.target.isDisposed()) {
215                     this.target.removeDisposeListener(disposeListener);
216                 }
217             }
218             
219             if (this.target == null && target != null) {
220                 // If we had previously forced the dummy control invisible, restore its visibility
221
control.setVisible(visible);
222             }
223             
224             this.target = target;
225             
226             if (target != null) {
227                 commonAncestor = SwtUtil.findCommonAncestor(this.target, control);
228                 for (Control next = control; next != null && next != commonAncestor; next = next.getParent()) {
229                     next.addControlListener(controlListener);
230                 }
231                 
232                 // Make the new target's visiblity match the visibility of the dummy control
233
target.setVisible(control.getVisible());
234                 // Add a dispose listener. Ensures that the target is cleared
235
// if it is ever disposed.
236
target.addDisposeListener(disposeListener);
237             } else {
238                 control.setVisible(false);
239             }
240         }
241     }
242     
243     public void setTarget(SizeCache cache) {
244         targetCache = cache;
245         
246         if (targetCache != null) {
247             setTargetControl(cache.getControl());
248         } else {
249             setTargetControl(null);
250         }
251     }
252     
253     /**
254      * Returns the proxy control
255      *
256      * @return the proxy control (not null)
257      */

258     public Control getControl() {
259         return control;
260     }
261     
262     public Control getTarget() {
263         return target;
264     }
265     
266     /**
267      * Moves the target control on top of the dummy control.
268      */

269     public void layout() {
270         if (getTarget() == null) {
271             return;
272         }
273         
274         // Compute the unclipped bounds of the target in display coordinates
275
Rectangle displayBounds = Geometry.toDisplay(control.getParent(), control.getBounds());
276         
277         // Clip the bounds of the target so that it doesn't go outside the dummy control's parent
278
Rectangle clippingRegion = DragUtil.getDisplayBounds(control.getParent());
279         displayBounds = displayBounds.intersection(clippingRegion);
280         
281         // Compute the bounds of the target, in the local coordinate system of its parent
282
Rectangle targetBounds = Geometry.toControl(getTarget().getParent(), displayBounds);
283         
284         // Move the target
285
getTarget().setBounds(targetBounds);
286     }
287 }
288
Popular Tags