]> gitweb.fperrin.net Git - GpsPrune.git/commitdiff
Version 16.3, July 2014
authoractivityworkshop <mail@activityworkshop.net>
Sun, 15 Feb 2015 16:08:22 +0000 (17:08 +0100)
committeractivityworkshop <mail@activityworkshop.net>
Sun, 15 Feb 2015 16:08:22 +0000 (17:08 +0100)
52 files changed:
tim/prune/App.java
tim/prune/DataStatus.java [new file with mode: 0644]
tim/prune/GpsPrune.java
tim/prune/config/Config.java
tim/prune/function/AboutScreen.java
tim/prune/function/AddMapSourceDialog.java
tim/prune/function/PhotoComparer.java
tim/prune/function/ShowThreeDFunction.java
tim/prune/function/srtm/DownloadSrtmFunction.java
tim/prune/function/weather/GetWeatherForecastFunction.java
tim/prune/function/weather/WeatherResults.java
tim/prune/function/weather/WeatherTableModel.java
tim/prune/gui/DisplayUtils.java
tim/prune/gui/TerrainDefinitionPanel.java
tim/prune/gui/images/add_photo_icon.png [changed mode: 0644->0755]
tim/prune/gui/images/add_textfile_icon.png [changed mode: 0644->0755]
tim/prune/gui/map/CloudmadeMapSource.java [deleted file]
tim/prune/gui/map/MapSourceLibrary.java
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_en_US.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_ru.properties
tim/prune/lang/prune-texts_sv.properties
tim/prune/lang/prune-texts_tr.properties
tim/prune/lang/prune-texts_zh.properties
tim/prune/load/BabelFileFormats.java
tim/prune/load/BabelLoadFromFile.java
tim/prune/readme.txt
tim/prune/save/GpsSaver.java
tim/prune/save/GpxExporter.java
tim/prune/save/PovExporter.java
tim/prune/save/xml/ByteBuffer.java [new file with mode: 0644]
tim/prune/save/xml/GpxCacher.java
tim/prune/save/xml/GpxSlicer.java
tim/prune/save/xml/XmlUtils.java
tim/prune/threedee/Java3DWindow.java
tim/prune/threedee/TerrainCache.java [new file with mode: 0644]
tim/prune/threedee/TerrainDefinition.java
tim/prune/threedee/TerrainHelper.java
tim/prune/threedee/ThreeDWindow.java
tim/prune/undo/UndoStack.java [new file with mode: 0644]

index 71bd354172ee3df66957c75b6faf1a8c08369db2..e57dcf6d5d15364fd6c5ede5f509d28728531404 100644 (file)
@@ -60,7 +60,7 @@ public class App
        private FileLoader _fileLoader = null;
        private JpegLoader _jpegLoader = null;
        private FileSaver _fileSaver = null;
-       private Stack<UndoOperation> _undoStack = null;
+       private UndoStack _undoStack = null;
        private boolean _mangleTimestampsConfirmed = false;
        private Viewport _viewport = null;
        private ArrayList<File> _dataFiles = null;
@@ -79,7 +79,7 @@ public class App
        public App(JFrame inFrame)
        {
                _frame = inFrame;
-               _undoStack = new Stack<UndoOperation>();
+               _undoStack = new UndoStack();
                _track = new Track();
                _trackInfo = new TrackInfo(_track);
                FunctionLibrary.initialise(this);
@@ -911,6 +911,12 @@ public class App
                UpdateMessageBroker.informSubscribers();
        }
 
+       /**
+        * @return the current data status, used for later comparison
+        */
+       public DataStatus getCurrentDataStatus() {
+               return new DataStatus(_undoStack.size(), _undoStack.getNumTimesDeleted());
+       }
 
        /**
         * Show a map url in an external browser
diff --git a/tim/prune/DataStatus.java b/tim/prune/DataStatus.java
new file mode 100644 (file)
index 0000000..cacb288
--- /dev/null
@@ -0,0 +1,34 @@
+package tim.prune;
+
+/**
+ * Class to remember the current status of the data,
+ * and make it possible to see whether the data has
+ * changed in any way since the DataStatus was requested
+ */
+public class DataStatus
+{
+       private int _undoSize = 0;
+       private int _deleteCount = 0;
+
+       /**
+        * Constructor
+        * @param inUndoSize current size of undo stack
+        * @param inDeleteCount number of times undo stack has been deleted
+        */
+       public DataStatus(int inUndoSize, int inDeleteCount)
+       {
+               _undoSize = inUndoSize;
+               _deleteCount = inDeleteCount;
+       }
+
+       /**
+        * Has the data changed compared to the previous status?
+        * @param inPreviousStatus previous status obtained from App
+        * @return true if the status is now different
+        */
+       public boolean hasDataChanged(DataStatus inPreviousStatus)
+       {
+               return _undoSize != inPreviousStatus._undoSize
+                       || _deleteCount != inPreviousStatus._deleteCount;
+       }
+}
index 0503ddaaf12d9365230e55853f29c0e285dd16f7..dd907653c10eec569035e6074d6c90df3565862f 100644 (file)
@@ -35,9 +35,9 @@ import tim.prune.gui.profile.ProfileChart;
 public class GpsPrune
 {
        /** Version number of application, used in about screen and for version check */
-       public static final String VERSION_NUMBER = "16";
+       public static final String VERSION_NUMBER = "16.3";
        /** Build number, just used for about screen */
-       public static final String BUILD_NUMBER = "301";
+       public static final String BUILD_NUMBER = "303c";
        /** Static reference to App object */
        private static App APP = null;
 
index 655847cf338cf9b4900cb426c850f1a8248d8681..35f5a311cea8cf8d19cfdb5b825c620e38f48abb 100644 (file)
@@ -45,6 +45,8 @@ public abstract class Config
        public static final String KEY_GPS_FORMAT = "prune.gpsformat";
        /** Key for GPSBabel filter string */
        public static final String KEY_GPSBABEL_FILTER = "prune.gpsbabelfilter";
+       /** Key for GPSBabel import file format */
+       public static final String KEY_IMPORT_FILE_FORMAT = "prune.lastimportfileformat";
        /** Key for Povray font */
        public static final String KEY_POVRAY_FONT = "prune.povrayfont";
        /** Key for the selected unit set */
@@ -169,6 +171,7 @@ public abstract class Config
                props.put(KEY_EXIFTOOL_PATH, "exiftool");
                props.put(KEY_GNUPLOT_PATH, "gnuplot");
                props.put(KEY_GPSBABEL_PATH, "gpsbabel");
+               props.put(KEY_IMPORT_FILE_FORMAT, "-1"); // no file format selected
                props.put(KEY_KMZ_IMAGE_SIZE, "240");
                props.put(KEY_AUTOSAVE_SETTINGS, "0"); // autosave false by default
                props.put(KEY_UNITSET_KEY, "unitset.kilometres"); // metric by default
index 70a9eb35ca6109e1af3abdcd0ae10b798f817e79..5a463a3d61bff35efa3233168728cb409ea28ffc 100644 (file)
@@ -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, \u0440\u0443\u0441\u0441\u043a\u0438\u0439 (russian), \u4e2d\u6587 (chinese), \u65E5\u672C\u8A9E (japanese),<br>" +
-                               " \uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean), schwiizerd\u00FC\u00FCtsch, t\u00FCrk\u00E7e, afrikaans, rom\u00E2n\u0103</p>");
+                               " \uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean), schwiizerd\u00FC\u00FCtsch, t\u00FCrk\u00E7e, afrikaans, rom\u00E2n\u0103, ukrainian</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));
index bcc8b7064bed60cb5f81b5672e560f8600f5c1a8..9207ac5655a82b2464a18daf2d8119cb001225f8 100644 (file)
@@ -1,12 +1,10 @@
 package tim.prune.function;
 
 import java.awt.BorderLayout;
-import java.awt.CardLayout;
 import java.awt.Component;
 import java.awt.FlowLayout;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
-import java.awt.GridLayout;
 import java.awt.Insets;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -24,7 +22,6 @@ import javax.swing.JRadioButton;
 import javax.swing.JTextField;
 
 import tim.prune.I18nManager;
-import tim.prune.gui.map.CloudmadeMapSource;
 import tim.prune.gui.map.MapSource;
 import tim.prune.gui.map.MapSourceLibrary;
 import tim.prune.gui.map.OsmMapSource;
@@ -36,18 +33,12 @@ public class AddMapSourceDialog
 {
        private SetMapBgFunction _parent = null;
        private JDialog _addDialog = null;
-       private JRadioButton[] _sourceTypeRadios = null;
-       private JPanel _cards = null;
        private MapSource _originalSource = null;
        // controls for osm panel
        private JTextField _oNameField = null;
        private JTextField _baseUrlField = null, _topUrlField = null;
        private JRadioButton[] _baseTypeRadios = null, _topTypeRadios = null;
        private JComboBox<Integer> _oZoomCombo = null;
-       // controls for cloudmade panel
-       private JTextField _cNameField = null;
-       private JTextField _cStyleField = null;
-       private JComboBox<Integer> _cZoomCombo = null;
        private JButton _okButton = null;
 
        /** array of file types */
@@ -76,31 +67,9 @@ public class AddMapSourceDialog
        {
                JPanel dialogPanel = new JPanel();
                dialogPanel.setLayout(new BorderLayout());
-               // Top panel with two radio buttons to select source type
-               JPanel radioPanel = new JPanel();
-               ButtonGroup radioGroup = new ButtonGroup();
-               radioPanel.setLayout(new GridLayout(1, 0));
-               _sourceTypeRadios = new JRadioButton[2];
-               _sourceTypeRadios[0] = new JRadioButton("Openstreetmap");
-               radioGroup.add(_sourceTypeRadios[0]);
-               radioPanel.add(_sourceTypeRadios[0]);
-               _sourceTypeRadios[1] = new JRadioButton("Cloudmade");
-               radioGroup.add(_sourceTypeRadios[1]);
-               radioPanel.add(_sourceTypeRadios[1]);
-               _sourceTypeRadios[0].setSelected(true);
-               // listener for clicks on type radios
-               ActionListener typeListener = new ActionListener() {
-                       public void actionPerformed(ActionEvent arg0) {
-                               onRadioClicked();
-                       }
-               };
-               _sourceTypeRadios[0].addActionListener(typeListener);
-               _sourceTypeRadios[1].addActionListener(typeListener);
-               radioPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-               dialogPanel.add(radioPanel, BorderLayout.NORTH);
+               // Top panel with spacer
+               dialogPanel.add(new JLabel(" "), BorderLayout.NORTH);
 
-               _cards = new JPanel();
-               _cards.setLayout(new CardLayout());
                // listener
                KeyAdapter keyListener = new KeyAdapter() {
                        public void keyReleased(KeyEvent e) {
@@ -149,7 +118,7 @@ public class AddMapSourceDialog
                c.gridx = 1; c.weightx = 1.0;
                gbPanel.add(_baseUrlField, c);
                _baseTypeRadios = new JRadioButton[3];
-               radioGroup = new ButtonGroup();
+               ButtonGroup radioGroup = new ButtonGroup();
                for (int i=0; i<3; i++)
                {
                        _baseTypeRadios[i] = new JRadioButton(FILE_TYPES[i]);
@@ -190,35 +159,11 @@ public class AddMapSourceDialog
                c.gridx = 1;
                gbPanel.add(_oZoomCombo, c);
                osmPanel.add(gbPanel, BorderLayout.NORTH);
-               _cards.add(osmPanel, "card1");
 
-               // Panel for cloudmade source
-               JPanel cloudPanel = new JPanel();
-               cloudPanel.setBorder(BorderFactory.createEmptyBorder(6, 3, 4, 3));
-               // Use a gridlayout inside a borderlayout to avoid stretching
-               cloudPanel.setLayout(new BorderLayout());
-               JPanel cloudGridPanel = new JPanel();
-               cloudGridPanel.setLayout(new GridLayout(0, 2, 5, 5));
-               cloudGridPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.sourcename")));
-               _cNameField = new JTextField(18);
-               _cNameField.addKeyListener(keyListener);
-               cloudGridPanel.add(_cNameField);
-               cloudGridPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.cloudstyle")));
-               _cStyleField = new JTextField(18);
-               _cStyleField.addKeyListener(keyListener);
-               cloudGridPanel.add(_cStyleField);
-               cloudGridPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.maxzoom")));
-               _cZoomCombo = new JComboBox<Integer>();
-               for (int i=10; i<=20; i++) {
-                       _cZoomCombo.addItem(i);
-               }
-               cloudGridPanel.add(_cZoomCombo);
-               cloudPanel.add(cloudGridPanel, BorderLayout.NORTH);
-               _cards.add(cloudPanel, "card2");
                // cards
                JPanel holderPanel = new JPanel();
                holderPanel.setLayout(new BorderLayout());
-               holderPanel.add(_cards, BorderLayout.NORTH);
+               holderPanel.add(osmPanel, BorderLayout.NORTH);
                dialogPanel.add(holderPanel, BorderLayout.CENTER);
 
                // button panel at bottom
@@ -267,13 +212,7 @@ public class AddMapSourceDialog
                _topUrlField.setText("");
                _topTypeRadios[0].setSelected(true);
                _oZoomCombo.setSelectedIndex(8);
-               _cNameField.setText("");
-               _cStyleField.setText("");
-               _cZoomCombo.setSelectedIndex(8);
                _okButton.setEnabled(false);
-               for (int i=0; i<2; i++) {
-                       _sourceTypeRadios[i].setEnabled(true);
-               }
                _addDialog.setVisible(true);
        }
 
@@ -287,67 +226,32 @@ public class AddMapSourceDialog
                        clearAllFields();
                        return;
                }
-               boolean sourceFound = false;
-               // See if it's a cloudmade source
+
+               // See if it's an osm source
                try
                {
-                       CloudmadeMapSource cloudSource = (CloudmadeMapSource) _originalSource;
-                       sourceFound = true;
-                       _cNameField.setText(cloudSource.getName());
-                       _cStyleField.setText(cloudSource.getStyle());
-                       _cZoomCombo.setSelectedIndex(getZoomIndex(cloudSource.getMaxZoomLevel()));
-                       _sourceTypeRadios[1].setSelected(true);
+                       OsmMapSource osmSource = (OsmMapSource) _originalSource;
+                       _oNameField.setText(osmSource.getName());
+                       _baseUrlField.setText(osmSource.getBaseUrl(0));
+                       int baseType = getBaseType(osmSource.getFileExtension(0));
+                       _baseTypeRadios[baseType].setSelected(true);
+                       _topUrlField.setText(osmSource.getNumLayers()==0?"":osmSource.getBaseUrl(1));
+                       int topType = getBaseType(osmSource.getFileExtension(1));
+                       _topTypeRadios[topType].setSelected(true);
+                       _oZoomCombo.setSelectedIndex(getZoomIndex(osmSource.getMaxZoomLevel()));
                }
                catch (ClassCastException cce) {} // ignore, sourceFound flag stays false
 
-               // See if it's an osm source
-               if (!sourceFound)
-               {
-                       try
-                       {
-                               OsmMapSource osmSource = (OsmMapSource) _originalSource;
-                               sourceFound = true;
-                               _oNameField.setText(osmSource.getName());
-                               _baseUrlField.setText(osmSource.getBaseUrl(0));
-                               int baseType = getBaseType(osmSource.getFileExtension(0));
-                               _baseTypeRadios[baseType].setSelected(true);
-                               _topUrlField.setText(osmSource.getNumLayers()==0?"":osmSource.getBaseUrl(1));
-                               int topType = getBaseType(osmSource.getFileExtension(1));
-                               _topTypeRadios[topType].setSelected(true);
-                               _oZoomCombo.setSelectedIndex(getZoomIndex(osmSource.getMaxZoomLevel()));
-                               _sourceTypeRadios[0].setSelected(true);
-                       }
-                       catch (ClassCastException cce) {} // ignore, sourceFound flag stays false
-               }
-               for (int i=0; i<2; i++) {
-                       _sourceTypeRadios[i].setEnabled(false);
-               }
-               onRadioClicked();
                _okButton.setEnabled(false);
                _addDialog.setVisible(true);
        }
 
-
-       /**
-        * React to one of the type radio buttons being clicked
-        */
-       private void onRadioClicked()
-       {
-               CardLayout cl = (CardLayout) _cards.getLayout();
-               if (_sourceTypeRadios[0].isSelected()) {cl.first(_cards);}
-               else {cl.last(_cards);}
-               enableOK();
-       }
-
        /**
         * Check the currently entered details and enable the OK button if it looks OK
         */
        private void enableOK()
        {
-               boolean ok = false;
-               if (_sourceTypeRadios[0].isSelected()) {ok = isOsmPanelOk();}
-               if (_sourceTypeRadios[1].isSelected()) {ok = isCloudPanelOk();}
-               _okButton.setEnabled(ok);
+               _okButton.setEnabled(isOsmPanelOk());
        }
 
        /**
@@ -370,21 +274,6 @@ public class AddMapSourceDialog
                return (ok && (baseUrl != null || topUrl != null));
        }
 
-       /**
-        * Check the cloudmade panel if all details are complete
-        * @return true if details look ok
-        */
-       private boolean isCloudPanelOk()
-       {
-               boolean ok = _cNameField.getText().trim().length() > 1;
-               int styleNum = 0;
-               try {
-                       styleNum = Integer.parseInt(_cStyleField.getText());
-               }
-               catch (NumberFormatException nfe) {}
-               return (ok && styleNum > 0);
-       }
-
        /**
         * Finish by adding the requested source and refreshing the parent
         */
@@ -392,7 +281,8 @@ public class AddMapSourceDialog
        {
                MapSource newSource = null;
                String origName = (_originalSource == null ? null : _originalSource.getName());
-               if (_sourceTypeRadios[0].isSelected())
+
+               if (isOsmPanelOk())
                {
                        // Openstreetmap source
                        String sourceName = getValidSourcename(_oNameField.getText(), origName);
@@ -402,12 +292,7 @@ public class AddMapSourceDialog
                        String ext2 = getFileExtension(_topTypeRadios);
                        newSource = new OsmMapSource(sourceName, url1, ext1, url2, ext2, _oZoomCombo.getSelectedIndex()+10);
                }
-               else if (_sourceTypeRadios[1].isSelected())
-               {
-                       String sourceName = getValidSourcename(_cNameField.getText(), origName);
-                       newSource = new CloudmadeMapSource(sourceName, _cStyleField.getText(),
-                               _cZoomCombo.getSelectedIndex()+10);
-               }
+
                // Add new source if ok
                if (newSource != null)
                {
index 86252d199bfd7d804c744f9a700ad4d6997a6d67..b15d57c981653e884266124fd82ace0058cd1035 100644 (file)
@@ -48,7 +48,7 @@ public class PhotoComparer implements Comparator<DataPoint>
                if (result == 0) {
                        result = compareSizes(inP1, inP2);
                }
-               return 0;
+               return result;
        }
 
        /**
index bbe771988fd640ee673a81b28f8d04c16cc95191..40c4e5af9f2a6e2b0057c81fce60ebb29ec6ce51 100644 (file)
@@ -57,7 +57,7 @@ public class ShowThreeDFunction extends GenericFunction
        }
 
        /**
-        * Show the help screen
+        * Begin the function
         */
        public void begin()
        {
@@ -169,6 +169,7 @@ public class ShowThreeDFunction extends GenericFunction
                                // Also pass the base image parameters from input dialog
                                window.setBaseImageParameters(_baseImagePanel.getImageDefinition());
                                window.setTerrainParameters(new TerrainDefinition(_terrainPanel.getUseTerrain(), _terrainPanel.getGridSize()));
+                               window.setDataStatus(_app.getCurrentDataStatus());
                                window.show();
                        }
                        catch (ThreeDException e)
index 8517cd0e88e083aa78d763e38754219e04b1e590..d0d92bb152062a7515a67410746643397a715173 100644 (file)
@@ -175,7 +175,12 @@ public class DownloadSrtmFunction extends GenericFunction implements Runnable
                if (errorMessage != null) {
                        _app.showErrorMessageNoLookup(getNameKey(), errorMessage);
                }
-               else if (numDownloaded > 0)
+               else if (numDownloaded == 1)
+               {
+                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getTextWithNumber("confirm.downloadsrtm.1", numDownloaded),
+                               I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
+               }
+               else if (numDownloaded > 1)
                {
                        JOptionPane.showMessageDialog(_parentFrame, I18nManager.getTextWithNumber("confirm.downloadsrtm", numDownloaded),
                                I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
index 7b6f8c7602dcce9ea88b0e44699876b262b32eb6..970d022f67032ce0e45cc9ffce7e5921abb77486 100644 (file)
@@ -73,6 +73,8 @@ public class GetWeatherForecastFunction extends GenericFunction implements Runna
 
        /** True to just simulate the calls and read files instead, false to call real API */
        private static final boolean SIMULATE_WITH_FILES = false;
+       /** Unique API key for GpsPrune */
+       private static final String OPENWEATHERMAP_API_KEY = "d1c5d792362f5a5c2eacf70a3b72ecd6";
 
 
        /**
@@ -365,7 +367,8 @@ public class GetWeatherForecastFunction extends GenericFunction implements Runna
                        + (_locationId == null ? ("lat=" + NumberUtils.formatNumberUk(lat, 5) + "&lon=" + NumberUtils.formatNumberUk(lon, 5))
                                : ("id=" + _locationId))
                        + "&lang=" + I18nManager.getText("openweathermap.lang")
-                       + "&mode=xml&units=" + (inUseCelsius ? "metric" : "imperial");
+                       + "&mode=xml&units=" + (inUseCelsius ? "metric" : "imperial")
+                       + "&APPID=" + OPENWEATHERMAP_API_KEY;
                // System.out.println(urlString);
 
                // Parse the returned XML with a special handler
@@ -431,7 +434,8 @@ public class GetWeatherForecastFunction extends GenericFunction implements Runna
                final String forecastCount = inDaily ? "8" : "3";
                final String urlString = "http://api.openweathermap.org/data/2.5/forecast"
                        + (inDaily ? "/daily" : "") + "?id=" + _locationId + "&lang=" + I18nManager.getText("openweathermap.lang")
-                       + "&mode=xml&units=" + (inCelsius ? "metric" : "imperial") + "&cnt=" + forecastCount;
+                       + "&mode=xml&units=" + (inCelsius ? "metric" : "imperial") + "&cnt=" + forecastCount
+                       + "&APPID=" + OPENWEATHERMAP_API_KEY;
                // System.out.println(urlString);
 
                // Parse the returned XML with a special handler
index 83c5ca0dfeb0828cfe9f0666d3e6768bca780cbe..10fd3635fd5474326dbc1ba6b3ba527f59cd132b 100644 (file)
@@ -1,6 +1,10 @@
 package tim.prune.function.weather;
 
 import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import tim.prune.gui.DisplayUtils;
 
 
 /**
@@ -96,8 +100,9 @@ public class WeatherResults
                if (inRiseTime != null && inRiseTime.length() == 19
                        && inSetTime != null && inSetTime.length() == 19)
                {
-                       _sunriseTime = inRiseTime.substring(11, 16);
-                       _sunsetTime  = inSetTime.substring(11, 16);
+                       // Convert from UTC to system's time zone (not necessarily target's time zone!)
+                       _sunriseTime = convertToLocalTimezone(inRiseTime.substring(11, 16));
+                       _sunsetTime  = convertToLocalTimezone(inSetTime.substring(11, 16));
                }
        }
 
@@ -130,4 +135,32 @@ public class WeatherResults
        {
                return _updateTime;
        }
+
+       /**
+        * Convert the given UTC time (HH:MM) into current timezone of computer
+        * @param inTimeString sunrise/sunset time in UTC (HH:MM)
+        * @return time in this timezone (HH:MM)
+        */
+       private static String convertToLocalTimezone(String inTimeString)
+       {
+               if (inTimeString != null && inTimeString.length() == 5)
+               {
+                       try
+                       {
+                               final int hour = Integer.parseInt(inTimeString.substring(0, 2));
+                               final int min  = Integer.parseInt(inTimeString.substring(3));
+                               Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+                               utcCal.set(Calendar.HOUR_OF_DAY, hour);
+                               utcCal.set(Calendar.MINUTE, min);
+                               // Make a second calendar in the current time zone and apply values
+                               Calendar currCal = Calendar.getInstance();
+                               currCal.setTimeInMillis(utcCal.getTimeInMillis());
+                               return DisplayUtils.makeTimeString(currCal.get(Calendar.HOUR_OF_DAY),
+                                       currCal.get(Calendar.MINUTE));
+                       }
+                       catch (NumberFormatException e) {} // ignore, just drop through
+               }
+               // Couldn't be parsed / converted
+               return inTimeString;
+       }
 }
index 274490e12256bfade9b79ceb7ce06f689cb1ccb4..35444b6dc9387786e5b870cc34f0c4f9da8000ea 100644 (file)
@@ -84,13 +84,12 @@ public class WeatherTableModel extends AbstractTableModel
                                        return buildDisplayString(null, I18nManager.getText("dialog.weather.day." + dayDesc));
                                }
                                case ROW_DESC: return buildDisplayString(null, forecast.getDescription());
-                               case ROW_WIND: return buildDisplayString("Wind", forecast.getWindDescription());
+                               case ROW_WIND: return buildDisplayString(I18nManager.getText("dialog.weather.wind"), forecast.getWindDescription());
                                case ROW_ICON: return forecast.getImageName();
-                               case ROW_TEMP: return buildDisplayString("Temp", forecast.getTemps()
+                               case ROW_TEMP: return buildDisplayString(I18nManager.getText("dialog.weather.temp"), forecast.getTemps()
                                        + (_results.isCelsius() ? UNITS_DEGC : UNITS_DEGF));
-                               case ROW_HUMID: return buildDisplayString("Humidity", forecast.getHumidity());
+                               case ROW_HUMID: return buildDisplayString(I18nManager.getText("dialog.weather.humidity"), forecast.getHumidity());
                        }
-                       // TODO: Use language-specific texts for wind, temp and humidity
                }
                return "";
        }
index 49ca3870b6304ccc3bc2c40f56b18d2b3685a6fe..25640d8e5072bfc2e70acfc3e26c7de208a494e3 100644 (file)
@@ -70,4 +70,24 @@ public abstract class DisplayUtils
                FORMAT_FLEX.setMinimumFractionDigits(numDigits);
                return FORMAT_FLEX.format(inVal);
        }
