]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/data/TrackInfo.java
Version 14, October 2012
[GpsPrune.git] / tim / prune / data / TrackInfo.java
index 4695d351e6c124c398e0df90c911dbe0583c4dbe..7bcbc641e75fcae730f07178d5ad93637486145c 100644 (file)
@@ -1,7 +1,6 @@
 package tim.prune.data;
 
-import java.util.List;
-
+import java.util.Set;
 import tim.prune.UpdateMessageBroker;
 
 /**
@@ -10,34 +9,31 @@ import tim.prune.UpdateMessageBroker;
  */
 public class TrackInfo
 {
-       private UpdateMessageBroker _broker = null;
        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;
+       private AudioList _audioList = null;
 
 
        /**
         * Constructor
         * @param inTrack Track object
-        * @param inBroker broker object
         */
-       public TrackInfo(Track inTrack, UpdateMessageBroker inBroker)
+       public TrackInfo(Track inTrack)
        {
-               _broker = inBroker;
                _track = inTrack;
-               _selection = new Selection(_track, inBroker);
+               _selection = new Selection(_track);
                _fileInfo = new FileInfo();
                _photoList = new PhotoList();
+               _audioList = new AudioList();
        }
 
 
        /**
         * @return the Track object
         */
-       public Track getTrack()
-       {
+       public Track getTrack() {
                return _track;
        }
 
@@ -45,8 +41,7 @@ public class TrackInfo
        /**
         * @return the Selection object
         */
-       public Selection getSelection()
-       {
+       public Selection getSelection() {
                return _selection;
        }
 
@@ -54,110 +49,141 @@ public class TrackInfo
        /**
         * @return the FileInfo object
         */
-       public FileInfo getFileInfo()
-       {
+       public FileInfo getFileInfo() {
                return _fileInfo;
        }
 
+       /**
+        * Replace the file info with a previously made clone
+        * @param inInfo cloned file info
+        */
+       public void setFileInfo(FileInfo inInfo) {
+               _fileInfo = inInfo;
+       }
+
        /**
         * @return the PhotoList object
         */
-       public PhotoList getPhotoList()
-       {
+       public PhotoList getPhotoList() {
                return _photoList;
        }
 
+       /**
+        * @return the AudioList object
+        */
+       public AudioList getAudioList() {
+               return _audioList;
+       }
+
        /**
         * Get the currently selected point, if any
         * @return DataPoint if single point selected, otherwise null
         */
-       public DataPoint getCurrentPoint()
-       {
+       public DataPoint getCurrentPoint() {
                return _track.getPoint(_selection.getCurrentPointIndex());
        }
 
+       /**
+        * Get the currently selected photo, if any
+        * @return Photo if selected, otherwise null
+        */
+       public Photo getCurrentPhoto() {
+               return _photoList.getPhoto(_selection.getCurrentPhotoIndex());
+       }
 
        /**
-        * Load the specified data into the Track
-        * @param inFieldArray array of Field objects describing fields
-        * @param inPointArray 2d object array containing data
-        * @param inAltFormat altitude format
+        * Get the currently selected audio clip, if any
+        * @return AudioClip if selected, otherwise null
         */
-       public void loadTrack(Field[] inFieldArray, Object[][] inPointArray, int inAltFormat)
-       {
-               _track.cropTo(0);
-               _track.load(inFieldArray, inPointArray, inAltFormat);
-               _selection.clearAll();
+       public AudioClip getCurrentAudio() {
+               return _audioList.getAudio(_selection.getCurrentAudioIndex());
        }
 
 
        /**
-        * Add a List of Photos
-        * @param inList List containing Photo objects
-        * @return number of photos added
+        * Add a Set of Photos
+        * @param inSet Set containing Photo objects
+        * @return array containing number of photos and number of points added
         */
-       public int addPhotos(List inList)
+       public int[] addPhotos(Set<Photo> inSet)
        {
-               // Firstly count number to add to make array
+               // Firstly count number of points and photos to add
                int numPhotosToAdd = 0;
-               if (inList != null && !inList.isEmpty())
+               int numPointsToAdd = 0;
+               if (inSet != null && !inSet.isEmpty())
                {
-                       for (int i=0; i<inList.size(); i++)
+                       for (Photo photo : inSet)
                        {
-                               try
+                               if (photo != null && !_photoList.contains(photo))
                                {
-                                       Photo photo = (Photo) inList.get(i);
-                                       if (photo != null && !_photoList.contains(photo))
-                                       {
-                                               numPhotosToAdd++;
+                                       numPhotosToAdd++;
+                                       if (photo.getDataPoint() != null) {
+                                               numPointsToAdd++;
                                        }
                                }
-                               catch (ClassCastException ce) {}
                        }
                }
                // If there are any photos to add, add them
                if (numPhotosToAdd > 0)
                {
-                       DataPoint[] dataPoints = new DataPoint[numPhotosToAdd];
+                       DataPoint[] dataPoints = new DataPoint[numPointsToAdd];
                        int pointNum = 0;
+                       boolean hasAltitude = false;
                        // Add each Photo in turn
-                       for (int i=0; i<inList.size(); i++)
+                       for (Photo photo : inSet)
                        {
-                               try
+                               if (photo != null && !_photoList.contains(photo))
                                {
-                                       Photo photo = (Photo) inList.get(i);
-                                       if (photo != null && !_photoList.contains(photo))
+                                       // Add photo
+                                       _photoList.addPhoto(photo);
+                                       // Add point if there is one
+                                       if (photo.getDataPoint() != null)
                                        {
-                                               _photoList.addPhoto(photo);
                                                dataPoints[pointNum] = photo.getDataPoint();
+                                               // Check if any points have altitudes
+                                               hasAltitude |= (photo.getDataPoint().getAltitude() != null);
                                                pointNum++;
                                        }
                                }
-                               catch (ClassCastException ce) {}
                        }
-                       _track.appendPoints(dataPoints);
+                       if (numPointsToAdd > 0)
+                       {
+                               // add points to track
+                               _track.appendPoints(dataPoints);
+                               // modify track field list
+                               _track.getFieldList().extendList(Field.LATITUDE);
+                               _track.getFieldList().extendList(Field.LONGITUDE);
+                               if (hasAltitude) {_track.getFieldList().extendList(Field.ALTITUDE);}
+                       }
                }
-               return numPhotosToAdd;
+               int[] result = {numPhotosToAdd, numPointsToAdd};
+               return result;
        }
 
-
        /**
-        * Delete the currently selected range of points
-        * @return true if successful
+        * Add a Set of Audio objects
+        * @param inSet Set containing Audio objects
+        * @return number of audio objects added
         */
-       public boolean deleteRange()
+       public int addAudios(Set<AudioClip> inSet)
        {
-               // TODO: Check whether to delete photos associated with this range
-               int currPoint = _selection.getCurrentPointIndex();
-               int startSel = _selection.getStart();
-               int endSel = _selection.getEnd();
-               boolean answer = _track.deleteRange(startSel, endSel);
-               // clear range selection
-               _selection.modifyRangeDeleted();
-               return answer;
+               int numAudiosAdded = 0;
+               if (inSet != null && !inSet.isEmpty())
+               {
+                       for (AudioClip audio : inSet)
+                       {
+                               if (audio != null && !_audioList.contains(audio))
+                               {
+                                       // Add audio object
+                                       _audioList.addAudio(audio);
+                                       numAudiosAdded++;
+                                       // audio objects never have points when they're loaded
+                               }
+                       }
+               }
+               return numAudiosAdded;
        }
 
-
        /**
         * Delete the currently selected point
         * @return true if point deleted
@@ -166,9 +192,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;
                }
                return false;
@@ -176,28 +200,87 @@ public class TrackInfo
 
 
        /**
-        * Compress the track to the given resolution
-        * @param inResolution resolution
-        * @return number of points deleted
+        * Delete the currently selected photo and optionally its point too
+        * @param inPointToo true to also delete associated point
+        * @return true if delete successful
         */
-       public int compress(int inResolution)
+       public boolean deleteCurrentPhoto(boolean inPointToo)
        {
-               int numDeleted = _track.compress(inResolution);
-               if (numDeleted > 0)
-                       _selection.clearAll();
-               return numDeleted;
+               int photoIndex = _selection.getCurrentPhotoIndex();
+               if (photoIndex >= 0)
+               {
+                       Photo photo = _photoList.getPhoto(photoIndex);
+                       _photoList.deletePhoto(photoIndex);
+                       // has it got a point?
+                       if (photo.getDataPoint() != null)
+                       {
+                               if (inPointToo)
+                               {
+                                       // delete point
+                                       int pointIndex = _track.getPointIndex(photo.getDataPoint());
+                                       _track.deletePoint(pointIndex);
+                               }
+                               else
+                               {
+                                       // disconnect point from photo
+                                       photo.getDataPoint().setPhoto(null);
+                                       photo.setDataPoint(null);
+                               }
+                       }
+                       // update subscribers
+                       _selection.modifyPointDeleted();
+                       UpdateMessageBroker.informSubscribers();
+               }
+               return true;
+       }
+
+       /**
+        * Delete the currently selected audio item and optionally its point too
+        * @param inPointToo true to also delete associated point
+        * @return true if delete successful
+        */
+       public boolean deleteCurrentAudio(boolean inPointToo)
+       {
+               int audioIndex = _selection.getCurrentAudioIndex();
+               if (audioIndex >= 0)
+               {
+                       AudioClip audio = _audioList.getAudio(audioIndex);
+                       _audioList.deleteAudio(audioIndex);
+                       // has it got a point?
+                       if (audio.getDataPoint() != null)
+                       {
+                               if (inPointToo)
+                               {
+                                       // delete point
+                                       int pointIndex = _track.getPointIndex(audio.getDataPoint());
+                                       _track.deletePoint(pointIndex);
+                               }
+                               else
+                               {
+                                       // disconnect point from audio
+                                       audio.getDataPoint().setAudio(null);
+                                       audio.setDataPoint(null);
+                               }
+                       }
+                       // update subscribers
+                       _selection.modifyPointDeleted();
+                       UpdateMessageBroker.informSubscribers();
+               }
+               return true;
        }
 
 
        /**
-        * Delete all the duplicate points in the track
+        * Delete all the points which have been marked for deletion
         * @return number of points deleted
         */
-       public int deleteDuplicates()
+       public int deleteMarkedPoints()
        {
-               int numDeleted = _track.deleteDuplicates();
-               if (numDeleted > 0)
+               int numDeleted = _track.deleteMarkedPoints();
+               if (numDeleted > 0) {
                        _selection.clearAll();
+                       UpdateMessageBroker.informSubscribers();
+               }
                return numDeleted;
        }
 
@@ -211,18 +294,43 @@ public class TrackInfo
                return _track.cloneRange(_selection.getStart(), _selection.getEnd());
        }
 
+       /**
+        * Merge the track segments within the given range
+        * @param inStart start index
+        * @param inEnd end index
+        * @return true if successful
+        */
+       public boolean mergeTrackSegments(int inStart, int inEnd)
+       {
+               boolean firstTrackPoint = true;
+               // Loop between start and end
+               for (int i=inStart; i<=inEnd; i++) {
+                       DataPoint point = _track.getPoint(i);
+                       // Set all segments to false apart from first track point
+                       if (point != null && !point.isWaypoint()) {
+                               point.setSegmentStart(firstTrackPoint);
+                               firstTrackPoint = false;
+                       }
+               }
+               // Find following track point, if any
+               DataPoint nextPoint = _track.getNextTrackPoint(inEnd+1);
+               if (nextPoint != null) {nextPoint.setSegmentStart(true);}
+               _selection.markInvalid();
+               UpdateMessageBroker.informSubscribers();
+               return true;
+       }
+
 
        /**
-        * Interpolate extra points between two selected ones
-        * @param inStartIndex start index of interpolation
-        * @param inNumPoints num points to insert
+        * Average selected points to create a new one
         * @return true if successful
         */
-       public boolean interpolate(int inNumPoints)
+       public boolean average()
        {
-               boolean success = _track.interpolate(_selection.getStart(), inNumPoints);
-               if (success)
-                       _selection.selectRangeEnd(_selection.getEnd() + inNumPoints);
+               boolean success = _track.average(_selection.getStart(), _selection.getEnd());
+               if (success) {
+                       selectPoint(_selection.getEnd()+1);
+               }
                return success;
        }
 
@@ -233,9 +341,161 @@ public class TrackInfo
         */
        public void selectPoint(DataPoint inPoint)
        {
-               // get the index of the given Point
-               int index = _track.getPointIndex(inPoint);
+               selectPoint(_track.getPointIndex(inPoint));
+       }
+
+       /**
+        * Increment the selected point index by the given increment
+        * @param inPointIncrement +1 for next point, -1 for previous etc
+        */
+       public void incrementPointIndex(int inPointIncrement)
+       {
+               int index = _selection.getCurrentPointIndex() + inPointIncrement;
+               if (index < 0) index = 0;
+               else if (index >= _track.getNumPoints()) index = _track.getNumPoints()-1;
+               selectPoint(index);
+       }
+
+       /**
+        * Select the data point with the given index
+        * @param inPointIndex index of DataPoint to select, or -1 for none
+        */
+       public void selectPoint(int inPointIndex)
+       {
+               if (_selection.getCurrentPointIndex() == inPointIndex || inPointIndex >= _track.getNumPoints()) {return;}
+               DataPoint selectedPoint = _track.getPoint(inPointIndex);
+               // get the index of the current photo
+               int photoIndex = _selection.getCurrentPhotoIndex();
+               // Check if point has photo or not
+               boolean pointHasPhoto = inPointIndex >= 0 && selectedPoint.getPhoto() != null;
+               if (pointHasPhoto) {
+                       photoIndex = _photoList.getPhotoIndex(selectedPoint.getPhoto());
+               }
+               else if (photoIndex < 0 || _photoList.getPhoto(photoIndex).isConnected()) {
+                       // selected point hasn't got a photo - deselect photo if necessary
+                       photoIndex = -1;
+               }
+               // Check if point has an audio item or not
+               int audioIndex = _selection.getCurrentAudioIndex();
+               boolean pointHasAudio = inPointIndex >= 0 && selectedPoint.getAudio() != null;
+               if (pointHasAudio) {
+                       audioIndex = _audioList.getAudioIndex(selectedPoint.getAudio());
+               }
+               else if (audioIndex < 0 || _audioList.getAudio(audioIndex).isConnected()) {
+                       // deselect current audio clip
+                       audioIndex = -1;
+               }
                // give to selection
-               _selection.selectPoint(index);
+               _selection.selectPointPhotoAudio(inPointIndex, photoIndex, audioIndex);
+       }
+
+       /**
+        * Select the given Photo and its point if any
+        * @param inPhotoIndex index of photo to select
+        */
+       public void selectPhoto(int inPhotoIndex)
+       {
+               if (_selection.getCurrentPhotoIndex() == inPhotoIndex) {return;}
+               // Photo is primary selection here, not as a result of a point selection
+               // Therefore the photo selection takes priority, deselecting point if necessary
+               // Find Photo object
+               Photo photo = _photoList.getPhoto(inPhotoIndex);
+               int pointIndex = _selection.getCurrentPointIndex();
+               DataPoint currPoint = getCurrentPoint();
+               if (photo != null)
+               {
+                       // Has the photo got a point?
+                       if (photo.isConnected()) {
+                               pointIndex = _track.getPointIndex(photo.getDataPoint());
+                       }
+                       else {
+                               // Check whether to deselect current point or not if photo not correlated
+                               if (pointIndex >= 0 && _track.getPoint(pointIndex).getPhoto() != null) {
+                                       pointIndex = -1;
+                               }
+                       }
+               }
+               else {
+                       // no photo, but maybe need to deselect point
+                       if (currPoint != null && currPoint.getPhoto() != null) {
+                               pointIndex = -1;
+                       }
+               }
+               // Has the new point got an audio clip?
+               DataPoint selectedPoint = _track.getPoint(pointIndex);
+               int audioIndex = _selection.getCurrentAudioIndex();
+               if (selectedPoint != null && selectedPoint.getAudio() != null) {
+                       // New point has an audio, so select it
+                       audioIndex = _audioList.getAudioIndex(selectedPoint.getAudio());
+               }
+               else if (currPoint != null && selectedPoint != currPoint && currPoint.getAudio() != null) {
+                       // Old point had an audio, so deselect it
+                       audioIndex = -1;
+               }
+               // give to selection object
+               _selection.selectPointPhotoAudio(pointIndex, inPhotoIndex, audioIndex);
+       }
+
+       /**
+        * Select the given audio object and its point if any
+        * @param inAudioIndex index of audio item to select
+        */
+       public void selectAudio(int inAudioIndex)
+       {
+               if (_selection.getCurrentAudioIndex() == inAudioIndex) {return;}
+               // Audio selection takes priority, deselecting point if necessary
+               AudioClip audio = _audioList.getAudio(inAudioIndex);
+               int pointIndex = _selection.getCurrentPointIndex();
+               DataPoint currPoint = getCurrentPoint();
+               if (audio != null)
+               {
+                       // Find point object and its index
+                       if (audio.isConnected()) {
+                               pointIndex = _track.getPointIndex(audio.getDataPoint());
+                       }
+                       else {
+                               // Check whether to deselect current point or not if audio not correlated
+                               if (pointIndex >= 0 && _track.getPoint(pointIndex).getAudio() != null) {
+                                       pointIndex = -1;
+                               }
+                       }
+               }
+               else {
+                       // check if current point has audio or not
+                       if (currPoint != null && currPoint.getAudio() != null) {
+                               pointIndex = -1;
+                       }
+               }
+               // Has the new point got a photo?
+               DataPoint selectedPoint = _track.getPoint(pointIndex);
+               int photoIndex = _selection.getCurrentPhotoIndex();
+               if (selectedPoint != null && selectedPoint.getPhoto() != null) {
+                       // New point has a photo, so select it
+                       photoIndex = _photoList.getPhotoIndex(selectedPoint.getPhoto());
+               }
+               else if (currPoint != null && selectedPoint != currPoint && currPoint.getPhoto() != null) {
+                       // Old point had a photo, so deselect it
+                       photoIndex = -1;
+               }
+               // give to selection object
+               _selection.selectPointPhotoAudio(pointIndex, photoIndex, inAudioIndex);
+       }
+
+
+       /**
+        * Extend the current selection to end at the given point, eg by shift-clicking
+        * @param inPointNum index of end point
+        */
+       public void extendSelection(int inPointNum)
+       {
+               // See whether to start selection from current range start or current point
+               int rangeStart = _selection.getStart();
+               if (rangeStart < 0 || _selection.getCurrentPointIndex() != _selection.getEnd()) {
+                       rangeStart = _selection.getCurrentPointIndex();
+               }
+               selectPoint(inPointNum);
+               if (rangeStart < inPointNum) {
+                       _selection.selectRange(rangeStart, inPointNum);
+               }
        }
 }