KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > PopupMenuExtender


1 /*******************************************************************************
2  * Copyright (c) 2000, 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  * Dan Rubel (dan_rubel@instantiations.com) - accessor to get menu id
11  *******************************************************************************/

12 package org.eclipse.ui.internal;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Collections JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.Set JavaDoc;
20
21 import org.eclipse.core.runtime.IConfigurationElement;
22 import org.eclipse.core.runtime.IExtensionDelta;
23 import org.eclipse.core.runtime.IExtensionPoint;
24 import org.eclipse.core.runtime.IRegistryChangeEvent;
25 import org.eclipse.core.runtime.IRegistryChangeListener;
26 import org.eclipse.core.runtime.Platform;
27 import org.eclipse.jface.action.ContributionManager;
28 import org.eclipse.jface.action.IContributionItem;
29 import org.eclipse.jface.action.IMenuListener2;
30 import org.eclipse.jface.action.IMenuManager;
31 import org.eclipse.jface.action.MenuManager;
32 import org.eclipse.jface.action.Separator;
33 import org.eclipse.jface.action.SubMenuManager;
34 import org.eclipse.jface.viewers.ISelection;
35 import org.eclipse.jface.viewers.ISelectionChangedListener;
36 import org.eclipse.jface.viewers.ISelectionProvider;
37 import org.eclipse.jface.viewers.StructuredSelection;
38 import org.eclipse.swt.widgets.Display;
39 import org.eclipse.ui.IEditorPart;
40 import org.eclipse.ui.IWorkbench;
41 import org.eclipse.ui.IWorkbenchActionConstants;
42 import org.eclipse.ui.IWorkbenchPart;
43 import org.eclipse.ui.IWorkbenchPartSite;
44 import org.eclipse.ui.internal.menus.WindowMenuService;
45 import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
46 import org.eclipse.ui.menus.IMenuService;
47 import org.eclipse.ui.menus.MenuUtil;
48
49 /**
50  * This class extends a single popup menu
51  */

