/**
 * File: WEEditor.java Created: 27.11.2005
 * 
 * /****************************************************************************
 * *** Copyright (c) 2005-2011 University of Augsburg, Germany <www.ds-lab.org>
 * 
 * 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: Christian Saad, Programming distributed Systems Lab, University
 * of Augsburg - initial API and implementation Mickael Istria, Open Wide, Lyon,
 * France - Extension Point listener
 *******************************************************************************/

package org.eclipse.jwt.we.editors;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.draw2d.IFigure;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.ui.URIEditorInput;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.xmi.ClassNotFoundException;
import org.eclipse.emf.ecore.xmi.PackageNotFoundException;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.commands.CommandStackListener;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.ui.actions.ActionBarContributor;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.SelectAllAction;
import org.eclipse.gef.ui.views.palette.PalettePage;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.bindings.IBindingManagerListener;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jwt.converter.Converter;
import org.eclipse.jwt.meta.commands.editDomain.JWTAdapterFactoryEditingDomain;
import org.eclipse.jwt.meta.model.core.Model;
import org.eclipse.jwt.meta.model.processes.Activity;
import org.eclipse.jwt.meta.model.processes.ProcessesFactory;
import org.eclipse.jwt.meta.providers.ResourceProviderRegistry;
import org.eclipse.jwt.we.Plugin;
import org.eclipse.jwt.we.PluginProperties;
import org.eclipse.jwt.we.commands.editdomain.GefEmfEditingDomain;
import org.eclipse.jwt.we.commands.gefEmfAdapter.GefToEmfCommandStackAdapter;
import org.eclipse.jwt.we.editors.actions.internalActions.CopyAction;
import org.eclipse.jwt.we.editors.actions.internalActions.CutAction;
import org.eclipse.jwt.we.editors.actions.internalActions.DeleteAction;
import org.eclipse.jwt.we.editors.actions.internalActions.DirectEditAction;
import org.eclipse.jwt.we.editors.actions.internalActions.PasteAction;
import org.eclipse.jwt.we.editors.actions.internalActions.PrintAction;
import org.eclipse.jwt.we.editors.actions.internalActions.RedoAction;
import org.eclipse.jwt.we.editors.actions.internalActions.UndoAction;
import org.eclipse.jwt.we.editors.actions.managed.recentfiles.RecentFilesListManager;
import org.eclipse.jwt.we.editors.actions.managed.zoom.ZoomControl;
import org.eclipse.jwt.we.editors.internal.BindingManagerListener;
import org.eclipse.jwt.we.editors.internal.EditorPropertyUpdater;
import org.eclipse.jwt.we.editors.internal.EditorTabUpdater;
import org.eclipse.jwt.we.editors.internal.PartActivationListener;
import org.eclipse.jwt.we.editors.outline.ModelOutlinePage;
import org.eclipse.jwt.we.editors.pages.activityEditor.WEEditorSheet;
import org.eclipse.jwt.we.editors.pages.activityEditor.internal.IActivityEditor;
import org.eclipse.jwt.we.editors.pages.externalSheet.internal.WEExternalSheetManager;
import org.eclipse.jwt.we.editors.pages.overviewPage.WEOverviewSheet;
import org.eclipse.jwt.we.editors.preferences.PreferenceReader;
import org.eclipse.jwt.we.editors.properties.extension.internal.PropertySheetPageExtensionPoint;
import org.eclipse.jwt.we.editors.selection.EditPartViewerSelectionConverter;
import org.eclipse.jwt.we.editors.selection.SelectionSynchronizer;
import org.eclipse.jwt.we.misc.extensions.externalNotificationListener.ExtensionPointNotifyChangedListener;
import org.eclipse.jwt.we.misc.logging.Logger;
import org.eclipse.jwt.we.misc.providers.ProviderInstanceFactory;
import org.eclipse.jwt.we.misc.util.EMFHelper;
import org.eclipse.jwt.we.misc.util.GeneralHelper;
import org.eclipse.jwt.we.misc.views.Views;
import org.eclipse.jwt.we.model.view.Diagram;
import org.eclipse.jwt.we.model.view.impl.ViewFactoryImpl;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPathEditorInput;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.ISaveablePart2;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.ide.FileStoreEditorInput;
import org.eclipse.ui.keys.IBindingService;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.PropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;

/**
 * This is the main editor.
 * 
 * <p>
 * It is called from the plugin and plugin.xml.
 * </p>
 * 
 * <h2>Editor</h2>
 * <p>
 * The editor contains:
 * <ul>
 * <li>An {@link EditDomain} to represent the model. It is an combination of an
 * EMF and GEF editing domain and provides loading, saving, querying and
 * changing of the model</li>
 * <li>An {@link ActionRegistry} that stores the actions and passes them to the
 * {@link ActionBarContributor}</li>
 * <li>A {@link org.eclipse.jwt.we.editors.properties property sheet page} to
 * edit the properties of the model elements.
 * <li>An {@link org.eclipse.jwt.we.editors.properties outline view} that is the
 * model editor.</li>
 * </ul>
 * </p>
 * 
 * <h2>Editing Domain</h2>
 * <p>
 * The editing is an combination of an EMF and GEF editing domain. The GEF
 * editing domain is needed for the GEF editor. The EMF editing domain provides
 * loading and saving of the model using {@link ResourceSet}s. It also creates
 * the commands to modify the model.
 * </p>
 * 
 * <h2>Adapter Factory</h2>
 * <p>
 * The EMF editing domain contains an {@link AdapterFactory} that is composed of
 * all available AdapterFactories for the model providers. This factory is able
 * to adapt all model elements to their edit providers.
 * </p>
 * 
 * <h2>Command Stack</h2>
 * <p>
 * The editor uses the command stack provided by the GEF {@link EditingDomain}.
 * The EMF editing domain contains a wrapper of the GEF command stack that
 * adapts it to an EMF command stack.
 * </p>
 * 
 * <h2>Selections</h2>
 * <p>
 * Elements in the {@link GraphicalViewer} and the outline can be selected. The
 * {@link GraphicalViewer} selects {@link EditPart}s, the outline model
 * elements.<br>
 * In order to provide a consistent selection e.g. to the property view this
 * selections must be synchronized. Therefore a {@link SelectionSynchronizer} is
 * used. The {@link SelectionSynchronizer} selects model elements. selections of
 * the {@link GraphicalViewer} are converted to model elements using an
 * {@link EditPartViewerSelectionConverter}.<br>
 * The {@link SelectionSynchronizer} is registered as the
 * {@link ISelectionProvider} of the editor, i.e. from the "outside" the editor
 * selects model elements.<br>
 * Whenever a global selection is needed the {@link ISelectionProvider} >from
 * {@link #getSelectionProvider()} should be used. If a selection of EditParts
 * is needed, the {@link GraphicalViewer} should be used as selection provider.
 * </p>
 * 
 * @version $Id: WEEditor.java,v 1.61 2010-06-30 10:46:33 chsaad Exp $
 * @author Markus Bauer (markusbauer@users.sourceforge.net), Programming
 *         distributed Systems Lab, University of Augsburg, Germany,
 *         www.ds-lab.org
 * @since 0.7
 */

