| /****************************************************************************** |
| * Copyright (c) 2004, 2006 IBM Corporation and others. |
| * 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: |
| * IBM Corporation - initial API and implementation |
| ****************************************************************************/ |
| |
| package org.eclipse.gmf.runtime.diagram.ui.commands; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.ListIterator; |
| |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.workspace.util.WorkspaceSynchronizer; |
| import org.eclipse.gef.EditPart; |
| import org.eclipse.gef.commands.Command; |
| import org.eclipse.gmf.runtime.common.core.command.AbstractCommand; |
| import org.eclipse.gmf.runtime.common.core.command.CommandResult; |
| import org.eclipse.gmf.runtime.common.core.command.ICommand; |
| import org.eclipse.gmf.runtime.common.core.util.ObjectAdapter; |
| import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages; |
| import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramCommandStack; |
| import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest; |
| import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequestFactory; |
| import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil; |
| import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; |
| import org.eclipse.gmf.runtime.emf.type.core.IElementType; |
| import org.eclipse.gmf.runtime.notation.View; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.MessageBox; |
| |
| /** |
| * A command used to optionally create a new view and new element. This command |
| * is used when it is not known at command creation time whether or not an |
| * element should be created as well. For example, when creating a connection to |
| * an unspecified target, did the user want to |
| * <li>create a new element for the target (view and element)?</li> |
| * <li>use an existing element and its view already on the diagram (nothing |
| * created)?</li> |
| * <li>use an existing element and add a new view to the diagram (view only)? |
| * |
| * <p> |
| * Note: This command will pop up a dialog box if the element exists already and |
| * there is a view for it on the diagram to ask the user what they want to do. |
| * </p> |
| * |
| * @author cmahoney |
| */ |
| public class CreateViewAndOptionallyElementCommand |
| extends AbstractCommand { |
| |
| /** |
| * Adapts to the element, if null at command execution time, an element is |
| * to be created. |
| */ |
| private IAdaptable elementAdapter; |
| |
| /** The location to create the new view. */ |
| private Point location; |
| |
| /** The container editpart to send the view request to. */ |
| private IGraphicalEditPart containerEP; |
| |
| /** The command executed, saved for undo/redo. */ |
| private Command command = null; |
| |
| /** The result to be returned from which the new view can be retrieved. */ |
| private ObjectAdapter resultAdapter = new ObjectAdapter(); |
| |
| /** |
| * The hint used to find the appropriate preference store from which general |
| * diagramming preference values for properties of shapes, connections, and |
| * diagrams can be retrieved. This hint is mapped to a preference store in |
| * the {@link DiagramPreferencesRegistry}. |
| */ |
| private PreferencesHint preferencesHint; |
| |
| /** |
| * Creates a new <code>CreateViewAndOptionallyElementCommand</code>. |
| * |
| * @param elementAdapter |
| * Adapts to the element, if null at command execution time, an |
| * element is to be created. |
| * @param containerEP |
| * The container edit part, where the view request is sent. |
| * @param location |
| * The location to create the new view. If null, a default |
| * location is used |
| * @param preferencesHint |
| * The preference hint that is to be used to find the appropriate |
| * preference store from which to retrieve diagram preference |
| * values. The preference hint is mapped to a preference store in |
| * the preference registry <@link DiagramPreferencesRegistry>. |
| */ |
| public CreateViewAndOptionallyElementCommand(IAdaptable elementAdapter, |
| IGraphicalEditPart containerEP, Point location, PreferencesHint preferencesHint) { |
| super(DiagramUIMessages.CreateCommand_Label, null); |
| |
| setElementAdapter(elementAdapter); |
| setContainerEP(containerEP); |
| if (location != null) { |
| setLocation(location); |
| } else { |
| setLocation(getContainerEP().getFigure().getBounds().getTopRight() |
| .translate(100, 100)); |
| } |
| setPreferencesHint(preferencesHint); |
| } |
| |
| public List getAffectedFiles() { |
| if (containerEP != null) { |
| View view = (View)containerEP.getModel(); |
| if (view != null) { |
| IFile f = WorkspaceSynchronizer.getFile(view.eResource()); |
| return f != null ? Collections.singletonList(f) : Collections.EMPTY_LIST; |
| } |
| } |
| |
| return super.getAffectedFiles(); |
| } |
| |
| /** |
| * Searches the container editpart to see if the element passed in already |
| * has a view. |
| * |
| * @param element |
| * @return IView the view if found; or null |
| */ |
| protected View getExistingView(EObject element) { |
| IGraphicalEditPart theTarget = (IGraphicalEditPart) findChildEditPart( |
| getContainerEP(), element); |
| if (theTarget != null) |
| return (View) theTarget.getModel(); |
| return null; |
| } |
| |
| /** |
| * Returns an immediate child editpart of the editpart passed in whose |
| * element is the same as the element passed in if it exists; returns null |
| * if such an editpart does not exist. |
| * |
| * @param editpart |
| * the parent editpart |
| * @param theElement |
| * the element to match |
| * @return an immediate child editpart of the editpart passed in whose |
| * element is the same as the element passed in if it exists; null |
| * otherwise |
| */ |
| private EditPart findChildEditPart(EditPart editpart, EObject theElement) { |
| if (theElement == null) { |
| return null; |
| } |
| |
| ListIterator childLI = editpart.getChildren().listIterator(); |
| while (childLI.hasNext()) { |
| EditPart epChild = (EditPart) childLI.next(); |
| Object model = epChild.getModel(); |
| |
| if (model instanceof View) { |
| EObject el = ((View) model).getElement(); |
| |
| if ((el != null) && el.equals(theElement)) { |
| return epChild; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Prompts the user to see if they would like to use an existing view on the |
| * diagram. Clients may subclass this method to customize the message |
| * dialog. |
| * |
| * @param view |
| * the existing view |
| * @return true if this view should be used; false otherwise |
| */ |
| protected boolean useExistingView(View view) { |
| MessageBox messageBox = new MessageBox(Display.getCurrent() |
| .getActiveShell(), SWT.YES | SWT.NO); |
| messageBox |
| .setText(DiagramUIMessages.CreateViewAndOptionallyElementCommand_ViewExists_Title); |
| messageBox |
| .setMessage(NLS |
| .bind( |
| DiagramUIMessages.CreateViewAndOptionallyElementCommand_ViewExists_Message, |
| EMFCoreUtil.getName(view.getElement()))); |
| return messageBox.open() == SWT.YES; |
| } |
| |
| /** |
| * <li>If the element adapter is empty, this command creates a new element |
| * and view for it.</li> |
| * <li>If the element adapter is not empty, and a view for this element |
| * exists in the container, this command will prompt the user to see if they |
| * want to use the existing view or create a new view for the element and |
| * then execute accordingly.</li> |
| * <li>If the element adapter is not empty, and a view for this element |
| * does not exist in the container, this command will create a new element |
| * and view.</li> |
| * |
| */ |
| protected CommandResult doExecuteWithResult( |
| IProgressMonitor progressMonitor, IAdaptable info) |
| throws ExecutionException { |
| |
| CreateViewRequest createRequest; |
| |
| // Create the element first, if one does not exist. |
| EObject element = (EObject) getElementAdapter().getAdapter( |
| EObject.class); |
| if (element == null) { |
| IElementType type = (IElementType) getElementAdapter() |
| .getAdapter(IElementType.class); |
| if (type == null) { |
| return CommandResult.newErrorCommandResult(getLabel()); |
| } |
| createRequest = CreateViewRequestFactory |
| .getCreateShapeRequest(type, getPreferencesHint()); |
| } else { |
| createRequest = new CreateViewRequest( |
| new CreateViewRequest.ViewDescriptor( |
| new EObjectAdapter(element), getPreferencesHint())); |
| } |
| createRequest.setLocation(getLocation()); |
| |
| if (createRequest != null) { |
| IGraphicalEditPart target = (IGraphicalEditPart) getContainerEP().getTargetEditPart(createRequest); |
| if ( target != null ) { |
| Command theCmd = target.getCommand(createRequest); |
| setCommand(theCmd); |
| |
| View theExistingView = getExistingView(element); |
| |
| if (theExistingView != null && useExistingView(theExistingView)) { |
| setResult(new EObjectAdapter(theExistingView)); |
| return CommandResult.newOKCommandResult(getResult()); |
| } |
| // Fall-thru and create a new view |
| if (getCommand().canExecute()) { |
| ICommand cmd = DiagramCommandStack.getICommand(getCommand()); |
| cmd.execute(progressMonitor, info); |
| if (progressMonitor.isCanceled()) { |
| return CommandResult.newCancelledCommandResult(); |
| }else if (!(cmd.getCommandResult().getStatus().isOK())){ |
| return cmd.getCommandResult(); |
| } |
| Object obj = ((List) createRequest.getNewObject()).get(0); |
| setResult((IAdaptable) obj); |
| return CommandResult.newOKCommandResult(getResult()); |
| } |
| } |
| } |
| containerEP = null;// to allow garbage collection |
| return CommandResult.newErrorCommandResult(getLabel()); |
| } |
| |
| public boolean canUndo() { |
| return getCommand() != null && getCommand().canUndo(); |
| } |
| |
| public boolean canRedo() { |
| return CommandUtilities.canRedo(command); |
| } |
| |
| |
| protected CommandResult doRedoWithResult(IProgressMonitor progressMonitor, IAdaptable info) |
| throws ExecutionException { |
| |
| if (getCommand() != null) { |
| getCommand().redo(); |
| } |
| return CommandResult.newOKCommandResult(); |
| } |
| |
| protected CommandResult doUndoWithResult(IProgressMonitor progressMonitor, IAdaptable info) |
| throws ExecutionException { |
| |
| if (getCommand() != null) { |
| getCommand().undo(); |
| } |
| return CommandResult.newOKCommandResult(); |
| } |
| |
| /** |
| * @return the adapter from which the view can be retrieved. |
| */ |
| public IAdaptable getResult() { |
| return resultAdapter; |
| } |
| |
| /** |
| * Sets the result to adapt to the view passed in. |
| * @param viewAdapter |
| */ |
| protected void setResult(IAdaptable viewAdapter) { |
| View view = (View) viewAdapter.getAdapter(View.class); |
| resultAdapter.setObject(view); |
| } |
| |
| /** |
| * Gets the elementAdapter. |
| * @return Returns the elementAdapter. |
| */ |
| protected IAdaptable getElementAdapter() { |
| return elementAdapter; |
| } |
| |
| /** |
| * Sets the elementAdapter. |
| * @param elementAdapter The elementAdapter to set. |
| */ |
| protected void setElementAdapter(IAdaptable elementAdapter) { |
| this.elementAdapter = elementAdapter; |
| } |
| |
| /** |
| * Gets the location. |
| * @return Returns the location. |
| */ |
| protected Point getLocation() { |
| return location; |
| } |
| |
| /** |
| * Sets the location. |
| * @param location The location to set. |
| */ |
| protected void setLocation(Point location) { |
| this.location = location; |
| } |
| |
| /** |
| * Gets the containerEP. |
| * @return Returns the containerEP. |
| */ |
| protected IGraphicalEditPart getContainerEP() { |
| return containerEP; |
| } |
| |
| /** |
| * Sets the containerEP. |
| * @param containerEP The containerEP to set. |
| */ |
| protected void setContainerEP(IGraphicalEditPart containerEP) { |
| this.containerEP = containerEP; |
| } |
| |
| /** |
| * Gets the preferences hint that is to be used to find the appropriate |
| * preference store from which to retrieve diagram preference values. The |
| * preference hint is mapped to a preference store in the preference |
| * registry <@link DiagramPreferencesRegistry>. |
| * |
| * @return the preferences hint |
| */ |
| protected PreferencesHint getPreferencesHint() { |
| return preferencesHint; |
| } |
| |
| /** |
| * Sets the preferences hint that is to be used to find the appropriate |
| * preference store from which to retrieve diagram preference values. The |
| * preference hint is mapped to a preference store in the preference |
| * registry <@link DiagramPreferencesRegistry>. |
| * |
| * @param preferencesHint the preferences hint |
| */ |
| protected void setPreferencesHint(PreferencesHint preferencesHint) { |
| this.preferencesHint = preferencesHint; |
| } |
| |
| /** |
| * Gets the command. |
| * @return Returns the command. |
| */ |
| protected Command getCommand() { |
| return command; |
| } |
| |
| /** |
| * Sets the command. |
| * @param command The command to set. |
| */ |
| protected void setCommand(Command command) { |
| this.command = command; |
| } |
| |
| |
| } |