简体   繁体   English

如何在Eclipse RCP e4中制作多个窗口

[英]How to make multiple windows in Eclipse RCP e4

We want to achieve an RCP application which may have multiple windows ( MWindow ) for distinct data. 我们想要实现一个RCP应用程序,该应用程序可能具有用于不同数据的多个窗口( MWindow )。 The Windows must be independent (unlike the Eclipse IDE new window menu entry), but it must be possible to copy & paste, drag & drop things from one window into another one. Windows必须是独立的(与Eclipse IDE的新窗口菜单项不同),但是必须可以将内容从一个窗口复制并粘贴,拖放到另一个窗口中。 Imagine an application like Word where you can have multiple documents open. 想象一下像Word这样的应用程序,您可以在其中打开多个文档。 We tried various approaches, but it is quiet difficult to find out the right e4 way: 我们尝试了各种方法,但是很难找到正确的e4方法:

1. Creating a new E4Application for each window 1.为每个窗口创建一个新的E4Application

Our first approach was to create and run a complete new E4Application for each new window. 我们的第一种方法是为每个新窗口创建并运行一个完整的新E4Application。 But this sounds not to be the right e4 way. 但这听起来不是正确的e4方法。 Also it is buggy: Key bindings does not work correct and also the LifecycleManager is called for each new application and therefor for each new window, which should not be. 也是有问题的:按键绑定无法正常工作,而且还为每个新应用程序调用了LifecycleManager ,因此为每个新窗口调用了LifecycleManager ,因此不应如此。

E4Application application = new E4Application();
BundleContext context = InternalPlatform.getDefault().getBundleContext();
ServiceReference<?> appContextService = context.getServiceReference(IApplicationContext.class);
IApplicationContext iac = (IApplicationContext) context.getService(appContextService);
IWorkbench workbench = application.createE4Workbench(iac, display);
 final E4Workbench implementation = (E4Workbench) workbench;
implementation.createAndRunUI(workbench.getApplication());

This seems not the right approach to do it. 这似乎不是正确的方法。

2. The Eclipse IDE approach 2. Eclipse IDE方法

In the Eclipse IDE you can go to the menu and click Window -> New Window which will open a complete new top level window. 在Eclipse IDE中,您可以转到菜单并单击Window -> New Window ,这将打开一个完整的新顶层窗口。 But it is synchronized: Open the same text file in both windows and editing it in the first one will alter it in the other one too. 但是它是同步的:在两个窗口中打开相同的文本文件,然后在第一个窗口中对其进行编辑也会在另一个窗口中对其进行更改。 Albeit we tried that approach by simply copy and pasting it from org.eclipse.ui.actions.OpenInNewWindowAction#run() : 尽管我们通过简单地从org.eclipse.ui.actions.OpenInNewWindowAction#run()复制并粘贴来尝试了该方法:

// Does not work because we do not have the RCP3 workbench in RCP4.
final IWorkbench workbench = PlatformUI.getWorkbench();
final IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow();
final IWorkbenchPage activePage = workbenchWindow.getActivePage();
final String perspectiveId;

if (activePage != null && activePage.getPerspective() != null) {
    perspectiveId = activePage.getPerspective().getId();
} else {
    perspectiveId = workbenchWindow.getWorkbench().getPerspectiveRegistry().getDefaultPerspective();
}

workbenchWindow.getWorkbench().openWorkbenchWindow(perspectiveId, null);

It looks like that the Eclipse IDE uses the RCP3 compatibility layer. 看来Eclipse IDE使用RCP3兼容性层。 We didn't found a way to obtain the IWorkbench object. 我们没有找到获取IWorkbench对象的方法。 Neither by PlatformUI#getWorkbench() , nor via the application context, nor the bundle context. 既不是通过PlatformUI#getWorkbench() ,也不是通过应用程序上下文,也不是通过捆绑软件上下文。

3. Clone the main window 3.克隆主窗口

We stumbled upon Opening multiple instances of an MTrimmedWindow complete with perspectives etc n-mtrimmedwindow-complete-with-perspectives-etc and did a lot of trial and error and came up with this muddy code: 我们偶然发现了一个打开MTrimmedWindow的多个实例的实例,这些实例带有透视图等 n-mtrimmedwindow-complete-with-perspectives-etc等,并进行了大量的试验和错误,并得出了以下代码:

class ElementCloningBasedCreator {

    EModelService models = ...; // injected
    MApplication app = ...; // injected

