diff --git a/toolkit/components/autocomplete/public/nsIAutoCompleteController.idl b/toolkit/components/autocomplete/public/nsIAutoCompleteController.idl index 893a045d7b28..a190151cb264 100644 --- a/toolkit/components/autocomplete/public/nsIAutoCompleteController.idl +++ b/toolkit/components/autocomplete/public/nsIAutoCompleteController.idl @@ -116,6 +116,12 @@ interface nsIAutoCompleteController : nsISupports */ boolean handleKeyNavigation(in unsigned short key); + /* + * Notify the controller that the user chose to delete the current + * auto-complete result. + */ + boolean handleDelete(); + /* * Get the value of the result at a given index in the last completed search */ diff --git a/toolkit/components/autocomplete/public/nsIAutoCompleteResultTypes.idl b/toolkit/components/autocomplete/public/nsIAutoCompleteResultTypes.idl index 04141f0ecf4c..a09ebc0f236b 100755 --- a/toolkit/components/autocomplete/public/nsIAutoCompleteResultTypes.idl +++ b/toolkit/components/autocomplete/public/nsIAutoCompleteResultTypes.idl @@ -73,7 +73,7 @@ interface nsIAutoCompleteMdbResult : nsIAutoCompleteBaseResult void addRow(in nsIMdbRow row); - void removeRowAt(in unsigned long rowIndex); + void removeRowAt(in unsigned long rowIndex, in boolean removeFromDb); nsIMdbRow getRowAt(in unsigned long rowIndex); diff --git a/toolkit/components/autocomplete/src/Makefile.in b/toolkit/components/autocomplete/src/Makefile.in index ffd4389d56e8..e87c01825220 100644 --- a/toolkit/components/autocomplete/src/Makefile.in +++ b/toolkit/components/autocomplete/src/Makefile.in @@ -29,12 +29,13 @@ MODULE = autocomplete LIBRARY_NAME = autocomplete_s FORCE_STATIC_LIB = 1 -REQUIRES = xpcom \ - string \ - dom \ - layout \ - mork \ - $(NULL) +REQUIRES = xpcom \ + string \ + dom \ + layout \ + mork \ + unicharutil \ + $(NULL) CPPSRCS = nsAutoCompleteController.cpp \ nsAutoCompleteMdbResult.cpp \ diff --git a/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp b/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp index 09d8e10776ac..10ef940587e3 100644 --- a/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp +++ b/toolkit/components/autocomplete/src/nsAutoCompleteController.cpp @@ -1,4 +1,5 @@ -/* ***** BEGIN LICENSE BLOCK ***** +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License @@ -20,6 +21,8 @@ * * Contributor(s): * Joe Hewitt (Original Author) + * Dean Tessman + * Johnny Stenback * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -37,12 +40,12 @@ #include "nsAutoCompleteController.h" +#include "nsIAutoCompleteResultTypes.h" #include "nsIServiceManager.h" -#include "nsIDOMKeyEvent.h" -#include "nsIDOMNode.h" -#include "nsIDOMEventTarget.h" +#include "nsIDOMElement.h" #include "nsIAtomService.h" #include "nsReadableUtils.h" +#include "nsUnicharUtils.h" static const char *kAutoCompleteSearchCID = "@mozilla.org/autocomplete/search;1?name="; @@ -52,7 +55,6 @@ NS_IMPL_ISUPPORTS4(nsAutoCompleteController, nsIAutoCompleteController, nsIAutoC nsAutoCompleteController::nsAutoCompleteController() : mEnterAfterSearch(PR_FALSE), - mNeedToComplete(PR_FALSE), mDefaultIndexCompleted(PR_FALSE), mBackspaced(PR_FALSE), mSearchStatus(0), @@ -120,7 +122,6 @@ nsAutoCompleteController::SetInput(nsIAutoCompleteInput *aInput) // Reset all search state members to default values mSearchString = newValue; mEnterAfterSearch = PR_FALSE; - mNeedToComplete = PR_FALSE; mDefaultIndexCompleted = PR_FALSE; mBackspaced = PR_FALSE; mSearchStatus = nsIAutoCompleteController::STATUS_NONE; @@ -163,7 +164,7 @@ nsAutoCompleteController::StartSearch(const nsAString &aSearchString) NS_IMETHODIMP nsAutoCompleteController::HandleText() -{ +{ // Stop current search in case it's async. StopSearch(); // Stop the queued up search on a timer @@ -173,8 +174,6 @@ nsAutoCompleteController::HandleText() mInput->GetDisableAutoComplete(&disabled); NS_ENSURE_TRUE(!disabled, NS_OK;); - mNeedToComplete = PR_TRUE; - nsAutoString newValue; mInput->GetTextValue(newValue); @@ -264,8 +263,6 @@ nsAutoCompleteController::HandleKeyNavigation(PRUint16 aKey, PRBool *_retval) // By default, don't cancel the event *_retval = PR_FALSE; - mNeedToComplete = PR_FALSE; - nsCOMPtr popup; mInput->GetPopup(getter_AddRefs(popup)); NS_ENSURE_TRUE(popup != nsnull, NS_ERROR_FAILURE); @@ -325,6 +322,80 @@ nsAutoCompleteController::HandleKeyNavigation(PRUint16 aKey, PRBool *_retval) return NS_OK; } +NS_IMETHODIMP +nsAutoCompleteController::HandleDelete(PRBool *_retval) +{ + *_retval = PR_FALSE; + PRBool isOpen = PR_FALSE; + mInput->GetPopupOpen(&isOpen); + if (!isOpen || mRowCount <= 0) { + // Nothing left to delete, proceed as normal + HandleText(); + return NS_OK; + } + + nsCOMPtr popup; + mInput->GetPopup(getter_AddRefs(popup)); + + PRInt32 index, searchIndex, rowIndex; + popup->GetSelectedIndex(&index); + RowIndexToSearch(index, &searchIndex, &rowIndex); + NS_ENSURE_TRUE(searchIndex >= 0 && rowIndex >= 0, NS_ERROR_FAILURE); + + nsCOMPtr result; + mResults->GetElementAt(searchIndex, getter_AddRefs(result)); + NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); + + nsAutoString search; + mInput->GetSearchParam(search); + + nsAutoString value; + result->GetValueAt(rowIndex, value); + + nsCOMPtr mdbResult(do_QueryInterface(result)); + if (mdbResult) { + // Clear the row in our result and in the DB. + mdbResult->RemoveRowAt(rowIndex, PR_TRUE); + + --mRowCount; + } + + // Unselect the current item. + popup->SetSelectedIndex(-1); + + // Tell the tree that the row count changed. + if (mTree) + mTree->RowCountChanged(mRowCount, -1); + + // Adjust index, if needed. + if (index >= (PRInt32)mRowCount) + index = mRowCount - 1; + + if (mRowCount > 0) { + // There are still rows in the popup, select the current index again. + popup->SetSelectedIndex(index); + + // Complete to the new current value. + nsAutoString value; + if (NS_SUCCEEDED(GetResultValueAt(index, PR_TRUE, value))) { + CompleteValue(value); + + // Make sure we cancel the event that triggerd this call. + *_retval = PR_TRUE; + } + + // Invalidate the popup. + popup->Invalidate(); + } else { + // Nothing left in the popup, clear any pending search timers and + // close the popup. + ClearSearchTimer(); + ClosePopup(); + } + + return NS_OK; +} + NS_IMETHODIMP nsAutoCompleteController::GetValueAt(PRInt32 aIndex, nsAString & _retval) { @@ -803,7 +874,7 @@ nsAutoCompleteController::EnterMatch() if (!value.IsEmpty()) { mInput->SetTextValue(value); - mInput->SelectTextRange(-1, -1); + mInput->SelectTextRange(value.Length(), value.Length()); mSearchString = value; } @@ -827,7 +898,6 @@ nsAutoCompleteController::RevertTextValue() mInput->SetTextValue(oldValue); mSearchString.Truncate(0); - mNeedToComplete = PR_FALSE; return NS_OK; } @@ -958,13 +1028,23 @@ nsAutoCompleteController::CompleteDefaultIndex(PRInt32 aSearchIndex) nsresult nsAutoCompleteController::CompleteValue(nsString &aValue) { - PRInt32 findIndex = aValue.Find(mSearchString, PR_FALSE); - if (findIndex == 0 || mSearchString.IsEmpty()) { - // The textbox value matches the beginning of the default value, so we can just - // append the latter portion + nsString::const_iterator start, end, iter; + aValue.BeginReading(start); + aValue.EndReading(end); + iter = start; + + FindInReadable(mSearchString, iter, end, + nsCaseInsensitiveStringComparator()); + + if (iter == start) { + // The textbox value matches the beginning of the default value, + // or the default value is empty, so we can just append the latter + // portion mInput->SetTextValue(aValue); mInput->SelectTextRange(mSearchString.Length(), aValue.Length()); } else { + PRInt32 findIndex = iter.get() - start.get(); + mInput->SetTextValue(mSearchString + Substring(aValue, mSearchString.Length()+findIndex, aValue.Length())); mInput->SelectTextRange(mSearchString.Length(), aValue.Length() - findIndex); diff --git a/toolkit/components/autocomplete/src/nsAutoCompleteController.h b/toolkit/components/autocomplete/src/nsAutoCompleteController.h index d30b74af3225..c05e41943fe2 100644 --- a/toolkit/components/autocomplete/src/nsAutoCompleteController.h +++ b/toolkit/components/autocomplete/src/nsAutoCompleteController.h @@ -102,7 +102,6 @@ protected: nsString mSearchString; PRPackedBool mEnterAfterSearch; - PRPackedBool mNeedToComplete; PRPackedBool mDefaultIndexCompleted; PRPackedBool mBackspaced; PRUint16 mSearchStatus; diff --git a/toolkit/components/autocomplete/src/nsAutoCompleteMdbResult.cpp b/toolkit/components/autocomplete/src/nsAutoCompleteMdbResult.cpp index a768074e2619..eb76c7033aa7 100644 --- a/toolkit/components/autocomplete/src/nsAutoCompleteMdbResult.cpp +++ b/toolkit/components/autocomplete/src/nsAutoCompleteMdbResult.cpp @@ -210,9 +210,18 @@ nsAutoCompleteMdbResult::AddRow(nsIMdbRow *aRow) } NS_IMETHODIMP -nsAutoCompleteMdbResult::RemoveRowAt(PRUint32 aRowIndex) +nsAutoCompleteMdbResult::RemoveRowAt(PRUint32 aRowIndex, PRBool aRemoveFromDb) { + nsIMdbRow *row = (nsIMdbRow *)mResults.ElementAt(aRowIndex); + NS_ENSURE_TRUE(row, NS_ERROR_INVALID_ARG); + mResults.RemoveElementAt(aRowIndex); + + if (aRemoveFromDb && mTable && mEnv) { + mdb_err err = mTable->CutRow(mEnv, row); + NS_ENSURE_TRUE(!err, NS_ERROR_FAILURE); + } + return NS_OK; } diff --git a/toolkit/components/history/src/nsGlobalHistory.cpp b/toolkit/components/history/src/nsGlobalHistory.cpp index d1df29fbf79e..1f5e1d429aa1 100644 --- a/toolkit/components/history/src/nsGlobalHistory.cpp +++ b/toolkit/components/history/src/nsGlobalHistory.cpp @@ -4154,7 +4154,7 @@ nsGlobalHistory::AutoCompleteSearch(const nsAString &aSearchString, aPrevResult->GetValueAt(i, url); if (!AutoCompleteCompare(url, aSearchString, aExclude)) - aPrevResult->RemoveRowAt(i); + aPrevResult->RemoveRowAt(i, PR_FALSE); } *aResult = aPrevResult; diff --git a/toolkit/components/satchel/src/nsFormFillController.cpp b/toolkit/components/satchel/src/nsFormFillController.cpp index 97f622aefebd..d9e8cbe9b1c5 100644 --- a/toolkit/components/satchel/src/nsFormFillController.cpp +++ b/toolkit/components/satchel/src/nsFormFillController.cpp @@ -227,12 +227,12 @@ nsFormFillController::GetPopupOpen(PRBool *aPopupOpen) NS_IMETHODIMP nsFormFillController::SetPopupOpen(PRBool aPopupOpen) { - if (aPopupOpen) { - nsRect popupRect = GetScreenOrigin(mFocusedInput); - if (mFocusedPopup) + if (mFocusedPopup) { + if (aPopupOpen) { + nsRect popupRect = GetScreenOrigin(mFocusedInput); mFocusedPopup->OpenPopup(this, popupRect.x, popupRect.y+popupRect.height, popupRect.width); - } else { - mFocusedPopup->ClosePopup(); + } else + mFocusedPopup->ClosePopup(); } return NS_OK; @@ -562,8 +562,20 @@ nsFormFillController::KeyPress(nsIDOMEvent* aEvent) PRUint32 k; keyEvent->GetKeyCode(&k); switch (k) { - case nsIDOMKeyEvent::DOM_VK_BACK_SPACE: case nsIDOMKeyEvent::DOM_VK_DELETE: + { + PRBool isShift = PR_FALSE; + keyEvent->GetShiftKey(&isShift); + + if (isShift) { + mController->HandleDelete(&cancel); + + break; + } + + // fall through + } + case nsIDOMKeyEvent::DOM_VK_BACK_SPACE: mController->HandleText(); break; case nsIDOMKeyEvent::DOM_VK_UP: diff --git a/toolkit/components/satchel/src/nsFormHistory.cpp b/toolkit/components/satchel/src/nsFormHistory.cpp index 721e3e937567..b11b4a9bc90d 100644 --- a/toolkit/components/satchel/src/nsFormHistory.cpp +++ b/toolkit/components/satchel/src/nsFormHistory.cpp @@ -1,3 +1,4 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * @@ -704,7 +705,7 @@ nsFormHistory::AutoCompleteSearch(const nsAString &aInputName, nsIMdbRow *row; result->GetRowAt(i, &row); if (!RowMatch(row, aInputName, aInputValue, nsnull)) - result->RemoveRowAt(i); + result->RemoveRowAt(i, PR_FALSE); } } else { result = do_CreateInstance("@mozilla.org/autocomplete/mdb-result;1"); @@ -790,11 +791,12 @@ nsFormHistory::SortComparison(const void *v1, const void *v2, void *closureVoid) PRBool nsFormHistory::RowMatch(nsIMdbRow *aRow, const nsAString &aInputName, const nsAString &aInputValue, PRUnichar **aValue) { - nsAutoString name, value; + nsAutoString name; GetRowValue(aRow, kToken_NameColumn, name); - GetRowValue(aRow, kToken_ValueColumn, value); - + if (name.Equals(aInputName)) { + nsAutoString value; + GetRowValue(aRow, kToken_ValueColumn, value); if (value.Length() != aInputValue.Length() && // ignore exact matches Compare(Substring(value, 0, aInputValue.Length()), aInputValue, nsCaseInsensitiveStringComparator()) == 0) {