/* * #%L * ===================================================== * _____ _ ____ _ _ _ _ * |_ _|_ __ _ _ ___| |_ / __ \| | | | ___ | | | | * | | | '__| | | / __| __|/ / _` | |_| |/ __|| |_| | * | | | | | |_| \__ \ |_| | (_| | _ |\__ \| _ | * |_| |_| \__,_|___/\__|\ \__,_|_| |_||___/|_| |_| * \____/ * * ===================================================== * * Hochschule Hannover * (University of Applied Sciences and Arts, Hannover) * Faculty IV, Dept. of Computer Science * Ricklinger Stadtweg 118, 30459 Hannover, Germany * * Email: trust@f4-i.fh-hannover.de * Website: http://trust.f4.hs-hannover.de/ * * This file is part of visitmeta-visualization, version 0.6.0, * implemented by the Trust@HsH research group at the Hochschule Hannover. * %% * Copyright (C) 2012 - 2016 Trust@HsH * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package de.hshannover.f4.trust.visitmeta.graphDrawer; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JComponent; import javax.swing.SwingUtilities; import org.apache.log4j.Logger; import org.piccolo2d.PCanvas; import org.piccolo2d.PLayer; import org.piccolo2d.PNode; import org.piccolo2d.activities.PActivity; import org.piccolo2d.activities.PTransformActivity; import org.piccolo2d.extras.nodes.PComposite; import org.piccolo2d.nodes.PPath; import org.piccolo2d.nodes.PText; import org.piccolo2d.util.PAffineTransform; import org.piccolo2d.util.PBounds; import org.piccolo2d.util.PPaintContext; import org.piccolo2d.util.PUtil; import de.hshannover.f4.trust.ironcommon.properties.Properties; import de.hshannover.f4.trust.visitmeta.Main; import de.hshannover.f4.trust.visitmeta.datawrapper.ExpandedLink; import de.hshannover.f4.trust.visitmeta.datawrapper.NodeIdentifier; import de.hshannover.f4.trust.visitmeta.datawrapper.NodeMetadata; import de.hshannover.f4.trust.visitmeta.datawrapper.NodeType; import de.hshannover.f4.trust.visitmeta.datawrapper.Position; import de.hshannover.f4.trust.visitmeta.graphDrawer.edgepainter.EdgePainter; import de.hshannover.f4.trust.visitmeta.graphDrawer.graphicwrapper.GraphicWrapper; import de.hshannover.f4.trust.visitmeta.graphDrawer.graphicwrapper.piccolo2d.Piccolo2DGraphicWrapper; import de.hshannover.f4.trust.visitmeta.graphDrawer.graphicwrapper.piccolo2d.Piccolo2DGraphicWrapperFactory; import de.hshannover.f4.trust.visitmeta.graphDrawer.nodeinformation.identifier.IdentifierInformationStrategy; import de.hshannover.f4.trust.visitmeta.graphDrawer.nodeinformation.identifier.IdentifierInformationStrategyFactory; import de.hshannover.f4.trust.visitmeta.graphDrawer.nodeinformation.identifier.IdentifierInformationStrategyType; import de.hshannover.f4.trust.visitmeta.graphDrawer.nodeinformation.metadata.MetadataInformationStrategy; import de.hshannover.f4.trust.visitmeta.graphDrawer.nodeinformation.metadata.MetadataInformationStrategyFactory; import de.hshannover.f4.trust.visitmeta.graphDrawer.nodeinformation.metadata.MetadataInformationStrategyType; import de.hshannover.f4.trust.visitmeta.graphDrawer.nodepainter.NodePainter; import de.hshannover.f4.trust.visitmeta.graphDrawer.piccolo2d.ClickEventHandler; import de.hshannover.f4.trust.visitmeta.graphDrawer.piccolo2d.NodeEventHandler; import de.hshannover.f4.trust.visitmeta.graphDrawer.piccolo2d.ZoomEventHandler; import de.hshannover.f4.trust.visitmeta.graphDrawer.piccolo2d.edgerenderer.Piccolo2dEdgeRenderer; import de.hshannover.f4.trust.visitmeta.graphDrawer.piccolo2d.edgerenderer.Piccolo2dEdgeRendererFactory; import de.hshannover.f4.trust.visitmeta.graphDrawer.piccolo2d.edgerenderer.Piccolo2dEdgeRendererType; import de.hshannover.f4.trust.visitmeta.graphDrawer.piccolo2d.noderenderer.Piccolo2dNodeRenderer; import de.hshannover.f4.trust.visitmeta.graphDrawer.piccolo2d.noderenderer.Piccolo2dNodeRendererFactory; import de.hshannover.f4.trust.visitmeta.graphDrawer.piccolo2d.noderenderer.Piccolo2dNodeRendererType; import de.hshannover.f4.trust.visitmeta.gui.GraphConnection; import de.hshannover.f4.trust.visitmeta.gui.GuiMode; import de.hshannover.f4.trust.visitmeta.gui.search.SearchAndFilterStrategy; import de.hshannover.f4.trust.visitmeta.gui.search.Searchable; import de.hshannover.f4.trust.visitmeta.interfaces.Identifier; import de.hshannover.f4.trust.visitmeta.interfaces.Metadata; import de.hshannover.f4.trust.visitmeta.util.MetadataHelper; import de.hshannover.f4.trust.visitmeta.util.VisualizationConfig; /** * Implementation of the {@link GraphPanel} and {@link Searchable} interfaces. * Creates a Piccolo2D-based panel for drawing a graph. Can also mark nodes * based on search terms provided by a {@link SearchAndFilterStrategy}. * * @author Bastian Hellmann * */ public class Piccolo2DPanel implements GraphPanel, Searchable { private static final Logger LOGGER = Logger.getLogger(Piccolo2DPanel.class); private static final Properties mConfig = Main.getConfig(); private PLayer mLayerNode = null; private PLayer mLayerEdge = null; private PLayer mLayerGlow = null; private PCanvas mPanel = new PCanvas(); private HashMap<Object, PComposite> mMapNode = new HashMap<>(); private HashMap<NodeMetadata, ArrayList<PPath>> mMapEdge = new HashMap<>(); private int mNodeTranslationDuration = 0; private double mAreaOffsetX = 0.0; private double mAreaOffsetY = 0.0; private double mAreaWidth = 650.0; private double mAreaHeight = 650.0; public double mGlowWidth = 80.0; public double mGlowHeight = 40.0; private int mFontSize = 20; private Color mColorBackground = null; private Color mColorNewNode = null; private Color mColorDeleteNode = null; private List<String> mPublisher = new ArrayList<>(); private IdentifierInformationStrategy mIdentifierInformationStrategy; private MetadataInformationStrategy mMetadataInformationStrategy; private GraphicWrapper mSelectedNode = null; private GraphicWrapper mMouseOverNode = null; private String mSearchTerm = ""; private SearchAndFilterStrategy mSearchAndFilterStrategy = null; private Map<GuiMode, List<NodePainter>> mNodePainter = new HashMap<>(); private Map<GuiMode, List<EdgePainter>> mEdgePainter = new HashMap<>(); private Piccolo2dNodeRenderer mPiccolo2dIdentifierRenderer = null; private Piccolo2dNodeRenderer mPiccolo2dMetadataRenderer = null; private Piccolo2dEdgeRenderer mPiccolo2dEdgeRenderer = null; private boolean mHideSearchMismatches = false; private GraphConnection mConnection; private GuiMode mGuiMode; public Piccolo2DPanel(GraphConnection connection) { mConnection = connection; mNodeTranslationDuration = connection.getSettingManager() .getNodeTranslationDuration(); mPanel.setDefaultRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); mPanel.setInteractingRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); mPanel.setAnimatingRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); mLayerNode = mPanel.getLayer(); mLayerEdge = new PLayer(); mPanel.getRoot().addChild(0, mLayerEdge); mPanel.getCamera().addLayer(0, mLayerEdge); mLayerGlow = new PLayer(); mPanel.getRoot().addChild(0, mLayerGlow); mPanel.getCamera().addLayer(0, mLayerGlow); mPanel.addMouseListener(new ClickEventHandler(this)); mPanel.setZoomEventHandler(new ZoomEventHandler(this)); mPanel.addInputEventListener(new NodeEventHandler(connection, this)); String vColorBackground = mConfig.getString(VisualizationConfig.KEY_COLOR_BACKGROUND, VisualizationConfig.DEFAULT_VALUE_COLOR_BACKGROUND); mColorBackground = Color.decode(vColorBackground); mPanel.setBackground(mColorBackground); String vColorNewNode = mConfig.getString(VisualizationConfig.KEY_COLOR_NODE_NEW, VisualizationConfig.DEFAULT_VALUE_COLOR_NODE_NEW); String vColorDeleteNode = mConfig.getString(VisualizationConfig.KEY_COLOR_NODE_DELETE, VisualizationConfig.DEFAULT_VALUE_COLOR_NODE_DELETE); mColorNewNode = Color.decode(vColorNewNode); mColorDeleteNode = Color.decode(vColorDeleteNode); String identifierInformationStyle = mConfig.getString( VisualizationConfig.KEY_IDENTIFIER_TEXT_STYLE, VisualizationConfig.DEFAULT_VALUE_IDENTIFIER_TEXT_STYLE); IdentifierInformationStrategyType identifierInformationStyleType; try { identifierInformationStyleType = IdentifierInformationStrategyType .valueOf(identifierInformationStyle); } catch (IllegalArgumentException e) { identifierInformationStyleType = IdentifierInformationStrategyType .valueOf(VisualizationConfig.DEFAULT_VALUE_IDENTIFIER_TEXT_STYLE); } mIdentifierInformationStrategy = IdentifierInformationStrategyFactory .create(identifierInformationStyleType); String metadataInformationStyle = mConfig.getString( VisualizationConfig.KEY_METADATA_TEXT_STYLE, VisualizationConfig.DEFAULT_VALUE_METADATA_TEXT_STYLE); MetadataInformationStrategyType metadataInformationStyleType; try { metadataInformationStyleType = MetadataInformationStrategyType .valueOf(metadataInformationStyle); } catch (IllegalArgumentException e) { metadataInformationStyleType = MetadataInformationStrategyType .valueOf(VisualizationConfig.DEFAULT_VALUE_METADATA_TEXT_STYLE); } mMetadataInformationStrategy = MetadataInformationStrategyFactory .create(metadataInformationStyleType); mPiccolo2dMetadataRenderer = createPiccolo2dNodeRenderer(VisualizationConfig.KEY_PICCOLO2D_METADATA_NODE_STYLE, VisualizationConfig.DEFAULT_VALUE_PICCOLO2D_METADATA_NODE_STYLE); mPiccolo2dIdentifierRenderer = createPiccolo2dNodeRenderer(VisualizationConfig.KEY_PICCOLO2D_IDENTIFIER_NODE_STYLE, VisualizationConfig.DEFAULT_VALUE_PICCOLO2D_IDENTIFIER_NODE_STYLE); String edgeRendererStyle = mConfig.getString(VisualizationConfig.KEY_PICCOLO2D_EDGE_STYLE, VisualizationConfig.DEFAULT_VALUE_PICCOLO2D_EDGE_STYLE); Piccolo2dEdgeRendererType type; try { type = Piccolo2dEdgeRendererType.valueOf(edgeRendererStyle); } catch (IllegalArgumentException e) { type = Piccolo2dEdgeRendererType .valueOf(VisualizationConfig.DEFAULT_VALUE_PICCOLO2D_EDGE_STYLE); } mPiccolo2dEdgeRenderer = Piccolo2dEdgeRendererFactory.create(type); mGuiMode = GuiMode.ANALYSIS; } private Piccolo2dNodeRenderer createPiccolo2dNodeRenderer(String key, String defaultValue) { String configEntry = mConfig.getString(key, defaultValue); Piccolo2dNodeRendererType type; try { type = Piccolo2dNodeRendererType.valueOf(configEntry); } catch (IllegalArgumentException e) { type = Piccolo2dNodeRendererType .valueOf(defaultValue); } return Piccolo2dNodeRendererFactory.create(type); } @Override public JComponent getPanel() { LOGGER.trace("Method getPanel() called."); return mPanel; } @Override public synchronized void addIdentifier(NodeIdentifier pNode) { LOGGER.trace("Method addIdentifier(" + pNode + ") called."); if (!mMapNode.containsKey(pNode)) { PText vText = new PText( mIdentifierInformationStrategy.getText(pNode .getIdentifier())); vText.setHorizontalAlignment(Component.CENTER_ALIGNMENT); vText.setFont(new Font(null, Font.PLAIN, mFontSize)); vText.setOffset(-0.5F * (float) vText.getWidth(), -0.5F * (float) vText.getHeight()); final PPath vNode = mPiccolo2dIdentifierRenderer.createNode(pNode.getIdentifier(), vText); /* Composite */ final PComposite vCom = new PComposite(); vCom.addChild(vNode); vCom.addChild(vText); vCom.setOffset( // Set position mAreaOffsetX + pNode.getX() * mAreaWidth, // x mAreaOffsetY + pNode.getY() * mAreaHeight // y ); // Add edges to node vCom.addAttribute("type", NodeType.IDENTIFIER); vCom.addAttribute("position", pNode); vCom.addAttribute("data", pNode.getIdentifier()); vCom.addAttribute("edges", new ArrayList<PPath>()); paintIdentifierNode(pNode.getIdentifier(), vNode, vText); mMapNode.put(pNode, vCom); // Add node to HashMap. SwingUtilities.invokeLater(new Runnable() { @Override public void run() { mLayerNode.addChild(vCom); // Add node to layer. } }); } } private synchronized void addMetadata(NodeMetadata pNode) { LOGGER.trace("Method addMetadata(" + pNode + ") called."); if (!mMapNode.containsKey(pNode)) { final String vPublisher = MetadataHelper.extractPublisherId(pNode.getMetadata()); if (!mPublisher.contains(vPublisher)) { mPublisher.add(vPublisher); } /* Text */ PText vText = new PText(mMetadataInformationStrategy.getText(pNode .getMetadata())); vText.setHorizontalAlignment(Component.CENTER_ALIGNMENT); vText.setFont(new Font(null, Font.PLAIN, mFontSize)); vText.setOffset(-0.5F * (float) vText.getWidth(), -0.5F * (float) vText.getHeight()); /* Rectangle */ final PPath vNode = mPiccolo2dMetadataRenderer.createNode(pNode.getMetadata(), vText); /* Composite */ final PComposite vCom = new PComposite(); vCom.addChild(vNode); vCom.addChild(vText); vCom.setOffset(mAreaOffsetX + pNode.getX() * mAreaWidth, mAreaOffsetY + pNode.getY() * mAreaHeight); vCom.addAttribute("type", NodeType.METADATA); vCom.addAttribute("publisher", vPublisher); vCom.addAttribute("position", pNode); vCom.addAttribute("data", pNode.getMetadata()); vCom.addAttribute("edges", new ArrayList<PPath>()); // Add // edges // to // node paintMetadataNode(pNode.getMetadata(), vNode, vText); mMapNode.put(pNode, vCom); // Add node to HashMap. SwingUtilities.invokeLater(new Runnable() { @Override public void run() { mLayerNode.addChild(vCom); // Add node to layer. } }); } } @Override public void addMetadata(NodeIdentifier pIdentifier, NodeMetadata pMetadata) { LOGGER.trace("Method addMetadata(" + pIdentifier + ", " + pMetadata + ") called."); addMetadata(pMetadata); addEdge(pMetadata, pIdentifier, pMetadata); } @Override public void addMetadata(ExpandedLink pLink, NodeMetadata pMetadata) { LOGGER.trace("Method addMetadata(" + pLink + ", " + pMetadata + ") called."); addMetadata(pMetadata); /* Edges form Identifier to Metadata. */ addEdge(pMetadata, pLink.getFirst(), pMetadata); /* Edges from Metadata to Identifier. */ addEdge(pMetadata, pMetadata, pLink.getSecond()); } /** * Add an edge to the graph. * * @param pKey * a key to group the edge. * @param pNodeFirst * the node where the edge starts. * @param pNodeSecond * the node where the edge ends. */ @Override @SuppressWarnings("unchecked") public synchronized void addEdge(NodeMetadata pKey, Position pNodeFirst, Position pNodeSecond) { LOGGER.trace("Method addEdge(" + pKey + ", " + pNodeFirst + ", " + pNodeSecond + ") called."); PPath vEdge = new PPath.Float(); PComposite vNodeFirst = mMapNode.get(pNodeFirst); PComposite vNodeSecond = mMapNode.get(pNodeSecond); /* Add Edge to Node. */ ((ArrayList<PPath>) vNodeFirst.getAttribute("edges")).add(vEdge); ((ArrayList<PPath>) vNodeSecond.getAttribute("edges")).add(vEdge); /* Add Node to Edge. */ vEdge.addAttribute("nodes", new ArrayList<PComposite>()); ((ArrayList<PComposite>) vEdge.getAttribute("nodes")).add(vNodeFirst); ((ArrayList<PComposite>) vEdge.getAttribute("nodes")).add(vNodeSecond); /* Add edge to layer. */ mLayerEdge.addChild(vEdge); /* Add edge to HashMap. */ ArrayList<PPath> vEdges = mMapEdge.get(pKey); if (vEdges == null) { // Is first entry? vEdges = new ArrayList<>(); mMapEdge.put(pKey, vEdges); } vEdges.add(vEdge); updateEdge(vEdge, pKey); } @Override @SuppressWarnings("unchecked") public void deleteEdge(Object pKey, PPath pEdge) { LOGGER.trace("Method deleteEdge(" + pKey + ", " + pEdge + ") called."); /* Remove edge from layer */ mLayerEdge.removeChild(pEdge); /* Remove edge from node */ for (PComposite vNode : ((ArrayList<PComposite>) pEdge .getAttribute("nodes"))) { ((ArrayList<PPath>) vNode.getAttribute("edges")).remove(pEdge); } } @Override public void updateIdentifier(NodeIdentifier pNode) { LOGGER.trace("Method updateIdentifier(" + pNode + ") called."); /* Update position */ updatePosition(pNode); } @Override public void updateMetadata(NodeMetadata pNode) { LOGGER.trace("Method updateMetadata(" + pNode + ") called."); /* Update position */ updatePosition(pNode); } /** * The the position of a node and its edges. * * @param pNode * the node in the graph. */ @SuppressWarnings("unchecked") private synchronized void updatePosition(final Position pNode) { LOGGER.trace("Method updatePosition(" + pNode + ") called."); if (!pNode.isInUse()) { final double vX = mAreaOffsetX + pNode.getX() * mAreaWidth; final double vY = mAreaOffsetY + pNode.getY() * mAreaHeight; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (mNodeTranslationDuration > 0) { final PComposite vNode = mMapNode.get(pNode); if (vNode != null) { final PAffineTransform vDestTransform = vNode .getTransform(); vDestTransform.setOffset(vX, vY); final PTransformActivity.Target vTarget = new PTransformActivity.Target() { @Override public void setTransform( final AffineTransform pTransform) { vNode.setTransform(pTransform); synchronized (vNode) { PPath vShadow = (PPath) vNode .getAttribute("glow"); if (vShadow != null) { vShadow.setTransform(pTransform); } } } @Override public void getSourceMatrix( final double[] aSource) { vNode.getTransformReference(true) .getMatrix(aSource); } }; PActivity vNodeTranslation = new PTransformActivity( mNodeTranslationDuration, PUtil.DEFAULT_ACTIVITY_STEP_RATE, vTarget, vDestTransform) { @Override protected void activityStep(long time) { /* Set position of the node. */ super.activityStep(time); /* Redraw edges. */ ArrayList<PPath> vEdges = (ArrayList<PPath>) vNode .getAttribute("edges"); for (PPath vEdge : vEdges) { updateEdge(vEdge, pNode); } } }; mMapNode.get(pNode).addAttribute("activity", vNodeTranslation); /* Add node activity */ vNode.addActivity(vNodeTranslation); } } else { final PComposite vNode = mMapNode.get(pNode); vNode.setOffset(vX, vY); ArrayList<PPath> vEdges = (ArrayList<PPath>) vNode .getAttribute("edges"); for (PPath vEdge : vEdges) { updateEdge(vEdge, pNode); } } } }); } } /** * Redraw a edge with the new position on the panel. * * @param pEdge * the edge to redraw. * @param pNodeMetadata */ @SuppressWarnings("unchecked") public void updateEdge(PPath pEdge, Position pNode) { LOGGER.trace("Method updateEdge(" + pEdge + ") called."); synchronized (pEdge) { List<PComposite> nodes = (ArrayList<PComposite>) pEdge.getAttribute("nodes"); PNode vNode1 = nodes .get(0); PNode vNode2 = nodes .get(1); Metadata metadata = null; Identifier identifier = null; Position p1 = (Position) nodes.get(0).getAttribute("position"); Position p2 = (Position) nodes.get(1).getAttribute("position"); if (p1 instanceof NodeMetadata) { metadata = ((NodeMetadata) p1).getMetadata(); } else { identifier = ((NodeIdentifier) p1).getIdentifier(); } if (p2 instanceof NodeMetadata) { metadata = ((NodeMetadata) p2).getMetadata(); } else { identifier = ((NodeIdentifier) p2).getIdentifier(); } Point2D vStart = vNode1.getFullBoundsReference().getCenter2D(); Point2D vEnd = vNode2.getFullBoundsReference().getCenter2D(); pEdge.reset(); /* Draw edge */ mPiccolo2dEdgeRenderer.drawEdge(pEdge, vStart, vEnd, metadata, identifier); /* Set edge color */ paintEdge(pEdge); pEdge.repaint(); } } @Override public synchronized void deleteNode(Position pPosition) { LOGGER.trace("Method deleteNode(" + pPosition + ") called."); PComposite vNode = mMapNode.get(pPosition); if (vNode != null) { /* Delete node from layer */ mLayerNode.removeChild(vNode); /* Remove Shadow */ PPath vShadow = (PPath) vNode.getAttribute("glow"); if (vShadow != null) { mLayerGlow.removeChild(vShadow); } /* Metadata */ if (pPosition instanceof NodeMetadata) { /* Delete edges from layer */ for (PPath vEdge : mMapEdge.get(pPosition)) { deleteEdge(pPosition, vEdge); } /* Delete edge from HashMap */ mMapEdge.remove(pPosition); } /* Delete node from HashMap */ mMapNode.remove(pPosition); } } @Override public synchronized void markAsNew(final Position pPosition) { LOGGER.trace("Method markAsNew(" + pPosition + ") called."); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { PComposite vNode = mMapNode.get(pPosition); if (vNode != null) { addGlow(vNode, mColorNewNode); } else { LOGGER.debug("Coundn't find " + pPosition + " to mark as new."); } } }); } @Override public synchronized void markAsDelete(final Position pPosition) { LOGGER.trace("Method markAsDelete(" + pPosition + ") called."); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { PComposite vNode = mMapNode.get(pPosition); if (vNode != null) { addGlow(vNode, mColorDeleteNode); } else { LOGGER.debug("Coundn't find " + pPosition + " to mark as delete."); } } }); } @Override public synchronized void clearHighlight(final Position pPosition) { LOGGER.trace("Method clearHighlight(" + pPosition + ") called."); /* Reset the Stroke of the node */ final PComposite vNode = mMapNode.get(pPosition); if (vNode != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { synchronized (vNode) { /* Remove Shadow */ final PPath vShadow = (PPath) vNode .getAttribute("glow"); if (vShadow != null) { vNode.addAttribute("glow", null); PActivity vFading = vShadow.animateToTransparency( 0.0f, 500); // TODO // Use // SettingManager PActivity vRemove = new PActivity(0) { @Override protected void activityStep(long time) { mLayerGlow.removeChild(vShadow); } }; vRemove.startAfter(vFading); vShadow.addActivity(vRemove); } } } }); } else { LOGGER.debug("Coundn't find " + pPosition + " to clear its highlights."); } } private void addGlow(PComposite pNode, Color pHighlight) { Point2D vPosition = pNode.getOffset(); PBounds vBound = pNode.getFullBoundsReference(); float vShadowWidth = (float) (1.1 * vBound.getWidth() + mGlowWidth); float vShadowHeight = (float) (vBound.getHeight() + mGlowHeight); PPath vShadow = PPath.createEllipse(-0.5F * vShadowWidth, // x -0.5F * vShadowHeight, // y vShadowWidth, // width vShadowHeight // height ); vShadow.setOffset((float) (vPosition.getX()), // x (float) (vPosition.getY()) // y ); vShadow.setStroke(null); Color opaqueHighlight = new Color(pHighlight.getRed(), pHighlight.getGreen(), pHighlight.getBlue(), 255); Color transparentHighlight = new Color(pHighlight.getRed(), pHighlight.getGreen(), pHighlight.getBlue(), 0); vShadow.setPaint(ColorHelper.createGradientColor(new Piccolo2DGraphicWrapper(vShadow, null), opaqueHighlight, transparentHighlight)); vShadow.setTransparency(0.0f); synchronized (pNode) { mLayerGlow.addChild(vShadow); pNode.addAttribute("glow", vShadow); } vShadow.animateToTransparency(1.0f, 500); // TODO Use SettingManager } @Override public synchronized void clearGraph() { mLayerEdge.removeAllChildren(); mLayerNode.removeAllChildren(); mLayerGlow.removeAllChildren(); mMapEdge.clear(); mMapNode.clear(); } /** * Adjust the size of the panel depending on the number and size of labels. */ @Override public synchronized void adjustPanelSize() { LOGGER.trace("Method adjustPanelSize() called."); int vNumberOfNodes = mMapNode.size(); int vNumberOfChars = 0; if (vNumberOfNodes > 0) { for (PComposite vNode : mMapNode.values()) { vNumberOfChars += ((PText) vNode.getChild(1)).getText() .length(); } double vAverage = vNumberOfChars / vNumberOfNodes; double vSize = (Math.sqrt(vNumberOfNodes) + vAverage) * 50; mAreaHeight = vSize; mAreaWidth = vSize; } } /** * Move the camera to the center of the graph. */ public synchronized void setFocusToCenter() { LOGGER.trace("Method setFocusToCenter() called."); double xMin = Double.POSITIVE_INFINITY; double xMax = Double.NEGATIVE_INFINITY; double yMin = Double.POSITIVE_INFINITY; double yMax = Double.NEGATIVE_INFINITY; if (mMapNode.values().size() > 0) { for (PComposite vNode : mMapNode.values()) { if (vNode.getOffset().getX() > xMax) { xMax = vNode.getOffset().getX(); } if (vNode.getOffset().getX() < xMin) { xMin = vNode.getOffset().getX(); } if (vNode.getOffset().getY() > yMax) { yMax = vNode.getOffset().getY(); } if (vNode.getOffset().getY() < yMin) { yMin = vNode.getOffset().getY(); } } int vOffset = 50; final PBounds vBounds = new PBounds(xMin - vOffset, yMin - vOffset, xMax - xMin + 2 * vOffset, yMax - yMin + 2 * vOffset); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { mPanel.getCamera().setViewBounds(vBounds); } }); } } @Override public synchronized void repaintNodes(NodeType pType) { LOGGER.trace("Method repaintNodes(" + pType + ") called."); for (Object key : mMapNode.keySet()) { PComposite vCom = mMapNode.get(key); PPath vNode = (PPath) vCom.getChild(0); PText vText = (PText) vCom.getChild(1); if (pType == NodeType.IDENTIFIER) { if (vCom.getAttribute("type").equals(pType)) { NodeIdentifier i = (NodeIdentifier) key; Identifier identifier = i.getIdentifier(); paintIdentifierNode(identifier, vNode, vText); } } else if (pType == NodeType.METADATA) { if (vCom.getAttribute("type").equals(pType)) { NodeMetadata m = (NodeMetadata) key; Metadata metadata = m.getMetadata(); paintMetadataNode(metadata, vNode, vText); } } } } private void paintMetadataNode(Metadata metadata, PPath vNode, PText vText) { GraphicWrapper g = Piccolo2DGraphicWrapperFactory.create(vNode, vText); for (NodePainter r : mNodePainter.get(mGuiMode)) { r.paintMetadataNode(metadata, g); } } private void paintIdentifierNode(Identifier identifier, PPath vNode, PText vText) { GraphicWrapper g = Piccolo2DGraphicWrapperFactory.create(vNode, vText); for (NodePainter r : mNodePainter.get(mGuiMode)) { r.paintIdentifierNode(identifier, g); } } private void paintEdge(PPath pEdge) { GraphicWrapper g = Piccolo2DGraphicWrapperFactory.create(pEdge, null); for (EdgePainter r : mEdgePainter.get(mGuiMode)) { r.paintEdge(g); } } @Override public void repaint() { mPanel.repaint(); } public double getAreaOffsetX() { LOGGER.trace("Method getAreaOffsetX called."); return mAreaOffsetX; } public double getAreaOffsetY() { LOGGER.trace("Method getAreaOffsetY called."); return mAreaOffsetY; } public double getAreaWidth() { LOGGER.trace("Method getAreaWidth called."); return mAreaWidth; } public double getAreaHeight() { LOGGER.trace("Method getAreaHeight called."); return mAreaHeight; } @Override public List<String> getPublisher() { LOGGER.trace("Method getPublisher called."); return mPublisher; } public void setAreaOffsetX(double pAreaOffsetX) { LOGGER.trace("Method setAreaOffsetX(" + pAreaOffsetX + ") called."); mAreaOffsetX = pAreaOffsetX; } public void setAreaOffsetY(double pAreaOffsetY) { LOGGER.trace("Method setAreaOffsetY(" + pAreaOffsetY + ") called."); mAreaOffsetY = pAreaOffsetY; } public void setAreaWidth(double pAreaWidth) { LOGGER.trace("Method setAreaWidth(" + pAreaWidth + ") called."); mAreaWidth = pAreaWidth; } public void setAreaHeight(double pAreaHeight) { LOGGER.trace("Method setAreaHeight(" + pAreaHeight + ") called."); mAreaHeight = pAreaHeight; } @Override public void setNodeTranslationDuration(int pNodeTranslationDuration) { mNodeTranslationDuration = pNodeTranslationDuration; } @Override public void selectNode(GraphicWrapper selectedNode) { LOGGER.trace("Method selectNode(" + selectedNode + ") called."); if ((selectedNode != null) && (mSelectedNode != selectedNode)) { mSelectedNode = selectedNode; repaintNodes(NodeType.IDENTIFIER); repaintNodes(NodeType.METADATA); } } @Override public void unselectNode() { LOGGER.trace("Method unselectNode() called."); mSelectedNode = null; repaintNodes(NodeType.IDENTIFIER); repaintNodes(NodeType.METADATA); } @Override public void search(String searchTerm) { LOGGER.trace("Search for '" + searchTerm + "'"); mSearchTerm = searchTerm; repaintNodes(NodeType.IDENTIFIER); repaintNodes(NodeType.METADATA); } @Override public void setGuiMode(GuiMode mode) { if (mode != mGuiMode) { mGuiMode = mode; repaintNodes(NodeType.IDENTIFIER); repaintNodes(NodeType.METADATA); } } @Override public void setSearchAndFilterStrategy(SearchAndFilterStrategy strategy) { this.mSearchAndFilterStrategy = strategy; } @Override public void setHideSearchMismatches(boolean b) { this.mHideSearchMismatches = b; repaintNodes(NodeType.IDENTIFIER); repaintNodes(NodeType.METADATA); } @Override public void addNodePainter(GuiMode mode, List<NodePainter> nodePainter) { if (mNodePainter.containsKey(mode)) { List<NodePainter> list = mNodePainter.get(mode); if (list != null) { list.addAll(nodePainter); } else { } } else { List<NodePainter> list = new ArrayList<>(); list.addAll(nodePainter); mNodePainter.put(mode, list); } } @Override public void addEdgeRenderer(GuiMode mode, List<EdgePainter> edgePainter) { if (mEdgePainter.containsKey(mode)) { List<EdgePainter> list = mEdgePainter.get(mode); if (list != null) { list.addAll(edgePainter); } else { } } else { List<EdgePainter> list = new ArrayList<>(); list.addAll(edgePainter); mEdgePainter.put(mode, list); } } @Override public SearchAndFilterStrategy getSearchAndFilterStrategy() { return mSearchAndFilterStrategy; } @Override public boolean getHideSearchMismatches() { return mHideSearchMismatches; } @Override public String getSearchTerm() { return mSearchTerm; } @Override public GraphicWrapper getSelectedNode() { return mSelectedNode; } @Override public void mouseEntered(GraphicWrapper node) { LOGGER.trace("Method mouseEntered(" + node + ") called."); if ((node != null) && (mMouseOverNode != node)) { mMouseOverNode = node; repaintNodes(NodeType.IDENTIFIER); repaintNodes(NodeType.METADATA); } } @Override public void mouseExited() { mMouseOverNode = null; repaintNodes(NodeType.IDENTIFIER); repaintNodes(NodeType.METADATA); } @Override public GraphicWrapper getMouseOverNode() { return mMouseOverNode; } @Override public GraphConnection getConnection() { return mConnection; } }