View Javadoc

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 		// find such an item in the list view
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 }