/****************************************************************************** * Copyright (c) 2002, 2007 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.tests.runtime.diagram.ui.util; import java.util.List; import java.util.ListIterator; import junit.framework.Assert; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.emf.transaction.util.TransactionUtil; import org.eclipse.emf.workspace.AbstractEMFOperation; import org.eclipse.gef.Request; import org.eclipse.gef.commands.Command; import org.eclipse.gef.commands.CommandStack; import org.eclipse.gef.requests.CreateConnectionRequest; import org.eclipse.gef.requests.CreateRequest; import org.eclipse.gmf.runtime.common.core.util.Log; import org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory; import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint; import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; import org.eclipse.gmf.runtime.diagram.ui.OffscreenEditPartFactory; import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart; import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart; import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants; import org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.util.IDEEditorUtil; import org.eclipse.gmf.runtime.emf.type.core.IElementType; import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.gmf.runtime.notation.Edge; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.gmf.tests.runtime.diagram.ui.AbstractTestBase; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.part.EditorPart; /** * @author choang * * Most fixture should extend fromthis Abstract class. The only things that are left to do is to implement the following * abstract methods * 1. createProject,createDiagram,craeteShapesAndConnectors * 2. Implement you test class which should extend from org.junit.org or @see org.eclipse.gmf.tests.runtime.diagram.ui.AbstractTestBase * */ public abstract class AbstractPresentationTestFixture extends Assert implements IPresentationTestFixture { private IProject project = null; private IDiagramWorkbenchPart diagramWorkbenchPart = null; private IFile diagramFile = null; private TransactionalEditingDomain editingDomain; private Resource resource; private Diagram diagram; private DiagramEditPart diagramEditPart; private Edge connectorView = null; // connector view for the test fixture /** * Temporary shell to be used when creating the diagram editpart. */ private Shell tempShell; /** verbose flag. */ private static boolean _verbose = Boolean.getBoolean(AbstractTestBase.SYSPROP_VERBOSE); /** * Returns the diagramFile. * @return IFile */ public IFile getDiagramFile() { return diagramFile; } /** * Enable verbose mode. If enabled, {@link junit.framework.Assert#fail(java.lang.String)} * will print the supplied string; otherwise the string is ignored. * * Verbose mode can also be enabled using the {@link AbstractTestBase#SYSPROP_VERBOSE} system property. * @param enabled boolean flag */ protected final void enableVerbose( boolean enabled ) { _verbose = enabled; } /** Return the verbose mode. */ public final boolean isVerbose() { return _verbose; } /** Calls <code>System.out.println(msg)</code> if in verbose mode. */ public static final void println( Object msg ) { if ( _verbose ) { System.out.println(msg); } } /** Calls <code>System.out.print(msg)</code> if in verbose mode. */ public static final void print( Object msg ) { if ( _verbose ) { System.out.print(msg); } } /** * Returns the editor. * @return IDiagramWorkbenchPart */ public IDiagramWorkbenchPart getDiagramWorkbenchPart() { if (diagramWorkbenchPart == null) { assertTrue( "It appears that the diagram needs to be opened for this test. Call openDiagram().", false); //$NON-NLS-1$ } return diagramWorkbenchPart; } /** * Returns the project. * @return IProject */ public IProject getProject() { return project; } /** * Sets the diagramFile. * @param diagramFile The diagramFile to set */ protected void setDiagramFile(IFile diagramFile) { this.diagramFile = diagramFile; } /** * Method getCommandStack. * @return CommandStack Command stack for the diagram edit domain */ public CommandStack getCommandStack() { return getDiagramEditPart().getDiagramEditDomain().getDiagramCommandStack(); } /** * Sets the diagramWorkbenchPart. * @param diagramWorkbenchPart The editorPart to set */ public void setDiagramWorkbenchPart(IDiagramWorkbenchPart diagramWorkbenchPart) { this.diagramWorkbenchPart = diagramWorkbenchPart; } /** * Sets the project. * @param project The project to set */ protected void setProject(IProject project) { this.project = project; } /** * * Setup up the data for a test. It will create the project,diagram and then opent the diagram * and then create the test shapes and connectors on the diagram for the tests. */ public void setup() throws Exception { createProject(); createDiagram(); createResource(); createDiagramEditPart(); flushEventQueue(); // so that all editor related events are fired createShapesAndConnectors(); } /** * Will delete the project that was used for the test and removed all the resources in it. */ public final void tearDown() throws Exception { if (tempShell != null) { tempShell.dispose(); tempShell = null; } // flushEventQueue(); boolean diagramClosed = false; Throwable cde = null; // close diagram exception Throwable pde = null; //project delete exception try { try { diagramClosed = closeDiagram(); } catch( Throwable cdt ) { cde = cdt; } try { if (project != null) project.delete(true, true, null); } catch( Throwable pdt ) { pde = pdt; } } finally { // erasing all the data setDiagramWorkbenchPart(null); // unload resource if (getResource() != null) { getResource().unload(); setResource(null); } setDiagramFile(null); setProject(null); setConnectorView(null); flushEventQueue(); if ( !diagramClosed ) { Log.error( TestsPlugin.getDefault(), IStatus.ERROR, "FAILED TO CLOSE DIAGRAM", cde);//$NON-NLS-1$ } if ( pde != null ) { Log.error( TestsPlugin.getDefault(), IStatus.ERROR, "FAILED TO DELETE PROJECT", pde);//$NON-NLS-1$ } } } /** * Returns the connectorView. * Maybe null if there is no connector view for this test * @return IConnectorView */ public Edge getConnectorView() { // maybe null if there is no connector view for this test return connectorView; } /** * Sets the connectorView. * @param connectorView The connectorView to set */ protected void setConnectorView(Edge connectorView) { this.connectorView = connectorView; } /** Clears the diaplay's event queue. */ public void flushEventQueue() { Display display = Display.getCurrent(); while (display.readAndDispatch()) { // empty block } } public void openDiagram() throws Exception { if (getDiagramFile() == null) { createDiagram(); } assertTrue("creation of diagram failed", getDiagramFile() != null); //$NON-NLS-1$ IWorkbenchPage page = PlatformUI.getWorkbench() .getActiveWorkbenchWindow() .getActivePage(); IDEEditorUtil.openDiagram(getDiagramFile(), page.getWorkbenchWindow(), false, new NullProgressMonitor()); setDiagramWorkbenchPart((IDiagramWorkbenchPart)IDE.openEditor(page, getDiagramFile(), true)); setDiagramEditPart(getDiagramWorkbenchPart().getDiagramEditPart()); setDiagram(getDiagramEditPart().getDiagramView()); setResource(getDiagram().eResource()); } public boolean closeDiagram() { boolean closed = true; if (diagramWorkbenchPart != null // only close if it was opened && diagramWorkbenchPart instanceof IEditorPart) { IWorkbenchPage page = getDiagramWorkbenchPart().getSite().getPage(); closed = page.closeEditor((IEditorPart)getDiagramWorkbenchPart(), false); setDiagramWorkbenchPart(null); } return closed; } protected boolean isDirty() { return ((EditorPart) getDiagramWorkbenchPart()).isDirty(); } /** * @param diagram The diagram to set. */ public void setDiagram(Diagram diagram) { this.diagram = diagram; } /** * @param diagramEditPart The diagramEditPart to set. */ public void setDiagramEditPart(DiagramEditPart diagramEditPart) { this.diagramEditPart = diagramEditPart; } public Diagram getDiagram() { return diagram; } public DiagramEditPart getDiagramEditPart() { return diagramEditPart; } /** * Implement to setup the project for the tests. */ protected abstract void createProject() throws Exception; /** * Implement to create the diagram and the diagram file for which * the test should run under. Please set the diagramFile variable. */ protected abstract void createDiagram() throws Exception; /** * Creates the editing domain and resource and adds the diagram to * that resource. */ protected void createResource() { if (getResource() == null) { IFile file = getDiagramFile(); if (file != null) { String filePath = file.getLocation().toOSString(); setResource(getEditingDomain().loadResource(filePath)); } else { setResource(getEditingDomain() .createResource("null:/org.eclipse.gmf.tests.runtime.diagram.ui")); //$NON-NLS-1$ } if (getDiagram() != null) { AbstractEMFOperation operation = new AbstractEMFOperation( getEditingDomain(), "AbstractPresentationTestFixture setup") { //$NON-NLS-1$ protected IStatus doExecute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { getResource().getContents().add(getDiagram()); return Status.OK_STATUS; }; }; try { operation.execute(new NullProgressMonitor(), null); } catch (ExecutionException ie) { fail("createResource failed: " + ie.getLocalizedMessage()); //$NON-NLS-1$ } } } } /** * Creates and sets the diagram editpart using the offscreen rendering * capabilities. */ protected void createDiagramEditPart() throws Exception { if (getDiagramEditPart() == null) { setDiagramEditPart(OffscreenEditPartFactory.getInstance() .createDiagramEditPart(getDiagram(), getTempShell())); } } public ShapeEditPart createShapeUsingTool(IElementType elementType, Point location, IGraphicalEditPart containerEP) { return createShapeUsingTool(elementType, location, null, containerEP); } /** * Creates a new shape using the request created by the * <code>CreationTool</code>. * * @param elementType * the type of the shape/element to be created * @param location * the location for the new shape * @return the new shape's editpart */ public ShapeEditPart createShapeUsingTool(IElementType elementType, Point location, Dimension size, IGraphicalEditPart containerEP) { CreateRequest request = getCreationRequest(elementType); request.setLocation(location); if (size != null) { request.setSize(size); } Command cmd = containerEP.getCommand(request); int previousNumChildren = containerEP.getChildren().size(); getCommandStack().execute(cmd); assertEquals(previousNumChildren + 1, containerEP.getChildren().size()); Object newView = ((IAdaptable) ((List) request.getNewObject()).get(0)).getAdapter(View.class); assertNotNull(newView); assertTrue(!ViewUtil.isTransient((View)newView)); EObject element = ((View)newView).getElement(); getCommandStack().undo(); assertEquals(previousNumChildren, containerEP.getChildren().size()); getCommandStack().redo(); assertEquals(previousNumChildren + 1, containerEP.getChildren().size()); IGraphicalEditPart newShape = null; if (element != null) { List children = containerEP.getChildren(); ListIterator li = children.listIterator(); while (li.hasNext()) { IGraphicalEditPart gep = (IGraphicalEditPart) li.next(); if (gep.getNotationView() != null && element.equals(gep.getNotationView().getElement())) { newShape = gep; } } } else { newShape = (ShapeEditPart) getDiagramEditPart() .getViewer().getEditPartRegistry().get(newView); assertNotNull(newShape); } assertTrue(newShape != null && newShape instanceof ShapeEditPart); return (ShapeEditPart)newShape; } /** * Given an <code>IElementType</code>, gets the creation request that can be used to * retrieve the command to creation the element for the type. * * @param elementType * @return */ public CreateRequest getCreationRequest(IElementType elementType) { class CreationTool extends org.eclipse.gmf.runtime.diagram.ui.tools.CreationTool { public CreationTool(IElementType theElementType) { super(theElementType); } /** Make public. */ public Request createTargetRequest() { return super.createTargetRequest(); } protected PreferencesHint getPreferencesHint() { return PreferencesHint.USE_DEFAULTS; } } CreationTool tool = new CreationTool(elementType); CreateRequest request = (CreateRequest) tool.createTargetRequest(); return request; } /** * Creates a new shape using the request created by the * <code>CreationTool</code>. * * @param elementType * the type of the shape/element to be created * @param location * the location for the new shape * @return the new shape's editpart */ public ShapeEditPart createShapeUsingTool(IElementType elementType, Point location) { return createShapeUsingTool(elementType, location, getDiagramEditPart()); } /** * Creates a new shape using the request created by the * <code>CreationTool</code>. * * @param elementType * the type of the shape/element to be created * @param location * the location for the new shape * @return the new shape's editpart */ public ShapeEditPart createShapeUsingTool(IElementType elementType, Point location, Dimension size) { return createShapeUsingTool(elementType, location, size, getDiagramEditPart()); } /** * Creates a new connector using the request created by the * <code>ConnectionCreationTool</code>. * * @param sourceEditPart * the new connector's source * @param targetEditPart * the new connector's target * @param elementType * the type of the connector/relationship to be created * @return the new connector's editpart */ public ConnectionEditPart createConnectorUsingTool( final IGraphicalEditPart sourceEditPart, final IGraphicalEditPart targetEditPart, IElementType elementType) { class ConnectorCreationTool extends org.eclipse.gmf.runtime.diagram.ui.tools.ConnectionCreationTool { public ConnectorCreationTool(IElementType theElementType) { super(theElementType); } /** Make public. */ public Request createTargetRequest() { return super.createTargetRequest(); } protected PreferencesHint getPreferencesHint() { return PreferencesHint.USE_DEFAULTS; } } ConnectorCreationTool tool = new ConnectorCreationTool(elementType); CreateConnectionRequest request = (CreateConnectionRequest) tool .createTargetRequest(); request.setTargetEditPart(sourceEditPart); request.setType(RequestConstants.REQ_CONNECTION_START); sourceEditPart.getCommand(request); request.setSourceEditPart(sourceEditPart); request.setTargetEditPart(targetEditPart); request.setType(RequestConstants.REQ_CONNECTION_END); Command cmd = targetEditPart.getCommand(request); int previousNumConnectors = getDiagramEditPart().getConnections().size(); getCommandStack().execute(cmd); assertEquals(previousNumConnectors + 1, getDiagramEditPart() .getConnections().size()); getCommandStack().undo(); assertEquals(previousNumConnectors, getDiagramEditPart() .getConnections().size()); getCommandStack().redo(); assertEquals(previousNumConnectors + 1, getDiagramEditPart() .getConnections().size()); Object newView = ((IAdaptable) request.getNewObject()) .getAdapter(View.class); assertNotNull(newView); ConnectionEditPart newConnector = (ConnectionEditPart) getDiagramEditPart() .getViewer().getEditPartRegistry().get(newView); assertNotNull(newConnector); return newConnector; } /** * Implement this to creates the shapes and the connectors for the tests. * Will set the connect view if there is one needed for the test. */ protected abstract void createShapesAndConnectors() throws Exception; public TransactionalEditingDomain getEditingDomain() { if (editingDomain == null) { if (getDiagram() != null) { editingDomain = TransactionUtil.getEditingDomain(getDiagram()); } else { editingDomain = DiagramEditingDomainFactory.getInstance() .createEditingDomain(); } } return editingDomain; } protected Resource getResource() { return resource; } protected void setResource(Resource resource) { this.resource = resource; } /** * Lazily creates a new shell. * @return */ private Shell getTempShell() { if (tempShell == null) { tempShell = new Shell(); } return tempShell; } }