]> gitweb.fperrin.net Git - GpsPrune.git/commitdiff
Version 2, March 2007
authoractivityworkshop <mail@activityworkshop.net>
Sat, 14 Feb 2015 13:38:26 +0000 (14:38 +0100)
committeractivityworkshop <mail@activityworkshop.net>
Sat, 14 Feb 2015 13:38:26 +0000 (14:38 +0100)
29 files changed:
tim/prune/App.java
tim/prune/DataSubscriber.java
tim/prune/GpsPruner.java
tim/prune/UpdateMessageBroker.java
tim/prune/data/Altitude.java
tim/prune/data/AltitudeRange.java
tim/prune/data/Coordinate.java
tim/prune/data/DataPoint.java
tim/prune/data/Distance.java
tim/prune/data/DoubleRange.java
tim/prune/data/FieldList.java
tim/prune/data/IntegerRange.java
tim/prune/data/Latitude.java
tim/prune/data/Longitude.java
tim/prune/data/Selection.java
tim/prune/data/Track.java
tim/prune/data/TrackInfo.java
tim/prune/gui/AboutScreen.java
tim/prune/gui/DetailsDisplay.java
tim/prune/gui/GenericChart.java
tim/prune/gui/MapChart.java
tim/prune/gui/MenuManager.java
tim/prune/lang/prune-texts.properties
tim/prune/lang/prune-texts_de.properties
tim/prune/lang/prune-texts_de_CH.properties
tim/prune/readme.txt
tim/prune/save/FileSaver.java
tim/prune/save/KmlExporter.java
tim/prune/undo/UndoDeletePoint.java

index a1e6a8b8756d2801bdd320fbf14c86a15a3f7b00..4ccaed688e40dcfd1aef3b1d7e464fad4b1b26ee 100644 (file)
@@ -1,6 +1,7 @@
 package tim.prune;
 
 import java.util.EmptyStackException;
+import java.util.List;
 import java.util.Stack;
 
 import javax.swing.JFrame;
@@ -10,18 +11,28 @@ import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
 import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
+import tim.prune.edit.FieldEditList;
+import tim.prune.edit.PointEditor;
+import tim.prune.edit.PointNameEditor;
 import tim.prune.gui.MenuManager;
 import tim.prune.gui.UndoManager;
 import tim.prune.load.FileLoader;
+import tim.prune.load.JpegLoader;
 import tim.prune.save.FileSaver;
 import tim.prune.save.KmlExporter;
+import tim.prune.save.PovExporter;
+import tim.prune.threedee.ThreeDException;
+import tim.prune.threedee.ThreeDWindow;
+import tim.prune.threedee.WindowFactory;
 import tim.prune.undo.UndoCompress;
 import tim.prune.undo.UndoDeleteDuplicates;
 import tim.prune.undo.UndoDeletePoint;
 import tim.prune.undo.UndoDeleteRange;
+import tim.prune.undo.UndoEditPoint;
 import tim.prune.undo.UndoException;
 import tim.prune.undo.UndoInsert;
 import tim.prune.undo.UndoLoad;
+import tim.prune.undo.UndoLoadPhotos;
 import tim.prune.undo.UndoOperation;
 import tim.prune.undo.UndoRearrangeWaypoints;
 import tim.prune.undo.UndoReverseSection;
@@ -39,6 +50,8 @@ public class App
        private int _lastSavePosition = 0;
        private MenuManager _menuManager = null;
        private FileLoader _fileLoader = null;
+       private JpegLoader _jpegLoader = null;
+       private PovExporter _povExporter = null;
        private Stack _undoStack = null;
        private UpdateMessageBroker _broker = null;
        private boolean _reversePointsConfirmed = false;
@@ -49,8 +62,6 @@ public class App
        public static final int REARRANGE_TO_NEAREST = 2;
 
 
-       // TODO: Make waypoint window to allow list of waypoints, edit names etc
-
        /**
         * Constructor
         * @param inFrame frame object for application
@@ -112,6 +123,17 @@ public class App
        }
 
 
+       /**
+        * Add a photo or a directory of photos which are already correlated
+        */
+       public void addPhotos()
+       {
+               if (_jpegLoader == null)
+                       _jpegLoader = new JpegLoader(this, _frame);
+               _jpegLoader.openFile();
+       }
+
+
        /**
         * Save the file in the selected format
         */
@@ -148,6 +170,60 @@ public class App
        }
 
 
+       /**
+        * Export track data as Pov without specifying settings
+        */
+       public void exportPov()
+       {
+               exportPov(false, 0.0, 0.0, 0.0, 0);
+       }
+
+       /**
+        * Export track data as Pov and also specify settings
+        * @param inX X component of unit vector
+        * @param inY Y component of unit vector
+        * @param inZ Z component of unit vector
+        * @param inAltitudeCap altitude cap
+        */
+       public void exportPov(double inX, double inY, double inZ, int inAltitudeCap)
+       {
+               exportPov(true, inX, inY, inZ, inAltitudeCap);
+       }
+
+       /**
+        * Export track data as Pov with optional angle specification
+        * @param inDefineAngles true to define angles, false to ignore
+        * @param inX X component of unit vector
+        * @param inY Y component of unit vector
+        * @param inZ Z component of unit vector
+        */
+       private void exportPov(boolean inDefineSettings, double inX, double inY, double inZ, int inAltitudeCap)
+       {
+               // Check track has data to export
+               if (_track == null || _track.getNumPoints() <= 0)
+               {
+                       JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.save.nodata"),
+                               I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
+               }
+               else
+               {
+                       // Make new exporter if necessary
+                       if (_povExporter == null)
+                       {
+                               _povExporter = new PovExporter(this, _frame, _track);
+                       }
+                       // Specify angles if necessary
+                       if (inDefineSettings)
+                       {
+                               _povExporter.setCameraCoordinates(inX, inY, inZ);
+                               _povExporter.setAltitudeCap(inAltitudeCap);
+                       }
+                       // Initiate export
+                       _povExporter.showDialog();
+               }
+       }
+
+
        /**
         * Exit the application if confirmed
         */
@@ -166,6 +242,62 @@ public class App
        }
 
 
+       /**
+        * Edit the currently selected point
+        */
+       public void editCurrentPoint()
+       {
+               if (_track != null)
+               {
+                       DataPoint currentPoint = _trackInfo.getCurrentPoint();
+                       if (currentPoint != null)
+                       {
+                               // Open point dialog to display details
+                               PointEditor editor = new PointEditor(this, _frame);
+                               editor.showDialog(_track, currentPoint);
+                       }
+               }
+       }
+
+
+       /**
+        * Complete the point edit
+        * @param inEditList list of edits
+        */
+       public void completePointEdit(FieldEditList inEditList, FieldEditList inUndoList)
+       {
+               DataPoint currentPoint = _trackInfo.getCurrentPoint();
+               if (inEditList != null && inEditList.getNumEdits() > 0 && currentPoint != null)
+               {
+                       // add information to undo stack
+                       UndoOperation undo = new UndoEditPoint(currentPoint, inUndoList);
+                       // pass to track for completion
+                       if (_track.editPoint(currentPoint, inEditList))
+                       {
+                               _undoStack.push(undo);
+                       }
+               }
+       }
+
+
+       /**
+        * Edit the name of the currently selected (way)point
+        */
+       public void editCurrentPointName()
+       {
+               if (_track != null)
+               {
+                       DataPoint currentPoint = _trackInfo.getCurrentPoint();
+                       if (currentPoint != null)
+                       {
+                               // Open point dialog to display details
+                               PointNameEditor editor = new PointNameEditor(this, _frame);
+                               editor.showDialog(_track, currentPoint);
+                       }
+               }
+       }
+
+
        /**
         * Delete the currently selected point
         */
@@ -359,9 +491,26 @@ public class App
         */
        public void show3dWindow()
        {
-               // TODO: open 3d view window
-               JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.function.notimplemented"),
-                       I18nManager.getText("error.function.notimplemented.title"), JOptionPane.WARNING_MESSAGE);
+               ThreeDWindow window = WindowFactory.getWindow(this, _frame);
+               if (window == null)
+               {
+                       JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.function.nojava3d"),
+                               I18nManager.getText("error.function.notavailable.title"), JOptionPane.WARNING_MESSAGE);
+               }
+               else
+               {
+                       try
+                       {
+                               // Pass the track object and show the window
+                               window.setTrack(_track);
+                               window.show();
+                       }
+                       catch (ThreeDException e)
+                       {
+                               JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.3d") + ": " + e.getMessage(),
+                                       I18nManager.getText("error.3d.title"), JOptionPane.ERROR_MESSAGE);
+                       }
+               }
        }
 
 
@@ -428,6 +577,40 @@ public class App
        }
 
 
+       /**
+        * Accept a list of loaded photos
+        * @param inPhotoList List of Photo objects
+        */
+       public void informPhotosLoaded(List inPhotoList)
+       {
+               if (inPhotoList != null && !inPhotoList.isEmpty())
+               {
+                       // TODO: Attempt to restrict loaded photos to current area (if any) ?
+                       int numAdded = _trackInfo.addPhotos(inPhotoList);
+                       if (numAdded > 0)
+                       {
+                               _undoStack.add(new UndoLoadPhotos(numAdded));
+                       }
+                       if (numAdded == 1)
+                       {
+                               JOptionPane.showMessageDialog(_frame,
+                                       "" + numAdded + " " + I18nManager.getText("dialog.jpegload.photoadded"),
+                                       I18nManager.getText("dialog.jpegload.title"), JOptionPane.INFORMATION_MESSAGE);
+                       }
+                       else
+                       {
+                               JOptionPane.showMessageDialog(_frame,
+                                       "" + numAdded + " " + I18nManager.getText("dialog.jpegload.photosadded"),
+                                       I18nManager.getText("dialog.jpegload.title"), JOptionPane.INFORMATION_MESSAGE);
+                       }
+                       // TODO: Improve message when photo(s) fail to load (eg already added)
+                       _broker.informSubscribers();
+                       // update menu
+                       _menuManager.informFileLoaded();
+               }
+       }
+
+
        /**
         * Inform the app that the data has been saved
         */
index ae6c3be8ee617825f1b7f38cf7fd07ea69ec9c77..766ed5399fda870f3a740e6e4e2bdd322c9a7aa6 100644 (file)
@@ -6,9 +6,17 @@ package tim.prune;
  */
 public interface DataSubscriber
 {
+       public static final byte DATA_ADDED_OR_REMOVED = 1;
+       public static final byte DATA_EDITED           = 2;
+       public static final byte SELECTION_CHANGED     = 4;
+       public static final byte WAYPOINTS_MODIFIED    = 8;
+       public static final byte PHOTOS_MODIFIED       = 16;
+       public static final byte UNITS_CHANGED         = 32;
+       public static final byte ALL                   = 63;
+
        /**
         * Inform clients that data has been updated
         */
-       public void dataUpdated();
+       public void dataUpdated(byte inUpdateType);
 
 }
