将SWT.OpenDocument SWT侦听器添加到RCP应用程序的E4Application

问题描述 投票:0回答:1

我想使用eclipse的launcher.openfile功能。因此,我阅读了一些文档(例如https://help.eclipse.org/2020-03/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Fguide%2Fproduct_open_file.htm)我正确实现了一个自定义的Application类,但是该类的内容缺少我想的东西,因为在LifeCycle类中不再可以找到主窗口,通常在使用标准E4Application时可以找到。

如何仅通过添加SWT侦听器SWT.OpenDocument来使用E4Application类的通用功能。

这里是我的申请代码:

package de.port.dsntool.ui.services;

import org.eclipse.core.runtime.IProduct;
import org.eclipse.core.runtime.Platform;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;

public class MyE4Application implements IApplication{

    //Application with Listener to SWT.OpenDocument
    private Display display = null;

    public Display getApplicationDisplay() {
        if (display == null) {
            display = Display.getDefault();
        }
        return display;
    }

    @Override
    public Object start(IApplicationContext context) throws Exception {
        System.out.println("START My Application");
        OpenDocumentEventProcessor openDocProcessor = 
                new OpenDocumentEventProcessor();

        IProduct product = Platform.getProduct();
        if (product != null && product.getName() != null) {
            Display.setAppName(product.getName());
        }
        Display display = getApplicationDisplay();
        display.addListener(SWT.OpenDocument, openDocProcessor);

        try {
            int returnCode = PlatformUI.createAndRunWorkbench(display, new 
                    ApplicationWorkbenchAdvisor(openDocProcessor));

            if (returnCode == PlatformUI.RETURN_RESTART) {
                return IApplication.EXIT_RESTART;
            }
            return IApplication.EXIT_OK;
        } finally {
            if (display != null)
                display.dispose();
        }
    }

    @Override
    public void stop() {
        // TODO Auto-generated method stub

    }

}

ApplicationWorkbenchAdvisor.java:

package my.package;

import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.application.WorkbenchAdvisor;

public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
    private OpenDocumentEventProcessor openDocProcessor;

    public ApplicationWorkbenchAdvisor(
            OpenDocumentEventProcessor openDocProcessor) {
        this.openDocProcessor = openDocProcessor;
    }


    @Override
    public void eventLoopIdle(Display display) {
        openDocProcessor.openFiles();
        super.eventLoopIdle(display);
    }


    @Override
    public String getInitialWindowPerspectiveId() {
        // TODO Auto-generated method stub
        return null;
    }
}

OpenDocumentEventProcessor.java:

package my.package;

import java.util.ArrayList;

import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;

public class OpenDocumentEventProcessor implements Listener {
    private ArrayList<String> filesToOpen = new ArrayList<String>(1);

    @Override
    public void handleEvent(Event event) {
        if (event.text != null)
            filesToOpen.add(event.text);
    }

    public void openFiles() {
        if (filesToOpen.isEmpty())
            return;

        String[] filePaths = filesToOpen.toArray(
            new String[filesToOpen.size()]);
        filesToOpen.clear();

        for (String path : filePaths) {
            // open the file path
        }
    }
}

LifeCycle.java ProcessAdditions代码段:

/**
 * Method to be invoked on ProcessAdditions life-cycle moment.
 * 
 * @param context Eclipse context.
 */
@ProcessAdditions
public void processAdditons(MApplication app, EModelService modelService,
        final IEclipseContext context,
        final IBrandingInfo branding) {
    /*obtain logger from context and publish it
     * to objects that require it*/
    final Logger logger = context.get(Logger.class);
    if (logger != null) {
        ProblemRegistry.INSTANCE.setLogger(logger);
    }

    /*obtain extension registry from context and publish
     * it to objects that require it*/
    final IExtensionRegistry registry = context
            .get(IExtensionRegistry.class);
    if (registry != null) {
        ProjectRegistry.INSTANCE.setExtensionRegistry(registry);
    }

    /* Push help service into context. */
    context.set(HelpService.class, new HelpServiceImpl(registry));


    MWindow window = (MWindow)modelService.find("my.package2.app.trimmedwindow.0", app);
    System.out.println("app: " + app);
    System.out.println("modelService: " + modelService);
    System.out.println("window: " + window);
    //ERROR: window is null here which is normally not when using standard E4Application
    window.setLabel(branding.getWindowTitle());


    ...
}

编辑

我在生命周期和EventloopAdvisor中使用PostContextCreate函数实现了您的解决方案@ greg-449。但是我发现了一个奇怪的错误:该解决方案仅在在PostContextCreate中实现侦听器之前或之后打开对话框时有效。