+
+       /**
+        * Convert the given hour and minute values into a string H:MM
+        * @param inHour hour of day, 0-24
+        * @param inMinute minute, 0-59
+        * @return string, either H:MM or HH:MM
+        */
+       public static String makeTimeString(int inHour, int inMinute)
+       {
+               StringBuilder sb = new StringBuilder();
+               final int hour = (inHour >= 0 && inHour <= 24) ? inHour : 0;
+               sb.append(hour);
+
+               sb.append(':');
+
+               final int minute = (inMinute >= 0 && inMinute <= 59) ? inMinute : 0;
+               if (minute <= 9) {sb.append('0');}
+               sb.append(minute);
+               return sb.toString();
+       }
 }
index 690c1aed55f81c91c1513be274c3f765dde9e308..064aa119da12452de470eeb3c9c7b3a75576e964 100644 (file)
@@ -44,7 +44,7 @@ public class TerrainDefinitionPanel extends JPanel
                JLabel label = new JLabel(I18nManager.getText("dialog.3d.terraingridsize") + ": ");
                add(label);
                _gridSizeField = new WholeNumberField(4);
-               _gridSizeField.setValue(10);
+               _gridSizeField.setValue(50); // default grid size
                _gridSizeField.setMaximumSize(new Dimension(100, 50));
                _gridSizeField.setEnabled(false);
                add(_gridSizeField);
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/tim/prune/gui/map/CloudmadeMapSource.java b/tim/prune/gui/map/CloudmadeMapSource.java
deleted file mode 100644 (file)
index 17d4efe..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-package tim.prune.gui.map;
-
-/**
- * Class to act as a source for Cloudmade maps with a given style
- */
-public class CloudmadeMapSource extends OsmMapSource
-{
-       /** Selected style number */
-       private String _style = null;
-       /** Server prefix including API-key unique to GpsPrune application */
-       private static final String SERVER_PREFIX = "[abc].tile.cloudmade.com/03d86b66f51f4a3b8c236ac06f2a2e57/";
-
-       /**
-        * Constructor
-        * @param inName name to use for map source
-        * @param inStyle style, given as integer
-        * @param inMaxZoom maximum zoom level, 18 by default
-        */
-       public CloudmadeMapSource(String inName, String inStyle, int inMaxZoom)
-       {
-               // Note: Could check style for valid integer value here
-               super(inName, SERVER_PREFIX + inStyle + "/256/", null, inMaxZoom);
-               _style = inStyle;
-       }
-
-       /**
-        * @return semicolon-separated list of all fields
-        */
-       public String getConfigString()
-       {
-               return "c:" +  getName() + ";" + _style + ";" + getMaxZoomLevel();
-       }
-
-       /**
-        * Construct a new map source from its config string
-        * @param inConfigString string from Config, separated by semicolons
-        * @return new map source, or null if not parseable
-        */
-       public static CloudmadeMapSource fromConfig(String inConfigString)
-       {
-               CloudmadeMapSource source = null;
-               if (inConfigString.startsWith("c:"))
-               {
-                       String[] items = inConfigString.substring(2).split(";");
-                       try {
-                               if (items.length == 3) {
-                                       source = new CloudmadeMapSource(items[0], items[1], Integer.parseInt(items[2]));
-                               }
-                       } catch (NumberFormatException nfe) {}
-               }
-               return source;
-       }
-
-       /**
-        * @return style as string, only required to populate edit dialog
-        */
-       public String getStyle()
-       {
-               return _style;
-       }
-}
index 5c20eacf9ba9fdc8a2da4bc4b76cf77e8f46b263..b82fd4e7a23e197a80120eb6d2b2e0c7a854f409 100644 (file)
@@ -47,7 +47,6 @@ public abstract class MapSourceLibrary
                        "http://toolserver.org/~cmarqu/hill/", 18));
                _sourceList.add(new OsmMapSource("Openseamap", "http://tile.openstreetmap.org/",
                        "http://tiles.openseamap.org/seamark/", 18));
