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.
This commit is contained in:
Adam Dunkels 2012-06-04 17:17:18 +02:00
parent bc0727a931
commit 4f21efe827

View file

@ -72,6 +72,7 @@ import javax.swing.Action;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem; import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
@ -125,7 +126,7 @@ import se.sics.cooja.plugins.skins.UDGMVisualizerSkin;
* @see UDGMVisualizerSkin * @see UDGMVisualizerSkin
* @author Fredrik Osterlind * @author Fredrik Osterlind
*/ */
@ClassDescription("Simulation visualizer") @ClassDescription("Network...")
@PluginType(PluginType.SIM_STANDARD_PLUGIN) @PluginType(PluginType.SIM_STANDARD_PLUGIN)
public class Visualizer extends VisPlugin implements HasQuickHelp { public class Visualizer extends VisPlugin implements HasQuickHelp {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -139,6 +140,8 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
private final JPanel canvas; private final JPanel canvas;
private boolean loadedConfig = false; private boolean loadedConfig = false;
private final JMenu viewMenu;
/* Viewport */ /* Viewport */
private AffineTransform viewportTransform; private AffineTransform viewportTransform;
public int resetViewport = 0; public int resetViewport = 0;
@ -202,11 +205,11 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
new ArrayList<Class<? extends MoteMenuAction>>(); new ArrayList<Class<? extends MoteMenuAction>>();
public Visualizer(Simulation simulation, GUI gui) { public Visualizer(Simulation simulation, GUI gui) {
super("Simulation Visualizer", gui); super("Network", gui);
this.gui = gui; this.gui = gui;
this.simulation = simulation; this.simulation = simulation;
/* Register external skins */ /* Register external visualizers */
String[] skins = gui.getProjectConfig().getStringArrayValue(Visualizer.class, "SKINS"); String[] skins = gui.getProjectConfig().getStringArrayValue(Visualizer.class, "SKINS");
if (skins != null) { if (skins != null) {
for (String skinClass: skins) { for (String skinClass: skins) {
@ -217,6 +220,43 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
} }
} }
/* 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 */ /* Main canvas */
canvas = new JPanel() { canvas = new JPanel() {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -254,7 +294,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
skinPopupMenu.setVisible(true); skinPopupMenu.setVisible(true);
} }
}); });
this.add(BorderLayout.NORTH, skinButton); /*this.add(BorderLayout.NORTH, skinButton);*/
this.add(BorderLayout.CENTER, canvas); this.add(BorderLayout.CENTER, canvas);
/* Observe simulation and mote positions */ /* 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) 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 */ 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<? extends VisualizerSkin> skinClass) { private void generateAndActivateSkin(Class<? extends VisualizerSkin> skinClass) {
@ -531,6 +573,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
simulation.getGUI().tryLoadClass(this, VisualizerSkin.class, skin); simulation.getGUI().tryLoadClass(this, VisualizerSkin.class, skin);
generateAndActivateSkin(skinClass); generateAndActivateSkin(skinClass);
} }
populateSkinMenu(viewMenu);
} }
public VisualizerSkin[] getCurrentSkins() { public VisualizerSkin[] getCurrentSkins() {
@ -641,12 +684,12 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
/* Visualizer skin actions */ /* Visualizer skin actions */
menu.add(new JSeparator()); menu.add(new JSeparator());
JMenu skinMenu = new JMenu("Visualizers"); /*JMenu skinMenu = new JMenu("Visualizers");
populateSkinMenu(skinMenu); populateSkinMenu(skinMenu);
menu.add(skinMenu); menu.add(skinMenu);
makeSkinsDefaultAction.putValue(Action.NAME, "Set default visualizers"); makeSkinsDefaultAction.putValue(Action.NAME, "Set default visualizers");
JMenuItem skinDefaultItem = new JMenuItem(makeSkinsDefaultAction); JMenuItem skinDefaultItem = new JMenuItem(makeSkinsDefaultAction);
menu.add(skinDefaultItem); menu.add(skinDefaultItem);*/
/* Show menu */ /* Show menu */
menu.setLocation(new Point( menu.setLocation(new Point(
@ -775,7 +818,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
if (motes != null && motes.length > 0) { if (motes != null && motes.length > 0) {
/* One of the clicked motes should be moved */ /* One of the clicked motes should be moved */
clickedMote = motes[0]; clickedMote = motes[0];
beginMoveRequest(motes[0], !mouseEvent.isAltDown(), !mouseEvent.isAltDown()); beginMoveRequest(motes[0], false, false);
} }
} }
@ -791,6 +834,26 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
repaint(); 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) { private void handleMouseMove(MouseEvent e, boolean stop) {
int x = e.getX(); int x = e.getX();
int y = e.getY(); int y = e.getY();
@ -841,17 +904,24 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
/* Moving */ /* Moving */
if (moving) { if (moving) {
Position newPos = transformPixelToPosition(x, y);
if (!stop) { if (!stop) {
canvas.setCursor(moveCursor); canvas.setCursor(moveCursor);
movedMote.getInterfaces().getPosition().setCoordinates(
newPos.getXCoordinate(),
newPos.getYCoordinate(),
movedMote.getInterfaces().getPosition().getZCoordinate()
);
repaint();
return; return;
} }
/* Restore cursor */ /* Restore cursor */
canvas.setCursor(Cursor.getDefaultCursor()); canvas.setCursor(Cursor.getDefaultCursor());
/* Move mote */ /* Move mote */
if (moveStartTime < 0 || System.currentTimeMillis() - moveStartTime > 300) { if (moveStartTime < 0 || System.currentTimeMillis() - moveStartTime > 300) {
Position newPos = transformPixelToPosition(x, y);
if (moveConfirm) { if (moveConfirm) {
String options[] = {"Yes", "Cancel"}; String options[] = {"Yes", "Cancel"};
int returnValue = JOptionPane.showOptionDialog(Visualizer.this, int returnValue = JOptionPane.showOptionDialog(Visualizer.this,
@ -1392,7 +1462,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
return "Move " + mote; return "Move " + mote;
} }
public void doAction(Visualizer visualizer, Mote 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() { public String getQuickHelp() {
return return
"<b>Visualizer</b> " + "<b>Network</b> " +
"<p>The visualizer shows the positions of simulated motes as viewed from above (XY-plane). " + "<p>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 (ALT+Mouse drag). " + "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 a mote or unoccupied space for a popup menu with more options. " + "Mouse right-click motes for options. " +
"<p>The visualizer supports \"visualizer skins\". " + "<p>The network window suppors different views. " +
"Each skin provides some specific information, such as ongoing simulated radio traffic, or the IP addresses of motes. " + "Each view provides some specific information, such as the IP addresses of motes. " +
"Multiple skins can be active at the same time. " + "Multiple views can be active at the same time. " +
"Click the upper \"Select visualizer skin\" button to select or deselect skins. " + "Use the View menu to select views. ";
"<p><b>Useful skins</b> " +
"<br>Mote IDs: prints the unique mote IDs inside motes. " +
"<br>Log output: prints the last printf message above motes. " +
"<br>Radio traffic: displays inter-mote radio communication. " +
"<br>Radio environment (UDGM): enables configurating the UDGM radio medium. " +
"<p><b>Tip</b><br> " +
"Right-click visualizer to show the popup menu, and click \"Hide window decorations\".";
}; };
} }