diff options
| -rw-r--r-- | AndroidManifest.xml | 8 | ||||
| -rw-r--r-- | res/layout/init.xml | 20 | ||||
| -rw-r--r-- | res/layout/mapfile_item.xml | 33 | ||||
| -rw-r--r-- | res/values/strings.xml | 7 | ||||
| -rw-r--r-- | src/cgeo/geocaching/cgFileList.java | 260 | ||||
| -rw-r--r-- | src/cgeo/geocaching/cgMapfileListAdapter.java | 90 | ||||
| -rw-r--r-- | src/cgeo/geocaching/cgSelectMapfile.java | 55 | ||||
| -rw-r--r-- | src/cgeo/geocaching/cgeoinit.java | 40 |
8 files changed, 505 insertions, 8 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 928a0b8..9b92d7f 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -280,5 +280,13 @@ <action android:name="cgeo.geocaching.CGEOGPXES"/> </intent-filter> </activity> + <activity + android:name=".cgSelectMapfile" + android:label="@string/app_name" + android:configChanges="keyboardHidden|orientation" > + <intent-filter> + <action android:name="cgeo.geocaching.CGEOSELMAP"/> + </intent-filter> + </activity> </application> </manifest> diff --git a/res/layout/init.xml b/res/layout/init.xml index 3f4d893..33354f0 100644 --- a/res/layout/init.xml +++ b/res/layout/init.xml @@ -494,11 +494,21 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:prompt="@string/init_mapsource_select" /> - <EditText style="@style/edittext" - android:id="@+id/mapfile" - android:singleLine="true" - android:lines="1" - android:scrollHorizontally="true" /> + <LinearLayout + android:id="@+id/init_mapfilegroup" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + <Button style="@style/button" + android:id="@+id/select_mapfile" + android:text="@string/init_select_mapfile" + android:layout_width="wrap_content" /> + <EditText style="@style/edittext" + android:id="@+id/mapfile" + android:singleLine="true" + android:lines="1" + android:scrollHorizontally="true" /> + </LinearLayout> <!-- ** --> <RelativeLayout style="@style/separator_horizontal_layout" > <View style="@style/separator_horizontal" /> diff --git a/res/layout/mapfile_item.xml b/res/layout/mapfile_item.xml new file mode 100644 index 0000000..a024b81 --- /dev/null +++ b/res/layout/mapfile_item.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/mapfile_item" + android:layout_height="wrap_content" + android:layout_width="fill_parent" + android:layout_margin="3dip" + android:paddingLeft="5dip" + android:paddingRight="5dip" + android:paddingBottom="7dip" + android:paddingTop="7dip" + android:orientation="vertical" + android:background="?background_color" > + <TextView android:id="@+id/mapfilepath" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:scrollHorizontally="true" + android:textSize="12dip" + android:gravity="right" + android:lines="1" + android:singleLine="true" + android:ellipsize="marquee" + android:textColor="?text_color_grey" /> + <TextView android:id="@+id/mapfilename" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:scrollHorizontally="true" + android:textSize="22dip" + android:gravity="left" + android:lines="1" + android:singleLine="true" + android:ellipsize="marquee" + android:textColor="?text_color" /> +</LinearLayout>
\ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 6c9ab8f..2266c6d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -402,6 +402,7 @@ <string name="init_mapsources">Map Sources</string> <!-- since: 2.26 RC3 --> <string name="init_mapsources_description">Here you can select the source for your maps. As an alternative to Google maps various OpenStreetMap styles are available and even off line map files (see http://code.google.com/p/mapsforge/ for details).</string> <!-- since: 2.26 RC3 --> <string name="init_mapsource_select">Select map source</string> + <string name="init_select_mapfile">...</string> <!-- map sources --> <string-array name="map_sources"> @@ -511,6 +512,12 @@ <string name="cache_spoiler_images_loading">Loading spoiler images...</string> <string name="cache_log_types">Log types</string> <!-- since: 2.10 RC2 --> <string name="cache_coordinates_no">This cache has no coordinates.</string> <!-- since: 2.26 RC2 --> + + <!-- file list base --> + <string name="file_searching_in">Searching for files\nin</string> + <string name="file_list_no_files">Sorry, c:geo found no appropriate files.</string> + <string name="file_searching">Searching for matching files</string> + <string name="file_title_searching">Searching</string> <!-- gpx --> <string name="gpx_import_searching_in">Searching for .gpx files\nin</string> diff --git a/src/cgeo/geocaching/cgFileList.java b/src/cgeo/geocaching/cgFileList.java new file mode 100644 index 0000000..2767cfe --- /dev/null +++ b/src/cgeo/geocaching/cgFileList.java @@ -0,0 +1,260 @@ +package cgeo.geocaching; + +import java.io.File; +import java.util.ArrayList; + +import android.app.Activity; +import android.app.ListActivity; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.view.View; +import android.widget.ArrayAdapter; + +public abstract class cgFileList<T extends ArrayAdapter<File>> extends ListActivity { + + private ArrayList<File> files = new ArrayList<File>(); + private cgeoapplication app = null; + private cgSettings settings = null; + private cgBase base = null; + private cgWarning warning = null; + private Activity activity = null; + private T adapter = null; + private ProgressDialog waitDialog = null; + private Resources res = null; + private loadFiles searchingThread = null; + private boolean endSearching = false; + private int listId = 1; + final private Handler changeWaitDialogHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + if (msg.obj != null && waitDialog != null) { + waitDialog.setMessage(res.getString(R.string.file_searching_in) + " " + (String) msg.obj); + } + } + }; + final private Handler loadFilesHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + try { + if (files == null || files.isEmpty()) { + if (waitDialog != null) { + waitDialog.dismiss(); + } + + warning.showToast(res.getString(R.string.file_list_no_files)); + + finish(); + return; + } else { + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } + + if (waitDialog != null) { + waitDialog.dismiss(); + } + } catch (Exception e) { + if (waitDialog != null) { + waitDialog.dismiss(); + } + Log.e(cgSettings.tag, "cgFileList.loadFilesHandler: " + e.toString()); + } + } + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // init + activity = this; + res = this.getResources(); + app = (cgeoapplication) this.getApplication(); + settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0)); + base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0)); + warning = new cgWarning(this); + + // set layout + if (settings.skin == 1) { + setTheme(R.style.light); + } else { + setTheme(R.style.dark); + } + setContentView(R.layout.gpx); + base.setTitle(activity, res.getString(R.string.gpx_import_title)); + + // google analytics + base.sendAnal(activity, "/file-import"); + + Bundle extras = getIntent().getExtras(); + if (extras != null) { + listId = extras.getInt("list"); + } + if (listId <= 0) { + listId = 1; + } + + setAdapter(); + + waitDialog = ProgressDialog.show( + this, + res.getString(R.string.file_title_searching), + res.getString(R.string.file_searching), + true, + true, + new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface arg0) { + if (searchingThread != null && searchingThread.isAlive()) { + searchingThread.notifyEnd(); + } + if (files.isEmpty() == true) { + finish(); + } + } + } + ); + + endSearching = false; + searchingThread = new loadFiles(); + searchingThread.start(); + } + + @Override + public void onResume() { + super.onResume(); + + settings.load(); + } + + final protected cgSettings getSettings() { + return settings; + } + + protected abstract T getAdapter(ArrayList<File> files); + + private void setAdapter() { + if (adapter == null) { + adapter = getAdapter(files); + setListAdapter(adapter); + } + } + + /** + * Gets the base folder for file searches + * @return The folder to start the recursive search in + */ + protected abstract String[] getBaseFolders(); + + private class loadFiles extends Thread { + public void notifyEnd() { + endSearching = true; + } + + @Override + public void run() { + ArrayList<File> list = new ArrayList<File>(); + + try { + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) == true) { + boolean loaded = false; + for(String baseFolder : getBaseFolders()) + { + final File dir = new File(baseFolder); + + if (dir.exists() && dir.isDirectory()) { + listDir(list, dir); + if (list.size() > 0) { + loaded = true; + break; + } + } + } + if (!loaded) { + listDir(list, Environment.getExternalStorageDirectory()); + } + } else { + Log.w(cgSettings.tag, "No external media mounted."); + } + } catch (Exception e) { + Log.e(cgSettings.tag, "cgFileList.loadFiles.run: " + e.toString()); + } + + final Message msg = new Message(); + msg.obj = "loaded directories"; + changeWaitDialogHandler.sendMessage(msg); + + files.addAll(list); + list.clear(); + + loadFilesHandler.sendMessage(new Message()); + } + } + + /** + * Get the file extension to search for + * @return The file extension + */ + protected abstract String getFileExtension(); + + private void listDir(ArrayList<File> list, File directory) { + if (directory == null || directory.isDirectory() == false || directory.canRead() == false) { + return; + } + + final File[] listPre = directory.listFiles(); + String fileExt = getFileExtension(); + + if (listPre != null && listPre.length > 0) { + final int listCnt = listPre.length; + + for (int i = 0; i < listCnt; i++) { + if (endSearching == true) { + return; + } + + if (listPre[i].canRead() == true && listPre[i].isFile() == true) { + final String[] nameParts = listPre[i].getName().split("\\."); + if (nameParts.length > 1) { + final String extension = nameParts[(nameParts.length - 1)].toLowerCase(); + + if (extension.equals(fileExt) == false) { + continue; + } + } else { + continue; // file has no extension + } + + list.add(listPre[i]); // add file to list + } else if (listPre[i].canRead() == true && listPre[i].isDirectory() == true) { + final Message msg = new Message(); + String name = listPre[i].getName(); + if (name.substring(0, 1).equals(".") == true) { + continue; // skip hidden directories + } + if (name.length() > 16) { + name = name.substring(0, 14) + "..."; + } + msg.obj = name; + changeWaitDialogHandler.sendMessage(msg); + + listDir(list, listPre[i]); // go deeper + } + } + } + + return; + } + + public void goHome(View view) { + base.goHome(activity); + } +} diff --git a/src/cgeo/geocaching/cgMapfileListAdapter.java b/src/cgeo/geocaching/cgMapfileListAdapter.java new file mode 100644 index 0000000..ba12280 --- /dev/null +++ b/src/cgeo/geocaching/cgMapfileListAdapter.java @@ -0,0 +1,90 @@ +package cgeo.geocaching; + +import java.io.File; +import java.util.List; + +import android.app.Activity; +import android.graphics.Typeface; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +public class cgMapfileListAdapter extends ArrayAdapter<File> { + + private cgSelectMapfile parentView; + private LayoutInflater inflater; + private MapfileView holder; + + public cgMapfileListAdapter(cgSelectMapfile parentIn, List<File> listIn) { + super(parentIn, 0, listIn); + + parentView = parentIn; + } + + @Override + public View getView(int position, View rowView, ViewGroup parent) { + if (inflater == null) inflater = ((Activity)getContext()).getLayoutInflater(); + + if (position > getCount()) { + Log.w(cgSettings.tag, "cgGPXListAdapter.getView: Attempt to access missing item #" + position); + return null; + } + + File file = getItem(position); + + if (rowView == null) { + rowView = (View)inflater.inflate(R.layout.mapfile_item, null); + + holder = new MapfileView(); + holder.filepath = (TextView)rowView.findViewById(R.id.mapfilepath); + holder.filename = (TextView)rowView.findViewById(R.id.mapfilename); + + rowView.setTag(holder); + } else { + holder = (MapfileView)rowView.getTag(); + } + + File current = new File(parentView.getCurrentMapfile()); + + if (file.equals(current)) { + holder.filename.setTypeface(holder.filename.getTypeface(), Typeface.BOLD); + } else { + holder.filename.setTypeface(holder.filename.getTypeface(), Typeface.NORMAL); + } + + final touchListener touchLst = new touchListener(file); + rowView.setOnClickListener(touchLst); + + holder.filepath.setText(file.getParent()); + holder.filename.setText(file.getName()); + + return rowView; + } + + @Override + public void notifyDataSetChanged() { + super.notifyDataSetChanged(); + } + + private class touchListener implements View.OnClickListener { + private File file = null; + + public touchListener(File fileIn) { + file = fileIn; + } + + // tap on item + public void onClick(View view) { + parentView.setMapfile(file.toString()); + parentView.close(); + } + } + + private class MapfileView { + public TextView filepath; + public TextView filename; + } +} diff --git a/src/cgeo/geocaching/cgSelectMapfile.java b/src/cgeo/geocaching/cgSelectMapfile.java new file mode 100644 index 0000000..b64148f --- /dev/null +++ b/src/cgeo/geocaching/cgSelectMapfile.java @@ -0,0 +1,55 @@ +package cgeo.geocaching; + +import java.io.File; +import java.util.ArrayList; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Environment; + +public class cgSelectMapfile extends cgFileList<cgMapfileListAdapter> { + + String mapFile; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mapFile = getSettings().getMapFile(); + } + + public void close() { + + Intent intent = new Intent(); + intent.putExtra("mapfile", mapFile); + + setResult(RESULT_OK, intent); + + finish(); + } + + @Override + protected cgMapfileListAdapter getAdapter(ArrayList<File> files) { + return new cgMapfileListAdapter(this, files); + } + + @Override + protected String[] getBaseFolders() { + String base = Environment.getExternalStorageDirectory().toString(); + return new String[]{base + "/mfmaps", base + "/Locus/mapsVector"}; + } + + @Override + protected String getFileExtension() { + return "map"; + } + + public String getCurrentMapfile() { + return mapFile; + } + + public void setMapfile(String newMapfile) { + mapFile = newMapfile; + } + +} diff --git a/src/cgeo/geocaching/cgeoinit.java b/src/cgeo/geocaching/cgeoinit.java index 0be2093..d78a57d 100644 --- a/src/cgeo/geocaching/cgeoinit.java +++ b/src/cgeo/geocaching/cgeoinit.java @@ -21,6 +21,7 @@ import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; +import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import android.widget.AdapterView.OnItemSelectedListener; @@ -31,6 +32,8 @@ import cgeo.geocaching.cgSettings.mapSourceEnum; public class cgeoinit extends Activity { + private final int SELECT_MAPFILE_REQUEST=1; + private cgeoapplication app = null; private Resources res = null; private Activity activity = null; @@ -402,8 +405,17 @@ public class cgeoinit extends Activity { mapSourceSelector.setSelection(mapsource); mapSourceSelector.setOnItemSelectedListener(new cgeoChangeMapSource()); - EditText mfmapFileEdit = (EditText) findViewById(R.id.mapfile); - mfmapFileEdit.setText(prefs.getString("mfmapfile", "")); + initMapfileEdittext(false); + + Button selectMapfile = (Button) findViewById(R.id.select_mapfile); + selectMapfile.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + Intent selectIntent = new Intent(activity, cgSelectMapfile.class); + activity.startActivityForResult(selectIntent, SELECT_MAPFILE_REQUEST); + } + }); setMapFileEditState(); @@ -418,6 +430,14 @@ public class cgeoinit extends Activity { } + private void initMapfileEdittext(boolean setFocus) { + EditText mfmapFileEdit = (EditText) findViewById(R.id.mapfile); + mfmapFileEdit.setText(prefs.getString("mfmapfile", "")); + if (setFocus) { + mfmapFileEdit.requestFocus(); + } + } + public void backup(View view) { final String file = app.backupDatabase(); @@ -447,7 +467,7 @@ public class cgeoinit extends Activity { } private void setMapFileEditState() { - EditText mapFileEdit = (EditText) findViewById(R.id.mapfile); + LinearLayout mapFileEdit = (LinearLayout) findViewById(R.id.init_mapfilegroup); if (settings.mapProvider == mapSourceEnum.mapsforgeOffline) { mapFileEdit.setVisibility(View.VISIBLE); } else { @@ -946,6 +966,20 @@ public class cgeoinit extends Activity { } } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == SELECT_MAPFILE_REQUEST) { + if (resultCode == RESULT_OK) { + if (data.hasExtra("mapfile")) { + settings.setMapFile(data.getStringExtra("mapfile")); + } + } + initMapfileEdittext(true); + } + } + public void goHome(View view) { base.goHome(activity); } |
