/** * Forwards mouse events to the plug-ins.<br> * * @author Sebastian Ebers */ public class EventDispatcher { private static final Logger log = SpyglassLoggerFactory.getLogger(EventDispatcher.class); private PluginManager pluginManager; private DrawingArea drawingArea; // -------------------------------------------------------------------------------- /** * Constructor * * @param pluginManager the instance which manages the plug-ins * @param drawingArea the area where the plug-ins' contents are visualized */ public EventDispatcher(final PluginManager pluginManager, final DrawingArea drawingArea) { this.pluginManager = pluginManager; this.drawingArea = drawingArea; } // -------------------------------------------------------------------------------- /** * Forwards a event to the first plug-in which can handle it. * * @param e the event to be forwarded */ public void handleEvent(final MouseEvent e) { final List<Plugin> plugins = pluginManager.getVisibleActivePlugins(); // this has to be done in reverse order since the "ordinary" order is used for painting // which means that the topmost element is actually the last element in the list for (int i = plugins.size() - 1; i >= 0; i--) { try { // for the moment only mouse events are dispatched to plug-ins if (plugins.get(i).handleEvent(e, drawingArea)) { return; } } catch (final Exception e1) { log.error("Plugin " + plugins.get(i) + " threw an exception while handling an event", e1); } } } }
public class RecordRecordAction extends Action { private static final Logger log = SpyglassLoggerFactory.getLogger(RecordRecordAction.class); private Spyglass spyglass; private boolean isRecording = false; private final ImageDescriptor imageDescriptorRecording = getImageDescriptor("record_record.png"); private final ImageDescriptor imageDescriptorPausing = getImageDescriptor("record_pause.png"); private Thread listenerThread; public RecordRecordAction(final Spyglass spyglass) { this.spyglass = spyglass; } @Override public void run() { if (spyglass.getPacketRecorder() == null) { MessageDialog.openError( null, "No recorder available", "The input type you selected does not support recording"); isRecording = false; } else { isRecording = spyglass.getPacketRecorder().setRecording(!isRecording); } setText(isRecording ? "Pause" : "Record"); setToolTipText(isRecording ? "Pause" : "Record"); setImageDescriptor(isRecording ? imageDescriptorPausing : imageDescriptorRecording); if (isRecording) { final Thread listenerThread = new Thread() { @Override public void run() { while (!isInterrupted()) { final PacketRecorder rec = spyglass.getPacketRecorder(); if (rec != null) { isRecording = rec.isRecord(); Display.getDefault() .asyncExec( new Runnable() { public void run() { setText(isRecording ? "Pause" : "Record"); setToolTipText(isRecording ? "Pause" : "Record"); setImageDescriptor( isRecording ? imageDescriptorPausing : imageDescriptorRecording); } }); } try { sleep(2000); } catch (final InterruptedException e) { // TODO Auto-generated catch block log.warn(e, e); interrupt(); } } } }; listenerThread.setDaemon(true); listenerThread.start(); } else { if (listenerThread != null) { listenerThread.interrupt(); } } log.debug("Pressed button RECORD_RECORD."); }; @Override public String getToolTipText() { return isRecording ? "Pause recording" : "Start recording"; } @Override public String getText() { return isRecording ? "Pause" : "Record"; } @Override public ImageDescriptor getImageDescriptor() { return isRecording ? imageDescriptorPausing : imageDescriptorRecording; } }
public class Grid extends DrawingObject { private static Logger log = SpyglassLoggerFactory.getLogger(Grid.class); private int gridElementHeight; private int numCols; private int lineWidth; private int gridElementWidth; private int numRows; @Override public void draw(final GC gc) { final Rectangle clipping = gc.getClipping(); final Color color = new Color(gc.getDevice(), getColor()); gc.setLineWidth(lineWidth); gc.setForeground(color); final AbsolutePosition pos = getPosition(); AbsolutePosition origin, dest; PixelPosition pxOrigin, pxDest; int originX, originY, destX, destY; int x1, x2, y1, y2; originX = pos.x; destX = originX + (gridElementWidth * numCols); for (int row = 0; row <= numRows; row++) { originY = destY = pos.y + (row * gridElementHeight); origin = new AbsolutePosition(originX, originY, 0); dest = new AbsolutePosition(destX, destY, 0); pxOrigin = getDrawingArea().absPoint2PixelPoint(origin); pxDest = getDrawingArea().absPoint2PixelPoint(dest); if ((pxOrigin.y >= clipping.y) && (pxOrigin.y <= (clipping.y + clipping.height))) { x1 = Math.max(clipping.x, pxOrigin.x); y1 = pxOrigin.y; x2 = Math.min((clipping.x + clipping.width), pxDest.x); y2 = pxDest.y; gc.drawLine(x1, y1, x2, y2); } } originY = pos.y; destY = originY + (gridElementHeight * numRows); for (int col = 0; col <= numCols; col++) { originX = destX = pos.x + (col * gridElementWidth); origin = new AbsolutePosition(originX, originY, 0); dest = new AbsolutePosition(destX, destY, 0); pxOrigin = getDrawingArea().absPoint2PixelPoint(origin); pxDest = getDrawingArea().absPoint2PixelPoint(dest); if ((pxOrigin.x >= clipping.x) && (pxOrigin.x <= (clipping.x + clipping.width))) { x1 = pxOrigin.x; y1 = Math.max(clipping.y, pxDest.y); x2 = pxDest.x; y2 = Math.min((clipping.y + clipping.height), pxOrigin.y); gc.drawLine(x1, y1, x2, y2); } } color.dispose(); } public synchronized void setGridElementHeight(final int gridElementHeight) { this.gridElementHeight = gridElementHeight; markBoundingBoxDirty(); } public synchronized void setGridElementWidth(final int gridElementWidth) { this.gridElementWidth = gridElementWidth; markBoundingBoxDirty(); } public synchronized void setLineWidth(final int lineWidth) { this.lineWidth = lineWidth; markContentDirty(); } public synchronized void setNumCols(final int numCols) { this.numCols = numCols; markBoundingBoxDirty(); } public synchronized void setNumRows(final int numRows) { this.numRows = numRows; markBoundingBoxDirty(); } @Override protected AbsoluteRectangle calculateBoundingBox() { return new AbsoluteRectangle( getPosition(), gridElementWidth * numCols, gridElementHeight * numRows); } }
/** * ObjectPainter plugin * * @author Dariush Forouher */ public class ObjectPainterPlugin extends BackgroundPainterPlugin implements NeedsMetric { static Logger log = SpyglassLoggerFactory.getLogger(ObjectPainterPlugin.class); @Element(name = "parameters") private final ObjectPainterXMLConfig config = new ObjectPainterXMLConfig();; /** Timer used for updating the trajectories */ private Timer timer = null; /** List of trajectories. Each trajectory is a TimerTask in our timer. */ final List<Trajectory> trajectories = Collections.synchronizedList(new ArrayList<Trajectory>()); final Layer layer = Layer.Factory.createQuadTreeLayer(); // -------------------------------------------------------------------------------- /** Constructor */ public ObjectPainterPlugin() { super(true); } @Override public PluginPreferencePage<ObjectPainterPlugin, ObjectPainterXMLConfig> createPreferencePage( final PluginPreferenceDialog dialog, final Spyglass spyglass) { return new ObjectPainterPreferencePage(dialog, spyglass, this); } public static PluginPreferencePage<ObjectPainterPlugin, ObjectPainterXMLConfig> createTypePreferencePage(final PluginPreferenceDialog dialog, final Spyglass spyglass) { return new ObjectPainterPreferencePage(dialog, spyglass); } public synchronized SortedSet<DrawingObject> getDrawingObjects(final AbsoluteRectangle area) { return layer.getDrawingObjects(area); } public static String getHumanReadableName() { return "ObjectPainter"; } @Override public ObjectPainterXMLConfig getXMLConfig() { return config; } @Override public synchronized void init(final PluginManager manager) throws Exception { super.init(manager); timer = new Timer("ObjectPainter-Timer"); } @Override protected void processPacket(final SpyglassPacket packet) { // Requirement for a trajectory packet if (!(packet instanceof Int16ListPacket)) { return; } if (!config.containsSemanticType(packet.getSemanticType())) { return; } final Int16ListPacket p = (Int16ListPacket) packet; final List<TrajectorySection> list; try { if (config.isPacketType3D()) { list = p.getTrajectory3D(); } else { list = p.getTrajectory2D(); } } catch (final ParseException e) { log.error("Could not extract trajectory information from the packet!", e); return; } // DEADLOCK warning: The constructor of Trajectory creates an SWT image, which tries to aquire // the // SWT display lock. To avoid a AB-BA deadlock, we must avoid creating the constructor with the // plugin-lock hold. final Trajectory t = new Trajectory(this, list, config.getImageFileName()); synchronized (this) { this.trajectories.add(t); timer.schedule(t, 0, config.getUpdateInterval()); } } @Override protected synchronized void resetPlugin() { // make a copy so trajectories can remove themselves final List<Trajectory> list = new ArrayList<Trajectory>(trajectories); // remove all trajectories for (final Trajectory t : list) { t.cancel(); } assert trajectories.size() == 0; this.layer.clear(); } @Override public synchronized Set<DrawingObject> getAutoZoomDrawingObjects() { return layer.getDrawingObjects(); } @Override public synchronized void shutdown() throws Exception { super.shutdown(); // make a copy so trajectories can remove themselves final List<Trajectory> list = new ArrayList<Trajectory>(trajectories); // remove all trajectories for (final Trajectory t : list) { t.cancel(); } assert trajectories.size() == 0; timer.cancel(); } /* Methods needed for scope-reasons */ void fireDrawingObjectAddedInternal(final DrawingObject dob) { fireDrawingObjectAdded(dob); } void fireDrawingObjectRemovedInternal(final DrawingObject dob) { fireDrawingObjectRemoved(dob); } }