package tim.prune;
import java.util.EmptyStackException;
+import java.util.List;
import java.util.Stack;
import javax.swing.JFrame;
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;
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;
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
}
+ /**
+ * 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
*/
}
+ /**
+ * 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
*/
}
+ /**
+ * 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
*/
*/
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);
+ }
+ }
}
}
+ /**
+ * 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
*/
*/
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);
}
*/
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;
* 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);
}
}
}
*/
public int getValue(int inFormat)
{
+ // TODO: Fix rounding errors here converting between units - return double?
if (inFormat == _format)
return _value;
if (inFormat == FORMAT_METRES)
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
* 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
_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;
}
// 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('°')
.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;
*/
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
_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];
}
+ /**
+ * 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;
{
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
*/
{
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
*/
// 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;
+ }
}
return inAngDist * EARTH_RADIUS_KM;
}
-
-
}
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
}
+ /**
+ * 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
*/
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
* @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);
}
* @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);
}
*/
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();
package tim.prune.data;
+import java.util.List;
+
import tim.prune.UpdateMessageBroker;
+import tim.prune.edit.FieldEdit;
+import tim.prune.edit.FieldEditList;
/**
*/
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
return true;
}
+ // TODO: Need to rearrange photo points too?
/**
* Interpolate extra points between two selected ones
// 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();
}
}
+ /**
+ * 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 ////////////////
_longRange.addValue(point.getLongitude().getDouble());
_latRange.addValue(point.getLatitude().getDouble());
if (point.getAltitude().isValid())
+ {
_altitudeRange.addValue(point.getAltitude());
+ }
if (point.isWaypoint())
hasWaypoint = true;
else
_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;
+ }
}
package tim.prune.data;
+import java.util.List;
+
import tim.prune.UpdateMessageBroker;
/**
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
_track = inTrack;
_selection = new Selection(_track, inBroker);
_fileInfo = new FileInfo();
+ _photoList = new PhotoList();
}
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
}
+ /**
+ * 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();
{
if (_track.deletePoint(_selection.getCurrentPointIndex()))
{
+ // TODO: Check whether to delete photo associated with this point
_selection.modifyPointDeleted();
_broker.informSubscribers();
return true;
_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);
+ }
}
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"));
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;
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;
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
trackDetailsPanel.add(_trackpointsLabel);
_filenameLabel = new JLabel("");
trackDetailsPanel.add(_filenameLabel);
-
+
// Point details panel
JPanel pointDetailsPanel = new JPanel();
pointDetailsPanel.setLayout(new BoxLayout(pointDetailsPanel, BoxLayout.Y_AXIS));
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);
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));
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();
_unitsDropdown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
- dataUpdated();
+ dataUpdated(DataSubscriber.UNITS_CHANGED);
}
});
lowerPanel.add(_unitsDropdown);
}
+ /**
+ * 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)
_longLabel.setText("");
_altLabel.setText("");
_timeLabel.setText("");
+ _photoFileLabel.setText("");
_nameLabel.setText("");
}
else
_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);
_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();
+ }
+ }
}
/**
* Method to inform map that data has changed
*/
- public void dataUpdated()
+ public void dataUpdated(byte inUpdateType)
{
repaint();
}
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;
/**
* 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);
}
// 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;
}
}
+ // Draw rectangle for dragging zoom area
if (_zoomDragging)
{
g.setColor(COLOR_CROSSHAIRS);
g.drawLine(_zoomDragToX, _zoomDragFromY, _zoomDragToX, _zoomDragToY);
g.drawLine(_zoomDragFromX, _zoomDragToY, _zoomDragToX, _zoomDragToY);
}
+
+ // Attempt to grab keyboard focus if possible
+ this.requestFocus();
}
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);
_offsetX = 0.0;
_offsetY = 0.0;
_numPoints = 0;
- dataUpdated();
+ dataUpdated(DataSubscriber.ALL);
}
if (_zoomScale < 0.5) _zoomScale = 0.5;
}
_numPoints = 0;
- dataUpdated();
+ dataUpdated(DataSubscriber.ALL);
}
_offsetX = _offsetX - (inRight * panFactor);
// Limit pan to sensible range??
_numPoints = 0;
- dataUpdated();
+ _image = null;
+ repaint();
}
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
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;
+ }
}
}
// 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;
{
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() {
}
});
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)
_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() {
_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)
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"));
}
- /**
- * @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());
_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());
# 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
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?
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
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
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
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
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
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
# 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
# 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
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
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
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
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
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
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
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
# 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
# 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
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
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
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
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
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
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
# 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
-Prune version 1
+Prune version 2
===============
Prune is an application for viewing, editing and managing coordinate data from GPS systems.
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
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
===============================
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;
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,
}
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();
}
altUnitsPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
secondCardHolder.add(altUnitsPanel);
+ // TODO: selection of format of timestamps
secondCard.add(secondCardHolder, BorderLayout.NORTH);
_cards.add(secondCard, "card2");
_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);
_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);
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
{
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++)
{
}
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
{
// 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();
}
}
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;
import tim.prune.I18nManager;
import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
-import tim.prune.data.Field;
import tim.prune.data.Track;
/**
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
}
public String getDescription()
{
- return "KML files";
+ return I18nManager.getText("dialog.exportkml.filetype");
}
});
_fileChooser.setAcceptAllFileFilterUsed(false);
{
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()))
{
chooseAgain = true;
}
}
+ else
+ {
+ chooseAgain = true;
+ }
}
} while (chooseAgain);
}
*/
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);
DataPoint point = null;
boolean hasTrackpoints = false;
// Loop over waypoints
+ boolean writtenPhotoHeader = false;
int numPoints = _track.getNumPoints();
for (i=0; i<numPoints; i++)
{
{
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;
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);
}
* 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(',');
\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
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
{\r
throw new UndoException(getDescription());\r
}\r
+ // TODO: Reinsert photo into list if necessary\r
}\r
}
\ No newline at end of file