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:
parent
bc0727a931
commit
4f21efe827
1 changed files with 104 additions and 41 deletions
|
@ -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,21 +205,58 @@ 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) {
|
||||||
Class<? extends VisualizerSkin> skin = gui.tryLoadClass(this, VisualizerSkin.class, skinClass);
|
Class<? extends VisualizerSkin> skin = gui.tryLoadClass(this, VisualizerSkin.class, skinClass);
|
||||||
if (registerVisualizerSkin(skin)) {
|
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 */
|
/* 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(
|
||||||
|
@ -752,7 +795,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
|
||||||
private void handleMousePress(MouseEvent mouseEvent) {
|
private void handleMousePress(MouseEvent mouseEvent) {
|
||||||
int x = mouseEvent.getX();
|
int x = mouseEvent.getX();
|
||||||
int y = mouseEvent.getY();
|
int y = mouseEvent.getY();
|
||||||
clickedMote = null;
|
clickedMote = null;
|
||||||
|
|
||||||
if (mouseEvent.isControlDown()) {
|
if (mouseEvent.isControlDown()) {
|
||||||
/* Zoom */
|
/* Zoom */
|
||||||
|
@ -765,7 +808,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
|
||||||
|
|
||||||
final Mote[] motes = findMotesAtPosition(x, y);
|
final Mote[] motes = findMotesAtPosition(x, y);
|
||||||
if (mouseEvent.isShiftDown() ||
|
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 */
|
/* No motes clicked or shift pressed: We should pan */
|
||||||
panning = true;
|
panning = true;
|
||||||
panningPosition = transformPixelToPosition(x, y);
|
panningPosition = transformPixelToPosition(x, y);
|
||||||
|
@ -774,8 +817,8 @@ 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,28 +904,35 @@ 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,
|
||||||
"Move mote to" +
|
"Move mote to" +
|
||||||
"\nX=" + newPos.getXCoordinate() +
|
"\nX=" + newPos.getXCoordinate() +
|
||||||
"\nY=" + newPos.getYCoordinate() +
|
"\nY=" + newPos.getYCoordinate() +
|
||||||
"\nZ=" + movedMote.getInterfaces().getPosition().getZCoordinate(),
|
"\nZ=" + movedMote.getInterfaces().getPosition().getZCoordinate(),
|
||||||
"Move mote?",
|
"Move mote?",
|
||||||
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
|
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
|
||||||
null, options, options[0]);
|
null, options, options[0]);
|
||||||
moving = returnValue == JOptionPane.YES_OPTION;
|
moving = returnValue == JOptionPane.YES_OPTION;
|
||||||
}
|
}
|
||||||
if (moving) {
|
if (moving) {
|
||||||
movedMote.getInterfaces().getPosition().setCoordinates(
|
movedMote.getInterfaces().getPosition().setCoordinates(
|
||||||
|
@ -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\".";
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue