From: Frédéric Perrin Date: Tue, 20 Oct 2020 19:25:42 +0000 (+0100) Subject: Merge remote-tracking branch 'upstream/master' into fp-integration X-Git-Tag: v20.0.fp1~1 X-Git-Url: https://gitweb.fperrin.net/?a=commitdiff_plain;h=9b2386d166007f68fefcaba8c27a1eefcd67af8b;hp=-c;p=GpsPrune.git Merge remote-tracking branch 'upstream/master' into fp-integration --- 9b2386d166007f68fefcaba8c27a1eefcd67af8b diff --combined buildtools/build.sh index d2311b5,193244b..ee29ad8 mode 100755,100644..100755 --- a/buildtools/build.sh +++ b/buildtools/build.sh @@@ -1,7 -1,7 +1,8 @@@ +set -e # Build script + set -e # Version number - PRUNENAME=gpsprune_19.2 + PRUNENAME=gpsprune_20 # remove compile directory rm -rf compile # remove dist directory @@@ -17,8 -17,6 +18,8 @@@ cp -r src/tim/prune/lang compile/tim/pr cp -r src/tim/prune/*.txt compile/tim/prune/ cp -r src/tim/prune/gui/images compile/tim/prune/gui/ cp src/tim/prune/function/srtm/srtmtiles.dat compile/tim/prune/function/srtm +mkdir compile/tim/prune/function/srtm/viewfinder/ +cp src/tim/prune/function/srtm/viewfinder/tiles.dat compile/tim/prune/function/srtm/viewfinder/ # make dist directory mkdir dist # build into jar file diff --combined pom.xml index f3a608c,15b6562..2cb4193 --- a/pom.xml +++ b/pom.xml @@@ -7,7 -7,7 +7,7 @@@ tim.prune gpsprune - 19.2 + 20 jar tim.prune.gpsprune @@@ -57,7 -57,6 +57,7 @@@ tim/prune/gui/images/* tim/prune/lang/* tim/prune/function/srtm/srtmtiles.dat + tim/prune/function/srtm/viewfinder/tiles.dat tim/prune/*.txt @@@ -79,11 -78,6 +79,11 @@@ maven-compiler-plugin 3.8.0 + + + -Xlint:deprecation + + maven-jar-plugin diff --combined src/tim/prune/App.java index 317064d,94e10e0..f76edb1 --- a/src/tim/prune/App.java +++ b/src/tim/prune/App.java @@@ -51,7 -51,6 +51,7 @@@ public class Ap { // Instance variables private JFrame _frame = null; + private String _titlePrefix = null; private Track _track = null; private TrackInfo _trackInfo = null; private int _lastSavePosition = 0; @@@ -70,7 -69,7 +70,7 @@@ private AppMode _appMode = AppMode.NORMAL; /** Enum for the app mode - currently only two options but may expand later */ - public enum AppMode {NORMAL, DRAWRECT}; + public enum AppMode {NORMAL, DRAWRECT} /** @@@ -80,7 -79,6 +80,7 @@@ public App(JFrame inFrame) { _frame = inFrame; + _titlePrefix = _frame.getTitle(); _undoStack = new UndoStack(); _track = new Track(); _trackInfo = new TrackInfo(_track); @@@ -456,22 -454,6 +456,22 @@@ } + /** + * 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 */ @@@ -667,7 -649,8 +667,8 @@@ loadedTrack.load(inFieldArray, inDataArray, inOptions); if (loadedTrack.getNumPoints() <= 0) { - showErrorMessage("error.load.dialogtitle", "error.load.nopoints"); + String msgKey = (inSourceInfo == null ? "error.load.nopointsintext" : "error.load.nopoints"); + showErrorMessage("error.load.dialogtitle", msgKey); // load next file if there's a queue loadNextFile(); return; @@@ -733,9 -716,12 +734,12 @@@ undo.setNumPhotosAudios(_trackInfo.getPhotoList().getNumPhotos(), _trackInfo.getAudioList().getNumAudios()); _undoStack.add(undo); _track.combine(inLoadedTrack); - // set source information - inSourceInfo.populatePointObjects(_track, inLoadedTrack.getNumPoints()); - _trackInfo.getFileInfo().addSource(inSourceInfo); + if (inSourceInfo != null) + { + // set source information + inSourceInfo.populatePointObjects(_track, inLoadedTrack.getNumPoints()); + _trackInfo.getFileInfo().addSource(inSourceInfo); + } } else if (answer == JOptionPane.NO_OPTION) { @@@ -750,8 -736,12 +754,12 @@@ _lastSavePosition = _undoStack.size(); _trackInfo.getSelection().clearAll(); _track.load(inLoadedTrack); - inSourceInfo.populatePointObjects(_track, _track.getNumPoints()); - _trackInfo.getFileInfo().replaceSource(inSourceInfo); + if (inSourceInfo != null) + { + // set source information + inSourceInfo.populatePointObjects(_track, _track.getNumPoints()); + _trackInfo.getFileInfo().replaceSource(inSourceInfo); + } _trackInfo.getPhotoList().removeCorrelatedPhotos(); _trackInfo.getAudioList().removeCorrelatedAudios(); } @@@ -765,22 -755,24 +773,28 @@@ _lastSavePosition = _undoStack.size(); _trackInfo.getSelection().clearAll(); _track.load(inLoadedTrack); - inSourceInfo.populatePointObjects(_track, _track.getNumPoints()); - _trackInfo.getFileInfo().addSource(inSourceInfo); + if (inSourceInfo != null) + { + inSourceInfo.populatePointObjects(_track, _track.getNumPoints()); + _trackInfo.getFileInfo().addSource(inSourceInfo); + } } // Update config before subscribers are told - boolean isRegularLoad = (inSourceInfo.getFileType() != FILE_TYPE.GPSBABEL); - Config.getRecentFileList().addFile(new RecentFile(inSourceInfo.getFile(), isRegularLoad)); + if (inSourceInfo != null) + { + boolean isRegularLoad = (inSourceInfo.getFileType() != FILE_TYPE.GPSBABEL); + Config.getRecentFileList().addFile(new RecentFile(inSourceInfo.getFile(), isRegularLoad)); + // Update status bar + UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile") + + " '" + inSourceInfo.getName() + "'"); + } UpdateMessageBroker.informSubscribers(); - // Update status bar - UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile") - + " '" + 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 @@@ -1023,16 -1015,4 +1037,16 @@@ 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 --combined src/tim/prune/FunctionLibrary.java index 4be286e,68303ed..58d049d --- a/src/tim/prune/FunctionLibrary.java +++ b/src/tim/prune/FunctionLibrary.java @@@ -18,17 -18,16 +18,17 @@@ import tim.prune.function.DiskCacheConf import tim.prune.function.DownloadOsmFunction; import tim.prune.function.DuplicatePoint; import tim.prune.function.FindWaypoint; - import tim.prune.function.FullRangeDetails; + import tim.prune.function.ProjectPoint; + import tim.prune.function.ShowFullDetails; import tim.prune.function.GetWikipediaFunction; import tim.prune.function.HelpScreen; import tim.prune.function.IgnoreExifThumb; import tim.prune.function.InterpolateFunction; - import tim.prune.function.PasteCoordinates; 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; @@@ -51,18 -50,16 +51,16 @@@ import tim.prune.function.distance.Dist import tim.prune.function.edit.PointNameEditor; import tim.prune.function.estimate.EstimateTime; import tim.prune.function.estimate.LearnParameters; - import tim.prune.function.gpsies.GetGpsiesFunction; - import tim.prune.function.gpsies.UploadGpsiesFunction; import tim.prune.function.settings.SaveConfig; import tim.prune.function.settings.SetAltitudeTolerance; import tim.prune.function.settings.SetColours; import tim.prune.function.settings.SetDisplaySettings; +import tim.prune.function.settings.SetEarthdataAuthentication; import tim.prune.function.settings.SetLanguage; import tim.prune.function.settings.SetMapBgFunction; import tim.prune.function.settings.SetPathsFunction; import tim.prune.function.sew.SewTrackSegmentsFunction; import tim.prune.function.sew.SplitSegmentsFunction; -import tim.prune.function.srtm.DownloadSrtmFunction; import tim.prune.function.srtm.LookupSrtmFunction; import tim.prune.function.weather.GetWeatherForecastFunction; import tim.prune.load.AudioLoader; @@@ -89,6 -86,7 +87,7 @@@ public abstract class FunctionLibrar public static GenericFunction FUNCTION_IMPORTBABEL = null; public static GenericFunction FUNCTION_SAVECONFIG = null; public static GenericFunction FUNCTION_EDIT_WAYPOINT_NAME = null; + public static GenericFunction FUNCTION_PROJECT_POINT = null; public static GenericFunction FUNCTION_REARRANGE_WAYPOINTS = null; public static GenericFunction FUNCTION_SELECT_SEGMENT = null; public static GenericFunction FUNCTION_SPLIT_SEGMENTS = null; @@@ -104,16 -102,15 +103,15 @@@ public static GenericFunction FUNCTION_DELETE_BY_DATE = null; public static SingleNumericParameterFunction FUNCTION_INTERPOLATE = null; public static GenericFunction FUNCTION_LOOKUP_SRTM = null; - public static GenericFunction FUNCTION_DOWNLOAD_SRTM = null; public static GenericFunction FUNCTION_NEARBY_WIKIPEDIA = null; public static GenericFunction FUNCTION_SEARCH_WIKIPEDIA = null; public static GenericFunction FUNCTION_SEARCH_OSMPOIS = null; 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; public static GenericFunction FUNCTION_FIND_WAYPOINT = null; public static GenericFunction FUNCTION_DUPLICATE_POINT = null; public static GenericFunction FUNCTION_CONNECT_TO_POINT = null; @@@ -128,12 -125,10 +126,10 @@@ public static GenericFunction FUNCTION_CHARTS = null; public static GenericFunction FUNCTION_3D = null; public static GenericFunction FUNCTION_DISTANCES = null; - public static GenericFunction FUNCTION_FULL_RANGE_DETAILS = null; + public static GenericFunction FUNCTION_FULL_DETAILS = null; public static GenericFunction FUNCTION_AUTOPLAY_TRACK = null; public static GenericFunction FUNCTION_ESTIMATE_TIME = null; public static GenericFunction FUNCTION_LEARN_ESTIMATION_PARAMS = null; - public static GenericFunction FUNCTION_GET_GPSIES = null; - public static GenericFunction FUNCTION_UPLOAD_GPSIES = null; public static GenericFunction FUNCTION_GET_WEATHER_FORECAST = null; public static GenericFunction FUNCTION_LOAD_AUDIO = null; public static GenericFunction FUNCTION_REMOVE_AUDIO = null; @@@ -147,7 -142,6 +143,7 @@@ public static GenericFunction FUNCTION_SET_COLOURS = null; public static GenericFunction FUNCTION_SET_LANGUAGE = null; public static SingleNumericParameterFunction FUNCTION_SET_ALTITUDE_TOLERANCE = null; + public static GenericFunction FUNCTION_SET_EARTHDATA_AUTH = null; public static GenericFunction FUNCTION_SET_TIMEZONE = null; public static GenericFunction FUNCTION_HELP = null; public static GenericFunction FUNCTION_SHOW_KEYS = null; @@@ -170,6 -164,7 +166,7 @@@ FUNCTION_IMPORTBABEL = new BabelLoadFromFile(inApp); FUNCTION_SAVECONFIG = new SaveConfig(inApp); FUNCTION_EDIT_WAYPOINT_NAME = new PointNameEditor(inApp); + FUNCTION_PROJECT_POINT = new ProjectPoint(inApp); FUNCTION_REARRANGE_WAYPOINTS = new RearrangeWaypointsFunction(inApp); FUNCTION_SELECT_SEGMENT = new SelectSegmentFunction(inApp); FUNCTION_SPLIT_SEGMENTS = new SplitSegmentsFunction(inApp); @@@ -185,16 -180,15 +182,15 @@@ FUNCTION_DELETE_BY_DATE = new DeleteByDateFunction(inApp); FUNCTION_INTERPOLATE = new InterpolateFunction(inApp); FUNCTION_LOOKUP_SRTM = new LookupSrtmFunction(inApp); - FUNCTION_DOWNLOAD_SRTM = new DownloadSrtmFunction(inApp); FUNCTION_NEARBY_WIKIPEDIA = new GetWikipediaFunction(inApp); FUNCTION_SEARCH_WIKIPEDIA = new SearchWikipediaNames(inApp); FUNCTION_SEARCH_OSMPOIS = new SearchOsmPoisFunction(inApp); 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); FUNCTION_FIND_WAYPOINT = new FindWaypoint(inApp); FUNCTION_DUPLICATE_POINT = new DuplicatePoint(inApp); FUNCTION_CONNECT_TO_POINT = new ConnectToPointFunction(inApp); @@@ -208,12 -202,10 +204,10 @@@ FUNCTION_CHARTS = new Charter(inApp); FUNCTION_3D = new ShowThreeDFunction(inApp); FUNCTION_DISTANCES = new DistanceFunction(inApp); - FUNCTION_FULL_RANGE_DETAILS = new FullRangeDetails(inApp); + FUNCTION_FULL_DETAILS = new ShowFullDetails(inApp); FUNCTION_AUTOPLAY_TRACK = new AutoplayFunction(inApp); FUNCTION_ESTIMATE_TIME = new EstimateTime(inApp); FUNCTION_LEARN_ESTIMATION_PARAMS = new LearnParameters(inApp); - FUNCTION_GET_GPSIES = new GetGpsiesFunction(inApp); - FUNCTION_UPLOAD_GPSIES = new UploadGpsiesFunction(inApp); FUNCTION_GET_WEATHER_FORECAST = new GetWeatherForecastFunction(inApp); FUNCTION_LOAD_AUDIO = new AudioLoader(inApp); FUNCTION_REMOVE_AUDIO = new RemoveAudioFunction(inApp); @@@ -229,7 -221,6 +223,7 @@@ FUNCTION_SET_LANGUAGE = new SetLanguage(inApp); FUNCTION_SET_ALTITUDE_TOLERANCE = new SetAltitudeTolerance(inApp); FUNCTION_SET_TIMEZONE = new SelectTimezoneFunction(inApp); + FUNCTION_SET_EARTHDATA_AUTH = new SetEarthdataAuthentication(inApp); FUNCTION_HELP = new HelpScreen(inApp); FUNCTION_SHOW_KEYS = new ShowKeysScreen(inApp); FUNCTION_ABOUT = new AboutScreen(inApp); diff --combined src/tim/prune/GpsPrune.java index a9b53f4,874ece5..f2bb7bd --- a/src/tim/prune/GpsPrune.java +++ b/src/tim/prune/GpsPrune.java @@@ -9,9 -9,11 +9,11 @@@ import java.io.File import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Locale; + import javax.swing.JFrame; import javax.swing.JSplitPane; import javax.swing.JToolBar; + import javax.swing.UIManager; import javax.swing.WindowConstants; import tim.prune.config.Config; @@@ -29,16 -31,16 +31,16 @@@ import tim.prune.gui.profile.ProfileCha /** * GpsPrune is a tool to visualize, edit, convert and prune GPS data * Please see the included readme.txt or https://activityworkshop.net - * This software is copyright activityworkshop.net 2006-2018 and made available through the Gnu GPL version 2. + * This software is copyright activityworkshop.net 2006-2020 and made available through the Gnu GPL version 2. * For license details please see the included license.txt. * GpsPrune is the main entry point to the application, including initialisation and launch */ public class GpsPrune { /** Version number of application, used in about screen and for version check */ - public static final String VERSION_NUMBER = "19.2"; + public static final String VERSION_NUMBER = "20"; /** Build number, just used for about screen */ - public static final String BUILD_NUMBER = "363d"; + public static final String BUILD_NUMBER = "378"; /** Static reference to App object */ private static App APP = null; @@@ -149,6 -151,14 +151,14 @@@ Config.setConfigString(Config.KEY_LANGUAGE_FILE, ""); } } + + // Set look-and-feel + try { + String windowStyle = Config.getConfigString(Config.KEY_WINDOW_STYLE); + UIManager.setLookAndFeel(windowStyle); + } + catch (Exception e) {} + // Set up the window and go launch(dataFiles); } @@@ -262,6 -272,8 +272,6 @@@ frame.setVisible(true); // Set position of map/profile splitter midSplit.setDividerLocation(0.75); - // Update menu (only needed for recent file list) - UpdateMessageBroker.informSubscribers(); // Make a full screen toggler SidebarController fsc = new SidebarController(new Component[] {leftPanel, profileDisp, rightPanel}, diff --combined src/tim/prune/config/Config.java index 3939c00,8c6eefe..35923d7 --- a/src/tim/prune/config/Config.java +++ b/src/tim/prune/config/Config.java @@@ -55,6 -55,8 +55,8 @@@ public abstract class Confi public static final String KEY_POVRAY_FONT = "prune.povrayfont"; /** Key for the selected unit set */ public static final String KEY_UNITSET_KEY = "prune.unitsetkey"; + /** Key for the selected coordinate display format */ + public static final String KEY_COORD_DISPLAY_FORMAT = "prune.coorddisplay"; /** Key for index of map source */ public static final String KEY_MAPSOURCE_INDEX = "prune.mapsource"; /** Key for number of fixed map sources */ @@@ -87,6 -89,8 +89,8 @@@ public static final String KEY_ANTIALIAS = "prune.antialias"; /** Key for kml track colour */ public static final String KEY_KML_TRACK_COLOUR = "prune.kmltrackcolour"; + /** Key for window style (name of look-and-feel) */ + public static final String KEY_WINDOW_STYLE = "prune.windowstyle"; /** Key for autosaving settings */ public static final String KEY_AUTOSAVE_SETTINGS = "prune.autosavesettings"; /** Key for recently used files */ @@@ -105,8 -109,6 +109,8 @@@ public static final String KEY_WAYPOINT_ICON_SIZE = "prune.waypointiconsize"; /** Id of selected timezone */ public static final String KEY_TIMEZONE_ID = "prune.timezoneid"; + /** Username/password to the Earthdata server for SRTM 1-arcsecond tiles */ + public static final String KEY_EARTHDATA_AUTH = "prune.earthdataauth"; /** Initialise the default properties */ @@@ -172,6 -174,8 +176,8 @@@ _unitSet = UnitSetLibrary.getUnitSet(_configValues.getProperty(KEY_UNITSET_KEY)); // Adjust map source index if necessary adjustSelectedMap(); + // Reset coord display format + setConfigInt(KEY_COORD_DISPLAY_FORMAT, 0); if (loadFailed) { throw new ConfigException(); @@@ -199,6 -203,7 +205,7 @@@ props.put(KEY_ANTIALIAS, "1"); // antialias on by default props.put(KEY_AUTOSAVE_SETTINGS, "0"); // autosave false by default props.put(KEY_UNITSET_KEY, "unitset.kilometres"); // metric by default + props.put(KEY_COORD_DISPLAY_FORMAT, "0"); // original props.put(KEY_HEIGHT_EXAGGERATION, "100"); // 100%, no exaggeration props.put(KEY_TERRAIN_GRID_SIZE, "50"); props.put(KEY_ALTITUDE_TOLERANCE, "0"); // 0, all exact as before @@@ -248,6 -253,14 +255,14 @@@ return _configFile; } + /** + * Set the file to which config was saved + */ + public static void setConfigFile(File inFile) + { + _configFile = inFile; + } + /** * @return config Properties object to allow all config values to be saved */ @@@ -381,7 -394,7 +396,7 @@@ public static void updatePointColourer(PointColourer inColourer) { _pointColourer = inColourer; - setConfigString(KEY_POINT_COLOURER, ColourerFactory.PointColourerToString(_pointColourer)); + setConfigString(KEY_POINT_COLOURER, ColourerFactory.pointColourerToString(_pointColourer)); } /** diff --combined src/tim/prune/data/FileInfo.java index 7eaac8f,0c4ee5f..6ca812e --- a/src/tim/prune/data/FileInfo.java +++ b/src/tim/prune/data/FileInfo.java @@@ -51,7 -51,9 +51,9 @@@ public class FileInf */ public void removeSource() { - _sources.remove(_sources.size()-1); + if (!_sources.isEmpty()) { + _sources.remove(_sources.size()-1); + } } /** @@@ -74,19 -76,6 +76,19 @@@ 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 --combined src/tim/prune/function/AddTimeOffset.java index 199ae50,115bfa5..ed75a5e --- a/src/tim/prune/function/AddTimeOffset.java +++ b/src/tim/prune/function/AddTimeOffset.java @@@ -33,8 -33,8 +33,8 @@@ public class AddTimeOffset extends Gene { private JDialog _dialog = null; private JRadioButton _addRadio = null, _subtractRadio = null; - private WholeNumberField _dayField = null, _hourField = null; - private WholeNumberField _minuteField = null; + private WholeNumberField _1024weekField = null, _dayField = null; + private WholeNumberField _hourField = null, _minuteField = null; private JButton _okButton = null; @@@ -103,11 -103,8 +103,11 @@@ // Make a central panel with the text boxes JPanel descPanel = new JPanel(); descPanel.setLayout(new GridLayout(0, 2)); + descPanel.add(makeRightLabel("dialog.addtimeoffset.1024week")); + _1024weekField = new WholeNumberField(3); + descPanel.add(_1024weekField); descPanel.add(makeRightLabel("dialog.addtimeoffset.days")); - _dayField = new WholeNumberField(3); + _dayField = new WholeNumberField(4); descPanel.add(_dayField); descPanel.add(makeRightLabel("dialog.addtimeoffset.hours")); _hourField = new WholeNumberField(3); @@@ -129,13 -126,11 +129,13 @@@ MouseAdapter mouseListener = new MouseAdapter() { public void mouseReleased(java.awt.event.MouseEvent arg0) { _okButton.setEnabled(getOffsetSecs() != 0L); - }; + } }; + _1024weekField.addKeyListener(keyListener); _dayField.addKeyListener(keyListener); _hourField.addKeyListener(keyListener); _minuteField.addKeyListener(keyListener); + _1024weekField.addMouseListener(mouseListener); _dayField.addMouseListener(mouseListener); _hourField.addMouseListener(mouseListener); _minuteField.addMouseListener(mouseListener); @@@ -185,8 -180,7 +185,8 @@@ { long offsetSecs = _minuteField.getValue() * 60L + _hourField.getValue() * 60L * 60L - + _dayField.getValue() * 60L * 60L * 24L; + + _dayField.getValue() * 60L * 60L * 24L + + _1024weekField.getValue() * 60L * 60L * 24L * 7L * 1024L; if (_subtractRadio.isSelected()) {offsetSecs = -offsetSecs;} return offsetSecs; } diff --combined src/tim/prune/function/srtm/LookupSrtmFunction.java index 947cca9,c48af01..8f4dc2e --- a/src/tim/prune/function/srtm/LookupSrtmFunction.java +++ b/src/tim/prune/function/srtm/LookupSrtmFunction.java @@@ -1,6 -1,12 +1,6 @@@ package tim.prune.function.srtm; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.net.URL; import java.util.ArrayList; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; import javax.swing.JOptionPane; @@@ -9,12 -15,14 +9,12 @@@ import tim.prune.DataSubscriber import tim.prune.GenericFunction; import tim.prune.I18nManager; import tim.prune.UpdateMessageBroker; -import tim.prune.config.Config; import tim.prune.data.Altitude; import tim.prune.data.DataPoint; import tim.prune.data.Field; import tim.prune.data.Track; import tim.prune.data.UnitSetLibrary; import tim.prune.gui.ProgressDialog; -import tim.prune.tips.TipManager; import tim.prune.undo.UndoLookupSrtm; /** @@@ -30,9 -38,13 +30,9 @@@ public class LookupSrtmFunction extend private Track _track = null; /** Flag for whether this is a real track or a terrain one */ private boolean _normalTrack = true; - /** Flag set when any tiles had to be downloaded (rather than just loaded locally) */ - private boolean _hadToDownload = false; /** Flag to check whether this function is currently running or not */ private boolean _running = false; - /** Expected size of hgt file in bytes */ - private static final long HGT_SIZE = 2884802L; /** Altitude below which is considered void */ private static final int VOID_VAL = -32768; @@@ -72,10 -84,7 +72,10 @@@ private void begin(Track inTrack, boolean inNormalTrack) { _running = true; - _hadToDownload = false; + if (! SrtmDiskCache.ensureCacheIsUsable()) + { + _app.showErrorMessage(getNameKey(), "error.cache.notthere"); + } if (_progress == null) { _progress = new ProgressDialog(_parentFrame, getNameKey()); } @@@ -122,7 -131,8 +122,7 @@@ for (int i = 0; i < _track.getNumPoints(); i++) { // Consider points which don't have altitudes or have zero values - if (!_track.getPoint(i).hasAltitude() - || (overwriteZeros && _track.getPoint(i).getAltitude().getValue() == 0)) + if (needsAltitude(_track.getPoint(i), overwriteZeros)) { SrtmTile tile = new SrtmTile(_track.getPoint(i)); boolean alreadyGot = false; @@@ -138,23 -148,12 +138,23 @@@ lookupValues(tileList, overwriteZeros); // Finished _running = false; - // Show tip if lots of online lookups were necessary - if (_hadToDownload) { - _app.showTip(TipManager.Tip_DownloadSrtm); - } } + /** + * true if we need to set the altitude of this point + */ + private boolean needsAltitude(DataPoint point, boolean overwriteZeros) + { + if (!point.hasAltitude()) + { + return true; + } + if (overwriteZeros && point.getAltitude().getValue() == 0) + { + return true; + } + return false; + } /** * Lookup the values from SRTM data @@@ -171,81 -170,52 +171,38 @@@ _progress.setMaximum(inTileList.size()); _progress.setValue(0); } - String errorMessage = null; - // Get urls for each tile - URL[] urls = TileFinder.getUrls(inTileList); - for (int t=0; t= 32768) {heights[i] -= 65536;} - } - } - // else { - // System.out.println("length not ok: " + entry.getSize()); - // } - // Close stream from url - inStream.close(); - } + errorMessage += "Tile "+tile.getTileName()+" not in cache!\n"; + continue; + } - if (entryOk) - { - numAltitudesFound += applySrtmTileToWholeTrack(tile, heights, inOverwriteZeros); - } - } - catch (IOException ioe) { - errorMessage = ioe.getClass().getName() + " - " + ioe.getMessage(); - } + // Set progress + _progress.setValue(t); + + int[] heights; + try { + heights = srtmSource.getTileHeights(tile); + } + catch (SrtmSourceException e) + { + errorMessage += e.getMessage(); + e.printStackTrace(); + continue; } + int rowSize = srtmSource.getRowSize(tile); + if (rowSize <= 0) + { + errorMessage += "Tile "+tile.getTileName()+" is corrupted"; + } + - // Loop over all points in track, try to apply altitude from array - for (int p = 0; p < _track.getNumPoints(); p++) - { - DataPoint point = _track.getPoint(p); - if (needsAltitude(point, inOverwriteZeros)) - { - if (new SrtmTile(point).equals(tile)) - { - double x = (point.getLongitude().getDouble() - tile.getLongitude()) * (rowSize - 1); - double y = rowSize - (point.getLatitude().getDouble() - tile.getLatitude()) * (rowSize - 1); - int idx1 = ((int)y)*rowSize + (int)x; - try - { - int[] fouralts = {heights[idx1], heights[idx1+1], heights[idx1-rowSize], heights[idx1-rowSize+1]}; - int numVoids = (fouralts[0]==VOID_VAL?1:0) + (fouralts[1]==VOID_VAL?1:0) - + (fouralts[2]==VOID_VAL?1:0) + (fouralts[3]==VOID_VAL?1:0); - // if (numVoids > 0) System.out.println(numVoids + " voids found"); - double altitude = 0.0; - switch (numVoids) - { - case 0: altitude = bilinearInterpolate(fouralts, x, y); break; - case 1: altitude = bilinearInterpolate(fixVoid(fouralts), x, y); break; - case 2: - case 3: altitude = averageNonVoid(fouralts); break; - default: altitude = VOID_VAL; - } - // Special case for terrain tracks, don't interpolate voids yet - if (!_normalTrack && numVoids > 0) { - altitude = VOID_VAL; - } - if (altitude != VOID_VAL) - { - point.setFieldValue(Field.ALTITUDE, ""+altitude, false); - // depending on settings, this value may have been added as feet, we need to force metres - point.getAltitude().reset(new Altitude((int)altitude, UnitSetLibrary.UNITS_METRES)); - numAltitudesFound++; - } - } - catch (ArrayIndexOutOfBoundsException obe) { - errorMessage += "Point not in tile? lat=" + point.getLatitude().getDouble() + ", x=" + x + ", y=" + y + ", idx=" + idx1+"\n"; - } - } - } - } ++ numAltitudesFound += applySrtmTimeToWholeTrack(tile, heights, rowSize, inOverwriteZeros); } _progress.dispose(); @@@ -253,10 -223,6 +210,10 @@@ return; } + if (! errorMessage.equals("")) { + _app.showErrorMessageNoLookup(getNameKey(), errorMessage); + return; + } if (numAltitudesFound > 0) { // Inform app including undo information @@@ -269,6 -235,9 +226,6 @@@ I18nManager.getTextWithNumber("confirm.lookupsrtm", numAltitudesFound)); } } - else if (errorMessage != null) { - _app.showErrorMessageNoLookup(getNameKey(), errorMessage); - } else if (inTileList.size() > 0) { _app.showErrorMessage(getNameKey(), "error.lookupsrtm.nonefound"); } @@@ -277,6 -246,95 +234,64 @@@ } } - /** - * See whether the SRTM file is already available locally first, then try online - * @param inUrl URL for online resource - * @return ZipInputStream either on the local file or on the downloaded zip file - */ - private ZipInputStream getStreamToHgtFile(URL inUrl) - throws IOException - { - String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE); - if (diskCachePath != null) - { - File srtmDir = new File(diskCachePath, "srtm"); - if (srtmDir.exists() && srtmDir.isDirectory() && srtmDir.canRead()) - { - File srtmFile = new File(srtmDir, new File(inUrl.getFile()).getName()); - if (srtmFile.exists() && srtmFile.isFile() && srtmFile.canRead() - && srtmFile.length() > 400) - { - // System.out.println("Lookup: Using file " + srtmFile.getAbsolutePath()); - // File found, use this one - return new ZipInputStream(new FileInputStream(srtmFile)); - } - } - } - // System.out.println("Lookup: Trying online: " + inUrl.toString()); - _hadToDownload = true; - // MAYBE: Only download if we're in online mode? - return new ZipInputStream(inUrl.openStream()); - } - + /** + * Given the height data read in from file, apply the given tile to all points + * in the track with missing altitude + * @param inTile tile being applied + * @param inHeights height data read in from file + * @param inOverwriteZeros true to overwrite zero altitude values + * @return number of altitudes found + */ - private int applySrtmTileToWholeTrack(SrtmTile inTile, int[] inHeights, boolean inOverwriteZeros) ++ private int applySrtmTimeToWholeTrack(SrtmTile inTile, int[] inHeights, int inRowSize, boolean inOverwriteZeros) + { + int numAltitudesFound = 0; + // Loop over all points in track, try to apply altitude from array + for (int p = 0; p < _track.getNumPoints(); p++) + { + DataPoint point = _track.getPoint(p); - if (!point.hasAltitude() - || (inOverwriteZeros && point.getAltitude().getValue() == 0)) ++ if (needsAltitude(point, inOverwriteZeros)) + { + if (new SrtmTile(point).equals(inTile)) + { - double x = (point.getLongitude().getDouble() - inTile.getLongitude()) * 1200; - double y = 1201 - (point.getLatitude().getDouble() - inTile.getLatitude()) * 1200; - int idx1 = ((int)y)*1201 + (int)x; ++ double x = (point.getLongitude().getDouble() - inTile.getLongitude()) * (inRowSize - 1); ++ double y = inRowSize - (point.getLatitude().getDouble() - inTile.getLatitude()) * (inRowSize - 1); ++ int idx1 = ((int)y)*inRowSize + (int)x; + try + { - int[] fouralts = {inHeights[idx1], inHeights[idx1+1], inHeights[idx1-1201], inHeights[idx1-1200]}; ++ int[] fouralts = {inHeights[idx1], inHeights[idx1+1], inHeights[idx1-inRowSize], inHeights[idx1-inRowSize+1]}; + int numVoids = (fouralts[0]==VOID_VAL?1:0) + (fouralts[1]==VOID_VAL?1:0) + + (fouralts[2]==VOID_VAL?1:0) + (fouralts[3]==VOID_VAL?1:0); + // if (numVoids > 0) System.out.println(numVoids + " voids found"); + double altitude = 0.0; + switch (numVoids) + { - case 0: altitude = bilinearInterpolate(fouralts, x, y); break; - case 1: altitude = bilinearInterpolate(fixVoid(fouralts), x, y); break; - case 2: - case 3: altitude = averageNonVoid(fouralts); break; - default: altitude = VOID_VAL; ++ case 0: altitude = bilinearInterpolate(fouralts, x, y); break; ++ case 1: altitude = bilinearInterpolate(fixVoid(fouralts), x, y); break; ++ case 2: ++ case 3: altitude = averageNonVoid(fouralts); break; ++ default: altitude = VOID_VAL; + } + // Special case for terrain tracks, don't interpolate voids yet + if (!_normalTrack && numVoids > 0) { + altitude = VOID_VAL; + } + if (altitude != VOID_VAL) + { + point.setFieldValue(Field.ALTITUDE, ""+altitude, false); + // depending on settings, this value may have been added as feet, we need to force metres + point.getAltitude().reset(new Altitude((int)altitude, UnitSetLibrary.UNITS_METRES)); + numAltitudesFound++; + } + } + catch (ArrayIndexOutOfBoundsException obe) { - // System.err.println("lat=" + point.getLatitude().getDouble() + ", x=" + x + ", y=" + y + ", idx=" + idx1); ++ System.err.println("Point not in tile? lat=" + point.getLatitude().getDouble() + ", x=" + x + ", y=" + y + ", idx=" + idx1+"\n"); + } + } + } + } + return numAltitudesFound; + } + /** * Perform a bilinear interpolation on the given altitude array * @param inAltitudes array of four altitude values on corners of square (bl, br, tl, tr) diff --combined src/tim/prune/gui/MenuManager.java index d3386fe,d289b78..ed8474c --- a/src/tim/prune/gui/MenuManager.java +++ b/src/tim/prune/gui/MenuManager.java @@@ -30,14 -30,14 +30,18 @@@ import tim.prune.data.Selection import tim.prune.data.Track; import tim.prune.data.TrackInfo; import tim.prune.function.ChooseSingleParameter; + import tim.prune.function.PasteCoordinateList; + import tim.prune.function.PasteCoordinates; + import tim.prune.function.PlusCodeFunction; import tim.prune.function.SearchOpenCachingDeFunction; import tim.prune.function.browser.UrlGenerator; import tim.prune.function.browser.WebMapFunction; import tim.prune.function.search.SearchMapillaryFunction; +import tim.prune.function.srtm.DownloadSrtmFunction; +import tim.prune.function.srtm.SrtmGl1Source; +import tim.prune.function.srtm.Srtm3Source; +import tim.prune.function.srtm.SrtmViewfinderSource; + import tim.prune.function.settings.SaveConfig; /** * Class to manage the menu bar and tool bar, @@@ -78,10 -78,10 +82,11 @@@ public class MenuManager implements Dat private JMenuItem _selectEndItem = null; private JMenuItem _findWaypointItem = null; private JMenuItem _duplicatePointItem = null; + private JMenuItem _projectPointItem = null; 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; @@@ -95,10 -95,8 +100,8 @@@ private JMenu _browserMapMenu = null; private JMenuItem _routingGraphHopperItem = null; private JMenuItem _chartItem = null; - private JMenuItem _getGpsiesItem = null; - private JMenuItem _uploadGpsiesItem = null; private JMenuItem _lookupSrtmItem = null; - private JMenuItem _downloadSrtmItem = null; + private JMenu _downloadSrtmMenu = null; private JMenuItem _nearbyWikipediaItem = null; private JMenuItem _nearbyOsmPoiItem = null; private JMenuItem _showPeakfinderItem = null; @@@ -108,7 -106,7 +111,7 @@@ private JMenuItem _downloadOsmItem = null; private JMenuItem _getWeatherItem = null; private JMenuItem _distanceItem = null; - private JMenuItem _fullRangeDetailsItem = null; + private JMenuItem _viewFullDetailsItem = null; private JMenuItem _estimateTimeItem = null; private JMenuItem _learnEstimationParams = null; private JMenuItem _autoplayTrack = null; @@@ -262,24 -260,9 +265,17 @@@ // SRTM _lookupSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_SRTM, false); onlineMenu.add(_lookupSrtmItem); - _downloadSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_DOWNLOAD_SRTM, false); - onlineMenu.add(_downloadSrtmItem); + // Download SRTM sub-menu + _downloadSrtmMenu = new JMenu(I18nManager.getText("function.downloadsrtm")); + _downloadSrtmMenu.setEnabled(false); + JMenuItem downloadStrmGl1Item = makeMenuItem(new DownloadSrtmFunction(_app, new SrtmGl1Source())); + _downloadSrtmMenu.add(downloadStrmGl1Item); + JMenuItem downloadStrmViewfinderItem = makeMenuItem(new DownloadSrtmFunction(_app, new SrtmViewfinderSource())); + _downloadSrtmMenu.add(downloadStrmViewfinderItem); + JMenuItem downloadStrm3Item = makeMenuItem(new DownloadSrtmFunction(_app, new Srtm3Source())); + _downloadSrtmMenu.add(downloadStrm3Item); + onlineMenu.add(_downloadSrtmMenu); - // Get gpsies tracks - _getGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_GPSIES, false); - onlineMenu.add(_getGpsiesItem); - // Upload to gpsies - _uploadGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_UPLOAD_GPSIES, false); - onlineMenu.add(_uploadGpsiesItem); - onlineMenu.addSeparator(); // browser submenu _browserMapMenu = new JMenu(I18nManager.getText("menu.view.browser")); @@@ -439,8 -422,6 +435,8 @@@ 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) { @@@ -507,9 -488,17 +503,17 @@@ // duplicate current point _duplicatePointItem = makeMenuItem(FunctionLibrary.FUNCTION_DUPLICATE_POINT, false); pointMenu.add(_duplicatePointItem); + // project current point + _projectPointItem = makeMenuItem(FunctionLibrary.FUNCTION_PROJECT_POINT, false); + pointMenu.add(_projectPointItem); // paste coordinates function - JMenuItem pasteCoordsItem = makeMenuItem(FunctionLibrary.FUNCTION_PASTE_COORDINATES); + JMenuItem pasteCoordsItem = makeMenuItem(new PasteCoordinates(_app)); pointMenu.add(pasteCoordsItem); + JMenuItem pasteCoordsListItem = makeMenuItem(new PasteCoordinateList(_app)); + pointMenu.add(pasteCoordsListItem); + // pluscodes function + JMenuItem plusCodeItem = makeMenuItem(new PlusCodeFunction(_app)); + pointMenu.add(plusCodeItem); menubar.add(pointMenu); // Add view menu @@@ -546,8 -535,8 +550,8 @@@ _distanceItem = makeMenuItem(FunctionLibrary.FUNCTION_DISTANCES, false); viewMenu.add(_distanceItem); // full range details - _fullRangeDetailsItem = makeMenuItem(FunctionLibrary.FUNCTION_FULL_RANGE_DETAILS, false); - viewMenu.add(_fullRangeDetailsItem); + _viewFullDetailsItem = makeMenuItem(FunctionLibrary.FUNCTION_FULL_DETAILS, false); + viewMenu.add(_viewFullDetailsItem); // estimate time _estimateTimeItem = makeMenuItem(FunctionLibrary.FUNCTION_ESTIMATE_TIME, false); viewMenu.add(_estimateTimeItem); @@@ -667,8 -656,6 +671,8 @@@ settingsMenu.add(makeMenuItem(new ChooseSingleParameter(_app, FunctionLibrary.FUNCTION_SET_ALTITUDE_TOLERANCE))); // Set timezone settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_TIMEZONE)); + // Set Earthdata authentication + settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_EARTHDATA_AUTH)); settingsMenu.addSeparator(); // Save configuration settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SAVECONFIG)); @@@ -677,7 -664,10 +681,10 @@@ _autosaveSettingsCheckbox.setSelected(Config.getConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS)); _autosaveSettingsCheckbox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - Config.setConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS, _autosaveSettingsCheckbox.isSelected()); + final boolean autosaveOn = _autosaveSettingsCheckbox.isSelected(); + Config.setConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS, autosaveOn); + // Maybe want to save config? + new SaveConfig(_app).autosaveSwitched(autosaveOn); } }); settingsMenu.add(_autosaveSettingsCheckbox); @@@ -886,7 -876,7 +893,7 @@@ _markRectangleItem.setEnabled(hasData); _markUphillLiftsItem.setEnabled(hasData && _track.hasAltitudeData()); _deleteMarkedPointsItem.setEnabled(hasData && _track.hasMarkedPoints()); - _rearrangeWaypointsItem.setEnabled(hasData && _track.hasTrackPoints() && _track.hasWaypoints()); + _rearrangeWaypointsItem.setEnabled(hasData && _track.hasWaypoints() && _track.getNumPoints() > 1); final boolean hasSeveralTrackPoints = hasData && _track.hasTrackPoints() && _track.getNumPoints() > 3; _splitSegmentsItem.setEnabled(hasSeveralTrackPoints); _sewSegmentsItem.setEnabled(hasSeveralTrackPoints); @@@ -898,8 -888,6 +905,6 @@@ _browserMapMenu.setEnabled(hasData); _distanceItem.setEnabled(hasData); _autoplayTrack.setEnabled(hasData && _track.getNumPoints() > 3); - _getGpsiesItem.setEnabled(hasData); - _uploadGpsiesItem.setEnabled(hasData && _track.hasTrackPoints()); _lookupSrtmItem.setEnabled(hasData); _nearbyWikipediaItem.setEnabled(hasData); _nearbyOsmPoiItem.setEnabled(hasData); @@@ -907,7 -895,7 +912,7 @@@ _getWeatherItem.setEnabled(hasData); _findWaypointItem.setEnabled(hasData && _track.hasWaypoints()); // have we got a cache? - _downloadSrtmItem.setEnabled(hasData && Config.getConfigString(Config.KEY_DISK_CACHE) != null); + _downloadSrtmMenu.setEnabled(hasData && Config.getConfigString(Config.KEY_DISK_CACHE) != null); // have we got any timestamps? _deleteByDateItem.setEnabled(hasData && _track.hasData(Field.TIMESTAMP)); @@@ -929,6 -917,7 +934,7 @@@ _selectEndItem.setEnabled(hasPoint); _selectEndButton.setEnabled(hasPoint); _duplicatePointItem.setEnabled(hasPoint); + _projectPointItem.setEnabled(hasPoint); _showPeakfinderItem.setEnabled(hasPoint); _showGeohackItem.setEnabled(hasPoint); _searchOpencachingDeItem.setEnabled(hasPoint); @@@ -974,10 -963,9 +980,10 @@@ _reverseItem.setEnabled(hasRange); _addTimeOffsetItem.setEnabled(hasRange); _addAltitudeOffsetItem.setEnabled(hasRange); + _removeAltitudesItem.setEnabled(hasRange); _convertNamesToTimesItem.setEnabled(hasRange && _track.hasWaypoints()); _deleteFieldValuesItem.setEnabled(hasRange); - _fullRangeDetailsItem.setEnabled(hasRange); + _viewFullDetailsItem.setEnabled(hasRange || hasPoint); _estimateTimeItem.setEnabled(hasRange); _learnEstimationParams.setEnabled(hasData && _track.hasTrackPoints() && _track.hasData(Field.TIMESTAMP) && _track.hasAltitudeData()); diff --combined src/tim/prune/gui/Viewport.java index aec78a6,38620e4..56711a3 --- a/src/tim/prune/gui/Viewport.java +++ b/src/tim/prune/gui/Viewport.java @@@ -7,7 -7,7 +7,7 @@@ import tim.prune.gui.map.MapUtils /** * Class to provide access to current viewport * The point of this class is to decouple the view from the MapCanvas object - * so that when the GetGpsies function needs to know the area currently viewed, it doesn't + * so that when a search function needs to know the area currently viewed, it doesn't * need to have a direct connection to the MapCanvas. Instead it asks the App for the viewport, * which is then able to get the map position from the MapCanvas. * I'm still not sure whether this is ugly or not, but it's more efficient than constantly listening. @@@ -40,12 -40,4 +40,12 @@@ public class Viewpor 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 --combined src/tim/prune/gui/map/MapCanvas.java index ad38d81,d305d1c..d3a1de5 --- a/src/tim/prune/gui/map/MapCanvas.java +++ b/src/tim/prune/gui/map/MapCanvas.java @@@ -92,7 -92,7 +92,7 @@@ public class MapCanvas extends JPanel i 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 +259,8 @@@ // 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,19 -337,16 +337,19 @@@ /** * 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); } @@@ -363,59 -360,70 +363,59 @@@ 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); @@@ -712,8 -720,8 +712,8 @@@ final double pointSeparationSqd = (prevX-px) * (prevX-px) + (prevY-py) * (prevY-py); if (pointSeparationSqd > pointSeparationForArrowsSqd) { - final double midX = (prevX + px) / 2; - final double midY = (prevY + py) / 2; + final double midX = (prevX + px) / 2.0; + final double midY = (prevY + py) / 2.0; final boolean midPointVisible = midX >= 0 && midX < winWidth && midY >= 0 && midY < winHeight; if (midPointVisible) { @@@ -1066,63 -1074,66 +1066,63 @@@ */ 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; @@@ -1397,6 -1408,10 +1397,6 @@@ } } 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 --combined src/tim/prune/gui/map/MapTileManager.java index d1e0047,8c2c6ee..b4a60c8 --- a/src/tim/prune/gui/map/MapTileManager.java +++ b/src/tim/prune/gui/map/MapTileManager.java @@@ -70,19 -70,10 +70,19 @@@ public class MapTileManager implements * @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; + } /** @@@ -171,6 -162,7 +171,7 @@@ tempCache = _tempCaches[inLayer]; // Should probably guard array indexes here tileImage = tempCache.getTile(inX, inY); if (tileImage != null) { + //System.out.println("Got tile from memory: " + inX + ", " + inY); return tileImage; } } @@@ -204,7 -196,6 +205,6 @@@ try { URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY)); - //System.out.println("Trying to fetch: " + tileUrl); if (useDisk) { DiskTileCacher.saveTile(tileUrl, diskCachePath, diff --combined src/tim/prune/lang/prune-texts_en.properties index 35ac13b,dbc4be4..fe5210c --- a/src/tim/prune/lang/prune-texts_en.properties +++ b/src/tim/prune/lang/prune-texts_en.properties @@@ -94,16 -94,17 +94,18 @@@ function.interpolate=Interpolate point 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 function.deletefieldvalues=Delete field values - function.pastecoordinates=Enter new coordinates + function.pastecoordinates=Enter point coordinates + function.pastecoordinatelist=Enter list of coordinates + function.enterpluscode=Enter pluscode function.charts=Charts function.show3d=Three-D view function.distances=Distances - function.fullrangedetails=Full range details + function.viewfulldetails=Full details function.estimatetime=Estimate time function.learnestimationparams=Learn time estimation parameters function.autoplay=Autoplay track @@@ -111,14 -112,8 +113,12 @@@ function.selectsegment=Select current s function.splitsegments=Split track into segments function.sewsegments=Sew track segments together function.createmarkerwaypoints=Create marker waypoints - function.getgpsies=Get Gpsies tracks - function.uploadgpsies=Upload track to Gpsies function.lookupsrtm=Get altitudes from SRTM function.downloadsrtm=Download SRTM tiles +function.downloadsrtm.SRTMGL1_v003=SRTM 1 arc-second tiles +function.downloadsrtm.SRTMGL1_v003.needsetup=An Earthdata account is necessary to download SRTM 1 arc-second tiles +function.downloadsrtm.SRTM3_v21=SRTM 3 arc-second tiles +function.downloadsrtm.SRTM_Viewfinder=Viewfinderpanoramas.org data function.getwikipedia=Get nearby Wikipedia articles function.searchwikipedianames=Search Wikipedia by name function.searchosmpois=Get nearby OSM points @@@ -126,6 -121,7 +126,7 @@@ function.searchopencachingde=Search Ope function.mapillary=Search for photos in Mapillary function.downloadosm=Download OSM data for area function.duplicatepoint=Duplicate point + function.projectpoint=Project point function.connecttopoint=Connect to point function.disconnectfrompoint=Disconnect from point function.removephoto=Remove photo @@@ -155,7 -151,6 +156,7 @@@ function.managetilecache=Manage tile ca function.getweatherforecast=Get weather forecast function.setaltitudetolerance=Set altitude tolerance function.selecttimezone=Set timezone +function.setearthdataauthentication=Set Earthdata authentication # Dialogs dialog.exit.confirm.title=Exit GpsPrune @@@ -308,7 -303,6 +309,7 @@@ dialog.pointnameedit.lowercase=lower ca dialog.pointnameedit.titlecase=Title Case dialog.addtimeoffset.add=Add time dialog.addtimeoffset.subtract=Subtract time +dialog.addtimeoffset.1024week=1024-week block dialog.addtimeoffset.days=Days dialog.addtimeoffset.hours=Hours dialog.addtimeoffset.minutes=Minutes @@@ -377,19 -371,6 +378,6 @@@ dialog.gpsies.column.length=Lengt dialog.gpsies.description=Description dialog.gpsies.nodescription=No description dialog.gpsies.nonefound=No tracks found - dialog.gpsies.username=Gpsies username - dialog.gpsies.password=Gpsies password - dialog.gpsies.keepprivate=Keep track private - dialog.gpsies.confirmopenpage=Open the web page for the uploaded track? - dialog.gpsies.activities=Activity types - dialog.gpsies.activity.trekking=Hiking - dialog.gpsies.activity.walking=Walking - dialog.gpsies.activity.jogging=Running - dialog.gpsies.activity.biking=Cycling - dialog.gpsies.activity.motorbiking=Motorbiking - dialog.gpsies.activity.snowshoe=Snowshoeing - dialog.gpsies.activity.sailing=Sailing - dialog.gpsies.activity.skating=Skating dialog.mapillary.nonefound=No photos found dialog.wikipedia.column.name=Article name dialog.wikipedia.column.distance=Distance @@@ -457,6 -438,10 +445,10 @@@ dialog.deletemarked.nonefound=No data p dialog.pastecoordinates.desc=Enter or paste the coordinates here dialog.pastecoordinates.coords=Coordinates dialog.pastecoordinates.nothingfound=Please check the coordinates and try again + dialog.pastecoordinatelist.desc=Enter the coordinates for the new points with one point per line + dialog.pluscode.desc=Enter or paste the pluscode here + dialog.pluscode.code=Pluscode + dialog.pluscode.nothingfound=Please check the code and try again dialog.help.help=Please see\n https://gpsprune.activityworkshop.net/\nfor more information and tips,\nincluding a PDF user guide you can buy. dialog.about.version=Version dialog.about.build=Build @@@ -496,25 -481,9 +488,9 @@@ dialog.keys.intro=You can use the follo dialog.keys.keylist=
Arrow keysPan map left right, up, down
Ctrl + left, right arrowSelect previous or next point
Ctrl + up, down arrowZoom in or out
Ctrl + PgUp, PgDownSelect previous, next segment
Ctrl + Home, EndSelect first, last point
DelDelete current point
dialog.keys.normalmodifier=Ctrl dialog.keys.macmodifier=Command - dialog.saveconfig.desc=The following settings can be saved to a configuration file : - dialog.saveconfig.prune.trackdirectory=Track directory - dialog.saveconfig.prune.photodirectory=Photo directory - dialog.saveconfig.prune.languagecode=Language code (EN) - dialog.saveconfig.prune.languagefile=Language file - dialog.saveconfig.prune.gpsdevice=GPS device - dialog.saveconfig.prune.gpsformat=GPS format - dialog.saveconfig.prune.povrayfont=Povray font - dialog.saveconfig.prune.gnuplotpath=Path to gnuplot - dialog.saveconfig.prune.gpsbabelpath=Path to gpsbabel - dialog.saveconfig.prune.exiftoolpath=Path to exiftool - dialog.saveconfig.prune.mapsource=Selected map source - dialog.saveconfig.prune.mapsourcelist=Map sources - dialog.saveconfig.prune.diskcache=Map cache - dialog.saveconfig.prune.kmzimagewidth=KMZ image size - dialog.saveconfig.prune.colourscheme=Colour scheme - dialog.saveconfig.prune.linewidth=Line width - dialog.saveconfig.prune.kmltrackcolour=KML track colour - dialog.saveconfig.prune.autosavesettings=Autosave settings + dialog.paths.prune.gnuplotpath=Path to gnuplot + dialog.paths.prune.gpsbabelpath=Path to gpsbabel + dialog.paths.prune.exiftoolpath=Path to exiftool dialog.setpaths.intro=If you need to, you can choose the paths to the external applications: dialog.setpaths.found=Path found? dialog.addaltitude.noaltitudes=The selected range does not contain altitudes @@@ -581,12 -550,10 +557,15 @@@ dialog.displaysettings.wpicon.pin=Boar dialog.displaysettings.size.small=Small dialog.displaysettings.size.medium=Medium dialog.displaysettings.size.large=Large + dialog.displaysettings.windowstyle=Window style (requires restart) + dialog.displaysettings.windowstyle.default=Default + dialog.displaysettings.windowstyle.nimbus=Nimbus dialog.downloadosm.desc=Confirm to download the raw OSM data for the specified area: +dialog.earthdataauth.intro=