index f76787c5730ef36fda0fb777b860fa42673ed00c..7e9476cf5b2b62c56604d83a91eb36a821765371 100644 (file)
@@ -18,8 +18,9 @@ import tim.prune.gui.ProfileChart;
  */
 public class GpsPruner
 {
-       public static final String VERSION_NUMBER = "1";
-       public static final String BUILD_NUMBER = "041";
+       // Version 2, released 29 March 2007, 1 April 2007
+       public static final String VERSION_NUMBER = "2";
+       public static final String BUILD_NUMBER = "056";
        private static App APP = null;
 
 
index f2dfd2aaeb2ca1a072a37ac21d36a32874d1bbdd..417d05547aa9b54e8bf3f7b09c0d11d2edae0f8d 100644 (file)
@@ -37,12 +37,22 @@ public class UpdateMessageBroker
         * the data has been updated
         */
        public void informSubscribers()
+       {
+               informSubscribers(DataSubscriber.ALL);
+       }
+
+
+       /**
+        * Send message to all subscribers
+        * @param inChange Change that occurred
+        */
+       public void informSubscribers(byte inChange)
        {
                for (int i=0; i<_subscribers.length; i++)
                {
                        if (_subscribers[i] != null)
                        {
-                               _subscribers[i].dataUpdated();
+                               _subscribers[i].dataUpdated(inChange);
                        }
                }
        }
index 73552ae62977528d97ca91784a9e3d1dec6cc5da..b55a429200c723e9f511a7a4b769e65befdcc622 100644 (file)
@@ -79,6 +79,7 @@ public class Altitude
         */
        public int getValue(int inFormat)
        {
+               // TODO: Fix rounding errors here converting between units - return double?
                if (inFormat == _format)
                        return _value;
                if (inFormat == FORMAT_METRES)
index 5b606f4574eac372d9fdd6850ff0a3d248307513..6c7e5d55a286c1c0715227cc4a1a7204a9a164d2 100644 (file)
@@ -10,6 +10,16 @@ public class AltitudeRange
        private int _format = Altitude.FORMAT_NONE;
 
 
+       /**
+        * Clear the altitude range
+        */
+       public void clear()
+       {
+               _range.clear();
+               _format = Altitude.FORMAT_NONE;
+       }
+
+
        /**
         * Add a value to the range
         * @param inValue value to add, only positive values considered
index e297a8d7036fdf7209f6ad15635d70b3c12f26bf..6d8de61197bec7ae945658662c1060c4dd0e7663 100644 (file)
@@ -128,8 +128,9 @@ public abstract class Coordinate
         * Constructor
         * @param inValue value of coordinate
         * @param inFormat format to use
+        * @param inCardinal cardinal
         */
-       protected Coordinate(double inValue, int inFormat)
+       protected Coordinate(double inValue, int inFormat, int inCardinal)
        {
                _asDouble = inValue;
                // Calculate degrees, minutes, seconds
@@ -140,10 +141,12 @@ public abstract class Coordinate
                _seconds = (int) numSecs;
                _fracs = (int) ((numSecs - _seconds) * 10);
                // Make a string to display on screen
+               _cardinal = inCardinal;
                _originalFormat = FORMAT_NONE;
                if (inFormat == FORMAT_NONE) inFormat = FORMAT_DEG_WITHOUT_CARDINAL;
                _originalString = output(inFormat);
                _originalFormat = inFormat;
+               _valid = true;
        }
 
 
@@ -193,7 +196,8 @@ public abstract class Coordinate
                        // format as specified
                        switch (inFormat)
                        {
-                               case FORMAT_DEG_MIN_SEC: {
+                               case FORMAT_DEG_MIN_SEC:
+                               {
                                        StringBuffer buffer = new StringBuffer();
                                        buffer.append(PRINTABLE_CARDINALS[_cardinal])
                                                .append(threeDigitString(_degrees)).append('°')
@@ -202,11 +206,17 @@ public abstract class Coordinate
                                                .append(_fracs);
                                        answer = buffer.toString(); break;
                                }
-                               case FORMAT_DEG_MIN: answer = "" + PRINTABLE_CARDINALS[_cardinal] + threeDigitString(_degrees) + "°"
-                                       + (_minutes + _seconds / 60.0 + _fracs / 600.0); break;
+                               case FORMAT_DEG_MIN:
+                               {
+                                       answer = "" + PRINTABLE_CARDINALS[_cardinal] + threeDigitString(_degrees) + "°"
+                                               + (_minutes + _seconds / 60.0 + _fracs / 600.0); break;
+                               }
                                case FORMAT_DEG:
-                               case FORMAT_DEG_WITHOUT_CARDINAL: answer = (_asDouble<0.0?"-":"")
-                               + (_degrees + _minutes / 60.0 + _seconds / 3600.0 + _fracs / 36000.0); break;
+                               case FORMAT_DEG_WITHOUT_CARDINAL:
+                               {
+                                       answer = (_asDouble<0.0?"-":"")
+                                               + (_degrees + _minutes / 60.0 + _seconds / 3600.0 + _fracs / 36000.0); break;
+                               }
                        }
                }
                return answer;
index 5d66ec55783a596d7bef1f1cd671dbe75a8c5b13..cd285d66790a83f263b78a44e0ef11ce1b7517cc 100644 (file)
@@ -7,19 +7,19 @@ package tim.prune.data;
  */
 public class DataPoint
 {
-       // Hold these as Strings?  Or FieldValue objects?
+       /** Array of Strings holding raw values */
        private String[] _fieldValues = null;
-       // list of fields
+       /** list of field definitions */
        private FieldList _fieldList = null;
-       // Special fields for coordinates
+       /** Special fields for coordinates */
        private Coordinate _latitude = null, _longitude = null;
        private Altitude _altitude;
        private Timestamp _timestamp = null;
+       private Photo _photo = null;
+       private String _waypointName = null;
        private boolean _pointValid = false;
 
 
-       // TODO: Make it possible to turn track point into waypoint - may need to alter FieldList
-
        /**
         * Constructor
         * @param inValueArray array of String values
@@ -32,22 +32,32 @@ public class DataPoint
                _fieldValues = inValueArray;
                // save list of fields
                _fieldList = inFieldList;
+               // parse fields into objects
+               parseFields(inAltFormat);
+       }
 
-               // parse fields
+
+       /**
+        * Parse the string values into objects eg Coordinates
+        * @param inAltFormat altitude format
+        */
+       private void parseFields(int inAltFormat)
+       {
                _latitude = new Latitude(getFieldValue(Field.LATITUDE));
                _longitude = new Longitude(getFieldValue(Field.LONGITUDE));
                _altitude = new Altitude(getFieldValue(Field.ALTITUDE), inAltFormat);
                _timestamp = new Timestamp(getFieldValue(Field.TIMESTAMP));
+               _waypointName = getFieldValue(Field.WAYPT_NAME);
        }
 
 
        /**
-        * Private constructor for artificially generated points (eg interpolated)
+        * Constructor for additional points (eg interpolated, photos)
         * @param inLatitude latitude
         * @param inLongitude longitude
         * @param inAltitude altitude
         */
-       private DataPoint(Coordinate inLatitude, Coordinate inLongitude, Altitude inAltitude)
+       public DataPoint(Coordinate inLatitude, Coordinate inLongitude, Altitude inAltitude)
        {
                // Only these three fields are available
                _fieldValues = new String[0];
@@ -83,6 +93,46 @@ public class DataPoint
        }
 
 
+       /**
+        * Set (or edit) the specified field value
+        * @param inField Field to set
+        * @param inValue value to set
+        */
+       public void setFieldValue(Field inField, String inValue)
+       {
+               // See if this data point already has this field
+               int fieldIndex = _fieldList.getFieldIndex(inField);
+               // Add to field list if necessary
+               if (fieldIndex < 0)
+               {
+                       // If value is empty & field doesn't exist then do nothing
+                       if (inValue == null || inValue.equals(""))
+                       {
+                               return;
+                       }
+                       // value isn't empty so extend field list
+                       fieldIndex = _fieldList.extendList(inField);
+               }
+               // Extend array of field values if necessary
+               if (fieldIndex >= _fieldValues.length)
+               {
+                       resizeValueArray(fieldIndex);
+               }
+               // Set field value in array
+               _fieldValues[fieldIndex] = inValue;
+               // Change Coordinate, Altitude, Name or Timestamp fields after edit
+               if (_altitude != null)
+               {
+                       parseFields(_altitude.getFormat());
+               }
+               else
+               {
+                       // use default altitude format of metres
+                       parseFields(Altitude.FORMAT_METRES);
+               }
+       }
+
+
        public Coordinate getLatitude()
        {
                return _latitude;
@@ -107,19 +157,22 @@ public class DataPoint
        {
                return _timestamp;
        }
+       public String getWaypointName()
+       {
+               return _waypointName;
+       }
 
        /**
         * @return true if point has a waypoint name
         */
        public boolean isWaypoint()
        {
-               String name = getFieldValue(Field.WAYPT_NAME);
-               return (name != null && !name.equals(""));
+               return (_waypointName != null && !_waypointName.equals(""));
        }
 
+
        /**
-        * Compare two DataPoint objects to see if they
-        * are duplicates
+        * Compare two DataPoint objects to see if they are duplicates
         * @param inOther other object to compare
         * @return true if the points are equivalent
         */
@@ -131,26 +184,45 @@ public class DataPoint
                {
                        return false;
                }
+               // Make sure photo points aren't specified as duplicates
+               if (_photo != null) return false;
                // Compare latitude and longitude
                if (!_longitude.equals(inOther._longitude) || !_latitude.equals(inOther._latitude))
                {
                        return false;
                }
                // Note that conversion from decimal to dms can make non-identical points into duplicates
-               // Compare description (if any)
-               String name1 = getFieldValue(Field.WAYPT_NAME);
-               String name2 = inOther.getFieldValue(Field.WAYPT_NAME);
-               if (name1 == null || name1.equals(""))
+               // Compare waypoint name (if any)
+               if (!isWaypoint())
                {
-                       return (name2 == null || name2.equals(""));
+                       return !inOther.isWaypoint();
                }
                else
                {
-                       return (name2 != null && name2.equals(name1));
+                       return (inOther._waypointName != null && inOther._waypointName.equals(_waypointName));
                }
        }
 
 
+       /**
+        * Set the photo for this data point
+        * @param inPhoto Photo object
+        */
+       public void setPhoto(Photo inPhoto)
+       {
+               _photo = inPhoto;
+       }
+
+
+       /**
+        * @return associated Photo object
+        */
+       public Photo getPhoto()
+       {
+               return _photo;
+       }
+
+
        /**
         * @return true if the point is valid
         */
@@ -210,4 +282,60 @@ public class DataPoint
                // phew
                return answer;
        }
+
+
+       /**
+        * Resize the value array
+        * @param inNewIndex new index to allow
+        */
+       private void resizeValueArray(int inNewIndex)
+       {
+               int newSize = inNewIndex + 1;
+               if (newSize > _fieldValues.length)
+               {
+                       String[] newArray = new String[newSize];
+                       System.arraycopy(_fieldValues, 0, newArray, 0, _fieldValues.length);
+                       _fieldValues = newArray;
+               }
+       }
+
+
+       /**
+        * @return a clone object with copied data
+        */
+       public DataPoint clonePoint()
+       {
+               // Copy all values
+               String[] valuesCopy = new String[_fieldValues.length];
+               System.arraycopy(_fieldValues, 0, valuesCopy, 0, _fieldValues.length);
+               // Make new object to hold cloned data
+               DataPoint point = new DataPoint(valuesCopy, _fieldList, _altitude.getFormat());
+               return point;
+       }
+
+
+       /**
+        * Restore the contents from another point
+        * @param inOther point containing contents to copy
+        * @return true if successful
+        */
+       public boolean restoreContents(DataPoint inOther)
+       {
+               if (inOther != null)
+               {
+                       // Copy string values across
+                       _fieldValues = inOther._fieldValues;
+                       if (_altitude != null)
+                       {
+                               parseFields(_altitude.getFormat());
+                       }
+                       else
+                       {
+                               // use default altitude format of metres
+                               parseFields(Altitude.FORMAT_METRES);
+                       }
+                       return true;
+               }
+               return false;
+       }
 }
index 61afdca0dd5f3ae1514c76f8ccca60fb7e19b5b9..77ab6d46bc13319aa6829418fd60d5c6c251a3d2 100644 (file)
@@ -31,6 +31,4 @@ public abstract class Distance
                return inAngDist * EARTH_RADIUS_KM;
        }
 
-
-       
 }
index b7d4771b5ce28c8d6a54fdffd077224a77cf16c1..f241d4d13470eb1b5e1feb60cdab5d22b686d5b8 100644 (file)
@@ -10,6 +10,16 @@ public class DoubleRange
        private double _min = 0.0, _max = 0.0;
 
 
+       /**
+        * Clear for a new calculation
+        */
+       public void clear()
+       {
+               _min = _max = 0.0;
+               _empty = true;
+       }
+
+
        /**
         * Add a value to the range
         * @param inValue value to add
index 58cf6d50ec318ab20bd40e7a7efa5a165f5b69ca..5e567ea8512bd80caae67370f0f58734979fabd1 100644 (file)
@@ -135,6 +135,27 @@ public class FieldList
        }
 
 
+       /**
+        * Extend the field list to include the specified field
+        * @param inField Field to add
+        * @return new index of added Field
+        */
+       public int extendList(Field inField)
+       {
+               // See if field is already in list
+               int currIndex = getFieldIndex(inField);
+               if (currIndex >= 0) return currIndex;
+               // Need to extend - increase array size
+               int oldNumFields = _fieldArray.length;
+               Field[] fields = new Field[oldNumFields + 1];
+               System.arraycopy(_fieldArray, 0, fields, 0, oldNumFields);
+               _fieldArray = fields;
+               // Add new field and return index
+               _fieldArray[oldNumFields] = inField;
+               return oldNumFields;
+       }
+
+
        /**
         * Convert to String for debug
         */
index 61ae34c4ad58f7e9d61a4f320bc76181f43da3e7..b11ba0e5b4993b9b53c39c40e1351dcf2aa1be82 100644 (file)
@@ -9,6 +9,16 @@ public class IntegerRange
        private int _min = -1, _max = -1;
 
 
