/*********************************************************************************************************************** * * Copyright (C) 2010 by the Stratosphere project (http://stratosphere.eu) * * 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. * **********************************************************************************************************************/ package eu.stratosphere.nephele.visualization.swt; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import eu.stratosphere.nephele.topology.NetworkNode; public class SWTNetworkNode extends AbstractSWTComponent { public final static int MAXWIDTH = 200; public final static int MAXHEIGHT = 120; private final static int TEXTBOXHEIGHT = 24; private final static int TEXTBOXSPACING = 10; private static Image LEAFNODEIMAGE; private final Image leafNodeImage; private final Rectangle leafNodeImageRect; private static Rectangle LEAFNODEIMAGERECT; private static Image NODEIMAGE; private static Rectangle NODEIMAGERECT; private final Image nodeImage; private final Rectangle nodeImageRect; private final NetworkNode networkNode; private SWTNetworkNode parentNode = null; private List<SWTNetworkNode> childNodes = new ArrayList<SWTNetworkNode>(); private int depth = -1; private float imageScaleFactor = 1.0f; public SWTNetworkNode(Display display, AbstractSWTComponent parentComponent, NetworkNode networkNode) { super(parentComponent); this.networkNode = networkNode; synchronized (SWTNetworkNode.class) { if (LEAFNODEIMAGE == null) { // Try to load the images InputStream in = getClass().getResourceAsStream( "/eu/stratosphere/nephele/visualization/swt/leafnode.png"); try { LEAFNODEIMAGE = new Image(display, in); LEAFNODEIMAGERECT = LEAFNODEIMAGE.getBounds(); } catch (Exception e) { e.printStackTrace(); } } this.leafNodeImage = LEAFNODEIMAGE; this.leafNodeImageRect = LEAFNODEIMAGERECT; if (NODEIMAGE == null) { // Try to load the images InputStream in = getClass().getResourceAsStream("/eu/stratosphere/nephele/visualization/swt/node.png"); try { NODEIMAGE = new Image(display, in); NODEIMAGERECT = NODEIMAGE.getBounds(); } catch (Exception e) { e.printStackTrace(); } } this.nodeImage = NODEIMAGE; this.nodeImageRect = NODEIMAGERECT; } } void setParentNode(SWTNetworkNode parentNode) { this.parentNode = parentNode; this.parentNode.addChildNode(this); } protected void addChildNode(SWTNetworkNode childNode) { this.childNodes.add(childNode); } public NetworkNode getNetworkNode() { return this.networkNode; } @Override public boolean isSelectable() { return true; } public int getDepth() { // Cache value if (this.depth < 0) { this.depth = this.networkNode.getDepth(); } return this.depth; } int getNumberOfNodesOnLevel(int level) { int numberOfNodesOnLevel = 0; if (level == getDepth()) { ++numberOfNodesOnLevel; } if (level > getDepth()) { // Consider children; final Iterator<SWTNetworkNode> it = this.childNodes.iterator(); while (it.hasNext()) { numberOfNodesOnLevel += it.next().getNumberOfNodesOnLevel(level); } } return numberOfNodesOnLevel; } @Override public void layout() { // Adapt scale factor if (this.networkNode.isLeafNode()) { if (this.leafNodeImage != null) { this.imageScaleFactor = (float) (this.rect.height - TEXTBOXHEIGHT) / (float) this.leafNodeImageRect.height; } } else { if (this.nodeImage != null) { this.imageScaleFactor = (float) (this.rect.height - TEXTBOXHEIGHT) / (float) this.nodeImageRect.height; } } } @Override protected void paintInternal(GC gc, Device device) { // Draw edge to parent if (this.parentNode != null) { gc.drawLine(this.rect.x + (rect.width / 2), this.rect.y + (this.rect.height - TEXTBOXHEIGHT) / 2, this.parentNode.getX() + (this.parentNode.getWidth() / 2), this.parentNode.getY() + this.parentNode.getHeight()); } if (this.networkNode.isLeafNode()) { if (this.leafNodeImage != null) { final int destHeight = (int) ((float) this.leafNodeImageRect.height * imageScaleFactor); final int destWidth = (int) ((float) this.leafNodeImageRect.width * imageScaleFactor); final int destX = this.rect.x + (this.rect.width - destWidth) / 2; final int destY = this.rect.y + ((this.rect.height - TEXTBOXHEIGHT) - destHeight) / 2; gc.drawImage(this.leafNodeImage, this.leafNodeImageRect.x, this.leafNodeImageRect.y, this.leafNodeImageRect.width, this.leafNodeImageRect.height, destX, destY, destWidth, destHeight); } } else { if (this.nodeImage != null) { final int destHeight = (int) ((float) this.nodeImageRect.height * imageScaleFactor); final int destWidth = (int) ((float) this.nodeImageRect.width * imageScaleFactor); final int destX = this.rect.x + (this.rect.width - destWidth) / 2; final int destY = this.rect.y + ((this.rect.height - TEXTBOXHEIGHT) - destHeight) / 2; gc.drawImage(this.nodeImage, this.nodeImageRect.x, this.nodeImageRect.y, this.nodeImageRect.width, this.nodeImageRect.height, destX, destY, destWidth, destHeight); } } // Determine width of text box String name = this.networkNode.getName(); Point pt = gc.textExtent(name); boolean cropped = false; while (pt.x > this.rect.width) { cropped = true; name = name.substring(0, name.length() - 1); pt = gc.textExtent(name + "..."); } if (cropped) { name += "..."; } // Draw text box gc.setBackground(ColorScheme.getNetworkNodeBackgroundColor(device)); gc.fillRectangle(this.rect.x + (this.rect.width - pt.x) / 2 - TEXTBOXSPACING, this.rect.y + this.rect.height - TEXTBOXHEIGHT, pt.x + (2 * TEXTBOXSPACING), TEXTBOXHEIGHT); gc.setForeground(ColorScheme.getNetworkNodeBorderColor(device)); gc.drawRectangle(this.rect.x + (this.rect.width - pt.x) / 2 - TEXTBOXSPACING, this.rect.y + this.rect.height - TEXTBOXHEIGHT, pt.x + (2 * TEXTBOXSPACING), TEXTBOXHEIGHT); // Draw name gc.setForeground(ColorScheme.getNetworkNodeBorderColor(device)); final int textX = this.rect.x + ((this.rect.width - pt.x) / 2); final int textY = this.rect.y + this.rect.height - TEXTBOXHEIGHT + ((TEXTBOXHEIGHT - pt.y) / 2); gc.drawText(name, textX, textY); } @Override public SWTToolTip constructToolTip(Shell parentShell, SWTToolTipCommandReceiver commandReceiver, int x, int y) { return new SWTInstanceToolTip(parentShell, commandReceiver, this.networkNode, x, y); } }