/* * Copyright (c) 2005-2010 KOM – Multimedia Communications Lab * * This file is part of PeerfactSim.KOM. * * PeerfactSim.KOM is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * PeerfactSim.KOM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PeerfactSim.KOM. If not, see . * */ package de.tud.kom.p2psim.impl.topology.views.visualization.world; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.RenderingHints; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import de.tud.kom.p2psim.api.common.SimHost; import de.tud.kom.p2psim.impl.topology.util.PositionVector; import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisNodeInformation; import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector; import de.tud.kom.p2psim.impl.topology.views.visualization.ui.VisualizationComponent; import de.tudarmstadt.maki.simonstrator.api.Event; import de.tudarmstadt.maki.simonstrator.api.EventHandler; import de.tudarmstadt.maki.simonstrator.api.Host; import de.tudarmstadt.maki.simonstrator.api.Oracle; import de.tudarmstadt.maki.simonstrator.api.Time; import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException; import de.tudarmstadt.maki.simonstrator.api.component.HostComponent; import de.tudarmstadt.maki.simonstrator.api.component.overlay.NodeInformation; /** * Generic component that visualizes information from nodes implementing the * {@link NodeInformation} interface. * * @author Bjoern Richerzhagen * @version 1.0, Jul 9, 2015 */ public class NodeInfoComponentVis extends JComponent implements VisualizationComponent { protected Collection nodes = new LinkedList<>(); private JMenu menu = new JMenu("Node Info"); protected boolean[] activeLayers = new boolean[0]; boolean hideInactiveNodes = false; private final String name; public NodeInfoComponentVis( final Class componentClass) { setBounds(0, 0, VisualizationInjector.getWorldX(), VisualizationInjector.getWorldY()); setOpaque(true); setVisible(true); this.name = componentClass.getSimpleName(); menu.setText("Info: "+name); Event.scheduleWithDelay(1 * Time.MICROSECOND, new EventHandler() { @Override public void eventOccurred(Object content, int type) { for (Host host : Oracle.getAllHosts()) { try { HostComponent c = host.getComponent(componentClass); if (c instanceof NodeInformation) { nodes.add(new NodeVis(host, (NodeInformation) c)); } } catch (ComponentNotAvailableException e) { // don't care } } initializeMenu(); } }, null, 0); } /** * Hide rings for inactive nodes. * @param hideOfflineNodes */ public void setHideInactiveNodes(boolean hideInactiveNodes) { this.hideInactiveNodes = hideInactiveNodes; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); boolean first = true; for (NodeVis vis : new ArrayList<>(nodes)) { vis.draw(g2); if (first) { first = false; vis.drawLegend(g2); } } } protected void initializeMenu() { for (NodeVis vis : nodes) { String[] dimensions = vis.nodeInfo .getNodeColorDimensionDescriptions(); activeLayers = new boolean[dimensions.length]; for (int dim = 0; dim < dimensions.length; dim++) { JCheckBoxMenuItem item = new JCheckBoxMenuItem( dimensions[dim]); item.setSelected(true); item.addChangeListener(new ChangeListenerImpl(dim)); menu.add(item); activeLayers[dim] = true; } break; } } private class ChangeListenerImpl implements ChangeListener { private final int dim; public ChangeListenerImpl(int dim) { this.dim = dim; } @Override public void stateChanged(ChangeEvent e) { activeLayers[dim] = !activeLayers[dim]; } } /** * Visualization-fragments for Node-centric visualiation-information. * * @author Bjoern Richerzhagen * @version 1.0, Sep 22, 2013 */ private class NodeVis { public final VisNodeInformation visNodeInfo; public final NodeInformation nodeInfo; private final SimHost host; private final PositionVector loc; private final Color activeGreen = new Color(0, 200, 0); private final Color[] baseColors = { Color.ORANGE, Color.BLUE, Color.RED, Color.PINK, Color.GRAY, Color.GREEN, Color.CYAN, Color.WHITE }; private final Color[] tuColors = { new Color(93, 133, 195), // 1a new Color(80, 182, 149), // 3a // new Color(221,223,72), // 5a new Color(248,186,60), // 7a new Color(233,80,62), // 9a new Color(128, 69, 151), // 11a new Color(0, 78, 138), // 1c new Color(0, 136, 119), // 3c // new Color(177, 189, 0), // 5c new Color(210, 135, 0), // 7c new Color(185, 15, 34), // 9c new Color(97, 28, 115), // 11c }; private Color[][] colors = null; public NodeVis(Host host, NodeInformation nodeInfo) { this.nodeInfo = nodeInfo; this.host = (SimHost) host; this.loc = this.host.getTopologyComponent().getRealPosition(); this.visNodeInfo = VisualizationInjector.getNodeInformation(host.getId()); /* * Create per-info-option colors by deriving the color from the base color */ colors = new Color[nodeInfo.getNodeColorDimensions()][]; for (int dim = 0; dim < colors.length; dim++) { Color baseColor = baseColors[dim]; int dimensionSize = nodeInfo .getNodeColorDescriptions(dim).length; colors[dim] = new Color[dimensionSize]; /* * http://stackoverflow.com/questions/2355157/dynamically- * creating-colors-with-different-brightness */ // float hsbVals[] = Color.RGBtoHSB(baseColor.getRed(), // baseColor.getGreen(), baseColor.getBlue(), null); for (int i = 0; i < dimensionSize; i++) { float hue = i / (float) dimensionSize; // colors[dim][i] = Color.getHSBColor(hue, hsbVals[1], // hsbVals[2]); colors[dim][i] = tuColors[i]; } } } /** * Called on one of the nodes to draw global objects such as a legend. * Called before draw. * * @param g2 */ public void drawLegend(Graphics2D g2) { String[] dimensions = nodeInfo.getNodeColorDimensionDescriptions(); int segments = dimensions.length; int segmentDegrees = (int) (360 / (double) segments); int arcSize = 8; g2.setStroke(new BasicStroke(3)); for (int color = 0; color < segments; color++) { if (activeLayers.length <= color || !activeLayers[color]) { continue; } g2.setColor(Color.DARK_GRAY); g2.drawArc(10, 20 * (color + 1)+10, 2*arcSize, 2*arcSize, color*segmentDegrees, segmentDegrees); String[] colorDescs = nodeInfo.getNodeColorDescriptions(color); for (int i = 0; i < colorDescs.length; i++) { g2.setColor(colors[color][i]); g2.fillRect(40 + i * 90, 20 * (color + 1)+10, 8, 8); g2.setColor(Color.DARK_GRAY); g2.drawString(colorDescs[i], 50 + i * 90, 20 * (color + 2)); } } g2.setStroke(new BasicStroke(1)); } public void draw(Graphics2D g2) { if (hideInactiveNodes && !nodeInfo.isActive()) { visNodeInfo.disableClickListener = true; return; } visNodeInfo.disableClickListener = false; Point center = loc.asPoint(); // Draw active (green) over underlay vis. g2.setColor(nodeInfo.isActive() ? activeGreen : Color.LIGHT_GRAY); int radius = 3; g2.drawOval(VisualizationInjector.scaleValue(center.x) - radius, VisualizationInjector.scaleValue(center.y) - radius, radius * 2, radius * 2); if (!nodeInfo.isActive()) { return; } g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); int segments = nodeInfo.getNodeColorDimensions(); int segmentDegrees = (int) (360 / (double) segments); int arcSize = 8; g2.setStroke(new BasicStroke(8, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); for (int dim = 0; dim < segments; dim++) { int value = nodeInfo.getNodeColor(dim); if (value < 0 || !activeLayers[dim]) { continue; } g2.setColor(colors[dim][value]); g2.drawArc(VisualizationInjector.scaleValue(center.x)-arcSize, VisualizationInjector.scaleValue(center.y)-arcSize, 2*arcSize, 2*arcSize, dim*segmentDegrees, segmentDegrees); } g2.setStroke(new BasicStroke(1)); String nodeDesc = nodeInfo.getNodeDescription(); g2.drawString(nodeDesc, center.x + 4, center.y + 4); } } @Override public JComponent getComponent() { return this; } @Override public JMenu getCustomMenu() { return menu; } @Override public boolean isHidden() { return false; } @Override public String getDisplayName() { return "Info: "+name; } }