1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/EditBookmarkDialog.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,241 @@ 1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +package org.mozilla.gecko; 1.10 + 1.11 +import org.mozilla.gecko.db.BrowserContract.Bookmarks; 1.12 +import org.mozilla.gecko.db.BrowserDB; 1.13 +import org.mozilla.gecko.util.ThreadUtils; 1.14 +import org.mozilla.gecko.util.UiAsyncTask; 1.15 + 1.16 +import android.content.Context; 1.17 +import android.app.AlertDialog; 1.18 +import android.content.DialogInterface; 1.19 +import android.database.Cursor; 1.20 +import android.text.Editable; 1.21 +import android.text.TextWatcher; 1.22 +import android.view.LayoutInflater; 1.23 +import android.view.View; 1.24 +import android.widget.EditText; 1.25 +import android.widget.Toast; 1.26 + 1.27 +/** 1.28 + * A dialog that allows editing a bookmarks url, title, or keywords 1.29 + * <p> 1.30 + * Invoked by calling one of the {@link org.mozilla.gecko.EditBookmarkDialog.show} 1.31 + * methods. 1.32 + */ 1.33 +public class EditBookmarkDialog { 1.34 + private static final String LOGTAG = "GeckoEditBookmarkDialog"; 1.35 + private Context mContext; 1.36 + 1.37 + public EditBookmarkDialog(Context context) { 1.38 + mContext = context; 1.39 + } 1.40 + 1.41 + /** 1.42 + * A private struct to make it easier to pass bookmark data across threads 1.43 + */ 1.44 + private class Bookmark { 1.45 + int id; 1.46 + String title; 1.47 + String url; 1.48 + String keyword; 1.49 + 1.50 + public Bookmark(int aId, String aTitle, String aUrl, String aKeyword) { 1.51 + id = aId; 1.52 + title = aTitle; 1.53 + url = aUrl; 1.54 + keyword = aKeyword; 1.55 + } 1.56 + } 1.57 + 1.58 + /** 1.59 + * This text watcher to enable or disable the OK button if the dialog contains 1.60 + * valid information. This class is overridden to do data checking diffferent fields. 1.61 + * By itself, it always enables the button. 1.62 + * 1.63 + * Callers can also assing a paired partner to the TextWatcher, and callers will check 1.64 + * that both are enabled before enabling the ok button. 1.65 + */ 1.66 + private class EditBookmarkTextWatcher implements TextWatcher { 1.67 + // A stored reference to the dialog containing the text field being watched 1.68 + protected AlertDialog mDialog; 1.69 + 1.70 + // A stored text watcher to do the real verification of a field 1.71 + protected EditBookmarkTextWatcher mPairedTextWatcher; 1.72 + 1.73 + // Whether or not the ok button should be enabled. 1.74 + protected boolean mEnabled = true; 1.75 + 1.76 + public EditBookmarkTextWatcher(AlertDialog aDialog) { 1.77 + mDialog = aDialog; 1.78 + } 1.79 + 1.80 + public void setPairedTextWatcher(EditBookmarkTextWatcher aTextWatcher) { 1.81 + mPairedTextWatcher = aTextWatcher; 1.82 + } 1.83 + 1.84 + public boolean isEnabled() { 1.85 + return mEnabled; 1.86 + } 1.87 + 1.88 + // Textwatcher interface 1.89 + @Override 1.90 + public void onTextChanged(CharSequence s, int start, int before, int count) { 1.91 + // Disable if the we're disabled or the paired partner is disabled 1.92 + boolean enabled = mEnabled && (mPairedTextWatcher == null || mPairedTextWatcher.isEnabled()); 1.93 + mDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled); 1.94 + } 1.95 + 1.96 + @Override 1.97 + public void afterTextChanged(Editable s) {} 1.98 + @Override 1.99 + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} 1.100 + } 1.101 + 1.102 + /** 1.103 + * A version of the EditBookmarkTextWatcher for the url field of the dialog. 1.104 + * Only checks if the field is empty or not. 1.105 + */ 1.106 + private class LocationTextWatcher extends EditBookmarkTextWatcher { 1.107 + public LocationTextWatcher(AlertDialog aDialog) { 1.108 + super(aDialog); 1.109 + } 1.110 + 1.111 + // Disables the ok button if the location field is empty. 1.112 + @Override 1.113 + public void onTextChanged(CharSequence s, int start, int before, int count) { 1.114 + mEnabled = (s.toString().trim().length() > 0); 1.115 + super.onTextChanged(s, start, before, count); 1.116 + } 1.117 + } 1.118 + 1.119 + /** 1.120 + * A version of the EditBookmarkTextWatcher for the keyword field of the dialog. 1.121 + * Checks if the field has any (non leading or trailing) spaces. 1.122 + */ 1.123 + private class KeywordTextWatcher extends EditBookmarkTextWatcher { 1.124 + public KeywordTextWatcher(AlertDialog aDialog) { 1.125 + super(aDialog); 1.126 + } 1.127 + 1.128 + @Override 1.129 + public void onTextChanged(CharSequence s, int start, int before, int count) { 1.130 + // Disable if the keyword contains spaces 1.131 + mEnabled = (s.toString().trim().indexOf(' ') == -1); 1.132 + super.onTextChanged(s, start, before, count); 1.133 + } 1.134 + } 1.135 + 1.136 + /** 1.137 + * Show the Edit bookmark dialog for a particular url. If the url is bookmarked multiple times 1.138 + * this will just edit the first instance it finds. 1.139 + * 1.140 + * @param url The url of the bookmark to edit. The dialog will look up other information like the id, 1.141 + * current title, or keywords associated with this url. If the url isn't bookmarked, the 1.142 + * dialog will fail silently. If the url is bookmarked multiple times, this will only show 1.143 + * information about the first it finds. 1.144 + */ 1.145 + public void show(final String url) { 1.146 + (new UiAsyncTask<Void, Void, Bookmark>(ThreadUtils.getBackgroundHandler()) { 1.147 + @Override 1.148 + public Bookmark doInBackground(Void... params) { 1.149 + Cursor cursor = BrowserDB.getBookmarkForUrl(mContext.getContentResolver(), url); 1.150 + if (cursor == null) { 1.151 + return null; 1.152 + } 1.153 + 1.154 + Bookmark bookmark = null; 1.155 + try { 1.156 + cursor.moveToFirst(); 1.157 + bookmark = new Bookmark(cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID)), 1.158 + cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.TITLE)), 1.159 + cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.URL)), 1.160 + cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.KEYWORD))); 1.161 + } finally { 1.162 + cursor.close(); 1.163 + } 1.164 + return bookmark; 1.165 + } 1.166 + 1.167 + @Override 1.168 + public void onPostExecute(Bookmark bookmark) { 1.169 + if (bookmark == null) 1.170 + return; 1.171 + 1.172 + show(bookmark.id, bookmark.title, bookmark.url, bookmark.keyword); 1.173 + } 1.174 + }).execute(); 1.175 + } 1.176 + 1.177 + /** 1.178 + * Show the Edit bookmark dialog for a set of data. This will show the dialog whether 1.179 + * a bookmark with this url exists or not, but the results will NOT be saved if the id 1.180 + * is not a valid bookmark id. 1.181 + * 1.182 + * @param id The id of the bookmark to change. If there is no bookmark with this ID, the dialog 1.183 + * will fail silently. 1.184 + * @param title The initial title to show in the dialog 1.185 + * @param url The initial url to show in the dialog 1.186 + * @param keyword The initial keyword to show in the dialog 1.187 + */ 1.188 + public void show(final int id, final String title, final String url, final String keyword) { 1.189 + AlertDialog.Builder editPrompt = new AlertDialog.Builder(mContext); 1.190 + final View editView = LayoutInflater.from(mContext).inflate(R.layout.bookmark_edit, null); 1.191 + editPrompt.setTitle(R.string.bookmark_edit_title); 1.192 + editPrompt.setView(editView); 1.193 + 1.194 + final EditText nameText = ((EditText) editView.findViewById(R.id.edit_bookmark_name)); 1.195 + final EditText locationText = ((EditText) editView.findViewById(R.id.edit_bookmark_location)); 1.196 + final EditText keywordText = ((EditText) editView.findViewById(R.id.edit_bookmark_keyword)); 1.197 + nameText.setText(title); 1.198 + locationText.setText(url); 1.199 + keywordText.setText(keyword); 1.200 + 1.201 + editPrompt.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() { 1.202 + @Override 1.203 + public void onClick(DialogInterface dialog, int whichButton) { 1.204 + (new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) { 1.205 + @Override 1.206 + public Void doInBackground(Void... params) { 1.207 + String newUrl = locationText.getText().toString().trim(); 1.208 + String newKeyword = keywordText.getText().toString().trim(); 1.209 + BrowserDB.updateBookmark(mContext.getContentResolver(), id, newUrl, nameText.getText().toString(), newKeyword); 1.210 + return null; 1.211 + } 1.212 + 1.213 + @Override 1.214 + public void onPostExecute(Void result) { 1.215 + Toast.makeText(mContext, R.string.bookmark_updated, Toast.LENGTH_SHORT).show(); 1.216 + } 1.217 + }).execute(); 1.218 + } 1.219 + }); 1.220 + 1.221 + editPrompt.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() { 1.222 + @Override 1.223 + public void onClick(DialogInterface dialog, int whichButton) { 1.224 + // do nothing 1.225 + } 1.226 + }); 1.227 + 1.228 + final AlertDialog dialog = editPrompt.create(); 1.229 + 1.230 + // Create our TextWatchers 1.231 + LocationTextWatcher locationTextWatcher = new LocationTextWatcher(dialog); 1.232 + KeywordTextWatcher keywordTextWatcher = new KeywordTextWatcher(dialog); 1.233 + 1.234 + // Cross reference the TextWatchers 1.235 + locationTextWatcher.setPairedTextWatcher(keywordTextWatcher); 1.236 + keywordTextWatcher.setPairedTextWatcher(locationTextWatcher); 1.237 + 1.238 + // Add the TextWatcher Listeners 1.239 + locationText.addTextChangedListener(locationTextWatcher); 1.240 + keywordText.addTextChangedListener(keywordTextWatcher); 1.241 + 1.242 + dialog.show(); 1.243 + } 1.244 +}