Добавьте прослушиватель SWT.OpenDocument SWT в E4Application приложения RCP - PullRequest
0 голосов
/ 06 мая 2020

Я хотел бы использовать функцию launcher.openfile в eclipse. Поэтому я прочитал несколько документов (например, https://help.eclipse.org/2020-03/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Fguide%2Fproduct_open_file.htm). Я правильно реализовал настраиваемый класс Application, но в содержимом этого класса что-то не хватает, я думаю, потому что в моем классе LifeCycle главное окно больше не может быть найдено, который обычно можно найти, когда я использую стандартное приложение E4Application.

Как я могу использовать общие функции класса E4Application, добавляя только SWT Listener SWT.OpenDocument.

Здесь мой код приложения:

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());


    ...
}

EDIT

Я реализовал ваше решение @ greg-449 с помощью функции PostContextCreate в моем жизненном цикле и EventloopAdvisor. Но я обнаружил странную ошибку: это решение работает ТОЛЬКО при открытии диалогового окна до или после реализации слушателя в 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);
}

Класс LicenseAgreementDialog открывает диалоговое окно только один раз перед запуском приложения RCP (открывается во время загрузки экрана-заставки), а после запуска приложения событие SWT.OpenDocument должным образом запускается другими файлами проекта с двойным щелчком. Но когда я закрываю приложение rcp и снова запускаю его, LicenseAgreementDialog снова не открывается правильно, а затем больше нет событий SWT.OpenDocument, которые запускаются. Я протестировал эту ошибку и пришел к решению, что мне всегда нужно открывать диалог в @PostContextCreateFunction, иначе событие SWT.OpenDocument не запускается. Я тестировал его также с обычным MessageDialog (-> MessageDialog.openInformation(new Shell(Display.getCurrent()), "Opening", "Now");) вместо LicenseAgreementDialog, который открывается каждый раз при запуске, который работает, но без какого-либо диалога, прежде чем он не будет.

Есть ли есть ли шанс избежать открытия фиктивного диалога для запуска события?

ОКОНЧАТЕЛЬНОЕ редактирование

После множества проб и ошибок я наконец нашел приемлемое решение, чтобы избежать этот фиктивный диалог в начале: я использовал подсказку с добавлением al oop readAndDispatch до его false, но только этот l oop не имеет значения. Мне пришлось добавить второй l oop, который ждет, пока 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);
    }

С этими двумя циклами событие SWT.OpenDocument всегда запускается правильно, даже если я этого не сделаю. показывать диалог раньше. Спасибо за помощь @ greg-449.

И вот небольшая подсказка, которую я уже имел: файл .ini должен иметь атрибут -name, который должен соответствовать метке главного окна автономного приложения RCP, когда вы используйте функцию openfile с событием SWT.OpenDocument (для меня я использую название продукта в качестве метки окна):

, когда метка вашего главного окна, например: My Rcp App

тогда ваш файл launcher.ini должен иметь свойство -name с той же строкой:

--launcher.defaultAction
openFile
-name
My Rcp App

или вы используете переменную для имени продукта вашего приложения rcp:

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

1 Ответ

1 голос
/ 06 мая 2020

Использование PlatformUI.createAndRunWorkbench делает ваш RCP режим совместимости 3.x RCP, который использует LegacyIDE.e4xmi, поэтому ваше окно не обнаруживается.

Я думаю, что для чистого E4 RCP вы, вероятно, можете просто настроить слушателя в LifeCycle и используйте IEventLoopAdvisor.

Итак, удалите MyE4Application и используйте стандартное E4Application. ApplicationWorkbenchAdvisor также должен быть удален.

Настройте вещи в LifeCycle @PostContextCreate

@PostContextCreate
public void postContextCreate(final IEclipseContext context)
{
  OpenDocumentEventProcessor openDocProcessor = new OpenDocumentEventProcessor();

  Display display = Display.getCurrent();

  display.addListener(SWT.OpenDocument, openDocProcessor);

  IEventLoopAdvisor eventLoopAdvisor = new EventLoopAdvisor(openDocProcessor);

  context.set(IEventLoopAdvisor.class, eventLoopAdvisor);
}

и используйте советник по событию l oop, например:

@SuppressWarnings("restriction")
class EventLoopAdvisor implements IEventLoopAdvisor
{
  private final OpenDocumentEventProcessor openDoc;

  EventLoopAdvisor(OpenDocumentEventProcessor openDoc)
  {
    this.openDoc = openDoc;
  }


  @Override
  public void eventLoopIdle(final Display display)
  {
    openDoc.openFiles();

    display.sleep();
  }


  @Override
  public void eventLoopException(final Throwable exception)
  {
    // TODO handle errors
  }
}
...