-               _sourceList.add(new CloudmadeMapSource("Pale Dawn", "998", 18));
        }
 
        /**
@@ -64,7 +63,6 @@ public abstract class MapSourceLibrary
                        {
                                String sourceString = configString.substring(0, splitPos);
                                MapSource source = OsmMapSource.fromConfig(sourceString);
-                               if (source == null) {source = CloudmadeMapSource.fromConfig(sourceString);}
                                if (source != null) {
                                        _sourceList.add(source);
                                }
index fc6c7ff18b50c69328b6b19193d9373a323f29c7..cab34c731463e498c3b98aa9ff606c85ad7132a5 100644 (file)
@@ -358,7 +358,6 @@ dialog.addmapsource.sourcename=N\u00e1zev zdroje
 dialog.addmapsource.layer1url=URL prvn\u00ed vrstvy
 dialog.addmapsource.layer2url=Voliteln\u011b URL druh\u00e9 vrstvy
 dialog.addmapsource.maxzoom=Maxim\u00e1ln\u00ed zv\u011bt\u0161en\u00ed
-dialog.addmapsource.cloudstyle=\u010c\u00edslo stylu
 dialog.addmapsource.noname=Bez n\u00e1zvu
 dialog.gpsies.column.name=N\u00e1zev stopy
 dialog.gpsies.column.length=D\u00e9lka
@@ -601,6 +600,7 @@ confirm.rotatephoto=fotografie oto\u010dena
 confirm.running=Prob\u00edh\u00e1 ...
 confirm.lookupsrtm=Nalezeno %d v\u00fd\u0161kov\u00fdch hodnot
 confirm.downloadsrtm=Do cache bylo sta\u017eeno %d soubor\u016f
+confirm.downloadsrtm.1=Do cache bylo sta\u017eeno %d soubor\u016f
 confirm.downloadsrtm.none=\u017d\u00e1dn\u00fd soubor nebylo t\u0159eba stahovat, v\u0161e u\u017e je v cachi.
 confirm.deletefieldvalues=Hodnoty pole smaz\u00e1ny
 confirm.audioload=Audionahr\u00e1vky p\u0159id\u00e1ny
index 91f75ac6b3e90e321606c1ccc0fb7e8d1706b314..19b6b029fe1906183bc79c90b63a38ebce8f33cc 100644 (file)
@@ -358,7 +358,6 @@ dialog.addmapsource.sourcename=Name der Quelle
 dialog.addmapsource.layer1url=URL f\u00fcr erste Ebene
 dialog.addmapsource.layer2url=URL f\u00fcr obere Ebene (falls n\u00f6tig)
 dialog.addmapsource.maxzoom=Maximales Zoom
-dialog.addmapsource.cloudstyle=Stilnummer
 dialog.addmapsource.noname=Unbenannt
 dialog.gpsies.column.name=Name des Tracks
 dialog.gpsies.column.length=L\u00e4nge
@@ -561,6 +560,9 @@ dialog.weather.day.thursday=Donnerstag
 dialog.weather.day.friday=Freitag
 dialog.weather.day.saturday=Samstag
 dialog.weather.day.sunday=Sonntag
+dialog.weather.wind=Wind
+dialog.weather.temp=Temp
+dialog.weather.humidity=R.L.
 dialog.weather.creditnotice=Diese Daten wurden von openweathermap.org zur Verf\u00fcgung gestellt. Die Webseite hat mehr Information.
 
 # 3d window
@@ -601,6 +603,7 @@ confirm.rotatephoto=Foto gedreht
 confirm.running=In Bearbeitung ...
 confirm.lookupsrtm=Es wurden %d H\u00f6henwerte gefunden
 confirm.downloadsrtm=Es wurden %d Dateien heruntergeladen
+confirm.downloadsrtm.1=Es wurde %d Datei heruntergeladen
 confirm.downloadsrtm.none=Keine Dateien heruntergeladen, alle waren schon gespeichert.
 confirm.deletefieldvalues=Feldwerte gel\u00f6scht
 confirm.audioload=Audiodateien geladen
index fd56f48b79e328e2ac9626e2d9923993e0273564..7e9b304cd6f233f897b576de1d18f91511b65f19 100644 (file)
@@ -353,7 +353,6 @@ dialog.addmapsource.sourcename=Sourcename
 dialog.addmapsource.layer1url=URL f\u00fcr erschti Ebene
 dialog.addmapsource.layer2url=URL f\u00fcr oberi Ebene (falls n\u00f6tig)
 dialog.addmapsource.maxzoom=Maximali Zoom
-dialog.addmapsource.cloudstyle=Stilnummere
 dialog.addmapsource.noname=Unbenannt
 dialog.gpsies.column.name=Track Name
 dialog.gpsies.column.length=L\u00e4nge
@@ -556,6 +555,9 @@ dialog.weather.day.thursday=Duunschtig
 dialog.weather.day.friday=Friitig
 dialog.weather.day.saturday=Samschtig
 dialog.weather.day.sunday=Sunntig
+dialog.weather.wind=Wind
+dialog.weather.temp=Temp
+dialog.weather.humidity=R.L.
 dialog.weather.creditnotice=Diese Date sin vo openweathermap.org zur Verf\u00fcegig gestellt worde. Uf d Websiite h\u00e4ts no meh Infos.
 
 # 3d window
@@ -596,7 +598,8 @@ confirm.rotatephoto=F\u00f6teli umgedr\u00e4it worde
 confirm.running=Am Laufe ...
 confirm.lookupsrtm=Es sin %d H\u00f6henwerte gfunde
 confirm.downloadsrtm=Es sin %d Files abeglade
-confirm.downloadsrtm.none=Kei Files abeglade, die sin scho da gsi.
+confirm.downloadsrtm.1=Sisch %d File abeglade
+confirm.downloadsrtm.none=Kei Files abeglade, die sin alli scho da gsi.
 confirm.deletefieldvalues=Feldw\u00e4rte gl\u00f6scht worde
 confirm.audioload=Audiofiles glade worde
 confirm.media.removed=entf\u00e4rnt
index 03d04dfc528566bfca8cdd245829478909dabb8c..bfef0dfcd3c42b44cdfc23b2ad76e6cf3488aadb 100644 (file)
@@ -358,7 +358,6 @@ dialog.addmapsource.sourcename=Name of source
 dialog.addmapsource.layer1url=URL of first layer
 dialog.addmapsource.layer2url=Optional URL of second layer
 dialog.addmapsource.maxzoom=Maximum zoom level
-dialog.addmapsource.cloudstyle=Style number
 dialog.addmapsource.noname=Unnamed
 dialog.gpsies.column.name=Track name
 dialog.gpsies.column.length=Length
@@ -561,6 +560,9 @@ dialog.weather.day.thursday=Thursday
 dialog.weather.day.friday=Friday
 dialog.weather.day.saturday=Saturday
 dialog.weather.day.sunday=Sunday
+dialog.weather.wind=Wind
+dialog.weather.temp=Temp
+dialog.weather.humidity=Humidity
 dialog.weather.creditnotice=This data is made available by openweathermap.org. Their website has more details.
 
 # 3d window
@@ -601,7 +603,8 @@ confirm.createpoint=point created
 confirm.running=Running ...
 confirm.lookupsrtm=Found %d altitude values
 confirm.downloadsrtm=Downloaded %d files to the cache
-confirm.downloadsrtm.none=No files downloaded, they were already in the cache.
+confirm.downloadsrtm.1=Downloaded %d file to the cache
+confirm.downloadsrtm.none=No files downloaded, they were already in the cache
 confirm.deletefieldvalues=Field values deleted
 confirm.audioload=Audio files added
 confirm.correlateaudios.single=audio was correlated
index 928d027dbc5180d6bd9b9ced150ed53aa0544eaf..a28dd50c88ccbf20f9e6283a50cc3b5b4c74fb99 100644 (file)
@@ -8,6 +8,7 @@ function.setcolours=Set colors
 dialog.exportkml.trackcolour=Track color
 dialog.saveconfig.prune.languagecode=Language code (EN_US)
 dialog.setcolours.intro=Click on a color patch to change the color
+dialog.colourchooser.title=Choose color
 
 # Measurement units
 units.metres=Meters
index 182e6700b94c5564fa32b4c0b78e461fc0d9d87a..b752c7cd1a295f9145ec425ec6a950ce30099325 100644 (file)
@@ -105,6 +105,8 @@ function.fullrangedetails=Detalles adicionales de rango
 function.estimatetime=Estimar duraci\u00f3n
 function.setmapbg=Configurar fondo de mapa
 function.setpaths=Configurar rutas del programas
+function.splitsegments=Segmentar el track
+function.sewsegments=Ensamblar los segmentos
 function.getgpsies=Bajar ruta de Gpsies
 function.uploadgpsies=Subir recorrido a Gpsies
 function.lookupsrtm=Obtener altitudes de SRTM
@@ -193,7 +195,11 @@ dialog.gpsbabel.filter.discard.intro=Desechar puntos si
 dialog.gpsbabel.filter.discard.hdop=Hdop >
 dialog.gpsbabel.filter.discard.vdop=Vdop >
 dialog.gpsbabel.filter.discard.numsats=N\u00famero de sat\u00e9lites <
-dialog.gpsbabel.filter.simplify.maxpoints=Numero de puntos <
+dialog.gpsbabel.filter.discard.nofix=Posici\u00f3n no precisa
+dialog.gpsbabel.filter.discard.unknownfix=Precisi\u00f3n desconocida
+dialog.gpsbabel.filter.simplify.intro=Desechar puntos hasta
+dialog.gpsbabel.filter.simplify.maxpoints=N\u00famero de puntos <
+dialog.gpsbabel.filter.simplify.maxerror=o desviaci\u00f3n <
 dialog.gpsbabel.filter.distance.distance=Si distancia <
 dialog.gpsbabel.filter.distance.time=y differencia horaria <
 dialog.gpsbabel.filter.interpolate.distance=Si distancia >
@@ -226,6 +232,9 @@ dialog.exportgpx.encoding=Codificaci\u00f3n
 dialog.exportgpx.encoding.system=Sistema
 dialog.exportgpx.encoding.utf8=UTF-8
 dialog.3d.useterrain=Terreno
+dialog.3d.terraingridsize=Dimensi\u00f3n de la cuadr\u00edcula
+dialog.exportpov.cannotmakebaseimage=Fallo al guardar la imagen
+dialog.exportpov.baseimage=Imagen de mapa
 dialog.exportpov.text=Introduca los par\u00e1metros para exportar
 dialog.exportpov.font=Fuente
 dialog.exportpov.camerax=C\u00e1mara X
@@ -234,7 +243,7 @@ dialog.exportpov.cameraz=C\u00e1mara Z
 dialog.exportpov.modelstyle=Estilo
 dialog.exportpov.ballsandsticks=Balas en palos
 dialog.exportpov.tubesandwalls=Tubos y paredes
-dialog.3d.warningtracksize=Este track contiene un gran numero de puntos. Puede ser que Java3D no los pueda visualizar. Est\u00e1 seguro de que desea continuar?
+dialog.3d.warningtracksize=Este track contiene un gran n\u00famero de puntos. Puede ser que Java3D no los pueda visualizar. Est\u00e1 seguro de que desea continuar?
 dialog.baseimage.title=Imagen de mapa
 dialog.baseimage.mapsource=Proveedor de mapas
 dialog.baseimage.useimage=Usar imagen
@@ -248,6 +257,7 @@ dialog.exportsvg.theta=\u00c1ngulo de elevaci\u00f3n
 dialog.exportsvg.gradients=Usar degradado para sombras
 dialog.exportimage.drawtrack=Dibujar track
 dialog.exportimage.drawtrackpoints=Dibujar puntos del track
+dialog.exportimage.textscalepercent=Agrandamiento del texto (%)
 dialog.pointtype.desc=Salvar los siguientes tipos de puntos:
 dialog.pointtype.track=Puntos del track
 dialog.pointtype.waypoint=Waypoints
@@ -257,14 +267,15 @@ dialog.pointtype.selection=Solo selecci\u00f3n
 dialog.confirmreversetrack.title=Confirmar inversi\u00f3n
 dialog.confirmreversetrack.text=Este track contiene informaci\u00f3n sobre la fecha, que estar\u00e1 fuera de secuencia despu\u00e9s de la inversi\u00f3n. \u00bfEst\u00e1 seguro que desea invertir esta secci\u00f3n?
 dialog.confirmcutandmove.title=Confirmar accion cortar/pegar
-dialog.confirmcutandmove.text=Este track contiene informaci\u00f3n sobre la fecha, que estar\u00e1 fuera de secuencia despu\u00e9s de mover.\n\u00bfEsta seguro que desea mover esta secci\u00f3n?
+dialog.confirmcutandmove.text=Este track contiene informaci\u00f3n sobre la fecha, que estar\u00e1 fuera de secuencia despu\u00e9s de mover.\n\u00bfEst\u00e1 seguro que desea mover esta secci\u00f3n?
 dialog.interpolate.parameter.text=N\u00famero de los puntos a insertar entre los puntos elegidos
+dialog.interpolate.betweenwaypoints=Interpolar entre los waypoints?
 dialog.undo.title=Deshacer
 dialog.undo.pretext=Por favor, seleccione la operaci\u00f3n(es) a deshacer
 dialog.undo.none.title=No se puede deshacer
 dialog.undo.none.text=Ninguna operaci\u00f3n a deshacer
 dialog.clearundo.title=Despejar la lista de deshacer
-dialog.clearundo.text=\u00bfEsta seguro que desea despejar la lista de deshacer?, \u00a1se perder\u00e1 toda la informaci\u00f3n!
+dialog.clearundo.text=\u00bfEst\u00e1 seguro que desea despejar la lista de deshacer?, \u00a1se perder\u00e1 toda la informaci\u00f3n!
 dialog.pointedit.title=Editar punto
 dialog.pointedit.intro=Seleccione cada campo para modificar el valor
 dialog.pointedit.table.field=Campo
@@ -310,19 +321,27 @@ dialog.distances.currentpoint=Punto actual
 dialog.distances.toofewpoints=Esta funcion necesita "waypoints" para poder calcular las distancias entre ellos
 dialog.fullrangedetails.intro=Aqui estan los detalles para la selecci\u00f3n de rangos
 dialog.estimatetime.details=Detalles
+dialog.estimatetime.gentle=Inclinaci\u00f3n peque\u00f1a
+dialog.estimatetime.steep=Inclinaci\u00f3n grande
 dialog.estimatetime.climb=Ascenso
 dialog.estimatetime.descent=Descenso
 dialog.estimatetime.parameters=Par\u00e1metros
+dialog.estimatetime.parameters.timefor=Duraci\u00f3n para
 dialog.estimatetime.results=Resultados
 dialog.estimatetime.results.estimatedtime=Duraci\u00f3n estimada
 dialog.estimatetime.results.actualtime=Duraci\u00f3n real
+dialog.learnestimationparams.combinedresults=Resultados combinados
+dialog.learnestimationparams.weight.100pccurrent=Mantener datos actuales
+dialog.learnestimationparams.weight.current=actuales
+dialog.learnestimationparams.weight.calculated=calculados
+dialog.learnestimationparams.weight.50pc=La media entre actuales y calculados
+dialog.learnestimationparams.weight.100pccalculated=Nuevos datos calculados
 dialog.setmapbg.intro=Seleccione un proveedor de mapas o a\u00f1ada uno nuevo
 dialog.addmapsource.title=A\u00f1adir un proveedor de mapas
 dialog.addmapsource.sourcename=Nombre del proveedor
 dialog.addmapsource.layer1url=URL de la primera capa
 dialog.addmapsource.layer2url=URL opcional de la segunda capa
 dialog.addmapsource.maxzoom=M\u00e1ximo nivel de zoom
-dialog.addmapsource.cloudstyle=N\u00famero del estilo
 dialog.addmapsource.noname=Innominada
 dialog.gpsies.column.name=Nombre del track
 dialog.gpsies.column.length=Distancia
@@ -432,7 +451,7 @@ dialog.about.credits.devtools=Herramientas de desarrollo
 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.error=El n\u00famero 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 GpsPrune
 dialog.checkversion.newversion1=\u00a1Una nueva versi\u00f3n de GpsPrune est\u00e1 disponible! La \u00faltima es ahora la versi\u00f3n
 dialog.checkversion.newversion2=.
@@ -458,7 +477,6 @@ dialog.saveconfig.prune.mapsource=Proveedor de mapas seleccionado
 dialog.saveconfig.prune.mapsourcelist=Proveedor de mapas
 dialog.saveconfig.prune.diskcache=Memoria intermedia de mapas
 dialog.saveconfig.prune.kmzimagewidth=Ancho de im\u00e1genes en KMZ
-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
@@ -507,6 +525,14 @@ dialog.deletefieldvalues.nofields=No hay campos 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:
+dialog.weather.location=Localidad
+dialog.weather.update=Actualizado
+dialog.weather.sunrise=Salida del sol
+dialog.weather.sunset=Puesta de sol
+dialog.weather.temperatureunits=Temperaturas
+dialog.weather.currentforecast=El tiempo actual
+dialog.weather.dailyforecast=Pron\u00f3stico diariamente
+dialog.weather.3hourlyforecast=Pron\u00f3stico hora a hora
 dialog.weather.day.now=Tiempo actual
 dialog.weather.day.today=Hoy
 dialog.weather.day.tomorrow=Ma\u00f1ana
@@ -517,6 +543,9 @@ dialog.weather.day.thursday=Jueves
 dialog.weather.day.friday=Viernes
 dialog.weather.day.saturday=S\u00e1bado
 dialog.weather.day.sunday=Domingo
+dialog.weather.wind=Viento
+dialog.weather.temp=Temp
+dialog.weather.humidity=Humedad
 
 # 3d window
 dialog.3d.title=GpsPrune vista 3-D
@@ -553,6 +582,8 @@ confirm.createpoint=punto creado
 confirm.rotatephoto=foto rotada
 confirm.running=Trabajando ...
 confirm.lookupsrtm=Encontrados %d valor de altitud para la funci\u00f3n de b\u00fasqueda SRTM
+confirm.downloadsrtm=Descargado %d archivos
+confirm.downloadsrtm.1=Descargado %d archivo
 confirm.deletefieldvalues=Valores del campo eliminados
 confirm.audioload=A\u00f1adidos archivos de audio
 confirm.correlateaudios.single=El audio fue correlacionado
@@ -577,6 +608,7 @@ button.close=Cerrar
 button.continue=Contin\u00fae
 button.yes=Si
 button.no=No
+button.always=Si, siempre
 button.yestoall=Si por todo
 button.notoall=No por todo
 button.select=Seleccionar
@@ -735,6 +767,8 @@ undo.deletemarked=eliminar puntos
 undo.insert=insertar puntos
 undo.reverse=invertir rango
 undo.mergetracksegments=unir los segmentos del track
+undo.splitsegments=segmentar el track
+undo.sewsegments=ensamblar los segmentos del track
 undo.addtimeoffset=a\u00f1adir margen de tiempo
 undo.addaltitudeoffset=a\u00f1adir margen de altitud
 undo.rearrangewaypoints=reordenar waypoints
@@ -788,7 +822,12 @@ 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.showphoto.failed=Fallo al cargar la foto
 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
+error.interpolate.invalidparameter=El n\u00famero de puntos necesita ser entre 1 y 1000
+error.tracksplit.nosplit=Imposible segmentar el track
+error.downloadsrtm.nocache=Imposible guardar los archivos.\nPor favor, compruebe el cache.
+error.sewsegments.nothingdone=Imposible ensamblar los segmentos.\nEl track tiene ahora %d segmentos.
index 4e7ceef17082c14fb7c967032ac640f87c9a7f34..d271c279a7531c2ae707d2ebfcdb6013c750d267 100644 (file)
@@ -7,6 +7,7 @@ menu.file.addphotos=Ajouter photos
 menu.file.recentfiles=Fichiers r\u00e9cents
 menu.file.save=Enregistrer
 menu.file.exit=Quitter
+menu.online=En ligne
 menu.track=Trace
 menu.track.undo=Annuler
 menu.track.clearundo=Purger la liste d'annulation
@@ -57,6 +58,7 @@ menu.map.editmode=Mode \u00e9dition
 
 # Alt keys for menus
 altkey.menu.file=F
+altkey.menu.online=L
 altkey.menu.track=T
 altkey.menu.range=E
 altkey.menu.point=P
@@ -103,9 +105,12 @@ function.fullrangedetails=Montrer tous les d\u00e9tails
 function.estimatetime=Temps estim\u00e9
 function.setmapbg=D\u00e9finir le fond de carte
 function.setpaths=D\u00e9finir les chemins des programmes
+function.splitsegments=S\u00e9pare les segments
+function.sewsegments=R\u00e9unis les segments
 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.downloadsrtm=T\u00e9l\u00e9charger les donn\u00e9es SRTM
 function.getwikipedia=Obtenir les articles de Wikip\u00e9dia \u00e0 proximit\u00e9
 function.searchwikipedianames=Rechercher dans Wikip\u00e9dia par nom
 function.downloadosm=T\u00e9l\u00e9charger les donn\u00e9es OSM de la zone
@@ -163,6 +168,8 @@ dialog.openoptions.deliminfo.norecords=Pas d'enregistrements
 dialog.openoptions.altitudeunits=Unit\u00e9s d'altitude
 dialog.openoptions.speedunits=Unit\u00e9s de vitesse
 dialog.openoptions.vertspeedunits=Unit\u00e9s de vitesse verticale
+dialog.openoptions.vspeed.positiveup=Vitesse positive en montant
+dialog.openoptions.vspeed.positivedown=Vitesse positive en bas
 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
@@ -181,12 +188,19 @@ dialog.gpssend.sendwaypoints=Envoyer les waypoints
 dialog.gpssend.sendtracks=Envoyer les traces
 dialog.gpssend.trackname=Nom de la trace
 dialog.gpsbabel.filters=Filtres
+dialog.addfilter.title=Ajouter un filtre
 dialog.gpsbabel.filter.discard=Jeter
 dialog.gpsbabel.filter.simplify=Simplifier
 dialog.gpsbabel.filter.interpolate=Interpoler
 dialog.gpsbabel.filter.discard.intro=Jeter les points si
 dialog.gpsbabel.filter.discard.hdop=Hdop >
 dialog.gpsbabel.filter.discard.vdop=Vdop >
+dialog.gpsbabel.filter.discard.numsats=Nombre de satellites <
+dialog.gpsbabel.filter.discard.nofix=Point n'a pas fix
+dialog.gpsbabel.filter.discard.unknownfix=Point a une fix inconnue
+dialog.gpsbabel.filter.simplify.intro=Effacer les points jusque
+dialog.gpsbabel.filter.simplify.maxpoints=Nombre de points <
+dialog.gpsbabel.filter.simplify.maxerror=ou erreur <
 dialog.gpsbabel.filter.distance=Distance
 dialog.gpsbabel.filter.distance.distance=Si la distance <
 dialog.gpsbabel.filter.distance.time=et difference de temps <
@@ -228,6 +242,9 @@ dialog.exportpov.modelstyle=Style du mod\u00e8le
 dialog.exportpov.ballsandsticks=Points et b\u00e2tons
 dialog.exportpov.tubesandwalls=Tubes et murs
 dialog.3d.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.3d.useterrain=Montrer terrain
+dialog.3d.terraingridsize=Taille de la grille
+dialog.exportpov.baseimage=Image de la carte
 dialog.baseimage.title=Image de la carte
 dialog.baseimage.useimage=Utiliser image
 dialog.baseimage.mapsource=Source de cartes
@@ -239,6 +256,8 @@ 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.exportimage.drawtrack=Dessiner la trace sur la carte
+dialog.exportimage.drawtrackpoints=Dessiner les points de trace
 dialog.pointtype.desc=Sauvegarder ces types de points:
 dialog.pointtype.track=Points de la trace
 dialog.pointtype.waypoint=Waypoints
@@ -260,6 +279,7 @@ dialog.clearundo.text=\u00cates-vous s\u00fbr de vouloir effacer la liste d'annu
 dialog.pointedit.title=\u00c9diter le point
 dialog.pointedit.intro=S\u00e9lectionner chaque champ pour voire et changer la valeur
 dialog.pointedit.table.field=Champ
+dialog.pointedit.nofield=Aucun champ choisi
 dialog.pointedit.table.value=Valeur
 dialog.pointnameedit.name=Nom de waypoint
 dialog.pointnameedit.uppercase=CASSE MAJUSCULES
@@ -302,15 +322,23 @@ dialog.distances.toofewpoints=Cette fonction a besoin de waypoints pour calculer
 dialog.fullrangedetails.intro=Voici les d\u00e9tails pour l\u2019\u00e9tendue s\u00e9lectionn\u00e9e
 dialog.fullrangedetails.coltotal=Inclure les cellules vides
 dialog.fullrangedetails.colsegments=Exclure les cellules vides
+dialog.estimatetime.details=D\u00e9tails
+dialog.estimatetime.steep=Escarp\u00e9
 dialog.estimatetime.climb=Mont\u00e9e
 dialog.estimatetime.descent=Descente
+dialog.estimatetime.parameters=Param\u00e8tres
+dialog.estimatetime.parameters.timefor=Dur\u00e9e pour
+dialog.estimatetime.results=R\u00e9sultats
+dialog.estimatetime.results.estimatedtime=Dur\u00e9e estim\u00e9e
+dialog.estimatetime.results.actualtime=Dur\u00e9e en fait
+dialog.learnestimationparams.averageerror=Erreur en moyenne
+dialog.learnestimationparams.combinedresults=R\u00e9sultats combin\u00e9es
 dialog.setmapbg.intro=S\u00e9lectionnez une source de cartes, ou ajoutez-en une nouvelle
 dialog.addmapsource.title=Ajouter une nouvelle source de cartes
 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=Num\u00e9ro du style
 dialog.addmapsource.noname=Sans titre
 dialog.gpsies.column.name=Nom de la trace
 dialog.gpsies.column.length=Distance
@@ -428,7 +456,7 @@ 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://gpsprune.activityworkshop.net/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 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.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>Ctrl + PgUp, PgDown</td><td>Choisir le segment pr\u00e9c\u00e9dent ou suivant</td></tr><tr><td>Ctrl + Home, End</td><td>Choisir le point premier, dernier</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:
@@ -446,7 +474,6 @@ 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
@@ -514,6 +541,10 @@ dialog.weather.day.thursday=Jeudi
 dialog.weather.day.friday=Vendredi
 dialog.weather.day.saturday=Samedi
 dialog.weather.day.sunday=Dimanche
+dialog.weather.wind=Vent
+dialog.weather.temp=Temp
+dialog.weather.humidity=Humidit\u00e9
+dialog.weather.creditnotice=Ces donn\u00e9es sont fournies par openweathermap.org. Consultez la page pour plus de d\u00e9tails.
 
 # 3d window
 dialog.3d.title=Vue 3D de GpsPrune
@@ -550,6 +581,9 @@ confirm.createpoint=Point cr\u00e9\u00e9
 confirm.rotatephoto=Photo tourn\u00e9e
 confirm.running=En cours...
 confirm.lookupsrtm=Trouv\u00e9 %d valeurs d'altitude
+confirm.downloadsrtm=%d fichiers ont \u00e9t\u00e9 t\u00e9l\u00e9charg\u00e9s
+confirm.downloadsrtm.1=%d fichier a \u00e9t\u00e9 t\u00e9l\u00e9charg\u00e9
+confirm.downloadsrtm.none=Pas de fichiers ont \u00e9t\u00e9 t\u00e9l\u00e9charg\u00e9s, ils sont d\u00e9j\u00e0 l\u00e0
 confirm.deletefieldvalues=Valeurs effac\u00e9es
 confirm.audioload=Fichiers audio ajout\u00e9s
 confirm.correlateaudios.single=fichier audio a \u00e9t\u00e9 corr\u00e9l\u00e9
@@ -557,6 +591,10 @@ confirm.correlateaudios.multi=fichiers audio ont \u00e9t\u00e9 corr\u00e9l\u00e9
 
 # Tips
 tip.title=Astuce
+tip.useamapcache=By setting up a disk cache (Pr\u00e9f\u00e9rences -> Enregistrer les cartes sur le disque)\nyou can speed up the display and reduce network traffic.
+tip.learntimeparams=The results will be more accurate if you use\nTrace -> Learn time estimation parameters\non your recorded tracks.
+tip.downloadsrtm=You can speed this up by calling\nEn ligne -> T\u00e9l\u00e9charger les donn\u00e9es SRTM\nto save the data in your map cache.
+tip.usesrtmfor3d=This track doesn't have altitudes.\nYou can use the SRTM functions to get approximate\naltitudes for the 3d view.
 tip.manuallycorrelateone=En corr\u00e9lant manuellement au moins une photo, le d\u00e9calage de temps peut \u00eatre calcul\u00e9 pour vous.
 
 # Buttons
@@ -576,6 +614,7 @@ button.yes=Oui
 button.no=Non
 button.yestoall=Oui pour tous
 button.notoall=Non pour tous
+button.always=Oui, toujours
 button.select=S\u00e9lectionner
 button.selectall=Tout s\u00e9lectionner
 button.selectnone=Ne rien s\u00e9lectionner
@@ -608,6 +647,7 @@ filetype.audio=Fichiers MP3, OGG, WAV
 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
+display.novalues=La trace ne comporte pas d'information pour ce champ
 details.trackdetails=D\u00e9tails de la trace
 details.notrack=Pas de trace charg\u00e9e
 details.track.points=Points
@@ -697,6 +737,10 @@ units.degminsec=Deg-min-sec
 units.degmin=Deg-min
 units.deg=Degr\u00e9s
 units.iso8601=ISO 8601
+units.degreescelsius=Celsius
+units.degreescelsius.short=\u00b0C
+units.degreesfahrenheit=Fahrenheit
+units.degreesfahrenheit.short=\u00b0F
 
 # How to combine conditions, such as filters
 logic.and=et
@@ -727,6 +771,8 @@ undo.deletemarked=effacer les points
 undo.insert=ins\u00e9rer les points
 undo.reverse=inverser l'\u00e9tendue
 undo.mergetracksegments=fusionner les segments de trace
+undo.splitsegments=s\u00e9parer les segments de trace
+undo.sewsegments=r\u00e9unir les segments de trace
 undo.addtimeoffset=ajouter d\u00e9calage d'heure
 undo.addaltitudeoffset=ajouter d\u00e9calage d'altitude
 undo.rearrangewaypoints=r\u00e9arranger les waypoints
@@ -786,3 +832,4 @@ error.cache.notthere=Le dossier du cache n'a pas \u00e9t\u00e9 trouv\u00e9
 error.cache.empty=Le dossier du cache est vide
 error.cache.cannotdelete=Effacement des dalles impossible
 error.interpolate.invalidparameter=Le nombre de points doit \u00eatre compris entre 1 et 1000
+error.tracksplit.nosplit=Impossible de s\u00e9parer les segments
index e0e6b1ded649a8704fd87541210d77388d1fe5ad..a1bf2ec6677d5fbc4471922a39a6dd0426cd4ba0 100644 (file)
@@ -358,7 +358,6 @@ dialog.addmapsource.sourcename=Forr\u00e1s neve
 dialog.addmapsource.layer1url=Els\u0151 r\u00e9teg URL-je
 dialog.addmapsource.layer2url=Opcion\u00e1lis m\u00e1sodik r\u00e9teg URL-je
 dialog.addmapsource.maxzoom=Maxim\u00e1lis nagy\u00edt\u00e1si szint
-dialog.addmapsource.cloudstyle=St\u00edlus sz\u00e1ma
 dialog.addmapsource.noname=N\u00e9vtelen
 dialog.gpsies.column.name=Nyomvonal neve
 dialog.gpsies.column.length=Hossz
@@ -601,6 +600,7 @@ confirm.rotatephoto=f\u00e9nyk\u00e9p elforgatva
 confirm.running=Futtat\u00e1s...
 confirm.lookupsrtm=%d magass\u00e1gi \u00e9rt\u00e9k tal\u00e1lhat\u00f3
 confirm.downloadsrtm=%d f\u00e1jl let\u00f6lt\u00e9se gyors\u00edt\u00f3t\u00e1rba
+confirm.downloadsrtm.1=%d f\u00e1jl let\u00f6lt\u00e9se gyors\u00edt\u00f3t\u00e1rba
 confirm.downloadsrtm.none=Nem kellett f\u00e1jlokat let\u00f6lteni, m\u00e1r gyors\u00edt\u00f3t\u00e1rban voltak.
 confirm.deletefieldvalues=Mez\u0151 \u00e9rt\u00e9kei t\u00f6r\u00f6lve
 confirm.audioload=Hangf\u00e1jl hozz\u00e1adva
index 63c70ea13ff24e7d392956bbfee8c5e0b540378c..14df8169a16abae54d82793a0e452175679537fc 100644 (file)
@@ -108,7 +108,7 @@ function.setmapbg=Configura sfondo mappa
 function.setpaths=Configura percorsi programmi
 function.splitsegments=Dividi traccia in segmenti
 function.sewsegments=Riorganizza segmenti insieme
-function.getgpsies=Ottieni traccie da Gpsies
+function.getgpsies=Ottieni tracce da Gpsies
 function.uploadgpsies=Carica traccia su Gpsies
 function.lookupsrtm=Ottieni quote da SRTM
 function.downloadsrtm=Scarica file da SRTM
@@ -358,7 +358,6 @@ dialog.addmapsource.sourcename=Nome della fonte
 dialog.addmapsource.layer1url=URL del primo layer
 dialog.addmapsource.layer2url=URL opzionale del secondo layer
 dialog.addmapsource.maxzoom=Massimo livello di zoom
-dialog.addmapsource.cloudstyle=Stile numero
 dialog.addmapsource.noname=Senza nome
 dialog.gpsies.column.name=Nome traccia
 dialog.gpsies.column.length=Lunghezza
@@ -480,7 +479,7 @@ dialog.keys.keylist=<table><tr><td>Tasti freccia</td><td>Muovi mappa destra, sin
 dialog.keys.normalmodifier=Ctrl
 dialog.keys.macmodifier=Comando
 dialog.saveconfig.desc=Le configurazioni seguenti possono essere salvati in un file di configurazione:
-dialog.saveconfig.prune.trackdirectory=Cartella traccie
+dialog.saveconfig.prune.trackdirectory=Cartella tracce
 dialog.saveconfig.prune.photodirectory=Cartella foto
 dialog.saveconfig.prune.languagecode=Codice lingua (IT)
 dialog.saveconfig.prune.languagefile=File lingua
@@ -494,7 +493,6 @@ dialog.saveconfig.prune.mapsource=Selezionale la fonte delle mappe
 dialog.saveconfig.prune.mapsourcelist=Fonte delle mappe
 dialog.saveconfig.prune.diskcache=Cache delle mappe
 dialog.saveconfig.prune.kmzimagewidth=larghezza immagine KMZ
-dialog.saveconfig.prune.kmzimageheight=altezza immagine KMZ
 dialog.saveconfig.prune.colourscheme=Schema colori
 dialog.saveconfig.prune.linewidth=Spessore linea
 dialog.saveconfig.prune.kmltrackcolour=Colore della traccia KML
@@ -562,6 +560,10 @@ dialog.weather.day.thursday=Gioved\u00ec
 dialog.weather.day.friday=Venerd\u00ec
 dialog.weather.day.saturday=Sabato
 dialog.weather.day.sunday=Domenica
+dialog.weather.wind=Vento
+dialog.weather.temp=Temp
+dialog.weather.humidity=Umidit\u00e0
+dialog.weather.creditnotice=Queste informazioni sono rese disponibili da openweathermap.org. Il loro sito web contiene ulteriori dettagli.
 
 # 3d window
 dialog.3d.title=Visione GpsPrune in 3D
@@ -580,6 +582,8 @@ confirm.addtimeoffset=Scarto temporale aggiunto
 confirm.addaltitudeoffset=Scarto altitudine aggiunto
 confirm.rearrangewaypoints=Waypoint riorganizzati
 confirm.rearrangephotos=Foto riorganizzate
+confirm.splitsegments=%d segmenti sono stati suddivisi
+confirm.sewsegments=%d segmenti sono stati raggruppati
 confirm.cutandmove=Selezione spostata
 confirm.interpolate=Aggiungi punto
 confirm.convertnamestotimes=Nome del waypoint convertito
@@ -598,6 +602,9 @@ confirm.createpoint=punto creato
 confirm.rotatephoto=foto ruotata
 confirm.running=Operazione in corso...
 confirm.lookupsrtm=Trovato %d valori di quota
+confirm.downloadsrtm=Scarica %d file nella cache
+confirm.downloadsrtm.1=Scarica %d file nella cache
+confirm.downloadsrtm.none=Nessun file scaricato, erano gi\u00e0 presenti nella cache
 confirm.deletefieldvalues=Valori del campo cancellati
 confirm.audioload=Ripresa audio aggiunta
 confirm.correlateaudios.single=la ripresa audio era correlata
@@ -605,6 +612,10 @@ confirm.correlateaudios.multi=le riprese audio erano correlate
 
 # Tips
 tip.title=Consiglio
+tip.useamapcache=Usando una cache della mappa (Preferenze -> Salva mappe su disco)\npuoi accelerare la visualizzazione e ridurre il traffico.
+tip.learntimeparams=I risultati saranno pi\u00f9 precisi usando\nTraccia -> Apprendi parametri di stima\ncon le tue tracce.
+tip.downloadsrtm=Puoi accelerare questa funzione usando\nOnline -> Scarica file da SRTM\nper salvare i dati nella cache.
+tip.usesrtmfor3d=La traccia non include informazioni sull'altitudine.\nPuoi utilizzare la funzione SRTM per ottenere le altitudini\nper la visione 3D.
 tip.manuallycorrelateone=Con il collegamento manuale di almeno una foto, lo scarto di orario viene calcolato per te
 
 # Buttons
@@ -713,7 +724,6 @@ fieldname.newsegment=Segmento
 fieldname.custom=Custom
 fieldname.prefix=Campo
 fieldname.distance=Distanza
-fieldname.movingdistance=Distanza in movimento
 fieldname.duration=Durata
 fieldname.speed=Velocit\u00e0
 fieldname.verticalspeed=Velocit\u00e0 verticale
@@ -844,3 +854,6 @@ error.cache.empty=Directory del cache di tasselli \u00e8 vuoto
 error.cache.cannotdelete=Impossibile cancellare tasselli
 error.interpolate.invalidparameter=Il numero di punti deve essere tra 1 e 1000
 error.learnestimationparams.failed=Non \u00e8 possibile apprendere i parametri da questa traccia.\nProva a caricare pi\u00f9 tracce.
+error.tracksplit.nosplit=La traccia non pu\u00f2 essere divisa
+error.downloadsrtm.nocache=Non \u00e8 stato possibile salvare i file.\nControlla la cache del disco.
+error.sewsegments.nothingdone=Non \u00e8 stato possibile riorganizzare nessun segmento.\nCi sono %d segmenti nella traccia.
index 5e09c49c5056b759799757b9c0d7c257abf3d878..e581c18b51e2fd2246225ba3248126b908424a95 100644 (file)
@@ -225,7 +225,6 @@ dialog.undo.none.text=\u30a2\u30f3\u30c9\u30a5\u3067\u304d\u308b\u4f5c\u696d\u75
 dialog.clearundo.title=\u30a2\u30f3\u30c9\u30a5\u30ea\u30b9\u30c8\u3092\u7a7a\u306b\u3059\u308b
 dialog.clearundo.text=\u672c\u5f53\u306b\u30a2\u30f3\u30c9\u30a5\u30ea\u30b9\u30c8\u3092\u7a7a\u306b\u3057\u307e\u3059\u304b?\n\u5168\u3066\u306e\u30a2\u30f3\u30c9\u30a5\u60c5\u5831\u304c\u5931\u308f\u308c\u307e\u3059\u3002
 dialog.pointedit.title=\u70b9\u3092\u7de8\u96c6
-dialog.pointedit.text=\u7de8\u96c6\u3059\u308b\u30d5\u30a3\u30fc\u30eb\u30c9\u3092\u9078\u629e\u3057\u3001'\u7de8\u96c6' \u30dc\u30bf\u30f3\u3067\u5024\u3092\u7de8\u96c6\u3057\u3066\u304f\u3060\u3055\u3044\u3002
 dialog.pointedit.table.field=\u30d5\u30a3\u30fc\u30eb\u30c9
 dialog.pointedit.table.value=\u503c
 dialog.pointnameedit.name=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u540d
@@ -270,7 +269,6 @@ dialog.fullrangedetails.intro=\u9078\u629e\u7bc4\u56f2\u306b\u306f\u8a73\u7d30\u
 dialog.addmapsource.title=\u65b0\u3057\u3044\u30de\u30c3\u30d7\u30fb\u30bd\u30fc\u30b9\u3092\u8ffd\u52a0
 dialog.addmapsource.sourcename=\u30bd\u30fc\u30b9\u306e\u540d\u524d
 dialog.addmapsource.maxzoom=\u6700\u5927\u30ba\u30fc\u30e0\u30ec\u30d9\u30eb
-dialog.addmapsource.cloudstyle=\u30b9\u30bf\u30a4\u30eb\u756a\u53f7
 dialog.addmapsource.noname=\u540d\u524d\u306a\u3057
 dialog.gpsies.column.name=\u30c8\u30e9\u30c3\u30af\u540d
 dialog.gpsies.column.length=\u9577\u3055
@@ -391,7 +389,6 @@ dialog.saveconfig.prune.mapsource=\u30de\u30c3\u30d7\u30fb\u30bd\u30fc\u30b9\u30
 dialog.saveconfig.prune.mapsourcelist=\u30de\u30c3\u30d7\u30fb\u30bd\u30fc\u30b9
 dialog.saveconfig.prune.diskcache=\u30de\u30c3\u30d7\u306e\u30ad\u30e3\u30c3\u30b7\u30e5
 dialog.saveconfig.prune.kmzimagewidth=KML \u753b\u50cf\u5e45
-dialog.saveconfig.prune.kmzimageheight=KML \u753b\u50cf\u9ad8
 dialog.saveconfig.prune.colourscheme=\u8272\u306e\u30b9\u30ad\u30fc\u30e0
 dialog.saveconfig.prune.linewidth=\u7dda\u306e\u5e45
 dialog.saveconfig.prune.kmltrackcolour=KML \u30c8\u30e9\u30c3\u30af\u306e\u8272
index 583c2c5d7e57c3a81ae973af3c1218be112dda0d..b14b0a5b6fa09761f499602e84e8d4e2e47455cd 100644 (file)
@@ -219,7 +219,6 @@ dialog.undo.none.text=\ub418\ub3cc\ub9b4 \uc791\uc5c5\uc774 \uc5c6\uc5b4\uc694!
 dialog.clearundo.title=\ub418\ub3cc\ub9ac\uae30 \ubaa9\ub85d \uc9c0\uc6b0\uae30
 dialog.clearundo.text=\uc815\ub9d0\ub85c \ub418\ub3cc\ub9ac\uae30 \ubaa9\ub85d \uc9c0\uc6b0\uc2e4\uac74\uac00\uc694? /n \ubaa8\ub4e0 \ub418\ub3cc\ub9ac\uae30 \uc815\ubcf4\uac00 \uc5c6\uc5b4\uc9c4\ub2e4\uad6c\uc694!
 dialog.pointedit.title=\uc9c0\uc810 \uc218\uc815\ud558\uae30
-dialog.pointedit.text=\uc218\uc815\ud560 \ud544\ub4dc\ub97c \uc120\ud0dd\ud558\uc2dc\uace0, \uc218\uc815\ud558\uae30 \ubc84\ud2bc\uc744 \uc0ac\uc6a9\ud558\uc138\uc694.
 dialog.pointedit.table.field=\ud544\ub4dc
 dialog.pointedit.table.value=\uac12
 dialog.pointnameedit.name=\uacbd\uc720\uc9c0 \uc774\ub984
@@ -267,7 +266,6 @@ dialog.addmapsource.sourcename=\uc18c\uc2a4 \uc774\ub984
 dialog.addmapsource.layer1url=\uccab \ub808\uc774\uc5b4\uc758 URL
 dialog.addmapsource.layer2url=\ub450\ubc88\uc9f8 \ub808\uc774\uc5b4\uc758 URL
 dialog.addmapsource.maxzoom=\ucd5c\uace0 \ud655\ub300
-dialog.addmapsource.cloudstyle=\uc2a4\ud0c0\uc77c \uc218
 dialog.addmapsource.noname=\uc774\ub984 \uc5c6\uc74c
 dialog.gpsies.column.name=\ud2b8\ub809 \uc774\ub984
 dialog.gpsies.column.length=\uae38\uc774
@@ -398,7 +396,6 @@ dialog.saveconfig.prune.mapsource=\uc120\ud0dd\ub41c \uc9c0\ub3c4 \uc704\uce58
 dialog.saveconfig.prune.mapsourcelist=\uc9c0\ub3c4 \uc18c\uc2a4
 dialog.saveconfig.prune.diskcache=\uc9c0\ub3c4 \uce90\uc2dc
 dialog.saveconfig.prune.kmzimagewidth=KMZ \uc774\ubbf8\uc9c0 \ub113\uc774
-dialog.saveconfig.prune.kmzimageheight=KMZ \uc774\ubbf8\uc9c0 \ub192\uc774
 dialog.saveconfig.prune.colourscheme=\uc0c9 \uad6c\uc131
 dialog.saveconfig.prune.linewidth=\ud2b8\ub799\uc120 \ub450\uaed8
 dialog.saveconfig.prune.kmltrackcolour=KML \ud2b8\ub799 \uc0c9
index 8c0e8a9cd8096264fd06f47ae5787bdf6ad9ac14..a077bc95e45a2ed9f476aa697d72712fb5f83b35 100644 (file)
@@ -358,7 +358,6 @@ dialog.addmapsource.sourcename=Naam van de bron
 dialog.addmapsource.layer1url=URL van de eerste laag
 dialog.addmapsource.layer2url=URL van de tweede laag (optioneel)
 dialog.addmapsource.maxzoom=Maximaal zoom-niveau
-dialog.addmapsource.cloudstyle=Stijl nummer
 dialog.addmapsource.noname=Onbenoemd
 dialog.gpsies.column.name=Routenaam
 dialog.gpsies.column.length=Lengte
@@ -561,6 +560,7 @@ dialog.weather.day.thursday=Donderdag
 dialog.weather.day.friday=Vrijdag
 dialog.weather.day.saturday=Zaterdag
 dialog.weather.day.sunday=Zondag
+dialog.weather.humidity=Luchtvocht.
 dialog.weather.creditnotice=Deze gegevens worden beschikbaar gesteld door openweathermap.org. Hun website heeft meer details.
 
 # 3d window
@@ -601,6 +601,7 @@ confirm.rotatephoto=foto geroteerd
 confirm.running=Bezig...
 confirm.lookupsrtm=Gevonden %d hoote waarden
 confirm.downloadsrtm=Er zijn %d bestanden gedownload nar de cache
+confirm.downloadsrtm.1=Er zijn %d bestanden gedownload nar de cache
 confirm.downloadsrtm.none=Geen bestanden gedownload, waren al aanwezig in de cache.
 confirm.deletefieldvalues=Veldwaarden gewist
 confirm.audioload=Audiobestanden toegevoegd
index 212eb695b30b10c751851f1bf6fd3ef77808a2b9..80a67c149e994878a750ba8777ab9090a52a3768 100644 (file)
@@ -352,7 +352,6 @@ dialog.addmapsource.sourcename=Nazwa dostawcy
 dialog.addmapsource.layer1url=URL pierwszej warstwy
 dialog.addmapsource.layer2url=Opcjonalny URL drugiej warstwy
 dialog.addmapsource.maxzoom=Maksymalny poziom zbli\u017cenia
-dialog.addmapsource.cloudstyle=Numer stylu
 dialog.addmapsource.noname=Nienazwane
 dialog.gpsies.column.name=Nazwa \u015bcie\u017cki
 dialog.gpsies.column.length=D\u0142ugo\u015b\u0107
index f70a01e9497d2d2624770e77f2192f3f135ddc98..85870ad0faf16167cd24df9298d57b083c37187d 100644 (file)
@@ -18,8 +18,8 @@ menu.track.rearrange.start=Tudo para o in\u00edcio do arquivo
 menu.track.rearrange.end=Tudo para o fim do arquivo
 menu.track.rearrange.nearest=Cada um para o ponto da rota mais pr\u00f3ximo
 menu.range=Intervalo
-menu.range.all=Selectionar tudo
-menu.range.none=N\u00e3o selecionar nenhuns
+menu.range.all=Selecionar tudo
+menu.range.none=Desmarcar todas as sele\u00e7\u00f5es
 menu.range.start=Definir in\u00edcio do intervalo
 menu.range.end=Definir fim do intervalo
 menu.range.average=Sele\u00e7\u00e3o m\u00e9dia
@@ -36,7 +36,7 @@ menu.view=Exibir
 menu.view.showsidebars=Mostrar barras laterais
 menu.view.browser=Mapear no navegador
 menu.view.browser.google=Mapas do Google
-menu.view.browser.openstreetmap=Mapas do Openstreetmap
+menu.view.browser.openstreetmap=Mapas do OpenStreetMap
 menu.view.browser.mapquest=Mapas do Mapquest
 menu.view.browser.yahoo=Mapas do Yahoo
 menu.view.browser.bing=Mapas do Bing
@@ -112,8 +112,8 @@ function.getgpsies=Obter rotas Gpsies
 function.uploadgpsies=Enviar rotas para o Gpsies
 function.lookupsrtm=Obter altitudes a partir do SRTM
 function.downloadsrtm=Baixar arquivos SRTM
-function.getwikipedia=Obter artigos da Wikipedia das redondezas
-function.searchwikipedianames=Procurar na Wikipedia por nome
+function.getwikipedia=Obter artigos da Wikip\u00e9dia das redondezas
+function.searchwikipedianames=Procurar na Wikip\u00e9dia por nome
 function.downloadosm=Baixar dados OSM para a \u00e1rea
 function.duplicatepoint=Duplicar ponto
 function.setcolours=Definir cores
@@ -127,7 +127,7 @@ function.rearrangephotos=Rearrumar fotos
 function.rotatephotoleft=Roda foto \u00e0 esquerda
 function.rotatephotoright=Roda foto \u00e0 direita
 function.photopopup=Mostrar janela da foto
-function.ignoreexifthumb=Ignorar miniatura do exif
+function.ignoreexifthumb=Ignorar miniatura do Exif
 function.loadaudio=Adicionar arquivos de \u00e1udio
 function.removeaudio=Remover arquivo de \u00e1udio
 function.correlateaudios=Correlacionar \u00e1udios
@@ -144,7 +144,7 @@ function.getweatherforecast=Baixar a previs\u00e3o do tempo para a \u00e1rea atu
 
 # Dialogs
 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.exit.confirm.text=Seus dados n\u00e3o foram salvos. Voc\u00ea tem certeza de que deseja sair?
 dialog.openappend.title=Adicionar aos dados existentes
 dialog.openappend.text=Adicionar estes dados aos dados j\u00e1 carregados?
 dialog.deletepoint.title=Remover Ponto
@@ -222,12 +222,12 @@ dialog.save.coordinateunits=Unidades das coordenadas
 dialog.save.altitudeunits=Unidades da altitude
 dialog.save.timestampformat=Formato da data-hora
 dialog.save.overwrite.title=Arquivo j\u00e1 existe
-dialog.save.overwrite.text=Este arquivo j\u00e1 existe. Voc\u00ea tem certeza que deseja sobrescrev\u00ea-lo?
+dialog.save.overwrite.text=Este arquivo j\u00e1 existe. Voc\u00ea tem certeza de que deseja sobrescrev\u00ea-lo?
 dialog.save.notypesselected=Nenhum tipo de ponto foi selecionado
 dialog.exportkml.text=T\u00edtulo para os dados
 dialog.exportkml.altitude=Incluir altitudes (para avia\u00e7\u00e3o)
-dialog.exportkml.kmz=Comprimir para criar arquivo kmz
-dialog.exportkml.exportimages=Exportar miniaturas de imagem para o kmz
+dialog.exportkml.kmz=Comprimir para criar arquivo KMZ
+dialog.exportkml.exportimages=Exportar miniaturas de imagem para o KMZ
 dialog.exportkml.imagesize=Tamanho da imagem
 dialog.exportkml.trackcolour=Cor da rota
 dialog.exportkml.standardkml=KML plano
@@ -247,7 +247,7 @@ dialog.exportpov.cameraz=Z da C\u00e2mera
 dialog.exportpov.modelstyle=Estilo do modelo
 dialog.exportpov.ballsandsticks=Bolas e galhos
 dialog.exportpov.tubesandwalls=Tubos e muros
-dialog.3d.warningtracksize=Esta rota possui um grande n\u00famero de pontos, os quais o Java3D n\u00e3o ser\u00e1 capaz de exibir.\n Voc\u00ea tem certeza que deseja continuar?
+dialog.3d.warningtracksize=Esta rota possui um grande n\u00famero de pontos, os quais o Java3D n\u00e3o ser\u00e1 capaz de exibir.\n Voc\u00ea tem certeza de que deseja continuar?
 dialog.3d.useterrain=Mostrar terreno
 dialog.3d.terraingridsize=Tamanho da grade
 dialog.exportpov.baseimage=Imagem base
@@ -274,9 +274,9 @@ dialog.pointtype.photo=Pontos de foto
 dialog.pointtype.audio=Pontos de \u00e1udio
 dialog.pointtype.selection=Apenas sele\u00e7\u00e3o
 dialog.confirmreversetrack.title=Confirmar invers\u00e3o
-dialog.confirmreversetrack.text=Esta rota possui informa\u00e7\u00f5es de data-hora, as quais estar\u00e3o fora de sequ\u00eancia ap\u00f3s a revers\u00e3o.\n Voc\u00ea tem certeza que deseja reverter esta se\u00e7\u00e3o?
+dialog.confirmreversetrack.text=Esta rota possui informa\u00e7\u00f5es de data-hora, as quais estar\u00e3o fora de sequ\u00eancia ap\u00f3s a revers\u00e3o.\n Voc\u00ea tem certeza de que deseja reverter esta se\u00e7\u00e3o?
 dialog.confirmcutandmove.title=Confirmar cortar e mover
-dialog.confirmcutandmove.text=A rota cont\u00e9m informa\u00e7\u00f5es de data-hora, as quais estar\u00e3o fora de sequ\u00eancia ap\u00f3s o movimento.\n Voc\u00ea tem certeza que deseja mover esta se\u00e7\u00e3o?
+dialog.confirmcutandmove.text=A rota cont\u00e9m informa\u00e7\u00f5es de data-hora, as quais estar\u00e3o fora de sequ\u00eancia ap\u00f3s o movimento.\n Voc\u00ea tem certeza de que deseja mover esta se\u00e7\u00e3o?
 dialog.interpolate.parameter.text=N\u00famero de pontos para inserir entre os pontos selecionados
 dialog.interpolate.betweenwaypoints=Interpolar entre os pontos do caminho?
 dialog.undo.title=A\u00e7\u00e3o(\u00f5es) de desfazer
@@ -284,7 +284,7 @@ dialog.undo.pretext=Por favor, selecione a a\u00e7\u00e3o(\u00f5es) a desfazer
 dialog.undo.none.title=N\u00e3o foi poss\u00edvel desfazer
 dialog.undo.none.text=Nenhuma opera\u00e7\u00e3o a desfazer!
 dialog.clearundo.title=Limpar lista de desfazer
-dialog.clearundo.text=Voc\u00ea tem certeza que deseja limpar a lista de desfazer?\n Todas as informa\u00e7\u00f5es para desfazer ser\u00e3o perdidas!
+dialog.clearundo.text=Voc\u00ea tem certeza de que deseja limpar a lista de desfazer?\n Todas as informa\u00e7\u00f5es para desfazer ser\u00e3o perdidas!
 dialog.pointedit.title=Editar ponto
 dialog.pointedit.intro=Selecionar cada campo para mudar o valor
 dialog.pointedit.table.field=Campo
@@ -358,7 +358,6 @@ dialog.addmapsource.sourcename=Nome da fonte
 dialog.addmapsource.layer1url=URL da primeira camada
 dialog.addmapsource.layer2url=URL opcional da segunda camada
 dialog.addmapsource.maxzoom=N\u00edvel de amplia\u00e7\u00e3o m\u00e1ximo
-dialog.addmapsource.cloudstyle=N\u00famero do estilo
 dialog.addmapsource.noname=Sem nome
 dialog.gpsies.column.name=Nome da rota
 dialog.gpsies.column.length=Extens\u00e3o
@@ -381,8 +380,8 @@ dialog.gpsies.activity.skating=Patina\u00e7\u00e3o
 dialog.wikipedia.column.name=Nome do artigo
 dialog.wikipedia.column.distance=Dist\u00e2ncia
 dialog.correlate.notimestamps=N\u00e3o existem data-hora nos dados dos pontos, assim n\u00e3o h\u00e1 nada para correlacionar com as fotos
-dialog.correlate.nouncorrelatedphotos=Existem fotos n\u00e3o correlacionadas.\nVoc\u00ea tem certeza que deseja continuar?
-dialog.correlate.nouncorrelatedaudios=Existem \u00e1udios n\u00e3o correlacionados.\nVoc\u00ea tem certeza que deseja continuar?
+dialog.correlate.nouncorrelatedphotos=Existem fotos n\u00e3o correlacionadas.\nVoc\u00ea tem certeza de que deseja continuar?
+dialog.correlate.nouncorrelatedaudios=Existem \u00e1udios n\u00e3o correlacionados.\nVoc\u00ea tem certeza de que deseja continuar?
 dialog.correlate.photoselect.intro=Selecione uma destas fotos correlacionadas para usar como diferen\u00e7a de tempo
 dialog.correlate.select.photoname=Nome da foto
 dialog.correlate.select.timediff=Diferen\u00e7a de tempo
@@ -561,6 +560,9 @@ dialog.weather.day.thursday=Quinta
 dialog.weather.day.friday=Sexta
 dialog.weather.day.saturday=S\u00e1bado
 dialog.weather.day.sunday=Domingo
+dialog.weather.wind=Vento
+dialog.weather.temp=Temp
+dialog.weather.humidity=Umidade
 dialog.weather.creditnotice=Estes dados foram disponibilizados por openweathermap.org. A p\u00e1gina Web possui mais detalhes.
 
 # 3d window
@@ -601,6 +603,7 @@ confirm.rotatephoto=foto rotacionada
 confirm.running=Rodando...
 confirm.lookupsrtm=Encontrado %d valores de altitude
 confirm.downloadsrtm=%d arquivos baixados para a cache
+confirm.downloadsrtm.1=%d arquivo baixados para a cache
 confirm.downloadsrtm.none=Nenhum arquivo baixado, pois j\u00e1 est\u00e3o na cache.
 confirm.deletefieldvalues=Valores do campo removidos
 confirm.audioload=Arquivos de \u00e1udio adicionados
index ce483bd554c74a1f629e57abace781711104787f..3481dba779666bd1f6f35496285ff2e3a40e6e0d 100644 (file)
@@ -7,6 +7,7 @@ menu.file.addphotos=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0444\u043
 menu.file.recentfiles=\u041f\u0440\u0438\u043d\u044f\u0442\u044b\u0435 \u0444\u0430\u0439\u043b\u044b
 menu.file.save=\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442
 menu.file.exit=\u0412\u044b\u0445\u043e\u0434
+menu.online=\u041e\u043d\u043b\u0430\u0439\u043d
 menu.track=\u0422\u0440\u0435\u043a
 menu.track.undo=\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c
 menu.track.clearundo=\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439
@@ -57,6 +58,7 @@ menu.map.editmode=\u0420\u0435\u0436\u0438\u043c \u0440\u0435\u0434\u0430\u043a\
 
 # Alt keys for menus
 altkey.menu.file=F
+altkey.menu.online=N
 altkey.menu.track=T
 altkey.menu.range=R
 altkey.menu.point=P
@@ -100,11 +102,16 @@ function.charts=\u0413\u0440\u0430\u0444\u0438\u043a\u0438
 function.show3d=3D-\u0432\u0438\u0434
 function.distances=\u0420\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u044f
 function.fullrangedetails=\u0414\u0435\u0442\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0443
+function.estimatetime=\u041f\u0440\u043e\u0433\u043d\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0440\u0435\u043c\u044f
+function.learnestimationparams=\u0417\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438
 function.setmapbg=\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u043a\u0430\u0440\u0442\u0443-\u043f\u043e\u0434\u043b\u043e\u0436\u043a\u0443
 function.setpaths=\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0443\u0442\u0438 \u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u043c
+function.splitsegments=\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0440\u0435\u043a \u043d\u0430 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b
+function.sewsegments=\u0421\u043a\u043b\u0435\u0438\u0442\u044c \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b \u0442\u0440\u0435\u043a\u0430 \u0432\u043e\u0435\u0434\u0438\u043d\u043e
 function.getgpsies=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0442\u0440\u0435\u043a\u0438
 function.uploadgpsies=\u0412\u044b\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0442\u0440\u0435\u043a \u043d\u0430 gpsies.com
 function.lookupsrtm=\u0412\u044b\u0441\u043e\u0442\u044b \u0432 SRTM
+function.downloadsrtm=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c STRM 
 function.getwikipedia=\u0421\u0442\u0430\u0442\u044c\u044f \u043e \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432 \u0412\u0438\u043a\u0438
 function.searchwikipedianames=\u041f\u043e\u0438\u0441\u043a \u0441\u0442\u0430\u0442\u0435\u0439 \u0432 \u0412\u0438\u043a\u0438 \u043f\u043e \u0438\u043c\u0435\u043d\u0438
 function.downloadosm=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c OSM \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0442\u0435\u0440\u0440\u0438\u0442\u043e\u0440\u0438\u044e
@@ -133,6 +140,7 @@ function.checkversion=\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0
 function.saveconfig=\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438
 function.diskcache=\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u0440\u0442\u044b \u043d\u0430 \u0434\u0438\u0441\u043a
 function.managetilecache=\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u0435\u0448\u0435\u043c
+function.getweatherforecast=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043f\u0440\u043e\u0433\u043d\u043e\u0437 \u043f\u043e\u0433\u043e\u0434\u044b
 
 # Dialogs
 dialog.exit.confirm.title=\u0412\u044b\u0445\u043e\u0434
@@ -158,7 +166,9 @@ dialog.delimiter.other=\u0414\u0440\u0443\u0433\u043e\u0435
 dialog.openoptions.deliminfo.records=\u0437\u0430\u043f\u0438\u0441\u044c, \u0441
 dialog.openoptions.deliminfo.fields=\u043f\u043e\u043b\u0435
 dialog.openoptions.deliminfo.norecords=\u041d\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u0435\u0439
-dialog.openoptions.altitudeunits=\u0415\u0434\u0438\u043d\u0438\u0446\u044b \u0432\u044b\u0441\u043e\u0442
+dialog.openoptions.altitudeunits=\u0415\u0434\u0438\u043d\u0438\u0446\u044b \u0432\u044b\u0441\u043e\u0442\u044b
+dialog.openoptions.speedunits=\u0415\u0434\u0438\u043d\u0438\u0446\u044b \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438
+dialog.openoptions.vertspeedunits=\u0415\u0434\u0438\u043d\u0438\u0446\u044b
 dialog.open.contentsdoubled=\u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0442\u043e\u0447\u043a\u0435,\n\u043e\u0434\u043d\u0430 \u043a\u0430\u043a \u043f\u0443\u0442\u0435\u0432\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0438 \u043e\u0434\u043d\u0430 \u043a\u0430\u043a \u0442\u043e\u0447\u043a\u0430 \u0442\u0440\u0435\u043a\u0430
 dialog.selecttracks.intro=\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0440\u0435\u043a(-\u0438) \u0434\u043b\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f
 dialog.selecttracks.noname=\u0411\u0435\u0437\u044b\u043c\u044f\u043d\u043d\u044b\u0439
@@ -176,6 +186,11 @@ dialog.gpsload.save=\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043
 dialog.gpssend.sendwaypoints=\u041f\u043e\u0441\u043b\u0430\u0442\u044c \u043f\u0443\u0442\u0435\u0432\u044b\u0435 \u0442\u043e\u0447\u043a\u0438
 dialog.gpssend.sendtracks=\u041f\u043e\u0441\u043b\u0430\u0442\u044c \u0442\u0440\u0435\u043a\u0438
 dialog.gpssend.trackname=\u0418\u043c\u044f \u0442\u0440\u0435\u043a\u0430
+dialog.gpsbabel.filters=\u0424\u0438\u043b\u044c\u0442\u0440\u044b
+dialog.addfilter.title=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440
+dialog.gpsbabel.filter.distance=\u0420\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435
+dialog.gpsbabel.filter.interpolate=\u0418\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u044f
+dialog.gpsbabel.filter.discard.numsats=\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043f\u0443\u0442\u043d\u0438\u043a\u043e\u0432 <
 dialog.saveoptions.title=\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0444\u0430\u0439\u043b
 dialog.save.fieldstosave=\u041f\u043e\u043b\u044f \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435
 dialog.save.table.field=\u041f\u043e\u043b\u0435
@@ -210,13 +225,25 @@ dialog.exportpov.modelstyle=\u0421\u0442\u0438\u043b\u044c \u043c\u043e\u0434\u0
 dialog.exportpov.ballsandsticks=\u041c\u044f\u0447\u0438 \u0438 \u043f\u0430\u043b\u043e\u0447\u043a\u0438
 dialog.exportpov.tubesandwalls=\u0422\u0440\u0443\u0431\u044b \u0438 \u0441\u0442\u0435\u043d\u044b
 dialog.3d.warningtracksize=\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0432 \u0442\u0440\u0435\u043a\u0435 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u043e\u0447\u0435\u043a - Java3D \u043c\u043e\u0436\u0435\u0442 \u0435\u0433\u043e \u043d\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c!\n\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?
-dialog.baseimage.mapsource=\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430
-dialog.baseimage.zoom=\u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442
+dialog.3d.useterrain=\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0440\u0435\u043b\u044c\u0435\u0444
+dialog.3d.terraingridsize=\u0420\u0430\u0437\u043c\u0435\u0440 \u0441\u0435\u0442\u043a\u0438
+dialog.exportpov.baseimage=\u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0430 \u043e\u0441\u043d\u043e\u0432\u044b(\u043f\u043e\u0434\u043b\u043e\u0436\u043a\u0438)
+dialog.exportpov.cannotmakebaseimage=\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443 \u043e\u0441\u043d\u043e\u0432\u044b
+dialog.baseimage.title=\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u044b
+dialog.baseimage.useimage=\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435
+dialog.baseimage.mapsource=\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a
+dialog.baseimage.zoom=\u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c
+dialog.baseimage.incomplete=\u041d\u0435 \u0432\u0441\u0435 \u0442\u0430\u0439\u043b\u044b \u0431\u044b\u043b\u0438 \u043d\u0430\u0439\u0434\u0435\u043d\u044b
+dialog.baseimage.tiles=\u0422\u0430\u0439\u043b\u044b
 dialog.baseimage.size=\u0420\u0430\u0437\u043c\u0435\u0440 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f
 dialog.exportsvg.text=\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 SVG
 dialog.exportsvg.phi=\u0410\u0437\u0438\u043c\u0443\u0442 \u03d5
 dialog.exportsvg.theta=\u0423\u0433\u043e\u043b \u03b8
 dialog.exportsvg.gradients=\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u0440\u0430\u0434\u0438\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u0442\u0435\u043d\u0435\u043d\u0438\u044f
+dialog.exportimage.noimagepossible=\u041a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u043a\u0430\u0440\u0442\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b \u043d\u0430 \u0434\u0438\u0441\u043a \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430
+dialog.exportimage.drawtrack=\u0420\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0435\u043a \u043d\u0430 \u043a\u0430\u0440\u0442\u0435
+dialog.exportimage.drawtrackpoints=\u041e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0442\u043e\u0447\u043a\u0438 \u0442\u0440\u0435\u043a\u0430
+dialog.exportimage.textscalepercent=\u041c\u0430\u0441\u0448\u0442\u0430\u0431 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 %
 dialog.pointtype.desc=\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0442\u0438\u043f\u044b \u0442\u043e\u0447\u0435\u043a:
 dialog.pointtype.track=\u0422\u043e\u0447\u043a\u0438 \u0442\u0440\u0435\u043a\u043e\u0432
 dialog.pointtype.waypoint=\u041f\u0443\u0442\u0435\u0432\u044b\u0435 \u0442\u043e\u0447\u043a\u0438
@@ -236,7 +263,9 @@ dialog.undo.none.text=\u041d\u0435\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0
 dialog.clearundo.title=\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b
 dialog.clearundo.text=\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b?\n\u0421\u043f\u0438\u0441\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u0447\u0438\u0449\u0435\u043d \u043d\u0430\u0432\u0441\u0435\u0433\u0434\u0430!
 dialog.pointedit.title=\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u0447\u043a\u0443
+dialog.pointedit.intro=\u0412\u044b\u0431\u0438\u0440\u0430\u0439\u0442\u0435 \u043a\u0430\u0436\u0434\u043e\u0435 \u043f\u043e\u043b\u0435 \u0447\u0442\u043e\u0431\u044b \u0432\u0438\u0434\u0435\u0442\u044c \u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435
 dialog.pointedit.table.field=\u041f\u043e\u043b\u0435
+dialog.pointedit.nofield=\u041f\u043e\u043b\u0435 \u043d\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043e
 dialog.pointedit.table.value=\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435
 dialog.pointnameedit.name=\u0418\u043c\u044f \u043f\u0443\u0442\u0435\u0432\u043e\u0439 \u0442\u043e\u0447\u043a\u0438
 dialog.pointnameedit.uppercase=\u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440
@@ -280,16 +309,27 @@ dialog.fullrangedetails.intro=\u0414\u0435\u0442\u0430\u043b\u0438\u0437\u0430\u
 dialog.fullrangedetails.coltotal=\u0412\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043a\u0438
 dialog.fullrangedetails.colsegments=\u0411\u0435\u0437 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043a\u043e\u0432
 dialog.estimatetime.details=\u0414\u0435\u0442\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f
+dialog.estimatetime.gentle=\u041f\u043b\u0430\u0432\u043d\u043e
+dialog.estimatetime.steep=\u0420\u0435\u0437\u043a\u043e
 dialog.estimatetime.climb=\u041f\u043e\u0434\u044a\u0435\u043c
 dialog.estimatetime.descent=\u0421\u043f\u0443\u0441\u043a
 dialog.estimatetime.parameters=\u041f\u0430\u0440\u0430\u0301\u043c\u0435\u0442\u0440\u044b
+dialog.estimatetime.parameters.timefor=\u0412\u0440\u0435\u043c\u044f \u0434\u043b\u044f
+dialog.estimatetime.results=\u0412\u043e\u0442:
+dialog.estimatetime.results.estimatedtime=\u041f\u0440\u043e\u0433\u043d\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f
+dialog.estimatetime.results.actualtime=\u0420\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f
+dialog.estimatetime.error.noaltitudes=\u0412\u044b\u0431\u043e\u0440\u043a\u0430 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0432\u044b\u0441\u043e\u0442\u0435
+dialog.learnestimationparams.averageerror=\u0421\u0440\u0435\u0434\u043d\u044f\u044f \u043e\u0448\u0438\u0431\u043a\u0430 (%)
+dialog.learnestimationparams.weight.current=\u0442\u0435\u043a\u0443\u0449\u0435\u0435
+dialog.learnestimationparams.weight.calculated=\u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u043d\u043e\u0435
+dialog.learnestimationparams.weight.50pc=\u0421\u0440\u0435\u0434\u043d\u0435\u0435 \u043e\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0438 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u043d\u043e\u0433\u043e
+dialog.learnestimationparams.weight.100pccalculated=\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435
 dialog.setmapbg.intro=\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0444\u043e\u043d\u0430 \u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043d\u043e\u0432\u044b\u0439
 dialog.addmapsource.title=\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043d\u043e\u0432\u044b\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0444\u043e\u043d\u0430
 dialog.addmapsource.sourcename=\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430
 dialog.addmapsource.layer1url=URL \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u043b\u043e\u044f
 dialog.addmapsource.layer2url=\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0439 URL \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u043b\u043e\u044f
 dialog.addmapsource.maxzoom=\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f
-dialog.addmapsource.cloudstyle=\u041d\u043e\u043c\u0435\u0440 \u0441\u0442\u0438\u043b\u044f
 dialog.addmapsource.noname=\u0411\u0435\u0437\u044b\u043c\u044f\u043d\u043d\u044b\u0439
 dialog.gpsies.column.name=\u0418\u043c\u044f \u0442\u0440\u0435\u043a\u0430
 dialog.gpsies.column.length=\u0414\u043b\u0438\u043d\u0430
@@ -474,6 +514,28 @@ dialog.deletefieldvalues.nofields=\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u0
 dialog.setlinewidth.text=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u043e\u043b\u0449\u0438\u043d\u0443 \u043b\u0438\u043d\u0438\u0439 \u0434\u043b\u044f \u0442\u0440\u0435\u043a\u043e\u0432 (1-4)
 dialog.downloadosm.desc=\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 OSM \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438:
 dialog.searchwikipedianames.search=\u041f\u043e\u0438\u0441\u043a \u0434\u043b\u044f:
+dialog.weather.location=\u041c\u0435\u0441\u0442\u043e
+dialog.weather.update=\u041f\u0440\u043e\u0433\u043d\u043e\u0437 \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d
+dialog.weather.sunrise=\u0412\u043e\u0441\u0445\u043e\u0434
+dialog.weather.sunset=\u0417\u0430\u043a\u0430\u0442
+dialog.weather.temperatureunits=\u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u044b
+dialog.weather.currentforecast=\u041f\u043e\u0433\u043e\u0434\u0430 \u0441\u0435\u0439\u0447\u0430\u0441
+dialog.weather.dailyforecast=\u041f\u0440\u043e\u0433\u043d\u043e\u0437 \u043d\u0430 \u0434\u0435\u043d\u044c
+dialog.weather.3hourlyforecast=\u041f\u0440\u043e\u0433\u043d\u043e\u0437 \u043d\u0430 3 \u0447\u0430\u0441\u0430
+dialog.weather.day.now=\u0422\u0435\u043a\u0443\u0449\u0430\u044f \u043f\u043e\u0433\u043e\u0434\u0430
+dialog.weather.day.today=\u0421\u0435\u0433\u043e\u0434\u043d\u044f
+dialog.weather.day.tomorrow=\u0417\u0430\u0432\u0442\u0440\u0430
+dialog.weather.day.monday=\u041f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a
+dialog.weather.day.tuesday=\u0412\u0442\u043e\u0440\u043d\u0438\u043a
+dialog.weather.day.wednesday=\u0421\u0440\u0435\u0434\u0430
+dialog.weather.day.thursday=\u0427\u0435\u0442\u0432\u0435\u0440\u0433
+dialog.weather.day.friday=\u041f\u044f\u0442\u043d\u0438\u0446\u0430
+dialog.weather.day.saturday=\u0421\u0443\u0431\u0431\u043e\u0442\u0430
+dialog.weather.day.sunday=\u0412\u043e\u0441\u043a\u0440\u0435\u0441\u0435\u043d\u044c\u0435
+dialog.weather.wind=\u0412\u0435\u0442\u0435\u0440
+dialog.weather.temp=\u0422\u00b0
+dialog.weather.humidity=\u0412\u043b\u0430\u0436\u043d\u043e\u0441\u0442\u044c
+dialog.weather.creditnotice=\u0414\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0439 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044C \u043F\u043E openweathermap.org.
 
 # 3d window
 dialog.3d.title=GpsPrune 3D-\u0432\u0438\u0434
@@ -492,6 +554,8 @@ confirm.addtimeoffset=\u041e\u0442\u043c\u0435\u0442\u043a\u0430 \u0432\u0440\u0
 confirm.addaltitudeoffset=\u041e\u0442\u043c\u0435\u0442\u043a\u0430 \u0432\u044b\u0441\u043e\u0442\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430
 confirm.rearrangewaypoints=\u041f\u0443\u0442\u0435\u0432\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u0430\u043d\u0430
 confirm.rearrangephotos=\u0424\u043e\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u0430\u043d\u043e
+confirm.splitsegments=\u0421\u0434\u0435\u043b\u0430\u043d\u043e %d \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0439 \u043d\u0430 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b
+confirm.sewsegments=\u0421\u0434\u0435\u043b\u0430\u043d\u043e %d \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432
 confirm.cutandmove=\u041e\u0442\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u043e
 confirm.interpolate=\u0422\u043e\u0447\u043a\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b
 confirm.convertnamestotimes=\u0418\u043c\u044f \u043f\u0443\u0442\u0435\u0432\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043e
@@ -510,12 +574,15 @@ confirm.createpoint=\u0442\u043e\u0447\u043a\u0430 \u0441\u043e\u0437\u0434\u043
 confirm.rotatephoto=\u0444\u043e\u0442\u043e \u043f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u043e
 confirm.running=\u0420\u0430\u0431\u043e\u0442\u0430\u044e...
 confirm.lookupsrtm=\u041d\u0430\u0439\u0434\u0435\u043d\u043e %d \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u044b\u0441\u043e\u0442\u044b
+confirm.downloadsrtm=\u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043e %d \u0444\u0430\u0439\u043b\u043e\u0432 \u0432 \u043a\u044d\u0448
+confirm.downloadsrtm.1=\u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043e %d \u0444\u0430\u0439\u043b\u043e\u0432 \u0432 \u043a\u044d\u0448
+confirm.downloadsrtm.none=\u0412\u0441\u0435 \u0444\u0430\u0439\u043b\u044b \u0443\u0436\u0435 \u0432 \u043a\u044d\u0448\u0435
 confirm.deletefieldvalues=\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u044b
 confirm.audioload=\u0424\u0430\u0439\u043b\u044b \u0437\u0432\u0443\u043a\u043e\u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b
 confirm.correlateaudios.single=\u0417\u0432\u0443\u043a\u043e\u0437\u0430\u043f\u0438\u0441\u044c \u0431\u044b\u043b\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430
 confirm.correlateaudios.multi=\u0417\u0432\u0443\u043a\u043e\u0437\u0430\u043f\u0438\u0441\u0438 \u0431\u044b\u043b\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b
 
-# Tips
+# Tips, shown just once when appropriate
 tip.title=\u0421\u043e\u0432\u0435\u0442
 tip.manuallycorrelateone=\u041f\u0440\u0438 \u0440\u0443\u0447\u043d\u043e\u043c \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043a\u0440\u0430\u0439\u043d\u0438\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043c\u0435\u0442\u043a\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438.
 
@@ -536,6 +603,7 @@ button.yes=\u0414\u0430
 button.no=\u041d\u0435\u0442
 button.yestoall=\u0414\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0445
 button.notoall=\u041d\u0435\u0442 \u0434\u043b\u044f \u0432\u0441\u0435\u0445
+button.always=\u0412\u0441\u0435\u0433\u0434\u0430
 button.select=\u0412\u044b\u0431\u0440\u0430\u0442\u044c
 button.selectall=\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435
 button.selectnone=\u041e\u0442\u043c\u0435\u043d\u0442\u0438\u0442\u044c \u0432\u044b\u0431\u043e\u0440\u043a\u0443
@@ -550,6 +618,7 @@ button.browse=\u041e\u0431\u0437\u043e\u0440...
 button.addnew=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u043e\u0435
 button.delete=\u0423\u0434\u0430\u043b\u0438\u0442\u044c
 button.manage=\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c
+button.combine=\u0421\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u0442\u044c
 
 # File types
 filetype.txt=TXT \u0444\u0430\u0439\u043b\u044b
@@ -567,6 +636,7 @@ filetype.audio=MP3, OGG, WAV \u0444\u0430\u0439\u043b\u044b
 display.nodata=\u0414\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b
 display.noaltitudes=\u0414\u0430\u043d\u043d\u044b\u0435 \u0432 \u0442\u0440\u0435\u043a\u0435 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0432\u044b\u0441\u043e\u0442\u043d\u044b\u0445 \u043e\u0442\u043c\u0435\u0442\u043e\u043a
 display.notimestamps=\u0414\u0430\u043d\u043d\u044b\u0435 \u0432 \u0442\u0440\u0435\u043a\u0435 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043e\u0442\u043c\u0435\u0442\u043e\u043a \u0432\u0440\u0435\u043c\u0435\u043d\u0438
+display.novalues=\u0412 \u0442\u0440\u0435\u043a\u0435 \u043d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044f
 details.trackdetails=\u0414\u0435\u0442\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0440\u0435\u043a\u0430
 details.notrack=\u0422\u0440\u0435\u043a \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d
 details.track.points=\u0422\u043e\u0447\u043a\u0438(-\u0435\u043a)
@@ -656,6 +726,10 @@ units.degminsec=\u0413\u0440\u0430\u0434-\u043c\u0438\u043d-\u0441\u0435\u043a
 units.degmin=\u0413\u0440\u0430\u0434-\u043c\u0438\u043d
 units.deg=\u0413\u0440\u0430\u0434\u0443\u0441\u044b
 units.iso8601=ISO 8601
+units.degreescelsius=\u0426\u0435\u043b\u044c\u0441\u0438\u0439
+units.degreescelsius.short=\u00b0C
+units.degreesfahrenheit=\u0424\u0430\u0440\u0435\u043d\u0433\u0435\u0439\u0442
+units.degreesfahrenheit.short=\u00b0F
 
 # How to combine conditions, such as filters
 logic.and=\u0438
@@ -686,6 +760,8 @@ undo.deletemarked=\u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0442\u043e\u0447\
 undo.insert=\u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u0447\u043a\u0438
 undo.reverse=\u043f\u0435\u0440\u0435\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b
 undo.mergetracksegments=\u0441\u043b\u0438\u044f\u043d\u0438\u0435 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u0442\u0440\u0435\u043a\u0430
+undo.splitsegments=\u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b \u0442\u0440\u0435\u043a\u0430
+undo.sewsegments=\u0441\u043a\u043b\u0435\u0438\u0442\u044c \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b \u0442\u0440\u0435\u043a\u0430
 undo.addtimeoffset=\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u043c\u0435\u0442\u043a\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438
 undo.addaltitudeoffset=\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u043c\u0435\u0442\u043a\u0443 \u0432\u044b\u0441\u043e\u0442\u044b
 undo.rearrangewaypoints=\u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u0443\u0442\u0435\u0432\u044b\u0435 \u0442\u043e\u0447\u043a\u0438
@@ -745,3 +821,4 @@ error.cache.notthere=\u041f\u0430\u043f\u043a\u0430 \u043a\u044d\u0448\u0430 \u0
 error.cache.empty=\u041f\u0430\u043f\u043a\u0430 \u043a\u044d\u0448\u0430 \u0441 \u0442\u0430\u0439\u043b\u0430\u043c\u0438 \u043f\u0443\u0441\u0442\u0430
 error.cache.cannotdelete=\u041d\u0435\u0442 \u0442\u0430\u0439\u043b\u043e\u0432, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f
 error.interpolate.invalidparameter=\u041d\u043e\u043c\u0435\u0440 \u0442\u043e\u0447\u043a\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043e\u0442 1 \u0434\u043e 1000
+error.tracksplit.nosplit=\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0440\u0435\u043a
index eeffcd930a60f77c5938c68333e0ec67fd25dd04..7f421c8d4070689bf0f93de6eebd01dcd1e751e3 100644 (file)
 # Swedish entries
 
 # Menu entries
-menu.file=Fil
+menu.file=Arkiv
 menu.file.addphotos=L\u00e4gg till foto
 menu.file.recentfiles=Senaste filer
 menu.file.save=Spara som text
 menu.file.exit=Avsluta
 menu.track=Sp\u00e5r
 menu.track.undo=\u00c5ngra
-menu.track.clearundo=Rensa \u00e5ngra
+menu.track.clearundo=Rensa \u00e5ngra-historik
 menu.track.markrectangle=Markera punkter i rektangel
 menu.track.deletemarked=Radera markerade punkter
-menu.track.rearrange=Arrangera om ruttpunkter
+menu.track.rearrange=Ordna waypoints
 menu.track.rearrange.start=Alla till b\u00f6rjan av fil
 menu.track.rearrange.end=Alla till slut av fil
 menu.track.rearrange.nearest=Varje till n\u00e4rmaste sp\u00e5rpunkt
-menu.range=Omr\u00e5de
+menu.range=Intervall
 menu.range.all=V\u00e4lj alla
 menu.range.none=V\u00e4lj ingen
-menu.range.start=St\u00e4ll in b\u00f6rjan p\u00e5 omr\u00e5de
-menu.range.end=St\u00e4ll in slut p\u00e5 omr\u00e5de
+menu.range.start=S\u00e4tt till b\u00f6rjan av intervall
+menu.range.end=S\u00e4tt till slutet av intervall
 menu.range.average=Medelv\u00e4rdesval
-menu.range.reverse=Backa omr\u00e5de
+menu.range.reverse=V\u00e4nd intervall
 menu.range.mergetracksegments=Sl\u00e5 ihop sp\u00e5rsegment
 menu.range.cutandmove=Klipp och flytta urval
 menu.point=Punkt
 menu.point.editpoint=Redigera punkt
 menu.point.deletepoint=Radera punkt
 menu.photo=Foto
-menu.photo.saveexif=Spara och avsluta
+menu.photo.saveexif=Spara till Exif
 menu.audio=Ljud
-menu.view=Vy
-menu.view.showsidebars=Visa sidolister
-menu.view.browser=Karta i ett l\u00e4sarf\u00f6nster
+menu.view=Visa
+menu.view.showsidebars=Visa sidopaneler
+menu.view.browser=Karta i webbl\u00e4sare
 menu.view.browser.google=Google Maps
 menu.view.browser.openstreetmap=Openstreetmap
 menu.view.browser.mapquest=Mapquest
 menu.view.browser.yahoo=Yahoo maps
 menu.view.browser.bing=Bing maps
 menu.settings=Inst\u00e4llningar
-menu.settings.onlinemode=Ladda karta fr\u00e5n Internet
+menu.settings.onlinemode=H\u00e4mta kartor fr\u00e5n Internet
 menu.settings.autosave=Autospara inst\u00e4llningar vid avslut
 menu.help=Hj\u00e4lp
+# Popup menu for map
+menu.map.zoomin=Zooma ut
+menu.map.zoomout=Zooma in
+menu.map.zoomfull=Zooma till passning
+menu.map.newpoint=Skapa ny punkt
+menu.map.drawpoints=Skapa en serie punkter
+menu.map.connect=F\u00f6rbind sp\u00e5rpunkter
+menu.map.autopan=Panorera automatiskt
+menu.map.showmap=Visa karta
+menu.map.showscalebar=Visa skala
+menu.map.editmode=Redigeringsl\u00e4ge
 
 # Alt keys for menus
-altkey.menu.file=F
+altkey.menu.file=A
 altkey.menu.track=S
-altkey.menu.range=O
+altkey.menu.range=I
 altkey.menu.point=P
 altkey.menu.view=V
-altkey.menu.photo=T
+altkey.menu.photo=F
 altkey.menu.audio=L
 altkey.menu.settings=I
 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.range.all=A
+shortcut.menu.help.help=H
+
+# Functions
+function.open=\u00d6ppna fil
+function.importwithgpsbabel=Importera fil med GPSBabel
+function.loadfromgps=Ladda fr\u00e5n GPS
+function.sendtogps=Skicka till GPS
+function.exportkml=Exportera KML
+function.exportgpx=Exportera GPX
+function.exportpov=Exportera POV
+function.exportsvg=Exportera SVG
+function.exportimage=Exportera bildfil
+function.editwaypointname=Redigera namn p\u00e5 waypoint
+function.compress=Komprimera sp\u00e5r
+function.deleterange=Radera intervall
+function.croptrack=Besk\u00e4r sp\u00e5r till intervall
+function.interpolate=Interpolera punkter
+function.addtimeoffset=Infoga tidsoffset
+function.addaltitudeoffset=Infoga h\u00f6jdoffset
+function.convertnamestotimes=Omvandla waypointnamn till tidpunkter
+function.findwaypoint=S\u00f6k waypoint
+function.pastecoordinates=Infoga koordinater
+function.charts=Diagram
+function.show3d=3D-vy
+function.distances=Avst\u00e5nd
+function.estimatetime=Uppskatta tid
+
 openweathermap.lang=se
index e509978ee6a2cf3ddb10c338f178b19c1a6ad479..4baf0dec79adc56ea46040281094a9422585f01a 100644 (file)
@@ -269,7 +269,6 @@ dialog.saveconfig.prune.exiftoolpath=exiftool'un yeriyolu
 dialog.saveconfig.prune.mapserverindex=Harita sunucunun index
 dialog.saveconfig.prune.mapserverurl=Harita sunucunun adresi
 dialog.saveconfig.prune.kmzimagewidth=KMZ resim geni\u015fli\u011fi
-dialog.saveconfig.prune.kmzimageheight=KMZ resim y\u00fcksekli\u011fi
 dialog.setpaths.intro=\u0130ste\u011fe ba\u011fl\u0131 a\u015fa\u011f\u0131daki uygulamalar\u0131n veriyolu kaydedebilirsin:
 dialog.addaltitude.noaltitudes=Se\u00e7ili s\u0131rada y\u00fckseklik bilgisi bulunmad\u0131
 dialog.addaltitude.desc=Eklenecek y\u00fckseklik ofseti
index d0225139fddbec476e7b110ddd2f0d1f91f6bc66..1fcca74ebd5a4ff88cb9c1871227b712846a3907 100644 (file)
@@ -358,7 +358,6 @@ dialog.addmapsource.sourcename=\u5730\u56fe\u6765\u6e90\u540d\u79f0
 dialog.addmapsource.layer1url=\u7b2c\u4e00\u5c42URL
 dialog.addmapsource.layer2url=\u53ef\u9009\u7b2c\u4e8c\u5c42URL
 dialog.addmapsource.maxzoom=\u6700\u5927\u7f29\u653e\u7ea7\u6570
-dialog.addmapsource.cloudstyle=\u6837\u5f0f\u53f7
 dialog.addmapsource.noname=\u672a\u547d\u540d
 dialog.gpsies.column.name=\u8f68\u8ff9\u540d\u79f0
 dialog.gpsies.column.length=\u957f\u5ea6
@@ -601,6 +600,7 @@ confirm.rotatephoto=\u7167\u7247\u5df2\u65cb\u8f6c
 confirm.running=\u8bf7\u7a0d\u7b49...
 confirm.lookupsrtm=\u627e\u5230 %d \u9ad8\u5ea6\u503c
 confirm.downloadsrtm=\u4e0b\u8f7d %d \u9ad8\u5ea6\u6587\u4ef6\u5230\u7f13\u5b58\u4e2d
+confirm.downloadsrtm.1=\u4e0b\u8f7d %d \u9ad8\u5ea6\u6587\u4ef6\u5230\u7f13\u5b58\u4e2d
 confirm.downloadsrtm.none=\u65e0\u9700\u4e0b\u8f7d\uff0c\u6587\u4ef6\u5df2\u5b58\u50a8\u5728\u7f13\u5b58\u4e2d
 confirm.deletefieldvalues=\u533a\u57df\u6570\u636e\u5df2\u5220\u9664
 confirm.audioload=\u5df2\u6dfb\u52a0\u58f0\u97f3\u6587\u4ef6
index 16030ca64cbb03223c4abd0ca32c89f0c4c8a0db..39359c1726f82167bc0ae848f66b8754ead6c0f4 100644 (file)
@@ -26,8 +26,10 @@ public abstract class BabelFileFormats
                {
                        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;
        }
index 187bb495c196ead68ad00b73a5926041267360e8..23ce909fc9dd8e9fd6089465659d980c315a7474 100644 (file)
@@ -200,6 +200,17 @@ public class BabelLoadFromFile extends BabelLoader
                return outerPanel;
        }
 
+       /**
+        * @return the suffix of the selected filename
+        */
+       private String getSelectedSuffix()
+       {
+               String filename = _inputFile.getName();
+               if (filename == null) {return "";}
+               int dotPos = filename.lastIndexOf('.');
+               return (dotPos > 0 ? filename.substring(dotPos) : "");
+       }
+
        /**
         * Initialise dialog
         */