+       /**
+        * Clear for a new range calculation
+        */
+       public void clear()
+       {
+               _min = -1;
+               _max = -1;
+       }
+
+
        /**
         * Add a value to the range
         * @param inValue value to add, only positive values considered
index 6d8bab6971310745aee49db8b6c725d74b6fbde7..61e8bb2ebbf17a9245ca1961f3b4f8c11d62ad88 100644 (file)
@@ -20,10 +20,9 @@ public class Latitude extends Coordinate
         * @param inValue value of coordinate
         * @param inFormat format to use
         */
-       protected Latitude(double inValue, int inFormat)
+       public Latitude(double inValue, int inFormat)
        {
-               super(inValue, inFormat);
-               _cardinal = inValue < 0.0 ? SOUTH : NORTH;
+               super(inValue, inFormat, inValue < 0.0 ? SOUTH : NORTH);
        }
 
 
index d61adbc2ce2f96dd3e5c9fd0d25a2b5f52f17bd2..6af58894aad3d4ba791f1588e9519ea8df16b6cd 100644 (file)
@@ -20,10 +20,9 @@ public class Longitude extends Coordinate
         * @param inValue value of coordinate
         * @param inFormat format to use
         */
-       protected Longitude(double inValue, int inFormat)
+       public Longitude(double inValue, int inFormat)
        {
-               super(inValue, inFormat);
-               _cardinal = inValue < 0.0 ? WEST : EAST;
+               super(inValue, inFormat, inValue < 0.0 ? WEST : EAST);
        }
 
 
index c375e820b4a05b022682deef2b675ee27a82b8d8..f09088dc218e6f498cef7d78a498a5995e019c02 100644 (file)
@@ -383,20 +383,28 @@ public class Selection
         */
        private void check()
        {
-               if (_track != null && _track.getNumPoints() > 0)
+               if (_track != null)
                {
-                       int maxIndex = _track.getNumPoints() - 1;
-                       if (_currentPoint > maxIndex)
+                       if (_track.getNumPoints() > 0)
                        {
-                               _currentPoint = maxIndex;
-                       }
-                       if (_endIndex > maxIndex)
-                       {
-                               _endIndex = maxIndex;
+                               int maxIndex = _track.getNumPoints() - 1;
+                               if (_currentPoint > maxIndex)
+                               {
+                                       _currentPoint = maxIndex;
+                               }
+                               if (_endIndex > maxIndex)
+                               {
+                                       _endIndex = maxIndex;
+                               }
+                               if (_startIndex > maxIndex)
+                               {
+                                       _startIndex = maxIndex;
+                               }
                        }
-                       if (_startIndex > maxIndex)
+                       else
                        {
-                               _startIndex = maxIndex;
+                               // track is empty, clear selections
+                               _currentPoint = _startIndex = _endIndex = -1;
                        }
                }
                _broker.informSubscribers();
index 683cd21fcf6b3f07da472b64fc151970372ef51d..e73fa736eb6731d1d7c86ee5d48dffc6bf35b0eb 100644 (file)
@@ -1,6 +1,10 @@
 package tim.prune.data;
 
+import java.util.List;
+
 import tim.prune.UpdateMessageBroker;
+import tim.prune.edit.FieldEdit;
+import tim.prune.edit.FieldEditList;
 
 
 /**
@@ -219,6 +223,7 @@ public class Track
         */
        public boolean deleteRange(int inStart, int inEnd)
        {
+               // TODO: Check for deleting photos?
                if (inStart < 0 || inEnd < 0 || inEnd < inStart)
                {
                        // no valid range selected so can't delete
@@ -433,6 +438,7 @@ public class Track
                return true;
        }
 
+       // TODO: Need to rearrange photo points too?
 
        /**
         * Interpolate extra points between two selected ones
@@ -452,10 +458,26 @@ public class Track
 
                // Make array of points to insert
                DataPoint[] insertedPoints = startPoint.interpolate(endPoint, inNumPoints);
-               
+
                // Insert points into track
-               insertRange(insertedPoints, inStartIndex + 1);
-               return true;
+               return insertRange(insertedPoints, inStartIndex + 1);
+       }
+
+
+       /**
+        * Append the specified points to the end of the track
+        * @param inPoints DataPoint objects to add
+        */
+       public void appendPoints(DataPoint[] inPoints)
+       {
+               // Insert points into track
+               if (inPoints != null && inPoints.length > 0)
+               {
+                       insertRange(inPoints, _numPoints);
+               }
+               // needs to be scaled again to recalc x, y
+               _scaled = false;
+               _broker.informSubscribers();
        }
 
 
@@ -581,6 +603,49 @@ public class Track
        }
 
 
+       /**
+        * Collect all the waypoints into the given List
+        * @param inList List to fill with waypoints
+        */
+       public void getWaypoints(List inList)
+       {
+               // clear list
+               inList.clear();
+               // loop over points and copy all waypoints into list
+               for (int i=0; i<=_numPoints-1; i++)
+               {
+                       if (_dataPoints[i].isWaypoint())
+                       {
+                               inList.add(_dataPoints[i]);
+                       }
+               }
+       }
+       // TODO: Make similar method to get list of photos
+
+
+       /**
+        * Search for the given Point in the track and return the index
+        * @param inPoint Point to look for
+        * @return index of Point, if any or -1 if not found
+        */
+       public int getPointIndex(DataPoint inPoint)
+       {
+               if (inPoint != null)
+               {
+                       // Loop over points in track
+                       for (int i=0; i<=_numPoints-1; i++)
+                       {
+                               if (_dataPoints[i] == inPoint)
+                               {
+                                       return i;
+                               }
+                       }
+               }
+               // not found
+               return -1;
+       }
+
+
        ///////// Internal processing methods ////////////////
 
 
@@ -604,7 +669,9 @@ public class Track
                                _longRange.addValue(point.getLongitude().getDouble());
                                _latRange.addValue(point.getLatitude().getDouble());
                                if (point.getAltitude().isValid())
+                               {
                                        _altitudeRange.addValue(point.getAltitude());
+                               }
                                if (point.isWaypoint())
                                        hasWaypoint = true;
                                else
@@ -790,4 +857,31 @@ public class Track
                _broker.informSubscribers();
                return true;
        }
+
+
+       /**
+        * Edit the specified point
+        * @param inPoint point to edit
+        * @param inEditList list of edits to make
+        * @return true if successful
+        */
+       public boolean editPoint(DataPoint inPoint, FieldEditList inEditList)
+       {
+               if (inPoint != null && inEditList != null && inEditList.getNumEdits() > 0)
+               {
+                       // go through edits one by one
+                       int numEdits = inEditList.getNumEdits();
+                       for (int i=0; i<numEdits; i++)
+                       {
+                               FieldEdit edit = inEditList.getEdit(i);
+                               inPoint.setFieldValue(edit.getField(), edit.getValue());
+                       }
+                       // possibly needs to be scaled again
+                       _scaled = false;
+                       // trigger listeners
+                       _broker.informSubscribers();
+                       return true;
+               }
+               return false;
+       }
 }
index 71363dae1053ed3e89dba907a8dea89adfada90f..4695d351e6c124c398e0df90c911dbe0583c4dbe 100644 (file)
@@ -1,5 +1,7 @@
 package tim.prune.data;
 
+import java.util.List;
+
 import tim.prune.UpdateMessageBroker;
 
 /**
@@ -12,6 +14,9 @@ public class TrackInfo
        private Track _track = null;
        private Selection _selection = null;
        private FileInfo _fileInfo = null;
+       // TODO: How to store photos? In separate list to be maintained or dynamic? Only store pointless photos?
+       private PhotoList _photoList = null;
+
 
        /**
         * Constructor
@@ -24,6 +29,7 @@ public class TrackInfo
                _track = inTrack;
                _selection = new Selection(_track, inBroker);
                _fileInfo = new FileInfo();
+               _photoList = new PhotoList();
        }
 
 
@@ -53,6 +59,14 @@ public class TrackInfo
                return _fileInfo;
        }
 
+       /**
+        * @return the PhotoList object
+        */
+       public PhotoList getPhotoList()
+       {
+               return _photoList;
+       }
+
        /**
         * Get the currently selected point, if any
         * @return DataPoint if single point selected, otherwise null
@@ -77,12 +91,63 @@ public class TrackInfo
        }
 
 
+       /**
+        * Add a List of Photos
+        * @param inList List containing Photo objects
+        * @return number of photos added
+        */
+       public int addPhotos(List inList)
+       {
+               // Firstly count number to add to make array
+               int numPhotosToAdd = 0;
+               if (inList != null && !inList.isEmpty())
+               {
+                       for (int i=0; i<inList.size(); i++)
+                       {
+                               try
+                               {
+                                       Photo photo = (Photo) inList.get(i);
+                                       if (photo != null && !_photoList.contains(photo))
+                                       {
+                                               numPhotosToAdd++;
+                                       }
+                               }
+                               catch (ClassCastException ce) {}
+                       }
+               }
+               // If there are any photos to add, add them
+               if (numPhotosToAdd > 0)
+               {
+                       DataPoint[] dataPoints = new DataPoint[numPhotosToAdd];
+                       int pointNum = 0;
+                       // Add each Photo in turn
+                       for (int i=0; i<inList.size(); i++)
+                       {
+                               try
+                               {
+                                       Photo photo = (Photo) inList.get(i);
+                                       if (photo != null && !_photoList.contains(photo))
+                                       {
+                                               _photoList.addPhoto(photo);
+                                               dataPoints[pointNum] = photo.getDataPoint();
+                                               pointNum++;
+                                       }
+                               }
+                               catch (ClassCastException ce) {}
+                       }
+                       _track.appendPoints(dataPoints);
+               }
+               return numPhotosToAdd;
+       }
+
+
        /**
         * Delete the currently selected range of points
         * @return true if successful
         */
        public boolean deleteRange()
        {
+               // TODO: Check whether to delete photos associated with this range
                int currPoint = _selection.getCurrentPointIndex();
                int startSel = _selection.getStart();
                int endSel = _selection.getEnd();
@@ -101,6 +166,7 @@ public class TrackInfo
        {
                if (_track.deletePoint(_selection.getCurrentPointIndex()))
                {
+                       // TODO: Check whether to delete photo associated with this point
                        _selection.modifyPointDeleted();
                        _broker.informSubscribers();
                        return true;
@@ -159,4 +225,17 @@ public class TrackInfo
                        _selection.selectRangeEnd(_selection.getEnd() + inNumPoints);
                return success;
        }
+
+
+       /**
+        * Select the given DataPoint
+        * @param inPoint DataPoint object to select
+        */
+       public void selectPoint(DataPoint inPoint)
+       {
+               // get the index of the given Point
+               int index = _track.getPointIndex(inPoint);
+               // give to selection
+               _selection.selectPoint(index);
+       }
 }
index 8e5c1da0f26fad3e3e9ef67121a0a98cfbabaa6a..09ce454ab056bafdb6b8bc04b4097226a5600d55 100644 (file)
@@ -56,12 +56,13 @@ public class AboutScreen extends JDialog
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.summarytext1")).append("</p>");
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.summarytext2")).append("</p>");
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.summarytext3")).append("</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));
                descPane.setEditable(false);
                descPane.setOpaque(false);
                descPane.setAlignmentX(JEditorPane.CENTER_ALIGNMENT);
-               // descPane.setBackground(Color.GRAY);
+
                mainPanel.add(descPane);
                mainPanel.add(new JLabel(" "));
                JButton okButton = new JButton(I18nManager.getText("button.ok"));
index e9ed7472806cf1a058eae06e5c10c50dfdda14a7..765b88b30c37f5206e6abb30ac676c5d850ce885 100644 (file)
@@ -17,17 +17,22 @@ import javax.swing.BoxLayout;
 import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JLabel;
+import javax.swing.JList;
 import javax.swing.JPanel;
 import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
 import javax.swing.border.EtchedBorder;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
 
 import tim.prune.App;
+import tim.prune.DataSubscriber;
 import tim.prune.I18nManager;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Distance;
-import tim.prune.data.Field;
 import tim.prune.data.IntegerRange;
 import tim.prune.data.Selection;
 import tim.prune.data.TrackInfo;
@@ -48,7 +53,7 @@ public class DetailsDisplay extends GenericDisplay
        private JLabel _indexLabel = null;
        private JLabel _latLabel = null, _longLabel = null;
        private JLabel _altLabel = null, _nameLabel = null;
-       private JLabel _timeLabel = null;
+       private JLabel _timeLabel = null, _photoFileLabel = null;
        // Scroll bar
        private JScrollBar _scroller = null;
        private boolean _ignoreScrollEvents = false;
