michael@0: /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko; michael@0: michael@0: import org.mozilla.gecko.db.BrowserContract.Bookmarks; michael@0: import org.mozilla.gecko.db.BrowserDB; michael@0: import org.mozilla.gecko.util.ThreadUtils; michael@0: import org.mozilla.gecko.util.UiAsyncTask; michael@0: michael@0: import android.content.Context; michael@0: import android.app.AlertDialog; michael@0: import android.content.DialogInterface; michael@0: import android.database.Cursor; michael@0: import android.text.Editable; michael@0: import android.text.TextWatcher; michael@0: import android.view.LayoutInflater; michael@0: import android.view.View; michael@0: import android.widget.EditText; michael@0: import android.widget.Toast; michael@0: michael@0: /** michael@0: * A dialog that allows editing a bookmarks url, title, or keywords michael@0: *

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