passes quick search unit test now. gloda-facet
authorAndrew Sutherland <asutherland@asutherland.org>
Wed, 09 Sep 2009 17:27:08 -0700
branchgloda-facet
changeset 3723 42c3a1ae9d02b7f22830b04e4974bc8127d37647
parent 3722 b6e40f00365caa4376ffe05cafe0bb3f82bd71db
child 3724 e28e10df4d1470247a08a74dbfbf9b4859c01b2d
push idunknown
push userunknown
push dateunknown
passes quick search unit test now.
mail/base/content/search.xml
mail/build.mk
mail/test/mozmill/folder-display/test-quick-search.js
mailnews/db/gloda/components/glautocomp.js
--- a/mail/base/content/search.xml
+++ b/mail/base/content/search.xml
@@ -194,17 +194,17 @@
       </handler>
     </handlers>
 
     <implementation implements="nsIObserver">
       <constructor><![CDATA[
         const Cc = Components.classes;
         const Ci = Components.interfaces;
         const Cu = Components.utils;
-        Cu.import("resource://gre/modules/errUtils.js");
+        Cu.import("resource://app/modules/errUtils.js");
         try {
           Cu.import("resource://app/modules/StringBundle.js");
           Cu.import("resource://app/modules/quickSearchManager.js");
 
           var prefBranch =
               Components.classes['@mozilla.org/preferences-service;1'].
               getService(Components.interfaces.nsIPrefBranch2);
           prefBranch.addObserver("mailnews.database.global.indexer.enabled",
@@ -257,17 +257,17 @@
           this.updateSaveItem();
           this.input = "";
           this.glodaEnabled =
             prefBranch.getBoolPref("mailnews.database.global.indexer.enabled");
           this.searchMode = this.glodaEnabled ? "global" :
             quickSearchModes[QuickSearchConstants.kQuickSearchFromOrSubject]
               .value.toString();
         } catch (e) {
-          logException(e);
+          logException(e, true);
         }
       ]]></constructor>
 
       <destructor>
         <![CDATA[
           var prefBranch =
               Components.classes['@mozilla.org/preferences-service;1'].
               getService(Components.interfaces.nsIPrefBranch);
@@ -340,17 +340,18 @@
             this.showGlodaItems(val); this._glodaEnabled = val;
           } catch(e) {
             logException(e);
           }
         ]]></setter>
       </property>
       <property name="autocompletePopup" readonly="true">
         <getter><![CDATA[
-          return document.getElementById(this.getAttribute('autocompletepopup'))
+          return document.getElementById(
+                   this.getAttribute('autocompletepopup'));
         ]]></getter>
       </property>
       <property name="showingSearchCriteria">
         <getter><![CDATA[
           return this.getAttribute('searchCriteria') == 'true';
         ]]></getter>
         <setter><![CDATA[
           this.setAttribute('searchCriteria', val); return val;
--- a/mail/build.mk
+++ b/mail/build.mk
@@ -117,15 +117,15 @@ else
 PROGRAM_LOCATION = ../../../$(DIST)/bin/
 PROGRAM = $(PROGRAM_LOCATION)thunderbird$(BIN_SUFFIX)
 endif
 
 mozmill::
 	cd $(MOZMILLDIR) && MACOSX_DEPLOYMENT_TARGET= $(PYTHON) \
 	runtestlist.py --list=mozmilltests.list --binary=$(PROGRAM) \
 	--dir=$(topsrcdir)/mail/test/mozmill \
-	--default-profile=$(PROGRAM_LOCATION)/defaults/profile
+	--default-profile=$(PROGRAM_LOCATION)/defaults/profile $(MOZMILL_EXTRA)
 
 mozmill-one::
 	cd $(MOZMILLDIR) && MACOSX_DEPLOYMENT_TARGET= $(PYTHON) runtest.py \
 	--test=$(topsrcdir)/mail/test/mozmill/$(SOLO_TEST) --binary=$(PROGRAM) \
-	--default-profile=$(PROGRAM_LOCATION)/defaults/profile
+	--default-profile=$(PROGRAM_LOCATION)/defaults/profile $(MOZMILL_EXTRA)
 endif
--- a/mail/test/mozmill/folder-display/test-quick-search.js
+++ b/mail/test/mozmill/folder-display/test-quick-search.js
@@ -56,39 +56,35 @@ function setupModule(module) {
     make_new_sets_in_folder(folder, [{subject: "foo", count: 1},
                                      {subject: "bar", count: 1}]);
 }
 
 /**
  *
  */
 function test_save_quick_search() {
-  mc.sleep(3000);
   be_in_folder(folder);
-  mc.sleep(2000);
 
-  // - Force it to do a subject search, not a gloda search!
-dump("GLODA SEARCH MODE: " + mc.e("gloda-search").searchMode + "\n");
-  mc.e("gloda-search").searchMode =
-    QuickSearchConstants.kQuickSearchSubject.toString();
-dump("GLODA SEARCH MODE: " + mc.e("gloda-search").searchMode + "\n");
+  // - We want to do a from or subject search
+  mc.e("searchInput").searchMode =
+    QuickSearchConstants.kQuickSearchFromOrSubject.toString();
 
   // - Type something in the quick search box.
   mc.type(mc.eid("searchInput"), "foo");
 
   mc.keypress(mc.eid("searchInput"), "VK_RETURN", {});
   wait_for_all_messages_to_load();
 
   // - Click the "Save Search as a Folder" button
   // This will create a virtual folder properties dialog...
   // (label: "New Saved Search Folder", source: virtualFolderProperties.xul
   //  no windowtype, id: "virtualFolderPropertiesDialog")
   plan_for_modal_dialog("mailnews:virtualFolderProperties",
                         subtest_save_search);
-  mc.click(mc.eid("quickSearchSaveAsVirtualFolder"));
+  mc.e("searchInput").saveAsVirtualFolder.doCommand();
   wait_for_modal_dialog("mailnews:virtualFolderProperties");
 }
 
 /**
  * Save the search, making sure that the "subject OR from" constraints are
  *  there.
  */
 function subtest_save_search(savc) {
--- a/mailnews/db/gloda/components/glautocomp.js
+++ b/mailnews/db/gloda/components/glautocomp.js
@@ -104,17 +104,17 @@ ResultRowMulti.prototype = {
 
 function nsAutoCompleteGlodaResult(aListener, aCompleter, aString) {
   this.listener = aListener;
   this.completer = aCompleter;
   this.searchString = aString;
   this._results = [];
   this._pendingCount = 0;
   this._problem = false;
-  
+
   this.wrappedJSObject = this;
 }
 nsAutoCompleteGlodaResult.prototype = {
   getObjectAt: function(aIndex) {
     return this._results[aIndex];
   },
   markPending: function ACGR_markPending(aCompleter) {
     this._pendingCount++;
@@ -122,17 +122,17 @@ nsAutoCompleteGlodaResult.prototype = {
   markCompleted: function ACGR_markCompleted(aCompleter) {
     if (--this._pendingCount == 0) {
       this.listener.onSearchResult(this.completer, this);
     }
   },
   addRows: function ACGR_addRows(aRows) {
     if (!aRows.length)
       return;
-    this._results.push.apply(this._results, aRows); 
+    this._results.push.apply(this._results, aRows);
     this.listener.onSearchResult(this.completer, this);
   },
   // ==== nsIAutoCompleteResult
   searchString: null,
   get searchResult() {
     if (this._problem)
       return Ci.nsIAutoCompleteResult.RESULT_FAILURE;
     if (this._results.length)
@@ -231,45 +231,45 @@ ContactIdentityCompleter.prototype = {
                for each ([iVal, val] in Iterator(contactToThing))];
 
     let rows = [new ResultRowSingle(match, "text", aResult.searchString)
                 for each ([iMatch, match] in Iterator(matches))];
     aResult.addRows(rows);
 
     // - match against database contacts / identities
     let pending = {contactToThing: contactToThing, pendingCount: 2};
-    
+
     let contactQuery = Gloda.newQuery(Gloda.NOUN_CONTACT);
     contactQuery.nameLike(contactQuery.WILD, aString, contactQuery.WILD);
     pending.contactColl = contactQuery.getCollection(this, aResult);
     pending.contactColl.becomeExplicit();
 
     let identityQuery = Gloda.newQuery(Gloda.NOUN_IDENTITY);
     identityQuery.kind("email").valueLike(identityQuery.WILD, aString,
         identityQuery.WILD);
     pending.identityColl = identityQuery.getCollection(this, aResult);
     pending.identityColl.becomeExplicit();
-    
+
     aResult._contactCompleterPending = pending;
 
     return true;
   },
   onItemsAdded: function(aItems, aCollection) {
   },
   onItemsModified: function(aItems, aCollection) {
   },
   onItemsRemoved: function(aItems, aCollection) {
   },
   onQueryCompleted: function(aCollection) {
     // handle the initial setup case...
     if (aCollection.data == null) {
       // cheat and explicitly add our own contact...
       if (!(Gloda.myContact.id in this.contactCollection._idMap))
         this.contactCollection._onItemsAdded([Gloda.myContact]);
-        
+
       // the set of identities owned by the contacts is automatically loaded as part
       //  of the contact loading...
       // (but only if we actually have any contacts)
       this.identityCollection =
         this.contactCollection.subCollections[Gloda.NOUN_IDENTITY];
 
       let contactNames = [(c.name.replace(" ", "").toLowerCase() || "x") for each
                           ([, c] in Iterator(this.contactCollection.items))];
@@ -284,31 +284,31 @@ ContactIdentityCompleter.prototype = {
       // In the degenerate case where identityCollection does not exist, it will
       //  be undefined.  Calling concat with an argument of undefined simply
       //  duplicates the list we called concat on, and is thus harmless.  Our
       //  use of && on identityCollection allows its undefined value to be
       //  passed through to concat.  identityMails will likewise be undefined.
       this.suffixTree = new MultiSuffixTree(contactNames.concat(identityMails),
         this.contactCollection.items.concat(this.identityCollection &&
           this.identityCollection.items));
-      
+
       return;
     }
-    
+
     // handle the completion case
     let result = aCollection.data;
     let pending = result._contactCompleterPending;
-    
+
     if (--pending.pendingCount == 0) {
       let possibleDudes = [];
-      
+
       let contactToThing = pending.contactToThing;
-      
+
       let items;
-      
+
       // check identities first because they are better than contacts in terms
       //  of display
       items = pending.identityColl.items;
       for (let iIdentity = 0; iIdentity < items.length; iIdentity++){
         let identity = items[iIdentity];
         if (!(identity.contactID in contactToThing)) {
           contactToThing[identity.contactID] = identity;
           possibleDudes.push(identity);
@@ -319,24 +319,24 @@ ContactIdentityCompleter.prototype = {
       items = pending.contactColl.items;
       for (let iContact = 0; iContact < items.length; iContact++) {
         let contact = items[iContact];
         if (!(contact.id in contactToThing)) {
           contactToThing[contact.id] = contact;
           possibleDudes.push(contact.identities[0]);
         }
       }
-      
+
       // sort in order of descending popularity
       possibleDudes.sort(this._popularitySorter);
       let rows = [new ResultRowSingle(dude, "text", result.searchString)
                   for each ([iDude, dude] in Iterator(possibleDudes))];
       result.addRows(rows);
       result.markCompleted(this);
-      
+
       // the collections no longer care about the result, make it clear.
       delete pending.identityColl.data;
       delete pending.contactColl.data;
       // the result object no longer needs us or our data
       delete result._contactCompleterPending;
     }
   }
 };
@@ -361,31 +361,31 @@ ContactTagCompleter.prototype = {
   },
   onFreeTagAdded: function(aTag) {
     this._suffixTreeDirty = true;
   },
   complete: function ContactTagCompleter_complete(aResult, aString) {
     // now is not the best time to do this; have onFreeTagAdded use a timer.
     if (this._suffixTreeDirty)
       this._buildSuffixTree();
-    
+
     if (aString.length < 2)
       return false; // no async mechanism that will add new rows
-    
+
     tags = this._suffixTree.findMatches(aString.toLowerCase());
     let rows = [];
     for each (let [iTag, tag] in Iterator(tags)) {
       let query = Gloda.newQuery(Gloda.NOUN_CONTACT);
       query.freeTags(tag);
       let resRow = new ResultRowMulti(Gloda.NOUN_CONTACT, "tag", tag.name,
                                       query);
       rows.push(resRow);
     }
     aResult.addRows(rows);
-    
+
     return false; // no async mechanism that will add new rows
   }
 };
 
 /**
  * Complete tags that are used on messages
  */
 function MessageTagCompleter() {
@@ -401,25 +401,25 @@ MessageTagCompleter.prototype = {
       tags.push(tag);
     }
     this._suffixTree = new MultiSuffixTree(tagNames, tags);
     this._suffixTreeDirty = false;
   },
   complete: function MessageTagCompleter_complete(aResult, aString) {
     if (aString.length < 2)
       return false;
-    
+
     tags = this._suffixTree.findMatches(aString.toLowerCase());
     let rows = [];
     for each (let [, tag] in Iterator(tags)) {
       let resRow = new ResultRowSingle(tag, "tag", tag.tag, TagNoun.id);
       rows.push(resRow);
     }
     aResult.addRows(rows);
-    
+
     return false; // no async mechanism that will add new rows
   }
 };
 
 /**
  * Complete with helpful hints about full-text search
  */
 function FullTextCompleter() {
@@ -440,34 +440,36 @@ FullTextCompleter.prototype = {
       resRow = new ResultRowFullText(aString, words, "any", false);
       rows.push(resRow);
     }
     aResult.addRows(rows);
     return false; // no async mechanism that will add new rows
   }
 };
 
+var LOG;
+
 function nsAutoCompleteGloda() {
   this.wrappedJSObject = this;
   try {
     // set up our awesome globals!
     if (Gloda === null) {
       let loadNS = {};
       Cu.import("resource://app/modules/gloda/public.js", loadNS);
       Gloda = loadNS.Gloda;
-  
+
       Cu.import("resource://app/modules/gloda/utils.js", loadNS);
       GlodaUtils = loadNS.GlodaUtils;
       Cu.import("resource://app/modules/gloda/suffixtree.js", loadNS);
       MultiSuffixTree = loadNS.MultiSuffixTree;
       Cu.import("resource://app/modules/gloda/noun_tag.js", loadNS);
       TagNoun = loadNS.TagNoun;
       Cu.import("resource://app/modules/gloda/noun_freetag.js", loadNS);
       FreeTagNoun = loadNS.FreeTagNoun;
-  
+
       Cu.import("resource://app/modules/gloda/log4moz.js", loadNS);
       LOG = loadNS["Log4Moz"].repository.getLogger("gloda.autocomp");
     }
 
     this.completers = [];
     this.curResult = null;
 
     this.completers.push(new FullTextCompleter());
@@ -487,23 +489,23 @@ nsAutoCompleteGloda.prototype = {
       Components.interfaces.nsIAutoCompleteSearch]),
 
   startSearch: function(aString, aParam, aResult, aListener) {
     try {
       let result = new nsAutoCompleteGlodaResult(aListener, this, aString);
       // save this for hacky access to the search.  I somewhat suspect we simply
       //  should not be using the formal autocomplete mechanism at all.
       this.curResult = result;
-      
+
       for each (let [iCompleter, completer] in Iterator(this.completers)) {
         // they will return true if they have something pending.
         if (completer.complete(result, aString))
           result.markPending(completer);
       }
-      
+
       aListener.onSearchResult(this, result);
     } catch (e) {
       logException(e);
     }
   },
 
   stopSearch: function() {
   }