public class WEEditor extends MultiPageEditorPart implements CommandStackListener,
		ISaveablePart2, ITabbedPropertySheetPageContributor
{

	/**
	 * The Logger.
	 */
	private static final Logger logger = Logger.getLogger(WEEditor.class);

	/**
	 * Update this editor on changes.
	 */
	private EditorPropertyUpdater editorPropertyUpdater;

	/**
	 * Update this editor on changes.
	 */
	private EditorTabUpdater editorTabUpdater;

	/**
	 * The {@link EditingDomain}. This combines an EMF and GEF editing domain.
	 */
	private GefEmfEditingDomain editDomain;

	/**
	 * Stores actions for this editor.
	 */
	private ActionRegistry actionRegistry;

	/**
	 * Main resource holding the root model.
	 */
	private Resource mainModelResource;

	/**
	 * Main resource holding the diagram data.
	 */
	private Resource mainDiagramResource;

	/**
	 * Keeps track of the PropertySheetPage.
	 */
	private IPropertySheetPage propertySheetPage;

	/**
	 * Keeps track of the outline page.
	 */
	private ModelOutlinePage outlinePage;

	/**
	 * The image used in the title.
	 */
	private Image titleImage;

	/**
	 * The synchronizer can be used to sync the selection of 2 or more
	 * EditPartViewers.
	 */
	private SelectionSynchronizer synchronizer;

	/**
	 * The overview page id
	 */
	private int overviewPageID = -1;

	/**
	 * Listener for part changes.
	 */
	private PartActivationListener partActivationListener;

	/**
	 * Listener for changes in command bindings. Used e.g. to update the toolbar
	 * labels.
	 */
	private IBindingManagerListener bindingManagerListener;


	/**
	 * The constructor
	 */
	public WEEditor()
	{
		logger.instanceCreation();

		// create the editing domain
		setEditDomain(new GefEmfEditingDomain(this));

		// register with general helper
		GeneralHelper.registerEditor(this);
		GeneralHelper.setInitializingEditor(this);

		// register icon and visibility provider with the meta model
		ResourceProviderRegistry.getInstance().setInitializingEditor(this);
		ResourceProviderRegistry.getInstance().registerImageProvider(this,
				ProviderInstanceFactory.getInstance().getDefaultImageProvider());
		ResourceProviderRegistry.getInstance().registerVisibilityProvider(this,
				ProviderInstanceFactory.getInstance().getDefaultVisibilityProvider());
		ResourceProviderRegistry.getInstance().registerCommandProvider(this,
				ProviderInstanceFactory.getInstance().getDefaultCommandProvider(this));

		// register service to listen on binding change
		IBindingService bindingService = (IBindingService) Plugin.getDefault()
				.getWorkbench().getService(IBindingService.class);
		bindingManagerListener = new BindingManagerListener(this);
		bindingService.addBindingManagerListener(bindingManagerListener);
	}


	// ///////////////////////////////////////////////////////////////////////////
	// Create the different pages of this editor
	//

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.part.MultiPageEditorPart#createPages()
	 */
	@Override
	protected void createPages()
	{
		// Add the part activation listener
		partActivationListener = new PartActivationListener(this);
		getSite().getWorkbenchWindow().getPartService()
				.addPartListener(partActivationListener);

		// Load the model resource
		try
		{
			this.createModel();
		}
		catch (Exception e)
		{
			logger.severe("Could not load input from " + getEditorInput().getName(), e); //$NON-NLS-1$

			// Close this editor
			final WEEditor thisWE = this;

			getSite().getShell().getDisplay().asyncExec(new Runnable()
			{

				public void run()
				{
					getSite().getPage().closeEditor(thisWE, false);

					MessageDialog.openError(getEditorSite().getShell(),
							PluginProperties.editor_ErrorMessage_title, NLS.bind(
									PluginProperties.editor_ErrorLoadingFile_message,
									getEditorInput().getName()));
				}
			});

			return;
		}

		// listen for changes after which the tabs have to be updated
		editorPropertyUpdater = new EditorPropertyUpdater(this);
		editorTabUpdater = new EditorTabUpdater(this);

		// create the palette
		getEditDomain().setPaletteRoot(
				Plugin.getInstance().getFactoryRegistry().getPaletteFactory()
						.getPaletteRoot(this));

		// refresh views checked state, toolbar dropdown and figure factory
		Views.getInstance().refreshViewsState(this);

		// check whether to load and show overview page
		boolean overviewVisible = PreferenceReader.appearanceOverviewShow.get();
		if (overviewVisible)
		{
			// load OVERVIEW page
			overviewPageID = addPage(new WEOverviewSheet(getContainer(), this));
			getTabFolder().getItem(overviewPageID).setText(
					PluginProperties.configPage_Title);
		}

		// load all EXTERNAL pages which are set to autoshow
		for (Iterator iterator = WEExternalSheetManager.getInstance().getExternalSheets()
				.keySet().iterator(); iterator.hasNext();)
		{
			String sheetTitle = (String) iterator.next();

			IConfigurationElement point = WEExternalSheetManager.getInstance()
					.getExternalSheets().get(sheetTitle);
			if (point.getAttribute("autoshow").equals("true")) //$NON-NLS-1$ //$NON-NLS-2$
			{
				WEExternalSheetManager.getInstance().displayExternalSheet(this,
						sheetTitle);
			}
		}

		// load ACTIVITYEDITOR page
		openActivityInNewPage(getFirstActivityModel());

		if (overviewVisible)
		{
			// activate overview page
			activatePage(overviewPageID);
		}

		// remove initialization reference to editor
		GeneralHelper.setInitializingEditor(null);
		ResourceProviderRegistry.getInstance().setInitializingEditor(null);
	}


	// ///////////////////////////////////////////////////////////////////////////
	// Palette
	//

	// ///////////////////////////////////////////////////////////////////////////
	// ActivityEditor management
	//

	/**
	 * Check if model is already open in some tab and switch to this tab.
	 * 
	 * @param newActivityModel
	 * @return
	 */
	public boolean activateIfAlreadyOpen(Activity newActivityModel)
	{
		for (int i = 0; i < getPageCount(); i++)
		{
			if (getEditor(i) instanceof IActivityEditor
					&& ((IActivityEditor) getEditor(i)).getActivityModel() == newActivityModel)
			{
				activatePage(i);
				return true;
			}
		}

		return false;
	}


	/**
	 * Opens the given Activity in the current MultiEditor page. If the current
	 * page is not an ActivityEditorSheet (this means an overview page), it is
	 * opened in a new page. If the Activity is already open, the editor just
	 * activates the page.
	 * 
	 * @param newActivityModel
	 *            The Activity which should be opened.
	 */
	public void openActivityInCurrentPage(Activity newActivityModel)
	{
		// check if already opened and switch to page if so
		if (activateIfAlreadyOpen(newActivityModel))
		{
			return;
		}

		// set model in current page if it is an editor page...
		if (getActiveEditor() instanceof IActivityEditor)
		{
			((IActivityEditor) getActiveEditor()).loadActivityModel(newActivityModel);
			activatePage(getActivePage());
			setPageText(getActivePage(), newActivityModel.getName());
		}
		// ...or open new page if it is not.
		else
		{
			openActivityInNewPage(newActivityModel);
		}
	}


	/**
	 * Opens the given Activity in a new MultiEditor page. The first activity
	 * page is always noncloseable
	 * 
	 * @param newActivityModel
	 *            The Activity which should be opened.
	 * @param closable
	 *            Provide a close button on the tab.
	 */
	public void openActivityInNewPage(Activity newActivityModel)
	{
		// check if already opened and switch to page if so
		if (activateIfAlreadyOpen(newActivityModel))
		{
			return;
		}

		// open activity in new page and switch
		try
		{
			// open new page and load activity model
			WEEditorSheet editorSheet = new WEEditorSheet(this);
			int pageID = addPage(editorSheet, getEditorInput());
			editorSheet.loadActivityModel(newActivityModel);
			setPageText(pageID, newActivityModel.getName());

			// make the tab page closable
			getTabFolder().getItem(pageID).setShowClose(true);

			// switch to the new page
			activatePage(pageID);
		}
		catch (PartInitException e)
		{
			ErrorDialog.openError(getSite().getShell(), "Open Error", //$NON-NLS-1$
					"An error occured during opening the activity editor.", e //$NON-NLS-1$
							.getStatus());
		}
	}


	/**
	 * Searches the MultiEditor pages for an editor with displays the given
	 * Activity, and closes the page.
	 * 
	 * This is not as easy as it sounds :)
	 * 
	 * @param oldActivityModel
	 *            The Activity which should be closed.
	 */
	public void removeActivityFromPage(Activity oldActivityModel)
	{
		// search for ActivityEditor displaying the activity model and close it
		for (int i = 0; i < getPageCount(); i++)
		{
			if (getEditor(i) instanceof IActivityEditor
					&& ((IActivityEditor) getEditor(i)).getActivityModel() == oldActivityModel)
			{
				// FOUND IT! NOW:

				// - dispose of the ActivityEditor
				// - dispose of the tab item
				if (i != 0)
				{
					removePage(i);
				}

				// activate overview sheet
				activatePage(0);
			}
		}
	}


	/**
	 * Returns the activityModel that is displayed (in the sheet).
	 * 
	 * @return The activityModel
	 */
	public Activity getDisplayedActivityModel()
	{
		if (getActiveEditor() instanceof IActivityEditor)
		{
			return ((IActivityEditor) getActiveEditor()).getActivityModel();
		}

		return null;
	}


	/**
	 * Returns a set of all activities which are currently displayed in a
	 * WEEditorSheet.
	 * 
	 * @return The activities
	 */
	public Set getOpenActivities()
	{
		Set result = new HashSet();

		for (int i = 0; i < getPageCount(); i++)
		{
			if (getEditor(i) instanceof IActivityEditor)
			{
				result.add(((IActivityEditor) getEditor(i)).getActivityModel());
			}
		}

		return result;
	}


	/**
	 * Returns the IActivityEditor of an open Activity.
	 * 
	 * @return The activities
	 */
	public IActivityEditor getPageForActivity(Activity activity)
	{
		for (int i = 0; i < getPageCount(); i++)
		{
			if (getEditor(i) instanceof IActivityEditor
					&& ((IActivityEditor) getEditor(i)).getActivityModel() == activity)
			{
				return (IActivityEditor) getEditor(i);
			}
		}

		return null;
	}


	/**
	 * Returns the current activity editor sheet. If the current page is not
	 * ActivityEditorSheet, the first ActivityEditorSheet found is returned.
	 * 
	 * @return the activity sheet page or <code>null</code>
	 */
	public WEEditorSheet getCurrentActivitySheet()
	{
		if (getActiveEditor() instanceof WEEditorSheet)
		{
			return ((WEEditorSheet) getActiveEditor());
		}
		else
		{
			for (int i = 0; i < getPageCount(); i++)
			{
				if (getEditor(i) instanceof IActivityEditor)
				{
					return ((WEEditorSheet) getEditor(i));
				}
			}
		}

		return null;
	}


	/**
	 * Activates the page with the given index. The page is set as active page
	 * and the editor/tab title+image, the palette viewer etc are updated.
	 * 
	 * It is important that pages are changed using this method and not using
	 * setActivePage().
	 * 
	 * @param pageIndex
	 */
	public void activatePage(int pageIndex)
	{
		// change to the specified page
		if (getActivePage() != pageIndex)
		{
			setActivePage(pageIndex);
		}

		// if active page is an WEOverviewSheet
		if (getActiveEditor() == null)
		{
			// select main model element
			getSelectionProvider().setSelection(new StructuredSelection(getModel()));
		}

		// if active page is an IActivityEditor
		if (getActiveEditor() instanceof IActivityEditor)
		{
			// set the grid according to the properties
			getCurrentActivitySheet().setGridProperties();

			// select activity model element
			getSelectionProvider()
					.setSelection(
							new StructuredSelection(getCurrentActivitySheet()
									.getActivityModel()));

			// set the palette viewer to the one of the current activity sheet
			getEditDomain()
					.setPaletteViewer(getCurrentActivitySheet().getPaletteViewer());
		}

		// refresh outline page
		refreshOutline();

		// refresh outline page
		refreshProperties();

		// update title and image
		updateTitleName();
		updateTitleImage();

		// refresh zoom if different sheet was selected
		refreshZoom();
	}


	/**
	 * The active page ID.
	 */
	public int getActivePage()
	{
		return super.getActivePage();
	}


	/**
	 * The amount of open editor pages.
	 */
	public int getPageCount()
	{
		return super.getPageCount();
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.part.MultiPageEditorPart#getEditor(int)
	 */
	@Override
	public IEditorPart getEditor(int pageIndex)
	{
		return super.getEditor(pageIndex);
	}


	/**
	 * Updates the model display in all pages (if view changed).
	 */
	public void refreshPages()
	{
		for (int i = 0; i < getPageCount(); i++)
		{
			// refresh sheets
			if (getEditor(i) instanceof IActivityEditor)
			{
				((IActivityEditor) getEditor(i)).refreshEditorSheet();
			}

			boolean overviewVisible = PreferenceReader.appearanceOverviewShow.get();
			if (overviewVisible)
			{
				if (overviewPageID == -1)
				{
					// load OVERVIEW page
					overviewPageID = addPage(new WEOverviewSheet(getContainer(), this));
					getTabFolder().getItem(overviewPageID).setText(
							PluginProperties.configPage_Title);
				}
			}
			else
			{ // overviewVisible == false!
				if (overviewPageID != -1)
				{
					getTabFolder().getItem(overviewPageID).dispose();
					overviewPageID = -1;
				}
			}
			// refresh overview sheet
			if (getControl(i) instanceof WEOverviewSheet)
			{
				((WEOverviewSheet) getControl(i)).reloadOverviewSheet();
			}
		}
	}


	/**
	 * Updates the zoom display
	 */
	public void refreshZoom()
	{
		if (getActiveEditor() instanceof IActivityEditor)
		{
			ZoomControl.getInstance().refreshZoomManager();
			ZoomControl.getInstance().enableZoom();
		}
		else
		{
			ZoomControl.getInstance().disableZoom();
		}
	}


	/**
	 * Refreshes the property sheet.
	 */
	public void refreshProperties()
	{
		if (propertySheetPage == null)
		{
			return;
		}

		// refresh normal or multitab property sheet
		if (propertySheetPage instanceof PropertySheetPage)
		{
			((PropertySheetPage) propertySheetPage).refresh();
		}
		else
		{
			((TabbedPropertySheetPage) propertySheetPage).refresh();
		}
	}


	/**
	 * change the palette with the view one
	 */
	public void refreshPalette()
	{
		// remove old palette adapters from model
		if (mainModelResource != null)
			for (Iterator iter = mainModelResource.getAllContents(); iter.hasNext();)
			{
				Object obj = iter.next();

				if (obj instanceof Notifier)
				{
					Set<Adapter> adapters = new HashSet<Adapter>();
					for (Adapter a : ((Notifier) obj).eAdapters())
						if (a instanceof PaletteRoot)
							adapters.add(a);
					((Notifier) obj).eAdapters().removeAll(adapters);
				}
			}

		// create and add new palette root
		getEditDomain().setPaletteRoot(
				Plugin.getInstance().getFactoryRegistry().getPaletteFactory()
						.getPaletteRoot(this));
	}


	/**
	 * Refreshes the outline view.
	 */
	public void refreshOutline()
	{
		if (outlinePage != null)
		{
			outlinePage.refresh();
		}
	}


	// ///////////////////////////////////////////////////////////////////////////
	// Getter and Setters
	//

	/**
	 * @return The extension for the editor to create.
	 */
	public static String getWorkflowExtension()
	{
		return PluginProperties.plugin_workflow_extension;
	}


	/**
	 * @return The extension for the diagram to create.
	 */
	public static String getDiagramExtension()
	{
		return PluginProperties.plugin_diagram_extension;
	}


	/**
	 * @return The extension for template import/export.
	 */
	public static String getTemplateExtension()
	{
		return PluginProperties.plugin_template_extension;
	}


	/**
	 * @return The main model resource.
	 */
	public Resource getMainModelResource()
	{
		return mainModelResource;
	}


	/**
	 * @return Returns the editDomain.
	 */
	public GefEmfEditingDomain getEditDomain()
	{
		return editDomain;
	}


	/**
	 * @param newEditDomain
	 *            The editDomain to set.
	 */
	protected void setEditDomain(GefEmfEditingDomain newEditDomain)
	{
		editDomain = newEditDomain;
		if (editDomain instanceof GefEmfEditingDomain)
		{
			((GefEmfEditingDomain) editDomain)
					.setEmfEditingDomain(createEmfEditingDomain());
		}
	}


	/**
	 * @return The EMF EditingDomain.
	 */
	public EditingDomain getEmfEditingDomain()
	{
		if (getEditDomain() == null || !(getEditDomain() instanceof GefEmfEditingDomain))
		{
			return null;
		}
		return ((GefEmfEditingDomain) getEditDomain()).getEmfEditingDomain();
	}


	/**
	 * @return The AdapterFactory used for the EMF EditingDomain
	 */
	public AdapterFactory getAdapterFactory()
	{
		EditingDomain editingDomain = getEmfEditingDomain();

		if (editingDomain == null
				|| !(editingDomain instanceof AdapterFactoryEditingDomain))
		{
			return null;
		}

		return ((AdapterFactoryEditingDomain) editingDomain).getAdapterFactory();
	}


	/**
	 * Lazily creates and returns the action registry.
	 * 
	 * @return The action registry.
	 */
	public ActionRegistry getActionRegistry()
	{
		if (actionRegistry == null)
		{
			actionRegistry = new ActionRegistry();
		}
		return actionRegistry;
	}


	/**
	 * @return A PropertySheet Page for this editor.
	 */
	public IPropertySheetPage getPropertySheetPage()
	{
		if (propertySheetPage == null)
		{
			propertySheetPage = PropertySheetPageExtensionPoint
					.createPropertySheetPage(this);
		}
		return propertySheetPage;
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @seeorg.eclipse.ui.views.properties.tabbed.
	 * ITabbedPropertySheetPageContributor# getContributorId()
	 */
	public String getContributorId()
	{
		// returns the id of the site (for the multitab properties view)
		return getSite().getId();
	}


	/**
	 * @return The outline for this editor.
	 */
	public ModelOutlinePage getOutlinePage()
	{
		if (outlinePage == null)
		{
			outlinePage = new ModelOutlinePage(this);
		}

		return outlinePage;
	}


	/**
	 * Get the root model.
	 * 
	 * @return The root of the editor's model.
	 */
	public Object getModel()
	{
		if (mainModelResource == null)
		{
			return null;
		}

		return mainModelResource.getContents().get(0);
	}


	/**
	 * Returns the diagram data that stores all information which is only
	 * necessary for the view but not for the core (business) model, i.e.
	 * References, ReferenceEdges and LayoutData.
	 * 
	 * @return Returns the diagramData.
	 */
	public Diagram getDiagramData()
	{
		// create diagram data file if not present
		if (mainDiagramResource == null || mainDiagramResource.getContents().size() == 0)
		{
			// get the URI for the diagram
			URI fileDiagramUri = mainModelResource.getURI().trimFileExtension()
					.appendFileExtension(WEEditor.getDiagramExtension());
			try
			{
				mainDiagramResource = mainModelResource.getResourceSet().createResource(
						fileDiagramUri);

				// add the initial diagram object to the contents.
				Diagram diagramData = ViewFactoryImpl.eINSTANCE.createDiagram();
				diagramData.setDescribesModel((Model) getModel());
				mainDiagramResource.getContents().add(diagramData);

				// Save the contents of the resource to the file system.
				Map options = new HashMap();
				options.put(XMLResource.OPTION_ENCODING, "UTF-8"); //$NON-NLS-1$
				mainDiagramResource.save(options);
			}
			catch (IOException e)
			{
				logger.severe("couldn't create diagram file " //$NON-NLS-1$
						+ fileDiagramUri.toFileString());
			}
		}

		return (Diagram) mainDiagramResource.getContents().get(0);
	}


	/**
	 * Returns the first activity model available. If none is present, a new
	 * activity is created.
	 * 
	 * @return The first activity model available in the model.
	 */
	public Activity getFirstActivityModel()
	{
		if (!(getModel() instanceof EObject))
		{
			return null;
		}

		// Return the first model element that is an Activity.
		TreeIterator contents = ((EObject) getModel()).eAllContents();
		while (contents.hasNext())
		{
			Object element = contents.next();
			if (element instanceof Activity)
			{
				return (Activity) element;
			}
		}

		// fix: if we don't find an Activity, we simple create one
		Activity activity = ProcessesFactory.eINSTANCE.createActivity();
		((org.eclipse.jwt.meta.model.core.Package) getModel()).getElements()
				.add(activity);
		activity.setName(PluginProperties.wizards_ModelWizardActivity_std);

		return activity;
	}


	/**
	 * Returns the active nested editor if there is one.
	 * 
	 * @return the active nested editor, or <code>null</code> if none
	 */
	public IEditorPart getActiveEditor()
	{
		return super.getActiveEditor();
	}


	/**
	 * Declare additional global actions IDs. Only IDs which were not already
	 * added directly or indirectly using {@link #addGlobalActionKey(String)}
	 * need to be added.
	 * 
	 * Indicates the existence of a global action identified by the specified
	 * key. This global action is defined outside the scope of this contributor,
	 * such as the Workbench's undo action, or an action provided by a workbench
	 * ActionSet. The list of global action keys is used whenever the active
	 * editor is changed ( {@link #setActiveEditor(IEditorPart)}). Keys provided
	 * here will result in corresponding actions being obtained from the active
	 * editor's <code>ActionRegistry</code>, and those actions will be
	 * registered with the ActionBars for this contributor. The editor's action
	 * handler and the global action must have the same key.
	 * 
	 * @see #addGlobalActionKey(String)
	 */
	public ArrayList getGlobalActionKeys()
	{
		ArrayList globalActionIDs = new ArrayList();

		globalActionIDs.add(ActionFactory.DELETE.getId());
		globalActionIDs.add(ActionFactory.UNDO.getId());
		globalActionIDs.add(ActionFactory.REDO.getId());
		globalActionIDs.add(ActionFactory.PRINT.getId());
		globalActionIDs.add(ActionFactory.SELECT_ALL.getId());
		globalActionIDs.add(ActionFactory.CUT.getId());
		globalActionIDs.add(ActionFactory.COPY.getId());
		globalActionIDs.add(ActionFactory.PASTE.getId());

		return globalActionIDs;
	}


	/**
	 * Returns the tab folder.
	 * 
	 * @return the tab folder
	 */
	public CTabFolder getTabFolder()
	{
		return (CTabFolder) getContainer();
	}


	/**
	 * Returns the EditorPropertyUpdater
	 * 
	 * @return EditorPropertyUpdater
	 */
	public EditorPropertyUpdater getEditorPropertyUpdater()
	{
		return editorPropertyUpdater;
	}


	/**
	 * Returns the overview sheet.
	 * 
	 * @return the overview page or <code>null</code>
	 */
	public WEOverviewSheet getOverviewSheet()
	{
		if (overviewPageID != -1)
		{
			return ((WEOverviewSheet) getControl(overviewPageID));
		}

		return null;
	}


	/**
	 * Returns the overviewPageID.
	 * 
	 * @return The overviewPageID
	 */
	public int getOverviewPageID()
	{
		return overviewPageID;
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.part.WorkbenchPart#setPageText(java.lang.Class)
	 */
	@Override
	public void setPageText(int pageIndex, String text)
	{
		if (text == null || text.equals("")) //$NON-NLS-1$
		{
			text = org.eclipse.jwt.meta.PluginProperties.model_Unnamed_name;
		}

		if (pageIndex != -1)
		{
			super.setPageText(pageIndex, text);
		}
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.part.MultiPageEditorPart#getPageText(int)
	 */
	@Override
	public String getPageText(int pageIndex)
	{
		// TODO Auto-generated method stub
		return super.getPageText(pageIndex);
	}


	/**
	 * Returns the selection syncronizer object. The synchronizer can be used to
	 * sync the selection of 2 or more EditPartViewers.
	 * 
	 * @return the synchronizer
	 */
	public SelectionSynchronizer getSelectionSynchronizer()
	{
		if (synchronizer == null)
		{
			synchronizer = new SelectionSynchronizer();
		}
		return synchronizer;
	}


	/**
	 * @return A selectionProvider that handles selections of this editor.
	 */
	public ISelectionProvider getSelectionProvider()
	{
		return getSelectionSynchronizer();
	}


	/**
	 * Returns a MenuListener that builds the default context menu for this
	 * editor.
	 * 
	 * @return A provider that can build the context menu.
	 */
	public IMenuListener getContextMenuProvider()
	{
		return (IMenuListener) getEditorSite().getActionBarContributor();
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
	 */
	@Override
	public Object getAdapter(Class type)
	{
		if (logger.isDebugEnabled())
		{
			logger.debug("type = " + type.getName()); //$NON-NLS-1$
		}

		if (type == IContentOutlinePage.class)
		{
			return getOutlinePage();
		}
		else if (type == IPropertySheetPage.class)
		{
			return getPropertySheetPage();
		}
		else if (EditingDomain.class.isAssignableFrom(type))
		{
			return getEmfEditingDomain();
		}
		else if (AdapterFactory.class.isAssignableFrom(type))
		{
			return getAdapterFactory();
		}
		else if (EditPartViewer.class.isAssignableFrom(type))
		{
			return getCurrentActivitySheet().getGraphicalViewer();
		}
		else if (type == CommandStack.class)
		{
			return getEditDomain().getCommandStack();
		}
		else if (type == ActionRegistry.class)
		{
			return getActionRegistry();
		}
		else if (IMenuListener.class.isAssignableFrom(type))
		{
			return this;
		}
		else if (type == PalettePage.class)
		{
			return getCurrentActivitySheet().getAdapter(PalettePage.class);
		}
		else if (type == EditPart.class
				&& getCurrentActivitySheet().getGraphicalViewer() != null)
		{
			return getCurrentActivitySheet().getGraphicalViewer().getRootEditPart();
		}
		else if (type == IFigure.class
				&& getCurrentActivitySheet().getGraphicalViewer() != null)
		{
			return ((GraphicalEditPart) getCurrentActivitySheet().getGraphicalViewer()
					.getRootEditPart()).getFigure();
		}
		else if (type == ZoomManager.class
				&& getActiveEditor() instanceof IActivityEditor
				&& getCurrentActivitySheet().getGraphicalViewer() != null)
		{
			return getCurrentActivitySheet().getGraphicalViewer().getProperty(
					ZoomManager.class.toString());
		}
		return super.getAdapter(type);
	}


	// ///////////////////////////////////////////////////////////////////////////
	// Creators
	//

	/**
	 * @return Returns the editingDomain.
	 */
	public EditingDomain createEmfEditingDomain()
	{
		// a composedadapterfactory with a reflectiveitemprovideradapterfactory
		ComposedAdapterFactory adapterFactory = new ComposedAdapterFactory(
				ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
		adapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());

		// add a listener (for notify extension point)
		adapterFactory.addListener(new ExtensionPointNotifyChangedListener());

		return new JWTAdapterFactoryEditingDomain(adapterFactory,
				new GefToEmfCommandStackAdapter(editDomain.getCommandStack()));
	}


	/**
	 * This is the method called to load a resource into the editing domain's
	 * resource set based on the editor's input.
	 * 
	 * @throws Exception
	 *             If the resource could not be loaded.
	 */
	public void createModel() throws Exception
	{
		URI resourceUri = null;

		// file in we-open dialog, file in workspace path
		if (getEditorInput() instanceof IFileEditorInput)
		{
			String fileName = ((IFileEditorInput) getEditorInput()).getFile()
					.getFullPath().toString();
			resourceUri = URI.createPlatformResourceURI(fileName, true);
		}
		// file in eclipse-open dialog - not in workspace path
		else if (getEditorInput() instanceof FileStoreEditorInput)
		{
			resourceUri = URI.createFileURI(((FileStoreEditorInput) getEditorInput())
					.getURI().getPath());
		}
		// uri in we-open dialog
		else if (getEditorInput() instanceof IPathEditorInput)
		{
			resourceUri = URI.createFileURI(((IPathEditorInput) getEditorInput())
					.getPath().toPortableString());
		}
		// file open
		else if (getEditorInput() instanceof URIEditorInput)
		{
			resourceUri = ((URIEditorInput) getEditorInput()).getURI();
		}

		// the uri of the view file
		URI viewURI = resourceUri.trimFileExtension().appendFileExtension(
				getDiagramExtension());

		// Load the resource through the editing domain
		try
		{
			// convert the model to the new version if necessary
			Converter.updateModel(resourceUri, GeneralHelper.getWEVersion(),
					!GeneralHelper.isPluginMode());

			// try to load the model resource
			mainModelResource = getEmfEditingDomain().getResourceSet().getResource(
					resourceUri, true);
		}
		catch (Exception e)
		{
			Throwable actualException = (e instanceof WrappedException) ? e.getCause()
					: e;
			if (actualException instanceof PackageNotFoundException)
			{
				PackageNotFoundException packageNotFoundException = (PackageNotFoundException) actualException;

				logger.severe(
						"Could not load input from " + getEditorInput().getName(), e); //$NON-NLS-1$

				MessageDialog.openError(getEditorSite().getShell(),
						PluginProperties.incomplete_jwt_extension_conf_title, NLS.bind(
								PluginProperties.incomplete_jwt_extension_conf_details,
								getEditorInput().getName(),
								packageNotFoundException.uri()));

				// TODO try to read "by hand" profile attrs (url...) and give it
				// to
				// the user
				throw e; // still throw exception so a dummy model will be
				// loaded
			}
			else if (actualException instanceof ClassNotFoundException)
			{
				org.eclipse.emf.ecore.xmi.ClassNotFoundException classNotFoundException = (ClassNotFoundException) actualException;

				// MessageDialog.openError(getEditorSite().getShell(),
				// PluginProperties
				// .getString("editor_ErrorMessage_title"),
				// PluginProperties.getString(
				// "editor_ErrorLoadingFile_message",
				// getEditorInput().getName()));
				MessageDialog
						.openError(
								getEditorSite().getShell(),
								PluginProperties.incorrect_metamodel_extension_definition_title,
								NLS.bind(
										PluginProperties.incorrect_metamodel_extension_definition_details,
										new Object[]
										{
												getEditorInput().getName(),
												classNotFoundException.getName(),
												classNotFoundException.getFactory()
														.getEPackage().getNsURI() }));
				// TODO try to read "by hand" profile attrs (url...) and give it
				// to the
				// user
				throw e; // still throw exception so a dummy model will be
				// loaded

			}
			else
			{
				throw e; // still throw exception so a dummy model will be
				// loaded
			}
		}

		/*
		 * // MDU checking required profiles against installed ones // TODO
		 * check versions, help migrate old ones if
		 * (!AspectManager.INSTANCE.getMissingInstalledProfiles((Model)
		 * getModel()).isEmpty()) { ManageActivatedProfileDialog dialog = new
		 * ManageActivatedProfileDialog( (AdapterFactory)
		 * this.getAdapter(AdapterFactory.class), (EObject) getModel(), false);
		 * dialog.open(); } // TODO if has no ConfModel, propose to migrate ; or
		 * in ManageActivatedProfilesAction ? // TODO handle profile-related
		 * load errors, through converter & load refactoring
		 */

		try
		{
			// try to load the diagram resource
			mainDiagramResource = getEmfEditingDomain().getResourceSet().getResource(
					viewURI, true);
		}
		catch (Exception e)
		{
			// if it failed, create new diagram resource
			getDiagramData();
		}

		// run consistency check for references/referenceedges
		EMFHelper.correctReferences(this, false);
	}


	/**
	 * Creates actions for this editor and register actions with the
	 * {@link ActionRegistry}.
	 */
	protected void createActions()
	{
		ActionRegistry registry = getActionRegistry();

		registry.registerAction(new CopyAction(getEmfEditingDomain(),
				getSelectionProvider()));
		registry.registerAction(new CutAction(getEmfEditingDomain(),
				getSelectionProvider()));
		registry.registerAction(new DeleteAction(getEmfEditingDomain(),
				getSelectionProvider()));
		registry.registerAction(new PasteAction(getEmfEditingDomain(),
				getSelectionProvider()));
		registry.registerAction(new PrintAction(this));
		registry.registerAction(new RedoAction(this));
		registry.registerAction(new UndoAction(this));
		registry.registerAction(new SelectAllAction(this));
		registry.registerAction(new DirectEditAction(this, getSelectionProvider()));
	}


	// ///////////////////////////////////////////////////////////////////////////
	// Initialization / Configuration
	//

	/**
	 * Sets the site and input for this editor then creates and initializes the
	 * actions. Subclasses may extend this method, but should always call
	 * <code>super.init(site, input)
	 * </code>.
	 * 
	 * @see org.eclipse.ui.IEditorPart#init(IEditorSite, IEditorInput)
	 */
	@Override
	public void init(IEditorSite site, IEditorInput input) throws PartInitException
	{
		// add a editor input listener that keeps recent files up to date
		addPropertyListener(new IPropertyListener()
		{

			public void propertyChanged(Object source, int propId)
			{
				if (propId == PROP_INPUT)
				{
					// add to recent files
					if (getEditorInput() instanceof URIEditorInput)
					{
						if (((URIEditorInput) getEditorInput()).getURI().toFileString() != null)
						{
							// file string
							RecentFilesListManager.getInstance().setNewFile(
									((URIEditorInput) getEditorInput()).getURI()
											.toFileString());
						}
						else
						{
							// url string
							RecentFilesListManager.getInstance().setNewFile(
									((URIEditorInput) getEditorInput()).getURI()
											.toString());
						}
					}
					else
					{
						// other
						RecentFilesListManager.getInstance().setNewFile(
								URI.createURI(getEditorInput().getName()).toFileString());
					}
				}
			}
		});

		setSite(site);
		setInputWithNotify(input);
		getEditDomain().getCommandStack().addCommandStackListener(this);
		getSite().setSelectionProvider(getSelectionSynchronizer());
		initializeActionRegistry();
	}


	/**
	 * Initializes the ActionRegistry. This registry may be used by
	 * {@link ActionBarContributor ActionBarContributors} and/or
	 * {@link ContextMenuProvider ContextMenuProviders}.
	 * <P>
	 * This method may be called on Editor creation, or lazily the first time
	 * {@link #getActionRegistry()} is called.
	 */
	protected void initializeActionRegistry()
	{
		createActions();
	}


	// ///////////////////////////////////////////////////////////////////////////
	// Loading / Saving
	//

	/**
	 * Returns <code>true</code> if the command stack is dirty
	 * 
	 * @see org.eclipse.ui.ISaveablePart#isDirty()
	 */
	@Override
	public boolean isDirty()
	{
		return getEditDomain().getCommandStack().isDirty();
	}


	/**
	 * Returns a String that looks like this: c:\modelfile.workflow#processname
	 * This is used for starting an instance of the simulator
	 */
	public String getNameofProcess()
	{
		if (mainModelResource == null || getDisplayedActivityModel() == null)
		{
			return null;
		}

		String pathtoprocess = mainModelResource.getURI().devicePath();
		pathtoprocess = pathtoprocess.replaceAll("%20", " "); //$NON-NLS-1$ //$NON-NLS-2$
		String path = pathtoprocess + "#" + getDisplayedActivityModel().getName(); //$NON-NLS-1$
		return path;
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @seeorg.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.
	 * IProgressMonitor)
	 */
	@Override
	public void doSave(IProgressMonitor monitor)
	{
		logger.enter();
		try
		{
			// run view data garbage collection
			EMFHelper.cleanViewData(this);
			// run consistency check for references/referenceedges
			EMFHelper.correctReferences(this, true);
			// save options
			Map options = new HashMap();
			options.put(XMLResource.OPTION_ENCODING, "UTF-8"); //$NON-NLS-1$
			// save
			mainModelResource.save(options);
			mainDiagramResource.save(options);
			// mark command stack
			getEditDomain().getCommandStack().markSaveLocation();
		}
		catch (Exception e)
		{
			logger.severe("Error saving file " + getEditorInput().getName() + ".", e); //$NON-NLS-1$ //$NON-NLS-2$

			MessageDialog.openError(getEditorSite().getShell(),
					PluginProperties.editor_ErrorMessage_title, NLS.bind(
							PluginProperties.editor_ErrorSavingFile_message,
							getEditorInput().getName()));
		}

		if (getOverviewSheet() != null)
		{
			getOverviewSheet().reloadFileInformation();
		}

		if (monitor != null)
		{
			monitor.done();
		}
	}


	/**
	 * This is a help method for save as. It is a slightly modified save method,
	 * that is called instead of the normal save method.
	 * 
	 * @param monitor
	 */
	private void doSaveAsInternal(IProgressMonitor monitor, String file)
	{
		logger.enter();

		// run view data garbage collection
		EMFHelper.cleanViewData(this);
		// run consistency check for references/referenceedges
		EMFHelper.correctReferences(this, true);

		try
		{
			// save with new uri
			Map options = new HashMap();
			options.put(XMLResource.OPTION_ENCODING, "UTF-8"); //$NON-NLS-1$
			mainModelResource.setURI(URI.createFileURI(file));
			mainModelResource.save(options);
			mainDiagramResource.setURI(mainModelResource.getURI().trimFileExtension()
					.appendFileExtension(WEEditor.getDiagramExtension()));
			mainDiagramResource.save(options);
			getEditDomain().getCommandStack().markSaveLocation();
		}
		catch (Exception e)
		{
			logger.severe("Error saving file " + getEditorInput().getName() + ".", e); //$NON-NLS-1$ //$NON-NLS-2$

			MessageDialog.openError(getEditorSite().getShell(),
					PluginProperties.editor_ErrorMessage_title, NLS.bind(
							PluginProperties.editor_ErrorSavingFile_message,
							getEditorInput().getName()));
		}

		getOverviewSheet().reloadFileInformation();
		monitor.done();
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.part.EditorPart#doSaveAs()
	 */
	@Override
	public void doSaveAs()
	{
		logger.enter();

		// show a SaveAs dialog
		Shell shell = getSite().getWorkbenchWindow().getShell();
		FileDialog fd = new FileDialog(shell, SWT.SAVE);
		String selectedfile = null;
		try
		{
			// set the standard file name
			fd.setFileName(getEditorInput().getName());

			// set the filter extensions
			fd.setFilterExtensions(new String[]
			{ "*." + getWorkflowExtension() }); //$NON-NLS-1$
			selectedfile = fd.open();
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}

		// return, if the dialog was aborted
		if (selectedfile == null)
		{
			return;
		}

		// the file
		final IPath path = new Path(selectedfile);
		final File file = path != null ? path.toFile() : null;

		// return, if file could not be created
		if (file == null)
		{
			MessageDialog.openError(getEditorSite().getShell(),
					PluginProperties.editor_ErrorMessage_title, NLS
							.bind(PluginProperties.editor_ErrorSavingFile_message,
									selectedfile));

			return;
		}

		// return, if destination file is currently open
		IWorkbenchPage workbenchPage = Plugin.getInstance().getWorkbench()
				.getActiveWorkbenchWindow().getActivePage();

		for (IEditorReference editorReference : workbenchPage.getEditorReferences())
		{
			String openFileName = ""; //$NON-NLS-1$
			try
			{
				if (editorReference.getEditorInput() instanceof URIEditorInput)
				{
					openFileName = ((URIEditorInput) editorReference.getEditorInput())
							.getURI().toFileString();
				}
				else if (editorReference.getEditorInput() instanceof FileStoreEditorInput)
				{
					openFileName = URI.createFileURI(
							((FileStoreEditorInput) editorReference.getEditorInput())
									.getURI().getPath()).toFileString();
				}
				else
				{
					openFileName = editorReference.getEditorInput().getName();
				}
			}
			catch (PartInitException e)
			{
			}

			if (openFileName.equals(selectedfile))
			{
				MessageDialog.openError(getEditorSite().getShell(),
						PluginProperties.editor_ErrorMessage_title, NLS.bind(
								PluginProperties.editor_ErrorCurrentlyOpen_message,
								selectedfile));
				return;
			}
		}

		// return, if the file already exists and should not be overwritten
		if (file.exists()
				&& !MessageDialog.openQuestion(getEditorSite().getShell(),
						PluginProperties.editor_QuestionOverwriteFile_title, NLS.bind(
								PluginProperties.editor_QuestionOverwriteFile_message,
								selectedfile)))
		{
			return;
		}

		// save
		try
		{
			WorkspaceModifyOperation operation = new WorkspaceModifyOperation()
			{

				@Override
				public void execute(final IProgressMonitor monitor)
				{
					String pathtofile = path.makeAbsolute().toFile().getAbsolutePath();
					doSaveAsInternal(monitor, pathtofile);
					setInputWithNotify(new URIEditorInput(mainModelResource.getURI()));
				}
			};

			new ProgressMonitorDialog(shell).run(false, // don't fork
					false, // not cancelable
					operation);
		}
		catch (InterruptedException ie)
		{
			// should not happen, since the monitor dialog is not
			// cancelable
			logger.warning(ie);
		}
		catch (InvocationTargetException ite)
		{
			logger.warning(ite);
		}
		catch (Exception e)
		{
			MessageDialog.openError(getEditorSite().getShell(),
					PluginProperties.editor_ErrorMessage_title, NLS
							.bind(PluginProperties.editor_ErrorSavingFile_message,
									selectedfile));
		}
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
	 */
	@Override
	public boolean isSaveAsAllowed()
	{
		return true;
	}


	// ///////////////////////////////////////////////////////////////////////////
	// Implementations of Interfaces / handling of changes
	//

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.gef.commands.CommandStackListener#commandStackChanged(java
	 * .util.EventObject )
	 */
	public void commandStackChanged(EventObject event)
	{
		firePropertyChange(IEditorPart.PROP_DIRTY);

		// update property sheet page
		final IPropertySheetPage localPropertySheetPage = propertySheetPage;

		if (localPropertySheetPage != null)
		{
			getEditorSite().getShell().getDisplay().asyncExec(new Runnable()
			{

				public void run()
				{
					if (!(localPropertySheetPage.getControl() == null)
							&& (!localPropertySheetPage.getControl().isDisposed()))
					{
						// refresh normal or multitab property sheet
						if (localPropertySheetPage instanceof PropertySheetPage)
						{
							((PropertySheetPage) localPropertySheetPage).refresh();
						}
						else if (localPropertySheetPage != null
								&& ((TabbedPropertySheetPage) localPropertySheetPage)
										.getCurrentTab() != null)
						{
							((TabbedPropertySheetPage) localPropertySheetPage).refresh();
						}
					}
				}
			});
		}
	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.jface.action.IMenuListener#menuAboutToShow(org.eclipse.jface
	 * .action .IMenuManager)
	 */
	public void menuAboutToShow(IMenuManager manager)
	{
		// delegate to actionBarContributer
		((IMenuListener) getEditorSite().getActionBarContributor())
				.menuAboutToShow(manager);
	}


	/**
	 * Update the title of the editor with the information of the current sheet.
	 */
	public void updateTitleName()
	{
		// set the tab name (either activity name oder overview page)
		String newTitle;

		// get the title
		if (getActiveEditor() instanceof IActivityEditor)
		{
			newTitle = getDisplayedActivityModel().getName();
		}
		else
		{
			newTitle = getTabFolder().getItem(getActivePage()).getText();
		}

		// make sure it is not null
		if (newTitle == null || newTitle.length() == 0)
		{
			newTitle = org.eclipse.jwt.meta.PluginProperties
					.model_Unnamed_name(getDisplayedActivityModel());
		}

		// set the title of the editor part
		setPartName(PluginProperties.editor_Title_text(newTitle, getEditorInput()
				.getName()));
	}


	/**
	 * Updates the icon of the editor with the information of the current sheet.
	 */
	public void updateTitleImage()
	{
		titleImage = null;

		// get image from displayed activity
		Activity activity = getDisplayedActivityModel();

		// if activity is displayed, get image from activity
		if (activity != null)
		{
			IItemLabelProvider itemLabelProvider = (IItemLabelProvider) getAdapterFactory()
					.adapt(activity, IItemLabelProvider.class);

			if (itemLabelProvider != null)
			{
				ImageDescriptor titleImageDescriptor = (ImageDescriptor) itemLabelProvider
						.getImage(activity);

				if (titleImageDescriptor != null)
				{
					titleImage = Plugin.getDefault().getFactoryRegistry()
							.getImageFactory().getImage(titleImageDescriptor);
				}
			}
		}

		if (titleImage == null)
		{
			titleImage = Plugin
					.getDefault()
					.getFactoryRegistry()
					.getImageFactory()
					.getImage(
							Plugin.getInstance()
									.getFactoryRegistry()
									.getImageFactory(
											Views.getInstance().getSelectedView())
									.createImageDescriptor(
											PluginProperties.model_Activity_icon));
		}

		setTitleImage(titleImage);
	}


	/**
	 * Custom closing message.
	 */
	public int promptToSaveOnClose()
	{
		String title = PluginProperties.editor_Closing_title;
		String message = NLS.bind(PluginProperties.editor_Closing_message,
				getEditorInput().getName());
		String yes = PluginProperties.editor_Yes_message;
		String no = PluginProperties.editor_No_message;
		String cancel = PluginProperties.editor_Cancel_message;

		return (new MessageDialog(getEditorSite().getShell(), title, null, message,
				MessageDialog.INFORMATION, new String[]
				{ yes, no, cancel }, 0)).open();
	}


	// ///////////////////////////////////////////////////////////////////////////
	// Cleanup
	//

	@Override
	public void dispose()
	{
		super.dispose();

		if (partActivationListener != null)
		{
			getSite().getWorkbenchWindow().getPartService()
					.removePartListener(partActivationListener);
			partActivationListener = null;
		}

		if (editorPropertyUpdater != null)
		{
			editorPropertyUpdater.dispose();
		}
		if (editorTabUpdater != null)
		{
			editorTabUpdater.dispose();
		}

		if (bindingManagerListener != null)
		{
			IBindingService bindingService = (IBindingService) Plugin.getDefault()
					.getWorkbench().getService(IBindingService.class);
			bindingService.removeBindingManagerListener(bindingManagerListener);
			bindingManagerListener = null;
		}

		getEditDomain().getCommandStack().removeCommandStackListener(this);
		getSite().setSelectionProvider(null);

		getEditDomain().setActiveTool(null);
		getActionRegistry().dispose();

		((ComposedAdapterFactory) getAdapterFactory()).dispose();
		// getSelectionSynchronizer().removeSelectionProvider(getActivitySheet().
		// getGraphicalViewer());

		if (outlinePage != null)
		{
			outlinePage.dispose();
			outlinePage = null;
		}

		if (propertySheetPage != null)
		{
			propertySheetPage.dispose();
			propertySheetPage = null;
		}

		if (titleImage != null)
		{
			titleImage = null;
		}

		setEditDomain(null);

		// deregister icon and visibility provider with the meta model
		ResourceProviderRegistry.getInstance().deregisterImageProvider(this);
		ResourceProviderRegistry.getInstance().deregisterVisibilityProvider(this);
		ResourceProviderRegistry.getInstance().deregisterCommandProvider(this);

		GeneralHelper.deregisterEditor(this);

		// if loading failed, make sure everything is back to initial state
		GeneralHelper.setInitializingEditor(null);
		ResourceProviderRegistry.getInstance().setInitializingEditor(null);
	}

}