NS_IMETHODIMP nsAutoCompleteController::GetValueAt(PRInt32 aIndex, nsAString & _retval) { GetResultValueAt(aIndex, PR_FALSE, _retval); return NS_OK; }
NS_IMETHODIMP nsAutoCompleteController::HandleDelete(bool *_retval) { *_retval = false; if (!mInput) return NS_OK; nsCOMPtr<nsIAutoCompleteInput> input(mInput); bool isOpen = false; input->GetPopupOpen(&isOpen); if (!isOpen || mRowCount <= 0) { // Nothing left to delete, proceed as normal HandleText(); return NS_OK; } nsCOMPtr<nsIAutoCompletePopup> popup; input->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); nsIAutoCompleteResult *result = mResults[searchIndex]; NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); nsAutoString search; input->GetSearchParam(search); // Clear the row in our result and in the DB. result->RemoveValueAt(rowIndex, true); --mRowCount; // We removed it, so make sure we cancel the event that triggered this call. *_retval = true; // 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. bool shouldComplete = false; mInput->GetCompleteDefaultIndex(&shouldComplete); if (shouldComplete) { nsAutoString value; if (NS_SUCCEEDED(GetResultValueAt(index, true, value))) { CompleteValue(value); } } // 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::HandleKeyNavigation(PRUint32 aKey, bool *_retval) { // By default, don't cancel the event *_retval = false; if (!mInput) { // Stop all searches in case they are async. StopSearch(); // Note: if now is after blur and IME end composition, // check mInput before calling. // See https://bugzilla.mozilla.org/show_bug.cgi?id=193544#c31 NS_ERROR("Called before attaching to the control or after detaching from the control"); return NS_OK; } nsCOMPtr<nsIAutoCompleteInput> input(mInput); nsCOMPtr<nsIAutoCompletePopup> popup; input->GetPopup(getter_AddRefs(popup)); NS_ENSURE_TRUE(popup != nsnull, NS_ERROR_FAILURE); bool disabled; input->GetDisableAutoComplete(&disabled); NS_ENSURE_TRUE(!disabled, NS_OK); if (aKey == nsIDOMKeyEvent::DOM_VK_UP || aKey == nsIDOMKeyEvent::DOM_VK_DOWN || aKey == nsIDOMKeyEvent::DOM_VK_PAGE_UP || aKey == nsIDOMKeyEvent::DOM_VK_PAGE_DOWN) { // Prevent the input from handling up/down events, as it may move // the cursor to home/end on some systems *_retval = true; bool isOpen = false; input->GetPopupOpen(&isOpen); if (isOpen) { bool reverse = aKey == nsIDOMKeyEvent::DOM_VK_UP || aKey == nsIDOMKeyEvent::DOM_VK_PAGE_UP ? true : false; bool page = aKey == nsIDOMKeyEvent::DOM_VK_PAGE_UP || aKey == nsIDOMKeyEvent::DOM_VK_PAGE_DOWN ? true : false; // Fill in the value of the textbox with whatever is selected in the popup // if the completeSelectedIndex attribute is set. We check this before // calling SelectBy of an earlier attempt to avoid crashing. bool completeSelection; input->GetCompleteSelectedIndex(&completeSelection); // Instruct the result view to scroll by the given amount and direction popup->SelectBy(reverse, page); if (completeSelection) { PRInt32 selectedIndex; popup->GetSelectedIndex(&selectedIndex); if (selectedIndex >= 0) { // A result is selected, so fill in its value nsAutoString value; if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, true, value))) { input->SetTextValue(value); input->SelectTextRange(value.Length(), value.Length()); } } else { // Nothing is selected, so fill in the last typed value input->SetTextValue(mSearchString); input->SelectTextRange(mSearchString.Length(), mSearchString.Length()); } } } else { #ifdef XP_MACOSX // on Mac, only show the popup if the caret is at the start or end of // the input and there is no selection, so that the default defined key // shortcuts for up and down move to the beginning and end of the field // otherwise. PRInt32 start, end; if (aKey == nsIDOMKeyEvent::DOM_VK_UP) { input->GetSelectionStart(&start); input->GetSelectionEnd(&end); if (start > 0 || start != end) *_retval = false; } else if (aKey == nsIDOMKeyEvent::DOM_VK_DOWN) { nsAutoString text; input->GetTextValue(text); input->GetSelectionStart(&start); input->GetSelectionEnd(&end); if (start != end || end < (PRInt32)text.Length()) *_retval = false; } #endif if (*_retval) { // Open the popup if there has been a previous search, or else kick off a new search if (mResults.Count() > 0) { if (mRowCount) { OpenPopup(); } } else { // Stop all searches in case they are async. StopSearch(); if (!mInput) { // StopSearch() can call PostSearchCleanup() which might result // in a blur event, which could null out mInput, so we need to check it // again. See bug #395344 for more details return NS_OK; } StartSearchTimer(); } } } } else if ( aKey == nsIDOMKeyEvent::DOM_VK_LEFT || aKey == nsIDOMKeyEvent::DOM_VK_RIGHT #ifndef XP_MACOSX || aKey == nsIDOMKeyEvent::DOM_VK_HOME #endif ) { // The user hit a text-navigation key. bool isOpen = false; input->GetPopupOpen(&isOpen); if (isOpen) { PRInt32 selectedIndex; popup->GetSelectedIndex(&selectedIndex); bool shouldComplete; input->GetCompleteDefaultIndex(&shouldComplete); if (selectedIndex >= 0) { // The pop-up is open and has a selection, take its value nsAutoString value; if (NS_SUCCEEDED(GetResultValueAt(selectedIndex, true, value))) { input->SetTextValue(value); input->SelectTextRange(value.Length(), value.Length()); } } else if (shouldComplete) { // We usually try to preserve the casing of what user has typed, but // if he wants to autocomplete, we will replace the value with the // actual autocomplete result. // The user wants explicitely to use that result, so this ensures // association of the result with the autocompleted text. nsAutoString value; nsAutoString inputValue; input->GetTextValue(inputValue); if (NS_SUCCEEDED(GetDefaultCompleteValue(-1, false, value)) && value.Equals(inputValue, nsCaseInsensitiveStringComparator())) { input->SetTextValue(value); input->SelectTextRange(value.Length(), value.Length()); } } // Close the pop-up even if nothing was selected ClearSearchTimer(); ClosePopup(); } // Update last-searched string to the current input, since the input may // have changed. Without this, subsequent backspaces look like text // additions, not text deletions. nsAutoString value; input->GetTextValue(value); mSearchString = value; } return NS_OK; }
nsresult nsAutoCompleteController::EnterMatch(bool aIsPopupSelection) { nsCOMPtr<nsIAutoCompleteInput> input(mInput); nsCOMPtr<nsIAutoCompletePopup> popup; input->GetPopup(getter_AddRefs(popup)); NS_ENSURE_TRUE(popup != nsnull, NS_ERROR_FAILURE); bool forceComplete; input->GetForceComplete(&forceComplete); // Ask the popup if it wants to enter a special value into the textbox nsAutoString value; popup->GetOverrideValue(value); if (value.IsEmpty()) { bool shouldComplete; mInput->GetCompleteDefaultIndex(&shouldComplete); bool completeSelection; input->GetCompleteSelectedIndex(&completeSelection); // If completeselectedindex is false or a row was selected from the popup, // enter it into the textbox. If completeselectedindex is true, or // EnterMatch was called via other means, for instance pressing Enter, // don't fill in the value as it will have already been filled in as needed. PRInt32 selectedIndex; popup->GetSelectedIndex(&selectedIndex); if (selectedIndex >= 0 && (!completeSelection || aIsPopupSelection)) GetResultValueAt(selectedIndex, true, value); else if (shouldComplete) { // We usually try to preserve the casing of what user has typed, but // if he wants to autocomplete, we will replace the value with the // actual autocomplete result. // The user wants explicitely to use that result, so this ensures // association of the result with the autocompleted text. nsAutoString defaultIndexValue; nsAutoString inputValue; input->GetTextValue(inputValue); if (NS_SUCCEEDED(GetDefaultCompleteValue(-1, false, defaultIndexValue)) && defaultIndexValue.Equals(inputValue, nsCaseInsensitiveStringComparator())) value = defaultIndexValue; } if (forceComplete && value.IsEmpty()) { // Since nothing was selected, and forceComplete is specified, that means // we have to find the first default match and enter it instead PRUint32 count = mResults.Count(); for (PRUint32 i = 0; i < count; ++i) { nsIAutoCompleteResult *result = mResults[i]; if (result) { PRInt32 defaultIndex; result->GetDefaultIndex(&defaultIndex); if (defaultIndex >= 0) { result->GetValueAt(defaultIndex, value); break; } } } } } nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService(); NS_ENSURE_STATE(obsSvc); obsSvc->NotifyObservers(input, "autocomplete-will-enter-text", nsnull); if (!value.IsEmpty()) { input->SetTextValue(value); input->SelectTextRange(value.Length(), value.Length()); mSearchString = value; } obsSvc->NotifyObservers(input, "autocomplete-did-enter-text", nsnull); ClosePopup(); bool cancel; input->OnTextEntered(&cancel); return NS_OK; }