diff -r 000000000000 -r 6474c204b198 mobile/android/base/EditBookmarkDialog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mobile/android/base/EditBookmarkDialog.java Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,241 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import org.mozilla.gecko.db.BrowserContract.Bookmarks; +import org.mozilla.gecko.db.BrowserDB; +import org.mozilla.gecko.util.ThreadUtils; +import org.mozilla.gecko.util.UiAsyncTask; + +import android.content.Context; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.database.Cursor; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.Toast; + +/** + * A dialog that allows editing a bookmarks url, title, or keywords + *

+ * Invoked by calling one of the {@link org.mozilla.gecko.EditBookmarkDialog.show} + * methods. + */ +public class EditBookmarkDialog { + private static final String LOGTAG = "GeckoEditBookmarkDialog"; + private Context mContext; + + public EditBookmarkDialog(Context context) { + mContext = context; + } + + /** + * A private struct to make it easier to pass bookmark data across threads + */ + private class Bookmark { + int id; + String title; + String url; + String keyword; + + public Bookmark(int aId, String aTitle, String aUrl, String aKeyword) { + id = aId; + title = aTitle; + url = aUrl; + keyword = aKeyword; + } + } + + /** + * This text watcher to enable or disable the OK button if the dialog contains + * valid information. This class is overridden to do data checking diffferent fields. + * By itself, it always enables the button. + * + * Callers can also assing a paired partner to the TextWatcher, and callers will check + * that both are enabled before enabling the ok button. + */ + private class EditBookmarkTextWatcher implements TextWatcher { + // A stored reference to the dialog containing the text field being watched + protected AlertDialog mDialog; + + // A stored text watcher to do the real verification of a field + protected EditBookmarkTextWatcher mPairedTextWatcher; + + // Whether or not the ok button should be enabled. + protected boolean mEnabled = true; + + public EditBookmarkTextWatcher(AlertDialog aDialog) { + mDialog = aDialog; + } + + public void setPairedTextWatcher(EditBookmarkTextWatcher aTextWatcher) { + mPairedTextWatcher = aTextWatcher; + } + + public boolean isEnabled() { + return mEnabled; + } + + // Textwatcher interface + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // Disable if the we're disabled or the paired partner is disabled + boolean enabled = mEnabled && (mPairedTextWatcher == null || mPairedTextWatcher.isEnabled()); + mDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled); + } + + @Override + public void afterTextChanged(Editable s) {} + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + } + + /** + * A version of the EditBookmarkTextWatcher for the url field of the dialog. + * Only checks if the field is empty or not. + */ + private class LocationTextWatcher extends EditBookmarkTextWatcher { + public LocationTextWatcher(AlertDialog aDialog) { + super(aDialog); + } + + // Disables the ok button if the location field is empty. + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + mEnabled = (s.toString().trim().length() > 0); + super.onTextChanged(s, start, before, count); + } + } + + /** + * A version of the EditBookmarkTextWatcher for the keyword field of the dialog. + * Checks if the field has any (non leading or trailing) spaces. + */ + private class KeywordTextWatcher extends EditBookmarkTextWatcher { + public KeywordTextWatcher(AlertDialog aDialog) { + super(aDialog); + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // Disable if the keyword contains spaces + mEnabled = (s.toString().trim().indexOf(' ') == -1); + super.onTextChanged(s, start, before, count); + } + } + + /** + * Show the Edit bookmark dialog for a particular url. If the url is bookmarked multiple times + * this will just edit the first instance it finds. + * + * @param url The url of the bookmark to edit. The dialog will look up other information like the id, + * current title, or keywords associated with this url. If the url isn't bookmarked, the + * dialog will fail silently. If the url is bookmarked multiple times, this will only show + * information about the first it finds. + */ + public void show(final String url) { + (new UiAsyncTask(ThreadUtils.getBackgroundHandler()) { + @Override + public Bookmark doInBackground(Void... params) { + Cursor cursor = BrowserDB.getBookmarkForUrl(mContext.getContentResolver(), url); + if (cursor == null) { + return null; + } + + Bookmark bookmark = null; + try { + cursor.moveToFirst(); + bookmark = new Bookmark(cursor.getInt(cursor.getColumnIndexOrThrow(Bookmarks._ID)), + cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.TITLE)), + cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.URL)), + cursor.getString(cursor.getColumnIndexOrThrow(Bookmarks.KEYWORD))); + } finally { + cursor.close(); + } + return bookmark; + } + + @Override + public void onPostExecute(Bookmark bookmark) { + if (bookmark == null) + return; + + show(bookmark.id, bookmark.title, bookmark.url, bookmark.keyword); + } + }).execute(); + } + + /** + * Show the Edit bookmark dialog for a set of data. This will show the dialog whether + * a bookmark with this url exists or not, but the results will NOT be saved if the id + * is not a valid bookmark id. + * + * @param id The id of the bookmark to change. If there is no bookmark with this ID, the dialog + * will fail silently. + * @param title The initial title to show in the dialog + * @param url The initial url to show in the dialog + * @param keyword The initial keyword to show in the dialog + */ + public void show(final int id, final String title, final String url, final String keyword) { + AlertDialog.Builder editPrompt = new AlertDialog.Builder(mContext); + final View editView = LayoutInflater.from(mContext).inflate(R.layout.bookmark_edit, null); + editPrompt.setTitle(R.string.bookmark_edit_title); + editPrompt.setView(editView); + + final EditText nameText = ((EditText) editView.findViewById(R.id.edit_bookmark_name)); + final EditText locationText = ((EditText) editView.findViewById(R.id.edit_bookmark_location)); + final EditText keywordText = ((EditText) editView.findViewById(R.id.edit_bookmark_keyword)); + nameText.setText(title); + locationText.setText(url); + keywordText.setText(keyword); + + editPrompt.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + (new UiAsyncTask(ThreadUtils.getBackgroundHandler()) { + @Override + public Void doInBackground(Void... params) { + String newUrl = locationText.getText().toString().trim(); + String newKeyword = keywordText.getText().toString().trim(); + BrowserDB.updateBookmark(mContext.getContentResolver(), id, newUrl, nameText.getText().toString(), newKeyword); + return null; + } + + @Override + public void onPostExecute(Void result) { + Toast.makeText(mContext, R.string.bookmark_updated, Toast.LENGTH_SHORT).show(); + } + }).execute(); + } + }); + + editPrompt.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + // do nothing + } + }); + + final AlertDialog dialog = editPrompt.create(); + + // Create our TextWatchers + LocationTextWatcher locationTextWatcher = new LocationTextWatcher(dialog); + KeywordTextWatcher keywordTextWatcher = new KeywordTextWatcher(dialog); + + // Cross reference the TextWatchers + locationTextWatcher.setPairedTextWatcher(keywordTextWatcher); + keywordTextWatcher.setPairedTextWatcher(locationTextWatcher); + + // Add the TextWatcher Listeners + locationText.addTextChangedListener(locationTextWatcher); + keywordText.addTextChangedListener(keywordTextWatcher); + + dialog.show(); + } +}