Give Each Editor Its Own Perspective

62 views Asked by At

I have a couple of editors with some detail views each that aren't relevant for the other editors. In fact, the customer doesn't want them there because they confuse them.

So I want to toggle the visibility of the views and thought the build-in perspectives in Eclipse might do the trick. I created a IPartListener like this:

public class ToEachTheirOwnPartListener implements IPartListener {

    private final Map<IWorkbenchPart, String> partToPerspectiveId = new IdentityHashMap<>(5);

    @Override
    public void partOpened(IWorkbenchPart part) {
        if (hasOwnPerspective(part)) {
            String perspectiveId = cloneEditorPerspective(part);
            this.partToPerspectiveId.put(part, perspectiveId);
        }
    }

    private static boolean hasOwnPerspective(IWorkbenchPart part) {
        return part instanceof IEditorPart;
    }

    String cloneEditorPerspective(IWorkbenchPart part) {
        final IPerspectiveRegistry registry = PlatformUI.getWorkbench().getPerspectiveRegistry();
        IWorkbenchPage page = part.getSite().getPage();
        // more later
    }

    @Override
    public void partBroughtToTop(IWorkbenchPart part) {
        if (hasOwnPerspective(part)) {
            final IPerspectiveRegistry registry = PlatformUI.getWorkbench().getPerspectiveRegistry();
            part.getSite().getPage().setPerspective(registry.findPerspectiveWithId(this.partToPerspectiveId.get(part)));
        }
    }

    @Override
    public void partClosed(IWorkbenchPart part) {
        if (hasOwnPerspective(part)) {
            final IPerspectiveRegistry registry = PlatformUI.getWorkbench().getPerspectiveRegistry();
            registry.deletePerspective(registry.findPerspectiveWithId(this.partToPerspectiveId.get(part)));
            this.partToPerspectiveId.remove(part);
        }
    }
}

I'm struggeling with the cloneEditorPerspective() method because allmost all methods are not implemented in E4 or plain buggy.

What I want to do is to just clone an existing perspective like this (okay honestly I would rather use IPerspectiveRegistry#clonePerspective but... E4):

page.savePerspectiveAs(page.getPerspective());

String defaultPerspectiveId = PlatformUI.getWorkbench().getPerspectiveRegistry().getDefaultPerspective();
final IPerspectiveDescriptor defaultPerspective = registry.findPerspectiveWithId(defaultPerspectiveId);
IPerspectiveDescriptor clone = ((PerspectiveRegistry) registry).createPerspective(UUID.randomUUID().toString(),
        (PerspectiveDescriptor) defaultPerspective);

But that throws the following exception (evidently the field PerspectiveDescriptor.configElement is null for the cloned perspective):

java.lang.NullPointerException at org.eclipse.ui.internal.registry.PerspectiveDescriptor.createFactory(PerspectiveDescriptor.java:74) at org.eclipse.ui.internal.WorkbenchPage.setPerspective(WorkbenchPage.java:4053) at ToEachTheirOwnPartListener.partBroughtToTop(ToEachTheirOwnPartListener.java:65)

I could add page.savePerspectiveAs(clone) to remove the exception, but then for reasons that are completely beyond me not the default perspective is cloned but the currently active one.

So another try; we set the application to an empty perspective, then clone this one:

IPerspectiveDescriptor perspective = registry.findPerspectiveWithId("org.acme.plugin.perspective");
window.getActivePage().setPerspective(perspective);
IPerspectiveDescriptor clone = ((PerspectiveRegistry) registry).createPerspective(UUID.randomUUID().toString(),
        (PerspectiveDescriptor) page.getPerspective());
page.savePerspectiveAs(clone);

That code works, but clones all views.

If I close the views manually all hell breaks lose with something like that:

java.lang.NullPointerException at org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem.canExecuteItem(HandledContributionItem.java:808) at org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem.access$1(HandledContributionItem.java:802) at org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem$3.run(HandledContributionItem.java:167) at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)

All variations I have tried seem to come down to these three: NPE, cloning the wrong perspective or duplicating the views.

Is there a way to give every editor its own perspective? If so, how?

1

There are 1 answers

0
Stefan S. On BEST ANSWER

Evidently the trick is to only clone the currently active perspective. Which means to switch to an empty perspective and then clone:

    // we save the current perspective
    IPerspectiveDescriptor currentPerspective = page.getPerspective();
    if (currentPerspective != null) {
        // E4 sometimes lacks perspective
        page.savePerspectiveAs(currentPerspective);
    }

    // switch to the default one (should never have views)
    String defaultPerspectiveId = PlatformUI.getWorkbench().getPerspectiveRegistry().getDefaultPerspective();
    final IPerspectiveDescriptor defaultPerspective = registry.findPerspectiveWithId(defaultPerspectiveId);
    page.setPerspective(defaultPerspective);

    // clone it
    IPerspectiveDescriptor clone = ((PerspectiveRegistry) registry).createPerspective(String.valueOf(this.nextId++),
            (PerspectiveDescriptor) defaultPerspective);
    page.savePerspectiveAs(clone);

There are still a bunch of random NPEs because the perspective is null, but that's how E4 rolls.