@@ -60,6 +65,12 @@ public class DetailsDisplay extends GenericDisplay
        private JLabel _rangeLabel = null;
        private JLabel _distanceLabel = null, _durationLabel = null;
        private JLabel _altRangeLabel = null, _updownLabel = null;
+       // Photos
+       private JList _photoList = null;
+       private PhotoListModel _photoListModel = null;
+       // Waypoints
+       private JList _waypointList = null;
+       private WaypointListModel _waypointListModel = null;
        // Units
        private JComboBox _unitsDropdown = null;
        // Formatter
@@ -113,7 +124,7 @@ public class DetailsDisplay extends GenericDisplay
                trackDetailsPanel.add(_trackpointsLabel);
                _filenameLabel = new JLabel("");
                trackDetailsPanel.add(_filenameLabel);
-               
+
                // Point details panel
                JPanel pointDetailsPanel = new JPanel();
                pointDetailsPanel.setLayout(new BoxLayout(pointDetailsPanel, BoxLayout.Y_AXIS));
@@ -133,6 +144,8 @@ public class DetailsDisplay extends GenericDisplay
                pointDetailsPanel.add(_altLabel);
                _timeLabel = new JLabel("");
                pointDetailsPanel.add(_timeLabel);
+               _photoFileLabel = new JLabel("");
+               pointDetailsPanel.add(_photoFileLabel);
                _nameLabel = new JLabel("");
                pointDetailsPanel.add(_nameLabel);
                pointDetailsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
@@ -214,8 +227,36 @@ public class DetailsDisplay extends GenericDisplay
                otherDetailsPanel.add(_updownLabel);
                otherDetailsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
 
-               // add the main panel at the top
-               add(mainPanel, BorderLayout.NORTH);
+               // Add tab panel for waypoints / photos
+               JPanel waypointsPanel = new JPanel();
+               waypointsPanel.setLayout(new BoxLayout(waypointsPanel, BoxLayout.Y_AXIS));
+               waypointsPanel.setBorder(BorderFactory.createCompoundBorder(
+                       BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(3, 3, 3, 3))
+               );
+               JTabbedPane tabPane = new JTabbedPane();
+               _waypointListModel = new WaypointListModel(_trackInfo.getTrack());
+               _waypointList = new JList(_waypointListModel);
+               _waypointList.setVisibleRowCount(5);
+               _waypointList.addListSelectionListener(new ListSelectionListener() {
+                       public void valueChanged(ListSelectionEvent e)
+                       {
+                               if (!e.getValueIsAdjusting()) selectWaypoint(_waypointList.getSelectedIndex());
+                       }});
+               tabPane.addTab(I18nManager.getText("details.waypointsphotos.waypoints"), new JScrollPane(_waypointList));
+               _photoListModel = new PhotoListModel(_trackInfo.getPhotoList());
+               _photoList = new JList(_photoListModel);
+               _photoList.setVisibleRowCount(5);
+               _photoList.addListSelectionListener(new ListSelectionListener() {
+                       public void valueChanged(ListSelectionEvent e)
+                       {
+                               if (!e.getValueIsAdjusting()) selectPhoto(_photoList.getSelectedIndex());
+                       }});
+               // TODO: Re-add photos list after v2
+               // tabPane.addTab(I18nManager.getText("details.waypointsphotos.photos"), new JScrollPane(_photoList));
+               tabPane.setAlignmentX(Component.LEFT_ALIGNMENT);
+               waypointsPanel.add(tabPane);
+               waypointsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+
                // add the slider, point details, and the other details to the main panel
                mainPanel.add(buttonPanel);
                mainPanel.add(Box.createVerticalStrut(5));
@@ -226,6 +267,10 @@ public class DetailsDisplay extends GenericDisplay
                mainPanel.add(pointDetailsPanel);
                mainPanel.add(Box.createVerticalStrut(5));
                mainPanel.add(otherDetailsPanel);
+               mainPanel.add(Box.createVerticalStrut(5));
+               mainPanel.add(waypointsPanel);
+               // add the main panel at the top
+               add(mainPanel, BorderLayout.NORTH);
 
                // Add units selection
                JPanel lowerPanel = new JPanel();
@@ -236,7 +281,7 @@ public class DetailsDisplay extends GenericDisplay
                _unitsDropdown.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               dataUpdated();
+                               dataUpdated(DataSubscriber.UNITS_CHANGED);
                        }
                });
                lowerPanel.add(_unitsDropdown);
@@ -257,10 +302,43 @@ public class DetailsDisplay extends GenericDisplay
        }
 
 
+       /**
+        * Select the specified photo
+        * @param inPhotoIndex index of selected photo
+        */
+       private void selectPhoto(int inPhotoIndex)
+       {
+               if (_photoListModel.getPhoto(inPhotoIndex) != null)
+               {
+                       // TODO: Deselect the photo when another point is selected
+                       // TODO: show photo thumbnail
+                       // select associated point, if any
+                       DataPoint point = _photoListModel.getPhoto(inPhotoIndex).getDataPoint();
+                       if (point != null)
+                       {
+                               _trackInfo.selectPoint(point);
+                       }
+               }
+       }
+
+
+       /**
+        * Select the specified waypoint
+        * @param inWaypointIndex index of selected waypoint
+        */
+       private void selectWaypoint(int inWaypointIndex)
+       {
+               if (inWaypointIndex >= 0)
+               {
+                       _trackInfo.selectPoint(_waypointListModel.getWaypoint(inWaypointIndex));
+               }
+       }
+
+
        /**
         * Notification that Track has been updated
         */
-       public void dataUpdated()
+       public void dataUpdated(byte inUpdateType)
        {
                // Update track data
                if (_track == null || _track.getNumPoints() <= 0)
@@ -297,6 +375,7 @@ public class DetailsDisplay extends GenericDisplay
                        _longLabel.setText("");
                        _altLabel.setText("");
                        _timeLabel.setText("");
+                       _photoFileLabel.setText("");
                        _nameLabel.setText("");
                }
                else
@@ -314,7 +393,14 @@ public class DetailsDisplay extends GenericDisplay
                                _timeLabel.setText(LABEL_POINT_TIMESTAMP + currentPoint.getTimestamp().getText());
                        else
                                _timeLabel.setText("");
-                       String name = currentPoint.getFieldValue(Field.WAYPT_NAME);
+                       if (currentPoint.getPhoto() != null && currentPoint.getPhoto().getFile() != null)
+                       {
+                               _photoFileLabel.setText(I18nManager.getText("details.photofile") + ": "
+                                       + currentPoint.getPhoto().getFile().getName());
+                       }
+                       else
+                               _photoFileLabel.setText("");
+                       String name = currentPoint.getWaypointName();
                        if (name != null && !name.equals(""))
                        {
                                _nameLabel.setText(LABEL_POINT_WAYPOINTNAME + name);
@@ -389,6 +475,37 @@ public class DetailsDisplay extends GenericDisplay
                                _updownLabel.setText("");
                        }
                }
+               // update waypoints and photos if necessary
+               if ((inUpdateType |
+                       (DataSubscriber.DATA_ADDED_OR_REMOVED | DataSubscriber.DATA_EDITED | DataSubscriber.WAYPOINTS_MODIFIED)) > 0)
+               {
+                       _waypointListModel.fireChanged();
+               }
+               if ((inUpdateType |
+                       (DataSubscriber.DATA_ADDED_OR_REMOVED | DataSubscriber.DATA_EDITED | DataSubscriber.PHOTOS_MODIFIED)) > 0)
+               {
+                       _photoListModel.fireChanged();
+               }
+               // Deselect selected waypoint if selected point has since changed
+               if (_waypointList.getSelectedIndex() >= 0)
+               {
+                       if (_trackInfo.getCurrentPoint() == null
+                        || !_waypointListModel.getWaypoint(_waypointList.getSelectedIndex()).equals(_trackInfo.getCurrentPoint()))
+                       {
+                               // point is selected in list but different from current point - deselect
+                               _waypointList.clearSelection();
+                       }
+               }
+               // Do the same for the photos
+               if (_photoList.getSelectedIndex() >= 0)
+               {
+                       if (_trackInfo.getCurrentPoint() == null
+                               || !_photoListModel.getPhoto(_photoList.getSelectedIndex()).getDataPoint().equals(_trackInfo.getCurrentPoint()))
+                       {
+                               // photo is selected in list but different from current point - deselect
+                               _photoList.clearSelection();
+                       }
+               }
        }
 
 
index 081c823257713aa5365aa8972a399c736ac6ceee..916c738d817c34e90defcb0f7d523e111f197ec9 100644 (file)
@@ -71,7 +71,7 @@ public abstract class GenericChart extends GenericDisplay implements MouseListen
        /**
         * Method to inform map that data has changed
         */
-       public void dataUpdated()
+       public void dataUpdated(byte inUpdateType)
        {
                repaint();
        }
index 13b1b7d9e00a54292e4fe62d31084868e74de854..1236f130558630c4278b7a8cc31762ec34630ad4 100644 (file)
@@ -19,9 +19,9 @@ import javax.swing.JMenuItem;
 import javax.swing.JPopupMenu;
 
 import tim.prune.App;
+import tim.prune.DataSubscriber;
 import tim.prune.I18nManager;
 import tim.prune.data.DataPoint;
-import tim.prune.data.Field;
 import tim.prune.data.TrackInfo;
 
 
@@ -83,16 +83,16 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
        /**
         * Override track updating to refresh image
         */
-       public void dataUpdated()
+       public void dataUpdated(byte inUpdateType)
        {
-               // Check if number of points has changed or Track
-               // object has a different signature
-               if (_track.getNumPoints() != _numPoints)
+               // Check if number of points has changed or data has been edited
+               if (_track.getNumPoints() != _numPoints || (inUpdateType & DATA_EDITED) > 0)
                {
                        _image = null;
+                       _lastSelectedPoint = -1;
                        _numPoints = _track.getNumPoints();
                }
-               super.dataUpdated();
+               super.dataUpdated(inUpdateType);
        }
 
 
@@ -126,25 +126,25 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                        // Autopan is enabled and a point is selected - work out x and y to see if it's within range
                        x = width/2 + (int) ((_track.getX(selectedPoint) - _offsetX) / _scale * _zoomScale);
                        y = height/2 - (int) ((_track.getY(selectedPoint) - _offsetY) / _scale * _zoomScale);
-                       if (x < BORDER_WIDTH)
+                       if (x <= BORDER_WIDTH)
                        {
                                // autopan left
                                _offsetX -= (width / 4 - x) * _scale / _zoomScale;
                                _image = null;
                        }
-                       else if (x > (width - BORDER_WIDTH))
+                       else if (x >= (width - BORDER_WIDTH))
                        {
                                // autopan right
                                _offsetX += (x - width * 3/4) * _scale / _zoomScale;
                                _image = null;
                        }
-                       if (y < BORDER_WIDTH)
+                       if (y <= BORDER_WIDTH)
                        {
                                // autopan up
                                _offsetY += (height / 4 - y) * _scale / _zoomScale;
                                _image = null;
                        }
-                       else if (y > (height - BORDER_WIDTH))
+                       else if (y >= (height - BORDER_WIDTH))
                        {
                                // autopan down
                                _offsetY -= (y - height * 3/4) * _scale / _zoomScale;
@@ -197,6 +197,7 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                        }
                }
 
+               // Draw rectangle for dragging zoom area
                if (_zoomDragging)
                {
                        g.setColor(COLOR_CROSSHAIRS);
@@ -205,6 +206,9 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                        g.drawLine(_zoomDragToX, _zoomDragFromY, _zoomDragToX, _zoomDragToY);
                        g.drawLine(_zoomDragFromX, _zoomDragToY, _zoomDragToX, _zoomDragToY);
                }
+
+               // Attempt to grab keyboard focus if possible
+               this.requestFocus();
        }
 
 
@@ -245,7 +249,7 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                for (int i=0; i<numPoints; i++)
                {
                        DataPoint point = _track.getPoint(i);
-                       String waypointName = point.getFieldValue(Field.WAYPT_NAME);
+                       String waypointName = point.getWaypointName();
                        if (waypointName != null && !waypointName.equals("") && numWaypointNamesShown < LIMIT_WAYPOINT_NAMES)
                        {
                                x = halfWidth + (int) ((_track.getX(i) - _offsetX) / _scale * _zoomScale);
@@ -359,7 +363,7 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                _offsetX = 0.0;
                _offsetY = 0.0;
                _numPoints = 0;
-               dataUpdated();
+               dataUpdated(DataSubscriber.ALL);
        }
 
 
@@ -381,7 +385,7 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                        if (_zoomScale < 0.5) _zoomScale = 0.5;
                }
                _numPoints = 0;
