Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 325392 | Differences between
and this patch

Collapse All | Expand All

(-)UIAllTests.launch (-1 / +1 lines)
Lines 27-33 Link Here
27
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
27
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
28
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
28
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
29
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
29
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
30
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
30
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
31
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.e4.ui.tests.UIAllTests"/>
31
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.e4.ui.tests.UIAllTests"/>
32
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl}"/>
32
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl}"/>
33
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.e4.ui.tests"/>
33
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.e4.ui.tests"/>
(-)src/org/eclipse/e4/ui/tests/workbench/MMenuItemTest.java (-14 / +146 lines)
Lines 34-44 Link Here
34
import org.eclipse.e4.ui.model.application.ui.menu.MMenuItem;
34
import org.eclipse.e4.ui.model.application.ui.menu.MMenuItem;
35
import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator;
35
import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator;
36
import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
36
import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
37
import org.eclipse.e4.ui.workbench.renderers.swt.MenuRenderer;
37
import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
38
import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
38
import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
39
import org.eclipse.jface.action.IContributionItem;
40
import org.eclipse.jface.action.MenuManager;
39
import org.eclipse.swt.SWT;
41
import org.eclipse.swt.SWT;
40
import org.eclipse.swt.widgets.Event;
42
import org.eclipse.swt.widgets.Event;
43
import org.eclipse.swt.widgets.Menu;
41
import org.eclipse.swt.widgets.MenuItem;
44
import org.eclipse.swt.widgets.MenuItem;
45
import org.eclipse.swt.widgets.Widget;
42
46
43
public class MMenuItemTest extends TestCase {
47
public class MMenuItemTest extends TestCase {
44
	protected IEclipseContext appContext;
48
	protected IEclipseContext appContext;
Lines 82-87 Link Here
82
		wb = new E4Workbench(window, appContext);
86
		wb = new E4Workbench(window, appContext);
83
		wb.createAndRunUI(window);
87
		wb.createAndRunUI(window);
84
88
89
		((MenuManager) ((Widget) menu.getWidget()).getData()).updateAll(true);
90
85
		Object widget = menuItem.getWidget();
91
		Object widget = menuItem.getWidget();
86
		assertNotNull(widget);
92
		assertNotNull(widget);
87
		assertTrue(widget instanceof MenuItem);
93
		assertTrue(widget instanceof MenuItem);
Lines 157-162 Link Here
157
		wb = new E4Workbench(window, appContext);
163
		wb = new E4Workbench(window, appContext);
158
		wb.createAndRunUI(window);
164
		wb.createAndRunUI(window);
159
165
166
		((MenuManager) ((Widget) menu.getWidget()).getData()).updateAll(true);
167
160
		Object widget1 = menuItem1.getWidget();
168
		Object widget1 = menuItem1.getWidget();
161
		assertNotNull(widget1);
169
		assertNotNull(widget1);
162
		assertTrue(widget1 instanceof MenuItem);
170
		assertTrue(widget1 instanceof MenuItem);
Lines 212-217 Link Here
212
		wb = new E4Workbench(window, appContext);
220
		wb = new E4Workbench(window, appContext);
213
		wb.createAndRunUI(window);
221
		wb.createAndRunUI(window);
214
222
223
		((MenuManager) ((Widget) menu.getWidget()).getData()).updateAll(true);
224
215
		Object widget1 = menuItem.getWidget();
225
		Object widget1 = menuItem.getWidget();
216
		assertNotNull(widget1);
226
		assertNotNull(widget1);
217
		assertTrue(widget1 instanceof MenuItem);
227
		assertTrue(widget1 instanceof MenuItem);
Lines 228-234 Link Here
228
		MCommand command = CommandsFactoryImpl.eINSTANCE.createCommand();
238
		MCommand command = CommandsFactoryImpl.eINSTANCE.createCommand();
229
239
230
		command.setElementId("commandId");
240
		command.setElementId("commandId");
231
		command.setCommandName("CommandForTest");
232
241
233
		menuItem.setCommand(command);
242
		menuItem.setCommand(command);
234
		menuItem.setType(ItemType.CHECK);
243
		menuItem.setType(ItemType.CHECK);
Lines 240-252 Link Here
240
		MApplication application = ApplicationFactoryImpl.eINSTANCE
249
		MApplication application = ApplicationFactoryImpl.eINSTANCE
241
				.createApplication();
250
				.createApplication();
242
		application.getChildren().add(window);
251
		application.getChildren().add(window);
243
		application.getCommands().add(command);
244
		application.setContext(appContext);
252
		application.setContext(appContext);
245
		appContext.set(MApplication.class.getName(), application);
253
		appContext.set(MApplication.class.getName(), application);
246
254
247
		wb = new E4Workbench(window, appContext);
255
		wb = new E4Workbench(window, appContext);
248
		wb.createAndRunUI(window);
256
		wb.createAndRunUI(window);
249
257
258
		MenuManager barManager = (MenuManager) ((Menu) menu.getWidget())
259
				.getData();
260
		barManager.updateAll(true);
261
250
		Object widget1 = menuItem.getWidget();
262
		Object widget1 = menuItem.getWidget();
251
		assertNotNull(widget1);
263
		assertNotNull(widget1);
252
		assertTrue(widget1 instanceof MenuItem);
264
		assertTrue(widget1 instanceof MenuItem);
Lines 255-261 Link Here
255
		assertTrue(menuItemWidget.getSelection());
267
		assertTrue(menuItemWidget.getSelection());
256
	}
268
	}
257
269
258
	public void XXXtestSubMenuCreation() throws Exception {
270
	public void testSubMenuCreation() throws Exception {
259
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
271
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
260
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
272
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
261
		menuBar.setElementId("org.eclipse.ui.main.menu");
273
		menuBar.setElementId("org.eclipse.ui.main.menu");
Lines 289-297 Link Here
289
		wb = new E4Workbench(window, appContext);
301
		wb = new E4Workbench(window, appContext);
290
		wb.createAndRunUI(window);
302
		wb.createAndRunUI(window);
291
303
304
		MenuManagerRenderer renderer = getRenderer(appContext, menuBar);
305
		MenuManager manager = renderer.getManager(menuBar);
306
		assertNotNull("failed to create menu bar manager", manager);
307
308
		assertEquals(1, manager.getSize());
309
310
		MenuManager fileManager = (MenuManager) manager.getItems()[0];
311
		MenuManager fileR = renderer.getManager(fileMenu);
312
		assertEquals(fileManager, fileR);
313
314
		assertEquals(3, fileManager.getSize());
292
	}
315
	}
293
316
294
	public void XXXtestTbrItem() throws Exception {
317
	public void testTbrItem() throws Exception {
295
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
318
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
296
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
319
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
297
		menuBar.setElementId("org.eclipse.ui.main.menu");
320
		menuBar.setElementId("org.eclipse.ui.main.menu");
Lines 326-336 Link Here
326
		wb = new E4Workbench(window, appContext);
349
		wb = new E4Workbench(window, appContext);
327
		wb.createAndRunUI(window);
350
		wb.createAndRunUI(window);
328
351
329
		// MenuRenderer renderer = getRenderer(appContext, menuBar);
352
		MenuManagerRenderer renderer = getRenderer(appContext, menuBar);
353
		MenuManager manager = renderer.getManager(menuBar);
354
		assertNotNull("failed to create menu bar manager", manager);
355
356
		assertEquals(1, manager.getSize());
357
358
		MenuManager fileManager = (MenuManager) manager.getItems()[0];
359
		MenuManager fileR = renderer.getManager(fileMenu);
360
		assertEquals(fileManager, fileR);
330
361
362
		assertEquals(2, fileManager.getSize());
331
	}
363
	}
