From: Frédéric Perrin Date: Sun, 1 Dec 2019 21:37:03 +0000 (+0000) Subject: Merge branch 'srtm-multi-sources' into fp-integration X-Git-Tag: v19.2.fp3 X-Git-Url: http://gitweb.fperrin.net/?p=GpsPrune.git;a=commitdiff_plain;h=4af8c81c67e21029fe2d0380e757d1f090d15127;hp=7850dc9de79806a7b58c01cdfb33a7b32cc6bfa5 Merge branch 'srtm-multi-sources' into fp-integration --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8e9e794 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.class +*.jar diff --git a/buildtools/build.sh b/buildtools/build.sh old mode 100644 new mode 100755 index b38e2ce..c7fcf3d --- a/buildtools/build.sh +++ b/buildtools/build.sh @@ -1,3 +1,4 @@ +set -e # Build script # Version number PRUNENAME=gpsprune_19.2 diff --git a/src/tim/prune/App.java b/src/tim/prune/App.java index 3a77858..317064d 100644 --- a/src/tim/prune/App.java +++ b/src/tim/prune/App.java @@ -51,6 +51,7 @@ public class App { // Instance variables private JFrame _frame = null; + private String _titlePrefix = null; private Track _track = null; private TrackInfo _trackInfo = null; private int _lastSavePosition = 0; @@ -79,6 +80,7 @@ public class App public App(JFrame inFrame) { _frame = inFrame; + _titlePrefix = _frame.getTitle(); _undoStack = new UndoStack(); _track = new Track(); _trackInfo = new TrackInfo(_track); @@ -454,6 +456,22 @@ public class App } + /** + * Remove altitudes from selected points + */ + public void removeAltitudes(int selStart, int selEnd) + { + UndoRemoveAltitudes undo = new UndoRemoveAltitudes(_trackInfo, selStart, selEnd); + if (_trackInfo.getTrack().removeAltitudes(selStart, selEnd)) + { + _undoStack.add(undo); + _trackInfo.getSelection().markInvalid(); + UpdateMessageBroker.informSubscribers(DataSubscriber.DATA_EDITED); + UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.removealtitudes")); + } + } + + /** * Merge the track segments within the current selection */ @@ -759,6 +777,10 @@ public class App + " '" + inSourceInfo.getName() + "'"); // update menu _menuManager.informFileLoaded(); + // recentre viewport on new file data + _viewport.recentreViewport(); + // update main window title + updateTitle(); // Remove busy lock _busyLoading = false; // load next file if there's a queue @@ -1001,4 +1023,16 @@ public class App public void setCurrentMode(AppMode inMode) { _appMode = inMode; } + + /** Update main window title **/ + public void updateTitle() { + ArrayList filenames = _trackInfo.getFileInfo().getFilenames(); + if (filenames.size() > 0) { + _frame.setTitle(_titlePrefix + ": " + String.join(", ", filenames)); + } + else + { + _frame.setTitle(_titlePrefix); + } + } } diff --git a/src/tim/prune/FunctionLibrary.java b/src/tim/prune/FunctionLibrary.java index ea78e9a..4be286e 100644 --- a/src/tim/prune/FunctionLibrary.java +++ b/src/tim/prune/FunctionLibrary.java @@ -28,6 +28,7 @@ import tim.prune.function.PhotoPopupFunction; import tim.prune.function.PlayAudioFunction; import tim.prune.function.RearrangePhotosFunction; import tim.prune.function.RearrangeWaypointsFunction; +import tim.prune.function.RemoveAltitudes; import tim.prune.function.RemoveAudioFunction; import tim.prune.function.RemovePhotoFunction; import tim.prune.function.RotatePhoto; @@ -109,6 +110,7 @@ public abstract class FunctionLibrary public static GenericFunction FUNCTION_DOWNLOAD_OSM = null; public static GenericFunction FUNCTION_ADD_TIME_OFFSET = null; public static GenericFunction FUNCTION_ADD_ALTITUDE_OFFSET = null; + public static GenericFunction FUNCTION_REMOVE_ALTITUDES = null; public static GenericFunction FUNCTION_CONVERT_NAMES_TO_TIMES = null; public static GenericFunction FUNCTION_DELETE_FIELD_VALUES = null; public static GenericFunction FUNCTION_PASTE_COORDINATES = null; @@ -189,6 +191,7 @@ public abstract class FunctionLibrary FUNCTION_DOWNLOAD_OSM = new DownloadOsmFunction(inApp); FUNCTION_ADD_TIME_OFFSET = new AddTimeOffset(inApp); FUNCTION_ADD_ALTITUDE_OFFSET = new AddAltitudeOffset(inApp); + FUNCTION_REMOVE_ALTITUDES = new RemoveAltitudes(inApp); FUNCTION_CONVERT_NAMES_TO_TIMES = new ConvertNamesToTimes(inApp); FUNCTION_DELETE_FIELD_VALUES = new DeleteFieldValues(inApp); FUNCTION_PASTE_COORDINATES = new PasteCoordinates(inApp); diff --git a/src/tim/prune/data/DataPoint.java b/src/tim/prune/data/DataPoint.java index 84f4800..01e9975 100644 --- a/src/tim/prune/data/DataPoint.java +++ b/src/tim/prune/data/DataPoint.java @@ -354,6 +354,16 @@ public class DataPoint } } + /** + * Remove altitude from point + */ + public void removeAltitude() + { + _altitude = Altitude.NONE; + _fieldValues[_fieldList.getFieldIndex(Field.ALTITUDE)] = _altitude.getStringValue(null); + setModified(false); + } + /** * Reset the altitude to the previous value (by an undo) * @param inClone altitude object cloned from earlier diff --git a/src/tim/prune/data/FileInfo.java b/src/tim/prune/data/FileInfo.java index 41900cb..7eaac8f 100644 --- a/src/tim/prune/data/FileInfo.java +++ b/src/tim/prune/data/FileInfo.java @@ -74,6 +74,19 @@ public class FileInfo return ""; } + /** + * @return The source names + */ + public ArrayList getFilenames() + { + ArrayList filenames = new ArrayList(); + for (SourceInfo source : _sources) + { + filenames.add(source.getName()); + } + return filenames; + } + /** * @param inIndex index number, starting from zero * @return source info object diff --git a/src/tim/prune/data/Track.java b/src/tim/prune/data/Track.java index f45854a..ef099d4 100644 --- a/src/tim/prune/data/Track.java +++ b/src/tim/prune/data/Track.java @@ -377,6 +377,31 @@ public class Track } + /** + * Remove altitudes from the specified range + * @param inStart start of range + * @param inEnd end of range + */ + public boolean removeAltitudes(int inStart, int inEnd) + { + // sanity check + if (inStart < 0 || inEnd < 0 || inStart >= inEnd || inEnd >= _numPoints) { + return false; + } + + boolean anyRemoved = false; + for (int i=inStart; i<=inEnd; i++) + { + DataPoint p = _dataPoints[i]; + if (p != null && p.hasAltitude()) + { + p.removeAltitude(); + anyRemoved = true; + } + } + return anyRemoved; + } + /** * Interleave all waypoints by each nearest track point * @return true if successful, false if no change diff --git a/src/tim/prune/function/RemoveAltitudes.java b/src/tim/prune/function/RemoveAltitudes.java new file mode 100644 index 0000000..1c8b05c --- /dev/null +++ b/src/tim/prune/function/RemoveAltitudes.java @@ -0,0 +1,60 @@ +package tim.prune.function; + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import tim.prune.App; +import tim.prune.GenericFunction; +import tim.prune.I18nManager; +import tim.prune.config.Config; +import tim.prune.data.Field; +import tim.prune.data.Unit; +import tim.prune.data.UnitSetLibrary; + +/** + * Class to provide the function to add remove the altitude from points in a + * track range + */ +public class RemoveAltitudes extends GenericFunction +{ + /** + * Constructor + * @param inApp application object for callback + */ + public RemoveAltitudes(App inApp) + { + super(inApp); + } + + /** Get the name key */ + public String getNameKey() { + return "function.removealtitudes"; + } + + /** + * Begin the function + */ + public void begin() + { + int selStart = _app.getTrackInfo().getSelection().getStart(); + int selEnd = _app.getTrackInfo().getSelection().getEnd(); + if (!_app.getTrackInfo().getTrack().hasData(Field.ALTITUDE, selStart, selEnd)) + { + _app.showErrorMessage(getNameKey(), "dialog.addaltitude.noaltitudes"); + return; + } + _app.removeAltitudes(selStart, selEnd); + } +} diff --git a/src/tim/prune/function/edit/PointEditor.java b/src/tim/prune/function/edit/PointEditor.java index c66201b..546a65e 100644 --- a/src/tim/prune/function/edit/PointEditor.java +++ b/src/tim/prune/function/edit/PointEditor.java @@ -307,10 +307,23 @@ public class PointEditor if (_model.getChanged(i)) { Field field = fieldList.getField(i); + if (field == field.WAYPT_NAME) { + if (wasNameAdded(_model.getValue(i))) { + _app.createPoint(_point.clonePoint()); + } + } editList.addEdit(new FieldEdit(field, _model.getValue(i))); undoList.addEdit(new FieldEdit(field, _point.getFieldValue(field))); } } _app.completePointEdit(editList, undoList); } + + private boolean wasNameAdded(String newName) + { + String prevName = _point.getWaypointName(); + boolean prevNull = (prevName == null || prevName.equals("")); + boolean newNull = (newName == null || newName.equals("")); + return (prevNull && !newNull); + } } diff --git a/src/tim/prune/function/edit/PointNameEditor.java b/src/tim/prune/function/edit/PointNameEditor.java index 53e1f83..ca5771d 100644 --- a/src/tim/prune/function/edit/PointNameEditor.java +++ b/src/tim/prune/function/edit/PointNameEditor.java @@ -206,7 +206,14 @@ public class PointNameEditor extends GenericFunction // Check whether name has really changed if (hasNameChanged()) { - // Make lists for edit and undo, and add the changed field + // If a new name has been added, changing the point + // from trackpoint to waypoint, duplicate it + if (wasNameAdded()) + { + _app.createPoint(_point.clonePoint()); + } + + // make lists for edit and undo, and add the changed field FieldEditList editList = new FieldEditList(); FieldEditList undoList = new FieldEditList(); editList.addEdit(new FieldEdit(Field.WAYPT_NAME, _nameField.getText().trim())); @@ -231,4 +238,17 @@ public class PointNameEditor extends GenericFunction || (!prevNull && newNull) || (!prevNull && !newNull && !prevName.equals(newName)); } + + /** + * Check whether a new name has been added + * @return true if it has indeed + */ + private boolean wasNameAdded() + { + String prevName = _point.getWaypointName(); + String newName = _nameField.getText().trim(); + boolean prevNull = (prevName == null || prevName.equals("")); + boolean newNull = (newName == null || newName.equals("")); + return (prevNull && !newNull); + } } diff --git a/src/tim/prune/gui/DisplayUtils.java b/src/tim/prune/gui/DisplayUtils.java index 25640d8..2300296 100644 --- a/src/tim/prune/gui/DisplayUtils.java +++ b/src/tim/prune/gui/DisplayUtils.java @@ -36,7 +36,8 @@ public abstract class DisplayUtils if (inNumSecs < 86400L) return "" + (inNumSecs / 60 / 60) + I18nManager.getText("display.range.time.hours") + " " + ((inNumSecs / 60) % 60) + I18nManager.getText("display.range.time.mins"); if (inNumSecs < 432000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days") - + " " + (inNumSecs / 60 / 60) % 24 + I18nManager.getText("display.range.time.hours"); + + " " + (inNumSecs / 60 / 60) % 24 + I18nManager.getText("display.range.time.hours") + + " " + ((inNumSecs / 60) % 60) + I18nManager.getText("display.range.time.mins"); if (inNumSecs < 86400000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days"); return "big"; } diff --git a/src/tim/prune/gui/MenuManager.java b/src/tim/prune/gui/MenuManager.java index b24c718..bd0d378 100644 --- a/src/tim/prune/gui/MenuManager.java +++ b/src/tim/prune/gui/MenuManager.java @@ -80,6 +80,7 @@ public class MenuManager implements DataSubscriber private JMenuItem _reverseItem = null; private JMenuItem _addTimeOffsetItem = null; private JMenuItem _addAltitudeOffsetItem = null; + private JMenuItem _removeAltitudesItem = null; private JMenuItem _mergeSegmentsItem = null; private JMenuItem _rearrangeWaypointsItem = null; private JMenuItem _splitSegmentsItem = null; @@ -435,6 +436,8 @@ public class MenuManager implements DataSubscriber rangeMenu.add(_addTimeOffsetItem); _addAltitudeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_ALTITUDE_OFFSET, false); rangeMenu.add(_addAltitudeOffsetItem); + _removeAltitudesItem = makeMenuItem(FunctionLibrary.FUNCTION_REMOVE_ALTITUDES, false); + rangeMenu.add(_removeAltitudesItem); _mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.range.mergetracksegments")); _mergeSegmentsItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -968,6 +971,7 @@ public class MenuManager implements DataSubscriber _reverseItem.setEnabled(hasRange); _addTimeOffsetItem.setEnabled(hasRange); _addAltitudeOffsetItem.setEnabled(hasRange); + _removeAltitudesItem.setEnabled(hasRange); _convertNamesToTimesItem.setEnabled(hasRange && _track.hasWaypoints()); _deleteFieldValuesItem.setEnabled(hasRange); _fullRangeDetailsItem.setEnabled(hasRange); diff --git a/src/tim/prune/gui/SelectorDisplay.java b/src/tim/prune/gui/SelectorDisplay.java index fa6630d..9dfc24f 100644 --- a/src/tim/prune/gui/SelectorDisplay.java +++ b/src/tim/prune/gui/SelectorDisplay.java @@ -228,8 +228,9 @@ public class SelectorDisplay extends GenericDisplay else if (numFiles > 1) { final String labelText = I18nManager.getText("details.track.numfiles") + ": " + numFiles; + final String filenameString = String.join(", ", _trackInfo.getFileInfo().getFilenames()); _filenameLabel.setText(labelText); - _filenameLabel.setToolTipText(labelText); + _filenameLabel.setToolTipText(filenameString); } else { diff --git a/src/tim/prune/gui/Viewport.java b/src/tim/prune/gui/Viewport.java index 25eba2f..aec78a6 100644 --- a/src/tim/prune/gui/Viewport.java +++ b/src/tim/prune/gui/Viewport.java @@ -40,4 +40,12 @@ public class Viewport double maxLon = MapUtils.getLongitudeFromX(mapPosition.getXFromPixels(width, width)); return new double[] {minLat, minLon, maxLat, maxLon}; } + + /** + * Recentre the viewport on the data + */ + public void recentreViewport() + { + _mapCanvas.zoomToFit(); + } } diff --git a/src/tim/prune/gui/map/MapCanvas.java b/src/tim/prune/gui/map/MapCanvas.java index aa25dbc..ad38d81 100644 --- a/src/tim/prune/gui/map/MapCanvas.java +++ b/src/tim/prune/gui/map/MapCanvas.java @@ -92,7 +92,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe WpIconDefinition _waypointIconDefinition = null; /** Constant for click sensitivity when selecting nearest point */ - private static final int CLICK_SENSITIVITY = 10; + private static final int CLICK_SENSITIVITY = 30; /** Constant for pan distance from key presses */ private static final int PAN_DISTANCE = 20; /** Constant for pan distance from autopan */ @@ -259,8 +259,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe // add control panels to this one setLayout(new BorderLayout()); - _topPanel.setVisible(false); - _sidePanel.setVisible(false); + _topPanel.setVisible(true); + _sidePanel.setVisible(true); add(_topPanel, BorderLayout.NORTH); add(_sidePanel, BorderLayout.WEST); add(_scaleBar, BorderLayout.SOUTH); @@ -337,16 +337,19 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe /** * Zoom to fit the current data area */ - private void zoomToFit() + public void zoomToFit() { + int maxZoom = (_track.getNumPoints() == 0)?2:_tileManager.getMaxZoomLevel(); _latRange = _track.getLatRange(); _lonRange = _track.getLonRange(); _xRange = new DoubleRange(MapUtils.getXFromLongitude(_lonRange.getMinimum()), MapUtils.getXFromLongitude(_lonRange.getMaximum())); _yRange = new DoubleRange(MapUtils.getYFromLatitude(_latRange.getMinimum()), MapUtils.getYFromLatitude(_latRange.getMaximum())); - _mapPosition.zoomToXY(_xRange.getMinimum(), _xRange.getMaximum(), _yRange.getMinimum(), _yRange.getMaximum(), - getWidth(), getHeight()); + _mapPosition.zoomToXY( + _xRange.getMinimum(), _xRange.getMaximum(), + _yRange.getMinimum(), _yRange.getMaximum(), + getWidth(), getHeight(), maxZoom); } @@ -360,70 +363,59 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe if (_mapImage != null && (_mapImage.getWidth() != getWidth() || _mapImage.getHeight() != getHeight())) { _mapImage = null; } - if (_track.getNumPoints() > 0) + // Check for autopan if enabled / necessary + if (_autopanCheckBox.isSelected()) { - // Check for autopan if enabled / necessary - if (_autopanCheckBox.isSelected()) + int selectedPoint = _selection.getCurrentPointIndex(); + if (selectedPoint >= 0 && _dragFromX == -1 && selectedPoint != _prevSelectedPoint) { - int selectedPoint = _selection.getCurrentPointIndex(); - if (selectedPoint >= 0 && _dragFromX == -1 && selectedPoint != _prevSelectedPoint) - { - autopanToPoint(selectedPoint); - } - _prevSelectedPoint = selectedPoint; + autopanToPoint(selectedPoint); } + _prevSelectedPoint = selectedPoint; + } - // Draw the map contents if necessary - if (_mapImage == null || _recalculate) - { - paintMapContents(); - _scaleBar.updateScale(_mapPosition.getZoom(), _mapPosition.getYFromPixels(0, 0)); - } - // Draw the prepared image onto the panel - if (_mapImage != null) { - inG.drawImage(_mapImage, 0, 0, getWidth(), getHeight(), null); - } + // Draw the map contents if necessary + if (_mapImage == null || _recalculate) + { + paintMapContents(); + _scaleBar.updateScale(_mapPosition.getZoom(), _mapPosition.getYFromPixels(0, 0)); + } + // Draw the prepared image onto the panel + if (_mapImage != null) { + inG.drawImage(_mapImage, 0, 0, getWidth(), getHeight(), null); + } - switch (_drawMode) - { - case MODE_DRAG_POINT: - drawDragLines(inG, _selection.getCurrentPointIndex()-1, _selection.getCurrentPointIndex()+1); - break; + switch (_drawMode) + { + case MODE_DRAG_POINT: + drawDragLines(inG, _selection.getCurrentPointIndex()-1, _selection.getCurrentPointIndex()+1); + break; - case MODE_CREATE_MIDPOINT: - drawDragLines(inG, _clickedPoint-1, _clickedPoint); - break; + case MODE_CREATE_MIDPOINT: + drawDragLines(inG, _clickedPoint-1, _clickedPoint); + break; - case MODE_ZOOM_RECT: - case MODE_MARK_RECTANGLE: - if (_dragFromX != -1 && _dragFromY != -1) - { - // Draw the zoom rectangle if necessary - inG.setColor(Color.RED); - inG.drawLine(_dragFromX, _dragFromY, _dragFromX, _dragToY); - inG.drawLine(_dragFromX, _dragFromY, _dragToX, _dragFromY); - inG.drawLine(_dragToX, _dragFromY, _dragToX, _dragToY); - inG.drawLine(_dragFromX, _dragToY, _dragToX, _dragToY); - } - break; - - case MODE_DRAW_POINTS_CONT: - // draw line to mouse position to show drawing mode - inG.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_POINT)); - int prevIndex = _track.getNumPoints()-1; - int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(prevIndex)); - int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(prevIndex)); - inG.drawLine(px, py, _dragToX, _dragToY); - break; - } - } - else - { - inG.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_BACKGROUND)); - inG.fillRect(0, 0, getWidth(), getHeight()); - inG.setColor(COLOR_MESSAGES); - inG.drawString(I18nManager.getText("display.nodata"), 50, getHeight()/2); - _scaleBar.updateScale(-1, 0); + case MODE_ZOOM_RECT: + case MODE_MARK_RECTANGLE: + if (_dragFromX != -1 && _dragFromY != -1) + { + // Draw the zoom rectangle if necessary + inG.setColor(Color.RED); + inG.drawLine(_dragFromX, _dragFromY, _dragFromX, _dragToY); + inG.drawLine(_dragFromX, _dragFromY, _dragToX, _dragFromY); + inG.drawLine(_dragToX, _dragFromY, _dragToX, _dragToY); + inG.drawLine(_dragFromX, _dragToY, _dragToX, _dragToY); + } + break; + + case MODE_DRAW_POINTS_CONT: + // draw line to mouse position to show drawing mode + inG.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_POINT)); + int prevIndex = _track.getNumPoints()-1; + int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(prevIndex)); + int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(prevIndex)); + inG.drawLine(px, py, _dragToX, _dragToY); + break; } // Draw slider etc on top paintChildren(inG); @@ -1074,66 +1066,63 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe */ public void mouseClicked(MouseEvent inE) { - if (_track != null && _track.getNumPoints() > 0) + // select point if it's a left-click + if (!inE.isMetaDown()) { - // select point if it's a left-click - if (!inE.isMetaDown()) + if (inE.getClickCount() == 1) { - if (inE.getClickCount() == 1) + // single click + if (_drawMode == MODE_DEFAULT) { - // single click - if (_drawMode == MODE_DEFAULT) + int pointIndex = _clickedPoint; + if (pointIndex == INDEX_UNKNOWN) { - 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); - } + // index hasn't been calculated yet + pointIndex = _track.getNearestPointIndex( + _mapPosition.getXFromPixels(inE.getX(), getWidth()), + _mapPosition.getYFromPixels(inE.getY(), getHeight()), + _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY), false); } - 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; + // Extend selection for shift-click + if (inE.isShiftDown()) { + _trackInfo.extendSelection(pointIndex); } - else if (_drawMode == MODE_DRAW_POINTS_CONT) - { - DataPoint point = createPointFromClick(inE.getX(), inE.getY()); - _app.createPoint(point, false); // not a new segment + else { + _trackInfo.selectPoint(pointIndex); } } - else if (inE.getClickCount() == 2) + else if (_drawMode == MODE_DRAW_POINTS_START) { - // 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; - } + _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, false); // not a new segment } } - else + else if (inE.getClickCount() == 2) { - // show the popup menu for right-clicks - _popupMenuX = inE.getX(); - _popupMenuY = inE.getY(); - _popup.show(this, _popupMenuX, _popupMenuY); + // 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; @@ -1408,10 +1397,6 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe } } repaint(); - // enable or disable components - boolean hasData = _track.getNumPoints() > 0; - _topPanel.setVisible(hasData); - _sidePanel.setVisible(hasData); // grab focus for the key presses this.requestFocus(); } diff --git a/src/tim/prune/gui/map/MapPosition.java b/src/tim/prune/gui/map/MapPosition.java index 25f05fc..71ab6cd 100644 --- a/src/tim/prune/gui/map/MapPosition.java +++ b/src/tim/prune/gui/map/MapPosition.java @@ -30,14 +30,14 @@ public class MapPosition * @param inWidth width of display * @param inHeight height of display */ - public void zoomToXY(double inMinX, double inMaxX, double inMinY, double inMaxY, int inWidth, int inHeight) + public void zoomToXY(double inMinX, double inMaxX, double inMinY, double inMaxY, int inWidth, int inHeight, int maxZoom) { // System.out.println("Zooming to " + inMinX + ", " + inMaxX + ", " + inMinY + ", " + inMaxY + "; width=" + inWidth + ", height=" + inHeight); double diffX = Math.abs(inMaxX - inMinX); double diffY = Math.abs(inMaxY - inMinY); // Find out what zoom level to go to int requiredZoom = -1; - for (int currZoom = MAX_ZOOM; currZoom >= 2; currZoom--) + for (int currZoom = maxZoom; currZoom >= 2; currZoom--) { if (transformToPixels(diffX, currZoom) < inWidth && transformToPixels(diffY, currZoom) < inHeight) diff --git a/src/tim/prune/gui/map/MapSource.java b/src/tim/prune/gui/map/MapSource.java index c4e2946..177ad67 100644 --- a/src/tim/prune/gui/map/MapSource.java +++ b/src/tim/prune/gui/map/MapSource.java @@ -104,7 +104,7 @@ public abstract class MapSource urlstr = "http://" + urlstr; } // check trailing / - if (!urlstr.endsWith("/")) { + if (!urlstr.endsWith("/") && !urlstr.contains("?")) { urlstr = urlstr + "/"; } // Validate current url, return null if not ok diff --git a/src/tim/prune/gui/map/MapTileManager.java b/src/tim/prune/gui/map/MapTileManager.java index f7370c5..d1e0047 100644 --- a/src/tim/prune/gui/map/MapTileManager.java +++ b/src/tim/prune/gui/map/MapTileManager.java @@ -70,10 +70,19 @@ public class MapTileManager implements ImageObserver * @return true if zoom is too high for tiles */ public boolean isOverzoomed() + { + return _zoom > getMaxZoomLevel(); + } + + /** + * @return the maximum useable zoom level for tiles + */ + public int getMaxZoomLevel() { // Ask current map source what maximum zoom is int maxZoom = (_mapSource == null?0:_mapSource.getMaxZoomLevel()); - return (_zoom > maxZoom); + return maxZoom; + } /** diff --git a/src/tim/prune/gui/map/OsmMapSource.java b/src/tim/prune/gui/map/OsmMapSource.java index 925fcf6..e3fe589 100644 --- a/src/tim/prune/gui/map/OsmMapSource.java +++ b/src/tim/prune/gui/map/OsmMapSource.java @@ -152,12 +152,31 @@ public class OsmMapSource extends MapSource /** * Make the URL to get the specified tile + * @param inLayerNum layer number + * @param inZoom zoom level + * @param inX x coordinate + * @param inY y coordinate + * @return relative file path as String */ public String makeURL(int inLayerNum, int inZoom, int inX, int inY) { // Check if the base url has a [1234], if so replace at random - StringBuffer url = new StringBuffer(); - url.append(pickServerUrl(_baseUrls[inLayerNum])); + String baseUrl = pickServerUrl(_baseUrls[inLayerNum]); + return makeUrl(baseUrl, inLayerNum, inZoom, inX, inY); + } + + public String makeUrl(String baseUrl, int inLayerNum, int inZoom, int inX, int inY) + { + // If the base URL has {x}/{y} placeholders, use them + if (baseUrl.contains("{x}")) { + baseUrl = baseUrl.replace("{z}", Integer.toString(inZoom)) + .replace("{x}", Integer.toString(inX)) + .replace("{y}", Integer.toString(inY)); + return baseUrl; + } + + // Else simply append the tile indices and file extension + StringBuffer url = new StringBuffer(baseUrl); url.append(inZoom).append('/').append(inX).append('/').append(inY); url.append('.').append(getFileExtension(inLayerNum)); if (_apiKey != null) @@ -167,6 +186,26 @@ public class OsmMapSource extends MapSource return url.toString(); } + /** + * Make a relative file path from the base directory including site name + * @param inLayerNum layer number + * @param inZoom zoom level + * @param inX x coordinate + * @param inY y coordinate + * @return relative file path as String + */ + public String makeFilePath(int inLayerNum, int inZoom, int inX, int inY) + { + String siteName = getSiteName(inLayerNum); + String filePath = makeUrl(siteName, inLayerNum, inZoom, inX, inY); + int indexParam = filePath.indexOf("?"); + if (indexParam > 0) + { + filePath = filePath.substring(0, indexParam); + } + return filePath; + } + /** * @return maximum zoom level */ diff --git a/src/tim/prune/lang/prune-texts_en.properties b/src/tim/prune/lang/prune-texts_en.properties index 736c145..82219b2 100644 --- a/src/tim/prune/lang/prune-texts_en.properties +++ b/src/tim/prune/lang/prune-texts_en.properties @@ -94,6 +94,7 @@ function.interpolate=Interpolate points function.deletebydate=Delete points by date function.addtimeoffset=Add time offset function.addaltitudeoffset=Add altitude offset +function.removealtitudes=Remove altitudes function.findwaypoint=Find waypoint function.rearrangewaypoints=Rearrange waypoints function.convertnamestotimes=Convert waypoint names to times @@ -641,6 +642,7 @@ confirm.mergetracksegments=Track segments merged confirm.reverserange=Range reversed confirm.addtimeoffset=Time offset added confirm.addaltitudeoffset=Altitude offset added +confirm.removealtitudes=Altitudes removed confirm.rearrangewaypoints=Waypoints rearranged confirm.rearrangephotos=Photos rearranged confirm.splitsegments=%d segment splits were made @@ -861,6 +863,7 @@ undo.splitsegments=split track segments undo.sewsegments=sew track segments undo.addtimeoffset=add time offset undo.addaltitudeoffset=add altitude offset +undo.removealtitudes=remove altitudes undo.rearrangewaypoints=rearrange waypoints undo.cutandmove=move section undo.connect=connect diff --git a/src/tim/prune/undo/UndoRemoveAltitudes.java b/src/tim/prune/undo/UndoRemoveAltitudes.java new file mode 100644 index 0000000..becf2d7 --- /dev/null +++ b/src/tim/prune/undo/UndoRemoveAltitudes.java @@ -0,0 +1,65 @@ +package tim.prune.undo; + +import tim.prune.I18nManager; +import tim.prune.UpdateMessageBroker; +import tim.prune.data.Altitude; +import tim.prune.data.DataPoint; +import tim.prune.data.TrackInfo; + +/** + * Undo removing (ie: restore the original) altitude from points + */ +public class UndoRemoveAltitudes implements UndoOperation +{ + /** Start index of section */ + private int _startIndex; + /** altitude values before operation */ + private Altitude[] _altitudes; + + + /** + * Constructor + * @param inTrackInfo track info object + */ + public UndoRemoveAltitudes(TrackInfo inTrackInfo, int inStart, int inEnd) + { + _startIndex = inStart; + final int numPoints = inEnd - inStart + 1; + // Make array of cloned altitude objects + _altitudes = new Altitude[numPoints]; + for (int i=0; i