ensure mouse-triggered event popups are not outside screen, updated to use new watchpoint interface

This commit is contained in:
Fredrik Osterlind 2012-03-21 16:59:42 +01:00
parent dcd0460e0b
commit 042c75e52c
1 changed files with 148 additions and 116 deletions

View File

@ -88,11 +88,12 @@ import se.sics.cooja.GUI;
import se.sics.cooja.Mote; import se.sics.cooja.Mote;
import se.sics.cooja.Plugin; import se.sics.cooja.Plugin;
import se.sics.cooja.PluginType; import se.sics.cooja.PluginType;
import se.sics.cooja.SimEventCentral.MoteCountListener;
import se.sics.cooja.Simulation; import se.sics.cooja.Simulation;
import se.sics.cooja.VisPlugin; import se.sics.cooja.VisPlugin;
import se.sics.cooja.Watchpoint; import se.sics.cooja.Watchpoint;
import se.sics.cooja.WatchpointMote; import se.sics.cooja.WatchpointMote;
import se.sics.cooja.SimEventCentral.MoteCountListener; import se.sics.cooja.WatchpointMote.WatchpointListener;
import se.sics.cooja.interfaces.LED; import se.sics.cooja.interfaces.LED;
import se.sics.cooja.interfaces.Radio; import se.sics.cooja.interfaces.Radio;
import se.sics.cooja.interfaces.Radio.RadioEvent; import se.sics.cooja.interfaces.Radio.RadioEvent;
@ -100,7 +101,7 @@ import se.sics.cooja.motes.AbstractEmulatedMote;
/** /**
* Shows events such as mote logs, LEDs, and radio transmissions, in a timeline. * Shows events such as mote logs, LEDs, and radio transmissions, in a timeline.
* *
* @author Fredrik Osterlind * @author Fredrik Osterlind
*/ */
@ClassDescription("Timeline") @ClassDescription("Timeline")
@ -118,13 +119,13 @@ public class TimeLine extends VisPlugin {
private double currentPixelDivisor = 200; private double currentPixelDivisor = 200;
private static final long[] ZOOM_LEVELS = { private static final long[] ZOOM_LEVELS = {
1, 2, 5, 10, 1, 2, 5, 10,
20, 50, 100, 200, 500, 1000, 20, 50, 100, 200, 500, 1000,
2000, 5000, 10000, 20000, 50000, 100000 }; 2000, 5000, 10000, 20000, 50000, 100000 };
private boolean needZoomOut = false; private boolean needZoomOut = false;
private static Logger logger = Logger.getLogger(TimeLine.class); private static Logger logger = Logger.getLogger(TimeLine.class);
private int paintedMoteHeight = EVENT_PIXEL_HEIGHT; private int paintedMoteHeight = EVENT_PIXEL_HEIGHT;
@ -137,7 +138,7 @@ public class TimeLine extends VisPlugin {
private JComponent timeline; private JComponent timeline;
private Box eventCheckboxes; private Box eventCheckboxes;
private JSplitPane splitPane; private JSplitPane splitPane;
private Observer moteHighlightObserver = null; private Observer moteHighlightObserver = null;
private ArrayList<Mote> highlightedMotes = new ArrayList<Mote>(); private ArrayList<Mote> highlightedMotes = new ArrayList<Mote>();
private final static Color HIGHLIGHT_COLOR = Color.CYAN; private final static Color HIGHLIGHT_COLOR = Color.CYAN;
@ -162,9 +163,9 @@ public class TimeLine extends VisPlugin {
public TimeLine(final Simulation simulation, final GUI gui) { public TimeLine(final Simulation simulation, final GUI gui) {
super("Timeline (Add motes to observe by clicking +)", gui); super("Timeline (Add motes to observe by clicking +)", gui);
this.simulation = simulation; this.simulation = simulation;
currentPixelDivisor = ZOOM_LEVELS[ZOOM_LEVELS.length/2]; currentPixelDivisor = ZOOM_LEVELS[ZOOM_LEVELS.length/2];
/* Box: events to observe */ /* Box: events to observe */
eventCheckboxes = Box.createVerticalBox(); eventCheckboxes = Box.createVerticalBox();
JCheckBox eventCheckBox; JCheckBox eventCheckBox;
@ -281,7 +282,7 @@ public class TimeLine extends VisPlugin {
for (Mote m: simulation.getMotes()) { for (Mote m: simulation.getMotes()) {
addMote(m); addMote(m);
} }
/* Update timeline for the duration of the plugin */ /* Update timeline for the duration of the plugin */
repaintTimelineTimer.start(); repaintTimelineTimer.start();
@ -351,12 +352,12 @@ public class TimeLine extends VisPlugin {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JComponent b = (JComponent) e.getSource(); JComponent b = (JComponent) e.getSource();
Mote m = (Mote) b.getClientProperty("mote"); Mote m = (Mote) b.getClientProperty("mote");
/* Sort by distance */ /* Sort by distance */
ArrayList<MoteEvents> sortedMoteEvents = new ArrayList<MoteEvents>(); ArrayList<MoteEvents> sortedMoteEvents = new ArrayList<MoteEvents>();
for (MoteEvents me: allMoteEvents.toArray(new MoteEvents[0])) { for (MoteEvents me: allMoteEvents.toArray(new MoteEvents[0])) {
double d = me.mote.getInterfaces().getPosition().getDistanceTo(m); double d = me.mote.getInterfaces().getPosition().getDistanceTo(m);
int i=0; int i=0;
for (i=0; i < sortedMoteEvents.size(); i++) { for (i=0; i < sortedMoteEvents.size(); i++) {
double d2 = m.getInterfaces().getPosition().getDistanceTo(sortedMoteEvents.get(i).mote); double d2 = m.getInterfaces().getPosition().getDistanceTo(sortedMoteEvents.get(i).mote);
@ -365,7 +366,7 @@ public class TimeLine extends VisPlugin {
} }
} }
sortedMoteEvents.add(i, me); sortedMoteEvents.add(i, me);
} }
allMoteEvents = sortedMoteEvents; allMoteEvents = sortedMoteEvents;
numberMotesWasUpdated(); numberMotesWasUpdated();
@ -376,7 +377,7 @@ public class TimeLine extends VisPlugin {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JComponent b = (JComponent) e.getSource(); JComponent b = (JComponent) e.getSource();
Mote m = (Mote) b.getClientProperty("mote"); Mote m = (Mote) b.getClientProperty("mote");
/* Sort by distance */ /* Sort by distance */
MoteEvents mEvent = null; MoteEvents mEvent = null;
for (MoteEvents me: allMoteEvents.toArray(new MoteEvents[0])) { for (MoteEvents me: allMoteEvents.toArray(new MoteEvents[0])) {
@ -441,7 +442,7 @@ public class TimeLine extends VisPlugin {
int leftPixel = (int) (focusTime/currentPixelDivisor - focusCenter*w); int leftPixel = (int) (focusTime/currentPixelDivisor - focusCenter*w);
Rectangle r = new Rectangle( Rectangle r = new Rectangle(
leftPixel, 0, leftPixel, 0,
w, 1 w, 1
); );
@ -456,7 +457,7 @@ public class TimeLine extends VisPlugin {
} }
}); });
} }
private Action zoomInAction = new AbstractAction("Zoom in (Ctrl+)") { private Action zoomInAction = new AbstractAction("Zoom in (Ctrl+)") {
private static final long serialVersionUID = -2592452356547803615L; private static final long serialVersionUID = -2592452356547803615L;
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
@ -476,13 +477,13 @@ public class TimeLine extends VisPlugin {
if (currentPixelDivisor <= ZOOM_LEVELS[zoomLevel]) break; if (currentPixelDivisor <= ZOOM_LEVELS[zoomLevel]) break;
zoomLevel++; zoomLevel++;
} }
if (zoomLevel > 0) { if (zoomLevel > 0) {
zoomLevel--; /* zoom in */ zoomLevel--; /* zoom in */
} }
currentPixelDivisor = ZOOM_LEVELS[zoomLevel]; currentPixelDivisor = ZOOM_LEVELS[zoomLevel];
logger.info("Zoom level: " + currentPixelDivisor + " microseconds/pixel " + ((zoomLevel==0)?"(MIN)":"")); logger.info("Zoom level: " + currentPixelDivisor + " microseconds/pixel " + ((zoomLevel==0)?"(MIN)":""));
forceRepaintAndFocus(centerTime, 0.5); forceRepaintAndFocus(centerTime, 0.5);
} }
}; };
@ -516,7 +517,7 @@ public class TimeLine extends VisPlugin {
forceRepaintAndFocus(centerTime, 0.5); forceRepaintAndFocus(centerTime, 0.5);
} }
}; };
private Action zoomSliderAction = new AbstractAction("Zoom slider (Ctrl+Mouse)") { private Action zoomSliderAction = new AbstractAction("Zoom slider (Ctrl+Mouse)") {
private static final long serialVersionUID = -4288046377707363837L; private static final long serialVersionUID = -4288046377707363837L;
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
@ -532,27 +533,27 @@ public class TimeLine extends VisPlugin {
zoomSlider.setPaintLabels(false); zoomSlider.setPaintLabels(false);
final long centerTime = (long) (popupLocation.x*currentPixelDivisor); final long centerTime = (long) (popupLocation.x*currentPixelDivisor);
zoomSlider.addChangeListener(new ChangeListener() { zoomSlider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) { public void stateChanged(ChangeEvent e) {
int zoomLevel = zoomSlider.getValue(); int zoomLevel = zoomSlider.getValue();
currentPixelDivisor = ZOOM_LEVELS[zoomLevel]; currentPixelDivisor = ZOOM_LEVELS[zoomLevel];
logger.info("Zoom level: " + currentPixelDivisor + " microseconds/pixel " + ((zoomLevel==ZOOM_LEVELS.length-1)?"(MAX)":"")); logger.info("Zoom level: " + currentPixelDivisor + " microseconds/pixel " + ((zoomLevel==ZOOM_LEVELS.length-1)?"(MAX)":""));
forceRepaintAndFocus(centerTime, 0.5); forceRepaintAndFocus(centerTime, 0.5);
} }
}); });
final JPopupMenu zoomPopup = new JPopupMenu(); final JPopupMenu zoomPopup = new JPopupMenu();
zoomPopup.add(zoomSlider); zoomPopup.add(zoomSlider);
zoomPopup.show(TimeLine.this, TimeLine.this.getWidth()/2, 0); zoomPopup.show(TimeLine.this, TimeLine.this.getWidth()/2, 0);
zoomSlider.requestFocus(); zoomSlider.requestFocus();
} }
}; };
/** /**
* Save logged raw data to file for post-processing. * Save logged raw data to file for post-processing.
*/ */
private Action saveDataAction = new AbstractAction("Save raw data to file") { private Action saveDataAction = new AbstractAction("Save raw data to file") {
private static final long serialVersionUID = 975176793514425718L; private static final long serialVersionUID = 975176793514425718L;
@ -641,15 +642,15 @@ public class TimeLine extends VisPlugin {
} }
repaint(); repaint();
} }
private class MoteStatistics { private class MoteStatistics {
Mote mote; Mote mote;
long onTimeRedLED = 0, onTimeGreenLED = 0, onTimeBlueLED = 0; long onTimeRedLED = 0, onTimeGreenLED = 0, onTimeBlueLED = 0;
int nrLogs = 0; int nrLogs = 0;
long radioOn = 0; long radioOn = 0;
long onTimeRX = 0, onTimeTX = 0, onTimeInterfered = 0; long onTimeRX = 0, onTimeTX = 0, onTimeInterfered = 0;
public String toString() { public String toString() {
return toString(true, true, true, true); return toString(true, true, true, true);
} }
@ -685,7 +686,7 @@ public class TimeLine extends VisPlugin {
logger.info(extractStatistics()); logger.info(extractStatistics());
} }
}; };
public String extractStatistics() { public String extractStatistics() {
return extractStatistics(true, true, true, true); return extractStatistics(true, true, true, true);
} }
@ -743,7 +744,7 @@ public class TimeLine extends VisPlugin {
stats.nrLogs++; stats.nrLogs++;
} }
} }
/* TODO Radio channels */ /* TODO Radio channels */
if (radioHW) { if (radioHW) {
@ -760,7 +761,7 @@ public class TimeLine extends VisPlugin {
} }
} }
} }
if (radioRXTX) { if (radioRXTX) {
for (MoteEvent ev: moteEvents.radioRXTXEvents) { for (MoteEvent ev: moteEvents.radioRXTXEvents) {
if (!(ev instanceof RadioRXTXEvent)) continue; if (!(ev instanceof RadioRXTXEvent)) continue;
@ -790,7 +791,7 @@ public class TimeLine extends VisPlugin {
} }
} }
} }
/* TODO Watchpoints */ /* TODO Watchpoints */
output.append(stats.toString(logs, leds, radioHW, radioRXTX)); output.append(stats.toString(logs, leds, radioHW, radioRXTX));
@ -799,7 +800,7 @@ public class TimeLine extends VisPlugin {
if (allStats.size() == 0) { if (allStats.size() == 0) {
return output.toString(); return output.toString();
} }
/* Average */ /* Average */
MoteStatistics average = new MoteStatistics(); MoteStatistics average = new MoteStatistics();
for (MoteStatistics stats: allStats) { for (MoteStatistics stats: allStats) {
@ -822,7 +823,7 @@ public class TimeLine extends VisPlugin {
output.append(average.toString(logs, leds, radioHW, radioRXTX)); output.append(average.toString(logs, leds, radioHW, radioRXTX));
return output.toString(); return output.toString();
} }
public void trySelectTime(final long toTime) { public void trySelectTime(final long toTime) {
java.awt.EventQueue.invokeLater(new Runnable() { java.awt.EventQueue.invokeLater(new Runnable() {
public void run() { public void run() {
@ -841,23 +842,23 @@ public class TimeLine extends VisPlugin {
forceRepaintAndFocus(toTime, 0.5, false); forceRepaintAndFocus(toTime, 0.5, false);
} }
}); });
} }
private Action radioLoggerAction = new AbstractAction("in Radio Logger") { private Action radioLoggerAction = new AbstractAction("in Radio Logger") {
private static final long serialVersionUID = 7690116136861949864L; private static final long serialVersionUID = 7690116136861949864L;
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (popupLocation == null) { if (popupLocation == null) {
return; return;
} }
long time = (long) ((double)popupLocation.x*currentPixelDivisor); long time = (long) (popupLocation.x*currentPixelDivisor);
Plugin[] plugins = simulation.getGUI().getStartedPlugins(); Plugin[] plugins = simulation.getGUI().getStartedPlugins();
for (Plugin p: plugins) { for (Plugin p: plugins) {
if (!(p instanceof RadioLogger)) { if (!(p instanceof RadioLogger)) {
continue; continue;
} }
/* Select simulation time */ /* Select simulation time */
RadioLogger plugin = (RadioLogger) p; RadioLogger plugin = (RadioLogger) p;
plugin.trySelectTime(time); plugin.trySelectTime(time);
@ -870,14 +871,14 @@ public class TimeLine extends VisPlugin {
if (popupLocation == null) { if (popupLocation == null) {
return; return;
} }
long time = (long) ((double)popupLocation.x*currentPixelDivisor); long time = (long) (popupLocation.x*currentPixelDivisor);
Plugin[] plugins = simulation.getGUI().getStartedPlugins(); Plugin[] plugins = simulation.getGUI().getStartedPlugins();
for (Plugin p: plugins) { for (Plugin p: plugins) {
if (!(p instanceof LogListener)) { if (!(p instanceof LogListener)) {
continue; continue;
} }
/* Select simulation time */ /* Select simulation time */
LogListener plugin = (LogListener) p; LogListener plugin = (LogListener) p;
plugin.trySelectTime(time); plugin.trySelectTime(time);
@ -929,8 +930,8 @@ public class TimeLine extends VisPlugin {
private Mote mote; private Mote mote;
private WatchpointMote watchpointMote; /* XXX */ private WatchpointMote watchpointMote; /* XXX */
private ActionListener watchpointListener; /* XXX */ private WatchpointListener watchpointListener; /* XXX */
public MoteObservation(Mote mote, Observable observable, Observer observer) { public MoteObservation(Mote mote, Observable observable, Observer observer) {
this.mote = mote; this.mote = mote;
this.observable = observable; this.observable = observable;
@ -938,12 +939,12 @@ public class TimeLine extends VisPlugin {
} }
/* XXX Special case, should be generalized */ /* XXX Special case, should be generalized */
public MoteObservation(Mote mote, WatchpointMote watchpointMote, ActionListener listener) { public MoteObservation(Mote mote, WatchpointMote watchpointMote, WatchpointListener listener) {
this.mote = mote; this.mote = mote;
this.watchpointMote = watchpointMote; this.watchpointMote = watchpointMote;
this.watchpointListener = listener; this.watchpointListener = listener;
} }
public Mote getMote() { public Mote getMote() {
return mote; return mote;
} }
@ -958,7 +959,7 @@ public class TimeLine extends VisPlugin {
observable = null; observable = null;
observer = null; observer = null;
} }
/* XXX */ /* XXX */
if (watchpointMote != null) { if (watchpointMote != null) {
watchpointMote.removeWatchpointListener(watchpointListener); watchpointMote.removeWatchpointListener(watchpointListener);
@ -971,7 +972,7 @@ public class TimeLine extends VisPlugin {
private void addMoteObservers(final Mote mote, final MoteEvents moteEvents) { private void addMoteObservers(final Mote mote, final MoteEvents moteEvents) {
/* TODO Log: final Log moteLog = mote.getInterfaces().getLog(); */ /* TODO Log: final Log moteLog = mote.getInterfaces().getLog(); */
/* TODO Unknown state event */ /* TODO Unknown state event */
/* LEDs */ /* LEDs */
final LED moteLEDs = mote.getInterfaces().getLED(); final LED moteLEDs = mote.getInterfaces().getLED();
if (moteLEDs != null) { if (moteLEDs != null) {
@ -1021,7 +1022,7 @@ public class TimeLine extends VisPlugin {
return; return;
} }
lastChannel = nowChannel; lastChannel = nowChannel;
RadioHWEvent ev = new RadioHWEvent( RadioHWEvent ev = new RadioHWEvent(
simulation.getSimulationTime(), moteRadio.isReceiverOn()); simulation.getSimulationTime(), moteRadio.isReceiverOn());
if (radioChannels) { if (radioChannels) {
@ -1067,7 +1068,7 @@ public class TimeLine extends VisPlugin {
radioEv == RadioEvent.RECEPTION_STARTED || radioEv == RadioEvent.RECEPTION_STARTED ||
radioEv == RadioEvent.RECEPTION_INTERFERED || radioEv == RadioEvent.RECEPTION_INTERFERED ||
radioEv == RadioEvent.RECEPTION_FINISHED) { radioEv == RadioEvent.RECEPTION_FINISHED) {
RadioRXTXEvent ev; RadioRXTXEvent ev;
/* Override events, instead show state */ /* Override events, instead show state */
if (moteRadio.isTransmitting()) { if (moteRadio.isTransmitting()) {
@ -1086,9 +1087,9 @@ public class TimeLine extends VisPlugin {
ev = new RadioRXTXEvent( ev = new RadioRXTXEvent(
simulation.getSimulationTime(), RXTXRadioEvent.IDLE); simulation.getSimulationTime(), RXTXRadioEvent.IDLE);
} }
moteEvents.addRadioRXTX(ev); moteEvents.addRadioRXTX(ev);
if (executionDetails && mote instanceof AbstractEmulatedMote) { if (executionDetails && mote instanceof AbstractEmulatedMote) {
String details = ((AbstractEmulatedMote) mote).getExecutionDetails(); String details = ((AbstractEmulatedMote) mote).getExecutionDetails();
if (details != null) { if (details != null) {
@ -1106,22 +1107,26 @@ public class TimeLine extends VisPlugin {
moteRadio.addObserver(observer); moteRadio.addObserver(observer);
activeMoteObservers.add(new MoteObservation(mote, moteRadio, observer)); activeMoteObservers.add(new MoteObservation(mote, moteRadio, observer));
} }
/* XXX Experimental: Watchpoints */ /* XXX Experimental: Watchpoints */
if (mote instanceof WatchpointMote) { if (mote instanceof WatchpointMote) {
final WatchpointMote watchpointMote = ((WatchpointMote)mote); final WatchpointMote watchpointMote = ((WatchpointMote)mote);
ActionListener listener = new ActionListener() { WatchpointListener listener = new WatchpointListener() {
public void actionPerformed(ActionEvent e) { public void watchpointTriggered(Watchpoint watchpoint) {
if (watchpointMote.getLastWatchpoint() == null) { WatchpointEvent ev = new WatchpointEvent(simulation.getSimulationTime(), watchpoint);
return;
if (executionDetails && mote instanceof AbstractEmulatedMote) {
String details = ((AbstractEmulatedMote) mote).getExecutionDetails();
if (details != null) {
details = "<br>" + details.replace("\n", "<br>");
ev.details = details;
}
} }
WatchpointEvent ev = new WatchpointEvent(
simulation.getSimulationTime(),
watchpointMote.getLastWatchpoint()
);
moteEvents.addWatchpoint(ev); moteEvents.addWatchpoint(ev);
} }
public void watchpointsChanged() {
}
}; };
watchpointMote.addWatchpointListener(listener); watchpointMote.addWatchpointListener(listener);
@ -1209,7 +1214,7 @@ public class TimeLine extends VisPlugin {
} }
simulation.getEventCentral().removeMoteCountListener(newMotesListener); simulation.getEventCentral().removeMoteCountListener(newMotesListener);
/* Remove active mote interface observers */ /* Remove active mote interface observers */
for (MoteObservation o: activeMoteObservers) { for (MoteObservation o: activeMoteObservers) {
o.dispose(); o.dispose();
@ -1295,7 +1300,7 @@ public class TimeLine extends VisPlugin {
for (MoteEvents moteEvents: allMoteEventsArr) { for (MoteEvents moteEvents: allMoteEventsArr) {
removeMote(moteEvents.mote); removeMote(moteEvents.mote);
} }
for (Element element : configXML) { for (Element element : configXML) {
String name = element.getName(); String name = element.getName();
if ("mote".equals(name)) { if ("mote".equals(name)) {
@ -1349,20 +1354,20 @@ public class TimeLine extends VisPlugin {
return true; return true;
} }
private int mousePixelPositionX = -1; private int mousePixelPositionX = -1;
private int mousePixelPositionY = -1; private int mousePixelPositionY = -1;
private int mouseDownPixelPositionX = -1; private int mouseDownPixelPositionX = -1;
class Timeline extends JComponent { class Timeline extends JComponent {
private static final long serialVersionUID = 2206491823778169359L; private static final long serialVersionUID = 2206491823778169359L;
public Timeline() { public Timeline() {
setLayout(null); setLayout(null);
setToolTipText(null); setToolTipText(null);
setBackground(COLOR_BACKGROUND); setBackground(COLOR_BACKGROUND);
addMouseListener(mouseAdapter); addMouseListener(mouseAdapter);
addMouseMotionListener(mouseAdapter); addMouseMotionListener(mouseAdapter);
/* Popup menu */ /* Popup menu */
final JPopupMenu popupMenu = new JPopupMenu(); final JPopupMenu popupMenu = new JPopupMenu();
@ -1379,7 +1384,7 @@ public class TimeLine extends VisPlugin {
popupMenu.add(new JMenuItem(saveDataAction)); popupMenu.add(new JMenuItem(saveDataAction));
popupMenu.add(new JMenuItem(statisticsAction)); popupMenu.add(new JMenuItem(statisticsAction));
popupMenu.add(new JMenuItem(clearAction)); popupMenu.add(new JMenuItem(clearAction));
popupMenu.addSeparator(); popupMenu.addSeparator();
JMenu focusMenu = new JMenu("Show in"); JMenu focusMenu = new JMenu("Show in");
@ -1417,7 +1422,7 @@ public class TimeLine extends VisPlugin {
popupLocation = e.getPoint(); popupLocation = e.getPoint();
showInAllAction.actionPerformed(null); showInAllAction.actionPerformed(null);
long time = (long) ((double)popupLocation.x*currentPixelDivisor); long time = (long) (popupLocation.x*currentPixelDivisor);
Plugin[] plugins = simulation.getGUI().getStartedPlugins(); Plugin[] plugins = simulation.getGUI().getStartedPlugins();
for (Plugin p: plugins) { for (Plugin p: plugins) {
if (!(p instanceof TimeLine)) { if (!(p instanceof TimeLine)) {
@ -1486,7 +1491,7 @@ public class TimeLine extends VisPlugin {
forceRepaintAndFocus(zoomCenterTime, zoomCenter); forceRepaintAndFocus(zoomCenterTime, zoomCenter);
return; return;
} }
if (mousePixelPositionX >= 0) { if (mousePixelPositionX >= 0) {
mousePixelPositionX = e.getX(); mousePixelPositionX = e.getX();
mousePixelPositionY = e.getY(); mousePixelPositionY = e.getY();
@ -1507,7 +1512,7 @@ public class TimeLine extends VisPlugin {
zoomCenterTime = (long) (e.getX()*currentPixelDivisor); zoomCenterTime = (long) (e.getX()*currentPixelDivisor);
return; return;
} }
if (popUpToolTip != null) { if (popUpToolTip != null) {
popUpToolTip.hide(); popUpToolTip.hide();
popUpToolTip = null; popUpToolTip = null;
@ -1524,7 +1529,34 @@ public class TimeLine extends VisPlugin {
if (t.getTipText() == null || t.getTipText().equals("")) { if (t.getTipText() == null || t.getTipText().equals("")) {
return; return;
} }
popUpToolTip = PopupFactory.getSharedInstance().getPopup(timeline, t, e.getXOnScreen(), e.getYOnScreen()); t.validate();
/* Check tooltip width */
Rectangle screenBounds = timeline.getGraphicsConfiguration().getBounds();
int x;
{
int tooltip = e.getLocationOnScreen().x + t.getPreferredSize().width;
int screen = screenBounds.x + screenBounds.width;
if (tooltip > screen) {
x = e.getLocationOnScreen().x - (tooltip-screen);
} else {
x = e.getLocationOnScreen().x;
}
}
/* Check tooltip height */
int y;
{
int tooltip = e.getLocationOnScreen().y + t.getPreferredSize().height;
int screen = screenBounds.y + screenBounds.height;
if (tooltip > screen) {
y = e.getLocationOnScreen().y - (tooltip-screen);
} else {
y = e.getLocationOnScreen().y;
}
}
popUpToolTip = PopupFactory.getSharedInstance().getPopup(null, t, x, y);
popUpToolTip.show(); popUpToolTip.show();
} }
} }
@ -1544,7 +1576,7 @@ public class TimeLine extends VisPlugin {
public void paintComponent(Graphics g) { public void paintComponent(Graphics g) {
Rectangle bounds = g.getClipBounds(); Rectangle bounds = g.getClipBounds();
/*logger.info("Clip bounds: " + bounds);*/ /*logger.info("Clip bounds: " + bounds);*/
if (needZoomOut) { if (needZoomOut) {
/* Need zoom out */ /* Need zoom out */
g.setColor(Color.RED); g.setColor(Color.RED);
@ -1556,12 +1588,12 @@ public class TimeLine extends VisPlugin {
FontMetrics fm = g.getFontMetrics(); FontMetrics fm = g.getFontMetrics();
int msgWidth = fm.stringWidth(msg); int msgWidth = fm.stringWidth(msg);
int msgHeight = fm.getHeight(); int msgHeight = fm.getHeight();
g.drawString(msg, g.drawString(msg,
vis.x + vis.width/2 - msgWidth/2, vis.x + vis.width/2 - msgWidth/2,
vis.y + vis.height/2 + msgHeight/2); vis.y + vis.height/2 + msgHeight/2);
return; return;
} }
long intervalStart = (long)(bounds.x*currentPixelDivisor); long intervalStart = (long)(bounds.x*currentPixelDivisor);
long intervalEnd = (long) (intervalStart + bounds.width*currentPixelDivisor); long intervalEnd = (long) (intervalStart + bounds.width*currentPixelDivisor);
@ -1584,12 +1616,12 @@ public class TimeLine extends VisPlugin {
int lineHeightOffset = FIRST_MOTE_PIXEL_OFFSET; int lineHeightOffset = FIRST_MOTE_PIXEL_OFFSET;
boolean dark = true; boolean dark = true;
for (int mIndex = 0; mIndex < allMoteEvents.size(); mIndex++) { for (int mIndex = 0; mIndex < allMoteEvents.size(); mIndex++) {
/* Mote separators */ /* Mote separators */
if (dark) { if (dark) {
g.setColor(SEPARATOR_COLOR); g.setColor(SEPARATOR_COLOR);
g.fillRect( g.fillRect(
0, lineHeightOffset-2, 0, lineHeightOffset-2,
getWidth(), paintedMoteHeight getWidth(), paintedMoteHeight
); );
} }
@ -1680,23 +1712,23 @@ public class TimeLine extends VisPlugin {
while (time <= end) { while (time <= end) {
if (time % (100*Simulation.MILLISECOND) == 0) { if (time % (100*Simulation.MILLISECOND) == 0) {
g.drawLine( g.drawLine(
(int) (time/currentPixelDivisor), (int)0, (int) (time/currentPixelDivisor), 0,
(int) (time/currentPixelDivisor), (int)TIME_MARKER_PIXEL_HEIGHT); (int) (time/currentPixelDivisor), TIME_MARKER_PIXEL_HEIGHT);
} else { } else {
g.drawLine( g.drawLine(
(int) (time/currentPixelDivisor), (int)0, (int) (time/currentPixelDivisor), 0,
(int) (time/currentPixelDivisor), (int)TIME_MARKER_PIXEL_HEIGHT/2); (int) (time/currentPixelDivisor), TIME_MARKER_PIXEL_HEIGHT/2);
} }
time += (10*Simulation.MILLISECOND); time += (10*Simulation.MILLISECOND);
} }
} }
private void drawMouseTime(Graphics g, long start, long end) { private void drawMouseTime(Graphics g, long start, long end) {
if (mousePixelPositionX >= 0) { if (mousePixelPositionX >= 0) {
long time = (long) ((double)mousePixelPositionX*currentPixelDivisor); long time = (long) (mousePixelPositionX*currentPixelDivisor);
long diff = (long) ((double)Math.abs(mouseDownPixelPositionX-mousePixelPositionX)*currentPixelDivisor); long diff = (long) (Math.abs(mouseDownPixelPositionX-mousePixelPositionX)*currentPixelDivisor);
String str = String str =
"Time (ms): " + (double)time/Simulation.MILLISECOND + "Time (ms): " + (double)time/Simulation.MILLISECOND +
" (" + (double)diff/Simulation.MILLISECOND + ")"; " (" + (double)diff/Simulation.MILLISECOND + ")";
int h = g.getFontMetrics().getHeight(); int h = g.getFontMetrics().getHeight();
@ -1707,21 +1739,21 @@ public class TimeLine extends VisPlugin {
/* Line */ /* Line */
g.setColor(Color.GRAY); g.setColor(Color.GRAY);
g.drawLine( g.drawLine(
mousePixelPositionX, 0, mousePixelPositionX, 0,
mousePixelPositionX, getHeight()); mousePixelPositionX, getHeight());
/* Text box */ /* Text box */
g.setColor(Color.DARK_GRAY); g.setColor(Color.DARK_GRAY);
g.fillRect( g.fillRect(
mousePixelPositionX-delta, y, mousePixelPositionX-delta, y,
w, h); w, h);
g.setColor(Color.BLACK); g.setColor(Color.BLACK);
g.drawRect( g.drawRect(
mousePixelPositionX-delta, y, mousePixelPositionX-delta, y,
w, h); w, h);
g.setColor(Color.WHITE); g.setColor(Color.WHITE);
g.drawString(str, g.drawString(str,
mousePixelPositionX+3-delta, mousePixelPositionX+3-delta,
y+h-1); y+h-1);
} }
} }
@ -1738,7 +1770,7 @@ public class TimeLine extends VisPlugin {
int mote = (event.getPoint().y-FIRST_MOTE_PIXEL_OFFSET)/paintedMoteHeight; int mote = (event.getPoint().y-FIRST_MOTE_PIXEL_OFFSET)/paintedMoteHeight;
if (mote < 0 || mote >= allMoteEvents.size()) { if (mote < 0 || mote >= allMoteEvents.size()) {
return null; return null;
} }
String tooltip = "<html>Mote: " + allMoteEvents.get(mote).mote + "<br>"; String tooltip = "<html>Mote: " + allMoteEvents.get(mote).mote + "<br>";
/* Time */ /* Time */
@ -1789,7 +1821,7 @@ public class TimeLine extends VisPlugin {
MoteEvent ev = getFirstIntervalEvent(events, time); MoteEvent ev = getFirstIntervalEvent(events, time);
if (ev != null && time >= ev.time) { if (ev != null && time >= ev.time) {
tooltip += ev + "<br>"; tooltip += ev + "<br>";
if (ev.details != null) { if (ev.details != null) {
tooltip += "Details:<br>" + ev.details; tooltip += "Details:<br>" + ev.details;
} }
@ -1846,7 +1878,7 @@ public class TimeLine extends VisPlugin {
private Mote getMote(Point p) { private Mote getMote(Point p) {
if (p.y < FIRST_MOTE_PIXEL_OFFSET) { if (p.y < FIRST_MOTE_PIXEL_OFFSET) {
return null; return null;
} }
int m = (p.y-FIRST_MOTE_PIXEL_OFFSET)/paintedMoteHeight; int m = (p.y-FIRST_MOTE_PIXEL_OFFSET)/paintedMoteHeight;
if (m < allMoteEvents.size()) { if (m < allMoteEvents.size()) {
@ -1899,9 +1931,9 @@ public class TimeLine extends VisPlugin {
/** /**
* Used by the default paint method to color events. * Used by the default paint method to color events.
* The event is not painted if the returned color is null. * The event is not painted if the returned color is null.
* *
* @see #paintInterval(Graphics, int, long) * @see #paintInterval(Graphics, int, long)
* @return Event color or null * @return Event color or null
*/ */
public abstract Color getEventColor(); public abstract Color getEventColor();
@ -1937,7 +1969,7 @@ public class TimeLine extends VisPlugin {
g.setColor(color); g.setColor(color);
g.fillRect( g.fillRect(
(int)(ev.time/currentPixelDivisor), lineHeightOffset, (int)(ev.time/currentPixelDivisor), lineHeightOffset,
w, EVENT_PIXEL_HEIGHT w, EVENT_PIXEL_HEIGHT
); );
@ -1987,7 +2019,7 @@ public class TimeLine extends VisPlugin {
if (state == RXTXRadioEvent.IDLE) { if (state == RXTXRadioEvent.IDLE) {
return "Radio idle from " + time + "<br>"; return "Radio idle from " + time + "<br>";
} else if (state == RXTXRadioEvent.TRANSMITTING) { } else if (state == RXTXRadioEvent.TRANSMITTING) {
return "Radio transmitting from " + time + "<br>"; return "Radio transmitting from " + time + "<br>";
} else if (state == RXTXRadioEvent.RECEIVING) { } else if (state == RXTXRadioEvent.RECEIVING) {
return "Radio receiving from " + time + "<br>"; return "Radio receiving from " + time + "<br>";
} else if (state == RXTXRadioEvent.INTERFERED) { } else if (state == RXTXRadioEvent.INTERFERED) {
@ -2007,18 +2039,18 @@ public class TimeLine extends VisPlugin {
} }
/* TODO Which colors? */ /* TODO Which colors? */
private final static Color[] CHANNEL_COLORS = new Color[] { private final static Color[] CHANNEL_COLORS = new Color[] {
Color.decode("0x008080"), Color.decode("0x808080"), Color.decode("0xC00000"), Color.decode("0x008080"), Color.decode("0x808080"), Color.decode("0xC00000"),
Color.decode("0x000020"), Color.decode("0x202000"), Color.decode("0x200020"), Color.decode("0x000020"), Color.decode("0x202000"), Color.decode("0x200020"),
Color.decode("0x002020"), Color.decode("0x202020"), Color.decode("0x006060"), Color.decode("0x002020"), Color.decode("0x202020"), Color.decode("0x006060"),
Color.decode("0x606060"), Color.decode("0xA00000"), Color.decode("0x00A000"), Color.decode("0x606060"), Color.decode("0xA00000"), Color.decode("0x00A000"),
Color.decode("0x0000A0"), Color.decode("0x400040"), Color.decode("0x004040"), Color.decode("0x0000A0"), Color.decode("0x400040"), Color.decode("0x004040"),
Color.decode("0x404040"), Color.decode("0x200000"), Color.decode("0x002000"), Color.decode("0x404040"), Color.decode("0x200000"), Color.decode("0x002000"),
Color.decode("0xA0A000"), Color.decode("0xA000A0"), Color.decode("0x00A0A0"), Color.decode("0xA0A000"), Color.decode("0xA000A0"), Color.decode("0x00A0A0"),
Color.decode("0xA0A0A0"), Color.decode("0xE00000"), Color.decode("0x600000"), Color.decode("0xA0A0A0"), Color.decode("0xE00000"), Color.decode("0x600000"),
Color.decode("0x000040"), Color.decode("0x404000"), Color.decode("0xFF0000"), Color.decode("0x000040"), Color.decode("0x404000"), Color.decode("0xFF0000"),
Color.decode("0x00FF00"), Color.decode("0x0000FF"), Color.decode("0xFFFF00"), Color.decode("0x00FF00"), Color.decode("0x0000FF"), Color.decode("0xFFFF00"),
Color.decode("0xFF00FF"), Color.decode("0x808000"), Color.decode("0x800080"), Color.decode("0xFF00FF"), Color.decode("0x808000"), Color.decode("0x800080"),
}; };
class RadioHWEvent extends MoteEvent { class RadioHWEvent extends MoteEvent {
boolean on; boolean on;
@ -2098,21 +2130,21 @@ public class TimeLine extends VisPlugin {
if (color.getRed() > 0) { if (color.getRed() > 0) {
g.setColor(new Color(color.getRed(), 0, 0)); g.setColor(new Color(color.getRed(), 0, 0));
g.fillRect( g.fillRect(
(int)(ev.time/currentPixelDivisor), lineHeightOffset, (int)(ev.time/currentPixelDivisor), lineHeightOffset,
w, LED_PIXEL_HEIGHT w, LED_PIXEL_HEIGHT
); );
} }
if (color.getGreen() > 0) { if (color.getGreen() > 0) {
g.setColor(new Color(0, color.getGreen(), 0)); g.setColor(new Color(0, color.getGreen(), 0));
g.fillRect( g.fillRect(
(int)(ev.time/currentPixelDivisor), lineHeightOffset+LED_PIXEL_HEIGHT, (int)(ev.time/currentPixelDivisor), lineHeightOffset+LED_PIXEL_HEIGHT,
w, LED_PIXEL_HEIGHT w, LED_PIXEL_HEIGHT
); );
} }
if (color.getBlue() > 0) { if (color.getBlue() > 0) {
g.setColor(new Color(0, 0, color.getBlue())); g.setColor(new Color(0, 0, color.getBlue()));
g.fillRect( g.fillRect(
(int)(ev.time/currentPixelDivisor), lineHeightOffset+2*LED_PIXEL_HEIGHT, (int)(ev.time/currentPixelDivisor), lineHeightOffset+2*LED_PIXEL_HEIGHT,
w, LED_PIXEL_HEIGHT w, LED_PIXEL_HEIGHT
); );
} }
@ -2120,7 +2152,7 @@ public class TimeLine extends VisPlugin {
} }
} }
public String toString() { public String toString() {
return return
"LED state:<br>" + "LED state:<br>" +
"Red = " + (red?"ON":"OFF") + "<br>" + "Red = " + (red?"ON":"OFF") + "<br>" +
"Green = " + (green?"ON":"OFF") + "<br>" + "Green = " + (green?"ON":"OFF") + "<br>" +
@ -2151,7 +2183,7 @@ public class TimeLine extends VisPlugin {
public String toString() { public String toString() {
String desc = watchpoint.getDescription(); String desc = watchpoint.getDescription();
desc = desc.replace("\n", "<br>"); desc = desc.replace("\n", "<br>");
return return
"Watchpoint triggered at time (ms): " + time/Simulation.MILLISECOND + ".<br>" "Watchpoint triggered at time (ms): " + time/Simulation.MILLISECOND + ".<br>"
+ desc + "<br>"; + desc + "<br>";
} }
@ -2171,7 +2203,7 @@ public class TimeLine extends VisPlugin {
g.setColor(color); g.setColor(color);
g.fillRect( g.fillRect(
(int)(ev.time/currentPixelDivisor), lineHeightOffset, (int)(ev.time/currentPixelDivisor), lineHeightOffset,
w, EVENT_PIXEL_HEIGHT w, EVENT_PIXEL_HEIGHT
); );
@ -2184,7 +2216,7 @@ public class TimeLine extends VisPlugin {
ArrayList<MoteEvent> radioRXTXEvents; ArrayList<MoteEvent> radioRXTXEvents;
ArrayList<MoteEvent> radioChannelEvents; ArrayList<MoteEvent> radioChannelEvents;
ArrayList<MoteEvent> radioHWEvents; ArrayList<MoteEvent> radioHWEvents;
ArrayList<MoteEvent> ledEvents; ArrayList<MoteEvent> ledEvents;
ArrayList<MoteEvent> logEvents; ArrayList<MoteEvent> logEvents;
ArrayList<MoteEvent> watchpointEvents; ArrayList<MoteEvent> watchpointEvents;
@ -2245,7 +2277,7 @@ public class TimeLine extends VisPlugin {
watchpointEvents.add(lastWatchpointEvent); watchpointEvents.add(lastWatchpointEvent);
} }
} }
public void addRadioRXTX(RadioRXTXEvent ev) { public void addRadioRXTX(RadioRXTXEvent ev) {
/* Link with previous events */ /* Link with previous events */
if (lastRadioRXTXEvent != null) { if (lastRadioRXTXEvent != null) {
@ -2317,7 +2349,7 @@ public class TimeLine extends VisPlugin {
if (now == lastRepaintSimulationTime) { if (now == lastRepaintSimulationTime) {
return; return;
} }
lastRepaintSimulationTime = now; lastRepaintSimulationTime = now;
/* Update timeline size */ /* Update timeline size */
int newWidth; int newWidth;
@ -2330,10 +2362,10 @@ public class TimeLine extends VisPlugin {
needZoomOut = false; needZoomOut = false;
} }
Rectangle visibleRectangle = timeline.getVisibleRect(); Rectangle visibleRectangle = timeline.getVisibleRect();
boolean isTracking = visibleRectangle.x + visibleRectangle.width >= timeline.getWidth(); boolean isTracking = visibleRectangle.x + visibleRectangle.width >= timeline.getWidth();
int newHeight = (int) (FIRST_MOTE_PIXEL_OFFSET + paintedMoteHeight * allMoteEvents.size()); int newHeight = (FIRST_MOTE_PIXEL_OFFSET + paintedMoteHeight * allMoteEvents.size());
timeline.setPreferredSize(new Dimension( timeline.setPreferredSize(new Dimension(
newWidth, newWidth,
newHeight newHeight
@ -2348,7 +2380,7 @@ public class TimeLine extends VisPlugin {
/* Update visible rectangle */ /* Update visible rectangle */
if (isTracking) { if (isTracking) {
Rectangle r = new Rectangle( Rectangle r = new Rectangle(
newWidth-1, visibleRectangle.y, newWidth-1, visibleRectangle.y,
1, 1); 1, 1);
timeline.scrollRectToVisible(r); timeline.scrollRectToVisible(r);
} }