KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > menus > PulldownDelegateWidgetProxy


1 /*******************************************************************************
2  * Copyright (c) 2005, 2007 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
12 package org.eclipse.ui.internal.menus;
13
14 import org.eclipse.core.commands.ParameterizedCommand;
15 import org.eclipse.core.commands.common.CommandException;
16 import org.eclipse.core.runtime.CoreException;
17 import org.eclipse.core.runtime.IConfigurationElement;
18 import org.eclipse.core.runtime.ISafeRunnable;
19 import org.eclipse.core.runtime.IStatus;
20 import org.eclipse.core.runtime.SafeRunner;
21 import org.eclipse.core.runtime.Status;
22 import org.eclipse.jface.menus.IWidget;
23 import org.eclipse.swt.SWT;
24 import org.eclipse.swt.events.DisposeEvent;
25 import org.eclipse.swt.events.DisposeListener;
26 import org.eclipse.swt.graphics.Point;
27 import org.eclipse.swt.graphics.Rectangle;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.swt.widgets.CoolBar;
31 import org.eclipse.swt.widgets.Event;
32 import org.eclipse.swt.widgets.Listener;
33 import org.eclipse.swt.widgets.Menu;
34 import org.eclipse.swt.widgets.MenuItem;
35 import org.eclipse.swt.widgets.ToolBar;
36 import org.eclipse.swt.widgets.ToolItem;
37 import org.eclipse.swt.widgets.Widget;
38 import org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
39 import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2;
40 import org.eclipse.ui.handlers.IHandlerService;
41 import org.eclipse.ui.internal.WorkbenchPlugin;
42 import org.eclipse.ui.services.IServiceLocator;
43
44 /**
45  * <p>
46  * A proxy for a {@link IWorkbenchWindowPulldownDelegate} on a pulldown action
47  * set action. This delays the class loading until the delegate is really asked
48  * for information. Asking a proxy for anything (except disposing) will cause
49  * the proxy to instantiate the proxied delegate.
50  * </p>
51  * <p>
52  * This class is not intended for use outside of the
53  * <code>org.eclipse.ui.workbench</code> plug-in.
54  * </p>
55  *
56  * @since 3.2
57  */