332
364
333
	public void XXXtestInvisibleItem() throws Exception {
365
	public void testInvisibleItem() throws Exception {
334
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
366
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
335
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
367
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
336
		menuBar.setElementId("org.eclipse.ui.main.menu");
368
		menuBar.setElementId("org.eclipse.ui.main.menu");
Lines 365-375 Link Here
365
		wb = new E4Workbench(window, appContext);
397
		wb = new E4Workbench(window, appContext);
366
		wb.createAndRunUI(window);
398
		wb.createAndRunUI(window);
367
399
368
		// MenuRenderer renderer = getRenderer(appContext, menuBar);
400
		MenuManagerRenderer renderer = getRenderer(appContext, menuBar);
401
		MenuManager manager = renderer.getManager(menuBar);
402
		assertNotNull("failed to create menu bar manager", manager);
403
404
		assertEquals(1, manager.getSize());
405
406
		MenuManager fileManager = (MenuManager) manager.getItems()[0];
407
		MenuManager fileR = renderer.getManager(fileMenu);
408
		assertEquals(fileManager, fileR);
369
409
410
		assertEquals(3, fileManager.getSize());
411
412
		assertEquals(false, fileManager.getItems()[2].isVisible());
370
	}
413
	}
371
414
372
	public void XXXtestMenuContribution() throws Exception {
415
	public void testMenuContribution() throws Exception {
373
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
416
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
374
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
417
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
375
		menuBar.setElementId("org.eclipse.ui.main.menu");
418
		menuBar.setElementId("org.eclipse.ui.main.menu");
Lines 404-412 Link Here
404
		wb = new E4Workbench(window, appContext);
447
		wb = new E4Workbench(window, appContext);
405
		wb.createAndRunUI(window);
448
		wb.createAndRunUI(window);
406
449
450
		MenuManagerRenderer renderer = getRenderer(appContext, menuBar);
451
452
		MenuManager fileManager = renderer.getManager(fileMenu);
453
		assertNotNull("No file menu?", fileManager);
454
455
		assertEquals(4, fileManager.getSize());
456
457
		assertEquals("mmc.item1", fileManager.getItems()[3].getId());
407
	}
458
	}
408
459
409
	public void XXXtestWithVisible() throws Exception {
460
	public void testWithVisible() throws Exception {
410
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
461
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
411
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
462
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
412
		menuBar.setElementId("org.eclipse.ui.main.menu");
463
		menuBar.setElementId("org.eclipse.ui.main.menu");
Lines 441-449 Link Here
441
		wb = new E4Workbench(window, appContext);
492
		wb = new E4Workbench(window, appContext);
442
		wb.createAndRunUI(window);
493
		wb.createAndRunUI(window);
443
494
495
		MenuManagerRenderer renderer = getRenderer(appContext, menuBar);
496
497
		MenuManager fileManager = renderer.getManager(fileMenu);
498
		assertNotNull("No file menu?", fileManager);
499
500
		assertEquals(4, fileManager.getSize());
501
502
		IContributionItem mmcItem = fileManager.getItems()[3];
503
		assertEquals("mmc.item1", mmcItem.getId());
504
		assertEquals("before the first show, we have no context to evaluate",
505
				true, mmcItem.isVisible());
506
507
		MenuManager manager = renderer.getManager(menuBar);
508
		manager.updateAll(true);
509
		Menu fileWidget = fileManager.getMenu();
510
		assertNotNull(fileWidget);
511
512
		Event show = new Event();
513
		show.widget = fileWidget;
514
		show.type = SWT.Show;
515
516
		Event hide = new Event();
517
		hide.widget = fileWidget;
518
		hide.type = SWT.Hide;
519
520
		fileWidget.notifyListeners(SWT.Show, show);
521
522
		assertEquals("after the first show, it should not be visible", false,
523
				mmcItem.isVisible());
524
525
		fileWidget.notifyListeners(SWT.Hide, hide);
526
527
		appContext.set("mmc1", Boolean.TRUE);
528
529
		assertEquals("Change should not show up until next show", false,
530
				mmcItem.isVisible());
531
532
		fileWidget.notifyListeners(SWT.Show, show);
533
534
		assertEquals(true, mmcItem.isVisible());
535
536
		fileWidget.notifyListeners(SWT.Hide, hide);
537
538
		appContext.remove("mmc1");
539
540
		fileWidget.notifyListeners(SWT.Show, show);
541
542
		assertEquals(false, mmcItem.isVisible());
543
544
		fileWidget.notifyListeners(SWT.Hide, hide);
444
	}
545
	}
445
546
446
	public void XXXtestMenuBarVisibility() throws Exception {
547
	public void testMenuBarVisibility() throws Exception {
447
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
548
		MWindow window = BasicFactoryImpl.eINSTANCE.createWindow();
448
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
549
		MMenu menuBar = MenuFactoryImpl.eINSTANCE.createMenu();
449
		menuBar.setElementId("org.eclipse.ui.main.menu");
550
		menuBar.setElementId("org.eclipse.ui.main.menu");
Lines 478-483 Link Here
478
		wb = new E4Workbench(window, appContext);
579
		wb = new E4Workbench(window, appContext);
479
		wb.createAndRunUI(window);
580
		wb.createAndRunUI(window);
480
581
582
		MenuManagerRenderer renderer = getRenderer(appContext, menuBar);
583
		MenuManager manager = renderer.getManager(menuBar);
584
		manager.updateAll(true);
585
586
		assertEquals(2, manager.getSize());
587
588
		MenuManager vanishManager = (MenuManager) manager.getItems()[1];
589
		assertEquals("vanish", vanishManager.getId());
590
591
		assertFalse(vanishManager.isVisible());
592
		assertNull(vanishManager.getMenu());
593
594
		appContext.set("mmc1", Boolean.TRUE);
595
596
		assertTrue(vanishManager.isVisible());
597
		assertNotNull(vanishManager.getMenu());
598
599
		appContext.remove("mmc1");
600
601
		assertFalse(vanishManager.isVisible());
602
		Menu vanishMenu = vanishManager.getMenu();
603
		if (vanishMenu != null) {
604
			assertTrue(vanishMenu.isDisposed());
605
		}
606
607
		appContext.set("mmc1", Boolean.TRUE);
608
609
		assertTrue(vanishManager.isVisible());
610
		assertNotNull(vanishManager.getMenu());
611
		assertFalse(vanishManager.getMenu().isDisposed());
481
	}
612
	}
482
613
483
	private MMenuContribution createContribution(boolean withVisibleWhen) {
614
	private MMenuContribution createContribution(boolean withVisibleWhen) {
Lines 537-547 Link Here
537
		application.getMenuContributions().add(mmc);
668
		application.getMenuContributions().add(mmc);
538
	}
669
	}
539
670
540
	MenuRenderer getRenderer(IEclipseContext context, MUIElement element) {
671
	private MenuManagerRenderer getRenderer(IEclipseContext context,
672
			MUIElement element) {
541
		IRendererFactory rendererFactory = context.get(IRendererFactory.class);
673
		IRendererFactory rendererFactory = context.get(IRendererFactory.class);
542
		AbstractPartRenderer renderer = rendererFactory.getRenderer(element,
674
		AbstractPartRenderer renderer = rendererFactory.getRenderer(element,
543
				null);
675
				null);
544
		assertEquals(MenuRenderer.class, renderer.getClass());
676
		assertEquals(MenuManagerRenderer.class, renderer.getClass());
545
		return (MenuRenderer) renderer;
677
		return (MenuManagerRenderer) renderer;
546
	}
678
	}
547
}
679
}
(-)src/org/eclipse/e4/ui/tests/workbench/MWindowTest.java (+3 lines)
Lines 30-35 Link Here
30
import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
30
import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
31
import org.eclipse.e4.ui.services.IServiceConstants;
31
import org.eclipse.e4.ui.services.IServiceConstants;
32
import org.eclipse.e4.ui.widgets.CTabFolder;
32
import org.eclipse.e4.ui.widgets.CTabFolder;
33
import org.eclipse.jface.action.MenuManager;
33
import org.eclipse.swt.SWT;
34
import org.eclipse.swt.SWT;
34
import org.eclipse.swt.graphics.Rectangle;
35
import org.eclipse.swt.graphics.Rectangle;
35
import org.eclipse.swt.widgets.Composite;
36
import org.eclipse.swt.widgets.Composite;
Lines 230-235 Link Here
230
231
231
		wb = new E4Workbench(application, appContext);
232
		wb = new E4Workbench(application, appContext);
232
		wb.createAndRunUI(window);
233
		wb.createAndRunUI(window);
234
		((MenuManager) ((Widget) window.getMainMenu().getWidget()).getData())
235
				.updateAll(true);