52 public class PopupMenuExtender implements IMenuListener2,
53         IRegistryChangeListener {
54     
55     /**
56      * The bit in <code>bitSet</code> that stores whether the static actions
57      * have been read from the registry.
58      */

59     private static final int STATIC_ACTION_READ = 1;
60
61     /**
62      * The bit in <code>bitSet</code> that stores whether the editor input
63      * should be included for the sake of object contributions.
64      */

65     private static final int INCLUDE_EDITOR_INPUT = 1 << 1;
66
67     private final MenuManager menu;
68
69     private SubMenuManager menuWrapper;
70
71     private final ISelectionProvider selProvider;
72
73     private final IWorkbenchPart part;
74
75     private Map JavaDoc staticActionBuilders = null;
76
77     /**
78      * The boolean properties maintained by this extender. A bit set is used to
79      * save memory.
80      */

81     private int bitSet = 0;
82     
83     private ArrayList JavaDoc contributionCache = new ArrayList JavaDoc();
84
85     /**
86      * Construct a new menu extender.
87      *
88      * @param id
89      * the menu id
90      * @param menu
91      * the menu to extend
92      * @param prov
93      * the selection provider
94      * @param part
95      * the part to extend
96      */

97     public PopupMenuExtender(String JavaDoc id, MenuManager menu,
98             ISelectionProvider prov, IWorkbenchPart part) {
99         this(id, menu, prov, part, true);
100     }
101
102     /**
103      * Construct a new menu extender.
104      *
105      * @param id
106      * the menu id
107      * @param menu
108      * the menu to extend
109      * @param prov
110      * the selection provider
111      * @param part
112      * the part to extend
113      * @param includeEditorInput
114      * Whether the editor input should be included when adding object
115      * contributions to this context menu.
116      */

117     public PopupMenuExtender(final String JavaDoc id, final MenuManager menu,
118             final ISelectionProvider prov, final IWorkbenchPart part,
119             final boolean includeEditorInput) {
120         super();
121         this.menu = menu;
122         this.selProvider = prov;
123         this.part = part;
124         if (includeEditorInput) {
125             bitSet |= INCLUDE_EDITOR_INPUT;
126         }
127         menu.addMenuListener(this);
128         if (!menu.getRemoveAllWhenShown()) {
129             menuWrapper = new SubMenuManager(menu);
130             menuWrapper.setVisible(true);
131         }
132         readStaticActionsFor(id);
133                 
134         Platform.getExtensionRegistry().addRegistryChangeListener(this);
135     }
136
137     // getMenuId() added by Dan Rubel (dan_rubel@instantiations.com)
138
/**
139      * Return the menu identifiers for this extender.
140      *
141      * @return The set of all identifiers that represent this extender.
142      */

143     public Set JavaDoc getMenuIds() {
144         if (staticActionBuilders == null) {
145             return Collections.EMPTY_SET;
146         }
147         
148         return staticActionBuilders.keySet();
149     }
150
151     /**
152      * <p>
153      * Adds another menu identifier to this extender. An extender can represent
154      * many menu identifiers. These identifiers should represent the same menu
155      * manager, selection provider and part. Duplicate identifiers are
156      * automatically ignored.
157      * </p>
158      * <p>
159      * For example, it is necessary to filter out duplicate identifiers for
160      * <code>CompilationUnitEditor</code> instances, as these define both
161      * <code>"#CompilationUnitEditorContext"</code> and
162      * <code>"org.eclipse.jdt.ui.CompilationUnitEditor.EditorContext"</code>
163      * as menu identifier for the same pop-up menu. We don't want to contribute
164      * duplicate items in this case.
165      * </p>
166      *
167      * @param menuId
168      * The menu identifier to add to this extender; should not be
169      * <code>null</code>.
170      */

171     public final void addMenuId(final String JavaDoc menuId) {
172         bitSet &= ~STATIC_ACTION_READ;
173         readStaticActionsFor(menuId);
174     }
175
176     /**
177      * Determines whether this extender would be the same as another extender
178      * created with the given values. Two extenders are equivalent if they have
179      * the same menu manager, selection provider and part (i.e., if the menu
180      * they represent is about to show, they would populate it with duplicate
181      * values).
182      *
183      * @param menuManager
184      * The menu manager with which to compare; may be
185      * <code>null</code>.
186      * @param selectionProvider
187      * The selection provider with which to compare; may be
188      * <code>null</code>.
189      * @param part
190      * The part with which to compare; may be <code>null</code>.
191      * @return <code>true</code> if the menu manager, selection provider and
192      * part are all the same.
193      */

194     public final boolean matches(final MenuManager menuManager,
195             final ISelectionProvider selectionProvider,
196             final IWorkbenchPart part) {
197         return (this.menu == menuManager)
198                 && (this.selProvider == selectionProvider)
199                 && (this.part == part);
200     }
201
202     /**
203      * Contributes items registered for the currently active editor.
204      */

205     private void addEditorActions(IMenuManager mgr) {
206         ISelectionProvider activeEditor = new ISelectionProvider() {
207
208             /* (non-Javadoc)
209              * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
210              */

211             public void addSelectionChangedListener(
212                     ISelectionChangedListener listener) {
213                 throw new UnsupportedOperationException JavaDoc(
214                 "This ISelectionProvider is static, and cannot be modified."); //$NON-NLS-1$
215
}
216
217             /* (non-Javadoc)
218              * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
219              */

220             public ISelection getSelection() {
221                 if (part instanceof IEditorPart) {
222                     final IEditorPart editorPart = (IEditorPart) part;
223                     return new StructuredSelection(new Object JavaDoc[] { editorPart
224                             .getEditorInput() });
225                 }
226
227                 return new StructuredSelection(new Object JavaDoc[0]);
228             }
229
230             /* (non-Javadoc)
231              * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
232              */

233             public void removeSelectionChangedListener(
234                     ISelectionChangedListener listener) {
235                 throw new UnsupportedOperationException JavaDoc(
236                 "This ISelectionProvider is static, and cannot be modified."); //$NON-NLS-1$
237
}
238
239             /* (non-Javadoc)
240              * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection)
241              */

242             public void setSelection(ISelection selection) {
243                 throw new UnsupportedOperationException JavaDoc(
244                         "This ISelectionProvider is static, and cannot be modified."); //$NON-NLS-1$
245
}
246         };
247         
248         if (ObjectActionContributorManager.getManager()
249                 .contributeObjectActions(part, mgr, activeEditor)) {
250             mgr.add(new Separator());
251         }
252     }
253
254     /**
255      * Contributes items registered for the object type(s) in
256      * the current selection.
257      */

258     private void addObjectActions(IMenuManager mgr) {
259         if (selProvider != null) {
260             if (ObjectActionContributorManager.getManager()
261                     .contributeObjectActions(part, mgr, selProvider)) {
262                 mgr.add(new Separator());
263             }
264         }
265     }
266     
267     /**
268      * Disposes all of the static actions.
269      */

270     private final void clearStaticActions() {
271         bitSet &= ~STATIC_ACTION_READ;
272         if (staticActionBuilders != null) {
273             final Iterator JavaDoc staticActionBuilderItr = staticActionBuilders
274                     .values().iterator();
275             while (staticActionBuilderItr.hasNext()) {
276                 final Object JavaDoc staticActionBuilder = staticActionBuilderItr
277                         .next();
278                 if (staticActionBuilder instanceof ViewerActionBuilder) {
279                     ((ViewerActionBuilder) staticActionBuilder).dispose();
280                 }
281             }
282         }
283     }
284
285     /**
286      * Adds static items to the context menu.
287      */

288     private void addStaticActions(IMenuManager mgr) {
289         if (staticActionBuilders != null) {
290             final Iterator JavaDoc staticActionBuilderItr = staticActionBuilders
291                     .values().iterator();
292             while (staticActionBuilderItr.hasNext()) {
293                 final ViewerActionBuilder staticActionBuilder = (ViewerActionBuilder) staticActionBuilderItr
294                         .next();
295                 staticActionBuilder.contribute(mgr, null, true);
296             }
297         }
298     }
299
300     /**
301      * Notifies the listener that the menu is about to be shown.
302      */

303     public void menuAboutToShow(IMenuManager mgr) {
304         IMenuManager originalManager = mgr;
305         
306         // Add this menu as a visible menu.
307
final IWorkbenchPartSite site = part.getSite();
308         if (site != null) {
309             final IWorkbench workbench = site.getWorkbenchWindow()
310                     .getWorkbench();
311             if (workbench instanceof Workbench) {
312                 final Workbench realWorkbench = (Workbench) workbench;
313                 ISelection input = null;
314                 if ((bitSet & INCLUDE_EDITOR_INPUT) != 0) {
315                     if (part instanceof IEditorPart) {
316                         final IEditorPart editorPart = (IEditorPart) part;
317                         input = new StructuredSelection(
318                                 new Object JavaDoc[] { editorPart.getEditorInput() });
319                     }
320                 }
321                 ISelection s = (selProvider == null ? null : selProvider
322                         .getSelection());
323                 realWorkbench.addShowingMenus(getMenuIds(), s, input);
324             }
325         }
326         
327         readStaticActions();
328         testForAdditions();
329         if (menuWrapper != null) {
330             mgr = menuWrapper;
331             menuWrapper.removeAll();
332         }
333         addMenuContributions(originalManager);
334         if ((bitSet & INCLUDE_EDITOR_INPUT) != 0) {
335             addEditorActions(mgr);
336         }
337         addObjectActions(mgr);
338         addStaticActions(mgr);
339         cleanUpContributionCache();
340     }
341     
342     private boolean contributionsPopulated = false;
343     
344     private void addMenuContributions(IMenuManager mgr) {
345         final IMenuService menuService = (IMenuService) part.getSite()
346                 .getService(IMenuService.class);
347         if (menuService == null) {
348             return;
349         }
350         if ((mgr.getRemoveAllWhenShown() || !contributionsPopulated)
351                 && mgr instanceof ContributionManager) {
352             ContributionManager manager = (ContributionManager) mgr;
353             contributionsPopulated = true;
354             menuService
355                     .populateContributionManager(manager, MenuUtil.ANY_POPUP);
356             Iterator JavaDoc i = getMenuIds().iterator();
357             WindowMenuService realService = (WindowMenuService) menuService;
358             while (i.hasNext()) {
359                 String JavaDoc id = "popup:" + i.next(); //$NON-NLS-1$
360
realService.populateContributionManager(manager, id, false);
361             }
362         }
363     }
364
365     /**
366      * Notifies the listener that the menu is about to be hidden.
367      */

368     public final void menuAboutToHide(final IMenuManager mgr) {
369         gatherContributions(mgr);
370         // Remove this menu as a visible menu.
371
final IWorkbenchPartSite site = part.getSite();
372         if (site != null) {
373             final IWorkbench workbench = site.getWorkbenchWindow().getWorkbench();
374             if (workbench instanceof Workbench) {
375                 // try delaying this until after the selection event
376
// has been fired.
377
// This is less threatening if the popup: menu
378
// contributions aren't tied to the evaluation service
379
workbench.getDisplay().asyncExec(new Runnable JavaDoc() {
380                     public void run() {
381                         final Workbench realWorkbench = (Workbench) workbench;
382                         realWorkbench.removeShowingMenus(getMenuIds(), null, null);
383                     }
384                 });
385             }
386         }
387     }
388     
389
390     /**
391      * @param mgr
392      */

393     private void gatherContributions(final IMenuManager mgr) {
394         final IContributionItem[] items = mgr.getItems();
395         for (int i = 0; i < items.length; i++) {
396             if (items[i] instanceof PluginActionContributionItem) {
397                 contributionCache.add(items[i]);
398             } else if (items[i] instanceof IMenuManager) {
399                 gatherContributions(((IMenuManager)items[i]));
400             }
401         }
402     }
403     
404     private void cleanUpContributionCache() {
405         PluginActionContributionItem[] items = (PluginActionContributionItem[]) contributionCache
406                 .toArray(new PluginActionContributionItem[contributionCache.size()]);
407         contributionCache.clear();
408         for (int i = 0; i < items.length; i++) {
409             items[i].dispose();
410         }
411     }
412
413     /**
414      * Read all of the static items for the content menu.
415      */

416     private final void readStaticActions() {
417         if (staticActionBuilders != null) {
418             final Iterator JavaDoc menuIdItr = staticActionBuilders.keySet().iterator();
419             while (menuIdItr.hasNext()) {
420                 final String JavaDoc menuId = (String JavaDoc) menuIdItr.next();
421                 readStaticActionsFor(menuId);
422             }
423         }
424     }
425
426     /**
427      * Read static items for a particular menu id, into the context menu.
428      */

429     private void readStaticActionsFor(final String JavaDoc menuId) {
430         if ((bitSet & STATIC_ACTION_READ) != 0) {
431             return;
432         }
433
434         bitSet |= STATIC_ACTION_READ;
435
436         // If no menu id provided, then there is no contributions
437
// to add. Fix for bug #33140.
438
if ((menuId == null) || (menuId.length() < 1)) {
439             return;
440         }
441
442         if (staticActionBuilders == null) {
443             staticActionBuilders = new HashMap JavaDoc();
444         }
445
446         Object JavaDoc object = staticActionBuilders.get(menuId);
447         if (!(object instanceof ViewerActionBuilder)) {
448             object = new ViewerActionBuilder();
449             staticActionBuilders.put(menuId, object);
450         }
451         final ViewerActionBuilder staticActionBuilder = (ViewerActionBuilder) object;
452         staticActionBuilder.readViewerContributions(menuId, selProvider, part);
453     }
454
455     /**
456      * Checks for the existance of an MB_ADDITIONS group.
457      */

458     private void testForAdditions() {
459         IContributionItem item = menu
460                 .find(IWorkbenchActionConstants.MB_ADDITIONS);
461         if (item == null) {
462             WorkbenchPlugin
463                     .log("Context menu missing standard group 'org.eclipse.ui.IWorkbenchActionConstants.MB_ADDITIONS'. (menu ids = " //$NON-NLS-1$
464
+ getMenuIds().toString() + ") part id = " //$NON-NLS-1$
465
+ (part == null ? "???" : part.getSite().getId()) //$NON-NLS-1$
466
+ ")"); //$NON-NLS-1$
467
}
468     }
469
470     /**
471      * Dispose of the menu extender. Should only be called when the part
472      * is disposed.
473      */

474     public void dispose() {
475         clearStaticActions();
476         final IMenuService menuService = (IMenuService) part.getSite()
477                 .getService(IMenuService.class);
478         if (menuService != null) {
479             menuService.releaseContributions(menu);
480         }
481         Platform.getExtensionRegistry().removeRegistryChangeListener(this);
482         menu.removeMenuListener(this);
483     }
484
485     /*
486      * (non-Javadoc)
487      *
488      * @see org.eclipse.core.runtime.IRegistryChangeListener#registryChanged(org.eclipse.core.runtime.IRegistryChangeEvent)
489      */

490     public void registryChanged(final IRegistryChangeEvent event) {
491         Display display = Display.getDefault();
492         if (part != null) {
493             display = part.getSite().getPage().getWorkbenchWindow().getWorkbench().getDisplay();
494         }
495         //check the delta to see if there are any viewer contribution changes. if so, null our builder to cause reparsing on the next menu show
496
IExtensionDelta [] deltas = event.getExtensionDeltas();
497         for (int i = 0; i < deltas.length; i++) {
498             IExtensionDelta delta = deltas[i];
499             IExtensionPoint extensionPoint = delta.getExtensionPoint();
500             if (extensionPoint.getNamespace().equals(
501                     WorkbenchPlugin.PI_WORKBENCH)
502                     && extensionPoint.getSimpleIdentifier().equals(
503                             IWorkbenchRegistryConstants.PL_POPUP_MENU)) {
504
505                 boolean clearPopups = false;
506                 IConfigurationElement [] elements = delta.getExtension().getConfigurationElements();
507                 for (int j = 0; j < elements.length; j++) {
508                     IConfigurationElement element = elements[j];
509                     if (element.getName().equals(IWorkbenchRegistryConstants.TAG_VIEWER_CONTRIBUTION)) {
510                         clearPopups = true;
511                         break;
512                     }
513                 }
514                                         
515                 if (clearPopups) {
516                     display.syncExec(new Runnable JavaDoc() {
517                         public void run() {
518                             clearStaticActions();
519                         }
520                     });
521                 }
522             }
523         }
524     }
525     
526     public MenuManager getManager() {
527         return menu;
528     }
529 }
530
Popular Tags