@@ -207,13 +218,16 @@ public class BabelLoadFromFile extends BabelLoader
        {
                _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)))
+               String suffix = getSelectedSuffix();
+               if (_lastSuffix == null || !suffix.equalsIgnoreCase(_lastSuffix))
                {
-                       // New suffix chosen, so select first appropriate format (if any)
+                       // New suffix has been chosen, so select first appropriate format (if any)
                        int selIndex = BabelFileFormats.getIndexForFileSuffix(suffix);
+                       if (selIndex < 0)
+                       {
+                               // Use the previous one from the Config (if any)
+                               selIndex = Config.getConfigInt(Config.KEY_IMPORT_FILE_FORMAT);
+                       }
                        if (selIndex >= 0) {
                                _formatDropdown.setSelectedIndex(selIndex);
                        }
@@ -229,5 +243,12 @@ public class BabelLoadFromFile extends BabelLoader
                // Save the filter string, clear it if it's now blank
                final String filter = _filterPanel.getFilterString();
                Config.setConfigString(Config.KEY_GPSBABEL_FILTER, filter);
+
+               // Check if there is a standard file type for the selected suffix
+               int selIndex = BabelFileFormats.getIndexForFileSuffix(getSelectedSuffix());
+               // If there is none, then get the index which the user chose and set in the Config
+               if (selIndex < 0) {
+                       Config.setConfigInt(Config.KEY_IMPORT_FILE_FORMAT, _formatDropdown.getSelectedIndex());
+               }
        }
 }
