Eclipse RCP IPageLayout Woes

I have an RCP Eclipse application with a view of three columns:

enter image description here

The editor area is in the extreme right order. Now that you get IPageLayout to work, an editor area has already been added. This is great: we add region B to the left of the editor and region A to the left of B, and the layout is exactly what we need.

The problem is that when you move a leaf between A and B, views A and B change without changing the size of the editor area (well;), but when you move another leaf between B and the editor’s environment, all three types change; The layout manager acts to maintain the ratio of width A to B, and this is not what we want. We want the user to be able to move each belt independently and influence only the two views that he touches.

It seems that the main reason for this is because the editor is in place when you get the IPageView , and therefore you need to put an IFolderLayout relative to it. If you could place the editor relative to B, resize instead, do the right thing.

So my questions are:

  • Is there a way to tell IPageView place the editor on the view, and not vice versa?
  • If this is not the case, is there any other way to influence the layout algorithm, for example, write some kind of layout manager?
+7
source share
2 answers

I do not know how to change the IPageLayout layout IPageLayout in Eclipse 3.x. However, in Eclipse 4.2, the application model can change dynamically at runtime.

So, if you plan to port your application to Eclipse 4, this solution might be an option. To keep the source application and user interface code unavailable, this solution will be

  • make full use of the compatibility level of Eclipse 4 to create an application model from an RCP application based on Eclipse 3. There is no need to create an application model or change the application user interface code.
  • Reorder the editor after the application is active. This is done by creating the addon class in a separate plugin.
  • make it easy to upgrade to more functional features of Eclipse 4 in the future: if you decide to create your own application model, you can simply disconnect the add-on plugin.

I started with the regular RCP Mail Eclipse 3 template and changed the perspective to recreate the problem. This is the Perspective class that I used in my test application:

 import org.eclipse.ui.IPageLayout; import org.eclipse.ui.IPerspectiveFactory; public class Perspective implements IPerspectiveFactory { public static final String ID = "wag.perspective"; public void createInitialLayout(IPageLayout layout) { String editorArea = layout.getEditorArea(); layout.setEditorAreaVisible(true); layout.addStandaloneView(AView.ID, false, IPageLayout.LEFT, 0.25f, editorArea); layout.addStandaloneView(BView.ID, false, IPageLayout.LEFT, 0.25f, editorArea); layout.getViewLayout(AView.ID).setCloseable(false); layout.getViewLayout(BView.ID).setCloseable(false); } } 

Basically, he creates the scenario you described: the arrangement of three columns, where one leaf acts on all three parts, and the other on only two.

Then I moved on to porting the application and changing the application model.

Porting an RCP Application to Eclipse 3 in Eclipse 4

Online tutorials are available for this process. I found Eclipse 4.1: Run your 3.x RCP in 4.1 and Eclipse 4 and the compatibility level is a tutorial to be very useful.

I recommend including org.eclipse.e4.tools.emf.liveeditor and its necessary plugins depending on your product. With a live editor, you can take a look at the application model created by the compatibility level.

As soon as the application starts, these wings will still behave the same. Open the live editor in the application window and take a look at your model.

layout tree created by the compatibility layer

You can see that the PartSashContainer containing the placeholder for AView contains another PartSashContainer . Moving the sash between AView and this container will update the rest of the layout tree by moving the sash between the BView , and the editor does not affect other parts of the layout.

Now you can drag the placeholder for AView to the container where the BView and editor are located. This would instantly create the effect you desire: the flaps would only affect their direct neighbors. But these changes will be saved in only one workspace of the work environment. Something else is needed to change the layout structure.

Change application model at runtime

Since I did not want to touch the source code, if possible, I created another plugin to contribute to the Application Model.

Create a plug-in project without Activator without using a template.

Add Addon class: select New-> Other-> Eclipse 4-> Classes-> New Addon Class

Add Model Fragment : select New-> Other-Eclipse 4-> Model-> New Model Fragment. Open the created fragment.e4xmi file and add Model Fragment . For the item ID, put org.eclipse.e4.legacy.ide.application (this is the standard identifier for legacy applications) and for Featurename addons . Add Addon to Model Fragment . Enter the identifier and set the Class URI to your addon class.