这是我生命周期中的实际代码段:

@PostContextCreate
public void postContextCreate(final IEclipseContext context) {
    final Shell shell = new Shell(Display.getCurrent());
    new LicenseAgreementDialog(shell).open();

    if(!shell.isDisposed())
        shell.dispose();

    OpenDocumentEventProcessor openDocProcessor = new OpenDocumentEventProcessor();
    Display display = Display.getCurrent();
    display.addListener(SWT.OpenDocument, openDocProcessor);
    IEventLoopAdvisor eventLoopAdvisor = new EventLoopAdvisor(openDocProcessor);
    context.set(IEventLoopAdvisor.class, eventLoopAdvisor);
}

Class LicenseAgreementDialog仅在启动RCP应用程序之前(在启动启动画面加载时打开)打开一个对话框,而在应用程序启动之后,由其他双击的项目文件正确触发了SWT.OpenDocument事件。但是,当我关闭rcp应用程序并再次启动它时,LicenseAgreementDialog没有正确打开,因此没有任何SWT.OpenDocument事件被触发。我通过此错误进行了测试,得出了必须始终在@PostContextCreateFunction中打开对话框的解决方案,否则不会触发SWT.OpenDocument事件。我也用普通的MessageDialog(-> MessageDialog.openInformation(new Shell(Display.getCurrent()), "Opening", "Now");)进行了测试,而不是每次启动时都打开的LicenseAgreementDialog,但此之前没有任何对话框。

是否有可能避免始终打开虚拟对话框来触发事件?

最终编辑

经过大量的试验和错误,我终于找到了一个可以避免的解决方案,可以避免在启动时出现这个虚假的Dialog:我在提示中添加了一个readAndDispatch循环,直到其为false为止,但仅此循环没有任何作用。我必须添加第二个循环,以等待readAndDispatch返回true。我以不同的顺序测试了这两个循环,依此类推,但这是唯一有效的解决方案:

@PostContextCreate
    public void postContextCreate(final IEclipseContext context,
            final IEventBroker eventBroker) {
        final Shell shell = new Shell(Display.getCurrent());
        new LicenseAgreementDialog(shell).open();

        /*check for clicked project file or only launcher.exe
         * when only launcher.exe is clicked there are no cmd arguments
         * when project file is double clicked and gets opened by file handler
         * the one and only cmd arg is the filepath from the clicked project file */
        if(Platform.getCommandLineArgs().length != 0) {
            while(Display.getCurrent().readAndDispatch()) { /* wait for false */ }
            while(!Display.getCurrent().readAndDispatch()) { /* wait for true */ }
        }

        if(!shell.isDisposed())
            shell.dispose();

        OpenDocumentEventProcessor openDocProcessor = new OpenDocumentEventProcessor(eventBroker);
        Display display = Display.getCurrent();
        display.addListener(SWT.OpenDocument, openDocProcessor);
        IEventLoopAdvisor eventLoopAdvisor = new EventLoopAdvisor(openDocProcessor);
        context.set(IEventLoopAdvisor.class, eventLoopAdvisor);
    }

通过这两个循环,即使我之前没有显示Dialog,也总是会正确触发SWT.OpenDocument事件。感谢您的帮助@ greg-449。

[这是我已经有的一个小提示:.ini文件必须具有-name属性,当您在SWT.OpenDocument事件中使用openfile功能时,该属性必须与您的独立RCP应用程序主窗口标签匹配(对我来说使用产品名称作为窗口标签):

当您的主窗口标签为例如:我的Rcp应用

然后,launcher.ini文件必须具有具有相同字符串的-name属性:

--launcher.defaultAction
openFile
-name
My Rcp App

或您将变量用作rcp应用程序的产品名称:

--launcher.defaultAction
openFile
-name
%product.name

我想使用eclipse的launcher.openfile功能。因此,我阅读了一些文档(例如https://help.eclipse.org/2020-03/index.jsp?topic =%2Forg.eclipse.platform.doc.isv%2Fguide%...

java eclipse eclipse-rcp e4
1个回答
1
投票
使用PlatformUI.createAndRunWorkbench使您的RCP成为3.x兼容模式RCP,该模式使用LegacyIDE.e4xmi,因此找不到您的窗口。

我认为对于纯e4 RCP,您可能只需在LifeCycle中设置侦听器并使用IEventLoopAdvisor

© www.soinside.com 2019 - 2024. All rights reserved.