Thomas
Thomas

Reputation: 1

Eclipse EditorPart save on partDeactivated

My problem is that I have a custom application, using EditorParts, which are persisted to a database. The user can open several Editors, and switch between them. I need to ask the user to save any unsaved changes in an Editor, before switching to the next Editor (or else close it).

I have created an IPartListener2, and I receive the partDeactivated notification. If isDirty()==true, I bring up a MessageDialog asking to save or not; because I want to call editor.doSave().

My problem is that does not work. I never see the MessageDialog, because another partDeactivated fires. I guess, this is caused by the MessageDialog over the Editor.

I have researched How to listen to lose focus event of a part in Eclipse E4 RCP?, but that did not help me.

thanks to help a e4 beginner

public class DatasetAttachmentEditor {
        ... // code here
    @Override
    public void init(IEditorSite site, IEditorInput input)  throws PartInitException {
        ... // code here
        site.getPage().addPartListener(new EditorsPartListener(this));
    }
}

public class EditorsPartListener implements IPartListener2 {

    private IEditorPart editor;

    public EditorsPartListener(IEditorPart editor) {
        this.editor = editor;
    }

    @Override
    public void partClosed(IWorkbenchPartReference partRef) {
        if (partRef.getPage().getActiveEditor().getClass().getName().equals(editor.getClass().getName())) {
            partRef.getPage().removePartListener(this);
        }
    }

    @Override
    public void partDeactivated(IWorkbenchPartReference partRef) {

        if (!partRef.getClass().getName().equals("org.eclipse.ui.internal.EditorReference")) {
            System.out.println("partDeactivated: not a Editor="+partRef.getClass().getName());
            return;
        }

        if (!editor.isDirty()) {
            // if the editor is not dirty - do nothing
            return;
        }

        // ask if to save
        int choice = EditorPartSaveDialog(partRef.getPage().getActiveEditor());
        if(choice == MessageDialog.OK) {
            // save the Editor
            try {
                ProgressMonitorDialog progress = new ProgressMonitorDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());                
                progress.setCancelable(false);
                progress.run(false, false, new IRunnableWithProgress() {
                    @Override
                    public void run(IProgressMonitor monitor) {
                        // do the save
                        editor.doSave(monitor);
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        else {
            // don't save: just close it
            partRef.getPage().closeEditor(editor, false);
        }
    }

    @Override
    public void partActivated(IWorkbenchPartReference partRef) {
    }

    @Override
    public void partBroughtToTop(IWorkbenchPartReference partRef) {
    }

    @Override
    public void partOpened(IWorkbenchPartReference partRef) {
    }

    @Override
    public void partHidden(IWorkbenchPartReference partRef) {
    }

    @Override
    public void partVisible(IWorkbenchPartReference partRef) {
    }

    @Override
    public void partInputChanged(IWorkbenchPartReference partRef) {
    }

    /**
     * Asks the user to Save changes
     * @param editor
     * @return MessageDialog.OK to save, MessageDialog.CANCEL otherwise
     */
    private int EditorPartSaveDialog(IEditorPart editor) {

        // If save confirmation is required ..
        String message = NLS.bind("''{0}'' has been modified. Save changes?", LegacyActionTools.escapeMnemonics(editor.getTitle()));

        // Show a dialog.
        MessageDialog d = new MessageDialog(
                            Display.getCurrent().getActiveShell(),
                            "Save Editor", null, message,
                            MessageDialog.QUESTION,
                            0,
                            "Save",// MessageDialog 0x0 (OK)
                            "Don't Save: close"// MessageDialog 0x1 (CANCEL)
                        )
        return d.open();
    }
}

Upvotes: 0

Views: 262

Answers (2)

Thomas
Thomas

Reputation: 1

I have found a great solution, using the suggestions above and Enumerating all my Eclipse editors? I am checking all editors first, then all persisted editors - skipping itself and the persisted objects.

Thanks for your comments!

public class ConceptAcronymValidator implements IValidator { 

    private ConceptInstanceEditor myEditor;

    public ConceptAcronymValidator(ConceptInstanceEditor editor) {
        super();
        this.myEditor = editor;
    }

    @Override
    public IStatus validate(Object value) {


        // check all Editors
        for (IEditorReference editorRef: PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getEditorReferences()) {
            IEditorPart editor = editorRef.getEditor(false);
            if (editor != null) {
                // don't check our own Editor
                if (!editor.equals(myEditor)) {
                    ConceptInstanceEditor conceptEditor = (ConceptInstanceEditor)editor;
                    if (conceptEditor.getTxtAcronym().equals(value.toString())) {
                        return ValidationStatus.error("This Concept is already used by Editor <"+
                                conceptEditor.getConceptModel().getName().getValue(MultilingualString.EN)+
                                ">");
                    }
                }
            }
        }

        // check all persisted Concepts
        List<Concept> concepts = ReferenceServiceFactory.getService().getConcepts();
        for (Concept concept: concepts) {
            Concept myConcept = (Concept) myEditor.getConceptModel().getInstance();
            // check if a new Editor
            if (myConcept == null) {
                if (concept.getAcronym().equals(value.toString())) {
                    return ValidationStatus.error("This Concept is already used by <"+
                            concept.getName().getValue(MultilingualString.EN)+
                            ">");
                }
            }
            else {
                // don't check own Instance
                if (!concept.equals(myConcept)) {
                    if (concept.getAcronym().equals(value.toString())) {
                        return ValidationStatus.error("This Concept is already used by <"+
                                concept.getName().getValue(MultilingualString.EN)+
                                ">");
                    }   
                }
            }
        }

        return Status.OK_STATUS;
    }
}

Upvotes: 0

greg-449
greg-449

Reputation: 111142

You probably need to run your code after the deactivate event has finished. You can do this using Display.asyncExec.

Something like:

@Override
public void partDeactivated(IWorkbenchPartReference partRef) {

    if (!partRef.getClass().getName().equals("org.eclipse.ui.internal.EditorReference")) {
        System.out.println("partDeactivated: not a Editor="+partRef.getClass().getName());
        return;
    }

    if (!editor.isDirty()) {
        // if the editor is not dirty - do nothing
        return;
    }

    Display.getDefault().asyncExec(() ->
      {
        // TODO the rest of your deactivate code goes here
      });
}

(Above code assumes you are using Java 8 or later)

This is 3.x compatibility mode code, not e4.

Upvotes: 1

Related Questions