Now add your fragment.e4xmi to your org.eclipse.e4.workbench.model extension point:

 <extension id="id1" point="org.eclipse.e4.workbench.model"> <fragment uri="fragment.e4xmi"> </fragment> </extension> 

Add your plugin for input depending on your application product. When you start your application and look at the model using the live editor, you should see your Addon specified in the model.

Now we can implement Addon . This is the code of my Addon class:

 package wag.contribution.addons; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.inject.Inject; import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.e4.ui.model.application.MApplication; import org.eclipse.e4.ui.model.application.ui.MElementContainer; import org.eclipse.e4.ui.model.application.ui.MUIElement; import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder; import org.eclipse.e4.ui.workbench.modeling.EModelService; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; public class LayoutSorter { @Inject private IEventBroker broker; private EventHandler handler; // The part IDs we are interested in, sorted in the sequence they should be // shown private static List<String> PART_IDS = Arrays.asList(new String[] { "wag.aView", "wag.bView", "org.eclipse.ui.editorss" }); // Listen to the e4 core service event broker to find the magical time // when the application is created and try to sort the layout. @PostConstruct void hookListeners(final MApplication application, final EModelService service) { if (handler == null) { handler = new EventHandler() { // Try to sort the layout. Unsubscribe from event broker if // successful. @Override public void handleEvent(Event event) { try { sort(application, service); // sort did finish: stop listening to the broker. broker.unsubscribe(handler); } catch (Exception e) { // Something went wrong, the application model was not ready yet. // Keep on listening. } } }; // Subscribe "ServiceEvent.MODIFIED" to grab the application.STARTED // event. Does anybody know how to do this in a better way? broker.subscribe("org/osgi/framework/ServiceEvent/MODIFIED", handler); } } private void sort(MApplication application, EModelService service) { // find all placeholders List<MPlaceholder> placeholders = service.findElements(application, null, MPlaceholder.class, null); // only keep the ones we are interested in for (int i = placeholders.size() - 1; i > -1; i--) { if (!PART_IDS.contains(placeholders.get(i).getElementId())) { placeholders.remove(i); } } // find the parents of the placeholders List<MElementContainer<MUIElement>> parents = new ArrayList<>( placeholders.size()); for (MPlaceholder placeholder : placeholders) { parents.add(placeholder.getParent()); } // find the parent that is "deepest down" in the tree MElementContainer<MUIElement> targetParent = null; for (MElementContainer<MUIElement> parent : parents) { for (MUIElement child : parent.getChildren()) { if (parents.contains(child)) { continue; } targetParent = parent; } } // move all parts to the target parent if (targetParent != null) { for (int i = 0; i < placeholders.size(); i++) { if (targetParent != placeholders.get(i).getParent()) { service.move(placeholders.get(i), targetParent, i); } } } } @PreDestroy void unhookListeners() { if (handler != null) { // in case it wasn't unhooked earlier broker.unsubscribe(handler); } } } 

(Note that the code above is a bit hacked because it really only works for this particular problem.)

After rebooting, the application should now behave in its own way. Take a look at the application model to see your changes.

It should be remembered that local changes are saved in the working time area in the .metadata\.plugins\org.eclipse.e4.workbench\workbench.xmi file if saving is enabled, therefore this file must be deleted to recreate an immutable model for testing.

+7
source

I don’t think that you can achieve exactly what you want (so the answers to your questions will be 1. no, 2. no). But there is a third option, which IMO behaves pretty well.

When trying in Eclipse: Start with viewA on the left and editor on the right. Then, when you drag viewB to the right side of viewA, you get the (wrong) setting that you are describing. But then you drag it to the left side of the editor, then you get a different configuration, where dragging the right sash behaves the way you want. Dragging the left frame resizes viewA and Editor and MOVES viewB.

I would say that the code to achieve this would be:

 IFolderLayout areaA = layout.createFolder("A", IPageLayout.LEFT, 0.33f, editorArea); IFolderLayout areaB = layout.createFolder("B", IPageLayout.LEFT, 0.5f, editorArea); 
+2
source

All Articles