org.wesnoth.ui.editor.WMLEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.wesnoth.ui.editor.WMLEditor.java

Source

/*******************************************************************************
 * Copyright (c) 2010 - 2013 by Timotei Dolean <timotei21@gmail.com>
 * 
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/
package org.wesnoth.ui.editor;

import java.io.File;

import org.apache.log4j.Level;

import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.ui.URIEditorInput;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IURIEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.FileStoreEditorInput;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.xtext.ui.editor.XtextEditor;
import org.eclipse.xtext.ui.editor.syntaxcoloring.HighlightingHelper;
import org.eclipse.xtext.ui.editor.utils.EditorUtils;

import org.wesnoth.Logger;
import org.wesnoth.WesnothPlugin;
import org.wesnoth.ui.Messages;

/**
 * The main WML Editor
 */
public class WMLEditor extends XtextEditor {
    private final static boolean DEBUG = false;

    protected static final String AUTOLINK_PROJECT_NAME = "_AutoLinked_CFGExternalFiles_"; //$NON-NLS-1$
    protected static final String ENCODING_UTF8 = "utf-8"; //$NON-NLS-1$

    protected HighlightingHelper highlightingHelper_;

    /**
     * Creates a new WML Editor
     */
    public WMLEditor() {
        super();
        if (DEBUG) {
            org.apache.log4j.Logger.getLogger(XtextEditor.class).setLevel(Level.DEBUG);
        }
        // activate the wesnoth plugin
        WesnothPlugin.getDefault();
    }

    /**
     * @return Returns the current {@link HighlightingHelper} instance
     */
    public HighlightingHelper getHighlightingHelper() {
        return highlightingHelper_;
    }

    @Override
    public boolean equals(Object obj) {
        if ((obj instanceof XtextEditor) == false) {
            return false;
        }
        if (getEditorInput() == null || ((XtextEditor) obj).getEditorInput() == null) {
            return false;
        }
        java.net.URI u1 = ((IURIEditorInput) getEditorInput()).getURI();
        java.net.URI u2 = ((IURIEditorInput) ((XtextEditor) obj).getEditorInput()).getURI();
        if (u1 == null || u2 == null) {
            return false;
        }
        return u1.toString().equals(u2.toString());
    }

    /**
     * Gets current edited file.
     * 
     * @return An IFile instance
     */
    public static IFile getActiveEditorFile() {
        return getEditorFile(EditorUtils.getActiveXtextEditor());
    }

    /**
     * Gets the edited file from the specified editor
     * 
     * @param editor
     *        The editor to get the file from
     * @return An IFile instance
     */
    public static IFile getEditorFile(XtextEditor editor) {
        if (editor == null) {
            return null;
        }
        return (IFile) editor.getEditorInput().getAdapter(IFile.class);
    }

    /**
     * Here it comes the part that handles external files
     * (from outside the workspace)
     * 
     */
    /**
     * Copyright (c) 2010, Cloudsmith Inc.
     * The code, documentation and other materials contained herein have been
     * licensed under the Eclipse Public License - v 1.0 by the copyright holder
     * listed above, as the Initial Contributor under such license. The text of
     * such license is available at www.eclipse.org.
     */

    private void createLink(IProject project, IFile linkFile, java.net.URI uri) throws CoreException {
        IPath path = linkFile.getFullPath();

        IPath folders = path.removeLastSegments(1).removeFirstSegments(1);
        IPath checkPath = Path.ROOT;
        int segmentCount = folders.segmentCount();
        for (int i = 0; i < segmentCount; i++) {
            checkPath = checkPath.addTrailingSeparator().append(folders.segment(i));
            IFolder folder = project.getFolder(checkPath);
            if (!folder.exists()) {
                folder.create(true, true, null);
            }
        }
        linkFile.createLink(uri, IResource.ALLOW_MISSING_LOCAL, null);
    }

    @Override
    public void dispose() {
        // Unlink the input if it was linked
        IEditorInput input = getEditorInput();
        if (input instanceof IFileEditorInput) {
            IFile file = ((IFileEditorInput) input).getFile();
            if (file.isLinked()) {
                file.getProject().getName().equals(AUTOLINK_PROJECT_NAME);
                try {
                    // if the editor is disposed because workbench is shutting
                    // down, it is NOT a good
                    // idea to delete the link
                    if (PlatformUI.isWorkbenchRunning() && !PlatformUI.getWorkbench().isClosing()) {
                        file.delete(true, null);
                    }
                } catch (CoreException e) {
                    // Nothing to do really, it will be recreated/refreshed
                    // later if ever used - some garbage may stay behind...
                    Logger.getInstance().logException(e);
                }
            }
        }
        super.dispose();
    }

    private IFile getWorkspaceFile(IFileStore fileStore) {
        IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
        IFile[] files = workspaceRoot.findFilesForLocationURI(fileStore.toURI());
        if (files != null && files.length == 1) {
            return files[0];
        }
        return null;
    }

