/*******************************************************************************
* Copyright (c) 2011 Red Hat, Inc.
* All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.eclipse.bpmn2.modeler.ui.editor;
import java.io.IOException;
import org.eclipse.bpmn2.modeler.core.ModelHandler;
import org.eclipse.bpmn2.modeler.core.ModelHandlerLocator;
import org.eclipse.bpmn2.modeler.core.ProxyURIConverterImplExtension;
import org.eclipse.bpmn2.modeler.core.di.DIImport;
import org.eclipse.bpmn2.modeler.core.utils.ModelUtil;
import org.eclipse.bpmn2.modeler.ui.Activator;
import org.eclipse.bpmn2.modeler.ui.util.ErrorUtils;
import org.eclipse.bpmn2.modeler.ui.wizards.BPMN2DiagramCreator;
import org.eclipse.bpmn2.util.Bpmn2ResourceImpl;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
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.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.command.BasicCommandStack;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.transaction.ExceptionHandler;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalCommandStack;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.TransactionalEditingDomain.Lifecycle;
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
import org.eclipse.graphiti.ui.editor.DiagramEditor;
import org.eclipse.graphiti.ui.editor.DiagramEditorInput;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchListener;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.WorkbenchAdvisor;
/**
*
*/
@SuppressWarnings("restriction")
public class BPMN2Editor extends DiagramEditor {
public static String EDITOR_ID = "org.eclipse.bpmn2.modeler.ui.bpmn2editor";
private ModelHandler modelHandler;
private URI modelUri;
private URI diagramUri;
private IFile modelFile;
private IFile diagramFile;
private IWorkbenchListener workbenchListener;
private boolean workbenchShutdown = false;
private BPMN2EditingDomainListener editingDomainListener;
@Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
try {
if (input instanceof IFileEditorInput) {
modelFile = ((IFileEditorInput) input).getFile();
input = createNewDiagramEditorInput();
} else if (input instanceof DiagramEditorInput) {
getModelPathFromInput((DiagramEditorInput) input);
// This was incorrectly constructed input, we ditch the old one and make a new and clean one instead
input = createNewDiagramEditorInput();
}
} catch (CoreException e) {
Activator.showErrorWithLogging(e);
}
// add a listener so we get notified if the workbench is shutting down.
// in this case we don't want to delete the temp file!
addWorkbenchListener();
super.init(site, input);
}
private void getModelPathFromInput(DiagramEditorInput input) {
URI uri = input.getDiagram().eResource().getURI();
String uriString = uri.trimFragment().toPlatformString(true);
modelFile = BPMN2DiagramCreator.getModelFile(new Path(uriString));
}
/**
* Beware, creates a new input and changes this editor!
*/
private IEditorInput createNewDiagramEditorInput() throws CoreException {
IPath fullPath = modelFile.getFullPath();
modelUri = URI.createPlatformResourceURI(fullPath.toString(), true);
IFolder folder = BPMN2DiagramCreator.getTempFolder(fullPath);
diagramFile = BPMN2DiagramCreator.getTempFile(fullPath,folder);
// Create new temporary diagram file
BPMN2DiagramCreator creator = new BPMN2DiagramCreator();
creator.setDiagramFile(diagramFile);
IEditorInput input = creator.createDiagram(false);
diagramUri = creator.getUri();
return input;
}
@Override
public void doSave(IProgressMonitor monitor) {
modelHandler.save();
((BasicCommandStack) getEditingDomain().getCommandStack()).saveIsDone();
}
@Override
protected void setInput(IEditorInput input) {
super.setInput(input);
// Hook a transaction exception handler so we can get diagnostics about EMF validation errors.
getEditingDomainListener();
BasicCommandStack basicCommandStack = (BasicCommandStack) getEditingDomain().getCommandStack();
if (input instanceof DiagramEditorInput) {
ResourceSet resourceSet = getEditingDomain().getResourceSet();
Bpmn2ResourceImpl bpmnResource = (Bpmn2ResourceImpl) resourceSet.createResource(modelUri,
"org.eclipse.bpmn2.content-type.xml");
resourceSet.setURIConverter(new ProxyURIConverterImplExtension());
modelHandler = ModelHandlerLocator.createModelHandler(modelUri, bpmnResource);
ModelHandlerLocator.put(diagramUri, modelHandler);
try {
if (modelFile.exists()) {
bpmnResource.load(null);
} else {
doSave(null);
}
} catch (IOException e) {
Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e);
ErrorUtils.showErrorWithLogging(status);
}
basicCommandStack.execute(new RecordingCommand(getEditingDomain()) {
@Override
protected void doExecute() {
importDiagram();
}
});
}
basicCommandStack.saveIsDone();
}
private void importDiagram() {
DIImport di = new DIImport();
di.setDiagram(getDiagramTypeProvider().getDiagram());
di.setDomain(getEditingDomain());
di.setModelHandler(modelHandler);
di.setFeatureProvider(getDiagramTypeProvider().getFeatureProvider());
di.generateFromDI();
}
private void addWorkbenchListener() {
if (workbenchListener==null) {
workbenchListener = new IWorkbenchListener() {
@Override
public boolean preShutdown(IWorkbench workbench, boolean forced) {
workbenchShutdown = true;
return true;
}
@Override
public void postShutdown(IWorkbench workbench) {
}
};
PlatformUI.getWorkbench().addWorkbenchListener(workbenchListener);
}
}
private void removeWorkbenchListener()
{
if (workbenchListener!=null) {
PlatformUI.getWorkbench().removeWorkbenchListener(workbenchListener);
workbenchListener = null;
}
}
public BPMN2EditingDomainListener getEditingDomainListener() {
if (editingDomainListener==null) {
TransactionalEditingDomainImpl editingDomain = (TransactionalEditingDomainImpl)getEditingDomain();
if (editingDomain==null) {
return null;
}
editingDomainListener = new BPMN2EditingDomainListener(this);
Lifecycle domainLifeCycle = (Lifecycle) editingDomain.getAdapter(Lifecycle.class);
domainLifeCycle.addTransactionalEditingDomainListener(editingDomainListener);
}
return editingDomainListener;
}
public BasicDiagnostic getDiagnostics() {
return getEditingDomainListener().getDiagnostics();
}
public void showErrorMessage(String msg) {
IWorkbench wb = PlatformUI.getWorkbench();
IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
IWorkbenchPage page = win.getActivePage();
IWorkbenchPart part = page.getActivePart();
IWorkbenchPartSite site = part.getSite();
IViewSite vSite = ( IViewSite ) site;
IActionBars actionBars = vSite.getActionBars();
if( actionBars == null )
return;
IStatusLineManager statusLineManager = actionBars.getStatusLineManager();
if( statusLineManager == null )
return;
statusLineManager.setErrorMessage(msg);
statusLineManager.markDirty();
statusLineManager.update(true);
}
@Override
public void dispose() {
// clear ID mapping tables if no more instances of editor are active
int instances = 0;
IWorkbenchPage[] pages = getEditorSite().getWorkbenchWindow().getPages();
for (IWorkbenchPage p : pages) {
IEditorReference[] refs = p.getEditorReferences();
instances += refs.length;
}
ModelUtil.clearIDs(modelHandler.getResource(), instances==0);
super.dispose();
ModelHandlerLocator.releaseModel(modelUri);
// get rid of temp files and folders, but only if the workbench is being shut down.
// when the workbench is restarted, we need to have those temp files around!
if (!workbenchShutdown)
BPMN2DiagramCreator.dispose(diagramFile);
removeWorkbenchListener();
}
public IFile getModelFile() {
return modelFile;
}
}