index 93303b205e0932bf640aceb56e4fc9cfad6ac75f..b9dd6c0ffbc995d063328c457c3e7abac65e3738 100644 (file)
@@ -1,5 +1,5 @@
-GpsPrune version 16
-===================
+GpsPrune version 16.3
+=====================
 
 GpsPrune is an application for viewing, editing and managing coordinate data from GPS systems,
 including format conversion, charting and photo correlation.
@@ -17,7 +17,7 @@ Running
 =======
 
 To run GpsPrune from the jar file, simply call it from a command prompt or shell:
-   java -jar gpsprune_16.jar
+   java -jar gpsprune_16.3.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,11 +25,36 @@ 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 gpsprune_16.jar --lang=DE
+   java -jar gpsprune_16.3.jar --lang=DE
 
 
-New with version 16
+New with version 16.3
 =====================
+The following fixes were added since version 16.2:
+  - Fix for gpx caching of points which failed to load
+  - Additional newlines / tabs in gpx export
+  - API key for openweathermap.org
+  - Improvements to 3d terrain reflections
+  - Additional translations
+
+New with version 16.2
+=====================
+The following fixes were added since version 16.1:
+  - Fix for Gpx-slicing UTF8 files
+  - Conversion of sunrise/sunset times to local timezone
+  - Removal of Cloudmade maps
+  - Additional translations
+
+New with version 16.1
+=====================
+The following fixes were added since version 16:
+  - Caching of terrain information for three-dimensional views
+  - Additional translations
+  - Improved void filling by interpolation
+  - Remembering file type of imported files
+
+New with version 16
+===================
 The following features were added since version 15:
   - Extend povray output using terrain and/or map image
   - Extend java3d output using terrain and/or map image
