Community
Participate
Working Groups
This has changed from R2.0.2 and can be considered a regression. In R2.0.2 the actions were constructed when the workbench was starting up. I understand that for performance reasons it was not a good idea to do it all at startup. In R2.1 it appears that they are not constructed until the user RMB (Right Mouse Button) on something in the view. And that is the problem. If the view is empty then there is nothing to RMB on and therefore the actions are not constructed/initialized. In my case I have contributed an action that will add something to the view. It is now impossible because the view is empty so the action remains disabled. The actions should be constructed the first time the user RMB in the view even if there is nothing in the view.
I want to increase the priority as I was able to reproduce this on Eclipse, WSWB and WSAD. This problem is consistent on the Eclipse or WSWB workbench. When I tested this on WSAD it only fails to create the actions if the view that the contributions apply to was visible when the workbench was closed down and restarted. If the view is not visible then the actions are created either as soon as the view is given focus or the popup menu is activated. (It was hard to tell which actually caused the actions to be created)
The following is the stack trace taken in WSAD when the init method of the contributed action *was* called. This doesn't happen when running on just the Eclipse workbench. Thread [main] (Suspended (breakpoint at line 44 in AddExpressionAction)) AddExpressionAction.init(IViewPart) line: 44 ViewPluginAction.initDelegate() line: 53 ViewPluginAction(PluginAction).createDelegate() line: 105 ViewPluginAction(PluginAction).selectionChanged(ISelection) line: 269 ViewPluginAction(PartPluginAction).registerSelectionListener (IWorkbenchPart) line: 39 ViewPluginAction.<init>(IConfigurationElement, String, IViewPart, String, int) line: 35 ActionDescriptor.createAction(int, IConfigurationElement, Object, String, String) line: 192 ActionDescriptor.<init>(IConfigurationElement, int, Object) line: 128 ViewerActionBuilder.createActionDescriptor(IConfigurationElement) line: 46 ViewerActionBuilder(PluginActionBuilder).readElement (IConfigurationElement) line: 144 ViewerActionBuilder.readElement(IConfigurationElement) line: 75 ViewerActionBuilder(RegistryReader).readElements(IConfigurationElement []) line: 130 ViewerActionBuilder(RegistryReader).readElementChildren (IConfigurationElement) line: 120 ViewerActionBuilder(PluginActionBuilder).readElement (IConfigurationElement) line: 127 ViewerActionBuilder.readElement(IConfigurationElement) line: 75 ViewerActionBuilder(RegistryReader).readElements(IConfigurationElement []) line: 130 ViewerActionBuilder(RegistryReader).readExtension(IExtension) line: 139 ViewerActionBuilder(RegistryReader).readRegistry(IPluginRegistry, String, String) line: 156 ViewerActionBuilder(PluginActionBuilder).readContributions(String, String, String) line: 100 ViewerActionBuilder.readViewerContributions(String, ISelectionProvider, IWorkbenchPart) line: 91 PopupMenuExtender.readStaticActions() line: 73 PopupMenuExtender.<init>(String, MenuManager, ISelectionProvider, IWorkbenchPart) line: 36 ViewSite(PartSite).registerContextMenu(String, MenuManager, ISelectionProvider) line: 151 ViewSite(PartSite).registerContextMenu(MenuManager, ISelectionProvider) line: 157 ExpressionView(AbstractDebugView).createContextMenu(Control) line: 504 ExpressionView(AbstractDebugView).createPartControl(Composite) line: 289 PartPane$4.run() line: 138 InternalPlatform.run(ISafeRunnable) line: 867 Platform.run(ISafeRunnable) line: 413 ViewPane(PartPane).createChildControl() line: 134 ViewPane.createChildControl() line: 202 ViewPane(PartPane).createControl(Composite) line: 183 ViewPane.createControl(Composite) line: 181 PartTabFolder.createPartTab(LayoutPart, String, int) line: 251 PartTabFolder.createControl(Composite) line: 223 RootLayoutContainer(PartSashContainer).createControl(Composite) line: 191 PerspectivePresentation.activate(Composite) line: 96 Perspective.onActivate() line: 715 WorkbenchPage.onActivate() line: 1777 WorkbenchWindow$7.run() line: 1474 BusyIndicator.showWhile(Display, Runnable) line: 65 WorkbenchWindow.setActivePage(IWorkbenchPage) line: 1461 WorkbenchWindow.restoreState(IMemento, IPerspectiveDescriptor) line: 1342 Workbench.restoreState(IMemento) line: 1132 Workbench.access$9(Workbench, IMemento) line: 1092 Workbench$10.run() line: 1010 InternalPlatform.run(ISafeRunnable) line: 867 Platform.run(ISafeRunnable) line: 413 Workbench.openPreviousWorkbenchState() line: 962 Workbench.init(String[]) line: 742 Workbench.run(Object) line: 1242 InternalBootLoader.run(String, URL, String, String[], Runnable) line: 845 BootLoader.run(String, URL, String, String[], Runnable) line: 461 Method.invoke(Object, Object[]) line: not available [native method] Main.basicRun(String[]) line: 247 Main.run(String[]) line: 703 Main.main(String[]) line: 539
Alan, - As the reporter, you can ajust the Severity field based on how important this problem is to you. The Priority field is reserved for the eclipse developers. So I adjusted both fields. - Do you have a sample plugin for Eclipse platform that we can use to reproduce this problem? - I'm not sure if I understand properly. Are you saying that if there are no elements in the view, no context menu is shown at all? Or does one popup but with no menu items in it?
Created attachment 4839 [details] Zip of test plugin Testcase to reproduce bug.
To reproduce: 1) unzip plugin into workspace of a basic Eclipse R2.1 workbench 2) launch self-hosted version and clear workspace 3) in self-hosted(SH) copy create a default plugin project. 4) RMB (Right Mouse Button) on the plugin.xml in the above project and click on the "New submenu"->"New action" to load the plugin. (console should show "plugin loaded") 5) change to the debug perspective and click on the breakpoint view tab. 6) the action is initialized ("init called" in console) < this is the expected behaviour > To reproduce error: 7) with the Breakpoint view visible close the SH workbench 8) restart the SH workbench 9) switch to the Resource perspective and click on the plugin.xml and the new menu/action to force the plugin to be loaded. 10) switch back to debug perspective and RMB in the breakpoint view and the action will not be initialized ("init called" does NOT appear in the console)
Please investigate a fix for 2.1.1 since this is a regression.
The behavior your are seeing with your test plugin is the expected one. Lets see if I can explain how the internals are currently working. In part 1, by invoking the action on the plugin.xml file will cause the plugin to load. So when you switch to the debug perspective and open the breakpoints view, we build up the collection of "static" context menu contributions for this view - which includes yours. Then we send a selectionChange event to them with the current selection (could be empty as in this case). When we hit your action contribution, we notice the plugin is already loaded so we load in the delegate. In part 2, when the workbench comes up, your plugin is not yet loaded. So when we build the "static" context menu contributions for the breakpoint view (since its visible). Then we send a selectionChange event to them with the current selection (could be empty as in this case). When we hit your action contribution, we notice the plugin is NOT loaded so we do NOT load in the delegate. Its not until your plugin gets loaded (by the action on plugin.xml) and the selection changes in the breakpoints view that the delegate gets loaded. We've always said that we will wait until the last possible moment before loading plugin code. In the case of the action delegate, that could be until the moment the user clicks on it to run it. Everything I mentionned above is how the internal currently behave and will change from release to release so don't depend on it. There were some problems with 2.0 which caused code to load way to early and was fixed in 2.1 release. In your situation, we recommend that your action be optimistic and set itself as enabled in the XML. When you are asked to run, your delegate will be asked to load, update the enablement state, and if we detect if becomes disable, we warn the user for you that the action is not available. So here are the rules to go by: - enablement should be done in XML if at all possible - there is never any guarantee when the action delegate will be loaded except when the action is to be run, then we guarantee your action delegate will be loaded (and note, it could get unloaded later on...not something we do in 2.1 but 3.0 might do this - for example, nothing in plugin A has been used in last 30 minutes so unload it).
I always worry about the behaviour of an extension point that requires discussing the internals to explain. ;-) I understand that you are trying to defer the loading as much as possible. Not ideal but why not load the delegates just before that action on the popup menu is requested? Give them a chance to determine its correct enablement state just before it is shown. For now I will try changing the enablement of my actions to always enable them.
Because we would be loading a bunch of plugins extending the popup menu - most/all of them never to be used.
I tried enabling my actions in the plugin.xml and it looks really bad. I add 5 actions using view contribution to the breakpoint view. At first they are all enabled (change to plugin.xml to remove enablesFor) and the first one that the user selects they get the action not enabled message and only that action is disabled. The other 4 actions are still enabled because they have not been created. The user would have to select each one and they will get an error for each one. The call to an action delegate should re-attempt creating other action delegates for that view that might have their plugin(s) loaded now. I still don't think that this is a closed issue.
You can push to have it reopen. In normal usuage, how often will the user end up in this situation. Maybe you can talk to your usuability group if they have any data on this. Making changes to preload delegates from plugins already loaded is not a "minor" change. It can have far reaching consequences which may not show up right away. So there needs to be a good arguments to consider this path.
Let me think about it over the long weekend. I will most likely leave it enabled for this release but I feel that enablement in general needs to allow for code to be called to determine the initial state. Could the extension point all for an attribute that would force the plugin to be loaded? That way plugins could determine if they need to be loaded to properly set the initial state.