    public void openNewWindow() {
        MWindow originWindow = (MWindow) models.find("the.main.window.id", app);
        MWindow newWindow = (MWindow) models.cloneElement(originWindow, null);

        MPerspectiveStack newPerspectiveStack =
            (MPerspectiveStack) models.find(the.main.perspective.stack.id, newWindow);
        newPerspectiveStack.setParent((MElementContainer) newWindow);

        addTo(app, newWindow);

        // Clone the shared elements. If we don't do that the rendering somewhere 
        // deep in the rabbit hole throws assertion erros because the recurisve 
        // finding of an element fails because the search root is null.
        for (final MUIElement originSharedElement : originWindow.getSharedElements()) {
            final MUIElement clonedSharedElement = models.cloneElement(originSharedElement, null);
            clonedSharedElement.setParent((MElementContainer) newWindow);
            newWindow.getSharedElements().add(clonedSharedElement);
        }

        cloneSnippets(app, originWindow, newPerspectiveStack, newWindow);
        newWindow.setContext(createContextForNewWindow(originWindow, newWindow));
        newWindow.setToBeRendered(true);
        newWindow.setVisible(true);
        newWindow.setOnTop(true);
        models.bringToTop(newWindow);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void addTo(MElementContainer target, MUIElement child) {
        child.setParent(target);
        target.getChildren().add(child);
    }

    /**
     * Clone each snippet that is a perspective and add the cloned perspective 
     * into the main PerspectiveStack.
     */
    private void cloneSnippets(MApplication app, MWindow originWindow,
        MPerspectiveStack newPerspectiveStack, MWindow newWindow) {
        boolean isFirstSnippet = true;

        for (MUIElement snippet : app.getSnippets()) {
            if (ignoreSnippet(snippet)) {
                continue;
            }

            String snipetId = snippet.getElementId();
            MPerspective clonedPerspective = 
                (MPerspective) models.cloneSnippet(app, snipetId, originWindow);
            findPlaceholdersAndCloneReferencedParts(clonedPerspective, newWindow);
            addTo(newPerspectiveStack, clonedPerspective);

            if (isFirstSnippet) {
                newPerspectiveStack.setSelectedElement(clonedPerspective);
                isFirstSnippet = false;
            }
        }
    }

    private boolean ignoreSnippet(MUIElement snippet) {
        return !(snippet instanceof MPerspective);
    }

    private void findPlaceholdersAndCloneReferencedParts(MPerspective clonedPerspective, MWindow newWindow) {
        List<MPlaceholder> placeholders = 
            models.findElements(clonedPerspective, null, MPlaceholder.class, null);

        for (MPlaceholder placeholder : placeholders) {
            MUIElement reference = placeholder.getRef();

            if (reference != null) {
                placeholder.setRef(models.cloneElement(placeholder.getRef(), null));
                placeholder.getRef().setParent((MElementContainer) newWindow);
            }
        }
    }
}

This code does not really work and we really need some hints/advices how to do it right, because of the lack of official documentation. 由于缺乏官方文档,因此此代码无法真正起作用,我们确实需要一些提示/建议以正确执行操作。 The questions open are: 打开的问题是:

  1. Do we need to clone the shared objects and if not how do we prevent the errors during rendering)? 我们是否需要克隆共享对象,如果不需要,我们如何防止在渲染过程中出现错误?
  2. We only saw code where the cloned elements are added to the parent via getChildren().add() , but we found out that the children din't get the parent automatically and it is null though. 我们只看到了通过getChildren().add()将克隆的元素添加到父元素的代码,但是我们发现子元素不会自动获取父元素,尽管它为null Is it the right pattern to add the parent to the child too? 将父级添加到子级也是正确的模式吗?
  3. We have the deep feeling that we are doing it not right. 我们深感我们做错了。 It looks way too complicated what we do here. 我们在这里所做的事情看起来太复杂了。 Is there a simpler/better approach? 有没有更简单/更好的方法?

You can use the EModelService cloneSnippet method to do this. 您可以使用EModelService cloneSnippet方法来执行此操作。

Design your MTrimmedWindow (or whatever type of window you want) in the Snippets section of the Application.e4xmi. 在Application.e4xmi的“ Snippets部分中设计MTrimmedWindow (或所需的任何窗口类型)。 Be sure that the To Be Rendered and Visible flags are checked. 确保已选中“ To Be RenderedVisible标志。 You may need to set the width and height bounds (and you may want to set the x and y position as well). 您可能需要设置宽度和高度范围(并且可能还需要设置x和y位置)。

Your command handler to create the new window would simply be: 您用于创建新窗口的命令处理程序将是:

@Execute
public void execute(EModelService modelService, MApplication app)
{
  MTrimmedWindow newWin = (MTrimmedWindow)modelService.cloneSnippet(app, "id of the snippet", null);

  app.getChildren().add(newWin);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM