Project: BPMN2-Editor-for-Eclipse
/******************************************************************************* 
 * 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; 
 
}