org.eclipse.papyrus.customization.properties.ui.CopyContextAction.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.papyrus.customization.properties.ui.CopyContextAction.java

Source

/*****************************************************************************
 * Copyright (c) 2010 CEA LIST.
 * 
 * All rights reserved. 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
 *
 * Contributors:
 *  Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
 *****************************************************************************/
package org.eclipse.papyrus.customization.properties.ui;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.papyrus.customization.properties.messages.Messages;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.views.properties.Activator;
import org.eclipse.papyrus.views.properties.catalog.PropertiesURIHandler;
import org.eclipse.papyrus.views.properties.contexts.Context;
import org.eclipse.papyrus.views.properties.contexts.ContextsPackage;
import org.eclipse.papyrus.views.properties.contexts.Section;
import org.eclipse.papyrus.views.properties.contexts.Tab;
import org.eclipse.papyrus.views.properties.runtime.ConfigurationManager;
import org.eclipse.papyrus.views.properties.util.PropertiesUtil;
import org.eclipse.swt.widgets.Display;

/**
 * An action to build a new Property view context from an existing one.
 * 
 * @author Camille Letavernier
 */
public class CopyContextAction {

    private IStatus result;

    /**
     * Copy an existing context to a new one with the given name.
     * The new context is registered to the {@link ConfigurationManager}.
     * To enable the edition of the context, an invisible project is created
     * in the workspace. The files are stored in the runtime plugin's preference
     * folder.
     * 
     * @param source
     *        The source Context to copy
     * @param targetName
     *        The name of the new context
     * @param activate
     *        If true, the new context will be activated and available immediately,
     *        while the previous one will be disabled to avoid conflicts
     * @return
     *         The new Context
     * 
     * @throws IOException
     *         If an error occured : the previous context cannot be read, or
     *         the new context cannot be created
     */
    public Context copy(Context source, String targetName, boolean activate) throws IOException {
        IPath targetDirectoryPath = Activator.getDefault().getPreferencesPath().append("/" + targetName); //$NON-NLS-1$
        final File targetDirectory = targetDirectoryPath.toFile();
        if (targetDirectory.exists()) {
            throw new IOException("A context with this name already exists"); //$NON-NLS-1$
        }
        URI targetModelUri = URI.createFileURI(targetDirectory.toString() + "/" + targetName + ".ctx"); //$NON-NLS-1$ //$NON-NLS-2$

        ResourceSet resourceSet = new ResourceSetImpl();
        Context sourceContext = (Context) EMFHelper.loadEMFModel(resourceSet, source.eResource().getURI());

        copyAll(sourceContext, new File(targetDirectory, targetName + ".ctx")); //$NON-NLS-1$

        if (result.getCode() == IStatus.OK) {
            Context targetContext = ConfigurationManager.instance.getContext(targetModelUri);

            targetContext.setName(targetName);
            targetContext.eResource().save(Collections.EMPTY_MAP);
            ConfigurationManager.instance.addContext(targetContext, activate);
            if (activate) {
                ConfigurationManager.instance.disableContext(source, true);
            }
            return targetContext;
        } else {
            return null;
        }
    }

    /**
     * Lightweight method for loading a resource set
     * This method ignores the *.xwt files, which do not contain any useful
     * cross-reference (As they can only reference Environment files), and are
     * really expensive to load.
     */
    private void resolveAllResources(Context source) {
        resolveAllResources(source, new HashSet<EObject>());
    }

    /**
     * Lightweight method for loading a resource set
     * This method ignores the *.xwt files, which do not contain any useful
     * cross-reference (As they can only reference Environment files), and are
     * really expensive to load.
     */
    private void resolveAllResources(EObject source, Set<EObject> visitedEObjects) {
        if (!visitedEObjects.add(source)) {
            return;
        }

        for (EReference reference : source.eClass().getEAllReferences()) {
            //Do not load *.xwt resources
            //These files do not contain any useful cross-reference, and are really expensive to load
            if (reference == ContextsPackage.eINSTANCE.getSection_Widget()) {
                continue;
            }

            Object value = source.eGet(reference);
            if (value instanceof EList) {
                for (Object object : (EList<?>) value) {
                    if (object instanceof EObject) {
                        resolveAllResources((EObject) object, visitedEObjects);
                    }
                }
            } else if (value instanceof EObject) {
                resolveAllResources((EObject) value, visitedEObjects);
            }
        }
    }