index 5c74a7a3894d22dd7c06d9e3e3bdb4b3fca7f1c3..672234fab4896b27e960189267631b6bda3e177b 100644 (file)
@@ -269,7 +269,7 @@ public class GpsSaver extends GenericFunction implements Runnable
                Process process = Runtime.getRuntime().exec(commands);
 
                String trackName = _trackNameField.getText();
-               if (trackName == null || trackName.equals("")) {trackName = "prune";}
+               if (trackName == null || trackName.equals("")) {trackName = "gpsprune";}
                // Generate the GPX file and send to the GPS
                OutputStreamWriter writer = new OutputStreamWriter(process.getOutputStream());
                boolean[] saveFlags = {true, true, true, true, false, true}; // export everything
index a4ac1a7de2e72ade39734e7f0099fe6e14f5faca..1b2263bc8260d6dc49115f969de5e9c40be1ffcb 100644 (file)
@@ -11,7 +11,6 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
-import java.nio.charset.Charset;
 
 import javax.swing.BorderFactory;
 import javax.swing.Box;
@@ -67,7 +66,6 @@ public class GpxExporter extends GenericFunction implements Runnable
        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 = "GpsPrune v" + GpsPrune.VERSION_NUMBER + " activityworkshop.net";
@@ -99,15 +97,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()) {
+               _encodingsPanel.setVisible(!XmlUtils.isSystemUtf8());
+               if (!XmlUtils.isSystemUtf8())
+               {
+                       String systemEncoding = XmlUtils.getSystemEncoding();
                        _useSystemRadio.setText(I18nManager.getText("dialog.exportgpx.encoding.system")
-                               + " (" + (_systemEncoding == null ? "unknown" : _systemEncoding) + ")");
+                               + " (" + (systemEncoding == null ? "unknown" : systemEncoding) + ")");
                }
                _dialog.setVisible(true);
        }
