|
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 package org.mozilla.gecko; |
|
7 |
|
8 import org.mozilla.gecko.db.BrowserContract.Bookmarks; |
|
9 import org.mozilla.gecko.db.BrowserDB; |
|
10 import org.mozilla.gecko.util.ThreadUtils; |
|
11 import org.mozilla.gecko.util.UiAsyncTask; |
|
12 |
|
13 import android.content.Context; |
|
14 import android.app.AlertDialog; |
|
15 import android.content.DialogInterface; |
|
16 import android.database.Cursor; |
|
17 import android.text.Editable; |
|
18 import android.text.TextWatcher; |
|
19 import android.view.LayoutInflater; |
|
20 import android.view.View; |
|
21 import android.widget.EditText; |
|
22 import android.widget.Toast; |
|
23 |
|
24 /** |
|
25 * A dialog that allows editing a bookmarks url, title, or keywords |
|
26 * <p> |
|
27 * Invoked by calling one of the {@link org.mozilla.gecko.EditBookmarkDialog.show} |
|
28 * methods. |
|
29 */ |
|
30 public class EditBookmarkDialog { |
|
31 private static final String LOGTAG = "GeckoEditBookmarkDialog"; |
|
32 private Context mContext; |
|
33 |
|
34 public EditBookmarkDialog(Context context) { |
|
35 mContext = context; |
|
36 } |
|
37 |
|
38 /** |
|
39 * A private struct to make it easier to pass bookmark data across threads |
|
40 */ |
|
41 private class Bookmark { |
|
42 int id; |
|
43 String title; |
|
44 String url; |
|
45 String keyword; |
|
46 |
|
47 public Bookmark(int aId, String aTitle, String aUrl, String aKeyword) { |
|
48 id = aId; |
|
49 title = aTitle; |
|
50 url = aUrl; |
|
51 keyword = aKeyword; |
|
52 } |
|
53 } |
|
54 |
|
55 /** |
|
56 * This text watcher to enable or disable the OK button if the dialog contains |
|
57 * valid information. This class is overridden to do data checking diffferent fields. |
|
58 * By itself, it always enables the button. |
|
59 * |
|
60 * Callers can also assing a paired partner to the TextWatcher, and callers will check |
|
61 * that both are enabled before enabling the ok button. |
|
62 */ |
|
63 private class EditBookmarkTextWatcher implements TextWatcher { |
|
64 // A stored reference to the dialog containing the text field being watched |
|
65 protected AlertDialog mDialog; |
|
66 |
|
67 // A stored text watcher to do the real verification of a field |
|
68 protected EditBookmarkTextWatcher mPairedTextWatcher; |
|
69 |
|
70 // Whether or not the ok button should be enabled. |
|
71 protected boolean mEnabled = true; |
|
72 |
|
73 public EditBookmarkTextWatcher(AlertDialog aDialog) { |
|
74 mDialog = aDialog; |
|
75 } |
|
76 |
|
77 public void setPairedTextWatcher(EditBookmarkTextWatcher aTextWatcher) { |
|
78 mPairedTextWatcher = aTextWatcher; |
|
79 } |
|
80 |
|
81 public boolean isEnabled() { |
|
82 return mEnabled; |
|
83 } |
|
84 |
|
85 // Textwatcher interface |
|
86 @Override |
|
87 public void onTextChanged(CharSequence s, int start, int before, int count) { |
|
88 // Disable if the we're disabled or the paired partner is disabled |
|
89 boolean enabled = mEnabled && (mPairedTextWatcher == null || mPairedTextWatcher.isEnabled()); |
|
90 mDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled); |
|
91 } |
|
92 |
|
93 @Override |
|
94 public void afterTextChanged(Editable s) {} |
|
95 @Override |
|
96 public void beforeTextChanged(CharSequence s, int start, int count, int after) {} |
|
97 } |
|
98 |
|
99 /** |
|
100 * A version of the EditBookmarkTextWatcher for the url field of the dialog. |
|
101 * Only checks if the field is empty or not. |
|
102 */ |
|
103 private class LocationTextWatcher extends EditBookmarkTextWatcher { |
|
104 public LocationTextWatcher(AlertDialog aDialog) { |
|
105 super(aDialog); |
|
106 } |
|
107 |
|
108 // Disables the ok button if the location field is empty. |
|
109 @Override |
|
110 public void onTextChanged(CharSequence s, int start, int before, int count) { |
|
111 mEnabled = (s.toString().trim().length() > 0); |
|
112 super.onTextChanged(s, start, before, count); |
|
113 } |
|
114 } |
|
115 |
|
116 /** |
|
117 * A version of the EditBookmarkTextWatcher for the keyword field of the dialog. |
|
118 * Checks if the field has any (non leading or trailing) spaces. |
|
119 */ |
|
120 private class KeywordTextWatcher extends EditBookmarkTextWatcher { |
|
121 public KeywordTextWatcher(AlertDialog aDialog) { |
|
122 super(aDialog); |
|
123 } |
|
124 |
|
125 @Override |
|
126 public void onTextChanged(CharSequence s, int start, int before, int count) { |
|
127 // Disable if the keyword contains spaces |
|
128 mEnabled = (s.toString().trim().indexOf(' ') == -1); |
|
129 super.onTextChanged(s, start, before, count); |
|
130 } |
|
131 } |
|
132 |
|
133 /** |
|
134 * Show the Edit bookmark dialog for a particular url. If the url is bookmarked multiple times |
|
135 * this will just edit the first instance it finds. |
|
136 * |
|
137 * @param url The url of the bookmark to edit. The dialog will look up other information like the id, |
|
138 * current title, or keywords associated with this url. If the url isn't bookmarked, the |
|
139 * dialog will fail silently. If the url is bookmarked multiple times, this will only show |
|
140 * information about the first it finds. |
|
141 */ |
|
142 public void show(final String url) { |
|
143 (new UiAsyncTask<Void, Void, Bookmark>(ThreadUtils.getBackgroundHandler()) { |
|
144 @Override |
|
145 public Bookmark doInBackground(Void... params) { |
|
146 Cursor cursor = BrowserDB.getBookmarkForUrl(mContext.getContentResolver(), url); |
|
147 if (cursor == null) { |
|
148 return null; |
|
149 } |
|
150 |
|
151 Bookmark bookmark = null; |
|
152 try { |
|
153 cursor.moveToFirst(); |
|
154 bookmark = new Bookmark(cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID)), |
|
155 cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.TITLE)), |
|
156 cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.URL)), |
|
157 cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.KEYWORD))); |
|
158 } finally { |
|
159 cursor.close(); |
|
160 } |
|
161 return bookmark; |
|
162 } |
|
163 |
|
164 @Override |
|
165 public void onPostExecute(Bookmark bookmark) { |
|
166 if (bookmark == null) |
|
167 return; |
|
168 |
|
169 show(bookmark.id, bookmark.title, bookmark.url, bookmark.keyword); |
|
170 } |
|
171 }).execute(); |
|
172 } |
|
173 |
|
174 /** |
|
175 * Show the Edit bookmark dialog for a set of data. This will show the dialog whether |
|
176 * a bookmark with this url exists or not, but the results will NOT be saved if the id |
|
177 * is not a valid bookmark id. |
|
178 * |
|
179 * @param id The id of the bookmark to change. If there is no bookmark with this ID, the dialog |
|
180 * will fail silently. |
|
181 * @param title The initial title to show in the dialog |
|
182 * @param url The initial url to show in the dialog |
|
183 * @param keyword The initial keyword to show in the dialog |
|
184 */ |
|
185 public void show(final int id, final String title, final String url, final String keyword) { |
|
186 AlertDialog.Builder editPrompt = new AlertDialog.Builder(mContext); |
|
187 final View editView = LayoutInflater.from(mContext).inflate(R.layout.bookmark_edit, null); |
|
188 editPrompt.setTitle(R.string.bookmark_edit_title); |
|
189 editPrompt.setView(editView); |
|
190 |
|
191 final EditText nameText = ((EditText) editView.findViewById(R.id.edit_bookmark_name)); |
|
192 final EditText locationText = ((EditText) editView.findViewById(R.id.edit_bookmark_location)); |
|
193 final EditText keywordText = ((EditText) editView.findViewById(R.id.edit_bookmark_keyword)); |
|
194 nameText.setText(title); |
|
195 locationText.setText(url); |
|
196 keywordText.setText(keyword); |
|
197 |
|
198 editPrompt.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() { |
|
199 @Override |
|
200 public void onClick(DialogInterface dialog, int whichButton) { |
|
201 (new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) { |
|
202 @Override |
|
203 public Void doInBackground(Void... params) { |
|
204 String newUrl = locationText.getText().toString().trim(); |
|
205 String newKeyword = keywordText.getText().toString().trim(); |
|
206 BrowserDB.updateBookmark(mContext.getContentResolver(), id, newUrl, nameText.getText().toString(), newKeyword); |
|
207 return null; |
|
208 } |
|
209 |
|
210 @Override |
|
211 public void onPostExecute(Void result) { |
|
212 Toast.makeText(mContext, R.string.bookmark_updated, Toast.LENGTH_SHORT).show(); |
|
213 } |
|
214 }).execute(); |
|
215 } |
|
216 }); |
|
217 |
|
218 editPrompt.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() { |
|
219 @Override |
|
220 public void onClick(DialogInterface dialog, int whichButton) { |
|
221 // do nothing |
|
222 } |
|
223 }); |
|
224 |
|
225 final AlertDialog dialog = editPrompt.create(); |
|
226 |
|
227 // Create our TextWatchers |
|
228 LocationTextWatcher locationTextWatcher = new LocationTextWatcher(dialog); |
|
229 KeywordTextWatcher keywordTextWatcher = new KeywordTextWatcher(dialog); |
|
230 |
|
231 // Cross reference the TextWatchers |
|
232 locationTextWatcher.setPairedTextWatcher(keywordTextWatcher); |
|
233 keywordTextWatcher.setPairedTextWatcher(locationTextWatcher); |
|
234 |
|
235 // Add the TextWatcher Listeners |
|
236 locationText.addTextChangedListener(locationTextWatcher); |
|
237 keywordText.addTextChangedListener(keywordTextWatcher); |
|
238 |
|
239 dialog.show(); |
|
240 } |
|
241 } |