-               dataUpdated();
+               dataUpdated(DataSubscriber.ALL);
        }
 
 
@@ -397,7 +401,8 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                _offsetX = _offsetX - (inRight * panFactor);
                // Limit pan to sensible range??
                _numPoints = 0;
-               dataUpdated();
+               _image = null;
+               repaint();
        }
 
 
@@ -454,6 +459,8 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                                double xZoom = Math.abs(getWidth() * 1.0 / (e.getX() - _zoomDragFromX));
                                double yZoom = Math.abs(getHeight() * 1.0 / (e.getY() - _zoomDragFromY));
                                double extraZoom = (xZoom>yZoom?yZoom:xZoom);
+                               // deselect point if selected (to stop autopan)
+                               _trackInfo.getSelection().selectPoint(-1);
                                // Pan first to ensure pan occurs with correct scale
                                panMap(yPan, xPan);
                                // Then zoom in and request repaint
@@ -513,7 +520,11 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                        panMap(upwardsPan, rightwardsPan);
                        // Check for delete key to delete current point
                        if (code == KeyEvent.VK_DELETE && _trackInfo.getSelection().getCurrentPointIndex() >= 0)
+                       {
                                _app.deleteCurrentPoint();
+                               // reset last selected point to trigger autopan
+                               _lastSelectedPoint = -1;
+                       }
                }
        }
 
index 665142e07b82f067176d7adfd62916c43db229c9..64a66d86aaba94296fb04e24535916d3e95670b9 100644 (file)
@@ -31,9 +31,12 @@ public class MenuManager implements DataSubscriber
 
        // Menu items which need enabling/disabling
        JMenuItem _saveItem = null;
-       JMenuItem _exportItem = null;
+       JMenuItem _exportKmlItem = null;
+       JMenuItem _exportPovItem = null;
        JMenuItem _undoItem = null;
        JMenuItem _clearUndoItem = null;
+       JMenuItem _editPointItem = null;
+       JMenuItem _editWaypointNameItem = null;
        JMenuItem _deletePointItem = null;
        JMenuItem _deleteRangeItem = null;
        JMenuItem _deleteDuplicatesItem = null;
@@ -71,6 +74,7 @@ public class MenuManager implements DataSubscriber
        {
                JMenuBar menubar = new JMenuBar();
                JMenu fileMenu = new JMenu(I18nManager.getText("menu.file"));
+               // Open file
                JMenuItem openMenuItem = new JMenuItem(I18nManager.getText("menu.file.open"));
                openMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK));
                openMenuItem.addActionListener(new ActionListener() {
@@ -80,6 +84,17 @@ public class MenuManager implements DataSubscriber
                        }
                });
                fileMenu.add(openMenuItem);
+               // Add photos
+               JMenuItem addPhotosMenuItem = new JMenuItem(I18nManager.getText("menu.file.addphotos"));
+               addPhotosMenuItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.addPhotos();
+                       }
+               });
+               // TODO: Re-add add photos menu item after v2
+               // fileMenu.add(addPhotosMenuItem);
+               // Save
                _saveItem = new JMenuItem(I18nManager.getText("menu.file.save"), KeyEvent.VK_S);
                _saveItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
@@ -90,15 +105,24 @@ public class MenuManager implements DataSubscriber
                _saveItem.setEnabled(false);
                fileMenu.add(_saveItem);
                // Export
-               _exportItem = new JMenuItem(I18nManager.getText("menu.file.export"));
-               _exportItem.addActionListener(new ActionListener() {
+               _exportKmlItem = new JMenuItem(I18nManager.getText("menu.file.exportkml"));
+               _exportKmlItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
                                _app.exportKml();
                        }
                });
-               _exportItem.setEnabled(false);
-               fileMenu.add(_exportItem);
+               _exportKmlItem.setEnabled(false);
+               fileMenu.add(_exportKmlItem);
+               _exportPovItem = new JMenuItem(I18nManager.getText("menu.file.exportpov"));
+               _exportPovItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.exportPov();
+                       }
+               });
+               _exportPovItem.setEnabled(false);
+               fileMenu.add(_exportPovItem);
                fileMenu.addSeparator();
                JMenuItem exitMenuItem = new JMenuItem(I18nManager.getText("menu.file.exit"));
                exitMenuItem.addActionListener(new ActionListener() {
@@ -130,6 +154,24 @@ public class MenuManager implements DataSubscriber
                _clearUndoItem.setEnabled(false);
                editMenu.add(_clearUndoItem);
                editMenu.addSeparator();
+               _editPointItem = new JMenuItem(I18nManager.getText("menu.edit.editpoint"));
+               _editPointItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.editCurrentPoint();
+                       }
+               });
+               _editPointItem.setEnabled(false);
+               editMenu.add(_editPointItem);
+               _editWaypointNameItem = new JMenuItem(I18nManager.getText("menu.edit.editwaypointname"));
+               _editWaypointNameItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.editCurrentPointName();
+                       }
+               });
+               _editWaypointNameItem.setEnabled(false);
+               editMenu.add(_editWaypointNameItem);
                _deletePointItem = new JMenuItem(I18nManager.getText("menu.edit.deletepoint"));
                _deletePointItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
@@ -240,21 +282,18 @@ public class MenuManager implements DataSubscriber
                selectMenu.add(_selectNoneItem);
                menubar.add(selectMenu);
 
-               // Add 3d menu if available
-               if (isJava3dEnabled())
-               {
-                       JMenu threeDMenu = new JMenu(I18nManager.getText("menu.3d"));
-                       _show3dItem = new JMenuItem(I18nManager.getText("menu.3d.show3d"));
-                       _show3dItem.addActionListener(new ActionListener() {
-                               public void actionPerformed(ActionEvent e)
-                               {
-                                       _app.show3dWindow();
-                               }
-                       });
-                       _show3dItem.setEnabled(false);
-                       threeDMenu.add(_show3dItem);
-                       menubar.add(threeDMenu);
-               }
+               // Add 3d menu (whether java3d available or not)
+               JMenu threeDMenu = new JMenu(I18nManager.getText("menu.3d"));
+               _show3dItem = new JMenuItem(I18nManager.getText("menu.3d.show3d"));
+               _show3dItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.show3dWindow();
+                       }
+               });
+               _show3dItem.setEnabled(false);
+               threeDMenu.add(_show3dItem);
+               menubar.add(threeDMenu);
 
                // Help menu for About
                JMenu helpMenu = new JMenu(I18nManager.getText("menu.help"));
@@ -285,34 +324,16 @@ public class MenuManager implements DataSubscriber
        }
 
 
-       /**
-        * @return true if 3d capability is installed
-        */
-       private static boolean isJava3dEnabled()
-       {
-               boolean has3d = false;
-               try
-               {
-                       Class universeClass = Class.forName("com.sun.j3d.utils.universe.SimpleUniverse");
-                       has3d = true;
-               }
-               catch (ClassNotFoundException e)
-               {
-                       // no java3d classes available
-               }
-               return has3d;
-       }
-
-
        /**
         * @see tim.prune.DataSubscriber#dataUpdated(tim.prune.data.Track)
         */