@@ -148,7 +147,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                mainPanel.add(checkPanel);
                // panel for selecting character encoding
                _encodingsPanel = new JPanel();
-               if (!isSystemUtf8())
+               if (!XmlUtils.isSystemUtf8())
                {
                        // only add this panel if system isn't utf8 (or can't be identified yet)
                        _encodingsPanel.setBorder(BorderFactory.createCompoundBorder(
@@ -384,6 +383,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                                                if (!exportTimestamps) {
                                                        pointSource = stripTime(pointSource);
                                                }
+                                               inWriter.write('\t');
                                                inWriter.write(pointSource);
                                                inWriter.write('\n');
                                        }
@@ -402,10 +402,10 @@ public class GpxExporter extends GenericFunction implements Runnable
                                exportAudios, exportTimestamps, true, inGpxCachers, "<rtept", "\t<rte><number>1</number>\n",
                                null, "\t</rte>\n");
                        // Output all track points, if any
-                       String trackStart = "\t<trk><name>" + trackName + "</name><number>1</number><trkseg>\n";
+                       String trackStart = "\t<trk>\n\t\t<name>" + trackName + "</name>\n\t\t<number>1</number>\n\t\t<trkseg>\n";
                        numSaved += writeTrackPoints(inWriter, inInfo, exportSelection, exportTrackpoints, exportPhotos,
                                exportAudios, exportTimestamps, false, inGpxCachers, "<trkpt", trackStart,
-                               "\t</trkseg>\n\t<trkseg>\n", "\t</trkseg></trk>\n");
+                               "\t</trkseg>\n\t<trkseg>\n", "\t\t</trkseg>\n\t</trk>\n");
                }
 
                inWriter.write("</gpx>\n");
@@ -432,11 +432,13 @@ public class GpxExporter extends GenericFunction implements Runnable
                }
                if (inName != null && !inName.equals(""))
                {
-                       inWriter.write("\t\t<name>");
+                       if (inIsVersion1_1) {inWriter.write('\t');}
+                       inWriter.write("\t<name>");
                        inWriter.write(inName);
                        inWriter.write("</name>\n");
                }
-               inWriter.write("\t\t<desc>");
+               if (inIsVersion1_1) {inWriter.write('\t');}
+               inWriter.write("\t<desc>");
                inWriter.write(desc);
                inWriter.write("</desc>\n");
                if (inIsVersion1_1)
@@ -486,7 +488,9 @@ public class GpxExporter extends GenericFunction implements Runnable
                                        // get the source from the point (if any)
                                        String pointSource = getPointSource(inCachers, point);
                                        // Clear point source if it's the wrong type of point (eg changed from waypoint or route point)
-                                       if (pointSource != null && !pointSource.toLowerCase().startsWith(inPointTag)) {pointSource = null;}
+                                       if (pointSource != null && !pointSource.trim().toLowerCase().startsWith(inPointTag)) {
+                                               pointSource = null;
+                                       }
                                        if (pointSource != null || !inOnlyCopies)
                                        {
                                                // restart track segment if necessary
@@ -626,63 +630,10 @@ public class GpxExporter extends GenericFunction implements Runnable
         */
        private static String getXmlHeaderString(OutputStreamWriter inWriter)
        {
-               return "<?xml version=\"1.0\" encoding=\"" + getEncoding(inWriter) + "\"?>\n";
+               return "<?xml version=\"1.0\" encoding=\"" + XmlUtils.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 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"));
-       }
-
        /**
         * Get the header string for the gpx tag
         * @param inCachers cacher list to ask for headers, if available
@@ -790,24 +741,24 @@ public class GpxExporter extends GenericFunction implements Runnable
                boolean inExportPhoto, boolean inExportAudio)
                throws IOException
        {
-               inWriter.write("\t\t<trkpt lat=\"");
+               inWriter.write("\t\t\t<trkpt lat=\"");
                inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write("\" lon=\"");
                inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
-               inWriter.write("\">");
+               inWriter.write("\">\n");
                // altitude
                if (inPoint.hasAltitude())
                {
-                       inWriter.write("<ele>");
+                       inWriter.write("\t\t\t\t<ele>");
                        inWriter.write("" + inPoint.getAltitude().getStringValue(UnitSetLibrary.UNITS_METRES));
-                       inWriter.write("</ele>");
+                       inWriter.write("</ele>\n");
                }
                // timestamp if available (and selected)
                if (inPoint.hasTimestamp() && inTimestamps)
                {
-                       inWriter.write("<time>");
+                       inWriter.write("\t\t\t\t<time>");
                        inWriter.write(inPoint.getTimestamp().getText(Timestamp.FORMAT_ISO_8601));
-                       inWriter.write("</time>");
+                       inWriter.write("</time>\n");
                }
                // photo, audio
                if (inPoint.getPhoto() != null && inExportPhoto) {
@@ -816,7 +767,7 @@ public class GpxExporter extends GenericFunction implements Runnable
                if (inPoint.getAudio() != null && inExportAudio) {
                        inWriter.write(makeMediaLink(inPoint.getAudio()));
                }
-               inWriter.write("</trkpt>\n");
+               inWriter.write("\t\t\t</trkpt>\n");
        }
 
 
@@ -867,6 +818,6 @@ public class GpxExporter extends GenericFunction implements Runnable
         */
        private static String stripTime(String inPointSource)
        {
-               return inPointSource.replaceAll("<time>.*?</time>", "");
+               return inPointSource.replaceAll("[ \t]*<time>.*?</time>", "");
        }
 }
index 1f29d4a70bb075420db66a471ca7a9d7e730c28d..19e4485c66bf0e09ec576793804bdf88c4187591 100644 (file)
@@ -43,6 +43,8 @@ import tim.prune.gui.map.MapSource;
 import tim.prune.gui.map.MapSourceLibrary;
 import tim.prune.load.GenericFileFilter;
 import tim.prune.threedee.ImageDefinition;
+import tim.prune.threedee.TerrainCache;
+import tim.prune.threedee.TerrainDefinition;
 import tim.prune.threedee.TerrainHelper;
 import tim.prune.threedee.ThreeDModel;
 
