comparison org.eclipse.jface/src/org/eclipse/jface/action/MenuManager.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
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 * Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 12116 [Contributions] widgets: MenuManager.setImageDescriptor() method needed
11 * Port to the D programming language:
12 * Frank Benoit <benoit@tionex.de>
13 *******************************************************************************/
14 module org.eclipse.jface.action.MenuManager;
15
16 import org.eclipse.jface.action.ContributionManager;
17 import org.eclipse.jface.action.IMenuManager;
18 import org.eclipse.jface.action.IContributionManagerOverrides;
19 import org.eclipse.jface.action.IContributionManager;
20 import org.eclipse.jface.action.IMenuListener;
21 import org.eclipse.jface.action.IMenuListener2;
22 import org.eclipse.jface.action.IContributionItem;
23 import org.eclipse.jface.action.SubContributionItem;
24 import org.eclipse.jface.action.IAction;
25 import org.eclipse.jface.action.ExternalActionManager;
26
27
28 import org.eclipse.swt.SWT;
29 import org.eclipse.swt.events.MenuAdapter;
30 import org.eclipse.swt.events.MenuEvent;
31 import org.eclipse.swt.widgets.Composite;
32 import org.eclipse.swt.widgets.Control;
33 import org.eclipse.swt.widgets.CoolBar;
34 import org.eclipse.swt.widgets.Decorations;
35 import org.eclipse.swt.widgets.Item;
36 import org.eclipse.swt.widgets.Menu;
37 import org.eclipse.swt.widgets.MenuItem;
38 import org.eclipse.swt.widgets.Shell;
39 import org.eclipse.swt.widgets.ToolBar;
40 import org.eclipse.core.runtime.ListenerList;
41 import org.eclipse.jface.resource.ImageDescriptor;
42 import org.eclipse.jface.resource.JFaceResources;
43 import org.eclipse.jface.resource.LocalResourceManager;
44
45 import java.lang.all;
46 import java.util.List;
47 import java.util.ArrayList;
48 import java.util.Iterator;
49 import java.util.Set;
50
51
52 /**
53 * A menu manager is a contribution manager which realizes itself and its items
54 * in a menu control; either as a menu bar, a sub-menu, or a context menu.
55 * <p>
56 * This class may be instantiated; it may also be subclassed.
57 * </p>
58 */
59 public class MenuManager : ContributionManager, IMenuManager {
60
61 public bool isDirty(){
62 return super.isDirty();
63 }
64
65 /**
66 * The menu id.
67 */
68 private String id;
69
70 /**
71 * List of registered menu listeners (element type: <code>IMenuListener</code>).
72 */
73 private ListenerList listeners;
74
75 /**
76 * The menu control; <code>null</code> before
77 * creation and after disposal.
78 */
79 private Menu menu = null;
80
81 /**
82 * The menu item widget; <code>null</code> before
83 * creation and after disposal. This field is used
84 * when this menu manager is a sub-menu.
85 */
86 private MenuItem menuItem;
87
88 /**
89 * The text for a sub-menu.
90 */
91 private String menuText;
92
93 /**
94 * The image for a sub-menu.
95 */
96 private ImageDescriptor image;
97
98 /**
99 * A resource manager to remember all of the images that have been used by this menu.
100 */
101 private LocalResourceManager imageManager;
102
103 /**
104 * The overrides for items of this manager
105 */
106 private IContributionManagerOverrides overrides;
107
108 /**
109 * The parent contribution manager.
110 */
111 private IContributionManager parent;
112
113 /**
114 * Indicates whether <code>removeAll</code> should be
115 * called just before the menu is displayed.
116 */
117 private bool removeAllWhenShown = false;
118
119 /**
120 * Indicates this item is visible in its manager; <code>true</code>
121 * by default.
122 * @since 3.3
123 */
124 protected bool visible = true;
125
126 /**
127 * allows a submenu to display a shortcut key. This is often used with the
128 * QuickMenu command or action which can pop up a menu using the shortcut.
129 */
130 private String definitionId = null;
131
132 /**
133 * Creates a menu manager. The text and id are <code>null</code>.
134 * Typically used for creating a context menu, where it doesn't need to be referred to by id.
135 */
136 public this() {
137 this(null, null, null);
138 }
139
140 /**
141 * Creates a menu manager with the given text. The id of the menu
142 * is <code>null</code>.
143 * Typically used for creating a sub-menu, where it doesn't need to be referred to by id.
144 *
145 * @param text the text for the menu, or <code>null</code> if none
146 */
147 public this(String text) {
148 this(text, null, null);
149 }
150
151 /**
152 * Creates a menu manager with the given text and id.
153 * Typically used for creating a sub-menu, where it needs to be referred to by id.
154 *
155 * @param text the text for the menu, or <code>null</code> if none
156 * @param id the menu id, or <code>null</code> if it is to have no id
157 */
158 public this(String text, String id) {
159 this(text, null, id);
160 }
161
162 /**
163 * Creates a menu manager with the given text, image, and id.
164 * Typically used for creating a sub-menu, where it needs to be referred to by id.
165 *
166 * @param text the text for the menu, or <code>null</code> if none
167 * @param image the image for the menu, or <code>null</code> if none
168 * @param id the menu id, or <code>null</code> if it is to have no id
169 * @since 3.4
170 */
171 public this(String text, ImageDescriptor image, String id) {
172 listeners = new ListenerList();
173 this.menuText = text;
174 this.image = image;
175 this.id = id;
176 }
177
178 /* (non-Javadoc)
179 * @see org.eclipse.jface.action.IMenuManager#addMenuListener(org.eclipse.jface.action.IMenuListener)
180 */
181 public void addMenuListener(IMenuListener listener) {
182 listeners.add(cast(Object)listener);
183 }
184
185 /**
186 * Creates and returns an SWT context menu control for this menu,
187 * and installs all registered contributions.
188 * Does not create a new control if one already exists.
189 * <p>
190 * Note that the menu is not expected to be dynamic.
191 * </p>
192 *
193 * @param parent the parent control
194 * @return the menu control
195 */
196 public Menu createContextMenu(Control parent) {
197 if (!menuExist()) {
198 menu = new Menu(parent);
199 initializeMenu();
200 }
201 return menu;
202 }
203
204 /**
205 * Creates and returns an SWT menu bar control for this menu,
206 * for use in the given <code>Decorations</code>, and installs all registered
207 * contributions. Does not create a new control if one already exists.
208 *
209 * @param parent the parent decorations
210 * @return the menu control
211 * @since 2.1
212 */
213 public Menu createMenuBar(Decorations parent) {
214 if (!menuExist()) {
215 menu = new Menu(parent, SWT.BAR);
216 update(false);
217 }
218 return menu;
219 }
220
221 /**
222 * Creates and returns an SWT menu bar control for this menu, for use in the
223 * given <code>Shell</code>, and installs all registered contributions. Does not
224 * create a new control if one already exists. This implementation simply calls
225 * the <code>createMenuBar(Decorations)</code> method
226 *
227 * @param parent the parent decorations
228 * @return the menu control
229 * @deprecated use <code>createMenuBar(Decorations)</code> instead.
230 */
231 public Menu createMenuBar(Shell parent) {
232 return createMenuBar(cast(Decorations) parent);
233 }
234
235 /**
236 * Disposes of this menu manager and frees all allocated SWT resources.
237 * Notifies all contribution items of the dispose. Note that this method does
238 * not clean up references between this menu manager and its associated
239 * contribution items. Use <code>removeAll</code> for that purpose.
240 */
241 public void dispose() {
242 if (menuExist()) {
243 menu.dispose();
244 }
245 menu = null;
246
247 if (menuItem !is null) {
248 menuItem.dispose();
249 menuItem = null;
250 }
251
252 disposeOldImages();
253
254 IContributionItem[] items = getItems();
255 for (int i = 0; i < items.length; i++) {
256 items[i].dispose();
257 }
258
259 markDirty();
260 }
261
262 /* (non-Javadoc)
263 * @see org.eclipse.jface.action.IContributionItem#fill(org.eclipse.swt.widgets.Composite)
264 */
265 public void fill(Composite parent) {
266 }
267
268 /* (non-Javadoc)
269 * @see org.eclipse.jface.action.IContributionItem#fill(org.eclipse.swt.widgets.CoolBar, int)
270 */
271 public void fill(CoolBar parent, int index) {
272 }
273
274 /* (non-Javadoc)
275 * @see org.eclipse.jface.action.IContributionItem#fill(org.eclipse.swt.widgets.Menu, int)
276 */
277 public void fill(Menu parent, int index) {
278 if (menuItem is null || menuItem.isDisposed()) {
279 if (index >= 0) {
280 menuItem = new MenuItem(parent, SWT.CASCADE, index);
281 } else {
282 menuItem = new MenuItem(parent, SWT.CASCADE);
283 }
284
285 menuItem.setText(getMenuText());
286
287 if (image !is null) {
288 LocalResourceManager localManager = new LocalResourceManager(
289 JFaceResources.getResources());
290 menuItem.setImage(localManager.createImage(image));
291 disposeOldImages();
292 imageManager = localManager;
293 }
294
295 if (!menuExist()) {
296 menu = new Menu(parent);
297 }
298
299 menuItem.setMenu(menu);
300
301 initializeMenu();
302
303 setDirty(true);
304 }
305 }
306
307 /* (non-Javadoc)
308 * @see org.eclipse.jface.action.IContributionItem#fill(org.eclipse.swt.widgets.ToolBar, int)
309 */
310 public void fill(ToolBar parent, int index) {
311 }
312
313 /* (non-Javadoc)
314 * @see org.eclipse.jface.action.IMenuManager#findMenuUsingPath(java.lang.String)
315 */
316 public IMenuManager findMenuUsingPath(String path) {
317 IContributionItem item = findUsingPath(path);
318 if (auto mm = cast(IMenuManager)item ) {
319 return mm;
320 }
321 return null;
322 }
323
324 /* (non-Javadoc)
325 * @see org.eclipse.jface.action.IMenuManager#findUsingPath(java.lang.String)
326 */
327 public IContributionItem findUsingPath(String path) {
328 String id = path;
329 String rest = null;
330 int separator = java.lang.all.indexOf( path, '/');
331 if (separator !is -1) {
332 id = path.substring(0, separator);
333 rest = path.substring(separator + 1);
334 } else {
335 return super.find(path);
336 }
337
338 IContributionItem item = super.find(id);
339 if (auto manager = cast(IMenuManager)item ) {
340 return manager.findUsingPath(rest);
341 }
342 return null;
343 }
344
345 /**
346 * Notifies any menu listeners that a menu is about to show.
347 * Only listeners registered at the time this method is called are notified.
348 *
349 * @param manager the menu manager
350 *
351 * @see IMenuListener#menuAboutToShow
352 */
353 private void fireAboutToShow(IMenuManager manager) {
354 Object[] listeners = this.listeners.getListeners();
355 for (int i = 0; i < listeners.length; ++i) {
356 (cast(IMenuListener) listeners[i]).menuAboutToShow(manager);
357 }
358 }
359
360 /**
361 * Notifies any menu listeners that a menu is about to hide.
362 * Only listeners registered at the time this method is called are notified.
363 *
364 * @param manager the menu manager
365 *
366 */
367 private void fireAboutToHide(IMenuManager manager) {
368 final Object[] listeners = this.listeners.getListeners();
369 for (int i = 0; i < listeners.length; ++i) {
370 final Object listener = listeners[i];
371 if (auto listener2 = cast(IMenuListener2)listener) {
372 listener2.menuAboutToHide(manager);
373 }
374 }
375 }
376
377 /**
378 * Returns the menu id. The menu id is used when creating a contribution
379 * item for adding this menu as a sub menu of another.
380 *
381 * @return the menu id
382 */
383 public String getId() {
384 return id;
385 }
386
387 /**
388 * Returns the SWT menu control for this menu manager.
389 *
390 * @return the menu control
391 */
392 public Menu getMenu() {
393 return menu;
394 }
395
396 /**
397 * Returns the text shown in the menu, potentially with a shortcut
398 * appended.
399 *
400 * @return the menu text
401 */
402 public String getMenuText() {
403 if (definitionId is null) {
404 return menuText;
405 }
406 ExternalActionManager.ICallback callback = ExternalActionManager
407 .getInstance().getCallback();
408 if (callback !is null) {
409 String shortCut = callback.getAcceleratorText(definitionId);
410 if (shortCut is null) {
411 return menuText;
412 }
413 return menuText ~ "\t" ~ shortCut; //$NON-NLS-1$
414 }
415 return menuText;
416 }
417
418 /**
419 * Returns the image for this menu as an image descriptor.
420 *
421 * @return the image, or <code>null</code> if this menu has no image
422 * @since 3.4
423 */
424 public ImageDescriptor getImageDescriptor() {
425 return image;
426 }
427
428 /* (non-Javadoc)
429 * @see org.eclipse.jface.action.IContributionManager#getOverrides()
430 */
431 public override IContributionManagerOverrides getOverrides() {
432 if (overrides is null) {
433 if (parent is null) {
434 overrides = new class IContributionManagerOverrides {
435 public Integer getAccelerator(IContributionItem item) {
436 return null;
437 }
438
439 public String getAcceleratorText(IContributionItem item) {
440 return null;
441 }
442
443 public Boolean getEnabled(IContributionItem item) {
444 return null;
445 }
446
447 public String getText(IContributionItem item) {
448 return null;
449 }
450 };
451 } else {
452 overrides = parent.getOverrides();
453 }
454 super.setOverrides(overrides);
455 }
456 return overrides;
457 }
458
459 /**
460 * Returns the parent contribution manager of this manger.
461 *
462 * @return the parent contribution manager
463 * @since 2.0
464 */
465 public IContributionManager getParent() {
466 return parent;
467 }
468
469 /* (non-Javadoc)
470 * @see org.eclipse.jface.action.IMenuManager#getRemoveAllWhenShown()
471 */
472 public bool getRemoveAllWhenShown() {
473 return removeAllWhenShown;
474 }
475
476 /**
477 * Notifies all listeners that this menu is about to appear.
478 */
479 private void handleAboutToShow() {
480 if (removeAllWhenShown) {
481 removeAll();
482 }
483 fireAboutToShow(this);
484 update(false, false);
485 }
486
487 /**
488 * Notifies all listeners that this menu is about to disappear.
489 */
490 private void handleAboutToHide() {
491 fireAboutToHide(this);
492 }
493
494 /**
495 * Initializes the menu control.
496 */
497 private void initializeMenu() {
498 menu.addMenuListener(new class MenuAdapter {
499 public void menuHidden(MenuEvent e) {
500 // ApplicationWindow.resetDescription(e.widget);
501 handleAboutToHide();
502 }
503
504 public void menuShown(MenuEvent e) {
505 handleAboutToShow();
506 }
507 });
508 // Don't do an update(true) here, in case menu is never opened.
509 // Always do it lazily in handleAboutToShow().
510 }
511
512 /* (non-Javadoc)
513 * @see org.eclipse.jface.action.IContributionItem#isDynamic()
514 */
515 public bool isDynamic() {
516 return false;
517 }
518
519 /**
520 * Returns whether this menu should be enabled or not.
521 * Used to enable the menu item containing this menu when it is realized as a sub-menu.
522 * <p>
523 * The default implementation of this framework method
524 * returns <code>true</code>. Subclasses may reimplement.
525 * </p>
526 *
527 * @return <code>true</code> if enabled, and
528 * <code>false</code> if disabled
529 */
530 public bool isEnabled() {
531 return true;
532 }
533
534 /* (non-Javadoc)
535 * @see org.eclipse.jface.action.IContributionItem#isGroupMarker()
536 */
537 public bool isGroupMarker() {
538 return false;
539 }
540
541 /* (non-Javadoc)
542 * @see org.eclipse.jface.action.IContributionItem#isSeparator()
543 */
544 public bool isSeparator() {
545 return false;
546 }
547
548 /**
549 * Check if the contribution is item is a subsitute for ourselves
550 *
551 * @param item the contribution item
552 * @return <code>true</code> if give item is a substitution for ourselves
553 * @deprecated this method is no longer a part of the
554 * {@link org.eclipse.jface.action.IContributionItem} API.
555 */
556 public bool isSubstituteFor(IContributionItem item) {
557 return this.opEquals(cast(Object)item) !is 0;
558 }
559
560 /* (non-Javadoc)
561 * @see org.eclipse.jface.action.IContributionItem#isVisible()
562 */
563 public bool isVisible() {
564 if (!visible) {
565 return false; // short circuit calculations in this case
566 }
567
568 if (removeAllWhenShown) {
569 // we have no way of knowing if the menu has children
570 return true;
571 }
572
573 // menus aren't visible if all of its children are invisible (or only contains visible separators).
574 IContributionItem[] childItems = getItems();
575 bool visibleChildren = false;
576 for (int j = 0; j < childItems.length; j++) {
577 if (childItems[j].isVisible() && !childItems[j].isSeparator()) {
578 visibleChildren = true;
579 break;
580 }
581 }
582
583 return visibleChildren;
584 }
585
586
587 /**
588 * The <code>MenuManager</code> implementation of this <code>ContributionManager</code> method
589 * also propagates the dirty flag up the parent chain.
590 *
591 * @since 3.1
592 */
593 public override void markDirty() {
594 super.markDirty();
595 // Can't optimize by short-circuiting when the first dirty manager is encountered,
596 // since non-visible children are not even processed.
597 // That is, it's possible to have a dirty sub-menu under a non-dirty parent menu
598 // even after the parent menu has been updated.
599 // If items are added/removed in the sub-menu, we still need to propagate the dirty flag up,
600 // even if the sub-menu is already dirty, since the result of isVisible() may change
601 // due to the added/removed items.
602 IContributionManager parent = getParent();
603 if (parent !is null) {
604 parent.markDirty();
605 }
606 }
607
608 /**
609 * Returns whether the menu control is created
610 * and not disposed.
611 *
612 * @return <code>true</code> if the control is created
613 * and not disposed, <code>false</code> otherwise
614 * @since 3.4 protected, was added in 3.1 as private method
615 */
616 protected bool menuExist() {
617 return menu !is null && !menu.isDisposed();
618 }
619
620 /* (non-Javadoc)
621 * @see org.eclipse.jface.action.IMenuManager#removeMenuListener(org.eclipse.jface.action.IMenuListener)
622 */
623 public void removeMenuListener(IMenuListener listener) {
624 listeners.remove(cast(Object)listener);
625 }
626
627 /* (non-Javadoc)
628 * @see org.eclipse.jface.action.IContributionItem#saveWidgetState()
629 */
630 public void saveWidgetState() {
631 }
632
633 /**
634 * Sets the overrides for this contribution manager
635 *
636 * @param newOverrides the overrides for the items of this manager
637 * @since 2.0
638 */
639 public override void setOverrides(IContributionManagerOverrides newOverrides) {
640 overrides = newOverrides;
641 super.setOverrides(overrides);
642 }
643
644 /* (non-Javadoc)
645 * @see org.eclipse.jface.action.IContributionItem#setParent(org.eclipse.jface.action.IContributionManager)
646 */
647 public void setParent(IContributionManager manager) {
648 parent = manager;
649 }
650
651 /* (non-Javadoc)
652 * @see org.eclipse.jface.action.IMenuManager#setRemoveAllWhenShown(bool)
653 */
654 public void setRemoveAllWhenShown(bool removeAll) {
655 this.removeAllWhenShown = removeAll;
656 }
657
658 /* (non-Javadoc)
659 * @see org.eclipse.jface.action.IContributionItem#setVisible(bool)
660 */
661 public void setVisible(bool visible) {
662 this.visible = visible;
663 }
664
665 /**
666 * Sets the action definition id of this action. This simply allows the menu
667 * item text to include a short cut if available. It can be used to
668 * notify a user of a key combination that will open a quick menu.
669 *
670 * @param definitionId
671 * the command definition id
672 * @since 3.4
673 */
674 public void setActionDefinitionId(String definitionId) {
675 this.definitionId = definitionId;
676 }
677
678 /* (non-Javadoc)
679 * @see org.eclipse.jface.action.IContributionItem#update()
680 */
681 public void update() {
682 updateMenuItem();
683 }
684
685 /**
686 * The <code>MenuManager</code> implementation of this <code>IContributionManager</code>
687 * updates this menu, but not any of its submenus.
688 *
689 * @see #updateAll
690 */
691 public void update(bool force) {
692 update(force, false);
693 }
694
695 /**
696 * Get all the items from the implementation's widget.
697 *
698 * @return the menu items
699 * @since 3.4
700 */
701 protected Item[] getMenuItems() {
702 if (menu !is null) {
703 return menu.getItems();
704 }
705 return null;
706 }
707
708 /**
709 * Get an item from the implementation's widget.
710 *
711 * @param index
712 * of the item
713 * @return the menu item
714 * @since 3.4
715 */
716 protected Item getMenuItem(int index) {
717 if (menu !is null) {
718 return menu.getItem(index);
719 }
720 return null;
721 }
722
723 /**
724 * Get the menu item count for the implementation's widget.
725 *
726 * @return the number of items
727 * @since 3.4
728 */
729 protected int getMenuItemCount() {
730 if (menu !is null) {
731 return menu.getItemCount();
732 }
733 return 0;
734 }
735
736 /**
737 * Call an <code>IContributionItem</code>'s fill method with the
738 * implementation's widget. The default is to use the <code>Menu</code>
739 * widget.<br>
740 * <code>fill(Menu menu, int index)</code>
741 *
742 * @param ci
743 * An <code>IContributionItem</code> whose <code>fill()</code>
744 * method should be called.
745 * @param index
746 * The position the <code>fill()</code> method should start
747 * inserting at.
748 * @since 3.4
749 */
750 protected void doItemFill(IContributionItem ci, int index) {
751 ci.fill(menu, index);
752 }
753
754 /**
755 * Incrementally builds the menu from the contribution items.
756 * This method leaves out double separators and separators in the first
757 * or last position.
758 *
759 * @param force <code>true</code> means update even if not dirty,
760 * and <code>false</code> for normal incremental updating
761 * @param recursive <code>true</code> means recursively update
762 * all submenus, and <code>false</code> means just this menu
763 */
764 protected void update(bool force, bool recursive) {
765 if (isDirty() || force) {
766 if (menuExist()) {
767 // clean contains all active items without double separators
768 IContributionItem[] items = getItems();
769 List clean = new ArrayList(items.length);
770 IContributionItem separator = null;
771 for (int i = 0; i < items.length; ++i) {
772 IContributionItem ci = items[i];
773 if (!ci.isVisible()) {
774 continue;
775 }
776 if (ci.isSeparator()) {
777 // delay creation until necessary
778 // (handles both adjacent separators, and separator at end)
779 separator = ci;
780 } else {
781 if (separator !is null) {
782 if (clean.size() > 0) {
783 clean.add(cast(Object)separator);
784 }
785 separator = null;
786 }
787 clean.add(cast(Object)ci);
788 }
789 }
790
791 // remove obsolete (removed or non active)
792 Item[] mi = getMenuItems();
793
794 for (int i = 0; i < mi.length; i++) {
795 Object data = mi[i].getData();
796
797 if (data is null || !clean.contains(data)) {
798 mi[i].dispose();
799 } else if (cast(IContributionItem)data
800 && (cast(IContributionItem) data).isDynamic()
801 && (cast(IContributionItem) data).isDirty()) {
802 mi[i].dispose();
803 }
804 }
805
806 // add new
807 mi = getMenuItems();
808 int srcIx = 0;
809 int destIx = 0;
810
811 for (Iterator e = clean.iterator(); e.hasNext();) {
812 IContributionItem src = cast(IContributionItem) e.next();
813 IContributionItem dest;
814
815 // get corresponding item in SWT widget
816 if (srcIx < mi.length) {
817 dest = cast(IContributionItem) mi[srcIx].getData();
818 } else {
819 dest = null;
820 }
821
822 if (dest !is null && (cast(Object)src).opEquals(cast(Object)dest)) {
823 srcIx++;
824 destIx++;
825 } else if (dest !is null && dest.isSeparator()
826 && src.isSeparator()) {
827 mi[srcIx].setData(cast(Object)src);
828 srcIx++;
829 destIx++;
830 } else {
831 int start = getMenuItemCount();
832 doItemFill(src, destIx);
833 int newItems = getMenuItemCount() - start;
834 for (int i = 0; i < newItems; i++) {
835 Item item = getMenuItem(destIx++);
836 item.setData(cast(Object)src);
837 }
838 }
839
840 // May be we can optimize this call. If the menu has just
841 // been created via the call src.fill(fMenuBar, destIx) then
842 // the menu has already been updated with update(true)
843 // (see MenuManager). So if force is true we do it again. But
844 // we can't set force to false since then information for the
845 // sub sub menus is lost.
846 if (recursive) {
847 IContributionItem item = src;
848 if ( auto sub = cast(SubContributionItem)item ) {
849 item = sub.getInnerItem();
850 }
851 if (auto mm = cast(IMenuManager)item ) {
852 mm.updateAll(force);
853 }
854 }
855
856 }
857
858 // remove any old menu items not accounted for
859 for (; srcIx < mi.length; srcIx++) {
860 mi[srcIx].dispose();
861 }
862
863 setDirty(false);
864 }
865 } else {
866 // I am not dirty. Check if I must recursivly walk down the hierarchy.
867 if (recursive) {
868 IContributionItem[] items = getItems();
869 for (int i = 0; i < items.length; ++i) {
870 IContributionItem ci = items[i];
871 if ( auto mm = cast(IMenuManager) ci ) {
872 if (mm.isVisible()) {
873 mm.updateAll(force);
874 }
875 }
876 }
877 }
878 }
879 updateMenuItem();
880 }
881
882 /* (non-Javadoc)
883 * @see org.eclipse.jface.action.IContributionItem#update(java.lang.String)
884 */
885 public void update(String property) {
886 IContributionItem items[] = getItems();
887
888 for (int i = 0; i < items.length; i++) {
889 items[i].update(property);
890 }
891
892 if (menu !is null && !menu.isDisposed() && menu.getParentItem() !is null) {
893 if (IAction.TEXT.equals(property)) {
894 String text = getOverrides().getText(this);
895
896 if (text is null) {
897 text = getMenuText();
898 }
899
900 if (text !is null) {
901 ExternalActionManager.ICallback callback = ExternalActionManager
902 .getInstance().getCallback();
903
904 if (callback !is null) {
905 int index = .indexOf( text, '&' ); // SWT collision with local indexOf
906
907 if (index >= 0 && index < text.length - 1) {
908
909 dchar character = CharacterToUpper(text
910 [index + 1 .. $].firstCodePoint());
911
912 if (callback.isAcceleratorInUse(SWT.ALT | character)) {
913 if (index is 0) {
914 text = text.substring(1);
915 } else {
916 text = text.substring(0, index)
917 ~ text.substring(index + 1);
918 }
919 }
920 }
921 }
922
923 menu.getParentItem().setText(text);
924 }
925 } else if (IAction.IMAGE.equals(property) && image !is null) {
926 LocalResourceManager localManager = new LocalResourceManager(JFaceResources
927 .getResources());
928 menu.getParentItem().setImage(localManager.createImage(image));
929 disposeOldImages();
930 imageManager = localManager;
931 }
932 }
933 }
934
935 /**
936 * Dispose any images allocated for this menu
937 */
938 private void disposeOldImages() {
939 if (imageManager !is null) {
940 imageManager.dispose();
941 imageManager = null;
942 }
943 }
944
945 /* (non-Javadoc)
946 * @see org.eclipse.jface.action.IMenuManager#updateAll(bool)
947 */
948 public void updateAll(bool force) {
949 update(force, true);
950 }
951
952 /**
953 * Updates the menu item for this sub menu.
954 * The menu item is disabled if this sub menu is empty.
955 * Does nothing if this menu is not a submenu.
956 */
957 private void updateMenuItem() {
958 /*
959 * Commented out until proper solution to enablement of
960 * menu item for a sub-menu is found. See bug 30833 for
961 * more details.
962 *
963 if (menuItem !is null && !menuItem.isDisposed() && menuExist()) {
964 IContributionItem items[] = getItems();
965 bool enabled = false;
966 for (int i = 0; i < items.length; i++) {
967 IContributionItem item = items[i];
968 enabled = item.isEnabled();
969 if(enabled) break;
970 }
971 // Workaround for 1GDDCN2: SWT:Linux - MenuItem.setEnabled() always causes a redraw
972 if (menuItem.getEnabled() !is enabled)
973 menuItem.setEnabled(enabled);
974 }
975 */
976 // Partial fix for bug #34969 - diable the menu item if no
977 // items in sub-menu (for context menus).
978 if (menuItem !is null && !menuItem.isDisposed() && menuExist()) {
979 bool enabled = removeAllWhenShown || menu.getItemCount() > 0;
980 // Workaround for 1GDDCN2: SWT:Linux - MenuItem.setEnabled() always causes a redraw
981 if (menuItem.getEnabled() !is enabled) {
982 // We only do this for context menus (for bug #34969)
983 Menu topMenu = menu;
984 while (topMenu.getParentMenu() !is null) {
985 topMenu = topMenu.getParentMenu();
986 }
987 if ((topMenu.getStyle() & SWT.BAR) is 0) {
988 menuItem.setEnabled(enabled);
989 }
990 }
991 }
992 }
993 }