-       public void dataUpdated()
+       public void dataUpdated(byte inUpdateType)
        {
                boolean hasData = (_track != null && _track.getNumPoints() > 0);
                // set functions which require data
                _saveItem.setEnabled(hasData);
-               _exportItem.setEnabled(hasData);
+               _exportKmlItem.setEnabled(hasData);
+               _exportPovItem.setEnabled(hasData);
                _deleteDuplicatesItem.setEnabled(hasData);
                _compressItem.setEnabled(hasData);
                _rearrangeMenu.setEnabled(hasData && _track.hasMixedData());
@@ -326,6 +347,8 @@ public class MenuManager implements DataSubscriber
                _clearUndoItem.setEnabled(hasUndo);
                // is there a current point?
                boolean hasPoint = (hasData && _selection.getCurrentPointIndex() >= 0);
+               _editPointItem.setEnabled(hasPoint);
+               _editWaypointNameItem.setEnabled(hasPoint);
                _deletePointItem.setEnabled(hasPoint);
                // is there a current range?
                boolean hasRange = (hasData && _selection.hasRangeSelected());
index 01f9dad7edf553c9b0f874ad49635810dd43dea3..ff556566ea9ce4e4e9592af815d47eefa3506149 100644 (file)
@@ -4,12 +4,16 @@
 # Menu entries
 menu.file=File
 menu.file.open=Open
+menu.file.addphotos=Add Photos
 menu.file.save=Save
-menu.file.export=Export KML
+menu.file.exportkml=Export KML
+menu.file.exportpov=Export POV
 menu.file.exit=Exit
 menu.edit=Edit
 menu.edit.undo=Undo
 menu.edit.clearundo=Clear undo list
+menu.edit.editpoint=Edit point
+menu.edit.editwaypointname=Edit waypoint name
 menu.edit.deletepoint=Delete point
 menu.edit.deleterange=Delete range
 menu.edit.deleteduplicates=Delete duplicates
@@ -34,7 +38,7 @@ menu.map.zoomfull=Zoom to full scale
 menu.map.autopan=Autopan
 
 # Dialogs
-dialog.exit.confirm.title=Exit prune
+dialog.exit.confirm.title=Exit Prune
 dialog.exit.confirm.text=Your data is not saved. Are you sure you want to exit?
 dialog.openappend.title=Append to existing data
 dialog.openappend.text=Append this data to the data already loaded?
@@ -64,19 +68,37 @@ dialog.openoptions.deliminfo.fields=fields
 dialog.openoptions.deliminfo.norecords=No records
 dialog.openoptions.tabledesc=Extract of file
 dialog.openoptions.altitudeunits=Altitude units
+dialog.jpegload.subdirectories=Include subdirectories
+dialog.jpegload.progress.title=Loading photos
+dialog.jpegload.progress=Please wait while the photos are searched
+dialog.jpegload.title=Loaded photos
+dialog.jpegload.photoadded=photo was added
+dialog.jpegload.photosadded=photos were added
 dialog.saveoptions.title=Save file
 dialog.save.fieldstosave=Fields to save
 dialog.save.table.field=Field
 dialog.save.table.hasdata=Has data
 dialog.save.table.save=Save
+dialog.save.headerrow=Output header row
 dialog.save.coordinateunits=Coordinate units
 dialog.save.units.original=Original
 dialog.save.altitudeunits=Altitude units
 dialog.save.oktitle=File saved
 dialog.save.ok1=Successfully saved
 dialog.save.ok2=points to file
+dialog.save.overwrite.title=File already exists
+dialog.save.overwrite.text=This file already exists. Are you sure you want to overwrite the file?
 dialog.exportkml.title=Export KML
 dialog.exportkml.text=Please enter a short description for the data
+dialog.exportkml.filetype=KML files
+dialog.exportpov.title=Export POV
+dialog.exportpov.text=Please enter the parameters for the POV export
+dialog.exportpov.font=Font
+dialog.exportpov.camerax=Camera X
+dialog.exportpov.cameray=Camera Y
+dialog.exportpov.cameraz=Camera Z
+dialog.exportpov.filetype=POV files
+dialog.exportpov.warningtracksize=This track has a large number of points, which Java3D might not be able to display.\nAre you sure you want to continue?
 dialog.confirmreversetrack.title=Confirm reversal
 dialog.confirmreversetrack.text=This track contains timestamp information, which will be out of sequence after a reversal.\nAre you sure you want to reverse this section?
 dialog.interpolate.title=Interpolate points
@@ -90,12 +112,29 @@ dialog.undo.none.title=Cannot undo
 dialog.undo.none.text=No operations to undo!
 dialog.clearundo.title=Clear undo list
 dialog.clearundo.text=Are you sure you want to clear the undo list?\nAll undo information will be lost!
-dialog.about.title=About
+dialog.pointedit.title=Edit point
+dialog.pointedit.text=Select each field to edit and use the 'Edit' button to change the value
+dialog.pointedit.table.field=Field
+dialog.pointedit.table.value=Value
+dialog.pointedit.table.changed=Changed
+dialog.pointedit.changevalue.text=Enter the new value for this field
+dialog.pointedit.changevalue.title=Edit field
+dialog.pointnameedit.title=Edit waypoint name
+dialog.pointnameedit.name=Waypoint name
+dialog.pointnameedit.uppercase=UPPER case
+dialog.pointnameedit.lowercase=lower case
+dialog.pointnameedit.sentencecase=Sentence case
+dialog.about.title=About Prune
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=Prune is a program for loading, displaying and editing data from GPS receivers.
 dialog.about.summarytext2=It is released under the Gnu GPL for free, open, worldwide use and enhancement.<br>Copying, redistribution and modification are permitted and encouraged<br>according to the conditions in the included <code>license.txt</code> file.
 dialog.about.summarytext3=Please see <code style="font-weight:bold">http://activityworkshop.net/</code> for more information and user guides.
+dialog.about.translatedby=English text by activityworkshop.
+
+# 3d window
+dialog.3d.title=Prune Three-d view
+dialog.3d.altitudecap=Minimum altitude range
 
 # Buttons
 button.ok=OK
@@ -103,13 +142,17 @@ button.back=Back
 button.next=Next
 button.finish=Finish
 button.cancel=Cancel
+button.overwrite=Overwrite
 button.moveup=Move up
 button.movedown=Move down
-button.startrange=Set range start
-button.endrange=Set range end
+button.startrange=Set start
+button.endrange=Set end
 button.deletepoint=Delete point
 button.deleterange=Delete range
+button.edit=Edit
 button.exit=Exit
+button.close=Close
+button.continue=Continue
 
 # Display components
 display.nodata=No data loaded
@@ -123,6 +166,7 @@ details.pointdetails=Point details
 details.index.selected=Index
 details.index.of=of
 details.nopointselection=No point selected
+details.photofile=Photo file
 details.norangeselection=No range selected
 details.rangedetails=Range details
 details.range.selected=Selected
@@ -135,6 +179,8 @@ display.range.time.secs=s
 display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=d
+details.waypointsphotos.waypoints=Waypoints
+details.waypointsphotos.photos=Photos
 
 # Field names
 fieldname.latitude=Latitude
@@ -162,8 +208,16 @@ units.degminsec=Deg-min-sec
 units.degmin=Deg-min
 units.deg=Degrees
 
+# Cardinals for 3d plots
+cardinal.n=N
+cardinal.s=S
+cardinal.e=E
+cardinal.w=W
+
 # Undo operations
 undo.load=load data
+undo.loadphotos=load photos
+undo.editpoint=edit point
 undo.deletepoint=delete point
 undo.deleterange=delete range
 undo.compress=compress track
@@ -175,13 +229,20 @@ undo.rearrangewaypoints=rearrange waypoints
 # Error messages
 error.save.dialogtitle=Error saving data
 error.save.nodata=No data to save
-error.save.fileexists=File already exists. Just to be safe this program won't overwrite it.
 error.save.failed=Failed to save the data to file:
 error.load.dialogtitle=Error loading data
 error.load.noread=Cannot read file
+error.jpegload.dialogtitle=Error loading photos
+error.jpegload.nofilesfound=No files found
+error.jpegload.nojpegsfound=No jpeg files found
+error.jpegload.noexiffound=No EXIF information found
+error.jpegload.nogpsfound=No GPS information found
 error.undofailed.title=Undo failed
 error.undofailed.text=Failed to undo operation
 error.function.noop.title=Function had no effect
 error.rearrange.noop=Rearranging waypoints had no effect
-error.function.notimplemented.title=Function not available
 error.function.notimplemented=Sorry, this function has not yet been implemented.
+error.function.notavailable.title=Function not available
+error.function.nojava3d=This function requires the Java3d library,\navailable from Sun.com or Blackdown.org.
+error.3d.title=Error in 3d display
+error.3d=An error occurred with the 3d display
index 2acf4d16be6f8b40f7651cbfacaa2e4f27d37e8c..98fc57c6b94199e98bfe0c5de649a64821bb20a9 100644 (file)
@@ -4,12 +4,16 @@
 # Menu entries
 menu.file=Datei
 menu.file.open=Öffnen
+menu.file.addphotos=Fotos laden
 menu.file.save=Speichern
-menu.file.export=KML exportieren
+menu.file.exportkml=KML exportieren
+menu.file.exportpov=POV exportieren
 menu.file.exit=Beenden
 menu.edit=Bearbeiten
 menu.edit.undo=Undo
 menu.edit.clearundo=Undo-Liste löschen
+menu.edit.editpoint=Punkt bearbeiten
+menu.edit.editwaypointname=Waypoint Name bearbeiten
 menu.edit.deletepoint=Punkt löschen
 menu.edit.deleterange=Spanne löschen
 menu.edit.deleteduplicates=Duplikate löschen
@@ -49,7 +53,7 @@ dialog.compresstrack.single.text=Punkt wurde entfernt
 dialog.compresstrack.multi.text=Punkte wurden entfernt
 dialog.compresstrack.nonefound=Keine Punkte konnten entfernt werden
 dialog.openoptions.title=Öffnen Optionen
-dialog.openoptions.filesnippet=Extrakt vom File
+dialog.openoptions.filesnippet=Extrakt von der Datei
 dialog.load.table.field=Feld
 dialog.load.table.datatype=Daten Typ
 dialog.load.table.description=Beschreibung
@@ -62,21 +66,39 @@ dialog.delimiter.other=Andere
 dialog.openoptions.deliminfo.records=Rekords, mit 
 dialog.openoptions.deliminfo.fields=Feldern
 dialog.openoptions.deliminfo.norecords=Keine Rekords
-dialog.openoptions.tabledesc=Extrakt vom File
+dialog.openoptions.tabledesc=Extrakt von der Datei
 dialog.openoptions.altitudeunits=Höhe Maßeinheiten
-dialog.saveoptions.title=File speichern
+dialog.jpegload.subdirectories=Subordnern auch durchsuchen
+dialog.jpegload.progress.title=Fotos werden geladen
+dialog.jpegload.progress=Bitte warten während die Fotos durchgesucht werden
+dialog.jpegload.title=Fotos geladen
+dialog.jpegload.photoadded=Foto wurde geladen
+dialog.jpegload.photosadded=Fotos wurden geladen
+dialog.saveoptions.title=Datei speichern
 dialog.save.fieldstosave=Felder zu speichern
 dialog.save.table.field=Feld
 dialog.save.table.hasdata=Hat Daten
 dialog.save.table.save=Speichern
+dialog.save.headerrow=Titel Zeile speichern
 dialog.save.coordinateunits=Koordinaten Maßeinheiten
 dialog.save.units.original=Original
 dialog.save.altitudeunits=Höhe Maßeinheiten
-dialog.save.oktitle=File gespeichert
+dialog.save.oktitle=Datei gespeichert
 dialog.save.ok1=Es wurden
 dialog.save.ok2=Punkte gespeichert nach
+dialog.save.overwrite.title=Datei existiert
+dialog.save.overwrite.text=Diese Datei existiert schon. Sind Sie sicher, Sie wollen die Datei Ã¼berschreiben?
 dialog.exportkml.title=KML exportieren
 dialog.exportkml.text=Kurze Beschreibung von den Daten
+dialog.exportkml.filetype=KML Dateien
+dialog.exportpov.title=POV exportieren
+dialog.exportpov.text=Geben Sie die Parameter ein für das POV Export
+dialog.exportpov.font=Font
+dialog.exportpov.camerax=Kamera X
+dialog.exportpov.cameray=Kamera Y
+dialog.exportpov.cameraz=Kamera Z
+dialog.exportpov.filetype=POV Dateien
+dialog.exportpov.warningtracksize=Dieser Track hat sehr viele Punkte, die Java3D vielleicht nicht bearbeiten kann.\nSind Sie sicher, Sie wollen fortsetzen?
 dialog.confirmreversetrack.title=Umkehrung bestätigen
 dialog.confirmreversetrack.text=Diese Daten enthalten Zeitstempel Informationen, die bei einer Umkehrung ausser Reihenfolge erscheinen würden.\nSind Sie sicher, Sie wollen diese Spanne umkehren?
 dialog.interpolate.title=Punkte interpolieren
@@ -90,12 +112,29 @@ dialog.undo.none.title=Undo nicht m
 dialog.undo.none.text=Keine Operationen können rückgängig gemacht werden.
 dialog.clearundo.title=Undo-Liste löschen
 dialog.clearundo.text=Sind Sie sicher, Sie wollen die Undo-Liste löschen?\nAlle Undo Information wird veloren gehen!
-dialog.about.title=Ãœber
+dialog.pointedit.title=Punkt bearbeiten
+dialog.pointedit.text=Wählen Sie jeden Feld aus zu bearbeiten, und mit dem 'Bearbeiten' Knopf den Wert Ã¤ndern
+dialog.pointedit.table.field=Feld
+dialog.pointedit.table.value=Wert
+dialog.pointedit.table.changed=Geändert
+dialog.pointedit.changevalue.text=Geben Sie den neuen Wert für dieses Feld ein
+dialog.pointedit.changevalue.title=Feld bearbeiten
+dialog.pointnameedit.title=Waypoint Name bearbeiten
+dialog.pointnameedit.name=Waypoint Name
+dialog.pointnameedit.uppercase=GROSS geschrieben
+dialog.pointnameedit.lowercase=klein geschrieben
+dialog.pointnameedit.sentencecase=Gemischt geschrieben
+dialog.about.title=Ãœber Prune
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=Prune ist ein Programm für das Laden, Darstellen und Editieren von Daten von GPS Geräten.
-dialog.about.summarytext2=Es ist unter den Gnu GPL zur Verfügung gestellt, für frei, gratis und offen Gebrauch und Weiterentwicklung.<br>Kopieren, Weiterverbreitung und Veränderungen sind erlaubt und willkommen<br>unter die Bedingungen im enthaltenen <code>license.txt</code> File.
+dialog.about.summarytext2=Es ist unter den Gnu GPL zur Verfügung gestellt, für frei, gratis und offen Gebrauch und Weiterentwicklung.<br>Kopieren, Weiterverbreitung und Veränderungen sind erlaubt und willkommen<br>unter die Bedingungen in der enthaltenen <code>license.txt</code> Datei.
 dialog.about.summarytext3=Bitte sehen Sie <code style="font-weight:bold">http://activityworkshop.net/</code> für weitere Information und Benutzeranleitungen.
+dialog.about.translatedby=Deutsche Ãœbersetzung von activityworkshop.
+
+# 3d window
+dialog.3d.title=Prune Drei-D Ansicht
+dialog.3d.altitudecap=Minimum Höhenskala
 
 # Buttons
 button.ok=OK
@@ -103,13 +142,17 @@ button.back=Zur
 button.next=Vorwärts
 button.finish=Fertig
 button.cancel=Abbrechen
+button.overwrite=Ãœberschreiben
 button.moveup=Aufwärts moven
 button.movedown=Abwärts moven
 button.startrange=Start setzen
 button.endrange=Stopp setzen
 button.deletepoint=Punkt löschen
 button.deleterange=Spanne löschen
+button.edit=Bearbeiten
 button.exit=Beenden
+button.close=Schließen
+button.continue=Fortsetzen
 
 # Display components
 display.nodata=Keine Daten geladen
@@ -123,6 +166,7 @@ details.pointdetails=Details vom Punkt
 details.index.selected=Index
 details.index.of=von
 details.nopointselection=Nichts selektiert
+details.photofile=Foto Datei
 details.norangeselection=Nichts selektiert
 details.rangedetails=Details von Spanne
 details.range.selected=Selektiert
@@ -135,6 +179,8 @@ display.range.time.secs=S
 display.range.time.mins=M
 display.range.time.hours=Std
 display.range.time.days=T
+details.waypointsphotos.waypoints=Waypoints
+details.waypointsphotos.photos=Fotos
 
 # Field names
 fieldname.latitude=Breitengrad
@@ -162,12 +208,20 @@ units.degminsec=Grad-Min-Sek
 units.degmin=Grad-Min
 units.deg=Grad
 
+# Cardinals for 3d plots
+cardinal.n=N
+cardinal.s=S
+cardinal.e=O
+cardinal.w=W
+
 # Undo operations
 undo.load=Daten laden
+undo.loadphotos=Fotos laden
+undo.editpoint=Punkt bearbeiten
 undo.deletepoint=Punkt löschen
 undo.deleterange=Spanne löschen
 undo.compress=Track komprimieren
-undo.insert=Punkte dazufügen
+undo.insert=Punkte hinzufügen
 undo.deleteduplicates=Duplikaten löschen
 undo.reverse=Spanne umdrehen
 undo.rearrangewaypoints=Waypoints reorganisieren
@@ -175,13 +229,20 @@ undo.rearrangewaypoints=Waypoints reorganisieren
 # Error messages
 error.save.dialogtitle=Fehler beim Speichern
 error.save.nodata=Keine Daten wurden geladen
-error.save.fileexists=File existiert schon.  Um sicher zu sein, wird dieses Programm den File nicht Ã¼berschreiben.
-error.save.failed=Speichern vom File fehlgeschlagen :
+error.save.failed=Speichern von der Datei fehlgeschlagen :
 error.load.dialogtitle=Fehler beim Laden
-error.load.noread=File konnte nicht gelesen werden
+error.load.noread=Datei konnte nicht gelesen werden
+error.jpegload.dialogtitle=Fehler beim Laden von Fotos
+error.jpegload.nofilesfound=Keine Dateien gefunden
+error.jpegload.nojpegsfound=Keine Jpeg Dateien gefunden
+error.jpegload.noexiffound=Keine EXIF Information gefunden
+error.jpegload.nogpsfound=Keine GPS Information gefunden
 error.undofailed.title=Undo fehlgeschlagen
 error.undofailed.text=Operation konnte nicht rückgängig gemacht werden
 error.function.noop.title=Funktion hat nichts gemacht
 error.rearrange.noop=Waypoints Reorganisieren hatte keinen Effekt
-error.function.notimplemented.title=Funktion nicht verfügbar
 error.function.notimplemented=Sorry, diese Funktion wurde noch nicht implementiert.
+error.function.notavailable.title=Funktion nicht verfügbar
+error.function.nojava3d=Diese Funktion braucht den Java3d Library,\nvon Sun.com oder Blackdown.org erhältlich.
+error.3d.title=Fehler mit 3d Darstellung
+error.3d=Ein Fehler ist mit der 3d Darstellung aufgetreten
index dd7bc9f9e9b15eaafb053c16c0018b372a643eec..e48b3b70c3c01a711b9f9caf5d955c1d60fe26e5 100644 (file)
@@ -4,18 +4,22 @@
 # Menu entries
 menu.file=Datei
 menu.file.open=Öffne
+menu.file.addphotos=Fötelis innätue
 menu.file.save=Speichere
-menu.file.export=KML exportiere
+menu.file.exportkml=KML exportiere
+menu.file.exportpov=POV exportiere
 menu.file.exit=Beände
 menu.edit=Editiere
 menu.edit.undo=Undo
 menu.edit.clearundo=Undo-Liste lösche
+menu.edit.editpoint=Punkt editiere
+menu.edit.editwaypointname=Waypoint Name editiere
 menu.edit.deletepoint=Punkt lösche
 menu.edit.deleterange=Spanne lösche
 menu.edit.deleteduplicates=Doppeldate lösche
 menu.edit.compress=Date komprimiere
 menu.edit.interpolate=Interpoliere
-menu.edit.reverse=Spanne umkehre
+menu.edit.reverse=Spanne umdrähie
 menu.edit.rearrange=Waypoints reorganisiere
 menu.edit.rearrange.start=Alli zum Aafang
 menu.edit.rearrange.end=Alli zum Ã„nde
@@ -63,20 +67,38 @@ dialog.openoptions.deliminfo.records=Rekords, mit
 dialog.openoptions.deliminfo.fields=Fäldere
 dialog.openoptions.deliminfo.norecords=Kei Rekords
 dialog.openoptions.tabledesc=Extrakt vom File
-dialog.openoptions.altitudeunits=Höchi Massiiheite
+dialog.openoptions.altitudeunits=Höchi Masseiheite
+dialog.jpegload.subdirectories=Subordnern au
+dialog.jpegload.progress.title=Fötelis lade
+dialog.jpegload.progress=Bitte warte während die Fötolis durägsucht werde
+dialog.jpegload.title=Fötelis glade worde
+dialog.jpegload.photoadded=Föteli isch glade worde
+dialog.jpegload.photosadded=Fötelis sin glade worde
 dialog.saveoptions.title=File speichere
 dialog.save.fieldstosave=Fälder zu speichere
 dialog.save.table.field=Fäld
 dialog.save.table.hasdata=Het Date
 dialog.save.table.save=Speichere
+dialog.save.headerrow=Titel Ziile speichere
 dialog.save.coordinateunits=Koordinate Massiiheite
 dialog.save.units.original=Original
 dialog.save.altitudeunits=Höchi Massiiheite
 dialog.save.oktitle=File gespeichert worde
 dialog.save.ok1=Es isch
 dialog.save.ok2=Punkte gespeichert worde na
+dialog.save.overwrite.title=s'File existiert scho
+dialog.save.overwrite.text=s'File existiert scho. Sind Sie sicher, Sie wend s'File Ã¼berschriibe?
 dialog.exportkml.title=KML exportiere
 dialog.exportkml.text=Kurze Beschriibig von den Date
+dialog.exportkml.filetype=KML Dateie
+dialog.exportpov.title=POV exportiere
+dialog.exportpov.text=Gäbet Sie die Parameter ii fürs POV Export
+dialog.exportpov.font=Font
+dialog.exportpov.camerax=Kamera X
+dialog.exportpov.cameray=Kamera Y
+dialog.exportpov.cameraz=Kamera Z
+dialog.exportpov.filetype=POV Dateie
+dialog.exportpov.warningtracksize=Dieser Track hät sehr viele Punkte, die Java3D villiicht nöd chann bearbeite.\nSind Sie sicher, Sie wend trotzdem fortsetze?
 dialog.confirmreversetrack.title=Umdrehig bestätige
 dialog.confirmreversetrack.text=Diese Daten enthalte Ziitstämpel Informatione, die bei dr Umkehrig usser Reihefolge erschiene würdi.\nSind Sie sicher, Sie wend diese Spanne umkehre?
 dialog.interpolate.title=Punkte interpoliere
@@ -90,12 +112,29 @@ dialog.undo.none.title=Undo n
 dialog.undo.none.text=Keini Operatione könne rückgängig gmacht werde.
 dialog.clearundo.title=Undo-Liste lösche
 dialog.clearundo.text=Sind Sie sicher, Sie wend die Undo-Liste lösche?\nAlle Undo Infos werdet verlore gah!
-dialog.about.title=Ãœber
+dialog.pointedit.title=Punkt editiere
+dialog.pointedit.text=Wählet Sie jäden Fäld uus zu editiere, und mitem 'Editiere' Chnopf den Wert Ã¤ndere
+dialog.pointedit.table.field=Fäld
+dialog.pointedit.table.value=Wert
+dialog.pointedit.table.changed=Geändert
+dialog.pointedit.changevalue.text=Gebet Sie den neuen Wert für diesen Fäld ina
+dialog.pointedit.changevalue.title=Fäld editiere
+dialog.pointnameedit.title=Waypoint Name editiere
+dialog.pointnameedit.name=Waypoint Name
+dialog.pointnameedit.uppercase=GROSS gschriebe
+dialog.pointnameedit.lowercase=chli gschriebe
+dialog.pointnameedit.sentencecase=Gmischt gschriebe
+dialog.about.title=Ãœber Prune
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=Prune isch n Programm fürs Lade, Darstelle und Editiere vo Date von GPS Geräte.
 dialog.about.summarytext2=Es isch unter den Gnu GPL zur Verfüegig gstellt,für frei, gratis und offen Gebruuch und Wiiterentwicklig.<br>Kopiere, Wiiterverbreitig und Veränderige sin erlaubt und willkommen<br>unter die Bedingunge im enthaltene <code>license.txt</code> File.
 dialog.about.summarytext3=Bitte lueg na <code style="font-weight:bold">http://activityworkshop.net/</code> für wiitere Information und Benutzeraaleitige.
+dialog.about.translatedby=Schwiizerdüütschi Ãœbersetzig vo activityworkshop.
+
+# 3d window
+dialog.3d.title=Prune Drüü-d aasicht
+dialog.3d.altitudecap=Minimum Höhenskala
 
 # Buttons
 button.ok=OK
@@ -103,13 +142,17 @@ button.back=Zrugg
 button.next=Nöchste
 button.finish=Fertig
 button.cancel=Abbräche
+button.overwrite=Ãœberschriibe
 button.moveup=Uufwärts move
 button.movedown=Abwärts move
 button.startrange=Start setze
 button.endrange=Stopp setze
 button.deletepoint=Punkt lösche
 button.deleterange=Spanne lösche
+button.edit=Editiere
 button.exit=Beände
+button.close=Schliesse
+button.continue=Fortsetze
 
 # Display components
 display.nodata=Kei Date glade worde
@@ -123,6 +166,7 @@ details.pointdetails=Details vom Punkt
 details.index.selected=Index
 details.index.of=vo
 details.nopointselection=Nüüt selektiert
+details.photofile=Föteli Datei
 details.norangeselection=Nüüt selektiert
 details.rangedetails=Details vo dr Spanne
 details.range.selected=Selektiert
@@ -135,6 +179,8 @@ display.range.time.secs=S
 display.range.time.mins=M
 display.range.time.hours=Std
 display.range.time.days=T
+details.waypointsphotos.waypoints=Waypoints
+details.waypointsphotos.photos=Fötelis
 
 # Field names
 fieldname.latitude=Breitegrad
@@ -162,8 +208,16 @@ units.degminsec=Grad-Min-Sek
 units.degmin=Grad-Min
 units.deg=Grad
 
+# Cardinals for 3d plots
+cardinal.n=N
+cardinal.s=S
+cardinal.e=O
+cardinal.w=W
+
 # Undo operations
 undo.load=Date lade
+undo.loadphotos=Fötelis lade
+undo.editpoint=Punkt editiere
 undo.deletepoint=Punkt lösche
 undo.deleterange=Spanne lösche
 undo.compress=Track komprimiere
@@ -175,13 +229,20 @@ undo.rearrangewaypoints=Waypoints reorganisiere
 # Error messages
 error.save.dialogtitle=Fehler bim Speichere
 error.save.nodata=Kei Date zum speichere
-error.save.fileexists=File existiert scho.  Um sicher z'sii, wird s'Programm s'File nöd Ã¼berschriibe.
 error.save.failed=Speichere vom File fehlgschlage :
 error.load.dialogtitle=Fehler bim Lade
 error.load.noread=File cha nöd glase werde
-error.undofailed.title=Undo isch fehlgschlage
+error.jpegload.dialogtitle=Fehler bim Lade von Fötelis
+error.jpegload.nofilesfound=Kei Dateie gfunde
+error.jpegload.nojpegsfound=Kei Jpegs gfunde
+error.jpegload.noexiffound=Kei EXIF Information gfunde
+error.jpegload.nogpsfound=Kei GPS Information gfunde
+error.undofailed.title=Undo isch fehlgschlage worde
 error.undofailed.text=Operation kann nöd rückgängig gmacht werde
 error.function.noop.title=Funktion hät gar nüüt gmacht
 error.rearrange.noop=Waypoints Reorganisiere hät kein Effäkt gha
-error.function.notimplemented.title=Funktion nöd verfüegbar
 error.function.notimplemented=Sorry, d'Funktion isch nonig implementiert worde.
+error.function.notavailable.title=Funktion nöd verfüegbar
+error.function.nojava3d=Sorry, d'Funktion brucht d Java3d Library,\nvo Sun.com odr Blackdown.org erhältlech.
+error.3d.title=Fähler mitm 3d Darstellig
+error.3d=N Fähler isch mitm 3d Darstellig ufgtrete
index fc788d2ad8c1b6720e56c8f538e81baa46551539..4437095b128bfe04cadabbf4068fc84d896fac01 100644 (file)
@@ -1,4 +1,4 @@
-Prune version 1
+Prune version 2
 ===============
 
 Prune is an application for viewing, editing and managing coordinate data from GPS systems.
@@ -14,8 +14,8 @@ losses incurred through use of the program, however caused.
 Running
 =======
 
-To run Prune from the jar file, simply call it from a Command Prompt or shell:
-   java -jar prune_1.jar
+To run Prune from the jar file, simply call it from a command prompt or shell:
+   java -jar prune_02.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
@@ -23,6 +23,16 @@ in a file manager window to execute it.  A shortcut, menu item, desktop icon or
 can of course be made should you wish.
 
 
+Updates since version 1
+=======================
+
+The following features were added since version 1:
+  - Display of data in 3d view using Java3D library
+  - Export of 3d model to POV format for rendering by povray
+  - Point edit dialog, waypoint name edit dialog
+  - Waypoint list
+
+
 Further information and updates
 ===============================
 
index b1ea368c03678f1b535a49ad146acabee97e9be3..f5f92bcc91af9ba6aec94e26877400b0bc4598c2 100644 (file)
@@ -17,6 +17,7 @@ import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
 import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JDialog;
 import javax.swing.JFileChooser;
 import javax.swing.JFrame;
@@ -56,6 +57,7 @@ public class FileSaver
        private JButton _moveUpButton = null, _moveDownButton = null;
        private JRadioButton[] _delimiterRadios = null;
        private JTextField _otherDelimiterText = null;
+       private JCheckBox _headerRowCheckbox = null;
        private JRadioButton[] _coordUnitsRadios = null;
        private JRadioButton[] _altitudeUnitsRadios = null;
        private static final int[] FORMAT_COORDS = {Coordinate.FORMAT_NONE, Coordinate.FORMAT_DEG_MIN_SEC,
@@ -214,6 +216,12 @@ public class FileSaver
                }
                delimsPanel.add(otherPanel);
                firstCard.add(delimsPanel);
+
+               // header checkbox
+               firstCard.add(Box.createRigidArea(new Dimension(0,10)));
+               _headerRowCheckbox = new JCheckBox(I18nManager.getText("dialog.save.headerrow"));
+               firstCard.add(_headerRowCheckbox);
+
                _cards.add(firstCard, "card1");
 
                JPanel secondCard = new JPanel();
@@ -260,6 +268,7 @@ public class FileSaver
                }
                altUnitsPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
                secondCardHolder.add(altUnitsPanel);