Configure username and password to access your NASA Earthdata login account.

Create an account at https://urs.earthdata.nasa.gov/users/new.

+dialog.earthdataauth.user=Username +dialog.earthdataauth.password=Password +dialog.earthdataauth.authaccepted=Username and password accepted +dialog.earthdataauth.authrejected=Username and password rejected dialog.searchwikipedianames.search=Search for: dialog.weather.location=Location dialog.weather.update=Forecast updated @@@ -628,6 -595,12 +607,12 @@@ dialog.autoplay.usetimestamps=Use poin dialog.autoplay.rewind=Back to beginning dialog.autoplay.pause=Pause dialog.autoplay.play=Play + dialog.markers.halves=Halfway points + dialog.markers.half.distance=Half distance + dialog.markers.half.climb=Half climb + dialog.markers.half.descent=Half descent + dialog.projectpoint.desc=Enter the direction and distance to project this point + dialog.projectpoint.bearing=Bearing (degrees from N) # 3d window dialog.3d.title=GpsPrune Three-d view @@@ -644,13 -617,12 +629,13 @@@ confirm.mergetracksegments=Track segmen 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 confirm.sewsegments=%d segment joins were made confirm.cutandmove=Selection moved - confirm.interpolate=Points added + confirm.pointsadded=%d points added confirm.convertnamestotimes=Waypoint names converted confirm.saveexif.ok=Saved %d photo files confirm.undo.single=operation undone @@@ -706,7 -678,6 +691,6 @@@ button.selectall=Select al button.selectnone=Select none button.preview=Preview button.load=Load - button.upload=Upload button.guessfields=Guess fields button.showwebpage=Show webpage button.check=Check @@@ -765,9 -736,6 +749,9 @@@ details.range.gradient=Gradien details.lists.waypoints=Waypoints details.lists.photos=Photos details.lists.audio=Audio +details.lists.segments=Segments +details.lists.segments.label=Segment # +details.lists.segments.to=to details.photodetails=Photo details details.nophoto=No photo selected details.photo.loading=Loading @@@ -783,6 -751,7 +767,7 @@@ map.overzoom=No maps available at this # Field names fieldname.latitude=Latitude fieldname.longitude=Longitude + fieldname.coordinates=Coordinates fieldname.altitude=Altitude fieldname.timestamp=Time fieldname.time=Time @@@ -797,6 -766,7 +782,7 @@@ fieldname.duration=Duratio fieldname.speed=Speed fieldname.verticalspeed=Vertical speed fieldname.description=Description + fieldname.comment=Comment fieldname.mediafilename=Filename # Measurement units @@@ -868,7 -838,6 +854,7 @@@ undo.splitsegments=split track segment 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 @@@ -897,6 -866,7 +883,7 @@@ error.load.nopoints=No coordinate infor error.load.unknownxml=Unrecognised xml format: error.load.noxmlinzip=No xml file found inside zip file error.load.othererror=Error reading file: + error.load.nopointsintext=No coordinate information found error.jpegload.dialogtitle=Error loading photos error.jpegload.nofilesfound=No files found error.jpegload.nojpegsfound=No jpeg files found