/***************************************************************************** * Copyright (c) 2008 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: * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.infra.gmfdiag.common; import java.util.ArrayList; import java.util.List; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.transaction.RecordingCommand; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.common.core.command.CompositeCommand; import org.eclipse.gmf.runtime.common.core.command.ICommand; import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint; import org.eclipse.gmf.runtime.diagram.core.services.ViewService; import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyElementRequest; import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.papyrus.commands.DestroyElementPapyrusCommand; import org.eclipse.papyrus.commands.wrappers.GMFtoEMFCommandWrapper; import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor; import org.eclipse.papyrus.infra.core.extension.commands.ICreationCommand; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageMngr; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider; import org.eclipse.papyrus.infra.core.services.ServiceException; import org.eclipse.papyrus.infra.core.services.ServicesRegistry; import org.eclipse.papyrus.infra.core.ui.IRevealSemanticElement; import org.eclipse.papyrus.infra.core.utils.BusinessModelResolver; import org.eclipse.papyrus.infra.core.utils.DiResourceSet; import org.eclipse.papyrus.infra.core.utils.EditorUtils; import org.eclipse.papyrus.infra.core.utils.OpenDiagramCommand; import org.eclipse.papyrus.views.modelexplorer.NavigatorUtils; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PlatformUI; /** * Command creating a new GMF diagram in Papyrus. This command is intended to be used in eclipse * extensions. * * Commands to create a GMF Diagram can subclass this class. There is two kinds of commands: - * Eclipse handlers issuing commands (toolbar, menu, ...). This commands can find the active editor * by using the Worbench.getActivePArt(). The entry point is {@link #execute(ExecutionEvent)}. - * Commands called during editor initializing (like wizard). This commands require the diResourceSet * to work. The entry point is {@link #createDiagram(DiResourceSet, EObject, String)} * * @author cedric dumoulin * @author <a href="mailto:jerome.benois@obeo.fr">Jerome Benois</a> */ public abstract class AbstractPapyrusGmfCreateDiagramCommandHandler extends AbstractHandler implements IHandler, ICreationCommand { /** * Method called when the command is invoked. */ public Object execute(ExecutionEvent event) throws ExecutionException { EObject container = null; // if editor is open and active if(getMultiDiagramEditor() != null) { container = getSelectedElement(); } runAsTransaction(container); return null; } /** * Create a new class diagram * * @param sharedObjects * @param container * The uml element to which the diagram should be attached, if possible. * @throws ExecutionException */ protected void runAsTransaction(EObject container) throws ExecutionException { DiResourceSet diResourceSet; try { diResourceSet = EditorUtils.getServiceRegistry().getService(DiResourceSet.class); } catch (ServiceException e) { throw new ExecutionException("Can't get diResourceSet", e); } runAsTransaction(diResourceSet, container, null); } /** * Create a new gmf diagram * * @param sharedObjects * @param container * The eObject to which the diagram should be attached, if possible. */ protected void runAsTransaction(final DiResourceSet diResourceSet, final EObject container, String name) { TransactionalEditingDomain dom = diResourceSet.getTransactionalEditingDomain(); CompositeCommand cmd = new CompositeCommand("Create diagram"); ICommand createCmd = getCreateDiagramCommand(diResourceSet, container, name); cmd.add(createCmd); cmd.add(new OpenDiagramCommand(dom, createCmd)); dom.getCommandStack().execute(new GMFtoEMFCommandWrapper(cmd)); } /** * Get the root element associated with canvas. */ protected EObject getRootElement(Resource modelResource) { EObject rootElement = null; if(modelResource != null && modelResource.getContents() != null && modelResource.getContents().size() > 0) { Object root = modelResource.getContents().get(0); if(root instanceof EObject) { rootElement = (EObject)root; } } return rootElement; } /** * Store model element in the resource. */ protected void attachModelToResource(EObject root, Resource resource) { resource.getContents().add(root); } /** * Get the type of the diagram to create. * * @return diagram type */ public String getCreatedDiagramType() { return getDiagramNotationID(); } /** * @return */ abstract protected String getDiagramNotationID(); /** * @return */ abstract protected PreferencesHint getPreferenceHint(); /** * Get the name used for diagram. * * @return */ abstract protected String getDefaultDiagramName(); /** * Get currently selected element. * * @return The currently selected element, or null if any. */ protected EObject getSelectedElement() { EObject eObject = null; Object selection = getCurrentSelection(); if(selection != null) { Object businessObject = BusinessModelResolver.getInstance().getBusinessModel(selection); if(businessObject instanceof EObject) { eObject = (EObject)businessObject; } } return eObject; } /** * Get current selection first element. * * @return the selected element or null. */ private Object getCurrentSelection() { ISelection selection = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection(); if(selection instanceof IStructuredSelection) { IStructuredSelection structuredSelection = (IStructuredSelection)selection; return structuredSelection.getFirstElement(); } return null; } /** * Create a diagram. * * @param diagramResource * the diagram resource * @param owner * the diagram container * @param name * the diagram name * @return */ protected Diagram createDiagram(Resource diagramResource, EObject owner, String name) { // create diagram Diagram diagram = ViewService.createDiagram(owner, getDiagramNotationID(), getPreferenceHint()); if(diagram != null) { diagram.setName(name); diagram.setElement(owner); initializeDiagram(diagram); diagramResource.getContents().add(diagram); } return diagram; } protected void initializeDiagram(EObject diagram) { }; /** * Get the current MultiDiagramEditor. * * @return */ protected IMultiDiagramEditor getMultiDiagramEditor() { IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); IEditorPart editorPart = page.getActiveEditor(); return (IMultiDiagramEditor)editorPart; } /** * Open popup to enter the new diagram name * * @param defaultValue * the default value * @return the entered diagram name */ protected String openDiagramNameDialog(String defaultValue) { if(defaultValue == null) { defaultValue = ""; } InputDialog inputDialog = new InputDialog(Display.getCurrent().getActiveShell(), Messages.AbstractPapyrusGmfCreateDiagramCommandHandler_SelectNewDiagramName, Messages.AbstractPapyrusGmfCreateDiagramCommandHandler_NewDiagramName, defaultValue, null); int result = inputDialog.open(); if(result == Window.OK) { String name = inputDialog.getValue(); if(name == null || name.length() == 0) { name = defaultValue; } return name; } return null; } /** * {@inheritDoc} */ public void createDiagram(final DiResourceSet diResourceSet, final EObject container, final String diagramName) { TransactionalEditingDomain transactionalEditingDomain = diResourceSet.getTransactionalEditingDomain(); RecordingCommand command = new RecordingCommand(transactionalEditingDomain) { @Override protected void doExecute() { runAsTransaction(diResourceSet, container, diagramName); } }; transactionalEditingDomain.getCommandStack().execute(command); } /** * {@inheritDoc} */ public ICommand getCreateDiagramCommand(final DiResourceSet diResourceSet, final EObject container, final String diagramName) { final Resource modelResource = diResourceSet.getAssociatedModelResource(container); final Resource notationResource = diResourceSet.getAssociatedNotationResource(container); final Resource diResource = diResourceSet.getAssociatedDiResource(container); ArrayList<IFile> modifiedFiles = new ArrayList<IFile>(); modifiedFiles.add(ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(modelResource.getURI().toPlatformString(true)))); modifiedFiles.add(ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(notationResource.getURI().toPlatformString(true)))); modifiedFiles.add(ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(diResource.getURI().toPlatformString(true)))); return new AbstractTransactionalCommand(diResourceSet.getTransactionalEditingDomain(), Messages.AbstractPapyrusGmfCreateDiagramCommandHandler_CreateDiagramCommandLabel, modifiedFiles) { protected Diagram diagram = null; @Override protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { String name = diagramName; if(name == null) { name = openDiagramNameDialog(getDefaultDiagramName()); } // canceled if(name == null) { return CommandResult.newCancelledCommandResult(); } EObject model = container; if(model == null) { model = getRootElement(modelResource); attachModelToResource(model, modelResource); } diagram = createDiagram(notationResource, model, name); if(diagram != null) { IPageMngr pageMngr = EditorUtils.getIPageMngr(diResource); pageMngr.addPage(diagram); return CommandResult.newOKCommandResult(diagram); } return CommandResult.newErrorCommandResult("Error during diagram creation"); } @Override protected IStatus doUndo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { // the undo corresponds to a destroy diagram command // during diagram creation no adapters are set to the diagram so the setElement is not registered // to remove the cross reference using the element reference it is better to use the destroy element command DestroyElementPapyrusCommand depc = (diagram != null) ? new DestroyElementPapyrusCommand(new DestroyElementRequest(diagram, false)) : null; IStatus status = super.doUndo(monitor, info); if (depc != null) { depc.execute(null, null); } return status; } }; } /** * Get the ServiceRegistry of the main editor. * * @return */ protected ServicesRegistry getServiceRegistry() { return EditorUtils.getServiceRegistry(); } /** * Get the ISashWindowsContentProvider from the main editor. * * @return */ protected ISashWindowsContentProvider getISashWindowsContentProvider() { return EditorUtils.getISashWindowsContentProvider(); } /** * Check if the creation of this diagram is strongly attached to its parent or if it can be reassigned after creation. * * @return true if parent can be reassigned */ public boolean isParentReassignable() { // yes by default return true; } }