@@ -392,19 +394,29 @@ public class PovExporter extends Export3dFunction
                        if (useTerrain)
                        {
                                TerrainHelper terrainHelper = new TerrainHelper(_terrainPanel.getGridSize());
-                               Track terrainTrack = terrainHelper.createGridTrack(_track);
-                               // Get the altitudes from SRTM for all the points in the track
-                               LookupSrtmFunction srtmLookup = (LookupSrtmFunction) FunctionLibrary.FUNCTION_LOOKUP_SRTM;
-                               srtmLookup.begin(terrainTrack);
-                               while (srtmLookup.isRunning())
+                               // See if there's a previously saved terrain track we can reuse
+                               TerrainDefinition terrainDef = new TerrainDefinition(_terrainPanel.getUseTerrain(), _terrainPanel.getGridSize());
+                               Track terrainTrack = TerrainCache.getTerrainTrack(_app.getCurrentDataStatus(), terrainDef);
+                               if (terrainTrack == null)
                                {
-                                       try {
-                                               Thread.sleep(750);  // just polling in a wait loop isn't ideal but simple
+                                       // Construct the terrain track according to these extents and the grid size
+                                       terrainTrack = terrainHelper.createGridTrack(_track);
+                                       // Get the altitudes from SRTM for all the points in the track
+                                       LookupSrtmFunction srtmLookup = (LookupSrtmFunction) FunctionLibrary.FUNCTION_LOOKUP_SRTM;
+                                       srtmLookup.begin(terrainTrack);
+                                       while (srtmLookup.isRunning())
+                                       {
+                                               try {
+                                                       Thread.sleep(750);  // just polling in a wait loop isn't ideal but simple
+                                               }
+                                               catch (InterruptedException e) {}
                                        }
-                                       catch (InterruptedException e) {}
+                                       // Fix the voids
+                                       terrainHelper.fixVoids(terrainTrack);
+
+                                       // Store this back in the cache, maybe we'll need it again
+                                       TerrainCache.storeTerrainTrack(terrainTrack, _app.getCurrentDataStatus(), terrainDef);
                                }
-                               // Fix the voids
-                               terrainHelper.fixVoids(terrainTrack);
 
                                model.setTerrain(terrainTrack);
                                model.scale();
diff --git a/tim/prune/save/xml/ByteBuffer.java b/tim/prune/save/xml/ByteBuffer.java
new file mode 100644 (file)
index 0000000..67091e1
--- /dev/null
@@ -0,0 +1,88 @@
+package tim.prune.save.xml;
+
+import java.nio.charset.Charset;
+
+/**
+ * Class to collect the bytes from an input stream
+ * and turn them into a String
+ */
+public class ByteBuffer
+{
+       // Array of bytes
+       private byte[] _bytes = new byte[1024];
+       // Current position to append
+       private int _currPos = 0;
+       // Flag for recognising utf8 encoded streams
+       private boolean _streamUtf8 = false;
+       // Flag for whether system is utf8 or not
+       private final boolean _systemUtf8 = XmlUtils.isSystemUtf8();
+
+       /**
+        * Append the given byte to the buffer
+        * @param inB byte to append
+        */
+       public void appendByte(byte inB)
+       {
+               // Resize array if necessary
+               if (_currPos >= _bytes.length)
+               {
+                       byte[] bigger = new byte[_bytes.length * 2];
+                       System.arraycopy(_bytes, 0, bigger, 0, _bytes.length);
+                       _bytes = bigger;
+               }
+               // Append byte and increment counter
+               _bytes[_currPos] = inB;
+               _currPos++;
+       }
+
+       /**
+        * Clear the buffer and reset
+        */
+       public void clear()
+       {
+               _currPos = 0;
+               // Reduce size back to default if it's got too big
+               if (_bytes.length > 5000) {
+                       _bytes = new byte[1024];
+               }
+       }
+
+       /**
+        * Set the flag that this stream is encoded with utf8
+        */
+       public void setEncodingUtf8() {
+               _streamUtf8 = true;
+       }
+
+       /**
+        * @return contents of buffer as a String
+        */
+       public String toString()
+       {
+               // Sometimes the encoding of the read file isn't the default encoding of the system
+               if (_streamUtf8 && !_systemUtf8)
+               {
+                       return new String(_bytes, 0, _currPos, Charset.forName("UTF-8"));
+               }
+               // Otherwise just use system encoding
+               return new String(_bytes, 0, _currPos);
+       }
+
+       /**
+        * Look for the given character sequence in the last characters read
+        * @param inChars sequence to look for
+        * @return true if sequence found
+        */
+       public boolean foundSequence(char[] inChars)
+       {
+               final int numChars = inChars.length;
+               if (_currPos < numChars) {return false;}
+               for (int i=0; i<numChars; i++)
+               {
+                       char searchChar = inChars[numChars - 1 - i];
+                       char sourceChar = (char) _bytes[_currPos - 1 - i];
+                       if (searchChar != sourceChar) {return false;}
+               }
+               return true;
+       }
+}
index 2c3204dab3fbee01e698c669d905a12b93e737ff..9ab8552e771cef536d8e942c17948f6d98fe3e65 100644 (file)
@@ -72,9 +72,19 @@ public class GpxCacher implements TagReceiver
                if (_headerString == null) {
                        _headerString = inTag;
                }
-               else {
-                       _strings[_pointNum] = inTag;
-                       _pointNum++;
+               else if (_strings != null)
+               {
+                       if (_pointNum < _strings.length)
+                       {
+                               _strings[_pointNum] = inTag;
+                               _pointNum++;
+                       }
+                       else
+                       {
+                               // _pointNum has got too high for the strings array
+                               // This means the cacher has failed, probably by invalid points - need to give up caching here
+                               _strings = null;
+                       }
                }
        }
 
@@ -95,7 +105,7 @@ public class GpxCacher implements TagReceiver
        public String getSourceString(DataPoint inPoint)
        {
                int index = _sourceInfo.getIndex(inPoint);
-               if (index >= 0) {
+               if (_strings != null && index >= 0 && index < _strings.length) {
                        return _strings[index];
                }
                return null;
index efc58b488666a7ee089dee174bc8f22668ff9dee..d18d7607656533d6aacbae5c599daa17df6076fe 100644 (file)
@@ -12,8 +12,6 @@ public class GpxSlicer
 {
        /** listener to receive tags */
        private TagReceiver _receiver = null;
-       /** string builder for copying source xml */
-       private StringBuilder _builder = null;
 
        // character sequences for start and end of tags
        private static final char[] GPX_START = "<gpx".toCharArray();
@@ -27,7 +25,6 @@ public class GpxSlicer
        private static final char[] CDATA_START = "<![CDATA[".toCharArray();
        private static final char[] CDATA_END = "]]>".toCharArray();
 
-
        /**
         * Constructor
         * @param inReceiver listener for tags
@@ -43,7 +40,8 @@ public class GpxSlicer
         */
        public void slice(InputStream inStream)
        {
-               _builder = new StringBuilder(100);
+               StringBuffer beginBuffer = new StringBuffer(200);
+               ByteBuffer byteBuffer = new ByteBuffer();
                boolean insideTag = false;
                boolean insideCdata = false;
                char[] endTag = null;
@@ -53,37 +51,49 @@ public class GpxSlicer
                {
                        while ((b = inStream.read()) >= 0)
                        {
-                               if (!insideTag && !insideCdata) {
-                                       if (b == '<') _builder.setLength(0);
-                               }
                                // copy character
-                               _builder.append((char)b);
+                               byteBuffer.appendByte((byte) b);
+                               // clear buffer if necessary
+                               if (!insideTag && !insideCdata && (b == '>' || b == '\n'))
+                               {
+                                       byteBuffer.clear();
+                                       continue;
+                               }
+                               // if we're still at the beginning, copy to the begin buffer as well
+                               if (beginBuffer != null) {beginBuffer.append((char) b);}
 
                                if (insideCdata) {
                                        // Just look for end of cdata block
-                                       if (foundSequence(CDATA_END)) {insideCdata = false;}
+                                       if (byteBuffer.foundSequence(CDATA_END)) {insideCdata = false;}
                                }
                                else
                                {
                                        if (!insideTag)
                                        {
                                                // Look for start of one of the tags
-                                               if (!foundHeader && foundSequence(GPX_START)) {
+                                               if (!foundHeader && byteBuffer.foundSequence(GPX_START))
+                                               {
                                                        insideTag = true;
                                                        foundHeader = true;
                                                        endTag = GPX_END;
+                                                       // Check begin buffer for utf8 encoding
+                                                       if (beginBuffer != null && beginBuffer.toString().toLowerCase().indexOf("encoding=\"utf-8\"") > 0)
+                                                       {
+                                                               byteBuffer.setEncodingUtf8();
+                                                       }
+                                                       beginBuffer = null; // don't need it any more
                                                }
                                                else if (b == 't')
                                                {
-                                                       if (foundSequence(TRKPT_START)) {
+                                                       if (byteBuffer.foundSequence(TRKPT_START)) {
                                                                insideTag = true;
                                                                endTag = TRKPT_END;
                                                        }
-                                                       else if (foundSequence(WPT_START)) {
+                                                       else if (byteBuffer.foundSequence(WPT_START)) {
                                                                insideTag = true;
                                                                endTag = WPT_END;
                                                        }
-                                                       else if (foundSequence(RTEPT_START)) {
+                                                       else if (byteBuffer.foundSequence(RTEPT_START)) {
                                                                insideTag = true;
                                                                endTag = RTEPT_END;
                                                        }
@@ -92,37 +102,21 @@ public class GpxSlicer
                                        else
                                        {
                                                // Look for end of found tag
-                                               if (foundSequence(endTag)) {
-                                                       _receiver.reportTag(_builder.toString());
-                                                       _builder.setLength(0);
+                                               if (byteBuffer.foundSequence(endTag))
+                                               {
+                                                       String tag = byteBuffer.toString();
+                                                       _receiver.reportTag(tag);
+                                                       byteBuffer.clear();
                                                        insideTag = false;
                                                }
                                        }
                                        // Look for start of cdata block
-                                       if (foundSequence(CDATA_START)) {insideCdata = true;}
+                                       if (byteBuffer.foundSequence(CDATA_START)) {
+                                               insideCdata = true;
+                                       }
                                }
                        }
                }
                catch (IOException e) {} // ignore
        }
-
-       /**
-        * Look for the given character sequence in the last characters read
-        * @param inChars sequence to look for
-        * @return true if sequence found
-        */
-       private boolean foundSequence(char[] inChars)
-       {
-               final int numChars = inChars.length;
-               final int bufflen = _builder.length();
-               if (bufflen < numChars) {return false;}
-               for (int i=0; i<numChars; i++)
-               {
-                       char searchChar = inChars[numChars - 1 - i];
-                       char sourceChar = _builder.charAt(bufflen - 1 - i);
-                       if (searchChar != sourceChar) {return false;}
-                       //if (Character.toLowerCase(searchChar) != Character.toLowerCase(sourceChar)) {return false;}
-               }
-               return true;
-       }
 }
index a4f9caec11704a46dcd56fe3d22bde4922a49f09..dc8284c30ea90d4586b0cdec70c72c6102346225 100644 (file)
@@ -1,5 +1,11 @@
 package tim.prune.save.xml;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+
 /**
  * Collection of utility functions for handling XML
  */
@@ -9,6 +15,8 @@ public abstract class XmlUtils
        private static final String CDATA_START = "<![CDATA[";
        /** End of Cdata sequence */
        private static final String CDATA_END = "]]>";
+       /** Cached copy of system encoding string */
+       private static String _systemEncoding = null;
 
        /**
         * Fix the CDATA blocks in the given String to give valid xml
@@ -34,4 +42,68 @@ public abstract class XmlUtils
                }
                return CDATA_START + result + CDATA_END;
        }
+
+
+       /**
+        * @return true if system uses UTF-8 by default
+        */
+       public static boolean isSystemUtf8()
+       {
+               String systemEncoding = getSystemEncoding();
+               return (systemEncoding != null && systemEncoding.toUpperCase().equals("UTF-8"));
+       }
+
+       /**
+        * @return name of the system's character encoding
+        */
+       public static String getSystemEncoding()
+       {
+               if (_systemEncoding == null) {
+                       _systemEncoding = determineSystemEncoding();
+               }
+               return _systemEncoding;
+       }
+
+       /**
+        * 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 determineSystemEncoding()
+       {
+               File tempFile = null;
+               String encoding = null;
+               try
+               {
+                       tempFile = File.createTempFile("gpsprune", 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;
+       }
+
+
+       /**
+        * Get the default system encoding using a writer
+        * @param inWriter writer object
+        * @return string defining encoding
+        */
+       public static String getEncoding(OutputStreamWriter inWriter)
+       {
+               String encoding = inWriter.getEncoding();
+               try {
+                       encoding =  Charset.forName(encoding).name();
+               }
+               catch (Exception e) {} // ignore failure to find encoding
+               return encoding;
+       }
 }
index ba1ed1530c282e5607d24816bc391f72d68d48c7..fdda0fcc4f53de305e4177866ea8132c09249a97 100644 (file)
@@ -27,9 +27,9 @@ import javax.media.j3d.QuadArray;
 import javax.media.j3d.Shape3D;
 import javax.media.j3d.Text3D;
 import javax.media.j3d.Texture;
+import javax.media.j3d.TextureAttributes;
 import javax.media.j3d.Transform3D;
 import javax.media.j3d.TransformGroup;
-import javax.media.j3d.TriangleStripArray;
 import javax.swing.JButton;
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
@@ -41,6 +41,7 @@ import javax.vecmath.Point3f;
 import javax.vecmath.TexCoord2f;
 import javax.vecmath.Vector3d;
 
+import tim.prune.DataStatus;
 import tim.prune.FunctionLibrary;
 import tim.prune.I18nManager;
 import tim.prune.data.Track;
@@ -53,6 +54,8 @@ import tim.prune.save.MapGrouter;
 import com.sun.j3d.utils.behaviors.vp.OrbitBehavior;
 import com.sun.j3d.utils.geometry.Box;
 import com.sun.j3d.utils.geometry.Cylinder;
+import com.sun.j3d.utils.geometry.GeometryInfo;
+import com.sun.j3d.utils.geometry.NormalGenerator;
 import com.sun.j3d.utils.geometry.Sphere;
 import com.sun.j3d.utils.image.TextureLoader;
 import com.sun.j3d.utils.universe.SimpleUniverse;
@@ -72,6 +75,7 @@ public class Java3DWindow implements ThreeDWindow
        private ImageDefinition _imageDefinition = null;
        private GroutedImage _baseImage = null;
        private TerrainDefinition _terrainDefinition = null;
+       private DataStatus _dataStatus = null;
 
        /** only prompt about big track size once */
        private static boolean TRACK_SIZE_WARNING_GIVEN = false;
@@ -134,6 +138,14 @@ public class Java3DWindow implements ThreeDWindow
                _terrainDefinition = inDefinition;
        }
 
+       /**
+        * Set the current data status
+        */
+       public void setDataStatus(DataStatus inStatus)
+       {
+               _dataStatus = inStatus;
+       }
+
        /**
         * Show the window
         */
@@ -331,24 +343,31 @@ public class Java3DWindow implements ThreeDWindow
 
                if (showTerrain)
                {
-                       // TODO: Is it maybe possible to cache the last terrainTrack?
-                       //       (if the dataTrack and the resolution haven't changed)
-                       // Construct the terrain track according to these extents and the grid size
                        TerrainHelper terrainHelper = new TerrainHelper(_terrainDefinition.getGridSize());
-                       Track terrainTrack = terrainHelper.createGridTrack(_track);
-                       // Get the altitudes from SRTM for all the points in the track
-                       LookupSrtmFunction srtmLookup = (LookupSrtmFunction) FunctionLibrary.FUNCTION_LOOKUP_SRTM;
-                       srtmLookup.begin(terrainTrack);
-                       while (srtmLookup.isRunning())
+                       // See if there's a previously saved terrain track we can reuse
+                       Track terrainTrack = TerrainCache.getTerrainTrack(_dataStatus, _terrainDefinition);
+                       if (terrainTrack == null)
                        {
-                               try {
-                                       Thread.sleep(750);  // just polling in a wait loop isn't ideal but simple
+                               // Construct the terrain track according to these extents and the grid size
+                               terrainTrack = terrainHelper.createGridTrack(_track);
+                               // Get the altitudes from SRTM for all the points in the track
+                               LookupSrtmFunction srtmLookup = (LookupSrtmFunction) FunctionLibrary.FUNCTION_LOOKUP_SRTM;
+                               srtmLookup.begin(terrainTrack);
+                               while (srtmLookup.isRunning())
+                               {
+                                       try {
+                                               Thread.sleep(750);  // just polling in a wait loop isn't ideal but simple
+                                       }
+                                       catch (InterruptedException e) {}
                                }
-                               catch (InterruptedException e) {}
-                       }
 
-                       // Fix the voids
-                       terrainHelper.fixVoids(terrainTrack);
+                               // Fix the voids
+                               terrainHelper.fixVoids(terrainTrack);
+
+                               // Store this back in the cache, maybe we'll need it again
+                               TerrainCache.storeTerrainTrack(terrainTrack, _dataStatus, _terrainDefinition);
+                       }
+                       // else System.out.println("Yay - reusing the cached track!");
 
                        // Give the terrain definition to the _model as well
                        _model.setTerrain(terrainTrack);
@@ -575,11 +594,8 @@ public class Java3DWindow implements ThreeDWindow
        {
                final int numNodes = inHelper.getGridSize();
                final int RESULT_SIZE = numNodes * (numNodes * 2 - 2);
-               final int GEOMETRY_COLOURING_TYPE = (inBaseImage == null ? GeometryArray.COLOR_3 : GeometryArray.TEXTURE_COORDINATE_2);
-
                int[] stripData = inHelper.getStripLengths();
-               TriangleStripArray tsa = new TriangleStripArray(RESULT_SIZE, GeometryArray.COORDINATES | GEOMETRY_COLOURING_TYPE,
-                       stripData);
+
                // Get the scaled terrainTrack coordinates (or just heights) from the model
                final int nSquared = numNodes * numNodes;
                Point3d[] rawPoints = new Point3d[nSquared];
@@ -590,23 +606,37 @@ public class Java3DWindow implements ThreeDWindow
                                Math.max(height, 0.05), // make sure it's above the box
                                -inModel.getScaledTerrainVertValue(i) * MODEL_SCALE_FACTOR);
                }
-               tsa.setCoordinates(0, inHelper.getTerrainCoordinates(rawPoints));
+
+               GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_STRIP_ARRAY);
+               gi.setCoordinates(inHelper.getTerrainCoordinates(rawPoints));
+               gi.setStripCounts(stripData);
 
                Appearance tAppearance = new Appearance();
                if (inBaseImage != null)
                {
-                       tsa.setTextureCoordinates(0, 0, inHelper.getTextureCoordinates());
+                       gi.setTextureCoordinateParams(1,  2); // one coord set of two dimensions
+                       gi.setTextureCoordinates(0, inHelper.getTextureCoordinates());
                        Texture mapImage = new TextureLoader(inBaseImage.getImage()).getTexture();
                        tAppearance.setTexture(mapImage);
+                       TextureAttributes texAttr = new TextureAttributes();
+                       texAttr.setTextureMode(TextureAttributes.MODULATE);
+                       tAppearance.setTextureAttributes(texAttr);
                }
                else
                {
                        Color3f[] colours = new Color3f[RESULT_SIZE];
                        Color3f terrainColour = new Color3f(0.1f, 0.2f, 0.2f);
                        for (int i=0; i<RESULT_SIZE; i++) {colours[i] = terrainColour;}
-                       tsa.setColors(0, colours);
+                       gi.setColors(colours);
                }
-               return new Shape3D(tsa, tAppearance);
+               new NormalGenerator().generateNormals(gi);
+               Material terrnMat = new Material(new Color3f(0.4f, 0.4f, 0.4f), // ambient colour
+                       new Color3f(0f, 0f, 0f), // emissive (none)
+                       new Color3f(0.8f, 0.8f, 0.8f), // diffuse
+                       new Color3f(0.2f, 0.2f, 0.2f), //specular
+                       30f); // shinyness
+               tAppearance.setMaterial(terrnMat);
+               return new Shape3D(gi.getGeometryArray(), tAppearance);
        }
 
        /**
diff --git a/tim/prune/threedee/TerrainCache.java b/tim/prune/threedee/TerrainCache.java
new file mode 100644 (file)
index 0000000..5f5733f
--- /dev/null
@@ -0,0 +1,57 @@
+package tim.prune.threedee;
+
+import tim.prune.DataStatus;
+import tim.prune.data.Track;
+
+/**
+ * This abstract class acts as a singleton to store a single
+ * terrain model (as a Track) for a given data status and terrain definition.
+ * When the data or the definition changes, this track becomes invalid.
+ */
+public abstract class TerrainCache
+{
+       /** The data status at the time this terrain was generated */
+       private static DataStatus _dataStatus = null;
+       /** The definition (grid size) for this terrain */
+       private static TerrainDefinition _terrainDef = null;
+       /** The generated grid of points with altitudes */
+       private static Track _terrainTrack = null;
+
+
+       /**
+        * Get the stored terrain track if it's still valid
+        * @param inCurrStatus current data status
+        * @param inTerrainDef currently selected terrain definition
+        * @return stored terrain track if it's valid, null otherwise
+        */
+       public static Track getTerrainTrack(DataStatus inCurrStatus, TerrainDefinition inTerrainDef)
+       {
+               if (_dataStatus == null || _terrainDef == null || _terrainTrack == null)
+               {
+                       return null; // nothing stored
+               }
+               if (inCurrStatus == null || inTerrainDef == null || !inTerrainDef.getUseTerrain())
+               {
+                       return null; // nonsense requested
+               }
+               if (inCurrStatus.hasDataChanged(_dataStatus) || !inTerrainDef.equals(_terrainDef))
+               {
+                       return null; // stored track is out of date
+               }
+               // we have a match
+               return _terrainTrack;
+       }
+
+       /**
+        * Now that a terrain track has been generated, store it for possible reuse
+        * @param inTrack terrain track to store
+        * @param inCurrStatus current data status
+        * @param inTerrainDef terrain definition
+        */
+       public static void storeTerrainTrack(Track inTrack, DataStatus inCurrStatus, TerrainDefinition inTerrainDef)
+       {
+               _terrainTrack = inTrack;
+               _dataStatus = inCurrStatus;
+               _terrainDef = inTerrainDef;
+       }
+}
index 0b35670aaa61d55042b1e20e20dac200fdf481d0..d6cf3854f9525dc2fbf1c6754ad3dfa20ea488c1 100644 (file)
@@ -51,4 +51,18 @@ public class TerrainDefinition
        public int getGridSize() {
                return _gridSize;
        }
+
+       @Override
+       /**
+        * Compare two TerrainDefinitions to see if they're equal
+        */
+       public boolean equals(Object obj)
+       {
+               if (obj == null || !(obj instanceof TerrainDefinition)) {
+                       return false;
+               }
+               TerrainDefinition other = (TerrainDefinition) obj;
+               return _useTerrain == other._useTerrain
+                       && _gridSize == other._gridSize;
+       }
 }
index 71bc196a46dce7c8c4658dfb23490ab8f23fc323..0be2216cdf592384e95feb5c5ac34add99453b69 100644 (file)
@@ -196,12 +196,13 @@ public class TerrainHelper
        {
                int numVoids = countVoids(inTerrainTrack);
                if (numVoids == 0) {return;}
-               // System.out.println("Starting to fix, num voids = " + numVoids);
+               //System.out.println("Starting to fix, num voids = " + numVoids);
                // Fix the holes which are surrounded on all four sides by non-holes
                fixSingleHoles(inTerrainTrack);
-               // System.out.println("Fixed single holes, now num voids = " + countVoids(inTerrainTrack));
+               //System.out.println("Fixed single holes, now num voids = " + countVoids(inTerrainTrack));
                // Maybe there is something to do in the corners?
-               fixCorners(inTerrainTrack);
+               fixCornersAndEdges(inTerrainTrack);
+               //System.out.println("Fixed corners, now num voids = " + countVoids(inTerrainTrack));
                // Now fix the bigger holes, which should fix everything left
                fixBiggerHoles(inTerrainTrack);
                final int numHolesLeft = countVoids(inTerrainTrack);
@@ -216,6 +217,21 @@ public class TerrainHelper
         */
        private static int countVoids(Track inTerrainTrack)
        {
+               // DEBUG: Show state of voids first
+//             final int gridSize = (int) Math.sqrt(inTerrainTrack.getNumPoints());
+//             StringBuilder sb = new StringBuilder();
+//             for (int i=0; i<inTerrainTrack.getNumPoints(); i++)
+//             {
+//                     if ((i%gridSize) == 0) sb.append('\n');
+//                     if (inTerrainTrack.getPoint(i).hasAltitude()) {
+//                             sb.append('A');
+//                     } else {
+//                             sb.append(' ');
+//                     }
+//             }
+//             System.out.println("Voids:" + sb.toString());
+               // END DEBUG
+
                int numVoids = 0;
                if (inTerrainTrack != null)
                {
@@ -271,7 +287,7 @@ public class TerrainHelper
 
                                                double altitude = 0.0;
                                                if (pll != null && pll.hasAltitude() && prr != null && prr.hasAltitude()
-                                                       && puu != null && puu.hasAltitude() && pdd != null & pdd.hasAltitude())
+                                                       && puu != null && puu.hasAltitude() && pdd != null && pdd.hasAltitude())
                                                {
                                                        // Use the double-neighbours too to take into account the gradients
                                                        altitude = (
@@ -304,15 +320,19 @@ public class TerrainHelper
        }
 
        /**
-        * Try to fix the corners, if they're blank
+        * Try to fix the corners and edges, if they're blank
         * @param inTerrainTrack terrain track
         */
-       private void fixCorners(Track inTerrainTrack)
+       private void fixCornersAndEdges(Track inTerrainTrack)
        {
                fixCorner(inTerrainTrack, 0, 1, 1);
                fixCorner(inTerrainTrack, _gridSize-1, -1, 1);
                fixCorner(inTerrainTrack, (_gridSize-1)*_gridSize, 1, -1);
                fixCorner(inTerrainTrack, _gridSize*_gridSize-1, -1, -1);
+               fixEdge(inTerrainTrack, 0, 1);
+               fixEdge(inTerrainTrack, _gridSize-1, _gridSize);
+               fixEdge(inTerrainTrack, (_gridSize-1)*_gridSize, -_gridSize);
+               fixEdge(inTerrainTrack, _gridSize*_gridSize-1, -1);
        }
 
        /**
@@ -355,6 +375,40 @@ public class TerrainHelper
                }
        }
 
+       /**
+        * Fix any holes found in the specified edge
+        * @param inTerrainTrack terrain track
+        * @param inCornerIndex index of corner to start from
+        * @param inInc increment along edge
+        */
+       private void fixEdge(Track inTerrainTrack, int inCornerIndex, int inInc)
+       {
+               int prevIndexWithAlt = -1;
+               int sIndex = inCornerIndex;
+               if (inTerrainTrack.getPoint(sIndex).hasAltitude()) {prevIndexWithAlt = 0;}
+               for (int i=1; i<_gridSize; i++)
+               {
+                       sIndex += inInc;
+                       if (inTerrainTrack.getPoint(sIndex).hasAltitude())
+                       {
+                               if (prevIndexWithAlt >= 0 && prevIndexWithAlt < (i-1))
+                               {
+                                       final int gapLen = i - prevIndexWithAlt;
+                                       final double alt1 = inTerrainTrack.getPoint(prevIndexWithAlt).getAltitude().getMetricValue();
+                                       final double alt2 = inTerrainTrack.getPoint(i).getAltitude().getMetricValue();
+                                       for (int j = 1; j < gapLen; j++)
+                                       {
+                                               // System.out.println("Fill in " + (prevIndexWithAlt + j) + " using " + prevIndexWithAlt + " and " + i);
+                                               final double alt = alt1 + (alt2-alt1) * j / gapLen;
+                                               final DataPoint p = inTerrainTrack.getPoint(inCornerIndex + (prevIndexWithAlt + j) * inInc);
+                                               p.setFieldValue(Field.ALTITUDE, "" + (int) alt, false);
+                                       }
+                               }
+                               prevIndexWithAlt = i;
+                       }
+               }
+       }
+
        /**
         * Try to fix bigger holes by interpolating between neighbours
         * @param inTerrainTrack terrain track
index b7c73d29cf5a6c2fd85d9627531912ea18029025..f4b3ed34d4b195f1c7a02a0d3b0476825e27b3a1 100644 (file)
@@ -1,5 +1,6 @@
 package tim.prune.threedee;
 
+import tim.prune.DataStatus;
 import tim.prune.data.Track;
 
 /**
@@ -29,6 +30,11 @@ public interface ThreeDWindow
         */
        public void setTerrainParameters(TerrainDefinition inDefinition);
 
+       /**
+        * @param inStatus current data status for caching
+        */
+       public void setDataStatus(DataStatus inStatus);
+
        /**
         * Show the window
         * @throws ThreeDException when 3d classes not found
diff --git a/tim/prune/undo/UndoStack.java b/tim/prune/undo/UndoStack.java
new file mode 100644 (file)
index 0000000..bca92b1
--- /dev/null
@@ -0,0 +1,24 @@
+package tim.prune.undo;
+
+import java.util.Stack;
+
+/**
+ * Stack of undo operations
+ * which also remembers how many times it's been cleared
+ */
+public class UndoStack extends Stack<UndoOperation>
+{
+       private int _numTimesDeleted = 0;
+
+       /** @return number of times this stack has been deleted */
+       public int getNumTimesDeleted() {
+               return _numTimesDeleted;
+       }
+
+       @Override
+       public void clear()
+       {
+               _numTimesDeleted++;
+               super.clear();
+       }
+}