/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.modeling.ui.diagramEditor; import gnu.trove.set.hash.THashSet; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTargetDragEvent; import java.awt.geom.AffineTransform; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import org.eclipse.jface.viewers.IStructuredSelection; import org.simantics.Logger; import org.simantics.db.ReadGraph; import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.common.request.UnaryRead; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.common.utils.OrderedSetUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.SelectionHints; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; import org.simantics.db.layer0.variable.Variables.Role; import org.simantics.diagram.adapter.GraphToDiagramSynchronizer; import org.simantics.diagram.content.ConnectionUtil; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.diagram.ui.DiagramModelHints; import org.simantics.g2d.diagram.handler.DataElementMap; import org.simantics.g2d.dnd.DnDHints; import org.simantics.g2d.dnd.ElementClassDragItem; import org.simantics.g2d.dnd.IDnDContext; import org.simantics.g2d.dnd.IDropTargetParticipant; import org.simantics.g2d.element.ElementHints; import org.simantics.g2d.element.IElement; import org.simantics.g2d.utils.Alignment; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.modeling.PropertyVariables; import org.simantics.modeling.PropertyVariablesImpl; import org.simantics.modeling.ui.diagram.monitor.MonitorClassFactory2; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.ui.dnd.LocalObjectTransfer; import org.simantics.ui.dnd.LocalObjectTransferable; import org.simantics.ui.selection.WorkbenchSelectionElement; import org.simantics.ui.selection.WorkbenchSelectionUtils; import org.simantics.utils.datastructures.Triple; import org.simantics.utils.datastructures.hints.IHintContext; import org.simantics.utils.ui.ISelectionUtils; public class PopulateElementMonitorDropParticipant extends PopulateElementDropParticipant implements IDropTargetParticipant { private static final boolean DEBUG = false; // Scale for the monitors double scaleX, scaleY; // Monitor type String typeURI; public PopulateElementMonitorDropParticipant(GraphToDiagramSynchronizer synchronizer, double scaleX, double scaleY) { super(synchronizer); this.scaleX = scaleX; this.scaleY = scaleY; this.typeURI = DiagramResource.URIs.Monitor; } public PopulateElementMonitorDropParticipant(GraphToDiagramSynchronizer synchronizer, String typeURI, double scaleX, double scaleY) { super(synchronizer); this.scaleX = scaleX; this.scaleY = scaleY; this.typeURI = typeURI; } @Override public void dragEnter(DropTargetDragEvent dtde, final IDnDContext dp) { Transferable tr = dtde.getTransferable(); if (tr.isDataFlavorSupported(LocalObjectTransferable.FLAVOR)) { // This must be done to have SWT transfer set the source data try { Object obj = tr.getTransferData(LocalObjectTransferable.FLAVOR); if (DEBUG) System.out.println("GOT FROM AWT: " + obj); // Check SWT if (!(obj instanceof IStructuredSelection)) { obj = LocalObjectTransfer.getTransfer().getObject(); if (DEBUG) System.out.println("GOT FROM SWT: " + obj); } if (obj instanceof IStructuredSelection) { IStructuredSelection sel = (IStructuredSelection) obj; for(WorkbenchSelectionElement wse : WorkbenchSelectionUtils.getWorkbenchSelectionElements(sel)) { dp.add(new WSEDragItem(wse)); } Session session = synchronizer.getSession(); List properties = resolveVariables(session, (IStructuredSelection) obj); if (properties.isEmpty()) return; List items = session.syncRequest(new ResolveItems(properties)); for (ElementClassDragItem item : items) dp.add(item); dp.getHints().setHint(DnDHints.KEY_DND_GRID_COLUMNS, Integer.valueOf(1)); } } catch (UnsupportedFlavorException e) { Logger.defaultLogError(e); } catch (IOException e) { Logger.defaultLogError(e); } catch (DatabaseException e) { Logger.defaultLogError(e); } } dtde.acceptDrag(DnDConstants.ACTION_COPY); } public void setHints(IHintContext context) { } protected List resolveVariables(RequestProcessor processor, IStructuredSelection sel) throws DatabaseException { if (sel.isEmpty()) return Collections.emptyList(); Variable property = WorkbenchSelectionUtils.getPossibleVariable(sel); if(property != null) return Collections.singletonList(property); property = ISelectionUtils.getSinglePossibleKey(sel, SelectionHints.KEY_SELECTION_PROPERTY, Variable.class); if (property != null) return Collections.singletonList(property); final List vars = ISelectionUtils.getPossibleKeys(sel, SelectionHints.KEY_MAIN, PropertyVariables.class); if (!vars.isEmpty()) { return processor.syncRequest(new UniqueRead>() { @Override public List perform(ReadGraph graph) throws DatabaseException { // FIXME: this is a hack for indexed value support List vs = PropertyVariablesImpl.resolve(graph, vars); List result = new ArrayList(vs.size()); for (PropertyVariables v : vs) result.add(v.getVisualVariable()); return result; } }); } return Collections.emptyList(); } protected class ResolveItems extends UnaryRead, List> { public ResolveItems(List parameter) { super(parameter); } @Override public List perform(ReadGraph graph) throws DatabaseException { List result = new ArrayList(parameter.size()); for (Variable property : parameter) result.addAll( resolve(graph, property) ); return result; } public List resolve(ReadGraph graph, Variable parameter) throws DatabaseException { if (DEBUG) { System.out.println("PARAM: " + parameter.getURI(graph)); Variable parent = parameter.browsePossible(graph, ".."); System.out.println("PARENT: " + parent.getURI(graph)); Resource parentComposite = parent.getPossibleRepresents(graph); System.out.println("PARENT REPRESENTS: " + NameUtils.getSafeLabel(graph, parentComposite)); String prvi = Variables.getRVI(graph, parent); System.out.println("PARENT RVI: " + prvi); String parvi = Variables.getRVI(graph, parameter); System.out.println("PARAM RVI: " + parvi); } Triple match = findElementInDiagram(graph, parameter, false); if (match == null) return Collections.emptyList(); if(match.third == null) { // We are in a different diagram, prevent creation of monitors // from UCs to different UCs or model configuration Resource diagram = synchronizer.getDiagram().getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE); Resource commonParent = findCommonParent(graph, diagram, match.second); StructuralResource2 STR = StructuralResource2.getInstance(graph); if(!graph.isInstanceOf(commonParent, STR.Composite)) return Collections.emptyList(); } if (DEBUG) { System.out.println("p=" + parameter.getURI(graph)); System.out.println("c=" + match.first.getURI(graph)); } String rvi = Variables.getRVI(graph, match.first, parameter); if (DEBUG) System.out.println("r=" + rvi); Resource type = graph.getResource(typeURI); ElementClassDragItem item = new ElementClassDragItem(MonitorClassFactory2.createMonitorClass(type, match.third, new HashMap(), match.second, rvi, scaleX, scaleY)); item.getHintContext().setHint(ElementHints.KEY_HORIZONTAL_ALIGN, Alignment.LEADING); if (match.third != null) item.getHintContext().setHint(ElementHints.KEY_PARENT_ELEMENT, match.third); AffineTransform initialTr = AffineTransform.getScaleInstance(scaleX, scaleY); item.getHintContext().setHint(ElementHints.KEY_TRANSFORM, initialTr); setHints(item.getHintContext()); return Collections.singletonList(item); } private Triple findElementInDiagram(ReadGraph graph, Variable property, boolean propertyRoleFound) throws DatabaseException { if (property == null) return null; if (DEBUG) System.out.println("findElementInDiagram " + property.getURI(graph) + " " + property); DiagramResource DIA = DiagramResource.getInstance(graph); ModelingResources MOD = ModelingResources.getInstance(graph); final Resource diagram = synchronizer.getDiagram().getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE); if (!propertyRoleFound) { Role role = property.getPossibleRole(graph); propertyRoleFound = role == Role.PROPERTY; } Resource represents = property.getPossibleRepresents(graph); if (represents != null) { if (DEBUG) System.out.println("represents " + NameUtils.getSafeName(graph, represents, true)); Resource elementResource = graph.getPossibleObject(represents, MOD.ComponentToElement); // There must have be at least one // PROPERTY role variable in the // browsed path before finding this // element. if(elementResource != null && propertyRoleFound) { Resource elementDiagram = OrderedSetUtils.getSingleOwnerList(graph, elementResource, DIA.Diagram); if(diagram.equals(elementDiagram)) { final DataElementMap map = synchronizer.getDiagram().getDiagramClass().getSingleItem(DataElementMap.class); IElement parentElement = map.getElement(synchronizer.getDiagram(), elementResource); if (graph.isInstanceOf(elementResource, DIA.Connection)) { Resource tailNode = ConnectionUtil.getConnectionTailNode(graph, elementResource); if (tailNode != null) { IElement tailNodeElement = map.getElement(synchronizer.getDiagram(), tailNode); if (tailNodeElement != null) parentElement = tailNodeElement; } } return Triple.make(property, represents, parentElement); } else { // The monitored target module is on another diagram/composite. // No parent for the monitor then. return Triple.make(property, represents, null); } } } return findElementInDiagram(graph, property.browsePossible(graph, "."), propertyRoleFound); } } private static Resource findCommonParent(ReadGraph graph, Resource a, Resource b) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); THashSet set = new THashSet<>(); while(true) { if(a != null) { if(!set.add(a)) return a; a = graph.getPossibleObject(a, L0.PartOf); } else if(b == null) return graph.getRootLibrary(); if(b != null) { if(!set.add(b)) return b; b = graph.getPossibleObject(a, L0.PartOf); } } } @Override public double getPriority() { return 9.0; } }