aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorSammysHP <sven@sammyshp.de>2012-04-06 20:24:44 +0200
committerSammysHP <sven@sammyshp.de>2012-04-06 20:24:44 +0200
commitc5e9616a2202c939ed73e8d27015b78e005970cb (patch)
treefb2482d71a4a5b3d55ea46a24b59683f905b0a4e /main
parent73b0a45d249ce13139b003732e66c540226989d4 (diff)
downloadcgeo-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')
-rw-r--r--main/res/layout/fieldnote_export_dialog.xml34
-rw-r--r--main/res/values-de/strings.xml12
-rw-r--r--main/res/values/strings.xml14
-rw-r--r--main/src/cgeo/geocaching/cgeocaches.java231
-rw-r--r--main/src/cgeo/geocaching/export/AbstractExport.java19
-rw-r--r--main/src/cgeo/geocaching/export/Export.java13
-rw-r--r--main/src/cgeo/geocaching/export/ExportFactory.java58
-rw-r--r--main/src/cgeo/geocaching/export/FieldnoteExport.java223
-rw-r--r--main/src/cgeo/geocaching/export/GpxExport.java216
9 files changed, 615 insertions, 205 deletions
diff --git a/main/res/layout/fieldnote_export_dialog.xml b/main/res/layout/fieldnote_export_dialog.xml
new file mode 100644
index 0000000..f897985
--- /dev/null
+++ b/main/res/layout/fieldnote_export_dialog.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="3dip" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/export_fieldnotes_info" />
+
+ <CheckBox
+ android:id="@+id/upload"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/export_fieldnotes_upload" />
+
+ <CheckBox
+ android:id="@+id/onlynew"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:text="@string/export_fieldnotes_onlynew" />
+
+ <Button
+ android:id="@+id/export"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="3dip"
+ android:text="@string/export" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/main/res/values-de/strings.xml b/main/res/values-de/strings.xml
index fcd962c..50701b0 100644
--- a/main/res/values-de/strings.xml
+++ b/main/res/values-de/strings.xml
@@ -752,6 +752,18 @@
<string name="addon_missing_title">Add-On fehlt</string>
<string name="addon_download_prompt">Jetzt im Google Play Store herunterladen</string>
+ <!-- export -->
+ <string name="export">Exportieren</string>
+ <string name="export_as">Exportieren als…</string>
+ <string name="export_exportedto">exportiert nach</string>
+ <string name="export_failed">Exportieren fehlgeschlagen</string>
+ <string name="export_fieldnotes">Field Notes</string>
+ <string name="export_fieldnotes_info">Field Notes werden nach /sdcard/field-notes mit dem aktuellen Datum und Zeit als Dateiname exportiert.</string>
+ <string name="export_fieldnotes_upload">Hochladen auf geocaching.com</string>
+ <string name="export_fieldnotes_uploading">Hochladen…</string>
+ <string name="export_fieldnotes_onlynew">Nur seit letztem Export</string>
+ <string name="export_gpx">GPX</string>
+
<!-- attributes (permissions -> allowed, not allowed) -->
<string name="attribute_dogs_yes">Hunde erlaubt</string>
<string name="attribute_dogs_no">Hunde nicht erlaubt</string>
diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml
index b71942a..953b8ad 100644
--- a/main/res/values/strings.xml
+++ b/main/res/values/strings.xml
@@ -786,7 +786,19 @@
<!-- add-ons -->
<string name="addon_missing_title">Missing Add-On</string>
<string name="addon_download_prompt">Get it now from Google Play.</string>
-
+
+ <!-- export -->
+ <string name="export">Export</string>
+ <string name="export_as">Export as…</string>
+ <string name="export_exportedto">exported to</string>
+ <string name="export_failed">Exported failed</string>
+ <string name="export_fieldnotes">Field Notes</string>
+ <string name="export_fieldnotes_info">Field Notes will be exported into /sdcard/field-notes with current date and time as file name.</string>
+ <string name="export_fieldnotes_upload">Upload to geocaching.com</string>
+ <string name="export_fieldnotes_uploading">Uploading…</string>
+ <string name="export_fieldnotes_onlynew">Only since last export</string>
+ <string name="export_gpx">GPX</string>
+
<!-- attributes (permissions -> allowed, not allowed) -->
<string name="attribute_dogs_yes">Dogs allowed</string>
<string name="attribute_dogs_no">Dogs not allowed</string>
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]);
+ }
+ }
+}