+
+
+ /**
+ * Respond to mouse click events
+ * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
+ */
+ public void mouseClicked(MouseEvent inE)
+ {
+ if (_track != null && _track.getNumPoints() > 0)
+ {
+ // select point if it's a left-click
+ if (!inE.isMetaDown())
+ {
+ if (inE.getClickCount() == 1)
+ {
+ // single click
+ if (_drawMode == MODE_DEFAULT)
+ {
+ int pointIndex = _clickedPoint;
+ if (pointIndex == INDEX_UNKNOWN)
+ {
+ // index hasn't been calculated yet
+ pointIndex = _track.getNearestPointIndex(
+ _mapPosition.getXFromPixels(inE.getX(), getWidth()),
+ _mapPosition.getYFromPixels(inE.getY(), getHeight()),
+ _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY), false);
+ }
+ // Extend selection for shift-click
+ if (inE.isShiftDown()) {
+ _trackInfo.extendSelection(pointIndex);
+ }
+ else {
+ _trackInfo.selectPoint(pointIndex);
+ }
+ }
+ else if (_drawMode == MODE_DRAW_POINTS_START)
+ {
+ _app.createPoint(createPointFromClick(inE.getX(), inE.getY()));
+ _dragToX = inE.getX();
+ _dragToY = inE.getY();
+ _drawMode = MODE_DRAW_POINTS_CONT;
+ }
+ else if (_drawMode == MODE_DRAW_POINTS_CONT)
+ {
+ DataPoint point = createPointFromClick(inE.getX(), inE.getY());
+ _app.createPoint(point);
+ point.setSegmentStart(false);
+ }
+ }
+ else if (inE.getClickCount() == 2)
+ {
+ // double click
+ if (_drawMode == MODE_DEFAULT) {
+ panMap(inE.getX() - getWidth()/2, inE.getY() - getHeight()/2);
+ zoomIn();
+ }
+ else if (_drawMode == MODE_DRAW_POINTS_START || _drawMode == MODE_DRAW_POINTS_CONT) {
+ _drawMode = MODE_DEFAULT;
+ }
+ }
+ }
+ else
+ {
+ // show the popup menu for right-clicks
+ _popupMenuX = inE.getX();
+ _popupMenuY = inE.getY();
+ _popup.show(this, _popupMenuX, _popupMenuY);
+ }
+ }
+ // Reset app mode
+ _app.setCurrentMode(App.AppMode.NORMAL);
+ if (_drawMode == MODE_MARK_RECTANGLE) _drawMode = MODE_DEFAULT;
+ }
+
+ /**
+ * Ignore mouse enter events
+ * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
+ */
+ public void mouseEntered(MouseEvent inE)
+ {
+ // ignore
+ }
+
+ /**
+ * Ignore mouse exited events
+ * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
+ */
+ public void mouseExited(MouseEvent inE)
+ {
+ // ignore
+ }
+
+ /**
+ * React to mouse pressed events to initiate a point drag
+ * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
+ */
+ public void mousePressed(MouseEvent inE)
+ {
+ _clickedPoint = INDEX_UNKNOWN;
+ if (_track == null || _track.getNumPoints() <= 0)
+ return;
+ if (!inE.isMetaDown())
+ {
+ // Left mouse drag - check if point is near; if so select it for dragging
+ if (_drawMode == MODE_DEFAULT)
+ {
+ /* Drag points if edit mode is enabled OR ALT is pressed */
+ if (_editmodeCheckBox.isSelected() || inE.isAltDown() || inE.isAltGraphDown())
+ {
+ final double clickX = _mapPosition.getXFromPixels(inE.getX(), getWidth());
+ final double clickY = _mapPosition.getYFromPixels(inE.getY(), getHeight());
+ final double clickSens = _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY);
+ _clickedPoint = _track.getNearestPointIndex(clickX, clickY, clickSens, false);
+
+ if (_clickedPoint >= 0)
+ {
+ // TODO: maybe use another color of the cross or remove the cross while dragging???
+
+ _trackInfo.selectPoint(_clickedPoint);
+ if (_trackInfo.getCurrentPoint() != null)
+ {
+ _drawMode = MODE_DRAG_POINT;
+ _dragFromX = _dragToX = inE.getX();
+ _dragFromY = _dragToY = inE.getY();
+ }
+ }
+ else
+ {
+ // Not a click on a point, so check half-way between two (connected) trackpoints
+ int midpointIndex = _midpoints.getNearestPointIndex(clickX, clickY, clickSens);
+ if (midpointIndex > 0)
+ {
+ _drawMode = MODE_CREATE_MIDPOINT;
+ _clickedPoint = midpointIndex;
+ _dragFromX = _dragToX = inE.getX();
+ _dragFromY = _dragToY = inE.getY();
+ }
+ }
+ }
+ }
+ }
+ // else right-press ignored
+ }
+
+ /**
+ * Respond to mouse released events
+ * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
+ */
+ public void mouseReleased(MouseEvent inE)
+ {
+ _recalculate = true;
+
+ if (_drawMode == MODE_DRAG_POINT)
+ {
+ if (Math.abs(_dragToX - _dragFromX) > 2
+ || Math.abs(_dragToY - _dragFromY) > 2)
+ {
+ movePointToMouse(_dragFromX, _dragFromY, _dragToX, _dragToY );
+ }
+ _drawMode = MODE_DEFAULT;
+ }
+ else if (_drawMode == MODE_CREATE_MIDPOINT)
+ {
+ _drawMode = MODE_DEFAULT;
+ _app.createPoint(createPointFromClick(_dragToX, _dragToY), _clickedPoint);
+ }
+ else if (_drawMode == MODE_ZOOM_RECT)
+ {
+ if (Math.abs(_dragToX - _dragFromX) > 20
+ && Math.abs(_dragToY - _dragFromY) > 20)
+ {
+ _mapPosition.zoomToPixels(_dragFromX, _dragToX, _dragFromY, _dragToY, getWidth(), getHeight());
+ }
+ _drawMode = MODE_DEFAULT;
+ }
+ else if (_drawMode == MODE_MARK_RECTANGLE)
+ {
+ // Reset app mode
+ _app.setCurrentMode(App.AppMode.NORMAL);
+ _drawMode = MODE_DEFAULT;
+ // Call a function to mark the points
+ MarkPointsInRectangleFunction marker = new MarkPointsInRectangleFunction(_app);
+ double lon1 = MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(_dragFromX, getWidth()));
+ double lat1 = MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(_dragFromY, getHeight()));
+ double lon2 = MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(_dragToX, getWidth()));
+ double lat2 = MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(_dragToY, getHeight()));
+ // Invalidate rectangle if pixel coords are (-1,-1)
+ if (_dragFromX < 0 || _dragFromY < 0) {
+ lon1 = lon2;
+ lat1 = lat2;
+ }
+ marker.setRectCoords(lon1, lat1, lon2, lat2);
+ marker.begin();
+ }
+ _dragFromX = _dragFromY = -1;
+ repaint();
+ }
+
+ /**
+ * Respond to mouse drag events
+ * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
+ */
+ public void mouseDragged(MouseEvent inE)
+ {
+ if (!inE.isMetaDown())
+ {
+ // Left mouse drag - either drag the point or pan the map
+ if (_drawMode == MODE_DRAG_POINT || _drawMode == MODE_CREATE_MIDPOINT)
+ {
+ // move point
+ _dragToX = inE.getX();
+ _dragToY = inE.getY();
+ _recalculate = true;
+ repaint();
+ }
+ else if (_drawMode == MODE_MARK_RECTANGLE)
+ {
+ // draw a rectangle for marking points
+ if (_dragFromX == -1) {
+ _dragFromX = inE.getX();
+ _dragFromY = inE.getY();
+ }
+ _dragToX = inE.getX();
+ _dragToY = inE.getY();
+ repaint();
+ }
+ else
+ {
+ // regular left-drag pans map by appropriate amount
+ if (_dragFromX != -1)
+ {
+ panMap(_dragFromX - inE.getX(), _dragFromY - inE.getY());
+ }
+ _dragFromX = _dragToX = inE.getX();
+ _dragFromY = _dragToY = inE.getY();
+ }
+ }
+ else
+ {
+ // Right-click and drag - update rectangle
+ _drawMode = MODE_ZOOM_RECT;
+ if (_dragFromX == -1) {
+ _dragFromX = inE.getX();
+ _dragFromY = inE.getY();
+ }
+ _dragToX = inE.getX();
+ _dragToY = inE.getY();
+ repaint();
+ }
+ }
+
+ /**
+ * Respond to mouse move events without button pressed
+ * @param inEvent ignored
+ */
+ public void mouseMoved(MouseEvent inEvent)
+ {
+ boolean useCrosshairs = false;
+ boolean useResize = false;
+ // Ignore unless we're drawing points
+ if (_drawMode == MODE_DRAW_POINTS_CONT)
+ {
+ _dragToX = inEvent.getX();
+ _dragToY = inEvent.getY();
+ repaint();
+ }
+ else if (_drawMode == MODE_MARK_RECTANGLE) {
+ useResize = true;
+ }
+ else if (_editmodeCheckBox.isSelected() || inEvent.isAltDown() || inEvent.isAltGraphDown())
+ {
+ // Try to find a point or a midpoint at this location, and if there is one
+ // then change the cursor to crosshairs
+ final double clickX = _mapPosition.getXFromPixels(inEvent.getX(), getWidth());
+ final double clickY = _mapPosition.getYFromPixels(inEvent.getY(), getHeight());
+ final double clickSens = _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY);
+ useCrosshairs = (_track.getNearestPointIndex(clickX, clickY, clickSens, false) >= 0
+ || _midpoints.getNearestPointIndex(clickX, clickY, clickSens) >= 0
+ );
+ }
+ if (useCrosshairs && !isCursorSet()) {
+ setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ }
+ else if (useResize && !isCursorSet()) {
+ setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
+ }
+ else if (!useCrosshairs && !useResize && isCursorSet()) {
+ setCursor(null);
+ }
+ }
+
+ /**
+ * Respond to status bar message from broker
+ * @param inMessage message, ignored
+ */
+ public void actionCompleted(String inMessage)
+ {
+ // ignore
+ }
+
+ /**
+ * Respond to data updated message from broker
+ * @param inUpdateType type of update
+ */
+ public void dataUpdated(byte inUpdateType)
+ {
+ _recalculate = true;
+ if ((inUpdateType & DataSubscriber.DATA_ADDED_OR_REMOVED) > 0) {
+ _checkBounds = true;
+ }
+ if ((inUpdateType & DataSubscriber.MAPSERVER_CHANGED) > 0) {
+ _tileManager.resetConfig();
+ }
+ if ((inUpdateType & (DataSubscriber.DATA_ADDED_OR_REMOVED + DataSubscriber.DATA_EDITED)) > 0) {
+ _midpoints.updateData(_track);
+ }
+ // See if rect mode has been activated
+ if (_app.getCurrentMode() == App.AppMode.DRAWRECT)
+ {
+ _drawMode = MODE_MARK_RECTANGLE;
+ if (!isCursorSet()) {
+ setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
+ }
+ }
+ repaint();
+ // enable or disable components
+ boolean hasData = _track.getNumPoints() > 0;
+ _topPanel.setVisible(hasData);
+ _sidePanel.setVisible(hasData);
+ // grab focus for the key presses
+ this.requestFocus();
+ }
+
+ /**
+ * Respond to key presses on the map canvas
+ * @param inE key event
+ */
+ public void keyPressed(KeyEvent inE)
+ {
+ int code = inE.getKeyCode();
+ int currPointIndex = _selection.getCurrentPointIndex();
+ // Check for Ctrl key (for Linux/Win) or meta key (Clover key for Mac)
+ if (inE.isControlDown() || inE.isMetaDown())
+ {
+ // Shift as well makes things faster
+ final int pointIncrement = inE.isShiftDown()?3:1;
+ // Check for arrow keys to zoom in and out
+ if (code == KeyEvent.VK_UP)
+ zoomIn();
+ else if (code == KeyEvent.VK_DOWN)
+ zoomOut();
+ // Key nav for next/prev point
+ else if (code == KeyEvent.VK_LEFT && currPointIndex > 0)
+ _trackInfo.incrementPointIndex(-pointIncrement);
+ else if (code == KeyEvent.VK_RIGHT)
+ _trackInfo.incrementPointIndex(pointIncrement);
+ else if (code == KeyEvent.VK_PAGE_UP)
+ _trackInfo.selectPoint(Checker.getPreviousSegmentStart(
+ _trackInfo.getTrack(), _trackInfo.getSelection().getCurrentPointIndex()));
+ else if (code == KeyEvent.VK_PAGE_DOWN)
+ _trackInfo.selectPoint(Checker.getNextSegmentStart(
+ _trackInfo.getTrack(), _trackInfo.getSelection().getCurrentPointIndex()));
+ // Check for home and end
+ else if (code == KeyEvent.VK_HOME)
+ _trackInfo.selectPoint(0);
+ else if (code == KeyEvent.VK_END)
+ _trackInfo.selectPoint(_trackInfo.getTrack().getNumPoints()-1);
+ }
+ else
+ {
+ // Check for arrow keys to pan
+ int upwardsPan = 0;
+ if (code == KeyEvent.VK_UP)
+ upwardsPan = -PAN_DISTANCE;
+ else if (code == KeyEvent.VK_DOWN)
+ upwardsPan = PAN_DISTANCE;
+ int rightwardsPan = 0;
+ if (code == KeyEvent.VK_RIGHT)
+ rightwardsPan = PAN_DISTANCE;
+ else if (code == KeyEvent.VK_LEFT)
+ rightwardsPan = -PAN_DISTANCE;
+ panMap(rightwardsPan, upwardsPan);
+ // Check for escape
+ if (code == KeyEvent.VK_ESCAPE)
+ _drawMode = MODE_DEFAULT;
+ // Check for backspace key to delete current point (delete key already handled by menu)
+ else if (code == KeyEvent.VK_BACK_SPACE && currPointIndex >= 0) {
+ _app.deleteCurrentPoint();
+ }
+ }
+ }
+
+ /**
+ * @param inE key released event, ignored
+ */
+ public void keyReleased(KeyEvent e)
+ {
+ // ignore
+ }
+
+ /**
+ * @param inE key typed event, ignored
+ */
+ public void keyTyped(KeyEvent inE)
+ {
+ // ignore
+ }
+
+ /**
+ * @param inE mouse wheel event indicating scroll direction
+ */
+ public void mouseWheelMoved(MouseWheelEvent inE)
+ {
+ int clicks = inE.getWheelRotation();
+ if (clicks < 0) {
+ panMap((inE.getX() - getWidth()/2)/2, (inE.getY() - getHeight()/2)/2);
+ zoomIn();
+ }
+ else if (clicks > 0) {
+ panMap(-(inE.getX() - getWidth()/2), -(inE.getY() - getHeight()/2));
+ zoomOut();
+ }
+ }
+
+ /**
+ * @return current map position
+ */
+ public MapPosition getMapPosition()
+ {
+ return _mapPosition;
+ }