我想使用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%...
PlatformUI.createAndRunWorkbench
使您的RCP成为3.x兼容模式RCP,该模式使用LegacyIDE.e4xmi,因此找不到您的窗口。我认为对于纯e4 RCP,您可能只需在LifeCycle中设置侦听器并使用IEventLoopAdvisor
。