view com.redhat.thermostat.tools.eclipse.plugin/src/com/redhat/thermostat/tools/eclipse/plugin/editor/MultiPageEditor.java @ 98:c3002fd38e27

Fix dirty state handling for edit pages
author Omair Majid <omajid@redhat.com>
date Fri, 07 Feb 2014 12:57:54 -0500
parents 8f2dd0dbdb87
children
line wrap: on
line source

package com.redhat.thermostat.tools.eclipse.plugin.editor;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Objects;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.IFormPage;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.wst.sse.ui.StructuredTextEditor;

import com.redhat.thermostat.tools.eclipse.plugin.model.Plugin;
import com.redhat.thermostat.tools.eclipse.plugin.model.PluginModelReaderWriter;

public class MultiPageEditor extends FormEditor implements IResourceChangeListener {

    private static final int INDEX_SOURCE = 3;

    private StructuredTextEditor editor;

    /**
     * Helps synchronizing changes between editor and model. Not related to
     * {@code isDirty()}.
     */
    private boolean editorIsDirty = false;

    private PluginModelReaderWriter modelHelper;
    private Plugin model;

    private int oldPage = -1;

    public MultiPageEditor() {
        super();
        ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
    }

    @Override
    public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException {
        if (!(editorInput instanceof IFileEditorInput))
            throw new PartInitException("Invalid Input: Must be IFileEditorInput"); //$NON-NLS-1$
        super.init(site, editorInput);

        try {
            IFile file = ((IFileEditorInput)getEditorInput()).getFile();
            modelHelper = new PluginModelReaderWriter(file);
            model = modelHelper.loadModel(file.getContents());
            Objects.requireNonNull(model);
        } catch (CoreException e) {
            e.printStackTrace();
        }

    }

    @Override
    protected void addPages() {
        try {
            OverviewPage overview = new OverviewPage(this, modelHelper.getPluginName());
            addPage(overview);

            CommandsPage commandsPage = new CommandsPage(this, model);
            addPage(commandsPage);

            ExtensionsPage extensionsPage = new ExtensionsPage(this, model);
            addPage(extensionsPage);

            createSourcePage();
        } catch (PartInitException pie) {
            throw new RuntimeException(pie);
            // ErrorDialog.openError(getSite().getShell(),
            //     "Error creating nested text editor", null, e.getStatus());

        }
    }

    void createSourcePage() throws PartInitException {
        editor = new StructuredTextEditor();
        addPage(editor, getEditorInput());
        setPageText(INDEX_SOURCE, editor.getTitle());

        getDocument().addDocumentListener(new IDocumentListener() {

            @Override
            public void documentChanged(DocumentEvent event) {
                editorIsDirty = true;
            }

            @Override
            public void documentAboutToBeChanged(DocumentEvent event) {
                // nothing to do
            }
        });
    }

    @Override
    public void dispose() {
        ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
        super.dispose();
    }

    @Override
    protected void pageChange(int newPageIndex) {
        if (oldPage != -1) {
            if (oldPage == INDEX_SOURCE && editorIsDirty) {
                updateModelFromSource();
            } else if (newPageIndex == INDEX_SOURCE) {
                updateSourceFromModel();
            }
        }

        super.pageChange(newPageIndex);

        oldPage = newPageIndex;
    }

    @Override
    public void doSave(IProgressMonitor monitor) {
        if (getActivePage() != INDEX_SOURCE) {
            updateSourceFromModel();
        }

        // save all the pages. this doesn't really do the saving, but tells each
        // page that it is being saved, so they can get a chance to update the
        // model and deal with changes
        Iterator iter = pages.iterator();
        while (iter.hasNext()) {
            Object obj = iter.next();

            if (obj instanceof IFormPage) {
                ((IFormPage) obj).doSave(monitor);
            }
        }

        // actually save the model
        editor.doSave(monitor);
    }

    @Override
    public boolean isSaveAsAllowed() {
        return false;
    }

    @Override
    public void doSaveAs() {
        throw new AssertionError("SaveAs is not allowed"); //$NON-NLS-1$
    }

    private void updateSourceFromModel() {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        modelHelper.saveModel(model, baos);
        String modelSource = new String(baos.toByteArray(), StandardCharsets.UTF_8);

        if (!getDocument().get().equals(modelSource)) {
            getDocument().set(modelSource);
        }

        editorIsDirty = false;
    }

    private void updateModelFromSource() {
        model = modelHelper.loadModel(getDocument().get());

        editorIsDirty = false;
    }

    private IDocument getDocument() {
        return editor.getDocumentProvider().getDocument(editor.getEditorInput());
    }

    /**
     * Closes all project files on project close.
     */
    public void resourceChanged(final IResourceChangeEvent event) {
        if (event.getType() == IResourceChangeEvent.PRE_CLOSE) {
            Display.getDefault().asyncExec(new Runnable() {
                public void run() {
                    IWorkbenchPage[] pages = getSite().getWorkbenchWindow()
                            .getPages();
                    for (int i = 0; i < pages.length; i++) {
                        if (((FileEditorInput) editor.getEditorInput())
                                .getFile().getProject()
                                .equals(event.getResource())) {
                            IEditorPart editorPart = pages[i].findEditor(editor
                                    .getEditorInput());
                            pages[i].closeEditor(editorPart, true);
                        }
                    }
                }
            });
        }
    }

}