import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.Set;
-import java.util.Stack;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
-import tim.prune.data.Altitude;
-import tim.prune.data.AudioFile;
+import tim.prune.config.Config;
import tim.prune.data.Checker;
import tim.prune.data.DataPoint;
import tim.prune.data.Field;
import tim.prune.data.LatLonRectangle;
-import tim.prune.data.MediaFile;
import tim.prune.data.NumberUtils;
import tim.prune.data.Photo;
import tim.prune.data.PhotoList;
+import tim.prune.data.PointCreateOptions;
+import tim.prune.data.RecentFile;
import tim.prune.data.SourceInfo;
import tim.prune.data.Track;
import tim.prune.data.TrackInfo;
+import tim.prune.data.SourceInfo.FILE_TYPE;
+import tim.prune.data.Unit;
+import tim.prune.function.AsyncMediaLoader;
+import tim.prune.function.SaveConfig;
import tim.prune.function.SelectTracksFunction;
-import tim.prune.function.browser.BrowserLauncher;
-import tim.prune.function.browser.UrlGenerator;
import tim.prune.function.edit.FieldEditList;
import tim.prune.function.edit.PointEditor;
-import tim.prune.gui.SidebarController;
import tim.prune.gui.MenuManager;
+import tim.prune.gui.SidebarController;
import tim.prune.gui.UndoManager;
import tim.prune.gui.Viewport;
+import tim.prune.gui.colour.ColourerCaretaker;
+import tim.prune.gui.colour.PointColourer;
import tim.prune.load.FileLoader;
import tim.prune.load.JpegLoader;
-import tim.prune.load.MediaHelper;
+import tim.prune.load.MediaLinkInfo;
import tim.prune.load.TrackNameList;
import tim.prune.save.ExifSaver;
import tim.prune.save.FileSaver;
+import tim.prune.tips.TipManager;
import tim.prune.undo.*;
private FileLoader _fileLoader = null;
private JpegLoader _jpegLoader = null;
private FileSaver _fileSaver = null;
- private Stack<UndoOperation> _undoStack = null;
+ private UndoStack _undoStack = null;
+ private ColourerCaretaker _colCaretaker = null;
private boolean _mangleTimestampsConfirmed = false;
private Viewport _viewport = null;
private ArrayList<File> _dataFiles = null;
- private boolean _firstDataFile = true;
+ private boolean _autoAppendNextFile = false;
+ private boolean _busyLoading = false;
+ private AppMode _appMode = AppMode.NORMAL;
+
+ /** Enum for the app mode - currently only two options but may expand later */
+ public enum AppMode {NORMAL, DRAWRECT};
/**
public App(JFrame inFrame)
{
_frame = inFrame;
- _undoStack = new Stack<UndoOperation>();
+ _undoStack = new UndoStack();
_track = new Track();
_trackInfo = new TrackInfo(_track);
FunctionLibrary.initialise(this);
+ _colCaretaker = new ColourerCaretaker(this);
+ UpdateMessageBroker.addSubscriber(_colCaretaker);
+ _colCaretaker.setColourer(Config.getPointColourer());
}
public boolean hasDataUnsaved()
{
return (_undoStack.size() > _lastSavePosition
- && (_track.getNumPoints() > 0 || _trackInfo.getPhotoList().getNumPhotos() > 0));
+ && (_track.getNumPoints() > 0 || _trackInfo.getPhotoList().hasModifiedMedia()));
}
/**
* @return the undo stack
*/
- public Stack<UndoOperation> getUndoStack()
+ public UndoStack getUndoStack()
{
return _undoStack;
}
+ /**
+ * Update the system's point colourer using the one in the Config
+ */
+ public void updatePointColourer()
+ {
+ if (_colCaretaker != null) {
+ _colCaretaker.setColourer(Config.getPointColourer());
+ }
+ }
+
+ /**
+ * @return colourer object, or null
+ */
+ public PointColourer getPointColourer()
+ {
+ if (_colCaretaker == null) {return null;}
+ return _colCaretaker.getColourer();
+ }
+
+ /**
+ * Show the specified tip if appropriate
+ * @param inTipNumber tip number from TipManager
+ */
+ public void showTip(int inTipNumber)
+ {
+ String key = TipManager.fireTipTrigger(inTipNumber);
+ if (key != null && !key.equals(""))
+ {
+ JOptionPane.showMessageDialog(_frame, I18nManager.getText(key),
+ I18nManager.getText("tip.title"), JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+
+
/**
* Load the specified data files one by one
* @param inDataFiles arraylist containing File objects to load
if (inDataFiles == null || inDataFiles.size() == 0) {
_dataFiles = null;
}
- else {
+ else
+ {
_dataFiles = inDataFiles;
File f = _dataFiles.get(0);
_dataFiles.remove(0);
// Start load of specified file
if (_fileLoader == null)
_fileLoader = new FileLoader(this, _frame);
- _firstDataFile = true;
+ _autoAppendNextFile = false; // prompt for append
_fileLoader.openFile(f);
}
}
{
_undoStack.add(inUndo);
UpdateMessageBroker.informSubscribers(inConfirmText);
+ setCurrentMode(AppMode.NORMAL);
}
/**
JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
== JOptionPane.YES_OPTION)
{
+ // save settings
+ if (Config.getConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS)) {
+ new SaveConfig(this).silentSave();
+ }
System.exit(0);
}
}
// pass to track for completion
if (_track.editPoint(currentPoint, inEditList, false))
{
- _undoStack.push(undo);
+ _undoStack.add(undo);
// Confirm point edit
UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.point.edit"));
}
DataPoint currentPoint = _trackInfo.getCurrentPoint();
if (currentPoint != null)
{
+ // Check for photo
boolean deletePhoto = false;
Photo currentPhoto = currentPoint.getPhoto();
if (currentPhoto != null)
{
// Confirm deletion of photo or decoupling
int response = JOptionPane.showConfirmDialog(_frame,
- I18nManager.getText("dialog.deletepoint.deletephoto") + " " + currentPhoto.getFile().getName(),
+ I18nManager.getText("dialog.deletepoint.deletephoto") + " " + currentPhoto.getName(),
I18nManager.getText("dialog.deletepoint.title"),
JOptionPane.YES_NO_CANCEL_OPTION);
if (response == JOptionPane.CANCEL_OPTION || response == JOptionPane.CLOSED_OPTION)
// store necessary information to undo it later
int pointIndex = _trackInfo.getSelection().getCurrentPointIndex();
int photoIndex = _trackInfo.getPhotoList().getPhotoIndex(currentPhoto);
+ int audioIndex = _trackInfo.getAudioList().getAudioIndex(currentPoint.getAudio());
DataPoint nextTrackPoint = _trackInfo.getTrack().getNextTrackPoint(pointIndex + 1);
// Construct Undo object
- UndoOperation undo = new UndoDeletePoint(pointIndex, currentPoint, photoIndex,
- nextTrackPoint != null && nextTrackPoint.getSegmentStart());
+ UndoDeletePoint undo = new UndoDeletePoint(pointIndex, currentPoint, photoIndex,
+ audioIndex, nextTrackPoint != null && nextTrackPoint.getSegmentStart());
+ undo.setAtBoundaryOfSelectedRange(pointIndex == _trackInfo.getSelection().getStart() ||
+ pointIndex == _trackInfo.getSelection().getEnd());
// call track to delete point
if (_trackInfo.deletePoint())
{
// Delete was successful so add undo info to stack
- _undoStack.push(undo);
+ _undoStack.add(undo);
if (currentPhoto != null)
{
// delete photo if necessary
// decouple photo from point
currentPhoto.setDataPoint(null);
}
+ UpdateMessageBroker.informSubscribers(DataSubscriber.PHOTOS_MODIFIED);
+ }
+ // Delete audio object (without bothering to ask)
+ if (audioIndex > -1) {
+ _trackInfo.getAudioList().deleteAudio(audioIndex);
}
// Confirm
UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.deletepoint.single"));
+ UpdateMessageBroker.informSubscribers(DataSubscriber.DATA_ADDED_OR_REMOVED);
}
}
}
- /**
- * Delete the currently selected range
- */
- public void deleteSelectedRange()
- {
- if (_track != null)
- {
- // Find out if photos should be deleted or not
- int selStart = _trackInfo.getSelection().getStart();
- int selEnd = _trackInfo.getSelection().getEnd();
- if (selStart >= 0 && selEnd >= selStart)
- {
- int numToDelete = selEnd - selStart + 1;
- boolean[] deletePhotos = new boolean[numToDelete];
- Photo[] photosToDelete = new Photo[numToDelete];
- boolean deleteAll = false;
- boolean deleteNone = false;
- String[] questionOptions = {I18nManager.getText("button.yes"), I18nManager.getText("button.no"),
- I18nManager.getText("button.yestoall"), I18nManager.getText("button.notoall"),
- I18nManager.getText("button.cancel")};
- DataPoint point = null;
- for (int i=0; i<numToDelete; i++)
- {
- point = _trackInfo.getTrack().getPoint(i + selStart);
- if (point != null && point.getPhoto() != null)
- {
- if (deleteAll)
- {
- deletePhotos[i] = true;
- photosToDelete[i] = point.getPhoto();
- }
- else if (deleteNone) {deletePhotos[i] = false;}
- else
- {
- int response = JOptionPane.showOptionDialog(_frame,
- I18nManager.getText("dialog.deletepoint.deletephoto") + " " + point.getPhoto().getFile().getName(),
- I18nManager.getText("dialog.deletepoint.title"),
- JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,
- questionOptions, questionOptions[1]);
- // check for cancel or close
- if (response == 4 || response == -1) {return;}
- // check for yes or yes to all
- if (response == 0 || response == 2)
- {
- deletePhotos[i] = true;
- photosToDelete[i] = point.getPhoto();
- if (response == 2) {deleteAll = true;}
- }
- // check for no to all
- if (response == 3) {deleteNone = true;}
- }
- }
- }
- // add information to undo stack
- UndoDeleteRange undo = new UndoDeleteRange(_trackInfo);
- // delete requested photos
- for (int i=0; i<numToDelete; i++)
- {
- point = _trackInfo.getTrack().getPoint(i + selStart);
- if (point != null && point.getPhoto() != null)
- {
- if (deletePhotos[i])
- {
- // delete photo from list
- _trackInfo.getPhotoList().deletePhoto(_trackInfo.getPhotoList().getPhotoIndex(point.getPhoto()));
- }
- else
- {
- // decouple from point
- point.getPhoto().setDataPoint(null);
- }
- }
- }
- // call track to delete range
- if (_trackInfo.deleteRange())
- {
- _undoStack.push(undo);
- // Confirm
- UpdateMessageBroker.informSubscribers("" + numToDelete + " "
- + I18nManager.getText("confirm.deletepoint.multi"));
- }
- }
- }
- }
-
-
- /**
- * Finish the compression by deleting the marked points
- */
- public void finishCompressTrack()
- {
- UndoCompress undo = new UndoCompress(_track);
- // call track to do compress
- int numPointsDeleted = _trackInfo.deleteMarkedPoints();
- // add to undo stack if successful
- if (numPointsDeleted > 0)
- {
- undo.setNumPointsDeleted(numPointsDeleted);
- _undoStack.add(undo);
- UpdateMessageBroker.informSubscribers("" + numPointsDeleted + " "
- + (numPointsDeleted==1?I18nManager.getText("confirm.deletepoint.single"):I18nManager.getText("confirm.deletepoint.multi")));
- }
- else {
- showErrorMessage("function.compress", "dialog.compress.nonefound");
- }
- }
-
/**
* Reverse the currently selected section of the track
*/
/**
* Complete the add altitude offset function with the specified offset
* @param inOffset altitude offset to add as String
- * @param inFormat altitude format of offset (eg Feet, Metres)
+ * @param inUnit altitude units of offset (eg Feet, Metres)
*/
- public void finishAddAltitudeOffset(String inOffset, Altitude.Format inFormat)
+ public void finishAddAltitudeOffset(String inOffset, Unit inUnit)
{
// Sanity check
- if (inOffset == null || inOffset.equals("") || inFormat==Altitude.Format.NO_FORMAT) {
+ if (inOffset == null || inOffset.equals("") || inUnit == null) {
return;
}
// Construct undo information
// Decimal offset given
try {
double offsetd = Double.parseDouble(inOffset);
- success = _trackInfo.getTrack().addAltitudeOffset(selStart, selEnd, offsetd, inFormat, numDecimals);
+ success = _trackInfo.getTrack().addAltitudeOffset(selStart, selEnd, offsetd, inUnit, numDecimals);
}
catch (NumberFormatException nfe) {}
if (success)
}
- /**
- * Interpolate the two selected points
- */
- public void interpolateSelection()
- {
- // Get number of points to add
- Object numPointsStr = JOptionPane.showInputDialog(_frame,
- I18nManager.getText("dialog.interpolate.parameter.text"),
- I18nManager.getText("dialog.interpolate.title"),
- JOptionPane.QUESTION_MESSAGE, null, null, "");
- int numPoints = parseNumber(numPointsStr);
- if (numPoints <= 0) return;
-
- UndoInsert undo = new UndoInsert(_trackInfo.getSelection().getStart() + 1,
- numPoints);
- // call track to interpolate
- if (_trackInfo.interpolate(numPoints))
- {
- _undoStack.add(undo);
- }
- }
-
-
/**
* Average the selected points
*/
/**
- * Create a new point at the given position
+ * Create a new point at the end of the track
* @param inPoint point to add
*/
public void createPoint(DataPoint inPoint)
+ {
+ createPoint(inPoint, true);
+ }
+
+ /**
+ * Create a new point at the end of the track
+ * @param inPoint point to add
+ * @param inNewSegment true for a single point, false for a continuation
+ */
+ public void createPoint(DataPoint inPoint, boolean inNewSegment)
{
// create undo object
UndoCreatePoint undo = new UndoCreatePoint();
_undoStack.add(undo);
// add point to track
- inPoint.setSegmentStart(true);
+ inPoint.setSegmentStart(inNewSegment);
_track.appendPoints(new DataPoint[] {inPoint});
// ensure track's field list contains point's fields
_track.extendFieldList(inPoint.getFieldList());
}
+ /**
+ * Create a new point before the given position
+ * @param inPoint point to add
+ * @param inIndex index of following point
+ */
+ public void createPoint(DataPoint inPoint, int inIndex)
+ {
+ // create undo object
+ UndoInsert undo = new UndoInsert(inIndex, 1);
+ _undoStack.add(undo);
+ // add point to track
+ _track.insertPoint(inPoint, inIndex);
+ // ensure track's field list contains point's fields
+ _track.extendFieldList(inPoint.getFieldList());
+ _trackInfo.selectPoint(inIndex);
+ final int selStart = _trackInfo.getSelection().getStart();
+ final int selEnd = _trackInfo.getSelection().getEnd();
+ if (selStart < inIndex && selEnd >= inIndex)
+ {
+ // Extend end of selection by 1
+ _trackInfo.getSelection().selectRange(selStart, selEnd+1);
+ }
+ // update listeners
+ UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.createpoint"));
+ }
+
+
/**
* Cut the current selection and move it to before the currently selected point
*/
}
/**
- * Receive loaded data and start load
+ * Receive loaded data and determine whether to filter on tracks or not
* @param inFieldArray array of fields
* @param inDataArray array of data
- * @param inAltFormat altitude format
* @param inSourceInfo information about the source of the data
+ * @param inTrackNameList information about the track names
*/
public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray,
- Altitude.Format inAltFormat, SourceInfo inSourceInfo)
+ SourceInfo inSourceInfo, TrackNameList inTrackNameList)
{
- informDataLoaded(inFieldArray, inDataArray, inAltFormat, inSourceInfo, null, null);
+ // no link array given
+ informDataLoaded(inFieldArray, inDataArray, null, inSourceInfo,
+ inTrackNameList, null);
}
/**
* Receive loaded data and determine whether to filter on tracks or not
* @param inFieldArray array of fields
* @param inDataArray array of data
- * @param inAltFormat altitude format
+ * @param inOptions creation options such as units
* @param inSourceInfo information about the source of the data
* @param inTrackNameList information about the track names
*/
public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray,
- Altitude.Format inAltFormat, SourceInfo inSourceInfo, TrackNameList inTrackNameList)
+ PointCreateOptions inOptions, SourceInfo inSourceInfo, TrackNameList inTrackNameList)
{
// no link array given
- informDataLoaded(inFieldArray, inDataArray, inAltFormat, inSourceInfo,
+ informDataLoaded(inFieldArray, inDataArray, inOptions, inSourceInfo,
inTrackNameList, null);
}
* Receive loaded data and determine whether to filter on tracks or not
* @param inFieldArray array of fields
* @param inDataArray array of data
- * @param inAltFormat altitude format
+ * @param inOptions creation options such as units
* @param inSourceInfo information about the source of the data
* @param inTrackNameList information about the track names
- * @param inLinkArray array of links to photo/audio files
+ * @param inLinkInfo links to photo/audio clips
*/
- public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray,
- Altitude.Format inAltFormat, SourceInfo inSourceInfo,
- TrackNameList inTrackNameList, String[] inLinkArray)
+ public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray, PointCreateOptions inOptions,
+ SourceInfo inSourceInfo, TrackNameList inTrackNameList, MediaLinkInfo inLinkInfo)
{
// Check whether loaded array can be properly parsed into a Track
Track loadedTrack = new Track();
- loadedTrack.load(inFieldArray, inDataArray, inAltFormat);
+ loadedTrack.load(inFieldArray, inDataArray, inOptions);
if (loadedTrack.getNumPoints() <= 0)
{
showErrorMessage("error.load.dialogtitle", "error.load.nopoints");
JOptionPane.showMessageDialog(_frame, I18nManager.getText("dialog.open.contentsdoubled"),
I18nManager.getText("function.open"), JOptionPane.WARNING_MESSAGE);
}
- // Attach photos and/or audio files to points
- if (inLinkArray != null)
+
+ _busyLoading = true;
+ // Attach photos and/or audio clips to points
+ if (inLinkInfo != null)
{
- for (int i=0; i<inLinkArray.length; i++)
- {
- if (inLinkArray[i] != null)
- {
- MediaFile mf = MediaHelper.createMediaFile(inLinkArray[i]);
- if (mf != null) {
- loadedTrack.getPoint(i).attachMedia(mf);
- mf.setOriginalStatus(MediaFile.Status.TAGGED);
- mf.setCurrentStatus(MediaFile.Status.TAGGED);
- }
- }
+ String[] linkArray = inLinkInfo.getLinkArray();
+ if (linkArray != null) {
+ new AsyncMediaLoader(this, inLinkInfo.getZipFile(), linkArray, loadedTrack, inSourceInfo.getFile()).begin();
}
}
// Look at TrackNameList, decide whether to filter or not
if (inTrackNameList != null && inTrackNameList.getNumTracks() > 1)
{
// Launch a dialog to let the user choose which tracks to load, then continue
- new SelectTracksFunction(this, inFieldArray, inDataArray, inAltFormat, inSourceInfo,
- inTrackNameList).begin();
+ new SelectTracksFunction(this, loadedTrack, inSourceInfo, inTrackNameList).begin();
}
else {
// go directly to load
informDataLoaded(loadedTrack, inSourceInfo);
}
+ setCurrentMode(AppMode.NORMAL);
}
{
// ask whether to replace or append
int answer = 0;
- if (_dataFiles == null || _firstDataFile) {
+ if (_autoAppendNextFile) {
+ // Automatically append the next file
+ answer = JOptionPane.YES_OPTION;
+ }
+ else {
+ // Ask whether to append or not
answer = JOptionPane.showConfirmDialog(_frame,
I18nManager.getText("dialog.openappend.text"),
I18nManager.getText("dialog.openappend.title"),
JOptionPane.YES_NO_CANCEL_OPTION);
}
- else {
- // Automatically append if there's a file load queue
- answer = JOptionPane.YES_OPTION;
- }
+ _autoAppendNextFile = false; // reset flag to cancel autoappend
+
if (answer == JOptionPane.YES_OPTION)
{
// append data to current Track
undo.setNumPhotosAudios(_trackInfo.getPhotoList().getNumPhotos(), _trackInfo.getAudioList().getNumAudios());
_undoStack.add(undo);
_track.combine(inLoadedTrack);
- // Add photos and audios (if any in loaded track) to list(s)
- MediaHelper.addMediaFromTrack(_track, _trackInfo.getPhotoList(), Photo.class);
- MediaHelper.addMediaFromTrack(_track, _trackInfo.getAudioList(), AudioFile.class);
// set source information
inSourceInfo.populatePointObjects(_track, inLoadedTrack.getNumPoints());
_trackInfo.getFileInfo().addSource(inSourceInfo);
_trackInfo.getFileInfo().replaceSource(inSourceInfo);
_trackInfo.getPhotoList().removeCorrelatedPhotos();
_trackInfo.getAudioList().removeCorrelatedAudios();
- // Add photos and audios (if any in loaded track) to list(s)
- MediaHelper.addMediaFromTrack(_track, _trackInfo.getPhotoList(), Photo.class);
- MediaHelper.addMediaFromTrack(_track, _trackInfo.getAudioList(), AudioFile.class);
}
}
else
_track.load(inLoadedTrack);
inSourceInfo.populatePointObjects(_track, _track.getNumPoints());
_trackInfo.getFileInfo().addSource(inSourceInfo);
- // Add photos and audios (if any in loaded track) to list(s)
- MediaHelper.addMediaFromTrack(_track, _trackInfo.getPhotoList(), Photo.class);
- MediaHelper.addMediaFromTrack(_track, _trackInfo.getAudioList(), AudioFile.class);
}
+ // Update config before subscribers are told
+ boolean isRegularLoad = (inSourceInfo.getFileType() != FILE_TYPE.GPSBABEL);
+ Config.getRecentFileList().addFile(new RecentFile(inSourceInfo.getFile(), isRegularLoad));
UpdateMessageBroker.informSubscribers();
// Update status bar
UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile")
+ " '" + inSourceInfo.getName() + "'");
// update menu
_menuManager.informFileLoaded();
+ // Remove busy lock
+ _busyLoading = false;
// load next file if there's a queue
loadNextFile();
}
loadNextFile();
}
+ /**
+ * External trigger to automatically append the next loaded file
+ * instead of prompting to replace or append
+ */
+ public void autoAppendNextFile()
+ {
+ _autoAppendNextFile = true;
+ }
+
/**
* Load the next file in the waiting list, if any
*/
private void loadNextFile()
{
- _firstDataFile = false;
if (_dataFiles == null || _dataFiles.size() == 0) {
_dataFiles = null;
}
public void run() {
File f = _dataFiles.get(0);
_dataFiles.remove(0);
+ _autoAppendNextFile = true;
_fileLoader.openFile(f);
}
}).start();
}
else
{
- new UndoManager(this, _frame);
+ new UndoManager(this, _frame).show();
}
}
{
for (int i=0; i<inNumUndos; i++)
{
- _undoStack.pop().performUndo(_trackInfo);
+ _undoStack.popOperation().performUndo(_trackInfo);
}
String message = "" + inNumUndos + " "
+ (inNumUndos==1?I18nManager.getText("confirm.undo.single"):I18nManager.getText("confirm.undo.multi"));
showErrorMessageNoLookup("error.undofailed.title",
I18nManager.getText("error.undofailed.text") + " : " + ue.getMessage());
_undoStack.clear();
- UpdateMessageBroker.informSubscribers();
}
catch (EmptyStackException empty) {}
+ UpdateMessageBroker.informSubscribers();
}
-
/**
- * Helper method to parse an Object into an integer
- * @param inObject object, eg from dialog
- * @return int value given
+ * @return the current data status, used for later comparison
*/
- private static int parseNumber(Object inObject)
+ public DataStatus getCurrentDataStatus()
{
- int num = 0;
- if (inObject != null)
- {
- try
- {
- num = Integer.parseInt(inObject.toString());
- }
- catch (NumberFormatException nfe)
- {}
- }
- return num;
+ return new DataStatus(_undoStack.size(), _undoStack.getNumUndos());
}
- /**
- * Show a map url in an external browser
- * @param inSourceIndex index of map source to use
- */
- public void showExternalMap(int inSourceIndex)
- {
- BrowserLauncher.launchBrowser(UrlGenerator.generateUrl(inSourceIndex, _trackInfo));
- }
/**
* Display a standard error message
{
_sidebarController.toggle();
}
+
+ /** @return true if App is currently busy with loading data */
+ public boolean isBusyLoading() {
+ return _busyLoading;
+ }
+
+ /** @return current app mode */
+ public AppMode getCurrentMode() {
+ return _appMode;
+ }
+
+ /** @param inMode the current app mode */
+ public void setCurrentMode(AppMode inMode) {
+ _appMode = inMode;
+ }
}