+               // TODO: selection of format of timestamps
                secondCard.add(secondCardHolder, BorderLayout.NORTH);
                _cards.add(secondCard, "card2");
 
@@ -270,10 +279,10 @@ public class FileSaver
                _backButton.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                           CardLayout cl = (CardLayout)(_cards.getLayout());
-                           cl.previous(_cards);
-                           _backButton.setEnabled(false);
-                           _nextButton.setEnabled(true);
+                               CardLayout cl = (CardLayout)(_cards.getLayout());
+                               cl.previous(_cards);
+                               _backButton.setEnabled(false);
+                               _nextButton.setEnabled(true);
                        }
                });
                _backButton.setEnabled(false);
@@ -283,10 +292,10 @@ public class FileSaver
                _nextButton.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                           CardLayout cl = (CardLayout)(_cards.getLayout());
-                           cl.next(_cards);
-                           _backButton.setEnabled(true);
-                           _nextButton.setEnabled(false);
+                               CardLayout cl = (CardLayout)(_cards.getLayout());
+                               cl.next(_cards);
+                               _backButton.setEnabled(true);
+                               _nextButton.setEnabled(false);
                        }
                });
                buttonPanel.add(_nextButton);
@@ -336,11 +345,20 @@ public class FileSaver
                                        coordFormat = FORMAT_COORDS[i];
                        int altitudeFormat = Altitude.FORMAT_NONE;
                        for (int i=0; i<_altitudeUnitsRadios.length; i++)
