diff options
-rw-r--r-- | res/layout/main_layout.xml | 2 | ||||
-rw-r--r-- | res/layout/search_dialog.xml | 24 | ||||
-rw-r--r-- | res/menu/options_menu.xml | 5 | ||||
-rw-r--r-- | res/values/strings.xml | 5 | ||||
-rw-r--r-- | src/org/madore/android/unicodeMap/UnicodeDatabase.java | 12 | ||||
-rw-r--r-- | src/org/madore/android/unicodeMap/UnicodeMapActivity.java | 109 |
6 files changed, 151 insertions, 6 deletions
diff --git a/res/layout/main_layout.xml b/res/layout/main_layout.xml index 571a2dc..89480d7 100644 --- a/res/layout/main_layout.xml +++ b/res/layout/main_layout.xml @@ -21,7 +21,7 @@ android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" /> - <Button android:id="@+id/button" + <Button android:id="@+id/copyButton" android:layout_width="wrap_content" android:layout_height="fill_parent" android:text="@string/copy_button" /> diff --git a/res/layout/search_dialog.xml b/res/layout/search_dialog.xml new file mode 100644 index 0000000..7c7be92 --- /dev/null +++ b/res/layout/search_dialog.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:padding="10dp" + android:orientation="vertical"> + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <EditText android:id="@+id/searchTerm" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" /> + <Button android:id="@+id/searchButton" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:text="@string/search_button" /> + </LinearLayout> + <TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="@string/search_hint" /> +</LinearLayout> diff --git a/res/menu/options_menu.xml b/res/menu/options_menu.xml new file mode 100644 index 0000000..a187813 --- /dev/null +++ b/res/menu/options_menu.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/menuSearch" + android:title="@string/menu_search" /> +</menu> diff --git a/res/values/strings.xml b/res/values/strings.xml index 605a255..b77be4a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6,4 +6,9 @@ <string name="copy_button">Copy</string> <string name="copied_toast">Copied to clipboard</string> <string name="empty_list">(Empty!)</string> + <string name="menu_search">Search</string> + <string name="search_title">Search in character names</string> + <string name="search_button">Search</string> + <string name="search_hint">Case is insensitive and matches whole string; use a % sign as wildcard (e.g.: "latin%letter r%")</string> + <string name="list_too_long">Only %d first results shown</string> </resources> diff --git a/src/org/madore/android/unicodeMap/UnicodeDatabase.java b/src/org/madore/android/unicodeMap/UnicodeDatabase.java index b81c99a..84efb63 100644 --- a/src/org/madore/android/unicodeMap/UnicodeDatabase.java +++ b/src/org/madore/android/unicodeMap/UnicodeDatabase.java @@ -217,7 +217,17 @@ public class UnicodeDatabase { "id >= ? AND id < ?", new String[] { Integer.toString(from), Integer.toString(to) }, - null, null, null, null); + null, null, "id", null); + return new CursorIterable(c); + } + + public Iterable<UnicodeCharacter> searchNames(String like, int limit) { + final Cursor c + = db.query(UNICODE_TABLE_NAME, queryColumns, + "name LIKE ?", + new String[] { like }, + null, null, "id", + (limit>0)?Integer.toString(limit):null); return new CursorIterable(c); } diff --git a/src/org/madore/android/unicodeMap/UnicodeMapActivity.java b/src/org/madore/android/unicodeMap/UnicodeMapActivity.java index 1b43d9d..74dca91 100644 --- a/src/org/madore/android/unicodeMap/UnicodeMapActivity.java +++ b/src/org/madore/android/unicodeMap/UnicodeMapActivity.java @@ -4,13 +4,18 @@ import java.util.Arrays; import java.util.List; import java.util.ArrayList; import java.util.Formatter; +import java.util.regex.Pattern; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; +import android.view.ViewGroup; import android.view.Window; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MenuInflater; import android.view.KeyEvent; import android.widget.*; import android.text.ClipboardManager; @@ -83,7 +88,10 @@ public final class UnicodeMapActivity extends ListActivity { list); stack.add(adapter); positionStack.add(position); - positionYStack.add(view.getTop()); + if ( view != null ) + positionYStack.add(view.getTop()); + else + positionYStack.add(0); setListAdapter(adapter); } else throw new AssertionError("unknown UnicodeDisplayable"); @@ -159,12 +167,12 @@ public final class UnicodeMapActivity extends ListActivity { setListAdapter(rootAdapter); final ClipboardManager cmgr = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE); - final Button btn = (Button) findViewById(R.id.button); + final Button btn = (Button) findViewById(R.id.copyButton); textForm = (EditText) findViewById(R.id.edit); btn.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { cmgr.setText(textForm.getText()); - Toast.makeText(getApplicationContext(), + Toast.makeText(UnicodeMapActivity.this, R.string.copied_toast, Toast.LENGTH_SHORT).show(); } @@ -176,17 +184,110 @@ public final class UnicodeMapActivity extends ListActivity { lv.setOnItemLongClickListener(listener); } + final static int searchLimit = 1000; + + protected void doSearch(String s) { + List<UnicodeDisplayable> list + = new ArrayList<UnicodeDisplayable>(128); + for ( UnicodeCharacter ch : db.searchNames(s,searchLimit+1) ) + list.add(ch); + boolean overflowed = ( list.size() > searchLimit ); + if ( overflowed ) + list.remove(list.size()-1); + UnicodeArrayAdapter adapter + = new UnicodeArrayAdapter(UnicodeMapActivity.this, + list); + stack.add(adapter); + final ListView lv = getListView(); + int position = lv.getSelectedItemPosition(); + int position0 = lv.getFirstVisiblePosition(); + if ( position == AdapterView.INVALID_POSITION ) + position = position0; + positionStack.add(position); + View view = lv.getChildAt(position-position0); + if ( view != null ) + positionYStack.add(view.getTop()); + else + positionYStack.add(0); + setListAdapter(adapter); + if ( overflowed ) { + String str = getResources().getString(R.string.list_too_long); + android.util.Log.e("UnicodeMapActivity", "format is: "+str); + Toast.makeText(UnicodeMapActivity.this, + String.format(str, searchLimit), + Toast.LENGTH_SHORT).show(); + } + } + + protected void querySearch() { + final Dialog dialog = new Dialog(UnicodeMapActivity.this); + // dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setTitle(R.string.search_title); + dialog.setOwnerActivity(this); + dialog.setContentView(R.layout.search_dialog); + dialog.setCancelable(true); + dialog.getWindow().setLayout(ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + final EditText textForm + = (EditText) dialog.findViewById(R.id.searchTerm); + textForm.setOnKeyListener(new View.OnKeyListener() { + public boolean onKey(View view, int keyCode, KeyEvent event) { + if ( ( event.getAction() == KeyEvent.ACTION_DOWN ) + && ( keyCode == KeyEvent.KEYCODE_ENTER ) ) { + String s = textForm.getText().toString(); + if ( ! Pattern.matches("^\\s*$", s) ) + doSearch(s); + dialog.dismiss(); + return true; + } + return false; + } + }); + final Button btn = (Button) dialog.findViewById(R.id.searchButton); + btn.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + String s = textForm.getText().toString(); + if ( ! Pattern.matches("^\\s*$", s) ) { + doSearch(s); + dialog.dismiss(); + } + } + }); + dialog.show(); + } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if ( ( keyCode == KeyEvent.KEYCODE_BACK) && stack.size() > 1 ) { + if ( ( keyCode == KeyEvent.KEYCODE_BACK ) && stack.size() > 1 ) { final ListView lv = getListView(); stack.remove(stack.size()-1); setListAdapter(stack.get(stack.size()-1)); lv.setSelectionFromTop(positionStack.remove(positionStack.size()-1), positionYStack.remove(positionYStack.size()-1)); return true; + } else if ( keyCode == KeyEvent.KEYCODE_SEARCH ) { + querySearch(); + return true; } return super.onKeyDown(keyCode, event); } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch ( item.getItemId() ) { + case R.id.menuSearch: + querySearch(); + return true; + default: + return super.onContextItemSelected(item); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.options_menu, menu); + return true; + } + } |