    /**
     * Translates an incoming IEditorInput being an FilestoreEditorInput, or
     * IURIEditorInput
     * that is not also a IFileEditorInput.
     * FilestoreEditorInput is used when opening external files in an IDE
     * environment.
     * The result is that the regular XtextEditor gets an IEFSEditorInput which
     * is also an
     * IStorageEditorInput.
     */
    @Override
    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
        // THE ISSUE HERE:
        // In the IDE, the File Open Dialog (and elsewhere) uses a
        // FilestoreEditorInput class
        // which is an IDE specific implementation.
        // The state at this point:
        // 1. When creating a file, the IEditorInput is an IURIEditorInput
        // 2. The only (non IDE specific) interface implemented by
        // FilestoreEditorInput is IURIEditorInput
        // 3. The creation of a file is however also an IFileEditorInput
        //
        // Remedy:
        if (input instanceof IURIEditorInput && !(input instanceof IFileEditorInput)) {
            java.net.URI uri = ((IURIEditorInput) input).getURI();
            String name = ((IURIEditorInput) input).getName();
            // Check if this is linkable input
            if (uri.getScheme().equals("file")) { //$NON-NLS-1$
                IFile linkedFile = obtainLink(uri);
                IFileEditorInput linkedInput = new LinkedFileEditorInput(linkedFile);
                super.init(site, linkedInput);

            } else {
                // use EMF URI (readonly) input - will open without validation
                // though...
                // (Could be improved, i.e. perform a download, make readonly,
                // and keep in project,
                // or stored in tmp, and processed as the other linked
                // resources..
                URIEditorInput uriInput = new URIEditorInput(URI.createURI(uri.toString()), name);
                super.init(site, uriInput);
                return;
            }
            return;
        }
        super.init(site, input);
    }

    /**
     * Throws WrappedException - the URI must refer to an existing file!
     * 
     * @param uri
     * @return
     */
    private IFile obtainLink(java.net.URI uri) {
        try {
            IWorkspace ws = ResourcesPlugin.getWorkspace();
            // get, or create project if non existing
            IProject project = ws.getRoot().getProject(AUTOLINK_PROJECT_NAME);
            boolean newProject = false;
            if (!project.exists()) {
                project.create(null);
                newProject = true;
            }
            if (!project.isOpen()) {
                project.open(null);
                project.setHidden(true);
            }

            if (newProject) {
                project.setDefaultCharset(ENCODING_UTF8, new NullProgressMonitor());
            }

            // path in project that is the same as the external file's path
            IFile linkFile = project.getFile(uri.getPath());
            if (linkFile.exists()) {
                linkFile.refreshLocal(1, null); // don't know if needed (or
            } else {
                // create the link
                createLink(project, linkFile, uri);
                // linkFile.createLink(uri, IResource.ALLOW_MISSING_LOCAL,
                // null);
            }
            return linkFile;

            // IPath location = new Path(name);
            // IFile file = project.getFile(location.lastSegment());
            // file.createLink(location, IResource.NONE, null);
        } catch (CoreException e) {
            throw new WrappedException(e);
        }
    }

    // SaveAs support for linked files - saves them on local disc, not to
    // workspace if file is in special
    // hidden external file link project.
    @Override
    protected void performSaveAs(IProgressMonitor progressMonitor) {

        Shell shell = getSite().getShell();
        final IEditorInput input = getEditorInput();

        // Customize save as if the file is linked, and it is in the special
        // external link project
        //
        if (input instanceof IFileEditorInput && ((IFileEditorInput) input).getFile().isLinked()
                && ((IFileEditorInput) input).getFile().getProject().getName().equals(AUTOLINK_PROJECT_NAME)) {
            final IEditorInput newInput;
            IDocumentProvider provider = getDocumentProvider();

            FileDialog dialog = new FileDialog(shell, SWT.SAVE);
            IPath oldPath = URIUtil.toPath(((IURIEditorInput) input).getURI());
            if (oldPath != null) {
                dialog.setFileName(oldPath.lastSegment());
                dialog.setFilterPath(oldPath.toOSString());
            }

            dialog.setFilterExtensions(new String[] { "*.b3", "*.*" }); //$NON-NLS-1$ //$NON-NLS-2$
            String path = dialog.open();
            if (path == null) {
                if (progressMonitor != null) {
                    progressMonitor.setCanceled(true);
                }
                return;
            }

            // Check whether file exists and if so, confirm overwrite
            final File localFile = new File(path);
            if (localFile.exists()) {
                MessageDialog overwriteDialog = new MessageDialog(shell, Messages.WMLEditor_0, null,
                        path + Messages.WMLEditor_1, MessageDialog.WARNING,
                        new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 1); // 'No' is the
                                                                                                                                                                                                                                             // default
                if (overwriteDialog.open() != Window.OK) {
                    if (progressMonitor != null) {
                        progressMonitor.setCanceled(true);
                        return;
                    }
                }
            }

            IFileStore fileStore;
            try {
                fileStore = EFS.getStore(localFile.toURI());
            } catch (CoreException ex) {
                Logger.getInstance().logException(ex);
                String title = Messages.WMLEditor_2;
                String msg = Messages.WMLEditor_3 + ex.getMessage();
                MessageDialog.openError(shell, title, msg);
                return;
            }

            IFile file = getWorkspaceFile(fileStore);
            if (file != null) {
                newInput = new FileEditorInput(file);
            } else {
                IURIEditorInput uriInput = new FileStoreEditorInput(fileStore);
                java.net.URI uri = uriInput.getURI();
                IFile linkedFile = obtainLink(uri);

                newInput = new FileEditorInput(linkedFile);
            }

            if (provider == null) {
                // editor has programmatically been closed while the dialog was
                // open
                return;
            }

            boolean success = false;
            try {

                provider.aboutToChange(newInput);
                provider.saveDocument(progressMonitor, newInput, provider.getDocument(input), true);
                success = true;

            } catch (CoreException x) {
                Logger.getInstance().logException(x);
                final IStatus status = x.getStatus();
                if (status == null || status.getSeverity() != IStatus.CANCEL) {
                    String title = Messages.WMLEditor_4;
                    String msg = Messages.WMLEditor_5 + x.getMessage();
                    MessageDialog.openError(shell, title, msg);
                }
            } finally {
                provider.changed(newInput);
                if (success) {
                    setInput(newInput);
                }
            }

            if (progressMonitor != null) {
                progressMonitor.setCanceled(!success);
            }

            return;
        }

        super.performSaveAs(progressMonitor);
    }
}