author | Neil Rashbrook <neil@parkwaycc.co.uk> |
Mon, 12 Aug 2013 23:49:35 +0100 | |
changeset 142288 | 73ec9b19228ac76a06599bc393783f4298478d9e |
parent 142287 | 716e54fb5d09e7f598aa64920c27fee2c4f449d0 |
child 142289 | cf1c3a76352d731ab402cf0d622a374e2c716a23 |
push id | 32364 |
push user | neil@parkwaycc.co.uk |
push date | Mon, 12 Aug 2013 22:58:55 +0000 |
treeherder | mozilla-inbound@f3e583c68088 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | IanN |
bugs | 896213 |
milestone | 26.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
xpfe/components/autocomplete/resources/content/autocomplete.xml | file | annotate | diff | comparison | revisions |
--- a/xpfe/components/autocomplete/resources/content/autocomplete.xml +++ b/xpfe/components/autocomplete/resources/content/autocomplete.xml @@ -63,18 +63,16 @@ this.ifSetAttribute("pastetimeout", 1000); this.ifSetAttribute("maxrows", 5); this.ifSetAttribute("showpopup", true); this.ifSetAttribute("disableKeyNavigation", true); // initialize the search sessions if (this.hasAttribute("autocompletesearch")) this.initAutoCompleteSearch(); - if (this.hasAttribute("searchSessions")) - this.initSearchSessions(); // hack to work around lack of bottom-up constructor calling if ("initialize" in this.popup) this.popup.initialize(); ]]></constructor> <destructor><![CDATA[ this.clearResults(false); @@ -234,52 +232,29 @@ this.mInputElt.dispatchEvent(event); return val; ]]></setter> </property> <property name="focused" onget="return this.getAttribute('focused') == 'true';"/> - <!-- space-delimited string of search session types to use --> - <property name="searchSessions" readonly="true" onget="return this.getAttribute('searchSessions') || ''"/> - - <method name="initSearchSessions"> - <body><![CDATA[ - var list = this.searchSessions.split(" "); - for (var i = 0; i < list.length; i++) { - var name = list[i]; - var contractid = "@mozilla.org/autocompleteSession;1?type=" + name; - if (contractid in Components.classes) { - try { - var session = - Components.classes[contractid].getService(Components.interfaces.nsIAutoCompleteSession); - this.addSession(session, name); - } catch (e) { - dump("### ERROR - unable to create search session \"" + name + "\".\n"); - } - } else { - dump("search session \"" + name + "\" not found - skipping.\n"); - } - } - ]]></body> - </method> - <method name="initAutoCompleteSearch"> <body><![CDATA[ var list = this.getAttribute("autocompletesearch").split(" "); for (var i = 0; i < list.length; i++) { var name = list[i]; var contractid = "@mozilla.org/autocomplete/search;1?name=" + name; if (contractid in Components.classes) { try { - var search = + this.mSessions[name] = Components.classes[contractid].getService(Components.interfaces.nsIAutoCompleteSearch); - var session = new (this.mAutoCompleteSession)(search); - this.addSession(session, name); + this.mLastResults[name] = null; + this.mLastRows[name] = 0; + ++this.sessionCount; } catch (e) { dump("### ERROR - unable to create search \"" + name + "\".\n"); } } else { dump("search \"" + name + "\" not found - skipping.\n"); } } ]]></body> @@ -340,19 +315,18 @@ <!-- state which indicates a search timeout is current waiting --> <property name="isWaiting" onget="return this.mAutoCompleteTimer != 0;"/> <!-- =================== PRIVATE PROPERTIES =================== --> <field name="mSessions">({})</field> - <field name="mListeners">({})</field> <field name="mLastResults">({})</field> - <field name="mLastStatus">({})</field> + <field name="mLastRows">({})</field> <field name="mLastKeyCode">null</field> <field name="mAutoCompleteTimer">0</field> <field name="mMenuOpen">false</field> <field name="mFireAfterSearch">false</field> <field name="mFinishAfterSearch">false</field> <field name="mNeedToFinish">false</field> <field name="mNeedToComplete">false</field> <field name="mTransientValue">false</field> @@ -397,261 +371,80 @@ this.self.closePopup(); } catch (e) { window.top.removeEventListener("DOMMenuBarActive", this, true); } } }) ]]></field> - <field name="mAutoCompleteSession"><![CDATA[ - var session = function(aSession) { this.session = aSession }; - session.prototype = { - session: null, - param: this, - onStartLookup: function(aSearchString, aPreviousSearchResult, aListener) { - this.session.startSearch(aSearchString, - this.param.searchParam, - aPreviousSearchResult && aPreviousSearchResult.lastResult, - aListener); - }, - onStopLookup: function() { - this.session.stopSearch(); - }, - onAutoComplete: function() { + <field name="mAutoCompleteObserver"><![CDATA[ + ({ + self: this, + onSearchResult: function(aSearch, aResult) { + for (var name in this.self.mSessions) + if (this.self.mSessions[name] == aSearch) + this.self.processResults(name, aResult); } - }; - session; - ]]></field> - - <field name="mAutoCompleteListener"><![CDATA[ - var listener = function(aName) { this.sessionName = aName }; - listener.prototype = { - param: this, - sessionName: null, - lastResult: null, - lastItems: [], - onAutoComplete: function(aResults, aStatus) - { - this.param.processResults(this.sessionName, aResults, aStatus); - }, - onSearchResult: function(aSearch, aResult) - { - this.lastResult = aResult; - this.lastItems = new Array(aResult.matchCount); - const nsIAutoCompleteStatus = Components.interfaces.nsIAutoCompleteStatus; - var status = nsIAutoCompleteStatus.failed; - if (aResult.errorDescription) { - status = nsIAutoCompleteStatus.failureItems; - this.lastItems = [{ - value: aResult.errorDescription, - comment: null, - className: null, - param: null - }]; - } - else if (aResult.searchResult == aResult.RESULT_IGNORED) - status = nsIAutoCompleteStatus.ignored; - else if (aResult.searchResult == aResult.RESULT_NOMATCH) - status = nsIAutoCompleteStatus.noMatch; - else if (aResult.searchResult == aResult.RESULT_SUCCESS) - status = nsIAutoCompleteStatus.matchFound; - else if (aResult.searchResult == aResult.RESULT_NOMATCH_ONGOING) - status = nsIAutoCompleteStatus.noMatchYet; - else if (aResult.searchResult == aResult.RESULT_SUCCESS_ONGOING) - status = nsIAutoCompleteStatus.matchSoFar; - this.param.processResults(this.sessionName, { - searchString: aResult.searchString, - items: this, - defaultItemIndex: aResult.defaultIndex, - param: null, - lastResult: aResult - }, status); - }, - Count: function() { - return this.lastItems.length; - }, - QueryElementAt: function(aIndex, aIID) { - if (aIndex < 0 || aIndex >= this.lastItems.length) - return null; - if (!this.lastItems[aIndex]) { - this.lastItems[aIndex] = { - value: this.lastResult.getValueAt(aIndex), - comment: this.lastResult.getCommentAt(aIndex), - className: this.lastResult.getStyleAt(aIndex), - param: null - } - } - return this.lastItems[aIndex]; - } - }; - listener; + }) ]]></field> <field name="mInputElt"><![CDATA[ document.getAnonymousElementByAttribute(this, "anonid", "input"); ]]></field> <field name="mMenuAccessKey"><![CDATA[ Components.classes["@mozilla.org/preferences-service;1"] .getService(Components.interfaces.nsIPrefBranch) .getIntPref("ui.key.menuAccessKey"); ]]></field> <!-- =================== PUBLIC METHODS =================== --> - <!-- get the result object from the autocomplete results from a specific session --> - <method name="getResultAt"> + <method name="getErrorAt"> <parameter name="aIndex"/> <body><![CDATA[ - var obj = this.convertIndexToSession(aIndex); - if (obj && this.mLastResults[obj.session]) { - const nsIAutoCompleteItem = Components.interfaces.nsIAutoCompleteItem; - if (obj.index >= 0) { - var item = this.mLastResults[obj.session].items.QueryElementAt(obj.index, nsIAutoCompleteItem); - return item; - } - } - return null; + var obj = aIndex < 0 ? null : this.convertIndexToSession(aIndex); + return obj && this.mLastResults[obj.session] && + this.mLastResults[obj.session].errorDescription; ]]></body> </method> - <!-- get the autocomplete session status returned by the session - that a given item came from --> - <method name="getSessionStatusAt"> - <parameter name="aIndex"/> - <body><![CDATA[ - var obj = this.convertIndexToSession(aIndex); - return obj ? this.mLastStatus[obj.session] : null; - ]]></body> - </method> - - <!-- get a value from the autocomplete results as a string via an absolute index--> <method name="getResultValueAt"> <parameter name="aIndex"/> <body><![CDATA[ var obj = this.convertIndexToSession(aIndex); return obj ? this.getSessionValueAt(obj.session, obj.index) : null; ]]></body> </method> - <!-- get the result object from the autocomplete results from a specific session --> - <method name="getSessionResultAt"> - <parameter name="aSession"/> - <parameter name="aIndex"/> - <body><![CDATA[ - var session = this.mLastResults[aSession]; - if (session) { - var item = session.items.QueryElementAt(aIndex, Components.interfaces.nsIAutoCompleteItem); - return item; - } - return null; - ]]></body> - </method> - <!-- get a value from the autocomplete results as a string from a specific session --> <method name="getSessionValueAt"> <parameter name="aSession"/> <parameter name="aIndex"/> <body><![CDATA[ - var result = this.getSessionResultAt(aSession, aIndex); - if (result) - return result.value; - return null; + var result = this.mLastResults[aSession]; + return result.errorDescription || result.getValueAt(aIndex); ]]></body> </method> <!-- get the total number of results overall --> <method name="getResultCount"> <body><![CDATA[ return this.view.rowCount; ]]></body> </method> - <!-- get a session object by index --> - <method name="getSession"> - <parameter name="aIndex"/> - <body><![CDATA[ - var idx = -1; - for (var name in this.mSessions) - if (++idx == aIndex) - return this.mSessions[name]; - - return null; - ]]></body> - </method> - - <!-- get a session object by name --> - <method name="getSessionByName"> - <parameter name="aSessionName"/> - <body><![CDATA[ - return this.mSessions[aSessionName]; - ]]></body> - </method> - - <!-- add a session by reference --> - <method name="addSession"> - <parameter name="aSession"/> - <parameter name="aName"/> - <body><![CDATA[ - ++this.sessionCount; - var name = aName || ("anon_" + this.sessionCount); - this.mSessions[name] = aSession; - this.mListeners[name] = new (this.mAutoCompleteListener)(name); - this.mLastResults[name] = null; - this.mLastStatus[name] = null; - return this.mSessions[name]; - ]]></body> - </method> - - <!-- remove a session by reference --> - <method name="removeSession"> - <parameter name="aSession"/> - <body><![CDATA[ - for (var name in this.mSessions) { - if (this.mSessions[name] == aSession) { - delete this.mSessions[name]; - delete this.mListeners[name]; - delete this.mLastResults[name]; - delete this.mLastStatus[name]; - --this.sessionCount; - break; - } - } - ]]></body> - </method> - - <!-- make this widget listen to all of the same autocomplete sessions - from another autocomplete widget --> - <method name="syncSessions"> - <parameter name="aCopyFrom"/> - <body><![CDATA[ - this.sessionCount = aCopyFrom.sessionCount; - this.mSessions = {}; - this.mListeners = {}; - this.mLastResults = {}; - this.mLastStatus = {}; - for (var name in aCopyFrom.mSessions) { - this.mSessions[name] = aCopyFrom.mSessions[name]; - this.mListeners[name] = new (this.mAutoCompleteListener)(name); - this.mLastResults[name] = null; - this.mLastStatus[name] = null; - } - ]]></body> - </method> - <!-- get the first session that has results --> <method name="getDefaultSession"> <body><![CDATA[ for (var name in this.mLastResults) { var results = this.mLastResults[name]; - var status = this.mLastStatus[name]; - if (results && results.items.Count() > 0 && status != - Components.interfaces.nsIAutoCompleteStatus.failureItems) + if (results && results.matchCount > 0 && !results.errorDescription) return name; } return null; ]]></body> </method> <!-- empty the cached result data and empty the results popup --> <method name="clearResults"> @@ -684,20 +477,16 @@ switch (aAction) { case "startLookup": me.startLookup(); break; case "stopLookup": me.stopLookup(); break; - - case "autoComplete": - me.autoComplete(); - break; } ]]></body> </method> <!-- --> <method name="startLookup"> <body><![CDATA[ var str = this.currentSearchString; @@ -714,89 +503,76 @@ this.mDefaultMatchFilled = false; // clear out our prefill state. // Notify the input that the search is beginning. this.onSearchBegin(); // tell each session to start searching... for (var name in this.mSessions) try { - this.mSessions[name].onStartLookup(str, this.mLastResults[name], this.mListeners[name]); + this.mSessions[name].startSearch(str, this.searchParam, this.mLastResults[name], this.mAutoCompleteObserver); } catch (e) { --this.mSessionReturns; this.searchFailed(); } ]]></body> </method> <!-- --> <method name="stopLookup"> <body><![CDATA[ for (var name in this.mSessions) - this.mSessions[name].onStopLookup(); - ]]></body> - </method> - - <!-- --> - <method name="autoComplete"> - <body><![CDATA[ - for (var name in this.mSessions) - this.mSessions[name].onAutoComplete(this.value, - this.mLastResults[name], - this.mListeners[name]); + this.mSessions[name].stopSearch(); ]]></body> </method> <!-- --> <method name="processResults"> <parameter name="aSessionName"/> <parameter name="aResults"/> - <parameter name="aStatus"/> <body><![CDATA[ if (this.disableAutoComplete) return; - if (aStatus != Components.interfaces.nsIAutoCompleteStatus.noMatchYet && - aStatus != Components.interfaces.nsIAutoCompleteStatus.matchSoFar) + const ACR = Components.interfaces.nsIAutoCompleteResult; + var status = aResults.searchResult; + if (status != ACR.RESULT_NOMATCH_ONGOING && + status != ACR.RESULT_SUCCESS_ONGOING) --this.mSessionReturns; - this.mLastStatus[aSessionName] = aStatus; - // check the many criteria for failure - if (aStatus == Components.interfaces.nsIAutoCompleteStatus.failed || - aStatus == Components.interfaces.nsIAutoCompleteStatus.ignored || - aStatus == Components.interfaces.nsIAutoCompleteStatus.noMatch || - aStatus == Components.interfaces.nsIAutoCompleteStatus.noMatchYet || - aResults == null || - aResults.items.Count() == 0 || - aResults.searchString != this.currentSearchString) + if (aResults.errorDescription) + ++this.mFailureItems; + else if (status == ACR.RESULT_IGNORED || + status == ACR.RESULT_FAILURE || + status == ACR.RESULT_NOMATCH || + status == ACR.RESULT_NOMATCH_ONGOING || + aResults.matchCount == 0 || + aResults.searchString != this.currentSearchString) { this.mLastResults[aSessionName] = null; if (this.mFirstReturn) this.clearResultElements(false); this.mFirstReturn = false; this.searchFailed(); return; } - if (aStatus == Components.interfaces.nsIAutoCompleteStatus.failureItems) - ++this.mFailureItems; if (this.mFirstReturn) { if (this.view.mTree) this.view.mTree.beginUpdateBatch(); this.clearResultElements(false); // clear results, but don't repaint yet } // always call openPopup...we may not have opened it // if a previous search session didn't return enough search results. // it's smart and doesn't try to open itself multiple times... // be sure to add our result elements before calling openResultPopuup as we need // to know the total # of results found so far. - this.addResultElements(aResults, this.mLastResults[aSessionName]); - this.mLastResults[aSessionName] = aResults; + this.addResultElements(aSessionName, aResults); this.autoFillInput(aSessionName, aResults, false); if (this.mFirstReturn && this.view.mTree) this.view.mTree.endUpdateBatch(); this.openPopup(); this.mFirstReturn = false; // if this is the last session to return... @@ -833,17 +609,18 @@ <method name="postSearchCleanup"> <body><![CDATA[ this.isSearching = false; // figure out if there are no matches in all search sessions var failed = true; for (var name in this.mSessions) { if (this.mLastResults[name]) - failed = this.mLastResults[name].items.Count() < 1; + failed = this.mLastResults[name].errorDescription || + this.mLastResults[name].matchCount == 0; if (!failed) break; } this.noMatch = failed; // if we have processed all of our searches, and none of them gave us a default index, // then we should try to auto fill the input field with the first match. // note: autoFillInput is smart enough to kick out if we've already prefilled something... @@ -885,19 +662,20 @@ this.mFinishAfterSearch = true; this.mFireAfterSearch = aFireTextCommand; return; } else { // we want to use the default item index for the first session which gave us a valid // default item index... for (var name in this.mLastResults) { var results = this.mLastResults[name]; - if (results && results.items.Count() > 0 && results.defaultItemIndex != -1) + if (results && results.matchCount > 0 && + !results.errorDescription && results.defaultIndex != -1) { - val = this.getSessionValueAt(name, results.defaultItemIndex); + val = this.getSessionValueAt(name, results.defaultIndex); this.setTextValue(val); this.mDefaultMatchFilled = true; this.mNeedToFinish = false; break; } } if (this.mNeedToFinish) { @@ -918,53 +696,45 @@ this.setTextValue(first); this.mDefaultMatchFilled = true; } } } this.stopLookup(); - if (!this.noMatch) - this.autoComplete(); - this.closePopup(); } this.mNeedToComplete = false; this.clearTimer(); if (aFireTextCommand) this._fireEvent("textentered", this.userAction, aTriggeringEvent); ]]></body> </method> <!-- when the user clicks an entry in the autocomplete popup --> <method name="onResultClick"> <body><![CDATA[ // set textbox value to either override value, or the clicked result - var errItem=null; + var errItem = this.getErrorAt(this.popup.selectedIndex); var val = this.popup.overrideValue; if (val) this.setTextValue(val); else if (this.popup.selectedIndex != -1) { - if (this.getSessionStatusAt(this.popup.selectedIndex) == - Components.interfaces.nsIAutoCompleteStatus.failureItems) { + if (errItem) { this.setTextValue(this.currentSearchString); this.mTransientValue = true; - errItem = this.getResultAt(this.popup.selectedIndex); } else { this.setTextValue(this.getResultValueAt( this.popup.selectedIndex)); } } - if (!this.noMatch) - this.autoComplete(); - this.mNeedToFinish = false; this.mNeedToComplete = false; this.closePopup(); this.currentSearchString = ""; if (errItem) @@ -988,24 +758,20 @@ this.mNeedToComplete = false; ]]></body> </method> <!-- convert an absolute result index into a session name/index pair --> <method name="convertIndexToSession"> <parameter name="aIndex"/> <body><![CDATA[ - var idx = 0; - for (var name in this.mLastResults) { - if (this.mLastResults[name]) { - if ((idx+this.mLastResults[name].items.Count())-1 >= aIndex) { - return {session: name, index: aIndex-idx}; - } - idx += this.mLastResults[name].items.Count(); - } + for (var name in this.mLastRows) { + if (aIndex < this.mLastRows[name]) + return { session: name, index: aIndex }; + aIndex -= this.mLastRows[name]; } return null; ]]></body> </method> <!-- ::::::::::::: user input handling ::::::::::::: --> <!-- --> @@ -1051,22 +817,17 @@ this.keyNavigation(aEvent); } } break; case KeyEvent.DOM_VK_RETURN: // if this is a failure item, save it for fireErrorCommand - var errItem = null; - if (this.popup.selectedIndex != -1 && - this.getSessionStatusAt(this.popup.selectedIndex) == - Components.interfaces.nsIAutoCompleteStatus.failureItems) { - errItem = this.getResultAt(this.popup.selectedIndex); - } + var errItem = this.getErrorAt(this.popup.selectedIndex); killEvent = this.mMenuOpen; this.finishAutoComplete(true, true, aEvent); this.closePopup(); if (errItem) { this._fireEvent("errorcommand", errItem); } break; @@ -1174,18 +935,17 @@ k == KeyEvent.DOM_VK_PAGE_UP; var page = k == KeyEvent.DOM_VK_PAGE_UP || k == KeyEvent.DOM_VK_PAGE_DOWN; var selected = this.popup.selectBy(reverse, page); // determine which value to place in the textbox this.ignoreInputEvent = true; if (selected != -1) { - if (this.getSessionStatusAt(selected) == - Components.interfaces.nsIAutoCompleteStatus.failureItems) { + if (this.getErrorAt(selected)) { if (this.currentSearchString) this.setTextValue(this.currentSearchString); } else { this.setTextValue(this.getResultValueAt(selected)); } this.mTransientValue = true; } else { if (this.currentSearchString) @@ -1211,17 +971,17 @@ if (this.mInputElt.selectionEnd < this.currentSearchString.length || this.mDefaultMatchFilled) return; if (!this.mFinishAfterSearch && (this.autoFill || this.completeDefaultIndex) && this.mLastKeyCode != KeyEvent.DOM_VK_BACK_SPACE && this.mLastKeyCode != KeyEvent.DOM_VK_DELETE) { - var indexToUse = aResults.defaultItemIndex; + var indexToUse = aResults.defaultIndex; if (aUseFirstMatchIfNoDefault && indexToUse == -1) indexToUse = 0; if (indexToUse != -1) { var resultValue = this.getSessionValueAt(aSessionName, indexToUse); var match = resultValue.toLowerCase(); var entry = this.currentSearchString.toLowerCase(); this.ignoreInputEvent = true; @@ -1275,30 +1035,41 @@ this.popup.hidePopup(); this.mMenuOpen = false; } ]]></body> </method> <!-- --> <method name="addResultElements"> + <parameter name="aSession"/> <parameter name="aResults"/> - <parameter name="aOldResults"/> <body><![CDATA[ + var count = aResults.errorDescription ? 1 : aResults.matchCount; if (this.focused && this.showPopup) { - this.view.replaceResults(aResults, aOldResults); + var row = 0; + for (var name in this.mSessions) { + row += this.mLastRows[name]; + if (name == aSession) + break; + } + this.view.updateResults(row, count - this.mLastRows[name]); this.popup.adjustHeight(); } + this.mLastResults[aSession] = aResults; + this.mLastRows[aSession] = count; ]]></body> </method> <!-- --> <method name="clearResultElements"> <parameter name="aInvalidate"/> <body><![CDATA[ + for (var name in this.mSessions) + this.mLastRows[name] = 0; this.view.clearResults(); if (aInvalidate) this.popup.adjustHeight(); this.noMatch = true; ]]></body> </method> @@ -1317,31 +1088,18 @@ this.dispatchEvent(evt); this.ignoreInputEvent = oldIgnoreInput; ]]></body> </method> <!-- --> <method name="clearResultData"> <body><![CDATA[ - const nsIAutoCompleteItem = - Components.interfaces.nsIAutoCompleteItem; - for (var name in this.mSessions) { - // clearing out mLastResults[name] does not guarantee that - // each result will go away right now (it might be gc'ed later) - // so we have to clear the 'param' element manually - var session = this.mLastResults[name]; - if (session) { - const resultCount = session.items.Count(); - for (var i=0; i<resultCount; i++) - session.items.QueryElementAt(i, nsIAutoCompleteItem).param = null; - this.mLastResults[name] = null; - } - this.mLastStatus[name] = null; - } + for (var name in this.mSessions) + this.mLastResults[name] = null; ]]></body> </method> <!-- ::::::::::::: miscellaneous ::::::::::::: --> <!-- --> <method name="ifSetAttribute"> <parameter name="aAttr"/> @@ -1387,52 +1145,35 @@ <!-- =================== TREE VIEW =================== --> <field name="view"><![CDATA[ ({ mTextbox: this, mTree: null, mSelection: null, - mResults: [], - mCounts: [], mRowCount: 0, clearResults: function() { var oldCount = this.mRowCount; this.mRowCount = 0; - this.mResults = []; - this.mCounts = []; if (this.mTree) { this.mTree.rowCountChanged(0, -oldCount); this.mTree.scrollToRow(0); } }, - replaceResults: function(aResults, aOldResults) + updateResults: function(aRow, aCount) { - var count = aResults.items.Count(); - var row = this.mRowCount; - var oldIndex = this.mResults.indexOf(aOldResults); - if (oldIndex == -1) { - this.mResults.push(aResults); - this.mCounts.push(count); - } else { - this.mResults[oldIndex] = aResults; - count -= this.mCounts[oldIndex]; - this.mCounts[oldIndex] += count; - while (++oldIndex < this.mCounts.length) - row -= this.mCounts[oldIndex]; - } - this.mRowCount += count; + this.mRowCount += aCount; if (this.mTree) - this.mTree.rowCountChanged(row, count); + this.mTree.rowCountChanged(aRow, aCount); }, ////////////////////////////////////////////////////////// // nsIAutoCompleteController interface // this is the only method required by the treebody mouseup handler handleEnter: function(aIsPopupSelection) { this.mTextbox.onResultClick(); @@ -1455,40 +1196,55 @@ setTree: function(aTree) { this.mTree = aTree; }, getCellText: function(aRow, aCol) { - var result = this.mTextbox.getResultAt(aRow); - if (!result) return ""; - return aCol.id == "treecolAutoCompleteValue" ? result.value : (aCol.id == "treecolAutoCompleteComment" ? result.comment : ""); + for (var name in this.mTextbox.mSessions) { + if (aRow < this.mTextbox.mLastRows[name]) { + var result = this.mTextbox.mLastResults[name]; + switch (aCol.id) { + case "treecolAutoCompleteValue": + return result.errorDescription || result.getValueAt(aRow); + case "treecolAutoCompleteComment": + if (!result.errorDescription) + return result.getCommentAt(aRow); + default: + return ""; + } + } + aRow -= this.mTextbox.mLastRows[name]; + } + return ""; }, - getRowProperties: function(aIndex) + getRowProperties: function(aIndex) { return ""; }, getCellProperties: function(aIndex, aCol) { // for the value column, append nsIAutoCompleteItem::className // to the property list so that we can style this column // using that property - try { - if (aCol.id == "treecolAutoCompleteValue") { - return this.mTextbox.getResultAt(aIndex).className; + if (aCol.id == "treecolAutoCompleteValue") { + for (var name in this.mTextbox.mSessions) { + if (aIndex < this.mTextbox.mLastRows[name]) { + var result = this.mTextbox.mLastResults[name]; + if (result.errorDescription) + return ""; + return result.getStyleAt(aIndex); + } + aIndex -= this.mTextbox.mLastRows[name]; } - } catch (ex) { - // the ability to style here is a frill, so don't abort - // if there's a problem - } - + } return ""; }, getColumnProperties: function(aCol) { return ""; },