Bug 660592 - Allow autocomplete results to hide themselves from the popup.
authorMichael Ventnor<ventnor.bugzilla@gmail.com>
Thu, 19 Jan 2012 12:31:19 +0100
changeset 86110 51dcdc85081c86bd0caa030f72248734507761ce
parent 86109 eea95e86541f0595ffc9da24e3904299b8c329ac
child 86111 f23efef7f6160a1620ee5d3af2bc2596f31079a7
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs660592
milestone12.0a1
Bug 660592 - Allow autocomplete results to hide themselves from the popup. r=mak sr=gavin
toolkit/components/autocomplete/nsAutoCompleteController.cpp
toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp
toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h
toolkit/components/autocomplete/nsIAutoCompleteResult.idl
toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl
toolkit/components/autocomplete/tests/unit/head_autocomplete.js
toolkit/components/autocomplete/tests/unit/test_330578.js
toolkit/components/autocomplete/tests/unit/test_378079.js
toolkit/components/autocomplete/tests/unit/test_393191.js
toolkit/components/autocomplete/tests/unit/test_440866.js
toolkit/components/autocomplete/tests/unit/test_463023.js
toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
toolkit/components/autocomplete/tests/unit/test_hiddenResult.js
toolkit/components/autocomplete/tests/unit/test_previousResult.js
toolkit/components/autocomplete/tests/unit/test_stopSearch.js
toolkit/components/autocomplete/tests/unit/xpcshell.ini
toolkit/components/filepicker/nsFileView.cpp
--- a/toolkit/components/autocomplete/nsAutoCompleteController.cpp
+++ b/toolkit/components/autocomplete/nsAutoCompleteController.cpp
@@ -19,16 +19,17 @@
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Joe Hewitt <hewitt@netscape.com> (Original Author)
  *   Dean Tessman <dean_tessman@hotmail.com>
  *   Johnny Stenback <jst@mozilla.jstenback.com>
  *   Masayuki Nakano <masayuki@d-toybox.com>
+ *   Michael Ventnor <m.ventnor@gmail.com>
  *
  * 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
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -1270,56 +1271,68 @@ nsAutoCompleteController::ProcessResult(
   }
   else {
     // replace the cached result
     mResults.ReplaceObjectAt(aResult, oldIndex);
     oldMatchCount = mMatchCounts[aSearchIndex];
     mMatchCounts[oldIndex] = matchCount;
   }
 