233
236
234
		Widget topWidget = (Widget) window.getWidget();
237
		Widget topWidget = (Widget) window.getWidget();
235
		assertNotNull(topWidget);
238
		assertNotNull(topWidget);
(-)src/org/eclipse/e4/ui/workbench/renderers/swt/MenuManagerRendererFilter.java (+369 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.e4.ui.workbench.renderers.swt;
12
13
import java.lang.reflect.InvocationTargetException;
14
import java.lang.reflect.Method;
15
import java.util.ArrayList;
16
import java.util.HashMap;
17
import java.util.List;
18
import javax.inject.Inject;
19
import org.eclipse.core.commands.ParameterizedCommand;
20
import org.eclipse.core.runtime.ISafeRunnable;
21
import org.eclipse.core.runtime.SafeRunner;
22
import org.eclipse.e4.core.commands.EHandlerService;
23
import org.eclipse.e4.core.contexts.IEclipseContext;
24
import org.eclipse.e4.core.services.log.Logger;
25
import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
26
import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
27
import org.eclipse.e4.ui.internal.workbench.swt.Policy;
28
import org.eclipse.e4.ui.internal.workbench.swt.WorkbenchSWTActivator;
29
import org.eclipse.e4.ui.model.application.MApplication;
30
import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
31
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
32
import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
33
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
34
import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu;
35
import org.eclipse.e4.ui.model.application.ui.menu.MRenderedMenu;
36
import org.eclipse.e4.ui.workbench.IPresentationEngine;
37
import org.eclipse.e4.ui.workbench.modeling.EModelService;
38
import org.eclipse.e4.ui.workbench.modeling.ExpressionContext;
39
import org.eclipse.jface.action.MenuManager;
40
import org.eclipse.swt.SWT;
41
import org.eclipse.swt.widgets.Event;
42
import org.eclipse.swt.widgets.Listener;
43
import org.eclipse.swt.widgets.Menu;
44
import org.eclipse.swt.widgets.MenuItem;
45
import org.eclipse.swt.widgets.Widget;
46
47
public class MenuManagerRendererFilter implements Listener {
48
	public static final String NUL_MENU_ITEM = "(None Applicable)"; //$NON-NLS-1$
49
50
	private static final String TMP_ORIGINAL_CONTEXT = "MenuServiceFilter.original.context"; //$NON-NLS-1$
51
52
	private static void trace(String msg, Widget menu, MMenu menuModel) {
53
		WorkbenchSWTActivator.trace(Policy.MENUS, msg + ": " + menu + ": " //$NON-NLS-1$ //$NON-NLS-2$
54
				+ menuModel, null);
55
	}
56
57
	private static Method aboutToShow;
58
59
	public static Method getAboutToShow() {
60
		if (aboutToShow == null) {
61
			try {
62
				aboutToShow = MenuManager.class
63
						.getDeclaredMethod("handleAboutToShow"); //$NON-NLS-1$
64
				aboutToShow.setAccessible(true);
65
			} catch (SecurityException e) {
66
				// TODO Auto-generated catch block
67
				e.printStackTrace();
68
			} catch (NoSuchMethodException e) {
69
				// TODO Auto-generated catch block
70
				e.printStackTrace();
71
			}
72
		}
73
		return aboutToShow;
74
	}
75
76
	@Inject
77
	private MApplication application;
78
79
	@Inject
80
	private IPresentationEngine renderer;
81
82
	@Inject
83
	private Logger logger;
84
85
	@Inject
86
	EModelService modelService;
87
88
	private HashMap<Menu, Runnable> pendingCleanup = new HashMap<Menu, Runnable>();
89
90
	public void handleEvent(final Event event) {
91
		// wrap the handling in a SafeRunner so that exceptions do not prevent
92
		// the menu from being shown
93
		SafeRunner.run(new ISafeRunnable() {
94
			public void handleException(Throwable e) {
95
				if (e instanceof Error) {
96
					// errors are deadly, we shouldn't ignore these
97
					throw (Error) e;
98
				} else {
99
					// log exceptions otherwise
100
					if (logger != null) {
101
						logger.error(e);
102
					}
103
				}
104
			}
105
106
			public void run() throws Exception {
107
				safeHandleEvent(event);
108
			}
109
		});
110
	}
111
112
	private void safeHandleEvent(Event event) {
113
		if (!(event.widget instanceof Menu)) {
114
			return;
115
		}
116
		final Menu menu = (Menu) event.widget;
117
		if (event.type == SWT.Dispose) {
118
			trace("handleMenu.Dispose", menu, null); //$NON-NLS-1$
119
			cleanUp(menu);
120
		}
121
		Object obj = menu.getData(AbstractPartRenderer.OWNING_ME);
122
		if (obj == null && menu.getParentItem() != null) {
123
			obj = menu.getParentItem().getData(AbstractPartRenderer.OWNING_ME);
124
		}
125
		if (obj instanceof MRenderedMenu) {
126
			handlerRenderedMenu(event, menu, (MRenderedMenu) obj);
127
		} else if (obj instanceof MPopupMenu) {
128
			handleContextMenu(event, menu, (MPopupMenu) obj);
129
		} else if (obj instanceof MMenu) {
130
			handleMenu(event, menu, (MMenu) obj);
131
		}
132
	}
133
134
	private void handleMenu(final Event event, final Menu menu,
135
			final MMenu menuModel) {
136
		if ((menu.getStyle() & SWT.BAR) != 0) {
137
			// don't process the menu bar, it's not fair :-)
138
			return;
139
		}
140
		switch (event.type) {
141
		case SWT.Show:
142
			trace("handleMenu.Show", menu, menuModel); //$NON-NLS-1$
143
			cleanUp(menu);
144
			showMenu(event, menu, menuModel);
145
			break;
146
		case SWT.Hide:
147
			trace("handleMenu.Hide", menu, menuModel); //$NON-NLS-1$
148
			// TODO we'll clean up on show
149
			break;
150
		}
151
	}
152
153
	public void showMenu(final Event event, final Menu menu,
154
			final MMenu menuModel) {
155
		final IEclipseContext parentContext = modelService
156
				.getContainingContext(menuModel);
157
158
		final ArrayList<MMenuContribution> toContribute = new ArrayList<MMenuContribution>();
159
		final ArrayList<MMenuElement> menuContributionsToRemove = new ArrayList<MMenuElement>();
160
		ExpressionContext eContext = new ExpressionContext(parentContext);
161
		ContributionsAnalyzer.gatherMenuContributions(menuModel,
162
				application.getMenuContributions(), menuModel.getElementId(),
163
				toContribute, eContext, false);
164
		if (menu.getItemCount() == 1) {
165
			MenuItem item = menu.getItem(0);
166
			if (NUL_MENU_ITEM.equals(item.getText())) {
167
				item.dispose();
168
			}
169
		}
170
		ContributionsAnalyzer.addMenuContributions(menuModel, toContribute,
171
				menuContributionsToRemove);
172
173
		// create a cleanup routine for the Hide or next Show
174
		pendingCleanup.put(menu, new Runnable() {
175
			public void run() {
176
				if (!menu.isDisposed()) {
177
					unrender(menuContributionsToRemove);
178
				}
179
				removeMenuContributions(menuModel, menuContributionsToRemove);
180
			}
181
		});
182
		render(menu, menuModel);
183
		if (menu.getItemCount() == 0) {
184
			MenuItem menuItem = new MenuItem(menu, SWT.PUSH);
185
			menuItem.setText(NUL_MENU_ITEM);
186
			menuItem.setEnabled(false);
187
		}
188
	}
189
190
	private void handleContextMenu(final Event event, final Menu menu,
191
			final MPopupMenu menuModel) {
192
		switch (event.type) {
193
		case SWT.Show:
194
			trace("handleContextMenu.Show", menu, menuModel); //$NON-NLS-1$
195
			cleanUp(menu);
196
			showPopup(event, menu, menuModel);
197
			break;
198
		case SWT.Hide:
199
			trace("handleContextMenu.Hide", menu, menuModel); //$NON-NLS-1$
200
			hidePopup(event, menu, menuModel);
201
			break;
202
		}
203
	}
204
205
	public void hidePopup(Event event, Menu menu, MPopupMenu menuModel) {
206
		final IEclipseContext popupContext = menuModel.getContext();
207
		final IEclipseContext originalChild = (IEclipseContext) popupContext
208
				.get(TMP_ORIGINAL_CONTEXT);
209
		popupContext.remove(TMP_ORIGINAL_CONTEXT);
210
		if (!menu.isDisposed()) {
211
			menu.getDisplay().asyncExec(new Runnable() {
212
				public void run() {
213
					if (originalChild == null) {
214
						popupContext.deactivate();
215
					} else {
216
						originalChild.activate();
217
					}
218
				}
219
			});
220
		}
221
	}
222
223
	public void showPopup(final Event event, final Menu menu,
224
			final MPopupMenu menuModel) {
225
		// System.err.println("showPopup: " + menuModel + "\n\t" + menu);
226
		// we need some context foolery here
227
		final IEclipseContext popupContext = menuModel.getContext();
228
		final IEclipseContext parentContext = popupContext.getParent();
229
		final IEclipseContext originalChild = parentContext.getActiveChild();
230
		popupContext.activate();
231
		popupContext.set(TMP_ORIGINAL_CONTEXT, originalChild);
232
233
		final ArrayList<MMenuContribution> toContribute = new ArrayList<MMenuContribution>();
234
		final ArrayList<MMenuElement> menuContributionsToRemove = new ArrayList<MMenuElement>();
235
		ExpressionContext eContext = new ExpressionContext(popupContext);
236
		ContributionsAnalyzer.gatherMenuContributions(menuModel,
237
				application.getMenuContributions(), menuModel.getElementId(),
238
				toContribute, eContext, true);
239
240
		for (String tag : menuModel.getTags()) {
241
			if (tag.startsWith("popup:") && tag.length() > 6) { //$NON-NLS-1$
242
				ContributionsAnalyzer.gatherMenuContributions(menuModel,
243
						application.getMenuContributions(), tag.substring(6),
244
						toContribute, eContext, false);
245
			}
246
		}
247
		ContributionsAnalyzer.addMenuContributions(menuModel, toContribute,
248
				menuContributionsToRemove);
249
250
		// create a cleanup routine for the Hide or next Show
251
		pendingCleanup.put(menu, new Runnable() {
252
			public void run() {
253
				if (!menu.isDisposed()) {
254
					unrender(menuContributionsToRemove);
255
				}
256
				removeMenuContributions(menuModel, menuContributionsToRemove);
257
			}
258
		});
259
		render(menu, menuModel);
260
	}
261
262
	private void render(final Menu menu, final MMenu menuModel) {
263
		trace("render", menu, menuModel); //$NON-NLS-1$
264
		for (MMenuElement element : menuModel.getChildren()) {
265
			renderer.createGui(element, menu, null);
266
			if (element instanceof MHandledMenuItem) {
267
				setEnabled((MHandledMenuItem) element);
268
			}
269
		}
270
	}
271
272
	private void setEnabled(MHandledMenuItem item) {
273
		if (!item.isToBeRendered() || !item.isVisible()
274
				|| item.getWidget() == null) {
275
			return;
276
		}
277
		ParameterizedCommand cmd = item.getWbCommand();
278
		if (cmd == null) {
279
			return;
280
		}
281
		final IEclipseContext lclContext = modelService
282
				.getContainingContext(item);
283
		EHandlerService service = lclContext.get(EHandlerService.class);
284
		item.setEnabled(service.canExecute(cmd));
285
	}
286
287
	private void unrender(final List<MMenuElement> menuModel) {
288
		trace("unrender", null, null); //$NON-NLS-1$
289
		for (MMenuElement element : menuModel) {
290
			renderer.removeGui(element);
291
		}
292
	}
293
294
	private void removeMenuContributions(final MMenu menuModel,
295
			final ArrayList<MMenuElement> menuContributionsToRemove) {
296
		for (MMenuElement item : menuContributionsToRemove) {
297
			trace("removeMenuContributions " + item, //$NON-NLS-1$
298
					(Widget) menuModel.getWidget(), menuModel);
299
			menuModel.getChildren().remove(item);
300
		}
301
	}
302
303
	private void handlerRenderedMenu(final Event event, final Menu menu,
304
			final MRenderedMenu menuModel) {
305
		// Do nothing here for the moment, except process any cleanups
306
		switch (event.type) {
307
		case SWT.Show:
308
			trace("handlerRenderedMenu.Show", menu, menuModel); //$NON-NLS-1$
309
			cleanUp(menu);
310
			showRenderedMenu(event, menu, menuModel);
311
			break;
312
		case SWT.Hide:
313
			trace("handlerRenderedMenu.Hide", menu, menuModel); //$NON-NLS-1$
314
			// TODO don't care
315
			break;
316
		}
317
	}
318
319
	public void showRenderedMenu(final Event event, final Menu menu,
320
			final MRenderedMenu menuModel) {
321
		if (!(menuModel.getContributionManager() instanceof MenuManager)) {
322
			return;
323
		}
324
325
		MenuManager manager = (MenuManager) menuModel.getContributionManager();
326
		Method handleAboutToShow = getAboutToShow();
327
		try {
328
			handleAboutToShow.invoke(manager);
329
		} catch (IllegalArgumentException e) {
330
			// TODO Auto-generated catch block
331
			e.printStackTrace();
332
		} catch (IllegalAccessException e) {
333
			// TODO Auto-generated catch block
334
			e.printStackTrace();
335
		} catch (InvocationTargetException e) {
336
			// TODO Auto-generated catch block
337
			e.printStackTrace();
338
		}
339
340
		if (menuModel.getChildren().size() == 1
341
				&& menuModel.getChildren().get(0) instanceof MPopupMenu) {
342
			showPopup(event, menu, (MPopupMenu) menuModel.getChildren().get(0));
343
		} else {
344
			showMenu(event, menu, menuModel);
345
		}
346
		event.type = SWT.None;
347
		event.doit = false;
348
	}
349
350
	public void cleanUp(final Menu menu) {
351
		trace("cleanUp", menu, null); //$NON-NLS-1$
352
		if (pendingCleanup.isEmpty()) {
353
			return;
354
		}
355
		Runnable cleanUp = pendingCleanup.remove(menu);
356
		if (cleanUp != null) {
357
			trace("cleanUp.run()", menu, null); //$NON-NLS-1$
358
			cleanUp.run();
359
		}
360
	}
361
362
	public void dispose() {
363
		Menu[] keys = pendingCleanup.keySet().toArray(
364
				new Menu[pendingCleanup.size()]);
365
		for (Menu menu : keys) {
366
			cleanUp(menu);
367
		}
368
	}
369
}
(-)src/org/eclipse/e4/ui/workbench/renderers/swt/MenuRenderer.java (-2 / +1 lines)
Lines 25-31 Link Here
25
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
25
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
26
import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator;
26
import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator;
27
import org.eclipse.e4.ui.workbench.modeling.ExpressionContext;
27
import org.eclipse.e4.ui.workbench.modeling.ExpressionContext;
28
import org.eclipse.e4.ui.workbench.swt.modeling.MenuServiceFilter;
29
import org.eclipse.emf.ecore.EObject;
28
import org.eclipse.emf.ecore.EObject;
30
import org.eclipse.swt.SWT;
29
import org.eclipse.swt.SWT;
31
import org.eclipse.swt.events.DisposeEvent;
30
import org.eclipse.swt.events.DisposeEvent;
Lines 102-108 Link Here
102
				}
