]> gitweb.fperrin.net Git - GpsPrune.git/commitdiff
Version 13, August 2011
authoractivityworkshop <mail@activityworkshop.net>
Sun, 15 Feb 2015 09:58:28 +0000 (10:58 +0100)
committeractivityworkshop <mail@activityworkshop.net>
Sun, 15 Feb 2015 09:58:28 +0000 (10:58 +0100)
130 files changed:
tim/prune/App.java
tim/prune/FunctionLibrary.java
tim/prune/GpsPrune.java [moved from tim/prune/GpsPruner.java with 93% similarity]
tim/prune/config/ColourScheme.java
tim/prune/config/Config.java
tim/prune/copyright.txt
tim/prune/correlate/AudioCorrelator.java
tim/prune/correlate/AudioTimestampSelector.java
tim/prune/correlate/Correlator.java
tim/prune/correlate/MediaPreviewTableModel.java
tim/prune/correlate/MediaSelectionTableModel.java
tim/prune/correlate/MediaSelectionTableRow.java
tim/prune/correlate/PointMediaPair.java
tim/prune/data/AudioClip.java [moved from tim/prune/data/AudioFile.java with 52% similarity]
tim/prune/data/AudioList.java
tim/prune/data/Coordinate.java
tim/prune/data/DataPoint.java
tim/prune/data/Field.java
tim/prune/data/MediaList.java
tim/prune/data/MediaObject.java [moved from tim/prune/data/MediaFile.java with 56% similarity]
tim/prune/data/Photo.java
tim/prune/data/PhotoList.java
tim/prune/data/RecentFile.java [new file with mode: 0644]
tim/prune/data/RecentFileList.java [new file with mode: 0644]
tim/prune/data/SourceInfo.java
tim/prune/data/Track.java
tim/prune/data/TrackInfo.java
tim/prune/function/AboutScreen.java
tim/prune/function/AsyncMediaLoader.java [new file with mode: 0644]
tim/prune/function/Cancellable.java [new file with mode: 0644]
tim/prune/function/CheckVersionScreen.java
tim/prune/function/ConnectToPointFunction.java
tim/prune/function/DisconnectAudioFunction.java
tim/prune/function/DisconnectPhotoFunction.java
tim/prune/function/DiskCacheConfig.java
tim/prune/function/DownloadOsmFunction.java
tim/prune/function/GetWikipediaFunction.java
tim/prune/function/GetWikipediaXmlHandler.java
tim/prune/function/HelpScreen.java
tim/prune/function/PhotoPopupFunction.java
tim/prune/function/PlayAudioFunction.java
tim/prune/function/RearrangePhotosFunction.java
tim/prune/function/RemoveAudioFunction.java
tim/prune/function/RemovePhotoFunction.java
tim/prune/function/SaveConfig.java
tim/prune/function/SearchWikipediaNames.java
tim/prune/function/SelectTracksFunction.java
tim/prune/function/SetLanguage.java
tim/prune/function/StopAudioFunction.java
tim/prune/function/cache/ManageCacheFunction.java [new file with mode: 0644]
tim/prune/function/cache/RowInfo.java [new file with mode: 0644]
tim/prune/function/cache/TileCacheModel.java [new file with mode: 0644]
tim/prune/function/cache/TileFilter.java [new file with mode: 0644]
tim/prune/function/cache/TileSet.java [new file with mode: 0644]
tim/prune/function/cache/TileSetTableModel.java [new file with mode: 0644]
tim/prune/function/charts/Charter.java
tim/prune/function/compress/CompressTrackFunction.java
tim/prune/function/compress/DouglasPeuckerAlgorithm.java [new file with mode: 0644]
tim/prune/function/compress/XYpoint.java [new file with mode: 0644]
tim/prune/function/gpsies/GetGpsiesFunction.java
tim/prune/function/srtm/LookupSrtmFunction.java
tim/prune/gui/AudioListener.java
tim/prune/gui/DetailsDisplay.java
tim/prune/gui/IconManager.java
tim/prune/gui/MediaListModel.java
tim/prune/gui/MenuManager.java
tim/prune/gui/PhotoThumbnail.java
tim/prune/gui/RecentFileTrigger.java [new file with mode: 0644]
tim/prune/gui/SelectorDisplay.java
tim/prune/gui/WaypointListModel.java
tim/prune/gui/map/CloudmadeMapSource.java
tim/prune/gui/map/DiskTileCacher.java
tim/prune/gui/map/MapCanvas.java
tim/prune/gui/map/MapSourceLibrary.java
tim/prune/gui/map/MapTileManager.java
tim/prune/gui/map/ScaleBar.java
tim/prune/gui/profile/AltitudeData.java
tim/prune/jpeg/ExternalExifLibrary.java
tim/prune/jpeg/JpegData.java
tim/prune/jpeg/drew/ExifReader.java
tim/prune/lang/prune-texts_af.properties
tim/prune/lang/prune-texts_cz.properties
tim/prune/lang/prune-texts_de.properties
tim/prune/lang/prune-texts_de_CH.properties
tim/prune/lang/prune-texts_en.properties
tim/prune/lang/prune-texts_es.properties
tim/prune/lang/prune-texts_fr.properties
tim/prune/lang/prune-texts_hu.properties
tim/prune/lang/prune-texts_it.properties
tim/prune/lang/prune-texts_ja.properties
tim/prune/lang/prune-texts_ko.properties
tim/prune/lang/prune-texts_nl.properties
tim/prune/lang/prune-texts_pl.properties
tim/prune/lang/prune-texts_pt.properties
tim/prune/lang/prune-texts_ro.properties
tim/prune/lang/prune-texts_tr.properties
tim/prune/lang/prune-texts_zh.properties
tim/prune/load/AudioLoader.java
tim/prune/load/BabelFileFormats.java [new file with mode: 0644]
tim/prune/load/BabelLoadFromFile.java [new file with mode: 0644]
tim/prune/load/BabelLoadFromGps.java [new file with mode: 0644]
tim/prune/load/BabelLoader.java [moved from tim/prune/load/GpsLoader.java with 53% similarity]
tim/prune/load/ByteScooper.java [new file with mode: 0644]
tim/prune/load/JpegLoader.java
tim/prune/load/MediaHelper.java
tim/prune/load/MediaLinkInfo.java [new file with mode: 0644]
tim/prune/load/MediaLoadProgressDialog.java [new file with mode: 0644]
tim/prune/load/MediaSorter.java
tim/prune/load/xml/GpxHandler.java
tim/prune/load/xml/GzipFileLoader.java
tim/prune/load/xml/KmlHandler.java
tim/prune/load/xml/XmlFileLoader.java
tim/prune/load/xml/ZipFileLoader.java
tim/prune/readme.txt
tim/prune/save/ExifSaver.java
tim/prune/save/FileSaver.java
tim/prune/save/GpxExporter.java
tim/prune/save/KmlExporter.java
tim/prune/save/PhotoTableEntry.java
tim/prune/save/PovExporter.java
tim/prune/save/SvgExporter.java
tim/prune/save/xml/XmlUtils.java [new file with mode: 0644]
tim/prune/undo/UndoConnectMedia.java
tim/prune/undo/UndoCorrelateAudios.java
tim/prune/undo/UndoDeleteAudio.java
tim/prune/undo/UndoDeletePhoto.java
tim/prune/undo/UndoDeletePoint.java
tim/prune/undo/UndoDisconnectMedia.java
tim/prune/undo/UndoLoadAudios.java
tim/prune/undo/UndoRotatePhoto.java

index 6fab5833af1c56ecddb5b506a9c4b03a2de31bbd..8189ffb6b4aafff66d62d60906961ebaf1ea3e67 100644 (file)
@@ -9,31 +9,34 @@ import java.util.Stack;
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
 
+import tim.prune.config.Config;
 import tim.prune.data.Altitude;
-import tim.prune.data.AudioFile;
 import tim.prune.data.Checker;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
 import tim.prune.data.LatLonRectangle;
-import tim.prune.data.MediaFile;
 import tim.prune.data.NumberUtils;
 import tim.prune.data.Photo;
 import tim.prune.data.PhotoList;
+import tim.prune.data.RecentFile;
 import tim.prune.data.SourceInfo;
 import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
+import tim.prune.data.SourceInfo.FILE_TYPE;
+import tim.prune.function.AsyncMediaLoader;
+import tim.prune.function.SaveConfig;
 import tim.prune.function.SelectTracksFunction;
 import tim.prune.function.browser.BrowserLauncher;
 import tim.prune.function.browser.UrlGenerator;
 import tim.prune.function.edit.FieldEditList;
 import tim.prune.function.edit.PointEditor;
-import tim.prune.gui.SidebarController;
 import tim.prune.gui.MenuManager;
+import tim.prune.gui.SidebarController;
 import tim.prune.gui.UndoManager;
 import tim.prune.gui.Viewport;
 import tim.prune.load.FileLoader;
 import tim.prune.load.JpegLoader;
-import tim.prune.load.MediaHelper;
+import tim.prune.load.MediaLinkInfo;
 import tim.prune.load.TrackNameList;
 import tim.prune.save.ExifSaver;
 import tim.prune.save.FileSaver;
@@ -60,6 +63,7 @@ public class App
        private Viewport _viewport = null;
        private ArrayList<File> _dataFiles = null;
        private boolean _firstDataFile = true;
+       private boolean _busyLoading = false;
 
 
        /**
@@ -209,6 +213,10 @@ public class App
                                JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
                        == JOptionPane.YES_OPTION)
                {
+                       // save settings
+                       if (Config.getConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS)) {
+                               new SaveConfig(this).silentSave();
+                       }
                        System.exit(0);
                }
        }
@@ -270,7 +278,7 @@ public class App
                        {
                                // Confirm deletion of photo or decoupling
                                int response = JOptionPane.showConfirmDialog(_frame,
-                                       I18nManager.getText("dialog.deletepoint.deletephoto") + " " + currentPhoto.getFile().getName(),
+                                       I18nManager.getText("dialog.deletepoint.deletephoto") + " " + currentPhoto.getName(),
                                        I18nManager.getText("dialog.deletepoint.title"),
                                        JOptionPane.YES_NO_CANCEL_OPTION);
                                if (response == JOptionPane.CANCEL_OPTION || response == JOptionPane.CLOSED_OPTION)
@@ -304,6 +312,7 @@ public class App
                                                // decouple photo from point
                                                currentPhoto.setDataPoint(null);
                                        }
+                                       UpdateMessageBroker.informSubscribers();
                                }
                                // Confirm
                                UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.deletepoint.single"));
@@ -317,82 +326,80 @@ public class App
         */
        public void deleteSelectedRange()
        {
-               if (_track != null)
+               if (_track == null) return;
+               // Find out if photos should be deleted or not
+               int selStart = _trackInfo.getSelection().getStart();
+               int selEnd = _trackInfo.getSelection().getEnd();
+               if (selStart >= 0 && selEnd >= selStart)
                {
-                       // Find out if photos should be deleted or not
-                       int selStart = _trackInfo.getSelection().getStart();
-                       int selEnd = _trackInfo.getSelection().getEnd();
-                       if (selStart >= 0 && selEnd >= selStart)
+                       int numToDelete = selEnd - selStart + 1;
+                       boolean[] deletePhotos = new boolean[numToDelete];
+                       Photo[] photosToDelete = new Photo[numToDelete];
+                       boolean deleteAll = false;
+                       boolean deleteNone = false;
+                       String[] questionOptions = {I18nManager.getText("button.yes"), I18nManager.getText("button.no"),
+                               I18nManager.getText("button.yestoall"), I18nManager.getText("button.notoall"),
+                               I18nManager.getText("button.cancel")};
+                       DataPoint point = null;
+                       for (int i=0; i<numToDelete; i++)
                        {
-                               int numToDelete = selEnd - selStart + 1;
-                               boolean[] deletePhotos = new boolean[numToDelete];
-                               Photo[] photosToDelete = new Photo[numToDelete];
-                               boolean deleteAll = false;
-                               boolean deleteNone = false;
-                               String[] questionOptions = {I18nManager.getText("button.yes"), I18nManager.getText("button.no"),
-                                       I18nManager.getText("button.yestoall"), I18nManager.getText("button.notoall"),
-                                       I18nManager.getText("button.cancel")};
-                               DataPoint point = null;
-                               for (int i=0; i<numToDelete; i++)
+                               point = _trackInfo.getTrack().getPoint(i + selStart);
+                               if (point != null && point.getPhoto() != null)
                                {
-                                       point = _trackInfo.getTrack().getPoint(i + selStart);
-                                       if (point != null && point.getPhoto() != null)
+                                       if (deleteAll)
+                                       {
+                                               deletePhotos[i] = true;
+                                               photosToDelete[i] = point.getPhoto();
+                                       }
+                                       else if (deleteNone) {deletePhotos[i] = false;}
+                                       else
                                        {
-                                               if (deleteAll)
+                                               int response = JOptionPane.showOptionDialog(_frame,
+                                                       I18nManager.getText("dialog.deletepoint.deletephoto") + " " + point.getPhoto().getName(),
+                                                       I18nManager.getText("dialog.deletepoint.title"),
+                                                       JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,
+                                                       questionOptions, questionOptions[1]);
+                                               // check for cancel or close
+                                               if (response == 4 || response == -1) {return;}
+                                               // check for yes or yes to all
+                                               if (response == 0 || response == 2)
                                                {
                                                        deletePhotos[i] = true;
                                                        photosToDelete[i] = point.getPhoto();
+                                                       if (response == 2) {deleteAll = true;}
                                                }
-                                               else if (deleteNone) {deletePhotos[i] = false;}
-                                               else
-                                               {
-                                                       int response = JOptionPane.showOptionDialog(_frame,
-                                                               I18nManager.getText("dialog.deletepoint.deletephoto") + " " + point.getPhoto().getFile().getName(),
-                                                               I18nManager.getText("dialog.deletepoint.title"),
-                                                               JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,
-                                                               questionOptions, questionOptions[1]);
-                                                       // check for cancel or close
-                                                       if (response == 4 || response == -1) {return;}
-                                                       // check for yes or yes to all
-                                                       if (response == 0 || response == 2)
-                                                       {
-                                                               deletePhotos[i] = true;
-                                                               photosToDelete[i] = point.getPhoto();
-                                                               if (response == 2) {deleteAll = true;}
-                                                       }
-                                                       // check for no to all
-                                                       if (response == 3) {deleteNone = true;}
-                                               }
+                                               // check for no to all
+                                               if (response == 3) {deleteNone = true;}
                                        }
                                }
-                               // add information to undo stack
-                               UndoDeleteRange undo = new UndoDeleteRange(_trackInfo);
-                               // delete requested photos
-                               for (int i=0; i<numToDelete; i++)
+                       }
+                       // add information to undo stack
+                       UndoDeleteRange undo = new UndoDeleteRange(_trackInfo);
+                       // delete requested photos
+                       for (int i=0; i<numToDelete; i++)
+                       {
+                               point = _trackInfo.getTrack().getPoint(i + selStart);
+                               if (point != null && point.getPhoto() != null)
                                {
-                                       point = _trackInfo.getTrack().getPoint(i + selStart);
-                                       if (point != null && point.getPhoto() != null)
+                                       if (deletePhotos[i])
                                        {
-                                               if (deletePhotos[i])
-                                               {
-                                                       // delete photo from list
-                                                       _trackInfo.getPhotoList().deletePhoto(_trackInfo.getPhotoList().getPhotoIndex(point.getPhoto()));
-                                               }
-                                               else
-                                               {
-                                                       // decouple from point
-                                                       point.getPhoto().setDataPoint(null);
-                                               }
+                                               // delete photo from list
+                                               _trackInfo.getPhotoList().deletePhoto(_trackInfo.getPhotoList().getPhotoIndex(point.getPhoto()));
+                                       }
+                                       else
+                                       {
+                                               // decouple from point
+                                               point.getPhoto().setDataPoint(null);
                                        }
                                }
-                               // call track to delete range
-                               if (_trackInfo.deleteRange())
-                               {
-                                       _undoStack.push(undo);
-                                       // Confirm
-                                       UpdateMessageBroker.informSubscribers("" + numToDelete + " "
-                                               + I18nManager.getText("confirm.deletepoint.multi"));
-                               }
+                       }
+                       // call track to delete range
+                       if (_trackInfo.deleteRange())
+                       {
+                               _undoStack.push(undo);
+                               // Confirm
+                               UpdateMessageBroker.informSubscribers("" + numToDelete + " "
+                                       + I18nManager.getText("confirm.deletepoint.multi"));
                        }
                }
        }
@@ -667,11 +674,11 @@ public class App
         * @param inAltFormat altitude format
         * @param inSourceInfo information about the source of the data
         * @param inTrackNameList information about the track names
-        * @param inLinkArray array of links to photo/audio files
+        * @param inLinkInfo links to photo/audio clips
         */
        public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray,
                Altitude.Format inAltFormat, SourceInfo inSourceInfo,
-               TrackNameList inTrackNameList, String[] inLinkArray)
+               TrackNameList inTrackNameList, MediaLinkInfo inLinkInfo)
        {
                // Check whether loaded array can be properly parsed into a Track
                Track loadedTrack = new Track();
@@ -688,28 +695,21 @@ public class App
                        JOptionPane.showMessageDialog(_frame, I18nManager.getText("dialog.open.contentsdoubled"),
                                I18nManager.getText("function.open"), JOptionPane.WARNING_MESSAGE);
                }
-               // Attach photos and/or audio files to points
-               if (inLinkArray != null)
+
+               _busyLoading = true;
+               // Attach photos and/or audio clips to points
+               if (inLinkInfo != null)
                {
-                       for (int i=0; i<inLinkArray.length; i++)
-                       {
-                               if (inLinkArray[i] != null)
-                               {
-                                       MediaFile mf = MediaHelper.createMediaFile(inLinkArray[i]);
-                                       if (mf != null) {
-                                               loadedTrack.getPoint(i).attachMedia(mf);
-                                               mf.setOriginalStatus(MediaFile.Status.TAGGED);
-                                               mf.setCurrentStatus(MediaFile.Status.TAGGED);
-                                       }
-                               }
+                       String[] linkArray = inLinkInfo.getLinkArray();
+                       if (linkArray != null) {
+                               new AsyncMediaLoader(this, inLinkInfo.getZipFile(), linkArray, loadedTrack).begin();
                        }
                }
                // Look at TrackNameList, decide whether to filter or not
                if (inTrackNameList != null && inTrackNameList.getNumTracks() > 1)
                {
                        // Launch a dialog to let the user choose which tracks to load, then continue
-                       new SelectTracksFunction(this, inFieldArray, inDataArray, inAltFormat, inSourceInfo,
-                               inTrackNameList).begin();
+                       new SelectTracksFunction(this, loadedTrack, inSourceInfo, inTrackNameList).begin();
                }
                else {
                        // go directly to load
@@ -747,9 +747,6 @@ public class App
                                undo.setNumPhotosAudios(_trackInfo.getPhotoList().getNumPhotos(), _trackInfo.getAudioList().getNumAudios());
                                _undoStack.add(undo);
                                _track.combine(inLoadedTrack);
-                               // Add photos and audios (if any in loaded track) to list(s)
-                               MediaHelper.addMediaFromTrack(_track, _trackInfo.getPhotoList(), Photo.class);
-                               MediaHelper.addMediaFromTrack(_track, _trackInfo.getAudioList(), AudioFile.class);
                                // set source information
                                inSourceInfo.populatePointObjects(_track, inLoadedTrack.getNumPoints());
                                _trackInfo.getFileInfo().addSource(inSourceInfo);
@@ -771,9 +768,6 @@ public class App
                                _trackInfo.getFileInfo().replaceSource(inSourceInfo);
                                _trackInfo.getPhotoList().removeCorrelatedPhotos();
                                _trackInfo.getAudioList().removeCorrelatedAudios();
-                               // Add photos and audios (if any in loaded track) to list(s)
-                               MediaHelper.addMediaFromTrack(_track, _trackInfo.getPhotoList(), Photo.class);
-                               MediaHelper.addMediaFromTrack(_track, _trackInfo.getAudioList(), AudioFile.class);
                        }
                }
                else
@@ -787,16 +781,18 @@ public class App
                        _track.load(inLoadedTrack);
                        inSourceInfo.populatePointObjects(_track, _track.getNumPoints());
                        _trackInfo.getFileInfo().addSource(inSourceInfo);
-                       // Add photos and audios (if any in loaded track) to list(s)
-                       MediaHelper.addMediaFromTrack(_track, _trackInfo.getPhotoList(), Photo.class);
-                       MediaHelper.addMediaFromTrack(_track, _trackInfo.getAudioList(), AudioFile.class);
                }
+               // Update config before subscribers are told
+               boolean isRegularLoad = (inSourceInfo.getFileType() != FILE_TYPE.GPSBABEL);
+               Config.getRecentFileList().addFile(new RecentFile(inSourceInfo.getFile(), isRegularLoad));
                UpdateMessageBroker.informSubscribers();
                // Update status bar
                UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile")
                        + " '" + inSourceInfo.getName() + "'");
                // update menu
                _menuManager.informFileLoaded();
+               // Remove busy lock
+               _busyLoading = false;
                // load next file if there's a queue
                loadNextFile();
        }
@@ -1034,4 +1030,9 @@ public class App
        {
                _sidebarController.toggle();
        }
+
+       /** @return true if App is currently busy with loading data */
+       public boolean isBusyLoading() {
+               return _busyLoading;
+       }
 }
index 93532b5cfa4dd5f32cfb5d54c4621c01e9969330..0830049b57bb69c74760bc6b608dd74cde760386 100644 (file)
@@ -11,7 +11,8 @@ import tim.prune.function.gpsies.GetGpsiesFunction;
 import tim.prune.function.gpsies.UploadGpsiesFunction;
 import tim.prune.function.srtm.LookupSrtmFunction;
 import tim.prune.load.AudioLoader;
-import tim.prune.load.GpsLoader;
+import tim.prune.load.BabelLoadFromFile;
+import tim.prune.load.BabelLoadFromGps;
 import tim.prune.save.GpsSaver;
 import tim.prune.save.GpxExporter;
 import tim.prune.save.KmlExporter;
@@ -29,6 +30,7 @@ public abstract class FunctionLibrary
        public static SvgExporter FUNCTION_SVGEXPORT     = null;
        public static GenericFunction FUNCTION_GPSLOAD  = null;
        public static GenericFunction FUNCTION_GPSSAVE  = null;
+       public static GenericFunction FUNCTION_IMPORTBABEL = null;
        public static GenericFunction FUNCTION_SAVECONFIG  = null;
        public static GenericFunction FUNCTION_EDIT_WAYPOINT_NAME = null;
        public static RearrangeWaypointsFunction FUNCTION_REARRANGE_WAYPOINTS = null;
@@ -88,8 +90,9 @@ public abstract class FunctionLibrary
                FUNCTION_KMLEXPORT = new KmlExporter(inApp);
                FUNCTION_POVEXPORT = new PovExporter(inApp);
                FUNCTION_SVGEXPORT = new SvgExporter(inApp);
-               FUNCTION_GPSLOAD   = new GpsLoader(inApp);
+               FUNCTION_GPSLOAD   = new BabelLoadFromGps(inApp);
                FUNCTION_GPSSAVE   = new GpsSaver(inApp);
+               FUNCTION_IMPORTBABEL = new BabelLoadFromFile(inApp);
                FUNCTION_SAVECONFIG = new SaveConfig(inApp);
                FUNCTION_EDIT_WAYPOINT_NAME = new PointNameEditor(inApp);
                FUNCTION_REARRANGE_WAYPOINTS = new RearrangeWaypointsFunction(inApp);
similarity index 93%
rename from tim/prune/GpsPruner.java
rename to tim/prune/GpsPrune.java
index 0028093a3e3412d8a0a51d613d5e61d65d6d19d8..41dac2b0d0300538ecb9813bd8f71462e5b8c828 100644 (file)
@@ -26,23 +26,23 @@ import tim.prune.gui.map.MapCanvas;
 import tim.prune.gui.profile.ProfileChart;
 
 /**
- * Prune is a tool to visualize, edit, convert and prune GPS data
+ * GpsPrune is a tool to visualize, edit, convert and prune GPS data
  * Please see the included readme.txt or http://activityworkshop.net
- * This software is copyright activityworkshop.net 2006-2010 and made available through the Gnu GPL version 2.
+ * This software is copyright activityworkshop.net 2006-2011 and made available through the Gnu GPL version 2.
  * For license details please see the included license.txt.
- * GpsPruner is the main entry point to the application, including initialisation and launch
+ * GpsPrune is the main entry point to the application, including initialisation and launch
  */
-public class GpsPruner
+public class GpsPrune
 {
        /** Version number of application, used in about screen and for version check */
-       public static final String VERSION_NUMBER = "12.1";
+       public static final String VERSION_NUMBER = "13";
        /** Build number, just used for about screen */
-       public static final String BUILD_NUMBER = "224";
+       public static final String BUILD_NUMBER = "240";
        /** Static reference to App object */
        private static App APP = null;
 
        /** Program name, used for Frame title and for Macs also on the system bar */
-       private static final String PROGRAM_NAME = "Prune";
+       private static final String PROGRAM_NAME = "GpsPrune";
 
 
        /**
@@ -200,7 +200,7 @@ public class GpsPruner
                UpdateMessageBroker.addSubscriber(profileDisp);
                StatusBar statusBar = new StatusBar();
                UpdateMessageBroker.addSubscriber(statusBar);
-               UpdateMessageBroker.informSubscribers("Prune v" + VERSION_NUMBER);
+               UpdateMessageBroker.informSubscribers("GpsPrune v" + VERSION_NUMBER);
 
                // Arrange in the frame using split panes
                JSplitPane midSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mapDisp, profileDisp);
@@ -235,6 +235,8 @@ public class GpsPruner
                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},
index 5f3e0cd725c396b48bf3ead4bfe72e05d88a46d0..babe9e1c14d54b4ac6ce54590dfb47abf71dd41c 100644 (file)
@@ -3,7 +3,7 @@ package tim.prune.config;
 import java.awt.Color;
 
 /**
- * Class to hold a colour scheme for Prune, including
+ * Class to hold a colour scheme for GpsPrune, including
  * colours for background, points, selections and texts
  */
 public class ColourScheme
index 0873b0f505be1ded6b2985b6da0509631890964e..412f408b803c79055ffbe7eb100ab9d707d606c2 100644 (file)
@@ -4,6 +4,8 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.util.Properties;
 
+import tim.prune.data.RecentFileList;
+
 
 /**
  * Abstract class to hold application-wide configuration
@@ -17,9 +19,12 @@ public abstract class Config
        private static Properties _configValues = new Properties();
        /** Colour scheme object is also part of config */
        private static ColourScheme _colourScheme = new ColourScheme();
+       /** Recently-used file list */
+       private static RecentFileList _recentFiles = new RecentFileList();
 
        /** Default config file */
-       private static final File DEFAULT_CONFIG_FILE = new File(".pruneconfig");
+       public static final File DEFAULT_CONFIG_FILE = new File(".pruneconfig");
+       public static final File HOME_CONFIG_FILE = new File(System.getProperty("user.home"), ".pruneconfig");
 
        /** Key for track directory */
        public static final String KEY_TRACK_DIR = "prune.trackdirectory";
@@ -63,6 +68,10 @@ public abstract class Config
        public static final String KEY_LINE_WIDTH = "prune.linewidth";
        /** Key for kml track colour */
        public static final String KEY_KML_TRACK_COLOUR = "prune.kmltrackcolour";
+       /** Key for autosaving settings */
+       public static final String KEY_AUTOSAVE_SETTINGS = "prune.autosavesettings";
+       /** Key for recently used files */
+       public static final String KEY_RECENT_FILES = "prune.recentfiles";
 
 
        /**
@@ -70,11 +79,21 @@ public abstract class Config
         */
        public static void loadDefaultFile()
        {
-               try
+               if (DEFAULT_CONFIG_FILE.exists())
+               {
+                       try {
+                               loadFile(DEFAULT_CONFIG_FILE);
+                               return;
+                       }
+                       catch (ConfigException ce) {} // ignore
+               }
+               if (HOME_CONFIG_FILE.exists())
                {
-                       loadFile(DEFAULT_CONFIG_FILE);
+                       try {
+                               loadFile(HOME_CONFIG_FILE);
+                       }
+                       catch (ConfigException ce) {} // ignore
                }
-               catch (ConfigException ce) {} // ignore
        }
 
 
@@ -107,6 +126,7 @@ public abstract class Config
                // Save all properties from file
                _configValues.putAll(props);
                _colourScheme.loadFromHex(_configValues.getProperty(KEY_COLOUR_SCHEME));
+               _recentFiles = new RecentFileList(_configValues.getProperty(KEY_RECENT_FILES));
                if (loadFailed) {
                        throw new ConfigException();
                }
@@ -130,6 +150,7 @@ public abstract class Config
                props.put(KEY_GPSBABEL_PATH, "gpsbabel");
                props.put(KEY_KMZ_IMAGE_WIDTH, "240");
                props.put(KEY_KMZ_IMAGE_HEIGHT, "240");
+               props.put(KEY_AUTOSAVE_SETTINGS, "0"); // autosave false by default
                return props;
        }
 
@@ -158,6 +179,8 @@ public abstract class Config
         */
        public static Properties getAllConfig()
        {
+               // Update recently-used files
+               _configValues.setProperty(KEY_RECENT_FILES, _recentFiles.getConfigString());
                return _configValues;
        }
 
@@ -169,6 +192,14 @@ public abstract class Config
                return _colourScheme;
        }
 
+       /**
+        * @return list of recently used files
+        */
+       public static RecentFileList getRecentFileList()
+       {
+               return _recentFiles;
+       }
+
        /**
         * Store the given configuration setting
         * @param inKey key (from constants)
index c25b77ef923fe6b703213fad87bf7b5d127da7f2..d65d1dda57ca108c6eb889548d2bfa055b6e4410 100644 (file)
@@ -1,4 +1,4 @@
-The source code of Prune is copyright 2006-2010 activityworkshop.net
+The source code of GpsPrune is copyright 2006-2011 activityworkshop.net
 and is distributed under the terms of the Gnu GPL version 2.
 
 Portions of the package jpeg.drew (if included in this package) were taken
index 57ecb7f05b513416afa1b386fb5f0619e7de9f1c..432674e1547dc7765d8b507fcd2baa9e4205a761 100644 (file)
@@ -11,17 +11,17 @@ import tim.prune.App;
 import tim.prune.DataSubscriber;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
-import tim.prune.data.AudioFile;
+import tim.prune.data.AudioClip;
 import tim.prune.data.AudioList;
 import tim.prune.data.DataPoint;
-import tim.prune.data.MediaFile;
+import tim.prune.data.MediaObject;
 import tim.prune.data.MediaList;
 import tim.prune.data.TimeDifference;
 import tim.prune.data.Timestamp;
 import tim.prune.undo.UndoCorrelateAudios;
 
 /**
- * Class to manage the automatic correlation of audio files to points
+ * Class to manage the automatic correlation of audio clips to points
  * which is very similar to the PhotoCorrelator apart from the clip lengths
  */
 public class AudioCorrelator extends Correlator
@@ -92,7 +92,7 @@ public class AudioCorrelator extends Correlator
        {
                for (int i=0; i<inAudios.getNumMedia(); i++)
                {
-                       AudioFile a = inAudios.getAudio(i);
+                       AudioClip a = inAudios.getAudio(i);
                        if (a.getLengthInSeconds() > 0) {return true;}
                }
                return false;
@@ -113,13 +113,13 @@ public class AudioCorrelator extends Correlator
                int numAudios = audios.getNumAudios();
                for (int i=0; i<numAudios; i++)
                {
-                       AudioFile audio = audios.getAudio(i);
+                       AudioClip audio = audios.getAudio(i);
                        PointMediaPair pair = getPointPairForMedia(_app.getTrackInfo().getTrack(), audio, inTimeDiff);
                        MediaPreviewTableRow row = new MediaPreviewTableRow(pair);
                        // Don't try to correlate audios which don't have points either side
                        boolean correlateAudio = pair.isValid();
                        // Don't select audios which already have a point
-                       if (audio.getCurrentStatus() != AudioFile.Status.NOT_CONNECTED) {correlateAudio = false;}
+                       if (audio.getCurrentStatus() != AudioClip.Status.NOT_CONNECTED) {correlateAudio = false;}
                        // Check time limits, distance limits
                        if (timeLimit != null && correlateAudio) {
                                long numSecs = pair.getMinSeconds();
@@ -161,11 +161,11 @@ public class AudioCorrelator extends Correlator
        /**
         * @return modified timestamp of specified media object
         */
-       protected Timestamp getMediaTimestamp(MediaFile inMedia)
+       protected Timestamp getMediaTimestamp(MediaObject inMedia)
        {
                Timestamp tstamp = super.getMediaTimestamp(inMedia);
                try {
-                       AudioFile audio = (AudioFile) inMedia;
+                       AudioClip audio = (AudioClip) inMedia;
                        int audioLength = audio.getLengthInSeconds();
                        // Each option is worth half the length of the audio clip, so need to divide by 2
                        int secsToAdd = audioLength *
@@ -203,11 +203,11 @@ public class AudioCorrelator extends Correlator
                                if (pair.getMinSeconds() == 0L)
                                {
                                        // exact match
-                                       AudioFile pointAudio = pair.getPointBefore().getAudio();
+                                       AudioClip pointAudio = pair.getPointBefore().getAudio();
                                        if (pointAudio == null)
                                        {
                                                // photo coincides with audioless point so connect the two
-                                               pair.getPointBefore().setAudio((AudioFile) pair.getMedia());
+                                               pair.getPointBefore().setAudio((AudioClip) pair.getMedia());
                                                pair.getMedia().setDataPoint(pair.getPointBefore());
                                        }
                                        else if (pointAudio.equals(pair.getMedia())) {
@@ -253,7 +253,7 @@ public class AudioCorrelator extends Correlator
                                        if (pointToAdd != null)
                                        {
                                                // link audio to point
-                                               pointToAdd.setAudio((AudioFile) pair.getMedia());
+                                               pointToAdd.setAudio((AudioClip) pair.getMedia());
                                                pair.getMedia().setDataPoint(pointToAdd);
                                                // set to start of segment so not joined in track
                                                pointToAdd.setSegmentStart(true);
index ee0ce0d1e5099517f921a6112240f7304d0e8df2..781dbd7a6b771d4cbbc2de89bb872245e1e2dfc9 100644 (file)
@@ -14,7 +14,7 @@ import tim.prune.I18nManager;
 
 /**
  * GUI element to allow the selection of timestamp options
- * for audio file correlation
+ * for audio clip correlation
  */
 public class AudioTimestampSelector extends JPanel
 {
index 248be18b11b49e24cef3cd59ab983e91c164859f..7ac2da797f855ab8e1a892829e2a2ef24c130771 100644 (file)
@@ -30,7 +30,7 @@ import tim.prune.I18nManager;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Distance;
 import tim.prune.data.Field;
-import tim.prune.data.MediaFile;
+import tim.prune.data.MediaObject;
 import tim.prune.data.MediaList;
 import tim.prune.data.TimeDifference;
 import tim.prune.data.Timestamp;
@@ -194,10 +194,10 @@ public abstract class Correlator extends GenericFunction
                int numMedia = mediaList.getNumMedia();
                for (int i=0; i<numMedia; i++)
                {
-                       MediaFile media = mediaList.getMedia(i);
+                       MediaObject media = mediaList.getMedia(i);
                        // For working out time differences, can't use media which already had point information
                        if (media.getDataPoint() != null && media.getDataPoint().hasTimestamp()
-                               && media.getOriginalStatus() == MediaFile.Status.NOT_CONNECTED)
+                               && media.getOriginalStatus() == MediaObject.Status.NOT_CONNECTED)
                        {
                                // Calculate time difference, add to table model
                                long timeDiff = getMediaTimestamp(media).getSecondsSince(media.getDataPoint().getTimestamp());
@@ -583,7 +583,7 @@ public abstract class Correlator extends GenericFunction
         * @param inTimeDiff time difference to use for time offsets
         * @param inFirstMedia first media object to use for calculating timezone
         */
-       protected void setupPreviewCard(TimeDifference inTimeDiff, MediaFile inFirstMedia)
+       protected void setupPreviewCard(TimeDifference inTimeDiff, MediaObject inFirstMedia)
        {
                _previewEnabled = false;
                TimeDifference timeDiff = inTimeDiff;
@@ -619,7 +619,7 @@ public abstract class Correlator extends GenericFunction
         * @param inMedia media object
         * @return normally just returns the media timestamp, overridden by audio correlator
         */
-       protected Timestamp getMediaTimestamp(MediaFile inMedia)
+       protected Timestamp getMediaTimestamp(MediaObject inMedia)
        {
                return inMedia.getTimestamp();
        }
@@ -631,7 +631,7 @@ public abstract class Correlator extends GenericFunction
         * @param inOffset time offset to apply
         * @return point pair resulting from correlation
         */
-       protected PointMediaPair getPointPairForMedia(Track inTrack, MediaFile inMedia, TimeDifference inOffset)
+       protected PointMediaPair getPointPairForMedia(Track inTrack, MediaObject inMedia, TimeDifference inOffset)
        {
                PointMediaPair pair = new PointMediaPair(inMedia);
                // Add/subtract offset to media timestamp
index ea930493224b284cb54e1f5a81fe6498468ebb5f..78120ec784050a9b697c9bd2e172200e427e0989 100644 (file)
@@ -87,7 +87,7 @@ public class MediaPreviewTableModel extends AbstractTableModel
        public Object getValueAt(int inRowIndex, int inColumnIndex)
        {
                MediaPreviewTableRow row = _list.get(inRowIndex);
-               if (inColumnIndex == 0) return row.getMedia().getFile().getName();
+               if (inColumnIndex == 0) return row.getMedia().getName();
                else if (inColumnIndex == 1) {
                        return row.getMedia().getTimestamp().getText();
                }
index b06a05e6356b926eebb9d81da83595f51c2d56c2..69d059fffe53e2116f93bc94f81f416900a21ebd 100644 (file)
@@ -3,7 +3,7 @@ package tim.prune.correlate;
 import java.util.ArrayList;
 import javax.swing.table.AbstractTableModel;
 import tim.prune.I18nManager;
-import tim.prune.data.MediaFile;
+import tim.prune.data.MediaObject;
 
 
 /**
@@ -82,7 +82,7 @@ public class MediaSelectionTableModel extends AbstractTableModel
        {
                // MAYBE: only show time of photos (not date) if dates all identical
                MediaSelectionTableRow row = _list.get(inRowIndex);
-               if (inColumnIndex == 0) return row.getMedia().getFile().getName();
+               if (inColumnIndex == 0) return row.getMedia().getName();
                else if (inColumnIndex == 1) return row.getMedia().getTimestamp().getText();
                else if (inColumnIndex == 2) return row.getTimeDiff().getDescription();
                return (row.getTimeDiff().getIsPositive() ? I18nManager.getText("dialog.about.yes") :
@@ -102,7 +102,7 @@ public class MediaSelectionTableModel extends AbstractTableModel
         * @param inMedia item to add
         * @param inTimeDiff time difference
         */
-       public void addMedia(MediaFile inMedia, long inTimeDiff)
+       public void addMedia(MediaObject inMedia, long inTimeDiff)
        {
                _list.add(new MediaSelectionTableRow(inMedia, inTimeDiff));
        }
index 6b9660bc0ed6bb18d0a147b17563c566dbc1cbc8..426a911580fb4354e83fdace8e0281f11613ceda 100644 (file)
@@ -1,6 +1,6 @@
 package tim.prune.correlate;
 
-import tim.prune.data.MediaFile;
+import tim.prune.data.MediaObject;
 import tim.prune.data.TimeDifference;
 
 /**
@@ -9,7 +9,7 @@ import tim.prune.data.TimeDifference;
  */
 public class MediaSelectionTableRow
 {
-       private MediaFile _media = null;
+       private MediaObject _media = null;
        private TimeDifference _timeDiff = null;
 
        /**
@@ -17,7 +17,7 @@ public class MediaSelectionTableRow
         * @param inMedia media item
         * @param inNumSecs number of seconds time difference as long
         */
-       public MediaSelectionTableRow(MediaFile inMedia, long inNumSecs)
+       public MediaSelectionTableRow(MediaObject inMedia, long inNumSecs)
        {
                _media = inMedia;
                _timeDiff = new TimeDifference(inNumSecs);
@@ -26,7 +26,7 @@ public class MediaSelectionTableRow
        /**
         * @return Media object
         */
-       public MediaFile getMedia() {
+       public MediaObject getMedia() {
                return _media;
        }
 
index 1ea83078dab88188be12befdb2df8be750e397c5..7e4b6de2a7ede28ba355d5d102bac68c358dd7b7 100644 (file)
@@ -1,14 +1,14 @@
 package tim.prune.correlate;
 
 import tim.prune.data.DataPoint;
-import tim.prune.data.MediaFile;
+import tim.prune.data.MediaObject;
 
 /**
  * Class to hold a pair of points used to hold the result of correlation
  */
 public class PointMediaPair
 {
-       private MediaFile _media = null;
+       private MediaObject _media = null;
        private DataPoint _pointBefore = null;
        private DataPoint _pointAfter = null;
        private long _secondsBefore = 1L;
@@ -19,7 +19,7 @@ public class PointMediaPair
         * Constructor
         * @param inMedia media object
         */
-       public PointMediaPair(MediaFile inMedia) {
+       public PointMediaPair(MediaObject inMedia) {
                _media = inMedia;
        }
 
@@ -58,7 +58,7 @@ public class PointMediaPair
        /**
         * @return Media object
         */
-       public MediaFile getMedia() {
+       public MediaObject getMedia() {
                return _media;
        }
 
similarity index 52%
rename from tim/prune/data/AudioFile.java
rename to tim/prune/data/AudioClip.java
index 43089ab85570526ad833bff0dcb68283165c167b..b6dbd87948d6d60870d30d33b18dcf88a2703a86 100644 (file)
@@ -1,15 +1,16 @@
 package tim.prune.data;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import javax.sound.sampled.AudioFileFormat;
 import javax.sound.sampled.AudioSystem;
 
 /**
- * Class to represent an audio file for correlation
+ * Class to represent an audio clip for correlation
  */
-public class AudioFile extends MediaFile
+public class AudioClip extends MediaObject
 {
-       /** length of current audio file in seconds */
+       /** length of current audio clip in seconds */
        private int _lengthInSeconds = LENGTH_UNKNOWN;
 
        private static final int LENGTH_UNKNOWN = -1;
@@ -19,21 +20,36 @@ public class AudioFile extends MediaFile
         * Constructor
         * @param inFile file object
         */
-       public AudioFile(File inFile)
+       public AudioClip(File inFile)
        {
                // Timestamp is always just taken from the file modification stamp
                super(inFile, new Timestamp(inFile.lastModified()));
        }
 
        /**
-        * @return length of this audio file in seconds
+        * Constructor
+        * @param inData byte array of data
+        * @param inName name of source file
+        * @param inUrl url from which it came (or null)
+        */
+       public AudioClip(byte[] inData, String inName, String inUrl)
+       {
+               super(inData, inName, inUrl);
+       }
+
+       /**
+        * @return length of this audio clip in seconds
         */
        public int getLengthInSeconds()
        {
                if (_lengthInSeconds == LENGTH_UNKNOWN)
                {
                        try {
-                               AudioFileFormat format = AudioSystem.getAudioFileFormat(getFile());
+                               AudioFileFormat format = null;
+                               if (getFile() != null)
+                                       format = AudioSystem.getAudioFileFormat(getFile());
+                               else
+                                       format = AudioSystem.getAudioFileFormat(new ByteArrayInputStream(_data));
                                _lengthInSeconds = (int) (format.getFrameLength() / format.getFormat().getFrameRate());
                        }
                        catch (Exception e) {
index 928f2b9301266a74c8441d617379a7245436cffa..e42527fd17b84d884839341b0bd6f65381e1fb82 100644 (file)
@@ -3,7 +3,7 @@ package tim.prune.data;
 import java.util.ArrayList;
 
 /**
- * Class to hold a list of audio files, using the MediaList superclass
+ * Class to hold a list of audio clips, using the MediaList superclass
  */
 public class AudioList extends MediaList
 {
@@ -16,9 +16,9 @@ public class AudioList extends MediaList
 
        /**
         * Constructor
-        * @param inList ArrayList containing audio file objects
+        * @param inList ArrayList containing audio clip objects
         */
-       private AudioList(ArrayList<MediaFile> inList) {
+       private AudioList(ArrayList<MediaObject> inList) {
                super(inList);
        }
 
@@ -28,37 +28,37 @@ public class AudioList extends MediaList
        public AudioList cloneList()
        {
                if (getNumMedia() == 0) return this;
-               ArrayList<MediaFile> listCopy = new ArrayList<MediaFile>();
+               ArrayList<MediaObject> listCopy = new ArrayList<MediaObject>();
                listCopy.addAll(_media);
                return new AudioList(listCopy);
        }
 
        /**
-        * @return the number of audio files in the list
+        * @return the number of audio clips in the list
         */
        public int getNumAudios() {
                return getNumMedia();
        }
 
        /**
-        * Add an audio file to the list
+        * Add an audio clip to the list
         * @param inAudio object to add
         */
-       public void addAudio(AudioFile inAudio) {
+       public void addAudio(AudioClip inAudio) {
                addMedia(inAudio);
        }
 
        /**
-        * Add an audio file to the list
+        * Add an audio clip to the list
         * @param inAudio object to add
         * @param inIndex index at which to add
         */
-       public void addAudio(AudioFile inAudio, int inIndex) {
+       public void addAudio(AudioClip inAudio, int inIndex) {
                addMedia(inAudio, inIndex);
        }
 
        /**
-        * Remove the selected audio file from the list
+        * Remove the selected audio clip from the list
         * @param inIndex index number to remove
         */
        public void deleteAudio(int inIndex) {
@@ -66,11 +66,11 @@ public class AudioList extends MediaList
        }
 
        /**
-        * Get the index of the given audio file
+        * Get the index of the given audio clip
         * @param inAudio object to check
         * @return index of this object in the list, or -1 if not found
         */
-       public int getAudioIndex(AudioFile inAudio) {
+       public int getAudioIndex(AudioClip inAudio) {
                return getMediaIndex(inAudio);
        }
 
@@ -79,8 +79,8 @@ public class AudioList extends MediaList
         * @param inIndex index number, starting at 0
         * @return specified object
         */
-       public AudioFile getAudio(int inIndex) {
-               return (AudioFile) getMedia(inIndex);
+       public AudioClip getAudio(int inIndex) {
+               return (AudioClip) getMedia(inIndex);
        }
 
        /**
index 556bd892797cac3834f89d316dadbb6a726d0fab..40853ebc62505983b132abb71c85afcc041bc115 100644 (file)
@@ -60,7 +60,7 @@ public abstract class Coordinate
                        inString = inString.trim();
                        strLen = inString.length();
                }
-               if (strLen > 1)
+               if (strLen > 0)
                {
                        // Check for cardinal character either at beginning or end
                        boolean hasCardinal = true;
@@ -98,8 +98,11 @@ public abstract class Coordinate
                                                        numFields++;
                                                        denoms[numFields-1] = 1;
                                                }
-                                               fields[numFields-1] = fields[numFields-1] * 10 + (currChar - '0');
-                                               denoms[numFields-1] *= 10;
+                                               if (denoms[numFields-1] < 1E18) // ignore trailing characters if too big for long
+                                               {
+                                                       fields[numFields-1] = fields[numFields-1] * 10 + (currChar - '0');
+                                                       denoms[numFields-1] *= 10;
+                                               }
                                        }
                                        else
                                        {
index e053e1ad14405add6a237b4e748884c8575fe3c4..3d17cbc5edec4797a3dd63fee6e58579bcdd6025 100644 (file)
@@ -19,8 +19,8 @@ public class DataPoint
        private Timestamp _timestamp = null;
        /** Attached photo */
        private Photo _photo = null;
-       /** Attached audio file */
-       private AudioFile _audio = null;
+       /** Attached audio clip */
+       private AudioClip _audio = null;
        private String _waypointName = null;
        private boolean _startOfSegment = false;
        private boolean _markedForDeletion = false;
@@ -315,10 +315,10 @@ public class DataPoint
        }
 
        /**
-        * Set the audio file for this point
+        * Set the audio clip for this point
         * @param inAudio audio object
         */
-       public void setAudio(AudioFile inAudio) {
+       public void setAudio(AudioClip inAudio) {
                _audio = inAudio;
                _modifyCount++;
        }
@@ -326,23 +326,23 @@ public class DataPoint
        /**
         * @return associated audio object
         */
-       public AudioFile getAudio() {
+       public AudioClip getAudio() {
                return _audio;
        }
 
        /**
         * Attach the given media object according to type
-        * @param inMedia either a photo or an audio file
+        * @param inMedia either a photo or an audio clip
         */
-       public void attachMedia(MediaFile inMedia)
+       public void attachMedia(MediaObject inMedia)
        {
                if (inMedia != null) {
                        if (inMedia instanceof Photo) {
                                setPhoto((Photo) inMedia);
                                inMedia.setDataPoint(this);
                        }
-                       else if (inMedia instanceof AudioFile) {
-                               setAudio((AudioFile) inMedia);
+                       else if (inMedia instanceof AudioClip) {
+                               setAudio((AudioClip) inMedia);
                                inMedia.setDataPoint(this);
                        }
                }
index fa4600d8888fe7f4c85dd3f0a25da7414cdc9205..6d877049e295515a7a6e895207b114f4c35b458c 100644 (file)
@@ -17,12 +17,13 @@ public class Field
        public static final Field TIMESTAMP = new Field("fieldname.timestamp", true);
        public static final Field WAYPT_NAME = new Field("fieldname.waypointname", true);
        public static final Field WAYPT_TYPE = new Field("fieldname.waypointtype", true);
+       public static final Field DESCRIPTION = new Field("fieldname.description", true);
        public static final Field NEW_SEGMENT = new Field("fieldname.newsegment", true);
 
        // TODO: Field for photo filename, ability to load (from text) and save (to text)
 
        private static final Field[] ALL_AVAILABLE_FIELDS = {
-               LATITUDE, LONGITUDE, ALTITUDE, TIMESTAMP, WAYPT_NAME, WAYPT_TYPE, NEW_SEGMENT,
+               LATITUDE, LONGITUDE, ALTITUDE, TIMESTAMP, WAYPT_NAME, WAYPT_TYPE, DESCRIPTION, NEW_SEGMENT,
                new Field(I18nManager.getText("fieldname.custom"))
        };
 
index 3fc87fe81a8dc936e5651dd541794f98927e068f..d7b4780e7cd6e32447dcaa77e10976cb73a9923f 100644 (file)
@@ -7,8 +7,8 @@ import java.util.ArrayList;
  */
 public abstract class MediaList
 {
-       /** list of media file objects */
-       protected ArrayList<MediaFile> _media = null;
+       /** list of media objects */
+       protected ArrayList<MediaObject> _media = null;
 
 
        /**
@@ -22,11 +22,11 @@ public abstract class MediaList
         * Constructor
         * @param inList ArrayList containing media objects
         */
-       protected MediaList(ArrayList<MediaFile> inList)
+       protected MediaList(ArrayList<MediaObject> inList)
        {
                _media = inList;
                if (_media == null) {
-                       _media = new ArrayList<MediaFile>();
+                       _media = new ArrayList<MediaObject>();
                }
        }
 
@@ -41,7 +41,7 @@ public abstract class MediaList
         * Add an object to the list
         * @param inObject object to add
         */
-       public void addMedia(MediaFile inObject)
+       public void addMedia(MediaObject inObject)
        {
                if (inObject != null) {
                        _media.add(inObject);
@@ -53,7 +53,7 @@ public abstract class MediaList
         * @param inObject object to add
         * @param inIndex index at which to add
         */
-       public void addMedia(MediaFile inObject, int inIndex)
+       public void addMedia(MediaObject inObject, int inIndex)
        {
                if (inObject != null) {
                        _media.add(inIndex, inObject);
@@ -77,7 +77,7 @@ public abstract class MediaList
         * @param inMedia media object to check
         * @return true if it's already in the list
         */
-       public boolean contains(MediaFile inMedia) {
+       public boolean contains(MediaObject inMedia) {
                return (getMediaIndex(inMedia) > -1);
        }
 
@@ -87,16 +87,16 @@ public abstract class MediaList
         * @param inMedia object to check
         * @return index of this object in the list, or -1 if not found
         */
-       public int getMediaIndex(MediaFile inMedia)
+       public int getMediaIndex(MediaObject inMedia)
        {
                // Check if we need to check
                final int num = getNumMedia();
-               if (num <= 0 || inMedia == null || inMedia.getFile() == null)
+               if (num <= 0 || inMedia == null)
                        return -1;
                // Loop over list
                for (int i=0; i<num; i++)
                {
-                       MediaFile m = _media.get(i);
+                       MediaObject m = _media.get(i);
                        if (m != null && m.equals(inMedia)) {
                                return i;
                        }
@@ -111,7 +111,7 @@ public abstract class MediaList
         * @param inIndex index number, starting at 0
         * @return specified object
         */
-       public MediaFile getMedia(int inIndex)
+       public MediaObject getMedia(int inIndex)
        {
                if (inIndex < 0 || inIndex >= getNumMedia()) return null;
                return _media.get(inIndex);
@@ -147,7 +147,7 @@ public abstract class MediaList
                final int num = getNumMedia();
                String[] names = new String[num];
                for (int i=0; i<num; i++) {
-                       names[i] = getMedia(i).getFile().getName();
+                       names[i] = getMedia(i).getName();
                }
                return names;
        }
@@ -158,7 +158,7 @@ public abstract class MediaList
         */
        public boolean hasCorrelatedMedia()
        {
-               for (MediaFile m : _media) {
+               for (MediaObject m : _media) {
                        if (m.getDataPoint() != null) {
                                return true;
                        }
@@ -171,7 +171,7 @@ public abstract class MediaList
         */
        public boolean hasUncorrelatedMedia()
        {
-               for (MediaFile m : _media) {
+               for (MediaObject m : _media) {
                        if (m.getDataPoint() == null) {
                                return true;
                        }
@@ -188,9 +188,9 @@ public abstract class MediaList
                if (getNumMedia() > 0)
                {
                        // Construct new list to copy into
-                       ArrayList<MediaFile> listCopy = new ArrayList<MediaFile>();
+                       ArrayList<MediaObject> listCopy = new ArrayList<MediaObject>();
                        // Loop over list
-                       for (MediaFile m : _media)
+                       for (MediaObject m : _media)
                        {
                                // Copy media if it has no point
                                if (m != null)
@@ -206,6 +206,19 @@ public abstract class MediaList
                }
        }
 
+       /**
+        * @return true if any of the media objects have Files
+        */
+       public boolean hasMediaWithFile()
+       {
+               for (MediaObject m: _media) {
+                       if (m.getFile() != null) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
        /**
         * @return clone of list contents
         */
similarity index 56%
rename from tim/prune/data/MediaFile.java
rename to tim/prune/data/MediaObject.java
index d860db8f91374e603bf82c948e11aedfd85f7493..e028f4ab4ddc7f1050f0c9e2e3792da90c3e6c41 100644 (file)
@@ -3,13 +3,19 @@ package tim.prune.data;
 import java.io.File;
 
 /**
- * Class to represent a general media file for correlation.
- * Subclasses are currently Photo and AudioFile
+ * Class to represent a general media object for correlation.
+ * Subclasses are currently Photo and AudioClip
  */
-public abstract class MediaFile
+public abstract class MediaObject
 {
-       /** File where media is stored */
+       /** File where media is stored (if any) */
        protected File _file = null;
+       /** Name of file */
+       protected String _name = null;
+       /** Cached data if downloaded */
+       protected byte[] _data = null;
+       /** URL if media came from net */
+       protected String _url = null;
        /** Timestamp, if any */
        protected Timestamp _timestamp = null;
        /** Associated DataPoint if correlated */
@@ -20,7 +26,8 @@ public abstract class MediaFile
        private Status _currentStatus = Status.NOT_CONNECTED;
 
        /** Connection status */
-       public enum Status {
+       public enum Status
+       {
                /** Media is not connected to any point */
                NOT_CONNECTED,
                /** Media has been connected to a point since it was loaded */
@@ -35,12 +42,29 @@ public abstract class MediaFile
         * @param inFile file object
         * @param inStamp timestamp object
         */
-       public MediaFile(File inFile, Timestamp inStamp)
+       public MediaObject(File inFile, Timestamp inStamp)
        {
                _file = inFile;
+               _name = inFile.getName();
+               _data = null;
                _timestamp = inStamp;
        }
 
+       /**
+        * Constructor for byte arrays
+        * @param inData byte array containing data
+        * @param inName name of object
+        * @param inUrl source url of object or null
+        */
+       public MediaObject(byte[] inData, String inName, String inUrl)
+       {
+               _file = null;
+               _data = inData;
+               _name = inName;
+               _url = inUrl;
+               _timestamp = null;
+       }
+
        /**
         * @return the file object
         */
@@ -48,6 +72,11 @@ public abstract class MediaFile
                return _file;
        }
 
+       /** @return media name */
+       public String getName() {
+               return _name;
+       }
+
        /**
         * @return the timestamp object
         */
@@ -62,11 +91,27 @@ public abstract class MediaFile
                _timestamp = inTimestamp;
        }
 
+       /**
+        * @return byte data of media
+        */
+       public byte[] getByteData() {
+               return _data;
+       }
+
+       /**
+        * @return source Url (or null)
+        */
+       public String getUrl() {
+               return _url;
+       }
+
        /**
         * @return true if details are valid (might not have timestamp)
         */
-       public boolean isValid() {
-               return _file != null && _file.exists() && _file.canRead();
+       public boolean isValid()
+       {
+               return ((_file != null && _file.exists() && _file.canRead())
+                       || (_data != null && _data.length > 0));
        }
 
        /**
@@ -77,14 +122,21 @@ public abstract class MediaFile
        }
 
        /**
-        * Check if this object refers to the same File as another
-        * @param inOther other MediaFile object
-        * @return true if the Files are the same
+        * Check if this object refers to the same object as another
+        * @param inOther other MediaObject
+        * @return true if the objects are the same
         */
-       public boolean equals(MediaFile inOther)
+       public boolean equals(MediaObject inOther)
        {
-               return (inOther != null && inOther.getFile() != null && getFile() != null
-                       && inOther.getFile().equals(getFile()));
+               if (_file != null)
+               {
+                       // compare file objects
+                       return (inOther != null && inOther.getFile() != null && getFile() != null
+                               && inOther.getFile().equals(getFile()));
+               }
+               // compare data arrays
+               return (inOther != null && _name != null && inOther._name != null && _name.equals(inOther._name)
+                       && _data != null && inOther._data != null && _data.length == inOther._data.length);
        }
 
        /**
@@ -143,7 +195,7 @@ public abstract class MediaFile
        }
 
        /**
-        * @return true if file is connected to a point
+        * @return true if this object is connected to a point
         */
        public boolean isConnected()
        {
@@ -151,7 +203,7 @@ public abstract class MediaFile
        }
 
        /**
-        * Reset any cached data held by the media file (eg thumbnail)
+        * Reset any cached data (eg thumbnail)
         */
        public void resetCachedData() {}
 }
index c9046743a704ca2629e8341ebef1d4497f878384..0c5d9e51da160610757b299c7c6eee0924cebee5 100644 (file)
@@ -8,14 +8,16 @@ import javax.swing.ImageIcon;
 /**
  * Class to represent a photo and link to DataPoint
  */
-public class Photo extends MediaFile
+public class Photo extends MediaObject
 {
        /** Size of original image */
        private Dimension _size = null;
        /** rotation flag (clockwise from 0 to 3) */
        private int _rotation = 0;
        // TODO: Need to store caption for image?
-       // thumbnail for image (from exif)
+       /** Bearing, if any */
+       private double _bearing = -1.0;
+       /** thumbnail for image (from exif) */
        private byte[] _exifThumbnail = null;
 
        /**
@@ -27,12 +29,27 @@ public class Photo extends MediaFile
                super(inFile, null);
        }
 
+       /**
+        * Constructor using data, eg from zip file or URL
+        * @param inData data as byte array
+        * @param inName name of file from which it came
+        * @param inUrl url from which it came (or null)
+        */
+       public Photo(byte[] inData, String inName, String inUrl)
+       {
+               super(inData, inName, inUrl);
+       }
+
        /**
         * Calculate the size of the image (slow)
         */
        private void calculateSize()
        {
-               ImageIcon icon = new ImageIcon(_file.getAbsolutePath());
+               ImageIcon icon = null;
+               if (_file != null)
+                       icon = new ImageIcon(_file.getAbsolutePath());
+               else
+                       icon = new ImageIcon(_data);
                int width = icon.getIconWidth();
                int height = icon.getIconHeight();
                if (width > 0 && height > 0)
@@ -57,11 +74,7 @@ public class Photo extends MediaFile
         */
        public int getWidth()
        {
-               if (_size == null)
-               {
-                       calculateSize();
-                       if (_size == null) {return -1;}
-               }
+               if (getSize() == null) {return -1;}
                return _size.width;
        }
 
@@ -70,11 +83,7 @@ public class Photo extends MediaFile
         */
        public int getHeight()
        {
-               if (_size == null)
-               {
-                       calculateSize();
-                       if (_size == null) {return -1;}
-               }
+               if (getSize() == null) {return -1;}
                return _size.height;
        }
 
@@ -130,4 +139,30 @@ public class Photo extends MediaFile
        {
                return _rotation * 90;
        }
+
+       /**
+        * @return a new image icon for the whole image
+        */
+       public ImageIcon createImageIcon()
+       {
+               if (_file != null) {
+                       return new ImageIcon(_file.getAbsolutePath());
+               }
+               if (_data != null) {
+                       return new ImageIcon(_data);
+               }
+               return null;
+       }
+
+       /**
+        * @param inValue bearing in degrees, 0 to 360
+        */
+       public void setBearing(double inValue) {
+               _bearing = inValue;
+       }
+
+       /** @return bearing in degrees */
+       public double getBearing() {
+               return _bearing;
+       }
 }
index 454055309285340476057efe4a51ad86a152ec74..328196259dcd1b20b259c436cc600c7ab6e9b52a 100644 (file)
@@ -18,7 +18,7 @@ public class PhotoList extends MediaList
         * Constructor
         * @param inList ArrayList containing Photo objects
         */
-       private PhotoList(ArrayList<MediaFile> inList) {
+       private PhotoList(ArrayList<MediaObject> inList) {
                super(inList);
        }
 
@@ -28,7 +28,7 @@ public class PhotoList extends MediaList
        public PhotoList cloneList()
        {
                if (getNumMedia() == 0) return this;
-               ArrayList<MediaFile> listCopy = new ArrayList<MediaFile>();
+               ArrayList<MediaObject> listCopy = new ArrayList<MediaObject>();
                listCopy.addAll(_media);
                return new PhotoList(listCopy);
        }
diff --git a/tim/prune/data/RecentFile.java b/tim/prune/data/RecentFile.java
new file mode 100644 (file)
index 0000000..d13388d
--- /dev/null
@@ -0,0 +1,77 @@
+package tim.prune.data;
+
+import java.io.File;
+
+/**
+ * Simple class to represent an entry in the recently-used files list
+ */
+public class RecentFile
+{
+       private boolean _regularLoad = true; // false for load via gpsbabel
+       private File _file = null;
+
+       /**
+        * Constructor
+        * @param inFile file
+        * @param inRegular true for regular load, false for gpsbabel load
+        */
+       public RecentFile(File inFile, boolean inRegular)
+       {
+               _file = inFile;
+               _regularLoad = inRegular;
+       }
+
+       /**
+        * Constructor
+        * @param inDesc String from config
+        */
+       public RecentFile(String inDesc)
+       {
+               if (inDesc != null && inDesc.length() > 3)
+               {
+                       _regularLoad = (inDesc.charAt(0) != 'g');
+                       _file = new File(inDesc.substring(1));
+               }
+       }
+
+       /**
+        * @return file object
+        */
+       public File getFile() {
+               return _file;
+       }
+
+       /**
+        * @return true for regular load, false for gpsbabel load
+        */
+       public boolean isRegularLoad() {
+               return _regularLoad;
+       }
+
+       /**
+        * @return true if file (still) exists
+        */
+       public boolean isValid() {
+               return _file != null && _file.exists() && _file.isFile();
+       }
+
+       /**
+        * @return string to save in config
+        */
+       public String getConfigString()
+       {
+               if (!isValid()) return "";
+               return (_regularLoad?"r":"g") + _file.getAbsolutePath();
+       }
+
+       /**
+        * Check for equality
+        * @param inOther other RecentFile object
+        * @return true if they both refer to the same file
+        */
+       public boolean isSameFile(RecentFile inOther)
+       {
+               return inOther != null && isValid() && inOther.isValid()
+                       && _file.equals(inOther._file);
+       }
+}
diff --git a/tim/prune/data/RecentFileList.java b/tim/prune/data/RecentFileList.java
new file mode 100644 (file)
index 0000000..ee8b84d
--- /dev/null
@@ -0,0 +1,164 @@
+package tim.prune.data;
+
+/**
+ * Class to hold and manage the list of recently used files
+ */
+public class RecentFileList
+{
+       private RecentFile[] _files = null;
+       private static final int DEFAULT_SIZE = 6;
+       private static final int MAX_SIZE = 20;
+
+       /**
+        * Default constructor
+        */
+       public RecentFileList()
+       {
+               _files = new RecentFile[DEFAULT_SIZE];
+       }
+
+       /**
+        * Constructor
+        * @param inString String from config
+        */
+       public RecentFileList(String inString)
+       {
+               _files = null;
+               int pos = 0;
+               if (inString != null && inString.length() > 0)
+               {
+                       for (String s : inString.split(";"))
+                       {
+                               if (pos == 0)
+                               {
+                                       int listSize = DEFAULT_SIZE;
+                                       try
+                                       {
+                                               listSize = Integer.parseInt(s);
+                                               if (listSize < 1 || listSize > MAX_SIZE) {
+                                                       listSize = DEFAULT_SIZE;
+                                               }
+                                       }
+                                       catch (NumberFormatException nfe) {}
+                                       _files = new RecentFile[listSize];
+                                       pos++;
+                               }
+                               else if (pos <= _files.length)
+                               {
+                                       RecentFile rf = new RecentFile(s);
+                                       if (rf.isValid())
+                                       {
+                                               _files[pos-1] = rf;
+                                               pos++;
+                                       }
+                               }
+                       }
+               }
+               if (_files == null) {
+                       _files = new RecentFile[DEFAULT_SIZE];
+               }
+       }
+
+       /**
+        * @return size of list (may not have this many entries yet)
+        */
+       public int getSize()
+       {
+               if (_files == null) return 0;
+               return _files.length;
+       }
+
+       /**
+        * @return the number of valid entries in the list
+        */
+       public int getNumEntries()
+       {
+               if (_files == null) return 0;
+               int numFound = 0;
+               for (RecentFile rf : _files) {
+                       if (rf != null && rf.isValid())
+                               numFound++;
+               }
+               return numFound;
+       }
+
+       /**
+        * @return string to save in config
+        */
+       public String getConfigString()
+       {
+               StringBuilder builder = new StringBuilder(100);
+               int size = getSize();
+               builder.append("" + size);
+               for (RecentFile f : _files)
+               {
+                       builder.append(';');
+                       if (f != null) builder.append(f.getConfigString());
+               }
+               return builder.toString();
+       }
+
+       /**
+        * Add the given file to the top of the list
+        * @param inRF file to add
+        */
+       public void addFile(RecentFile inRF)
+       {
+               // Build a new array with the latest file at the top
+               RecentFile[] files = new RecentFile[_files.length];
+               int rfIndex = 0;
+               if (inRF != null && inRF.isValid())
+               {
+                       files[rfIndex] = inRF;
+                       rfIndex++;
+               }
+               // Loop, copying the other files
+               for (RecentFile rf : _files)
+               {
+                       if (rf != null && rf.isValid() && (inRF==null || !rf.isSameFile(inRF)))
+                       {
+                               files[rfIndex] = rf;
+                               rfIndex++;
+                               if (rfIndex >= files.length) break;
+                       }
+               }
+               _files = files;
+       }
+
+       /**
+        * Verify all the entries and remove the invalid ones
+        */
+       public void verifyAll() {
+               addFile(null);
+       }
+
+       /**
+        * Get the RecentFile object at the given index
+        * @param inIndex index, starting at 0
+        * @return RecentFile object or null if out of range
+        */
+       public RecentFile getFile(int inIndex)
+       {
+               if (inIndex < 0 || inIndex >= _files.length) return null;
+               return _files[inIndex];
+       }
+
+       /**
+        * Resize the list to the new size
+        * @param inNewSize new size of list
+        */
+       public void resizeList(int inNewSize)
+       {
+               // don't do anything if size doesn't make sense
+               if (inNewSize > 0 && inNewSize <= MAX_SIZE)
+               {
+                       RecentFile[] files = new RecentFile[inNewSize];
+                       int numToCopy = _files.length;
+                       if (inNewSize < numToCopy) {
+                               numToCopy = inNewSize;
+                       }
+                       System.arraycopy(_files, 0, files, 0, numToCopy);
+                       _files = files;
+               }
+       }
+}
index 341bf0299410a3f767adcf9fbe9f3064d9053aef..e78d5754cbb40a14594f25c73f87edb2b4ac9fd0 100644 (file)
@@ -125,6 +125,7 @@ public class SourceInfo
                for (int i=0; i<_points.length && (idx < 0); i++) {
                        if (_points[i] == inPoint) {idx = i;}
                }
+               if (idx == -1) {return idx;}             // point not found
                if (_pointIndices == null) {return idx;} // All points loaded
                return _pointIndices[idx]; // use point index mapping
        }
index fa1be1e5f4c27fa8b076d075b8b621e8926bc273..fc65959bd3c6f2c25442d4e3bd15a78d98842f60 100644 (file)
@@ -46,6 +46,19 @@ public class Track
                _scaled = false;
        }
 
+       /**
+        * Constructor using fields and points from another Track
+        * @param inFieldList Field list from another Track object
+        * @param inPoints (edited) point array
+        */
+       public Track(FieldList inFieldList, DataPoint[] inPoints)
+       {
+               _masterFieldList = inFieldList;
+               _dataPoints = inPoints;
+               if (_dataPoints == null) _dataPoints = new DataPoint[0];
+               _numPoints = _dataPoints.length;
+               _scaled = false;
+       }
 
        /**
         * Load method, for initialising and reinitialising data
@@ -966,6 +979,7 @@ public class Track
         */
        public DataPoint getPreviousTrackPoint(int inStartIndex)
        {
+               // end index is given as _numPoints but actually it just counts down to -1
                return getNextTrackPoint(inStartIndex, _numPoints, false);
        }
 
@@ -1178,4 +1192,18 @@ public class Track
                }
                return false;
        }
+
+       /**
+        * @param inPoint point to check
+        * @return true if this track contains the given point
+        */
+       public boolean containsPoint(DataPoint inPoint)
+       {
+               if (inPoint == null) return false;
+               for (int i=0; i < getNumPoints(); i++)
+               {
+                       if (getPoint(i) == inPoint) return true;
+               }
+               return false; // not found
+       }
 }
index 3df964b2652643624352a72b4e0c2be93114ed14..58344142d390faf734df76edbf8fc557d5649c8e 100644 (file)
@@ -92,10 +92,10 @@ public class TrackInfo
        }
 
        /**
-        * Get the currently selected audio file, if any
-        * @return AudioFile if selected, otherwise null
+        * Get the currently selected audio clip, if any
+        * @return AudioClip if selected, otherwise null
         */
-       public AudioFile getCurrentAudio() {
+       public AudioClip getCurrentAudio() {
                return _audioList.getAudio(_selection.getCurrentAudioIndex());
        }
 
@@ -165,12 +165,12 @@ public class TrackInfo
         * @param inSet Set containing Audio objects
         * @return number of audio objects added
         */
-       public int addAudios(Set<AudioFile> inSet)
+       public int addAudios(Set<AudioClip> inSet)
        {
                int numAudiosAdded = 0;
                if (inSet != null && !inSet.isEmpty())
                {
-                       for (AudioFile audio : inSet)
+                       for (AudioClip audio : inSet)
                        {
                                if (audio != null && !_audioList.contains(audio))
                                {
@@ -208,7 +208,6 @@ public class TrackInfo
                if (_track.deletePoint(_selection.getCurrentPointIndex()))
                {
                        _selection.modifyPointDeleted();
-                       UpdateMessageBroker.informSubscribers();
                        return true;
                }
                return false;
@@ -260,7 +259,7 @@ public class TrackInfo
                int audioIndex = _selection.getCurrentAudioIndex();
                if (audioIndex >= 0)
                {
-                       AudioFile audio = _audioList.getAudio(audioIndex);
+                       AudioClip audio = _audioList.getAudio(audioIndex);
                        _audioList.deleteAudio(audioIndex);
                        // has it got a point?
                        if (audio.getDataPoint() != null)
@@ -374,6 +373,18 @@ public class TrackInfo
                selectPoint(_track.getPointIndex(inPoint));
        }
 
+       /**
+        * Increment the selected point index by the given increment
+        * @param inPointIncrement +1 for next point, -1 for previous etc
+        */
+       public void incrementPointIndex(int inPointIncrement)
+       {
+               int index = _selection.getCurrentPointIndex() + inPointIncrement;
+               if (index < 0) index = 0;
+               else if (index >= _track.getNumPoints()) index = _track.getNumPoints()-1;
+               selectPoint(index);
+       }
+
        /**
         * Select the data point with the given index
         * @param inPointIndex index of DataPoint to select, or -1 for none
@@ -400,7 +411,7 @@ public class TrackInfo
                        audioIndex = _audioList.getAudioIndex(selectedPoint.getAudio());
                }
                else if (audioIndex < 0 || _audioList.getAudio(audioIndex).isConnected()) {
-                       // deselect current audio file
+                       // deselect current audio clip
                        audioIndex = -1;
                }
                // give to selection
@@ -439,7 +450,7 @@ public class TrackInfo
                                pointIndex = -1;
                        }
                }
-               // Has the new point got an audio file?
+               // Has the new point got an audio clip?
                DataPoint selectedPoint = _track.getPoint(pointIndex);
                int audioIndex = _selection.getCurrentAudioIndex();
                if (selectedPoint != null) {
@@ -460,7 +471,7 @@ public class TrackInfo
        {
                if (_selection.getCurrentAudioIndex() == inAudioIndex) {return;}
                // Audio selection takes priority, deselecting point if necessary
-               AudioFile audio = _audioList.getAudio(inAudioIndex);
+               AudioClip audio = _audioList.getAudio(inAudioIndex);
                int pointIndex = _selection.getCurrentPointIndex();
                DataPoint currPoint = getCurrentPoint();
                if (audio != null)
index d0e4d3cdc56eaa77843bd826d72ca664d5456349..c2dc3fee7d08f1d1f7791408757b7d3cefbdfb67 100644 (file)
@@ -32,7 +32,7 @@ import javax.swing.JTextArea;
 import tim.prune.App;
 import tim.prune.ExternalTools;
 import tim.prune.GenericFunction;
-import tim.prune.GpsPruner;
+import tim.prune.GpsPrune;
 import tim.prune.I18nManager;
 import tim.prune.jpeg.ExifGateway;
 import tim.prune.threedee.WindowFactory;
@@ -81,14 +81,14 @@ public class AboutScreen extends GenericFunction
                JPanel aboutPanel = new JPanel();
                aboutPanel.setLayout(new BoxLayout(aboutPanel, BoxLayout.Y_AXIS));
                aboutPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-               JLabel titleLabel = new JLabel("Prune");
+               JLabel titleLabel = new JLabel("GpsPrune");
                titleLabel.setFont(new Font("SansSerif", Font.BOLD, 24));
                titleLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
                aboutPanel.add(titleLabel);
-               JLabel versionLabel = new JLabel(I18nManager.getText("dialog.about.version") + ": " + GpsPruner.VERSION_NUMBER);
+               JLabel versionLabel = new JLabel(I18nManager.getText("dialog.about.version") + ": " + GpsPrune.VERSION_NUMBER);
                versionLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
                aboutPanel.add(versionLabel);
-               JLabel buildLabel = new JLabel(I18nManager.getText("dialog.about.build") + ": " + GpsPruner.BUILD_NUMBER);
+               JLabel buildLabel = new JLabel(I18nManager.getText("dialog.about.build") + ": " + GpsPrune.BUILD_NUMBER);
                buildLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
                aboutPanel.add(buildLabel);
                aboutPanel.add(new JLabel(" "));
@@ -99,7 +99,7 @@ public class AboutScreen extends GenericFunction
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.languages")).append(" : ")
                        .append("\u010de\u0161tina, deutsch, english, espa\u00F1ol, fran\u00E7ais, italiano, magyar,<br>" +
                                " nederlands, polski, portugu\u00EAs, \u4e2d\u6587 (chinese), \u65E5\u672C\u8A9E (japanese), \uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean),<br>" +
-                               " schwiizerd\u00FC\u00FCtsch, t\u00FCrk\u00E7e, rom\u00E2n\u0103, afrikaans, bahasa indonesia, farsi</p>");
+                               " schwiizerd\u00FC\u00FCtsch, t\u00FCrk\u00E7e, rom\u00E2n\u0103, afrikaans, bahasa indonesia</p>");
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.translatedby")).append("</p>");
                JEditorPane descPane = new JEditorPane("text/html", descBuffer.toString());
                descPane.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
diff --git a/tim/prune/function/AsyncMediaLoader.java b/tim/prune/function/AsyncMediaLoader.java
new file mode 100644 (file)
index 0000000..0365125
--- /dev/null
@@ -0,0 +1,158 @@
+package tim.prune.function;
+
+import java.io.File;
+
+import tim.prune.App;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.AudioClip;
+import tim.prune.data.MediaObject;
+import tim.prune.data.Photo;
+import tim.prune.data.Track;
+import tim.prune.load.MediaHelper;
+import tim.prune.load.MediaLoadProgressDialog;
+import tim.prune.undo.UndoLoadAudios;
+import tim.prune.undo.UndoLoadPhotos;
+
+/**
+ * Function to load media asynchronously,
+ * either from inside a zip/kmz file or remotely
+ */
+public class AsyncMediaLoader extends GenericFunction
+implements Runnable, Cancellable
+{
+       /** Archive from which points were loaded */
+       private File _zipFile = null;
+       /** Array of links */
+       private String[] _linkArray = null;
+       /** Track to use for connecting */
+       private Track _track = null;
+       /** Cancelled flag */
+       private boolean _cancelled = false;
+
+
+       /**
+        * Constructor
+        * @param inApp App object
+        * @param inLinkArray array of links
+        * @param inTrack Track object for connecting points
+        */
+       public AsyncMediaLoader(App inApp, File inZipFile, String[] inLinkArray, Track inTrack)
+       {
+               super(inApp);
+               _zipFile = inZipFile;
+               _linkArray = inLinkArray;
+               _track = inTrack;
+       }
+
+       /**
+        * Begin the load
+        */
+       public void begin()
+       {
+               _cancelled = false;
+               if (_linkArray != null)
+                       new Thread(this).start();
+       }
+
+       /** Cancel */
+       public void cancel() {
+               _cancelled = true;
+       }
+
+       /**
+        * @return the name key
+        */
+       public String getNameKey() {
+               return "function.asyncmediaload";
+       }
+
+       /**
+        * Execute the load in a separate thread
+        */
+       public void run()
+       {
+               // Count links first so that progress bar can be shown
+               int numLinks = 0;
+               for (int i=0; i<_linkArray.length; i++) {
+                       if (_linkArray[i] != null) {
+                               numLinks++;
+                       }
+               }
+               if (numLinks <= 0) return;
+               // Make progress dialog
+               MediaLoadProgressDialog progressDialog = new MediaLoadProgressDialog(_app.getFrame(), this);
+               // Make array to store results
+               MediaObject[] media = new MediaObject[numLinks];
+               int currLink = 0;
+               for (int i=0; i<_linkArray.length && !_cancelled; i++)
+               {
+                       if (_linkArray[i] != null)
+                       {
+                               MediaObject mf = MediaHelper.createMediaObject(_zipFile, _linkArray[i]);
+                               if (mf != null)
+                               {
+                                       // attach media to point and set status
+                                       _track.getPoint(i).attachMedia(mf);
+                                       mf.setOriginalStatus(MediaObject.Status.TAGGED);
+                                       mf.setCurrentStatus(MediaObject.Status.TAGGED);
+                                       media[currLink] = mf;
+                                       // update progress
+                                       if (!_app.isBusyLoading())
+                                               progressDialog.showProgress(currLink, numLinks);
+                                       currLink++;
+                               }
+                               try {Thread.sleep(100);} catch (InterruptedException ie) {}
+                       }
+               }
+               progressDialog.close();
+
+               // Wait until App is ready to receive media (may have to ask about append/replace etc)
+               waitUntilAppReady();
+
+               // Go through the loaded media and check if the points are still in the track
+               int numPhotos = 0, numAudios = 0;
+               for (currLink=0; currLink<numLinks; currLink++)
+               {
+                       MediaObject mo = media[currLink];
+                       if (mo != null && _track.containsPoint(mo.getDataPoint()))
+                       {
+                               if (mo instanceof Photo)
+                               {
+                                       _app.getTrackInfo().getPhotoList().addPhoto((Photo) mo);
+                                       numPhotos++;
+                               }
+                               else if (mo instanceof AudioClip)
+                               {
+                                       _app.getTrackInfo().getAudioList().addAudio((AudioClip) mo);
+                                       numAudios++;
+                               }
+                       }
+               }
+               // Confirm and update
+               if (numPhotos > 0) {
+                       _app.completeFunction(new UndoLoadPhotos(numPhotos, 0), "" + numPhotos + " " +
+                               I18nManager.getText(numPhotos == 1?"confirm.jpegload.single":"confirm.jpegload.multi"));
+               }
+               if (numAudios > 0) {
+                       _app.completeFunction(new UndoLoadAudios(numAudios), I18nManager.getText("confirm.audioload"));
+               }
+               UpdateMessageBroker.informSubscribers(DataSubscriber.DATA_ADDED_OR_REMOVED);
+       }
+
+
+       /**
+        * Wait until the App is ready
+        */
+       private void waitUntilAppReady()
+       {
+               long waitInterval = 500; // milliseconds
+               while (_app.isBusyLoading())
+               {
+                       try {Thread.sleep(waitInterval);} catch (InterruptedException ie) {}
+                       waitInterval *= 1.2;
+               }
+       }
+}
diff --git a/tim/prune/function/Cancellable.java b/tim/prune/function/Cancellable.java
new file mode 100644 (file)
index 0000000..ad51474
--- /dev/null
@@ -0,0 +1,12 @@
+package tim.prune.function;
+
+/**
+ * Interface implemented by functions which can be cancelled
+ */
+public interface Cancellable
+{
+       /**
+        * Cancel the function
+        */
+       public void cancel();
+}
index a34319f26e899f68866dbae39b2ba05a64c6bec9..1d3192ab009ea9ad9ed1ecae95aba450a857e599 100644 (file)
@@ -11,12 +11,12 @@ import javax.swing.JOptionPane;
 
 import tim.prune.App;
 import tim.prune.GenericFunction;
-import tim.prune.GpsPruner;
+import tim.prune.GpsPrune;
 import tim.prune.I18nManager;
 import tim.prune.function.browser.BrowserLauncher;
 
 /**
- * Class to check the version of Prune
+ * Class to check the version of GpsPrune
  * and show an appropriate dialog
  */
 public class CheckVersionScreen extends GenericFunction
@@ -42,7 +42,7 @@ public class CheckVersionScreen extends GenericFunction
         */
        public void begin()
        {
-               final String filePathStart = "http://activityworkshop.net/software/prune/prune_versioncheck_";
+               final String filePathStart = "http://activityworkshop.net/software/gpsprune/gpsprune_versioncheck_";
                final String filePathEnd = ".txt";
                String latestVer = null;
                String nextVersion = null;
@@ -51,7 +51,7 @@ public class CheckVersionScreen extends GenericFunction
                try
                {
                        // Load properties from the url on the server
-                       InputStream inStream = new URL(filePathStart + GpsPruner.VERSION_NUMBER + filePathEnd).openStream();
+                       InputStream inStream = new URL(filePathStart + GpsPrune.VERSION_NUMBER + filePathEnd).openStream();
                        props.load(inStream);
 
                        // Extract the three fields we want, ignore others
@@ -68,7 +68,7 @@ public class CheckVersionScreen extends GenericFunction
                        JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.checkversion.error"),
                                I18nManager.getText(getNameKey()), JOptionPane.ERROR_MESSAGE);
                }
-               else if (latestVer.equals(GpsPruner.VERSION_NUMBER))
+               else if (latestVer.equals(GpsPrune.VERSION_NUMBER))
                {
                        // Version on the server is the same as this one
                        String displayMessage = I18nManager.getText("dialog.checkversion.uptodate");
@@ -106,7 +106,7 @@ public class CheckVersionScreen extends GenericFunction
                                == JOptionPane.YES_OPTION)
                        {
                                // User selected to launch home page
-                               BrowserLauncher.launchBrowser("http://activityworkshop.net/software/prune/download.html");
+                               BrowserLauncher.launchBrowser("http://activityworkshop.net/software/gpsprune/download.html");
                        }
                }
        }
index fa6f30b5c70cd2adf3935b13f4fa65bc3968678f..0998020f2f2f871ed9d1d8522af91d13b72ef9b5 100644 (file)
@@ -5,14 +5,14 @@ import tim.prune.DataSubscriber;
 import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
-import tim.prune.data.AudioFile;
+import tim.prune.data.AudioClip;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Photo;
 import tim.prune.undo.UndoConnectMedia;
 import tim.prune.undo.UndoOperation;
 
 /**
- * Function to connect either a photo or an audio file to the current point
+ * Function to connect either a photo or an audio clip to the current point
  */
 public class ConnectToPointFunction extends GenericFunction
 {
@@ -38,7 +38,7 @@ public class ConnectToPointFunction extends GenericFunction
        {
                Photo photo = _app.getTrackInfo().getCurrentPhoto();
                DataPoint point = _app.getTrackInfo().getCurrentPoint();
-               AudioFile audio = _app.getTrackInfo().getCurrentAudio();
+               AudioClip audio = _app.getTrackInfo().getCurrentAudio();
                boolean connectPhoto = (point != null && photo != null && point.getPhoto() == null);
                boolean connectAudio = (point != null && audio != null && point.getAudio() == null);
 
@@ -46,8 +46,8 @@ public class ConnectToPointFunction extends GenericFunction
                        // TODO: Let user choose whether to connect photo/audio or both
                }
                // Make undo object
-               UndoOperation undo = new UndoConnectMedia(point, connectPhoto?photo.getFile().getName():null,
-                       connectAudio?audio.getFile().getName():null);
+               UndoOperation undo = new UndoConnectMedia(point, connectPhoto?photo.getName():null,
+                       connectAudio?audio.getName():null);
                // Connect the media
                if (connectPhoto) {
                        photo.setDataPoint(point);
index abcd9c47ea182cfc1c3471154e52f780cf8c60d0..962da710a2a0ff65cf8e965c1dc8886f0c989a48 100644 (file)
@@ -5,7 +5,7 @@ import tim.prune.DataSubscriber;
 import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
-import tim.prune.data.AudioFile;
+import tim.prune.data.AudioClip;
 import tim.prune.data.DataPoint;
 import tim.prune.undo.UndoDisconnectMedia;
 import tim.prune.undo.UndoOperation;
@@ -33,11 +33,11 @@ public class DisconnectAudioFunction extends GenericFunction
         */
        public void begin()
        {
-               AudioFile audio = _app.getTrackInfo().getCurrentAudio();
+               AudioClip audio = _app.getTrackInfo().getCurrentAudio();
                if (audio != null && audio.getDataPoint() != null)
                {
                        DataPoint point = audio.getDataPoint();
-                       UndoOperation undo = new UndoDisconnectMedia(point, false, true, audio.getFile().getName());
+                       UndoOperation undo = new UndoDisconnectMedia(point, false, true, audio.getName());
                        // disconnect
                        audio.setDataPoint(null);
                        point.setAudio(null);
index 6223433ef5f21ad06a3287a9988c4cac744bed09..96e039dbe8856475f8a3fd464180ba606f64399a 100644 (file)
@@ -36,7 +36,7 @@ public class DisconnectPhotoFunction extends GenericFunction
                if (photo != null && photo.getDataPoint() != null)
                {
                        DataPoint point = photo.getDataPoint();
-                       UndoDisconnectMedia undo = new UndoDisconnectMedia(point, true, false, photo.getFile().getName());
+                       UndoDisconnectMedia undo = new UndoDisconnectMedia(point, true, false, photo.getName());
                        // disconnect
                        photo.setDataPoint(null);
                        point.setPhoto(null);
index 58643d1432f3a8be74a7f9486e31c255de087579..98a6405d7bc7f79633abb9ff1055ea63d0156639 100644 (file)
@@ -24,6 +24,7 @@ import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
 import tim.prune.config.Config;
+import tim.prune.function.cache.ManageCacheFunction;
 
 /**
  * Class to show the popup window for setting the path to disk cache
@@ -34,7 +35,7 @@ public class DiskCacheConfig extends GenericFunction
        private JCheckBox _cacheCheckbox = null;
        private JTextField _cacheDirBox = null;
        private JButton _browseButton = null;
-       private JButton _okButton = null;
+       private JButton _okButton = null, _manageButton = null;
        private boolean _initialCheckState = false;
        private String _initialCacheDir = null;
 
@@ -67,7 +68,7 @@ public class DiskCacheConfig extends GenericFunction
                _cacheCheckbox = new JCheckBox(I18nManager.getText("dialog.diskcache.save"));
                _cacheCheckbox.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent arg0) {
-                               enableOk();
+                               enableButtons();
                        }
                });
                topPanel.add(_cacheCheckbox);
@@ -75,12 +76,12 @@ public class DiskCacheConfig extends GenericFunction
                // dir panel
                JPanel dirPanel = new JPanel();
                dirPanel.setLayout(new BorderLayout());
-               dirPanel.add(new JLabel(I18nManager.getText("dialog.diskcache.dir")), BorderLayout.WEST);
+               dirPanel.add(new JLabel(I18nManager.getText("dialog.diskcache.dir") + " : "), BorderLayout.WEST);
                _cacheDirBox = new JTextField(24);
                _cacheDirBox.addKeyListener(new KeyAdapter() {
                        public void keyReleased(KeyEvent arg0) {
                                super.keyReleased(arg0);
-                               enableOk();
+                               enableButtons();
                        }
                });
                dirPanel.add(_cacheDirBox, BorderLayout.CENTER);
@@ -91,20 +92,23 @@ public class DiskCacheConfig extends GenericFunction
                        }
                });
                dirPanel.add(_browseButton, BorderLayout.EAST);
-               dialogPanel.add(dirPanel, BorderLayout.CENTER);
+               // holder panel so it doesn't expand vertically
+               JPanel dirHolderPanel = new JPanel();
+               dirHolderPanel.setLayout(new BorderLayout());
+               dirHolderPanel.add(dirPanel, BorderLayout.NORTH);
+               dialogPanel.add(dirHolderPanel, BorderLayout.CENTER);
 
-               // Cancel button at the bottom
-               JPanel buttonPanel = new JPanel();
-               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               // OK, Cancel buttons at the bottom right
+               JPanel buttonPanelr = new JPanel();
+               buttonPanelr.setLayout(new FlowLayout(FlowLayout.RIGHT));
                _okButton = new JButton(I18nManager.getText("button.ok"));
-               _okButton.addActionListener(new ActionListener()
-               {
+               _okButton.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
                                finish();
                        }
                });
-               buttonPanel.add(_okButton);
+               buttonPanelr.add(_okButton);
                JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
                cancelButton.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
@@ -112,17 +116,36 @@ public class DiskCacheConfig extends GenericFunction
                                _dialog.dispose();
                        }
                });
-               buttonPanel.add(cancelButton);
+               buttonPanelr.add(cancelButton);
+
+               // Manage button at the bottom left
+               JPanel buttonPanell = new JPanel();
+               buttonPanell.setLayout(new FlowLayout(FlowLayout.LEFT));
+               _manageButton = new JButton(I18nManager.getText("button.manage"));
+               _manageButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               finish();
+                               new ManageCacheFunction(_app).begin();
+                       }
+               });
+               buttonPanell.add(_manageButton);
+               // Put them together
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new BorderLayout());
+               buttonPanel.add(buttonPanelr, BorderLayout.EAST);
+               buttonPanel.add(buttonPanell, BorderLayout.WEST);
                dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
                return dialogPanel;
        }
 
        /**
-        * Enable or disable the ok button according to what's changed
+        * Enable or disable the buttons according to what's changed
         */
-       private void enableOk()
+       private void enableButtons()
        {
-               boolean checkState = _cacheCheckbox.isSelected();
+               final boolean checkState = _cacheCheckbox.isSelected();
+               final String path = _cacheDirBox.getText();
                _cacheDirBox.setEditable(checkState);
                _browseButton.setEnabled(checkState);
                boolean ok = false;
@@ -131,9 +154,9 @@ public class DiskCacheConfig extends GenericFunction
                else {
                        // If checkbox has been switched off then enable
                        if (!checkState) {ok = true;}
-                       else {
+                       else
+                       {
                                // checkbox is on, check value
-                               String path = _cacheDirBox.getText();
                                if (path.equals("") || (_initialCacheDir != null && path.equals(_initialCacheDir))) {
                                        // Value blank or same as before
                                        ok = false;
@@ -144,6 +167,14 @@ public class DiskCacheConfig extends GenericFunction
                        }
                }
                _okButton.setEnabled(ok);
+               // Manage button needs a valid cache
+               boolean cacheDirGood = false;
+               if (checkState && !path.equals(""))
+               {
+                       File dir = new File(path);
+                       cacheDirGood = dir.exists() && dir.canRead() && dir.isDirectory();
+               }
+               _manageButton.setEnabled(cacheDirGood);
        }
 
        /**
@@ -162,7 +193,7 @@ public class DiskCacheConfig extends GenericFunction
                String currPath = Config.getConfigString(Config.KEY_DISK_CACHE);
                _cacheCheckbox.setSelected(currPath != null);
                _cacheDirBox.setText(currPath==null?"":currPath);
-               enableOk();
+               enableButtons();
                // Remember current state
                _initialCheckState = _cacheCheckbox.isSelected();
                _dialog.setVisible(true);
@@ -182,7 +213,7 @@ public class DiskCacheConfig extends GenericFunction
                {
                        _cacheDirBox.setText(chooser.getSelectedFile().getAbsolutePath());
                }
-               enableOk();
+               enableButtons();
        }
 
        /**
index bef09adb14574e0ea87ff46e2cc98fe0ff3f7330..e3d362738d6814c8fc99cf6c86ec20baaaace679 100644 (file)
@@ -243,7 +243,7 @@ public class DownloadOsmFunction extends GenericFunction implements Runnable
         */
        public void run()
        {
-               final String url = "http://www.informationfreeway.org/api/0.6/map?bbox=" +
+               final String url = "http://xapi.openstreetmap.org/api/0.6/map?bbox=" +
                        _latLonLabels[1].getText() + "," + _latLonLabels[3].getText() + "," +
                        _latLonLabels[2].getText() + "," + _latLonLabels[0].getText();
 
@@ -263,8 +263,7 @@ public class DownloadOsmFunction extends GenericFunction implements Runnable
                }
                catch (MalformedURLException mue) {}
                catch (IOException ioe) {
-                       // TODO: throw exception or show dialog
-                       System.out.println("Exception: " + ioe.getClass().getName());
+                       _app.showErrorMessageNoLookup(getNameKey(), ioe.getClass().getName() + " - " + ioe.getMessage());
                }
                // clean up streams
                finally {
index acef09c6a15d3ba2a396df9b6733c781f97b856b..dc2da5b3cf37419704e8f08078208bf96210b26f 100644 (file)
@@ -26,6 +26,8 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
        private static final int MAX_RESULTS = 20;
        /** Maximum distance from point in km */
        private static final int MAX_DISTANCE = 15;
+       /** Username to use for geonames queries */
+       private static final String GEONAMES_USERNAME = "gpsprune";
 
 
        /**
@@ -77,10 +79,11 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
                String descMessage = "";
                InputStream inStream = null;
 
-               // Example http://ws.geonames.org/findNearbyWikipedia?lat=47&lng=9
-               String urlString = "http://ws.geonames.org/findNearbyWikipedia?lat=" +
+               // Example http://api.geonames.org/findNearbyWikipedia?lat=47&lng=9
+               String urlString = "http://api.geonames.org/findNearbyWikipedia?lat=" +
                        lat + "&lng=" + lon + "&maxRows=" + MAX_RESULTS
-                       + "&radius=" + MAX_DISTANCE + "&lang=" + I18nManager.getText("wikipedia.lang");
+                       + "&radius=" + MAX_DISTANCE + "&lang=" + I18nManager.getText("wikipedia.lang")
+                       + "&username=" + GEONAMES_USERNAME;
                // Parse the returned XML with a special handler
                GetWikipediaXmlHandler xmlHandler = new GetWikipediaXmlHandler();
                try
@@ -106,8 +109,16 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
                        descMessage = I18nManager.getText("dialog.gpsies.nonefound");
                }
                _statusLabel.setText(descMessage);
+               // Show error message if any
+               if (trackList == null || trackList.size() == 0) {
+                       String error = xmlHandler.getErrorMessage();
+                       if (error != null && !error.equals("")) {
+                               _app.showErrorMessageNoLookup(getNameKey(), error);
+                       }
+               }
        }
 
+
        /**
         * Load the selected track or point
         */
index 3cca682f7b6790a90cf5781339f728975b84f8bd..d9a3b747bf14d8e39ab1c92952e333039f22bd6d 100644 (file)
@@ -17,6 +17,7 @@ public class GetWikipediaXmlHandler extends DefaultHandler
        private ArrayList<GpsiesTrack> _trackList = null;
        private GpsiesTrack _track = null;
        private String _lat = null, _lon = null;
+       private String _errorMessage = null;
 
 
        /**
@@ -33,6 +34,9 @@ public class GetWikipediaXmlHandler extends DefaultHandler
                        _lat = null;
                        _lon = null;
                }
+               else if (inTagName.equals("status")) {
+                       _errorMessage = inAttributes.getValue("message");
+               }
                else _value = null;
                super.startElement(inUri, inLocalName, inTagName, inAttributes);
        }
@@ -90,4 +94,11 @@ public class GetWikipediaXmlHandler extends DefaultHandler
        {
                return _trackList;
        }
+
+       /**
+        * @return error message, if any
+        */
+       public String getErrorMessage() {
+               return _errorMessage;
+       }
 }
index 53816dce41ecd61d1eba1d5c7e97e1a487b201d2..25fb8ec42bae058dfb29cb4df2fe2f28646318f0 100644 (file)
@@ -41,7 +41,7 @@ public class HelpScreen extends GenericFunction
                        == JOptionPane.YES_OPTION)
                {
                        // User selected to launch home page
-                       BrowserLauncher.launchBrowser("http://activityworkshop.net/software/prune/index.html");
+                       BrowserLauncher.launchBrowser("http://activityworkshop.net/software/gpsprune/index.html");
                }
        }
 }
index 6b8b3e016143861f3caf648ce7f5dba03be381e4..1a81be110ad7636a6a314b8e44942be8e71887b1 100644 (file)
@@ -71,8 +71,8 @@ public class PhotoPopupFunction extends GenericFunction
        {
                _frame.setVisible(false);
                Photo photo = _app.getTrackInfo().getCurrentPhoto();
-               _frame.setTitle(photo.getFile().getName());
-               _label.setText("'" + photo.getFile().getName() + "' ("
+               _frame.setTitle(photo.getName());
+               _label.setText("'" + photo.getName() + "' ("
                        + photo.getWidth() + " x " + photo.getHeight() + ")");
                _photoThumb.setPhoto(photo);
        }
index 7e7a34a8ab56d05af8140f75d4e6def27d6f1c35..0e14d7c9ad1f9f6c9f4df9f761b7c466838b751d 100644 (file)
@@ -1,5 +1,6 @@
 package tim.prune.function;
 
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import javax.sound.sampled.AudioInputStream;
@@ -8,9 +9,10 @@ import javax.sound.sampled.Clip;
 
 import tim.prune.App;
 import tim.prune.GenericFunction;
+import tim.prune.data.AudioClip;
 
 /**
- * Class to play the current audio file
+ * Class to play the current audio clip
  */
 public class PlayAudioFunction extends GenericFunction implements Runnable
 {
@@ -49,12 +51,13 @@ public class PlayAudioFunction extends GenericFunction implements Runnable
         */
        public void run()
        {
-               File audioFile = _app.getTrackInfo().getCurrentAudio().getFile();
+               AudioClip audio = _app.getTrackInfo().getCurrentAudio();
+               File audioFile = audio.getFile();
                boolean played = false;
-               if (audioFile.exists() && audioFile.isFile() && audioFile.canRead())
+               if (audioFile != null && audioFile.exists() && audioFile.isFile() && audioFile.canRead())
                {
                        // First choice is to play using java
-                       played = playClip(audioFile);
+                       played = playClip(audio);
                        // Second choice is to try the Desktop library from java 6, if available
                        if (!played) {
                                try {
@@ -84,6 +87,10 @@ public class PlayAudioFunction extends GenericFunction implements Runnable
                                }
                        }
                }
+               else if (audioFile == null && audio.getByteData() != null) {
+                       // Try to play audio clip using byte array (can't use Desktop or Runtime)
+                       played = playClip(audio);
+               }
                if (!played)
                {
                        // If still not worked, show error message
@@ -93,16 +100,21 @@ public class PlayAudioFunction extends GenericFunction implements Runnable
 
        /**
         * Try to play the sound file using built-in java libraries
+        * @param inAudio audio clip to play
         * @return true if play was successful
         */
-       private boolean playClip(File inFile)
+       private boolean playClip(AudioClip inClip)
        {
                boolean success = false;
                AudioInputStream audioInputStream = null;
                _clip = null;
                try
                {
-                       audioInputStream = AudioSystem.getAudioInputStream(inFile);
+                       if (inClip.getFile() != null)
+                               audioInputStream = AudioSystem.getAudioInputStream(inClip.getFile());
+                       else if (inClip.getByteData() != null)
+                               audioInputStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(inClip.getByteData()));
+                       else return false;
                        _clip = AudioSystem.getClip();
                        _clip.open(audioInputStream);
                        // play the clip
@@ -110,6 +122,7 @@ public class PlayAudioFunction extends GenericFunction implements Runnable
                        _clip.drain();
                        success = true;
                } catch (Exception e) {
+                       System.err.println(e.getClass().getName() + " - " + e.getMessage());
                } finally {
                        // close the stream to clean up
                        try {
index 7a408c04988da527ce5d8a67366cc1a2de783ea7..b8d9312de7dce3c1c349c466ec101b8fe72c3d56 100644 (file)
@@ -194,17 +194,21 @@ public class RearrangePhotosFunction extends GenericFunction
        private static void sortPhotos(DataPoint[] inPhotos, boolean inSortByFile)
        {
                Comparator<DataPoint> comparator = null;
-               if (inSortByFile) {
+               if (inSortByFile)
+               {
                        // sort by filename
                        comparator = new Comparator<DataPoint>() {
                                public int compare(DataPoint inP1, DataPoint inP2) {
                                        if (inP2 == null) return -1; // all nulls at end
                                        if (inP1 == null) return 1;
+                                       if (inP1.getPhoto().getFile() == null || inP2.getPhoto().getFile() == null)
+                                               return inP1.getPhoto().getName().compareTo(inP2.getPhoto().getName());
                                        return inP1.getPhoto().getFile().compareTo(inP2.getPhoto().getFile());
                                }
                        };
                }
-               else {
+               else
+               {
                        // sort by photo timestamp
                        comparator = new Comparator<DataPoint>() {
                                public int compare(DataPoint inP1, DataPoint inP2) {
index fa859bec74f2a85ed643bd988ed1eaa2c87ee6f6..c4aa7200b3ba5e5f435fcfac4e4d9fab75c1f49a 100644 (file)
@@ -5,11 +5,11 @@ import javax.swing.JOptionPane;
 import tim.prune.App;
 import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
-import tim.prune.data.AudioFile;
+import tim.prune.data.AudioClip;
 import tim.prune.undo.UndoDeleteAudio;
 
 /**
- * Function to remove the currently selected audio file
+ * Function to remove the currently selected audio clip
  */
 public class RemoveAudioFunction extends GenericFunction
 {
@@ -32,7 +32,7 @@ public class RemoveAudioFunction extends GenericFunction
        public void begin()
        {
                // Delete the current audio, and optionally its point too, keeping undo information
-               AudioFile currentAudio = _app.getTrackInfo().getCurrentAudio();
+               AudioClip currentAudio = _app.getTrackInfo().getCurrentAudio();
                if (currentAudio != null)
                {
                        // Audio is selected, see if it has a point or not
@@ -61,7 +61,7 @@ public class RemoveAudioFunction extends GenericFunction
                        }
                        // Add undo information to stack if necessary
                        if (deleted) {
-                               _app.completeFunction(undoAction, currentAudio.getFile().getName() + " " + I18nManager.getText("confirm.media.removed"));
+                               _app.completeFunction(undoAction, currentAudio.getName() + " " + I18nManager.getText("confirm.media.removed"));
                        }
                }
        }
index b09ae102958eddc8b7d19b8705629f6f2fd71502..8cdf7bcf3cc935bddf3c47a374b85e460db1db66 100644 (file)
@@ -62,7 +62,7 @@ public class RemovePhotoFunction extends GenericFunction
                        }
                        // Add undo information to stack if necessary
                        if (photoDeleted) {
-                               _app.completeFunction(undoAction, currentPhoto.getFile().getName() + " " + I18nManager.getText("confirm.media.removed"));
+                               _app.completeFunction(undoAction, currentPhoto.getName() + " " + I18nManager.getText("confirm.media.removed"));
                        }
                }
        }
index 6c0e4d089cedcfc43e9b17ef7f5c0f328efcd6fb..af7eb83e20eee289c03f2588e1a27fe67f14eca5 100644 (file)
@@ -128,28 +128,46 @@ public class SaveConfig extends GenericFunction
        private void finish()
        {
                File configFile = Config.getConfigFile();
-               if (configFile == null) {configFile = new File(".pruneconfig");}
+               if (configFile == null) {configFile = Config.HOME_CONFIG_FILE;}
                JFileChooser chooser = new JFileChooser(configFile.getAbsoluteFile().getParent());
                chooser.setSelectedFile(configFile);
                int response = chooser.showSaveDialog(_parentFrame);
                if (response == JFileChooser.APPROVE_OPTION)
                {
                        File saveFile = chooser.getSelectedFile();
-                       FileOutputStream outStream = null;
-                       try
-                       {
-                               outStream = new FileOutputStream(saveFile);
-                               Config.getAllConfig().store(outStream, "Prune config file");
-                       }
-                       catch (IOException ioe) {
-                               _app.showErrorMessageNoLookup(getNameKey(),
-                                       I18nManager.getText("error.save.failed") + " : " + ioe.getMessage());
-                       }
-                       finally {
-                               try {outStream.close();} catch (Exception e) {}
-                       }
+                       saveConfig(saveFile);
                }
                _dialog.dispose();
                _dialog = null;
        }
+
+       /**
+        * Autosave the settings file without any prompts
+        */
+       public void silentSave()
+       {
+               saveConfig(Config.getConfigFile());
+       }
+
+       /**
+        * Actually save the config file
+        * @param inSaveFile file to save to
+        */
+       private void saveConfig(File inSaveFile)
+       {
+               FileOutputStream outStream = null;
+               try
+               {
+                       outStream = new FileOutputStream(inSaveFile);
+                       Config.getAllConfig().store(outStream, "GpsPrune config file");
+               }
+               catch (IOException ioe) {
+                       _app.showErrorMessageNoLookup(getNameKey(),
+                               I18nManager.getText("error.save.failed") + " : " + ioe.getMessage());
+               }
+               catch (NullPointerException npe) {} // no config file given
+               finally {
+                       try {outStream.close();} catch (Exception e) {}
+               }
+       }
 }
index 4377df81d5a39bbdd65bc897d0bf575104b2011e..ab24522eb68120168b49c420996f245ea8ffb32d 100644 (file)
@@ -1,7 +1,9 @@
 package tim.prune.function;
 
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
 import java.net.URL;
+import java.net.URLEncoder;
 import java.util.ArrayList;
 
 import javax.swing.JOptionPane;
@@ -26,6 +28,8 @@ public class SearchWikipediaNames extends GenericDownloaderFunction
        private String _searchTerm = null;
        /** Maximum number of results to get */
        private static final int MAX_RESULTS = 20;
+       /** Username to use for geonames queries */
+       private static final String GEONAMES_USERNAME = "gpsprune";
 
        /**
         * Constructor
@@ -88,9 +92,16 @@ public class SearchWikipediaNames extends GenericDownloaderFunction
                else {
                        lang = "en";
                }
+               // Replace awkward characters with character equivalents
+               String searchTerm;
+               try {
+                       searchTerm = URLEncoder.encode(_searchTerm, "UTF-8");
+               } catch (UnsupportedEncodingException e1) {
+                       searchTerm = _searchTerm;
+               }
                // Example http://ws.geonames.org/wikipediaSearch?q=london&maxRows=10
-               String urlString = "http://ws.geonames.org/wikipediaSearch?title=" + _searchTerm + "&maxRows=" + MAX_RESULTS
-                       + "&lang=" + lang;
+               String urlString = "http://api.geonames.org/wikipediaSearch?title=" + searchTerm
+                       + "&maxRows=" + MAX_RESULTS + "&lang=" + lang + "&username=" + GEONAMES_USERNAME;
                // Parse the returned XML with a special handler
                GetWikipediaXmlHandler xmlHandler = new GetWikipediaXmlHandler();
                try
index b7ff0a46c4759ea5c8caa0dba23798af581dd255..f2fe23b1c5488f69a89a1c51f90d2fa712500277 100644 (file)
@@ -18,8 +18,7 @@ import javax.swing.ListSelectionModel;
 import tim.prune.App;
 import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
-import tim.prune.data.Altitude;
-import tim.prune.data.Field;
+import tim.prune.data.DataPoint;
 import tim.prune.data.SourceInfo;
 import tim.prune.data.Track;
 import tim.prune.load.TrackNameList;
@@ -29,9 +28,7 @@ import tim.prune.load.TrackNameList;
  */
 public class SelectTracksFunction extends GenericFunction
 {
-       private Field[] _fieldArray = null;
-       private Object[][] _dataArray = null;
-       private Altitude.Format _altFormat = Altitude.Format.NO_FORMAT;
+       private Track _track = null;
        private SourceInfo _sourceInfo = null;
        private TrackNameList _trackNameList = null;
        private JDialog _dialog = null;
@@ -40,19 +37,15 @@ public class SelectTracksFunction extends GenericFunction
        /**
         * Constructor
         * @param inApp app object to use for load
-        * @param inFieldArray field array
-        * @param inDataArray data array
-        * @param inAltFormat altitude format
+        * @param inTrack loaded track object
         * @param inSourceInfo source information
         * @param inTrackNameList track name list
         */
-       public SelectTracksFunction(App inApp, Field[] inFieldArray, Object[][] inDataArray,
-               Altitude.Format inAltFormat, SourceInfo inSourceInfo, TrackNameList inTrackNameList)
+       public SelectTracksFunction(App inApp, Track inTrack, SourceInfo inSourceInfo,
+               TrackNameList inTrackNameList)
        {
                super(inApp);
-               _fieldArray = inFieldArray;
-               _dataArray = inDataArray;
-               _altFormat = inAltFormat;
+               _track = inTrack;
                _sourceInfo = inSourceInfo;
                _trackNameList = inTrackNameList;
        }
@@ -147,13 +140,10 @@ public class SelectTracksFunction extends GenericFunction
        private void finish()
        {
                _dialog.dispose();
-               // Load track as it is, which is expensive but makes interrogating waypoints easier
-               Track loadedTrack = new Track();
-               loadedTrack.load(_fieldArray, _dataArray, _altFormat);
                int[] tracks = _trackList.getSelectedIndices();
                // Check if all tracks are selected, then don't have to filter at all
                if (tracks.length == _trackNameList.getNumTracks()) {
-                       _app.informDataLoaded(loadedTrack, _sourceInfo);
+                       _app.informDataLoaded(_track, _sourceInfo);
                }
                else
                {
@@ -165,13 +155,13 @@ public class SelectTracksFunction extends GenericFunction
                        // Loop over all points, counting points which survive filter and making flag array
                        int numPointsSelected = 0;
                        int currentTrack = -1;
-                       final int totalPoints = loadedTrack.getNumPoints();
+                       final int totalPoints = _track.getNumPoints();
                        boolean[] selectedPoints = new boolean[totalPoints];
                        for (int i=0; i<totalPoints; i++)
                        {
                                final int startOfNextTrack = _trackNameList.getStartIndex(currentTrack+1);
                                if (i == startOfNextTrack) {currentTrack++;}
-                               if (currentTrack < 0 || selectedTracks[currentTrack] || loadedTrack.getPoint(i).isWaypoint()) {
+                               if (currentTrack < 0 || selectedTracks[currentTrack] || _track.getPoint(i).isWaypoint()) {
                                        selectedPoints[i] = true;
                                        numPointsSelected++;
                                }
@@ -180,21 +170,21 @@ public class SelectTracksFunction extends GenericFunction
                        if (numPointsSelected <= 0) {
                                _app.informNoDataLoaded();
                        }
-                       else {
-                               // Create new data array of required length
-                               Object[][] newDataArray = new String[numPointsSelected][];
-                               // Loop over all points again, copying surviving points
+                       else
+                       {
+                               // Create new point array of required length
+                               DataPoint[] croppedPoints = new DataPoint[numPointsSelected];
+                               // Loop over all points again, copying surviving ones
                                int currPoint = 0;
                                for (int i=0; i<totalPoints; i++)
                                {
                                        if (selectedPoints[i]) {
-                                               newDataArray[currPoint] = _dataArray[i];
+                                               croppedPoints[currPoint] = _track.getPoint(i);
                                                currPoint++;
                                        }
                                }
                                // Construct Track and call informDataLoaded
-                               Track filteredTrack = new Track();
-                               filteredTrack.load(_fieldArray, newDataArray, _altFormat);
+                               Track filteredTrack = new Track(_track.getFieldList(), croppedPoints);
                                // Tell source info object which points were selected (pass selectedPoints array)
                                _sourceInfo.setPointIndices(selectedPoints);
                                _app.informDataLoaded(filteredTrack, _sourceInfo);
index f2ef5d3bb3073a5617fe3f2e38ca01a39dec658f..10ce804c5e46ac9790c2af9cd60b4e6ae6af900c 100644 (file)
@@ -45,11 +45,11 @@ public class SetLanguage extends GenericFunction
                "espa\u00F1ol", "fran\u00E7ais", "italiano", "magyar", "nederlands", "polski",
                "portugu\u00EAs", "\u4e2d\u6587 (chinese)", "\u65E5\u672C\u8A9E (japanese)",
                "\uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean)", "schwiizerd\u00FC\u00FCtsch", "t\u00FCrk\u00E7e",
-               "rom\u00E2n\u0103", "afrikaans", "bahasa indonesia", "farsi"
+               "rom\u00E2n\u0103", "afrikaans", "bahasa indonesia"
        };
        /** Associated language codes (must be in same order as names!) */
        private static final String[] LANGUAGE_CODES = {"cz", "de", "en", "es", "fr", "it", "hu",
-               "nl", "pl", "pt", "zh", "ja", "ko", "de_ch", "tr", "ro", "af", "in", "fa"
+               "nl", "pl", "pt", "zh", "ja", "ko", "de_ch", "tr", "ro", "af", "in"
        };
 
 
@@ -327,8 +327,10 @@ public class SetLanguage extends GenericFunction
         */
        private void showEndMessage()
        {
+               final String messageKey = Config.getConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS)?
+                       "dialog.setlanguage.endmessagewithautosave":"dialog.setlanguage.endmessage";
                JOptionPane.showMessageDialog(_parentFrame,
-                       I18nManager.getText("dialog.setlanguage.endmessage"),
+                       I18nManager.getText(messageKey),
                        I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
        }
 }
index 1d58ddacd3ffc2c5379b191121538bea4c5e29c1..889f9191d6115a48530b5c330d15b4c58bc08450 100644 (file)
@@ -5,7 +5,7 @@ import tim.prune.FunctionLibrary;
 import tim.prune.GenericFunction;
 
 /**
- * Class to stop playing the current audio file
+ * Class to stop playing the current audio clip
  */
 public class StopAudioFunction extends GenericFunction
 {
diff --git a/tim/prune/function/cache/ManageCacheFunction.java b/tim/prune/function/cache/ManageCacheFunction.java
new file mode 100644 (file)
index 0000000..551eb35
--- /dev/null
@@ -0,0 +1,413 @@
+package tim.prune.function.cache;
+
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.config.Config;
+import tim.prune.gui.WholeNumberField;
+
+/**
+ * Function class to manage the tile cache on local disk
+ */
+public class ManageCacheFunction extends GenericFunction implements Runnable
+{
+       private JDialog _dialog = null;
+       private CardLayout _cards = null;
+       private JPanel _cardPanel = null;
+       private JProgressBar _progressBar = null;
+       private File _cacheDir = null;
+       private TileCacheModel _model = null;
+       private JTable _setsTable = null;
+       private JButton _deleteSetButton = null;
+       private JLabel _tileSetLabel = null, _zoomLabel = null;
+       private JLabel _ageLabel = null;
+       private JRadioButton _deleteAllRadio = null;
+       private WholeNumberField _daysField = null;
+
+       private static TileFilter _TILEFILTER = new TileFilter();
+
+
+       /**
+        * Constructor
+        * @param inApp App object
+        */
+       public ManageCacheFunction(App inApp) {
+               super(inApp);
+       }
+
+       /**
+        * @return name key
+        */
+       public String getNameKey() {
+               return "function.managetilecache";
+       }
+
+       /**
+        * Show the dialog to start
+        */
+       public void begin()
+       {
+               // First check if directory even exists
+               _cacheDir = null;
+               String path = Config.getConfigString(Config.KEY_DISK_CACHE);
+               if (path != null && !path.equals("")) {
+                       _cacheDir = new File(path);
+               }
+               if (_cacheDir == null || !_cacheDir.exists() || !_cacheDir.isDirectory())
+               {
+                       _app.showErrorMessage(getNameKey(), "error.cache.notthere");
+                       return;
+               }
+
+               // Build the dialog if it hasn't already been built
+               if (_dialog == null)
+               {
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true); // modal
+                       _dialog.setLocationRelativeTo(_parentFrame);
+                       _cardPanel = makeContents();
+                       _dialog.getContentPane().add(_cardPanel);
+                       _dialog.pack();
+               }
+               // Start a new thread to build the model
+               new Thread(this).start();
+               // Show the first panel of the dialog including progress bar
+               _cards.first(_cardPanel);
+               _dialog.setVisible(true);
+       }
+
+
+       /**
+        * Make the components for the dialog
+        * @return contents inside a panel
+        */
+       private JPanel makeContents()
+       {
+               JPanel dialogPanel = new JPanel();
+               _cards = new CardLayout();
+               dialogPanel.setLayout(_cards);
+
+               // Make first card including progress bar
+               JPanel firstCard = new JPanel();
+               firstCard.setLayout(new BorderLayout());
+               JPanel progPanel = new JPanel();
+               progPanel.setLayout(new BoxLayout(progPanel, BoxLayout.Y_AXIS));
+               progPanel.add(Box.createVerticalGlue());
+               progPanel.add(new JLabel(I18nManager.getText("confirm.running")));
+               _progressBar = new JProgressBar(0, 10);
+               _progressBar.setIndeterminate(true);
+               progPanel.add(_progressBar);
+               progPanel.add(Box.createVerticalGlue());
+               firstCard.add(progPanel, BorderLayout.CENTER);
+               // Cancel button at bottom
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               // Cancel model building and close dialog
+                               if (_model != null) _model.cancel();
+                               _dialog.dispose();
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               firstCard.add(buttonPanel, BorderLayout.SOUTH);
+               dialogPanel.add(firstCard, "card1");
+
+               // Make second card including tileset table
+               JPanel secondCard = new JPanel();
+               secondCard.setLayout(new BorderLayout());
+               // Table in the middle
+               JPanel midPanel = new JPanel();
+               midPanel.setLayout(new BorderLayout());
+               _setsTable = new JTable();
+               _setsTable.setPreferredScrollableViewportSize(new Dimension(500, 130));
+               _setsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+               midPanel.add(new JScrollPane(_setsTable), BorderLayout.CENTER);
+               midPanel.setBorder(BorderFactory.createEmptyBorder(8, 5, 8, 5));
+               secondCard.add(midPanel, BorderLayout.CENTER);
+               // Activate buttons if a tileset is selected
+               _setsTable.getSelectionModel().addListSelectionListener(
+                       new ListSelectionListener() {
+                               public void valueChanged(ListSelectionEvent e) {
+                                       ListSelectionModel lsm = (ListSelectionModel) e.getSource();
+                                       _deleteSetButton.setEnabled(!lsm.isSelectionEmpty());
+                               }
+                       });
+
+               // button panel at bottom
+               buttonPanel = new JPanel();
+               // left group
+               JPanel leftPanel = new JPanel();
+               leftPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
+               _deleteSetButton = new JButton(I18nManager.getText("button.delete"));
+               _deleteSetButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               showDeleteCard();
+                       }
+               });
+               leftPanel.add(_deleteSetButton);
+               // right group
+               JPanel rightPanel = new JPanel();
+               rightPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               JButton closeButton = new JButton(I18nManager.getText("button.close"));
+               closeButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               if (_dialog != null) _dialog.dispose();
+                       }
+               });
+               rightPanel.add(closeButton);
+               buttonPanel.add(leftPanel, BorderLayout.WEST);
+               buttonPanel.add(rightPanel, BorderLayout.EAST);
+               secondCard.add(buttonPanel, BorderLayout.SOUTH);
+               dialogPanel.add(secondCard, "card2");
+
+               // Make third card including delete options
+               JPanel thirdCard = new JPanel();
+               thirdCard.setLayout(new BorderLayout());
+               // main panel
+               JPanel mainPanel = new JPanel();
+               GridBagLayout gridbag = new GridBagLayout();
+               GridBagConstraints c = new GridBagConstraints();
+               mainPanel.setLayout(gridbag);
+               c.gridx = 0; c.gridy = 0;
+               c.gridheight = 1; c.gridwidth = 2;
+               c.weightx = 0.0; c.weighty = 0.0;
+               c.anchor = GridBagConstraints.FIRST_LINE_START;
+               _tileSetLabel = new JLabel("tileset label");
+               mainPanel.add(_tileSetLabel, c);
+               c.gridx = 0; c.gridy = 1;
+               c.ipady = 20;
+               _zoomLabel = new JLabel("zoom label");
+               mainPanel.add(_zoomLabel, c);
+
+               JRadioButton deleteOldRadio = new JRadioButton(I18nManager.getText("dialog.diskcache.deleteold"));
+               _deleteAllRadio = new JRadioButton(I18nManager.getText("dialog.diskcache.deleteall"));
+               ButtonGroup bGroup = new ButtonGroup();
+               bGroup.add(_deleteAllRadio);
+               bGroup.add(deleteOldRadio);
+               _deleteAllRadio.addChangeListener(new ChangeListener() {
+                       public void stateChanged(ChangeEvent e) {
+                               enableAgeFields();
+                       }
+               });
+               c.gridx = 0; c.gridy = 2;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.ipady = 0;
+               mainPanel.add(deleteOldRadio, c);
+               c.gridwidth = 1;
+               c.gridx = 0; c.gridy = 3;
+               c.insets = new Insets(0, 40, 0, 0);
+               _ageLabel = new JLabel("Maximum age (days)");
+               mainPanel.add(_ageLabel, c);
+               _daysField = new WholeNumberField(2);
+               _daysField.setMinimumSize(new Dimension(20, 1));
+               _daysField.setText("30"); // default is 30 days
+               c.gridx = 1; c.gridy = 3;
+               c.ipadx = 20;
+               c.insets = new Insets(0, 15, 0, 0);
+               mainPanel.add(_daysField, c);
+               c.gridx = 0; c.gridy = 4;
+               c.gridwidth = 2;
+               c.ipadx = 0;
+               c.insets = new Insets(0, 0, 0, 0);
+               mainPanel.add(_deleteAllRadio, c);
+               _deleteAllRadio.setSelected(true);
+               thirdCard.add(mainPanel, BorderLayout.CENTER);
+               // button panel
+               buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               JButton deleteButton = new JButton(I18nManager.getText("button.delete"));
+               deleteButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               deleteCurrentSets();
+                       }
+               });
+               buttonPanel.add(deleteButton);
+               cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               // Go back to second card
+                               _cards.show(_cardPanel, "card2");
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               thirdCard.add(buttonPanel, BorderLayout.SOUTH);
+               dialogPanel.add(thirdCard, "card3");
+               return dialogPanel;
+       }
+
+
+       /**
+        * Construct the model in a separate thread
+        * and go on to the second panel of the dialog
+        */
+       public void run()
+       {
+               // Check if directory has anything in it
+               _model = new TileCacheModel(_cacheDir);
+               _model.buildTileSets();
+               if (_model.isAborted()) return;
+
+               if (_model.getNumTileSets() <= 0)
+               {
+                       _app.showErrorMessage(getNameKey(), "error.cache.empty");
+                       return;
+               }
+
+               // Set controls according to current config
+               _setsTable.setModel(new TileSetTableModel(_model));
+               _deleteSetButton.setEnabled(false);
+               // Set column widths after model has been set
+               _setsTable.getColumnModel().getColumn(0).setPreferredWidth(220);
+               _setsTable.getColumnModel().getColumn(1).setPreferredWidth(200);
+               // Show second panel
+               _cards.next(_cardPanel);
+       }
+
+       /**
+        * Prepare and show the delete panel
+        */
+       private void showDeleteCard()
+       {
+               // set tileset label
+               int numSelected = 0;
+               String desc = null;
+               RowInfo totals = new RowInfo();
+               for (int i=0; i<_setsTable.getRowCount(); i++) {
+                       if (_setsTable.isRowSelected(i))
+                       {
+                               if (desc == null) desc = _model.getTileSet(i).getPath();
+                               totals.addRow(_model.getTileSet(i).getRowInfo());
+                               numSelected++;
+                       }
+               }
+               if (numSelected == 0) return;
+               String tileSetDesc = (numSelected == 1?desc:I18nManager.getText("dialog.diskcache.tileset.multiple"));
+               _tileSetLabel.setText(I18nManager.getText("dialog.diskcache.tileset") + " : "
+                       + tileSetDesc);
+               _zoomLabel.setText(I18nManager.getText("dialog.diskcache.table.zoom") + " : "
+                       + totals.getZoomRange());
+
+               // enable/disable edit fields
+               enableAgeFields();
+               // show the next card
+               _cards.next(_cardPanel);
+       }
+
+       /**
+        * Enable or disable the fields for entering tile age
+        */
+       private void enableAgeFields()
+       {
+               boolean showAgeBoxes = !_deleteAllRadio.isSelected();
+               _ageLabel.setEnabled(showAgeBoxes);
+               _daysField.setEnabled(showAgeBoxes);
+       }
+
+       /**
+        * Try to delete all the files in the currently selected tilesets
+        * (Maybe more than one tileset is selected in the table)
+        */
+       private void deleteCurrentSets()
+       {
+               // Determine age limit if given
+               int ageLimit = -1;
+               if (!_deleteAllRadio.isSelected()) {
+                       ageLimit = _daysField.getValue();
+               }
+               // Loop over selected tilesets and delete them
+               int totalDeleted = 0;
+               for (int i=0; i<_setsTable.getRowCount(); i++)
+               {
+                       if (_setsTable.isRowSelected(i))
+                       {
+                               File dir = new File(_model.getCacheDir(), _model.getTileSet(i).getPath());
+                               if (dir.exists())
+                               {
+                                       int numFilesDeleted = deleteFilesFrom(dir, ageLimit);
+                                       if (numFilesDeleted > 0) {
+                                               totalDeleted += numFilesDeleted;
+                                       }
+                               }
+                       }
+               }
+               if (totalDeleted > 0)
+               {
+                       // Show confirmation message
+                       JOptionPane.showMessageDialog(_dialog, I18nManager.getText("dialog.diskcache.deleted1")
+                               + " " + totalDeleted + " " + I18nManager.getText("dialog.diskcache.deleted2"),
+                               I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
+                       // reload model
+                       _cards.first(_cardPanel);
+                       new Thread(this).start();
+               }
+               else {
+                       _app.showErrorMessage(getNameKey(), "error.cache.cannotdelete");
+               }
+       }
+
+
+       /**
+        * Delete recursively all files which are older than the age limit
+        * @param inDir directory to delete from
+        * @param inMaxDays age limit in days
+        * @return number of files deleted
+        */
+       private static int deleteFilesFrom(File inDir, int inMaxDays)
+       {
+               int numDeleted = 0;
+               long now = System.currentTimeMillis();
+               if (inDir.exists() && inDir.isDirectory())
+               {
+                       for (File subdir : inDir.listFiles())
+                       {
+                               if (subdir.isDirectory()) {
+                                       numDeleted += deleteFilesFrom(subdir, inMaxDays);
+                               }
+                               else if (subdir.isFile() && subdir.exists() && _TILEFILTER.accept(subdir))
+                               {
+                                       long fileAge = (now - subdir.lastModified()) / 1000 / 60 / 60 / 24;
+                                       if (inMaxDays < 0 || fileAge > inMaxDays)
+                                       {
+                                               if (subdir.delete()) {
+                                                       numDeleted++;
+                                               }
+                                       }
+                               }
+                       }
+                       // Try to delete the directory (doesn't work if not empty)
+                       inDir.delete();
+               }
+               return numDeleted;
+       }
+}
diff --git a/tim/prune/function/cache/RowInfo.java b/tim/prune/function/cache/RowInfo.java
new file mode 100644 (file)
index 0000000..dc90abd
--- /dev/null
@@ -0,0 +1,121 @@
+package tim.prune.function.cache;
+
+/**
+ * Class to hold the information for a single table row.
+ * Used to describe a tileset or for a single zoom level of a tileset.
+ */
+public class RowInfo
+{
+       private int _zoom = -1;
+       private int _minZoom = -1, _maxZoom = -1;
+       private int _numTiles = 0;
+       private long _totalSize = 0L;
+       private boolean _unexpected = false;
+
+
+       /**
+        * Set the zoom level
+        * @param inZoom zoom level
+        */
+       public void setZoom(int inZoom) {
+               _zoom = inZoom;
+       }
+
+       /**
+        * Add a zoom level and adjust max/min
+        * @param inZoom zoom level
+        */
+       public void addZoom(int inZoom)
+       {
+               if (_minZoom < 0 || _minZoom > inZoom)
+                       _minZoom = inZoom;
+               if (_maxZoom < inZoom)
+                       _maxZoom = inZoom;
+       }
+
+       /**
+        * @return the zoom level
+        */
+       public int getZoom() {
+               return _zoom;
+       }
+
+       /**
+        * @return the zoom range as a string
+        */
+       public String getZoomRange()
+       {
+               if (_minZoom < 0 && _maxZoom < 0) return "";
+               if (_minZoom == _maxZoom || _maxZoom < 0) return "" + _minZoom;
+               if (_minZoom < 0) return "" + _maxZoom;
+               return "" + _minZoom + " - " + _maxZoom;
+       }
+
+       /**
+        * Add a single tile of the given size
+        * @param inSize size in bytes
+        */
+       public void addTile(long inSize) {
+               addTiles(1, inSize);
+       }
+
+       /**
+        * Add the given tiles
+        * @param inNumTiles number of tiles to add
+        * @param inSize total size of the tiles in bytes
+        */
+       public void addTiles(int inNumTiles, long inSize)
+       {
+               _numTiles += inNumTiles;
+               _totalSize += inSize;
+       }
+
+       /**
+        * @return the total number of tiles found
+        */
+       public int getNumTiles() {
+               return _numTiles;
+       }
+
+       /**
+        * @return the total size of the tiles in bytes
+        */
+       public long getTotalSize() {
+               return _totalSize;
+       }
+
+       /**
+        * Mark that an unexpected file or directory was found
+        */
+       public void foundUnexpected() {
+               _unexpected = true;
+       }
+
+       /**
+        * @return true if any unexpected files or directories were found
+        */
+       public boolean wasUnexpected() {
+               return _unexpected;
+       }
+
+       /**
+        * Add the given RowInfo object to this one
+        * @param inOther other row object
+        */
+       public void addRow(RowInfo inOther)
+       {
+               if (inOther == null)
+                       return;
+               _numTiles  += inOther._numTiles;
+               _totalSize += inOther._totalSize;
+               // TODO: Max age
+               // Zoom range
+               if (inOther._minZoom > 0)
+                       addZoom(inOther._minZoom);
+               if (inOther._maxZoom > 0)
+                       addZoom(inOther._maxZoom);
+               if (inOther._zoom > 0)
+                       addZoom(inOther._zoom);
+               _unexpected = _unexpected || inOther._unexpected;
+       }
+}
diff --git a/tim/prune/function/cache/TileCacheModel.java b/tim/prune/function/cache/TileCacheModel.java
new file mode 100644 (file)
index 0000000..2f45414
--- /dev/null
@@ -0,0 +1,216 @@
+package tim.prune.function.cache;
+
+import java.io.File;
+import java.util.ArrayList;
+
+import tim.prune.gui.map.MapSource;
+import tim.prune.gui.map.MapSourceLibrary;
+
+/**
+ * Class to obtain and hold information about the current
+ * tile cache including its subdirectories
+ */
+public class TileCacheModel
+{
+       /** Cache directory */
+       private File _cacheDir = null;
+       /** Array of tilesets */
+       private ArrayList<TileSet> _tileSets = null;
+       /** Summary information */
+       private RowInfo _summaryRow = null;
+       /** Cancelled flag */
+       private boolean _cancelled = false;
+
+
+       /**
+        * Constructor
+        * @param inDir start directory
+        */
+       public TileCacheModel(File inDir)
+       {
+               if (inDir != null && inDir.exists() && inDir.isDirectory() && inDir.canRead()) {
+                       _cacheDir = inDir;
+               }
+               _cancelled = false;
+       }
+
+       /**
+        * Build the tilesets by searching recursively
+        */
+       public void buildTileSets()
+       {
+               if (_cacheDir == null) return;
+
+               _tileSets = new ArrayList<TileSet>();
+               // go through subdirectories, if any
+               File[] subdirs = _cacheDir.listFiles();
+               for (File subdir : subdirs)
+               {
+                       if (subdir != null && subdir.isDirectory() && subdir.exists() && subdir.canRead()
+                               && !_cancelled)
+                       {
+                               getTileSets(subdir, null, _tileSets);
+                       }
+               }
+               // Loop over found tile sets and create summary rowinfo
+               _summaryRow = new RowInfo();
+               for (TileSet ts : _tileSets)
+               {
+                       _summaryRow.addRow(ts.getRowInfo());
+               }
+       }
+
+       /**
+        * Get all the tilesets from the given directory
+        * @param inDir directory to search
+        * @return array of TileSet objects
+        */
+       private static void getTileSets(File inDir, String inParentPath, ArrayList<TileSet> inTsList)
+       {
+               final String wholePath = (inParentPath == null ? "" : inParentPath)
+                       + inDir.getName() + File.separator;
+               // See if any configured backgrounds use this directory
+               // or if the directories match OSM structure
+               String usedByDesc = matchConfig(wholePath);
+               boolean tsFound = false;
+               if (usedByDesc != null || looksLikeCacheDir(inDir))
+               {
+                       TileSet ts = new TileSet(inDir, wholePath, usedByDesc);
+                       if (usedByDesc != null || ts.getRowInfo().getNumTiles() > 0)
+                       {
+                               tsFound = true;
+                               inTsList.add(ts);
+                       }
+               }
+               // If a tileset wasn't found, look through subdirectories
+               if (!tsFound)
+               {
+                       // Go through subdirectories and look at each of them too
+                       File[] subdirs = inDir.listFiles();
+                       if (subdirs != null) {
+                               for (File subdir : subdirs)
+                               {
+                                       if (subdir != null && subdir.exists() && subdir.isDirectory()
+                                               && subdir.canRead())
+                                       {
+                                               getTileSets(subdir, wholePath, inTsList);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Match the given directory name to find the configs which use it
+        * @param inName name of directory to match
+        * @return null if not used, otherwise comma-separated list of background names
+        */
+       private static String matchConfig(String inName)
+       {
+               if (inName == null || inName.equals(""))
+                       return null;
+               String usedBy = null;
+               for (int i=0; i<MapSourceLibrary.getNumSources(); i++)
+               {
+                       MapSource ms = MapSourceLibrary.getSource(i);
+                       for (int l=0; l<2; l++)
+                       {
+                               String msdir = ms.getSiteName(l);
+                               if (msdir != null && msdir.equals(inName))
+                               {
+                                       if (usedBy == null)
+                                               usedBy = ms.getName();
+                                       else
+                                               usedBy = usedBy + ", " + ms.getName();
+                               }
+                       }
+               }
+               return usedBy;
+       }
+
+       /**
+        * @param inDir directory to test
+        * @return true if the subdirectories meet the normal osm layout
+        */
+       private static boolean looksLikeCacheDir(File inDir)
+       {
+               // look for at least one numeric directory, nothing else
+               boolean numFound = false;
+               if (inDir != null && inDir.exists() && inDir.isDirectory() && inDir.canRead())
+               {
+                       for (File subdir : inDir.listFiles())
+                       {
+                               // Only consider readable things which exist
+                               if (subdir != null && subdir.exists() && subdir.canRead())
+                               {
+                                       // subdirectories should have numeric names (for the zoom levels)
+                                       if (subdir.isDirectory() && TileSet.isNumeric(subdir.getName())
+                                               && subdir.getName().length() < 3)
+                                       {
+                                               numFound = true;
+                                       }
+                                       else return false; // either a file or non-numeric directory
+                               }
+                       }
+               }
+               return numFound;
+       }
+
+       /**
+        * @return cache directory
+        */
+       public File getCacheDir() {
+               return _cacheDir;
+       }
+
+       /**
+        * @return number of tile sets
+        */
+       public int getNumTileSets()
+       {
+               if (_tileSets == null) return 0;
+               return _tileSets.size();
+       }
+
+       /**
+        * @return the total number of tile images found
+        */
+       public int getTotalTiles()
+       {
+               return _summaryRow.getNumTiles();
+       }
+
+       /**
+        * @return the total number of bytes taken up with tile images
+        */
+       public long getTotalBytes()
+       {
+               return _summaryRow.getTotalSize();
+       }
+
+       /**
+        * @param inIndex index of tileset
+        * @return requested tileset
+        */
+       public TileSet getTileSet(int inIndex)
+       {
+               if (inIndex >= 0 && inIndex < getNumTileSets()) {
+                       return _tileSets.get(inIndex);
+               }
+               return null;
+       }
+
+       /**
+        * Cancel the search
+        */
+       public void cancel() {
+               _cancelled = true;
+       }
+
+       /**
+        * @return true if search was cancelled
+        */
+       public boolean isAborted() {
+               return _cancelled;
+       }
+}
diff --git a/tim/prune/function/cache/TileFilter.java b/tim/prune/function/cache/TileFilter.java
new file mode 100644 (file)
index 0000000..dd87056
--- /dev/null
@@ -0,0 +1,15 @@
+package tim.prune.function.cache;
+
+import tim.prune.load.GenericFileFilter;
+
+/**
+ * File filter for map tiles
+ */
+public class TileFilter extends GenericFileFilter
+{
+       /** Constructor */
+       public TileFilter()
+       {
+               super("filetype.jpeg", new String[] {"jpg", "png", "gif", "temp"});
+       }
+}
diff --git a/tim/prune/function/cache/TileSet.java b/tim/prune/function/cache/TileSet.java
new file mode 100644 (file)
index 0000000..3e308ba
--- /dev/null
@@ -0,0 +1,114 @@
+package tim.prune.function.cache;
+
+import java.io.File;
+import java.util.ArrayList;
+
+
+/**
+ * Class to hold information about a single tile set
+ * within the overall Tile Cache.
+ */
+public class TileSet
+{
+       /** Summary row info for whole tileset */
+       private RowInfo _rowInfo = null;
+       /** Path relative to mapcache root */
+       private String _path = null;
+       /** Comma-separated list of configs using this tileset */
+       private String _usedBy = null;
+       /** List of infos for each zoom level */
+       private ArrayList<RowInfo> _zoomLevels = null;
+
+
+       /**
+        * Constructor
+        * @param inDir directory of tileset
+        * @param inPath String describing relative path from cache root
+        * @param inUsedBy String describing which configs use this Tileset
+        */
+       public TileSet(File inDir, String inPath, String inUsedBy)
+       {
+               _path = inPath;
+               _usedBy = inUsedBy;
+               _rowInfo = new RowInfo();
+               _zoomLevels = new ArrayList<RowInfo>();
+               // Go through zoom directories and construct row info objects
+               if (inDir != null && inDir.exists() && inDir.isDirectory() && inDir.canRead())
+               {
+                       for (File subdir : inDir.listFiles())
+                       {
+                               if (subdir != null && subdir.exists() && subdir.isDirectory()
+                                       && subdir.canRead() && isNumeric(subdir.getName()))
+                               {
+                                       RowInfo row = makeRowInfo(subdir);
+                                       _zoomLevels.add(row);
+                                       _rowInfo.addRow(row);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Check if a directory name is numeric
+        * @param inName name of directory
+        * @return true if it only contains characters 0-9
+        */
+       public static boolean isNumeric(String inName)
+       {
+               if (inName == null || inName.equals("")) return false;
+               for (int i=0; i<inName.length(); i++)
+               {
+                       char a = inName.charAt(i);
+                       if (a < '0' || a > '9') return false;
+               }
+               return true;
+       }
+
+       /**
+        * Make a RowInfo object from the given directory
+        * @param inDir directory for a single zoom level
+        * @return RowInfo object describing files and size
+        */
+       private static RowInfo makeRowInfo(File inDir)
+       {
+               RowInfo row = new RowInfo();
+               row.setZoom(Integer.parseInt(inDir.getName()));
+               for (File subdir : inDir.listFiles())
+               {
+                       if (subdir != null && subdir.exists() && subdir.isDirectory()
+                               && subdir.canRead() && isNumeric(subdir.getName()))
+                       {
+                               // Found a directory of images (finally!)
+                               for (File f : subdir.listFiles())
+                               {
+                                       if (f != null && f.exists() && f.isFile() && f.canRead())
+                                       {
+                                               final String filename = f.getName();
+                                               int dotpos = filename.lastIndexOf('.');
+                                               if (dotpos > 0 && isNumeric(filename.substring(0, dotpos))) {
+                                                       row.addTile(f.length());
+                                               }
+                                       }
+                               }
+                       }
+               }
+               return row;
+       }
+
+       /**
+        * @return row info object
+        */
+       public RowInfo getRowInfo() {
+               return _rowInfo;
+       }
+
+       /** @return relative path to tileset */
+       public String getPath() {
+               return _path;
+       }
+
+       /** @return users of tileset */
+       public String getUsedBy() {
+               return _usedBy;
+       }
+}
diff --git a/tim/prune/function/cache/TileSetTableModel.java b/tim/prune/function/cache/TileSetTableModel.java
new file mode 100644 (file)
index 0000000..8803894
--- /dev/null
@@ -0,0 +1,77 @@
+package tim.prune.function.cache;
+
+import javax.swing.table.AbstractTableModel;
+
+import tim.prune.I18nManager;
+
+/**
+ * Class to act as a table model for the list of tile sets
+ */
+public final class TileSetTableModel extends AbstractTableModel
+{
+       /** Model from which values are drawn */
+       private TileCacheModel _model = null;
+
+
+       /**
+        * Constructor
+        * @param inModel model to use
+        */
+       public TileSetTableModel(TileCacheModel inModel) {
+               _model = inModel;
+       }
+
+       /** @return the column count (always constant) */
+       public int getColumnCount() {
+               return 5;
+       }
+
+       /** @return name of specified column */
+       public String getColumnName(int inColumnIndex)
+       {
+               switch (inColumnIndex)
+               {
+                       case 0: return I18nManager.getText("dialog.diskcache.table.path");
+                       case 1: return I18nManager.getText("dialog.diskcache.table.usedby");
+                       case 2: return I18nManager.getText("dialog.diskcache.table.zoom");
+                       case 3: return I18nManager.getText("dialog.diskcache.table.tiles");
+                       case 4: return I18nManager.getText("dialog.diskcache.table.megabytes");
+               }
+               return "";
+       }
+
+       /**
+        * @return number of rows in the table
+        */
+       public int getRowCount()
+       {
+               if (_model == null)
+                       return 0;
+               return _model.getNumTileSets();
+       }
+
+       /**
+        * @param inRowIndex row index
+        * @param inColumnIndex column index
+        * @return the value of the specified cell
+        */
+       public Object getValueAt(int inRowIndex, int inColumnIndex)
+       {
+               if (_model != null && inColumnIndex >= 0 && inColumnIndex < getColumnCount())
+               {
+                       TileSet set = _model.getTileSet(inRowIndex);
+                       if (set != null)
+                       {
+                               switch (inColumnIndex)
+                               {
+                                       case 0: return set.getPath();
+                                       case 1: return set.getUsedBy();
+                                       case 2: return set.getRowInfo().getZoomRange();
+                                       case 3: return "" + set.getRowInfo().getNumTiles();
+                                       case 4: return "" + (set.getRowInfo().getTotalSize() / 1024 / 1024) + " MB";
+                               }
+                       }
+               }
+               return null;
+       }
+}
index 3edb4753aceabdd648b9b0a6254c6a5351f33132..502c91439dc1434085e42cce1165352708e10ab5 100644 (file)
@@ -380,7 +380,7 @@ public class Charter extends GenericFunction
                FileWriter tempFileWriter = null;
                try {
                        tempFileWriter = new FileWriter(tempFile);
-                       tempFileWriter.write("# Temporary data file for Prune charts\n\n");
+                       tempFileWriter.write("# Temporary data file for GpsPrune charts\n\n");
                        for (int i=0; i<inTrack.getNumPoints(); i++) {
                                if (xValues.hasData(i) && yValues.hasData(i)) {
                                        tempFileWriter.write("" + xValues.getData(i) + ", " + yValues.getData(i) + "\n");
index b347305c7968c511aa9e4072e291d56000a100cd..d4ecc8898e59208de1c1aa815c7067860e5bbc7e 100644 (file)
@@ -156,7 +156,8 @@ public class CompressTrackFunction extends GenericFunction
                        new DuplicatePointAlgorithm(_track, details, changeListener),
                        new ClosePointsAlgorithm(_track, details, changeListener),
                        new WackyPointAlgorithm(_track, details, changeListener),
-                       new SingletonAlgorithm(_track, details, changeListener)
+                       new SingletonAlgorithm(_track, details, changeListener),
+                       new DouglasPeuckerAlgorithm(_track, details, changeListener)
                };
        }
 
diff --git a/tim/prune/function/compress/DouglasPeuckerAlgorithm.java b/tim/prune/function/compress/DouglasPeuckerAlgorithm.java
new file mode 100644 (file)
index 0000000..42d7ece
--- /dev/null
@@ -0,0 +1,175 @@
+package tim.prune.function.compress;
+
+import java.awt.Component;
+import java.awt.event.ActionListener;
+
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+
+/**
+ * Douglas-Peucker algorithm for compresssion
+ */
+public class DouglasPeuckerAlgorithm extends SingleParameterAlgorithm
+{
+       /**
+        * Constructor
+        * @param inTrack track object
+        * @param inDetails track details object
+        * @param inListener listener to attach to activation control
+        */
+       public DouglasPeuckerAlgorithm(Track inTrack, TrackDetails inDetails, ActionListener inListener)
+       {
+               super(inTrack, inDetails, inListener);
+       }
+
+       /**
+        * Perform the compression and work out which points should be deleted
+        * @param inFlags deletion flags from previous algorithms
+        * @return number of points deleted
+        */
+       protected int compress(boolean[] inFlags)
+       {
+               // Parse parameter
+               double param = getParameter();
+               // Use 1/x if x greater than 1
+               if (param > 1.0) param = 1.0 / param;
+               if (param <= 0.0 || param >= 1.0) {
+                       // Parameter isn't valid, don't delete any
+                       return 0;
+               }
+               double threshold = _trackDetails.getTrackSpan() * param;
+
+               int numPoints = _track.getNumPoints();
+               int origNumDeleted = countFlags(inFlags);
+               // Convert inFlags into keepFlags
+               int[] keepFlags = new int[numPoints];
+               int segStart = -1, segEnd = -1;
+               // Loop over all points in track
+               for (int i=0; i<numPoints; i++)
+               {
+                       DataPoint currPoint = _track.getPoint(i);
+                       if (currPoint.getSegmentStart())
+                       {
+                               // new segment found, so process previous one
+                               if (segStart > -1 && segEnd > segStart)
+                               {
+                                       keepFlags[segEnd] = 1; // keep
+                                       compressSegment(keepFlags, segStart, segEnd, threshold);
+                                       segStart = segEnd = -1;
+                               }
+                       }
+                       if (inFlags[i]) keepFlags[i] = -1; // already deleted
+                       else if (currPoint.isWaypoint() || currPoint.hasMedia() || currPoint.getSegmentStart()) {
+                               keepFlags[i] = 1; // keep
+                       }
+                       // Don't consider points which are already marked as deleted, ignore waypoints
+                       if (!inFlags[i] && !currPoint.isWaypoint())
+                       {
+                               // remember starts and ends
+                               if (segStart < 0) {segStart = i;}
+                               else {segEnd = i;}
+                       }
+               }
+               // Last segment, if any
+               if (segStart >= 0 && segEnd > segStart) {
+                       keepFlags[segEnd] = 1; // keep
+                       compressSegment(keepFlags, segStart, segEnd, threshold);
+               }
+               // Convert keepFlags back into inFlags
+               for (int i=1; i<numPoints; i++) {
+                       if (keepFlags[i] < 1) inFlags[i] = true;
+               }
+               return countFlags(inFlags) - origNumDeleted;
+       }
+
+
+       /**
+        * Count the number of true flags in the given array
+        * @param inFlags array of boolean flags
+        * @return number of flags which are set to true
+        */
+       private static int countFlags(boolean[] inFlags)
+       {
+               int numDeleted = 0;
+               for (int i=0; i<inFlags.length; i++) {
+                       if (inFlags[i]) numDeleted++;
+               }
+               return numDeleted;
+       }
+
+       /**
+        * Compress the given segment (recursively)
+        * @param inFlags int array of deletion flags for entire track
+        * @param inSegStart index of start of segment
+        * @param inSegEnd index of end of segment
+        * @param inThreshold threshold to use
+        */
+       private void compressSegment(int[] inFlags, int inSegStart, int inSegEnd,
+               double inThreshold)
+       {
+               //System.out.println("Compress segment " + inSegStart + "-" + inSegEnd);
+               final int numPoints = inSegEnd - inSegStart + 1;
+               if (numPoints < 3) {return;} // segment too short to compress
+               // Calculate parameters of straight line between first and last
+               XYpoint startxy = new XYpoint(_track.getX(inSegStart), _track.getY(inSegStart));
+               XYpoint endxy = new XYpoint(_track.getX(inSegEnd), _track.getY(inSegEnd));
+               XYpoint ab = startxy.vectorTo(endxy);
+               final double dist2AB = ab.len2();
+               // create unit vector perpendicular to AB
+               final double distAB = ab.len();
+               XYpoint perpendicular = new XYpoint(ab.y/distAB, -ab.x/distAB);
+
+               double maxDist = -1.0, dist = -1.0;
+               int furthestIndex = -1;
+               for (int i=inSegStart+1; i<inSegEnd; i++)
+               {
+                       if (inFlags[i] == 0) // unknown status
+                       {
+                               XYpoint currPoint = new XYpoint(_track.getX(i), _track.getY(i));
+                               XYpoint ac = startxy.vectorTo(currPoint);
+                               double distAP = ab.dot(ac) / dist2AB;
+                               // calc distance from point to line depending on distAP
+                               if (distAP < 0.0) {
+                                       dist = ac.len(); // outside line segment AB on the A side
+                               }
+                               else if (distAP > 1.0) {
+                                       dist = endxy.vectorTo(currPoint).len(); // outside on the B side
+                               }
+                               else {
+                                       // P lies between A and B so use dot product
+                                       dist = Math.abs(perpendicular.dot(ac));
+                               }
+                               if (dist > maxDist)
+                               {
+                                       maxDist = dist;
+                                       furthestIndex = i;
+                               }
+                       }
+               }
+               // Check furthest point and see if it's further than the threshold
+               if (maxDist > inThreshold)
+               {
+                       inFlags[furthestIndex] = 1;
+                       // Make recursive calls for bit before and bit after kept point
+                       compressSegment(inFlags, inSegStart, furthestIndex, inThreshold);
+                       compressSegment(inFlags, furthestIndex, inSegEnd, inThreshold);
+               }
+       }
+
+
+       /**
+        * @return specific gui components for dialog
+        */
+       protected Component getSpecificGuiComponents()
+       {
+               return getSpecificGuiComponents("dialog.compress.douglaspeucker.paramdesc", "2000");
+       }
+
+       /**
+        * @return title key for box
+        */
+       protected String getTitleTextKey()
+       {
+               return "dialog.compress.douglaspeucker.title";
+       }
+}
diff --git a/tim/prune/function/compress/XYpoint.java b/tim/prune/function/compress/XYpoint.java
new file mode 100644 (file)
index 0000000..b3d93d1
--- /dev/null
@@ -0,0 +1,49 @@
+package tim.prune.function.compress;
+
+/**
+ * Basic class to hold x and y coordinates
+ * for a point or a vector
+ */
+public class XYpoint
+{
+       // x and y coordinates
+       public double x = 0.0, y = 0.0;
+
+       /**
+        * Empty constructor
+        */
+       public XYpoint() {
+               this(0.0, 0.0);
+       }
+
+       /**
+        * Constructor
+        * @param inX x value
+        * @param inY y value
+        */
+       public XYpoint(double inX, double inY) {
+               x = inX; y = inY;
+       }
+
+       /**
+        * @param inOther other vector
+        * @return scalar dot product
+        */
+       public double dot(XYpoint inOther) {
+               return (x * inOther.x + y * inOther.y);
+       }
+
+       /** @return length of vector */
+       public double len() {return Math.sqrt(len2());}
+
+       /** @return squared length of vector */
+       public double len2() {return (x*x + y*y);}
+
+       /**
+        * @param inOther other point object
+        * @return vector from this one to the other one
+        */
+       public XYpoint vectorTo(XYpoint inOther) {
+               return new XYpoint(inOther.x - x, inOther.y - y);
+       }
+}
index 804c4ce12e8d897369c47037b5b85c0951fff186..51085cf14742a8ae57b6b4bf75930439ee1fb8b0 100644 (file)
@@ -3,12 +3,14 @@ package tim.prune.function.gpsies;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.net.URLConnection;
 import java.util.ArrayList;
 
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
 import tim.prune.App;
+import tim.prune.GpsPrune;
 import tim.prune.I18nManager;
 import tim.prune.load.xml.XmlFileLoader;
 import tim.prune.load.xml.ZipFileLoader;
@@ -23,6 +25,8 @@ public class GetGpsiesFunction extends GenericDownloaderFunction
        private static final int RESULTS_PER_PAGE = 20;
        /** Maximum number of results to get */
        private static final int MAX_RESULTS = 60;
+       /** New API key (specific to this program) */
+       private static final String GPSIES_API_KEY = "oumgvvbckiwpvsnb";
 
 
        /**
@@ -69,16 +73,19 @@ public class GetGpsiesFunction extends GenericDownloaderFunction
                // Loop for each page of the results
                do
                {
-                       String urlString = "http://www.gpsies.com/api.do?BBOX=" +
+                       String urlString = "http://ws.gpsies.com/api.do?BBOX=" +
                                coords[1] + "," + coords[0] + "," + coords[3] + "," + coords[2] +
-                               "&limit=" + RESULTS_PER_PAGE + "&resultPage=" + currPage;
+                               "&limit=" + RESULTS_PER_PAGE + "&resultPage=" + currPage +
+                               "&key=" + GPSIES_API_KEY;
                        // Parse the returned XML with a special handler
                        GpsiesXmlHandler xmlHandler = new GpsiesXmlHandler();
                        try
                        {
                                url = new URL(urlString);
                                SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
-                               inStream = url.openStream();
+                               URLConnection conn = url.openConnection();
+                               conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER);
+                               inStream = conn.getInputStream();
                                saxParser.parse(inStream, xmlHandler);
                        }
                        catch (Exception e) {
index 1bf26cd8646c9b36ad8761f07b74c55f0636a978..22ee8311a11c91222f58475dfdd2df6e0f750ca2 100644 (file)
@@ -104,6 +104,7 @@ public class LookupSrtmFunction extends GenericFunction implements Runnable
                cancelButton.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e) {
                                _cancelled = true;
+                               _dialog.dispose();
                        }
                });
                buttonPanel.add(cancelButton);
@@ -178,6 +179,7 @@ public class LookupSrtmFunction extends GenericFunction implements Runnable
                _progressBar.setMaximum(inTileList.size());
                _progressBar.setIndeterminate(inTileList.size() <= 1);
                _progressBar.setValue(0);
+               String errorMessage = null;
                // Get urls for each tile
                URL[] urls = TileFinder.getUrls(inTileList);
                for (int t=0; t<inTileList.size() && !_cancelled; t++)
@@ -185,8 +187,8 @@ public class LookupSrtmFunction extends GenericFunction implements Runnable
                        if (urls[t] != null)
                        {
                                SrtmTile tile = inTileList.get(t);
-                               // System.out.println("tile " + t + " of " + tileList.size() + " = " + urls[t].toString());
-                               try {
+                               try
+                               {
                                        _progressBar.setValue(t);
                                        final int ARRLENGTH = 1201*1201;
                                        int[] heights = new int[ARRLENGTH];
@@ -247,11 +249,12 @@ public class LookupSrtmFunction extends GenericFunction implements Runnable
                                        }
                                }
                                catch (IOException ioe) {
-                                       //System.err.println("eek - " + ioe.getMessage());
+                                       errorMessage = ioe.getClass().getName() + " - " + ioe.getMessage();
                                }
                        }
                }
                _dialog.dispose();
+               if (_cancelled) {return;}
                if (numAltitudesFound > 0)
                {
                        // Inform app including undo information
@@ -260,6 +263,9 @@ public class LookupSrtmFunction extends GenericFunction implements Runnable
                        _app.completeFunction(undo, I18nManager.getText("confirm.lookupsrtm1") + " " + numAltitudesFound
                                + " " + I18nManager.getText("confirm.lookupsrtm2"));
                }
+               else if (errorMessage != null) {
+                       _app.showErrorMessageNoLookup(getNameKey(), errorMessage);
+               }
                else if (inTileList.size() > 0) {
                        _app.showErrorMessage(getNameKey(), "error.lookupsrtm.nonefound");
                }
index fe1e9332b769ebad2c092c6786425cf8a9561614..6bf3ffe56f4bfde148bf1b4a37e269f5f8cd6286 100644 (file)
@@ -10,7 +10,7 @@ import tim.prune.function.PlayAudioFunction;
 
 /**
  * Class to update the supplied progress bar on the basis of
- * the currently playing audio file (if any)
+ * the currently playing audio clip (if any)
  */
 public class AudioListener implements Runnable, ActionListener
 {
index dee14a9cd72c3d8016c54b99f165c0c62175e959..ec68e162633dc66472138c20d6c1ac3a602c7303 100644 (file)
@@ -27,7 +27,7 @@ import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
 import tim.prune.config.Config;
 import tim.prune.data.Altitude;
-import tim.prune.data.AudioFile;
+import tim.prune.data.AudioClip;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Distance;
@@ -63,6 +63,7 @@ public class DetailsDisplay extends GenericDisplay
        private PhotoThumbnail _photoThumbnail = null;
        private JLabel _photoTimestampLabel = null;
        private JLabel _photoConnectedLabel = null;
+       private JLabel _photoBearingLabel = null;
        private JPanel _rotationButtons = null;
 
        // Audio details
@@ -160,6 +161,8 @@ public class DetailsDisplay extends GenericDisplay
                _photoDetailsPanel.add(_photoTimestampLabel);
                _photoConnectedLabel = new JLabel("");
                _photoDetailsPanel.add(_photoConnectedLabel);
+               _photoBearingLabel = new JLabel("");
+               _photoDetailsPanel.add(_photoBearingLabel);
                _photoThumbnail = new PhotoThumbnail();
                _photoThumbnail.setVisible(false);
                _photoThumbnail.setPreferredSize(new Dimension(100, 100));
@@ -381,17 +384,24 @@ public class DetailsDisplay extends GenericDisplay
                        _photoLabel.setText(I18nManager.getText("details.nophoto"));
                        _photoTimestampLabel.setText("");
                        _photoConnectedLabel.setText("");
+                       _photoBearingLabel.setText("");
                        _photoThumbnail.setVisible(false);
                        _rotationButtons.setVisible(false);
                }
                else
                {
                        if (currentPhoto == null) {currentPhoto = currentPoint.getPhoto();}
-                       _photoLabel.setText(I18nManager.getText("details.photofile") + ": " + currentPhoto.getFile().getName());
-                       _photoTimestampLabel.setText(LABEL_POINT_TIMESTAMP + currentPhoto.getTimestamp().getText());
+                       _photoLabel.setText(I18nManager.getText("details.photofile") + ": " + currentPhoto.getName());
+                       _photoTimestampLabel.setText(currentPhoto.hasTimestamp()?(LABEL_POINT_TIMESTAMP + currentPhoto.getTimestamp().getText()):"");
                        _photoConnectedLabel.setText(I18nManager.getText("details.media.connected") + ": "
                                + (currentPhoto.getCurrentStatus() == Photo.Status.NOT_CONNECTED ?
                                        I18nManager.getText("dialog.about.no"):I18nManager.getText("dialog.about.yes")));
+                       if (currentPhoto.getBearing() >= 0.0 && currentPhoto.getBearing() <= 360.0)
+                       {
+                               _photoBearingLabel.setText(I18nManager.getText("details.photo.bearing") + ": "
+                                       + (int) currentPhoto.getBearing() + " \u00B0");
+                       }
+                       else _photoBearingLabel.setText("");
                        _photoThumbnail.setVisible(true);
                        _photoThumbnail.setPhoto(currentPhoto);
                        _rotationButtons.setVisible(true);
@@ -401,7 +411,7 @@ public class DetailsDisplay extends GenericDisplay
 
                // audio details
                _audioDetailsPanel.setVisible(_trackInfo.getAudioList().getNumAudios() > 0);
-               AudioFile currentAudio = _trackInfo.getAudioList().getAudio(_trackInfo.getSelection().getCurrentAudioIndex());
+               AudioClip currentAudio = _trackInfo.getAudioList().getAudio(_trackInfo.getSelection().getCurrentAudioIndex());
                if (currentAudio == null) {
                        _audioLabel.setText(I18nManager.getText("details.noaudio"));
                        _audioTimestampLabel.setText("");
@@ -410,8 +420,8 @@ public class DetailsDisplay extends GenericDisplay
                }
                else
                {
-                       _audioLabel.setText(LABEL_AUDIO_FILE + currentAudio.getFile().getName());
-                       _audioTimestampLabel.setText(LABEL_POINT_TIMESTAMP + currentAudio.getTimestamp().getText());
+                       _audioLabel.setText(LABEL_AUDIO_FILE + currentAudio.getName());
+                       _audioTimestampLabel.setText(currentAudio.hasTimestamp()?(LABEL_POINT_TIMESTAMP + currentAudio.getTimestamp().getText()):"");
                        int audioLength = currentAudio.getLengthInSeconds();
                        _audioLengthLabel.setText(audioLength < 0?"":LABEL_RANGE_DURATION + DisplayUtils.buildDurationString(audioLength));
                        _audioConnectedLabel.setText(I18nManager.getText("details.media.connected") + ": "
index 858e97a2dd9daeeed49706443b8d2b3eda5d9190..1c0cc7e43d478e86d43073b438b91835284b4d40 100644 (file)
@@ -62,9 +62,9 @@ public abstract class IconManager
        public static final String ROTATE_RIGHT = "rotate_right_icon.png";
        /** Icon for showing photo popup */
        public static final String SHOW_DETAILS = "show_details_icon.gif";
-       /** Icon for playing audio file */
+       /** Icon for playing audio clip */
        public static final String PLAY_AUDIO = "play_audio.gif";
-       /** Icon for stopping the current audio file */
+       /** Icon for stopping the current audio clip */
        public static final String STOP_AUDIO = "stop_audio.gif";
 
        /**
index 2d8eb6ed54620596243666bfc84edf3c1edb6b1d..e2a73079dd16e48e4cb5d5c9a31982b7f5f80e53 100644 (file)
@@ -2,7 +2,7 @@ package tim.prune.gui;
 
 import javax.swing.AbstractListModel;
 
-import tim.prune.data.MediaFile;
+import tim.prune.data.MediaObject;
 import tim.prune.data.MediaList;
 
 /**
@@ -33,9 +33,9 @@ public class MediaListModel extends AbstractListModel
         */
        public Object getElementAt(int inIndex)
        {
-               MediaFile m = _media.getMedia(inIndex);
+               MediaObject m = _media.getMedia(inIndex);
                // * means modified since loading
-               return (m.getCurrentStatus() == m.getOriginalStatus()?"":"* ") + m.getFile().getName();
+               return (m.getCurrentStatus() == m.getOriginalStatus()?"":"* ") + m.getName();
        }
 
        /**
index 47044f2b568637eec671ab38355226663eda18b8..8229aa322fb58458db950de8eabdb27f9e16ddeb 100644 (file)
@@ -20,8 +20,10 @@ import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
 import tim.prune.config.Config;
-import tim.prune.data.AudioFile;
+import tim.prune.data.AudioClip;
 import tim.prune.data.Photo;
+import tim.prune.data.RecentFile;
+import tim.prune.data.RecentFileList;
 import tim.prune.data.Selection;
 import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
@@ -45,6 +47,7 @@ public class MenuManager implements DataSubscriber
        private JMenuItem _exportGpxItem = null;
        private JMenuItem _exportPovItem = null;
        private JMenuItem _exportSvgItem = null;
+       private JMenu     _recentFileMenu = null;
        private JMenuItem _undoItem = null;
        private JMenuItem _clearUndoItem = null;
        private JMenuItem _editPointItem = null;
@@ -97,6 +100,7 @@ public class MenuManager implements DataSubscriber
        private JMenuItem _correlateAudiosItem = null;
        private JMenuItem _selectNoAudioItem = null;
        private JCheckBoxMenuItem _onlineCheckbox = null;
+       private JCheckBoxMenuItem _autosaveSettingsCheckbox = null;
 
        // ActionListeners for reuse by menu and toolbar
        private ActionListener _openFileAction = null;
@@ -160,6 +164,9 @@ public class MenuManager implements DataSubscriber
                };
                openMenuItem.addActionListener(_openFileAction);
                fileMenu.add(openMenuItem);
+               // import through gpsbabel
+               JMenuItem importBabelItem = makeMenuItem(FunctionLibrary.FUNCTION_IMPORTBABEL);
+               fileMenu.add(importBabelItem);
                // Add photos
                JMenuItem addPhotosMenuItem = new JMenuItem(I18nManager.getText("menu.file.addphotos"));
                _addPhotoAction = new ActionListener() {
@@ -169,9 +176,13 @@ public class MenuManager implements DataSubscriber
                };
                addPhotosMenuItem.addActionListener(_addPhotoAction);
                fileMenu.add(addPhotosMenuItem);
-               // Add audio files
+               // Add audio clips
                JMenuItem addAudioMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_LOAD_AUDIO);
                fileMenu.add(addAudioMenuItem);
+               // recent files
+               _recentFileMenu = new JMenu(I18nManager.getText("menu.file.recentfiles"));
+               _recentFileMenu.setEnabled(false);
+               fileMenu.add(_recentFileMenu);
                fileMenu.addSeparator();
                // Load from GPS
                JMenuItem loadFromGpsMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSLOAD);
@@ -213,6 +224,7 @@ public class MenuManager implements DataSubscriber
                });
                fileMenu.add(exitMenuItem);
                menubar.add(fileMenu);
+
                // Track menu
                JMenu trackMenu = new JMenu(I18nManager.getText("menu.track"));
                setAltKey(trackMenu, "altkey.menu.track");
@@ -449,6 +461,7 @@ public class MenuManager implements DataSubscriber
                                _app.toggleSidebars();
                        }
                });
+               sidebarsCheckbox.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0)); // shortcut F11
                viewMenu.add(sidebarsCheckbox);
                // 3d
                _show3dItem = makeMenuItem(FunctionLibrary.FUNCTION_3D, false);
@@ -570,14 +583,14 @@ public class MenuManager implements DataSubscriber
                // connect audio
                _connectAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_CONNECT_TO_POINT, false);
                audioMenu.add(_connectAudioItem);
-               // Disconnect current audio file
+               // Disconnect current audio clip
                _disconnectAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_DISCONNECT_AUDIO, false);
                audioMenu.add(_disconnectAudioItem);
-               // Remove current audio file
+               // Remove current audio clip
                _removeAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_REMOVE_AUDIO, false);
                audioMenu.add(_removeAudioItem);
                audioMenu.addSeparator();
-               // Correlate audio files
+               // Correlate audio clips
                _correlateAudiosItem = makeMenuItem(FunctionLibrary.FUNCTION_CORRELATE_AUDIOS, false);
                audioMenu.add(_correlateAudiosItem);
                menubar.add(audioMenu);
@@ -613,6 +626,15 @@ public class MenuManager implements DataSubscriber
                settingsMenu.addSeparator();
                // Save configuration
                settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SAVECONFIG));
+               _autosaveSettingsCheckbox = new JCheckBoxMenuItem(
+                       I18nManager.getText("menu.settings.autosave"), false);
+               _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());
+                       }
+               });
+               settingsMenu.add(_autosaveSettingsCheckbox);
                menubar.add(settingsMenu);
 
                // Help menu
@@ -832,11 +854,11 @@ public class MenuManager implements DataSubscriber
                _duplicatePointItem.setEnabled(hasPoint);
                // are there any photos?
                boolean anyPhotos = _app.getTrackInfo().getPhotoList().getNumPhotos() > 0;
-               _saveExifItem.setEnabled(anyPhotos);
+               _saveExifItem.setEnabled(anyPhotos && _app.getTrackInfo().getPhotoList().hasMediaWithFile());
                // is there a current photo, audio?
                Photo currentPhoto = _app.getTrackInfo().getCurrentPhoto();
                boolean hasPhoto = currentPhoto != null;
-               AudioFile currentAudio = _app.getTrackInfo().getCurrentAudio();
+               AudioClip currentAudio = _app.getTrackInfo().getCurrentAudio();
                boolean hasAudio = currentAudio != null;
                // connect is available if (photo/audio) and point selected, and media has no point
                boolean connectAvailable = (hasPhoto && hasPoint && currentPhoto.getDataPoint() == null)
@@ -881,6 +903,41 @@ public class MenuManager implements DataSubscriber
                if (_mapCheckbox.isSelected() != mapsOn) {
                        _mapCheckbox.setSelected(mapsOn);
                }
+               // Are there any recently-used files?
+               RecentFileList rfl = Config.getRecentFileList();
+               final int numRecentFiles = rfl.getNumEntries();
+               final boolean hasRecentFiles = numRecentFiles > 0;
+               _recentFileMenu.setEnabled(hasRecentFiles);
+               if (hasRecentFiles)
+               {
+                       int numItems = _recentFileMenu.getMenuComponentCount();
+                       if (numItems == numRecentFiles)
+                       {
+                               // Right number of items, just change texts
+                               for (int i=0; i<numRecentFiles; i++)
+                               {
+                                       JMenuItem item = _recentFileMenu.getItem(i);
+                                       item.setText(rfl.getFile(i)==null?"":rfl.getFile(i).getFile().getName());
+                                       item.setToolTipText(rfl.getFile(i)==null?null:rfl.getFile(i).getFile().getAbsolutePath());
+                               }
+                       }
+                       else
+                       {
+                               // Rebuild menus
+                               _recentFileMenu.removeAll();
+                               for (int i=0; i<rfl.getSize(); i++)
+                               {
+                                       RecentFile rf = rfl.getFile(i);
+                                       if (rf != null && rf.isValid())
+                                       {
+                                               JMenuItem menuItem = new JMenuItem(rf.getFile().getName());
+                                               menuItem.setToolTipText(rf.getFile().getAbsolutePath());
+                                               menuItem.addActionListener(new RecentFileTrigger(_app, i));
+                                               _recentFileMenu.add(menuItem);
+                                       }
+                               }
+                       }
+               }
        }
 
 
index 686d90a1ac1eff972a0b20380e40e2cf03c05ea9..3e8b093a644c5c57ddfa2a078210b964be346e29 100644 (file)
@@ -148,7 +148,7 @@ public class PhotoThumbnail extends JPanel implements Runnable
                                        // calculate maximum thumbnail size
                                        Dimension thumbSize = ImageUtils.getThumbnailSize(picWidth, picHeight, DEFAULT_THUMB_SIZE, DEFAULT_THUMB_SIZE);
                                        // Make icon to load image into
-                                       Image image = new ImageIcon(_photo.getFile().getAbsolutePath()).getImage();
+                                       Image image = _photo.createImageIcon().getImage();
                                        // save scaled, smoothed thumbnail for reuse
                                        _thumbnail = ImageUtils.createScaledImage(image, thumbSize.width, thumbSize.height);
                                        image = null;
@@ -157,7 +157,7 @@ public class PhotoThumbnail extends JPanel implements Runnable
                        }
                }
                else {
-                       _thumbnail = new ImageIcon(_photo.getFile().getAbsolutePath()).getImage();
+                       _thumbnail = _photo.createImageIcon().getImage();
                }
                _loadingImage = false;
                repaint();
diff --git a/tim/prune/gui/RecentFileTrigger.java b/tim/prune/gui/RecentFileTrigger.java
new file mode 100644 (file)
index 0000000..4be35d0
--- /dev/null
@@ -0,0 +1,62 @@
+package tim.prune.gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.ArrayList;
+
+import tim.prune.App;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.config.Config;
+import tim.prune.data.RecentFile;
+import tim.prune.load.BabelLoadFromFile;
+
+/**
+ * Class to act as a trigger when a menu item for a recent file is clicked
+ */
+public class RecentFileTrigger implements ActionListener
+{
+       private App _app = null;
+       private int _index = 0;
+
+
+       /**
+        * Constructor
+        * @param inApp App object
+        * @param inIndex menu index from 0
+        */
+       public RecentFileTrigger(App inApp, int inIndex)
+       {
+               _app = inApp;
+               _index = inIndex;
+       }
+
+       /**
+        * React to click on menu item
+        */
+       public void actionPerformed(ActionEvent arg0)
+       {
+               RecentFile rf = Config.getRecentFileList().getFile(_index);
+               if (rf != null && rf.isValid())
+               {
+                       if (rf.isRegularLoad())
+                       {
+                               // Trigger a regular file load
+                               ArrayList<File> dataFiles = new ArrayList<File>();
+                               dataFiles.add(rf.getFile());
+                               _app.loadDataFiles(dataFiles);
+                       }
+                       else
+                       {
+                               // Trigger a load via gpsbabel
+                               new BabelLoadFromFile(_app).beginWithFile(rf.getFile());
+                       }
+               }
+               else
+               {
+                       _app.showErrorMessage("function.open", "error.load.noread");
+                       Config.getRecentFileList().verifyAll(); // Called on a file which no longer exists
+                       UpdateMessageBroker.informSubscribers();
+               }
+       }
+}
index f0772bf2695a3aed6ab7a803623dbe180c2fbe3a..73a504a50160efa3581feb9cb43e001898616aae 100644 (file)
@@ -130,7 +130,7 @@ public class SelectorDisplay extends GenericDisplay
                _photoListPanel = makeListPanel("details.lists.photos", _photoList);
                // don't add photo list (because there aren't any photos yet)
 
-               // List for audio files
+               // List for audio clips
                _audioListModel = new MediaListModel(_trackInfo.getAudioList());
                _audioList = new JList(_audioListModel);
                _audioList.addListSelectionListener(new ListSelectionListener() {
@@ -181,8 +181,8 @@ public class SelectorDisplay extends GenericDisplay
        }
 
        /**
-        * Select the specified audio file
-        * @param inIndex index of selected audio file
+        * Select the specified audio clip
+        * @param inIndex index of selected audio clip
         */
        private void selectAudio(int inIndex)
        {
@@ -289,7 +289,7 @@ public class SelectorDisplay extends GenericDisplay
                                }
                        }
                }
-               // Same for audio files
+               // Same for audio clips
                if (_audioListModel.getSize() > 0)
                {
                        int audioIndex = _trackInfo.getSelection().getCurrentAudioIndex();
index e5b41865e739a0cb08dc95382fc82eb692472ffd..350869713c0a2851ad5b47a17502b2422f303d11 100644 (file)
@@ -38,8 +38,11 @@ public class WaypointListModel extends AbstractListModel
         */
        public Object getElementAt(int inIndex)
        {
-               if (inIndex < 0 || inIndex >= getSize()) return "";
-               return _waypoints.get(inIndex).getWaypointName();
+               DataPoint p = null;
+               if (inIndex < 0 || inIndex >= getSize()
+                       || _waypoints == null || (p = _waypoints.get(inIndex)) == null)
+                       return "";
+               return p.getWaypointName();
        }
 
        /**
index 0cc9b770056e4eb9d5b4d4767470b33a3c0c3e27..2e627a86351618afac46cecefe83e5a7d4b387f9 100644 (file)
@@ -7,7 +7,7 @@ public class CloudmadeMapSource extends OsmMapSource
 {
        /** Selected style number */
        private String _style = null;
-       /** Server prefix including API-key unique to Prune application */
+       /** Server prefix including API-key unique to GpsPrune application */
        private static final String SERVER_PREFIX = "tile.cloudmade.com/03d86b66f51f4a3b8c236ac06f2a2e57/";
 
        /**
index a250e236256a07d54acc7350c626ea39f1dfc4fa..84f54def64ec34b4a004c75dae4342f1db083cb0 100644 (file)
@@ -68,28 +68,29 @@ public class DiskTileCacher implements Runnable
         * @param inBasePath base path to disk cache
         * @param inTilePath relative path to this tile
         * @param inObserver observer to inform when load complete
+        * @return true if successful, false for failure
         */
-       public static void saveTile(URL inUrl, String inBasePath, String inTilePath, ImageObserver inObserver)
+       public static boolean saveTile(URL inUrl, String inBasePath, String inTilePath, ImageObserver inObserver)
        {
-               if (inBasePath == null || inTilePath == null) {return;}
+               if (inBasePath == null || inTilePath == null) {return false;}
                // save file if possible
                File basePath = new File(inBasePath);
                if (!basePath.exists() || !basePath.isDirectory() || !basePath.canWrite()) {
-                       //System.err.println("Can't write");
                        // Can't write to base path
-                       return;
+                       return false;
                }
                File tileFile = new File(basePath, inTilePath);
                // Check if this file is already being loaded
-               if (!isBeingLoaded(tileFile))
+               if (isBeingLoaded(tileFile)) {return true;}
+
+               File dir = tileFile.getParentFile();
+               // Start a new thread to load the image if necessary
+               if ((dir.exists() || dir.mkdirs()) && dir.canWrite())
                {
-                       File dir = tileFile.getParentFile();
-                       // Start a new thread to load the image if necessary
-                       if (dir.exists() || dir.mkdirs())
-                       {
-                               new DiskTileCacher(inUrl, tileFile, inObserver);
-                       }
+                       new DiskTileCacher(inUrl, tileFile, inObserver);
+                       return true;
                }
+               return false; // couldn't write the file
        }
 
        /**
index acac7a186dc6d923f1fec056479ae893dd015511..82cf434f7387adcfe56b5ff5c9d48710844d4d66 100644 (file)
@@ -9,7 +9,6 @@ import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Image;
-import java.awt.RenderingHints;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
@@ -22,7 +21,6 @@ import java.awt.event.MouseMotionListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 import java.awt.image.BufferedImage;
-import java.awt.image.RescaleOp;
 
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
@@ -171,16 +169,22 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                _topPanel.setLayout(new FlowLayout());
                _topPanel.setOpaque(false);
                // Make slider for transparency
-               _transparencySlider = new JSlider(0, 5, 0);
+               _transparencySlider = new JSlider(-6, 6, 0);
                _transparencySlider.setPreferredSize(new Dimension(100, 20));
                _transparencySlider.setMajorTickSpacing(1);
                _transparencySlider.setSnapToTicks(true);
                _transparencySlider.setOpaque(false);
+               _transparencySlider.setValue(0);
                _transparencySlider.addChangeListener(new ChangeListener() {
                        public void stateChanged(ChangeEvent e)
                        {
-                               _recalculate = true;
-                               repaint();
+                               int val = _transparencySlider.getValue();
+                               if (val == 1 || val == -1)
+                                       _transparencySlider.setValue(0);
+                               else {
+                                       _recalculate = true;
+                                       repaint();
+                               }
                        }
                });
                _transparencySlider.setFocusable(false); // stop slider from stealing keyboard focus
@@ -339,7 +343,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                _yRange = new DoubleRange(MapUtils.getYFromLatitude(_latRange.getMinimum()),
                        MapUtils.getYFromLatitude(_latRange.getMaximum()));
                _mapPosition.zoomToXY(_xRange.getMinimum(), _xRange.getMaximum(), _yRange.getMinimum(), _yRange.getMaximum(),
-                               getWidth(), getHeight());
+                       getWidth(), getHeight());
        }
 
 
@@ -487,15 +491,15 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                                        }
                                }
 
-                               // Make maps brighter / fainter
-                               final float[] scaleFactors = {1.0f, 1.05f, 1.1f, 1.2f, 1.6f, 2.2f};
-                               final float scaleFactor = scaleFactors[_transparencySlider.getValue()];
-                               if (scaleFactor > 1.0f)
+                               // Make maps brighter / fainter according to slider
+                               final int brightnessIndex = Math.max(1, _transparencySlider.getValue()) - 1;
+                               if (brightnessIndex > 0)
                                {
-                                       RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
-                                       hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
-                                       RescaleOp op = new RescaleOp(scaleFactor, 0, hints);
-                                       op.filter(_mapImage, _mapImage);
+                                       final int[] alphas = {0, 40, 80, 120, 160, 210};
+                                       Color bgColor = Config.getColourScheme().getColour(ColourScheme.IDX_BACKGROUND);
+                                       bgColor = new Color(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), alphas[brightnessIndex]);
+                                       g.setColor(bgColor);
+                                       g.fillRect(0, 0, getWidth(), getHeight());
                                }
                        }
                }
@@ -532,11 +536,16 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
        private int paintPoints(Graphics inG)
        {
                // Set up colours
-               final Color pointColour = Config.getColourScheme().getColour(ColourScheme.IDX_POINT);
-               final Color rangeColour = Config.getColourScheme().getColour(ColourScheme.IDX_SELECTION);
-               final Color currentColour = Config.getColourScheme().getColour(ColourScheme.IDX_PRIMARY);
-               final Color secondColour = Config.getColourScheme().getColour(ColourScheme.IDX_SECONDARY);
-               final Color textColour = Config.getColourScheme().getColour(ColourScheme.IDX_TEXT);
+               final ColourScheme cs = Config.getColourScheme();
+               final int[] opacities = {255, 190, 130, 80, 40, 0};
+               int opacity = 255;
+               if (_transparencySlider.getValue() < 0)
+                       opacity = opacities[-1 - _transparencySlider.getValue()];
+               final Color pointColour  = makeTransparentColour(cs.getColour(ColourScheme.IDX_POINT), opacity);
+               final Color rangeColour  = makeTransparentColour(cs.getColour(ColourScheme.IDX_SELECTION), opacity);
+               final Color currentColour = makeTransparentColour(cs.getColour(ColourScheme.IDX_PRIMARY), opacity);
+               final Color secondColour = makeTransparentColour(cs.getColour(ColourScheme.IDX_SECONDARY), opacity);
+               final Color textColour   = makeTransparentColour(cs.getColour(ColourScheme.IDX_TEXT), opacity);
 
                // try to set line width for painting
                if (inG instanceof Graphics2D)
@@ -740,6 +749,17 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                return false;
        }
 
+       /**
+        * Make a semi-transparent colour for drawing with
+        * @param inColour base colour (fully opaque)
+        * @param inOpacity opacity where 0=invisible and 255=full
+        * @return new colour object
+        */
+       private static Color makeTransparentColour(Color inColour, int inOpacity)
+       {
+               if (inOpacity > 240) return inColour;
+               return new Color(inColour.getRed(), inColour.getGreen(), inColour.getBlue(), inOpacity);
+       }
 
        /**
         * Inform that tiles have been updated and the map can be repainted
@@ -869,7 +889,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                                                point.setSegmentStart(false);
                                        }
                                }
-                               else if (inE.getClickCount() == 2) {
+                               else if (inE.getClickCount() == 2)
+                               {
                                        // double click
                                        if (_drawMode == MODE_DEFAULT) {
                                                panMap(inE.getX() - getWidth()/2, inE.getY() - getHeight()/2);
@@ -927,8 +948,9 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                if (_drawMode == MODE_ZOOM_RECT && Math.abs(_dragToX - _dragFromX) > 20
                        && Math.abs(_dragToY - _dragFromY) > 20)
                {
-                       //System.out.println("Finished zoom: " + _dragFromX + ", " + _dragFromY + " to " + _dragToX + ", " + _dragToY);
                        _mapPosition.zoomToPixels(_dragFromX, _dragToX, _dragFromY, _dragToY, getWidth(), getHeight());
+               }
+               if (_drawMode == MODE_ZOOM_RECT) {
                        _drawMode = MODE_DEFAULT;
                }
                _dragFromX = _dragFromY = -1;
@@ -1024,6 +1046,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                // Check for Ctrl key (for Linux/Win) or meta key (Clover key for Mac)
                if (inE.isControlDown() || inE.isMetaDown())
                {
+                       // Shift as well makes things faster
+                       final int pointIncrement = inE.isShiftDown()?3:1;
                        // Check for arrow keys to zoom in and out
                        if (code == KeyEvent.VK_UP)
                                zoomIn();
@@ -1031,9 +1055,9 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                                zoomOut();
                        // Key nav for next/prev point
                        else if (code == KeyEvent.VK_LEFT && currPointIndex > 0)
-                               _trackInfo.selectPoint(currPointIndex-1);
+                               _trackInfo.incrementPointIndex(-pointIncrement);
                        else if (code == KeyEvent.VK_RIGHT)
-                               _trackInfo.selectPoint(currPointIndex+1);
+                               _trackInfo.incrementPointIndex(pointIncrement);
                        else if (code == KeyEvent.VK_PAGE_UP)
                                _trackInfo.selectPoint(Checker.getPreviousSegmentStart(
                                        _trackInfo.getTrack(), _trackInfo.getSelection().getCurrentPointIndex()));
index df30219b9f944a21b438cc1e71f8ed51720c18f1..24833ce3e7be4ce8f7f288068768d155cf394ed6 100644 (file)
@@ -41,8 +41,8 @@ public abstract class MapSourceLibrary
                _sourceList.add(new OsmMapSource("Mapnik", "http://tile.openstreetmap.org/"));
                _sourceList.add(new OsmMapSource("Osma", "http://tah.openstreetmap.org/Tiles/tile/"));
                _sourceList.add(new OsmMapSource("Cyclemap", "http://andy.sandbox.cloudmade.com/tiles/cycle/"));
-               _sourceList.add(new OsmMapSource("Reitkarte", "http://topo.geofabrik.de/hills/",
-                       "http://topo.openstreetmap.de/topo/", 18));
+               _sourceList.add(new OsmMapSource("Reitkarte", "http://wanderreitkarte.de/hills/",
+                       "http://topo2.wanderreitkarte.de/topo/", 18));
                _sourceList.add(new MffMapSource("Mapsforfree", "http://maps-for-free.com/layer/relief/", ".jpg",
                        "http://maps-for-free.com/layer/water/", ".gif", 11));
                _sourceList.add(new CloudmadeMapSource("Pale Dawn", "998", 18));
index 9f1fbfe70f8ccde2ca78d87240dc48fb51ef923a..f7a281b1022ca8059a02e4fe9aef004431b464fc 100644 (file)
@@ -126,7 +126,8 @@ public class MapTileManager implements ImageObserver
                if (useDisk)
                {
                        tile = DiskTileCacher.getTile(diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), onlineMode);
-                       if (tile != null) {
+                       if (tile != null)
+                       {
                                // Pass tile to memory cache
                                tempCache.setTile(tile, inX, inY);
                                if (tile.getWidth(this) > 0) {return tile;}
@@ -139,11 +140,13 @@ public class MapTileManager implements ImageObserver
                        try
                        {
                                URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY));
-                               if (useDisk) {
-                                       // Copy image directly from URL stream to disk cache
-                                       DiskTileCacher.saveTile(tileUrl, diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this);
+                               if (useDisk && DiskTileCacher.saveTile(tileUrl, diskCachePath,
+                                       _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this))
+                               {
+                                       // Image now copied directly from URL stream to disk cache
                                }
-                               else {
+                               else
+                               {
                                        // Load image asynchronously, using observer
                                        tile = Toolkit.getDefaultToolkit().createImage(tileUrl);
                                        // Pass to memory cache
index fdd2949446c6b387c8c1fd7f33bedc4209ac9918..3f3f848ee505f55938b88a7d121d644d705d37b0 100644 (file)
@@ -10,7 +10,7 @@ import tim.prune.config.ColourScheme;
 import tim.prune.config.Config;
 
 /**
- * Class to show a scale bar on the main map of Prune
+ * Class to show a scale bar on the main map of GpsPrune
  */
 public class ScaleBar extends JPanel
 {
index 7f2e10f2e1ab80f01de61feba9681b6333c984b4..f92046a798c1509aa1a049cb72c4cd78ea1170da 100644 (file)
@@ -30,28 +30,35 @@ public class AltitudeData extends ProfileData
                initArrays();
                _hasData = false;
                _altitudeFormat = Altitude.Format.NO_FORMAT;
-               if (_track != null) {
+               if (_track != null)
+               {
                        for (int i=0; i<_track.getNumPoints(); i++)
                        {
-                               DataPoint point = _track.getPoint(i);
-                               if (point != null && point.hasAltitude())
+                               try
                                {
-                                       // Point has an altitude - if it's the first one, use its format
-                                       if (_altitudeFormat == Altitude.Format.NO_FORMAT)
+                                       DataPoint point = _track.getPoint(i);
+                                       if (point != null && point.hasAltitude())
                                        {
-                                               _altitudeFormat = point.getAltitude().getFormat();
-                                               _minValue = _maxValue = point.getAltitude().getValue();
+                                               // Point has an altitude - if it's the first one, use its format
+                                               if (_altitudeFormat == Altitude.Format.NO_FORMAT)
+                                               {
+                                                       _altitudeFormat = point.getAltitude().getFormat();
+                                                       _minValue = _maxValue = point.getAltitude().getValue();
+                                               }
+                                               // Store the value and maintain max and min values
+                                               double value = point.getAltitude().getValue(_altitudeFormat);
+                                               _pointValues[i] = value;
+                                               if (value < _minValue) {_minValue = value;}
+                                               if (value > _maxValue) {_maxValue = value;}
+       
+                                               _hasData = true;
+                                               _pointHasData[i] = true;
                                        }
-                                       // Store the value and maintain max and min values
-                                       double value = point.getAltitude().getValue(_altitudeFormat);
-                                       _pointValues[i] = value;
-                                       if (value < _minValue) {_minValue = value;}
-                                       if (value > _maxValue) {_maxValue = value;}
-
-                                       _hasData = true;
-                                       _pointHasData[i] = true;
+                                       else _pointHasData[i] = false;
                                }
-                               else _pointHasData[i] = false;
+                               catch (ArrayIndexOutOfBoundsException obe)
+                               {} // must be due to the track size changing during calculation
+                                  // assume that a redraw will be triggered
                        }
                }
        }
index cff2346e531dff458d4b91a1a49822a270087d51..0d94f038479b829f3393ffc1fcbfc76fc795954c 100644 (file)
@@ -5,6 +5,7 @@ import java.io.File;
 import com.drew.lang.Rational;
 import com.drew.metadata.Directory;
 import com.drew.metadata.Metadata;
+import com.drew.metadata.MetadataException;
 import com.drew.metadata.exif.ExifDirectory;
 import com.drew.metadata.exif.ExifReader;
 import com.drew.metadata.exif.GpsDirectory;
@@ -12,7 +13,7 @@ import com.drew.metadata.exif.GpsDirectory;
 /**
  * Class to act as a gateway into the external exif library functions.
  * This should be the only class with dependence on the lib-metadata-extractor-java
- * classes (which are NOT delivered with Prune).
+ * classes (which are NOT delivered with GpsPrune).
  * This class will not compile without this extra dependency (but is not required if
  * the ExifGateway uses the InternalExifLibrary instead).
  * Should not be included if the internal library will be used (from jpeg.drew package).
@@ -60,16 +61,29 @@ public class ExternalExifLibrary implements ExifLibrary
                                        data.setAltitudeRef(altRef);
                                }
 
-                               // Timestamp and datestamp (if present)
-                               final int TAG_GPS_DATESTAMP = 0x001d;
-                               if (gpsdir.containsTag(GpsDirectory.TAG_GPS_TIME_STAMP) && gpsdir.containsTag(TAG_GPS_DATESTAMP))
+                               try
                                {
-                                       Rational[] times = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_TIME_STAMP);
-                                       data.setGpsTimestamp(new int[] {times[0].intValue(), times[1].intValue(),
-                                               times[2].intValue()});
-                                       Rational[] dates = gpsdir.getRationalArray(TAG_GPS_DATESTAMP);
-                                       if (dates != null) {
-                                               data.setGpsDatestamp(new int[] {dates[0].intValue(), dates[1].intValue(), dates[2].intValue()});
+                                       // Timestamp and datestamp (if present)
+                                       final int TAG_GPS_DATESTAMP = 0x001d;
+                                       if (gpsdir.containsTag(GpsDirectory.TAG_GPS_TIME_STAMP) && gpsdir.containsTag(TAG_GPS_DATESTAMP))
+                                       {
+                                               Rational[] times = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_TIME_STAMP);
+                                               data.setGpsTimestamp(new int[] {times[0].intValue(), times[1].intValue(),
+                                                       times[2].intValue()});
+                                               Rational[] dates = gpsdir.getRationalArray(TAG_GPS_DATESTAMP);
+                                               if (dates != null) {
+                                                       data.setGpsDatestamp(new int[] {dates[0].intValue(), dates[1].intValue(), dates[2].intValue()});
+                                               }
+                                       }
+                               }
+                               catch (MetadataException me) {} // ignore, use other tags instead
+
+                               // Image bearing (if present)
+                               if (gpsdir.containsTag(GpsDirectory.TAG_GPS_IMG_DIRECTION) && gpsdir.containsTag(GpsDirectory.TAG_GPS_IMG_DIRECTION_REF))
+                               {
+                                       Rational bearing = gpsdir.getRational(GpsDirectory.TAG_GPS_IMG_DIRECTION);
+                                       if (bearing != null) {
+                                               data.setBearing(bearing.doubleValue());
                                        }
                                }
                        }
@@ -108,6 +122,7 @@ public class ExternalExifLibrary implements ExifLibrary
                }
                catch (Exception e) {
                        // Exception reading metadata, just ignore it
+                       //System.err.println("Error: " + e.getClass().getName() + " - " + e.getMessage());
                }
                return data;
        }
index 62e54aff2f03846412d231d951429146995f6827..8a25f6d276cf0d4355439b7495ba44ef463d2a34 100644 (file)
@@ -21,6 +21,7 @@ public class JpegData
        private String _digitizedTimestamp = null;
        private int _orientationCode = -1;
        private byte[] _thumbnail = null;
+       private double _bearing = -1.0;
        private ArrayList<String> _errors = null;
 
 
@@ -145,6 +146,15 @@ public class JpegData
                }
        }
 
+       /**
+        * Set the bearing (0 - 360)
+        * @param inBearing bearing in degrees
+        */
+       public void setBearing(double inBearing)
+       {
+               _bearing = inBearing;
+       }
+
        /** @return latitude ref as char */
        public char getLatitudeRef() { return _latitudeRef; }
        /** @return latitude as array of 3 Rationals */
@@ -169,6 +179,8 @@ public class JpegData
        public String getOriginalTimestamp() { return _originalTimestamp; }
        /** @return digitized timestamp as string */
        public String getDigitizedTimestamp() { return _digitizedTimestamp; }
+       /** @return bearing in degrees or -1 */
+       public double getBearing() { return _bearing; }
 
        /**
         * Set the thumbnail
index 384778d7418a77544f60e8f5524adacf580c4040..08f30128035a8c2f2b7a483ba3e69daeeacf30d9 100644 (file)
@@ -85,6 +85,8 @@ public class ExifReader
        private static final int TAG_THUMBNAIL_LENGTH = 0x0202;\r
        /** Orientation of image */\r
        private static final int TAG_ORIENTATION = 0x0112;\r
+       /** Bearing direction of image */\r
+       private static final int TAG_BEARING = 0x0011;\r
 \r
 \r
        /**\r
@@ -369,7 +371,8 @@ public class ExifReader
                                        if (dates != null) {\r
                                                inMetadata.setGpsDatestamp(new int[] {dates[0].intValue(), dates[1].intValue(), dates[2].intValue()});\r
                                        }\r
-                                       else {\r
+                                       else\r
+                                       {\r
                                                // Not in rational array format, but maybe as String?\r
                                                String date = readString(inTagValueOffset, inFormatCode, inComponentCount);\r
                                                if (date != null && date.length() == 10) {\r
@@ -378,6 +381,12 @@ public class ExifReader
                                                }\r
                                        }\r
                                        break;\r
+                               case TAG_BEARING:\r
+                                       Rational val = readRational(inTagValueOffset, inFormatCode, inComponentCount);\r
+                                       if (val != null) {\r
+                                               inMetadata.setBearing(val.doubleValue());\r
+                                       }\r
+                                       break;\r
                                default: // ignore all other tags\r
                        }\r
                }\r
index 2c0b6ce41b4d0c121a387caeefa3052339a3c057..58618b8cd32c07ecc960ecaafcd4d03b84b7b3b8 100644 (file)
@@ -1,4 +1,4 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Afrikaans entries as extra
 
 # Menu entries
@@ -6,32 +6,30 @@ menu.file=L\u00eaer
 menu.file.addphotos=Voeg Fotos By
 menu.file.save=Stoor
 menu.file.exit=Gaan Uit
+menu.track=Spoor
 menu.track.undo=Herroep
 menu.track.clearundo=Herroep Lys Skoonmaak
-menu.point.editpoint=Redigeer Punt
-menu.point.deletepoint=Punt Uitvee
-menu.range.deleterange=Reeks Uitvee
 menu.track.deletemarked=Gemerkde Punt Uitvee
-menu.range.interpolate=Interpoleer
-menu.range.average=Gemiddelde Seleksie
-menu.range.reverse=Reeks Omkeer
-menu.range.mergetracksegments=Saamvoeg van spoor segmente
 menu.track.rearrange=Herrangskik bakens
 menu.track.rearrange.start=Bakens na begin van l\u00eaer
 menu.track.rearrange.end=Bakens na einde van l\u00eaer
 menu.track.rearrange.nearest=Beweeg elk na naaste spoor punt
-menu.range.cutandmove=Sny en skuif seleksie
 menu.range=Reeks
-menu.point=Punt
 menu.range.all=Selekteer Alles
 menu.range.none=Selekteer Niks
 menu.range.start=Stel Reeks Begin
 menu.range.end=Stel Reeks Einde
+menu.range.deleterange=Reeks Uitvee
+menu.range.interpolate=Interpoleer
+menu.range.average=Gemiddelde Seleksie
+menu.range.reverse=Reeks Omkeer
+menu.range.mergetracksegments=Saamvoeg van spoor segmente
+menu.range.cutandmove=Sny en skuif seleksie
+menu.point=Punt
+menu.point.editpoint=Redigeer Punt
+menu.point.deletepoint=Punt Uitvee
 menu.photo=Foto
 menu.photo.saveexif=Stoor na EXIF
-function.connecttopoint=Las foto by huidige punt
-function.disconnectfrompoint=Ontkoppel vanaf huidige punt
-function.removephoto=Verwyder foto
 menu.view=Kyk
 menu.view.browser=Kaart in werf blaaier
 menu.view.browser.google=Google Kaarte
@@ -49,6 +47,7 @@ menu.map.newpoint=Skep nuwe punt
 menu.map.connect=Connekteer baan punte
 menu.map.autopan=Automatiese Skuif van Kyk Venster
 menu.map.showmap=Wys Kaart
+menu.map.showscalebar=Wys SkalleerStaaf
 
 # Alt keys for menus
 altkey.menu.file=L
@@ -75,16 +74,32 @@ function.sendtogps=Stuur van GPS data
 function.exportkml=KML Uitvoer
 function.exportgpx=GPS Uitvoer
 function.exportpov=POV Uitvoer
+function.exportsvg=SVG Uitvoer
 function.editwaypointname=Redigeer Baken Naam
 function.compress=Kompakteer spoor
 function.addtimeoffset=Voeg tyd spruit by
+function.addaltitudeoffset=Voeg hoogte spruit by
+function.convertnamestotimes=Omskakel baken name na tye
 function.findwaypoint=Vind Baken
+function.pastecoordinates=Enter nuwe koordinate
 function.charts=Grafieke
 function.show3d=3D Kyk
 function.distances=Afstande
+function.fullrangedetails=Vol reeks besonderhede
 function.setmapbg=Stel Kaart agtergrond
+function.setpaths=Stel program paaie
 function.getgpsies=Kry GPS spore
+function.duplicatepoint=Dupliseer Punt
+function.setcolours=Stel kleure
+function.setlanguage=Stel tale
+function.connecttopoint=Las foto by huidige punt
+function.disconnectfrompoint=Ontkoppel vanaf huidige punt
+function.removephoto=Verwyder foto
 function.correlatephotos=Korreleer Fotos
+function.rearrangephotos=Herrangskik fotos
+function.rotatephotoleft=Roteer foto links
+function.rotatephotoright=Roteer foto regs
+function.ignoreexifthumb=Ignoreer EXIF thumbnail
 function.help=Hulp
 function.showkeys=Wys Kortpad sleutels
 function.about=Omtrent Prune
@@ -125,6 +140,7 @@ dialog.gpsload.device=Apparaat naam
 dialog.gpsload.format=Formaat
 dialog.gpsload.getwaypoints=Laai Bakens
 dialog.gpsload.gettracks=Laai spore
+dialog.gpsload.save=Stoor na l\u00eaer
 dialog.gpssend.sendwaypoints=Stuur Bakens
 dialog.gpssend.sendtracks=Stuur Spore
 dialog.gpssend.trackname=Spoor name
@@ -139,13 +155,16 @@ dialog.save.altitudeunits=Hoogte Eenhede
 dialog.save.timestampformat=Tyd Stempel Formaat
 dialog.save.overwrite.title=L\u00eaer bestaan reeds
 dialog.save.overwrite.text=Hierdie L\u00eaer bestaan reeds. Is jy seker jy wil die l\u00eaer oorskryf?
+dialog.save.notypesselected=Geen punt tipes is geselekteer nie
 dialog.exportkml.text=Titel vir die data
 dialog.exportkml.altitude=Absolute hoogte (vir aviasie)
 dialog.exportkml.kmz=Kompakteer om kmz l\u00eaer te maak
 dialog.exportkml.exportimages=Voer beeld duimnaelsketse uit na kmz
+dialog.exportkml.trackcolour=Spoor kleur
 dialog.exportgpx.name=Naam
 dialog.exportgpx.desc=Beskrywing
 dialog.exportgpx.includetimestamps=Tydstempel Insluit
+dialog.exportgpx.copysource=Kopieer bron xml
 dialog.exportpov.text=Steutel asseblief parameters in vir POV uitvoer
 dialog.exportpov.font=Font
 dialog.exportpov.camerax=Kamera X
@@ -172,3 +191,18 @@ dialog.undo.none.text=Geen operasies om te herroep!
 dialog.clearundo.title=Maak Herroep lys uit skoon
 dialog.clearundo.text=Is jy seker jy wil die herroep lys skoon maak?\nAlle herroep informasie sal verlore gaan!
 dialog.pointedit.title=Redigeer punt
+dialog.pointedit.table.field=Veld
+dialog.pointedit.table.value=Waarde
+dialog.pointedit.table.changed=Verander
+dialog.pointnameedit.name=Baken naam
+dialog.pointnameedit.uppercase=Hoof letter
+dialog.pointnameedit.lowercase=Klein letter
+dialog.addtimeoffset.add=Voeg tyd by
+dialog.addtimeoffset.subtract=Vat tyd weg
+dialog.addtimeoffset.days=Dae
+dialog.addtimeoffset.hours=Ure
+dialog.addtimeoffset.minutes=Minute
+dialog.findwaypoint.search=Soek
+dialog.saveexif.title=Stoor Exif
+dialog.saveexif.table.status=Status
+dialog.saveexif.table.save=Stoor
index 37ab63723ea9093171d87e5769bf78b779da34ed..ae344cae8fb501d255bbef50f7d1cae16f26895a 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Czech entries thanks to prot_d
 
 # Menu entries
 menu.file=Soubor
 menu.file.addphotos=P\u0159idat fotografie
+menu.file.recentfiles=Naposledy otev\u0159en\u00e9
 menu.file.save=Ulo\u017eit jako text
 menu.file.exit=Konec
 menu.track=Trasa
@@ -41,6 +42,7 @@ menu.view.browser.yahoo=Mapy Yahoo
 menu.view.browser.bing=Mapy Bing
 menu.settings=Nastaven\u00ed
 menu.settings.onlinemode=Na\u010d\u00edtat mapy z internetu
+menu.settings.autosave=P\u0159i ukon\u010den\u00ed automaticky ukl\u00e1dat
 menu.help=Pomoc
 # Popup menu for map
 menu.map.zoomin=P\u0159ibl\u00ed\u017eit
@@ -75,6 +77,7 @@ shortcut.menu.help.help=P
 
 # Functions
 function.open=Otev\u0159\u00edt soubor
+function.importwithgpsbabel=Importovat p\u0159es GPSBabel
 function.loadfromgps=Na\u010d\u00edst data z GPS
 function.sendtogps=Poslat data do GPS
 function.exportkml=Export KML
@@ -126,9 +129,10 @@ function.about=O programu
 function.checkversion=Zkontrolovat existenci nov\u00e9 verze
 function.saveconfig=Ulo\u017eit nastaven\u00ed
 function.diskcache=Ulo\u017eit mapy na disk
+function.managetilecache=Upravit cache map
 
 # Dialogs
-dialog.exit.confirm.title=Ukon\u010dit Prune
+dialog.exit.confirm.title=Ukon\u010dit GpsPrune
 dialog.exit.confirm.text=Data nejsou ulo\u017eena. Opravdu chcete ukon\u010dit program?
 dialog.openappend.title=P\u0159ipojit k na\u010dten\u00fdm dat\u016fm
 dialog.openappend.text=P\u0159ipojit tato data k ji\u017e na\u010dten\u00fdm dat\u016fm?
@@ -189,6 +193,9 @@ dialog.exportgpx.name=N\u00e1zev
 dialog.exportgpx.desc=Popis
 dialog.exportgpx.includetimestamps=Ulo\u017eit \u010dasov\u00e9 zna\u010dky
 dialog.exportgpx.copysource=Zkop\u00edrovat zdrojov\u00e9 xml
+dialog.exportgpx.encoding=K\u00f3dov\u00e1n\u00ed
+dialog.exportgpx.encoding.system=Implicitn\u00ed dle OS
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Pros\u00edm vlo\u017ete paramerty exportu do POV
 dialog.exportpov.font=Font
 dialog.exportpov.camerax=Kamera X
@@ -341,14 +348,16 @@ dialog.compress.wackypoints.paramdesc=Koeficient vzd\u00e1lnosti
 dialog.compress.singletons.title=Odstran\u011bn\u00ed osamocen\u00fdch bod\u016f
 dialog.compress.singletons.paramdesc=Koeficient vzd\u00e1lenosti
 dialog.compress.duplicates.title=Odstran\u011bn\u00ed zdvojen\u00fdch bod\u016f
+dialog.compress.douglaspeucker.title=Douglasova-Peuckerova komprese
+dialog.compress.douglaspeucker.paramdesc=Povolen\u00e1 odchylka
 dialog.compress.summarylabel=Bod\u016f ke smaz\u00e1n\u00ed
 dialog.pastecoordinates.desc=Zadejte sou\u0159adnice
 dialog.pastecoordinates.coords=Sou\u0159adnice
 dialog.pastecoordinates.nothingfound=Pros\u00edm ov\u011b\u0159te sou\u0159adnice a zkuste znovu
-dialog.help.help=V\u00edce informac\u00ed v\u010detn\u011b manu\u00e1l\u016f (bohu\u017eel nikoli v \u010de\u0161tin\u011b) naleznete na adrese:\n http://activityworkshop.net/software/prune/
+dialog.help.help=V\u00edce informac\u00ed v\u010detn\u011b manu\u00e1l\u016f (bohu\u017eel nikoli v \u010de\u0161tin\u011b) naleznete na adrese:\n http://activityworkshop.net/software/gpsprune/
 dialog.about.version=Verze
 dialog.about.build=Build
-dialog.about.summarytext1=Prune je program k na\u010d\u00edt\u00e1n\u00ed, zobrazov\u00e1n\u00ed a editaci dat z navigac\u00ed GPS.
+dialog.about.summarytext1=GpsPrune je program k na\u010d\u00edt\u00e1n\u00ed, zobrazov\u00e1n\u00ed a editaci dat z navigac\u00ed GPS.
 dialog.about.summarytext2=Je vyd\u00e1n pod licenc\u00ed GNU GPL, tak\u017ee je zdarma a voln\u011b k u\u017e\u00edv\u00e1n\u00ed a vylep\u0161ov\u00e1n\u00ed.<br>Kop\u00edrov\u00e1n\u00ed, redistribuce a \u00fapravy jsou povoleny a podporov\u00e1ny<br>podle podm\u00ednek popsan\u00fdch v souboru <code>licence.txt</code>.
 dialog.about.summarytext3=V\u00edce informac\u00ed v\u010detn\u011b manu\u00e1l\u016f (bohu\u017eel nikoli v \u010de\u0161tin\u011b) naleznete<br> na adrese: <code style="font-weight:bold">http://activityworkshop.net/</code>.
 dialog.about.languages=Dostupn\u00e9 jazyky
@@ -379,12 +388,12 @@ dialog.about.credits.othertools=Dal\u0161\u00ed n\u00e1stroje
 dialog.about.credits.thanks=D\u011bkujeme
 dialog.about.readme=Readme
 dialog.checkversion.error=\u010c\u00edslo verze se nepoda\u0159ilo zkontrolovat.\nPros\u00edm ov\u011b\u0159te p\u0159ipojen\u00ed k internetu.
-dialog.checkversion.uptodate=Pou\u017e\u00edv\u00e1te posledn\u00ed verzi Prune.
-dialog.checkversion.newversion1=Nov\u00e1 verze Prune je u\u017e dostupn\u00e1! Posledn\u00ed verze m\u00e1 \u010d\u00edslo
+dialog.checkversion.uptodate=Pou\u017e\u00edv\u00e1te posledn\u00ed verzi GpsPrune.
+dialog.checkversion.newversion1=Nov\u00e1 verze GpsPrune je u\u017e dostupn\u00e1! Posledn\u00ed verze m\u00e1 \u010d\u00edslo
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=Tato verze byla vyd\u00e1na
 dialog.checkversion.releasedate2=.
-dialog.checkversion.download=Novou verzi m\u016f\u017eete st\u00e1hnout na adrese http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=Novou verzi m\u016f\u017eete st\u00e1hnout na adrese http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=M\u00edsto my\u0161i m\u016f\u017eete pou\u017e\u00edvat n\u00e1sleduj\u00edc\u00ed kl\u00e1vesov\u00e9 zkratky
 dialog.keys.keylist=<table><tr><td>\u0160ipky</td><td>Posunout mapu vlevo, vpravo, nahoru, dol\u016f</td></tr><tr><td>Ctrl + \u0161ipka vlevo, vpravo</td><td>Vybrat p\u0159edchoz\u00ed nebo n\u00e1sleduj\u00edc\u00ed bod</td></tr><tr><td>Ctrl + \u0161ipka nahoru, dol\u016f</td><td>P\u0159ibl\u00ed\u017eit, odd\u00e1lit</td></tr><tr><td>Ctrl + PgUp, PgDown</td><td>Vybrat p\u0159edchoz\u00ed, n\u00e1sleduj\u00edc\u00ed \u010d\u00e1st trasy</td></tr><tr><td>Ctrl + Home, End</td><td>Vybrat prvn\u00ed, posledn\u00ed bod</td></tr><tr><td>Del</td><td>Smazat aktu\u00e1ln\u00ed bod</td></tr></table>
 dialog.keys.normalmodifier=Ctrl
@@ -409,6 +418,7 @@ dialog.saveconfig.prune.kmzimageheight=V\u00fd\u0161ka bitmapy KMZ
 dialog.saveconfig.prune.colourscheme=Barevn\u00e9 sch\u00e9ma
 dialog.saveconfig.prune.linewidth=Tlou\u0161\u0165ka \u010d\u00e1ry
 dialog.saveconfig.prune.kmltrackcolour=Barva trasy v KML
+dialog.saveconfig.prune.autosavesettings=Mo\u017enosti ukl\u00e1d\u00e1n\u00ed
 dialog.setpaths.intro=Je-li to t\u0159eba, m\u016f\u017eete nastavit cesty k extern\u00edm aplikac\u00edm:
 dialog.setpaths.found=Cesta nalezena?
 dialog.addaltitude.noaltitudes=Vybran\u00e9 rozmez\u00ed neobsahuje nadmo\u0159skou v\u00fd\u0161ku
@@ -428,23 +438,35 @@ dialog.colourchooser.red=\u010cerven\u00e1
 dialog.colourchooser.green=Zelen\u00e1
 dialog.colourchooser.blue=Modr\u00e1
 dialog.setlanguage.firstintro=M\u016f\u017eete bu\u010f zvolit jeden z vypsan\u00fdch jazyk\u016f,<p>nebo vybrat textov\u00fd soubor
-dialog.setlanguage.secondintro=Aby do\u0161lo ke zm\u011bn\u011b jazyka, je t\u0159eba ulo\u017eit nastaven\u00ed<p> a potom restartovat program Prune.
+dialog.setlanguage.secondintro=Aby do\u0161lo ke zm\u011bn\u011b jazyka, je t\u0159eba ulo\u017eit nastaven\u00ed<p> a potom restartovat program GpsPrune.
 dialog.setlanguage.language=Jazyk
 dialog.setlanguage.languagefile=Jazykov\u00fd soubor
-dialog.setlanguage.endmessage=Aby do\u0161lo ke zm\u011bn\u011b jazyka, nyn\u00ed ulo\u017ete nastaven\u00ed\na spus\u0165te Prune nanovo.
+dialog.setlanguage.endmessage=Aby do\u0161lo ke zm\u011bn\u011b jazyka, nyn\u00ed ulo\u017ete nastaven\u00ed\na spus\u0165te GpsPrune nanovo.
+dialog.setlanguage.endmessagewithautosave=Aby byla dokon\u010dena zm\u011bna jazyka, pros\u00edm restartujte program.
 dialog.diskcache.save=Ukl\u00e1dat mapov\u00e9 podklady na disk
 dialog.diskcache.dir=Adres\u00e1\u0159 s cache
 dialog.diskcache.createdir=Vytvo\u0159it adres\u00e1\u0159
 dialog.diskcache.nocreate=Adres\u00e1\u0159 nebyl vytvo\u0159en
+dialog.diskcache.table.path=Cesta
+dialog.diskcache.table.usedby=Pou\u017e\u00edv\u00e1
+dialog.diskcache.table.zoom=Zv\u011bt\u0161en\u00ed
+dialog.diskcache.table.tiles=Dla\u017edic
+dialog.diskcache.table.megabytes=Megabyt\u016f
+dialog.diskcache.tileset=Mapov\u00fd podklad
+dialog.diskcache.tileset.multiple=v\u00edce sad
+dialog.diskcache.deleteold=Smazat star\u00e9 soubory
+dialog.diskcache.deleteall=Smazat v\u0161echny soubory
+dialog.diskcache.deleted1=Smaz\u00e1no
+dialog.diskcache.deleted2=soubor\u016f z cache
 dialog.deletefieldvalues.intro=Vyberte pole, kter\u00e9 se m\u00e1 z aktu\u00e1ln\u00edho rozmez\u00ed odstranit
 dialog.setlinewidth.text=Zvolte tlou\u0161\u0165ku \u010d\u00e1ry, kterou se nakresl\u00ed trasa (1-4)
 dialog.downloadosm.desc=Potvr\u010fte, \u017ee se maj\u00ed k dan\u00e9 oblasti st\u00e1hnout data OSM:
 dialog.searchwikipedianames.search=Vyhledat:
 
 # 3d window
-dialog.3d.title=Trojrozm\u011brn\u00e9 zobrazen\u00ed Prune
+dialog.3d.title=Trojrozm\u011brn\u00e9 zobrazen\u00ed GpsPrune
 dialog.3d.altitudefactor=Faktor zd\u016frazn\u011bn\u00ed v\u00fd\u0161ky
-dialog.3dlines.title=Linky m\u0159\u00ed\u017eky Prune
+dialog.3dlines.title=Linky m\u0159\u00ed\u017eky GpsPrune
 dialog.3dlines.empty=Nejsou \u017e\u00e1dn\u00e9 linky k zobrazen\u00ed!
 dialog.3dlines.intro=Toto jsou linky m\u0159\u00ed\u017eky trojrozm\u011brn\u00e9ho zobrazen\u00ed
 
@@ -516,6 +538,7 @@ button.resettodefaults=Resetovat
 button.browse=Proch\u00e1zet...
 button.addnew=P\u0159idat nov\u00e9
 button.delete=Smazat
+button.manage=Upravit
 
 # File types
 filetype.txt=soubory TXT
@@ -567,6 +590,7 @@ details.lists.audio=Audionahr\u00e1vky
 details.photodetails=Detaily fotografie
 details.nophoto=Fotografie nevybr\u00e1na
 details.photo.loading=Na\u010d\u00edt\u00e1m
+details.photo.bearing=Azimut
 details.media.connected=P\u0159ipojeno
 details.audiodetails=Detaily audionahr\u00e1vky
 details.noaudio=Audionahr\u00e1vka nevybr\u00e1na
@@ -590,6 +614,7 @@ fieldname.movingdistance=Najeto
 fieldname.duration=Celkov\u00fd \u010das
 fieldname.speed=Rychlost
 fieldname.verticalspeed=Vertik. rychlost
+fieldname.description=Popis
 
 # Measurement units
 units.original=P\u016fvodn\u00ed
@@ -684,10 +709,13 @@ error.3d=P\u0159i trojrozm\u011brn\u00e9m zobrazen\u00ed do\u0161lo k chyb\u011b
 error.readme.notfound=Nenalezen soubor readme
 error.osmimage.dialogtitle=Chyba p\u0159i na\u010d\u00edt\u00e1n\u00ed mapov\u00fdch podklad\u016f
 error.osmimage.failed=Selhalo na\u010dten\u00ed mapov\u00fdch podklad\u016f. Pros\u00edm zkontrolujte p\u0159ipojen\u00ed k internetu.
-error.language.wrongfile=Vybran\u00fd soubor nevypad\u00e1 jako jazykov\u00fd soubor pro Prune
+error.language.wrongfile=Vybran\u00fd soubor nevypad\u00e1 jako jazykov\u00fd soubor pro GpsPrune
 error.convertnamestotimes.nonames=N\u00e1zvy nemohou b\u00fdt p\u0159evedeny na \u010dasov\u00e9 zna\u010dky
 error.lookupsrtm.nonefound=Pro tyto body nen\u00ed k dispozici informace o nadmo\u0159sk\u00e9 v\u00fd\u0161ce
 error.lookupsrtm.nonerequired=U v\u0161ech bod\u016f u\u017e je informaci o v\u00fd\u0161ce, tak\u017ee nen\u00ed co dohled\u00e1vat
 error.gpsies.uploadnotok=Server gpsies vr\u00e1til hl\u00e1\u0161en\u00ed
 error.gpsies.uploadfailed=Chyba - nepoda\u0159ilo se nahr\u00e1t data.
 error.playaudiofailed=Nepoda\u0159ilo se p\u0159ehr\u00e1t zvukov\u00fd soubor.
+error.cache.notthere=Nepoda\u0159ilo se nal\u00e9zt adres\u00e1\u0159 s cache map.
+error.cache.empty=Adres\u00e1\u0159 s cache map je pr\u00e1zdn\u00fd.
+error.cache.cannotdelete=Nelze smazat soubory map.
index a2a45baa6e3190a4d381773d10462a8af927c53e..6e102d4468f56ff1f0f3eddd739faf7b68bd182d 100644 (file)
@@ -1,14 +1,15 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # German entries as extra
 
 # Menu entries
 menu.file=Datei
 menu.file.addphotos=Fotos laden
+menu.file.recentfiles=Zuletzt verwendete Dateien
 menu.file.save=Als Text Speichern
 menu.file.exit=Beenden
 menu.track=Track
 menu.track.undo=R\u00fcckg\u00e4ngig
-menu.track.clearundo=Liste der letzten Ã„nderungen l\u00f6schen
+menu.track.clearundo=Liste der letzten \u00c4nderungen l\u00f6schen
 menu.track.deletemarked=Komprimierte Punkte l\u00f6schen
 menu.track.rearrange=Wegpunkte reorganisieren
 menu.track.rearrange.start=Alle Wegpunkte zum Anfang
@@ -30,15 +31,13 @@ menu.point.editpoint=Punkt bearbeiten
 menu.point.deletepoint=Punkt l\u00f6schen
 menu.photo=Foto
 menu.photo.saveexif=Exif Daten speichern
-function.connecttopoint=Mit Punkt verkn\u00fcpfen
-function.disconnectfrompoint=Vom Punkt trennen
-function.removephoto=Foto entfernen
 menu.audio=Audio
 menu.view=Ansicht
 menu.view.showsidebars=Seitenleisten anzeigen
 menu.view.browser=Karte in Browser
 menu.settings=Einstellungen
 menu.settings.onlinemode=Karten aus dem Internet laden
+menu.settings.autosave=Einstellungen automatisch speichern
 menu.help=Hilfe
 # Popup menu for map
 menu.map.zoomin=Hineinzoomen
@@ -73,6 +72,7 @@ shortcut.menu.help.help=H
 
 # Functions
 function.open=Datei \u00f6ffnen
+function.importwithgpsbabel=Datei mit GPSBabel importieren
 function.loadfromgps=Vom GPS laden
 function.sendtogps=zum GPS schicken
 function.exportkml=KML exportieren
@@ -84,7 +84,7 @@ function.compress=Track komprimieren
 function.addtimeoffset=Zeitverschiebung aufrechnen
 function.addaltitudeoffset=H\u00f6henverschiebung aufrechnen
 function.convertnamestotimes=Wegpunktenamen in Zeitstempel umwandeln
-function.deletefieldvalues=Werte eines Feldes löschen
+function.deletefieldvalues=Werte eines Feldes l\u00f6schen
 function.findwaypoint=Wegpunkt finden
 function.pastecoordinates=Neue Koordinaten eingeben
 function.charts=Diagramme
@@ -97,13 +97,16 @@ function.setpaths=Programmpfade setzen
 function.getgpsies=Gpsies Tracks holen
 function.uploadgpsies=Daten zum Gpsies hochladen
 function.lookupsrtm=H\u00f6hendaten von SRTM holen
-function.getwikipedia=Wikipediaartikeln in der N\u00e4he nachschlagen
+function.getwikipedia=Wikipediaartikel in der N\u00e4he nachschlagen
 function.searchwikipedianames=Wikipedia mit Name durchsuchen
 function.downloadosm=OSM Daten f\u00fcr dieses Gebiet herunterladen
 function.duplicatepoint=Punkt verdoppeln
 function.setcolours=Farben einstellen
-function.setlinewidth=Liniedicke einstellen
+function.setlinewidth=Liniendicke einstellen
 function.setlanguage=Sprache einstellen
+function.connecttopoint=Mit Punkt verkn\u00fcpfen
+function.disconnectfrompoint=Vom Punkt trennen
+function.removephoto=Foto entfernen
 function.correlatephotos=Fotos korrelieren
 function.rearrangephotos=Fotos reorganisieren
 function.rotatephotoleft=Foto nach Links drehen
@@ -117,13 +120,14 @@ function.playaudio=Audiodatei abspielen
 function.stopaudio=Abspielen abbrechen
 function.help=Hilfe
 function.showkeys=Tastenkombinationen anzeigen
-function.about=\u00dcber Prune
+function.about=\u00dcber GpsPrune
 function.checkversion=Nach neuen Versionen suchen
 function.saveconfig=Einstellungen speichern
 function.diskcache=Karten auf Festplatte speichern
+function.managetilecache=Kartenkacheln verwalten
 
 # Dialogs
-dialog.exit.confirm.title=Prune beenden
+dialog.exit.confirm.title=GpsPrune beenden
 dialog.exit.confirm.text=Ihre Daten wurden nicht gespeichert. Wollen Sie das Programm trotzdem beenden?
 dialog.openappend.title=Daten anh\u00e4ngen oder ersetzen
 dialog.openappend.text=Diese Daten an die aktuellen Daten anh\u00e4ngen?
@@ -142,9 +146,9 @@ dialog.delimiter.tab=Tab
 dialog.delimiter.space=Leerzeichen
 dialog.delimiter.semicolon=Strichpunkt ;
 dialog.delimiter.other=Andere
-dialog.openoptions.deliminfo.records=Aufnahmen, mit
+dialog.openoptions.deliminfo.records=Datens\u00e4tze, mit
 dialog.openoptions.deliminfo.fields=Feldern
-dialog.openoptions.deliminfo.norecords=Keine Rekords
+dialog.openoptions.deliminfo.norecords=Keine Datens\u00e4tze
 dialog.openoptions.altitudeunits=H\u00f6he Ma\u00dfeinheiten
 dialog.open.contentsdoubled=Diese Datei enth\u00e4lt zwei Kopien von jedem Punkt,\neinmal als Waypoint und einmal als Trackpunkt.
 dialog.selecttracks.intro=W\u00e4hlen Sie den Track oder die Tracks aus, die Sie laden m\u00f6chten
@@ -184,6 +188,9 @@ dialog.exportgpx.name=Name
 dialog.exportgpx.desc=Beschreibung
 dialog.exportgpx.includetimestamps=Zeitstempel mit exportieren
 dialog.exportgpx.copysource=Xml von Quelle kopieren
+dialog.exportgpx.encoding=Enkodierung
+dialog.exportgpx.encoding.system=System
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Geben Sie die Parameter f\u00fcr den POV Export ein
 dialog.exportpov.font=Font
 dialog.exportpov.camerax=Kamera X
@@ -193,10 +200,10 @@ dialog.exportpov.modelstyle=Modellstil
 dialog.exportpov.ballsandsticks=B\u00e4lle und Stangen
 dialog.exportpov.tubesandwalls=R\u00f6hren und W\u00e4nde
 dialog.exportpov.warningtracksize=Dieser Track hat sehr viele Punkte, die Java3D vielleicht nicht bearbeiten kann.\nM\u00f6chten Sie den Vorgang trotzdem fortsetzen?
-dialog.exportsvg.text=Wählen Sie die Parameter für den SVG Export aus
-dialog.exportsvg.phi=Richtungswinkel \u03D5
-dialog.exportsvg.theta=Neigungswinkel \u03B8
-dialog.exportsvg.gradients=Farbverläufe verwenden
+dialog.exportsvg.text=W\u00e4hlen Sie die Parameter f\u00fcr den SVG Export aus
+dialog.exportsvg.phi=Richtungswinkel \u03d5
+dialog.exportsvg.theta=Neigungswinkel \u03b8
+dialog.exportsvg.gradients=Farbverl\u00e4ufe verwenden
 dialog.pointtype.desc=Folgende Punkttypen speichern:
 dialog.pointtype.track=Trackpunkte
 dialog.pointtype.waypoint=Wegpunkte
@@ -277,7 +284,7 @@ dialog.gpsies.nonefound=Keine Tracks gefunden
 dialog.gpsies.username=Gpsies Username
 dialog.gpsies.password=Gpsies Passwort
 dialog.gpsies.keepprivate=Track privat halten
-dialog.gpsies.confirmopenpage=Webseite für den hochgeladenen Track Ã¶ffnen?
+dialog.gpsies.confirmopenpage=Webseite f\u00fcr den hochgeladenen Track \u00f6ffnen?
 dialog.gpsies.activities=Aktivit\u00e4ten
 dialog.gpsies.activity.trekking=Wandern
 dialog.gpsies.activity.walking=Walking
@@ -336,14 +343,16 @@ dialog.compress.wackypoints.paramdesc=Distanzfaktor
 dialog.compress.singletons.title=Singletons (isolierte Punkte) entfernen
 dialog.compress.singletons.paramdesc=Distanzfaktor
 dialog.compress.duplicates.title=Duplikate entfernen
+dialog.compress.douglaspeucker.title=Douglas-Peucker Komprimierung
+dialog.compress.douglaspeucker.paramdesc=Span Faktor
 dialog.compress.summarylabel=Punkte zu entfernen
 dialog.pastecoordinates.desc=Geben Sie die Koordinaten ein
 dialog.pastecoordinates.coords=Koordinaten
 dialog.pastecoordinates.nothingfound=Bitte pr\u00fcfen Sie die Koordinaten und versuchen Sie es nochmals
-dialog.help.help=Weitere Informationen und Benutzeranleitungen finden Sie unter\n http://activityworkshop.net/software/prune/
+dialog.help.help=Weitere Informationen und Benutzeranleitungen finden Sie unter\n http://activityworkshop.net/software/gpsprune/
 dialog.about.version=Version
 dialog.about.build=Build
-dialog.about.summarytext1=Prune ist ein Programm zum Laden, Darstellen und Editieren von Daten von GPS Ger\u00e4ten.
+dialog.about.summarytext1=GpsPrune ist ein Programm zum Laden, Darstellen und Editieren von Daten von GPS Ger\u00e4ten.
 dialog.about.summarytext2=Es wird unter der Gnu GPL zur Verf\u00fcgung gestellt, zum freien, kostenlosen und offenen Gebrauch und zur Weiterentwicklung.<br>Kopieren, Weiterverbreitung und Ver\u00e4nderungen sind erlaubt und willkommen<br>unter den in der <code>license.txt</code> Datei enthaltenen Bedingungen.
 dialog.about.summarytext3=Auf der Seite <code style="font-weight:bold">http://activityworkshop.net/</code> finden Sie weitere Informationen und Bedienungsanleitungen.
 dialog.about.languages=Verf\u00fcgbare Sprachen
@@ -364,7 +373,7 @@ dialog.about.systeminfo.exiflib.external.failed=Extern (nicht gefunden)
 dialog.about.yes=Ja
 dialog.about.no=Nein
 dialog.about.credits=Credits
-dialog.about.credits.code=Prune Code geschrieben von
+dialog.about.credits.code=GpsPrune Code geschrieben von
 dialog.about.credits.exifcode=Exif Code von
 dialog.about.credits.icons=Einige Bilder von
 dialog.about.credits.translators=Dolmetscher
@@ -374,12 +383,12 @@ dialog.about.credits.othertools=Andere Programme
 dialog.about.credits.thanks=Dank an
 dialog.about.readme=Liesmich
 dialog.checkversion.error=Die Versionnummer konnte nicht ermittelt werden.\nBitte pr\u00fcfen Sie die Internet Verbindung.
-dialog.checkversion.uptodate=Sie haben schon die neueste Version von Prune.
-dialog.checkversion.newversion1=Eine neue Version vom Prune ist jetzt verf\u00fcgbar! Die neue Version ist Version
+dialog.checkversion.uptodate=Sie haben schon die neueste Version von GpsPrune.
+dialog.checkversion.newversion1=Eine neue Version vom GpsPrune ist jetzt verf\u00fcgbar! Die neue Version ist Version
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=Diese neue Version ist am
 dialog.checkversion.releasedate2=ver\u00f6ffentlicht worden.
-dialog.checkversion.download=Um die neue Version herunterzuladen, gehen Sie zu http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=Um die neue Version herunterzuladen, gehen Sie zu http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=Anstelle der Maus k\u00f6nnen Sie folgende Tastenkombinationen nutzen
 dialog.keys.keylist=<table><tr><td>Pfeil Tasten</td><td>Karte verschieben</td></tr><tr><td>Strg + links, rechts Pfeil</td><td>Vorherigen oder n\u00e4chsten Punkt markieren</td></tr><tr><td>Strg + auf, abw\u00e4rts Pfeil</td><td>Ein- oder Auszoomen</td></tr><tr><td>Strg + Bild auf, ab</td><td>Vorherigen oder n\u00e4chsten Segment markieren</td></tr><tr><td>Strg + Pos1, Ende</td><td>Ersten oder letzten Punkt markieren</td></tr><tr><td>Entf</td><td>Aktuellen Punkt entfernen</td></tr></table>
 dialog.keys.normalmodifier=Strg
@@ -404,6 +413,7 @@ dialog.saveconfig.prune.kmzimageheight=Bildh\u00f6he in KMZ
 dialog.saveconfig.prune.colourscheme=Farbschema
 dialog.saveconfig.prune.linewidth=Liniedicke
 dialog.saveconfig.prune.kmltrackcolour=KML Trackfarbe
+dialog.saveconfig.prune.autosavesettings=Einstellungen speichern
 dialog.setpaths.intro=Sie k\u00f6nnen hier die Pfade f\u00fcr externe Applikationen setzen:
 dialog.setpaths.found=Pfad gefunden?
 dialog.addaltitude.noaltitudes=Der markierte Bereich enth\u00e4lt keine H\u00f6henangaben
@@ -423,23 +433,35 @@ dialog.colourchooser.red=Rot
 dialog.colourchooser.green=Gr\u00fcn
 dialog.colourchooser.blue=Blau
 dialog.setlanguage.firstintro=Sie k\u00f6nnen entweder eine von den mitgelieferten Sprachen<p>oder eine Text-Datei ausw\u00e4hlen.
-dialog.setlanguage.secondintro=Sie m\u00fcssen Ihre Einstellungen speichern und dann<p>Prune neu starten um die Sprache zu \u00e4ndern.
+dialog.setlanguage.secondintro=Sie m\u00fcssen Ihre Einstellungen speichern und dann<p>GpsPrune neu starten um die Sprache zu \u00e4ndern.
 dialog.setlanguage.language=Sprache
 dialog.setlanguage.languagefile=Sprachdatei
-dialog.setlanguage.endmessage=Speichern Sie nun Ihre Einstellungen und starten Sie Prune neu\num die neue Sprache zu verwenden.
+dialog.setlanguage.endmessage=Speichern Sie nun Ihre Einstellungen und starten Sie GpsPrune neu\num die neue Sprache zu verwenden.
+dialog.setlanguage.endmessagewithautosave=Starten Sie GpsPrune neu um die neue Sprache zu verwenden.
 dialog.diskcache.save=Karten auf Festplatte speichern
 dialog.diskcache.dir=Kartenordner
 dialog.diskcache.createdir=Ordner anlegen
 dialog.diskcache.nocreate=Ordner wurde nicht angelegt
+dialog.diskcache.table.path=Pfad
+dialog.diskcache.table.usedby=Anwender
+dialog.diskcache.table.zoom=Zoom
+dialog.diskcache.table.tiles=Kacheln
+dialog.diskcache.table.megabytes=Megabytes
+dialog.diskcache.tileset=Ordner
+dialog.diskcache.tileset.multiple=mehrere
+dialog.diskcache.deleteold=Veraltete Kacheln l\u00f6schen
+dialog.diskcache.deleteall=Alle Kacheln l\u00f6schen
+dialog.diskcache.deleted1=Es wurden
+dialog.diskcache.deleted2=Dateien aus dem Ordner gel\u00f6scht
 dialog.deletefieldvalues.intro=W\u00e4hlen Sie das Feld aus, die Sie l\u00f6schen m\u00f6chten
 dialog.setlinewidth.text=Geben Sie die Dicke der Linien ein (1-4)
 dialog.downloadosm.desc=Best\u00e4tigen um rohe OSM Daten f\u00fcr den Gebiet herunterzuladen:
 dialog.searchwikipedianames.search=Suche nach:
 
 # 3d window
-dialog.3d.title=Prune 3D Ansicht
-dialog.3d.altitudefactor=Vervielfachungsfaktor für Höhen
-dialog.3dlines.title=Prune Gitterlinien
+dialog.3d.title=GpsPrune 3D Ansicht
+dialog.3d.altitudefactor=Vervielfachungsfaktor f\u00fcr H\u00f6hen
+dialog.3dlines.title=GpsPrune Gitterlinien
 dialog.3dlines.empty=Keine Linien zum Anzeigen!
 dialog.3dlines.intro=Hier sind die Linien f\u00fcr die 3D Ansicht
 
@@ -467,6 +489,7 @@ confirm.jpegload.multi=Fotos wurden geladen
 confirm.media.connect=Media verbunden
 confirm.photo.disconnect=Foto getrennt
 confirm.audio.disconnect=Audio getrennt
+confirm.media.removed=entfernt
 confirm.correlatephotos.single=Foto wurde korreliert
 confirm.correlatephotos.multi=Fotos wurden korreliert
 confirm.createpoint=Punkt erzeugt
@@ -474,9 +497,8 @@ confirm.rotatephoto=Foto gedreht
 confirm.running=In Bearbeitung ...
 confirm.lookupsrtm1=Es wurden
 confirm.lookupsrtm2=H\u00f6henwerte gefunden
-confirm.deletefieldvalues=Feldwerte gelöscht
+confirm.deletefieldvalues=Feldwerte gel\u00f6scht
 confirm.audioload=Audiodateien geladen
-confirm.media.removed=entfernt
 confirm.correlateaudios.single=Audio wurde korreliert
 confirm.correlateaudios.multi=Audios wurden korreliert
 
@@ -487,8 +509,8 @@ button.next=Vorw\u00e4rts
 button.finish=Fertig
 button.cancel=Abbrechen
 button.overwrite=\u00dcberschreiben
-button.moveup=Nach oben verschieben
-button.movedown=Nach unten verschieben
+button.moveup=Nach oben
+button.movedown=Nach unten
 button.showlines=Linien anzeigen
 button.edit=Bearbeiten
 button.exit=Beenden
@@ -511,6 +533,7 @@ button.resettodefaults=Zur\u00fccksetzen
 button.browse=Durchsuchen...
 button.addnew=Hinzuf\u00fcgen
 button.delete=Entfernen
+button.manage=Verwalten
 
 # File types
 filetype.txt=TXT Dateien
@@ -551,18 +574,19 @@ display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=T
 details.range.avespeed=Durchschnittsgeschwindigkeit
-details.range.avemovingspeed=Durchschnittsgeschwindigkeit unterwegs
+details.range.avemovingspeed=Durchschnittsgeschwindigkeit gleitend
 details.range.maxspeed=H\u00f6chstgeschwindigkeit
 details.range.numsegments=Anzahl Abschnitte
 details.range.pace=Tempo
 details.range.gradient=Gef\u00e4lle
 details.lists.waypoints=Wegpunkte
 details.lists.photos=Fotos
+details.lists.audio=Audio
 details.photodetails=Fotodetails
 details.nophoto=Kein Foto ausgew\u00e4hlt
 details.photo.loading=Laden
+details.photo.bearing=Richtung
 details.media.connected=Verbunden
-details.lists.audio=Audio
 details.audiodetails=Audiodetails
 details.noaudio=Keine Audiodatei ausgew\u00e4hlt
 details.audio.file=Audiodatei
@@ -585,6 +609,7 @@ fieldname.movingdistance=Wegstrecke
 fieldname.duration=Zeitdauer
 fieldname.speed=Geschwindigkeit
 fieldname.verticalspeed=Vertikale Geschwindigkeit
+fieldname.description=Beschreibung
 
 # Measurement units
 units.original=Original
@@ -636,7 +661,7 @@ undo.createpoint=Punkt erzeugen
 undo.rotatephoto=Foto umdrehen
 undo.convertnamestotimes=Namen in Zeitstempel umwandeln
 undo.lookupsrtm=H\u00f6hendaten von SRTM holen
-undo.deletefieldvalues=Feldwerte löschen
+undo.deletefieldvalues=Feldwerte l\u00f6schen
 undo.correlateaudios=Audios korrelieren
 
 # Error messages
@@ -673,10 +698,13 @@ error.3d=Ein Fehler ist bei der 3D Darstellung aufgetreten
 error.readme.notfound=Liesmich Datei nicht gefunden
 error.osmimage.dialogtitle=Laden von Karten-Bildern fehlgeschlagen
 error.osmimage.failed=Laden von Karten-Bildern fehlgeschlagen. Bitte pr\u00fcfen Sie die Internetverbindung.
-error.language.wrongfile=Die ausgew\u00e4hlte Datei scheint keine Sprachdatei f\u00fcr Prune zu sein
+error.language.wrongfile=Die ausgew\u00e4hlte Datei scheint keine Sprachdatei f\u00fcr GpsPrune zu sein
 error.convertnamestotimes.nonames=Es konnten keine Namen umgewandelt werden
-error.lookupsrtm.nonefound=Keine H\u00f6hendaten verfügbar für diese Punkte
-error.lookupsrtm.nonerequired=Alle Punkte haben schon Höhendaten
+error.lookupsrtm.nonefound=Keine H\u00f6hendaten verf\u00fcgbar f\u00fcr diese Punkte
+error.lookupsrtm.nonerequired=Alle Punkte haben schon H\u00f6hendaten
 error.gpsies.uploadnotok=Der Gpsies Server hat geantwortet
 error.gpsies.uploadfailed=Das Hochladen ist fehlgeschlagen
 error.playaudiofailed=Das Abspielen der Audiodatei ist fehlgeschlagen
+error.cache.notthere=Der Ordner wurde nicht gefunden
+error.cache.empty=Der Ordner ist leer
+error.cache.cannotdelete=Es konnte keine Kacheln gel\u00f6scht werden
index b4a3cb07ff1bac70d4bc2d16e7123f3d2265f45c..4e6f73ff5f40b54d9cbf8356b080cb3ddfe61cd0 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Swiss-German entries as extra
 
 # Menu entries
 menu.file=File
 menu.file.addphotos=Fötelis innätue
+menu.file.recentfiles=Letzschti aagluegte Files
 menu.file.save=Als Text Speichere
 menu.file.exit=Beände
 menu.track=Track
@@ -38,7 +39,8 @@ menu.view=Aasicht
 menu.view.showsidebars=Seiteleischten aazeige
 menu.view.browser=Karte inem Browser
 menu.settings=Iistellige
-menu.settings.onlinemode=Karte uusem Internet lade
+menu.settings.onlinemode=Karten uusem Internet lade
+menu.settings.autosave=Iistellige automatisch speichere
 menu.help=Hilfe
 # Popup menu for map
 menu.map.zoomin=Innezoome
@@ -73,6 +75,7 @@ shortcut.menu.help.help=H
 
 # Functions
 function.open=File Ã¶ffne
+function.importwithgpsbabel=mit GPSBabel importiere
 function.loadfromgps=uusem GPS lade
 function.sendtogps=zum GPS schicke
 function.exportkml=KML exportierä
@@ -117,13 +120,14 @@ function.setlinewidth=Liniedicke setz
 function.setlanguage=Sproch setzä
 function.help=Hilfe
 function.showkeys=Tastekombinatione aazeige
-function.about=Ãœber Prune
+function.about=Ãœber GpsPrune
 function.checkversion=Pruef nach ne noie Version
 function.saveconfig=Iistellige speichere
-function.diskcache=Karte uufem Disk speichere
+function.diskcache=Karten uufem Disk speichere
+function.managetilecache=Kartebildli verwolte
 
 # Dialogs
-dialog.exit.confirm.title=Prune beände
+dialog.exit.confirm.title=GpsPrune beände
 dialog.exit.confirm.text=Ihri Date sind nonig gspeicheret worde. Wend Sie trotzdem s Programm beände?
 dialog.openappend.title=Date aahänge oder ersätze
 dialog.openappend.text=Häng diese Date zur aktuelli Daten aa?
@@ -184,6 +188,9 @@ dialog.exportgpx.name=Name
 dialog.exportgpx.desc=Beschriibig
 dialog.exportgpx.includetimestamps=Au Ziitstämpel
 dialog.exportgpx.copysource=Xml-Quälle kopierä
+dialog.exportgpx.encoding=Enkodierig
+dialog.exportgpx.encoding.system=System
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Gäbet Sie die Parameter ii fürs POV Export
 dialog.exportpov.font=Font
 dialog.exportpov.camerax=Kamera X
@@ -336,14 +343,16 @@ dialog.compress.wackypoints.title=Komischi Punkte entf
 dialog.compress.wackypoints.paramdesc=Distanz Faktor
 dialog.compress.singletons.title=Singletons entfärnä
 dialog.compress.singletons.paramdesc=Distanz faktor
+dialog.compress.douglaspeucker.title=Douglas-Peucker Komprimierig
+dialog.compress.douglaspeucker.paramdesc=Span Faktor
 dialog.compress.summarylabel=Punkte zu entfärnä
 dialog.pastecoordinates.desc=Gäbet Sie hier die Koordinaten innä
 dialog.pastecoordinates.coords=Koordinate
 dialog.pastecoordinates.nothingfound=Prüefet Sie die Koordinate und versuechet nomal
-dialog.help.help=Bitte lueg na\n http://activityworkshop.net/software/prune/\nfür wiitere Information und Benutzeraaleitige.
+dialog.help.help=Bitte lueg na\n http://activityworkshop.net/software/gpsprune/\nfür wiitere Information und Benutzeraaleitige.
 dialog.about.version=Version
 dialog.about.build=Build
-dialog.about.summarytext1=Prune isch s Programm fürs Lade, Darstelle und Editiere vo Date von GPS Geräte.
+dialog.about.summarytext1=GpsPrune isch s Programm fürs Lade, Darstelle und Editiere vo Date von GPS Geräte.
 dialog.about.summarytext2=Es isch unter den Gnu GPL zur Verfüegig gstellt,für frei, gratis und offen Gebruuch und Wiiterentwicklig.<br>Kopiere, Wiiterverbreitig und Veränderige sin erlaubt und willkomme<br>unter die Bedingige im enthaltene <code>license.txt</code> File.
 dialog.about.summarytext3=Bitte lueget Sie na <code style="font-weight:bold">http://activityworkshop.net/</code> für wiitere Informatione und Benutzeraaleitige.
 dialog.about.languages=Verfüegbare Sproche
@@ -364,7 +373,7 @@ dialog.about.systeminfo.exiflib.external.failed=Ext
 dialog.about.yes=Ja
 dialog.about.no=Nei
 dialog.about.credits=Credits
-dialog.about.credits.code=Prune Code gschriebä vo
+dialog.about.credits.code=GpsPrune Code gschriebä vo
 dialog.about.credits.exifcode=Exif Code vo
 dialog.about.credits.icons=Einigi Bilder vo
 dialog.about.credits.translators=Dolmätscher
@@ -374,12 +383,12 @@ dialog.about.credits.othertools=Anderi W
 dialog.about.credits.thanks=Danke an
 dialog.about.readme=Läsmi
 dialog.checkversion.error=Die Versionnummer könne nöd gefprüft werdä.\nGits ne internet Verbindig?
-dialog.checkversion.uptodate=Sie han die noischti Version vonem Prune scho.
-dialog.checkversion.newversion1=Ne noii Version vonem Prune isch jetzt usse! Die heisst jetzt Version
+dialog.checkversion.uptodate=Sie han die noischti Version vonem GpsPrune scho.
+dialog.checkversion.newversion1=Ne noii Version vonem GpsPrune isch jetzt usse! Die heisst jetzt Version
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=Die noii Version isch am
 dialog.checkversion.releasedate2=ussecho.
-dialog.checkversion.download=Um die noii Version runterzlade, schauet Sie na http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=Um die noii Version runterzlade, schauet Sie na http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=Aastatt d'Muus könnet Sie diese Tastekombinationen nutze
 dialog.keys.keylist=<table><tr><td>Pfiil Taste</td><td>Karte verschiebe</td></tr><tr><td>Strg + links, rächts Pfiil</td><td>Vorherigi oder nöchsti Punkt markiere</td></tr><tr><td>Strg + uuf, aba Pfiil</td><td>Ii- oder Uusezoome</td></tr><tr><td>Strg + Bild uuf, ab</td><td>Vorherigi oder nöchsti Segmänt markiere</td></tr><tr><td>Strg + Pos1, Ã„nde</td><td>Erschti oder letschti Punkt markiere</td></tr><tr><td>Entf</td><td>Aktuelli Punkt lösche</td></tr></table>
 dialog.keys.normalmodifier=Strg
@@ -404,6 +413,7 @@ dialog.saveconfig.prune.kmzimageheight=Bildh
 dialog.saveconfig.prune.colourscheme=Farbeschema
 dialog.saveconfig.prune.linewidth=Liniedicke
 dialog.saveconfig.prune.kmltrackcolour=KML Trackfarb
+dialog.saveconfig.prune.autosavesettings=Iistellige speichere
 dialog.setpaths.intro=Sie könnet dann die Pfade für dia Applikatione setzä:
 dialog.setpaths.found=Pfad gfunde?
 dialog.addaltitude.noaltitudes=Dr seläktierte Beriich hät keini Höchiinformation
@@ -423,23 +433,35 @@ dialog.colourchooser.red=Rot
 dialog.colourchooser.green=Grüen
 dialog.colourchooser.blue=Blau
 dialog.setlanguage.firstintro=Sie könnet entweder eini vo den iigebouti Sproche<p>oder ne Text-Datei uuswähle.
-dialog.setlanguage.secondintro=Sie münt Ihri Iistellige speichere und dann<p>Prune wieder neustarte um die Sproch z'ändere.
+dialog.setlanguage.secondintro=Sie münt Ihri Iistellige speichere und dann<p>GpsPrune wieder neustarte um die Sproch z'ändere.
 dialog.setlanguage.language=Sproch
 dialog.setlanguage.languagefile=Sproch Datei
-dialog.setlanguage.endmessage=Jetze speicheret Sie Ihri Iistellige und startet Sie Prune neu\num t noii Sproch z' verwände.
+dialog.setlanguage.endmessage=Jetze speicheret Sie Ihri Iistellige und startet Sie GpsPrune neu\num t noii Sproch z' verwände.
+dialog.setlanguage.endmessagewithautosave=Startet Sie GpsPrune neu um t noii Sproch z' verwände.
 dialog.diskcache.save=Karten uufem Disk speichere
 dialog.diskcache.dir=Kartenordner
 dialog.diskcache.createdir=Ordner kreiere
 dialog.diskcache.nocreate=Ordner isch nöd kreiert worde
+dialog.diskcache.table.path=Pfad
+dialog.diskcache.table.usedby=Aawänder
+dialog.diskcache.table.zoom=Zoom
+dialog.diskcache.table.tiles=Kachle
+dialog.diskcache.table.megabytes=Megabytes
+dialog.diskcache.tileset=Ordner
+dialog.diskcache.tileset.multiple=mehreri
+dialog.diskcache.deleteold=Uualti Kachle l\u00f6sche
+dialog.diskcache.deleteall=Alli Kachle l\u00f6sche
+dialog.diskcache.deleted1=Es sin
+dialog.diskcache.deleted2=Files uusem Ordner gl\u00f6scht worde
 dialog.deletefieldvalues.intro=Wählet Sie s Fäld uus zum lösche
 dialog.setlinewidth.text=Gäbet Sie die Dicke vonen Linien ii (1-4)
 dialog.downloadosm.desc=Best\ätige um rohi OSM Date fürn Gebiet aba zlade:
 dialog.searchwikipedianames.search=Sueche na:
 
 # 3d window
-dialog.3d.title=Prune Drüü-d Aasicht
+dialog.3d.title=GpsPrune Drüü-d Aasicht
 dialog.3d.altitudefactor=Höchivervilfachigsfaktor
-dialog.3dlines.title=Prune Gitterlinie
+dialog.3dlines.title=GpsPrune Gitterlinie
 dialog.3dlines.empty=Kei Linie zum aazeigä!
 dialog.3dlines.intro=Hier sin die Linie für die drüü-D Aasicht
 
@@ -511,6 +533,7 @@ button.resettodefaults=Zur
 button.browse=Durasuechä...
 button.addnew=Hinzuefügä
 button.delete=Entfärnä
+button.manage=Verwoltä
 
 # File types
 filetype.txt=TXT Dateie
@@ -561,6 +584,7 @@ details.lists.photos=F
 details.photodetails=Details vonem Föteli
 details.nophoto=Kei föteli selektiert
 details.photo.loading=Ladä
+details.photo.bearing=Richtig
 details.media.connected=Verbundä
 details.lists.audio=Audio
 details.audiodetails=Audiodetails
@@ -585,6 +609,7 @@ fieldname.movingdistance=Wegl
 fieldname.duration=Ziitlängi
 fieldname.speed=Gschwindikeit
 fieldname.verticalspeed=Uf/Ab Gschwindikeit
+fieldname.description=Bschriibig
 
 # Measurement units
 units.original=Original
@@ -673,10 +698,13 @@ error.3d=N F
 error.readme.notfound=Läs mi File nöd gfunde
 error.osmimage.dialogtitle=Fähle bim Bildli-Lade
 error.osmimage.failed=Map Bildli könne nöd glade werde.  Gits ne Internet Verbindig?
-error.language.wrongfile=Die uusgewählti Datei scheint kei Sproch-Datei für Prune z'sii
+error.language.wrongfile=Die uusgewählti Datei scheint kei Sproch-Datei für GpsPrune z'sii
 error.convertnamestotimes.nonames=Kei Namen han könnet verwondlet werde
 error.lookupsrtm.nonefound=Kei Höhendate verfüegbar für d'Punkte
 error.lookupsrtm.nonerequired=Alle Punkte han die Höhendate scho.  Nüüt z'tue.
 error.gpsies.uploadnotok=Der Gpsies Server hät gseit gha
 error.gpsies.uploadfailed=S Uufalade isch fehlgschlage
 error.playaudiofailed=S Abschpiele vonem File isch fehlgschlage
+error.cache.notthere=D Ordner isch nöd gfunde worde
+error.cache.empty=D Ordner hät nüüt drinne
+error.cache.cannotdelete=Es sin kei Kachle gl\u00f6scht worde
index 869af6d0298e35fe4bfdf3fbc42aa96ff814e7cd..d105404dea21a37978839aa934451b44aacfcdc9 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # English entries as default - others can be added
 
 # Menu entries
 menu.file=File
 menu.file.addphotos=Add photos
+menu.file.recentfiles=Recent files
 menu.file.save=Save as text
 menu.file.exit=Exit
 menu.track=Track
@@ -41,6 +42,7 @@ menu.view.browser.yahoo=Yahoo maps
 menu.view.browser.bing=Bing maps
 menu.settings=Settings
 menu.settings.onlinemode=Load maps from internet
+menu.settings.autosave=Autosave settings on exit
 menu.help=Help
 # Popup menu for map
 menu.map.zoomin=Zoom in
@@ -75,6 +77,7 @@ shortcut.menu.help.help=H
 
 # Functions
 function.open=Open file
+function.importwithgpsbabel=Import file with GPSBabel
 function.loadfromgps=Load data from GPS
 function.sendtogps=Send data to GPS
 function.exportkml=Export KML
@@ -109,11 +112,11 @@ function.rotatephotoleft=Rotate photo left
 function.rotatephotoright=Rotate photo right
 function.photopopup=Show photo popup
 function.ignoreexifthumb=Ignore exif thumbnail
-function.loadaudio=Add audio files
-function.removeaudio=Remove audio file
+function.loadaudio=Add audio clips
+function.removeaudio=Remove audio clip
 function.correlateaudios=Correlate audios
-function.playaudio=Play audio file
-function.stopaudio=Stop audio file
+function.playaudio=Play audio clip
+function.stopaudio=Stop audio clip
 function.setmapbg=Set map background
 function.setkmzimagesize=Set KMZ image size
 function.setpaths=Set program paths
@@ -122,13 +125,14 @@ function.setlinewidth=Set line width
 function.setlanguage=Set language
 function.help=Help
 function.showkeys=Show shortcut keys
-function.about=About Prune
+function.about=About GpsPrune
 function.checkversion=Check for new version
 function.saveconfig=Save settings
 function.diskcache=Save maps to disk
+function.managetilecache=Manage tile cache
 
 # Dialogs
-dialog.exit.confirm.title=Exit Prune
+dialog.exit.confirm.title=Exit GpsPrune
 dialog.exit.confirm.text=Your data is not saved. Are you sure you want to exit?
 dialog.openappend.title=Append to existing data
 dialog.openappend.text=Append this data to the data already loaded?
@@ -189,6 +193,9 @@ dialog.exportgpx.name=Name
 dialog.exportgpx.desc=Description
 dialog.exportgpx.includetimestamps=Include timestamps
 dialog.exportgpx.copysource=Copy source xml
+dialog.exportgpx.encoding=Encoding
+dialog.exportgpx.encoding.system=System
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Please enter the parameters for the POV export
 dialog.exportpov.font=Font
 dialog.exportpov.camerax=Camera X
@@ -341,14 +348,16 @@ dialog.compress.wackypoints.title=Wacky point removal
 dialog.compress.wackypoints.paramdesc=Distance factor
 dialog.compress.singletons.title=Singleton removal
 dialog.compress.singletons.paramdesc=Distance factor
+dialog.compress.douglaspeucker.title=Douglas-Peucker compression
+dialog.compress.douglaspeucker.paramdesc=Span factor
 dialog.compress.summarylabel=Points to delete
 dialog.pastecoordinates.desc=Enter or paste the coordinates here
 dialog.pastecoordinates.coords=Coordinates
 dialog.pastecoordinates.nothingfound=Please check the coordinates and try again
-dialog.help.help=Please see\n http://activityworkshop.net/software/prune/\nfor more information and user guides.
+dialog.help.help=Please see\n http://activityworkshop.net/software/gpsprune/\nfor more information and user guides.
 dialog.about.version=Version
 dialog.about.build=Build
-dialog.about.summarytext1=Prune is a program for loading, displaying and editing data from GPS receivers.
+dialog.about.summarytext1=GpsPrune is a program for loading, displaying and editing data from GPS receivers.
 dialog.about.summarytext2=It is released under the Gnu GPL for free, open, worldwide use and enhancement.<br>Copying, redistribution and modification are permitted and encouraged<br>according to the conditions in the included <code>license.txt</code> file.
 dialog.about.summarytext3=Please see <code style="font-weight:bold">http://activityworkshop.net/</code> for more information and user guides.
 dialog.about.languages=Available languages
@@ -369,7 +378,7 @@ dialog.about.systeminfo.exiflib.external.failed=External (not found)
 dialog.about.yes=Yes
 dialog.about.no=No
 dialog.about.credits=Credits
-dialog.about.credits.code=Prune code written by
+dialog.about.credits.code=GpsPrune code written by
 dialog.about.credits.exifcode=Exif code by
 dialog.about.credits.icons=Some icons taken from
 dialog.about.credits.translators=Translators
@@ -379,12 +388,12 @@ dialog.about.credits.othertools=Other tools
 dialog.about.credits.thanks=Thanks to
 dialog.about.readme=Readme
 dialog.checkversion.error=The version number couldn't be checked.\nPlease check the internet connection.
-dialog.checkversion.uptodate=You are using the latest version of Prune.
-dialog.checkversion.newversion1=A new version of Prune is now available!  The latest version is now version
+dialog.checkversion.uptodate=You are using the latest version of GpsPrune.
+dialog.checkversion.newversion1=A new version of GpsPrune is now available!  The latest version is now version
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=This new version was released on
 dialog.checkversion.releasedate2=.
-dialog.checkversion.download=To download the new version, go to http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=To download the new version, go to http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=You can use the following shortcut keys instead of using the mouse
 dialog.keys.keylist=<table><tr><td>Arrow keys</td><td>Pan map left right, up, down</td></tr><tr><td>Ctrl + left, right arrow</td><td>Select previous or next point</td></tr><tr><td>Ctrl + up, down arrow</td><td>Zoom in or out</td></tr><tr><td>Ctrl + PgUp, PgDown</td><td>Select previous, next segment</td></tr><tr><td>Ctrl + Home, End</td><td>Select first, last point</td></tr><tr><td>Del</td><td>Delete current point</td></tr></table>
 dialog.keys.normalmodifier=Ctrl
@@ -409,6 +418,7 @@ dialog.saveconfig.prune.kmzimageheight=KMZ image height
 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.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
@@ -428,23 +438,35 @@ dialog.colourchooser.red=Red
 dialog.colourchooser.green=Green
 dialog.colourchooser.blue=Blue
 dialog.setlanguage.firstintro=You can either select one of the included languages,<p>or select a text file to use instead.
-dialog.setlanguage.secondintro=You need to save your settings and then<p>restart Prune to change the language.
+dialog.setlanguage.secondintro=You need to save your settings and then<p>restart GpsPrune to change the language.
 dialog.setlanguage.language=Language
 dialog.setlanguage.languagefile=Language file
-dialog.setlanguage.endmessage=Now save your settings and restart Prune\nfor the language change to take effect.
+dialog.setlanguage.endmessage=Now save your settings and restart GpsPrune\nfor the language change to take effect.
+dialog.setlanguage.endmessagewithautosave=Please restart GpsPrune for the language change to take effect.
 dialog.diskcache.save=Save map images to disk
 dialog.diskcache.dir=Cache directory
 dialog.diskcache.createdir=Create directory
 dialog.diskcache.nocreate=Cache directory not created
+dialog.diskcache.table.path=Path
+dialog.diskcache.table.usedby=Used by
+dialog.diskcache.table.zoom=Zoom
+dialog.diskcache.table.tiles=Tiles
+dialog.diskcache.table.megabytes=Megabytes
+dialog.diskcache.tileset=Tileset
+dialog.diskcache.tileset.multiple=multiple
+dialog.diskcache.deleteold=Delete old tiles
+dialog.diskcache.deleteall=Delete all tiles
+dialog.diskcache.deleted1=Deleted
+dialog.diskcache.deleted2=files from the cache
 dialog.deletefieldvalues.intro=Select the field to delete for the current range
 dialog.setlinewidth.text=Enter the thickness of lines to draw for the tracks (1-4)
 dialog.downloadosm.desc=Confirm to download the raw OSM data for the specified area:
 dialog.searchwikipedianames.search=Search for:
 
 # 3d window
-dialog.3d.title=Prune Three-d view
+dialog.3d.title=GpsPrune Three-d view
 dialog.3d.altitudefactor=Altitude exaggeration factor
-dialog.3dlines.title=Prune gridlines
+dialog.3dlines.title=GpsPrune gridlines
 dialog.3dlines.empty=No gridlines to display!
 dialog.3dlines.intro=These are the gridlines for the three-d view
 
@@ -516,6 +538,7 @@ button.resettodefaults=Reset to defaults
 button.browse=Browse...
 button.addnew=Add new
 button.delete=Delete
+button.manage=Manage
 
 # File types
 filetype.txt=TXT files
@@ -567,9 +590,10 @@ details.lists.audio=Audio
 details.photodetails=Photo details
 details.nophoto=No photo selected
 details.photo.loading=Loading
+details.photo.bearing=Bearing
 details.media.connected=Connected
 details.audiodetails=Audio details
-details.noaudio=No audio file selected
+details.noaudio=No audio clip selected
 details.audio.file=Audio file
 details.audio.playing=playing...
 map.overzoom=No maps available at this zoom level
@@ -590,6 +614,7 @@ fieldname.movingdistance=Moving distance
 fieldname.duration=Duration
 fieldname.speed=Speed
 fieldname.verticalspeed=Vertical speed
+fieldname.description=Description
 
 # Measurement units
 units.original=Original
@@ -625,11 +650,11 @@ cardinal.w=W
 # Undo operations
 undo.load=load data
 undo.loadphotos=load photos
-undo.loadaudios=load audio files
+undo.loadaudios=load audio clips
 undo.editpoint=edit point
 undo.deletepoint=delete point
 undo.removephoto=remove photo
-undo.removeaudio=remove audio file
+undo.removeaudio=remove audio clip
 undo.deleterange=delete range
 undo.compress=compress track
 undo.insert=insert points
@@ -672,7 +697,7 @@ error.jpegload.nofilesfound=No files found
 error.jpegload.nojpegsfound=No jpeg files found
 error.jpegload.nogpsfound=No GPS information found
 error.jpegload.exifreadfailed=Failed to read EXIF information. No EXIF information can be read\nwithout either an internal or external library.
-error.audioload.nofilesfound=No audio files found
+error.audioload.nofilesfound=No audio clips found
 error.gpsload.unknown=Unknown error
 error.undofailed.title=Undo failed
 error.undofailed.text=Failed to undo operation
@@ -684,10 +709,13 @@ error.3d=An error occurred with the 3d display
 error.readme.notfound=Readme file not found
 error.osmimage.dialogtitle=Error loading map images
 error.osmimage.failed=Failed to load map images. Please check internet connection.
-error.language.wrongfile=The selected file doesn't appear to be a language file for Prune
+error.language.wrongfile=The selected file doesn't appear to be a language file for GpsPrune
 error.convertnamestotimes.nonames=No names could be converted into times
 error.lookupsrtm.nonefound=No altitude values available for these points
 error.lookupsrtm.nonerequired=All points already have altitudes, so there's nothing to lookup
 error.gpsies.uploadnotok=The gpsies server returned the message
 error.gpsies.uploadfailed=The upload failed with the error
-error.playaudiofailed=Failed to play audio file
+error.playaudiofailed=Failed to play audio clip
+error.cache.notthere=The tile cache directory was not found
+error.cache.empty=The tile cache directory is empty
+error.cache.cannotdelete=No tiles could be deleted
index c554ab365a2832b8a7b27e9a9e22e6aaf2cf5004..6cd6654fe5507fd01aa74acd67d5a6c26302783e 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Spanish entries as extra
 
 # Menu entries
 menu.file=Archivo
 menu.file.addphotos=Cargar fotos
+menu.file.recentfiles=Archivos recientes
 menu.file.save=Guardar
 menu.file.exit=Salir
 menu.track=Track
@@ -41,6 +42,7 @@ menu.view.browser.yahoo=Mapas Yahoo
 menu.view.browser.bing=Mapas Bing
 menu.settings=Preferencias
 menu.settings.onlinemode=Cargar mapas de Internet
+menu.settings.autosave=Auto Guardar
 menu.help=Ayuda
 # Popup menu for map
 menu.map.zoomin=Ampliar zoom
@@ -75,6 +77,7 @@ shortcut.menu.help.help=H
 
 # Functions
 function.open=Abrir archivo
+function.importwithgpsbabel=Importar archivo con GPSBabel
 function.loadfromgps=Cargar datos del GPS
 function.sendtogps=Enviar datos al GPS
 function.exportkml=Exportar KML
@@ -122,14 +125,15 @@ function.playaudio=Reproducir archivo de audio
 function.stopaudio=Detener reproducci\u00f3n de audio
 function.help=Ayuda
 function.showkeys=Mostrar teclas o combinaciones de atajo
-function.about=Acerca de Prune
+function.about=Acerca de GpsPrune
 function.checkversion=Buscar una nueva versi\u00f3n
 function.saveconfig=Guardar preferencias
 function.diskcache=Guardar mapas en disco
+function.managetilecache=Administrar cache de mapas
 
 # Dialogs
-dialog.exit.confirm.title=Salir de Prune
-dialog.exit.confirm.text=\u00bfLos datos han sido modificados. Desea salir de Prune?
+dialog.exit.confirm.title=Salir de GpsPrune
+dialog.exit.confirm.text=\u00bfLos datos han sido modificados. Desea salir de GpsPrune?
 dialog.openappend.title=\u00bfAgregar a datos existentes
 dialog.openappend.text=\u00bfAgregar estos datos a los datos ya guardados?
 dialog.deletepoint.title=Borrar punto
@@ -189,6 +193,9 @@ dialog.exportgpx.name=Nombre
 dialog.exportgpx.desc=Descripci\u00f3n
 dialog.exportgpx.includetimestamps=Tiempo tambien
 dialog.exportgpx.copysource=Copiar la fuente
+dialog.exportgpx.encoding=Codificaci\u00f3n
+dialog.exportgpx.encoding.system=Sistema
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Introdzca los Parametros para exportar
 dialog.exportpov.font=Fuente
 dialog.exportpov.camerax=C\u00e1mara X
@@ -341,14 +348,16 @@ dialog.compress.wackypoints.paramdesc=Factor distancia
 dialog.compress.singletons.title=Eliminar puntos aislados
 dialog.compress.singletons.paramdesc=Factor distancia
 dialog.compress.duplicates.title=Eliminar duplicados
+dialog.compress.douglaspeucker.title=Compresion Douglas-Peucker
+dialog.compress.douglaspeucker.paramdesc=Factor de extensi\u00f3n
 dialog.compress.summarylabel=Puntos para eliminar
 dialog.pastecoordinates.desc=Ingresar o pegar las coordenadas aqu\u00ed
 dialog.pastecoordinates.coords=Coordenadas
 dialog.pastecoordinates.nothingfound=Por favor verificar las coordenadas e intentar nuevamente
-dialog.help.help=Por favor, ver\n http://activityworkshop.net/software/prune/\npara m\u00e1s informaci\u00f3n y gu\u00edas del usuario.
+dialog.help.help=Por favor, ver\n http://activityworkshop.net/software/gpsprune/\npara m\u00e1s informaci\u00f3n y gu\u00edas del usuario.
 dialog.about.version=Versi\u00f3n
 dialog.about.build=Construcci\u00f3n
-dialog.about.summarytext1=Prune es un programa para cargar, mostrar y editar datos de receptores GPS.
+dialog.about.summarytext1=GpsPrune es un programa para cargar, mostrar y editar datos de receptores GPS.
 dialog.about.summarytext2=Distribuido bajo el GNU GPL para uso libre y gratuito.<br>Se permite (y se anima) la copia, redistribuci\u00f3n y modificaci\u00f3n de acuerdo<br>a las condiciones incluidas en el archivo <code>licence.txt</code>.
 dialog.about.summarytext3=Por favor, ver <code style="font-weight:bold">http://activityworkshop.net/</code> para m\u00e1s informaci\u00f3n y gu\u00edas del usuario.
 dialog.about.languages=Idiomas disponibles
@@ -369,7 +378,7 @@ dialog.about.systeminfo.exiflib.external.failed=Externa (no encontrada)
 dialog.about.yes=Si
 dialog.about.no=No
 dialog.about.credits=Cr\u00e9ditos
-dialog.about.credits.code=El c\u00f3digo de Prune fue escrito por
+dialog.about.credits.code=El c\u00f3digo de GpsPrune fue escrito por
 dialog.about.credits.exifcode=El c\u00f3digo Exif por
 dialog.about.credits.icons=Algunos iconos se tomaron de
 dialog.about.credits.translators=Traductores
@@ -379,14 +388,16 @@ dialog.about.credits.othertools=Otras herramientas
 dialog.about.credits.thanks=Gracias a
 dialog.about.readme=Readme
 dialog.checkversion.error=El numero de versi\u00f3n no pudo ser verificada.\n Por favor verificar la conexi\u00f3n de Internet
-dialog.checkversion.uptodate=Esta usted utilizando la \u00faltima versi\u00f3n de Prune
-dialog.checkversion.newversion1=¡Una nueva versi\u00f3n de Prune est\u00e1 disponible! La \u00faltima es ahora la versi\u00f3n
+dialog.checkversion.uptodate=Esta usted utilizando la \u00faltima versi\u00f3n de GpsPrune
+dialog.checkversion.newversion1=¡Una nueva versi\u00f3n de GpsPrune est\u00e1 disponible! La \u00faltima es ahora la versi\u00f3n
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=La nueva versi\u00f3n fue lanzada en
 dialog.checkversion.releasedate2=.
-dialog.checkversion.download=Para descargar la nueva versi\u00f3n visite http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=Para descargar la nueva versi\u00f3n visite http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=Usted puede usar el siguiente atajo en lugar de usar el rat\u00f3n
 dialog.keys.keylist=<table><tr><td>Teclas de cursor</td><td>Desplazar a la izquierde, derecha, arriba, abajo</td></tr><tr><td>Ctrl + cursor izquierda, derecha</td><td>Seleccionar punto siguiente o anterior</td></tr><tr><td>Ctrl + cursor arriba, abajo</td><td>Ampliar o reducir zoom</td></tr><tr><td>Ctrl + Av Pag, Re Pag</td><td>Seleccionar segmento siguiente, anterior</td></tr><tr><td>Ctrl + Inicio, Fin</td><td>Seleccionar primer, \u00faltimo punto</td></tr><tr><td>Supr</td><td>Eliminar punto actual</td></tr></table>
+dialog.keys.normalmodifier=Ctrl
+dialog.keys.macmodifier=Command
 dialog.saveconfig.desc=La siguiente configuraci\u00f3n puede ser salvada en un archivo de configuraci\u00f3n
 dialog.saveconfig.prune.trackdirectory=Directorio de pista
 dialog.saveconfig.prune.photodirectory=Directorio de foto
@@ -407,6 +418,7 @@ dialog.saveconfig.prune.kmzimageheight=Alto de im\u00e1genes en KMZ
 dialog.saveconfig.prune.colourscheme=Color de esquema
 dialog.saveconfig.prune.linewidth=Ancho de l\u00ednea
 dialog.saveconfig.prune.kmltrackcolour=Color de pista de KML
+dialog.saveconfig.prune.autosavesettings=Guardar preferencias al salir
 dialog.setpaths.intro=Si usted necesita, puede escoger las rutas a aplicaciones externas
 dialog.setpaths.found=\u00bfRuta encontrada?
 dialog.addaltitude.noaltitudes=Los rangos seleccionados no contienen altitudes
@@ -426,23 +438,35 @@ dialog.colourchooser.red=Rojo
 dialog.colourchooser.green=Verde
 dialog.colourchooser.blue=Azul
 dialog.setlanguage.firstintro=Puede usted seleccionar algunos de los lenguajes incluidos,<p>o puede en lugar de esto seleccionar un archivo de texto
-dialog.setlanguage.secondintro=Usted necesita guardar sus preferencias y luego<p>reiniciar Prune para cambiar el lenguaje
+dialog.setlanguage.secondintro=Usted necesita guardar sus preferencias y luego<p>reiniciar GpsPrune para cambiar el lenguaje
 dialog.setlanguage.language=Lenguaje
 dialog.setlanguage.languagefile=Archivo de lenguaje
-dialog.setlanguage.endmessage=Ahora guarde sus preferencias y reinicie Prune\npara que los cambios tomen efecto.
+dialog.setlanguage.endmessage=Ahora guarde sus preferencias y reinicie GpsPrune\npara que los cambios tomen efecto.
+dialog.setlanguage.endmessagewithautosave=Ahora reinicie GpsPrune para que los cambios tomen efecto.
 dialog.diskcache.save=Guardar im\u00e1genes de mapa a disco
 dialog.diskcache.dir=Directorio de mapas
 dialog.diskcache.createdir=Crear directorio
 dialog.diskcache.nocreate=No se ha creado el directorio de mapas
+dialog.diskcache.table.path=Ruta
+dialog.diskcache.table.usedby=Utilizado por
+dialog.diskcache.table.zoom=Zoom
+dialog.diskcache.table.tiles=Recuadros
+dialog.diskcache.table.megabytes=Megabytes
+dialog.diskcache.tileset=Conjunto de recuadros
+dialog.diskcache.tileset.multiple=varios
+dialog.diskcache.deleteold=Borrar recuadros antiguos
+dialog.diskcache.deleteall=Borrar todos los recuadros
+dialog.diskcache.deleted1=Borrado
+dialog.diskcache.deleted2=Archivos del cache
 dialog.deletefieldvalues.intro=Seleccionar el campo a eliminar para el rango actual
 dialog.setlinewidth.text=Introduzca la anchura de las l\u00edneas a dibujar para los recorridos (1-4)
 dialog.downloadosm.desc=Confirmar la descarga de datos en bruto de OSM para el \u00e1rea especificada.
 dialog.searchwikipedianames.search=Buscar:
 
 # 3d window
-dialog.3d.title=Prune vista 3-D
+dialog.3d.title=GpsPrune vista 3-D
 dialog.3d.altitudefactor=Factor de exageraci\u00f3n de altura
-dialog.3dlines.title=Cuadr\u00edcula Prune
+dialog.3dlines.title=Cuadr\u00edcula GpsPrune
 dialog.3dlines.empty=¡No hay ninguna cuadr\u00edcula!
 dialog.3dlines.intro=Informaci\u00f3n de la cuadr\u00edcula
 
@@ -514,6 +538,7 @@ button.resettodefaults=Restablecer valores a los predeterminados
 button.browse=Navegar...
 button.addnew=A\u00f1adir nuevo
 button.delete=Eliminar
+button.manage=Administrar
 
 # File types
 filetype.txt=Archivos TXT
@@ -565,6 +590,7 @@ details.lists.audio=Audio
 details.photodetails=Detalles de la foto
 details.nophoto=Ninguna foto seleccionada
 details.photo.loading=Cargando
+details.photo.bearing=Rumbo
 details.media.connected=Conectada
 details.audiodetails=Detalles de audio
 details.noaudio=No se ha seleccionado ning\u00fan archivo de audio
@@ -588,6 +614,7 @@ fieldname.movingdistance=Distancia en movimiento
 fieldname.duration=Duraci\u00f3n
 fieldname.speed=Velocidad
 fieldname.verticalspeed=Velocidad vertical
+fieldname.description=Descripci\u00f3n
 
 # Measurement units
 units.original=Original
@@ -682,10 +709,13 @@ error.3d=Ha ocurrido un error con la funci\u00f3n 3-D
 error.readme.notfound=Archivo readme no encontrado
 error.osmimage.dialogtitle=Error al cargar el mapa
 error.osmimage.failed=Imposible cargar el mapa. Por favor, compruebe la conexi\u00f3n a internet.
-error.language.wrongfile=El archivo seleccionado no parece ser un archivo de lenguaje para Prune
+error.language.wrongfile=El archivo seleccionado no parece ser un archivo de lenguaje para GpsPrune
 error.convertnamestotimes.nonames=Los nombres no pudieron ser convertidos en tiempos
 error.lookupsrtm.nonefound=No se encontraron valores de altitud
 error.lookupsrtm.nonerequired=Todos los puntos tienen altitudes, as\u00ed que no hay nada que buscar.
 error.gpsies.uploadnotok=El servidor de gpsies ha devuelto el mensaje
 error.gpsies.uploadfailed=La carga ha fallado con el error
 error.playaudiofailed=Fallo reproduciendo archivo de audio
+error.cache.notthere=No se encontr\u00f3 la carpeta del cache de recuadros 
+error.cache.empty=La carpeta del cache de recuadros esta vac\u00edo
+error.cache.cannotdelete=No se pudieron borrar recuadros
index 8c7f1b3456d6a7e795e717231c21daa2e4590100..1e0164b3a87def438f01c537164dbee4792e64cb 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # French entries as extra
 
 # Menu entries
 menu.file=Fichier
 menu.file.addphotos=Ajouter photos
+menu.file.recentfiles=Derniers Fichiers utilis\u00e9s
 menu.file.save=Enregistrer
 menu.file.exit=Quitter
 menu.track=Trace
@@ -26,14 +27,13 @@ menu.range.reverse=Inverser l'\u00e9tendue
 menu.range.mergetracksegments=Fusionner les segments de trace
 menu.range.cutandmove=Couper et bouger la s\u00e9lection
 menu.point=Point
-menu.point.editpoint=Editer le point
+menu.point.editpoint=\u00c9diter le point
 menu.point.deletepoint=Supprimer le point
 menu.photo=Photo
 menu.photo.saveexif=Enregistrer dans les Exif
-function.connecttopoint=Relier au point
-function.disconnectfrompoint=D\u00e9tacher du point
-function.removephoto=Retirer la photo
+menu.audio=Audio
 menu.view=Affichage
+menu.view.showsidebars=Montrer les barres lat\u00e9rales
 menu.view.browser=Ouvrir la carte dans le navigateur
 menu.view.browser.google=Google maps
 menu.view.browser.openstreetmap=Openstreetmap
@@ -41,13 +41,15 @@ menu.view.browser.mapquest=Mapquest
 menu.view.browser.yahoo=Yahoo maps
 menu.view.browser.bing=Cartes dans Bing
 menu.settings=Pr\u00e9f\u00e9rences
-menu.settings.onlinemode=Charger une carte depuis internet
+menu.settings.onlinemode=Charger cartes depuis internet
+menu.settings.autosave=Sauver automatiquement en quittant
 menu.help=Aide
 # Popup menu for map
 menu.map.zoomin=Zoom avant
 menu.map.zoomout=Zoom arri\u00e8re
 menu.map.zoomfull=Adapter \u00e0 la vue
 menu.map.newpoint=Ajouter un point
+menu.map.drawpoints=Ajouter une s\u00e9rie des points
 menu.map.connect=Relier les points de trace
 menu.map.autopan=D\u00e9placement automatique
 menu.map.showmap=Montrer la carte
@@ -60,6 +62,7 @@ altkey.menu.range=E
 altkey.menu.point=P
 altkey.menu.view=A
 altkey.menu.photo=H
+altkey.menu.audio=U
 altkey.menu.settings=R
 altkey.menu.help=I
 
@@ -79,11 +82,13 @@ function.sendtogps=Envoyer donn\u00e9es au GPS
 function.exportkml=Exporter en KML
 function.exportgpx=Exporter en GPX
 function.exportpov=Exporter en POV
-function.editwaypointname=Editer le nom du waypoint
+function.exportsvg=Exporter en SVG
+function.editwaypointname=\u00c9diter le nom du waypoint
 function.compress=Compresser la trace
 function.addtimeoffset=Ajouter un d\u00e9calage d'horaire
 function.addaltitudeoffset=Ajouter un d\u00e9calage d'altitude
 function.convertnamestotimes=Convertir les noms de waypoints en horodatages
+function.deletefieldvalues=Effacer les valeurs du champ
 function.findwaypoint=Trouver un waypoint
 function.pastecoordinates=Coller les coordonn\u00e9es
 function.charts=Graphiques
@@ -94,26 +99,39 @@ function.setmapbg=D\u00e9finir le fond de carte
 function.setkmzimagesize=D\u00e9finir la taille de l'image KMZ
 function.setpaths=D\u00e9finir les chemins des programmes
 function.getgpsies=R\u00e9cup\u00e9rer les traces Gpsies
+function.uploadgpsies=T\u00e9l\u00e9charger la trace sur Gpsies
 function.lookupsrtm=R\u00e9cup\u00e9rer les altitudes depuis SRTM
-function.duplicatepoint=Duppliquer le point
-function.setcolours=R\u00e9gler les couleurs
-function.setlanguage=R\u00e9gler la langue
+function.getwikipedia=Obtenir les articles de Wikip\u00e9dia \u00e0 proxilit\u00e9
+function.searchwikipedianames=Rechercher dans Wikip\u00e9dia par nom
+function.downloadosm=T\u00e9l\u00e9charger les donn\u00e9es OSM de la zone
+function.duplicatepoint=Dupliquer le point
+function.setcolours=Choisir les couleurs
+function.setlinewidth=Choisir la largeur de ligne
+function.setlanguage=Choisir la langue
+function.connecttopoint=Relier au point
+function.disconnectfrompoint=D\u00e9tacher du point
+function.removephoto=Retirer la photo
 function.correlatephotos=Corr\u00e9ler les photos
 function.rearrangephotos=R\u00e9arranger les photos
 function.rotatephotoleft=Tourner la photo vers la gauche
 function.rotatephotoright=Tourner la photo vers la droite
 function.photopopup=Montrer la photo
 function.ignoreexifthumb=Ignorer l\u2019aper\u00e7u Exif
+function.loadaudio=Ajouter des fichiers audio
+function.removeaudio=Retirer des fichiers audio
+function.correlateaudios=Corr\u00e9ler les fichiers audio
+function.playaudio=Lire le fichier audio
+function.stopaudio=Arr\u00eater la lecture du fichier audio
 function.help=Aide
 function.showkeys=Montrer les raccourcis clavier
-function.about=À propos de Prune
+function.about=\u00c0 propos de GpsPrune
 function.checkversion=Chercher une mise \u00e0 jour
 function.saveconfig=Enregistrer les pr\u00e9f\u00e9rences
 function.diskcache=Enregistrer les cartes sur le disque
 
 # Dialogs
-dialog.exit.confirm.title=Quitter Prune
-dialog.exit.confirm.text=Les donn\u00e9es ont \u00e9t\u00e9 modifi\u00e9es. Souhaitez-vous quitter Prune sans les enregistrer ?
+dialog.exit.confirm.title=Quitter GpsPrune
+dialog.exit.confirm.text=Les donn\u00e9es ont \u00e9t\u00e9 modifi\u00e9es. Souhaitez-vous quitter GpsPrune sans les enregistrer ?
 dialog.openappend.title=Ajouter aux donn\u00e9es existantes
 dialog.openappend.text=Ajouter aux donn\u00e9es d\u00e9j\u00e0 charg\u00e9es ?
 dialog.deletepoint.title=Effacer le point
@@ -135,6 +153,9 @@ dialog.openoptions.deliminfo.records=enregistrements, avec
 dialog.openoptions.deliminfo.fields=champs
 dialog.openoptions.deliminfo.norecords=Pas d'enregistrements
 dialog.openoptions.altitudeunits=Unit\u00e9s d'altitude
+dialog.open.contentsdoubled=Ce fichier contient deux copies de chaque point,\nune fois comme waypoint, une autre comme point de trace.
+dialog.selecttracks.intro=S\u00e9lectionner la ou les traces \u00e0 charger
+dialog.selecttracks.noname=Sans titre
 dialog.jpegload.subdirectories=Inclure les sous-dossiers
 dialog.jpegload.loadjpegswithoutcoords=Inclure les photos sans coordonn\u00e9es
 dialog.jpegload.loadjpegsoutsidearea=Inclure des photos en dehors de la zone actuel
@@ -170,6 +191,8 @@ dialog.exportgpx.name=Nom
 dialog.exportgpx.desc=L\u00e9gende
 dialog.exportgpx.includetimestamps=Inclure l'heure pour chaque point
 dialog.exportgpx.copysource=Copier la source xml
+dialog.exportgpx.encoding.system=Syst\u00e8me
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Entrez les param\u00e8tres pour l'export POV
 dialog.exportpov.font=Police
 dialog.exportpov.camerax=Cam\u00e9ra X
@@ -179,10 +202,15 @@ dialog.exportpov.modelstyle=Style du mod\u00e8le
 dialog.exportpov.ballsandsticks=Points et b\u00e2tons
 dialog.exportpov.tubesandwalls=Tubes et murs
 dialog.exportpov.warningtracksize=Cette trace poss\u00e8de un grand nombre de points, Java3D peut ne pas pouvoir l'afficher.\n\u00cates-vous s\u00fbr de vouloir continuer ?
+dialog.exportsvg.text=S\u00e9lectionner les param\u00e8tres de l'export SVG
+dialog.exportsvg.phi=Angle d'azimuth \u03d5
+dialog.exportsvg.theta=Angle d'\u00e9l\u00e9vation \u03b8
+dialog.exportsvg.gradients=Utiliser des d\u00e9grad\u00e9s pour l'ombrage
 dialog.pointtype.desc=Sauvegarder ces types de points:
 dialog.pointtype.track=Points de la trace
 dialog.pointtype.waypoint=Waypoints
 dialog.pointtype.photo=Points de photos
+dialog.pointtype.audio=Points audio
 dialog.pointtype.selection=Uniquement la s\u00e9lection
 dialog.confirmreversetrack.title=Confirmer l'inversion
 dialog.confirmreversetrack.text=Cette trace contient des informations temporelles qui seront d\u00e9sordonn\u00e9es apr\u00e8s une inversion.\n\u00cates-vous s\u00fbr de vouloir inverser cette section ?
@@ -195,14 +223,14 @@ dialog.undo.pretext=S\u00e9lectionnez les actions \u00e0 annuler
 dialog.undo.none.title=Annulation impossible
 dialog.undo.none.text=Pas d'op\u00e9ration \u00e0 annuler !
 dialog.clearundo.title=Purger la liste d'annulation
-dialog.clearundo.text=Etes-vous s\u00fbr de vouloir effacer la liste d'annulation ?\nToutes les informations d'annulation seront perdues !
-dialog.pointedit.title=Editer le point
-dialog.pointedit.text=S\u00e9lectionner chaque champ \u00e0 \u00e9diter et utiliser le bouton 'Editer' pour changer la valeur
+dialog.clearundo.text=\u00cates-vous s\u00fbr de vouloir effacer la liste d'annulation ?\nToutes les informations d'annulation seront perdues !
+dialog.pointedit.title=\u00c9diter le point
+dialog.pointedit.text=S\u00e9lectionner chaque champ \u00e0 \u00e9diter et utiliser le bouton '\u00c9diter' pour changer la valeur
 dialog.pointedit.table.field=Champ
 dialog.pointedit.table.value=Valeur
 dialog.pointedit.table.changed=Chang\u00e9
 dialog.pointedit.changevalue.text=Entrer la nouvelle valeur pour ce champ
-dialog.pointedit.changevalue.title=Editer le champ
+dialog.pointedit.changevalue.title=\u00c9diter le champ
 dialog.pointnameedit.name=Nom de waypoint
 dialog.pointnameedit.uppercase=CASSE MAJUSCULES
 dialog.pointnameedit.lowercase=casse minuscules
@@ -225,7 +253,7 @@ dialog.saveexif.table.save=Enregistrer
 dialog.saveexif.photostatus.connected=Connect\u00e9
 dialog.saveexif.photostatus.disconnected=D\u00e9connect\u00e9
 dialog.saveexif.photostatus.modified=Modifi\u00e9
-dialog.saveexif.overwrite=Ecraser les fichiers
+dialog.saveexif.overwrite=\u00c9craser les fichiers
 dialog.saveexif.force=Ignorer les erreurs mineures
 dialog.charts.xaxis=Axe des x
 dialog.charts.yaxis=Axe des y
@@ -248,13 +276,17 @@ dialog.addmapsource.sourcename=Nom de la source
 dialog.addmapsource.layer1url=URL de la premi\u00e8re couche
 dialog.addmapsource.layer2url=URL optionnelle de la deuxi\u00e8me couche
 dialog.addmapsource.maxzoom=Niveau de zoom maximum
-dialog.addmapsource.cloudstyle=Taille
-dialog.addmapsource.noname=Sans-titre
+dialog.addmapsource.cloudstyle=Num\u00e9ro du style
+dialog.addmapsource.noname=Sans titre
 dialog.gpsies.column.name=Nom de trace
 dialog.gpsies.column.length=Distance
 dialog.gpsies.description=Description
 dialog.gpsies.nodescription=Aucune description
-dialog.gpsies.nonefound=Aucun trace trouv\u00e9
+dialog.gpsies.nonefound=Aucune trace trouv\u00e9e
+dialog.gpsies.username=Nom d'utilisateur Gpsies
+dialog.gpsies.password=Mot de passe Gpsies
+dialog.gpsies.keepprivate=Trace priv\u00e9e
+dialog.gpsies.confirmopenpage=Ouvrir la page web de la trace t\u00e9l\u00e9charg\u00e9e ?
 dialog.gpsies.activities=Activit\u00e9
 dialog.gpsies.activity.trekking=Trekking
 dialog.gpsies.activity.walking=Randonn\u00e9e
@@ -264,6 +296,8 @@ dialog.gpsies.activity.motorbiking=Moto
 dialog.gpsies.activity.snowshoe=Raquette
 dialog.gpsies.activity.sailing=Volle
 dialog.gpsies.activity.skating=Skating
+dialog.wikipedia.column.name=Nom de l'article
+dialog.wikipedia.column.distance=Distance
 dialog.correlate.notimestamps=Les points n'ont pas d'indication de temps, il n'est pas possible de les corr\u00e9ler.
 dialog.correlate.nouncorrelatedphotos=Il n'y a pas de photos non-corr\u00e9l\u00e9es.\nVoulez-vous continuer ?
 dialog.correlate.photoselect.intro=S\u00e9lectionner une de ces photos corr\u00e9l\u00e9es pour d\u00e9finir le d\u00e9calage de temps
@@ -279,6 +313,8 @@ dialog.correlate.options.offset.minutes=minutes et
 dialog.correlate.options.offset.seconds=secondes
 dialog.correlate.options.photolater=Photo post\u00e9rieure au point
 dialog.correlate.options.pointlaterphoto=Point post\u00e9rieur \u00e0 la photo
+dialog.correlate.options.audiolater=Audio post\u00e9rieur au point
+dialog.correlate.options.pointlateraudio=Point post\u00e9rieur \u00e0 l'audio
 dialog.correlate.options.limitspanel=Limites de corr\u00e9lation
 dialog.correlate.options.notimelimit=Pas de limite de temps
 dialog.correlate.options.timelimit=Limite de temps
@@ -286,6 +322,15 @@ dialog.correlate.options.nodistancelimit=Pas de limite de distance
 dialog.correlate.options.distancelimit=Limite de distance
 dialog.correlate.options.correlate=Corr\u00e9ler
 dialog.correlate.alloutsiderange=Les photos ne correspondent pas \u00e0 la plage de temps de la trace, aucune ne peut \u00eatre corr\u00e9l\u00e9e.\nEssayez de modifier le d\u00e9calage ou de corr\u00e9ler manuellement au moins une photo.
+dialog.correlate.filetimes=La date du fichier indique :
+dialog.correlate.filetimes2=de l'extrait audio
+dialog.correlate.correltimes=Pour la corr\u00e9lation, utiliser :
+dialog.correlate.timestamp.beginning=Le d\u00e9but
+dialog.correlate.timestamp.middle=Le milieu
+dialog.correlate.timestamp.end=La fin
+dialog.correlate.audioselect.intro=Choisir un de ces fichiers audio corr\u00e9l\u00e9s comme d\u00e9calage de temps
+dialog.correlate.select.audioname=Nom du fichier audio
+dialog.correlate.select.audiolater=Audio apr\u00e8s
 dialog.rearrangephotos.desc=Choisissez la destination et l\u2019ordre des points des photos
 dialog.rearrangephotos.tostart=Aller au d\u00e9but
 dialog.rearrangephotos.toend=Aller \u00e0 la fin
@@ -300,14 +345,16 @@ dialog.compress.wackypoints.paramdesc=Distance
 dialog.compress.singletons.title=Suppression des points isol\u00e9s
 dialog.compress.singletons.paramdesc=Distance
 dialog.compress.duplicates.title=Suppression des doublons
+dialog.compress.douglaspeucker.title=Compression Douglas-Peucker
+dialog.compress.douglaspeucker.paramdesc=Taille du voisinage
 dialog.compress.summarylabel=Points \u00e0 supprimer
 dialog.pastecoordinates.desc=Entrez ou collez les coordonn\u00e9es ici
 dialog.pastecoordinates.coords=Coordonn\u00e9es
 dialog.pastecoordinates.nothingfound=V\u00e9rifier les coordonn\u00e9es et essayez \u00e0 nouveau
-dialog.help.help=Consultez la page\n http://activityworkshop.net/software/prune/\npour plus de d\u00e9tails et des manuels utilisateur.
+dialog.help.help=Consultez la page\n http://activityworkshop.net/software/gpsprune/\npour plus de d\u00e9tails et des manuels utilisateur.
 dialog.about.version=Version
 dialog.about.build=Build
-dialog.about.summarytext1=Prune est un programme pour charger, afficher et \u00e9diter des donn\u00e9es de r\u00e9cepteurs GPS.
+dialog.about.summarytext1=GpsPrune est un programme pour charger, afficher et \u00e9diter des donn\u00e9es de r\u00e9cepteurs GPS.
 dialog.about.summarytext2=Distribu\u00e9 sous license Gnu GPL pour un usage et une am\u00e9lioration libres, ouverts et mondiaux.<br>La copie, la redistribution et la modification sont autoris\u00e9es et encourag\u00e9es<br>selon les conditions d\u00e9taill\u00e9es dans le fichier <code>license.txt</code> inclus.
 dialog.about.summarytext3=Consultez la page <code style="font-weight:bold">http://activityworkshop.net/</code> pour plus de d\u00e9tails et des manuels utilisateur.
 dialog.about.languages=Langues disponibles
@@ -328,7 +375,7 @@ dialog.about.systeminfo.exiflib.external.failed=Externe (non-trouv\u00e9)
 dialog.about.yes=Oui
 dialog.about.no=Non
 dialog.about.credits=Cr\u00e9dits
-dialog.about.credits.code=Code de Prune \u00e9crit par
+dialog.about.credits.code=Code de GpsPrune \u00e9crit par
 dialog.about.credits.exifcode=Code Exif par
 dialog.about.credits.icons=Quelques ic\u00f4nes provenant de
 dialog.about.credits.translators=Interpr\u00e8tes
@@ -338,14 +385,16 @@ dialog.about.credits.othertools=Autre outils
 dialog.about.credits.thanks=Merci \u00e0
 dialog.about.readme=Lisez-moi
 dialog.checkversion.error=Ne peut pas v\u00e9rifier la version.\nVeuillez v\u00e9rifier votre connexion Internet.
-dialog.checkversion.uptodate=Vous utilisez d\u00e9j\u00e0 la version actuelle de Prune.
+dialog.checkversion.uptodate=Vous utilisez d\u00e9j\u00e0 la version actuelle de GpsPrune.
 dialog.checkversion.newversion1=La version actuelle est maintenant la version
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=La nouvelle version est sortie le
 dialog.checkversion.releasedate2=.
-dialog.checkversion.download=Pour t\u00e9l\u00e9charger la nouvelle version, aller \u00e0 http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=Pour t\u00e9l\u00e9charger la nouvelle version, aller \u00e0 http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=Vous pouvez utiliser ces raccourcis clavier \u00e0 la place de la souris
-dialog.keys.keylist=<table><tr><td>Touches-fl\u00e8ches</td><td>Faire d\u00e9filer la carte horizontallement et verticallement</td></tr><tr><td>Ctrl + gauche, Ctrl + droite</td><td>Choisir le point pr\u00e9c\u00e9dent ou suivant</td></tr><tr><td>Ctrl + haut, Ctrl + bas</td><td>Zoomer, s'\u00e9loigner</td></tr><tr><td>Suppr</td><td>Effacer le point courant</td></tr></table>
+dialog.keys.keylist=<table><tr><td>Touches-fl\u00e8ches</td><td>Faire d\u00e9filer la carte horizontalement et verticalement</td></tr><tr><td>Ctrl + gauche, Ctrl + droite</td><td>Choisir le point pr\u00e9c\u00e9dent ou suivant</td></tr><tr><td>Ctrl + haut, Ctrl + bas</td><td>Zoomer, s'\u00e9loigner</td></tr><tr><td>Suppr</td><td>Effacer le point courant</td></tr></table>
+dialog.keys.normalmodifier=Ctrl
+dialog.keys.macmodifier=Command
 dialog.saveconfig.desc=Les param\u00e8tres suivants peuvent \u00eatre sauvegard\u00e9s dans un fichier de configuration:
 dialog.saveconfig.prune.trackdirectory=Dossier des traces
 dialog.saveconfig.prune.photodirectory=Dossier des Photos
@@ -358,19 +407,20 @@ dialog.saveconfig.prune.metricunits=Utiliser le syst\u00e8me m\u00e9trique ?
 dialog.saveconfig.prune.gnuplotpath=Chemin gnuplot
 dialog.saveconfig.prune.gpsbabelpath=Chemin gpsbabel
 dialog.saveconfig.prune.exiftoolpath=Chemin exiftool
-dialog.saveconfig.prune.mapserverindex=Index du serveur de carte
-dialog.saveconfig.prune.mapserverurl=URL du serveur de carte
 dialog.saveconfig.prune.mapsource=Carte source s\u00e9lectionn\u00e9e
 dialog.saveconfig.prune.mapsourcelist=Sources de cartes
 dialog.saveconfig.prune.diskcache=Cache de carte
 dialog.saveconfig.prune.kmzimagewidth=Largeur de l'image KMZ
 dialog.saveconfig.prune.kmzimageheight=Hauteur de l'image KMZ
 dialog.saveconfig.prune.colourscheme=Mod\u00e8le de couleurs
+dialog.saveconfig.prune.linewidth=Largeur de ligne
 dialog.saveconfig.prune.kmltrackcolour=Couleur de la trace KML
+dialog.saveconfig.prune.autosavesettings=R\u00e9glages de sauvegarde automatique
 dialog.setpaths.intro=Si vous le souhaitez, vous pouvez d\u00e9finir les chemins des applications externes:
 dialog.setpaths.found=Chemin trouv\u00e9 ?
 dialog.addaltitude.noaltitudes=L'\u00e9tendue s\u00e9lectionn\u00e9e de contient pas d'altitudes
-dialog.addaltitude.desc=D\u00e9callage d'altitude \u00e0 ajouter
+dialog.addaltitude.desc=D\u00e9calage d'altitude \u00e0 ajouter
+dialog.lookupsrtm.overwritezeros=Ramener les valeurs d'altitude \u00e0 z\u00e9ro ?
 dialog.setcolours.intro=Cliquez sur une couleur pour la changer
 dialog.setcolours.background=Arri\u00e8re-plan
 dialog.setcolours.borders=Bordures
@@ -385,22 +435,28 @@ dialog.colourchooser.red=Rouge
 dialog.colourchooser.green=Vert
 dialog.colourchooser.blue=Bleu
 dialog.setlanguage.firstintro=Vous pouvez s\u00e9lectionner l'une des langues disponibles,<p> ou bien un fichier de langue \u00e0 utiliser.
-dialog.setlanguage.secondintro=Vous devez sauvegarder vos param\u00e8tres puis<p>red\u00e9marrer Prune pour changer de langue.
+dialog.setlanguage.secondintro=Vous devez sauvegarder vos param\u00e8tres puis<p>red\u00e9marrer GpsPrune pour changer de langue.
 dialog.setlanguage.language=Langue
 dialog.setlanguage.languagefile=Fichier de langue
-dialog.setlanguage.endmessage=Enregistrez vos r\u00e9glages et red\u00e9marrez Prune\npour que le changement de langue soit effectif.
+dialog.setlanguage.endmessage=Enregistrez vos r\u00e9glages et red\u00e9marrez GpsPrune\npour que le changement de langue soit effectif.
+dialog.setlanguage.endmessagewithautosave=Red\u00e9marrez GpsPrune pour que le changement de langue soit effectif.
 dialog.diskcache.save=Enregistrer les images de carte sur le disque
 dialog.diskcache.dir=R\u00e9pertoire cache
 dialog.diskcache.createdir=Cr\u00e9er r\u00e9pertoire
 dialog.diskcache.nocreate=Le r\u00e9pertoire cache n'est pas cr\u00e9\u00e9
+dialog.deletefieldvalues.intro=Choisir le champ \u00e0 effacer pour l'\u00e9tendue actuelle
+dialog.setlinewidth.text=Entrer l'\u00e9paisseur des lignes des traces (1-4)
+dialog.downloadosm.desc=Confirmer le t\u00e9l\u00e9chargement des donn\u00e9es OSM brutes pour la zone indiqu\u00e9e :
+dialog.searchwikipedianames.search=Chercher :
 
 # 3d window
-dialog.3d.title=Vue 3D de Prune
-dialog.3dlines.title=Grille de Prune
+dialog.3d.title=Vue 3D de GpsPrune
+dialog.3d.altitudefactor=Facteur d'exag\u00e9ration de l'altitude
+dialog.3dlines.title=Grille de GpsPrune
 dialog.3dlines.empty=Pas de grille \u00e0 afficher !
 dialog.3dlines.intro=Ceci est la grille pour la vue 3D
 
-# Confirm messages || These are displayed as confirmation in the status bar
+# Confirm messages
 confirm.loadfile=Donn\u00e9es charg\u00e9es depuis le fichier
 confirm.save.ok1=Enregistrement r\u00e9ussi de
 confirm.save.ok2=points dans le fichier
@@ -408,7 +464,7 @@ confirm.deletepoint.single=point a \u00e9t\u00e9 effac\u00e9
 confirm.deletepoint.multi=points ont \u00e9t\u00e9 effac\u00e9s
 confirm.point.edit=point \u00e9dit\u00e9
 confirm.mergetracksegments=Segments de trace ont \u00e9t\u00e9 fusionn\u00e9
-confirm.reverserange=Etendue invers\u00e9e
+confirm.reverserange=\u00c9tendue invers\u00e9e
 confirm.addtimeoffset=D\u00e9calage ajout\u00e9
 confirm.addaltitudeoffset=D\u00e9calage d'altitude ajout\u00e9
 confirm.rearrangewaypoints=Waypoints r\u00e9arrang\u00e9s
@@ -423,6 +479,8 @@ confirm.jpegload.single=la photo a \u00e9t\u00e9 ajout\u00e9e
 confirm.jpegload.multi=les photos ont \u00e9t\u00e9 ajout\u00e9es
 confirm.media.connect=m\u00e9dia reli\u00e9e
 confirm.photo.disconnect=photo d\u00e9tach\u00e9e
+confirm.audio.disconnect=audio d\u00e9tach\u00e9
+confirm.media.removed=retir\u00e9
 confirm.correlatephotos.single=photo a \u00e9t\u00e9 corr\u00e9l\u00e9e
 confirm.correlatephotos.multi=photos ont \u00e9t\u00e9 corr\u00e9l\u00e9es
 confirm.createpoint=Point cr\u00e9\u00e9
@@ -430,6 +488,10 @@ confirm.rotatephoto=Photo tourn\u00e9e
 confirm.running=En cours...
 confirm.lookupsrtm1=Trouv\u00e9
 confirm.lookupsrtm2=valeurs d'altitude
+confirm.deletefieldvalues=Valeurs effac\u00e9es
+confirm.audioload=Fichiers audio ajout\u00e9s
+confirm.correlateaudios.single=fichier audio a \u00e9t\u00e9 corr\u00e9l\u00e9
+confirm.correlateaudios.multi=fichiers audio ont \u00e9t\u00e9 corr\u00e9l\u00e9s
 
 # Buttons
 button.ok=OK
@@ -454,6 +516,7 @@ button.selectall=Tout s\u00e9lectionner
 button.selectnone=Ne rien s\u00e9lectionner
 button.preview=Aper\u00e7u
 button.load=T\u00e9l\u00e9charger
+button.upload=Envoyer
 button.guessfields=Deviner les champs
 button.showwebpage=Montrer page web
 button.check=V\u00e9rifier
@@ -471,8 +534,9 @@ filetype.kmz=Fichiers KMZ
 filetype.gpx=Fichiers GPX
 filetype.pov=Fichiers POV
 filetype.svg=Fichiers SVG
+filetype.audio=Fichiers MP3, OGG, WAV
 
-# Display components || These are all for the side panels showing point/range details
+# Display components
 display.nodata=Pas de donn\u00e9es charg\u00e9es
 display.noaltitudes=La trace ne comporte pas d'information d'altitude
 display.notimestamps=La trace ne comporte pas d'information de temps
@@ -507,10 +571,15 @@ details.range.pace=Allure
 details.range.gradient=Pente
 details.lists.waypoints=Waypoints
 details.lists.photos=Photos
+details.lists.audio=Audio
 details.photodetails=D\u00e9tails de la photo
 details.nophoto=Pas de photo
 details.photo.loading=Chargement
 details.media.connected=Reli\u00e9e
+details.audiodetails=D\u00e9tails de l'audio
+details.noaudio=Pas de fichier audio s\u00e9lectionner
+details.audio.file=Fichier audio
+details.audio.playing=Lecture en cours...
 map.overzoom=Aucune carte disponible \u00e0 ce niveau de zoom
 
 # Field names
@@ -529,6 +598,7 @@ fieldname.movingdistance=Distance continue
 fieldname.duration=Dur\u00e9e
 fieldname.speed=Vitesse
 fieldname.verticalspeed=Vitesse verticale
+fieldname.description=Description
 
 # Measurement units
 units.original=Original
@@ -561,12 +631,14 @@ cardinal.s=S
 cardinal.e=E
 cardinal.w=O
 
-# Undo operations || These will be displayed in the undo list after you've performed the operation, to tell you what you did
+# Undo operations
 undo.load=charger les donn\u00e9es
 undo.loadphotos=charger les photos
+undo.loadaudios=charger les fichiers audio
 undo.editpoint=\u00e9diter le point
 undo.deletepoint=effacer le point
 undo.removephoto=retirer la photo
+undo.removeaudio=retirer le fichier audio
 undo.deleterange=effacer l'\u00e9tendue
 undo.compress=compresser la trace
 undo.insert=ins\u00e9rer les points
@@ -579,16 +651,18 @@ undo.cutandmove=d\u00e9placer la s\u00e9lection
 undo.connect=relier
 undo.disconnect=d\u00e9tacher
 undo.correlatephotos=corr\u00e9ler les photos
-undo.rearrangephotos=R\u00e9arranger les photos
+undo.rearrangephotos=r\u00e9arranger les photos
 undo.createpoint=ajouter un point
-undo.rotatephoto=Tourner la photo
-undo.convertnamestotimes=Convertir les noms en points
-undo.lookupsrtm=Rechercher les altitudes depuis SRTM
+undo.rotatephoto=tourner la photo
+undo.convertnamestotimes=convertir les noms en points
+undo.lookupsrtm=rechercher les altitudes depuis SRTM
+undo.deletefieldvalues=effacer les valeurs
+undo.correlateaudios=corr\u00e9ler les fichiers audio
 
 # Error messages
 error.save.dialogtitle=Erreur \u00e0 l'enregistrement des donn\u00e9es
 error.save.nodata=Pas de donn\u00e9es \u00e0 enregistrer
-error.save.failed=Echec de l'enregistrement des donn\u00e9es dans le fichier
+error.save.failed=\u00c9chec de l'enregistrement des donn\u00e9es dans le fichier
 error.saveexif.filenotfound=Fichier photo introuvable
 error.saveexif.cannotoverwrite1=Le fichier photo
 error.saveexif.cannotoverwrite2=est en lecture seule et ne peut pas \u00eatre \u00e9craser. Enregistrer sur une copie ?
@@ -607,9 +681,10 @@ error.jpegload.nofilesfound=Aucun fichier trouv\u00e9
 error.jpegload.nojpegsfound=Aucun fichier jpeg trouv\u00e9
 error.jpegload.nogpsfound=Aucune information GPS trouv\u00e9e
 error.jpegload.exifreadfailed=Information EXIF illisible. Aucune information EXIF ne peut \u00eatre lue\nsans une librairie interne ou externe.
+error.audioload.nofilesfound=Aucun fichier audio trouv\u00e9
 error.gpsload.unknown=Erreur inconnue
-error.undofailed.title=Echec de l'annulation
-error.undofailed.text=Echec de l'op\u00e9ration d'annulation
+error.undofailed.title=\u00c9chec de l'annulation
+error.undofailed.text=\u00c9chec de l'op\u00e9ration d'annulation
 error.function.noop.title=Fonction sans effet
 error.rearrange.noop=R\u00e9arrangement des points sans effet
 error.function.notavailable.title=Function non-disponible
@@ -618,6 +693,10 @@ error.3d=Un probl\u00e8me est survenu avec l'affichage 3D
 error.readme.notfound=Fichier Lisez-moi introuvable
 error.osmimage.dialogtitle=Erreur au chargement des portions de cartes
 error.osmimage.failed=Erreur du chargement des portions de cartes. V\u00e9rifiez votre connexion internet.
-error.language.wrongfile=Le fichier s\u00e9lectionn\u00e9 n'est pas un fichier de langue pour Prune
+error.language.wrongfile=Le fichier s\u00e9lectionn\u00e9 n'est pas un fichier de langue pour GpsPrune
 error.convertnamestotimes.nonames=Aucun nom n'a pu \u00eatre converti en horaire
 error.lookupsrtm.nonefound=Aucune valeur d'altitude trouv\u00e9e pour les points
+error.lookupsrtm.nonerequired=Tous les points ont d\u00e9j\u00e0 une altitude, il n'y a rien \u00e0 r\u00e9cup\u00e9rer
+error.gpsies.uploadnotok=Le serveur de Gpsies \u00e0 renvoy\u00e9 le message
+error.gpsies.uploadfailed=L'envoi a \u00e9chou\u00e9 avec l'erreur
+error.playaudiofailed=\u00c9chec de la lecture du fichier audio
index 29840ddd25d6e542418814bff5a2c01b88ee1758..1336c010701931f6879dd3cd973eafae6efd582e 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Hungarian entries thanks to Gy\u00f6rgy Ball\u00f3
 
 # Menu entries
 menu.file=F\u00e1jl
 menu.file.addphotos=F\u00e9nyk\u00e9pek hozz\u00e1ad\u00e1sa
+menu.file.recentfiles=Legut\u00f3bbi f\u00e1jlok
 menu.file.save=Ment\u00e9s sz\u00f6vegk\u00e9nt
 menu.file.exit=Kil\u00e9p\u00e9s
 menu.track=Nyomvonal
@@ -41,6 +42,7 @@ menu.view.browser.yahoo=Yahoo! Maps
 menu.view.browser.bing=Bing Maps
 menu.settings=Be\u00e1ll\u00edt\u00e1sok
 menu.settings.onlinemode=T\u00e9rk\u00e9pek bet\u00f6lt\u00e9se az internetr\u0151l
+menu.settings.autosave=Be\u00e1ll\u00edt\u00e1sok automatikus ment\u00e9se a programb\u00f3l t\u00f6rt\u00e9n\u0151 kil\u00e9p\u00e9skor
 menu.help=S\u00fag\u00f3
 # Popup menu for map
 menu.map.zoomin=Nagy\u00edt\u00e1s
@@ -75,6 +77,7 @@ shortcut.menu.help.help=H
 
 # Functions
 function.open=F\u00e1jl megnyit\u00e1sa
+function.importwithgpsbabel=F\u00e1jl import\u00e1l\u00e1sa GPSBabellel
 function.loadfromgps=Adatok let\u00f6lt\u00e9se GPS-r\u0151l
 function.sendtogps=Adatok felt\u00f6lt\u00e9se GPS-re
 function.exportkml=Export\u00e1l\u00e1s KML-be
@@ -122,13 +125,14 @@ function.playaudio=Hangf\u00e1jl lej\u00e1tsz\u00e1sa
 function.stopaudio=Hangf\u00e1jl meg\u00e1ll\u00edt\u00e1sa
 function.help=S\u00fag\u00f3
 function.showkeys=Gyorsbillenty\u0171k megjelen\u00edt\u00e9se
-function.about=A Prune n\u00e9vjegye
+function.about=A GpsPrune n\u00e9vjegye
 function.checkversion=\u00daj verzi\u00f3 keres\u00e9se
 function.saveconfig=Be\u00e1ll\u00edt\u00e1sok ment\u00e9se
 function.diskcache=T\u00e9rk\u00e9pek ment\u00e9se lemezre
+function.managetilecache=Csempegyors\u00edt\u00f3t\u00e1r kezel\u00e9se
 
 # Dialogs
-dialog.exit.confirm.title=Kil\u00e9p\u00e9s a Prune-b\u00f3l
+dialog.exit.confirm.title=Kil\u00e9p\u00e9s a GpsPrune-b\u00f3l
 dialog.exit.confirm.text=Az adatok nincsenek elmentve. Biztos benne, hogy kil\u00e9p?
 dialog.openappend.title=Hozz\u00e1f\u0171z\u00e9s a megl\u00e9v\u0151 adatokhoz
 dialog.openappend.text=Hozz\u00e1f\u0171zi ezeket az adatokat a m\u00e1r bet\u00f6lt\u00f6tt adatokhoz?
@@ -189,6 +193,9 @@ dialog.exportgpx.name=N\u00e9v
 dialog.exportgpx.desc=Le\u00edr\u00e1s
 dialog.exportgpx.includetimestamps=Id\u0151b\u00e9lyegek is
 dialog.exportgpx.copysource=Forr\u00e1s xml m\u00e1sol\u00e1sa
+dialog.exportgpx.encoding=Karakterk\u00f3dol\u00e1s
+dialog.exportgpx.encoding.system=Rendszer
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Adja meg a param\u00e9tereket a POV exporthoz
 dialog.exportpov.font=Bet\u0171t\u00edpus
 dialog.exportpov.camerax=X kamera
@@ -341,14 +348,16 @@ dialog.compress.wackypoints.paramdesc=T\u00e1vols\u00e1gt\u00e9nyez\u0151
 dialog.compress.singletons.title=Egyke pontok elt\u00e1vol\u00edt\u00e1sa
 dialog.compress.singletons.paramdesc=T\u00e1vols\u00e1gt\u00e9nyez\u0151
 dialog.compress.duplicates.title=Kett\u0151z\u00f6tt pontok elt\u00e1vol\u00edt\u00e1sa
+dialog.compress.douglaspeucker.title=Douglas-Peucker t\u00f6m\u00f6r\u00edt\u00e9s
+dialog.compress.douglaspeucker.paramdesc=T\u00f6m\u00f6r\u00edt\u00e9si t\u00e9nyez\u0151
 dialog.compress.summarylabel=T\u00f6rlend\u0151 pontok
 dialog.pastecoordinates.desc=Adja meg vagy illessze be a koordin\u00e1t\u00e1kat ide
 dialog.pastecoordinates.coords=Koordin\u00e1t\u00e1k
 dialog.pastecoordinates.nothingfound=Ellen\u0151rizze a koordin\u00e1t\u00e1kat, \u00e9s pr\u00f3b\u00e1lja \u00f3jra
-dialog.help.help=Tov\u00e1bbi inform\u00e1ci\u00f3k\u00e9rt \u00e9s kezel\u00e9si \u00fatmutat\u00f3\u00e9rt l\u00e1sd a \n http://activityworkshop.net/software/prune/\nwebhelyet.
+dialog.help.help=Tov\u00e1bbi inform\u00e1ci\u00f3k\u00e9rt \u00e9s kezel\u00e9si \u00fatmutat\u00f3\u00e9rt l\u00e1sd a \n http://activityworkshop.net/software/gpsprune/\nwebhelyet.
 dialog.about.version=Verzi\u00f3
 dialog.about.build=Build
-dialog.about.summarytext1=A Prune egy program GPS vev\u0151kr\u0151l sz\u00e1rmaz\u00f3 adatok bet\u00f6lt\u00e9s\u00e9re, megjelen\u00edt\u00e9s\u00e9re \u00e9s szerkeszt\u00e9s\u00e9re.
+dialog.about.summarytext1=A GpsPrune egy program GPS vev\u0151kr\u0151l sz\u00e1rmaz\u00f3 adatok bet\u00f6lt\u00e9s\u00e9re, megjelen\u00edt\u00e9s\u00e9re \u00e9s szerkeszt\u00e9s\u00e9re.
 dialog.about.summarytext2=Gnu GPL licenc alatt ker\u00fclt kiad\u00e1sra a szabad, ny\u00edlt, vil\u00e1gm\u00e9ret\u0171 haszn\u00e1lathoz \u00e9s fejleszt\u00e9shez.<br>M\u00e1sol\u00e1sa, terjeszt\u00e9se \u00e9s m\u00f3dos\u00edt\u00e1sa megengedett \u00e9s \u00f6szt\u00f6nz\u00f6tt<br>a mell\u00e9kelt <code>license.txt</code> f\u00e1jlban r\u00f6gz\u00edtett felt\u00e9telek szerint
 dialog.about.summarytext3=Tov\u00e1bbi inform\u00e1ci\u00f3k\u00e9rt \u00e9s kezel\u00e9si \u00fatmutat\u00f3\u00e9rt l\u00e1sd a <code style="font-weight:bold">http://activityworkshop.net/</code> webhelyet.
 dialog.about.languages=El\u00e9rhet\u0151 nyelvek
@@ -369,7 +378,7 @@ dialog.about.systeminfo.exiflib.external.failed=K\u00fcls\u0151 (nem tal\u00e1lh
 dialog.about.yes=Igen
 dialog.about.no=Nem
 dialog.about.credits=K\u00e9sz\u00edt\u0151k
-dialog.about.credits.code=Prune k\u00f3dj\u00e1t \u00edrta:
+dialog.about.credits.code=GpsPrune k\u00f3dj\u00e1t \u00edrta:
 dialog.about.credits.exifcode=Exif k\u00f3d:
 dialog.about.credits.icons=N\u00e9h\u00e1ny ikon sz\u00e1rmazik:
 dialog.about.credits.translators=Ford\u00edt\u00f3k
@@ -379,12 +388,12 @@ dialog.about.credits.othertools=Egy\u00e9b eszk\u00f6z\u00f6k
 dialog.about.credits.thanks=K\u00f6sz\u00f6net:
 dialog.about.readme=Olvassel
 dialog.checkversion.error=A verzi\u00f3sz\u00e1m nem ellen\u0151rizhet\u0151.\nEllen\u0151rizze az internetkapcsolatot.
-dialog.checkversion.uptodate=A Prune leg\u00fajabb verzi\u00f3j\u00e1t haszn\u00e1lja.
-dialog.checkversion.newversion1=El\u00e9rhet\u0151 a Prune \u00faj verzi\u00f3ja! A leg\u00fajabb veri\u00f3 most:
+dialog.checkversion.uptodate=A GpsPrune leg\u00fajabb verzi\u00f3j\u00e1t haszn\u00e1lja.
+dialog.checkversion.newversion1=El\u00e9rhet\u0151 a GpsPrune \u00faj verzi\u00f3ja! A leg\u00fajabb verzi\u00f3 most:
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=Ez az \u00faj verzi\u00f3 kiad\u00e1sra ker\u00fclt:
 dialog.checkversion.releasedate2=.
-dialog.checkversion.download=Az \u00faj verzi\u00f3 let\u00f6lt\u00e9s\u00e9hez keresse fel a http://activityworkshop.net/software/prune/download.html webhelyet.
+dialog.checkversion.download=Az \u00faj verzi\u00f3 let\u00f6lt\u00e9s\u00e9hez keresse fel a http://activityworkshop.net/software/gpsprune/download.html webhelyet.
 dialog.keys.intro=A k\u00f6vetkez\u0151 gyorsbillenty\u0171k haszn\u00e1lhat\u00f3k az eg\u00e9r haszn\u00e1lata helyett
 dialog.keys.keylist=<table><tr><td>Ny\u00edlbillenty\u0171k</td><td>T\u00e9rk\u00e9p mozgat\u00e1sa balra, jobbra, fel, le</td></tr><tr><td>Ctrl + bal, jobb ny\u00edl</td><td>El\u0151z\u0151 vagy k\u00f6vetkez\u0151 pont kiv\u00e1laszt\u00e1sa</td></tr><tr><td>Ctrl + fel, le ny\u00edl</td><td>Nagy\u00edt\u00e1s vagy kicsiny\u00edt\u00e9s</td></tr><tr><td>Ctrl + PgUp, PgDown</td><td>El\u0151z\u0151, k\u00f6vetkez\u0151 szakasz kiv\u00e1laszt\u00e1sa</td></tr><tr><td>Ctrl + Home, End</td><td>Els\u0151, utols\u00f3 pont kiv\u00e1laszt\u00e1sa</td></tr><tr><td>Del</td><td>Jelenlegi pont t\u00f6rl\u00e9se</td></tr></table>
 dialog.keys.normalmodifier=Ctrl
@@ -409,6 +418,7 @@ dialog.saveconfig.prune.kmzimageheight=KMZ k\u00e9pmagass\u00e1g
 dialog.saveconfig.prune.colourscheme=Sz\u00edns\u00e9ma
 dialog.saveconfig.prune.linewidth=Vonalsz\u00e9less\u00e9g
 dialog.saveconfig.prune.kmltrackcolour=KML nyomvonal sz\u00edne
+dialog.saveconfig.prune.autosavesettings=Automatikus ment\u00e9s be\u00e1ll\u00edt\u00e1sai
 dialog.setpaths.intro=Ha sz\u00fcks\u00e9ges, kiv\u00e1laszthatja a k\u00fcls\u0151 alkalmaz\u00e1sok \u00fatvonalait:
 dialog.setpaths.found=\u00datvonal megtal\u00e1lhat\u00f3?
 dialog.addaltitude.noaltitudes=A kiv\u00e1lasztott tartom\u00e1ny nem tartalmaz magass\u00e1gi \u00e9rt\u00e9keket
@@ -428,23 +438,35 @@ dialog.colourchooser.red=Piros
 dialog.colourchooser.green=Z\u00f6ld
 dialog.colourchooser.blue=K\u00e9k
 dialog.setlanguage.firstintro=Kiv\u00e1laszthat egy be\u00e9p\u00edtett nyelvet,<p>vagy v\u00e1lasszon egy sz\u00f6vegf\u00e1jlt helyette.
-dialog.setlanguage.secondintro=Mentenie kell a be\u00e1ll\u00edt\u00e1sokat, majd<p>a nyelv v\u00e1lt\u00e1s\u00e1hoz ind\u00edtsa \u00fajra a Prune-t.
+dialog.setlanguage.secondintro=Mentenie kell a be\u00e1ll\u00edt\u00e1sokat, majd<p>a nyelv v\u00e1lt\u00e1s\u00e1hoz ind\u00edtsa \u00fajra a GpsPrune-t.
 dialog.setlanguage.language=Nyelv
 dialog.setlanguage.languagefile=Nyelvi f\u00e1jl
-dialog.setlanguage.endmessage=Most mentse a be\u00e1ll\u00edt\u00e1sokat, \u00e9s ind\u00edtsa \u00fajra a Prune-t,\nhogy a nyelv v\u00e1lt\u00e1sa \u00e9rv\u00e9nybe l\u00e9pjen
+dialog.setlanguage.endmessage=Most mentse a be\u00e1ll\u00edt\u00e1sokat, \u00e9s ind\u00edtsa \u00fajra a GpsPrune-t,\nhogy a nyelv v\u00e1lt\u00e1sa \u00e9rv\u00e9nybe l\u00e9pjen
+dialog.setlanguage.endmessagewithautosave=A nyelv megv\u00e1ltoztat\u00e1s\u00e1nak \u00e9rv\u00e9nyes\u00edt\u00e9s\u00e9hez ind\u00edtsa \u00fajra a GpsPrune-t.
 dialog.diskcache.save=T\u00e9rk\u00e9pek ment\u00e9se a lemezre
 dialog.diskcache.dir=Gyors\u00edt\u00f3t\u00e1r k\u00f6nyvt\u00e1ra
 dialog.diskcache.createdir=K\u00f6nyvt\u00e1r l\u00e9trehoz\u00e1sa
 dialog.diskcache.nocreate=A gyors\u00edt\u00f3t\u00e1r k\u00f6nyvt\u00e1ra nem ker\u00fclt l\u00e9trehoz\u00e1sra
+dialog.diskcache.table.path=El\u00e9r\u00e9si \u00fat
+dialog.diskcache.table.usedby=Haszn\u00e1lja
+dialog.diskcache.table.zoom=Nagy\u00edt\u00e1s
+dialog.diskcache.table.tiles=Csemp\u00e9k
+dialog.diskcache.table.megabytes=Megab\u00e1jt
+dialog.diskcache.tileset=Csempecsoport
+dialog.diskcache.tileset.multiple=t\u00f6bb
+dialog.diskcache.deleteold=R\u00e9gi csemp\u00e9k t\u00f6rl\u00e9se
+dialog.diskcache.deleteall=Az \u00f6sszes csempe t\u00f6rl\u00e9se
+dialog.diskcache.deleted1=
+dialog.diskcache.deleted2=f\u00e1jl t\u00f6r\u00f6lve a gyors\u00edt\u00f3t\u00e1rb\u00f3l
 dialog.deletefieldvalues.intro=V\u00e1lassza ki a t\u00f6rlend\u0151 mez\u0151t a jelenlegi tartom\u00e1nyban
 dialog.setlinewidth.text=Adja meg a rajzoland\u00f3 vonalak vastags\u00e1g\u00e1t a nyomvonalak sz\u00e1m\u00e1ra (1-4)
 dialog.downloadosm.desc=Nyers OSM adatok let\u00f6lt\u00e9s\u00e9nek meger\u0151s\u00edt\u00e9se a megadott ter\u00fcletre:
 dialog.searchwikipedianames.search=Keres\u00e9s erre:
 
 # 3d window
-dialog.3d.title=Prune 3D n\u00e9zet
+dialog.3d.title=GpsPrune 3D n\u00e9zet
 dialog.3d.altitudefactor=Magass\u00e1gi ny\u00fajt\u00e1si t\u00e9nyez\u0151
-dialog.3dlines.title=Prune r\u00e1csvonalak
+dialog.3dlines.title=GpsPrune r\u00e1csvonalak
 dialog.3dlines.empty=Nincsenek megjelen\u00edthet\u0151 r\u00e1csvonalak!
 dialog.3dlines.intro=Ezek a r\u00e1csvonalak a 3D n\u00e9zethez
 
@@ -516,6 +538,7 @@ button.resettodefaults=Vissza\u00e1ll\u00edt\u00e1s az alap\u00e9rtelmezettre
 button.browse=B\u00f6ng\u00e9sz\u00e9s...
 button.addnew=\u00daj hozz\u00e1ad\u00e1sa
 button.delete=T\u00f6rl\u00e9s
+button.manage=Kezel\u00e9s
 
 # File types
 filetype.txt=TXT f\u00e1jlok
@@ -567,9 +590,10 @@ details.lists.audio=Hang
 details.photodetails=F\u00e9nyk\u00e9p r\u00e9szletei
 details.nophoto=Nincs f\u00e9nyk\u00e9p kiv\u00e1lasztva
 details.photo.loading=Bet\u00f6lt\u00e9s
+details.photo.bearing=Ir\u00e1ny
 details.media.connected=\u00d6sszekapcsolva
 details.audiodetails=Hang r\u00e9szletei
-details.noaudio=Nincs hang kiv\u00e1lasztva
+details.noaudio=Nincs hangf\u00e1jl kiv\u00e1lasztva
 details.audio.file=Hangf\u00e1jl
 details.audio.playing=lej\u00e1tsz\u00e1s...
 map.overzoom=Nem \u00e9rhet\u0151 el t\u00e9rk\u00e9p ezen a nagy\u00edt\u00e1si szinten
@@ -590,6 +614,7 @@ fieldname.movingdistance=Mozg\u00e1si t\u00e1vols\u00e1g
 fieldname.duration=Id\u0151tartam
 fieldname.speed=Sebess\u00e9g
 fieldname.verticalspeed=F\u00fcgg\u0151leges sebess\u00e9g
+fieldname.description=Le\u00edr\u00e1s
 
 # Measurement units
 units.original=Eredeti
@@ -684,10 +709,13 @@ error.3d=Hiba t\u00f6rt\u00e9nt a 3d megjelen\u00edt\u00e9ssel
 error.readme.notfound=Az olvassel f\u00e1jl nem tal\u00e1lhat\u00f3
 error.osmimage.dialogtitle=Hiba a t\u00e9rk\u00e9p bet\u00f6lt\u00e9sekor
 error.osmimage.failed=A t\u00e9rk\u00e9p bet\u00f6lt\u00e9se nem siker\u00fclt. Ellen\u0151rizze az internetkapcsolatot.
-error.language.wrongfile=\u00dagy t\u0171nik, hogy a kiv\u00e1lasztott f\u00e1jl nem egy nyelvi f\u00e1jl a Prune-hoz
+error.language.wrongfile=\u00dagy t\u0171nik, hogy a kiv\u00e1lasztott f\u00e1jl nem egy nyelvi f\u00e1jl a GpsPrune-hoz
 error.convertnamestotimes.nonames=A nevek nem konvert\u00e1lhat\u00f3k id\u0151adatokk\u00e1
 error.lookupsrtm.nonefound=Nem \u00e9rhet\u0151 el magass\u00e1gi \u00e9rt\u00e9k ezekhez a pontokhoz
 error.lookupsrtm.nonerequired=Az \u00f6sszes pont m\u00e1r rendelkezik magass\u00e1gadatokkal, \u00edgy nincs mit keresni
 error.gpsies.uploadnotok=A gpsies szerver a k\u00f6vetkez\u0151 \u00fczenetet adta vissza
 error.gpsies.uploadfailed=A felt\u00f6lt\u00e9s nem siker\u00fclt a k\u00f6vetkez\u0151 hib\u00e1val
 error.playaudiofailed=A hangf\u00e1jl lej\u00e1tsz\u00e1sa nem siker\u00fclt
+error.cache.notthere=A csempegyors\u00edt\u00f3t\u00e1r k\u00f6nyvt\u00e1ra nem tal\u00e1lhat\u00f3
+error.cache.empty=A csempegyors\u00edt\u00f3t\u00e1r k\u00f6nyvt\u00e1ra \u00fcres
+error.cache.cannotdelete=Nincs t\u00f6r\u00f6lhet\u0151 csempe
index bf19b955ce146563310ba03d27dafafbfb080dfc..eb4d1ff0b46f4d982646afff44ff44d9e7e9025c 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Italian entries thanks to josatoc
 
 # Menu entries
 menu.file=File
 menu.file.addphotos=Aggiungi foto
+menu.file.recentfiles=File recenti
 menu.file.save=Salva
 menu.file.exit=Esci
 menu.track=Traccia
@@ -122,13 +123,13 @@ function.playaudio=Riproduci ripresa audio
 function.stopaudio=Ferma ripresa audio
 function.help=Aiuto
 function.showkeys=Visualizza tasti scelta rapida
-function.about=Informazioni su Prune
+function.about=Informazioni su GpsPrune
 function.checkversion=Controlla gli aggiornamenti
 function.saveconfig=Salva configurazione
 function.diskcache=Salva mappe su disco
 
 # Dialogs
-dialog.exit.confirm.title=Esci da Prune
+dialog.exit.confirm.title=Esci da GpsPrune
 dialog.exit.confirm.text=Le modifiche non sono state salvate. Sei sicuro di voler uscire?
 dialog.openappend.title=Aggiungi ai dati esistenti
 dialog.openappend.text=Aggiungi questi dati a quelli gi\u00e0 caricati?
@@ -189,6 +190,8 @@ dialog.exportgpx.name=Nome
 dialog.exportgpx.desc=Descrizione
 dialog.exportgpx.includetimestamps=Includi dati temporali
 dialog.exportgpx.copysource=Copia xml sorgente
+dialog.exportgpx.encoding.system=Sistema
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Per favore inserisci i parametri per l'esportazione in POV
 dialog.exportpov.font=Font
 dialog.exportpov.camerax=Camera X
@@ -345,10 +348,10 @@ dialog.compress.summarylabel=Punti da cancellare
 dialog.pastecoordinates.desc=Inserisci o incolla qui le coordinate
 dialog.pastecoordinates.coords=Coordinate
 dialog.pastecoordinates.nothingfound=Per favore, controlla le coordinate e riprova
-dialog.help.help=Per favore vedi\n http://activityworkshop.net/software/prune/\nper maggiori informazioni e per la guida utente.
+dialog.help.help=Per favore vedi\n http://activityworkshop.net/software/gpsprune/\nper maggiori informazioni e per la guida utente.
 dialog.about.version=Versione
 dialog.about.build=Build
-dialog.about.summarytext1=Prune \u00e8 un programma per il caricamento, la visione e l'edit di dati provenienti da un GPS.
+dialog.about.summarytext1=GpsPrune \u00e8 un programma per il caricamento, la visione e l'edit di dati provenienti da un GPS.
 dialog.about.summarytext2=\u00c8 rilasciato sotto la licenza Gnu GPL per l'uso gratuito e aperto ed il suo miglioramento, con validit\u00e0 mondiale.<br>La copia, la ridistribuzione sono permesse e incoraggiate<br>in accordo con i termini inclusi nel file <code>license.txt</code>.
 dialog.about.summarytext3=Per favore vedi <code style="font-weight:bold">http://activityworkshop.net/</code> per maggiori informazioni e per la guida utente.
 dialog.about.languages=Lingue disponibili
@@ -369,7 +372,7 @@ dialog.about.systeminfo.exiflib.external.failed=Esterna (non trovata)
 dialog.about.yes=S\u00ec
 dialog.about.no=No
 dialog.about.credits=Crediti
-dialog.about.credits.code=Il codice Prune code \u00e8 scritto da
+dialog.about.credits.code=Il codice GpsPrune code \u00e8 scritto da
 dialog.about.credits.exifcode=Il codice Exif \u00e8 scritto da
 dialog.about.credits.icons=Alcune icone prese da
 dialog.about.credits.translators=Traduttori
@@ -379,12 +382,12 @@ dialog.about.credits.othertools=Altri tool
 dialog.about.credits.thanks=Grazie a
 dialog.about.readme=Leggimi
 dialog.checkversion.error=Non posso verificare l'aggiornamento.\nPer favore controlla la connessione internet.
-dialog.checkversion.uptodate=Stai usando l'ultima versione di Prune
-dialog.checkversion.newversion1=Una nuova versione di Prune \u00e8 disponibile! L'ultima versione \u00e8 ora la versione
+dialog.checkversion.uptodate=Stai usando l'ultima versione di GpsPrune
+dialog.checkversion.newversion1=Una nuova versione di GpsPrune \u00e8 disponibile! L'ultima versione \u00e8 ora la versione
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=Questa nuova versione \u00e8 stata rilasciata il
 dialog.checkversion.releasedate2=.
-dialog.checkversion.download=Per scaricare la nuova versione vai a http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=Per scaricare la nuova versione vai a http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=Puoi utilizzare i seguenti tast di scelta rapida al posto del mouse
 dialog.keys.keylist=<table><tr><td>Tasti freccia</td><td>Muovi mappa destra, sinistra, su, giu'</td></tr><tr><td>Ctrl + freccia destra, sinistra</td><td>Selezione punto successivo o precedente</td></tr><tr><td>Ctrl + freccia su, giu'</td><td>Zoom in o out</td></tr><tr><td>Del</td><td>Cancella punto attuale</td></tr></table>
 dialog.keys.normalmodifier=Ctrl
@@ -428,10 +431,10 @@ dialog.colourchooser.red=Rosso
 dialog.colourchooser.green=Verde
 dialog.colourchooser.blue=Blu
 dialog.setlanguage.firstintro=Puoi selezionare una delle lingue incluse,<p>oppure selezionare un file di testo.
-dialog.setlanguage.secondintro=Devi salvare le impostazioni e<p> riavviare Prune per cambiare la lingua.
+dialog.setlanguage.secondintro=Devi salvare le impostazioni e<p> riavviare GpsPrune per cambiare la lingua.
 dialog.setlanguage.language=Lingua
 dialog.setlanguage.languagefile=File della lingua
-dialog.setlanguage.endmessage=Ora salva le tue preferenze e riavvia Prune\n per rendere effettivo il cambio di lingua
+dialog.setlanguage.endmessage=Ora salva le tue preferenze e riavvia GpsPrune\n per rendere effettivo il cambio di lingua
 dialog.diskcache.save=Salva la mappa sul disco
 dialog.diskcache.dir=Cartella della cache
 dialog.diskcache.createdir=Crea cartella
@@ -442,9 +445,9 @@ dialog.downloadosm.desc=Conferma lo scarico dei dati raw OSM per l'area specific
 dialog.searchwikipedianames.search=Cerca per:
 
 # 3d window
-dialog.3d.title=Visione Prune in 3D
+dialog.3d.title=Visione GpsPrune in 3D
 dialog.3d.altitudefactor=Fattore di moltiplicazione della quota
-dialog.3dlines.title=Griglia di Prune
+dialog.3dlines.title=Griglia di GpsPrune
 dialog.3dlines.empty=Nessuna griglia mostrata!
 dialog.3dlines.intro=Queste sono le linee della griglia per la visione 3D
 
@@ -684,7 +687,7 @@ error.3d=\u00c8 avvenuto un errore nella visualizzazione 3D
 error.readme.notfound=Non ho trovato il file Leggimi
 error.osmimage.dialogtitle=Errore nel caricamento nelle immagini della mappa
 error.osmimage.failed=Impossibile caricare le immagini della mappa. Per favore verifica la connessione a internet.
-error.language.wrongfile=Il file selezionato non sembra essere un file di lingua per Prune
+error.language.wrongfile=Il file selezionato non sembra essere un file di lingua per GpsPrune
 error.convertnamestotimes.nonames=Nomi non convertibili in orari
 error.lookupsrtm.nonefound=Valori di quota non trovati
 error.lookupsrtm.nonerequired=Tutti i punti hanno gi\u00e0 una quota, non c'\u00e8 niente da cercare
index c6b165320aeca9f3afc4799fd13a89cb9692a302..30c3556bcb3a9be9f014e4605807b080a81dcfc9 100644 (file)
@@ -1,4 +1,4 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Japanese entries as extra
 
 # Menu entries
@@ -84,12 +84,12 @@ function.rotatephotoright=\u5199\u771f\u3092\u53f3\u306b\u56de\u3059
 function.ignoreexifthumb=EXIF\u30b5\u30e0\u30cd\u30a4\u30eb\u3092\u7121\u8996
 function.help=\u30d8\u30eb\u30d7
 function.showkeys=\u30b7\u30e7\u30fc\u30c8\u30ab\u30c3\u30c8\u30ad\u30fc\u3092\u8868\u793a
-function.about=Prune \u306b\u3064\u3044\u3066
+function.about=GpsPrune \u306b\u3064\u3044\u3066
 function.checkversion=\u65b0\u3057\u3044\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u8868\u793a
 function.saveconfig=\u8a2d\u5b9a\u3092\u4fdd\u5b58
 
 # Dialogs
-dialog.exit.confirm.title=Prune \u3092\u7d42\u4e86
+dialog.exit.confirm.title=GpsPrune \u3092\u7d42\u4e86
 dialog.exit.confirm.text=\u30c7\u30fc\u30bf\u306f\u4fdd\u5b58\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u672c\u5f53\u306b\u7d42\u4e86\u3057\u307e\u3059\u304b\uff1f
 dialog.openappend.title=\u65e2\u5b58\u306e\u30c7\u30fc\u30bf\u3092\u52a0\u3048\u308b
 dialog.openappend.text=\u3053\u306e\u30c7\u30fc\u30bf\u306b\u65e2\u5b58\u306e\u30c7\u30fc\u30bf\u30fc\u3092\u8aad\u307f\u8fbc\u3080\u3002
@@ -277,10 +277,10 @@ dialog.compress.summarylabel=\u524a\u9664\u3059\u308b\u70b9
 dialog.pastecoordinates.desc=\u5ea7\u6a19\u3092\u3053\u3053\u306b\u5165\u529b\u3059\u308b\u304b\u30da\u30fc\u30b9\u30c8\u3057\u3066\u304f\u3060\u3055\u3044\u3002
 dialog.pastecoordinates.coords=\u5ea7\u6a19
 dialog.pastecoordinates.nothingfound=\u5ea7\u6a19\u306e\u78ba\u8a8d\u3092\u3057\u3066\u3001\u3082\u3046\u4e00\u5ea6\u8a66\u3057\u3066\u304f\u3060\u3055\u3044\u3002
-dialog.help.help=\u8a73\u3057\u3044\u60c5\u5831\u3084\u3001\u30e6\u30fc\u30b6\u30fc\u30ac\u30a4\u30c9\u306a\u3069\u306f\u3001\nhttp://activityworkshop.net/software/prune/ \u3092\u898b\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.help.help=\u8a73\u3057\u3044\u60c5\u5831\u3084\u3001\u30e6\u30fc\u30b6\u30fc\u30ac\u30a4\u30c9\u306a\u3069\u306f\u3001\nhttp://activityworkshop.net/software/gpsprune/ \u3092\u898b\u3066\u304f\u3060\u3055\u3044\u3002
 dialog.about.version=\u30d0\u30fc\u30b8\u30e7\u30f3
 dialog.about.build=Build
-dialog.about.summarytext1=Prune \u306f\u3001GPS\u53d7\u4fe1\u6a5f\u304b\u3089\u306e\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u307f\u3001\u8868\u793a\u3057\u3001\u7de8\u96c6\u3059\u308b\u305f\u3081\u306e\u30d7\u30ed\u30b0\u30e9\u30e0\u3067\u3059\u3002
+dialog.about.summarytext1=GpsPrune \u306f\u3001GPS\u53d7\u4fe1\u6a5f\u304b\u3089\u306e\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u307f\u3001\u8868\u793a\u3057\u3001\u7de8\u96c6\u3059\u308b\u305f\u3081\u306e\u30d7\u30ed\u30b0\u30e9\u30e0\u3067\u3059\u3002
 dialog.about.summarytext2=\u3053\u308c\u306f\u3001Gnu GPL\u306e\u4e0b\u306b\u516c\u958b\u3055\u308c\u3001\u81ea\u7531\u3067\u3001\u30aa\u30fc\u30d7\u30f3\u3067\u3001\u4e16\u754c\u4e2d\u3067\u3064\u304b\u3048\u3001\u62e1\u5f35\u53ef\u80fd\u3067\u3059\u3002<br><code>"license.txt"</code>\u306b\u304b\u304b\u308c\u3066\u3044\u308b\u6761\u4ef6\u306b\u3088\u308b\u3068\u3001<br>\u8907\u88fd\u30fb\u518d\u914d\u5e03\u30fb\u6539\u5909\u306f\u3001\u8a31\u3055\u308c\u3066\u304a\u308a\u3001\u304b\u3064\u5968\u52b1\u3055\u308c\u3066\u3044\u307e\u3059\u3002
 dialog.about.summarytext3=\u3082\u3063\u3068\u8a73\u3057\u3044\u60c5\u5831\u3084\u30e6\u30fc\u30b6\u30fc\u30ac\u30a4\u30c9\u306a\u3069\u306f\u3001<code style="font-weight:bold">http://activityworkshop.net/</code>\u3092\u898b\u3066\u304f\u3060\u3055\u3044\u3002
 dialog.about.languages=\u5229\u7528\u53ef\u80fd\u306a\u8a00\u8a9e
@@ -296,7 +296,7 @@ dialog.about.systeminfo.gnuplot=Gnuplot \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u6e
 dialog.about.yes=\u306f\u3044
 dialog.about.no=\u3044\u3044\u3048
 dialog.about.credits=\u30af\u30ec\u30b8\u30c3\u30c8
-dialog.about.credits.code=Prune \u306e\u30b3\u30fc\u30c9\u306e\u4f5c\u8005
+dialog.about.credits.code=GpsPrune \u306e\u30b3\u30fc\u30c9\u306e\u4f5c\u8005
 dialog.about.credits.exifcode=Exif \u306e\u30b3\u30fc\u30c9\u306e\u4f5c\u8005
 dialog.about.credits.icons=\u3044\u304f\u3064\u304b\u306e\u30a2\u30a4\u30b3\u30f3
 dialog.about.credits.translators=\u7ffb\u8a33\u8005
@@ -306,12 +306,12 @@ dialog.about.credits.othertools=\u305d\u306e\u4ed6\u30c4\u30fc\u30eb
 dialog.about.credits.thanks=\u611f\u8b1d
 dialog.about.readme=\u521d\u3081\u306b\u8aad\u3093\u3067\u304f\u3060\u3055\u3044
 dialog.checkversion.error=\u30d0\u30fc\u30b8\u30e7\u30f3\u756a\u53f7\u304c\u30c1\u30a7\u30c3\u30af\u3067\u304d\u307e\u305b\u3093\u3002\n\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u63a5\u7d9a\u306e\u78ba\u8a8d\u3092\u3057\u3066\u304f\u3060\u3055\u3044\u3002
-dialog.checkversion.uptodate=\u3042\u306a\u305f\u306f\u6700\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306ePrune\u3092\u4f7f\u3063\u3066\u3044\u307e\u3059\u3002
-dialog.checkversion.newversion1=\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306e Prune \u304c\u5165\u624b\u53ef\u80fd\u3067\u3059\u3002\u6700\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306f\u73fe\u5728
+dialog.checkversion.uptodate=\u3042\u306a\u305f\u306f\u6700\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306eGpsPrune\u3092\u4f7f\u3063\u3066\u3044\u307e\u3059\u3002
+dialog.checkversion.newversion1=\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306e GpsPrune \u304c\u5165\u624b\u53ef\u80fd\u3067\u3059\u3002\u6700\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306f\u73fe\u5728
 dialog.checkversion.newversion2=\u3067\u3059\u3002
 dialog.checkversion.releasedate1=\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306f\u3001
 dialog.checkversion.releasedate2=\u306b\u30ea\u30ea\u30fc\u30b9\u3057\u307e\u3057\u305f\u3002
-dialog.checkversion.download=\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3059\u308b\u306b\u306f\u3001 http://activityworkshop.net/software/prune/download.html \u3078\u884c\u3063\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.checkversion.download=\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3059\u308b\u306b\u306f\u3001 http://activityworkshop.net/software/gpsprune/download.html \u3078\u884c\u3063\u3066\u304f\u3060\u3055\u3044\u3002
 dialog.keys.intro=\u30de\u30a6\u30b9\u306e\u4ee3\u308f\u308a\u306b\u6b21\u306e\u30b7\u30e7\u30fc\u30c8\u30ab\u30c3\u30c8\u30ad\u30fc\u3092\u4f7f\u3046\u4e8b\u304c\u3067\u304d\u307e\u3059\u3002
 dialog.keys.keylist=<table><tr><td>\u77e2\u5370\u30ad\u30fc</td><td>\u5730\u56f3\u3092\u4e0a\u4e0b\u5de6\u53f3\u306b\u79fb\u52d5</td></tr><tr><td>Ctrl + \u5de6\u30fb\u53f3\u77e2\u5370</td><td>\u524d\u30fb\u6b21\u306e\u70b9\u3092\u9078\u629e</td></tr><tr><td>Ctrl + \u4e0a\u30fb\u4e0b\u77e2\u5370</td><td>\u62e1\u5927\u30fb\u7e2e\u5c0f</td></tr><tr><td>Del</td><td>\u73fe\u5728\u306e\u70b9\u3092\u524a\u9664</td></tr></table>
 dialog.saveconfig.desc=\u4e0b\u8a18\u306e\u8a2d\u5b9a\u304c\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306b\u4fdd\u5b58\u3055\u308c\u307e\u3059
@@ -349,14 +349,14 @@ dialog.colourchooser.red=\u8d64
 dialog.colourchooser.green=\u7dd1
 dialog.colourchooser.blue=\u9752
 dialog.setlanguage.firstintro=\u642d\u8f09\u3055\u308c\u3066\u3044\u308b\u8a00\u8a9e\u306e\u4e00\u3064\u3092\u9078\u3076\u304b\u3001<p>\u4ee3\u308f\u308a\u306b\u4f7f\u3046\u30c6\u30ad\u30b9\u30c8\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u3073\u307e\u3059\u3002
-dialog.setlanguage.secondintro=\u8a00\u8a9e\u3092\u5207\u308a\u66ff\u3048\u308b\u306b\u306f\u3001\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u3066<p>Prune \u3092\u518d\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.setlanguage.secondintro=\u8a00\u8a9e\u3092\u5207\u308a\u66ff\u3048\u308b\u306b\u306f\u3001\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u3066<p>GpsPrune \u3092\u518d\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002
 dialog.setlanguage.language=\u8a00\u8a9e
 dialog.setlanguage.languagefile=\u8a00\u8a9e\u30d5\u30a1\u30a4\u30eb
-dialog.setlanguage.endmessage=\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u3001\u8a00\u8a9e\u306e\u5909\u66f4\u3092\u6709\u52b9\u306b\u3059\u308b\u305f\u3081\u306b\nPrune \u3092\u518d\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.setlanguage.endmessage=\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u3001\u8a00\u8a9e\u306e\u5909\u66f4\u3092\u6709\u52b9\u306b\u3059\u308b\u305f\u3081\u306b\nGpsPrune \u3092\u518d\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002
 
 # 3d window
-dialog.3d.title=Prune 3D \u8868\u793a
-dialog.3dlines.title=Prune \u683c\u5b50\u7dda
+dialog.3d.title=GpsPrune 3D \u8868\u793a
+dialog.3dlines.title=GpsPrune \u683c\u5b50\u7dda
 dialog.3dlines.empty=\u683c\u5b50\u7dda\u304c\u8868\u793a\u3055\u308c\u307e\u305b\u3093
 dialog.3dlines.intro=\u3053\u308c\u3089\u304c 3D \u8868\u793a\u7528\u306e\u683c\u5b50\u7dda\u3067\u3059\u3002
 
@@ -569,5 +569,5 @@ error.3d=3D \u8868\u793a\u3067\u30a8\u30e9\u30fc\u304c\u8d77\u304d\u307e\u3057\u
 error.readme.notfound=Readme \u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
 error.osmimage.dialogtitle=\u5730\u56f3\u753b\u50cf\u3092\u8aad\u307f\u8fbc\u307f\u6642\u306e\u30a8\u30e9\u30fc
 error.osmimage.failed=\u5730\u56f3\u753b\u50cf\u3092\u8aad\u307f\u8fbc\u307f\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u63a5\u7d9a\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002
-error.language.wrongfile=\u9078\u629e\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb\u306fPrune \u7528\u306e\u8a00\u8a9e\u30d5\u30a1\u30a4\u30eb\u306b\u898b\u3048\u307e\u305b\u3093\u3002
+error.language.wrongfile=\u9078\u629e\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb\u306fGpsPrune \u7528\u306e\u8a00\u8a9e\u30d5\u30a1\u30a4\u30eb\u306b\u898b\u3048\u307e\u305b\u3093\u3002
 error.convertnamestotimes.nonames=\u3069\u306e\u540d\u524d\u3082\u6642\u9593\u306b\u5909\u63db\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002
index eb4ef927c7ca02bd3b7f6926ffc18d059ae81d8d..be9b40e0669226c3b91d701233c7d4fca40d28e6 100644 (file)
@@ -1,4 +1,4 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Korean entries thanks to HooAU
 
 # Menu entries
@@ -122,13 +122,13 @@ function.playaudio=\uc18c\ub9ac\ud30c\uc77c \uc7ac\uc0dd
 function.stopaudio=\uc18c\ub9ac\ud30c\uc77c \uba48\ucda4
 function.help=\ub3c4\uc6c0\ub9d0
 function.showkeys=\ub2e8\ucd95\ud0a4 \ubcf4\uae30
-function.about=Prune \uc815\ubcf4
+function.about=GpsPrune \uc815\ubcf4
 function.checkversion=\uc0c8\ubc84\uc804\uc774 \uc788\ub294\uc9c0 \uac80\uc0ac
 function.saveconfig=\uc124\uc815 \uc800\uc7a5\ud558\uae30
 function.diskcache=\ub514\uc2a4\ud06c\uc5d0 \ub9f5 \uc800\uc7a5
 
 # Dialogs
-dialog.exit.confirm.title=Prune \uc885\ub8cc
+dialog.exit.confirm.title=GpsPrune \uc885\ub8cc
 dialog.exit.confirm.text=\ub370\uc774\ud0c0\uac00 \uc800\uc7a5\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. \uadf8\ub798\ub3c4 \ub098\uac00\uc2dc\uac8c\uc2b5\ub2c8\uae4c?
 dialog.openappend.title=\ub370\uc774\ud130 \ucd94\uac00\ud558\uae30
 dialog.openappend.text=\uc774\uc804\uc5d0 \ubd88\ub7ec\uc628 \ub370\uc774\ud0c0\ub85c \ucd94\uac00\ud558\uae30\uaca0\uc2b5\ub2c8\uae4c?
@@ -345,10 +345,10 @@ dialog.compress.summarylabel=\uc0ad\uc81c\ud560 \uc9c0\uc810
 dialog.pastecoordinates.desc=\uc790\ud45c\ub97c \ub123\uc73c\uc138\uc694
 dialog.pastecoordinates.coords=\uc88c\ud45c
 dialog.pastecoordinates.nothingfound=\uc88c\ud45c\ub97c \ud655\uc778\ud558\uc2dc\uace0 \ub2e4\uc2dc \uc2dc\ub3c4\ud574 \ubcf4\uc138\uc694.
-dialog.help.help=http://activityworkshop.net/software/prun
+dialog.help.help=\ub354 \uc790\uc138\ud55c \uc815\ubcf4\ub098 \uc0ac\uc6a9\uc790\uc124\uba85\uc740 \uc774\uacf3\uc744 \ucc38\uace0\ud574\uc8fc\uc138\uc694.\n http://activityworkshop.net/software/gpsprune/
 dialog.about.version=\ubc84\uc804
 dialog.about.build=\ube4c\ub4dc
-dialog.about.summarytext1=Prune\uc740 GPS\uc218\uc2e0\uae30\uc5d0\uc11c \uc704\uce58 \uc815\ubcf4\ub97c \ubc1b\uace0, \ud654\uba74\uc5d0 \ubcf4\uc5ec\uc8fc\uace0, \uc218\uc815\ud558\uac8c \ud574\uc8fc\ub294 \ud504\ub85c\uadf8\ub7a8\uc785\ub2c8\ub2e4.
+dialog.about.summarytext1=GpsPrune\uc740 GPS\uc218\uc2e0\uae30\uc5d0\uc11c \uc704\uce58 \uc815\ubcf4\ub97c \ubc1b\uace0, \ud654\uba74\uc5d0 \ubcf4\uc5ec\uc8fc\uace0, \uc218\uc815\ud558\uac8c \ud574\uc8fc\ub294 \ud504\ub85c\uadf8\ub7a8\uc785\ub2c8\ub2e4.
 dialog.about.summarytext2=\uc774 \ud504\ub85c\uadf8\ub7a8\uc740 \uc790\uc720\ub86d\uac8c, \uac1c\ubc29\uc801\uc73c\ub85c, \uadf8\ub9ac\uace0 \uc804\uc138\uacc4\uc801\uc73c\ub85c \uc0ac\uc6a9\ud558\uace0 \uac1c\uc120\ud558\uae30 \uc704\ud574 Gnu GPL \uc5d0 \ub530\ub77c\uc11c \ubc30\ud3ec\ub429\ub2c8\ub2e4. <br> \uc774 \ud504\ub85c\uadf8\ub7a8\uc5d0 \ud3ec\ud568\ub41c <code>license.txt</code> \ud30c\uc77c\uc758 \uc870\uac74\uc5d0 \ub530\ub77c \ubcf5\uc81c, \uc7ac\ubc30\ud3ec, \uc218\uc815\uc774 \ud5c8\uac00\ub418\uace0, \uc7a5\ub824\ub429\ub2c8\ub2e4.
 dialog.about.summarytext3=\ub354 \uc790\uc138\ud55c \uc815\ubcf4\ub098 \uc0ac\uc6a9\uc790\uc124\uba85\uc740 \uc774\uacf3\uc744 \ucc38\uace0\ud574\uc8fc\uc138\uc694.<code style="font-weight:bold">http://activityworkshop.net/</code></span>
 dialog.about.languages=\uc0ac\uc6a9 \uac00\ub2a5\ud55c \uc5b8\uc5b4\ub4e4
@@ -369,7 +369,7 @@ dialog.about.systeminfo.exiflib.external.failed=\uc678\uc7a5(\ucc3e\uc9c0\ubabb\
 dialog.about.yes=\uc608
 dialog.about.no=\uc544\ub2c8\uc624
 dialog.about.credits=\uc5d0\uac8c \uac10\uc0ac\ub97c
-dialog.about.credits.code=Prune \ucf54\ub4dc\ub97c \uc791\uc131\ud574\uc900
+dialog.about.credits.code=GpsPrune \ucf54\ub4dc\ub97c \uc791\uc131\ud574\uc900
 dialog.about.credits.exifcode=Exif \ucf54\ub4dc\ub97c \uc791\uc131\ud574\uc900
 dialog.about.credits.icons=\uc77c\ubd80 \uc544\uc774\ucf58\uc744 \uac00\uc838\uc628
 dialog.about.credits.translators=\ubc88\uc5ed\uc790\ub4e4
@@ -379,12 +379,12 @@ dialog.about.credits.othertools=\ub2e4\ub978 \ub3c4\uad6c\ub4e4
 dialog.about.credits.thanks=\uac10\uc0ac\ud569\ub2c8\ub2e4.
 dialog.about.readme=\uc77d\uc5b4\uc8fc\uc138\uc694
 dialog.checkversion.error=\ubc84\uc804\uc774 \ud655\uc778\ub418\uc9c0 \uc54a\uc558\uc5b4\uc694./n \uc778\ud130\ub137 \uc5f0\uacb0\uc744 \ud655\uc778\ud574\uc8fc\uc138\uc694.
-dialog.checkversion.uptodate=\ub2f9\uc2e0\uc740 Prune\uc758 \ucd5c\uc2e0 \ubc84\uc804\uc744 \uc0ac\uc6a9\ud558\uace0 \uacc4\uc2ed\ub2c8\ub2e4.
-dialog.checkversion.newversion1=Prune\uc758 \uc0c8 \ubc84\uc804\uc744 \uc9c0\uae08 \uc0ac\uc6a9\ud560 \uc218 \uc788\uaca0\ub124\uc694. \ucd5c\uc2e0\ubc84\uc804\uc740
+dialog.checkversion.uptodate=\ub2f9\uc2e0\uc740 GpsPrune\uc758 \ucd5c\uc2e0 \ubc84\uc804\uc744 \uc0ac\uc6a9\ud558\uace0 \uacc4\uc2ed\ub2c8\ub2e4.
+dialog.checkversion.newversion1=GpsPrune\uc758 \uc0c8 \ubc84\uc804\uc744 \uc9c0\uae08 \uc0ac\uc6a9\ud560 \uc218 \uc788\uaca0\ub124\uc694. \ucd5c\uc2e0\ubc84\uc804\uc740
 dialog.checkversion.newversion2=\ubc84\uc804\uc785\ub2c8\ub2e4.
 dialog.checkversion.releasedate1=\uc0c8 \ubc84\uc804\uc740
 dialog.checkversion.releasedate2=\uc5d0 \ubc30\ud3ec\ub418\uc5c8\uc2b5\ub2c8\ub2e4.
-dialog.checkversion.download=\uc0c8 \ubc84\uc804\uc744 \ub2e4\uc6b4\ubc1b\uace0 \uc2f6\uc73c\uc138\uc694? \uadf8\ub7fc \uc544\ub798 URL\ub85c \uc640\uc8fc\uc138\uc694. /n http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=\uc0c8 \ubc84\uc804\uc744 \ub2e4\uc6b4\ubc1b\uace0 \uc2f6\uc73c\uc138\uc694? \uadf8\ub7fc \uc544\ub798 URL\ub85c \uc640\uc8fc\uc138\uc694. /n http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=\ub9c8\uc6b0\uc2a4\ub97c \uc0ac\uc6a9\ud558\uc9c0 \ub9c8\uc2dc\uace0 \uc544\ub798 \ub2e8\ucd95\ud0a4\ub97c \uc0ac\uc6a9\ud574\ubcf4\uc138\uc694.
 dialog.keys.keylist=<table><tr><td>\ud654\uc0b4\ud45c \ud0a4</td><td>\uc88c,\uc6b0,\uc544\ub798,\uc704\ub85c \uc9c0\ub3c4 \uc774\ub3d9</td></tr><tr><td>Ctrl + \uc67c\ucabd, \uc624\ub978\ucabd \ud654\uc0b4\ud45c</td><td>\uc9c0\uc810 \uc120\ud0dd \uc774\ub3d9</td></tr><tr><td>Ctrl + \uc704, \uc544\ub798 \ud654\uc0b4\ud45c</td><td>\uc9c0\ub3c4 \ud655\ub300 \ucd95\uc18c</td></tr><tr><td>Ctrl + PgUp, PgDown</td><td>\uc774\uc804 \uc774\ud6c4 \ubd80\ubd84 \uc120\ud0dd</td></tr><tr><td>Ctrl + Home, End</td><td>\ucc98\uc74c \uc9c0\uc810, \ub9c8\uc9c0\ub9c9 \uc9c0\uc810 \uc120\ud0dd</td></tr><tr><td>Del</td><td>\ud604\uc7ac \uc9c0\uc810 \uc0ad\uc81c</td></tr></table>
 dialog.keys.normalmodifier=Ctrl
@@ -428,10 +428,10 @@ dialog.colourchooser.red=\ube68\uac15
 dialog.colourchooser.green=\ub179\uc0c9
 dialog.colourchooser.blue=\ud30c\ub791
 dialog.setlanguage.firstintro=\ud3ec\ud568\ub41c \uc5b8\uc5b4\ub4e4 \uc911 \ud558\ub098\ub97c \uc120\ud0dd\ud558\uc2e4 \uc218 \uc788\uc5b4\uc694,<p> \ud639\uc740 \ub300\uc2e0 \uc0ac\uc6a9\ud560 \ud14d\uc2a4\ud2b8 \ud30c\uc77c\uc744 \uc120\ud0dd\ud558\uc138\uc694.
-dialog.setlanguage.secondintro=\uc124\uc815\uc744 \uc800\uc7a5\ud558\uace0, <p> \uc5b8\uc5b4\ub97c \ubc14\uafb8\uae30\uc704\ud574\uc11c\ub294 Prune\uc744 \uc7ac\uc2dc\uc791\ud558\uc154\uc57c \ud574\uc694.
+dialog.setlanguage.secondintro=\uc124\uc815\uc744 \uc800\uc7a5\ud558\uace0, <p> \uc5b8\uc5b4\ub97c \ubc14\uafb8\uae30\uc704\ud574\uc11c\ub294 GpsPrune\uc744 \uc7ac\uc2dc\uc791\ud558\uc154\uc57c \ud574\uc694.
 dialog.setlanguage.language=\uc5b8\uc5b4
 dialog.setlanguage.languagefile=\uc5b8\uc5b4 \ud30c\uc77c
-dialog.setlanguage.endmessage=\ubcc0\uacbd\ub41c \uc5b8\uc5b4\ub97c \uc801\uc6a9\ud558\uc2e4\ub824\uba74/n\uc124\uc815\uc744 \uc800\uc7a5\ud558\uace0 Prune\uc744 \uc7ac\uc2dc\uc791\ud558\uc138\uc694.
+dialog.setlanguage.endmessage=\ubcc0\uacbd\ub41c \uc5b8\uc5b4\ub97c \uc801\uc6a9\ud558\uc2e4\ub824\uba74/n\uc124\uc815\uc744 \uc800\uc7a5\ud558\uace0 GpsPrune\uc744 \uc7ac\uc2dc\uc791\ud558\uc138\uc694.
 dialog.diskcache.save=\ub514\uc2a4\ud06c\ub85c \uc9c0\ub3c4 \uc774\ubbf8\uc9c0\ub97c \uc800\uc7a5
 dialog.diskcache.dir=\uce90\uc2dc \ub514\ub809\ud1a0\ub9ac
 dialog.diskcache.createdir=\ub514\ub809\ud1a0\ub9ac \ub9cc\ub4e4\uae30
@@ -442,9 +442,9 @@ dialog.downloadosm.desc=\ud2b9\uc815\uc9c0\uc5ed\uc758 raw OSM \ub370\uc774\ud13
 dialog.searchwikipedianames.search=\ucc3e\uae30
 
 # 3d window
-dialog.3d.title=Prune 3D \ubcf4\uae30
+dialog.3d.title=GpsPrune 3D \ubcf4\uae30
 dialog.3d.altitudefactor=\uace0\ub3c4 \uacfc\uc7a5 \uacc4\uc218
-dialog.3dlines.title=Prune \uaca9\uc790\uc120
+dialog.3dlines.title=GpsPrune \uaca9\uc790\uc120
 dialog.3dlines.empty=\uaca9\uc790\uc120 \uc5c6\uc774 \ud45c\uc2dc\ud558\uae30
 dialog.3dlines.intro=3D \ubcf4\uae30\ub97c \uc704\ud55c \uaca9\uc790\uc120\uc785\ub2c8\ub2e4.
 
@@ -684,7 +684,7 @@ error.3d=3D \ud45c\uc2dc\ud558\ub2e4\uac00 \uc5d0\ub7ec\ubc1c\uc0dd
 error.readme.notfound=Readme \ud30c\uc77c\uc744 \ubabb \ucc3e\uc74c
 error.osmimage.dialogtitle=\uc9c0\ub3c4 \uc774\ubbf8\uc9c0 \ubd88\ub7ec\uc624\uae30\uc911 \uc624\ub958
 error.osmimage.failed=\uc9c0\ub3c4 \uc774\ubbf8\uc9c0 \ubd88\ub7ec\uc624\uae30 \uc2e4\ud328./n\uc778\ud130\ub137 \uc5f0\uacb0\uc744 \ud655\uc778\ud574\uc8fc\uc138\uc694.
-error.language.wrongfile=\uc120\ud0dd\ud558\uc2e0 \ud30c\uc77c\uc774 Prune\uc744 \uc704\ud55c \uc5b8\uc5b4\ud30c\uc77c\uc774 \uc544\ub2cc\uac70 \uac19\uc544\uc694.
+error.language.wrongfile=\uc120\ud0dd\ud558\uc2e0 \ud30c\uc77c\uc774 GpsPrune\uc744 \uc704\ud55c \uc5b8\uc5b4\ud30c\uc77c\uc774 \uc544\ub2cc\uac70 \uac19\uc544\uc694.
 error.convertnamestotimes.nonames=\uc774\ub984\uc744 \uc2dc\uac04\uc73c\ub85c \ubcc0\ud658 \ud560 \uc218 \uc5c6\uc5b4\uc694./n(\uacbd\uc720\uc9c0\uc774\ub984\uc744 \ucc3e\uc9c0 \ubabb\ud588\uac70\ub098 \ubcc0\ud658\ud560 \uc218 \uc5c6\ub294 \uacbd\uc6b0\uc5d0\uc694.)
 error.lookupsrtm.nonefound=\uc774 \uc9c0\uc810\ub4e4\uc5d0\uc11c \uace0\ub3c4\uac12\uc744 \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc5b4\uc694./n\uc774 \uc601\uc5ed\uc5d0\uc11c \ud0c0\uc77c\uc774 \uc5c6\uac70\ub098, \uc790\ub8cc\uac00 \uc54c\uc218 \uc5c6\ub294 \uac83\ub4e4\uc744 \ud3ec\ud568\ud558\uace0 \uc788\ub294 \uacbd\uc720.
 error.lookupsrtm.nonerequired=\ubaa8\ub4e0 \uc9c0\uc810\uc774 \uace0\ub3c4 \uc815\ubcf4\uac00 \uc788\uc5b4\uc11c, \ucc3e\uc744\uac8c \uc544\ubb34\uac83\ub3c4 \uc5c6\ub124\uc694.
index 162b160f1c539255f5f8e6b0b9d5ed63af7f1528..ec9efa520c711a84237999e2cbd509197a8dd9d8 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Dutch entries as extra
 
 # Menu entries
 menu.file=Bestand
 menu.file.addphotos=Foto's toevoegen
+menu.file.recentfiles=Onlangs geopend
 menu.file.save=Opslaan als tekst
 menu.file.exit=Afsluiten
 menu.track=Route
@@ -41,6 +42,7 @@ menu.view.browser.yahoo=Yahoo maps
 menu.view.browser.bing=Bing maps
 menu.settings=Instellingen
 menu.settings.onlinemode=Kaarten van internet ophalen
+menu.settings.autosave=Automatisch opslaan bij afsluiten
 menu.help=Help
 # Popup menu for map
 menu.map.zoomin=Zoom +
@@ -75,6 +77,7 @@ shortcut.menu.help.help=H
 
 # Functions
 function.open=Open bestand
+function.importwithgpsbabel=Bestand importeren met GPSBabel
 function.loadfromgps=Gegevens lezen van GPS
 function.sendtogps=Gegevens verzenden naar GPS
 function.exportkml=Export KML
@@ -122,13 +125,14 @@ function.playaudio=Afspelen audiobestand
 function.stopaudio=Stop audiobestand
 function.help=Help
 function.showkeys=Toon sneltoetsen
-function.about=Over Prune
+function.about=Over GpsPrune
 function.checkversion=Controleer op nieuwe versie
 function.saveconfig=Instellingen opslaan
 function.diskcache=Kaart opslaan op schijf
+function.managetilecache=Beheer tegelcache
 
 # Dialogs
-dialog.exit.confirm.title=Prune afsluiten
+dialog.exit.confirm.title=GpsPrune afsluiten
 dialog.exit.confirm.text=Uw data is niet opgeslagen. Weet u zeker dat u wilt afsluiten?
 dialog.openappend.title=Toevoegen aan bestaande data
 dialog.openappend.text=Wilt u deze data toevoegen aan de reeds geladen data?
@@ -189,6 +193,9 @@ dialog.exportgpx.name=Naam
 dialog.exportgpx.desc=Omschrijving
 dialog.exportgpx.includetimestamps=Tijden meenemen
 dialog.exportgpx.copysource=Kopieer bron xml
+dialog.exportgpx.encoding=Coderen
+dialog.exportgpx.encoding.system=Systeem
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Geef parameters voor POV export
 dialog.exportpov.font=Lettertype
 dialog.exportpov.camerax=Camera X
@@ -341,14 +348,16 @@ dialog.compress.wackypoints.paramdesc=Afstandfactor
 dialog.compress.singletons.title=Singletons verwijderen
 dialog.compress.singletons.paramdesc=Afstandfactor
 dialog.compress.duplicates.title=Verwijderen duplicaten
+dialog.compress.douglaspeucker.title=Douglas-Peucker compressie
+dialog.compress.douglaspeucker.paramdesc=Span factor
 dialog.compress.summarylabel=Te verwijderen punten
 dialog.pastecoordinates.desc=Geef co\u00f6rdinaten in
 dialog.pastecoordinates.coords=Co\u00f6rdinaten
 dialog.pastecoordinates.nothingfound=Controleer de co\u00f6rdinaten en probeer het nogmaals
-dialog.help.help=Ga naar\n http://activityworkshop.net/software/prune/\nvoor meer informatie en handleidingen.
+dialog.help.help=Ga naar\n http://activityworkshop.net/software/gpsprune/\nvoor meer informatie en handleidingen.
 dialog.about.version=Versie
 dialog.about.build=Build
-dialog.about.summarytext1=Prune is een programma voor het laden, tonen en wijzigen van data uit GPS ontvangers.
+dialog.about.summarytext1=GpsPrune is een programma voor het laden, tonen en wijzigen van data uit GPS ontvangers.
 dialog.about.summarytext2=Uitgebracht onder de Gnu GPL voor gratis, open, wereldwijd gebruik en verbetering<br>Kopieren, verspreiding en aanpassing is toegestaan en aangemoedigd<br>volgens de voorwaarden in het bestand <code>license.txt</code>.
 dialog.about.summarytext3=Ga naar <code style="font-weight:bold">http://activityworkshop.net/</code> voor meer informatie en handleidingen.
 dialog.about.languages=Beschikbare talen
@@ -369,7 +378,7 @@ dialog.about.systeminfo.exiflib.external.failed=Extern (niet gevonden)
 dialog.about.yes=Ja
 dialog.about.no=Nee
 dialog.about.credits=Credits
-dialog.about.credits.code=Prune code geschreven door
+dialog.about.credits.code=GpsPrune code geschreven door
 dialog.about.credits.exifcode=Exif code door
 dialog.about.credits.icons=Sommige iconen overgenomen van
 dialog.about.credits.translators=Vertalers
@@ -379,12 +388,12 @@ dialog.about.credits.othertools=Overige tools
 dialog.about.credits.thanks=Dank aan
 dialog.about.readme=Leesmij
 dialog.checkversion.error=Versienummer kon niet worden gecontroleerd.\nControleer de internetverbinding.
-dialog.checkversion.uptodate=U gebruikt de laatste versie van Prune.
-dialog.checkversion.newversion1=Een nieuwe versie van Prune is beschikbaar. De nieuwste versie is nu versie
+dialog.checkversion.uptodate=U gebruikt de laatste versie van GpsPrune.
+dialog.checkversion.newversion1=Een nieuwe versie van GpsPrune is beschikbaar. De nieuwste versie is nu versie
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=Deze nieuwe versie was vrijgegeven op
 dialog.checkversion.releasedate2=.
-dialog.checkversion.download=Om de nieuwst versie te downloaden, ga naar http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=Om de nieuwst versie te downloaden, ga naar http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=De volgende sneltoetsen vervangen muisacties
 dialog.keys.keylist=<table><tr><td>Pijltjestoetsen</td><td>verschuif de kaart links, rechts, omhoog, omlaag</td></tr><tr><td>Ctrl + pijltje naar links, rechts</td><td>Selecteer volgende, vorige punt</td></tr><tr><td>Ctrl + pijltje omhoog, omlaag</td><td>Zoom in of uit</td></tr><tr><td>Ctrl + PgUp, PgDown</td><td>Selecteer vorig, volgend segment</td></tr><tr><td>Ctrl + Home, End</td><td>Select eerste, laatste punt</td></tr><tr><td>Del</td><td>Verwijder huidige punt</td></tr></table>
 dialog.keys.normalmodifier=Ctrl
@@ -409,6 +418,7 @@ dialog.saveconfig.prune.kmzimageheight=KMZ afbeelding hoogte
 dialog.saveconfig.prune.colourscheme=Kleurenschema
 dialog.saveconfig.prune.linewidth=Lijndikte
 dialog.saveconfig.prune.kmltrackcolour=KML routekleur
+dialog.saveconfig.prune.autosavesettings=Instellingen automatisch opslaan
 dialog.setpaths.intro=Indien nodig kan je de paden naar externe applicaties kiezen:
 dialog.setpaths.found=Pad gevonden?
 dialog.addaltitude.noaltitudes=De geselecteerde reeks bevat geen hoogtes
@@ -428,23 +438,35 @@ dialog.colourchooser.red=Rood
 dialog.colourchooser.green=Groen
 dialog.colourchooser.blue=Blauw
 dialog.setlanguage.firstintro=U kunt kiezen uit \u00e9\u00e9n van de meegeleverde talen,<p>of selecteer een tekstbestand.
-dialog.setlanguage.secondintro=U dient uw instellingen op te slaan en<p>Prune te herstarten om de taal te kunnen wijzigen
+dialog.setlanguage.secondintro=U dient uw instellingen op te slaan en<p>GpsPrune te herstarten om de taal te kunnen wijzigen
 dialog.setlanguage.language=Taal
 dialog.setlanguage.languagefile=Taal bestand
-dialog.setlanguage.endmessage=Sla nu uw instellingen op en herstart Prune\nom de taalwijziging te activeren
+dialog.setlanguage.endmessage=Sla nu uw instellingen op en herstart GpsPrune\nom de taalwijziging te activeren
+dialog.setlanguage.endmessagewithautosave=Herstart GpsPrune om te taalwijziging actief te maken.
 dialog.diskcache.save=Kaartafbeeldingen opslaan op schijf
 dialog.diskcache.dir=Cache map
 dialog.diskcache.createdir=Cre\u00eber map
 dialog.diskcache.nocreate=Cache map niet aangemaakt
+dialog.diskcache.table.path=Pad
+dialog.diskcache.table.usedby=Gebruikt door
+dialog.diskcache.table.zoom=Zoom
+dialog.diskcache.table.tiles=Tegels
+dialog.diskcache.table.megabytes=Megabytes
+dialog.diskcache.tileset=Tegelset
+dialog.diskcache.tileset.multiple=meerdere
+dialog.diskcache.deleteold=Verwijder oude tegels
+dialog.diskcache.deleteall=Verwijder alle tegels
+dialog.diskcache.deleted1=
+dialog.diskcache.deleted2=bestanden uit de cache verwijderd
 dialog.deletefieldvalues.intro=Selecteer het te verwijderen veld voor de huidige reeks
 dialog.setlinewidth.text=Geef lijndikte voor routes (1-4)
 dialog.downloadosm.desc=Bevestig het downloaden van ruwe OSM data voor dit gebied:
 dialog.searchwikipedianames.search=Zoeken naar:
 
 # 3d window
-dialog.3d.title=Prune in 3D
+dialog.3d.title=GpsPrune in 3D
 dialog.3d.altitudefactor=Hoogte overdrijvingsfactor
-dialog.3dlines.title=Prune raster
+dialog.3dlines.title=GpsPrune raster
 dialog.3dlines.empty=Geen raster om af te beelden
 dialog.3dlines.intro=Dit is het raster voor 3D
 
@@ -516,6 +538,7 @@ button.resettodefaults=Terug naar beginwaarden
 button.browse=Browse...
 button.addnew=Nieuwe toevoegen
 button.delete=Verwijderen
+button.manage=Beheer
 
 # File types
 filetype.txt=TXT bestand
@@ -567,6 +590,7 @@ details.lists.audio=Audio
 details.photodetails=Foto details
 details.nophoto=Geen foto geselecteerd
 details.photo.loading=Bezig met laden
+details.photo.bearing=Richting
 details.media.connected=Geconnecteerd
 details.audiodetails=Audio details
 details.noaudio=Geen audiobestand geselecteerd
@@ -590,6 +614,7 @@ fieldname.movingdistance=Snelheid in beweging
 fieldname.duration=Duur
 fieldname.speed=Snelheid
 fieldname.verticalspeed=Verticale snelheid
+fieldname.description=Omschrijving
 
 # Measurement units
 units.original=Oorspronkelijke
@@ -684,10 +709,13 @@ error.3d=Er is een fout opgetreden bij de 3d afbeelding
 error.readme.notfound=Leesmij bestand niet gevonden
 error.osmimage.dialogtitle=Fout bij inlezen kaart afbeeldingen
 error.osmimage.failed=Fout bij inlezen kaart afbeeldingen. Controleer je internet verbinding
-error.language.wrongfile=Het geselecteerde bestand is vermoedelijk geen taalbestand voor Prune
+error.language.wrongfile=Het geselecteerde bestand is vermoedelijk geen taalbestand voor GpsPrune
 error.convertnamestotimes.nonames=Namen konden niet naar tijden worden geconverteerd
 error.lookupsrtm.nonefound=Geen hoogtewaarden beschikbaar voor deze punten
 error.lookupsrtm.nonerequired=Alle punten hebben reeds hoogte, er hoeft niets te worden opgezocht.
 error.gpsies.uploadnotok=Gpsies server antwoordde met
 error.gpsies.uploadfailed=De upload is mislukt. Fout
 error.playaudiofailed=Kon audiobestand niet afspelen
+error.cache.notthere=De tegelcache map niet gevonden
+error.cache.empty=De tegelcache map is leeg
+error.cache.cannotdelete=Er konden geen tegels verwijderd worden
index 378c08db651f17b5810b42d9fa17c5d070b6f68d..c0f9982bc7518fbdc738a28867d56ba057b41f91 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Polish entries as extra
 
 # Menu entries
 menu.file=Plik
 menu.file.addphotos=Dodaj zdj\u0119cia
+menu.file.recentfiles=Ostatnio u\u017cywane
 menu.file.save=Zapisz
 menu.file.exit=Zako\u0144cz
 menu.track=\u015acie\u017cka
@@ -41,6 +42,7 @@ menu.view.browser.yahoo=Mapy Yahoo
 menu.view.browser.bing=Mapy Bing
 menu.settings=Ustawienia
 menu.settings.onlinemode=\u0141aduj mapy z sieci
+menu.settings.autosave=Autozapis ustawie\u0144 przy wyj\u015bciu
 menu.help=Pomoc
 # Popup menu for map
 menu.map.zoomin=Powi\u0119ksz
@@ -75,6 +77,7 @@ shortcut.menu.help.help=H
 
 # Functions
 function.open=Otw\u00f3rz
+function.importwithgpsbabel=Importuj plik z GPSBabel
 function.loadfromgps=\u0141aduj z GPS
 function.sendtogps=Wy\u015blij dane do urz\u0105dzenia GPS
 function.exportkml=Eksportuj KML
@@ -122,13 +125,14 @@ function.playaudio=Odtw\u00f3rz plik audio
 function.stopaudio=Zatrzymaj plik audio
 function.help=Pomoc
 function.showkeys=Poka\u017c klawisze skr\u00f3tu
-function.about=O Prune
+function.about=O GpsPrune
 function.checkversion=Sprawd\u017a czy jest nowa wersja
 function.saveconfig=Zapisz ustawienia
 function.diskcache=Zapisz mapy na dysk
+function.managetilecache=Zarz\u0105dzaj keszem p\u0142ytek
 
 # Dialogs
-dialog.exit.confirm.title=Zako\u0144cz Prune
+dialog.exit.confirm.title=Zako\u0144cz GpsPrune
 dialog.exit.confirm.text=Dane nie s\u0105 zapisane. Czy na pewno chcesz wyj\u015b\u0107?
 dialog.openappend.title=Dodaj do istniej\u0105cych danych
 dialog.openappend.text=Doda\u0107 dane do ju\u017c za\u0142adowanych?
@@ -189,6 +193,9 @@ dialog.exportgpx.name=Nazwa
 dialog.exportgpx.desc=Opis
 dialog.exportgpx.includetimestamps=Do\u0142\u0105cz znaczniki czasu
 dialog.exportgpx.copysource=Kopiuj \u017ar\u00f3d\u0142owy xml
+dialog.exportgpx.encoding=Kodowanie
+dialog.exportgpx.encoding.system=Systemowe
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Wprowad\u017a dodatkowe parametry eksportu do formatu POV
 dialog.exportpov.font=Czcionka
 dialog.exportpov.camerax=Kamera X
@@ -341,14 +348,16 @@ dialog.compress.wackypoints.paramdesc=Wsp\u00f3\u0142czynnik odleg\u0142o\u015bc
 dialog.compress.singletons.title=Usuwanie odosobnionych punkt\u00f3w
 dialog.compress.singletons.paramdesc=Wsp\u00f3\u0142czynnik odleg\u0142o\u015bci
 dialog.compress.duplicates.title=Usuwanie duplikat\u00f3w
+dialog.compress.douglaspeucker.title=kompresja Douglasa-Peuckera
+dialog.compress.douglaspeucker.paramdesc=wsp\u00f3\u0142czynnik rozpi\u0119to\u015bci (szeroko\u015bci korytarza)
 dialog.compress.summarylabel=Punkty do usuni\u0119cia
 dialog.pastecoordinates.desc=Wprowad\u017a lub wklej wsp\u00f3\u0142rz\u0119dne
 dialog.pastecoordinates.coords=Wsp\u00f3\u0142rz\u0119dne
 dialog.pastecoordinates.nothingfound=Sprawd\u017a wsp\u00f3\u0142rz\u0119dne i spr\u00f3buj jeszcze raz
-dialog.help.help=Na stronie\n http://activityworkshop.net/software/prune/ \nznajdziesz wi\u0119cej informacji oraz podr\u0119cznik u\u017cytkownika
+dialog.help.help=Na stronie\n http://activityworkshop.net/software/gpsprune/ \nznajdziesz wi\u0119cej informacji oraz podr\u0119cznik u\u017cytkownika
 dialog.about.version=Wersja
 dialog.about.build=Build
-dialog.about.summarytext1=Prune s\u0142u\u017cy do pobierania, wy\u015bwietlania i edycji danych z odbiornik\u00f3w GPS.
+dialog.about.summarytext1=GpsPrune s\u0142u\u017cy do pobierania, wy\u015bwietlania i edycji danych z odbiornik\u00f3w GPS.
 dialog.about.summarytext2=Ten program zosta\u0142 udost\u0119pniony na podstawie licencji GNU pozwalaj\u0105cej<br>na jego wolne, nieograniczone i og\u00f3lno\u015bwiatowe u\u017cytkowanie i rozszerzanie. <br>Kopiowanie, rozprowadzanie i modyfikowanie s\u0105 dozwolone i zalecane<br>zgodnie z warunkami zawartymi w do\u0142\u0105czonym pliku<code>license.txt</code>
 dialog.about.summarytext3=Na stronie <code style="font-weight:bold">http://activityworkshop.net/</code> znajdziesz wi\u0119cej informacji oraz podr\u0119cznik u\u017cytkownika.
 dialog.about.languages=Dost\u0119pne j\u0119zyki
@@ -369,7 +378,7 @@ dialog.about.systeminfo.exiflib.external.failed=Zewn\u0119trzny (nie znaleziony)
 dialog.about.yes=Tak
 dialog.about.no=Nie
 dialog.about.credits=Podzi\u0119kowania
-dialog.about.credits.code=Kod Prune napisany przez
+dialog.about.credits.code=Kod GpsPrune napisany przez
 dialog.about.credits.exifcode=Kod Exif przez
 dialog.about.credits.icons=Niekt\u00f3re ikony z
 dialog.about.credits.translators=T\u0142umacze
@@ -379,12 +388,12 @@ dialog.about.credits.othertools=Inne narz\u0119dzia
 dialog.about.credits.thanks=Podzi\u0119kowania dla
 dialog.about.readme=Czytaj to
 dialog.checkversion.error=Nie mo\u017cna sprawdzi\u0107 numeru wersji.\nSprawd\u017a po\u0142\u0105czenie z internetem.
-dialog.checkversion.uptodate=U\u017cywasz najnowszej wersji Prune.
-dialog.checkversion.newversion1=Dost\u0119pna jest nowa wersja Prune! Najnowsz\u0105 wersj\u0105 jest wersja
+dialog.checkversion.uptodate=U\u017cywasz najnowszej wersji GpsPrune.
+dialog.checkversion.newversion1=Dost\u0119pna jest nowa wersja GpsPrune! Najnowsz\u0105 wersj\u0105 jest wersja
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=Nowa wersja zosta\u0142a opublikowana
 dialog.checkversion.releasedate2=.
-dialog.checkversion.download=Aby \u015bci\u0105gn\u0105\u0107 now\u0105 wersj\u0119 przejd\u017a na http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=Aby \u015bci\u0105gn\u0105\u0107 now\u0105 wersj\u0119 przejd\u017a na http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=U\u017cuwaj nast\u0119puj\u0105cych klawiszy skr\u00f3t\u00f3w zamiast myszki
 dialog.keys.keylist=<table><tr><td>klawisze strza\u0142ek</td><td>Przesuwa map\u0119 w lewo, w prawo, w g\u00f3r\u0119, w d\u00f3\u0142</td></tr><tr><td>Ctrl + lewa, prawa strza\u0142ka</td><td>Wybierz punkt poprzedni lub nast\u0119pny</td></tr><tr><td>Ctrl + strza\u0142ka w g\u00f3r\u0119, w d\u00f3\u0142</td><td>Powi\u0119ksz, pomniejsz</td></tr><tr><td>Del</td><td>Usun bie\u017c\u0105cy punkt</td></tr></table>
 dialog.keys.normalmodifier=Ctrl
@@ -409,6 +418,7 @@ dialog.saveconfig.prune.kmzimageheight=wysoko\u015b\u0107 obrazka w KMZ
 dialog.saveconfig.prune.colourscheme=Schemat kolor\u00f3w
 dialog.saveconfig.prune.linewidth=Szeroko\u015b\u0107 linii
 dialog.saveconfig.prune.kmltrackcolour=Kolor \u015bcie\u017cki w pliku KML
+dialog.saveconfig.prune.autosavesettings=ustawienia autozapisu
 dialog.setpaths.intro=Je\u015bli zachodzi tak potrzeba, mo\u017cesz wybra\u0107 \u015bcie\u017cki do aplikacji zewn\u0119trznych
 dialog.setpaths.found=Znalezione \u015bcie\u017cki?
 dialog.addaltitude.noaltitudes=Wybrany zakres nie zawiera danych o wysoko\u015bciach
@@ -428,21 +438,33 @@ dialog.colourchooser.red=Czerwony
 dialog.colourchooser.green=Zielony
 dialog.colourchooser.blue=Niebieski
 dialog.setlanguage.firstintro=Mo\u017cesz wybra\u0107 jeden z do\u0142\u0105czonych j\u0119zyk\u00f3w<p>Albo wybra\u0107 wybrany przez siebie plik tekstowy.
-dialog.setlanguage.secondintro=B\u0119dziesz musia\u0142 zapisa\u0107 ustawienia<p>i zrestartowa\u0107 Prune by zmieni\u0107 j\u0119zyk.
+dialog.setlanguage.secondintro=B\u0119dziesz musia\u0142 zapisa\u0107 ustawienia<p>i zrestartowa\u0107 GpsPrune by zmieni\u0107 j\u0119zyk.
 dialog.setlanguage.language=J\u0119zyk
 dialog.setlanguage.languagefile=Plik t\u0142umaczenia
-dialog.setlanguage.endmessage=Zapisz ustawienia i zrestartuj Prune\n by zmiana j\u0119zyka odnios\u0142a skutek.
+dialog.setlanguage.endmessage=Zapisz ustawienia i zrestartuj GpsPrune\n by zmiana j\u0119zyka odnios\u0142a skutek.
+dialog.setlanguage.endmessagewithautosave=Zrestartuj GpsPrune by zmiana j\u0119zyka odnios\u0142a skutek.
 dialog.diskcache.save=Zapisz mapy na dysk
 dialog.diskcache.dir=katalog pami\u0119ci podr\u0119cznej
 dialog.diskcache.createdir=stw\u00f3rz katalog
 dialog.diskcache.nocreate=Nie utworzono katalogu pami\u0119ci podr\u0119cznej
+dialog.diskcache.table.path=\u015acie\u017cka
+dialog.diskcache.table.usedby=u\u017cywane przez
+dialog.diskcache.table.zoom=Powi\u0119kszenie
+dialog.diskcache.table.tiles=p\u0142ytek
+dialog.diskcache.table.megabytes=megabajt\u00f3w
+dialog.diskcache.tileset=zestaw p\u0142ytek
+dialog.diskcache.tileset.multiple=wiele
+dialog.diskcache.deleteold=Usu\u0144 stare p\u0142ytki
+dialog.diskcache.deleteall=Usu\u0144 wszystkie p\u0142ytki
+dialog.diskcache.deleted1=Usuni\u0119to
+dialog.diskcache.deleted2=plik\u00f3w z kesza
 dialog.deletefieldvalues.intro=Wybierz pola do skasowania z wybranego zakresu
 dialog.setlinewidth.text=Wprowad\u017a grubo\u015b\u0107 linii do rysowania \u015bcie\u017cek
 dialog.downloadosm.desc=Potwierd\u017a \u015bci\u0105gni\u0119cie danych dla tego obszaru z OSM:
 dialog.searchwikipedianames.search=Szukaj
 
 # 3d window
-dialog.3d.title=Prune widok tr\u00f3jwymiarowy
+dialog.3d.title=GpsPrune widok tr\u00f3jwymiarowy
 dialog.3d.altitudefactor=Wsp\u00f3\u0142czynnik skalowania wysoko\u015bci
 dialog.3dlines.title=Linie siatki
 dialog.3dlines.empty=Brak siatki do wy\u015bwietlenia!
@@ -516,6 +538,7 @@ button.resettodefaults=Przywr\u00f3\u0107 domy\u015blne
 button.browse=Przegl\u0105daj...
 button.addnew=Dodaj nowy
 button.delete=Usu\u0144
+button.manage=Zarz\u0105dzaj
 
 # File types
 filetype.txt=Pliki TXT
@@ -567,6 +590,7 @@ details.lists.audio=Audio
 details.photodetails=Szczeg\u00f3\u0142y zdj\u0119cia
 details.nophoto=Brak zaznaczonego zdj\u0119cia
 details.photo.loading=Wczytywanie
+details.photo.bearing=Kierunek
 details.media.connected=Pod\u0142\u0105czony
 details.audiodetails=Szczeg\u00f3\u0142y audio
 details.noaudio=Brak zaznaczonego audio
@@ -590,6 +614,7 @@ fieldname.movingdistance=Odleg\u0142o\u015b\u0107 przesuni\u0119cia
 fieldname.duration=Czas trwania
 fieldname.speed=Pr\u0119dko\u015b\u0107
 fieldname.verticalspeed=Pr\u0119dko\u015b\u0107 pionowa
+fieldname.description=Opis
 
 # Measurement units
 units.original=Oryginalny
@@ -684,10 +709,13 @@ error.3d=Nast\u0105pi\u0142 b\u0142\u0105d z wy\u015bwietlaniem 3D
 error.readme.notfound=Nie znaleziono pliku Readme
 error.osmimage.dialogtitle=B\u0142\u0105d przy \u0142adowaniu obraz\u00f3w map
 error.osmimage.failed=B\u0142\u0105d przy \u0142adowaniu obraz\u00f3w map. Sprawd\u017a po\u0142\u0105czenie z internetem.
-error.language.wrongfile=Wybrany plik nie jest plikiem z t\u0142umaczeniem dla Prune
+error.language.wrongfile=Wybrany plik nie jest plikiem z t\u0142umaczeniem dla GpsPrune
 error.convertnamestotimes.nonames=\u017badne nazwy nie mog\u0142y zosta\u0107 zmienione na czas
 error.lookupsrtm.nonefound=Nie znaleziono danych o wysoko\u015bci.
 error.lookupsrtm.nonerequired=Wszystkie pola maj\u0105 informacj\u0119 o wysoko\u015bci, nie ma czego szuka\u0107
 error.gpsies.uploadnotok=Serwer Gpsies zwr\u00f3ci\u0142 informacj\u0119
 error.gpsies.uploadfailed=B\u0142\u0105d wysy\u0142ania
 error.playaudiofailed=Nie powiod\u0142o si\u0119 odtwarzanie pliku audio
+error.cache.notthere=Nie znaleziono katalogu kesza
+error.cache.empty=Katalog kesza jest pusty
+error.cache.cannotdelete=\u017badne p\u0142ytki nie mog\u0142y zosta\u0107 usuni\u0119te
index 8596b3900b607670fc6283e7b60c5bf29d608556..8d09afebe951cea13c9a4e85cbf24a450e6e86b4 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # (Brazilian) Portuguese entries as extra
 
 # Menu entries
 menu.file=Arquivo
 menu.file.addphotos=Adicionar fotos
+menu.file.recentfiles=Arquivos recentes
 menu.file.save=Salvar
 menu.file.exit=Sair
 menu.track=Rota
@@ -41,6 +42,7 @@ menu.view.browser.yahoo=Mapas do Yahoo
 menu.view.browser.bing=Mapas do Bing
 menu.settings=Configura\u00e7\u00f5es
 menu.settings.onlinemode=Carregar mapas da Internet
+menu.settings.autosave=Autosalvar configura\u00e7\u00f5es ao sair
 menu.help=Ajuda
 # Popup menu for map
 menu.map.zoomin=Ampliar
@@ -75,6 +77,7 @@ shortcut.menu.help.help=J
 
 # Functions
 function.open=Abrir
+function.importwithgpsbabel=Importar arquivo com GPSBabel
 function.loadfromgps=Carregar dados do GPS
 function.sendtogps=Enviar dados para o GPS
 function.exportkml=Exportar para KML
@@ -122,13 +125,14 @@ function.playaudio=Reproduzir arquivo de \u00e1udio
 function.stopaudio=Parar arquivo de \u00e1udio
 function.help=Ajuda
 function.showkeys=Mostrar atalhos de teclado
-function.about=Sobre o Prune
+function.about=Sobre o GpsPrune
 function.checkversion=Verificar novas vers\u00f5es
 function.saveconfig=Salvar configura\u00e7\u00f5es
 function.diskcache=Salvar mapas para o disco
+function.managetilecache=Gerenciar cache de fundos
 
 # Dialogs
-dialog.exit.confirm.title=Sair do Prune
+dialog.exit.confirm.title=Sair do GpsPrune
 dialog.exit.confirm.text=Seus dados n\u00e3o foram salvos. Voc\u00ea tem certeza que deseja sair?
 dialog.openappend.title=Adicionar aos dados existentes
 dialog.openappend.text=Adicionar estes dados aos dados j\u00e1 carregados?
@@ -189,6 +193,9 @@ dialog.exportgpx.name=Nome
 dialog.exportgpx.desc=Descri\u00e7\u00e3o
 dialog.exportgpx.includetimestamps=Incluir data-hora
 dialog.exportgpx.copysource=Copiar fonte xml
+dialog.exportgpx.encoding=Codifica\u00e7\u00e3o
+dialog.exportgpx.encoding.system=Sistema
+dialog.exportgpx.encoding.utf8=UTF-8
 dialog.exportpov.text=Por favor, insira os par\u00e2metros para a exporta\u00e7\u00e3o POV
 dialog.exportpov.font=Fonte
 dialog.exportpov.camerax=X da C\u00e2mera
@@ -335,20 +342,22 @@ dialog.rearrangephotos.sortbyfilename=Ordenar pelo nome do arquivo
 dialog.rearrangephotos.sortbytime=Ordenar pela hora
 dialog.compress.nonefound=Nenhum dado dos pontos pode ser removido
 dialog.compress.closepoints.title=Remo\u00e7\u00e3o de ponto pr\u00f3ximo
-dialog.compress.closepoints.paramdesc=Fator de 'span'
+dialog.compress.closepoints.paramdesc=Fator de deslocamento
 dialog.compress.wackypoints.title=Remo\u00e7\u00e3o de ponto exc\u00eantrica
 dialog.compress.wackypoints.paramdesc=Fator de dist\u00e3ncia
 dialog.compress.singletons.title=Remo\u00e7\u00e3o avulsa
 dialog.compress.singletons.paramdesc=Fator de dist\u00e2ncia
 dialog.compress.duplicates.title=Remo\u00e7\u00e3o de duplicado
+dialog.compress.douglaspeucker.title=Compress\u00e3o Douglas-Peucker
+dialog.compress.douglaspeucker.paramdesc=Fator de deslocamento
 dialog.compress.summarylabel=Pontos para remover
 dialog.pastecoordinates.desc=Insira ou cole as coordenadas aqui
 dialog.pastecoordinates.coords=Coordenadas
 dialog.pastecoordinates.nothingfound=Por favor, verifique as coordenadas novamente
-dialog.help.help=Por favor, veja\n http://activityworkshop.net/software/prune/\npara mais informa\u00e7\u00f5es e guia do usu\u00e1rio.
+dialog.help.help=Por favor, veja\n http://activityworkshop.net/software/gpsprune/\npara mais informa\u00e7\u00f5es e guia do usu\u00e1rio.
 dialog.about.version=Vers\u00e3o
 dialog.about.build=Compila\u00e7\u00e3o
-dialog.about.summarytext1=Prune \u00e9 um programa para carregar, exibir e editar dados de receptores de GPS.
+dialog.about.summarytext1=GpsPrune \u00e9 um programa para carregar, exibir e editar dados de receptores de GPS.
 dialog.about.summarytext2=Isto est\u00e1 lan\u00e7ado sob a Gnu GPL para uso e melhoria livre, aberto e em todo o mundo.<br>A c\u00f3pia, redistribui\u00e7\u00e3o e modifica\u00e7\u00e3o s\u00e3o permitidas e encorajadas<br>de acordo coma as condi\u00e7\u00f5es no arquivo <code>license.txt</code>inclu\u00eddo.
 dialog.about.summarytext3=Por favor, veja <code style="font-weight:bold">http://activityworkshop.net/</code> para mais informa\u00e7\u00f5es e guia do usu\u00e1rio.
 dialog.about.languages=Idiomas dispon\u00edveis
@@ -369,7 +378,7 @@ dialog.about.systeminfo.exiflib.external.failed=Externa (n\u00e3o encontrada)
 dialog.about.yes=Sim
 dialog.about.no=N\u00e3o
 dialog.about.credits=Cr\u00e9ditos
-dialog.about.credits.code=C\u00f3digo do Prune escrito por
+dialog.about.credits.code=C\u00f3digo do GpsPrune escrito por
 dialog.about.credits.exifcode=C\u00f3digo do Exif por
 dialog.about.credits.icons=Alguns \u00edcones obtidos de
 dialog.about.credits.translators=Tradutores
@@ -379,12 +388,12 @@ dialog.about.credits.othertools=Outras ferramentas
 dialog.about.credits.thanks=Agradecimentos a
 dialog.about.readme=Leiame
 dialog.checkversion.error=O n\u00famero da vers\u00e3o n\u00e3o pode ser verificado.\n Por favor, verifique a conex\u00e3o \u00e0 Internet.
-dialog.checkversion.uptodate=Voc\u00ea est\u00e1 usando a \u00faltima vers\u00e3o do Prune.
-dialog.checkversion.newversion1=Uma nova vers\u00e3o do Prune est\u00e1 dispon\u00edvel! A \u00faltima vers\u00e3o \u00e9 agora a vers\u00e3o
+dialog.checkversion.uptodate=Voc\u00ea est\u00e1 usando a \u00faltima vers\u00e3o do GpsPrune.
+dialog.checkversion.newversion1=Uma nova vers\u00e3o do GpsPrune est\u00e1 dispon\u00edvel! A \u00faltima vers\u00e3o \u00e9 agora a vers\u00e3o
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=Esta nova vers\u00e3o foi lan\u00e7ada em
 dialog.checkversion.releasedate2=.
-dialog.checkversion.download=Para baixar a nova vers\u00e3o, v\u00e1 para http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.download=Para baixar a nova vers\u00e3o, v\u00e1 para http://activityworkshop.net/software/gpsprune/download.html.
 dialog.keys.intro=Voc\u00ea pode usar os seguintes atalhos de teclado ao inv\u00e9s de usar o mouse
 dialog.keys.keylist=<table><tr><td>Cursores</td><td>Move o mapa para esquerda, direita, acima e abaixo</td></tr><tr><td>Ctrl + cursores esquerdo e direito</td><td>Seleciona o pr\u00f3ximo ponto ou o anterior</td></tr><tr><td>Ctrl + cursores acima e abaixo</td><td>Amplia ou reduz</td></tr><tr><td>Del</td><td>Remove o ponto atual</td></tr></table>
 dialog.keys.normalmodifier=Ctrl
@@ -409,6 +418,7 @@ dialog.saveconfig.prune.kmzimageheight=Altura da imagem KMZ
 dialog.saveconfig.prune.colourscheme=Esquema de cores
 dialog.saveconfig.prune.linewidth=Espessura da linha
 dialog.saveconfig.prune.kmltrackcolour=Cor da rota KML
+dialog.saveconfig.prune.autosavesettings=Configura\u00e7\u00f5es para salvamento autom\u00e1tico
 dialog.setpaths.intro=Se voc\u00ea precisar, voc\u00ea pode escolher os caminhos para as aplica\u00e7\u00f5es externas:
 dialog.setpaths.found=Caminho encontrado?
 dialog.addaltitude.noaltitudes=O intervalo selecionado n\u00e3o cont\u00e9m altitudes
@@ -428,23 +438,35 @@ dialog.colourchooser.red=Vermelho
 dialog.colourchooser.green=Verde
 dialog.colourchooser.blue=Azul
 dialog.setlanguage.firstintro=Voc\u00ea pode selecionar um dos idiomas inclu\u00eddos,<p>ou selecionar um arquivo de texto para usar.
-dialog.setlanguage.secondintro=Voc\u00ea precisa salvar suas configura\u00e7\u00f5es e ent\u00e3o<p>reiniciar o Prune para mudar o idioma.
+dialog.setlanguage.secondintro=Voc\u00ea precisa salvar suas configura\u00e7\u00f5es e ent\u00e3o<p>reiniciar o GpsPrune para mudar o idioma.
 dialog.setlanguage.language=Idioma
 dialog.setlanguage.languagefile=Arquivo de idioma
-dialog.setlanguage.endmessage=Agora salve suas configura\u00e7\u00f5es e reinicie o Prune\npara que a mudan\u00e7a de idioma ocorra.
+dialog.setlanguage.endmessage=Agora salve suas configura\u00e7\u00f5es e reinicie o GpsPrune\npara que a mudan\u00e7a de idioma ocorra.
+dialog.setlanguage.endmessagewithautosave=Por favor, reinicie o GpsPrune para que a mudan\u00e7a de idioma tenha efeito.
 dialog.diskcache.save=Salvar imagens do mapa para o disco
 dialog.diskcache.dir=Diret\u00f3rio da cache
 dialog.diskcache.createdir=Criar diret\u00f3rio
 dialog.diskcache.nocreate=Diret\u00f3rio da cache n\u00e3o foi criado
+dialog.diskcache.table.path=Caminho
+dialog.diskcache.table.usedby=Usado por
+dialog.diskcache.table.zoom=Zoom
+dialog.diskcache.table.tiles=Fundos
+dialog.diskcache.table.megabytes=Megabytes
+dialog.diskcache.tileset=Conjunto de fundos
+dialog.diskcache.tileset.multiple=m\u00faltiplos
+dialog.diskcache.deleteold=Apagar fundos antigos
+dialog.diskcache.deleteall=Apagar todos os fundos
+dialog.diskcache.deleted1=Removidos
+dialog.diskcache.deleted2=arquivos do cache
 dialog.deletefieldvalues.intro=Selecione o campo a remover para o intervalo atual
 dialog.setlinewidth.text=Insira a espessura das linhas para desenhar as rotas (1-4)
 dialog.downloadosm.desc=Confirmar a transfer\u00eancia de dados OSM brutos para a \u00e1rea especificada:
 dialog.searchwikipedianames.search=Procurar por:
 
 # 3d window
-dialog.3d.title=Vista 3D do Prune
+dialog.3d.title=Vista 3D do GpsPrune
 dialog.3d.altitudefactor=Fator de exagera\u00e7\u00e3o de altitude
-dialog.3dlines.title=Linhas da grade do Prune
+dialog.3dlines.title=Linhas da grade do GpsPrune
 dialog.3dlines.empty=Nenhuma linha de grade para exibir!
 dialog.3dlines.intro=Estas s\u00e3o as linhas da grade para a vista 3D.
 
@@ -516,6 +538,7 @@ button.resettodefaults=Restaurar para os padr\u00f5es
 button.browse=Navegar...
 button.addnew=Adicionar novo
 button.delete=Remover
+button.manage=Gerenciar
 
 # File types
 filetype.txt=Arquivos TXT
@@ -567,6 +590,7 @@ details.lists.audio=\u00c1udio
 details.photodetails=Detalhes da foto
 details.nophoto=Nenhuma foto selecionada
 details.photo.loading=Carregando
+details.photo.bearing=Apontando
 details.media.connected=Conectada
 details.audiodetails=Detalhes do \u00e1udio
 details.noaudio=Nenhum arquivo de \u00e1udio selecionado
@@ -590,6 +614,7 @@ fieldname.movingdistance=Dist\u00e2ncia de movimento
 fieldname.duration=Dura\u00e7\u00e3o
 fieldname.speed=Velocidade
 fieldname.verticalspeed=Velocidade vertical
+fieldname.description=Descri\u00e7\u00e3o
 
 # Measurement units
 units.original=Original
@@ -684,10 +709,13 @@ error.3d=Um erro ocorreu com a exibi\u00e7\u00e3o 3D
 error.readme.notfound=Arquivo Leiame n\u00e3o encontrado
 error.osmimage.dialogtitle=Erro ao carregar imagens do mapa
 error.osmimage.failed=Falha ao carregar imagens do mapa. Por favor, verifique a conex\u00e3o \u00e0 Internet.
-error.language.wrongfile=O arquivo selecionado n\u00e3o parece ser um arquivo de idioma do Prune
+error.language.wrongfile=O arquivo selecionado n\u00e3o parece ser um arquivo de idioma do GpsPrune
 error.convertnamestotimes.nonames=Nenhum nome pode ser convertido para tempo
 error.lookupsrtm.nonefound=Nenhum valor de altitude encontrado
 error.lookupsrtm.nonerequired=Todos os pontos j\u00e1 possuem altitude, assim n\u00e3o h\u00e1 nada a procurar
 error.gpsies.uploadnotok=O servidor Gpsies retornou a mensagem
 error.gpsies.uploadfailed=O envio falhou com o erro
 error.playaudiofailed=Falha ao reproduzir arquivo de \u00e1udio
+error.cache.notthere=A paste de cache de fundos n\u00e3o foi encontrada
+error.cache.empty=A pasta de cache de fundos est\u00e1 vazia
+error.cache.cannotdelete=Nenhum fundo pode ser removido
index f6dd8037966f4402e8c9f9e844fb5e90d78ff28f..cfb6a1794f794b74dd0976ddf4b0555768441fd7 100644 (file)
@@ -1,4 +1,4 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Romanian entries as extra
 
 # Menu entries
@@ -81,11 +81,11 @@ function.setcolours=Selectare culorile
 function.setlanguage=Selectare limba
 function.help=Ajutor
 function.showkeys=Arat\u0103 tastele scurt\u0103turi
-function.about=Despre Prune
+function.about=Despre GpsPrune
 function.checkversion=Verific\u0103 pentru o versiune noua
 
 # Dialogs
-dialog.exit.confirm.title=Ie\u015fire din programul Prune
+dialog.exit.confirm.title=Ie\u015fire din programul GpsPrune
 dialog.exit.confirm.text=Datele dumneavoastra nu sunt salvate.\nSunte\u0163i sigur ca\u0103 dori\u0163i s\u0103 ie\u015fiti?
 dialog.openappend.title=Adauga la datele existente
 dialog.openappend.text=Adauga la datele deja incarcate?
index ad0ea20062006078bca5d1d860187d1b99968916..81602655e35e29df63fe23bdd5be266c8ad4b0f9 100644 (file)
@@ -1,4 +1,4 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Turkish entries as extra
 
 # Menu entries
@@ -100,12 +100,12 @@ function.rotatephotoright=Fotoyu sa\u011fa d\u00f6nd\u00fcr
 function.ignoreexifthumb=Exif t\u0131rnak resmi bo\u015fver
 function.help=Yard\u0131m
 function.showkeys=K\u0131sayol tu\u015flar\u0131 g\u00f6ster
-function.about=Prune hakk\u0131nda
+function.about=GpsPrune hakk\u0131nda
 function.checkversion=Yeni s\u00fcr\u00fcm\u00fc i\u00e7in denetle
 function.saveconfig=Ayarlar\u0131 kaydet
 
 # Dialogs
-dialog.exit.confirm.title=Prune'dan \u00e7\u0131k
+dialog.exit.confirm.title=GpsPrune'dan \u00e7\u0131k
 dialog.exit.confirm.text=Ver\u0131 kaydetmedin -Ger\u00e7ekten \u00e7\u0131kmak istiyor musun?
 dialog.openappend.title=Varolan verisine ekle
 dialog.openappend.text=Append this data to the data already loaded?
@@ -231,12 +231,12 @@ dialog.correlate.options.offset.seconds=saniye
 dialog.correlate.options.photolater=Foto noktadan sonra
 dialog.correlate.options.pointlaterphoto=Nokta fotodan sonra
 dialog.pastecoordinates.coords=Koordinatlar
-dialog.help.help=Ayr\u0131nt\u0131l\u0131 bilgi ve kullanma k\u0131lavuzu i\u00e7in l\u00fctfen\n http://activityworkshop.net/software/prune/\n sitesinde bak.
+dialog.help.help=Ayr\u0131nt\u0131l\u0131 bilgi ve kullanma k\u0131lavuzu i\u00e7in l\u00fctfen\n http://activityworkshop.net/software/gpsprune/\n sitesinde bak.
 dialog.about.version=S\u00fcr\u00fcm
 dialog.about.build=Build
-dialog.about.summarytext1=Prune GPS ayg\u0131tlardan veri y\u00fckler, g\u00f6r\u00fcnt\u00fcler ver d\u00fczenler bir uygulamad\u0131r.
+dialog.about.summarytext1=GpsPrune GPS ayg\u0131tlardan veri y\u00fckler, g\u00f6r\u00fcnt\u00fcler ver d\u00fczenler bir uygulamad\u0131r.
 dialog.about.summarytext3=Ayr\u0131nt\u0131l\u0131 bilgi ve kullanma k\u0131lavuzu i\u00e7in l\u00fctfen\n <code style="font-weight:bold">http://activityworkshop.net/</code> sitesinde bak.
-dialog.about.languages=Prune ile kullanabilir diller
+dialog.about.languages=GpsPrune ile kullanabilir diller
 dialog.about.translatedby=Turkish text by katpatuka
 dialog.about.systeminfo=Sistem bilgisi
 dialog.about.systeminfo.os=\u0130\u015fletim Sistemi
@@ -251,12 +251,12 @@ dialog.about.no=Hay\u0131r
 dialog.about.credits.translators=Çevirmen
 dialog.about.credits.thanks=Te\u015fekk\u00fcrler
 dialog.about.readme=Beni oku
-dialog.checkversion.uptodate=Prune'nin so s\u00fcr\u00fcm\u00fc kullan\u0131yorsun.
-dialog.checkversion.newversion1=Prune'nin yeni bir s\u00fcr\u00fcm\u00fc \u00e7\u0131kt\u0131! Son s\u00fcr\u00fcm \u015fimdi
+dialog.checkversion.uptodate=GpsPrune'nin so s\u00fcr\u00fcm\u00fc kullan\u0131yorsun.
+dialog.checkversion.newversion1=GpsPrune'nin yeni bir s\u00fcr\u00fcm\u00fc \u00e7\u0131kt\u0131! Son s\u00fcr\u00fcm \u015fimdi
 dialog.checkversion.newversion2=.
 dialog.checkversion.releasedate1=Yeni s\u00fcr\u00fcm\u00fcn\u00fcn devir tarihi
 dialog.checkversion.releasedate2=.
-dialog.checkversion.download=Yeni s\u00fcr\u00fcm indirmek i\u00e7in http://activityworkshop.net/software/prune/download.html adresine git.
+dialog.checkversion.download=Yeni s\u00fcr\u00fcm indirmek i\u00e7in http://activityworkshop.net/software/gpsprune/download.html adresine git.
 dialog.keys.intro=Fare yerinde a\u015fa\u011f\u0131daki k\u0131sayol tu\u015flar\u0131 kullanabilirsin:
 dialog.keys.keylist=<table><tr><td>Ok tu\u015flar\u0131</td><td>Haritay\u0131 sola/sa\u011fa/a\u015fa\u011f\u0131/yukar\u0131 kayd\u0131r</td></tr><tr><td>Ctrl + sol, sa\u011f</td><td>\u00d6nceki/sonraki noktay\u0131 se\u00e7</td></tr><tr><td>Ctrl + yukar/a\u015fa\u011f\u0131</td><td>Yak\u0131nla\u015ft\u0131r/Uzakla\u015ft\u0131r</td></tr><tr><td>Del</td><td>Se\u00e7ili noltay\u0131 sil</td></tr></table>
 dialog.saveconfig.desc=A\u011fa\u015f\u0131daki ayarlar\u0131 bir dasyada kaydedilir:
index 4dfc88a02824453d1ccd536df507792105df65bf..290c1fe9b4dd1c8a79840e9c813e0813f220c36e 100644 (file)
@@ -1,9 +1,10 @@
-# Text entries for the Prune application
+# Text entries for the GpsPrune application
 # Chinese entries as extra
 
 # Menu entries
 menu.file=\u6587\u4ef6
 menu.file.addphotos=\u6dfb\u52a0\u76f8\u7247
+menu.file.recentfiles=\u6700\u8fd1\u6253\u5f00\u8fc7\u6587\u4ef6
 menu.file.save=\u4fdd\u5b58
 menu.file.exit=\u9000\u51fa
 menu.track=\u8f68\u8ff9
@@ -41,6 +42,7 @@ menu.view.browser.yahoo=Yahoo\u5730\u56fe
 menu.view.browser.bing=Bing(\u5fc5\u5e94\uff09\u5730\u56fe
 menu.settings=\u8bbe\u7f6e
 menu.settings.onlinemode=\u4ece\u7f51\u4e0a\u5bfc\u5165\u5730\u56fe
+menu.settings.autosave=\u9000\u51fa\u65f6\u81ea\u52a8\u4fdd\u5b58\u8bbe\u7f6e
 menu.help=\u5e2e\u52a9
 # Popup menu for map
 menu.map.zoomin=\u653e\u5927
@@ -53,8 +55,29 @@ menu.map.autopan=\u81ea\u52a8\u7f29\u653e
 menu.map.showmap=\u663e\u793a\u5730\u56fe
 menu.map.showscalebar=\u663e\u793a\u6bd4\u4f8b\u5c3a
 
+# Alt keys for menus
+altkey.menu.file=F
+altkey.menu.track=T
+altkey.menu.range=R
+altkey.menu.point=P
+altkey.menu.view=V
+altkey.menu.photo=O
+altkey.menu.audio=A
+altkey.menu.settings=S
+altkey.menu.help=H
+
+# Ctrl shortcuts for menu items
+shortcut.menu.file.open=O
+shortcut.menu.file.load=L
+shortcut.menu.file.save=S
+shortcut.menu.track.undo=Z
+shortcut.menu.edit.compress=C
+shortcut.menu.range.all=A
+shortcut.menu.help.help=H
+
 # Functions
 function.open=\u6253\u5f00
+function.importwithgpsbabel=\u7528GPSBabel\u5bfc\u5165\u6587\u4ef6
 function.loadfromgps=\u4eceGPS\u5bfc\u5165
 function.sendtogps=\u53d1\u9001\u81f3GPS
 function.exportkml=\u8f93\u51faKML\u6587\u4ef6
@@ -102,10 +125,11 @@ function.playaudio=\u64ad\u653e\u58f0\u97f3\u6587\u4ef6
 function.stopaudio=\u505c\u6b62\u64ad\u653e
 function.help=\u5e2e\u52a9
 function.showkeys=\u663e\u793a\u5feb\u6377\u952e
-function.about=\u5173\u4e8ePrune
+function.about=\u5173\u4e8eGpsPrune
 function.checkversion=\u68c0\u67e5\u66f4\u65b0
 function.saveconfig=\u4fdd\u5b58\u8bbe\u7f6e
 function.diskcache=\u4fdd\u5b58\u5730\u56fe
+function.managetilecache=\u7ba1\u7406\u5730\u56fe\u533a\u57df\u6570\u636e\u7f13\u5b58
 
 # Dialogs
 dialog.exit.confirm.title=\u9000\u51fa
@@ -169,6 +193,9 @@ dialog.exportgpx.name=\u540d\u79f0
 dialog.exportgpx.desc=\u63cf\u8ff0
 dialog.exportgpx.includetimestamps=\u5305\u542b\u65f6\u95f4
 dialog.exportgpx.copysource=\u4ece\u6e90XML\u6587\u4ef6\u590d\u5236
+dialog.exportgpx.encoding=\u7f16\u7801
+dialog.exportgpx.encoding.system=\u9ed8\u8ba4\u7cfb\u7edf\u7f16\u7801
+dialog.exportgpx.encoding.utf8=\u4f7f\u7528UTF-8
 dialog.exportpov.text=\u8bf7\u8f93\u5165POV\u53c2\u6570
 dialog.exportpov.font=\u5b57\u4f53
 dialog.exportpov.camerax=X\u76f8\u673a
@@ -321,14 +348,16 @@ dialog.compress.wackypoints.paramdesc=\u8ddd\u79bb\u7cfb\u6570
 dialog.compress.singletons.title=\u79bb\u6563\u70b9\u5220\u9664
 dialog.compress.singletons.paramdesc=\u8ddd\u79bb\u7cfb\u6570
 dialog.compress.duplicates.title=\u91cd\u590d\u70b9\u5220\u9664
+dialog.compress.douglaspeucker.title=Douglas-Peucker \u538b\u7f29
+dialog.compress.douglaspeucker.paramdesc=\u95f4\u8ddd\u7cfb\u6570
 dialog.compress.summarylabel=\u8981\u5220\u9664\u7684\u70b9
 dialog.pastecoordinates.desc=\u5728\u6b64\u8f93\u5165\u6216\u7c98\u8d34\u5750\u6807\u70b9
 dialog.pastecoordinates.coords=\u5750\u6807\u70b9
 dialog.pastecoordinates.nothingfound=\u8bf7\u68c0\u67e5\u5750\u6807\u6570\u636e\u5e76\u91cd\u8bd5
-dialog.help.help=\u66f4\u591a\u4fe1\u606f\u548c\u7528\u6cd5\uff0c\u8bf7\u53c2\u8003\u7f51\u7ad9\nhttp://activityworkshop.net/software/prune///
+dialog.help.help=\u66f4\u591a\u4fe1\u606f\u548c\u7528\u6cd5\uff0c\u8bf7\u53c2\u8003\u7f51\u7ad9\nhttp://activityworkshop.net/software/gpsprune/
 dialog.about.version=\u7248\u672c
 dialog.about.build=Build
-dialog.about.summarytext1=Prune\u662f\u4e00\u4e2a\u4eceGPS\u4e2d\u5bfc\u5165\u6570\u636e\uff0c\u663e\u793a\u6570\u636e\u548c\u7f16\u8f91\u6570\u636e\u7684\u8f6f\u4ef6
+dialog.about.summarytext1=GpsPrune\u662f\u4e00\u4e2a\u4eceGPS\u4e2d\u5bfc\u5165\u6570\u636e\uff0c\u663e\u793a\u6570\u636e\u548c\u7f16\u8f91\u6570\u636e\u7684\u8f6f\u4ef6
 dialog.about.summarytext2=\u5b83\u7684\u53d1\u884c\u662f\u57fa\u4e8eGnu GPL\u89c4\u5219\uff0c\u662f\u514d\u8d39\u7684\uff0c\u5f00\u653e\u5f0f\u7684\uff0c\u5168\u4e16\u754c\u5171\u7528\u5e76\u6539\u5584\u589e\u5f3a\u5176\u529f\u80fd\n\u5728\u7b26\u5408"license.txt"\u6761\u4ef6\u4e0b\uff0c\u5bb9\u8bb8\u5e76\u9f13\u52b1\u590d\u5236\uff0c\u5206\u53d1\u53ca\u4fee\u6539\u3002
 dialog.about.summarytext3=\u66f4\u591a\u4fe1\u606f\u53ca\u7528\u6cd5\u6307\u5357\uff0c\u8bf7\u53c2\u8003\u7f51\u7ad9\uff1a\nhttp:activityworkshop.net/
 dialog.about.languages=\u652f\u6301\u8bed\u8a00
@@ -349,7 +378,7 @@ dialog.about.systeminfo.exiflib.external.failed=\u5916\u90e8\uff08\u672a\u627e\u
 dialog.about.yes=\u662f
 dialog.about.no=\u5426
 dialog.about.credits=\u81f4\u8c22
-dialog.about.credits.code=Prune \u539f\u7801\u7f16\u5199
+dialog.about.credits.code=GpsPrune \u539f\u7801\u7f16\u5199
 dialog.about.credits.exifcode=Exif \u539f\u7801\u7f16\u5199
 dialog.about.credits.icons=\u56fe\u6807\u6765\u81ea\u4e8e
 dialog.about.credits.translators=\u8bd1\u8005
@@ -364,7 +393,7 @@ dialog.checkversion.newversion1=\u65b0\u7248\u672c\u5b58\u5728\uff0c \u6700\u65b
 dialog.checkversion.newversion2=
 dialog.checkversion.releasedate1=\u65b0\u7248\u672c\u53d1\u884c\u4e8e
 dialog.checkversion.releasedate2=
-dialog.checkversion.download=\u4e0b\u8f7d\u6700\u65b0\u7248\u672c\uff0c\u8bf7\u767b\u9646\u7f51\u7ad9\uff1a\nhttp://activityworkshop.net/software/prune/download.html
+dialog.checkversion.download=\u4e0b\u8f7d\u6700\u65b0\u7248\u672c\uff0c\u8bf7\u767b\u9646\u7f51\u7ad9\uff1a\nhttp:activityworkshop.net/software/gpsprune/download.html
 dialog.keys.intro=\u53ef\u7528\u4e0b\u5217\u5feb\u6377\u952e\u66ff\u4ee3\u9f20\u6807
 dialog.keys.keylist=<table><tr><td>\u7bad\u5934</td><td>\u4e0a\u4e0b\u5de6\u53f3\u79fb\u52a8\u5730\u56fe</td></tr><tr><td>Ctrl + \u5de6\u53f3\u7bad\u5934</td><td>\u9009\u53d6\u524d\uff0c\u540e\u70b9</td></tr><tr><td>Ctrl + \u4e0a\u4e0b\u7bad\u5934</td><td>\u653e\u5927\u7f29\u5c0f</td></tr><tr><td>Ctrl + PgUp, PgDown</td><td>\u9009\u62e9\u524d\u540e\u6bb5</td></tr><tr><td>Ctrl + Home, End</td><td>\u9009\u62e9\u9996\u672b\u70b9</td></tr><tr><td>Del</td><td>\u5220\u9664\u5f53\u524d\u70b9</td></tr></table>
 dialog.keys.normalmodifier=Ctrl
@@ -389,6 +418,7 @@ dialog.saveconfig.prune.kmzimageheight=KMZ\u56fe\u50cf\u9ad8\u5ea6
 dialog.saveconfig.prune.colourscheme=\u989c\u8272
 dialog.saveconfig.prune.linewidth=\u7ebf\u4f53\u5bbd\u5ea6
 dialog.saveconfig.prune.kmltrackcolour=KML\u8f68\u8ff9\u989c\u8272
+dialog.saveconfig.prune.autosavesettings=\u81ea\u52a8\u4fdd\u5b58\u8bbe\u7f6e
 dialog.setpaths.intro=\u82e5\u9700\u8981\uff0c\u53ef\u8bbe\u5b9a\u5916\u6302\u7a0b\u5e8f\u8def\u5f84
 dialog.setpaths.found=\u627e\u5230\u8def\u5f84\uff1f
 dialog.addaltitude.noaltitudes=\u8f68\u8ff9\u4e0d\u542b\u9ad8\u5ea6\u4fe1\u606f
@@ -408,23 +438,35 @@ dialog.colourchooser.red=\u7ea2
 dialog.colourchooser.green=\u7eff
 dialog.colourchooser.blue=\u84dd
 dialog.setlanguage.firstintro=\u4f60\u53ef\u4ee5\u9009\u62e9\u5df2\u6709\u8bed\u8a00,<p>\u6216\u9009\u62e9\u5916\u6302\u8bed\u8a00\u5305
-dialog.setlanguage.secondintro=\u8bf7\u4fdd\u5b58\u8bbe\u7f6e<p>\u5e76\u91cd\u542fPrune\u4f7f\u8bbe\u7f6e\u751f\u6548
+dialog.setlanguage.secondintro=\u8bf7\u4fdd\u5b58\u8bbe\u7f6e<p>\u5e76\u91cd\u542fGpsPrune\u4f7f\u8bbe\u7f6e\u751f\u6548
 dialog.setlanguage.language=\u8bed\u8a00
 dialog.setlanguage.languagefile=\u8bed\u8a00\u5305
-dialog.setlanguage.endmessage=\u73b0\u5728\u8bf7\u4fdd\u5b58\u8bbe\u7f6e\u5e76\u91cd\u542fPrune\n\u4f7f\u8bbe\u7f6e\u751f\u6548
+dialog.setlanguage.endmessage=\u73b0\u5728\u8bf7\u4fdd\u5b58\u8bbe\u7f6e\u5e76\u91cd\u542fGpsPrune\n\u4f7f\u8bbe\u7f6e\u751f\u6548
+dialog.setlanguage.endmessagewithautosave=\u8981\u4f7f\u6240\u9009\u8bed\u8a00\u751f\u6548\uff0c\u8bf7\u91cd\u65b0\u542f\u52a8GosPrune
 dialog.diskcache.save=\u5730\u56fe\u56fe\u7247\u4fdd\u5b58\u5230\u7535\u8111
 dialog.diskcache.dir=\u4fdd\u5b58\u8def\u5f84
 dialog.diskcache.createdir=\u65b0\u5efa\u8def\u5f84
 dialog.diskcache.nocreate=\u672a\u65b0\u5efa\u8def\u5f84
+dialog.diskcache.table.path=\u8def\u5f84
+dialog.diskcache.table.usedby=\u4f7f\u7528\u8005
+dialog.diskcache.table.zoom=\u653e\u5927\u7f29\u5c0f
+dialog.diskcache.table.tiles=\u627e\u5230\u7684\u5730\u56fe\u533a\u57df\u6570\u636e
+dialog.diskcache.table.megabytes=MB
+dialog.diskcache.tileset=\u5730\u56fe\u533a\u57df\u6570\u5b58\u653e\u8def\u5f84
+dialog.diskcache.tileset.multiple=\u6570\u76ee
+dialog.diskcache.deleteold=\u5220\u9664\u65e7\u533a\u57df\u6570\u636e
+dialog.diskcache.deleteall=\u5220\u9664\u6240\u6709\u533a\u57df\u6570\u636e
+dialog.diskcache.deleted1=\u5df2\u5220\u9664
+dialog.diskcache.deleted2=\u7f13\u5b58\u5185\u6587\u4ef6
 dialog.deletefieldvalues.intro=\u9009\u62e9\u5f53\u524d\u8303\u56f4\u5185\u8981\u5220\u9664\u7684\u533a\u57df
 dialog.setlinewidth.text=\u8f93\u5165\u8f68\u8ff9\u7ebf\u5bbd\u50cf\u7d20\u503c\uff081-4\uff09
 dialog.downloadosm.desc=\u786e\u8ba4\u4eceOSM\u4e0b\u8f7d\u8be5\u5730\u533a\u539f\u59cb\u6570\u636e
 dialog.searchwikipedianames.search=\u67e5\u627e
 
 # 3d window
-dialog.3d.title=Prune 3D \u663e\u793a
+dialog.3d.title=GpsPrune 3D \u663e\u793a
 dialog.3d.altitudefactor=\u9ad8\u5ea6\u653e\u5927\u7cfb\u6570
-dialog.3dlines.title=Prune \u7f51\u683c\u7ebf
+dialog.3dlines.title=GpsPrune \u7f51\u683c\u7ebf
 dialog.3dlines.empty=\u65e0\u6cd5\u663e\u793a\u7f51\u683c\u7ebf
 dialog.3dlines.intro=3D \u7f51\u683c\u7ebf
 
@@ -496,6 +538,7 @@ button.resettodefaults=\u6062\u590d\u9ed8\u8ba4
 button.browse=\u6d4f\u89c8...
 button.addnew=\u6dfb\u52a0
 button.delete=\u5220\u9664
+button.manage=\u7ba1\u7406
 
 # File types
 filetype.txt=TXT\u6587\u4ef6
@@ -547,6 +590,7 @@ details.lists.audio=\u58f0\u97f3
 details.photodetails=\u76f8\u7247\u4fe1\u606f
 details.nophoto=\u65e0\u76f8\u7247\u88ab\u9009\u4e2d
 details.photo.loading=\u6b63\u5bfc\u5165
+details.photo.bearing=\u65b9\u5411
 details.media.connected=\u5df2\u94fe\u63a5
 details.audiodetails=\u8be6\u7ec6\u4fe1\u606f
 details.noaudio=\u672a\u9009\u62e9\u58f0\u97f3\u6587\u4ef6
@@ -570,6 +614,7 @@ fieldname.movingdistance=\u79fb\u52a8\u8ddd\u79bb
 fieldname.duration=\u65f6\u957f
 fieldname.speed=\u901f\u5ea6
 fieldname.verticalspeed=\u5782\u76f4\u901f\u5ea6
+fieldname.description=\u63cf\u8ff0
 
 # Measurement units
 units.original=\u539f\u59cb
@@ -671,3 +716,6 @@ error.lookupsrtm.nonerequired=\u6240\u6709\u70b9\u5747\u542b\u9ad8\u5ea6\u4fe1\u
 error.gpsies.uploadnotok=gpsies\u670d\u52a1\u5668\u8fd4\u56de\u4fe1\u606f\uff1a
 error.gpsies.uploadfailed=\u4e0a\u4f20\u51fa\u9519\u5931\u8d25
 error.playaudiofailed=\u65e0\u6cd5\u64ad\u653e\u58f0\u97f3\u6587\u4ef6
+error.cache.notthere=\u672a\u627e\u5230\u533a\u57df\u6570\u636e\u7f13\u5b58\u6587\u4ef6\u5939
+error.cache.empty=\u533a\u57df\u6570\u636e\u6587\u4ef6\u5939\u7a7a
+error.cache.cannotdelete=\u65e0\u53ef\u5220\u9664\u533a\u57df\u6570\u636e
index 1997db2b41b20fe0e507857a6bcd3bb7d8335874..9da33d2d5a68419ec94e4d4b1cd0c24a233b3cd5 100644 (file)
@@ -9,17 +9,17 @@ import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
 import tim.prune.config.Config;
-import tim.prune.data.AudioFile;
+import tim.prune.data.AudioClip;
 import tim.prune.undo.UndoLoadAudios;
 
 /**
- * Class to manage the loading of audio files
+ * Class to manage the loading of audio clips
  */
 public class AudioLoader extends GenericFunction
 {
        private JFileChooser _fileChooser = null;
        private GenericFileFilter _fileFilter = null;
-       private TreeSet<AudioFile> _fileList = null;
+       private TreeSet<AudioClip> _fileList = null;
 
 
        /**
@@ -58,7 +58,7 @@ public class AudioLoader extends GenericFunction
                // Show file dialog to choose file / directory(ies)
                if (_fileChooser.showOpenDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
                {
-                       _fileList = new TreeSet<AudioFile>(new MediaSorter());
+                       _fileList = new TreeSet<AudioClip>(new MediaSorter());
                        processFileList(_fileChooser.getSelectedFiles());
                        final int numFiles = _fileList.size();
                        if (numFiles == 0) {
@@ -87,7 +87,7 @@ public class AudioLoader extends GenericFunction
                        {
                                if (file.isFile()) {
                                        if (_fileFilter.accept(file)) {
-                                               _fileList.add(new AudioFile(file));
+                                               _fileList.add(new AudioClip(file));
                                        }
                                }
                                else if (file.isDirectory()) {
diff --git a/tim/prune/load/BabelFileFormats.java b/tim/prune/load/BabelFileFormats.java
new file mode 100644 (file)
index 0000000..ed7e627
--- /dev/null
@@ -0,0 +1,216 @@
+package tim.prune.load;
+
+/**
+ * Class to manage the list of file formats supported by Gpsbabel
+ * (older versions of gpsbabel might not support all of these, of course).
+ * Certain supported formats such as txt, csv, gpx are not included here
+ * as GpsPrune can already load them directly.
+ */
+public abstract class BabelFileFormats
+{
+       /**
+        * @return an object array for the format descriptions
+        */
+       public static Object[] getDescriptions() {
+               return getColumn(0);
+       }
+
+       /**
+        * Find the (first) appropriate file format for the given file suffix
+        * @param inSuffix end of filename including .
+        * @return matching index or -1 if not found
+        */
+       public static int getIndexForFileSuffix(String inSuffix)
+       {
+               if (inSuffix != null && inSuffix.length() > 1)
+               {
+                       final String[] suffixes = getColumn(2);
+                       for (int i=0; i<suffixes.length; i++)
+                               if (suffixes[i] != null && suffixes[i].equalsIgnoreCase(inSuffix))
+                                       return i;
+               }
+               return -1;
+       }
+
+       /**
+        * Get the format name for the selected row
+        * @param inIndex index of selected format
+        * @return name of this format to give to gpsbabel
+        */
+       public static String getFormat(int inIndex)
+       {
+               String[] formats = getColumn(1);
+               if (inIndex >= 0 && inIndex < formats.length)
+                       return formats[inIndex];
+               return null;
+       }
+
+       /**
+        * Extract the specified column of the data array
+        * @param inIndex column index from 0 to 2
+        * @return string array containing required data
+        */
+       private static String[] getColumn(int inIndex)
+       {
+               final String[] allFormats = {
+                       "Alan Map500 tracklogs", "alantrl", ".trl",
+                       "Alan Map500 waypoints and routes", "alanwpr", ".wpr",
+                       "Brauniger IQ Series Barograph Download", "baroiq", null,
+                       "Bushnell GPS Trail file", "bushnell_trl", null,
+                       "Bushnell GPS Waypoint file", "bushnell", null,
+                       "Cambridge/Winpilot glider software", "cambridge", null,
+                       "CarteSurTable data file", "cst", null,
+                       "Cetus for Palm/OS", "cetus", null,
+                       "CoastalExplorer XML", "coastexp", null,
+                       "Columbus/Visiontac V900 files", "v900", ".csv",
+                       "CompeGPS data files", "compegps", ".wpt/.trk/.rte",
+                       "CoPilot Flight Planner for Palm/OS", "copilot", null,
+                       "cotoGPS for Palm/OS", "coto", null,
+                       "Data Logger iBlue747 csv", "iblue747", null,
+                       "Dell Axim Navigation System file format", "axim_gpb", ".gpb",
+                       "DeLorme .an1 (drawing) file", "an1", null,
+                       "DeLorme GPL", "gpl", null,
+                       "DeLorme PN-20/PN-30/PN-40 USB protocol", "delbin", null,
+                       "DeLorme Street Atlas Plus", "saplus", null,
+                       "DeLorme Street Atlas Route", "saroute", null,
+                       "DeLorme XMap HH Native .WPT", "xmap", null,
+                       "DeLorme XMap/SAHH 2006 Native .TXT", "xmap2006", null,
+                       "DeLorme XMat HH Street Atlas USA .WPT (PPC)", "xmapwpt", null,
+                       "Destinator Itineraries", "destinator_itn", ".dat",
+                       "Destinator Points of Interest", "destinator_poi", ".dat",
+                       "Destinator TrackLogs", "destinator_trl", ".dat",
+                       "EasyGPS binary format", "easygps", null,
+                       "Enigma binary waypoint file", "enigma", ".ert",
+                       "FAI/IGC Flight Recorder Data Format", "igc", null,
+                       "Franson GPSGate Simulation", "gpssim", null,
+                       "Fugawi", "fugawi", null,
+                       "G7ToWin data files", "g7towin", ".g7t",
+                       "Garmin 301 Custom position and heartrate", "garmin301", null,
+                       "Garmin Logbook XML", "glogbook", null,
+                       "Garmin MapSource - gdb", "gdb", null,
+                       "Garmin MapSource - mps", "mapsource", null,
+                       "Garmin PCX5", "pcx", null,
+                       "Garmin POI database", "garmin_poi", null,
+                       "Garmin Points of Interest", "garmin_gpi", ".gpi",
+                       "Garmin Training Center", "gtrnctr", null,
+                       "Garmin Training Center", "gtrnctr", ".tcx",
+                       "Geocaching.com .loc", "geo", null,
+                       "GeocachingDB for Palm/OS", "gcdb", null,
+                       "Geogrid-Viewer ascii overlay file", "ggv_ovl", ".ovl",
+                       "Geogrid-Viewer tracklogs", "ggv_log", ".log",
+                       "GEOnet Names Server (GNS)", "geonet", null,
+                       "GeoNiche .pdb", "geoniche", null,
+                       "GlobalSat DG-100/BT-335 Download", "dg-100", null,
+                       "Google Maps XML", "google", null,
+                       "Google Navigator Tracklines", "gnav_trl", ".trl",
+                       "GoPal GPS track log", "gopal", ".trk",
+                       "GpilotS", "gpilots", null,
+                       "GPS TrackMaker", "gtm", null,
+                       "GpsDrive Format", "gpsdrive", null,
+                       "GpsDrive Format for Tracks", "gpsdrivetrack", null,
+                       "GPSman", "gpsman", null,
+                       "GPSPilot Tracker for Palm/OS", "gpspilot", null,
+                       "gpsutil", "gpsutil", null,
+                       "HikeTech", "hiketech", null,
+                       "Holux (gm-100) .wpo Format", "holux", null,
+                       "Holux M-241 (MTK based) Binary File Format", "m241-bin", null,
+                       "Holux M-241 (MTK based) download", "m241", null,
+                       "Honda/Acura Navigation System VP Log File Format", "vpl", null,
+                       "HSA Endeavour Navigator export File", "hsandv", null,
+                       "Humminbird tracks", "humminbird_ht", ".ht",
+                       "Humminbird waypoints and routes", "humminbird", ".hwr",
+                       "IGN Rando track files", "ignrando", null,
+                       "iGO2008 points of interest", "igo2008_poi", ".upoi",
+                       "IGO8 .trk", "igo8", null,
+                       "Jelbert GeoTagger data file", "jtr", null,
+                       "Jogmap.de XML format", "jogmap", null,
+                       "Kartex 5 Track File", "ktf2", null,
+                       "Kartex 5 Waypoint File", "kwf2", null,
+                       "Kompass (DAV) Track", "kompass_tk", ".tk",
+                       "Kompass (DAV) Waypoints", "kompass_wp", ".wp",
+                       "KuDaTa PsiTrex text", "psitrex", null,
+                       "Lowrance USR", "lowranceusr", null,
+                       "Magellan Explorist Geocaching", "maggeo", null,
+                       "Magellan Mapsend", "mapsend", null,
+                       "Magellan NAV Companion for Palm/OS", "magnav", null,
+                       "Magellan SD files (as for eXplorist)", "magellanx", null,
+                       "Magellan SD files (as for Meridian)", "magellan", null,
+                       "Magellan serial protocol", "magellan", null,
+                       "MagicMaps IK3D project file", "ik3d", ".ikt",
+                       "Map&Guide 'TourExchangeFormat' XML", "tef", null,
+                       "Map&Guide to Palm/OS exported files", "mag_pdb", ".pdb",
+                       "MapAsia track file", "mapasia_tr7", ".tr7",
+                       "Mapopolis.com Mapconverter CSV", "mapconverter", null,
+                       "MapTech Exchange Format", "mxf", null,
+                       "Memory-Map Navigator overlay files", "mmo", ".mmo",
+                       "Microsoft AutoRoute 2002 (pin/route reader)", "msroute", null,
+                       "Microsoft Streets and Trips (pin/route reader)", "msroute", null,
+                       "Microsoft Streets and Trips 2002-2007", "s_and_t", null,
+                       "Mobile Garmin XT Track files", "garmin_xt", null,
+                       "Motorrad Routenplaner (Map&Guide) .bcr files", "bcr", null,
+                       "MS PocketStreets 2002 Pushpin", "psp", null,
+                       "MTK Logger (iBlue 747,...) Binary File Format", "mtk-bin", null,
+                       "MTK Logger (iBlue 747,Qstarz BT-1000,...) download", "mtk", null,
+                       "National Geographic Topo .tpg (waypoints)", "tpg", null,
+                       "National Geographic Topo 2.x .tpo", "tpo2", null,
+                       "National Geographic Topo 3.x/4.x .tpo", "tpo3", null,
+                       "Navicache.com XML", "navicache", null,
+                       "Navigon Mobile Navigator .rte files", "nmn4", null,
+                       "Navigon Waypoints", "navigonwpt", null,
+                       "NaviGPS GT-11/BGT-11 Download", "navilink", null,
+                       "NaviGPS GT-31/BGT-31 datalogger", "sbp", ".sbp",
+                       "NaviGPS GT-31/BGT-31 SiRF binary logfile", "sbn", ".sbn",
+                       "Naviguide binary route file", "naviguide", ".twl",
+                       "Navitel binary track", "navitel_trk", ".bin",
+                       "Navitrak DNA marker format", "dna", null,
+                       "NetStumbler Summary File", "netstumbler", "text",
+                       "NIMA/GNIS Geographic Names File", "nima", null,
+                       "Nokia Landmark Exchange", "lmx", null,
+                       "OpenStreetMap data files", "osm", ".osm",
+                       "OziExplorer", "ozi", null,
+                       "PalmDoc Output", "palmdoc", null,
+                       "PathAway Database for Palm/OS", "pathaway", null,
+                       "PocketFMS breadcrumbs", "pocketfms_bc", null,
+                       "PocketFMS flightplan", "pocketfms_fp", ".xml",
+                       "PocketFMS waypoints", "pocketfms_wp", ".txt",
+                       "Quovadis", "quovadis", null,
+                       "Raymarine Waypoint File", "raymarine", ".rwf",
+                       "Ricoh GPS Log File", "ricoh", null,
+                       "See You flight analysis data", "cup", null,
+                       "Skymap / KMD150 ascii files", "skyforce", null,
+                       "SkyTraq Venus based loggers (download)", "skytraq", null,
+                       "SkyTraq Venus based loggers Binary File Format", "skytraq-bin", null,
+                       "Sportsim track files (part of zipped .ssz files)", "sportsim", null,
+                       "SubRip subtitles for video mapping", "subrip", ".srt",
+                       "Suunto Trek Manager (STM) .sdf files", "stmsdf", null,
+                       "Suunto Trek Manager (STM) WaypointPlus files", "stmwpp", null,
+                       "Swiss Map 25/50/100", "xol", ".xol",
+                       "TomTom Itineraries", "tomtom_itn", ".itn",
+                       "TomTom Places Itineraries", "tomtom_itn_places", ".itn",
+                       "TomTom POI file", "tomtom_asc", ".asc",
+                       "TomTom POI file", "tomtom", ".ov2",
+                       "TopoMapPro Places File", "tmpro", null,
+                       "TrackLogs digital mapping", "dmtlog", ".trl",
+                       "U.S. Census Bureau Tiger Mapping Service", "tiger", null,
+                       "Vcard Output (for iPod)", "vcard", null,
+                       "VidaOne GPS for Pocket PC", "vidaone", ".gpb",
+                       "Vito Navigator II tracks", "vitosmt", null,
+                       "Vito SmartMap tracks", "vitovtt", ".vtt",
+                       "WiFiFoFum 2.0 for PocketPC XML", "wfff", null,
+                       "Wintec TES file", "wintec_tes", null,
+                       "Wintec WBT-100/200 Binary File Format", "wbt-bin", null,
+                       "Wintec WBT-100/200 GPS Download", "wbt", null,
+                       "Wintec WBT-201/G-Rays 2 Binary File Format", "wbt-tk1", null,
+                       "XAiOX iTrackU Logger", "itracku", null,
+                       "XAiOX iTrackU Logger Binary File Format", "itracku-bin", null,
+                       "Yahoo Geocode API data", "yahoo", null,
+               };
+               // Copy elements into new array
+               final int numRows = allFormats.length / 3;
+               String[] result = new String[numRows];
+               for (int i=0; i<numRows; i++) {
+                       result[i] = allFormats[i*3 + inIndex];
+               }
+               return result;
+       }
+}
diff --git a/tim/prune/load/BabelLoadFromFile.java b/tim/prune/load/BabelLoadFromFile.java
new file mode 100644 (file)
index 0000000..f7866ef
--- /dev/null
@@ -0,0 +1,221 @@
+package tim.prune.load;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import tim.prune.App;
+import tim.prune.I18nManager;
+import tim.prune.config.Config;
+import tim.prune.data.SourceInfo;
+import tim.prune.data.SourceInfo.FILE_TYPE;
+import tim.prune.gui.GuiGridLayout;
+
+
+/**
+ * Class to manage the loading of data from a file using GpsBabel.
+ * This allows the use of Gpsbabel's importing functions to convert to gpx.
+ */
+public class BabelLoadFromFile extends BabelLoader
+{
+       // file chooser
+       private JFileChooser _fileChooser = null;
+       // Input file
+       private File _inputFile = null;
+       // Label for filename
+       private JLabel _inputFileLabel = null;
+       // Dropdown for format of file
+       private JComboBox _formatDropdown = null;
+       // Last used file suffix
+       private String _lastSuffix = null;
+
+       /**
+        * Constructor
+        * @param inApp Application object to inform of data load
+        */
+       public BabelLoadFromFile(App inApp) {
+               super(inApp);
+       }
+
+       /** Get the name key */
+       public String getNameKey() {
+               return "function.importwithgpsbabel";
+       }
+
+       /** @return complete input file path for gpsbabel call */
+       protected String getFilePath() {
+               return _inputFile.getAbsolutePath();
+       }
+
+       /** @return Source info */
+       protected SourceInfo getSourceInfo() {
+               return new SourceInfo(_inputFile, FILE_TYPE.GPSBABEL);
+       }
+
+       /** @return input format */
+       protected String getInputFormat() {
+               return BabelFileFormats.getFormat(_formatDropdown.getSelectedIndex());
+       }
+
+       /** @return true if function can be run */
+       protected boolean isInputOk() {
+               return _inputFile.exists() && _inputFile.canRead();
+       }
+
+       /**
+        * Override the begin method to specify input file first
+        */
+       public void begin()
+       {
+               // Construct file chooser if necessary
+               if (_fileChooser == null)
+               {
+                       _fileChooser = new JFileChooser();
+                       // start from directory in config if already set
+                       String configDir = Config.getConfigString(Config.KEY_TRACK_DIR);
+                       if (configDir == null) {configDir = Config.getConfigString(Config.KEY_PHOTO_DIR);}
+                       if (configDir != null) {_fileChooser.setCurrentDirectory(new File(configDir));}
+                       _fileChooser.setMultiSelectionEnabled(false); // Single files only
+               }
+               // Show the open dialog
+               if (_fileChooser.showOpenDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
+               {
+                       _inputFile = _fileChooser.getSelectedFile();
+                       if (_inputFile != null && isInputOk()) {
+                               super.begin();
+                       }
+               }
+       }
+
+       /**
+        * Begin the load function with a previously-specified file
+        * @param inFile file to load
+        */
+       public void beginWithFile(File inFile)
+       {
+               _inputFile = inFile;
+               super.begin();
+       }
+
+       /**
+        * @return a panel containing the main dialog components
+        */
+       protected JPanel makeDialogComponents()
+       {
+               JPanel outerPanel = new JPanel();
+               outerPanel.setLayout(new BorderLayout());
+               // Main panel with options etc
+               JPanel mainPanel = new JPanel();
+               mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+
+               // text fields for options
+               JPanel gridPanel = new JPanel();
+               GuiGridLayout grid = new GuiGridLayout(gridPanel);
+               JLabel nameLabel = new JLabel(I18nManager.getText("details.track.file"));
+               grid.add(nameLabel);
+               _inputFileLabel = new JLabel("------------");
+               grid.add(_inputFileLabel);
+               JLabel formatLabel = new JLabel(I18nManager.getText("dialog.gpsload.format"));
+               grid.add(formatLabel);
+               _formatDropdown = new JComboBox(BabelFileFormats.getDescriptions());
+               grid.add(_formatDropdown);
+               gridPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
+               gridPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 20));
+               mainPanel.add(gridPanel);
+
+               // checkboxes
+               ChangeListener checkboxListener = new ChangeListener() {
+                       public void stateChanged(ChangeEvent e)
+                       {
+                               enableOkButton();
+                       }
+               };
+               _waypointCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.getwaypoints"), true);
+               _waypointCheckbox.addChangeListener(checkboxListener);
+               _waypointCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+               mainPanel.add(_waypointCheckbox);
+               _trackCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.gettracks"), true);
+               _trackCheckbox.addChangeListener(checkboxListener);
+               _trackCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+               mainPanel.add(_trackCheckbox);
+               // Checkbox for immediately saving to file
+               _saveCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.save"));
+               _saveCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+               mainPanel.add(_saveCheckbox);
+
+               // progress bar (initially invisible)
+               _progressBar = new JProgressBar(0, 10);
+               mainPanel.add(_progressBar);
+               outerPanel.add(mainPanel, BorderLayout.NORTH);
+
+               // Lower panel with ok and cancel buttons
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               _okButton = new JButton(I18nManager.getText("button.ok"));
+               ActionListener okListener = new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               // start thread to call gpsbabel
+                               _cancelled = false;
+                               new Thread(BabelLoadFromFile.this).start();
+                       }
+               };
+               _okButton.addActionListener(okListener);
+               buttonPanel.add(_okButton);
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _cancelled = true;
+                               _dialog.dispose();
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               outerPanel.add(buttonPanel, BorderLayout.SOUTH);
+               return outerPanel;
+       }
+
+       /**
+        * Initialise dialog
+        */
+       protected void initDialog()
+       {
+               _inputFileLabel.setText(_inputFile.getName());
+               // Get suffix of filename and compare with previous one
+               String filename = _inputFile.getName();
+               int dotPos = filename.lastIndexOf('.');
+               String suffix = (dotPos > 0 ? filename.substring(dotPos) : null);
+               if (suffix != null && !suffix.equals(".") && (_lastSuffix == null || !suffix.equalsIgnoreCase(_lastSuffix)))
+               {
+                       // New suffix chosen, so select first appropriate format (if any)
+                       int selIndex = BabelFileFormats.getIndexForFileSuffix(suffix);
+                       if (selIndex >= 0) {
+                               _formatDropdown.setSelectedIndex(selIndex);
+                       }
+               }
+               _lastSuffix = suffix;
+       }
+
+       /**
+        * Save settings in config
+        */
+       protected void saveConfigValues()
+       {
+               // nothing needed
+       }
+}
diff --git a/tim/prune/load/BabelLoadFromGps.java b/tim/prune/load/BabelLoadFromGps.java
new file mode 100644 (file)
index 0000000..8c4b4dd
--- /dev/null
@@ -0,0 +1,175 @@
+package tim.prune.load;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import tim.prune.App;
+import tim.prune.I18nManager;
+import tim.prune.config.Config;
+import tim.prune.data.SourceInfo;
+import tim.prune.data.SourceInfo.FILE_TYPE;
+
+/**
+ * Class to manage the loading of data from a GPS device using GpsBabel
+ */
+public class BabelLoadFromGps extends BabelLoader
+{
+       // Text fields for entering device and format
+       private JTextField _deviceField = null, _formatField = null;
+
+
+       /**
+        * Constructor
+        * @param inApp Application object to inform of data load
+        */
+       public BabelLoadFromGps(App inApp) {
+               super(inApp);
+       }
+
+       /** Get the name key */
+       public String getNameKey() {
+               return "function.loadfromgps";
+       }
+
+       /** @return device name as file path */
+       protected String getFilePath() {
+               return _deviceField.getText();
+       }
+
+       /** @return Source info */
+       protected SourceInfo getSourceInfo() {
+               return new SourceInfo(_deviceField.getText(), FILE_TYPE.GPSBABEL);
+       }
+
+       /** @return input format */
+       protected String getInputFormat() {
+               return _formatField.getText();
+       }
+
+       /** @return true if function can be run */
+       protected boolean isInputOk() {
+               return _waypointCheckbox.isSelected() || _trackCheckbox.isSelected();
+       }
+
+       /**
+        * @return a panel containing the main dialog components
+        */
+       protected JPanel makeDialogComponents()
+       {
+               JPanel outerPanel = new JPanel();
+               outerPanel.setLayout(new BorderLayout());
+               // Main panel with options etc
+               JPanel mainPanel = new JPanel();
+               mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+
+               // text fields for options
+               JPanel gridPanel = new JPanel();
+               gridPanel.setLayout(new GridLayout(0, 2, 10, 3));
+               JLabel deviceLabel = new JLabel(I18nManager.getText("dialog.gpsload.device"));
+               deviceLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+               gridPanel.add(deviceLabel);
+               _deviceField = new JTextField(Config.getConfigString(Config.KEY_GPS_DEVICE), 12);
+               KeyAdapter escapeListener = new KeyAdapter() {
+                       public void keyReleased(KeyEvent e)
+                       {
+                               // close dialog if escape pressed
+                               if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
+                                       _dialog.dispose();
+                               }
+                       }
+               };
+               _deviceField.addKeyListener(escapeListener);
+               gridPanel.add(_deviceField);
+               JLabel formatLabel = new JLabel(I18nManager.getText("dialog.gpsload.format"));
+               formatLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+               gridPanel.add(formatLabel);
+               _formatField = new JTextField(Config.getConfigString(Config.KEY_GPS_FORMAT), 12);
+               _formatField.addKeyListener(escapeListener);
+               gridPanel.add(_formatField);
+               gridPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
+               gridPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 20));
+               mainPanel.add(gridPanel);
+
+               // checkboxes
+               ChangeListener checkboxListener = new ChangeListener() {
+                       public void stateChanged(ChangeEvent e)
+                       {
+                               enableOkButton();
+                       }
+               };
+               _waypointCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.getwaypoints"), true);
+               _waypointCheckbox.addChangeListener(checkboxListener);
+               _waypointCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+               mainPanel.add(_waypointCheckbox);
+               _trackCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.gettracks"), true);
+               _trackCheckbox.addChangeListener(checkboxListener);
+               _trackCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+               mainPanel.add(_trackCheckbox);
+               // Checkbox for immediately saving to file
+               _saveCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.save"));
+               _saveCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+               mainPanel.add(_saveCheckbox);
+
+               // progress bar (initially invisible)
+               _progressBar = new JProgressBar(0, 10);
+               mainPanel.add(_progressBar);
+               outerPanel.add(mainPanel, BorderLayout.NORTH);
+
+               // Lower panel with ok and cancel buttons
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               _okButton = new JButton(I18nManager.getText("button.ok"));
+               ActionListener okListener = new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               // start thread to call gpsbabel
+                               _cancelled = false;
+                               new Thread(BabelLoadFromGps.this).start();
+                       }
+               };
+               _okButton.addActionListener(okListener);
+               _deviceField.addActionListener(okListener);
+               _formatField.addActionListener(okListener);
+               buttonPanel.add(_okButton);
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _cancelled = true;
+                               _dialog.dispose();
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               outerPanel.add(buttonPanel, BorderLayout.SOUTH);
+               return outerPanel;
+       }
+
+       /**
+        * Save GPS settings in config
+        */
+       protected void saveConfigValues()
+       {
+               final String device = _deviceField.getText().trim();
+               final String format = _formatField.getText().trim();
+               Config.setConfigString(Config.KEY_GPS_DEVICE, device);
+               Config.setConfigString(Config.KEY_GPS_FORMAT, format);
+       }
+}
similarity index 53%
rename from tim/prune/load/GpsLoader.java
rename to tim/prune/load/BabelLoader.java
index 2196e0c3ff29695a13ac72f8abdf3e8bf528dcea..b970665c0c36d3f19de4d3d3583d4da9b1ce1c2a 100644 (file)
@@ -1,32 +1,17 @@
 package tim.prune.load;
 
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.FlowLayout;
-import java.awt.GridLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
 
-import javax.swing.BorderFactory;
-import javax.swing.BoxLayout;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JDialog;
-import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JProgressBar;
-import javax.swing.JTextField;
-import javax.swing.SwingConstants;
 import javax.swing.SwingUtilities;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
@@ -42,35 +27,32 @@ import tim.prune.load.xml.XmlHandler;
 import tim.prune.save.GpxExporter;
 
 /**
- * Class to manage the loading of GPS data using GpsBabel
+ * Superclass to manage the loading of data using GpsBabel
+ * Subclasses handle either from GPS or from file
  */
-public class GpsLoader extends GenericFunction implements Runnable
+public abstract class BabelLoader extends GenericFunction implements Runnable
 {
        private boolean _gpsBabelChecked = false;
-       private JDialog _dialog = null;
-       private JTextField _deviceField = null, _formatField = null;
-       private JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
-       private JCheckBox _saveCheckbox = null;
-       private JButton _okButton = null;
-       private JProgressBar _progressBar = null;
-       private File _saveFile = null;
-       private boolean _cancelled = false;
+       protected JDialog _dialog = null;
+       // Checkboxes for which kinds of points to load
+       protected JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
+       // Checkbox to save to file or not
+       protected JCheckBox _saveCheckbox = null;
+       protected JButton _okButton = null;
+       protected JProgressBar _progressBar = null;
+       protected File _saveFile = null;
+       protected boolean _cancelled = false;
 
 
        /**
         * Constructor
         * @param inApp Application object to inform of data load
         */
-       public GpsLoader(App inApp)
+       public BabelLoader(App inApp)
        {
                super(inApp);
        }
 
-       /** Get the name key */
-       public String getNameKey() {
-               return "function.loadfromgps";
-       }
-
        /**
         * Open the GUI to select options and start the load
         */
@@ -96,6 +78,7 @@ public class GpsLoader extends GenericFunction implements Runnable
                        // Initialise progress bars, buttons
                        enableOkButton();
                        setupProgressBar(true);
+                       initDialog(); // do any subclass-specific init here
                        _dialog.setVisible(true);
                }
        }
@@ -104,91 +87,11 @@ public class GpsLoader extends GenericFunction implements Runnable
        /**
         * @return a panel containing the main dialog components
         */
-       private JPanel makeDialogComponents()
-       {
-               JPanel outerPanel = new JPanel();
-               outerPanel.setLayout(new BorderLayout());
-               // Main panel with options etc
-               JPanel mainPanel = new JPanel();
-               mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
-
-               // text fields for options
-               JPanel gridPanel = new JPanel();
-               gridPanel.setLayout(new GridLayout(0, 2, 10, 3));
-               JLabel deviceLabel = new JLabel(I18nManager.getText("dialog.gpsload.device"));
-               deviceLabel.setHorizontalAlignment(SwingConstants.RIGHT);
-               gridPanel.add(deviceLabel);
-               _deviceField = new JTextField(Config.getConfigString(Config.KEY_GPS_DEVICE), 12);
-               _deviceField.addKeyListener(new KeyAdapter() {
-                       public void keyReleased(KeyEvent e)
-                       {
-                               // close dialog if escape pressed
-                               if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
-                                       _dialog.dispose();
-                               }
-                       }
-               });
-               gridPanel.add(_deviceField);
-               JLabel formatLabel = new JLabel(I18nManager.getText("dialog.gpsload.format"));
-               formatLabel.setHorizontalAlignment(SwingConstants.RIGHT);
-               gridPanel.add(formatLabel);
-               _formatField = new JTextField(Config.getConfigString(Config.KEY_GPS_FORMAT), 12);
-               gridPanel.add(_formatField);
-               gridPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
-               gridPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 20));
-               mainPanel.add(gridPanel);
-
-               // checkboxes
-               ChangeListener checkboxListener = new ChangeListener() {
-                       public void stateChanged(ChangeEvent e)
-                       {
-                               enableOkButton();
-                       }
-               };
-               _waypointCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.getwaypoints"), true);
-               _waypointCheckbox.addChangeListener(checkboxListener);
-               _waypointCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
-               mainPanel.add(_waypointCheckbox);
-               _trackCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.gettracks"), true);
-               _trackCheckbox.addChangeListener(checkboxListener);
-               _trackCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
-               mainPanel.add(_trackCheckbox);
-               // Checkbox for immediately saving to file
-               _saveCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.save"));
-               _saveCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
-               mainPanel.add(_saveCheckbox);
+       protected abstract JPanel makeDialogComponents();
 
-               // progress bar (initially invisible)
-               _progressBar = new JProgressBar(0, 10);
-               mainPanel.add(_progressBar);
-               outerPanel.add(mainPanel, BorderLayout.NORTH);
-
-               // Lower panel with ok and cancel buttons
-               JPanel buttonPanel = new JPanel();
-               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
-               _okButton = new JButton(I18nManager.getText("button.ok"));
-               _okButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               // start thread to call gpsbabel
-                               _cancelled = false;
-                               new Thread(GpsLoader.this).start();
-                       }
-               });
-               buttonPanel.add(_okButton);
-               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
-               cancelButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               _cancelled = true;
-                               _dialog.dispose();
-                       }
-               });
-               buttonPanel.add(cancelButton);
-               outerPanel.add(buttonPanel, BorderLayout.SOUTH);
-               return outerPanel;
-       }
 
+       /** Do any subclass-specific dialog initialisation necessary */
+       protected void initDialog() {}
 
        /**
         * @param inStart true if the dialog is restarting
@@ -206,11 +109,15 @@ public class GpsLoader extends GenericFunction implements Runnable
        /**
         * Enable or disable the ok button
         */
-       private void enableOkButton()
+       protected void enableOkButton()
        {
-               _okButton.setEnabled(_waypointCheckbox.isSelected() || _trackCheckbox.isSelected());
+               _okButton.setEnabled(isInputOk());
        }
 
+       /**
+        * @return true if input fields of dialog are valid
+        */
+       protected abstract boolean isInputOk();
 
        /**
         * Run method for performing tasks in separate thread
@@ -219,7 +126,7 @@ public class GpsLoader extends GenericFunction implements Runnable
        {
                _okButton.setEnabled(false);
                setupProgressBar(false);
-               if (_waypointCheckbox.isSelected() || _trackCheckbox.isSelected())
+               if (isInputOk())
                {
                        _progressBar.setIndeterminate(true);
                        _saveFile = null;
@@ -249,12 +156,9 @@ public class GpsLoader extends GenericFunction implements Runnable
        private void callGpsBabel() throws Exception
        {
                // Set up command to call gpsbabel
-               final String device = _deviceField.getText().trim();
-               final String format = _formatField.getText().trim();
-               String[] commands = getCommandArray(device, format);
+               String[] commands = getCommandArray();
                // Save GPS settings in config
-               Config.setConfigString(Config.KEY_GPS_DEVICE, device);
-               Config.setConfigString(Config.KEY_GPS_FORMAT, format);
+               saveConfigValues();
 
                String errorMessage = "", errorMessage2 = "";
                XmlHandler handler = null;
@@ -326,7 +230,7 @@ public class GpsLoader extends GenericFunction implements Runnable
 
                        // Send data back to app
                        _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(), Altitude.Format.METRES,
-                               new SourceInfo(_deviceField.getText(), SourceInfo.FILE_TYPE.GPSBABEL),
+                               getSourceInfo(),
                                handler.getTrackNameList());
                }
        }
@@ -334,11 +238,9 @@ public class GpsLoader extends GenericFunction implements Runnable
 
        /**
         * Get the commands to call
-        * @param inDevice device name to use
-        * @param inFormat format to use
         * @return String array containing commands
         */
-       private String[] getCommandArray(String inDevice, String inFormat)
+       private String[] getCommandArray()
        {
                String[] commands = null;
                final String command = Config.getConfigString(Config.KEY_GPSBABEL_PATH);
@@ -346,14 +248,14 @@ public class GpsLoader extends GenericFunction implements Runnable
                final boolean loadTrack = _trackCheckbox.isSelected();
                if (loadWaypoints && loadTrack) {
                        // Both waypoints and track points selected
-                       commands = new String[] {command, "-w", "-t", "-i", inFormat,
-                               "-f", inDevice, "-o", "gpx", "-F", "-"};
+                       commands = new String[] {command, "-w", "-t", "-i", getInputFormat(),
+                               "-f", getFilePath(), "-o", "gpx", "-F", "-"};
                }
                else
                {
                        // Only waypoints OR track points selected
-                       commands = new String[] {command, "-w", "-i", inFormat,
-                               "-f", inDevice, "-o", "gpx", "-F", "-"};
+                       commands = new String[] {command, "-w", "-i", getInputFormat(),
+                               "-f", getFilePath(), "-o", "gpx", "-F", "-"};
                        if (loadTrack) {
                                commands[1] = "-t";
                        }
@@ -368,4 +270,24 @@ public class GpsLoader extends GenericFunction implements Runnable
                }
                return commands;
        }
+
+       /**
+        * @return SourceInfo object corresponding to the load
+        */
+       protected abstract SourceInfo getSourceInfo();
+
+       /**
+        * @return complete file path or device path for gpsbabel call
+        */
+       protected abstract String getFilePath();
+
+       /**
+        * @return file name or device name
+        */
+       protected abstract String getInputFormat();
+
+       /**
+        * Save any config values necessary
+        */
+       protected abstract void saveConfigValues();
 }
diff --git a/tim/prune/load/ByteScooper.java b/tim/prune/load/ByteScooper.java
new file mode 100644 (file)
index 0000000..facf1c5
--- /dev/null
@@ -0,0 +1,52 @@
+package tim.prune.load;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Class to scoop bytes from an input stream into an array.
+ * The size of the array doesn't have to be known in advance.
+ * This is used for getting images and sound files out of zip
+ * files or from remote URLs.
+ */
+public class ByteScooper
+{
+       /** Bucket size in bytes */
+       private static final int BUCKET_SIZE = 5000;
+       /** Amount by which barrel size is increased on demand */
+       private static final int BARREL_SIZE_INCREMENT = 100000;
+
+       /**
+        * Scoop bytes from the given input stream and return the result
+        * @param inIs input stream to scoop bytes from
+        * @return byte array
+        */
+       public static byte[] scoop(InputStream inIs) throws IOException
+       {
+               byte[] _barrel = new byte[BARREL_SIZE_INCREMENT];
+               byte[] _bucket = new byte[BUCKET_SIZE];
+               int numBytesInBarrel = 0;
+               // read from stream into the bucket
+               int numBytesRead = inIs.read(_bucket);
+               while (numBytesRead >= 0)
+               {
+                       // expand barrel if necessary
+                       if ((numBytesInBarrel + numBytesRead) > _barrel.length)
+                       {
+                               byte[] newBarrel = new byte[_barrel.length + BARREL_SIZE_INCREMENT];
+                               System.arraycopy(_barrel, 0, newBarrel, 0, numBytesInBarrel);
+                               _barrel = newBarrel;
+                       }
+                       // copy from bucket into barrel
+                       System.arraycopy(_bucket, 0, _barrel, numBytesInBarrel, numBytesRead);
+                       numBytesInBarrel += numBytesRead;
+                       // read next lot from stream into the bucket
+                       numBytesRead = inIs.read(_bucket);
+               }
+               // Now we know how many bytes there are, so crop to size
+               if (numBytesInBarrel == 0) return null;
+               byte[] result = new byte[numBytesInBarrel];
+               System.arraycopy(_barrel, 0, result, 0, numBytesInBarrel);
+               return result;
+       }
+}
index a6a45c60b5d1ffe56c8257ac29b9f5e3f31e4a3b..8a376d8e6367b81aff9a9fca9f2c1f4edd1bafaa 100644 (file)
@@ -1,20 +1,13 @@
 package tim.prune.load;
 
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.io.File;
 import java.util.TreeSet;
 
-import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
-import javax.swing.JButton;
 import javax.swing.JCheckBox;
-import javax.swing.JDialog;
 import javax.swing.JFileChooser;
 import javax.swing.JFrame;
-import javax.swing.JLabel;
 import javax.swing.JPanel;
-import javax.swing.JProgressBar;
 
 import tim.prune.App;
 import tim.prune.I18nManager;
@@ -27,13 +20,14 @@ import tim.prune.data.Latitude;
 import tim.prune.data.Longitude;
 import tim.prune.data.Photo;
 import tim.prune.data.Timestamp;
+import tim.prune.function.Cancellable;
 import tim.prune.jpeg.ExifGateway;
 import tim.prune.jpeg.JpegData;
 
 /**
  * Class to manage the loading of Jpegs and dealing with the GPS data from them
  */
-public class JpegLoader implements Runnable
+public class JpegLoader implements Runnable, Cancellable
 {
        private App _app = null;
        private JFrame _parentFrame = null;
@@ -42,8 +36,7 @@ public class JpegLoader implements Runnable
        private JCheckBox _subdirCheckbox = null;
        private JCheckBox _noExifCheckbox = null;
        private JCheckBox _outsideAreaCheckbox = null;
-       private JDialog _progressDialog   = null;
-       private JProgressBar _progressBar = null;
+       private MediaLoadProgressDialog _progressDialog = null;
        private int[] _fileCounts = null;
        private boolean _cancelled = false;
        private LatLonRectangle _trackRectangle = null;
@@ -101,45 +94,16 @@ public class JpegLoader implements Runnable
                if (_fileChooser.showOpenDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
                {
                        // Bring up dialog before starting
-                       if (_progressDialog == null) {
-                               createProgressDialog();
-                       }
-                       // reset dialog and show it
-                       _progressBar.setValue(0);
-                       _progressBar.setString("");
-                       _progressDialog.setVisible(true);
+                       _progressDialog = new MediaLoadProgressDialog(_parentFrame, this);
+                       _progressDialog.show();
                        // start thread for processing
                        new Thread(this).start();
                }
        }
 
-
-       /**
-        * Create the dialog to show the progress
-        */
-       private void createProgressDialog()
-       {
-               _progressDialog = new JDialog(_parentFrame, I18nManager.getText("dialog.jpegload.progress.title"));
-               _progressDialog.setLocationRelativeTo(_parentFrame);
-               _progressBar = new JProgressBar(0, 100);
-               _progressBar.setValue(0);
-               _progressBar.setStringPainted(true);
-               _progressBar.setString("");
-               JPanel panel = new JPanel();
-               panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
-               panel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
-               panel.add(new JLabel(I18nManager.getText("dialog.jpegload.progress")));
-               panel.add(_progressBar);
-               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
-               cancelButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               _cancelled = true;
-                       }
-               });
-               panel.add(cancelButton);
-               _progressDialog.getContentPane().add(panel);
-               _progressDialog.pack();
+       /** Cancel */
+       public void cancel() {
+               _cancelled = true;
        }
 
 
@@ -155,14 +119,12 @@ public class JpegLoader implements Runnable
                // Loop recursively over selected files/directories to count files
                int numFiles = countFileList(files, true, _subdirCheckbox.isSelected());
                // Set up the progress bar for this number of files
-               _progressBar.setMaximum(numFiles);
-               _progressBar.setValue(0);
+               _progressDialog.showProgress(0, numFiles);
                _cancelled = false;
 
                // Process the files recursively and build lists of photos
                processFileList(files, true, _subdirCheckbox.isSelected());
-               _progressDialog.setVisible(false);
-               _progressDialog.dispose(); // Sometimes dialog doesn't disappear without this dispose
+               _progressDialog.close();
                if (_cancelled) {return;}
 
                if (_fileCounts[0] == 0)
@@ -196,29 +158,27 @@ public class JpegLoader implements Runnable
         */
        private void processFileList(File[] inFiles, boolean inFirstDir, boolean inDescend)
        {
-               if (inFiles != null)
+               if (inFiles == null) return;
+               // Loop over elements in array
+               for (int i=0; i<inFiles.length && !_cancelled; i++)
                {
-                       // Loop over elements in array
-                       for (int i=0; i<inFiles.length && !_cancelled; i++)
+                       File file = inFiles[i];
+                       if (file.exists() && file.canRead())
                        {
-                               File file = inFiles[i];
-                               if (file.exists() && file.canRead())
+                               // Check whether it's a file or a directory
+                               if (file.isFile())
                                {
-                                       // Check whether it's a file or a directory
-                                       if (file.isFile())
-                                       {
-                                               processFile(file);
-                                       }
-                                       else if (file.isDirectory() && (inFirstDir || inDescend))
-                                       {
-                                               // Always process first directory,
-                                               // only process subdirectories if checkbox selected
-                                               File[] files = file.listFiles();
-                                               processFileList(files, false, inDescend);
-                                       }
+                                       processFile(file);
+                               }
+                               else if (file.isDirectory() && (inFirstDir || inDescend))
+                               {
+                                       // Always process first directory,
+                                       // only process subdirectories if checkbox selected
+                                       File[] files = file.listFiles();
+                                       processFileList(files, false, inDescend);
                                }
-                               // if file doesn't exist or isn't readable - ignore
                        }
+                       // if file doesn't exist or isn't readable - ignore
                }
        }
 
@@ -231,9 +191,7 @@ public class JpegLoader implements Runnable
        {
                // Update progress bar
                _fileCounts[0]++; // file found
-               _progressBar.setValue(_fileCounts[0]);
-               _progressBar.setString("" + _fileCounts[0] + " / " + _progressBar.getMaximum());
-               _progressBar.repaint();
+               _progressDialog.showProgress(_fileCounts[0], -1);
 
                // Check whether filename corresponds with accepted filenames
                if (!_fileFilter.acceptFilename(inFile.getName())) {return;}
@@ -289,6 +247,8 @@ public class JpegLoader implements Runnable
                        photo.setExifThumbnail(jpegData.getThumbnailImage());
                        // Also extract orientation tag for setting rotation state of photo
                        photo.setRotation(jpegData.getRequiredRotation());
+                       // Set bearing, if any
+                       photo.setBearing(jpegData.getBearing());
                }
                // Use file timestamp if exif timestamp isn't available
                if (timestamp == null) {
index 9b029d72729e62b5066761f05a90014c357f683b..d14798270740a0525b0f56f8a7414bb82028dada 100644 (file)
@@ -1,12 +1,15 @@
 package tim.prune.load;
 
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 
-import tim.prune.data.AudioFile;
-import tim.prune.data.MediaFile;
-import tim.prune.data.MediaList;
+import tim.prune.data.AudioClip;
+import tim.prune.data.MediaObject;
 import tim.prune.data.Photo;
-import tim.prune.data.Track;
 
 /**
  * Class to provide helper functions for loading media
@@ -16,55 +19,108 @@ public abstract class MediaHelper
        /** File filters */
        private static GenericFileFilter _jpegFilter = null, _audioFilter = null;
 
+
+       /**
+        * Construct a MediaObject for the given path
+        * @param inZipFile path to archive file (if any)
+        * @param inPath path to media file
+        * @return either Photo or AudioClip object as appropriate, or null
+        */
+       public static MediaObject createMediaObject(File inZipFile, String inPath)
+       {
+               if (inPath == null || inPath.length() < 5) return null;
+               InputStream is = null;
+               ZipFile zf     = null;
+               byte[] data    = null;
+               String url     = null;
+               try
+               {
+                       // Check if path is a URL, in which case get an input stream from it
+                       if (inPath.substring(0, 5).toLowerCase().equals("http:"))
+                       {
+                               url = inPath;
+                               is = new URL(inPath).openStream();
+                               data = ByteScooper.scoop(is);
+                       }
+               }
+               catch (IOException ioe) {
+                       System.err.println("Got ioe from url: " + ioe.getMessage());
+               } // is stays null
+
+               // Now see if file is in the zip file
+               if (is == null && inZipFile != null && inZipFile.exists() && inZipFile.canRead())
+               {
+                       try
+                       {
+                               zf = new ZipFile(inZipFile);
+                               ZipEntry entry = zf.getEntry(inPath);
+                               if (entry != null && entry.getSize() > 0)
+                               {
+                                       data = ByteScooper.scoop(zf.getInputStream(entry));
+                                       // System.out.println("Size of data " + (data.length == entry.getSize()?"matches":"DOESN'T match"));
+                               }
+                       }
+                       catch (IOException ioe) {
+                               System.err.println("Got ioe from zip file: " + ioe.getMessage());
+                       }
+               }
+               // Clean up input streams
+               if (is != null) try {
+                       is.close();
+               } catch (IOException ioe) {}
+               if (zf != null) try {
+                       zf.close();
+               } catch (IOException ioe) {}
+
+               if (data != null)
+               {
+                       // Create Photo or AudioClip using this entry
+                       String filename = new File(inPath).getName();
+                       initFilters();
+                       if (_jpegFilter.acceptFilename(inPath)) {
+                               return new Photo(data, filename, url);
+                       }
+                       else if (_audioFilter.acceptFilename(inPath)) {
+                               return new AudioClip(data, filename, url);
+                       }
+                       return null;
+               }
+               else
+                       // If we haven't got a result by now, try to just load plain file
+                       return createMediaObject(inPath);
+       }
+
        /**
-        * Construct a MediaFile object for the given path
+        * Construct a MediaObject for the given path
         * @param inPath path to file
-        * @return either Photo or AudioFile object as appropriate, or null
+        * @return either Photo or AudioClip object as appropriate, or null
         */
-       public static MediaFile createMediaFile(String inPath)
+       private static MediaObject createMediaObject(String inPath)
        {
                if (inPath == null) {return null;}
                File file = new File(inPath);
                if (!file.exists() || !file.canRead() || !file.isFile()) {return null;}
-               // Initialise filters if necessary
-               if (_jpegFilter == null) {
-                       _jpegFilter = new JpegFileFilter();
-                       _audioFilter = new AudioFileFilter();
-               }
+               initFilters();
                // Check if filename looks like a jpeg
                if (_jpegFilter.acceptFilename(file.getName())) {
                        return JpegLoader.createPhoto(file);
                }
-               // Check if filename looks like an audio file
+               // Check if filename looks like an audio clip
                if (_audioFilter.acceptFilename(file.getName())) {
-                       return new AudioFile(file);
+                       return new AudioClip(file);
                }
                // Neither photo nor audio
                return null;
        }
 
        /**
-        * Add all the media from the given track into the specified list
-        * @param inTrack track from which media to take
-        * @param inMediaList list to which media should be added
-        * @param inMediaClass class of media, either Photo or AudioFile
+        * Initialise filters if necessary
         */
-       public static void addMediaFromTrack(Track inTrack, MediaList inMediaList,
-               Class<?> inMediaClass)
+       private static void initFilters()
        {
-               final int numPoints = inTrack.getNumPoints();
-               for (int i=0; i<numPoints; i++)
-               {
-                       MediaFile media = null;
-                       if (inMediaClass == Photo.class) {
-                               media = inTrack.getPoint(i).getPhoto();
-                       }
-                       else if (inMediaClass == AudioFile.class) {
-                               media = inTrack.getPoint(i).getAudio();
-                       }
-                       if (media != null) {
-                               inMediaList.addMedia(media);
-                       }
+               if (_jpegFilter == null) {
+                       _jpegFilter = new JpegFileFilter();
+                       _audioFilter = new AudioFileFilter();
                }
        }
 }
diff --git a/tim/prune/load/MediaLinkInfo.java b/tim/prune/load/MediaLinkInfo.java
new file mode 100644 (file)
index 0000000..dd9372a
--- /dev/null
@@ -0,0 +1,58 @@
+package tim.prune.load;
+
+import java.io.File;
+
+/**
+ * Container class to hold media link information from a loaded file
+ * including whether the media files are actual files or inside a kmz / zip
+ */
+public class MediaLinkInfo
+{
+       /** zip file (or kmz file) containing media files */
+       private File _zipFile = null;
+       /** array of URLs */
+       private String[] _linkArray = null;
+
+
+       /**
+        * Constructor for regular files
+        * @param inLinkArray array of links to files
+        */
+       public MediaLinkInfo(String[] inLinkArray)
+       {
+               _zipFile = null;
+               _linkArray = inLinkArray;
+       }
+
+       /**
+        * Constructor for media files inside a zip / kmz file
+        * @param inZipFile archive file
+        * @param inLinkArray array of file links
+        */
+       public MediaLinkInfo(File inZipFile, String[] inLinkArray)
+       {
+               _zipFile = inZipFile;
+               _linkArray = inLinkArray;
+       }
+
+       /**
+        * @return true if these media files are inside a zip / kmz
+        */
+       public boolean insideArchive() {
+               return _zipFile != null && _zipFile.exists();
+       }
+
+       /**
+        * @return zip file
+        */
+       public File getZipFile() {
+               return _zipFile;
+       }
+
+       /**
+        * @return link array
+        */
+       public String[] getLinkArray() {
+               return _linkArray;
+       }
+}
diff --git a/tim/prune/load/MediaLoadProgressDialog.java b/tim/prune/load/MediaLoadProgressDialog.java
new file mode 100644 (file)
index 0000000..4ed2ab0
--- /dev/null
@@ -0,0 +1,108 @@
+package tim.prune.load;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+
+import tim.prune.I18nManager;
+import tim.prune.function.Cancellable;
+
+/**
+ * Class to show a progress dialog for loading media.
+ * Used for regular photo / audio loads plus the async
+ * loading function.
+ */
+public class MediaLoadProgressDialog
+{
+       private JDialog _progressDialog   = null;
+       private JProgressBar _progressBar = null;
+       private JFrame _parentFrame = null;
+       private Cancellable _function = null;
+
+       /**
+        * Constructor
+        * @param inParentFrame parent frame for creating dialog
+        * @param inFunction function which can be cancelled
+        */
+       public MediaLoadProgressDialog(JFrame inParentFrame, Cancellable inFunction)
+       {
+               _parentFrame = inParentFrame;
+               _function = inFunction;
+       }
+
+       /**
+        * Create the dialog to show the progress
+        */
+       private void createProgressDialog()
+       {
+               _progressDialog = new JDialog(_parentFrame, I18nManager.getText("dialog.jpegload.progress.title"));
+               _progressDialog.setLocationRelativeTo(_parentFrame);
+               _progressBar = new JProgressBar(0, 100);
+               _progressBar.setValue(0);
+               _progressBar.setStringPainted(true);
+               _progressBar.setString("");
+               JPanel panel = new JPanel();
+               panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+               panel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
+               panel.add(new JLabel(I18nManager.getText("dialog.jpegload.progress")));
+               panel.add(_progressBar);
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _function.cancel();
+                       }
+               });
+               panel.add(cancelButton);
+               _progressDialog.getContentPane().add(panel);
+               _progressDialog.pack();
+               _progressDialog.setVisible(true);
+       }
+
+       /**
+        * Show the dialog in indeterminate mode, before limits are calculated
+        */
+       public void show()
+       {
+               if (_progressDialog == null)
+               {
+                       createProgressDialog();
+                       _progressBar.setIndeterminate(true);
+               }
+       }
+
+       /**
+        * Update the progress bar
+        * @param inCurrent current value
+        * @param inMax maximum value
+        */
+       public void showProgress(int inCurrent, int inMax)
+       {
+               if (_progressDialog == null)
+                       createProgressDialog();
+               if (_progressBar.isIndeterminate())
+                       _progressBar.setIndeterminate(false);
+               if (inMax > 0)
+                       _progressBar.setMaximum(inMax);
+               _progressBar.setValue(inCurrent);
+               _progressBar.setString("" + inCurrent + " / " + _progressBar.getMaximum());
+               // TODO: Need to repaint?
+       }
+
+       /**
+        * Close the dialog
+        */
+       public void close()
+       {
+               if (_progressDialog != null)
+                       _progressDialog.dispose();
+       }
+}
index 897b5aa0ff6957e80b859fa485c15b554cf73d8d..e67a32bfd2a45ca0b728ce1b1a8f35556b6c2ef2 100644 (file)
@@ -2,31 +2,39 @@ package tim.prune.load;
 
 import java.io.File;
 import java.util.Comparator;
-import tim.prune.data.MediaFile;
-
+import tim.prune.data.MediaObject;
 
 /**
- * Class to sort photos by name
+ * Class to sort photos, audios by name
  */
-public class MediaSorter implements Comparator<MediaFile>
+public class MediaSorter implements Comparator<MediaObject>
 {
-
        /**
-        * Compare two media files
+        * Compare two media objects
         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
         */
-       public int compare(MediaFile o1, MediaFile o2)
+       public int compare(MediaObject o1, MediaObject o2)
        {
+               int nameComp = o1.getName().compareTo(o2.getName());
+               if (nameComp != 0) {
+                       // names different
+                       return nameComp;
+               }
                File file1 = o1.getFile();
                File file2 = o2.getFile();
-               int nameComp = file1.getName().compareTo(file2.getName());
-               if (nameComp == 0)
+               if (file1 != null && file2 != null)
                {
                        // names same, maybe in different directories
-                       return file1.getAbsolutePath().compareTo(file2.getAbsolutePath());
+                       nameComp = file1.getAbsolutePath().compareTo(file2.getAbsolutePath());
+               }
+               else if (o1.getByteData() != null && o2.getByteData() != null) {
+                       // compare data lengths instead
+                       nameComp = o1.getByteData().length - o2.getByteData().length;
+               }
+               else {
+                       // one's a file, one's from data
+                       nameComp = 1;
                }
-               // names different
                return nameComp;
        }
-
 }
index ec52f8b5b4b81c54cadb5976a0ed4633d528f494..4208014e44c1e9e8c9df262c0caa3083f3bd76f3 100644 (file)
@@ -22,7 +22,8 @@ public class GpxHandler extends XmlHandler
        private GpxTag _name = new GpxTag(), _trackName = new GpxTag();
        private String _latitude = null, _longitude = null;
        private GpxTag _elevation = new GpxTag(), _time = new GpxTag();
-       private GpxTag _type = new GpxTag(), _link = new GpxTag();
+       private GpxTag _type = new GpxTag(), _description = new GpxTag();
+       private GpxTag _link = new GpxTag();
        private GpxTag _currentTag = null;
        private ArrayList<String[]> _pointList = new ArrayList<String[]>();
        private ArrayList<String> _linkList = new ArrayList<String>();
@@ -55,6 +56,7 @@ public class GpxHandler extends XmlHandler
                        _time.setValue(null);
                        _type.setValue(null);
                        _link.setValue(null);
+                       _description.setValue(null);
                }
                else if (tag.equals("ele")) {
                        _currentTag = _elevation;
@@ -68,6 +70,9 @@ public class GpxHandler extends XmlHandler
                else if (tag.equals("type")) {
                        _currentTag = _type;
                }
+               else if (tag.equals("description")) {
+                       _currentTag = _description;
+               }
                else if (tag.equals("link")) {
                        _link.setValue(attributes.getValue("href"));
                }
@@ -137,17 +142,19 @@ public class GpxHandler extends XmlHandler
        private void processPoint()
        {
                // Put the values into a String array matching the order in getFieldArray()
-               String[] values = new String[7];
+               String[] values = new String[8];
                values[0] = _latitude;
                values[1] = _longitude;
                values[2] = _elevation.getValue();
                if (_insideWaypoint) {values[3] = _name.getValue();}
                values[4] = _time.getValue();
-               if (_startSegment && !_insideWaypoint) {
+               if (_startSegment && !_insideWaypoint)
+               {
                        values[5] = "1";
                        _startSegment = false;
                }
                values[6] = _type.getValue();
+               values[7] = _description.getValue();
                _pointList.add(values);
                _trackNameList.addPoint(_trackNum, _trackName.getValue(), _isTrackPoint);
                _linkList.add(_link.getValue());
@@ -160,7 +167,8 @@ public class GpxHandler extends XmlHandler
        public Field[] getFieldArray()
        {
                final Field[] fields = {Field.LATITUDE, Field.LONGITUDE, Field.ALTITUDE,
-                       Field.WAYPT_NAME, Field.TIMESTAMP, Field.NEW_SEGMENT, Field.WAYPT_TYPE};
+                       Field.WAYPT_NAME, Field.TIMESTAMP, Field.NEW_SEGMENT,
+                       Field.WAYPT_TYPE, Field.DESCRIPTION};
                return fields;
        }
 
index 55b88f11847aef3d33c0599f80b9fe3899692bf3..98ef9467943645182d8f6a78d9865e50ab51ba6d 100644 (file)
@@ -9,6 +9,7 @@ import tim.prune.App;
 import tim.prune.I18nManager;
 import tim.prune.data.Altitude;
 import tim.prune.data.SourceInfo;
+import tim.prune.load.MediaLinkInfo;
 
 /**
  * Class to handle the loading of gzipped xml files
@@ -48,15 +49,18 @@ public class GzipFileLoader
                        if (handler == null) {
                                _app.showErrorMessage("error.load.dialogtitle", "error.load.noread");
                        }
-                       else {
+                       else
+                       {
                                // Send back to app
                                SourceInfo sourceInfo = new SourceInfo(inFile,
                                        (handler instanceof GpxHandler?SourceInfo.FILE_TYPE.GPX:SourceInfo.FILE_TYPE.KML));
                                _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
-                                       Altitude.Format.METRES, sourceInfo, handler.getTrackNameList(), handler.getLinkArray());
+                                       Altitude.Format.METRES, sourceInfo, handler.getTrackNameList(),
+                                       new MediaLinkInfo(inFile, handler.getLinkArray()));
                        }
                }
-               catch (Exception e) {
+               catch (Exception e)
+               {
                        // Error occurred, could be a non-xml file borking the parser
                        _app.showErrorMessageNoLookup("error.load.dialogtitle",
                                I18nManager.getText("error.load.othererror") + " " + e.getClass().getName());
index 787dd0bd1cfc8d1df08cdd3caeb74c471a497bcb..47fc7213adb1d447a57e639edbb9e2aaa7c530f9 100644 (file)
@@ -12,12 +12,16 @@ import tim.prune.data.Field;
  */
 public class KmlHandler extends XmlHandler
 {
-       private boolean _insidePlacemark = false;
-       private boolean _insideName = false;
        private boolean _insideCoordinates = false;
-       private String _name = null;
+       private String _value = null;
+       private String _name = null, _desc = null;
+       private String _imgLink = null;
        private StringBuffer _coordinates = null;
        private ArrayList<String[]> _pointList = new ArrayList<String[]>();
+       private ArrayList<String> _linkList = new ArrayList<String>();
+       // variables for gx extensions
+       private ArrayList<String> _whenList = new ArrayList<String>();
+       private ArrayList<String> _whereList = new ArrayList<String>();
 
 
        /**
@@ -25,13 +29,12 @@ public class KmlHandler extends XmlHandler
         * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
         */
        public void startElement(String uri, String localName, String qName,
-                       Attributes attributes) throws SAXException
+               Attributes attributes) throws SAXException
        {
                String tagName = localName;
                if (tagName == null || tagName.equals("")) {tagName = qName;}
-               if (tagName.equalsIgnoreCase("Placemark")) _insidePlacemark = true;
-               else if (tagName.equalsIgnoreCase("coordinates")) {_insideCoordinates = true; _coordinates = null;}
-               else if (tagName.equalsIgnoreCase("name")) {_insideName = true; _name = null;}
+               if (tagName.equalsIgnoreCase("coordinates")) {_insideCoordinates = true; _coordinates = null;}
+               _value = null;
                super.startElement(uri, localName, qName, attributes);
        }
 
@@ -48,10 +51,23 @@ public class KmlHandler extends XmlHandler
                if (tagName.equalsIgnoreCase("Placemark"))
                {
                        processPlacemark();
-                       _insidePlacemark = false;
+                       _name = _desc = _imgLink = null;
                }
                else if (tagName.equalsIgnoreCase("coordinates")) _insideCoordinates = false;
-               else if (tagName.equalsIgnoreCase("name")) _insideName = false;
+               else if (tagName.equalsIgnoreCase("name")) _name = _value;
+               else if (tagName.equalsIgnoreCase("description")) {
+                       _desc = _value;
+                       _imgLink = getImgLink(_desc);
+               }
+               else if (tagName.equalsIgnoreCase("when")) {
+                       _whenList.add(_value);
+               }
+               else if (tagName.equalsIgnoreCase("gx:coord")) {
+                       _whereList.add(_value);
+               }
+               else if (tagName.equalsIgnoreCase("gx:Track")) {
+                       processGxTrack();
+               }
                super.endElement(uri, localName, qName);
        }
 
@@ -63,18 +79,19 @@ public class KmlHandler extends XmlHandler
        public void characters(char[] ch, int start, int length)
                        throws SAXException
        {
-               if (_insidePlacemark && (_insideName || _insideCoordinates))
+               String val = new String(ch, start, length);
+               if (_insideCoordinates)
                {
-                       String value = new String(ch, start, length);
-                       if (_insideName) {_name = value;}
-                       else if (_insideCoordinates)
-                       {
-                               if (_coordinates == null)
-                               {
-                                       _coordinates = new StringBuffer();
-                               }
-                               _coordinates.append(value);
+                       if (_coordinates == null) {
+                               _coordinates = new StringBuffer();
                        }
+                       _coordinates.append(val);
+               }
+               else
+               {
+                       // Store string in _value
+                       if (_value == null) _value = val;
+                       else _value = _value + val;
                }
                super.characters(ch, start, length);
        }
@@ -92,7 +109,8 @@ public class KmlHandler extends XmlHandler
                if (numPoints == 1)
                {
                        // Add single waypoint to list
-                       _pointList.add(makeStringArray(allCoords, _name));
+                       _pointList.add(makeStringArray(allCoords, _name, _desc));
+                       _linkList.add(_imgLink);
                }
                else if (numPoints > 1)
                {
@@ -102,28 +120,94 @@ public class KmlHandler extends XmlHandler
                        {
                                if (coordArray[p] != null && coordArray[p].trim().length()>3)
                                {
-                                       String[] pointArray = makeStringArray(coordArray[p], null);
-                                       if (firstPoint) {pointArray[4] = "1";} // start of segment flag
+                                       String[] pointArray = makeStringArray(coordArray[p], null, null);
+                                       if (firstPoint) {pointArray[5] = "1";} // start of segment flag
                                        firstPoint = false;
                                        _pointList.add(pointArray);
                                }
+                               _linkList.add(null);
                        }
                }
        }
 
+       /**
+        * Process a Gx track including timestamps
+        */
+       private void processGxTrack()
+       {
+               if (_whenList.size() > 0 && _whenList.size() == _whereList.size())
+               {
+                       // Add each of the unnamed track points to list
+                       boolean firstPoint = true;
+                       final int numPoints = _whenList.size();
+                       for (int p=0; p < numPoints; p++)
+                       {
+                               String when  = _whenList.get(p);
+                               String where = _whereList.get(p);
+                               if (where != null)
+                               {
+                                       String[] coords = where.split(" ");
+                                       if (coords.length == 3)
+                                       {
+                                               String[] pointArray = new String[7];
+                                               pointArray[0] = coords[0];
+                                               pointArray[1] = coords[1];
+                                               pointArray[2] = coords[2];
+                                               // leave name and description empty
+                                               if (firstPoint) {pointArray[5] = "1";} // start of segment flag
+                                               firstPoint = false;
+                                               pointArray[6] = when; // timestamp
+                                               _pointList.add(pointArray);
+                                       }
+                               }
+                               _linkList.add(null);
+                       }
+               }
+               _whenList.clear();
+               _whereList.clear();
+       }
+
+       /**
+        * Extract an image link from the point description
+        * @param inDesc description tag contents
+        * @return image link if found or null
+        */
+       private static String getImgLink(String inDesc)
+       {
+               if (inDesc == null || inDesc.equals("")) {return null;}
+               // Pull out <img tag from description (if any)
+               int spos = inDesc.indexOf("<img");
+               int epos = inDesc.indexOf('>', spos + 10);
+               if (spos < 0 || epos < 0) return null;
+               String imgtag = inDesc.substring(spos + 4, epos);
+               // Find the src attribute from img tag
+               int quotepos = imgtag.toLowerCase().indexOf("src=");
+               if (quotepos < 0) return null;
+               // source may be quoted with single or double quotes
+               char quotechar = imgtag.charAt(quotepos + 4);
+               int equotepos = imgtag.indexOf(quotechar, quotepos + 7);
+               if (equotepos < 0) return null;
+               return imgtag.substring(quotepos + 5, equotepos);
+       }
 
        /**
         * Construct the String array for the given coordinates and name
         * @param inCoordinates coordinate string in Kml format
         * @param inName name of waypoint, or null if track point
+        * @param inDesc description of waypoint, if any
         * @return String array for point
         */
-       private static String[] makeStringArray(String inCoordinates, String inName)
+       private static String[] makeStringArray(String inCoordinates,
+               String inName, String inDesc)
        {
-               String[] result = new String[5];
+               String[] result = new String[7];
                String[] values = inCoordinates.split(",");
-               if (values.length == 3) {System.arraycopy(values, 0, result, 0, 3);}
+               final int numValues = values.length;
+               if (numValues == 3 || numValues == 2) {
+                       System.arraycopy(values, 0, result, 0, numValues);
+               }
                result[3] = inName;
+               result[4] = inDesc;
                return result;
        }
 
@@ -133,7 +217,8 @@ public class KmlHandler extends XmlHandler
         */
        public Field[] getFieldArray()
        {
-               final Field[] fields = {Field.LONGITUDE, Field.LATITUDE, Field.ALTITUDE, Field.WAYPT_NAME, Field.NEW_SEGMENT};
+               final Field[] fields = {Field.LONGITUDE, Field.LATITUDE, Field.ALTITUDE,
+                       Field.WAYPT_NAME, Field.DESCRIPTION, Field.NEW_SEGMENT, Field.TIMESTAMP};
                return fields;
        }
 
@@ -147,11 +232,26 @@ public class KmlHandler extends XmlHandler
                int numPoints = _pointList.size();
                // construct data array
                String[][] result = new String[numPoints][];
-               for (int i=0; i<numPoints; i++)
-               {
+               for (int i=0; i<numPoints; i++) {
                        result[i] = _pointList.get(i);
                }
                return result;
        }
 
+       /**
+        * @return array of links, or null if none
+        */
+       public String[] getLinkArray()
+       {
+               int numPoints = _linkList.size();
+               boolean hasLink = false;
+               String[] result = new String[numPoints];
+               for (int i=0; i<numPoints; i++)
+               {
+                       result[i] = _linkList.get(i);
+                       if (result[i] != null) {hasLink = true;}
+               }
+               if (!hasLink) {result = null;}
+               return result;
+       }
 }
index 454149f2c35cd432761edde2c8d271c50d2b3b15..4c4239d6b2081d2ca2799d6d38a6fe8136b659e1 100644 (file)
@@ -14,6 +14,7 @@ import tim.prune.App;
 import tim.prune.I18nManager;
 import tim.prune.data.Altitude;
 import tim.prune.data.SourceInfo;
+import tim.prune.load.MediaLinkInfo;
 
 /**
  * Class for handling loading of Xml files, and passing the
@@ -85,7 +86,8 @@ public class XmlFileLoader extends DefaultHandler implements Runnable
                                SourceInfo sourceInfo = new SourceInfo(_file,
                                        (_handler instanceof GpxHandler?SourceInfo.FILE_TYPE.GPX:SourceInfo.FILE_TYPE.KML));
                                _app.informDataLoaded(_handler.getFieldArray(), _handler.getDataArray(),
-                                       Altitude.Format.METRES, sourceInfo, _handler.getTrackNameList(), _handler.getLinkArray());
+                                       Altitude.Format.METRES, sourceInfo, _handler.getTrackNameList(),
+                                       new MediaLinkInfo(_handler.getLinkArray()));
                        }
                }
                catch (Exception e)
index 20b3ab2f753d69d302cb27cb13098a8109ad3069..88a3d87706943ad1a5ad17b8d3fbe913e35d3ba9 100644 (file)
@@ -13,6 +13,7 @@ import javax.xml.parsers.SAXParserFactory;
 import tim.prune.App;
 import tim.prune.data.Altitude;
 import tim.prune.data.SourceInfo;
+import tim.prune.load.MediaLinkInfo;
 
 /**
  * Class to handle the loading of zipped xml files
@@ -62,12 +63,14 @@ public class ZipFileLoader
                                                if (handler == null) {
                                                        _app.showErrorMessage("error.load.dialogtitle", "error.load.othererror");
                                                }
-                                               else {
+                                               else
+                                               {
                                                        // Send back to app
                                                        SourceInfo sourceInfo = new SourceInfo(inFile,
                                                                (handler instanceof GpxHandler?SourceInfo.FILE_TYPE.GPX:SourceInfo.FILE_TYPE.KML));
                                                        _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
-                                                               Altitude.Format.METRES, sourceInfo, handler.getTrackNameList(), handler.getLinkArray());
+                                                               Altitude.Format.METRES, sourceInfo, handler.getTrackNameList(),
+                                                               new MediaLinkInfo(inFile, handler.getLinkArray()));
                                                        xmlFound = true;
                                                }
                                        }
@@ -110,7 +113,8 @@ public class ZipFileLoader
                                                if (handler == null) {
                                                        _app.showErrorMessage("error.load.dialogtitle", "error.load.othererror");
                                                }
-                                               else {
+                                               else
+                                               {
                                                        // Send back to app
                                                        _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
                                                                Altitude.Format.METRES, new SourceInfo("gpsies", SourceInfo.FILE_TYPE.GPSIES),
index ccdc8cbebdf35897e79bba10fef58279183b5c0a..22c8d81bb40ff29f5062815106ef1d05edd3bb83 100644 (file)
@@ -1,23 +1,23 @@
-Prune version 12
-================
+GpsPrune version 13
+===================
 
-Prune is an application for viewing, editing and managing coordinate data from GPS systems,
+GpsPrune is an application for viewing, editing and managing coordinate data from GPS systems,
 including format conversion, charting and photo correlation.
-Full details can be found at http://activityworkshop.net/software/prune/
+Full details can be found at http://activityworkshop.net/software/gpsprune/
 
-Prune is copyright 2006-2010 activityworkshop.net and distributed under the terms of the Gnu GPL version 2.
+GpsPrune is copyright 2006-2011 activityworkshop.net and distributed under the terms of the Gnu GPL version 2.
 You may freely use the software, and may help others to freely use it too.  For further information
 on your rights and how they are protected, see the included license.txt file.
 
-Prune comes without warranty and without guarantee - the authors cannot be held responsible for
+GpsPrune comes without warranty and without guarantee - the authors cannot be held responsible for
 losses incurred through use of the program, however caused.
 
 
 Running
 =======
 
-To run Prune from the jar file, simply call it from a command prompt or shell:
-   java -jar prune_12.jar
+To run GpsPrune from the jar file, simply call it from a command prompt or shell:
+   java -jar gpsprune_13.jar
 
 If the jar file is saved in a different directory, you will need to include the path.
 Depending on your system settings, you may be able to click or double-click on the jar file
@@ -25,7 +25,24 @@ in a file manager window to execute it.  A shortcut, menu item, alias, desktop i
 or other link can of course be made should you wish.
 
 To specify a language other than the default, use an additional parameter, eg:
-   java -jar prune_12.jar --lang=DE
+   java -jar gpsprune_13.jar --lang=DE
+
+
+New with version 13
+===================
+The following features were added since version 12:
+  - Name change from Prune to GpsPrune
+  - Handling of description field for waypoints
+  - Opening of images from within kmz files, zip files and from http links
+  - Compression using Douglas-Peucker algorithm
+  - Option to save settings automatically on exit
+  - Dialog to show the local tile cache, report sizes and allow deletion
+    of tiles, either deleting whole tilesets or individual tiles older than
+    a specified number of days
+  - Checkbox on GPX export to specify UTF-8 rather than default system encoding
+  - Importing of files through GPSBabel
+  - List of recently used files in the menu
+  - Display of bearing at which a photo was taken (display only)
 
 New with version 12
 ===================
@@ -182,8 +199,8 @@ To obtain the source code (if it wasn't included in your jar file), or for furth
 please visit the website:  http://activityworkshop.net/
 
 You will find there user guides, screenshots and demo videos illustrating the major features.
-As Prune is further developed, subsequent versions of the program will also be made freely
+As GpsPrune is further developed, subsequent versions of the program will also be made freely
 available at this website.
 
-You can also provide feedback on Prune, and find out more about contributing to the development,
+You can also provide feedback on GpsPrune, and find out more about contributing to the development,
 especially with regard to language translations.
index bc8d220c41ac7559f7695e107272bd04b71f49a1..020ef537ff4fa3f936c6e23cc1032bd0abb360ca 100644 (file)
@@ -296,6 +296,10 @@ public class ExifSaver implements Runnable
         */
        private boolean savePhoto(Photo inPhoto, boolean inOverwriteFlag, boolean inForceFlag)
        {
+               // If photos don't have a file, then can't save them
+               if (inPhoto.getFile() == null) {
+                       return false;
+               }
                // Check whether photo file still exists
                if (!inPhoto.getFile().exists())
                {
index f2ea066179efed753aef009243bc4ab174b12ba5..debe0e799bb1134416b950ca29700c7c111d7143 100644 (file)
@@ -40,6 +40,7 @@ import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
 import tim.prune.data.FieldList;
+import tim.prune.data.RecentFile;
 import tim.prune.data.Timestamp;
 import tim.prune.data.Track;
 import tim.prune.load.GenericFileFilter;
@@ -527,7 +528,10 @@ public class FileSaver
                                }
                                // Store directory in config for later
                                Config.setConfigString(Config.KEY_TRACK_DIR, saveFile.getParentFile().getAbsolutePath());
+                               // Add to recent file list
+                               Config.getRecentFileList().addFile(new RecentFile(inSaveFile, true));
                                // Save successful
+                               UpdateMessageBroker.informSubscribers();
                                UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
                                         + " " + numSaved + " " + I18nManager.getText("confirm.save.ok2")
                                         + " " + saveFile.getAbsolutePath());
index fd4c869c03fac79608b194eb17ca3ffdf0720b08..a7f2823c42a2d5dfbd6b5766a4ec5fd619ed3262 100644 (file)
@@ -16,6 +16,7 @@ import java.nio.charset.Charset;
 import javax.swing.BorderFactory;
 import javax.swing.Box;
 import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JDialog;
@@ -24,26 +25,30 @@ import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
+import javax.swing.JRadioButton;
 import javax.swing.JTextField;
+import javax.swing.border.EtchedBorder;
 
 import tim.prune.App;
 import tim.prune.GenericFunction;
-import tim.prune.GpsPruner;
+import tim.prune.GpsPrune;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
 import tim.prune.config.Config;
 import tim.prune.data.Altitude;
-import tim.prune.data.AudioFile;
+import tim.prune.data.AudioClip;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
-import tim.prune.data.MediaFile;
+import tim.prune.data.MediaObject;
 import tim.prune.data.Photo;
+import tim.prune.data.RecentFile;
 import tim.prune.data.Timestamp;
 import tim.prune.data.TrackInfo;
 import tim.prune.gui.DialogCloser;
 import tim.prune.load.GenericFileFilter;
 import tim.prune.save.xml.GpxCacherList;
+import tim.prune.save.xml.XmlUtils;
 
 
 /**
@@ -59,10 +64,13 @@ public class GpxExporter extends GenericFunction implements Runnable
        private PointTypeSelector _pointTypeSelector = null;
        private JCheckBox _timestampsCheckbox = null;
        private JCheckBox _copySourceCheckbox = null;
+       private JPanel _encodingsPanel = null;
+       private JRadioButton _useSystemRadio = null, _forceUtf8Radio = null;
        private File _exportFile = null;
+       private static String _systemEncoding = null;
 
        /** this program name */
-       private static final String GPX_CREATOR = "Prune v" + GpsPruner.VERSION_NUMBER + " activityworkshop.net";
+       private static final String GPX_CREATOR = "GpsPrune v" + GpsPrune.VERSION_NUMBER + " activityworkshop.net";
 
 
        /**
@@ -91,10 +99,16 @@ public class GpxExporter extends GenericFunction implements Runnable
                        _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
                        _dialog.setLocationRelativeTo(_parentFrame);
                        _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+                       _systemEncoding = getSystemEncoding();
                        _dialog.getContentPane().add(makeDialogComponents());
                        _dialog.pack();
                }
                _pointTypeSelector.init(_app.getTrackInfo());
+               _encodingsPanel.setVisible(!isSystemUtf8());
+               if (!isSystemUtf8()) {
+                       _useSystemRadio.setText(I18nManager.getText("dialog.exportgpx.encoding.system")
+                               + " (" + (_systemEncoding == null ? "unknown" : _systemEncoding) + ")");
+               }
                _dialog.setVisible(true);
        }
 
@@ -109,7 +123,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                dialogPanel.setLayout(new BorderLayout());
                JPanel mainPanel = new JPanel();
                mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
-               // Make a central panel with the text boxes
+               // Make a panel for the name/desc text boxes
                JPanel descPanel = new JPanel();
                descPanel.setLayout(new GridLayout(2, 2));
                descPanel.add(new JLabel(I18nManager.getText("dialog.exportgpx.name")));
@@ -132,6 +146,28 @@ public class GpxExporter extends GenericFunction implements Runnable
                _copySourceCheckbox.setSelected(true);
                checkPanel.add(_copySourceCheckbox);
                mainPanel.add(checkPanel);
+               // panel for selecting character encoding
+               _encodingsPanel = new JPanel();
+               if (!isSystemUtf8())
+               {
+                       // only add this panel if system isn't utf8 (or can't be identified yet)
+                       _encodingsPanel.setBorder(BorderFactory.createCompoundBorder(
+                               BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(4, 4, 4, 4)));
+                       _encodingsPanel.setLayout(new BorderLayout());
+                       _encodingsPanel.add(new JLabel(I18nManager.getText("dialog.exportgpx.encoding")), BorderLayout.NORTH);
+                       JPanel radioPanel = new JPanel();
+                       radioPanel.setLayout(new FlowLayout());
+                       ButtonGroup radioGroup = new ButtonGroup();
+                       _useSystemRadio = new JRadioButton(I18nManager.getText("dialog.exportgpx.encoding.system"));
+                       _forceUtf8Radio = new JRadioButton(I18nManager.getText("dialog.exportgpx.encoding.utf8"));
+                       radioGroup.add(_useSystemRadio);
+                       radioGroup.add(_forceUtf8Radio);
+                       radioPanel.add(_useSystemRadio);
+                       radioPanel.add(_forceUtf8Radio);
+                       _useSystemRadio.setSelected(true);
+                       _encodingsPanel.add(radioPanel, BorderLayout.CENTER);
+                       mainPanel.add(_encodingsPanel);
+               }
                dialogPanel.add(mainPanel, BorderLayout.CENTER);
 
                // close dialog if escape pressed
@@ -168,7 +204,8 @@ public class GpxExporter extends GenericFunction implements Runnable
        private void startExport()
        {
                // OK pressed, so check selections
-               if (!_pointTypeSelector.getAnythingSelected()) {
+               if (!_pointTypeSelector.getAnythingSelected())
+               {
                        JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.notypesselected"),
                                I18nManager.getText("dialog.saveoptions.title"), JOptionPane.WARNING_MESSAGE);
                        return;
@@ -183,6 +220,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                }
        }
 
+
        /**
         * Select a GPX file to save to
         * @param inParentFrame parent frame for file chooser dialog
@@ -234,6 +272,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                return saveFile;
        }
 
+
        /**
         * Run method for controlling separate thread for exporting
         */
@@ -242,8 +281,11 @@ public class GpxExporter extends GenericFunction implements Runnable
                OutputStreamWriter writer = null;
                try
                {
-                       // normal writing to file
-                       writer = new OutputStreamWriter(new FileOutputStream(_exportFile));
+                       // normal writing to file - firstly specify UTF8 encoding if requested
+                       if (_forceUtf8Radio != null && _forceUtf8Radio.isSelected())
+                               writer = new OutputStreamWriter(new FileOutputStream(_exportFile), "UTF-8");
+                       else
+                               writer = new OutputStreamWriter(new FileOutputStream(_exportFile));
                        final boolean[] saveFlags = {_pointTypeSelector.getTrackpointsSelected(), _pointTypeSelector.getWaypointsSelected(),
                                _pointTypeSelector.getPhotopointsSelected(), _pointTypeSelector.getAudiopointsSelected(),
                                _pointTypeSelector.getJustSelection(), _timestampsCheckbox.isSelected()};
@@ -255,7 +297,10 @@ public class GpxExporter extends GenericFunction implements Runnable
                        writer.close();
                        // Store directory in config for later
                        Config.setConfigString(Config.KEY_TRACK_DIR, _exportFile.getParentFile().getAbsolutePath());
+                       // Add to recent file list
+                       Config.getRecentFileList().addFile(new RecentFile(_exportFile, true));
                        // Show confirmation
+                       UpdateMessageBroker.informSubscribers();
                        UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
                                 + " " + numPoints + " " + I18nManager.getText("confirm.save.ok2")
                                 + " " + _exportFile.getAbsolutePath());
@@ -300,7 +345,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                inWriter.write(getXmlHeaderString(inWriter));
                inWriter.write(getGpxHeaderString(gpxCachers));
                // Name field
-               String trackName = "PruneTrack";
+               String trackName = "GpsPruneTrack";
                if (inName != null && !inName.equals(""))
                {
                        trackName = inName;
@@ -310,7 +355,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                }
                // Description field
                inWriter.write("\t<desc>");
-               inWriter.write((inDesc != null && !inDesc.equals(""))?inDesc:"Export from Prune");
+               inWriter.write((inDesc != null && !inDesc.equals(""))?inDesc:"Export from GpsPrune");
                inWriter.write("</desc>\n");
 
                int i = 0;
@@ -333,21 +378,20 @@ public class GpxExporter extends GenericFunction implements Runnable
                for (i=0; i<numPoints; i++)
                {
                        point = inInfo.getTrack().getPoint(i);
-                       if (!exportSelection || (i>=selStart && i<=selEnd)) {
+                       if (!exportSelection || (i>=selStart && i<=selEnd))
+                       {
                                // Make a wpt element for each waypoint
-                               if (point.isWaypoint()) {
-                                       if (exportWaypoints)
-                                       {
-                                               String pointSource = (inUseCopy?getPointSource(gpxCachers, point):null);
-                                               if (pointSource != null) {
-                                                       inWriter.write(pointSource);
-                                                       inWriter.write('\n');
-                                               }
-                                               else {
-                                                       exportWaypoint(point, inWriter, exportTimestamps, exportPhotos, exportAudios);
-                                               }
-                                               numSaved++;
+                               if (point.isWaypoint() && exportWaypoints)
+                               {
+                                       String pointSource = (inUseCopy?getPointSource(gpxCachers, point):null);
+                                       if (pointSource != null) {
+                                               inWriter.write(pointSource);
+                                               inWriter.write('\n');
+                                       }
+                                       else {
+                                               exportWaypoint(point, inWriter, exportTimestamps, exportPhotos, exportAudios);
                                        }
+                                       numSaved++;
                                }
                        }
                }
@@ -369,6 +413,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                return numSaved;
        }
 
+
        /**
         * Loop through the track outputting the relevant track points
         * @param inWriter writer object for output
@@ -451,7 +496,12 @@ public class GpxExporter extends GenericFunction implements Runnable
                source = replaceGpxTags(source, "lon=\"", "\"", inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                source = replaceGpxTags(source, "<ele>", "</ele>", inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
                source = replaceGpxTags(source, "<time>", "</time>", inPoint.getTimestamp().getText(Timestamp.FORMAT_ISO_8601));
-               if (inPoint.isWaypoint()) {source = replaceGpxTags(source, "<name>", "</name>", inPoint.getWaypointName());}  // only for waypoints
+               if (inPoint.isWaypoint())
+               {
+                       source = replaceGpxTags(source, "<name>", "</name>", inPoint.getWaypointName());
+                       source = replaceGpxTags(source, "<description>", "</description>",
+                               XmlUtils.fixCdata(inPoint.getFieldValue(Field.DESCRIPTION)));
+               }
                // photo / audio links
                if (source != null && (inPoint.hasMedia() || source.indexOf("</link>") > 0)) {
                        source = replaceMediaLinks(source, makeMediaLink(inPoint));
@@ -494,6 +544,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                return null;
        }
 
+
        /**
         * Replace the media tags in the given XML string
         * @param inSource source XML for point
@@ -531,19 +582,73 @@ public class GpxExporter extends GenericFunction implements Runnable
                return null;
        }
 
+
        /**
         * Get the header string for the xml document including encoding
         * @param inWriter writer object
         * @return header string defining encoding
         */
        private static String getXmlHeaderString(OutputStreamWriter inWriter)
+       {
+               return "<?xml version=\"1.0\" encoding=\"" + getEncoding(inWriter) + "\"?>\n";
+       }
+
+
+       /**
+        * Get the default system encoding using a writer
+        * @param inWriter writer object
+        * @return string defining encoding
+        */
+       private static String getEncoding(OutputStreamWriter inWriter)
        {
                String encoding = inWriter.getEncoding();
                try {
                        encoding =  Charset.forName(encoding).name();
                }
                catch (Exception e) {} // ignore failure to find encoding
-               return "<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>\n";
+               // Hack to fix bugs with Mac OSX (which reports MacRoman but is actually UTF-8)
+               if (encoding == null || encoding.toLowerCase().startsWith("macroman")) {
+                       encoding = "UTF-8";
+               }
+               return encoding;
+       }
+
+
+       /**
+        * Use a temporary file to obtain the name of the default system encoding
+        * @return name of default system encoding, or null if write failed
+        */
+       private static String getSystemEncoding()
+       {
+               File tempFile = null;
+               String encoding = null;
+               try
+               {
+                       tempFile = File.createTempFile("prune", null);
+                       OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(tempFile));
+                       encoding = getEncoding(writer);
+                       writer.close();
+               }
+               catch (IOException e) {} // value stays null
+               // Delete temp file
+               if (tempFile != null && tempFile.exists()) {
+                       if (!tempFile.delete()) {
+                               System.err.println("Cannot delete temp file: " + tempFile.getAbsolutePath());
+                       }
+               }
+               // If writing failed (eg permissions) then just ask system for default
+               if (encoding == null) encoding = Charset.defaultCharset().name();
+               return encoding;
+       }
+
+       /**
+        * Creates temp file if necessary to check system encoding
+        * @return true if system uses UTF-8 by default
+        */
+       private static boolean isSystemUtf8()
+       {
+               if (_systemEncoding == null) _systemEncoding = getSystemEncoding();
+               return (_systemEncoding != null && _systemEncoding.toUpperCase().equals("UTF-8"));
        }
 
        /**
@@ -566,6 +671,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                return gpxHeader + "\n";
        }
 
+
        /**
         * Export the specified waypoint into the file
         * @param inPoint waypoint to export
@@ -602,6 +708,14 @@ public class GpxExporter extends GenericFunction implements Runnable
                inWriter.write("\t\t<name>");
                inWriter.write(inPoint.getWaypointName().trim());
                inWriter.write("</name>\n");
+               // description, if any
+               String desc = XmlUtils.fixCdata(inPoint.getFieldValue(Field.DESCRIPTION));
+               if (desc != null && !desc.equals(""))
+               {
+                       inWriter.write("\t\t<description>");
+                       inWriter.write(desc);
+                       inWriter.write("</description>\n");
+               }
                // Media links, if any
                if (inPhoto && inPoint.getPhoto() != null)
                {
@@ -672,6 +786,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                inWriter.write("</trkpt>\n");
        }
 
+
        /**
         * Make the xml for the media link(s)
         * @param inPoint point to generate text for
@@ -680,7 +795,7 @@ public class GpxExporter extends GenericFunction implements Runnable
        private static String makeMediaLink(DataPoint inPoint)
        {
                Photo photo = inPoint.getPhoto();
-               AudioFile audio = inPoint.getAudio();
+               AudioClip audio = inPoint.getAudio();
                if (photo == null && audio == null) {
                        return null;
                }
@@ -699,8 +814,15 @@ public class GpxExporter extends GenericFunction implements Runnable
         * @param inMedia media item, either photo or audio
         * @return link for this media
         */
-       private static String makeMediaLink(MediaFile inMedia)
+       private static String makeMediaLink(MediaObject inMedia)
        {
-               return "<link href=\"" + inMedia.getFile().getAbsolutePath() + "\"><text>" + inMedia.getFile().getName() + "</text></link>";
+               if (inMedia.getFile() != null)
+                       // file link
+                       return "<link href=\"" + inMedia.getFile().getAbsolutePath() + "\"><text>" + inMedia.getName() + "</text></link>";
+               if (inMedia.getUrl() != null)
+                       // url link
+                       return "<link href=\"" + inMedia.getUrl() + "\"><text>" + inMedia.getName() + "</text></link>";
+               // No link available, must have been loaded from zip file - no link possible
+               return "";
        }
 }
index 7f90dbc8cca16e897ee70072aabc1e88c8f82b10..e1cc1516ac77e4e8c9da1967f748bd3ee78cd89c 100644 (file)
@@ -45,6 +45,7 @@ import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
+import tim.prune.data.RecentFile;
 import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
 import tim.prune.gui.ColourChooser;
@@ -52,6 +53,7 @@ import tim.prune.gui.ColourPatch;
 import tim.prune.gui.DialogCloser;
 import tim.prune.gui.ImageUtils;
 import tim.prune.load.GenericFileFilter;
+import tim.prune.save.xml.XmlUtils;
 
 /**
  * Class to export track information
@@ -378,7 +380,10 @@ public class KmlExporter extends GenericFunction implements Runnable
                        _imageDimensions = null;
                        // Store directory in config for later
                        Config.setConfigString(Config.KEY_TRACK_DIR, _exportFile.getParentFile().getAbsolutePath());
+                       // Add to recent file list
+                       Config.getRecentFileList().addFile(new RecentFile(_exportFile, true));
                        // show confirmation
+                       UpdateMessageBroker.informSubscribers();
                        UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
                                 + " " + numPoints + " " + I18nManager.getText("confirm.save.ok2")
                                 + " " + _exportFile.getAbsolutePath());
@@ -422,7 +427,7 @@ public class KmlExporter extends GenericFunction implements Runnable
                        inWriter.write(_descriptionField.getText());
                }
                else {
-                       inWriter.write("Export from Prune");
+                       inWriter.write("Export from GpsPrune");
                }
                inWriter.write("</name>\n");
 
@@ -472,7 +477,7 @@ public class KmlExporter extends GenericFunction implements Runnable
                                exportPhotoPoint(point, inWriter, inExportImages, i, photoNum, absoluteAltitudes);
                                numSaved++;
                        }
-                       // Make a blob with description for each audio file
+                       // Make a blob with description for each audio clip
                        if (point.getAudio() != null && writeAudios && writeCurrentPoint)
                        {
                                if (!writtenAudioHeader)
@@ -552,7 +557,7 @@ public class KmlExporter extends GenericFunction implements Runnable
        private void exportWaypoint(DataPoint inPoint, Writer inWriter, boolean inAbsoluteAltitude) throws IOException
        {
                String name = inPoint.getWaypointName().trim();
-               exportNamedPoint(inPoint, inWriter, name, null, null, inAbsoluteAltitude);
+               exportNamedPoint(inPoint, inWriter, name, inPoint.getFieldValue(Field.DESCRIPTION), null, inAbsoluteAltitude);
        }
 
 
@@ -565,8 +570,11 @@ public class KmlExporter extends GenericFunction implements Runnable
         */
        private void exportAudioPoint(DataPoint inPoint, Writer inWriter, boolean inAbsoluteAltitude) throws IOException
        {
-               String name = inPoint.getAudio().getFile().getName();
-               String desc = inPoint.getAudio().getFile().getAbsolutePath();
+               String name = inPoint.getAudio().getName();
+               String desc = null;
+               if (inPoint.getAudio().getFile() != null) {
+                       desc = inPoint.getAudio().getFile().getAbsolutePath();
+               }
                exportNamedPoint(inPoint, inWriter, name, desc, "audio_icon", inAbsoluteAltitude);
        }
 
@@ -585,7 +593,7 @@ public class KmlExporter extends GenericFunction implements Runnable
                int inPointNumber, int inImageNumber, boolean inAbsoluteAltitude)
        throws IOException
        {
-               String name = inPoint.getPhoto().getFile().getName();
+               String name = inPoint.getPhoto().getName();
                String desc = null;
                if (inImageLink)
                {
@@ -593,7 +601,7 @@ public class KmlExporter extends GenericFunction implements Runnable
                        // Create html for the thumbnail images
                        desc = "<![CDATA[<br/><table border='0'><tr><td><center><img src='images/image"
                                + inImageNumber + ".jpg' width='" + imageSize.width + "' height='" + imageSize.height + "'></center></td></tr>"
-                               + "<tr><td><center>" + inPoint.getPhoto().getFile().getName() + "</center></td></tr></table>]]>";
+                               + "<tr><td><center>" + name + "</center></td></tr></table>]]>";
                }
                // Export point
                exportNamedPoint(inPoint, inWriter, name, desc, "camera_icon", inAbsoluteAltitude);
@@ -620,9 +628,9 @@ public class KmlExporter extends GenericFunction implements Runnable
                if (inDesc != null)
                {
                        // Write out description
-                       inWriter.write("<description>");
-                       inWriter.write(inDesc);
-                       inWriter.write("</description>");
+                       inWriter.write("\t\t<description>");
+                       inWriter.write(XmlUtils.fixCdata(inDesc));
+                       inWriter.write("</description>\n");
                }
                if (inStyle != null)
                {
@@ -714,9 +722,9 @@ public class KmlExporter extends GenericFunction implements Runnable
                                ZipEntry entry = new ZipEntry("images/image" + photoNum + ".jpg");
                                inZipStream.putNextEntry(entry);
                                // Load image and write to outstream
-                               ImageIcon icon = new ImageIcon(point.getPhoto().getFile().getAbsolutePath());
+                               ImageIcon icon = point.getPhoto().createImageIcon();
 
-                               // Scale and smooth image to required size
+                               // Scale image to required size TODO: should it also be smoothed, or only if it's smaller than a certain size?
                                BufferedImage bufferedImage = ImageUtils.rotateImage(icon.getImage(),
                                        inThumbWidth, inThumbHeight, point.getPhoto().getRotationDegrees());
                                // Store image dimensions so that it doesn't have to be calculated again for the points
index 34fd2b98206a3592a48a24c691cc6e926b5c9dd6..f42720ef5f05b6cdf1d490a0602961a1bea1ec23 100644 (file)
@@ -22,7 +22,7 @@ public class PhotoTableEntry
                _photo = inPhoto;
                if (inPhoto != null)
                {
-                       _photoName = inPhoto.getFile().getName();
+                       _photoName = inPhoto.getName();
                        _status = getStatusString(inPhoto.getOriginalStatus(), inPhoto.getCurrentStatus());
                }
        }
index 313b72aea19ff9080917377516bc285c532d8cea..e360878006443a82da87f60e7bf38594ae7bcac5 100644 (file)
@@ -377,7 +377,7 @@ public class PovExporter extends Export3dFunction
        private void writeStartOfFile(FileWriter inWriter, double inModelSize, String inLineSeparator)
        throws IOException
        {
-               inWriter.write("// Pov file produced by Prune - see http://activityworkshop.net/");
+               inWriter.write("// Pov file produced by GpsPrune - see http://activityworkshop.net/");
                inWriter.write(inLineSeparator);
                inWriter.write(inLineSeparator);
                // Select font based on user input
index 5bfd7c033adf5a62764304da5fe799666aa93fce..69f51683cfdbd2e508c8bbede28cca83362b45e8 100644 (file)
@@ -316,7 +316,7 @@ public class SvgExporter extends Export3dFunction
        {
                inWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
                inWriter.write(inLineSeparator);
-               inWriter.write("<!-- Svg file produced by Prune - see http://activityworkshop.net/ -->");
+               inWriter.write("<!-- Svg file produced by GpsPrune - see http://activityworkshop.net/ -->");
                inWriter.write(inLineSeparator);
                inWriter.write("<svg width=\"800\" height=\"700\">");
                inWriter.write(inLineSeparator);
diff --git a/tim/prune/save/xml/XmlUtils.java b/tim/prune/save/xml/XmlUtils.java
new file mode 100644 (file)
index 0000000..a4f9cae
--- /dev/null
@@ -0,0 +1,37 @@
+package tim.prune.save.xml;
+
+/**
+ * Collection of utility functions for handling XML
+ */
+public abstract class XmlUtils
+{
+       /** Start of Cdata sequence */
+       private static final String CDATA_START = "<![CDATA[";
+       /** End of Cdata sequence */
+       private static final String CDATA_END = "]]>";
+
+       /**
+        * Fix the CDATA blocks in the given String to give valid xml
+        * @param inString String to modify
+        * @return fixed String
+        */
+       public static String fixCdata(String inString)
+       {
+               if (inString == null) return "";
+               if (inString.indexOf('<') < 0 && inString.indexOf('>') < 0) {
+                       return inString;
+               }
+               String result = inString;
+               // Remove cdata block at start if present
+               if (result.startsWith(CDATA_START)) {
+                       result = result.substring(CDATA_START.length());
+               }
+               // Remove all instances of end block
+               result = result.replaceAll(CDATA_END, "");
+               // Now check whether cdata block is required
+               if (result.indexOf('<') < 0 && result.indexOf('>') < 0) {
+                       return result;
+               }
+               return CDATA_START + result + CDATA_END;
+       }
+}
index e75f02fae273d9a0e7313ab97c3f9cf538cf2ed2..d7feb633de6b11a30beb7b730b62ca09db9042ea 100644 (file)
@@ -2,7 +2,7 @@ package tim.prune.undo;
 \r
 import tim.prune.I18nManager;\r
 import tim.prune.UpdateMessageBroker;\r
-import tim.prune.data.AudioFile;\r
+import tim.prune.data.AudioClip;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.Photo;\r
 import tim.prune.data.TrackInfo;\r
@@ -62,7 +62,7 @@ public class UndoConnectMedia implements UndoOperation
                if (_audioFilename != null)\r
                {\r
                        // Disconnect audio\r
-                       AudioFile audio = _point.getAudio();\r
+                       AudioClip audio = _point.getAudio();\r
                        if (audio != null)\r
                        {\r
                                _point.setAudio(null);\r
index e0c1f9591eeb8be80e9abf2409b35e61d245853f..60cfbe6cd3ddc5338e5e3e93b14641260ef1e8ba 100644 (file)
@@ -1,7 +1,7 @@
 package tim.prune.undo;\r
 \r
 import tim.prune.I18nManager;\r
-import tim.prune.data.AudioFile;\r
+import tim.prune.data.AudioClip;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.TrackInfo;\r
 \r
@@ -60,9 +60,9 @@ public class UndoCorrelateAudios implements UndoOperation
                // restore audio association\r
                for (int i=0; i<_audioPoints.length; i++)\r
                {\r
-                       AudioFile audio = inTrackInfo.getAudioList().getAudio(i);\r
+                       AudioClip audio = inTrackInfo.getAudioList().getAudio(i);\r
                        // Only need to look at connected ones, since correlation wouldn't disconnect\r
-                       if (audio.getCurrentStatus() == AudioFile.Status.CONNECTED)\r
+                       if (audio.getCurrentStatus() == AudioClip.Status.CONNECTED)\r
                        {\r
                                DataPoint prevPoint = _audioPoints[i];\r
                                DataPoint currPoint = audio.getDataPoint();\r
index e413426a075f646948458344233b4707d84c7883..0a4973284dd4c02f32c880a1ed3beb260804dd94 100644 (file)
@@ -2,7 +2,7 @@ package tim.prune.undo;
 \r
 import tim.prune.I18nManager;\r
 import tim.prune.UpdateMessageBroker;\r
-import tim.prune.data.AudioFile;\r
+import tim.prune.data.AudioClip;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.TrackInfo;\r
 \r
@@ -12,7 +12,7 @@ import tim.prune.data.TrackInfo;
 public class UndoDeleteAudio implements UndoOperation\r
 {\r
        private int _audioIndex = -1;\r
-       private AudioFile _audio = null;\r
+       private AudioClip _audio = null;\r
        private int _pointIndex = -1;\r
        private DataPoint _point = null;\r
 \r
@@ -24,7 +24,7 @@ public class UndoDeleteAudio implements UndoOperation
         * @param inPoint data point\r
         * @param inPointIndex index number of point within track\r
         */\r
-       public UndoDeleteAudio(AudioFile inAudio, int inAudioIndex, DataPoint inPoint, int inPointIndex)\r
+       public UndoDeleteAudio(AudioClip inAudio, int inAudioIndex, DataPoint inPoint, int inPointIndex)\r
        {\r
                _audio = inAudio;\r
                _audioIndex = inAudioIndex;\r
@@ -37,7 +37,7 @@ public class UndoDeleteAudio implements UndoOperation
         * @return description of operation including filename\r
         */\r
        public String getDescription() {\r
-               return I18nManager.getText("undo.removeaudio") + " " + _audio.getFile().getName();\r
+               return I18nManager.getText("undo.removeaudio") + " " + _audio.getName();\r
        }\r
 \r
 \r
index 4c37e616faf31f76c320ddaafe69e11edb00b982..5edd37bfb664cb3a65fa1d52d37f097440d0bb97 100644 (file)
@@ -38,7 +38,7 @@ public class UndoDeletePhoto implements UndoOperation
         */\r
        public String getDescription()\r
        {\r
-               String desc = I18nManager.getText("undo.removephoto") + " " + _photo.getFile().getName();\r
+               String desc = I18nManager.getText("undo.removephoto") + " " + _photo.getName();\r
                return desc;\r
        }\r
 \r
index 57abc98814ebef54551fc529f3c49be934d2eca1..adb2ea397d0baffcb3d5f410c850c8d3cc3b3cd1 100644 (file)
@@ -65,7 +65,9 @@ public class UndoDeletePoint implements UndoOperation
                                inTrackInfo.getPhotoList().addPhoto(_point.getPhoto(), _photoIndex);\r
                        }\r
                        // Ensure that photo is associated with point\r
-                       _point.getPhoto().setDataPoint(_point);\r
+                       if (_point.getPhoto().getDataPoint() != _point) {\r
+                               _point.getPhoto().setDataPoint(_point);\r
+                       }\r
                }\r
                // Restore previous status of following track point if necessary\r
                if (!_segmentStart)\r
index 51b310f89ac4e435e401cd28c3c98fddccde21d8..f40ab2d27d5db4c46e76edc4140cae534cfdddaa 100644 (file)
@@ -1,7 +1,7 @@
 package tim.prune.undo;\r
 \r
 import tim.prune.I18nManager;\r
-import tim.prune.data.AudioFile;\r
+import tim.prune.data.AudioClip;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.Photo;\r
 import tim.prune.data.TrackInfo;\r
@@ -13,7 +13,7 @@ public class UndoDisconnectMedia implements UndoOperation
 {\r
        private DataPoint _point = null;\r
        private Photo _photo = null;\r
-       private AudioFile _audio = null;\r
+       private AudioClip _audio = null;\r
        private String _filename = null;\r
 \r
 \r
index c5b49fc29beb3fa9305e2b304ca1d5a70ee813b7..7a48cd22705d93d54b2b66a408b51f7605acecd5 100644 (file)
@@ -8,7 +8,7 @@ import tim.prune.data.TrackInfo;
  */\r
 public class UndoLoadAudios implements UndoOperation\r
 {\r
-       /** Number of audio files added */\r
+       /** Number of audio clips added */\r
        private int _numAudios = -1;\r
 \r
 \r
index 495effa6c3277d55bc75766c1497435a3870eeb1..72cf40f92d68d800d0c3f202f9f4305fa8eb6d82 100644 (file)
@@ -31,7 +31,7 @@ public class UndoRotatePhoto implements UndoOperation
         */\r
        public String getDescription()\r
        {\r
-               return I18nManager.getText("undo.rotatephoto") + " " + _photo.getFile().getName();\r
+               return I18nManager.getText("undo.rotatephoto") + " " + _photo.getName();\r
        }\r
 \r
 \r