From 4f21efe827fa37b6b99f4cc00b0cc9ed3c0b0572 Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Mon, 4 Jun 2012 17:17:18 +0200 Subject: [PATCH] Rewrote the code to use real menus instead of relying on context menus for top-level operaions. The transition is not complete yet; there are still a few functions left in context menus, such as radio medium configuration options. Renamed the window to better match what the user sees in the window. Updated how mote movement is implemented: the user now sees that the mote moves when the mouse is moved. --- .../se/sics/cooja/plugins/Visualizer.java | 145 +++++++++++++----- 1 file changed, 104 insertions(+), 41 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java b/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java index 594e30a88..78531452c 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java +++ b/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java @@ -72,6 +72,7 @@ import javax.swing.Action; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenu; +import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -125,7 +126,7 @@ import se.sics.cooja.plugins.skins.UDGMVisualizerSkin; * @see UDGMVisualizerSkin * @author Fredrik Osterlind */ -@ClassDescription("Simulation visualizer") +@ClassDescription("Network...") @PluginType(PluginType.SIM_STANDARD_PLUGIN) public class Visualizer extends VisPlugin implements HasQuickHelp { private static final long serialVersionUID = 1L; @@ -139,6 +140,8 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { private final JPanel canvas; private boolean loadedConfig = false; + private final JMenu viewMenu; + /* Viewport */ private AffineTransform viewportTransform; public int resetViewport = 0; @@ -202,21 +205,58 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { new ArrayList>(); public Visualizer(Simulation simulation, GUI gui) { - super("Simulation Visualizer", gui); + super("Network", gui); this.gui = gui; this.simulation = simulation; - /* Register external skins */ + /* Register external visualizers */ String[] skins = gui.getProjectConfig().getStringArrayValue(Visualizer.class, "SKINS"); if (skins != null) { for (String skinClass: skins) { Class skin = gui.tryLoadClass(this, VisualizerSkin.class, skinClass); if (registerVisualizerSkin(skin)) { - logger.info("Registered external visualizer: " + skinClass); + logger.info("Registered external visualizer: " + skinClass); } } } + + /* Menus */ + JMenuBar menuBar = new JMenuBar(); + + viewMenu = new JMenu("View"); + JMenu zoomMenu = new JMenu("Zoom"); + + menuBar.add(viewMenu); + menuBar.add(zoomMenu); + + this.setJMenuBar(menuBar); + + JMenuItem zoomInItem = new JMenuItem("Zoom in"); + zoomInItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + zoomToFactor(zoomFactor() * 1.2); + } + }); + zoomMenu.add(zoomInItem); + + JMenuItem zoomOutItem = new JMenuItem("Zoom out"); + zoomOutItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + zoomToFactor(zoomFactor() / 1.2); + } + }); + zoomMenu.add(zoomOutItem); + + JMenuItem resetViewportItem = new JMenuItem("Reset viewport"); + resetViewportItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + resetViewport = 1; + repaint(); + } + }); + zoomMenu.add(resetViewportItem); + /* Main canvas */ canvas = new JPanel() { private static final long serialVersionUID = 1L; @@ -254,7 +294,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { skinPopupMenu.setVisible(true); } }); - this.add(BorderLayout.NORTH, skinButton); + /*this.add(BorderLayout.NORTH, skinButton);*/ this.add(BorderLayout.CENTER, canvas); /* Observe simulation and mote positions */ @@ -481,9 +521,11 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { new DropTarget(canvas, DnDConstants.ACTION_COPY_OR_MOVE, dTargetListener, true, null) ); - this.setSize(300, 300); - setLocation(gui.getDesktopPane().getWidth() - getWidth(), 0); resetViewport = 3; /* XXX Quick-fix */ + + /* XXX HACK: here we set the position and size of the window when it appears on a blank simulation screen. */ + this.setLocation(1, 1); + this.setSize(400, 400); } private void generateAndActivateSkin(Class skinClass) { @@ -531,6 +573,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { simulation.getGUI().tryLoadClass(this, VisualizerSkin.class, skin); generateAndActivateSkin(skinClass); } + populateSkinMenu(viewMenu); } public VisualizerSkin[] getCurrentSkins() { @@ -641,12 +684,12 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { /* Visualizer skin actions */ menu.add(new JSeparator()); - JMenu skinMenu = new JMenu("Visualizers"); + /*JMenu skinMenu = new JMenu("Visualizers"); populateSkinMenu(skinMenu); menu.add(skinMenu); makeSkinsDefaultAction.putValue(Action.NAME, "Set default visualizers"); JMenuItem skinDefaultItem = new JMenuItem(makeSkinsDefaultAction); - menu.add(skinDefaultItem); + menu.add(skinDefaultItem);*/ /* Show menu */ menu.setLocation(new Point( @@ -752,7 +795,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { private void handleMousePress(MouseEvent mouseEvent) { int x = mouseEvent.getX(); int y = mouseEvent.getY(); - clickedMote = null; + clickedMote = null; if (mouseEvent.isControlDown()) { /* Zoom */ @@ -765,7 +808,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { final Mote[] motes = findMotesAtPosition(x, y); if (mouseEvent.isShiftDown() || - (!mouseEvent.isAltDown() && (motes == null || motes.length == 0))) { + (!mouseEvent.isAltDown() && (motes == null || motes.length == 0))) { /* No motes clicked or shift pressed: We should pan */ panning = true; panningPosition = transformPixelToPosition(x, y); @@ -774,8 +817,8 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { if (motes != null && motes.length > 0) { /* One of the clicked motes should be moved */ - clickedMote = motes[0]; - beginMoveRequest(motes[0], !mouseEvent.isAltDown(), !mouseEvent.isAltDown()); + clickedMote = motes[0]; + beginMoveRequest(motes[0], false, false); } } @@ -791,6 +834,26 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { repaint(); } + private double zoomFactor() + { + return viewportTransform.getScaleX(); + } + + private void zoomToFactor(double newZoom) { + viewportTransform.setToScale( + newZoom, + newZoom + ); + + /*Position moved = transformPixelToPosition(zoomingPixel); + viewportTransform.translate( + moved.getXCoordinate() - zoomingPosition.getXCoordinate(), + moved.getYCoordinate() - zoomingPosition.getYCoordinate() + );*/ + repaint(); + + } + private void handleMouseMove(MouseEvent e, boolean stop) { int x = e.getX(); int y = e.getY(); @@ -841,28 +904,35 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { /* Moving */ if (moving) { + Position newPos = transformPixelToPosition(x, y); + if (!stop) { canvas.setCursor(moveCursor); + movedMote.getInterfaces().getPosition().setCoordinates( + newPos.getXCoordinate(), + newPos.getYCoordinate(), + movedMote.getInterfaces().getPosition().getZCoordinate() + ); + repaint(); return; } - /* Restore cursor */ canvas.setCursor(Cursor.getDefaultCursor()); + /* Move mote */ if (moveStartTime < 0 || System.currentTimeMillis() - moveStartTime > 300) { - Position newPos = transformPixelToPosition(x, y); if (moveConfirm) { - String options[] = {"Yes", "Cancel"}; - int returnValue = JOptionPane.showOptionDialog(Visualizer.this, - "Move mote to" + - "\nX=" + newPos.getXCoordinate() + - "\nY=" + newPos.getYCoordinate() + - "\nZ=" + movedMote.getInterfaces().getPosition().getZCoordinate(), - "Move mote?", - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, - null, options, options[0]); - moving = returnValue == JOptionPane.YES_OPTION; + String options[] = {"Yes", "Cancel"}; + int returnValue = JOptionPane.showOptionDialog(Visualizer.this, + "Move mote to" + + "\nX=" + newPos.getXCoordinate() + + "\nY=" + newPos.getYCoordinate() + + "\nZ=" + movedMote.getInterfaces().getPosition().getZCoordinate(), + "Move mote?", + JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, + null, options, options[0]); + moving = returnValue == JOptionPane.YES_OPTION; } if (moving) { movedMote.getInterfaces().getPosition().setCoordinates( @@ -1392,7 +1462,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { return "Move " + mote; } public void doAction(Visualizer visualizer, Mote mote) { - visualizer.beginMoveRequest(mote, false, true); + visualizer.beginMoveRequest(mote, false, false); } }; @@ -1455,20 +1525,13 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { public String getQuickHelp() { return - "Visualizer " + - "

The visualizer shows the positions of simulated motes as viewed from above (XY-plane). " + - "It is possible to zoom (CRTL+Mouse drag) and pan (Shift+Mouse drag) the current view. Motes can be moved by dragging them (ALT+Mouse drag). " + - "Mouse right-click a mote or unoccupied space for a popup menu with more options. " + - "

The visualizer supports \"visualizer skins\". " + - "Each skin provides some specific information, such as ongoing simulated radio traffic, or the IP addresses of motes. " + - "Multiple skins can be active at the same time. " + - "Click the upper \"Select visualizer skin\" button to select or deselect skins. " + - "

Useful skins " + - "
Mote IDs: prints the unique mote IDs inside motes. " + - "
Log output: prints the last printf message above motes. " + - "
Radio traffic: displays inter-mote radio communication. " + - "
Radio environment (UDGM): enables configurating the UDGM radio medium. " + - "

Tip
" + - "Right-click visualizer to show the popup menu, and click \"Hide window decorations\"."; + "Network " + + "

The network windo shows the positions of simulated motes. " + + "It is possible to zoom (CRTL+Mouse drag) and pan (Shift+Mouse drag) the current view. Motes can be moved by dragging them. " + + "Mouse right-click motes for options. " + + "

The network window suppors different views. " + + "Each view provides some specific information, such as the IP addresses of motes. " + + "Multiple views can be active at the same time. " + + "Use the View menu to select views. "; }; }