Community
Participate
Working Groups
R3.0 Currently, whenever a component like a view, preference page, or action set, is defined, it is also placed in the UI. That is, attributes like its label, icon, parent category, containing menu, etc. are defined in the same extension as the component itself. This is problematic for creating components designed to be reused in different applications, since this assumes a particular arrangement of containing menus, categories, labeling, etc. Presentation and placement of a component should be separable from the declaration of the component itself. As with the current way of doing things, we want to preserve the ability to refer to an component by id, without having to expose its implementation class as API. Some known cases are: - reusing the progress view: bug 71747, comment 2 - reusing the keys preference page: bug 73510 - update UI actions: bug 63081
As discussed on eclipse.platform.rcp I'm posting these comments here: In my RCP app I'm currently re-using some internal Preference pages: - Appearance (in org.eclipse.ui.internal.dialogs.ViewsPreferencePage) I've seen no serious problems with re-using this one and putting it in public API. The only thing is that the choice for Presentation and Theme depends on extra presentation factories being available. If they're not available these choiches give you exactly one choice. Maybe don't show them in that case? - Startup (in org.eclipse.ui.internal.dialogs.StartupPreferencePage) (this one is extended by the IDE) No problems with this one and putting it in public API. Seems to have no serious dependencies. The IDE puts some extra info on this page. The question 'Confirm exit when closing last window' can be useful for RCP to, but maybe things like this should be configureable. - Keys (in org.eclipse.ui.internal.commands.KeysPreferencePage) There is work for this in progress on another bug number, so no comment from me. - Colors And Fonts (in org.eclipse.ui.internal.themes.ColorsAndFontsPreferencePage) No problems re-using this one. I have no exact idea if all entries are actually used in the libraries in the RCP platform. - Perspectives Well, this one includes a choice 'Switch to associated perspective when creating a new project' thus has a dependency on the ide. Maybe a trimmed down version can be available as public API? I'm not using it yet. If necessary I can attach screenshots of using them in an RCP app.
Note that the perspectives pref page is divided into PerspectivesPreferencePage (in the UI layer) and its subclass IDEPerspectivesPreferencepage (in the IDE layer). The 'Switch to associated perspective' pref is in the latter. You should be able to copy the extension for this pref page into your own app, but change the class to refer to org.eclipse.ui.internal.dialogs.PerspectivesPreferencePage Of course, then you're referring to an internal class, which is not recommended. But addressing that problem is the subject of this PR.
Deferring to M6. One idea which may help is to allow a factory to be specified as the extension class, rather than the concrete class. This way, the factory can be API and the concrete class can remain internal. So a reusable component like Update would just expose factories as API, and then product plug-ins would define the extension, referring to the factory class. This would be far simpler than breaking up each extension point into separate declaration and presentation elements. Such a separation would allow multiple presentations to be declared, which we're not well set up to handle. It would also allow them to be added/removed separately, which would really complicate the dynamic plugin support.
I've been experimenting with the factory approach, and it works very well. We would need to provide something like the proposal in bug 86236 (the initial proposal -- extra lifecycle management not required). While we could provide an IExecutableExtensionFactory at UI level, I don't want to introduce anything that would conflict with anything similar at runtime.
Here's an excerpt for separating product-specific aspects out of org.eclipse.update.ui into a new plug-in, org.eclipse.update.ui.ide: <?xml version="1.0" encoding="UTF-8"?> <?eclipse version="3.0"?> <plugin id="org.eclipse.update.ui.ide" name="%Plugin.name" version="3.1.0" provider-name="%Plugin.providerName"> <runtime> <library name="."> <export name="*"/> </library> </runtime> <requires> <import plugin="org.eclipse.update.ui"/> </requires> <extension point="org.eclipse.ui.actionSets"> <actionSet label="%UpdateActionSet.label" visible="true" id="org.eclipse.update.ui.softwareUpdates"> <menu label="%UpdateActionSet.menu.label" path="help/group.updates" id="org.eclipse.update.ui.updateMenu"> <separator name="group0"> </separator> <separator name="group1"> </separator> </menu> <action label="%UpdateActionSet.configManager.label" icon="icons/elcl16/configs.gif" helpContextId="org.eclipse.update.ui.newUpdates" class="org.eclipse.update.ui.ActionFactory:org.eclipse.update.ui.configManager" menubarPath="help/org.eclipse.update.ui.updateMenu/group0" id="org.eclipse.update.ui.configManager"> </action> <action label="%UpdateActionSet.updates.label" icon="icons/elcl16/usearch_obj.gif" helpContextId="org.eclipse.update.ui.newUpdates" class="org.eclipse.update.ui.ActionFactory:org.eclipse.update.ui.newUpdates" menubarPath="help/org.eclipse.update.ui.updateMenu/group0" id="org.eclipse.update.ui.newUpdates"> </action> </actionSet> </extension> <extension point="org.eclipse.ui.preferencePages"> <page name="%mainPreference.name" class="org.eclipse.update.ui.PreferencePageFactory:org.eclipse.update.ui.preferences.MainPreferencePage" id="org.eclipse.update.ui.preferences.MainPreferencePage"> </page> </extension> </plugin> org.eclipse.update.ui provides the factories (as API) that hide the (internal) concrete actions and preference page. For example: package org.eclipse.update.ui; import org.eclipse.ui.ExecutableExtensionFactory; import org.eclipse.update.internal.ui.preferences.MainPreferencePage; public class PreferencePageFactory extends ExecutableExtensionFactory { private static final String MAIN = "org.eclipse.update.ui.preferences.MainPreferencePage"; //$NON-NLS-1$ public PreferencePageFactory() { // do nothing } protected Object create(String id) { if (id.equals(MAIN)) return new MainPreferencePage(); return null; } } Where ExecutableExtensionFactory is a convenience implementation of IExecutableExtensionFactory which is just: public interface IExecutableExtensionFactory { Object create() throws CoreException; }
Created attachment 19263 [details] Patch to org.eclipse.ui.ide for moving Update contributions out Now that the extension factory mechanism is in place, I've updated the prototype split of Update UI. This first part removes the Update action set and related action delegates from org.eclipse.ui.ide.
Created attachment 19265 [details] Patch to org.eclipse.update.ui for the split prototype This second part moves the action delegate implementations back to being internal in org.eclipse.update.ui, and removes the preference page extension.
Created attachment 19266 [details] Zip of org.eclipse.update.ui.ide for the split prototype This third and last part is a zip of a separate plug-in, org.eclipse.update.ui.ide, that has the product-specific extensions for the action set and preference page, referring to the factory defined in org.eclipse.update.ui (forgot to mention the factory in the last post).
Had a good chat with Dorian about this earlier, which I'll briefly summarize. Dorian, please correct me if I've misrepresented anything. Dorian argues that support for product-specific overrides of existing extensions should be something that can be done more directly via a runtime-level mechanism, e.g. using some kind of product configuration mechanism that's akin to our current preference_customization.ini mechanism, but for arbitrary extensions rather than preferences. Something like J2EE deployment descriptors. I tried to characterize the differences as: with factories, you can provide a generic component C in a plugin P, and separate its presentation aspects into a separate plugin Q. But it also -requires- them to be in separate plug-ins. With a configuration mechanism, P can provide C and some default presentation aspects, and the configuration mechanism allows its presentation aspects to be overridden by the product. The upshot was, Dorian currently feels it would not be appropriate to apply factories to Update for 3.1, partly due to the extra API commitment, and partly just due to feeling like it's not the appropriate mechanism to allow product-specific configuration, but he would be willing to separate the current extensions into a separate "friends" plug-in like what I proposed for org.eclipse.update.ui.ide, but without the factories (or any new API) and without being IDE-specific. This would allow RCP apps to have three levels: 1. o.e.update.core - just the core API 2. o.e.update.core and o.e.update.ui - the core API and API to invoke the update UI, but no action set or preference page showing up by default 3. o.e.update.core, o.e.update.ui and o.e.update.ui.??? - adds the action set and preference page extensions (referring to internal classes in o.e.update.ui) (2) would support RCP apps that want the update UI, but want to provide their own UI for invoking it. They would not be able to reuse the preference page or action delegates. Note that, while at EclipseCon, we heard from several RCP app authors who were tring to reuse the existing Update pref page, but everyone wanted to tweak it in their own specific ways, so it's unclear that reusing the preference page as-is would be helpful anyway.
In the case of the contributions in the generic workbench though (Keys pref page, Progress view, etc), factories do seem like a good solution, and will allow us to address some of the component boundary violations due to org.eclipse.ui.ide referencing these internals. I will go ahead with this for M6.
Released org.eclipse.ui.ExtensionFactory with IDs for the preference pages in the generic workbench, plus the Progress view. The corresponding extensions in org.eclipse.ui.ide's plugin.xml now go through this factory, eliminating several internal class references.
What about the new preference link area exposed in some of these pages? They hard link to other pages by ID. We can no longer guarentee these links will be valid. Even if the linked-to page exists its id may differ.
> We can no longer guarentee these links will be valid. I think the links should check if the destination exists before creating the controls. > Even if the linked-to page exists its id may differ. Not an easy problem to solve without finer-grained control over what goes into a preference page (e.g. contributing preference sections instead of whole pages). If we can just do the check, I can live with the other limitation for 3.1.
I've entered Bug 89338 to address the link area issue.
The new API in M6 addresses this issue: - IExecutableExtensionFactory in core enables plug-ins to provide executable extensions without exposing their concrete implementation (with no changes required for existing extension points, either in their code or schema). - The ExtensionFactory in the workbench exposes its preference pages and the progress view in this way - the IDE has been fixed up to refer to them using this factory - other plug-ins can use this mechanism similarly We will look at the Update scenario again in M7, but the current plan is to leave as-is for 3.1.
Verified in I20050331-0800.