X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.debug.graphical%2Fsrc%2Forg%2Fsimantics%2Fdebug%2Fgraphical%2FDebuggerCanvas.java;h=310d8a0865e824cfc8b0f6e51dd26af1bf41c78b;hb=195c63dd5c7600170f594750de96793ebf06a0ad;hp=86000643ba647fb7c17426f95821ffdf27de93a1;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.debug.graphical/src/org/simantics/debug/graphical/DebuggerCanvas.java b/bundles/org.simantics.debug.graphical/src/org/simantics/debug/graphical/DebuggerCanvas.java index 86000643b..310d8a086 100644 --- a/bundles/org.simantics.debug.graphical/src/org/simantics/debug/graphical/DebuggerCanvas.java +++ b/bundles/org.simantics.debug.graphical/src/org/simantics/debug/graphical/DebuggerCanvas.java @@ -1,610 +1,690 @@ -package org.simantics.debug.graphical; - -import gnu.trove.list.array.TDoubleArrayList; -import gnu.trove.map.hash.THashMap; -import gnu.trove.map.hash.TObjectIntHashMap; - -import java.awt.Color; -import java.awt.GradientPaint; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.datatransfer.Transferable; -import java.awt.datatransfer.UnsupportedFlavorException; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DropTarget; -import java.awt.dnd.DropTargetAdapter; -import java.awt.dnd.DropTargetDropEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseMotionAdapter; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Random; - -import javax.swing.JPanel; -import javax.swing.SwingUtilities; - -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.simantics.Simantics; -import org.simantics.db.ChangeSet; -import org.simantics.db.ChangeSetIdentifier; -import org.simantics.db.ReadGraph; -import org.simantics.db.Resource; -import org.simantics.db.Session; -import org.simantics.db.Statement; -import org.simantics.db.common.request.ReadRequest; -import org.simantics.db.common.utils.NameUtils; -import org.simantics.db.exception.DatabaseException; -import org.simantics.db.service.ManagementSupport; -import org.simantics.debug.graphical.layout.ExtensionLayoutAlgorithm; -import org.simantics.debug.graphical.layout.LayoutGraph; -import org.simantics.debug.graphical.model.Edge; -import org.simantics.debug.graphical.model.LabelContent; -import org.simantics.debug.graphical.model.Node; -import org.simantics.debug.graphical.model.NodeData; -import org.simantics.layer0.Layer0; -import org.simantics.ui.dnd.LocalObjectTransfer; -import org.simantics.ui.dnd.LocalObjectTransferable; -import org.simantics.ui.selection.AnyResource; -import org.simantics.ui.selection.WorkbenchSelectionElement; - -public class DebuggerCanvas extends JPanel { - - private static final long serialVersionUID = -718678297301786379L; - - ArrayList nodes = new ArrayList(); - THashMap nodeMap = new THashMap(); - ArrayList edges = new ArrayList(); - ArrayList extensionNodes = new ArrayList(); - ArrayList extensionEdges = new ArrayList(); - ArrayList addedEdges = new ArrayList(); - ArrayList removedEdges = new ArrayList(); - double canvasPosX = 0.0; - double canvasPosY = 0.0; - double canvasZoom = 1.0; - boolean extensionMode = false; - Random random = new Random(); - - LabelingPreferences labelingPreferences = - new LabelingPreferences(); - - @Override - public void paint(Graphics _g) { - Graphics2D g = (Graphics2D)_g; - - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, - RenderingHints.VALUE_FRACTIONALMETRICS_ON); - g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - - g.setPaint(new GradientPaint(0.0f, 0.0f, new Color(200, 200, 200), getWidth(), getHeight(), Color.WHITE)); - g.fill(new Rectangle2D.Double(0, 0, getWidth(), getHeight())); - g.setColor(Color.BLACK); - g.setTransform(new AffineTransform( - canvasZoom, 0.0, - 0.0, canvasZoom, - -canvasPosX*canvasZoom, -canvasPosY*canvasZoom)); - for(Node node : nodes) - node.render(g); - for(Edge edge : edges) - edge.render(g); - if(extensionMode) { - for(Node node : extensionNodes) - node.render(g); - for(Edge edge : extensionEdges) - edge.render(g); - } - g.setColor(Color.GREEN); - for(Edge edge : addedEdges) - edge.render(g); - g.setColor(Color.RED); - for(Edge edge : removedEdges) - edge.render(g); - } - - public Node pick(double x, double y) { - for(Node node : nodes) - if(node.pick(x, y)) - return node; - return null; - } - - public Node pickExtension(double x, double y) { - for(Node node : extensionNodes) - if(node.pick(x, y)) - return node; - return null; - } - - { - addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - double x = canvasPosX+e.getX()/canvasZoom; - double y = canvasPosY+e.getY()/canvasZoom; - if(e.getButton() == MouseEvent.BUTTON1) - handleMouseLeftPressed(x, y); - else if(e.getButton() == MouseEvent.BUTTON2) - handleMouseMiddlePressed(x, y); - } - @Override - public void mouseMoved(MouseEvent e) { - handleMouseMoved(canvasPosX+e.getX()/canvasZoom, - canvasPosY+e.getY()/canvasZoom); - } - @Override - public void mouseReleased(MouseEvent e) { - handleMouseReleased(canvasPosX+e.getX()/canvasZoom, - canvasPosY+e.getY()/canvasZoom); - } - @Override - public void mouseWheelMoved(MouseWheelEvent e) { - double x = canvasPosX+e.getX()/canvasZoom; - double y = canvasPosY+e.getY()/canvasZoom; - handleMouseWheelMoved(x, y, e.getWheelRotation()); - } - }); - addMouseMotionListener(new MouseMotionAdapter() { - @Override - public void mouseDragged(MouseEvent e) { - handleMouseMoved(canvasPosX+e.getX()/canvasZoom, - canvasPosY+e.getY()/canvasZoom); - } - }); - addMouseWheelListener(new MouseWheelListener() { - @Override - public void mouseWheelMoved(MouseWheelEvent e) { - double x = canvasPosX+e.getX()/canvasZoom; - double y = canvasPosY+e.getY()/canvasZoom; - handleMouseWheelMoved(x, y, e.getWheelRotation()); - } - }); - addKeyListener(new UsefulKeyAdapter(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent e) { - DebuggerCanvas.this.keyPressed(e); - } - @Override - public void keyReleased(KeyEvent e) { - DebuggerCanvas.this.keyReleased(e); - } - })); - DropTarget dropTarget = new DropTarget(this, new DropTargetAdapter() { - @Override - public void drop(DropTargetDropEvent dtde) { - try { - Transferable transferable = dtde.getTransferable(); - - if( transferable.isDataFlavorSupported( - LocalObjectTransferable.FLAVOR ) ) { - dtde.acceptDrop( DnDConstants.ACTION_MOVE ); - - transferable.getTransferData(LocalObjectTransferable.FLAVOR ); - Object obj = LocalObjectTransfer.getTransfer().getObject(); - double x = canvasPosX+dtde.getLocation().getX()/canvasZoom; - double y = canvasPosY+dtde.getLocation().getY()/canvasZoom; - handleDrop(x, y, obj); - - dtde.getDropTargetContext().dropComplete( true ); - } - else { - dtde.rejectDrop(); - } - } catch( IOException exception ) { - exception.printStackTrace(); - dtde.rejectDrop(); - } catch( UnsupportedFlavorException ufException ) { - ufException.printStackTrace(); - dtde.rejectDrop(); - } - } - }); - } - - public void keyPressed(KeyEvent e) { - switch(e.getKeyCode()) { - case KeyEvent.VK_1: - zoomToFit(); - break; - case KeyEvent.VK_L: - layoutGraph(); - break; - case KeyEvent.VK_CONTROL: - if(!extensionMode) { - initializeExtension(); - extensionMode = true; - repaint(); - } - break; - case KeyEvent.VK_C: - findPreviousChangeset(); - break; - case KeyEvent.VK_DELETE: - if (!extensionMode && dragging != null) { - nodes.remove(dragging); - scheduleUpdate(); - repaint(); - } - break; - } - } - - public void keyReleased(KeyEvent e) { - if(e.getKeyCode() == KeyEvent.VK_CONTROL) { - extensionMode = false; - scheduleUpdate(); - repaint(); - } - } - - private static Resource extractResource(Object obj) { - System.out.println("- " + obj.getClass().getName()); - if(obj instanceof WorkbenchSelectionElement) { - Resource resource = ((WorkbenchSelectionElement)obj).getContent(new AnyResource(Simantics.getSession())); - if(resource != null) - return resource; - } - if(obj instanceof IAdaptable) { - Resource resource = (Resource)((IAdaptable)obj).getAdapter(Resource.class); - if(resource != null) - return resource; - } - return null; - } - - private void handleDrop(double x, double y, Object obj) { - //System.out.println(obj.getClass().getName()); - if(obj instanceof IStructuredSelection) { - for(Object element : ((IStructuredSelection)obj).toArray()) { - Resource resource = extractResource(element); - if(resource != null && !nodeMap.containsKey(resource)) { - addResource(x, y, resource); - repaint(); - } - } - } - } - - private Node addResource(double x, double y, Resource resource) { - Node a = new Node(new NodeData(resource)); - a.setPos(x, y); - scheduleUpdate(); - nodes.add(a); - return a; - } - - private void scheduleUpdate() { - Simantics.getSession().asyncRequest(new ReadRequest() { - @Override - public void run(ReadGraph graph) throws DatabaseException { - updateNodes(graph); - updateEdges(graph); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - repaint(); - } - - }); - } - }); - } - - public void layoutGraph() { - ArrayList allEdges = new ArrayList( - edges.size() + addedEdges.size() + removedEdges.size() - ); - allEdges.addAll(edges); - allEdges.addAll(addedEdges); - allEdges.addAll(removedEdges); - LayoutGraph.layout( - nodes.toArray(new Node[nodes.size()]), - allEdges.toArray(new Edge[edges.size()])); - repaint(); - } - - private void updateNodes(ReadGraph graph) throws DatabaseException { - for(Node node : nodes) { - node.getData().updateData(graph, labelingPreferences); - node.setContent(new LabelContent(node.getData().getLabels())); - } - nodeMap.clear(); - for(Node node : nodes) { - NodeData data = node.getData(); - nodeMap.put(data.getResource(), node); - } - } - - private void updateEdges(ReadGraph graph) throws DatabaseException { - ArrayList edges = new ArrayList(); - for(Node node : nodes) { - NodeData data = node.getData(); - Resource subject = data.getResource(); - ArrayList filteredStatements = new ArrayList(data.getStatements().size()); - for(Statement stat : data.getStatements()) { - Resource object = stat.getObject(); - Node node2 = nodeMap.get(object); - if(node2 != null) { - if(object.getResourceId() > subject.getResourceId() || - graph.getPossibleInverse(stat.getPredicate()) == null) { - edges.add(createEdge(graph, stat, node, node2)); - } - } - else - filteredStatements.add(stat); - } - data.setStatements(filteredStatements); - } - this.edges = edges; - this.addedEdges = filterEdgesWithoutNodes( this.addedEdges ); - this.removedEdges = filterEdgesWithoutNodes( this.removedEdges ); - } - - private ArrayList filterEdgesWithoutNodes(Collection edges) { - ArrayList result = new ArrayList(edges.size()); - for (Edge e : edges) { - if (!nodeMap.containsValue(e.getA()) || !nodeMap.containsValue(e.getB())) - continue; - result.add(e); - } - return result; - } - - private Edge createEdge(ReadGraph graph, Statement stat, Node n1, Node n2) throws DatabaseException { - Resource predicate = stat.getPredicate(); - Resource inverse = graph.getPossibleInverse(predicate); - if(inverse != null) { - Layer0 L0 = Layer0.getInstance(graph); - if(graph.hasStatement(predicate, L0.PartOf, inverse) - || predicate.equals(L0.PartOf) - || predicate.equals(L0.SuperrelationOf) - || predicate.equals(L0.SupertypeOf)) { - predicate = inverse; - Node temp = n1; - n1 = n2; - n2 = temp; - } - } - Edge edge = new Edge(n1, n2); - edge.setContent(new LabelContent(new String[] { - NameUtils.getSafeName(graph, predicate)})); - return edge; - } - - Node dragging = null; - double dragDX, dragDY; - private void handleMouseLeftPressed(double x, double y) { - Node node; - if(extensionMode) { - node = pickExtension(x, y); - if(node != null) { - nodes.add(node); - extensionNodes.remove(node); - } - } - else - node = pick(x, y); - if(node != null) { - dragDX = x - node.getX(); - dragDY = y - node.getY(); - dragging = node; - } - } - - Point2D panningStartMouse; - private void handleMouseMiddlePressed(double x, double y) { - panningStartMouse = new Point2D.Double(x, y); - } - - private void handleMouseMoved(double x, double y) { - if(dragging != null) { - dragging.setPos(x-dragDX, y-dragDY); - repaint(); - } - if(panningStartMouse != null) { - canvasPosX -= x - panningStartMouse.getX(); - canvasPosY -= y - panningStartMouse.getY(); - repaint(); - } - } - - private void handleMouseWheelMoved(double x, double y, double amount) { - double s = Math.exp(-0.2*amount); - canvasZoom *= s; - canvasPosX = x - (x-canvasPosX)/s; - canvasPosY = y - (y-canvasPosY)/s; - repaint(); - } - - private void handleMouseReleased(double x, double y) { - dragging = null; - panningStartMouse = null; - } - - public void zoomToFit() { - if(!nodes.isEmpty()) { - double minX = Double.POSITIVE_INFINITY; - double minY = Double.POSITIVE_INFINITY; - double maxX = Double.NEGATIVE_INFINITY; - double maxY = Double.NEGATIVE_INFINITY; - System.out.println("(" + minX + "," + minY + ") - (" + maxX + "," + maxY + ")"); - for(Node node : nodes) { - minX = Math.min(minX, node.getMinX()); - minY = Math.min(minY, node.getMinY()); - maxX = Math.max(maxX, node.getMaxX()); - maxY = Math.max(maxY, node.getMaxY()); - } - canvasZoom = Math.min(getWidth()/(maxX-minX), getHeight()/(maxY-minY)); - canvasZoom *= 0.9; - canvasPosX = minX - 0.5 * (getWidth()/canvasZoom - maxX+minX); - canvasPosY = minY - 0.5 * (getHeight()/canvasZoom - maxY+minY); - repaint(); - } - } - - THashMap extensionNodeMap = new THashMap(); - public void initializeExtension() { - extensionNodes.clear(); - extensionEdges.clear(); - try { - Simantics.getSession().syncRequest(new ReadRequest() { - @Override - public void run(ReadGraph graph) throws DatabaseException { - THashMap oldExtensionNodeMap = DebuggerCanvas.this.extensionNodeMap; - THashMap extensionNodeMap = new THashMap(); - for(Node node : nodes) { - for(Statement stat : node.getData().getStatements()) { - Resource object = stat.getObject(); - Node node2 = extensionNodeMap.get(object); - if(node2 == null) { - node2 = oldExtensionNodeMap.get(object); - if(node2 == null) { - node2 = new Node(new NodeData(object)); - double angle = random.nextDouble() * Math.PI * 2.0; - double dx = Math.cos(angle); - double dy = Math.sin(angle); - double len = 150.0; - node2.setPos(node.getX() + dx*len, node.getY() + dy*len); - } - node2.getData().updateData(graph, labelingPreferences); - node2.setContent(new LabelContent(node2.getData().getLabels())); - extensionNodeMap.put(object, node2); - extensionNodes.add(node2); - } - extensionEdges.add(createEdge(graph, stat, node, node2)); - } - } - DebuggerCanvas.this.extensionNodeMap = extensionNodeMap; - layoutExtension(); - } - }); - } catch (DatabaseException e) { - e.printStackTrace(); - } - } - - private void layoutExtension() { - TObjectIntHashMap extensionNodeIds = new TObjectIntHashMap(); - for(int i=0;i css = - ms.fetchChangeSets(graph, firstId, lastId); - Layer0 L0 = Layer0.getInstance(graph); - for(ChangeSet cs : css) { - for(ChangeSet.StatementChange stat : cs.changedStatements()) { - Resource predicate = stat.getPredicate(); - if(predicate.equals(L0.InstanceOf) || - predicate.equals(L0.HasName) || - predicate.equals(L0.NameOf)) - continue; - Edge edge = createEdge(graph, stat, - getNode(stat.getSubject()), - getNode(stat.getObject())); - if(stat.isClaim()) - addedEdges.add(edge); - else - removedEdges.add(edge); - } - } - scheduleUpdate(); - } - }); - } catch(DatabaseException e) { - e.printStackTrace(); - } - } - - private static long getOpId(ManagementSupport ms, long revisionId) throws DatabaseException { - Collection ids = ms.getChangeSetIdentifiers(revisionId, revisionId); - ChangeSetIdentifier curId = ids.iterator().next(); - byte[] opIdData = curId.getMetadata().get("opid"); - System.out.println(new String(opIdData)); - long opId = Long.parseLong(new String(opIdData)); - if(opId == 0) - opId = revisionId; - return opId; - } - -} +package org.simantics.debug.graphical; + +import java.awt.Color; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Random; + +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.simantics.Simantics; +import org.simantics.db.ChangeSet; +import org.simantics.db.ChangeSetIdentifier; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.Statement; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; +import org.simantics.db.service.ManagementSupport; +import org.simantics.db.service.SerialisationSupport; +import org.simantics.debug.graphical.layout.ExtensionLayoutAlgorithm; +import org.simantics.debug.graphical.layout.LayoutGraph; +import org.simantics.debug.graphical.model.Edge; +import org.simantics.debug.graphical.model.LabelContent; +import org.simantics.debug.graphical.model.Node; +import org.simantics.debug.graphical.model.NodeData; +import org.simantics.layer0.Layer0; +import org.simantics.scl.runtime.SCLContext; +import org.simantics.scl.runtime.function.Function; +import org.simantics.ui.dnd.LocalObjectTransfer; +import org.simantics.ui.dnd.LocalObjectTransferable; +import org.simantics.ui.selection.AnyResource; +import org.simantics.ui.selection.WorkbenchSelectionElement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.NumericNode; + +import gnu.trove.list.array.TDoubleArrayList; +import gnu.trove.map.hash.THashMap; +import gnu.trove.map.hash.TObjectIntHashMap; + +public class DebuggerCanvas extends JPanel { + private static final Logger LOGGER = LoggerFactory.getLogger(DebuggerCanvas.class); + + private static final long serialVersionUID = -718678297301786379L; + + ArrayList nodes = new ArrayList(); + THashMap nodeMap = new THashMap(); + ArrayList edges = new ArrayList(); + ArrayList extensionNodes = new ArrayList(); + ArrayList extensionEdges = new ArrayList(); + ArrayList addedEdges = new ArrayList(); + ArrayList removedEdges = new ArrayList(); + double canvasPosX = 0.0; + double canvasPosY = 0.0; + double canvasZoom = 1.0; + boolean extensionMode = false; + Random random = new Random(); + public Function statementFilter; + + LabelingPreferences labelingPreferences = + new LabelingPreferences(); + + public void setStatementFilter(Function statementFilter) { + this.statementFilter = statementFilter; + } + + public void removeStatementFilter() { + this.statementFilter = null; + } + + @Override + public void paint(Graphics _g) { + Graphics2D g = (Graphics2D)_g; + + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + g.setPaint(new GradientPaint(0.0f, 0.0f, new Color(200, 200, 200), getWidth(), getHeight(), Color.WHITE)); + g.fill(new Rectangle2D.Double(0, 0, getWidth(), getHeight())); + g.setColor(Color.BLACK); + g.setTransform(new AffineTransform( + canvasZoom, 0.0, + 0.0, canvasZoom, + -canvasPosX*canvasZoom, -canvasPosY*canvasZoom)); + for(Node node : nodes) + node.render(g); + for(Edge edge : edges) + edge.render(g); + if(extensionMode) { + for(Node node : extensionNodes) + node.render(g); + for(Edge edge : extensionEdges) + edge.render(g); + } + g.setColor(Color.GREEN); + for(Edge edge : addedEdges) + edge.render(g); + g.setColor(Color.RED); + for(Edge edge : removedEdges) + edge.render(g); + } + + public Node pick(double x, double y) { + for(Node node : nodes) + if(node.pick(x, y)) + return node; + return null; + } + + public Node pickExtension(double x, double y) { + for(Node node : extensionNodes) + if(node.pick(x, y)) + return node; + return null; + } + + { + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + double x = canvasPosX+e.getX()/canvasZoom; + double y = canvasPosY+e.getY()/canvasZoom; + if(e.getButton() == MouseEvent.BUTTON1) + handleMouseLeftPressed(x, y); + else if(e.getButton() == MouseEvent.BUTTON2) + handleMouseMiddlePressed(x, y); + } + @Override + public void mouseMoved(MouseEvent e) { + handleMouseMoved(canvasPosX+e.getX()/canvasZoom, + canvasPosY+e.getY()/canvasZoom); + } + @Override + public void mouseReleased(MouseEvent e) { + handleMouseReleased(canvasPosX+e.getX()/canvasZoom, + canvasPosY+e.getY()/canvasZoom); + } + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + double x = canvasPosX+e.getX()/canvasZoom; + double y = canvasPosY+e.getY()/canvasZoom; + handleMouseWheelMoved(x, y, e.getWheelRotation()); + } + }); + addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseDragged(MouseEvent e) { + handleMouseMoved(canvasPosX+e.getX()/canvasZoom, + canvasPosY+e.getY()/canvasZoom); + } + }); + addMouseWheelListener(new MouseWheelListener() { + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + double x = canvasPosX+e.getX()/canvasZoom; + double y = canvasPosY+e.getY()/canvasZoom; + handleMouseWheelMoved(x, y, e.getWheelRotation()); + } + }); + addKeyListener(new UsefulKeyAdapter(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + DebuggerCanvas.this.keyPressed(e); + } + @Override + public void keyReleased(KeyEvent e) { + DebuggerCanvas.this.keyReleased(e); + } + })); + DropTarget dropTarget = new DropTarget(this, new DropTargetAdapter() { + @Override + public void drop(DropTargetDropEvent dtde) { + try { + Transferable transferable = dtde.getTransferable(); + if( transferable.isDataFlavorSupported( + LocalObjectTransferable.FLAVOR ) ) { + dtde.acceptDrop( DnDConstants.ACTION_MOVE ); + + transferable.getTransferData(LocalObjectTransferable.FLAVOR); + Object obj = LocalObjectTransfer.getTransfer().getObject(); + handleDrop(dtde, obj); + } + else { + DataFlavor textFlavor = DataFlavor.selectBestTextFlavor(transferable.getTransferDataFlavors()); + if(textFlavor != null) { + // Try to read the textual content of the drop event as a JSON object containing a field named resourceId + try(Reader reader = textFlavor.getReaderForText(transferable)) { + ObjectMapper mapper = new ObjectMapper(); + JsonNode node = mapper.readTree(reader); + Object resourceId = node.get("resourceId"); + if(resourceId instanceof NumericNode) { + dtde.acceptDrop( DnDConstants.ACTION_MOVE ); + + transferable.getTransferData(LocalObjectTransferable.FLAVOR); + Object obj = new StructuredSelection(Simantics.getSession().syncRequest(new Read() { + public Resource perform(ReadGraph graph) throws DatabaseException { + SerialisationSupport ss = graph.getService(SerialisationSupport.class); + return ss.getResource(((NumericNode)resourceId).longValue()); + } + })); + handleDrop(dtde, obj); + return; + } + } + } + dtde.rejectDrop(); + } + } catch( Exception exception ) { + LOGGER.warn("Drop failed.", exception); + dtde.rejectDrop(); + } + } + }); + } + + private void handleDrop(DropTargetDropEvent dtde, Object obj) { + double x = canvasPosX+dtde.getLocation().getX()/canvasZoom; + double y = canvasPosY+dtde.getLocation().getY()/canvasZoom; + handleDrop(x, y, obj); + + dtde.getDropTargetContext().dropComplete( true ); + } + + public void keyPressed(KeyEvent e) { + switch(e.getKeyCode()) { + case KeyEvent.VK_1: + zoomToFit(); + break; + case KeyEvent.VK_L: + layoutGraph(); + break; + case KeyEvent.VK_CONTROL: + if(!extensionMode) { + initializeExtension(); + extensionMode = true; + repaint(); + } + break; + case KeyEvent.VK_C: + findPreviousChangeset(); + break; + case KeyEvent.VK_DELETE: + if (!extensionMode && dragging != null) { + nodes.remove(dragging); + scheduleUpdate(); + repaint(); + } + break; + } + } + + public void keyReleased(KeyEvent e) { + if(e.getKeyCode() == KeyEvent.VK_CONTROL) { + extensionMode = false; + scheduleUpdate(); + repaint(); + } + } + + private static Resource extractResource(Object obj) { + System.out.println("- " + obj.getClass().getName()); + if(obj instanceof WorkbenchSelectionElement) { + Resource resource = ((WorkbenchSelectionElement)obj).getContent(new AnyResource(Simantics.getSession())); + if(resource != null) + return resource; + } + if(obj instanceof IAdaptable) { + Resource resource = (Resource)((IAdaptable)obj).getAdapter(Resource.class); + if(resource != null) + return resource; + } + if(obj instanceof Resource) + return (Resource)obj; + return null; + } + + private void handleDrop(double x, double y, Object obj) { + //System.out.println(obj.getClass().getName()); + if(obj instanceof IStructuredSelection) { + for(Object element : ((IStructuredSelection)obj).toArray()) { + Resource resource = extractResource(element); + if(resource != null && !nodeMap.containsKey(resource)) { + addResource(x, y, resource); + repaint(); + } + } + } + } + + private Node addResource(double x, double y, Resource resource) { + Node a = new Node(new NodeData(resource)); + a.setPos(x, y); + scheduleUpdate(); + nodes.add(a); + return a; + } + + public void addResource(Resource resource) { + double x, y; + if(nodes.isEmpty()) { + x = 0.0; + y = 0.0; + } + else { + double xMin=Double.POSITIVE_INFINITY, yMin=Double.POSITIVE_INFINITY; + double xMax=Double.NEGATIVE_INFINITY, yMax=Double.NEGATIVE_INFINITY; + for(Node node : nodes) { + xMin = Math.min(node.getMinX(), xMin); + yMin = Math.min(node.getMinY(), yMin); + xMax = Math.max(node.getMaxX(), xMax); + yMax = Math.max(node.getMaxY(), yMax); + } + x = xMin + (xMax - xMin) * random.nextDouble(); + y = yMin + (yMax - yMin) * random.nextDouble(); + } + + addResource(x, y, resource); + repaint(); + } + + private void scheduleUpdate() { + Simantics.getSession().asyncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + updateNodes(graph); + updateEdges(graph); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + repaint(); + } + + }); + } + }); + } + + public void layoutGraph() { + ArrayList allEdges = new ArrayList( + edges.size() + addedEdges.size() + removedEdges.size() + ); + allEdges.addAll(edges); + allEdges.addAll(addedEdges); + allEdges.addAll(removedEdges); + LayoutGraph.layout( + nodes.toArray(new Node[nodes.size()]), + allEdges.toArray(new Edge[edges.size()])); + repaint(); + } + + private void updateNodes(ReadGraph graph) throws DatabaseException { + for(Node node : nodes) { + node.getData().updateData(graph, labelingPreferences); + node.setContent(new LabelContent(node.getData().getLabels())); + } + nodeMap.clear(); + for(Node node : nodes) { + NodeData data = node.getData(); + nodeMap.put(data.getResource(), node); + } + } + + private void updateEdges(ReadGraph graph) throws DatabaseException { + ArrayList edges = new ArrayList(); + for(Node node : nodes) { + NodeData data = node.getData(); + Resource subject = data.getResource(); + ArrayList filteredStatements = new ArrayList(data.getStatements().size()); + for(Statement stat : data.getStatements()) { + Resource object = stat.getObject(); + Node node2 = nodeMap.get(object); + if(node2 != null) { + if(object.getResourceId() > subject.getResourceId() || + graph.getPossibleInverse(stat.getPredicate()) == null) { + edges.add(createEdge(graph, stat, node, node2)); + } + } + else + filteredStatements.add(stat); + } + data.setStatements(filteredStatements); + } + this.edges = edges; + this.addedEdges = filterEdgesWithoutNodes( this.addedEdges ); + this.removedEdges = filterEdgesWithoutNodes( this.removedEdges ); + } + + private ArrayList filterEdgesWithoutNodes(Collection edges) { + ArrayList result = new ArrayList(edges.size()); + for (Edge e : edges) { + if (!nodeMap.containsValue(e.getA()) || !nodeMap.containsValue(e.getB())) + continue; + result.add(e); + } + return result; + } + + private Edge createEdge(ReadGraph graph, Statement stat, Node n1, Node n2) throws DatabaseException { + Resource predicate = stat.getPredicate(); + Resource inverse = graph.getPossibleInverse(predicate); + if(inverse != null) { + Layer0 L0 = Layer0.getInstance(graph); + if(graph.hasStatement(predicate, L0.PartOf, inverse) + || predicate.equals(L0.PartOf) + || predicate.equals(L0.SuperrelationOf) + || predicate.equals(L0.SupertypeOf)) { + predicate = inverse; + Node temp = n1; + n1 = n2; + n2 = temp; + } + } + Edge edge = new Edge(n1, n2); + edge.setContent(new LabelContent(new String[] { + NameUtils.getSafeName(graph, predicate)})); + return edge; + } + + Node dragging = null; + double dragDX, dragDY; + private void handleMouseLeftPressed(double x, double y) { + Node node; + if(extensionMode) { + node = pickExtension(x, y); + if(node != null) { + nodes.add(node); + extensionNodes.remove(node); + } + } + else + node = pick(x, y); + if(node != null) { + dragDX = x - node.getX(); + dragDY = y - node.getY(); + dragging = node; + } + } + + Point2D panningStartMouse; + private void handleMouseMiddlePressed(double x, double y) { + panningStartMouse = new Point2D.Double(x, y); + } + + private void handleMouseMoved(double x, double y) { + if(dragging != null) { + dragging.setPos(x-dragDX, y-dragDY); + repaint(); + } + if(panningStartMouse != null) { + canvasPosX -= x - panningStartMouse.getX(); + canvasPosY -= y - panningStartMouse.getY(); + repaint(); + } + } + + private void handleMouseWheelMoved(double x, double y, double amount) { + double s = Math.exp(-0.2*amount); + canvasZoom *= s; + canvasPosX = x - (x-canvasPosX)/s; + canvasPosY = y - (y-canvasPosY)/s; + repaint(); + } + + private void handleMouseReleased(double x, double y) { + dragging = null; + panningStartMouse = null; + } + + public void zoomToFit() { + if(!nodes.isEmpty()) { + double minX = Double.POSITIVE_INFINITY; + double minY = Double.POSITIVE_INFINITY; + double maxX = Double.NEGATIVE_INFINITY; + double maxY = Double.NEGATIVE_INFINITY; + System.out.println("(" + minX + "," + minY + ") - (" + maxX + "," + maxY + ")"); + for(Node node : nodes) { + minX = Math.min(minX, node.getMinX()); + minY = Math.min(minY, node.getMinY()); + maxX = Math.max(maxX, node.getMaxX()); + maxY = Math.max(maxY, node.getMaxY()); + } + canvasZoom = Math.min(getWidth()/(maxX-minX), getHeight()/(maxY-minY)); + canvasZoom *= 0.9; + canvasPosX = minX - 0.5 * (getWidth()/canvasZoom - maxX+minX); + canvasPosY = minY - 0.5 * (getHeight()/canvasZoom - maxY+minY); + repaint(); + } + } + + THashMap extensionNodeMap = new THashMap(); + public void initializeExtension() { + extensionNodes.clear(); + extensionEdges.clear(); + try { + Simantics.getSession().syncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + SCLContext sclContext = SCLContext.getCurrent(); + Object oldGraph = sclContext.put("graph", graph); + try { + THashMap oldExtensionNodeMap = DebuggerCanvas.this.extensionNodeMap; + THashMap extensionNodeMap = new THashMap(); + for(Node node : nodes) { + for(Statement stat : node.getData().getStatements()) { + Resource object = stat.getObject(); + Node node2 = extensionNodeMap.get(object); + if(node2 == null) { + if(statementFilter != null && Boolean.FALSE.equals(statementFilter.apply(stat))) + continue; + node2 = oldExtensionNodeMap.get(object); + if(node2 == null) { + node2 = new Node(new NodeData(object)); + double angle = random.nextDouble() * Math.PI * 2.0; + double dx = Math.cos(angle); + double dy = Math.sin(angle); + double len = 150.0; + node2.setPos(node.getX() + dx*len, node.getY() + dy*len); + } + node2.getData().updateData(graph, labelingPreferences); + node2.setContent(new LabelContent(node2.getData().getLabels())); + extensionNodeMap.put(object, node2); + extensionNodes.add(node2); + } + extensionEdges.add(createEdge(graph, stat, node, node2)); + } + } + } catch (Throwable t) { + if (t instanceof DatabaseException) + throw (DatabaseException) t; + throw new DatabaseException(t); + } finally { + sclContext.put("graph", oldGraph); + } + DebuggerCanvas.this.extensionNodeMap = extensionNodeMap; + layoutExtension(); + } + }); + } catch (DatabaseException e) { + e.printStackTrace(); + } + } + + private void layoutExtension() { + TObjectIntHashMap extensionNodeIds = new TObjectIntHashMap(); + for(int i=0;i css = + ms.fetchChangeSets(graph, firstId, lastId); + Layer0 L0 = Layer0.getInstance(graph); + for(ChangeSet cs : css) { + for(ChangeSet.StatementChange stat : cs.changedStatements()) { + Resource predicate = stat.getPredicate(); + if(predicate.equals(L0.InstanceOf) || + predicate.equals(L0.HasName) || + predicate.equals(L0.NameOf)) + continue; + Edge edge = createEdge(graph, stat, + getNode(stat.getSubject()), + getNode(stat.getObject())); + if(stat.isClaim()) + addedEdges.add(edge); + else + removedEdges.add(edge); + } + } + scheduleUpdate(); + } + }); + } catch(DatabaseException e) { + e.printStackTrace(); + } + } + + private static long getOpId(ManagementSupport ms, long revisionId) throws DatabaseException { + Collection ids = ms.getChangeSetIdentifiers(revisionId, revisionId); + ChangeSetIdentifier curId = ids.iterator().next(); + byte[] opIdData = curId.getMetadata().get("opid"); + System.out.println(new String(opIdData)); + long opId = Long.parseLong(new String(opIdData)); + if(opId == 0) + opId = revisionId; + return opId; + } + +}