/*
* ShareNav - Copyright (c) 2008 Kai Krueger apm at users dot sourceforge dot net
* Copyright (c) 2008 mbaeurle at users dot sourceforge dot net
* Copyright (c) 2012 Jyrki Kuoppala jkpj at users dot sourceforge dot net
* See COPYING
*/
package net.sharenav.sharenav.ui;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.List;
import java.util.Vector;
import net.sharenav.sharenav.data.Configuration;
import net.sharenav.sharenav.data.PersistEntity;
import net.sharenav.sharenav.data.TrackPlayer;
import net.sharenav.midlet.ui.CompletionListener;
import net.sharenav.midlet.ui.InputListener;
import net.sharenav.midlet.ui.ProgressDisplay;
import net.sharenav.midlet.ui.UploadListener;
import net.sharenav.util.Logger;
import de.enough.polish.util.Locale;
/**
* GuiGpx represents the track management screen. It allows export, import,
* deletion, display and renaming of GPX tracklogs. It handles the GUI part of
* track management. The real GPX data is handled in the GPX class.
*/
public class GuiGpx extends List implements CommandListener,
ShareNavDisplayable, UploadListener, InputListener, CompletionListener {
private final static Logger logger = Logger.getInstance(GuiGpx.class, Logger.DEBUG);
private final Command SEND_CMD = new Command(Locale.get("guigpx.Export")/*Export*/, Command.OK, 1);
private final Command LOAD_CMD = new Command(Locale.get("guigpx.Import")/*Import*/, Command.ITEM, 3);
private final Command DISP_CMD = new Command(Locale.get("guigpx.Display")/*Display*/, Locale.get("guigpx.DispSelectedTracks")/*Display selected tracks*/, Command.ITEM, 3);
private final Command UNDISP_CMD = new Command(Locale.get("guigpx.Undisplay")/*Undisplay*/, Locale.get("guigpx.UndispLoadedTracks")/*Undisplay loaded tracks*/, Command.ITEM, 3);
private final Command ROUTE_CMD = new Command(Locale.get("guigpx.Route")/*Use as route*/, Locale.get("guigpx.Route2")/*Use this track as a route */, Command.ITEM, 3);
private final Command FOLLOW_CMD = new Command(Locale.get("guigpx.Follow")/*Follow track*/, Locale.get("guigpx.Follow2")/*Follow this track */, Command.ITEM, 3);
private final Command RENAME_CMD = new Command(Locale.get("guigpx.Rename")/*Rename*/, Locale.get("guigpx.RenameFirstSelected")/*Rename first selected*/, Command.ITEM, 3);
private final Command REPLAY_START_CMD = new Command(Locale.get("guigpx.Replay")/*Replay*/, Command.ITEM, 3);
private final Command REPLAY_STOP_CMD = new Command(Locale.get("guigpx.StopReplay")/*Stop Replay*/, Command.ITEM, 3);
private final Command DEL_CMD = new Command(Locale.get("generic.Delete")/*Delete*/, Command.ITEM, 3);
private final Command SALL_CMD = new Command(Locale.get("guigpx.SelectAll")/*Select All*/, Command.ITEM, 4);
private final Command DSALL_CMD = new Command(Locale.get("guigpx.DeselectAll")/*Deselect All*/, Command.ITEM, 4);
private final Command BACK_CMD = new Command(Locale.get("generic.Back")/*Back*/, Command.BACK, 5);
/** Value for mJob: No job */
private static final int JOB_IDLE = 0;
/** Value for mJob: Exporting tracks to GPX */
private static final int JOB_EXPORT_TRKS = 1;
/** Value for mJobState: Importing GPX data */
private static final int JOB_IMPORT_GPX = 2;
/** Value for mJobState: Deleting tracks */
private static final int JOB_DELETE_TRKS = 3;
/** Information which job is running. */
private int mJob;
/** Index of first selected track in list. NOTE: This is only updated by
* the operations that need it!
*/
private int idx;
/** Reference to the Trace class, needed to access the Gpx class and
* to switch back to the map. */
private final Trace parent;
/** Alert to display the progress of the operations. */
private final ProgressDisplay progress;
/** Tracks displayed to the user. */
private PersistEntity [] trks;
/** Tracks that are processed (exported, deleted). */
private final Vector processTracks;
public GuiGpx(Trace parent) throws Exception {
super(Locale.get("guigpx.GPXlogs")/*GPX tracklogs*/, List.MULTIPLE);
this.parent = parent;
progress = new ProgressDisplay(this);
processTracks = new Vector();
setCommandListener(this);
initTracks();
if (TrackPlayer.isPlaying) {
addCommand(REPLAY_STOP_CMD);
}
addCommand(SEND_CMD);
addCommand(LOAD_CMD);
addCommand(DISP_CMD);
addCommand(UNDISP_CMD);
addCommand(ROUTE_CMD);
addCommand(FOLLOW_CMD);
addCommand(RENAME_CMD);
// to avoid trouble with user deleting currently recording track, disable deletions if recording is on
if (!parent.gpx.isRecordingTrk()) {
addCommand(DEL_CMD);
}
addCommand(SALL_CMD);
addCommand(DSALL_CMD);
if (!TrackPlayer.isPlaying && !parent.gpx.isRecordingTrk()) {
addCommand(REPLAY_START_CMD);
}
addCommand(BACK_CMD);
}
/**
* Read tracks from the GPX recordStore and display the names in the list on screen.
*/
private void initTracks() {
int count = this.size();
if (count != 0) {
/* Workaround: On some SE phones the selection state of list elements
* must be explicitely cleared before re-adding list elements -
* otherwise they stay selected.
*/
boolean[] boolSelected = new boolean[count];
for (int i = 0; i < count; i++) {
boolSelected[i] = false;
}
this.setSelectedFlags(boolSelected);
}
this.deleteAll();
trks = parent.gpx.listTrks();
for (int i = 0; i < trks.length; i++) {
try {
//#style listItem
this.append(trks[i].displayName, null);
} catch (NullPointerException e) {
// Just ignore it, error is already generated by Gpx.listTrks().
}
}
this.setTitle(Locale.get("guigpx.GPXTracklogs")/*GPX tracklogs (*/ + trks.length + ")");
}
public void commandAction(Command c, Displayable d) {
//#debug debug
logger.debug("got Command " + c.getLabel());
if (c == SEND_CMD) {
updateProcessVector();
if (processTracks.size() > 0) {
mJob = JOB_EXPORT_TRKS;
int numAllPtsInTrack = 0;
try {
for (int i = 0; i < processTracks.size(); i++){
numAllPtsInTrack += ((PersistEntity)processTracks.elementAt(i)).getTrackSize();
}
if (progress != null) {
progress.showProgressDisplay(Locale.get("guigpx.ExportingTracks")
/*Exporting tracks*/, numAllPtsInTrack);
}
} catch (ClassCastException cce) {
logger.exception(Locale.get("guigpx.ClassCastExceptionInCommandAction")
/*ClassCastException in commandAction*/, cce);
}
parent.gpx.exportTracks(Configuration.getGpxUrl(), this, processTracks );
}
return;
}
if (c == LOAD_CMD) {
mJob = JOB_IMPORT_GPX;
GuiGpxLoad ggl = new GuiGpxLoad(this, this, false);
ggl.show();
return;
}
if (c == DISP_CMD) {
updateProcessVector();
if (processTracks.size() > 0) {
parent.gpx.displayTrk(processTracks);
parent.show();
}
return;
}
if (c == REPLAY_START_CMD) {
if (parent.isGpsConnected()) {
parent.show();
parent.alert(Locale.get("guigpx.TrackPlayer")/*TrackPlayer*/, Locale.get("guigpx.CantReplayGPS")/* Can't replay while connected to GPS */, 2500);
return;
} else {
updateProcessVector();
if (processTracks.size() > 0) {
parent.gpx.replayTrk(processTracks);
parent.show();
}
}
return;
}
if (c == REPLAY_STOP_CMD) {
TrackPlayer.getInstance().stop();
parent.show();
return;
}
if (c == UNDISP_CMD) {
parent.gpx.undispLoadedTracks();
parent.show();
return;
}
if (c == ROUTE_CMD) {
idx = getFirstSelectedIndex();
if (idx >= 0) {
parent.gpxAsRoute = idx;
}
return;
}
if (c == FOLLOW_CMD) {
idx = getFirstSelectedIndex();
if (idx >= 0) {
parent.gpxToFollow = idx;
}
return;
}
if (c == RENAME_CMD) {
idx = getFirstSelectedIndex();
if (idx >= 0) {
GuiNameEnter gne = new GuiNameEnter(this, Locale.get("guigpx.RenameTrack")/*Rename Track*/,
trks[idx].displayName, Configuration.MAX_TRACKNAME_LENGTH);
gne.show();
}
return;
}
if (c == DEL_CMD) {
updateProcessVector();
if (processTracks.size() > 0)
{
mJob = JOB_DELETE_TRKS;
if (progress != null) {
progress.showProgressDisplay(Locale.get("guigpx.DeletingTracks")/*Deleting tracks*/);
progress.addProgressText(Locale.get("guigpx.Deleting")/*Deleting */ + processTracks.size() + " " + Locale.get("guigpx.Tracks")/*track(s)*/ + ".\n");
}
parent.gpx.deleteTracks(processTracks, this);
}
return;
}
if ((c == SALL_CMD) || (c == DSALL_CMD)) {
boolean select = (c == SALL_CMD);
boolean[] sel = new boolean[trks.length];
for (int i = 0; i < trks.length; i++) {
sel[i] = select;
}
this.setSelectedFlags(sel);
return;
}
if (c == BACK_CMD) {
parent.show();
return;
}
}
/** Updates the Vector of GPX tracks that should be processed by another method. */
private void updateProcessVector() {
// find out which tracks should be exported **/
boolean[] boolSelected = new boolean[this.size()];
this.getSelectedFlags(boolSelected);
// create new list of tracks which need to be processed / exported
processTracks.removeAllElements();
for (int i = 0; i < boolSelected.length; i++) {
if (boolSelected[i] == true) {
processTracks.addElement(trks[i]);
}
}
}
public int getFirstSelectedIndex() {
boolean[] boolSelected = new boolean[this.size()];
this.getSelectedFlags(boolSelected);
for (int i = 0; i < boolSelected.length; i++) {
if (boolSelected[i] == true) {
return i;
}
}
// None selected -> return -1
return -1;
}
public void startProgress(String title) {
if (progress != null) {
progress.showProgressDisplay(title);
}
}
public void setProgress(String message) {
// Not supported/used at the moment.
}
public void updateProgress(String message) {
if (progress != null) {
progress.addProgressText(message);
}
}
/**
* Implementing the UploadListener interface.
* Updates the progress bar by increasing the progress by the given value.
*/
public void updateProgressValue(int inc) {
//#if not polish.android
if (progress != null) {
progress.updateProgressValue(inc);
}
//#endif
}
public void completedUpload(boolean success, String message) {
String alertMsg;
if (mJob == JOB_EXPORT_TRKS) {
if (success) {
alertMsg = Locale.get("guigpx.Finished")/*Finished!*/;
} else {
alertMsg = Locale.get("guigpx.GPXExportFailed")/*GPX export failed: */ + message;
}
} else if (mJob == JOB_IMPORT_GPX) {
if (success) {
alertMsg = "***********\n" + Locale.get("guigpx.CompletedGPXImport")/*Completed GPX import: */ + message;
} else {
alertMsg = Locale.get("guigpx.GPXImportFailed")/*GPX import failed: */ + message;
}
initTracks();
} else {
// Can only be JOB_DELETE_TRKS but if we check against it,
// the compiler warns that alertMsg may not be initialized.
if (success) {
alertMsg = Locale.get("guigpx.Finished")/*Finished!*/;
} else {
alertMsg = Locale.get("guigpx.DeletingTrackFailed")/*Deleting track(s) failed: */ + message;
}
initTracks();
}
if (progress != null) {
progress.addProgressText(alertMsg);
progress.finishProgressDisplay();
}
mJob = JOB_IDLE;
}
public void uploadAborted() {
initTracks();
mJob = JOB_IDLE;
}
public void show() {
// In case that we return to this screen, make sure our state is correct.
mJob = JOB_IDLE;
ShareNav.getInstance().show(this);
}
/** Called by the screen where the new track name is entered (GuiNameEnter).
* @param strResult The string entered by the user
*/
public void inputCompleted(String strResult) {
if (strResult != null) {
// rename track
trks[idx].displayName = strResult;
parent.gpx.updateTrackName(trks[idx]);
// change item in list
set(idx, strResult, null);
}
show();
}
/** Called when the user closes the progress popup.
*/
public void actionCompleted() {
show();
}
}