    private void copyAll(final Context source, final File target) {
        final File targetDirectory = target.getParentFile();
        final String targetName = target.getName();

        ProgressMonitorDialog dialog = new ProgressMonitorDialog(Display.getCurrent().getActiveShell());
        try {
            dialog.run(true, false, new IRunnableWithProgress() {

                public void run(IProgressMonitor monitor) {
                    monitor.beginTask(Messages.CopyContextAction_InitializingTheCopyOf + source.getName()
                            + Messages.CopyContextAction_ThisMayTakeSomeTime, IProgressMonitor.UNKNOWN);
                    //EcoreUtil.resolveAll(source); //This method is too expensive
                    resolveAllResources(source); //Ignores the *.xwt files. We will copy them manually.
                    monitor.done();
                    result = Status.OK_STATUS;
                }
            });

            dialog = new ProgressMonitorDialog(Display.getCurrent().getActiveShell());

            if (result.getCode() == IStatus.OK) {

                dialog.run(true, true, new IRunnableWithProgress() {

                    public void run(IProgressMonitor monitor) {
                        try {
                            targetDirectory.mkdirs();

                            int filesToCopy = source.eResource().getResourceSet().getResources().size();
                            List<Context> contexts = new LinkedList<Context>();
                            for (Context context : PropertiesUtil.getDependencies(source)) {
                                if (isRelative(source, context.eResource())) {
                                    contexts.add(context);
                                    for (Tab tab : context.getTabs()) {
                                        filesToCopy += tab.getSections().size();
                                    }
                                }
                            }

                            monitor.beginTask(Messages.CopyContextAction_Copying + source.getName()
                                    + Messages.CopyContextAction_To + targetName, filesToCopy);

                            //Copy of the context
                            copy(source.eResource(), target);
                            monitor.worked(1);

                            //Copy of the dependent resources which are located in the same folder
                            //(or subfolders)
                            for (Resource resource : source.eResource().getResourceSet().getResources()) {
                                if (monitor.isCanceled()) {
                                    return;
                                }
                                if (source.eResource() != resource && isRelative(source, resource)) {
                                    copy(resource, targetDirectory, source, targetName);
                                }
                                monitor.worked(1);
                            }

                            //Copy the XWT files (they haven't been loaded in the resource set)
                            for (Context context : contexts) {
                                for (Tab tab : context.getTabs()) {
                                    for (Section section : tab.getSections()) {
                                        if (monitor.isCanceled()) {
                                            return;
                                        }
                                        copy(section.getSectionFile(), targetDirectory, source);
                                        monitor.worked(1);
                                    }
                                }
                            }

                            monitor.done();
                        } catch (IOException ex) {
                            Activator.log.error(ex);
                            result = new Status(IStatus.ERROR, Activator.PLUGIN_ID,
                                    "An error occured during the copy of " + source.getName(), ex); //$NON-NLS-1$
                            return;
                        }
                        result = Status.OK_STATUS;
                    }
                });
            }
        } catch (InvocationTargetException ex) {
            Activator.log.error(ex);
        } catch (InterruptedException ex) {
            Activator.log.error(ex);
        }
    }

    protected void copy(String xwtFileName, File targetDirectory, Context source) {
        File target = new File(targetDirectory, xwtFileName);
        URI sourceURI = URI.createURI(xwtFileName).resolve(source.eResource().getURI());
        PropertiesURIHandler uriHandler = new PropertiesURIHandler();
        if (uriHandler.canHandle(sourceURI)) {
            sourceURI = uriHandler.getConvertedURI(sourceURI);
        }

        try {
            java.net.URL netURL = new java.net.URL(sourceURI.toString());
            InputStream is = netURL.openStream();
            copy(is, target);
        } catch (MalformedURLException ex) {
            Activator.log.error(ex);
        } catch (IOException ex) {
            Activator.log.error(ex);
        }
    }

    protected void copy(Resource resource, File target) throws IOException {
        PropertiesURIHandler uriHandler = new PropertiesURIHandler();
        URI uri = resource.getURI();
        if (uriHandler.canHandle(uri)) {
            uri = uriHandler.getConvertedURI(uri);
        }
        copy(new URL(uri.toString()).openStream(), target);
    }

    private void copy(Resource resource, File directory, EObject source, String targetName) throws IOException {
        URI relativeURI = resource.getURI().deresolve(source.eResource().getURI());
        if (relativeURI.toString().equals("")) { //$NON-NLS-1$
            relativeURI = URI.createURI(targetName + ".ctx"); //$NON-NLS-1$
        }
        File target = new File(directory, relativeURI.toString());
        copy(resource, target);
    }

    private boolean isRelative(EObject source, Resource resource) {
        URI baseURI = source.eResource().getURI();
        URI resourceURI = resource.getURI();
        URI uri = resourceURI.deresolve(baseURI);
        if (uri.isRelative()) {
            if (!(uri.toString().startsWith("..") || uri.toString().startsWith("/"))) { //$NON-NLS-1$ //$NON-NLS-2$
                return true;
            }
        }
        return false;
    }

    //Strict copy : we read directly the file, instead of interpreting it as a Model
    private void copy(InputStream source, File target) throws IOException {
        if (!target.getParentFile().exists()) {
            target.getParentFile().mkdirs();
        }

        FileWriter out = new FileWriter(target);
        try {
            int c;

            while ((c = source.read()) != -1) {
                out.write(c);
            }

        } catch (IOException ex) {
            throw ex;
        } finally {
            source.close();
            out.close();
        }
    }
}