-  PRUint32 oldRowCount = mRowCount;
-  // If the search failed, increase the match count
-  // to include the error description
-  if (result == nsIAutoCompleteResult::RESULT_FAILURE) {
-    nsAutoString error;
-    aResult->GetErrorDescription(error);
-    if (!error.IsEmpty()) {
-      ++mRowCount;
-      if (mTree)
-        mTree->RowCountChanged(oldRowCount, 1);
+  bool isTypeAheadResult = false;
+  if (aResult) {
+    aResult->GetTypeAheadResult(&isTypeAheadResult);
+  }
+
+  if (!isTypeAheadResult) {
+    PRUint32 oldRowCount = mRowCount;
+    // If the search failed, increase the match count to include the error
+    // description.
+    if (result == nsIAutoCompleteResult::RESULT_FAILURE) {
+      nsAutoString error;
+      aResult->GetErrorDescription(error);
+      if (!error.IsEmpty()) {
+        ++mRowCount;
+        if (mTree) {
+          mTree->RowCountChanged(oldRowCount, 1);
+        }
+      }
+    } else if (result == nsIAutoCompleteResult::RESULT_SUCCESS ||
+               result == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
+      // Increase the match count for all matches in this result.
+      mRowCount += matchCount - oldMatchCount;
+
+      if (mTree) {
+        mTree->RowCountChanged(oldRowCount, matchCount - oldMatchCount);
+      }
     }
-  } else if (result == nsIAutoCompleteResult::RESULT_SUCCESS ||
-             result == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
-    // Increase the match count for all matches in this result
-    mRowCount += matchCount - oldMatchCount;
+
+    // Refresh the popup view to display the new search results
+    nsCOMPtr<nsIAutoCompletePopup> popup;
+    input->GetPopup(getter_AddRefs(popup));
+    NS_ENSURE_TRUE(popup != nsnull, NS_ERROR_FAILURE);
+    popup->Invalidate();
 
-    if (mTree)
-      mTree->RowCountChanged(oldRowCount, matchCount - oldMatchCount);
+    // Make sure the popup is open, if necessary, since we now have at least one
+    // search result ready to display. Don't force the popup closed if we might
+    // get results in the future to avoid unnecessarily canceling searches.
+    if (mRowCount) {
+      OpenPopup();
+    } else if (result != nsIAutoCompleteResult::RESULT_NOMATCH_ONGOING) {
+      ClosePopup();
+    }
+  }
 
-    // Try to autocomplete the default index for this search
+  if (result == nsIAutoCompleteResult::RESULT_SUCCESS ||
+      result == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
+    // Try to autocomplete the default index for this search.
     CompleteDefaultIndex(aSearchIndex);
   }
 
-  // Refresh the popup view to display the new search results
-  nsCOMPtr<nsIAutoCompletePopup> popup;
-  input->GetPopup(getter_AddRefs(popup));
-  NS_ENSURE_TRUE(popup != nsnull, NS_ERROR_FAILURE);
-  popup->Invalidate();
-
-  // Make sure the popup is open, if necessary, since we now have at least one
-  // search result ready to display. Don't force the popup closed if we might
-  // get results in the future to avoid unnecessarily canceling searches.
-  if (mRowCount) {
-    OpenPopup();
-  } else if (mSearchesOngoing == 0) {
-    ClosePopup();
-  }
-
   if (mSearchesOngoing == 0) {
-    // If this is the last search to return, cleanup
+    // If this is the last search to return, cleanup.
     PostSearchCleanup();
   }
 
   return NS_OK;
 }
 
 nsresult
 nsAutoCompleteController::PostSearchCleanup()
@@ -1368,17 +1381,17 @@ nsAutoCompleteController::ClearResults()
     }
   }
   return NS_OK;
 }
 
 nsresult
 nsAutoCompleteController::CompleteDefaultIndex(PRInt32 aSearchIndex)
 {
-  if (mDefaultIndexCompleted || mBackspaced || mRowCount == 0 || mSearchString.Length() == 0)
+  if (mDefaultIndexCompleted || mBackspaced || mSearchString.Length() == 0)
     return NS_OK;
 
   PRInt32 selectionStart;
   mInput->GetSelectionStart(&selectionStart);
   PRInt32 selectionEnd;
   mInput->GetSelectionEnd(&selectionEnd);
 
   // Don't try to automatically complete to the first result if there's already
@@ -1424,17 +1437,21 @@ nsAutoCompleteController::GetDefaultComp
   nsIAutoCompleteResult *result = mResults.SafeObjectAt(index);
   NS_ENSURE_TRUE(result != nsnull, NS_ERROR_FAILURE);
 
   if (defaultIndex < 0) {
     // The search must explicitly provide a default index in order
     // for us to be able to complete.
     result->GetDefaultIndex(&defaultIndex);
   }
-  NS_ENSURE_TRUE(defaultIndex >= 0, NS_ERROR_FAILURE);
+  if (defaultIndex < 0) {
+    // We were given a result index, but that result doesn't want to
+    // be autocompleted.
+    return NS_ERROR_FAILURE;
+  }
 
   nsAutoString resultValue;
   result->GetValueAt(defaultIndex, resultValue);
   if (aPreserveCasing &&
       StringBeginsWith(resultValue, mSearchString,
                        nsCaseInsensitiveStringComparator())) {
     // We try to preserve user casing, otherwise we would end up changing
     // the case of what he typed, if we have a result with a different casing.
@@ -1521,17 +1538,17 @@ nsAutoCompleteController::GetResultLabel
 nsresult
 nsAutoCompleteController::GetResultValueAt(PRInt32 aIndex, bool aValueOnly, nsAString & _retval)
 {
   return GetResultValueLabelAt(aIndex, aValueOnly, true, _retval);
 }
 
 nsresult
 nsAutoCompleteController::GetResultValueLabelAt(PRInt32 aIndex, bool aValueOnly,
-                                               bool aGetValue, nsAString & _retval)
+                                                bool aGetValue, nsAString & _retval)
 {
   NS_ENSURE_TRUE(aIndex >= 0 && (PRUint32) aIndex < mRowCount, NS_ERROR_ILLEGAL_VALUE);
 
   PRInt32 rowIndex;
   nsIAutoCompleteResult *result;
   nsresult rv = GetResultAt(aIndex, &result, &rowIndex);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1569,25 +1586,32 @@ nsAutoCompleteController::RowIndexToSear
 
   // Move index through the results of each registered nsIAutoCompleteSearch
   // until we find the given row
   for (PRUint32 i = 0; i < count; ++i) {
     nsIAutoCompleteResult *result = mResults.SafeObjectAt(i);
     if (!result)
       continue;
 
-    PRUint16 searchResult;
-    result->GetSearchResult(&searchResult);
+    PRUint32 rowCount = 0;
+
+    // Skip past the result completely if it is marked as hidden
+    bool isTypeAheadResult = false;
+    result->GetTypeAheadResult(&isTypeAheadResult);
 
-    // Find out how many results were provided by the
-    // current nsIAutoCompleteSearch
-    PRUint32 rowCount = 0;
-    if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS ||
-        searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
-      result->GetMatchCount(&rowCount);
+    if (!isTypeAheadResult) {
+      PRUint16 searchResult;
+      result->GetSearchResult(&searchResult);
+
+      // Find out how many results were provided by the
+      // current nsIAutoCompleteSearch.
+      if (searchResult == nsIAutoCompleteResult::RESULT_SUCCESS ||
+          searchResult == nsIAutoCompleteResult::RESULT_SUCCESS_ONGOING) {
+        result->GetMatchCount(&rowCount);
+      }
     }
 
     // If the given row index is within the results range
     // of the current nsIAutoCompleteSearch then return the
     // search index and sub-index into the results array
     if ((rowCount != 0) && (index + rowCount-1 >= (PRUint32) aRowIndex)) {
       *aSearchIndex = i;
       *aItemIndex = aRowIndex - index;
--- a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp
+++ b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.cpp
@@ -38,17 +38,18 @@
 #include "nsAutoCompleteSimpleResult.h"
 
 NS_IMPL_ISUPPORTS2(nsAutoCompleteSimpleResult,
                    nsIAutoCompleteResult,
                    nsIAutoCompleteSimpleResult)
 
 nsAutoCompleteSimpleResult::nsAutoCompleteSimpleResult() :
   mDefaultIndex(-1),
-  mSearchResult(RESULT_NOMATCH)
+  mSearchResult(RESULT_NOMATCH),
+  mTypeAheadResult(false)
 {
 }
 
 // searchString
 NS_IMETHODIMP
 nsAutoCompleteSimpleResult::GetSearchString(nsAString &aSearchString)
 {
   aSearchString = mSearchString;
@@ -99,16 +100,30 @@ nsAutoCompleteSimpleResult::GetErrorDesc
 NS_IMETHODIMP
 nsAutoCompleteSimpleResult::SetErrorDescription(
                                              const nsAString &aErrorDescription)
 {
   mErrorDescription.Assign(aErrorDescription);
   return NS_OK;
 }
 
+// typeAheadResult
+NS_IMETHODIMP
+nsAutoCompleteSimpleResult::GetTypeAheadResult(bool *aTypeAheadResult)
+{
+  *aTypeAheadResult = mTypeAheadResult;
+  return NS_OK;
+}
+NS_IMETHODIMP
+nsAutoCompleteSimpleResult::SetTypeAheadResult(bool aTypeAheadResult)
+{
+  mTypeAheadResult = aTypeAheadResult;
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsAutoCompleteSimpleResult::AppendMatch(const nsAString& aValue,
                                         const nsAString& aComment,
                                         const nsAString& aImage,
                                         const nsAString& aStyle)
 {
   CheckInvariants();
 
--- a/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h
+++ b/toolkit/components/autocomplete/nsAutoCompleteSimpleResult.h
@@ -73,12 +73,14 @@ protected:
   nsTArray<nsString> mImages;
   nsTArray<nsString> mStyles;
 
   nsString mSearchString;
   nsString mErrorDescription;
   PRInt32 mDefaultIndex;
   PRUint32 mSearchResult;
 
+  bool mTypeAheadResult;
+
   nsCOMPtr<nsIAutoCompleteSimpleResultListener> mListener;
 };
 
 #endif // __nsAutoCompleteSimpleResult__
--- a/toolkit/components/autocomplete/nsIAutoCompleteResult.idl
+++ b/toolkit/components/autocomplete/nsIAutoCompleteResult.idl
@@ -32,17 +32,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(0f06dae4-0b87-4c16-a7bd-903461771478)]
+[scriptable, uuid(7b43fad1-c735-4b45-9383-c3f057fed20d)]
 interface nsIAutoCompleteResult : nsISupports
 {
   /**
    * Possible values for the searchResult attribute
    */
   const unsigned short RESULT_IGNORED = 1; /* indicates invalid searchString */
   const unsigned short RESULT_FAILURE = 2; /* indicates failure */
   const unsigned short RESULT_NOMATCH = 3; /* indicates success with no matches
@@ -78,16 +78,23 @@ interface nsIAutoCompleteResult : nsISup
   readonly attribute AString errorDescription;
 
   /**
    * The number of matches
    */
   readonly attribute unsigned long matchCount;
 
   /**
+   * If true, the results will not be displayed in the popup. However,
+   * if a default index is specified, the default item will still be
+   * completed in the input.
+   */
+  readonly attribute boolean typeAheadResult;
+
+  /**
    * Get the value of the result at the given index
    */
   AString getValueAt(in long index);
 
   /**
    * This returns the string that is displayed in the dropdown
    */
   AString getLabelAt(in long index);
--- a/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl
+++ b/toolkit/components/autocomplete/nsIAutoCompleteSimpleResult.idl
@@ -42,17 +42,17 @@ interface nsIAutoCompleteSimpleResultLis
 
 /**
  * This class implements nsIAutoCompleteResult and provides simple methods
  * for setting the value and result items. It can be used whenever some basic
  * auto complete results are needed that can be pre-generated and filled into
  * an array.
  */
 
-[scriptable, uuid(f9841787-ad26-49e6-a2dd-ba9020ee1c64)]
+[scriptable, uuid(c738dc26-aa71-4561-a3fd-b5a0e4aa80d2)]
 interface nsIAutoCompleteSimpleResult : nsIAutoCompleteResult
 {
   /**
    * A writer for the readonly attribute 'searchString' which should contain
    * the string that the user typed.
    */
   void setSearchString(in AString aSearchString);
 
@@ -70,16 +70,22 @@ interface nsIAutoCompleteSimpleResult : 
   /**
    * A writer for the readonly attribute 'searchResult' which should contain
    * one of the constants nsIAutoCompleteResult.RESULT_* indicating the success
    * of the search.
    */
   void setSearchResult(in unsigned short aSearchResult);
 
   /**
+   * A writer for the readonly attribute 'typeAheadResult', typically set
+   * because a result is only intended for type-ahead completion.
+   */
+  void setTypeAheadResult(in boolean aHidden);
+
+  /**
    * Appends a result item consisting of the given value, comment, image and style.
    * This is how you add results.  Note:  image and style are optional. 
    */
   void appendMatch(in AString aValue, in AString aComment, 
                    [optional] in AString aImage, 
                    [optional] in AString aStyle);
 
   /**
new file mode 100644
--- /dev/null
+++ b/toolkit/components/autocomplete/tests/unit/head_autocomplete.js
@@ -0,0 +1,187 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+/**
+ * Dummy nsIAutoCompleteInput source that returns
+ * the given list of AutoCompleteSearch names. 
+ * 
+ * Implements only the methods needed for this test.
+ */
+function AutoCompleteInputBase(aSearches) {
+  this.searches = aSearches;
+}
+AutoCompleteInputBase.prototype = {
+ 
+  // Array of AutoCompleteSearch names
+  searches: null,
+  
+  minResultsForPopup: 0,
+  timeout: 10,
+  searchParam: "",
+  textValue: "",
+  disableAutoComplete: false,  
+  completeDefaultIndex: false,
+
+  // Text selection range
+  _selStart: 0,
+  _selEnd: 0,
+  get selectionStart() {
+    return this._selStart;
+  },
+  get selectionEnd() {
+    return this._selEnd;
+  },
+  selectTextRange: function(aStart, aEnd) {
+    this._selStart = aStart;
+    this._selEnd = aEnd;
+  },
+  
+  get searchCount() {
+    return this.searches.length;
+  },
+  
+  getSearchAt: function(aIndex) {
+    return this.searches[aIndex];
+  },
+  
+  onSearchBegin: function() {},
+  onSearchComplete: function() {},
+  
+  popupOpen: false,  
+  
+  popup: { 
+    selectedIndex: 0,
+    invalidate: function() {},
+
+    // nsISupports implementation
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompletePopup])   
+  },
+    
+  // nsISupports implementation
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteInput])
+}
+
+/** 
+ * nsIAutoCompleteResult implementation
+ */
+function AutoCompleteResultBase(aValues) {
+  this._values = aValues;
+}
+AutoCompleteResultBase.prototype = {
+  
+  // Arrays
+  _values: null,
+  _comments: [],
+  _styles: [],
+  
+  searchString: "",
+  searchResult: null,
+  
+  defaultIndex: -1,
+  
+  _typeAheadResult: false,
+  get typeAheadResult() {
+    return this._typeAheadResult;
+  },
+
+  get matchCount() {
+    return this._values.length;
+  },
+
+  getValueAt: function(aIndex) {
+    return this._values[aIndex];
+  },
+
+  getLabelAt: function(aIndex) {
+    return this.getValueAt(aIndex);
+  },
+  
+  getCommentAt: function(aIndex) {
+    return this._comments[aIndex];
+  },
+  
+  getStyleAt: function(aIndex) {
+    return this._styles[aIndex];
+  },
+  
+  getImageAt: function(aIndex) {
+    return "";
+  },
+
+  removeValueAt: function (aRowIndex, aRemoveFromDb) {},
+
+  // nsISupports implementation
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult])
+}
+
+/** 
+ * nsIAutoCompleteSearch implementation that always returns
+ * the same result set.
+ */
+function AutoCompleteSearchBase(aName, aResult) {
+  this.name = aName;
+  this._result = aResult;
+}
+AutoCompleteSearchBase.prototype = {
+  
+  // Search name. Used by AutoCompleteController
+  name: null,
+
+  // AutoCompleteResult
+  _result: null,
+
+  startSearch: function(aSearchString, 
+                        aSearchParam, 
+                        aPreviousResult, 
+                        aListener) {
+    var result = this._result;
+
+    result.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
+    aListener.onSearchResult(this, result);
+  },
+  
+  stopSearch: function() {},
+
+  // nsISupports implementation
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory,
+                                         Ci.nsIAutoCompleteSearch]),
+  
+  // nsIFactory implementation
+  createInstance: function(outer, iid) {
+    return this.QueryInterface(iid);
+  }
+}
+
+/** 
+ * Helper to register an AutoCompleteSearch with the given name.
+ * Allows the AutoCompleteController to find the search.
+ */
+function registerAutoCompleteSearch(aSearch) {
+  var name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name;
+  var cid = Cc["@mozilla.org/uuid-generator;1"].
+            getService(Ci.nsIUUIDGenerator).
+            generateUUID();
+
+  var desc = "Test AutoCompleteSearch";
+  var componentManager = Components.manager
+                                   .QueryInterface(Ci.nsIComponentRegistrar);
+  componentManager.registerFactory(cid, desc, name, aSearch);
+
+  // Keep the id on the object so we can unregister later
+  aSearch.cid = cid; 
+}
+
+/** 
+ * Helper to unregister an AutoCompleteSearch. 
+ */
+function unregisterAutoCompleteSearch(aSearch) {
+  var componentManager = Components.manager
+                                   .QueryInterface(Ci.nsIComponentRegistrar);  
+  componentManager.unregisterFactory(aSearch.cid, aSearch);
+}
+
--- a/toolkit/components/autocomplete/tests/unit/test_330578.js
+++ b/toolkit/components/autocomplete/tests/unit/test_330578.js
@@ -31,19 +31,16 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
 var gResultListener = {
   _lastResult: null,
   _lastValue: "",
   _lastRemoveFromDb: false,
 
   onValueRemoved: function(aResult, aValue, aRemoveFromDb) {
     this._lastResult = aResult;
     this._lastValue = aValue;
--- a/toolkit/components/autocomplete/tests/unit/test_378079.js
+++ b/toolkit/components/autocomplete/tests/unit/test_378079.js
@@ -31,19 +31,16 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
 /**
  * Unit test for Bug 378079 - AutoComplete returns invalid rows when
  * more than one AutoCompleteSearch is used.
  */
 
 
 
 /**
--- a/toolkit/components/autocomplete/tests/unit/test_393191.js
+++ b/toolkit/components/autocomplete/tests/unit/test_393191.js
@@ -31,19 +31,16 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
 /**
  * Unit test for Bug 393191 - AutoComplete crashes if result is null
  */
 
 
 
 /**
  * Dummy nsIAutoCompleteInput source that returns
--- a/toolkit/components/autocomplete/tests/unit/test_440866.js
+++ b/toolkit/components/autocomplete/tests/unit/test_440866.js
@@ -30,19 +30,16 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
 /**
  * Unit test for Bug 440866 - First AutoCompleteSearch that returns
  * RESULT_NOMATCH cancels all other searches when popup is open
  */
 
 
 
 /**
--- a/toolkit/components/autocomplete/tests/unit/test_463023.js
+++ b/toolkit/components/autocomplete/tests/unit/test_463023.js
@@ -31,17 +31,14 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
 // main
 function run_test() {
   var result = Cc["@mozilla.org/autocomplete/controller;1"].
                createInstance(Ci.nsIAutoCompleteController);
   do_check_eq(result.searchStatus, Ci.nsIAutoCompleteController.STATUS_NONE);
 }
--- a/toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
+++ b/toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
@@ -31,19 +31,16 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
 /**
  * Dummy nsIAutoCompleteInput source that returns
  * the given list of AutoCompleteSearch names. 
  * 
  * Implements only the methods needed for this test.
  */
 function AutoCompleteInput(aSearches) {
   this.searches = aSearches;
new file mode 100644
--- /dev/null
+++ b/toolkit/components/autocomplete/tests/unit/test_hiddenResult.js
@@ -0,0 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function AutoCompleteResult(aValues) {
+  this._values = aValues;
+  this.defaultIndex = -1;
+  this._typeAheadResult = false;
+}
+AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
+
+function AutoCompleteTypeAheadResult(aValues) {
+  this._values = aValues;
+  this.defaultIndex = 0;
+  this._typeAheadResult = true;
+}
+AutoCompleteTypeAheadResult.prototype = Object.create(AutoCompleteResultBase.prototype);
+
+
+/** 
+ * Test AutoComplete with multiple AutoCompleteSearch sources, with one of them
+ * being hidden from the popup, but can still do typeahead completion.
+ */
+function run_test() {
+  do_test_pending();
+
+  var inputStr = "moz";
+
+  // Type ahead result
+  var searchTypeAhead = new AutoCompleteSearchBase("search1",
+                                                   new AutoCompleteTypeAheadResult(["mozillaTest1"]));
+  // Regular result
+  var searchNormal = new AutoCompleteSearchBase("search2",
+                                                new AutoCompleteResult(["mozillaTest2"]));
+  
+  // Register searches so AutoCompleteController can find them
+  registerAutoCompleteSearch(searchNormal);
+  registerAutoCompleteSearch(searchTypeAhead);
+  
+  // Make an AutoCompleteInput that uses our searches
+  // and confirms results on search complete.
+  var input = new AutoCompleteInputBase([searchTypeAhead.name, searchNormal.name]);
+  input.completeDefaultIndex = true;
+  input.textValue = inputStr;
+
+  // Caret must be at the end. Autofill doesn't happen unless you're typing
+  // characters at the end.
+  var strLen = inputStr.length;
+  input.selectTextRange(strLen, strLen);
+  do_check_eq(input.selectionStart, strLen);
+  do_check_eq(input.selectionEnd, strLen);
+
+  var controller = Cc["@mozilla.org/autocomplete/controller;1"].
+                   getService(Ci.nsIAutoCompleteController);  
+
+  controller.input = input;
+  controller.startSearch(inputStr);
+
+  input.onSearchComplete = function() {
+    // Hidden results should still be able to do inline autocomplete
+    do_check_eq(input.textValue, "mozillaTest1");
+
+    // Now, let's fill the textbox with the first result of the popup.
+    // The first search is marked as hidden, so we must always get the
+    // second search.
+    controller.handleEnter(true);
+    do_check_eq(input.textValue, "mozillaTest2");
+
+    // Only one item in the popup.
+    do_check_eq(controller.matchCount, 1);
+
+    // Unregister searches
+    unregisterAutoCompleteSearch(searchNormal);
+    unregisterAutoCompleteSearch(searchTypeAhead);
+    do_test_finished();
+  };
+}
--- a/toolkit/components/autocomplete/tests/unit/test_previousResult.js
+++ b/toolkit/components/autocomplete/tests/unit/test_previousResult.js
@@ -31,19 +31,16 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
 /**
  * Unit test for Bug 438861 - Previous search results not returned to multiple
  * searches.
  */
 
 
 /**
  * Dummy nsIAutoCompleteInput source that returns
--- a/toolkit/components/autocomplete/tests/unit/test_stopSearch.js
+++ b/toolkit/components/autocomplete/tests/unit/test_stopSearch.js
@@ -2,18 +2,16 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 /**
  * Purpose of the test is to check that a stopSearch call comes always before a
  * startSearch call.
  */
-const Cc = Components.classes;
-const Ci = Components.interfaces;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 
 /**
  * Dummy nsIAutoCompleteInput source that returns
  * the given list of AutoCompleteSearch names.
  *
--- a/toolkit/components/autocomplete/tests/unit/xpcshell.ini
+++ b/toolkit/components/autocomplete/tests/unit/xpcshell.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
-head = 
+head = head_autocomplete.js
 tail = 
 
 [test_330578.js]
 [test_378079.js]
 [test_393191.js]
 [test_440866.js]
 [test_463023.js]
 [test_autocomplete_multiple.js]
+[test_hiddenResult.js]
 [test_previousResult.js]
 [test_stopSearch.js]
--- a/toolkit/components/filepicker/nsFileView.cpp
+++ b/toolkit/components/filepicker/nsFileView.cpp
@@ -156,16 +156,23 @@ NS_IMETHODIMP nsFileResult::GetErrorDesc
 
 NS_IMETHODIMP nsFileResult::GetMatchCount(PRUint32 *aMatchCount)
 {
   NS_ENSURE_ARG_POINTER(aMatchCount);
   *aMatchCount = mValues.Length();
   return NS_OK;
 }
 
+NS_IMETHODIMP nsFileResult::GetTypeAheadResult(bool *aTypeAheadResult)
+{
+  NS_ENSURE_ARG_POINTER(aTypeAheadResult);
+  *aTypeAheadResult = PR_FALSE;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsFileResult::GetValueAt(PRInt32 index, nsAString & aValue)
 {
   aValue = mValues[index];
   return NS_OK;
 }
 
 NS_IMETHODIMP nsFileResult::GetLabelAt(PRInt32 index, nsAString & aValue)
 {