101
				}
103
				Menu menu = mi.getMenu();
102
				Menu menu = mi.getMenu();
104
				MenuItem menuItem = new MenuItem(menu, SWT.PUSH);
103
				MenuItem menuItem = new MenuItem(menu, SWT.PUSH);
105
				menuItem.setText(MenuServiceFilter.NUL_MENU_ITEM);
104
				menuItem.setText(MenuManagerRendererFilter.NUL_MENU_ITEM);
106
				menuItem.setEnabled(false);
105
				menuItem.setEnabled(false);
107
			}
106
			}
108
		}
107
		}
(-)src/org/eclipse/e4/ui/workbench/renderers/swt/SeparatorRenderer.java (-16 / +2 lines)
Lines 12-22 Link Here
12
12
13
import java.util.List;
13
import java.util.List;
14
import org.eclipse.e4.ui.model.application.ui.MUIElement;
14
import org.eclipse.e4.ui.model.application.ui.MUIElement;
15
import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator;
16
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarSeparator;
15
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarSeparator;
17
import org.eclipse.swt.SWT;
16
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.widgets.Menu;
19
import org.eclipse.swt.widgets.MenuItem;
20
import org.eclipse.swt.widgets.ToolBar;
17
import org.eclipse.swt.widgets.ToolBar;
21
import org.eclipse.swt.widgets.ToolItem;
18
import org.eclipse.swt.widgets.ToolItem;
22
import org.eclipse.swt.widgets.Widget;
19
import org.eclipse.swt.widgets.Widget;
Lines 41-61 Link Here
41
			return null;