+                       {
                                if (_altitudeUnitsRadios[i].isSelected())
+                               {
                                        altitudeFormat = FORMAT_ALTS[i];
-                       
-                       // Check if file exists, don't overwrite any files for v1!
-                       if (!saveFile.exists())
+                               }
+                       }
+
+                       // Check if file exists, and confirm overwrite if necessary
+                       Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
+                       if (!saveFile.exists() || JOptionPane.showOptionDialog(_parentFrame,
+                                       I18nManager.getText("dialog.save.overwrite.text"),
+                                       I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
+                                       JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
+                               == JOptionPane.YES_OPTION)
                        {
                                try
                                {
@@ -350,14 +368,39 @@ public class FileSaver
                                        char delimiter = getDelimiter();
                                        FieldInfo info = null;
                                        Field field = null;
+
                                        StringBuffer buffer = null;
-                                       // For now, just spit out to console
-                                       int numPoints = _track.getNumPoints();
                                        int numFields = _model.getRowCount();
+                                       boolean firstField = true;
+                                       // Write header row if required
+                                       if (_headerRowCheckbox.isSelected())
+                                       {
+                                               buffer = new StringBuffer();
+                                               for (int f=0; f<numFields; f++)
+                                               {
+                                                       info = _model.getFieldInfo(f);
+                                                       if (info.isSelected())
+                                                       {
+                                                               if (!firstField)
+                                                               {
+                                                                       // output field separator
+                                                                       buffer.append(delimiter);
+                                                               }
+                                                               field = info.getField();
+                                                               buffer.append(field.getName());
+                                                               firstField = false;
+                                                       }
+                                               }
+                                               writer.write(buffer.toString());
+                                               writer.write(lineSeparator);
+                                       }
+
+                                       // Loop over points outputting each in turn to buffer
+                                       int numPoints = _track.getNumPoints();
                                        for (int p=0; p<numPoints; p++)
                                        {
                                                DataPoint point = _track.getPoint(p);
-                                               boolean firstField = true;
+                                               firstField = true;
                                                buffer = new StringBuffer();
                                                for (int f=0; f<numFields; f++)
                                                {
@@ -381,11 +424,19 @@ public class FileSaver
                                                                }
                                                                else if (field == Field.ALTITUDE)
                                                                {
-                                                                       buffer.append(point.getAltitude().getValue(altitudeFormat));
+                                                                       try
+                                                                       {
+                                                                               buffer.append(point.getAltitude().getValue(altitudeFormat));
+                                                                       }
+                                                                       catch (NullPointerException npe) {}
                                                                }
                                                                else if (field == Field.TIMESTAMP)
                                                                {
-                                                                       buffer.append(point.getTimestamp().getText());
+                                                                       try
+                                                                       {
+                                                                               buffer.append(point.getTimestamp().getText());
+                                                                       }
+                                                                       catch (NullPointerException npe) {}
                                                                }
                                                                else
                                                                {
@@ -405,7 +456,7 @@ public class FileSaver
                                        // Save successful
                                        JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.ok1")
                                                 + " " + numPoints + " " + I18nManager.getText("dialog.save.ok2")
-                                                + saveFile.getAbsolutePath(),
+                                                + " " + saveFile.getAbsolutePath(),
                                                I18nManager.getText("dialog.save.oktitle"), JOptionPane.INFORMATION_MESSAGE);
                                        _app.informDataSaved();
                                }
@@ -432,9 +483,8 @@ public class FileSaver
                        }
                        else
                        {
+                               // Overwrite file confirm cancelled
                                saveOK = false;
-                               JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.save.fileexists"),
-                                       I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
                        }
                }
                return saveOK;
index 6c95b4c5163c6908a536431429792716698f66ab..16624ad1495dd26c549a0af26a3c087fbb0364c7 100644 (file)
@@ -14,7 +14,6 @@ import tim.prune.App;
 import tim.prune.I18nManager;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
-import tim.prune.data.Field;
 import tim.prune.data.Track;
 
 /**
@@ -53,6 +52,7 @@ public class KmlExporter
                        I18nManager.getText("dialog.exportkml.text"),
                        I18nManager.getText("dialog.exportkml.title"),
                        JOptionPane.QUESTION_MESSAGE, null, null, "");
+               // TODO: Make dialog window including colour selection, line width, track description
                if (description != null)
                {
                        // OK pressed, so choose output file
@@ -66,7 +66,7 @@ public class KmlExporter
                                }
                                public String getDescription()
                                {
-                                       return "KML files";
+                                       return I18nManager.getText("dialog.exportkml.filetype");
                                }
                        });
                        _fileChooser.setAcceptAllFileFilterUsed(false);
@@ -83,14 +83,13 @@ public class KmlExporter
                                        {
                                                file = new File(file.getAbsolutePath() + ".kml");
                                        }
-                                       // Check if file exists - if so don't overwrite
-                                       if (file.exists())
-                                       {
-                                               JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.save.fileexists"),
-                                                       I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
-                                               chooseAgain = true;
-                                       }
-                                       else
+                                       // Check if file exists and if necessary prompt for overwrite
+                                       Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
+                                       if (!file.exists() || JOptionPane.showOptionDialog(_parentFrame,
+                                                       I18nManager.getText("dialog.save.overwrite.text"),
+                                                       I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
+                                                       JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
+                                               == JOptionPane.YES_OPTION)
                                        {
                                                if (exportFile(file, description.toString()))
                                                {
@@ -101,6 +100,10 @@ public class KmlExporter
                                                        chooseAgain = true;
                                                }
                                        }
+                                       else
+                                       {
+                                               chooseAgain = true;
+                                       }
                                }
                        } while (chooseAgain);
                }
@@ -115,9 +118,10 @@ public class KmlExporter
         */
        private boolean exportFile(File inFile, String inDescription)
        {
+               FileWriter writer = null;
                try
                {
-                       FileWriter writer = new FileWriter(inFile);
+                       writer = new FileWriter(inFile);
                        writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<kml xmlns=\"http://earth.google.com/kml/2.1\">\n<Folder>\n");
                        writer.write("\t<name>");
                        writer.write(inDescription);
@@ -127,6 +131,7 @@ public class KmlExporter
                        DataPoint point = null;
                        boolean hasTrackpoints = false;
                        // Loop over waypoints
+                       boolean writtenPhotoHeader = false;
                        int numPoints = _track.getNumPoints();
                        for (i=0; i<numPoints; i++)
                        {
@@ -135,6 +140,15 @@ public class KmlExporter
                                {
                                        exportWaypoint(point, writer);
                                }
+                               else if (point.getPhoto() != null)
+                               {
+                                       if (!writtenPhotoHeader)
+                                       {
+                                               writer.write("<Style id=\"camera_icon\"><IconStyle><Icon><href>http://maps.google.com/mapfiles/kml/pal4/icon46.png</href></Icon></IconStyle></Style>");
+                                               writtenPhotoHeader = true;
+                                       }
+                                       exportPhotoPoint(point, writer);
+                               }
                                else
                                {
                                        hasTrackpoints = true;
@@ -160,12 +174,16 @@ public class KmlExporter
                        writer.close();
                        JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.ok1")
                                 + " " + numPoints + " " + I18nManager.getText("dialog.save.ok2")
-                                + inFile.getAbsolutePath(),
+                                + " " + inFile.getAbsolutePath(),
                                I18nManager.getText("dialog.save.oktitle"), JOptionPane.INFORMATION_MESSAGE);
                        return true;
                }
                catch (IOException ioe)
                {
+                       try {
+                               if (writer != null) writer.close();
+                       }
+                       catch (IOException ioe2) {}
                        JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.save.failed") + ioe.getMessage(),
                                I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
                }
@@ -177,12 +195,34 @@ public class KmlExporter
         * Export the specified waypoint into the file
         * @param inPoint waypoint to export
         * @param inWriter writer object
+        * @throws IOException on write failure
         */
        private void exportWaypoint(DataPoint inPoint, Writer inWriter) throws IOException
        {
                inWriter.write("\t<Placemark>\n\t\t<name>");
-               inWriter.write(inPoint.getFieldValue(Field.WAYPT_NAME).trim());
+               inWriter.write(inPoint.getWaypointName().trim());
+               inWriter.write("</name>\n");
+               inWriter.write("\t\t<Point>\n\t\t\t<coordinates>");
+               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(',');
+               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(",0</coordinates>\n\t\t</Point>\n\t</Placemark>\n");
+       }
+
+
+       /**
+        * Export the specified photo into the file
+        * @param inPoint data point including photo
+        * @param inWriter writer object
+        * @throws IOException on write failure
+        */
+       private void exportPhotoPoint(DataPoint inPoint, Writer inWriter) throws IOException
+       {
+               // TODO: Export photos to KML too - for photos need kmz!
+               inWriter.write("\t<Placemark>\n\t\t<name>");
+               inWriter.write(inPoint.getPhoto().getFile().getName());
                inWriter.write("</name>\n");
+               inWriter.write("<styleUrl>#camera_icon</styleUrl>\n");
                inWriter.write("\t\t<Point>\n\t\t\t<coordinates>");
                inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
                inWriter.write(',');
index ebc4d89c9fcdf236448ea78caac40540f1b652c0..4cc09b47f23aa752b1b362f515d1c27acb562bf5 100644 (file)
@@ -2,7 +2,6 @@ package tim.prune.undo;
 \r
 import tim.prune.I18nManager;\r
 import tim.prune.data.DataPoint;\r
-import tim.prune.data.Field;\r
 import tim.prune.data.TrackInfo;\r
 \r
 /**\r
@@ -32,7 +31,7 @@ public class UndoDeletePoint implements UndoOperation
        public String getDescription()\r
        {\r
                String desc = I18nManager.getText("undo.deletepoint");\r
-               String pointName = _point.getFieldValue(Field.WAYPT_NAME);\r
+               String pointName = _point.getWaypointName();\r
                if (pointName != null && !pointName.equals(""))\r
                        desc = desc + " " + pointName;\r
                return desc;\r
@@ -50,5 +49,6 @@ public class UndoDeletePoint implements UndoOperation
                {\r
                        throw new UndoException(getDescription());\r
                }\r
+               // TODO: Reinsert photo into list if necessary\r
        }\r
 }
\ No newline at end of file