123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574 |
- package de.tu_darmstadt.tk.SmartHomeNetworkSim.view;
- import java.awt.BasicStroke;
- import java.awt.Color;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.RenderingHints;
- import java.awt.Stroke;
- import java.awt.event.ComponentEvent;
- import java.awt.event.ComponentListener;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.Observable;
- import java.util.Observer;
- import javax.swing.JPanel;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.LinkColorController;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.SettingsController;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.Controller;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.NetworkController;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Connection;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Link;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Port;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.SmartDevice;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.util.Pair;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.VisualizationInteractor;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.view.util.LinkToolTip;
- /**
- * Panel which visualizes the SmartHome Network, it's Devices and Connections
- *
- *
- * @author Andreas T. Meyer-Berg
- */
- @SuppressWarnings("serial")
- public class VisualizationPanel extends JPanel implements Observer {
- /**
- * Controller to notify when the model changes
- */
- private Controller control;
-
- /**
- * Settings Controller
- */
- private SettingsController config;
-
- /**
- * Network Controller
- */
- private NetworkController network;
-
- /**
- * Listener which processes the GUI Interactions
- */
- private VisualizationInteractor interactor;
-
- /**
- * Initializes the Visualization Panel
- *
- * @param control
- * Control, which changes the model
- */
- public VisualizationPanel(Controller control) {
- super();
- this.control = control;
- this.config = control.getSettingsController();
- this.network = control.getNetworkController();
-
- this.interactor = new VisualizationInteractor(control, this);
- this.addMouseMotionListener(interactor);
- this.addMouseListener(interactor);
- this.addKeyListener(interactor);
- }
- /**
- * Performs further initializations, which have to be performed, after the
- * model was made visible
- */
- public void delayedInit() {
- this.addComponentListener(new ComponentListener() {
- @Override
- public void componentShown(ComponentEvent e) {
- }
- @Override
- public void componentResized(ComponentEvent e) {
- config.setDimension(getWidth(), getHeight(), control.getSettingsController().getDepth(),
- true);
- repaint();
- }
- @Override
- public void componentMoved(ComponentEvent e) {
- }
- @Override
- public void componentHidden(ComponentEvent e) {
- }
- });
- config.setDimension(getWidth(), getHeight(), control.getSettingsController().getDepth(),
- true);
- repaint();
- }
- @Override
- public void paint(Graphics g) {
- setRenderOptions(g);
-
- // paint white background
- g.setColor(Color.white);
- g.fillRect(0, 0, this.getWidth(), this.getHeight());
- if(config.isShowConnections())
- paintConnections(g);
- if(config.isShowSmartDevices())
- paintDevices(g);
-
- paintDrag(g);
-
- paintToolTip(g);
-
- paintDebugInformation(g);
-
- paintLinkLabels(g);
- }
- /**
- * Paints debug information like the current interaction mode
- * @param g Graphics which should be used
- */
- private void paintDebugInformation(Graphics g) {
- if(!config.isDebugModus())
- return;
-
- /**
- * Visual representation of the interaction modus
- */
- String modus;
- switch (interactor.mode) {
- case VisualizationInteractor.DRAG_CONNECTION:
- modus="Drag Connection";
- break;
- case VisualizationInteractor.SELECTED_DRAG:
- modus="Drag Device";
- break;
- case VisualizationInteractor.DRAG_SELECT:
- modus="Drag Select";
- break;
- case VisualizationInteractor.NOTHING:
- modus="Nothing";
- break;
- case VisualizationInteractor.RIGHTCLICK_MENU:
- modus="RightClick Menu";
- break;
- case VisualizationInteractor.SELECTED:
- modus="Selected";
- break;
- default:
- modus="Unknown";
- break;
- }
- g.setColor(Color.RED);
- g.drawString("Debug(Modus:"+modus+")", 0, 10);
- if(interactor.controlDown)
- g.drawString("Control down", 0, 20);
- }
-
- /**
- * Paints a list of all Link names on the left hand side
- * @param g Graphics to be used
- */
- private void paintLinkLabels(Graphics g) {
- if(!config.isShowLinks()||network.getLinks().isEmpty()||!config.isShowLinkNameList())
- return;
- g.setColor(Color.BLACK);
- /**
- * y-position of the next text Link line
- */
- int yPositionLink = 10;
- if(config.isDebugModus())
- yPositionLink+=25;
- g.drawString("Links:", 0, yPositionLink);
- yPositionLink += 10;
- for(Link l: network.getLinks()){
- if(!config.getNetworkTreeSettingsController().isVisible(l))continue;
- g.setColor(config.getLinkColors().getColorOfLink(l).getRight());
- g.drawString(l.getName(), 0, yPositionLink);
- yPositionLink+=10;
- }
- }
- /**
- * Sets the different rending options if available
- * @param g Graphics to be improved
- */
- private void setRenderOptions(Graphics g) {
- // More beautiful Graphics
- if(g instanceof Graphics2D){
- /**
- * Graphics2D options, if enabled on the machine
- */
- Graphics2D graphics = (Graphics2D) g;
- /**
- * Rendering Options for the visualization
- */
- RenderingHints renders = new RenderingHints(new HashMap<>());
- /**
- * Add AntiAliasing
- */
- renders.add(new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON));
- /**
- * Add Text AntiAliasing
- */
- renders.add(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON));
- /**
- * Add Improved Color Rendering
- */
- renders.add(new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY));
- /**
- * Add general quality Rendering
- */
- renders.add(new RenderingHints(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY));
- /**
- * Add improved interpolation for images
- */
- renders.add(new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC));
- graphics.setRenderingHints(renders);
- }
- }
- /**
- * Paints the smart devices of the Model
- *
- * @param g
- * the Graphics object to visualize on
- */
- protected void paintDevices(Graphics g) {
- /**
- * Radius of devices
- */
- int deviceRadius = config.getDeviceVisualizationRadius();
- /*
- * Visualization calculations for all devices
- */
- /**
- * Number of Links in the Model
- */
- int numberOfLinks = network.getVisibleLinks().size();
- /**
- * Angle per Link in "linkSlice degrees"
- */
- double linkSlice = Math.min(360.0 / numberOfLinks,90.0);
- /**
- * Map of links to Colors and position of the Color
- */
- LinkColorController linkColors = config.getLinkColors();
-
- if(config.isShowLinks()){
- int i = 0;
- for(Link l: network.getVisibleLinks()){
- /**
- * Index & Color
- */
- Pair<Integer, Color> p = config.getLinkColors().getColorOfLink(l);
- p.setLeft(i);
- i++;
- }
- }
- /**
- * Original Stroke - if it was changed
- */
- Stroke f = null;
- /**
- * Set bigger brush size if possible
- */
- if(g instanceof Graphics2D){
- Graphics2D g2 = (Graphics2D) g;
- f = g2.getStroke();
- g2.setStroke(new BasicStroke(Math.max(deviceRadius/20.0f,1f)));
- }
- /**
- * Paint Devices
- */
-
- //Values for dragging of multiple Devices
- /**
- * Pixel offset of dragged devices on the x axis
- */
- int x_offset = 0;
- /**
- * Pixel offset of dragged devices on the y axis
- */
- int y_offset = 0;
- if(interactor.mode == VisualizationInteractor.SELECTED_DRAG && !control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevices.isEmpty()){
- x_offset = interactor.dragged_x-interactor.dragged.getX();
- y_offset = interactor.dragged_y-interactor.dragged.getY();
- }
- //Paint Devices
- for (SmartDevice s: network.getVisibleSmartDevices()) {
- /**
- * x Position of the device
- */
- int x = s.getX();
- /**
- * y Position of the device
- */
- int y = s.getY();
- if(interactor.mode==VisualizationInteractor.SELECTED_DRAG && control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevices.contains(s)) {
- // Update visualization of dragged object
- x += x_offset;
- y += y_offset;
- }
- //Paint Links of Device V0.0
- if(config.isShowLinks()){
- for(Link l:s.getLinks()){
- /*
- * Split circle around the object into NumberOfLinks Sections, color the sections, connected with the device
- */
- /**
- * Number and color of the current link
- */
- Pair<Integer, Color> linkPos = linkColors.getColorOfLink(l);
- if(linkPos==null||!config.getNetworkTreeSettingsController().isVisible(l))continue;//Skip Links, which are not in the model or hidden
- g.setColor(linkPos.getRight());
- g.fillArc(x - deviceRadius - config.getLinkRadius(), y - deviceRadius - config.getLinkRadius(),
- 2 * deviceRadius - 1 + 2 * config.getLinkRadius(), 2 * deviceRadius - 1 + 2*config.getLinkRadius(),
- (int)Math.round(linkPos.getLeft()*linkSlice), (int)Math.ceil(linkSlice));
- }
-
- }
- if(//(interactor.mode==VisualisationInteractor.SELECTED||interactor.mode==VisualisationInteractor.DRAG_SELECT ||interactor.mode == VisualisationInteractor.SELECTED_DRAG || interactor.mode == VisualisationInteractor.RIGHTCLICK_MENU)&&
- (control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevices.contains(s)^control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevicesDrag.contains(s))){
- //HighlightSelected Devices
- g.setColor(new Color(135,206,235));
- }else{
- g.setColor(Color.WHITE);
- }
- fillCircle(g, x, y, deviceRadius);
- g.setColor(Color.BLACK);
- drawCircle(g,x,y,deviceRadius);
- g.setColor(new Color(91, 162, 229));
- /**
- * Distance in pixels between the two circles at the border
- */
- int innerDistance = Math.max(2, Math.round(deviceRadius/13f));
- drawCircle(g, x, y, deviceRadius-innerDistance);
- g.setColor(Color.BLACK);
- if(config.isShowSmartDeviceNames())
- g.drawString(s.getName(),
- x - g.getFontMetrics().stringWidth(s.getName()) / 2, y
- + deviceRadius + 11 + (config.isShowLinks()?config.getLinkRadius():0));
- }
-
- if(f!=null)
- ((Graphics2D) g).setStroke(f);
- }
-
- /**
- * Paints the Connections
- *
- * @param g
- * the Graphics object to visualize on
- */
- protected void paintConnections(Graphics g) {
- //Values for dragging of multiple Devices
- int x_offset = 0;
- int y_offset = 0;
- if(interactor.mode == VisualizationInteractor.SELECTED_DRAG && !control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevices.isEmpty()){
- x_offset = interactor.dragged_x-interactor.dragged.getX();
- y_offset = interactor.dragged_y-interactor.dragged.getY();
- }
-
- // For all Connections
- for (Connection c : network.getVisibleConnections()) {
- Color connectionState;
- switch (c.getStatus()) {
- case Connection.ACTIVE:
- connectionState = Color.GREEN;
- break;
- case Connection.HALTED:
- connectionState = Color.ORANGE;
- break;
- case Connection.DONE:
- connectionState = Color.GRAY;
- break;
- case Connection.TERMINATED:
- case Connection.FINISHED:
- connectionState = Color.RED;
- break;
- default:
- connectionState = Color.BLUE;
- break;
- }
- g.setColor(connectionState);
- /**
- * All Devices that are part of the connection
- */
- Collection<Port> d = c.getParticipants();
- if(d.size()==0){
- System.out.println("WARNING: Empty, undeleted Connection: "+c.toString());
- continue;
- }
- if(c.getProtocol()==null){
- System.out.println("WARNING: Protocol is null: "+c.toString());
- continue;
- }
- for(Pair<Port,Port> p: c.getProtocol().getTopology() ){
- if(p.getLeft() != null && p.getLeft().getOwner() != null && p.getRight() != null && p.getRight().getOwner() != null){
- if(control.getSettingsController().getConfigurationManager().getSelectionModel().clickedConnection.contains(new Pair<Connection, Pair<Port,Port>>(c, p)))
- g.setColor(Color.BLUE);
- else
- g.setColor(connectionState);
- SmartDevice from = p.getLeft().getOwner();
- SmartDevice to = p.getRight().getOwner();
- if(!config.getNetworkTreeSettingsController().isVisible(from)||!config.getNetworkTreeSettingsController().isVisible(to))continue;
- int xFrom = from.getX();
- int yFrom = from.getY();
- int xTo = to.getX();
- int yTo = to.getY();
- if(control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevices.contains(from)^control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevicesDrag.contains(from)){
- xFrom+=x_offset;
- yFrom+=y_offset;
- }
- if(control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevices.contains(to)^control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevicesDrag.contains(to)){
- xTo+=x_offset;
- yTo+=y_offset;
- }
- g.drawLine(xFrom, yFrom, xTo, yTo);
- }
- }
- for(Pair<Port,Port> p: c.getProtocol().getDeletedTopology() ){
- if(control.getSettingsController().getConfigurationManager().getSelectionModel().clickedConnection.contains(new Pair<Connection, Pair<Port,Port>>(c, p)))
- g.setColor(Color.BLUE);
- else{
- //Just paint terminated connection, if config says so
- if(config.isShowTerminatedConnections())
- g.setColor(Color.RED);
- else
- continue;
-
- }
- if(p.getLeft() != null && p.getLeft().getOwner() != null && p.getRight() != null && p.getRight().getOwner() != null){
- SmartDevice from = p.getLeft().getOwner();
- SmartDevice to = p.getRight().getOwner();
- int xFrom = from.getX();
- int yFrom = from.getY();
- int xTo = to.getX();
- int yTo = to.getY();
- if(control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevices.contains(from)^control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevicesDrag.contains(from)){
- xFrom+=x_offset;
- yFrom+=y_offset;
- }
- if(control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevices.contains(to)^control.getSettingsController().getConfigurationManager().getSelectionModel().selectedDevicesDrag.contains(to)){
- xTo+=x_offset;
- yTo+=y_offset;
- }
- g.drawLine(xFrom, yFrom, xTo, yTo);
- }
- }
- }
- // paint new in progress connection, if a connection or link is in
- // creation
- if (interactor.mode == VisualizationInteractor.DRAG_CONNECTION && interactor.connectionFrom != null){
- g.setColor(Color.ORANGE);
- g.drawLine(interactor.connectionFrom.getX(),
- interactor.connectionFrom.getY(), interactor.dragged_x,
- interactor.dragged_y);
- }
- }
-
- /**
- * Paints the new dragged Connection
- * @param g graphics of this panel
- */
- protected void paintDrag(Graphics g){
- if(interactor.mode!=VisualizationInteractor.DRAG_SELECT)
- return;
- int low_x = Math.min(interactor.dragged_x, interactor.dragged_x_start);
- int low_y = Math.min(interactor.dragged_y, interactor.dragged_y_start);
- int high_x = Math.max(interactor.dragged_x, interactor.dragged_x_start);
- int high_y = Math.max(interactor.dragged_y, interactor.dragged_y_start);
- g.setColor(Color.BLUE);
- g.drawRect(low_x, low_y, high_x-low_x, high_y-low_y);
- }
-
- /**
- * Paints the link ToolTip
- * @param g graphics of this panel
- */
- protected void paintToolTip(Graphics g) {
- /**
- * ToolTip which is visualized
- */
- LinkToolTip toolTip = interactor.getToolTip();
- if (toolTip.isEnabled() && config.isShowLinkToolTips()) {
- /**
- * free space around the ToolTipText
- */
- int border = 2;
- /**
- * Width of the text (multiLine later ?)
- */
- int textWidth = g.getFontMetrics().stringWidth(toolTip.getText()) + 2 * border;
- /**
- * Height of the Text
- */
- int textHeigth = 12 + 2 * border;
- /**
- * top left x position of the ToolTip
- */
- int fixXPos = toolTip.getX();
- /**
- * top left y position of the ToolTip
- */
- int fixYPos = toolTip.getY();
-
- //Check position that toolTip stays in bound
- if (fixXPos < 0) {
- fixXPos = 0;
- } else if (fixXPos + textWidth >= this.getWidth()) {
- fixXPos -= (fixXPos + textWidth + 1) - this.getWidth();
- }
- if (fixYPos < 0){
- fixYPos = 0;
- }
- else if(fixYPos + textHeigth >= this.getHeight()) {
- fixYPos -= (fixYPos + textHeigth + 1) - this.getHeight();
- }
- //Paint background (toolTip Color (light yellow/brown))
- g.setColor(new Color(255, 255, 225));
- g.fillRect(fixXPos, fixYPos, textWidth, textHeigth);
- //Paint black surrounding rectangle
- g.setColor(Color.BLACK);
- g.drawRect(fixXPos, fixYPos, textWidth, textHeigth);
- //Draw the ToolTip text
- g.drawString(toolTip.getText(), fixXPos + 2, fixYPos + 12);
- }
- }
-
- @Override
- public void update(Observable o, Object arg) {
- repaint();
- }
-
- /**
- * Fills a circle of radius radius around the given point (Radius includes middle), So width may be 2*radius-1
- * @param g Graphics to be used
- * @param x x Position of the middle
- * @param y y Position of the middle
- * @param radius radius of the circle
- */
- public void fillCircle(Graphics g, int x, int y, int radius){
- g.fillOval(x-radius, y-radius, 2*radius+1, 2*radius+1);
- }
-
- /**
- * Draws a circle of radius radius around the given point (Radius includes middle)
- * @param g Graphics to be used
- * @param x x Position of the middle
- * @param y y Position of the middle
- * @param radius radius of the circle
- */
- public void drawCircle(Graphics g, int x, int y, int radius){
- g.drawOval(x-radius, y-radius, 2*radius-1, 2*radius-1);
- }
- }
|