diff options
author | SammysHP <sven@sammyshp.de> | 2012-04-06 20:24:44 +0200 |
---|---|---|
committer | SammysHP <sven@sammyshp.de> | 2012-04-06 20:24:44 +0200 |
commit | c5e9616a2202c939ed73e8d27015b78e005970cb (patch) | |
tree | fb2482d71a4a5b3d55ea46a24b59683f905b0a4e /main/src/cgeo/geocaching | |
parent | 73b0a45d249ce13139b003732e66c540226989d4 (diff) | |
download | cgeo-c5e9616a2202c939ed73e8d27015b78e005970cb.zip cgeo-c5e9616a2202c939ed73e8d27015b78e005970cb.tar.gz cgeo-c5e9616a2202c939ed73e8d27015b78e005970cb.tar.bz2 |
New: Export feature
- Generic export framework for caches
- Refactored Field Notes export and moved to export framework
- Created experimental GPX exporter
TODO:
- GPX export: Logs, Waypoints, Attributes, correct type/size strings
- Field Notes: upload, only new logs
Diffstat (limited to 'main/src/cgeo/geocaching')
-rw-r--r-- | main/src/cgeo/geocaching/cgeocaches.java | 231 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/export/AbstractExport.java | 19 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/export/Export.java | 13 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/export/ExportFactory.java | 58 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/export/FieldnoteExport.java | 223 | ||||
-rw-r--r-- | main/src/cgeo/geocaching/export/GpxExport.java | 216 |
6 files changed, 556 insertions, 204 deletions
diff --git a/main/src/cgeo/geocaching/cgeocaches.java b/main/src/cgeo/geocaching/cgeocaches.java index 63b9a2e..09c0f5a 100644 --- a/main/src/cgeo/geocaching/cgeocaches.java +++ b/main/src/cgeo/geocaching/cgeocaches.java @@ -11,6 +11,7 @@ import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.export.ExportFactory; import cgeo.geocaching.files.GPXImporter; import cgeo.geocaching.filter.AttributeFilter; import cgeo.geocaching.filter.IFilter; @@ -54,7 +55,6 @@ import android.content.Intent; import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; -import android.os.Environment; import android.os.Handler; import android.os.Message; import android.view.ContextMenu; @@ -71,18 +71,11 @@ import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -110,7 +103,7 @@ public class cgeocaches extends AbstractListActivity { private static final int MENU_SORT_VOTE = 19; private static final int MENU_SORT_INVENTORY = 20; private static final int MENU_IMPORT_WEB = 21; - private static final int MENU_EXPORT_NOTES = 22; + private static final int MENU_EXPORT = 22; private static final int MENU_REMOVE_FROM_HISTORY = 23; private static final int MENU_DROP_CACHE = 24; private static final int MENU_MOVE_TO_LIST = 25; @@ -166,7 +159,6 @@ public class cgeocaches extends AbstractListActivity { private LoadDetailsThread threadDetails = null; private LoadFromWebThread threadWeb = null; private DropDetailsThread threadR = null; - private ExportFieldNotesThread threadF = null; private RemoveFromHistoryThread threadH = null; private int listId = StoredList.TEMPORARY_LIST_ID; private List<StoredList> lists = null; @@ -469,39 +461,6 @@ public class cgeocaches extends AbstractListActivity { } } }; - private Handler exportFieldNotesHandler = new Handler() { - - @Override - public void handleMessage(Message msg) - { - setAdapter(); - - if (msg.what > -1) - { - cacheList.get(msg.what).setStatusChecked(false); - progress.setProgress(detailProgress); - } - else if (-2 == msg.what) - { - showToast(res.getString(R.string.info_fieldnotes_exported_to) + ": " + msg.obj.toString()); - } - else if (-3 == msg.what) - { - showToast(res.getString(R.string.err_fieldnotes_export_failed)); - } else if (msg.what == MSG_CANCEL) { - if (threadF != null) { - threadF.kill(); - } - } else { - if (adapter != null) - { - adapter.setSelectMode(false, true); - } - - progress.dismiss(); - } - } - }; private Handler importGpxAttachementFinishedHandler = new Handler() { @Override @@ -808,7 +767,7 @@ public class cgeocaches extends AbstractListActivity { subMenu.add(0, MENU_DROP_CACHES_AND_LIST, 0, res.getString(R.string.caches_drop_all_and_list)); subMenu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.cache_offline_refresh)); // download details for all caches subMenu.add(0, MENU_MOVE_TO_LIST, 0, res.getString(R.string.cache_menu_move_list)); - subMenu.add(0, MENU_EXPORT_NOTES, 0, res.getString(R.string.cache_export_fieldnote)); // export field notes + subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches if (Settings.getWebDeviceCode() == null) { menu.add(0, MENU_IMPORT_GPX, 0, res.getString(R.string.gpx_import_title)).setIcon(android.R.drawable.ic_menu_upload); // import gpx file @@ -822,7 +781,7 @@ public class cgeocaches extends AbstractListActivity { { SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_HISTORY, 0, res.getString(R.string.caches_manage)).setIcon(android.R.drawable.ic_menu_save); subMenu.add(0, MENU_REMOVE_FROM_HISTORY, 0, res.getString(R.string.cache_clear_history)); // remove from history - subMenu.add(0, MENU_EXPORT_NOTES, 0, res.getString(R.string.cache_export_fieldnote)); // export field notes + subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches } menu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.caches_store_offline)).setIcon(android.R.drawable.ic_menu_set_as); // download details for all caches } @@ -934,23 +893,12 @@ public class cgeocaches extends AbstractListActivity { } } - item = menu.findItem(MENU_EXPORT_NOTES); - if (null != item) { - // Hide Field Notes export if there are no caches with logs - item.setVisible(false); - for (cgCache cache : cacheList) { - if (cache.isLogOffline()) { - item.setVisible(true); - if (hasSelection) { - item.setTitle(res.getString(R.string.cache_export_fieldnote) + " (" + adapter.getChecked() + ")"); - } else { - item.setTitle(res.getString(R.string.cache_export_fieldnote)); - } - break; - } - } + item = menu.findItem(MENU_EXPORT); + if (hasSelection) { + item.setTitle(res.getString(R.string.export) + " (" + adapter.getChecked() + ")"); + } else { + item.setTitle(res.getString(R.string.export)); } - } catch (Exception e) { Log.e(Settings.tag, "cgeocaches.onPrepareOptionsMenu: " + e.toString()); } @@ -1070,8 +1018,8 @@ public class cgeocaches extends AbstractListActivity { case MENU_IMPORT_WEB: importWeb(); return false; - case MENU_EXPORT_NOTES: - exportFieldNotes(); + case MENU_EXPORT: + exportCaches(); return false; case MENU_REMOVE_FROM_HISTORY: removeFromHistoryCheck(); @@ -1508,27 +1456,23 @@ public class cgeocaches extends AbstractListActivity { threadH.start(); } - public void exportFieldNotes() - { - if (adapter != null && adapter.getChecked() > 0) - { - // there are some checked caches - detailTotal = adapter.getChecked(); - } - else - { - // no checked caches, export all - detailTotal = cacheList.size(); - } - detailProgress = 0; - - showProgress(false); + public void exportCaches() { - progress.show(this, null, res.getString(R.string.caches_exporting_fieldnote), ProgressDialog.STYLE_HORIZONTAL, exportFieldNotesHandler.obtainMessage(MSG_CANCEL)); - progress.setMaxProgressAndReset(detailTotal); + List<cgCache> caches; + if (adapter != null && adapter.getChecked() > 0) { + // there are some caches checked + caches = new LinkedList<cgCache>(); + for (cgCache cache : cacheList) { + if (cache.isStatusChecked()) { + caches.add(cache); + } + } + } else { + // no caches checked, export all + caches = cacheList; + } - threadF = new ExportFieldNotesThread(exportFieldNotesHandler); - threadF.start(); + ExportFactory.showExportMenu(caches, this); } public void importWeb() { @@ -2055,127 +1999,6 @@ public class cgeocaches extends AbstractListActivity { } } - private class ExportFieldNotesThread extends Thread - { - private final Handler handler; - private volatile boolean needToStop = false; - private int checked = 0; - - public ExportFieldNotesThread(Handler handlerIn) - { - setPriority(Thread.MIN_PRIORITY); - - handler = handlerIn; - - if (adapter != null) - { - checked = adapter.getChecked(); - } - } - - public void kill() - { - needToStop = true; - } - - @Override - public void run() - { - SimpleDateFormat fieldNoteDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - StringBuilder fieldNoteBuffer = new StringBuilder(500); - - // We need our own HashMap because LogType will give us localized and maybe - // different strings than gc.com expects in the field note - // We only need such logtypes that are possible to log via c:geo - Map<LogType, String> logTypes = new HashMap<LogType, String>(); - logTypes.put(LogType.LOG_FOUND_IT, "Found it"); - logTypes.put(LogType.LOG_DIDNT_FIND_IT, "Didn't find it"); - logTypes.put(LogType.LOG_NOTE, "Write Note"); - logTypes.put(LogType.LOG_NEEDS_ARCHIVE, "Needs archived"); - logTypes.put(LogType.LOG_NEEDS_MAINTENANCE, "Needs Maintenance"); - logTypes.put(LogType.LOG_WILL_ATTEND, "Will Attend"); - logTypes.put(LogType.LOG_ATTENDED, "Attended"); - logTypes.put(LogType.LOG_WEBCAM_PHOTO_TAKEN, "Webcam Photo Taken"); - - for (cgCache cache : cacheList) { - if (checked > 0 && !cache.isStatusChecked()) { - handler.sendEmptyMessage(0); - - yield(); - continue; - } - - try { - if (needToStop) - { - Log.i(Settings.tag, "Stopped exporting process."); - break; - } - - if (cache.isLogOffline()) - { - cgLog log = app.loadLogOffline(cache.getGeocode()); - - if (null != logTypes.get(log.type)) - { - fieldNoteBuffer.append(cache.getGeocode()) - .append(',') - .append(fieldNoteDateFormat.format(new Date(log.date))) - .append(',') - .append(logTypes.get(log.type)) - .append(",\"") - .append(StringUtils.replaceChars(log.log, '"', '\'')) - .append("\"\n"); - } - } - - detailProgress++; - - handler.sendEmptyMessage(cacheList.indexOf(cache)); - - yield(); - } catch (Exception e) { - Log.e(Settings.tag, "cgeocaches.ExportFieldNotesThread: " + e.toString()); - } - } - - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) - { - File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/field-notes"); - exportLocation.mkdirs(); - - SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); - File exportFile = new File(exportLocation + "/" + fileNameDateFormat.format(new Date()) + ".txt"); - - OutputStream os = null; - Writer fw = null; - try - { - os = new FileOutputStream(exportFile); - fw = new OutputStreamWriter(os, "ISO-8859-1"); // TODO: gc.com doesn't support UTF-8 - fw.write(fieldNoteBuffer.toString()); - - Message.obtain(handler, -2, exportFile).sendToTarget(); - } catch (IOException e) { - Log.e(Settings.tag, "cgeocaches.ExportFieldNotesThread: " + e.toString()); - handler.sendEmptyMessage(-3); - } finally - { - if (fw != null) - { - try { - fw.close(); - } catch (IOException e) { - Log.e(Settings.tag, "cgeocaches.ExportFieldNotesThread: " + e.toString()); - } - } - } - } - - handler.sendEmptyMessage(MSG_DONE); - } - } - private class MoreCachesListener implements View.OnClickListener { @Override diff --git a/main/src/cgeo/geocaching/export/AbstractExport.java b/main/src/cgeo/geocaching/export/AbstractExport.java new file mode 100644 index 0000000..e88b1e6 --- /dev/null +++ b/main/src/cgeo/geocaching/export/AbstractExport.java @@ -0,0 +1,19 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.cgeoapplication; + +public abstract class AbstractExport implements Export { + private String name; + + protected AbstractExport(final String name) { + this.name = name; + } + + public String getName() { + return name; + } + + protected static String getString(int ressourceId) { + return cgeoapplication.getInstance().getString(ressourceId); + } +} diff --git a/main/src/cgeo/geocaching/export/Export.java b/main/src/cgeo/geocaching/export/Export.java new file mode 100644 index 0000000..257238c --- /dev/null +++ b/main/src/cgeo/geocaching/export/Export.java @@ -0,0 +1,13 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.cgCache; + +import android.app.Activity; + +import java.util.List; + +public interface Export { + public void export(List<cgCache> caches, Activity activity); + + public String getName(); +} diff --git a/main/src/cgeo/geocaching/export/ExportFactory.java b/main/src/cgeo/geocaching/export/ExportFactory.java new file mode 100644 index 0000000..01343c3 --- /dev/null +++ b/main/src/cgeo/geocaching/export/ExportFactory.java @@ -0,0 +1,58 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.R; +import cgeo.geocaching.cgCache; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import java.util.List; + +public class ExportFactory { + public enum Exporters { + FIELDNOTES(new FieldnoteExport()), + GPX(new GpxExport()); + + Exporters(Export exporter) { + this.exporter = exporter; + } + + public final Export exporter; + } + + public static void showExportMenu(final List<cgCache> caches, final Activity activity) { + final AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(R.string.export).setIcon(android.R.drawable.ic_menu_share); + + final ArrayAdapter<Exporters> adapter = new ArrayAdapter<Exporters>(activity, android.R.layout.select_dialog_item, Exporters.values()) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + TextView textView = (TextView) super.getView(position, convertView, parent); + textView.setText(getItem(position).exporter.getName()); + return textView; + } + + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + TextView textView = (TextView) super.getDropDownView(position, convertView, parent); + textView.setText(getItem(position).exporter.getName()); + return textView; + } + }; + adapter.setDropDownViewResource(android.R.layout.select_dialog_item); + + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + Exporters selectedItem = adapter.getItem(item); + selectedItem.exporter.export(caches, activity); + } + }); + + builder.create().show(); + } +} diff --git a/main/src/cgeo/geocaching/export/FieldnoteExport.java b/main/src/cgeo/geocaching/export/FieldnoteExport.java new file mode 100644 index 0000000..e00a8b0 --- /dev/null +++ b/main/src/cgeo/geocaching/export/FieldnoteExport.java @@ -0,0 +1,223 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.R; +import cgeo.geocaching.Settings; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgLog; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.activity.Progress; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.StringUtils; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.os.AsyncTask; +import android.os.Environment; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FieldnoteExport extends AbstractExport { + private static final File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/field-notes"); + private static final SimpleDateFormat fieldNoteDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + + public FieldnoteExport() { + super(getString(R.string.export_fieldnotes)); + } + + private class ExportOptionsDialog extends AlertDialog { + public ExportOptionsDialog(final List<cgCache> caches, final Activity activity) { + super(activity); + + View layout = activity.getLayoutInflater().inflate(R.layout.fieldnote_export_dialog, null); + setView(layout); + + ((Button) layout.findViewById(R.id.export)).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + new ExportTask( + caches, + activity, + ((CheckBox) findViewById(R.id.upload)).isChecked(), + ((CheckBox) findViewById(R.id.onlynew)).isChecked()) + .execute((Void) null); + } + }); + } + } + + @Override + public void export(final List<cgCache> caches, final Activity activity) { + new ExportOptionsDialog(caches, activity).show(); + } + + private class ExportTask extends AsyncTask<Void, Integer, Boolean> { + private final List<cgCache> caches; + private final Activity activity; + private final boolean upload; + private final boolean onlyNew; + private final Progress progress = new Progress(); + private File exportFile; + + private static final int STATUS_UPLOAD = -1; + + public ExportTask(final List<cgCache> caches, final Activity activity, final boolean upload, final boolean onlyNew) { + this.caches = caches; + this.activity = activity; + this.upload = upload; + this.onlyNew = onlyNew; + } + + @Override + protected void onPreExecute() { + progress.show(activity, null, getString(R.string.export) + ": " + getName(), ProgressDialog.STYLE_HORIZONTAL, null); + progress.setMaxProgressAndReset(caches.size()); + } + + @Override + protected Boolean doInBackground(Void... params) { + final StringBuilder fieldNoteBuffer = new StringBuilder(); + + // We need our own HashMap because LogType will give us localized and maybe + // different strings than gc.com expects in the field note + // We only need such logtypes that are possible to log via c:geo + Map<LogType, String> logTypes = new HashMap<LogType, String>(); + logTypes.put(LogType.LOG_FOUND_IT, "Found it"); + logTypes.put(LogType.LOG_DIDNT_FIND_IT, "Didn't find it"); + logTypes.put(LogType.LOG_NOTE, "Write Note"); + logTypes.put(LogType.LOG_NEEDS_ARCHIVE, "Needs archived"); + logTypes.put(LogType.LOG_NEEDS_MAINTENANCE, "Needs Maintenance"); + logTypes.put(LogType.LOG_WILL_ATTEND, "Will Attend"); + logTypes.put(LogType.LOG_ATTENDED, "Attended"); + logTypes.put(LogType.LOG_WEBCAM_PHOTO_TAKEN, "Webcam Photo Taken"); + + for (int i = 0; i < caches.size(); i++) { + try { + final cgCache cache = caches.get(i); + if (cache.isLogOffline()) { + cgLog log = cgeoapplication.getInstance().loadLogOffline(cache.getGeocode()); + if (null != logTypes.get(log.type)) { + fieldNoteBuffer.append(cache.getGeocode()) + .append(',') + .append(fieldNoteDateFormat.format(new Date(log.date))) + .append(',') + .append(logTypes.get(log.type)) + .append(",\"") + .append(StringUtils.replaceChars(log.log, '"', '\'')) + .append("\"\n"); + } + } + publishProgress(i + 1); + } catch (Exception e) { + Log.e(Settings.tag, "FieldnoteExport.ExportTask generation", e); + return false; + } + } + + fieldNoteBuffer.append("\n"); + + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + exportLocation.mkdirs(); + + SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + exportFile = new File(exportLocation + "/" + fileNameDateFormat.format(new Date()) + ".txt"); + + OutputStream os = null; + Writer fw = null; + try { + os = new FileOutputStream(exportFile); + fw = new OutputStreamWriter(os, "ISO-8859-1"); // TODO: gc.com doesn't support UTF-8 + fw.write(fieldNoteBuffer.toString()); + } catch (IOException e) { + Log.e(Settings.tag, "FieldnoteExport.ExportTask export", e); + return false; + } finally { + if (fw != null) { + try { + fw.close(); + } catch (IOException e) { + Log.e(Settings.tag, "FieldnoteExport.ExportTask export", e); + return false; + } + } + } + } else { + return false; + } + + /* + * if (upload) { + * TODO Use multipart POST request for uploading + * publishProgress(STATUS_UPLOAD); + * + * final Parameters uploadParams = new Parameters( + * "__EVENTTARGET", "", + * "__EVENTARGUMENT", "", + * "__VIEWSTATE", "", + * //TODO "ctl00$ContentBody$chkSuppressDate", "on", + * "ctl00$ContentBody$FieldNoteLoader", fieldNoteBuffer.toString(), + * "ctl00$ContentBody$btnUpload", "Upload Field Note"); + * final String uri = "http://www.geocaching.com/my/uploadfieldnotes.aspx"; + * + * String page = Network.getResponseData(Network.postRequest(uri, uploadParams)); + * if (!Login.getLoginStatus(page)) { + * final StatusCode loginState = Login.login(); + * if (loginState == StatusCode.NO_ERROR) { + * page = Network.getResponseData(Network.postRequest(uri, uploadParams)); + * } else { + * Log.e(Settings.tag, "FieldnoteExport.ExportTask upload: No login (error: " + loginState + ")"); + * return false; + * } + * } + * + * if (StringUtils.isBlank(page)) { + * Log.e(Settings.tag, "FieldnoteExport.ExportTask upload: No data from server"); + * return false; + * } + * } + */ + + return true; + } + + @Override + protected void onPostExecute(Boolean result) { + progress.dismiss(); + + if (result) { + if (onlyNew) { + // update last export time in settings + } + ActivityMixin.showToast(activity, getName() + " " + getString(R.string.export_exportedto) + ": " + exportFile.toString()); + } else { + ActivityMixin.showToast(activity, getString(R.string.export_failed)); + } + } + + @Override + protected void onProgressUpdate(Integer... status) { + if (STATUS_UPLOAD == status[0]) { + progress.setMessage(getString(R.string.export_fieldnotes_uploading)); + } else { + progress.setProgress(status[0]); + } + } + } +} diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java new file mode 100644 index 0000000..1e7d973 --- /dev/null +++ b/main/src/cgeo/geocaching/export/GpxExport.java @@ -0,0 +1,216 @@ +package cgeo.geocaching.export; + +import cgeo.geocaching.R; +import cgeo.geocaching.Settings; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.activity.Progress; +import cgeo.geocaching.enumerations.LoadFlags; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.StringEscapeUtils; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.os.AsyncTask; +import android.os.Environment; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +public class GpxExport extends AbstractExport { + private static final File exportLocation = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/gpx-export"); + private static final SimpleDateFormat dateFormatZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + + protected GpxExport() { + super(getString(R.string.export_gpx)); + } + + @Override + public void export(final List<cgCache> caches, final Activity activity) { + new ExportTask(caches, activity).execute((Void) null); + } + + private class ExportTask extends AsyncTask<Void, Integer, Boolean> { + private final List<cgCache> caches; + private final Activity activity; + private final Progress progress = new Progress(); + private File exportFile; + + public ExportTask(final List<cgCache> caches, final Activity activity) { + this.caches = caches; + this.activity = activity; + } + + @Override + protected void onPreExecute() { + progress.show(activity, null, getString(R.string.export) + ": " + getName(), ProgressDialog.STYLE_HORIZONTAL, null); + progress.setMaxProgressAndReset(caches.size()); + } + + @Override + protected Boolean doInBackground(Void... params) { + final StringBuilder gpx = new StringBuilder(); + + gpx.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + gpx.append("<gpx version=\"1.0\" creator=\"c:geo - http://www.cgeo.org\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/0\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd\">"); + + try { + for (int i = 0; i < caches.size(); i++) { + cgCache cache = caches.get(i); + + if (!cache.isDetailed()) { + cache = cgeoapplication.getInstance().loadCache(caches.get(i).getGeocode(), LoadFlags.LOAD_ALL_DB_ONLY); + } + + gpx.append("<wpt "); + gpx.append("lat=\"" + cache.getCoords().getLatitude() + "\" "); + gpx.append("lon=\"" + cache.getCoords().getLongitude() + "\">"); + + gpx.append("<time>"); + gpx.append(StringEscapeUtils.escapeXml(dateFormatZ.format(cache.getHiddenDate()))); + gpx.append("</time>"); + + gpx.append("<name>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getGeocode())); + gpx.append("</name>"); + + gpx.append("<desc>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getName())); + gpx.append("</desc>"); + + gpx.append("<sym>"); + gpx.append(cache.isFound() ? "Geocache Found" : "Geocache"); + gpx.append("</sym>"); + + gpx.append("<type>"); + gpx.append(StringEscapeUtils.escapeXml("Geocache|" + cache.getType().toString())); //TODO: Correct (english) string + gpx.append("</type>"); + + gpx.append("<groundspeak:cache "); + gpx.append("available=\"" + (!cache.isDisabled() ? "True" : "False")); + gpx.append("\" archived=\"" + (cache.isArchived() ? "True" : "False") + "\" "); + gpx.append("xmlns:groundspeak=\"http://www.groundspeak.com/cache/1/0/1\">"); + + gpx.append("<groundspeak:name>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getName())); + gpx.append("</groundspeak:name>"); + + gpx.append("<groundspeak:placed_by>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getOwner())); + gpx.append("</groundspeak:placed_by>"); + + gpx.append("<groundspeak:owner>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getOwnerReal())); + gpx.append("</groundspeak:owner>"); + + gpx.append("<groundspeak:type>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getType().toString())); //TODO: Correct (english) string + gpx.append("</groundspeak:type>"); + + gpx.append("<groundspeak:container>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getSize().toString())); //TODO: Correct (english) string + gpx.append("</groundspeak:container>"); + + //TODO: Attributes + + gpx.append("<groundspeak:difficulty>"); + gpx.append(Float.toString(cache.getDifficulty())); + gpx.append("</groundspeak:difficulty>"); + + gpx.append("<groundspeak:terrain>"); + gpx.append(Float.toString(cache.getTerrain())); + gpx.append("</groundspeak:terrain>"); + + gpx.append("<groundspeak:country>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getLocation())); + gpx.append("</groundspeak:country>"); + + gpx.append("<groundspeak:state>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getLocation())); + gpx.append("</groundspeak:state>"); + + gpx.append("<groundspeak:short_description html=\"True\">"); + gpx.append(StringEscapeUtils.escapeXml(cache.getShortDescription())); + gpx.append("</groundspeak:short_description>"); + + gpx.append("<groundspeak:long_description html=\"True\">"); + gpx.append(StringEscapeUtils.escapeXml(cache.getDescription())); + gpx.append("</groundspeak:long_description>"); + + gpx.append("<groundspeak:encoded_hints>"); + gpx.append(StringEscapeUtils.escapeXml(cache.getHint())); + gpx.append("</groundspeak:encoded_hints>"); + + gpx.append("</groundspeak:cache>"); + + //TODO: Waypoints + //TODO: Logs + + gpx.append("</wpt>"); + + publishProgress(i + 1); + } + } catch (Exception e) { + Log.e(Settings.tag, "GpxExport.ExportTask generation", e); + return false; + } + + gpx.append("</gpx>"); + + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + exportLocation.mkdirs(); + + SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + exportFile = new File(exportLocation + "/" + fileNameDateFormat.format(new Date()) + ".gpx"); + + OutputStream os = null; + Writer fw = null; + try { + os = new FileOutputStream(exportFile); + fw = new OutputStreamWriter(os, "UTF-8"); + fw.write(gpx.toString()); + } catch (IOException e) { + Log.e(Settings.tag, "GpxExport.ExportTask export", e); + return false; + } finally { + if (fw != null) { + try { + fw.close(); + } catch (IOException e) { + Log.e(Settings.tag, "GpxExport.ExportTask export", e); + return false; + } + } + } + } else { + return false; + } + + return true; + } + + @Override + protected void onPostExecute(Boolean result) { + progress.dismiss(); + if (result) { + ActivityMixin.showToast(activity, getName() + " " + getString(R.string.export_exportedto) + ": " + exportFile.toString()); + } else { + ActivityMixin.showToast(activity, getString(R.string.export_failed)); + } + } + + @Override + protected void onProgressUpdate(Integer... status) { + progress.setProgress(status[0]); + } + } +} |