58 final class PulldownDelegateWidgetProxy implements IWidget {
59
60     /**
61      * A wrapper for loading the menu that defends against possible exceptions
62      * triggered outside of the workbench.
63      */

64     private static final class MenuLoader implements ISafeRunnable {
65
66         /**
67          * The parent for the menu to be created. This value is
68          * <code>null</code> if the parent is a menu.
69          */

70         private final Control control;
71
72         /**
73          * The delegate from which to load the menu.
74          */

75         private final IWorkbenchWindowPulldownDelegate delegate;
76
77         /**
78          * The loaded menu. This value is <code>null</code> if the load
79          * failed, or if it hasn't been loaded yet.
80          */

81         private Menu menu = null;
82
83         /**
84          * The parent for the menu to be created. This value is
85          * <code>null</code> if the parent is a control.
86          */

87         private final Menu parent;
88
89         /**
90          * Constructs a new instance of <code>MenuLoader</code>
91          *
92          * @param delegate
93          * The delegate from which the menu will be loaded; this
94          * value must not be <code>null</code>.
95          * @param parent
96          * The parent of the menu to be loaded; this value must not
97          * be <code>null</code>.
98          */

99         private MenuLoader(final IWorkbenchWindowPulldownDelegate delegate,
100                 final Control parent) {
101             this.delegate = delegate;
102             this.parent = null;
103             this.control = parent;
104         }
105
106         /**
107          * Constructs a new instance of <code>MenuLoader</code>
108          *
109          * @param delegate
110          * The delegate from which the menu will be loaded; this
111          * value must not be <code>null</code>.
112          * @param parent
113          * The parent of the menu to be loaded; this value must not
114          * be <code>null</code>.
115          */

116         private MenuLoader(final IWorkbenchWindowPulldownDelegate2 delegate,
117                 final Menu parent) {
118             this.delegate = delegate;
119             this.parent = parent;
120             this.control = null;
121         }
122
123         /**
124          * Returns the menu loaded, if any.
125          *
126          * @return the loaded menu, or <code>null</code> if none.
127          */

128         private Menu getMenu() {
129             return menu;
130         }
131
132         /**
133          * @see ISafeRunnable#handleException(java.lang.Throwable)
134          */

135         public void handleException(Throwable JavaDoc exception) {
136             // Do nothing
137
}
138
139         /**
140          * @see ISafeRunnable#run()
141          */

142         public void run() throws Exception JavaDoc {
143             if (parent == null) {
144                 menu = delegate.getMenu(control);
145             } else {
146                 menu = ((IWorkbenchWindowPulldownDelegate2) delegate)
147                         .getMenu(parent);
148             }
149         }
150     }
151
152     /**
153      * The command to execute when the pulldown delegate appears in a tool bar,
154      * and the arrow is <em>not</em> clicked. This also carries a help context
155      * identifier. This value must be <code>null</code>.
156      */

157     private final ParameterizedCommand command;
158
159     /**
160      * The configuration element from which the delegate can be created. This
161      * value will exist until the element is converted into a real class -- at
162      * which point this value will be set to <code>null</code>.
163      */

164     private IConfigurationElement configurationElement;
165
166     /**
167      * The real delegate. This value is <code>null</code> until the proxy is
168      * forced to load the real delegate. At this point, the configuration
169      * element is converted, nulled out, and this delegate gains a reference.
170      */

171     private IWorkbenchWindowPulldownDelegate delegate = null;
172
173     /**
174      * The name of the configuration element attribute which contains the
175      * information necessary to instantiate the real delegate.
176      */

177     private final String JavaDoc delegateAttributeName;
178
179     private final DisposeListener disposeListener = new DisposeListener() {
180         public void widgetDisposed(DisposeEvent e) {
181             if (e.widget == widget) {
182                 dispose();
183                 widget = null;
184
185                 // TODO Is this necessary?
186
// disposeOldImages();
187
}
188         }
189     };
190
191     /**
192      * The service locator from which a handler service can be retrieved. This
193      * is needed if the pulldown appears in the tool bar, and the drop-down
194      * arrow is <em>not</em> clicked. This value must not be <code>null</code>.
195      */

196     private final IServiceLocator locator;
197
198     private final Listener selectionListener = new Listener() {
199         public final void handleEvent(final Event event) {
200             final Widget item = event.widget;
201             if (item == null) {
202                 return;
203             }
204
205             final int style = item.getStyle();
206             if (((style & SWT.DROP_DOWN) != 0) && (event.detail == SWT.ARROW)
207                     && (item instanceof ToolItem)) {
208                 // Create the submenu.
209
final ToolItem toolItem = (ToolItem) item;
210                 final ToolBar toolBar = toolItem.getParent();
211                 if (loadDelegate()
212                         && (delegate instanceof IWorkbenchWindowPulldownDelegate2)) {
213                     final IWorkbenchWindowPulldownDelegate2 delegate2 = (IWorkbenchWindowPulldownDelegate2) delegate;
214                     final MenuLoader loader = new MenuLoader(delegate2, toolBar);
215                     SafeRunner.run(loader);
216                     final Menu subMenu = loader.getMenu();
217                     if (subMenu != null) {
218                         // position the menu below the drop down item
219
final Rectangle bounds = toolItem.getBounds();
220                         final Point location = toolBar.toDisplay(new Point(
221                                 bounds.x, bounds.y + bounds.height));
222                         subMenu.setLocation(location);
223                         subMenu.setVisible(true);
224                         return; // we don't fire the command
225
}
226                 }
227             }
228
229             final IHandlerService service = (IHandlerService) locator
230                     .getService(IHandlerService.class);
231             try {
232                 service.executeCommand(command, event);
233             } catch (final CommandException e) {
234                 /*
235                  * TODO There should be an API on IHandlerService that handles
236                  * the exceptions.
237                  */

238             }
239         }
240
241     };
242
243     /**
244      * The widget created for this pulldown delegate. If this proxy has not been
245      * asked to fill or it has been disposed, then this value is
246      * <code>null</code>.
247      */

248     private Widget widget = null;
249
250     /**
251      * Constructs a new instance of <code>PulldownDelegateWidgetProxy</code>
252      * with all the information it needs to try to avoid loading until it is
253      * needed.
254      *
255      * @param configurationElement
256      * The configuration element from which the real class can be
257      * loaded at run-time; must not be <code>null</code>.
258      * @param delegateAttributeName
259      * The name of the attibute or element containing the delegate;
260      * must not be <code>null</code>.
261      * @param command
262      * The command to execute if this the pulldown is not shown; must
263      * not be <code>null</code>.
264      * @param locator
265      * A service locator from which a handler service can be
266      * retrieved; must not be <code>null</code>.
267      */

268     public PulldownDelegateWidgetProxy(
269             final IConfigurationElement configurationElement,
270             final String JavaDoc delegateAttributeName,
271             final ParameterizedCommand command, final IServiceLocator locator) {
272         if (configurationElement == null) {
273             throw new NullPointerException JavaDoc(
274                     "The configuration element backing a handler proxy cannot be null"); //$NON-NLS-1$
275
}
276
277         if (delegateAttributeName == null) {
278             throw new NullPointerException JavaDoc(
279                     "The attribute containing the handler class must be known"); //$NON-NLS-1$
280
}
281
282         if (command == null) {
283             throw new NullPointerException JavaDoc("The command cannot be null"); //$NON-NLS-1$
284
}
285
286         this.configurationElement = configurationElement;
287         this.delegateAttributeName = delegateAttributeName;
288         this.command = command;
289         this.locator = locator;
290     }
291
292     /**
293      * Passes the dipose on to the proxied handler, if it has been loaded.
294      */

295     public final void dispose() {
296         if (delegate != null) {
297             delegate.dispose();
298         }
299     }
300
301     public final void fill(final Composite parent) {
302         // This does not need to be supported.
303
}
304
305     public final void fill(CoolBar parent, final int index) {
306         // This does not need to be supported.
307
}
308
309     public final void fill(final Menu parent, final int index) {
310         if ((widget != null) || (parent == null)) {
311             return;
312         }
313
314         // Create the menu item.
315
final MenuItem menuItem;
316         if (index >= 0) {
317             menuItem = new MenuItem(parent, SWT.CASCADE, index);
318         } else {
319             menuItem = new MenuItem(parent, SWT.CASCADE);
320         }
321         menuItem.setData(this);
322         widget = menuItem;
323
324         // Create the submenu.
325
if (loadDelegate()
326                 && (delegate instanceof IWorkbenchWindowPulldownDelegate2)) {
327             final IWorkbenchWindowPulldownDelegate2 delegate2 = (IWorkbenchWindowPulldownDelegate2) delegate;
328             final MenuLoader loader = new MenuLoader(delegate2, parent);
329             SafeRunner.run(loader);
330             final Menu subMenu = loader.getMenu();
331             if (subMenu != null) {
332                 menuItem.setMenu(subMenu);
333             }
334         }
335
336         menuItem.addDisposeListener(disposeListener);
337         menuItem.addListener(SWT.Selection, selectionListener);
338
339         // TODO Needs a way to be linked to a command.
340
// if (action.getHelpListener() != null)
341
// menuItem.addHelpListener(action.getHelpListener());
342

343         // TODO Needs a way of updating itself
344
// update(null);
345
}
346
347     public final void fill(final ToolBar parent, final int index) {
348         if ((widget != null) && (parent == null)) {
349             return;
350         }
351
352         final ToolItem toolItem;
353         if (index >= 0) {
354             toolItem = new ToolItem(parent, SWT.DROP_DOWN, index);
355         } else {
356             toolItem = new ToolItem(parent, SWT.DROP_DOWN);
357         }
358         toolItem.setData(this);
359         widget = toolItem;
360
361         // Attach some listeners.
362
toolItem.addDisposeListener(disposeListener);
363         toolItem.addListener(SWT.Selection, selectionListener);
364
365         // TODO Needs a way to be linked to a command.
366
// toolItem.addListener(SWT.Selection, getToolItemListener());
367
// action.addPropertyChangeListener(propertyListener);
368
// if (action != null) {
369
// String commandId = action.getActionDefinitionId();
370
// ExternalActionManager.ICallback callback = ExternalActionManager
371
// .getInstance().getCallback();
372
//
373
// if ((callback != null) && (commandId != null)) {
374
// callback.addPropertyChangeListener(commandId,
375
// actionTextListener);
376
// }
377
// }
378

379         // TODO Needs a way of updating itself
380
// update(null);
381
}
382
383     /**
384      * Loads the delegate, if possible. If the delegate is loaded, then the
385      * member variables are updated accordingly.
386      *
387      * @return <code>true</code> if the delegate is now non-null;
388      * <code>false</code> otherwise.
389      */

390     private final boolean loadDelegate() {
391         if (delegate == null) {
392             // Load the handler.
393
try {
394                 delegate = (IWorkbenchWindowPulldownDelegate) configurationElement
395                         .createExecutableExtension(delegateAttributeName);
396                 configurationElement = null;
397                 return true;
398
399             } catch (final ClassCastException JavaDoc e) {
400                 final String JavaDoc message = "The proxied delegate was the wrong class"; //$NON-NLS-1$
401
final IStatus status = new Status(IStatus.ERROR,
402                         WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
403                 WorkbenchPlugin.log(message, status);
404                 return false;
405
406             } catch (final CoreException e) {
407                 final String JavaDoc message = "The proxied delegate for '" + configurationElement.getAttribute(delegateAttributeName) //$NON-NLS-1$
408
+ "' could not be loaded"; //$NON-NLS-1$
409
IStatus status = new Status(IStatus.ERROR,
410                         WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
411                 WorkbenchPlugin.log(message, status);
412                 return false;
413             }
414         }
415
416         return true;
417     }
418
419     public final String JavaDoc toString() {
420         if (delegate == null) {
421             return configurationElement.getAttribute(delegateAttributeName);
422         }
423
424         return delegate.toString();
425     }
426 }
427
Popular Tags