/**
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.airavata.xbaya.ui.graph;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.swing.SwingUtilities;
import org.apache.airavata.workflow.model.graph.Edge;
import org.apache.airavata.workflow.model.graph.Graph;
import org.apache.airavata.workflow.model.graph.GraphPiece;
import org.apache.airavata.workflow.model.graph.Node;
import org.apache.airavata.workflow.model.graph.Port;
import org.apache.airavata.workflow.model.graph.system.MemoNode;
import org.apache.airavata.workflow.model.graph.system.StreamSourceNode;
import org.apache.airavata.workflow.model.graph.util.GraphUtil;
import org.apache.airavata.xbaya.XBayaEngine;
import org.apache.airavata.xbaya.graph.controller.NodeController;
public class GraphGUI implements GraphPieceGUI {
private Graph graph;
/**
* @param graph
*/
public GraphGUI(Graph graph) {
this.graph = graph;
}
/**
* @see org.apache.airavata.xbaya.ui.graph.GraphPieceGUI#mouseClicked(java.awt.event.MouseEvent,
* org.apache.airavata.xbaya.XBayaEngine)
*/
public void mouseClicked(MouseEvent event, XBayaEngine engine) {
GraphPiece piece = getGraphPieceAt(event.getPoint());
if (piece != null && graph.isEditable()) {
NodeController.getGUI(piece).mouseClicked(event, engine);
}
}
/**
* Gets the bounding Rectangle of this Graph.
*
* @return A rectangle indicating this component's bounds
*/
protected Rectangle getBounds() {
Rectangle bounds = new Rectangle();
for (Node node : this.graph.getNodes()) {
bounds.add(NodeController.getGUI(node).getBounds());
}
final int margin = 10;
bounds.height += margin;
bounds.width += margin;
return bounds;
}
/**
* @param g
*/
protected void paint(Graphics2D g) {
// Calcurate the widge of the nodes.
for (Node node : this.graph.getNodes()) {
NodeController.getGUI(node).calculatePositions(g);
}
LinkedList<Node> nodes = new LinkedList<Node>(this.graph.getNodes());
List<MemoNode> memoNodes = GraphUtil.getNodes(this.graph, MemoNode.class);
nodes.removeAll(memoNodes);
// Paints the edges before nodes.
for (Edge edge : this.graph.getEdges()) {
NodeController.getGUI(edge).paint(g);
}
// Paint regular nodes.
// The ports are painted from inside of each node.
for (Node node : nodes) {
NodeController.getGUI(node).paint(g);
}
// Print memoNodes at last so that they stay on top of everything.
for (MemoNode node : memoNodes) {
NodeController.getGUI(node).paint(g);
}
}
protected StreamSourceNode getStreamSourceAt(Point point) {
for (Node node : this.graph.getNodes()) {
// Check the node first
if (NodeController.getGUI(node).isIn(point) && node instanceof StreamSourceNode) {
return (StreamSourceNode) node;
}
}
return null;
}
/**
* Returns the visible object at the specified location. The object is either a Node, a Port, or an Edge.
*
* @param point
* The location
* @return The visible object a the specified location
*/
protected GraphPiece getGraphPieceAt(Point point) {
GraphPiece piece = null;
// Starts from edge because it is drawn first, which means it's at the
// bottom.
double minEdgeDist = Double.MAX_VALUE;
Edge closestEdge = null;
for (Edge edge : this.graph.getEdges()) {
double dist = NodeController.getGUI(edge).getMiddlePosition().distance(point);
if (dist < minEdgeDist) {
closestEdge = edge;
minEdgeDist = dist;
}
}
if (minEdgeDist < 20) {
piece = closestEdge;
}
// Then, each node and ports of it.
for (Node node : this.graph.getNodes()) {
// Check the node first
if (NodeController.getGUI(node).isIn(point)) {
piece = node;
}
// Find the closest port of this node.
double minPortDist = Double.MAX_VALUE;
Port closestPort = null;
for (Port port : node.getAllPorts()) {
double dist = NodeController.getGUI(port).getPosition().distance(point);
if (dist < minPortDist) {
closestPort = port;
minPortDist = dist;
}
}
if (minPortDist <= PortGUI.DATA_PORT_SIZE) {
piece = closestPort;
}
// Don't break from this loop because the later ones are drawn at
// the top of other nodes.
}
return piece;
}
/**
* Returns the visible object in the specified area. The objects are either a Node, a Port, or an Edge.
*
* @param rec
* area to cover
* @return The visible object a the specified location
*/
protected List<Node> getNodesIn(Rectangle rec) {
ArrayList<Node> pieces = new ArrayList<Node>();
// Then, each node and ports of it.
for (Node node : this.graph.getNodes()) {
Rectangle inter = SwingUtilities.computeIntersection(rec.x, rec.y, rec.width, rec.height, NodeController.getGUI(node)
.getBounds());
if (inter.width != 0 && inter.height != 0)
pieces.add(node);
}
return pieces;
}
}