Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
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/. */
6 package org.mozilla.gecko;
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;
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;
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;
34 public EditBookmarkDialog(Context context) {
35 mContext = context;
36 }
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;
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 }
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;
67 // A stored text watcher to do the real verification of a field
68 protected EditBookmarkTextWatcher mPairedTextWatcher;
70 // Whether or not the ok button should be enabled.
71 protected boolean mEnabled = true;
73 public EditBookmarkTextWatcher(AlertDialog aDialog) {
74 mDialog = aDialog;
75 }
77 public void setPairedTextWatcher(EditBookmarkTextWatcher aTextWatcher) {
78 mPairedTextWatcher = aTextWatcher;
79 }
81 public boolean isEnabled() {
82 return mEnabled;
83 }
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 }
93 @Override
94 public void afterTextChanged(Editable s) {}
95 @Override
96 public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
97 }
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 }
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 }
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 }
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 }
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 }
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 }
164 @Override
165 public void onPostExecute(Bookmark bookmark) {
166 if (bookmark == null)
167 return;
169 show(bookmark.id, bookmark.title, bookmark.url, bookmark.keyword);
170 }
171 }).execute();
172 }
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);
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);
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 }
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 });
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 });
225 final AlertDialog dialog = editPrompt.create();
227 // Create our TextWatchers
228 LocationTextWatcher locationTextWatcher = new LocationTextWatcher(dialog);
229 KeywordTextWatcher keywordTextWatcher = new KeywordTextWatcher(dialog);
231 // Cross reference the TextWatchers
232 locationTextWatcher.setPairedTextWatcher(keywordTextWatcher);
233 keywordTextWatcher.setPairedTextWatcher(locationTextWatcher);
235 // Add the TextWatcher Listeners
236 locationText.addTextChangedListener(locationTextWatcher);
237 keywordText.addTextChangedListener(keywordTextWatcher);
239 dialog.show();
240 }
241 }