Пользовательские ISaveHandler и IWindowCloseHandler для приложения текстового редактора Eclipse e4

Относится к вопросу "Пользовательское сообщение при закрытии части в Eclipse RCP 4" У меня также есть приложение Eclipse RCP 4 с несколькими частями редактора (реализующими MDirtyable и @Persist).

Части закрываются. Когда пользователь закрывает часть, должно появиться специальное всплывающее окно, которое спрашивает пользователя, действительно ли он хочет сохранить часть или нет.

Также, когда пользователь закрывает приложение, всплывающее окно должно предлагать пользователю закрыть/сохранить грязные части. В основном он предназначен для удаления диалогов закрытия eclipse e4 по умолчанию.

Я реализовал пользовательские ISaveHandler и IWindowCloseHandler, подписанные на событие завершения запуска приложения UIEvents.UILifeCycle.APP_STARTUP_COMPLETE в классе жизненного цикла.

Пользовательский IWindowCloseHandler отлично работает (с точки зрения диалогов), а пользовательский ISaveHandler — нет.

ISaveHandler.save возвращает ошибку stackoverflow, если определено следующим образом:

@Override
public boolean save(MPart dirtyPart, boolean confirm) {
    EPartService partService = dirtyPart.getContext().get(EPartService.class);
    //Try to close the part and save the document to disc by 
    //calling the @Persist method
    return partService.savePart(dirtyPart, confirm);

}

Я прикрепил полный класс LifeCycleManager:

public class LifeCycleManager {
@Inject IEventBroker eventBroker;

@ProcessAdditions
public void processAdditions(MApplication application, EModelService modelService){
     MWindow window =(MWindow)modelService.find("application-trimmedwindow", application);
     eventBroker.subscribe(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE,
                          new AppStartupCompleteEventHandler(window, modelService, application));
}
public class AppStartupCompleteEventHandler implements EventHandler {
    private MWindow theWindow;
    private MApplication app;
    private ISaveHandler saveHandler;

    AppStartupCompleteEventHandler(MWindow window, EModelService modelService, MApplication application){
        theWindow = window;
        app = application;
    }

    @Override
    public void handleEvent(Event event) {
        theWindow.getContext().set(ISaveHandler.class, new ISaveHandler() {
            @Override
            public boolean save(MPart dirtyPart, boolean confirm) {
                System.out.println("PARTE PARA SALVAR..." + dirtyPart.getLabel());
                EPartService partService = dirtyPart.getContext().get(EPartService.class);
                //partService.hidePart(dirtyPart,true);
                return partService.savePart(dirtyPart, confirm);
                //return true;
            }

            @Override
            public boolean saveParts(Collection<MPart> dirtyParts, boolean confirm) {
                return false;
            }
            @Override
            public Save promptToSave(MPart dirtyPart) {
                return promptToSaveDialog(dirtyPart);
            }
            @Override
            public Save[] promptToSave(Collection<MPart> dirtyParts) {
                return null;
            }
        });
        saveHandler  = (ISaveHandler)theWindow.getContext().get(ISaveHandler.class);
        theWindow.getContext().set(IWindowCloseHandler.class, new IWindowCloseHandler() {
            @Override
            public boolean close(MWindow window) {
                List<MHandler> listHandlers = window.getHandlers();
                System.out.println(listHandlers.size());
                Shell shell = (Shell) window.getWidget();
                if (MessageDialog.openConfirm(shell, "Close Nastran Editor", "Do you really want to close the entire application?")) {
                    Collection<EPartService> allPartServices = getAllPartServices(app);
                    if (containsDirtyParts(allPartServices)) {
                        return iterateOverDirtyParts( allPartServices);
                    }
                else {
                    return true;
                }
            }
            return false;
        }});
}
private Collection<EPartService> getAllPartServices(MApplication application) {
    List<EPartService> partServices = new ArrayList<EPartService>();
    EModelService modelService = application.getContext().get(EModelService.class);
    List<MWindow> elements = modelService.findElements(application, MWindow.class, EModelService.IN_ACTIVE_PERSPECTIVE,
            new ElementMatcher(null, MWindow.class, (List<String>) null));
    for (MWindow w : elements) {
        if (w.isVisible() && w.isToBeRendered()) {
            EPartService partService = w.getContext().get(EPartService.class);
            if (partService != null) {
                partServices.add(partService);
            }
        }
    }
    return partServices;
}
private boolean containsDirtyParts(Collection<EPartService> partServices) {
    for (EPartService partService : partServices) {
        if (!partService.getDirtyParts().isEmpty()) return true;
    }
    return false;
}
private  boolean iterateOverDirtyParts(Collection<EPartService> allPartServices) {
    for (EPartService partService : allPartServices) {
        Collection<MPart> dirtyParts = partService.getDirtyParts();
        for(MPart dirtyPart : dirtyParts) {
            switch(saveHandler.promptToSave(dirtyPart)) {
                case NO: break;
                case YES:
                    saveHandler.save(dirtyPart, false);
                    break;
                case CANCEL:return false;
            }
        }
    }
    return true;
}
private Save promptToSaveDialog(MPart dirtyPart) {
    MessageDialog dialog = new MessageDialog( (Shell)theWindow.getWidget(), "Save file", null,
            "'"+dirtyPart.getLabel()+"' has been modified. Save changes?", MessageDialog.QUESTION, new String[] { "YES", "NO", "CANCEL" }, 0);
        switch (dialog.open()){
            case 0: return Save.YES;
            case 1: return Save.NO;
            case 2: return Save.CANCEL;
            default:return Save.CANCEL;
        }
}
}
}///END of LifeCycleManager

person J Robes    schedule 30.08.2017    source источник


Ответы (1)


Метод save для ISaveHandler вызывается из метода EPartService savePart, поэтому вы не можете снова вызвать savePart.

Вместо этого вы должны просто вызвать метод @Persist части. Итак, что-то вроде:

@Override
public boolean save(final MPart dirtyPart, final boolean confirm)
{
  if (confirm)
   {
     switch (promptToSave(dirtyPart))
     {
       default:
       case NO:
         return true;
       case CANCEL:
         return false;
       case YES:
         break;
     }
   }

  try
   {
     ContextInjectionFactory.invoke(dirtyPart.getObject(), Persist.class, dirtyPart.getContext());
   }
  catch (final InjectionException ex)
   {
     // TODO ignore or log error
   }

  return true;
}
person greg-449    schedule 30.08.2017