38
			return null;
42
		}
39
		}
43
		if (nextVisibleChild.isVisible()
40
		if (nextVisibleChild.isVisible()
44
				&& (nextVisibleChild instanceof MMenuSeparator || nextVisibleChild instanceof MToolBarSeparator)) {
41
				&& (nextVisibleChild instanceof MToolBarSeparator)) {
45
			return null;
42
			return null;
46
		}
43
		}
47
		if (element instanceof MMenuSeparator) {
44
		if (element instanceof MToolBarSeparator) {
48
			Menu menu = null;
49
			Object widget = element.getParent().getWidget();
50
			if (widget instanceof Menu) {
51
				menu = (Menu) widget;
52
			} else if (widget instanceof MenuItem) {
53
				menu = ((MenuItem) widget).getMenu();
54
			}
55
			if (menu != null) {
56
				newSep = new MenuItem(menu, SWT.SEPARATOR, addIndex);
57
			}
58
		} else if (element instanceof MToolBarSeparator) {
59
			ToolBar tb = parent instanceof ToolBar ? (ToolBar) parent
45
			ToolBar tb = parent instanceof ToolBar ? (ToolBar) parent
60
					: (ToolBar) element.getParent().getWidget();
46
					: (ToolBar) element.getParent().getWidget();
61
			newSep = new ToolItem(tb, SWT.SEPARATOR, addIndex);
47
			newSep = new ToolItem(tb, SWT.SEPARATOR, addIndex);
(-)src/org/eclipse/e4/ui/workbench/renderers/swt/WorkbenchRendererFactory.java (-34 / +2 lines)
Lines 14-25 Link Here
14
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
14
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
15
import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
15
import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
16
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
16
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
17
import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem;
18
import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
19
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
17
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
20
import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator;
18
import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator;
21
import org.eclipse.e4.ui.model.application.ui.menu.MRenderedMenu;
22
import org.eclipse.e4.ui.model.application.ui.menu.MRenderedMenuItem;
23
import org.eclipse.e4.ui.model.application.ui.menu.MRenderedToolBar;
19
import org.eclipse.e4.ui.model.application.ui.menu.MRenderedToolBar;
24
import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
20
import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
25
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarSeparator;
21
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarSeparator;
Lines 30-37 Link Here
30
public class WorkbenchRendererFactory implements IRendererFactory {
26
public class WorkbenchRendererFactory implements IRendererFactory {
31
27
32
	private AreaRenderer areaRenderer;
28
	private AreaRenderer areaRenderer;
33
	private MenuRenderer menuRenderer;
29
	private MenuManagerRenderer menuRenderer;
34
	private HandledMenuItemRenderer handledMenuItemRenderer;
35
	private ToolBarRenderer toolbarRenderer;
30
	private ToolBarRenderer toolbarRenderer;
36
	private ToolItemRenderer toolItemRenderer;
31
	private ToolItemRenderer toolItemRenderer;
37
	private SeparatorRenderer separatorRenderer;
32
	private SeparatorRenderer separatorRenderer;
Lines 46-54 Link Here
46
	private WBWRenderer wbwRenderer;
41
	private WBWRenderer wbwRenderer;
47
42
48
	private IEclipseContext context;
43
	private IEclipseContext context;
49
	private DirectMenuItemRenderer directMenuItemRenderer;
50
	private RenderedMenuRenderer renderedMenuRenderer;
51
	private RenderedMenuItemRenderer renderedMenuItemRenderer;
52
	private RenderedToolBarRenderer renderedToolbarRenderer;
44
	private RenderedToolBarRenderer renderedToolbarRenderer;
53
45
54
	public AbstractPartRenderer getRenderer(MUIElement uiElement, Object parent) {
46
	public AbstractPartRenderer getRenderer(MUIElement uiElement, Object parent) {
Lines 64-96 Link Here
64
				initRenderer(contributedPartRenderer);
56
				initRenderer(contributedPartRenderer);
65
			}
57
			}
66
			return contributedPartRenderer;
58
			return contributedPartRenderer;
67
		} else if (uiElement instanceof MHandledMenuItem) {
68
			if (handledMenuItemRenderer == null) {
69
				handledMenuItemRenderer = new HandledMenuItemRenderer();
70
				initRenderer(handledMenuItemRenderer);
71
			}
72
			return handledMenuItemRenderer;
73
		} else if (uiElement instanceof MDirectMenuItem) {
74
			if (directMenuItemRenderer == null) {
75
				directMenuItemRenderer = new DirectMenuItemRenderer();
76
				initRenderer(directMenuItemRenderer);
77
			}
78
			return directMenuItemRenderer;
79
		} else if (uiElement instanceof MRenderedMenu) {
80
			if (renderedMenuRenderer == null) {
81
				renderedMenuRenderer = new RenderedMenuRenderer();
82
				initRenderer(renderedMenuRenderer);
83
			}
84
			return renderedMenuRenderer;
85
		} else if (uiElement instanceof MRenderedMenuItem) {
86
			if (renderedMenuItemRenderer == null) {
87
				renderedMenuItemRenderer = new RenderedMenuItemRenderer();
88
				initRenderer(renderedMenuItemRenderer);
89
			}
90
			return renderedMenuItemRenderer;
91
		} else if (uiElement instanceof MMenu) {
59
		} else if (uiElement instanceof MMenu) {
92
			if (menuRenderer == null) {
60
			if (menuRenderer == null) {
93
				menuRenderer = new MenuRenderer();
61
				menuRenderer = new MenuManagerRenderer();
94
				initRenderer(menuRenderer);
62
				initRenderer(menuRenderer);
95
			}
63
			}
96
			return menuRenderer;
64
			return menuRenderer;
(-)src/org/eclipse/e4/ui/internal/workbench/swt/PartRenderingEngine.java (-23 / +6 lines)
Lines 52-57 Link Here
52
import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
52
import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
53
import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
53
import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
54
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
54
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
55
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
55
import org.eclipse.e4.ui.services.IStylingEngine;
56
import org.eclipse.e4.ui.services.IStylingEngine;
56
import org.eclipse.e4.ui.workbench.IPresentationEngine;
57
import org.eclipse.e4.ui.workbench.IPresentationEngine;
57
import org.eclipse.e4.ui.workbench.IResourceUtilities;
58
import org.eclipse.e4.ui.workbench.IResourceUtilities;
Lines 59-65 Link Here
59
import org.eclipse.e4.ui.workbench.UIEvents;
60
import org.eclipse.e4.ui.workbench.UIEvents;
60
import org.eclipse.e4.ui.workbench.modeling.EModelService;
61
import org.eclipse.e4.ui.workbench.modeling.EModelService;
61
import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
62
import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
62
import org.eclipse.e4.ui.workbench.swt.modeling.MenuServiceFilter;
63
import org.eclipse.emf.ecore.impl.EObjectImpl;
63
import org.eclipse.emf.ecore.impl.EObjectImpl;
64
import org.eclipse.equinox.app.IApplication;
64
import org.eclipse.equinox.app.IApplication;
65
import org.eclipse.equinox.app.IApplicationContext;
65
import org.eclipse.equinox.app.IApplicationContext;
Lines 91-98 Link Here
91
91
92
	IRendererFactory curFactory = null;
92
	IRendererFactory curFactory = null;
93
93
94
	MenuServiceFilter menuServiceFilter;
95
96
	org.eclipse.swt.widgets.Listener keyListener;
94
	org.eclipse.swt.widgets.Listener keyListener;
97
95
98
	// Life Cycle handlers
96
	// Life Cycle handlers
Lines 109-116 Link Here
109
						.eContainer();
107
						.eContainer();
110
			}
108
			}
111
109
110
			boolean menuChild = parent instanceof MMenu;
111
112
			// If the parent isn't displayed who cares?
112
			// If the parent isn't displayed who cares?
113
			if (parent == null || parent.getWidget() == null)
113
			if (parent == null || parent.getWidget() == null || menuChild)
114
				return;
114
				return;
115
115
116
			if (changedElement.isToBeRendered()) {
116
			if (changedElement.isToBeRendered()) {
Lines 202-210 Link Here
202
			MElementContainer<MUIElement> changedElement = (MElementContainer<MUIElement>) changedObj;
202
			MElementContainer<MUIElement> changedElement = (MElementContainer<MUIElement>) changedObj;
203
			boolean isApplication = changedObj instanceof MApplication;
203
			boolean isApplication = changedObj instanceof MApplication;
204
204
205
			boolean menuChild = changedObj instanceof MMenu;
205
			// If the parent isn't in the UI then who cares?
206
			// If the parent isn't in the UI then who cares?
206
			AbstractPartRenderer renderer = getRendererFor(changedElement);
207
			AbstractPartRenderer renderer = getRendererFor(changedElement);
207
			if (!isApplication && renderer == null)
208
			if ((!isApplication && renderer == null) || menuChild)
208
				return;
209
				return;
209
210
210
			String eventType = (String) event
211
			String eventType = (String) event
Lines 695-707 Link Here
695
				display.addFilter(SWT.KeyDown, keyListener);
696
				display.addFilter(SWT.KeyDown, keyListener);
696
				display.addFilter(SWT.Traverse, keyListener);
697
				display.addFilter(SWT.Traverse, keyListener);
697
698
698
				menuServiceFilter = ContextInjectionFactory.make(
699
						MenuServiceFilter.class, runContext);
700
				display.addFilter(SWT.Show, menuServiceFilter);
701
				display.addFilter(SWT.Hide, menuServiceFilter);
702
				display.addFilter(SWT.Dispose, menuServiceFilter);
703
				runContext.set(MenuServiceFilter.class, menuServiceFilter);
704
705
				// Show the initial UI
699
				// Show the initial UI
706
700
707
				// Create a 'limbo' shell (used to host controls that shouldn't
701
				// Create a 'limbo' shell (used to host controls that shouldn't
Lines 834-850 Link Here
834
	 * why this is needed we should make this safe for multiple calls
828
	 * why this is needed we should make this safe for multiple calls
835
	 */
829
	 */
836
	private void cleanUp() {
830
	private void cleanUp() {
837
		if (menuServiceFilter != null) {
838
			Display display = Display.getDefault();
839
			if (!display.isDisposed()) {
840
				display.removeFilter(SWT.Show, menuServiceFilter);
841
				display.removeFilter(SWT.Hide, menuServiceFilter);
842
				display.removeFilter(SWT.Dispose, menuServiceFilter);
843
				menuServiceFilter.dispose();
844
				menuServiceFilter = null;
845
				appContext.remove(MenuServiceFilter.class);
846
			}
847
		}
848
		if (keyListener != null) {
831
		if (keyListener != null) {
849
			Display display = Display.getDefault();
832
			Display display = Display.getDefault();
850
			if (!display.isDisposed()) {
833
			if (!display.isDisposed()) {
(-)src/org/eclipse/e4/ui/workbench/swt/modeling/MenuService.java (-14 / +33 lines)
Lines 13-25 Link Here
13
import javax.inject.Inject;
13
import javax.inject.Inject;
14
import org.eclipse.e4.core.contexts.IEclipseContext;
14
import org.eclipse.e4.core.contexts.IEclipseContext;
15
import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
15
import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
16
import org.eclipse.e4.ui.model.application.ui.MElementContainer;
17
import org.eclipse.e4.ui.model.application.ui.MUIElement;
16
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
18
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
17
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
19
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
18
import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu;
20
import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu;
19
import org.eclipse.swt.SWT;
21
import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
20
import org.eclipse.swt.widgets.Control;
22
import org.eclipse.swt.widgets.Control;
21
import org.eclipse.swt.widgets.Event;
22
import org.eclipse.swt.widgets.Listener;
23
import org.eclipse.swt.widgets.Menu;
23
import org.eclipse.swt.widgets.Menu;
24
24
25
public class MenuService implements EMenuService {
25
public class MenuService implements EMenuService {
Lines 49-68 Link Here
49
		if (mmenu.getWidget() != null) {
49
		if (mmenu.getWidget() != null) {
50
			return false;
50
			return false;
51
		}
51
		}
52
		Menu menu = new Menu(parentControl);
52
		// we need to delegate to the renderer so that it "processes" the
53
		parentControl.setMenu(menu);
53
		// MenuManager correctly
54
		mmenu.setWidget(menu);
54
		IRendererFactory rendererFactory = myPart.getContext().get(
55
		menu.setData(AbstractPartRenderer.OWNING_ME, mmenu);
55
				IRendererFactory.class);
56
		AbstractPartRenderer renderer = rendererFactory.getRenderer(mmenu,
57
				parentControl);
56
		IEclipseContext popupContext = myPart.getContext().createChild(
58
		IEclipseContext popupContext = myPart.getContext().createChild(
57
				"popup:" + mmenu.getElementId());
59
				"popup:" + mmenu.getElementId());
58
		mmenu.setContext(popupContext);
60
		mmenu.setContext(popupContext);
59
		menu.addListener(SWT.Dispose, new Listener() {
61
		Object widget = renderer.createWidget(mmenu, parentControl);
60
			public void handleEvent(Event event) {
62
		if (!(widget instanceof Menu)) {
61
				mmenu.getContext().dispose();
63
			return false;
62
				mmenu.setContext(null);
64
		}
63
				mmenu.setWidget(null);
65
		renderer.bindWidget(mmenu, widget);
64
			}
66
		renderer.hookControllerLogic(mmenu);
65
		});
67
68
		// Process its internal structure through the renderer that created
69
		// it
70
		Object castObject = mmenu;
71
		renderer.processContents((MElementContainer<MUIElement>) castObject);
72
73
		// Allow a final chance to set up
74
		renderer.postProcess(mmenu);
75
76
		// Now that we have a widget let the parent (if any) know
77
		if (mmenu.getParent() instanceof MUIElement) {
78
			MElementContainer<MUIElement> parentElement = mmenu.getParent();
79
			AbstractPartRenderer parentRenderer = rendererFactory.getRenderer(
80
					parentElement, null);
81
			if (parentRenderer != null)
82
				parentRenderer.childRendered(parentElement, mmenu);
83
		}
84
66
		return true;
85
		return true;
67
	}
86
	}
68
}
87
}
(-)src/org/eclipse/e4/ui/workbench/swt/modeling/MenuServiceFilter.java (-369 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.e4.ui.workbench.swt.modeling;
12
13
import java.lang.reflect.InvocationTargetException;
14
import java.lang.reflect.Method;
15
import java.util.ArrayList;
16
import java.util.HashMap;
17
import java.util.List;
18
import javax.inject.Inject;
19
import org.eclipse.core.commands.ParameterizedCommand;
20
import org.eclipse.core.runtime.ISafeRunnable;
21
import org.eclipse.core.runtime.SafeRunner;
22
import org.eclipse.e4.core.commands.EHandlerService;
23
import org.eclipse.e4.core.contexts.IEclipseContext;
24
import org.eclipse.e4.core.services.log.Logger;
25
import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
26
import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
27
import org.eclipse.e4.ui.internal.workbench.swt.Policy;
28
import org.eclipse.e4.ui.internal.workbench.swt.WorkbenchSWTActivator;
29
import org.eclipse.e4.ui.model.application.MApplication;
30
import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
31
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
32
import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
33
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
34
import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu;
35
import org.eclipse.e4.ui.model.application.ui.menu.MRenderedMenu;
36
import org.eclipse.e4.ui.workbench.IPresentationEngine;
37
import org.eclipse.e4.ui.workbench.modeling.EModelService;
38
import org.eclipse.e4.ui.workbench.modeling.ExpressionContext;
39
import org.eclipse.jface.action.MenuManager;
40
import org.eclipse.swt.SWT;
41
import org.eclipse.swt.widgets.Event;
42
import org.eclipse.swt.widgets.Listener;
43
import org.eclipse.swt.widgets.Menu;
44
import org.eclipse.swt.widgets.MenuItem;
45
import org.eclipse.swt.widgets.Widget;
46
47
public class MenuServiceFilter implements Listener {
48
	public static final String NUL_MENU_ITEM = "(None Applicable)"; //$NON-NLS-1$
49
50
	private static final String TMP_ORIGINAL_CONTEXT = "MenuServiceFilter.original.context";
51
52
	private static void trace(String msg, Widget menu, MMenu menuModel) {
53
		WorkbenchSWTActivator.trace(Policy.MENUS, msg + ": " + menu + ": "
54
				+ menuModel, null);
55
	}
56
57
	private static Method aboutToShow;
58
59
	public static Method getAboutToShow() {
60
		if (aboutToShow == null) {
61
			try {
62
				aboutToShow = MenuManager.class
63
						.getDeclaredMethod("handleAboutToShow");
64
				aboutToShow.setAccessible(true);
65
			} catch (SecurityException e) {
66
				// TODO Auto-generated catch block
67
				e.printStackTrace();
68
			} catch (NoSuchMethodException e) {
69
				// TODO Auto-generated catch block
70
				e.printStackTrace();
71
			}
72
		}
73
		return aboutToShow;
74
	}
75
76
	@Inject
77
	private MApplication application;
78
79
	@Inject
80
	private IPresentationEngine renderer;
81
82
	@Inject
83
	private Logger logger;
84
85
	@Inject
86
	EModelService modelService;
87
88
	private HashMap<Menu, Runnable> pendingCleanup = new HashMap<Menu, Runnable>();
89
90
	public void handleEvent(final Event event) {
91
		// wrap the handling in a SafeRunner so that exceptions do not prevent
92
		// the menu from being shown
93
		SafeRunner.run(new ISafeRunnable() {
94
			public void handleException(Throwable e) {
95
				if (e instanceof Error) {
96
					// errors are deadly, we shouldn't ignore these
97
					throw (Error) e;
98
				} else {
99
					// log exceptions otherwise
100
					if (logger != null) {
101
						logger.error(e);
102
					}
103
				}
104
			}
105
106
			public void run() throws Exception {
107
				safeHandleEvent(event);
108
			}
109
		});
110
	}
111
112
	private void safeHandleEvent(Event event) {
113
		if (!(event.widget instanceof Menu)) {
114
			return;
115
		}
116
		final Menu menu = (Menu) event.widget;
117
		if (event.type == SWT.Dispose) {
118
			trace("handleMenu.Dispose", menu, null);
119
			cleanUp(menu);
120
		}
121
		Object obj = menu.getData(AbstractPartRenderer.OWNING_ME);
122
		if (obj == null && menu.getParentItem() != null) {
123
			obj = menu.getParentItem().getData(AbstractPartRenderer.OWNING_ME);
124
		}
125
		if (obj instanceof MRenderedMenu) {
126
			handlerRenderedMenu(event, menu, (MRenderedMenu) obj);
127
		} else if (obj instanceof MPopupMenu) {
128
			handleContextMenu(event, menu, (MPopupMenu) obj);
129
		} else if (obj instanceof MMenu) {
130
			handleMenu(event, menu, (MMenu) obj);
131
		}
132
	}
133
134
	private void handleMenu(final Event event, final Menu menu,
135
			final MMenu menuModel) {
136
		if ((menu.getStyle() & SWT.BAR) != 0) {
137
			// don't process the menu bar, it's not fair :-)
138
			return;
139
		}
140
		switch (event.type) {
141
		case SWT.Show:
142
			trace("handleMenu.Show", menu, menuModel);
143
			cleanUp(menu);
144
			showMenu(event, menu, menuModel);
145
			break;
146
		case SWT.Hide:
147
			trace("handleMenu.Hide", menu, menuModel);
148
			// TODO we'll clean up on show
149
			break;
150
		}
151
	}
152
153
	public void showMenu(final Event event, final Menu menu,
154
			final MMenu menuModel) {
155
		final IEclipseContext parentContext = modelService
156
				.getContainingContext(menuModel);
157
158
		final ArrayList<MMenuContribution> toContribute = new ArrayList<MMenuContribution>();
159
		final ArrayList<MMenuElement> menuContributionsToRemove = new ArrayList<MMenuElement>();
160
		ExpressionContext eContext = new ExpressionContext(parentContext);
161
		ContributionsAnalyzer.gatherMenuContributions(menuModel,
162
				application.getMenuContributions(), menuModel.getElementId(),
163
				toContribute, eContext, false);
164
		if (menu.getItemCount() == 1) {
165
			MenuItem item = menu.getItem(0);
166
			if (NUL_MENU_ITEM.equals(item.getText())) {
167
				item.dispose();
168
			}
169
		}
170
		ContributionsAnalyzer.addMenuContributions(menuModel, toContribute,
171
				menuContributionsToRemove);
172
173
		// create a cleanup routine for the Hide or next Show
174
		pendingCleanup.put(menu, new Runnable() {
175
			public void run() {
176
				if (!menu.isDisposed()) {
177
					unrender(menuContributionsToRemove);
178
				}
179
				removeMenuContributions(menuModel, menuContributionsToRemove);
180
			}
181
		});
182
		render(menu, menuModel);
183
		if (menu.getItemCount() == 0) {
184
			MenuItem menuItem = new MenuItem(menu, SWT.PUSH);
185
			menuItem.setText(NUL_MENU_ITEM);
186
			menuItem.setEnabled(false);
187
		}
188
	}
189
190
	private void handleContextMenu(final Event event, final Menu menu,
191
			final MPopupMenu menuModel) {
192
		switch (event.type) {
193
		case SWT.Show:
194
			trace("handleContextMenu.Show", menu, menuModel);
195
			cleanUp(menu);
196
			showPopup(event, menu, menuModel);
197
			break;
198
		case SWT.Hide:
199
			trace("handleContextMenu.Hide", menu, menuModel);
200
			hidePopup(event, menu, menuModel);
201
			break;
202
		}
203
	}
204
205
	public void hidePopup(Event event, Menu menu, MPopupMenu menuModel) {
206
		final IEclipseContext popupContext = menuModel.getContext();
207
		final IEclipseContext originalChild = (IEclipseContext) popupContext
208
				.get(TMP_ORIGINAL_CONTEXT);
209
		popupContext.remove(TMP_ORIGINAL_CONTEXT);
210
		if (!menu.isDisposed()) {
211
			menu.getDisplay().asyncExec(new Runnable() {
212
				public void run() {
213
					if (originalChild == null) {
214
						popupContext.deactivate();
215
					} else {
216
						originalChild.activate();
217
					}
218
				}
219
			});
220
		}
221
	}
222
223
	public void showPopup(final Event event, final Menu menu,
224
			final MPopupMenu menuModel) {
225
		// System.err.println("showPopup: " + menuModel + "\n\t" + menu);
226
		// we need some context foolery here
227
		final IEclipseContext popupContext = menuModel.getContext();
228
		final IEclipseContext parentContext = popupContext.getParent();
229
		final IEclipseContext originalChild = parentContext.getActiveChild();
230
		popupContext.activate();
231
		popupContext.set(TMP_ORIGINAL_CONTEXT, originalChild);
232
233
		final ArrayList<MMenuContribution> toContribute = new ArrayList<MMenuContribution>();
234
		final ArrayList<MMenuElement> menuContributionsToRemove = new ArrayList<MMenuElement>();
235
		ExpressionContext eContext = new ExpressionContext(popupContext);
236
		ContributionsAnalyzer.gatherMenuContributions(menuModel,
237
				application.getMenuContributions(), menuModel.getElementId(),
238
				toContribute, eContext, true);
239
240
		for (String tag : menuModel.getTags()) {
241
			if (tag.startsWith("popup:") && tag.length() > 6) {
242
				ContributionsAnalyzer.gatherMenuContributions(menuModel,
243
						application.getMenuContributions(), tag.substring(6),
244
						toContribute, eContext, false);
245
			}
246
		}
247
		ContributionsAnalyzer.addMenuContributions(menuModel, toContribute,
248
				menuContributionsToRemove);
249
250
		// create a cleanup routine for the Hide or next Show
251
		pendingCleanup.put(menu, new Runnable() {
252
			public void run() {
253
				if (!menu.isDisposed()) {
254
					unrender(menuContributionsToRemove);
255
				}
256
				removeMenuContributions(menuModel, menuContributionsToRemove);
257
			}
258
		});
259
		render(menu, menuModel);
260
	}
261
262
	private void render(final Menu menu, final MMenu menuModel) {
263
		trace("render", menu, menuModel);
264
		for (MMenuElement element : menuModel.getChildren()) {
265
			renderer.createGui(element, menu, null);
266
			if (element instanceof MHandledMenuItem) {
267
				setEnabled((MHandledMenuItem) element);
268
			}
269
		}
270
	}
271
272
	private void setEnabled(MHandledMenuItem item) {
273
		if (!item.isToBeRendered() || !item.isVisible()
274
				|| item.getWidget() == null) {
275
			return;
276
		}
277
		ParameterizedCommand cmd = item.getWbCommand();
278
		if (cmd == null) {
279
			return;
280
		}
281
		final IEclipseContext lclContext = modelService
282
				.getContainingContext(item);
283
		EHandlerService service = lclContext.get(EHandlerService.class);
284
		item.setEnabled(service.canExecute(cmd));
285
	}
286
287
	private void unrender(final List<MMenuElement> menuModel) {
288
		trace("unrender", null, null);
289
		for (MMenuElement element : menuModel) {
290
			renderer.removeGui(element);
291
		}
292
	}
293
294
	private void removeMenuContributions(final MMenu menuModel,
295
			final ArrayList<MMenuElement> menuContributionsToRemove) {
296
		for (MMenuElement item : menuContributionsToRemove) {
297
			trace("removeMenuContributions " + item,
298
					(Widget) menuModel.getWidget(), menuModel);
299
			menuModel.getChildren().remove(item);
300
		}
301
	}
302
303
	private void handlerRenderedMenu(final Event event, final Menu menu,
304
			final MRenderedMenu menuModel) {
305
		// Do nothing here for the moment, except process any cleanups
306
		switch (event.type) {
307
		case SWT.Show:
308
			trace("handlerRenderedMenu.Show", menu, menuModel);
309
			cleanUp(menu);
310
			showRenderedMenu(event, menu, menuModel);
311
			break;
312
		case SWT.Hide:
313
			trace("handlerRenderedMenu.Hide", menu, menuModel);
314
			// TODO don't care
315
			break;
316
		}
317
	}
318
319
	public void showRenderedMenu(final Event event, final Menu menu,
320
			final MRenderedMenu menuModel) {
321
		if (!(menuModel.getContributionManager() instanceof MenuManager)) {
322
			return;
323
		}
324
325
		MenuManager manager = (MenuManager) menuModel.getContributionManager();
326
		Method handleAboutToShow = getAboutToShow();
327
		try {
328
			handleAboutToShow.invoke(manager);
329
		} catch (IllegalArgumentException e) {
330
			// TODO Auto-generated catch block
331
			e.printStackTrace();
332
		} catch (IllegalAccessException e) {
333
			// TODO Auto-generated catch block
334
			e.printStackTrace();
335
		} catch (InvocationTargetException e) {
336
			// TODO Auto-generated catch block
337
			e.printStackTrace();
338
		}
339
340
		if (menuModel.getChildren().size() == 1
341
				&& menuModel.getChildren().get(0) instanceof MPopupMenu) {
342
			showPopup(event, menu, (MPopupMenu) menuModel.getChildren().get(0));
343
		} else {
344
			showMenu(event, menu, menuModel);
345
		}
346
		event.type = SWT.None;
347
		event.doit = false;
348
	}
349
350
	public void cleanUp(final Menu menu) {
351
		trace("cleanUp", menu, null);
352
		if (pendingCleanup.isEmpty()) {
353
			return;
354
		}
355
		Runnable cleanUp = pendingCleanup.remove(menu);
356
		if (cleanUp != null) {
357
			trace("cleanUp.run()", menu, null);
358
			cleanUp.run();
359
		}
360
	}
361
362
	public void dispose() {
363
		Menu[] keys = pendingCleanup.keySet().toArray(
364
				new Menu[pendingCleanup.size()]);
365
		for (Menu menu : keys) {
366
			cleanUp(menu);
367
		}
368
	}
369
}
(-)Eclipse UI/org/eclipse/ui/internal/e4/compatibility/CompatibilityView.java (-6 / +16 lines)
Lines 12-25 Link Here
12
package org.eclipse.ui.internal.e4.compatibility;
12
package org.eclipse.ui.internal.e4.compatibility;
13
13
14
import javax.inject.Inject;
14
import javax.inject.Inject;
15
import org.eclipse.e4.core.contexts.IEclipseContext;
15
import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
16
import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
17
import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
16
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
18
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
17
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
19
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
18
import org.eclipse.e4.ui.model.application.ui.menu.MRenderedMenu;
19
import org.eclipse.e4.ui.model.application.ui.menu.MRenderedToolBar;
20
import org.eclipse.e4.ui.model.application.ui.menu.MRenderedToolBar;
20
import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
21
import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
21
import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
22
import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
23
import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
24
import org.eclipse.e4.ui.workbench.renderers.swt.MenuRenderer;
22
import org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer;
25
import org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer;
26
import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
23
import org.eclipse.jface.action.MenuManager;
27
import org.eclipse.jface.action.MenuManager;
24
import org.eclipse.jface.action.ToolBarManager;
28
import org.eclipse.jface.action.ToolBarManager;
25
import org.eclipse.swt.widgets.Composite;
29
import org.eclipse.swt.widgets.Composite;
Lines 75-90 Link Here
75
		// dispose the tb, it will be re-created when the tab is shown
79
		// dispose the tb, it will be re-created when the tab is shown
76
		tb.dispose();
80
		tb.dispose();
77
81
82
		IEclipseContext context = getModel().getContext();
83
		IRendererFactory rendererFactory = context.get(IRendererFactory.class);
84
78
		MenuManager mm = (MenuManager) actionBars.getMenuManager();
85
		MenuManager mm = (MenuManager) actionBars.getMenuManager();
79
		MRenderedMenu menu = null;
86
		MMenu menu = null;
80
		for (MMenu me : part.getMenus()) {
87
		for (MMenu me : part.getMenus()) {
81
			if (me.getTags().contains(StackRenderer.TAG_VIEW_MENU) && (me instanceof MRenderedMenu)) {
88
			if (me.getTags().contains(StackRenderer.TAG_VIEW_MENU)) {
82
				menu = (MRenderedMenu) me;
89
				menu = me;
83
				break;
90
				break;
84
			}
91
			}
85
		}
92
		}
86
		if (menu == null) {
93
		if (menu == null) {
87
			menu = MenuFactoryImpl.eINSTANCE.createRenderedMenu();
94
			menu = MenuFactoryImpl.eINSTANCE.createMenu();
88
			menu.setElementId(part.getElementId());
95
			menu.setElementId(part.getElementId());
89
96
90
			menu.getTags().add(StackRenderer.TAG_VIEW_MENU);
97
			menu.getTags().add(StackRenderer.TAG_VIEW_MENU);
Lines 92-98 Link Here
92
			part.getMenus().add(menu);
99
			part.getMenus().add(menu);
93
100
94
		}
101
		}
95
		menu.setContributionManager(mm);
102
		AbstractPartRenderer apr = rendererFactory.getRenderer(menu, parent);
103
		if (apr instanceof MenuRenderer) {
104
			((MenuManagerRenderer) apr).linkModelToManager(menu, mm);
105
		}
96
106
97
		// Construct the toolbar (if necessary)
107
		// Construct the toolbar (if necessary)
98
		MToolBar toolbar = part.getToolbar();
108
		MToolBar toolbar = part.getToolbar();

Return to bug 325392