Mercurial > projects > dwt2
comparison org.eclipse.jface/src/org/eclipse/jface/action/ActionContributionItem.d @ 12:bc29606a740c
Added dwt-addons in original directory structure of eclipse.org
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 14 Mar 2009 18:23:29 +0100 |
parents | |
children | 735224fcc45f |
comparison
equal
deleted
inserted
replaced
11:43904fec5dca | 12:bc29606a740c |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2008 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 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.jface.action.ActionContributionItem; | |
14 | |
15 import org.eclipse.jface.action.ContributionItem; | |
16 import org.eclipse.jface.action.IAction; | |
17 import org.eclipse.jface.action.LegacyActionTools; | |
18 import org.eclipse.jface.action.Action; | |
19 import org.eclipse.jface.action.IMenuCreator; | |
20 import org.eclipse.jface.action.IContributionManagerOverrides; | |
21 | |
22 import org.eclipse.swt.SWT; | |
23 import org.eclipse.swt.graphics.GC; | |
24 import org.eclipse.swt.graphics.Point; | |
25 import org.eclipse.swt.widgets.Button; | |
26 import org.eclipse.swt.widgets.Composite; | |
27 import org.eclipse.swt.widgets.Display; | |
28 import org.eclipse.swt.widgets.Event; | |
29 import org.eclipse.swt.widgets.Item; | |
30 import org.eclipse.swt.widgets.Listener; | |
31 import org.eclipse.swt.widgets.Menu; | |
32 import org.eclipse.swt.widgets.MenuItem; | |
33 import org.eclipse.swt.widgets.ToolBar; | |
34 import org.eclipse.swt.widgets.ToolItem; | |
35 import org.eclipse.swt.widgets.Widget; | |
36 import org.eclipse.jface.action.ExternalActionManager; | |
37 import org.eclipse.core.commands.ExecutionException; | |
38 import org.eclipse.core.commands.NotEnabledException; | |
39 import org.eclipse.jface.bindings.Trigger; | |
40 import org.eclipse.jface.bindings.TriggerSequence; | |
41 import org.eclipse.jface.bindings.keys.IKeyLookup; | |
42 import org.eclipse.jface.bindings.keys.KeyLookupFactory; | |
43 import org.eclipse.jface.bindings.keys.KeyStroke; | |
44 import org.eclipse.jface.resource.ImageDescriptor; | |
45 import org.eclipse.jface.resource.JFaceResources; | |
46 import org.eclipse.jface.resource.LocalResourceManager; | |
47 import org.eclipse.jface.resource.ResourceManager; | |
48 import org.eclipse.jface.util.IPropertyChangeListener; | |
49 import org.eclipse.jface.util.Policy; | |
50 import org.eclipse.jface.util.PropertyChangeEvent; | |
51 | |
52 import java.lang.all; | |
53 import java.util.Set; | |
54 import java.lang.JThread; | |
55 import tango.io.Stdout; | |
56 | |
57 /** | |
58 * A contribution item which delegates to an action. | |
59 * <p> | |
60 * This class may be instantiated; it is not intended to be subclassed. | |
61 * </p> | |
62 * @noextend This class is not intended to be subclassed by clients. | |
63 */ | |
64 public class ActionContributionItem : ContributionItem { | |
65 alias ContributionItem.fill fill; | |
66 | |
67 /** | |
68 * Mode bit: Show text on tool items or buttons, even if an image is | |
69 * present. If this mode bit is not set, text is only shown on tool items if | |
70 * there is no image present. | |
71 * | |
72 * @since 3.0 | |
73 */ | |
74 public static int MODE_FORCE_TEXT = 1; | |
75 | |
76 /** a string inserted in the middle of text that has been shortened */ | |
77 private static const String ellipsis = "..."; //$NON-NLS-1$ | |
78 | |
79 /** | |
80 * Stores the result of the action. False when the action returned failure. | |
81 */ | |
82 private Boolean result = null; | |
83 | |
84 private static bool USE_COLOR_ICONS = true; | |
85 | |
86 /** | |
87 * Returns whether color icons should be used in toolbars. | |
88 * | |
89 * @return <code>true</code> if color icons should be used in toolbars, | |
90 * <code>false</code> otherwise | |
91 */ | |
92 public static bool getUseColorIconsInToolbars() { | |
93 return USE_COLOR_ICONS; | |
94 } | |
95 | |
96 /** | |
97 * Sets whether color icons should be used in toolbars. | |
98 * | |
99 * @param useColorIcons | |
100 * <code>true</code> if color icons should be used in toolbars, | |
101 * <code>false</code> otherwise | |
102 */ | |
103 public static void setUseColorIconsInToolbars(bool useColorIcons) { | |
104 USE_COLOR_ICONS = useColorIcons; | |
105 } | |
106 | |
107 /** | |
108 * The presentation mode. | |
109 */ | |
110 private int mode = 0; | |
111 | |
112 /** | |
113 * The action. | |
114 */ | |
115 private IAction action; | |
116 | |
117 /** | |
118 * The listener for changes to the text of the action contributed by an | |
119 * external source. | |
120 */ | |
121 private const IPropertyChangeListener actionTextListener; | |
122 | |
123 /** | |
124 * Remembers all images in use by this contribution item | |
125 */ | |
126 private LocalResourceManager imageManager; | |
127 | |
128 /** | |
129 * Listener for SWT button widget events. | |
130 */ | |
131 private Listener buttonListener; | |
132 | |
133 /** | |
134 * Listener for SWT menu item widget events. | |
135 */ | |
136 private Listener menuItemListener; | |
137 | |
138 /** | |
139 * Listener for action property change notifications. | |
140 */ | |
141 private const IPropertyChangeListener propertyListener; | |
142 | |
143 /** | |
144 * Listener for SWT tool item widget events. | |
145 */ | |
146 private Listener toolItemListener; | |
147 | |
148 /** | |
149 * The widget created for this item; <code>null</code> before creation and | |
150 * after disposal. | |
151 */ | |
152 private Widget widget = null; | |
153 | |
154 private Listener menuCreatorListener; | |
155 | |
156 /** | |
157 * Creates a new contribution item from the given action. The id of the | |
158 * action is used as the id of the item. | |
159 * | |
160 * @param action | |
161 * the action | |
162 */ | |
163 public this(IAction action) { | |
164 super(action.getId()); | |
165 this.action = action; | |
166 actionTextListener = new class IPropertyChangeListener { | |
167 /** | |
168 * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent) | |
169 */ | |
170 public void propertyChange(PropertyChangeEvent event) { | |
171 update(event.getProperty()); | |
172 } | |
173 }; | |
174 propertyListener = new class IPropertyChangeListener { | |
175 public void propertyChange(PropertyChangeEvent event) { | |
176 actionPropertyChange(event); | |
177 } | |
178 }; | |
179 } | |
180 | |
181 /** | |
182 * Handles a property change event on the action (forwarded by nested | |
183 * listener). | |
184 */ | |
185 private void actionPropertyChange(PropertyChangeEvent e) { | |
186 // This code should be removed. Avoid using free asyncExec | |
187 | |
188 if (isVisible() && widget !is null) { | |
189 Display display = widget.getDisplay(); | |
190 if (display.getThread() is JThread.currentThread().nativeThread()) { | |
191 update(e.getProperty()); | |
192 } else { | |
193 display.asyncExec(dgRunnable( (PropertyChangeEvent e_) { | |
194 update(e_.getProperty()); | |
195 }, e)); | |
196 } | |
197 | |
198 } | |
199 } | |
200 | |
201 /** | |
202 * Compares this action contribution item with another object. Two action | |
203 * contribution items are equal if they refer to the identical Action. | |
204 */ | |
205 public override int opEquals(Object o) { | |
206 if (!(cast(ActionContributionItem)o )) { | |
207 return false; | |
208 } | |
209 return (cast(Object)action).opEquals(cast(Object)(cast(ActionContributionItem) o).action); | |
210 } | |
211 | |
212 /** | |
213 * The <code>ActionContributionItem</code> implementation of this | |
214 * <code>IContributionItem</code> method creates an SWT | |
215 * <code>Button</code> for the action using the action's style. If the | |
216 * action's checked property has been set, the button is created and primed | |
217 * to the value of the checked property. | |
218 */ | |
219 public override void fill(Composite parent) { | |
220 if (widget is null && parent !is null) { | |
221 int flags = SWT.PUSH; | |
222 if (action !is null) { | |
223 if (action.getStyle() is IAction.AS_CHECK_BOX) { | |
224 flags = SWT.TOGGLE; | |
225 } | |
226 if (action.getStyle() is IAction.AS_RADIO_BUTTON) { | |
227 flags = SWT.RADIO; | |
228 } | |
229 } | |
230 | |
231 Button b = new Button(parent, flags); | |
232 b.setData(this); | |
233 b.addListener(SWT.Dispose, getButtonListener()); | |
234 // Don't hook a dispose listener on the parent | |
235 b.addListener(SWT.Selection, getButtonListener()); | |
236 if (action.getHelpListener() !is null) { | |
237 b.addHelpListener(action.getHelpListener()); | |
238 } | |
239 widget = b; | |
240 | |
241 update(null); | |
242 | |
243 // Attach some extra listeners. | |
244 action.addPropertyChangeListener(propertyListener); | |
245 if (action !is null) { | |
246 String commandId = action.getActionDefinitionId(); | |
247 ExternalActionManager.ICallback callback = ExternalActionManager | |
248 .getInstance().getCallback(); | |
249 | |
250 if ((callback !is null) && (commandId !is null)) { | |
251 callback.addPropertyChangeListener(commandId, | |
252 actionTextListener); | |
253 } | |
254 } | |
255 } | |
256 } | |
257 | |
258 /** | |
259 * The <code>ActionContributionItem</code> implementation of this | |
260 * <code>IContributionItem</code> method creates an SWT | |
261 * <code>MenuItem</code> for the action using the action's style. If the | |
262 * action's checked property has been set, a button is created and primed to | |
263 * the value of the checked property. If the action's menu creator property | |
264 * has been set, a cascading submenu is created. | |
265 */ | |
266 public override void fill(Menu parent, int index) { | |
267 if (widget is null && parent !is null) { | |
268 int flags = SWT.PUSH; | |
269 if (action !is null) { | |
270 int style = action.getStyle(); | |
271 if (style is IAction.AS_CHECK_BOX) { | |
272 flags = SWT.CHECK; | |
273 } else if (style is IAction.AS_RADIO_BUTTON) { | |
274 flags = SWT.RADIO; | |
275 } else if (style is IAction.AS_DROP_DOWN_MENU) { | |
276 flags = SWT.CASCADE; | |
277 } | |
278 } | |
279 | |
280 MenuItem mi = null; | |
281 if (index >= 0) { | |
282 mi = new MenuItem(parent, flags, index); | |
283 } else { | |
284 mi = new MenuItem(parent, flags); | |
285 } | |
286 widget = mi; | |
287 | |
288 mi.setData(this); | |
289 mi.addListener(SWT.Dispose, getMenuItemListener()); | |
290 mi.addListener(SWT.Selection, getMenuItemListener()); | |
291 if (action.getHelpListener() !is null) { | |
292 mi.addHelpListener(action.getHelpListener()); | |
293 } | |
294 | |
295 if (flags is SWT.CASCADE) { | |
296 // just create a proxy for now, if the user shows it then | |
297 // fill it in | |
298 Menu subMenu = new Menu(parent); | |
299 subMenu.addListener(SWT.Show, getMenuCreatorListener()); | |
300 subMenu.addListener(SWT.Hide, getMenuCreatorListener()); | |
301 mi.setMenu(subMenu); | |
302 } | |
303 | |
304 update(null); | |
305 | |
306 // Attach some extra listeners. | |
307 action.addPropertyChangeListener(propertyListener); | |
308 if (action !is null) { | |
309 String commandId = action.getActionDefinitionId(); | |
310 ExternalActionManager.ICallback callback = ExternalActionManager | |
311 .getInstance().getCallback(); | |
312 | |
313 if ((callback !is null) && (commandId !is null)) { | |
314 callback.addPropertyChangeListener(commandId, | |
315 actionTextListener); | |
316 } | |
317 } | |
318 } | |
319 } | |
320 | |
321 /** | |
322 * The <code>ActionContributionItem</code> implementation of this , | |
323 * <code>IContributionItem</code> method creates an SWT | |
324 * <code>ToolItem</code> for the action using the action's style. If the | |
325 * action's checked property has been set, a button is created and primed to | |
326 * the value of the checked property. If the action's menu creator property | |
327 * has been set, a drop-down tool item is created. | |
328 */ | |
329 public override void fill(ToolBar parent, int index) { | |
330 if (widget is null && parent !is null) { | |
331 int flags = SWT.PUSH; | |
332 if (action !is null) { | |
333 int style = action.getStyle(); | |
334 if (style is IAction.AS_CHECK_BOX) { | |
335 flags = SWT.CHECK; | |
336 } else if (style is IAction.AS_RADIO_BUTTON) { | |
337 flags = SWT.RADIO; | |
338 } else if (style is IAction.AS_DROP_DOWN_MENU) { | |
339 flags = SWT.DROP_DOWN; | |
340 } | |
341 } | |
342 | |
343 ToolItem ti = null; | |
344 if (index >= 0) { | |
345 ti = new ToolItem(parent, flags, index); | |
346 } else { | |
347 ti = new ToolItem(parent, flags); | |
348 } | |
349 ti.setData(this); | |
350 ti.addListener(SWT.Selection, getToolItemListener()); | |
351 ti.addListener(SWT.Dispose, getToolItemListener()); | |
352 | |
353 widget = ti; | |
354 | |
355 update(null); | |
356 | |
357 // Attach some extra listeners. | |
358 action.addPropertyChangeListener(propertyListener); | |
359 if (action !is null) { | |
360 String commandId = action.getActionDefinitionId(); | |
361 ExternalActionManager.ICallback callback = ExternalActionManager | |
362 .getInstance().getCallback(); | |
363 | |
364 if ((callback !is null) && (commandId !is null)) { | |
365 callback.addPropertyChangeListener(commandId, | |
366 actionTextListener); | |
367 } | |
368 } | |
369 } | |
370 } | |
371 | |
372 /** | |
373 * Returns the action associated with this contribution item. | |
374 * | |
375 * @return the action | |
376 */ | |
377 public IAction getAction() { | |
378 return action; | |
379 } | |
380 | |
381 /** | |
382 * Returns the listener for SWT button widget events. | |
383 * | |
384 * @return a listener for button events | |
385 */ | |
386 private Listener getButtonListener() { | |
387 if (buttonListener is null) { | |
388 buttonListener = new class Listener { | |
389 public void handleEvent(Event event) { | |
390 switch (event.type) { | |
391 case SWT.Dispose: | |
392 handleWidgetDispose(event); | |
393 break; | |
394 case SWT.Selection: | |
395 Widget ew = event.widget; | |
396 if (ew !is null) { | |
397 handleWidgetSelection(event, (cast(Button) ew) | |
398 .getSelection()); | |
399 } | |
400 break; | |
401 default: | |
402 } | |
403 } | |
404 }; | |
405 } | |
406 return buttonListener; | |
407 } | |
408 | |
409 /** | |
410 * Returns the listener for SWT menu item widget events. | |
411 * | |
412 * @return a listener for menu item events | |
413 */ | |
414 private Listener getMenuItemListener() { | |
415 if (menuItemListener is null) { | |
416 menuItemListener = new class Listener { | |
417 public void handleEvent(Event event) { | |
418 switch (event.type) { | |
419 case SWT.Dispose: | |
420 handleWidgetDispose(event); | |
421 break; | |
422 case SWT.Selection: | |
423 Widget ew = event.widget; | |
424 if (ew !is null) { | |
425 handleWidgetSelection(event, (cast(MenuItem) ew) | |
426 .getSelection()); | |
427 } | |
428 break; | |
429 default: | |
430 } | |
431 } | |
432 }; | |
433 } | |
434 return menuItemListener; | |
435 } | |
436 | |
437 /** | |
438 * Returns the presentation mode, which is the bitwise-or of the | |
439 * <code>MODE_*</code> constants. The default mode setting is 0, meaning | |
440 * that for menu items, both text and image are shown (if present), but for | |
441 * tool items, the text is shown only if there is no image. | |
442 * | |
443 * @return the presentation mode settings | |
444 * | |
445 * @since 3.0 | |
446 */ | |
447 public int getMode() { | |
448 return mode; | |
449 } | |
450 | |
451 /** | |
452 * Returns the listener for SWT tool item widget events. | |
453 * | |
454 * @return a listener for tool item events | |
455 */ | |
456 private Listener getToolItemListener() { | |
457 if (toolItemListener is null) { | |
458 toolItemListener = new class Listener { | |
459 public void handleEvent(Event event) { | |
460 switch (event.type) { | |
461 case SWT.Dispose: | |
462 handleWidgetDispose(event); | |
463 break; | |
464 case SWT.Selection: | |
465 Widget ew = event.widget; | |
466 if (ew !is null) { | |
467 handleWidgetSelection(event, (cast(ToolItem) ew) | |
468 .getSelection()); | |
469 } | |
470 break; | |
471 default: | |
472 } | |
473 } | |
474 }; | |
475 } | |
476 return toolItemListener; | |
477 } | |
478 | |
479 /** | |
480 * Handles a widget dispose event for the widget corresponding to this item. | |
481 */ | |
482 private void handleWidgetDispose(Event e) { | |
483 // Check if our widget is the one being disposed. | |
484 if (e.widget is widget) { | |
485 // Dispose of the menu creator. | |
486 if (action.getStyle() is IAction.AS_DROP_DOWN_MENU | |
487 && menuCreatorCalled) { | |
488 IMenuCreator mc = action.getMenuCreator(); | |
489 if (mc !is null) { | |
490 mc.dispose(); | |
491 } | |
492 } | |
493 | |
494 // Unhook all of the listeners. | |
495 action.removePropertyChangeListener(propertyListener); | |
496 if (action !is null) { | |
497 String commandId = action.getActionDefinitionId(); | |
498 ExternalActionManager.ICallback callback = ExternalActionManager | |
499 .getInstance().getCallback(); | |
500 | |
501 if ((callback !is null) && (commandId !is null)) { | |
502 callback.removePropertyChangeListener(commandId, | |
503 actionTextListener); | |
504 } | |
505 } | |
506 | |
507 // Clear the widget field. | |
508 widget = null; | |
509 | |
510 disposeOldImages(); | |
511 } | |
512 } | |
513 | |
514 /** | |
515 * Handles a widget selection event. | |
516 */ | |
517 private void handleWidgetSelection(Event e, bool selection) { | |
518 | |
519 Widget item = e.widget; | |
520 if (item !is null) { | |
521 int style = item.getStyle(); | |
522 | |
523 if ((style & (SWT.TOGGLE | SWT.CHECK)) !is 0) { | |
524 if (action.getStyle() is IAction.AS_CHECK_BOX) { | |
525 action.setChecked(selection); | |
526 } | |
527 } else if ((style & SWT.RADIO) !is 0) { | |
528 if (action.getStyle() is IAction.AS_RADIO_BUTTON) { | |
529 action.setChecked(selection); | |
530 } | |
531 } else if ((style & SWT.DROP_DOWN) !is 0) { | |
532 if (e.detail is 4) { // on drop-down button | |
533 if (action.getStyle() is IAction.AS_DROP_DOWN_MENU) { | |
534 IMenuCreator mc = action.getMenuCreator(); | |
535 menuCreatorCalled = true; | |
536 ToolItem ti = cast(ToolItem) item; | |
537 // we create the menu as a sub-menu of "dummy" so that | |
538 // we can use | |
539 // it in a cascading menu too. | |
540 // If created on a SWT control we would get an SWT | |
541 // error... | |
542 // Menu dummy= new Menu(ti.getParent()); | |
543 // Menu m= mc.getMenu(dummy); | |
544 // dummy.dispose(); | |
545 if (mc !is null) { | |
546 Menu m = mc.getMenu(ti.getParent()); | |
547 if (m !is null) { | |
548 // position the menu below the drop down item | |
549 Point point = ti.getParent().toDisplay( | |
550 new Point(e.x, e.y)); | |
551 m.setLocation(point.x, point.y); // waiting | |
552 // for SWT | |
553 // 0.42 | |
554 m.setVisible(true); | |
555 return; // we don't fire the action | |
556 } | |
557 } | |
558 } | |
559 } | |
560 } | |
561 | |
562 ExternalActionManager.IExecuteCallback callback = null; | |
563 String actionDefinitionId = action.getActionDefinitionId(); | |
564 if (actionDefinitionId !is null) { | |
565 Object obj = cast(Object) ExternalActionManager.getInstance() | |
566 .getCallback(); | |
567 if (null !is cast(ExternalActionManager.IExecuteCallback)obj ) { | |
568 callback = cast(ExternalActionManager.IExecuteCallback) obj; | |
569 } | |
570 } | |
571 | |
572 // Ensure action is enabled first. | |
573 // See 1GAN3M6: ITPUI:WINNT - Any IAction in the workbench can be | |
574 // executed while disabled. | |
575 if (action.isEnabled()) { | |
576 bool trace = Policy.TRACE_ACTIONS; | |
577 | |
578 long ms = 0L; | |
579 if (trace) { | |
580 ms = System.currentTimeMillis(); | |
581 Stdout.formatln("Running action: {}", action.getText()); //$NON-NLS-1$ | |
582 } | |
583 | |
584 IPropertyChangeListener resultListener = null; | |
585 if (callback !is null) { | |
586 resultListener = new class IPropertyChangeListener { | |
587 public void propertyChange(PropertyChangeEvent event) { | |
588 // Check on result | |
589 if (event.getProperty().equals(IAction.RESULT)) { | |
590 if (null !is cast(Boolean)event.getNewValue() ) { | |
591 result = cast(Boolean) event.getNewValue(); | |
592 } | |
593 } | |
594 } | |
595 }; | |
596 action.addPropertyChangeListener(resultListener); | |
597 callback.preExecute(action, e); | |
598 } | |
599 | |
600 action.runWithEvent(e); | |
601 | |
602 if (callback !is null) { | |
603 if (result is null || result.opEquals(Boolean.TRUE)) { | |
604 callback.postExecuteSuccess(action, Boolean.TRUE); | |
605 } else { | |
606 callback.postExecuteFailure(action, | |
607 new ExecutionException(action.getText() | |
608 ~ " returned failure.")); //$NON-NLS-1$ | |
609 } | |
610 } | |
611 | |
612 if (resultListener !is null) { | |
613 result = null; | |
614 action.removePropertyChangeListener(resultListener); | |
615 } | |
616 if (trace) { | |
617 Stdout.formatln("{} ms to run action: {}",(System.currentTimeMillis() - ms), action.getText()); //$NON-NLS-1$ | |
618 } | |
619 } else { | |
620 if (callback !is null) { | |
621 callback.notEnabled(action, new NotEnabledException(action | |
622 .getText() | |
623 ~ " is not enabled.")); //$NON-NLS-1$ | |
624 } | |
625 } | |
626 } | |
627 } | |
628 | |
629 /* | |
630 * (non-Javadoc) Method declared on Object. | |
631 */ | |
632 public override hash_t toHash() { | |
633 return (cast(Object)action).toHash(); | |
634 } | |
635 | |
636 /** | |
637 * Returns whether the given action has any images. | |
638 * | |
639 * @param actionToCheck | |
640 * the action | |
641 * @return <code>true</code> if the action has any images, | |
642 * <code>false</code> if not | |
643 */ | |
644 private bool hasImages(IAction actionToCheck) { | |
645 return actionToCheck.getImageDescriptor() !is null | |
646 || actionToCheck.getHoverImageDescriptor() !is null | |
647 || actionToCheck.getDisabledImageDescriptor() !is null; | |
648 } | |
649 | |
650 /** | |
651 * Returns whether the command corresponding to this action is active. | |
652 */ | |
653 private bool isCommandActive() { | |
654 IAction actionToCheck = getAction(); | |
655 | |
656 if (actionToCheck !is null) { | |
657 String commandId = actionToCheck.getActionDefinitionId(); | |
658 ExternalActionManager.ICallback callback = ExternalActionManager | |
659 .getInstance().getCallback(); | |
660 | |
661 if (callback !is null) { | |
662 return callback.isActive(commandId); | |
663 } | |
664 } | |
665 return true; | |
666 } | |
667 | |
668 /** | |
669 * The action item implementation of this <code>IContributionItem</code> | |
670 * method returns <code>true</code> for menu items and <code>false</code> | |
671 * for everything else. | |
672 */ | |
673 public override bool isDynamic() { | |
674 if (cast(MenuItem)widget ) { | |
675 // Optimization. Only recreate the item is the check or radio style | |
676 // has changed. | |
677 bool itemIsCheck = (widget.getStyle() & SWT.CHECK) !is 0; | |
678 bool actionIsCheck = getAction() !is null | |
679 && getAction().getStyle() is IAction.AS_CHECK_BOX; | |
680 bool itemIsRadio = (widget.getStyle() & SWT.RADIO) !is 0; | |
681 bool actionIsRadio = getAction() !is null | |
682 && getAction().getStyle() is IAction.AS_RADIO_BUTTON; | |
683 return (itemIsCheck !is actionIsCheck) | |
684 || (itemIsRadio !is actionIsRadio); | |
685 } | |
686 return false; | |
687 } | |
688 | |
689 /* | |
690 * (non-Javadoc) Method declared on IContributionItem. | |
691 */ | |
692 public override bool isEnabled() { | |
693 return action !is null && action.isEnabled(); | |
694 } | |
695 | |
696 /** | |
697 * Returns <code>true</code> if this item is allowed to enable, | |
698 * <code>false</code> otherwise. | |
699 * | |
700 * @return if this item is allowed to be enabled | |
701 * @since 2.0 | |
702 */ | |
703 protected bool isEnabledAllowed() { | |
704 if (getParent() is null) { | |
705 return true; | |
706 } | |
707 auto value = getParent().getOverrides().getEnabled(this); | |
708 return (value is null) ? true : value.value; | |
709 } | |
710 | |
711 /** | |
712 * The <code>ActionContributionItem</code> implementation of this | |
713 * <code>ContributionItem</code> method extends the super implementation | |
714 * by also checking whether the command corresponding to this action is | |
715 * active. | |
716 */ | |
717 public override bool isVisible() { | |
718 return super.isVisible() && isCommandActive(); | |
719 } | |
720 | |
721 /** | |
722 * Sets the presentation mode, which is the bitwise-or of the | |
723 * <code>MODE_*</code> constants. | |
724 * | |
725 * @param mode | |
726 * the presentation mode settings | |
727 * | |
728 * @since 3.0 | |
729 */ | |
730 public void setMode(int mode) { | |
731 this.mode = mode; | |
732 update(); | |
733 } | |
734 | |
735 /** | |
736 * The action item implementation of this <code>IContributionItem</code> | |
737 * method calls <code>update(null)</code>. | |
738 */ | |
739 public override final void update() { | |
740 update(null); | |
741 } | |
742 | |
743 /** | |
744 * Synchronizes the UI with the given property. | |
745 * | |
746 * @param propertyName | |
747 * the name of the property, or <code>null</code> meaning all | |
748 * applicable properties | |
749 */ | |
750 public override void update(String propertyName) { | |
751 if (widget !is null) { | |
752 // determine what to do | |
753 bool textChanged = propertyName is null | |
754 || propertyName.equals(IAction.TEXT); | |
755 bool imageChanged = propertyName is null | |
756 || propertyName.equals(IAction.IMAGE); | |
757 bool tooltipTextChanged = propertyName is null | |
758 || propertyName.equals(IAction.TOOL_TIP_TEXT); | |
759 bool enableStateChanged = propertyName is null | |
760 || propertyName.equals(IAction.ENABLED) | |
761 || propertyName | |
762 .equals(IContributionManagerOverrides.P_ENABLED); | |
763 bool checkChanged = (action.getStyle() is IAction.AS_CHECK_BOX || action | |
764 .getStyle() is IAction.AS_RADIO_BUTTON) | |
765 && (propertyName is null || propertyName | |
766 .equals(IAction.CHECKED)); | |
767 | |
768 if (cast(ToolItem)widget ) { | |
769 ToolItem ti = cast(ToolItem) widget; | |
770 String text = action.getText(); | |
771 // the set text is shown only if there is no image or if forced | |
772 // by MODE_FORCE_TEXT | |
773 bool showText = text !is null | |
774 && ((getMode() & MODE_FORCE_TEXT) !is 0 || !hasImages(action)); | |
775 | |
776 // only do the trimming if the text will be used | |
777 if (showText && text !is null) { | |
778 text = Action.removeAcceleratorText(text); | |
779 text = Action.removeMnemonics(text); | |
780 } | |
781 | |
782 if (textChanged) { | |
783 String textToSet = showText ? text : ""; //$NON-NLS-1$ | |
784 bool rightStyle = (ti.getParent().getStyle() & SWT.RIGHT) !is 0; | |
785 if (rightStyle || !ti.getText().equals(textToSet)) { | |
786 // In addition to being required to update the text if | |
787 // it | |
788 // gets nulled out in the action, this is also a | |
789 // workaround | |
790 // for bug 50151: Using SWT.RIGHT on a ToolBar leaves | |
791 // blank space | |
792 ti.setText(textToSet); | |
793 } | |
794 } | |
795 | |
796 if (imageChanged) { | |
797 // only substitute a missing image if it has no text | |
798 updateImages(!showText); | |
799 } | |
800 | |
801 if (tooltipTextChanged || textChanged) { | |
802 String toolTip = action.getToolTipText(); | |
803 if ((toolTip is null) || (toolTip.length is 0)) { | |
804 toolTip = text; | |
805 } | |
806 | |
807 ExternalActionManager.ICallback callback = ExternalActionManager | |
808 .getInstance().getCallback(); | |
809 String commandId = action.getActionDefinitionId(); | |
810 if ((callback !is null) && (commandId !is null) | |
811 && (toolTip !is null)) { | |
812 String acceleratorText = callback | |
813 .getAcceleratorText(commandId); | |
814 if (acceleratorText !is null | |
815 && acceleratorText.length !is 0) { | |
816 toolTip = JFaceResources.format( | |
817 "Toolbar_Tooltip_Accelerator", //$NON-NLS-1$ | |
818 [ toolTip, acceleratorText ]); | |
819 } | |
820 } | |
821 | |
822 // if the text is showing, then only set the tooltip if | |
823 // different | |
824 if (!showText || toolTip !is null && !toolTip.equals(text)) { | |
825 ti.setToolTipText(toolTip); | |
826 } else { | |
827 ti.setToolTipText(null); | |
828 } | |
829 } | |
830 | |
831 if (enableStateChanged) { | |
832 bool shouldBeEnabled = action.isEnabled() | |
833 && isEnabledAllowed(); | |
834 | |
835 if (ti.getEnabled() !is shouldBeEnabled) { | |
836 ti.setEnabled(shouldBeEnabled); | |
837 } | |
838 } | |
839 | |
840 if (checkChanged) { | |
841 bool bv = action.isChecked(); | |
842 | |
843 if (ti.getSelection() !is bv) { | |
844 ti.setSelection(bv); | |
845 } | |
846 } | |
847 return; | |
848 } | |
849 | |
850 if (cast(MenuItem)widget ) { | |
851 MenuItem mi = cast(MenuItem) widget; | |
852 | |
853 if (textChanged) { | |
854 int accelerator = 0; | |
855 String acceleratorText = null; | |
856 IAction updatedAction = getAction(); | |
857 String text = null; | |
858 accelerator = updatedAction.getAccelerator(); | |
859 ExternalActionManager.ICallback callback = ExternalActionManager | |
860 .getInstance().getCallback(); | |
861 | |
862 // Block accelerators that are already in use. | |
863 if ((accelerator !is 0) && (callback !is null) | |
864 && (callback.isAcceleratorInUse(accelerator))) { | |
865 accelerator = 0; | |
866 } | |
867 | |
868 /* | |
869 * Process accelerators on GTK in a special way to avoid Bug | |
870 * 42009. We will override the native input method by | |
871 * allowing these reserved accelerators to be placed on the | |
872 * menu. We will only do this for "Ctrl+Shift+[0-9A-FU]". | |
873 */ | |
874 String commandId = updatedAction | |
875 .getActionDefinitionId(); | |
876 if (("gtk".equals(SWT.getPlatform())) && (cast(ExternalActionManager.IBindingManagerCallback)callback ) //$NON-NLS-1$ | |
877 && (commandId !is null)) { | |
878 ExternalActionManager.IBindingManagerCallback bindingManagerCallback = cast(ExternalActionManager.IBindingManagerCallback) callback; | |
879 IKeyLookup lookup = KeyLookupFactory.getDefault(); | |
880 TriggerSequence[] triggerSequences = bindingManagerCallback | |
881 .getActiveBindingsFor(commandId); | |
882 for (int i = 0; i < triggerSequences.length; i++) { | |
883 TriggerSequence triggerSequence = triggerSequences[i]; | |
884 Trigger[] triggers = triggerSequence | |
885 .getTriggers(); | |
886 if (triggers.length is 1) { | |
887 Trigger trigger = triggers[0]; | |
888 if (cast(KeyStroke)trigger ) { | |
889 KeyStroke currentKeyStroke = cast(KeyStroke) trigger; | |
890 int currentNaturalKey = currentKeyStroke | |
891 .getNaturalKey(); | |
892 if ((currentKeyStroke.getModifierKeys() is (lookup | |
893 .getCtrl() | lookup.getShift())) | |
894 && ((currentNaturalKey >= '0' && currentNaturalKey <= '9') | |
895 || (currentNaturalKey >= 'A' && currentNaturalKey <= 'F') || (currentNaturalKey is 'U'))) { | |
896 accelerator = currentKeyStroke | |
897 .getModifierKeys() | |
898 | currentNaturalKey; | |
899 acceleratorText = triggerSequence | |
900 .format(); | |
901 break; | |
902 } | |
903 } | |
904 } | |
905 } | |
906 } | |
907 | |
908 if (accelerator is 0) { | |
909 if ((callback !is null) && (commandId !is null)) { | |
910 acceleratorText = callback | |
911 .getAcceleratorText(commandId); | |
912 } | |
913 } | |
914 | |
915 IContributionManagerOverrides overrides = null; | |
916 | |
917 if (getParent() !is null) { | |
918 overrides = getParent().getOverrides(); | |
919 } | |
920 | |
921 if (overrides !is null) { | |
922 text = getParent().getOverrides().getText(this); | |
923 } | |
924 | |
925 mi.setAccelerator(accelerator); | |
926 | |
927 if (text is null) { | |
928 text = updatedAction.getText(); | |
929 } | |
930 | |
931 if (text !is null && acceleratorText is null) { | |
932 // use extracted accelerator text in case accelerator | |
933 // cannot be fully represented in one int (e.g. | |
934 // multi-stroke keys) | |
935 acceleratorText = LegacyActionTools | |
936 .extractAcceleratorText(text); | |
937 if (acceleratorText is null && accelerator !is 0) { | |
938 acceleratorText = Action | |
939 .convertAccelerator(accelerator); | |
940 } | |
941 } | |
942 | |
943 if (text is null) { | |
944 text = ""; //$NON-NLS-1$ | |
945 } else { | |
946 text = Action.removeAcceleratorText(text); | |
947 } | |
948 | |
949 if (acceleratorText is null) { | |
950 mi.setText(text); | |
951 } else { | |
952 mi.setText(text ~ '\t' ~ acceleratorText); | |
953 } | |
954 } | |
955 | |
956 if (imageChanged) { | |
957 updateImages(false); | |
958 } | |
959 | |
960 if (enableStateChanged) { | |
961 bool shouldBeEnabled = action.isEnabled() | |
962 && isEnabledAllowed(); | |
963 | |
964 if (mi.getEnabled() !is shouldBeEnabled) { | |
965 mi.setEnabled(shouldBeEnabled); | |
966 } | |
967 } | |
968 | |
969 if (checkChanged) { | |
970 bool bv = action.isChecked(); | |
971 | |
972 if (mi.getSelection() !is bv) { | |
973 mi.setSelection(bv); | |
974 } | |
975 } | |
976 | |
977 return; | |
978 } | |
979 | |
980 if (cast(Button)widget ) { | |
981 Button button = cast(Button) widget; | |
982 | |
983 if (imageChanged) { | |
984 updateImages(false); | |
985 } | |
986 | |
987 if (textChanged) { | |
988 String text = action.getText(); | |
989 bool showText = text !is null && ((getMode() & MODE_FORCE_TEXT) !is 0 || !hasImages(action)); | |
990 // only do the trimming if the text will be used | |
991 if (showText) { | |
992 text = Action.removeAcceleratorText(text); | |
993 } | |
994 String textToSet = showText ? text : ""; //$NON-NLS-1$ | |
995 button.setText(textToSet); | |
996 } | |
997 | |
998 if (tooltipTextChanged) { | |
999 button.setToolTipText(action.getToolTipText()); | |
1000 } | |
1001 | |
1002 if (enableStateChanged) { | |
1003 bool shouldBeEnabled = action.isEnabled() | |
1004 && isEnabledAllowed(); | |
1005 | |
1006 if (button.getEnabled() !is shouldBeEnabled) { | |
1007 button.setEnabled(shouldBeEnabled); | |
1008 } | |
1009 } | |
1010 | |
1011 if (checkChanged) { | |
1012 bool bv = action.isChecked(); | |
1013 | |
1014 if (button.getSelection() !is bv) { | |
1015 button.setSelection(bv); | |
1016 } | |
1017 } | |
1018 return; | |
1019 } | |
1020 } | |
1021 } | |
1022 | |
1023 /** | |
1024 * Updates the images for this action. | |
1025 * | |
1026 * @param forceImage | |
1027 * <code>true</code> if some form of image is compulsory, and | |
1028 * <code>false</code> if it is acceptable for this item to have | |
1029 * no image | |
1030 * @return <code>true</code> if there are images for this action, | |
1031 * <code>false</code> if not | |
1032 */ | |
1033 private bool updateImages(bool forceImage) { | |
1034 | |
1035 ResourceManager parentResourceManager = JFaceResources.getResources(); | |
1036 | |
1037 if (cast(ToolItem)widget ) { | |
1038 if (USE_COLOR_ICONS) { | |
1039 ImageDescriptor image = action.getHoverImageDescriptor(); | |
1040 if (image is null) { | |
1041 image = action.getImageDescriptor(); | |
1042 } | |
1043 ImageDescriptor disabledImage = action | |
1044 .getDisabledImageDescriptor(); | |
1045 | |
1046 // Make sure there is a valid image. | |
1047 if (image is null && forceImage) { | |
1048 image = ImageDescriptor.getMissingImageDescriptor(); | |
1049 } | |
1050 | |
1051 LocalResourceManager localManager = new LocalResourceManager( | |
1052 parentResourceManager); | |
1053 | |
1054 // performance: more efficient in SWT to set disabled and hot | |
1055 // image before regular image | |
1056 (cast(ToolItem) widget) | |
1057 .setDisabledImage(disabledImage is null ? null | |
1058 : localManager | |
1059 .createImageWithDefault(disabledImage)); | |
1060 (cast(ToolItem) widget).setImage(image is null ? null | |
1061 : localManager.createImageWithDefault(image)); | |
1062 | |
1063 disposeOldImages(); | |
1064 imageManager = localManager; | |
1065 | |
1066 return image !is null; | |
1067 } | |
1068 ImageDescriptor image = action.getImageDescriptor(); | |
1069 ImageDescriptor hoverImage = action.getHoverImageDescriptor(); | |
1070 ImageDescriptor disabledImage = action.getDisabledImageDescriptor(); | |
1071 | |
1072 // If there is no regular image, but there is a hover image, | |
1073 // convert the hover image to gray and use it as the regular image. | |
1074 if (image is null && hoverImage !is null) { | |
1075 image = ImageDescriptor.createWithFlags(action | |
1076 .getHoverImageDescriptor(), SWT.IMAGE_GRAY); | |
1077 } else { | |
1078 // If there is no hover image, use the regular image as the | |
1079 // hover image, | |
1080 // and convert the regular image to gray | |
1081 if (hoverImage is null && image !is null) { | |
1082 hoverImage = image; | |
1083 image = ImageDescriptor.createWithFlags(action | |
1084 .getImageDescriptor(), SWT.IMAGE_GRAY); | |
1085 } | |
1086 } | |
1087 | |
1088 // Make sure there is a valid image. | |
1089 if (hoverImage is null && image is null && forceImage) { | |
1090 image = ImageDescriptor.getMissingImageDescriptor(); | |
1091 } | |
1092 | |
1093 // Create a local resource manager to remember the images we've | |
1094 // allocated for this tool item | |
1095 LocalResourceManager localManager = new LocalResourceManager( | |
1096 parentResourceManager); | |
1097 | |
1098 // performance: more efficient in SWT to set disabled and hot image | |
1099 // before regular image | |
1100 (cast(ToolItem) widget).setDisabledImage(disabledImage is null ? null | |
1101 : localManager.createImageWithDefault(disabledImage)); | |
1102 (cast(ToolItem) widget).setHotImage(hoverImage is null ? null | |
1103 : localManager.createImageWithDefault(hoverImage)); | |
1104 (cast(ToolItem) widget).setImage(image is null ? null : localManager | |
1105 .createImageWithDefault(image)); | |
1106 | |
1107 // Now that we're no longer referencing the old images, clear them | |
1108 // out. | |
1109 disposeOldImages(); | |
1110 imageManager = localManager; | |
1111 | |
1112 return image !is null; | |
1113 } else if (cast(Item)widget || cast(Button)widget ) { | |
1114 | |
1115 // Use hover image if there is one, otherwise use regular image. | |
1116 ImageDescriptor image = action.getHoverImageDescriptor(); | |
1117 if (image is null) { | |
1118 image = action.getImageDescriptor(); | |
1119 } | |
1120 // Make sure there is a valid image. | |
1121 if (image is null && forceImage) { | |
1122 image = ImageDescriptor.getMissingImageDescriptor(); | |
1123 } | |
1124 | |
1125 // Create a local resource manager to remember the images we've | |
1126 // allocated for this widget | |
1127 LocalResourceManager localManager = new LocalResourceManager( | |
1128 parentResourceManager); | |
1129 | |
1130 if (cast(Item)widget) { | |
1131 (cast(Item) widget).setImage(image is null ? null : localManager | |
1132 .createImageWithDefault(image)); | |
1133 } else if (cast(Button)widget) { | |
1134 (cast(Button) widget).setImage(image is null ? null : localManager | |
1135 .createImageWithDefault(image)); | |
1136 } | |
1137 | |
1138 // Now that we're no longer referencing the old images, clear them | |
1139 // out. | |
1140 disposeOldImages(); | |
1141 imageManager = localManager; | |
1142 | |
1143 return image !is null; | |
1144 } | |
1145 return false; | |
1146 } | |
1147 | |
1148 /** | |
1149 * Dispose any images allocated for this contribution item | |
1150 */ | |
1151 private void disposeOldImages() { | |
1152 if (imageManager !is null) { | |
1153 imageManager.dispose(); | |
1154 imageManager = null; | |
1155 } | |
1156 } | |
1157 | |
1158 /** | |
1159 * Shorten the given text <code>t</code> so that its length doesn't exceed | |
1160 * the width of the given ToolItem.The default implementation replaces | |
1161 * characters in the center of the original string with an ellipsis ("..."). | |
1162 * Override if you need a different strategy. | |
1163 * | |
1164 * @param textValue | |
1165 * the text to shorten | |
1166 * @param item | |
1167 * the tool item the text belongs to | |
1168 * @return the shortened string | |
1169 * | |
1170 */ | |
1171 protected String shortenText(String textValue, ToolItem item) { | |
1172 if (textValue is null) { | |
1173 return null; | |
1174 } | |
1175 | |
1176 GC gc = new GC(item.getParent()); | |
1177 | |
1178 int maxWidth = item.getImage().getBounds().width * 4; | |
1179 | |
1180 if (gc.textExtent(textValue).x < maxWidth) { | |
1181 gc.dispose(); | |
1182 return textValue; | |
1183 } | |
1184 | |
1185 for (int i = textValue.length; i > 0; i--) { | |
1186 String test = textValue.substring(0, i); | |
1187 test = test ~ ellipsis; | |
1188 if (gc.textExtent(test).x < maxWidth) { | |
1189 gc.dispose(); | |
1190 return test; | |
1191 } | |
1192 | |
1193 } | |
1194 gc.dispose(); | |
1195 // If for some reason we fall through abort | |
1196 return textValue; | |
1197 } | |
1198 | |
1199 /* | |
1200 * (non-Javadoc) | |
1201 * | |
1202 * @see org.eclipse.jface.action.ContributionItem#dispose() | |
1203 */ | |
1204 public void dispose() { | |
1205 if (widget !is null) { | |
1206 widget.dispose(); | |
1207 widget = null; | |
1208 } | |
1209 holdMenu = null; | |
1210 } | |
1211 | |
1212 /** | |
1213 * Handle show and hide on the proxy menu for IAction.AS_DROP_DOWN_MENU | |
1214 * actions. | |
1215 * | |
1216 * @return the appropriate listener | |
1217 * @since 3.4 | |
1218 */ | |
1219 private Listener getMenuCreatorListener() { | |
1220 if (menuCreatorListener is null) { | |
1221 menuCreatorListener = new class Listener { | |
1222 public void handleEvent(Event event) { | |
1223 switch (event.type) { | |
1224 case SWT.Show: | |
1225 handleShowProxy(cast(Menu) event.widget); | |
1226 break; | |
1227 case SWT.Hide: | |
1228 handleHideProxy(cast(Menu) event.widget); | |
1229 break; | |
1230 default: | |
1231 } | |
1232 } | |
1233 }; | |
1234 } | |
1235 return menuCreatorListener; | |
1236 } | |
1237 | |
1238 /** | |
1239 * This is the easiest way to hold the menu until we can swap it in to the | |
1240 * proxy. | |
1241 */ | |
1242 private Menu holdMenu = null; | |
1243 | |
1244 private bool menuCreatorCalled = false; | |
1245 | |
1246 /** | |
1247 * The proxy menu is being shown, we better get the real menu. | |
1248 * | |
1249 * @param proxy | |
1250 * the proxy menu | |
1251 * @since 3.4 | |
1252 */ | |
1253 private void handleShowProxy(Menu proxy) { | |
1254 proxy.removeListener(SWT.Show, getMenuCreatorListener()); | |
1255 IMenuCreator mc = action.getMenuCreator(); | |
1256 menuCreatorCalled = true; | |
1257 if (mc is null) { | |
1258 return; | |
1259 } | |
1260 holdMenu = mc.getMenu(proxy.getParentMenu()); | |
1261 if (holdMenu is null) { | |
1262 return; | |
1263 } | |
1264 copyMenu(holdMenu, proxy); | |
1265 } | |
1266 | |
1267 /** | |
1268 * Create MenuItems in the proxy menu that can execute the real menu items | |
1269 * if selected. Create proxy menus for any real item submenus. | |
1270 * | |
1271 * @param realMenu | |
1272 * the real menu to copy from | |
1273 * @param proxy | |
1274 * the proxy menu to populate | |
1275 * @since 3.4 | |
1276 */ | |
1277 private void copyMenu(Menu realMenu, Menu proxy) { | |
1278 if (realMenu.isDisposed() || proxy.isDisposed()) { | |
1279 return; | |
1280 } | |
1281 | |
1282 // we notify the real menu so it can populate itself if it was | |
1283 // listening for SWT.Show | |
1284 realMenu.notifyListeners(SWT.Show, null); | |
1285 | |
1286 final Listener passThrough = new class Listener { | |
1287 public void handleEvent(Event event) { | |
1288 if (!event.widget.isDisposed()) { | |
1289 Widget realItem = cast(Widget) event.widget.getData(); | |
1290 if (!realItem.isDisposed()) { | |
1291 int style = event.widget.getStyle(); | |
1292 if (event.type is SWT.Selection | |
1293 && ((style & (SWT.TOGGLE | SWT.CHECK)) !is 0) | |
1294 && (null !is cast(MenuItem)realItem )) { | |
1295 (cast(MenuItem) realItem) | |
1296 .setSelection((cast(MenuItem) event.widget) | |
1297 .getSelection()); | |
1298 } | |
1299 event.widget = realItem; | |
1300 realItem.notifyListeners(event.type, event); | |
1301 } | |
1302 } | |
1303 } | |
1304 }; | |
1305 | |
1306 MenuItem[] items = realMenu.getItems(); | |
1307 for (int i = 0; i < items.length; i++) { | |
1308 final MenuItem realItem = items[i]; | |
1309 final MenuItem proxyItem = new MenuItem(proxy, realItem.getStyle()); | |
1310 proxyItem.setData(realItem); | |
1311 proxyItem.setAccelerator(realItem.getAccelerator()); | |
1312 proxyItem.setEnabled(realItem.getEnabled()); | |
1313 proxyItem.setImage(realItem.getImage()); | |
1314 proxyItem.setSelection(realItem.getSelection()); | |
1315 proxyItem.setText(realItem.getText()); | |
1316 | |
1317 // pass through any events | |
1318 proxyItem.addListener(SWT.Selection, passThrough); | |
1319 proxyItem.addListener(SWT.Arm, passThrough); | |
1320 proxyItem.addListener(SWT.Help, passThrough); | |
1321 | |
1322 final Menu itemMenu = realItem.getMenu(); | |
1323 if (itemMenu !is null) { | |
1324 // create a proxy for any sub menu items | |
1325 final Menu subMenu = new Menu(proxy); | |
1326 subMenu.setData(itemMenu); | |
1327 proxyItem.setMenu(subMenu); | |
1328 subMenu.addListener(SWT.Show, new class(subMenu, itemMenu) Listener { | |
1329 Menu subMenu_; | |
1330 Menu itemMenu_; | |
1331 this(Menu a,Menu b){ | |
1332 subMenu_=a; | |
1333 itemMenu_=b; | |
1334 } | |
1335 void handleEvent(Event event){ | |
1336 event.widget.removeListener(SWT.Show, this); | |
1337 if (event.type is SWT.Show) { | |
1338 copyMenu(itemMenu_, subMenu_); | |
1339 } | |
1340 } | |
1341 }); | |
1342 subMenu.addListener(SWT.Help, passThrough); | |
1343 subMenu.addListener(SWT.Hide, passThrough); | |
1344 } | |
1345 } | |
1346 } | |
1347 | |
1348 /** | |
1349 * The proxy menu is being hidden, so we need to make it go away. | |
1350 * | |
1351 * @param proxy | |
1352 * the proxy menu | |
1353 * @since 3.4 | |
1354 */ | |
1355 private void handleHideProxy(Menu proxy) { | |
1356 proxy.removeListener(SWT.Hide, getMenuCreatorListener()); | |
1357 proxy.getDisplay().asyncExec(dgRunnable( (Menu proxy_) { | |
1358 if (!proxy_.isDisposed()) { | |
1359 MenuItem parentItem = proxy_.getParentItem(); | |
1360 proxy_.dispose(); | |
1361 parentItem.setMenu(holdMenu); | |
1362 } | |
1363 if (holdMenu !is null && !holdMenu.isDisposed()) { | |
1364 holdMenu.notifyListeners(SWT.Hide, null); | |
1365 } | |
1366 holdMenu = null; | |
1367 }, proxy )); | |
1368 } | |
1369 | |
1370 /** | |
1371 * Return the widget associated with this contribution item. It should not | |
1372 * be cached, as it can be disposed and re-created by its containing | |
1373 * ContributionManager, which controls all of the widgets lifecycle methods. | |
1374 * <p> | |
1375 * This can be used to set layout data on the widget if appropriate. The | |
1376 * actual type of the widget can be any valid control for this | |
1377 * ContributionItem's current ContributionManager. | |
1378 * </p> | |
1379 * | |
1380 * @return the widget, or <code>null</code> depending on the lifecycle. | |
1381 * @since 3.4 | |
1382 */ | |
1383 public Widget getWidget() { | |
1384 return widget; | |
1385 } | |
1386 } |