package tim.prune.data; import java.util.Set; import tim.prune.UpdateMessageBroker; /** * Class to hold all track information, including data * and the selection information */ public class TrackInfo { private Track _track = null; private Selection _selection = null; private FileInfo _fileInfo = null; private PhotoList _photoList = null; private AudioList _audioList = null; /** * Constructor * @param inTrack Track object */ public TrackInfo(Track inTrack) { _track = inTrack; _selection = new Selection(_track); _fileInfo = new FileInfo(); _photoList = new PhotoList(); _audioList = new AudioList(); } /** * @return the Track object */ public Track getTrack() { return _track; } /** * @return the Selection object */ public Selection getSelection() { return _selection; } /** * @return the FileInfo object */ 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() { 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() { 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()); } /** * Get the currently selected audio clip, if any * @return AudioClip if selected, otherwise null */ public AudioClip getCurrentAudio() { return _audioList.getAudio(_selection.getCurrentAudioIndex()); } /** * 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(Set inSet) { // Firstly count number of points and photos to add int numPhotosToAdd = 0; int numPointsToAdd = 0; if (inSet != null && !inSet.isEmpty()) { for (Photo photo : inSet) { if (photo != null && !_photoList.contains(photo)) { numPhotosToAdd++; if (photo.getDataPoint() != null) { numPointsToAdd++; } } } } // If there are any photos to add, add them if (numPhotosToAdd > 0) { DataPoint[] dataPoints = new DataPoint[numPointsToAdd]; int pointNum = 0; boolean hasAltitude = false; // Add each Photo in turn for (Photo photo : inSet) { if (photo != null && !_photoList.contains(photo)) { // Add photo _photoList.addPhoto(photo); // Add point if there is one if (photo.getDataPoint() != null) { dataPoints[pointNum] = photo.getDataPoint(); // Check if any points have altitudes hasAltitude |= (photo.getDataPoint().getAltitude() != null); pointNum++; } } } 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);} } } int[] result = {numPhotosToAdd, numPointsToAdd}; return result; } /** * Add a Set of Audio objects * @param inSet Set containing Audio objects * @return number of audio objects added */ public int addAudios(Set inSet) { 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 */ public boolean deletePoint() { if (_track.deletePoint(_selection.getCurrentPointIndex())) { _selection.modifyPointDeleted(); return true; } return false; } /** * Delete the currently selected photo and optionally its point too * @param inPointToo true to also delete associated point * @return true if delete successful */ public boolean deleteCurrentPhoto(boolean inPointToo) { 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 points which have been marked for deletion * @param inSplitSegments true to split segments at deleted points * @return number of points deleted */ public int deleteMarkedPoints(boolean inSplitSegments) { int numDeleted = _track.deleteMarkedPoints(inSplitSegments); if (numDeleted > 0) { _selection.clearAll(); UpdateMessageBroker.informSubscribers(); } return numDeleted; } /** * Clone the selected range of data points * @return shallow copy of DataPoint objects */ public DataPoint[] cloneSelectedRange() { 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; } /** * Average selected points to create a new one * @return true if successful */ public boolean average() { boolean success = _track.average(_selection.getStart(), _selection.getEnd()); if (success) { selectPoint(_selection.getEnd()+1); } return success; } /** * Select the given DataPoint * @param inPoint DataPoint object to select */ public void selectPoint(DataPoint 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.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); } } }