1 /***
2 * Ambient - A music player for the Android platform
3 Copyright (C) 2007 Martin Vysny
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package sk.baka.ambient.views.gesturelist.keypad;
20
21 import java.util.List;
22
23 import sk.baka.ambient.R;
24 import sk.baka.ambient.views.ContainedPopupWindow;
25 import sk.baka.ambient.views.gesturelist.GesturesListView;
26 import android.view.KeyEvent;
27 import android.widget.AdapterView;
28 import android.widget.TextView;
29
30 /***
31 * Performs search using a keypad.
32 *
33 * @author Martin Vysny
34 */
35 public final class KeypadSearch extends AbstractKeypadHandler {
36
37 /***
38 * Creates new search utility class.
39 *
40 * @param owner
41 * owner listview
42 */
43 public KeypadSearch(final GesturesListView owner) {
44 super(owner);
45 queryWindow = new ContainedPopupWindow(owner,
46 new ContainedPopupWindow.IPlaceable() {
47 public int[] getCoordinates(ContainedPopupWindow popup,
48 CharSequence text, TextView textView) {
49 final int y = owner.getHeight()
50 - (int) textView.getPaint().getTextSize();
51 final int x = (owner.getWidth() - (int) textView
52 .getPaint().measureText(text.toString())) / 2;
53 return new int[] { x, y };
54 }
55 });
56 }
57
58 @Override
59 protected boolean onKey(int keyCode, int count, KeyEvent event) {
60 final int c = event.getUnicodeChar();
61 if (Character.isLetterOrDigit(c)) {
62 addCharacter((char) c);
63 return true;
64 }
65 switch (keyCode) {
66 case KeyEvent.KEYCODE_DEL:
67 deleteCharacter();
68 return true;
69 case KeyEvent.KEYCODE_DPAD_UP: {
70 final String q = query.toString();
71 int start = owner.getSelectedItemPosition();
72 if (start == AdapterView.INVALID_POSITION) {
73 start = owner.getModel().getModel().size();
74 }
75 final int i = findFirst(start - 1, -1, q);
76 if (i >= 0) {
77 owner.setSelection(i);
78 }
79 }
80 return true;
81 case KeyEvent.KEYCODE_DPAD_DOWN: {
82 final String q = query.toString();
83 int start = owner.getSelectedItemPosition();
84 if (start == AdapterView.INVALID_POSITION) {
85 start = -1;
86 }
87 final int i = findFirst(start + 1, 1, q);
88 if (i >= 0) {
89 owner.setSelection(i);
90 }
91 }
92 return true;
93 case KeyEvent.KEYCODE_ENTER:
94 case KeyEvent.KEYCODE_DPAD_CENTER:
95 case KeyEvent.KEYCODE_BACK:
96 stop();
97 return true;
98 }
99 stop();
100 return false;
101 }
102
103 private void deleteCharacter() {
104 if (query.length() == 0) {
105 return;
106 }
107 query.deleteCharAt(query.length() - 1);
108 queryChanged();
109 }
110
111 /***
112 * Contains the search query.
113 */
114 private final StringBuilder query = new StringBuilder();
115
116 /***
117 * Displays the search query.
118 */
119 private final ContainedPopupWindow queryWindow;
120
121 private void addCharacter(char c) {
122 query.append(c);
123 queryChanged();
124 }
125
126 private void queryChanged() {
127 if (query.length() == 0) {
128 stop();
129 return;
130 }
131 final String q = query.toString();
132 queryWindow.setText(q);
133 int start = owner.getSelectedItemPosition();
134 if (start == AdapterView.INVALID_POSITION) {
135 start = 0;
136 }
137 int i = findFirst(start, 1, q);
138 if (i < 0) {
139 i = findFirst(0, 1, q);
140 }
141 owner.setSelection(i);
142 }
143
144 /***
145 * Finds first item which contains given substring.
146 *
147 * @param startIndex
148 * search from this item onwards, including the item.
149 * @param query
150 * search for this substring
151 * @return index of item or -1.
152 */
153 private int findFirst(final int startIndex, final int delta,
154 final String query) {
155 final String q = query.toLowerCase();
156 final List<String> strModel = owner.getModel().getModelAsString();
157 final int modelLen = strModel.size();
158
159 for (int i = startIndex; (i < modelLen) && (i >= 0); i += delta) {
160 if (strModel.get(i).contains(q)) {
161 return i;
162 }
163 }
164 return -1;
165 }
166
167 @Override
168 public boolean isActivatedByKey(int keyCode, final KeyEvent event) {
169 final int c = event.getUnicodeChar();
170 return Character.isLetterOrDigit(c);
171 }
172
173 @Override
174 public boolean isStarted() {
175 return query.length() > 0;
176 }
177
178 @Override
179 public void start() {
180 query.delete(0, query.length());
181 owner.setTooltip(R.string.keySearch, this, false);
182 }
183
184 @Override
185 public void stop() {
186 query.delete(0, query.length());
187 queryWindow.dismiss();
188 owner.clearTooltip(this);
189 }
190 }