Bug 73587 - [RCP] Allow separation of declaration and placement of workbench extensions
Summary: [RCP] Allow separation of declaration and placement of workbench extensions
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.0   Edit
Hardware: PC Windows 2000
: P2 normal (vote)
Target Milestone: 3.1 M6   Edit
Assignee: Nick Edgar CLA
QA Contact:
URL:
Whiteboard:
Keywords: api
Depends on:
Blocks: 73510
  Show dependency tree
 
Reported: 2004-09-09 12:40 EDT by Nick Edgar CLA
Modified: 2005-04-12 16:30 EDT (History)
10 users (show)

See Also:


Attachments
Patch to org.eclipse.ui.ide for moving Update contributions out (10.04 KB, patch)
2005-03-28 22:19 EST, Nick Edgar CLA
no flags Details | Diff
Patch to org.eclipse.update.ui for the split prototype (9.66 KB, patch)
2005-03-28 22:22 EST, Nick Edgar CLA
no flags Details | Diff
Zip of org.eclipse.update.ui.ide for the split prototype (3.33 KB, application/zip)
2005-03-28 22:25 EST, Nick Edgar CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Nick Edgar CLA 2004-09-09 12:40:35 EDT
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
Comment 1 Erwin Gribnau CLA 2004-12-21 16:57:29 EST
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.
Comment 2 Nick Edgar CLA 2004-12-21 17:16:49 EST
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.
Comment 3 Nick Edgar CLA 2005-02-18 09:49:07 EST
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.
Comment 4 Nick Edgar CLA 2005-03-23 11:37:06 EST
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.
Comment 5 Nick Edgar CLA 2005-03-23 11:42:56 EST
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;    
}
Comment 6 Nick Edgar CLA 2005-03-28 22:19:23 EST
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.
Comment 7 Nick Edgar CLA 2005-03-28 22:22:35 EST
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.
Comment 8 Nick Edgar CLA 2005-03-28 22:25:12 EST
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).
Comment 9 Nick Edgar CLA 2005-03-28 22:46:49 EST
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.
Comment 10 Nick Edgar CLA 2005-03-28 22:50:23 EST
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.
Comment 11 Nick Edgar CLA 2005-03-29 00:36:30 EST
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.
Comment 12 Kim Horne CLA 2005-03-29 06:06:42 EST
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.
Comment 13 Nick Edgar CLA 2005-03-29 07:46:23 EST
>  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.
Comment 14 Kim Horne CLA 2005-03-29 08:26:58 EST
I've entered Bug 89338 to address the link area issue.
Comment 15 Nick Edgar CLA 2005-03-30 11:54:02 EST
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.
Comment 16 Nick Edgar CLA 2005-03-31 11:40:28 EST
Verified in I20050331-0800.