package org.framed.orm.ui.editor; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.EventObject; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.draw2d.geometry.Point; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.edit.provider.ItemPropertyDescriptor.PropertyValueWrapper; import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider; import org.eclipse.gef.DefaultEditDomain; import org.eclipse.gef.EditDomain; import org.eclipse.gef.EditPart; import org.eclipse.gef.GraphicalViewer; import org.eclipse.gef.KeyStroke; import org.eclipse.gef.Request; import org.eclipse.gef.commands.CommandStack; import org.eclipse.gef.commands.CompoundCommand; import org.eclipse.gef.dnd.TemplateTransferDragSourceListener; import org.eclipse.gef.dnd.TemplateTransferDropTargetListener; import org.eclipse.gef.dnd.TransferDropTargetListener; import org.eclipse.gef.palette.CombinedTemplateCreationEntry; import org.eclipse.gef.palette.CreationToolEntry; import org.eclipse.gef.palette.PaletteRoot; import org.eclipse.gef.requests.DirectEditRequest; import org.eclipse.gef.ui.actions.ActionRegistry; import org.eclipse.gef.ui.actions.DirectEditAction; import org.eclipse.gef.ui.actions.GEFActionConstants; import org.eclipse.gef.ui.actions.ToggleGridAction; import org.eclipse.gef.ui.actions.ToggleSnapToGeometryAction; import org.eclipse.gef.ui.palette.PaletteViewer; import org.eclipse.gef.ui.parts.GraphicalEditor; import org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette; import org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler; import org.eclipse.gef.ui.properties.UndoablePropertySheetEntry; import org.eclipse.gef.ui.properties.UndoablePropertySheetPage; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.views.properties.IPropertyDescriptor; import org.eclipse.ui.views.properties.IPropertySheetPage; import org.eclipse.ui.views.properties.IPropertySource; import org.eclipse.ui.views.properties.IPropertySourceProvider; import org.eclipse.ui.views.properties.PropertySheetPage; import org.framed.orm.model.Model; import org.framed.orm.model.OrmFactory; import org.framed.orm.model.Relation; import org.framed.orm.model.Shape; import org.framed.orm.model.Type; import org.framed.orm.model.provider.OrmItemProviderAdapterFactory; import org.framed.orm.transformation.TransformationExecutor; import org.framed.orm.ui.action.CreateAttributeOperationAction; import org.framed.orm.ui.action.FulfillRolesAction; import org.framed.orm.ui.action.RelationshipConstraintsAction; import org.framed.orm.ui.action.StepInAction; import org.framed.orm.ui.action.StepInNewPageAction; import org.framed.orm.ui.action.StepInNewTabAction; import org.framed.orm.ui.action.StepOutAction; import org.framed.orm.ui.command.connectionkinds.ORMRelationshipConstraintCreateCommand; import org.framed.orm.ui.command.connectionkinds.ORMRelationshipConstraintDeleteCommand; import org.framed.orm.ui.editPart.ORMEditPartFactory; import org.framed.orm.ui.editPart.connectionkinds.ORMRelationshipEditPart; import org.framed.orm.ui.editor.palette.CreationConstraintToolEntry; /** * The {@link GraphicalEditor} you can see. Interacts with the user and shows * the contents. * * @author Kay BierzynskiS * @author Paul Peschel * @author Duc Dung Dam * */ public class ORMGraphicalEditor extends AbstractGraphicalEditor { /** * This enum describes the editor type, which can be COMPARTMENT or ROLES. * */ public enum EditorType { COMPARTMENT, /* the editor shows compartments at the moment */ ROLES /* the editor shows roles at the moment (e.g. after step in) */ }; // if the editor does not allow to create role-related components, it's a // COMPARTMENT-editor /** * The input {@link Resource} of this editor, which contains the emf model. * */ private final Resource cdResource; /** * The Root {@link Model}, which represents the root of the model tree and * which is the first content for editor viewer. * */ private Model rootmodel; /** * The {@link ORMMultiPageEditor}, where this editor is registered and * managed. * */ private final IEditorPart parentEditor; // the multipageditor /** * A boolean flag, which indicates if this edito shows the method list of * the {@link Type} model elements or not. false = this is a behaviour * editor true = this is a data editor * */ private final boolean isEditorData; /** * The {@link PropertySheetPage} of this editor, which shown in the * Properties. * */ private PropertySheetPage propertyPage; /** * The {@link EditorChangeNotifier} of this editor. * */ private final EditorChangeNotifier changeNotifier; /** * The {@link EditorType} of this editor, which need to change the * visibility of palett entrys. * */ private EditorType editorType; /** * The constructor of this class. The most of the gloabal variables are * initialized here and the {@link EditDomain} ot the editor is set here as * well. * */ public ORMGraphicalEditor(final IEditorPart editor, final Resource resource, final boolean flag) { isEditorData = flag; parentEditor = editor; cdResource = resource; changeNotifier = new EditorChangeNotifier(this); editorType = EditorType.COMPARTMENT; // standard is compartment setEditDomain(new DefaultEditDomain(this)); } /** * A getter for the editor type of this editor. * * @return {@link EditorType} * */ public EditorType getEditorType() { return editorType; } /** * A getter for the viewer of this editor. * * @return {@link GraphicalViewer} * */ public GraphicalViewer getOwnViewer() { return getGraphicalViewer(); } /** * A getter for the parenteditor({@link ORMMultiPageEditor}) of this editor. * * @return parentEditor {@link IEditorPart} * */ public IEditorPart getParentEditor() { return parentEditor; } /** * A getter for the isEditorData flag. * * @return isEditorData boolean * */ public boolean getIsEditorData() { return isEditorData; } /** * A getter for action registry of this editor. * * @return {@link ActionRegistry} * */ public ActionRegistry getEditorActionRegistry() { return getActionRegistry(); } /** * Initializes the graphical viewer responsible for the contents of the * editor. */ @Override protected void initializeGraphicalViewer() { super.initializeGraphicalViewer(); GraphicalViewer viewer = getGraphicalViewer(); viewer.setContents(rootmodel); ((ORMMultiPageEditor) parentEditor) .createCustomTitleForEditor(rootmodel); // add the change notifier as listener viewer.getEditDomain().getCommandStack() .addCommandStackEventListener(changeNotifier); } /** * Configures the graphical viewer. * * Sets org.framed.orm.ui.editPart.ORMEditPartFactory.ORMEditPartFactory(), * org.framed.orm.ui.editor .ORMGraphicalEditorContextMenuProvider. * ORMGraphicalEditorContextMenuProvider(EditPartViewer, ActionRegistry). * * Registers button actions of grid * (org.eclipse.gef.ui.actions.ToggleGridAction * .ToggleGridAction(GraphicalViewer) ) and snap to geometry * (org.eclipse.gef * .ui.actions.ToggleSnapToGeometryAction.ToggleSnapToGeometryAction( * GraphicalViewer) ) * * Configures the keyboard shortcuts @see * org.framed.orm.ui.editor.ORMGraphicalEditor.configureKeyboardShortcuts() * * Adds drag and drop listener for shape creation by dragging objects from * palette to EditorViewer. * * Adds mouse listener for handling onClick events on constraint entries. * This will create/delete a constraint for a current selected relationship. */ @Override protected void configureGraphicalViewer() { super.configureGraphicalViewer(); final GraphicalViewer viewer = getGraphicalViewer(); final PaletteViewer paletteViewer = getEditDomain().getPaletteViewer(); viewer.setEditPartFactory(new ORMEditPartFactory()); // set Contextmenu provider class + action registry viewer.setContextMenu( new ORMGraphicalEditorContextMenuProvider(getGraphicalViewer(), getActionRegistry())); // register grid and snap to geometry action getActionRegistry().registerAction( new ToggleGridAction(getGraphicalViewer())); getActionRegistry().registerAction( new ToggleSnapToGeometryAction(getGraphicalViewer())); // set the shortcuts configureKeyboardShortcuts(); // add drag and drop listener viewer.addDropTargetListener(new TemplateTransferDropTargetListener(viewer)); getEditDomain().getPaletteViewer().addDragSourceListener( new TemplateTransferDragSourceListener(getEditDomain().getPaletteViewer())); //add the mouse listener paletteViewer.getControl().addMouseListener(new MouseListener(){ Point p_temp; @Override public void mouseDown(MouseEvent e) { p_temp = new Point(e.x,e.y); } @Override public void mouseUp(MouseEvent e) { if (p_temp.equals(new Point(e.x,e.y))){ final EditPart editPart = paletteViewer.findObjectAt(new Point(e.x,e.y)); if (editPart instanceof EditPart && editPart.getModel() instanceof CreationConstraintToolEntry) { EditPart ep = (EditPart) viewer.getSelectedEditParts().get(0); if (ep instanceof ORMRelationshipEditPart) { ORMRelationshipEditPart ep_relationship = (ORMRelationshipEditPart) ep; Relation relationship = ep_relationship.getRelationship(); List<Relation> constraints = relationship.getReferencedRelation(); System.out.println("Relationship: "+relationship.getName()); System.out.println("Existing constraints: "+relationship.getReferencedRelation().toString()); Relation relation = OrmFactory.eINSTANCE.createRelation(); Type type = Type.get(((CreationConstraintToolEntry)editPart.getModel()).getTypeValue()); relation.setType(type); relation.setName(type.getName()); boolean constraintExist = false; for (Relation r : constraints){ if (r.getType().equals(type)){ constraintExist = true; System.out.println("Constraint delete!"); ORMRelationshipConstraintDeleteCommand command = new ORMRelationshipConstraintDeleteCommand(); command.setRelation(r); command.setEPViewer(ep.getViewer()); getCommandStack().execute(command); break; } } if (!constraintExist){ relationship.getReferencedRelation().add(relation); ORMRelationshipConstraintCreateCommand command = new ORMRelationshipConstraintCreateCommand(); command.setRelation(relation); command.setRelationContainer(relationship.getContainer()); command.setSource((Shape) relationship.getSource()); command.setTarget((Shape) relationship.getTarget()); command.setSourceLabel(null); command.setTargetLabel(null); ArrayList<Relation> refrencedRelation = new ArrayList<Relation>(); refrencedRelation.add(relationship); command.setRefrencedRelations(refrencedRelation); getCommandStack().execute(command); } } } } } @Override public void mouseDoubleClick(MouseEvent e) {} }); } /** * {@inheritDoc} We need to override this method, because * getSite.getPage().getActiveEditor() would return the * {@link ORMMultiPageEditor} that leads to the problem that the select * actions doesn't work. */ @Override public void selectionChanged(final IWorkbenchPart part, final ISelection selection) { updateActions(getSelectionActions()); } /** * This method sets shortcuts for actions. * */ private void configureKeyboardShortcuts() { getGraphicalViewer().getKeyHandler(); GraphicalViewerKeyHandler keyHandler = new GraphicalViewerKeyHandler( getGraphicalViewer()); keyHandler.put(KeyStroke.getPressed(SWT.F2, 0), getActionRegistry() .getAction(GEFActionConstants.DIRECT_EDIT)); keyHandler.put( KeyStroke.getPressed(SWT.CR, '\r', 0), getActionRegistry().getAction( CreateAttributeOperationAction.CREATE_A_M_ID)); getGraphicalViewer().setKeyHandler(keyHandler); } /** * {@inheritDoc} In this method the {@link ORMGraphicalEditorPalette} of * this editor is registered by the changeNotifier as well. */ @Override protected PaletteRoot getPaletteRoot() { ORMGraphicalEditorPalette tmp = new ORMGraphicalEditorPalette(); changeNotifier.register(tmp); // register the palette for editor changes if (getEditorType() == EditorType.ROLES) { // if we show only roles tmp.setRoleEntriesVisibility(true); // show only palette entries // belonging to roles } else { // compartments tmp.setRoleEntriesVisibility(false); // show only palette entries // belonging to compartment } return tmp; } /** {@inheritDoc} */ @Override protected void createActions() { super.createActions(); // TODO: when the Ediptpart of the Relation and shape are uncomment // these actions IAction action = new StepInAction(this); getActionRegistry().registerAction(action); getSelectionActions().add(action.getId()); action = new StepOutAction(this); getActionRegistry().registerAction(action); getSelectionActions().add(action.getId()); action = new StepInNewPageAction(this); getActionRegistry().registerAction(action); getSelectionActions().add(action.getId()); action = new StepInNewTabAction(this); getActionRegistry().registerAction(action); getSelectionActions().add(action.getId()); action = new FulfillRolesAction(this); getActionRegistry().registerAction(action); getSelectionActions().add(action.getId()); action = new RelationshipConstraintsAction(this); getActionRegistry().registerAction(action); getSelectionActions().add(action.getId()); action = new CreateAttributeOperationAction(this); getActionRegistry().registerAction(action); getSelectionActions().add(action.getId()); // create direct editing action for shortcuts action = new DirectEditAction(this); getActionRegistry().registerAction(action); getSelectionActions().add(action.getId()); } /** * Save the model using the resource from which it was opened, and mark the * current location in the {@link CommandStack}. */ @Override public void doSave(final IProgressMonitor monitor) { // save graphical resource boolean graphicalResourceSaved = saveGraphicalResource(); if (!graphicalResourceSaved) { return; } // transform graphical model to crom boolean modelTransformationSucceed = transformModel(); if (!modelTransformationSucceed) { return; } getCommandStack().markSaveLocation(); } /** * Transforms the graphical model into an instance of crom model. * @return true if transformation succeeds, otherwise false. */ private boolean transformModel() { // resolve target uri URI sourceURI = cdResource.getURI(); // Remove .crom_dia file extension sourceURI = sourceURI.trimFileExtension(); // Add .crom file extension sourceURI = sourceURI.appendFileExtension("crom"); // Get file path relative to workspace (needed for URI.createPlatformResourceURI) Path path = new Path(sourceURI.toFileString()); IFile myFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path); // create target resource (using createPlatformResourceURI // updates the project explorer to show the file upon initial save) URI targetURI = URI.createPlatformResourceURI(myFile.getFullPath().toString(), true); ResourceSet set = new ResourceSetImpl(); Resource res = set.createResource(targetURI); // setup model transformation TransformationExecutor exe = new TransformationExecutor(); exe.setSourceModelFile(cdResource); exe.setTargetModelFile(res); // execute transformation try { res.save(Collections.EMPTY_MAP); exe.execute(); return true; } catch (Exception e) { e.printStackTrace(); } return false; } /** * Saves the graphical resource. * @return True if saving of model succeeds, otherwise false. */ private boolean saveGraphicalResource() { if (cdResource == null) { return false; } try { cdResource.save(null); return true; } catch (IOException e) { // TODO do something smarter. e.printStackTrace(); } return false; } /** {@inheritDoc} */ @Override public void init(final IEditorSite site, final IEditorInput input) throws PartInitException { super.init(site, input); if (cdResource != null) { rootmodel = (Model) cdResource.getContents().get(0); } } /** * Fire a {@link IEditorPart#PROP_DIRTY} property change and call super * implementation. Enable save from Eclipse. */ @Override public void commandStackChanged(EventObject event) { firePropertyChange(PROP_DIRTY); super.commandStackChanged(event); } /** * This methods implements adapting to {@link IPropertySheetPage}. All other * requests are forwarded to the * {@link GraphicalEditorWithFlyoutPalette#getAdapter(Class) parent} * implementation. */ @Override public Object getAdapter(@SuppressWarnings("rawtypes") Class type) { super.getAdapter(type); if (type.equals(IPropertySheetPage.class)) { if (propertyPage == null) { propertyPage = (UndoablePropertySheetPage) super .getAdapter(type); // A new PropertySourceProvider was implemented to fetch the // model // from the edit part when required. The property source is // provided // by the generated EMF classes and wrapped by the // AdapterFactoryContentProvider // to yield standard eclipse interfaces. IPropertySourceProvider sourceProvider = new IPropertySourceProvider() { IPropertySourceProvider modelPropertySourceProvider = new AdapterFactoryContentProvider( new OrmItemProviderAdapterFactory()); @Override public IPropertySource getPropertySource(Object object) { IPropertySource source = null; if (object instanceof EditPart) { source = modelPropertySourceProvider .getPropertySource(((EditPart) object) .getModel()); } else { source = modelPropertySourceProvider .getPropertySource(object); } if (source != null) { return new UnwrappingPropertySource(source); } else { return null; } } }; UndoablePropertySheetEntry root = new UndoablePropertySheetEntry( getCommandStack()); root.setPropertySourceProvider(sourceProvider); propertyPage.setRootEntry(root); } return propertyPage; } return super.getAdapter(type); } /** * This method updates the {@link EditorType} of this editor and the * behaviour/data(depending on which type this editor is) editor, when the * user steps in or out of {@link Compartment}s or {@link Grouping}s. * */ public void updateEditorType() { EditorType temptype = this.editorType; if (getGraphicalViewer().getContents().getModel() instanceof Model) { temptype = EditorType.COMPARTMENT; } if (getGraphicalViewer().getContents().getModel() instanceof Shape) { Shape shape = (Shape) getGraphicalViewer().getContents().getModel(); if (shape.getType() == Type.GROUP) { temptype = EditorType.COMPARTMENT; } if (shape.getType() == Type.COMPARTMENT_TYPE) { temptype = EditorType.ROLES; } } if (this.editorType.equals(temptype)) { return; } this.editorType = temptype; changeNotifier.editorTypeChanged(editorType); // set data editor type to the same type as the behaviour editor type // (btw: the complete design // of this editor hick-hack should be refactored) ((ORMMultiPageEditor) getParentEditor()).getDataEditor() .updateEditorType(); ; } /** * A property source which unwraps values that are wrapped in an EMF * {@link PropertyValueWrapper} * * */ public class UnwrappingPropertySource implements IPropertySource { private final IPropertySource source; /** * The constructor of this class, where the source is set. * */ public UnwrappingPropertySource(final IPropertySource source) { this.source = source; } /** {@inheritDoc} */ @Override public Object getEditableValue() { Object value = source.getEditableValue(); if (value instanceof PropertyValueWrapper) { PropertyValueWrapper wrapper = (PropertyValueWrapper) value; return wrapper.getEditableValue(null); } else { return source.getEditableValue(); } } /** {@inheritDoc} */ @Override public IPropertyDescriptor[] getPropertyDescriptors() { return source.getPropertyDescriptors(); } /** {@inheritDoc} */ @Override public Object getPropertyValue(final Object id) { final Object value = source.getPropertyValue(id); if (value instanceof PropertyValueWrapper) { PropertyValueWrapper wrapper = (PropertyValueWrapper) value; return wrapper.getEditableValue(null); } else { return source.getPropertyValue(id); } } /** {@inheritDoc} */ @Override public boolean isPropertySet(final Object id) { return source.isPropertySet(id); } /** {@inheritDoc} */ @Override public void resetPropertyValue(final Object id) { source.resetPropertyValue(id); } /** {@inheritDoc} */ @Override public void setPropertyValue(final Object id, final Object value) { source.setPropertyValue(id, value); } } }