LCOV - code coverage report
Current view: top level - dom/xul/templates - nsXULTreeBuilder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 941 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 99 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsXULTreeBuilder.h"
       7             : #include "nscore.h"
       8             : #include "nsError.h"
       9             : #include "nsIContent.h"
      10             : #include "mozilla/dom/NodeInfo.h"
      11             : #include "nsIDOMElement.h"
      12             : #include "nsIBoxObject.h"
      13             : #include "nsITreeBoxObject.h"
      14             : #include "nsITreeSelection.h"
      15             : #include "nsITreeColumns.h"
      16             : #include "nsTreeUtils.h"
      17             : #include "nsIServiceManager.h"
      18             : #include "nsReadableUtils.h"
      19             : #include "nsQuickSort.h"
      20             : #include "nsTemplateRule.h"
      21             : #include "nsTemplateMatch.h"
      22             : #include "nsTreeColumns.h"
      23             : #include "nsGkAtoms.h"
      24             : #include "nsXULContentUtils.h"
      25             : #include "nsIXULSortService.h"
      26             : #include "nsTArray.h"
      27             : #include "nsUnicharUtils.h"
      28             : #include "nsNameSpaceManager.h"
      29             : #include "nsWhitespaceTokenizer.h"
      30             : #include "nsTreeContentView.h"
      31             : #include "nsIXULStore.h"
      32             : #include "mozilla/BinarySearch.h"
      33             : #include "mozilla/dom/DataTransfer.h"
      34             : #include "mozilla/dom/TreeBoxObject.h"
      35             : #include "mozilla/dom/XULTemplateBuilderBinding.h"
      36             : 
      37             : // For security check
      38             : #include "nsIDocument.h"
      39             : 
      40           0 : NS_IMPL_ADDREF_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder)
      41           0 : NS_IMPL_RELEASE_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder)
      42             : 
      43           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder,
      44             :                                    mBoxObject,
      45             :                                    mSelection,
      46             :                                    mPersistStateStore,
      47             :                                    mLocalStore,
      48             :                                    mObservers)
      49             : 
      50           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXULTreeBuilder)
      51           0 :     NS_INTERFACE_MAP_ENTRY(nsIXULTreeBuilder)
      52           0 :     NS_INTERFACE_MAP_ENTRY(nsITreeView)
      53           0 : NS_INTERFACE_MAP_END_INHERITING(nsXULTemplateBuilder)
      54             : 
      55             : 
      56           0 : nsXULTreeBuilder::nsXULTreeBuilder(Element* aElement)
      57             :     : nsXULTemplateBuilder(aElement),
      58           0 :       mSortDirection(eDirection_Natural), mSortHints(0)
      59             : {
      60           0 : }
      61             : 
      62           0 : nsXULTreeBuilder::~nsXULTreeBuilder()
      63             : {
      64           0 : }
      65             : 
      66             : JSObject*
      67           0 : nsXULTreeBuilder::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
      68             : {
      69           0 :     return XULTreeBuilderBinding::Wrap(aCx, this, aGivenProto);
      70             : }
      71             : 
      72             : void
      73           0 : nsXULTreeBuilder::Uninit(bool aIsFinal)
      74             : {
      75           0 :     int32_t count = mRows.Count();
      76           0 :     mRows.Clear();
      77             : 
      78           0 :     if (mBoxObject) {
      79           0 :         mBoxObject->BeginUpdateBatch();
      80           0 :         mBoxObject->RowCountChanged(0, -count);
      81           0 :         if (mBoxObject) {
      82           0 :             mBoxObject->EndUpdateBatch();
      83             :         }
      84             :     }
      85             : 
      86           0 :     nsXULTemplateBuilder::Uninit(aIsFinal);
      87           0 : }
      88             : 
      89             : 
      90             : //----------------------------------------------------------------------
      91             : //
      92             : // nsIXULTreeBuilder methods
      93             : //
      94             : 
      95             : already_AddRefed<nsIRDFResource>
      96           0 : nsXULTreeBuilder::GetResourceAtIndex(int32_t aRowIndex, ErrorResult& aError)
      97             : {
      98           0 :     if (!IsValidRowIndex(aRowIndex)) {
      99           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     100           0 :         return nullptr;
     101             :     }
     102             : 
     103           0 :     nsCOMPtr<nsIRDFResource> result;
     104           0 :     aError = GetResourceFor(aRowIndex, getter_AddRefs(result));
     105           0 :     return result.forget();
     106             : }
     107             : 
     108             : NS_IMETHODIMP
     109           0 : nsXULTreeBuilder::GetResourceAtIndex(int32_t aRowIndex, nsIRDFResource** aResult)
     110             : {
     111           0 :     ErrorResult rv;
     112           0 :     *aResult = GetResourceAtIndex(aRowIndex, rv).take();
     113           0 :     return rv.StealNSResult();
     114             : }
     115             : 
     116             : int32_t
     117           0 : nsXULTreeBuilder::GetIndexOfResource(nsIRDFResource* aResource,
     118             :                                      ErrorResult& aError)
     119             : {
     120           0 :     nsTreeRows::iterator iter = mRows.FindByResource(aResource);
     121           0 :     return iter == mRows.Last() ? -1 : iter.GetRowIndex();
     122             : }
     123             : 
     124             : NS_IMETHODIMP
     125           0 : nsXULTreeBuilder::GetIndexOfResource(nsIRDFResource* aResource, int32_t* aResult)
     126             : {
     127           0 :     NS_ENSURE_ARG_POINTER(aResource);
     128             : 
     129           0 :     ErrorResult rv;
     130           0 :     *aResult = GetIndexOfResource(aResource, rv);
     131           0 :     return rv.StealNSResult();
     132             : }
     133             : 
     134             : void
     135           0 : nsXULTreeBuilder::AddObserver(XULTreeBuilderObserver& aObserver)
     136             : {
     137             :     CallbackObjectHolder<XULTreeBuilderObserver, nsIXULTreeBuilderObserver>
     138           0 :         holder(&aObserver);
     139           0 :     mObservers.AppendElement(holder.ToXPCOMCallback());
     140           0 : }
     141             : 
     142             : NS_IMETHODIMP
     143           0 : nsXULTreeBuilder::AddObserver(nsIXULTreeBuilderObserver* aObserver)
     144             : {
     145           0 :     mObservers.AppendElement(aObserver);
     146           0 :     return NS_OK;
     147             : }
     148             : 
     149             : void
     150           0 : nsXULTreeBuilder::RemoveObserver(XULTreeBuilderObserver& aObserver)
     151             : {
     152             :     CallbackObjectHolder<XULTreeBuilderObserver, nsIXULTreeBuilderObserver>
     153           0 :         holder(&aObserver);
     154           0 :     nsCOMPtr<nsIXULTreeBuilderObserver> observer(holder.ToXPCOMCallback());
     155           0 :     mObservers.RemoveElement(observer);
     156           0 : }
     157             : 
     158             : NS_IMETHODIMP
     159           0 : nsXULTreeBuilder::RemoveObserver(nsIXULTreeBuilderObserver* aObserver)
     160             : {
     161           0 :     mObservers.RemoveElement(aObserver);
     162           0 :     return NS_OK;
     163             : }
     164             : 
     165             : void
     166           0 : nsXULTreeBuilder::Sort(Element& aElement)
     167             : {
     168           0 :     if (aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::sortLocked,
     169             :                              nsGkAtoms::_true, eCaseMatters)) {
     170           0 :         return;
     171             :     }
     172             : 
     173           0 :     nsAutoString sort;
     174           0 :     aElement.GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort);
     175             : 
     176           0 :     if (sort.IsEmpty()) {
     177           0 :         return;
     178             :     }
     179             : 
     180             :     // Grab the new sort variable
     181           0 :     mSortVariable = NS_Atomize(sort);
     182             : 
     183           0 :     nsAutoString hints;
     184           0 :     aElement.GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, hints);
     185             : 
     186           0 :     bool hasNaturalState = true;
     187           0 :     nsWhitespaceTokenizer tokenizer(hints);
     188           0 :     while (tokenizer.hasMoreTokens()) {
     189           0 :       const nsDependentSubstring& token(tokenizer.nextToken());
     190           0 :       if (token.EqualsLiteral("comparecase"))
     191           0 :         mSortHints |= nsIXULSortService::SORT_COMPARECASE;
     192           0 :       else if (token.EqualsLiteral("integer"))
     193           0 :         mSortHints |= nsIXULSortService::SORT_INTEGER;
     194           0 :       else if (token.EqualsLiteral("twostate"))
     195           0 :         hasNaturalState = false;
     196             :     }
     197             : 
     198             :     // Cycle the sort direction
     199           0 :     nsAutoString dir;
     200           0 :     aElement.GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, dir);
     201             : 
     202           0 :     if (dir.EqualsLiteral("ascending")) {
     203           0 :         dir.AssignLiteral("descending");
     204           0 :         mSortDirection = eDirection_Descending;
     205             :     }
     206           0 :     else if (hasNaturalState && dir.EqualsLiteral("descending")) {
     207           0 :         dir.AssignLiteral("natural");
     208           0 :         mSortDirection = eDirection_Natural;
     209             :     }
     210             :     else {
     211           0 :         dir.AssignLiteral("ascending");
     212           0 :         mSortDirection = eDirection_Ascending;
     213             :     }
     214             : 
     215             :     // Sort it.
     216           0 :     SortSubtree(mRows.GetRoot());
     217           0 :     mRows.InvalidateCachedRow();
     218           0 :     if (mBoxObject)
     219           0 :         mBoxObject->Invalidate();
     220             : 
     221           0 :     nsTreeUtils::UpdateSortIndicators(&aElement, dir);
     222             : }
     223             : 
     224             : NS_IMETHODIMP
     225           0 : nsXULTreeBuilder::Sort(nsIDOMElement* aElement)
     226             : {
     227           0 :     nsCOMPtr<Element> header = do_QueryInterface(aElement);
     228           0 :     if (!header) {
     229           0 :         return NS_ERROR_FAILURE;
     230             :     }
     231           0 :     Sort(*header);
     232           0 :     return NS_OK;
     233             : }
     234             : 
     235             : //----------------------------------------------------------------------
     236             : //
     237             : // nsITreeView methods
     238             : //
     239             : 
     240             : NS_IMETHODIMP
     241           0 : nsXULTreeBuilder::GetRowCount(int32_t* aRowCount)
     242             : {
     243           0 :     *aRowCount = RowCount();
     244           0 :     return NS_OK;
     245             : }
     246             : 
     247             : NS_IMETHODIMP
     248           0 : nsXULTreeBuilder::GetSelection(nsITreeSelection** aSelection)
     249             : {
     250           0 :     NS_IF_ADDREF(*aSelection = GetSelection());
     251           0 :     return NS_OK;
     252             : }
     253             : 
     254             : void
     255           0 : nsXULTreeBuilder::SetSelection(nsITreeSelection* aSelection,
     256             :                                ErrorResult& aError)
     257             : {
     258           0 :     if (aSelection && !nsTreeContentView::CanTrustTreeSelection(aSelection)) {
     259           0 :         aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
     260           0 :         return;
     261             :     }
     262             : 
     263           0 :     mSelection = aSelection;
     264             : }
     265             : 
     266             : NS_IMETHODIMP
     267           0 : nsXULTreeBuilder::SetSelection(nsITreeSelection* aSelection)
     268             : {
     269           0 :     ErrorResult rv;
     270           0 :     SetSelection(aSelection, rv);
     271           0 :     return rv.StealNSResult();
     272             : }
     273             : 
     274             : void
     275           0 : nsXULTreeBuilder::GetRowProperties(int32_t aRow, nsAString& aProperties,
     276             :                                    ErrorResult& aError)
     277             : {
     278           0 :     if (!IsValidRowIndex(aRow)) {
     279           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     280           0 :         return;
     281             :     }
     282             : 
     283           0 :     nsCOMPtr<nsIContent> row;
     284           0 :     GetTemplateActionRowFor(aRow, getter_AddRefs(row));
     285           0 :     if (row) {
     286           0 :         nsAutoString raw;
     287           0 :         row->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, raw);
     288             : 
     289           0 :         if (!raw.IsEmpty()) {
     290           0 :             SubstituteText(mRows[aRow]->mMatch->mResult, raw, aProperties);
     291             :         }
     292             :     }
     293             : }
     294             : 
     295             : NS_IMETHODIMP
     296           0 : nsXULTreeBuilder::GetRowProperties(int32_t aIndex, nsAString& aProps)
     297             : {
     298           0 :     ErrorResult rv;
     299           0 :     GetRowProperties(aIndex, aProps, rv);
     300           0 :     return rv.StealNSResult();
     301             : }
     302             : 
     303             : void
     304           0 : nsXULTreeBuilder::GetCellProperties(int32_t aRow, nsTreeColumn& aColumn,
     305             :                                     nsAString& aProperties, ErrorResult& aError)
     306             : {
     307           0 :     if (!IsValidRowIndex(aRow)) {
     308           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     309           0 :         return;
     310             :     }
     311             : 
     312           0 :     nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
     313           0 :     if (cell) {
     314           0 :         nsAutoString raw;
     315           0 :         cell->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, raw);
     316             : 
     317           0 :         if (!raw.IsEmpty()) {
     318           0 :             SubstituteText(mRows[aRow]->mMatch->mResult, raw, aProperties);
     319             :         }
     320             :     }
     321             : }
     322             : 
     323             : NS_IMETHODIMP
     324           0 : nsXULTreeBuilder::GetCellProperties(int32_t aRow, nsITreeColumn* aCol,
     325             :                                     nsAString& aProps)
     326             : {
     327           0 :     RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     328           0 :     NS_ENSURE_ARG(col);
     329             : 
     330           0 :     ErrorResult rv;
     331           0 :     GetCellProperties(aRow, *col, aProps, rv);
     332           0 :     return rv.StealNSResult();
     333             : }
     334             : 
     335             : NS_IMETHODIMP
     336           0 : nsXULTreeBuilder::GetColumnProperties(nsITreeColumn* aCol, nsAString& aProps)
     337             : {
     338           0 :     NS_ENSURE_ARG_POINTER(aCol);
     339             :     // XXX sortactive fu
     340           0 :     return NS_OK;
     341             : }
     342             : 
     343             : bool
     344           0 : nsXULTreeBuilder::IsContainer(int32_t aRow, ErrorResult& aError)
     345             : {
     346           0 :     if (!IsValidRowIndex(aRow)) {
     347           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     348           0 :         return false;
     349             :     }
     350             : 
     351           0 :     nsTreeRows::iterator iter = mRows[aRow];
     352             : 
     353             :     bool isContainer;
     354           0 :     iter->mMatch->mResult->GetIsContainer(&isContainer);
     355             : 
     356           0 :     iter->mContainerType = isContainer
     357           0 :         ? nsTreeRows::eContainerType_Container
     358             :         : nsTreeRows::eContainerType_Noncontainer;
     359             : 
     360           0 :     return iter->mContainerType == nsTreeRows::eContainerType_Container;
     361             : }
     362             : 
     363             : NS_IMETHODIMP
     364           0 : nsXULTreeBuilder::IsContainer(int32_t aIndex, bool* aResult)
     365             : {
     366           0 :     ErrorResult rv;
     367           0 :     *aResult = IsContainer(aIndex, rv);
     368           0 :     return rv.StealNSResult();
     369             : }
     370             : 
     371             : bool
     372           0 : nsXULTreeBuilder::IsContainerOpen(int32_t aRow, ErrorResult& aError)
     373             : {
     374           0 :     if (!IsValidRowIndex(aRow)) {
     375           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     376           0 :         return false;
     377             :     }
     378             : 
     379           0 :     nsTreeRows::iterator iter = mRows[aRow];
     380             : 
     381           0 :     if (iter->mContainerState == nsTreeRows::eContainerState_Unknown) {
     382           0 :         bool isOpen = IsContainerOpen(iter->mMatch->mResult);
     383             : 
     384           0 :         iter->mContainerState = isOpen
     385           0 :             ? nsTreeRows::eContainerState_Open
     386             :             : nsTreeRows::eContainerState_Closed;
     387             :     }
     388             : 
     389           0 :     return iter->mContainerState == nsTreeRows::eContainerState_Open;
     390             : }
     391             : 
     392             : NS_IMETHODIMP
     393           0 : nsXULTreeBuilder::IsContainerOpen(int32_t aIndex, bool* aOpen)
     394             : {
     395           0 :     ErrorResult rv;
     396           0 :     *aOpen = IsContainerOpen(aIndex, rv);
     397           0 :     return rv.StealNSResult();
     398             : }
     399             : 
     400             : bool
     401           0 : nsXULTreeBuilder::IsContainerEmpty(int32_t aRow, ErrorResult& aError)
     402             : {
     403           0 :     if (!IsValidRowIndex(aRow)) {
     404           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     405           0 :         return false;
     406             :     }
     407             : 
     408           0 :     nsTreeRows::iterator iter = mRows[aRow];
     409           0 :     NS_ASSERTION(iter->mContainerType == nsTreeRows::eContainerType_Container,
     410             :                  "asking for empty state on non-container");
     411             : 
     412             :     // if recursion is disabled, pretend that the container is empty. This
     413             :     // ensures that folders are still displayed as such, yet won't display
     414             :     // their children
     415           0 :     if ((mFlags & eDontRecurse) && (iter->mMatch->mResult != mRootResult)) {
     416           0 :         return true;
     417             :     }
     418             : 
     419           0 :     if (iter->mContainerFill == nsTreeRows::eContainerFill_Unknown) {
     420             :         bool isEmpty;
     421           0 :         iter->mMatch->mResult->GetIsEmpty(&isEmpty);
     422             : 
     423           0 :         iter->mContainerFill = isEmpty
     424           0 :             ? nsTreeRows::eContainerFill_Empty
     425             :             : nsTreeRows::eContainerFill_Nonempty;
     426             :     }
     427             : 
     428           0 :     return iter->mContainerFill == nsTreeRows::eContainerFill_Empty;
     429             : }
     430             : 
     431             : NS_IMETHODIMP
     432           0 : nsXULTreeBuilder::IsContainerEmpty(int32_t aIndex, bool* aResult)
     433             : {
     434           0 :     ErrorResult rv;
     435           0 :     *aResult = IsContainerEmpty(aIndex, rv);
     436           0 :     return rv.StealNSResult();
     437             : }
     438             : 
     439             : bool
     440           0 : nsXULTreeBuilder::IsSeparator(int32_t aRow, ErrorResult& aError)
     441             : {
     442           0 :     if (!IsValidRowIndex(aRow)) {
     443           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     444           0 :         return false;
     445             :     }
     446             : 
     447           0 :     nsAutoString type;
     448           0 :     nsTreeRows::Row& row = *(mRows[aRow]);
     449           0 :     row.mMatch->mResult->GetType(type);
     450             : 
     451           0 :     return type.EqualsLiteral("separator");
     452             : }
     453             : 
     454             : NS_IMETHODIMP
     455           0 : nsXULTreeBuilder::IsSeparator(int32_t aIndex, bool* aResult)
     456             : {
     457           0 :     ErrorResult rv;
     458           0 :     *aResult = IsSeparator(aIndex, rv);
     459           0 :     return rv.StealNSResult();
     460             : }
     461             : 
     462             : int32_t
     463           0 : nsXULTreeBuilder::GetParentIndex(int32_t aRow, ErrorResult& aError)
     464             : {
     465           0 :     if (!IsValidRowIndex(aRow)) {
     466           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     467           0 :         return -1;
     468             :     }
     469             : 
     470             :     // Construct a path to the row
     471           0 :     nsTreeRows::iterator iter = mRows[aRow];
     472             : 
     473             :     // The parent of the row will be at the top of the path
     474           0 :     nsTreeRows::Subtree* parent = iter.GetParent();
     475             : 
     476             :     // Now walk through our previous siblings, subtracting off each
     477             :     // one's subtree size
     478           0 :     int32_t index = iter.GetChildIndex();
     479           0 :     while (--index >= 0)
     480           0 :         aRow -= mRows.GetSubtreeSizeFor(parent, index) + 1;
     481             : 
     482             :     // Now the parent's index will be the first row's index, less one.
     483           0 :     return aRow - 1;
     484             : }
     485             : 
     486             : NS_IMETHODIMP
     487           0 : nsXULTreeBuilder::GetParentIndex(int32_t aRowIndex, int32_t* aResult)
     488             : {
     489           0 :     ErrorResult rv;
     490           0 :     *aResult = GetParentIndex(aRowIndex, rv);
     491           0 :     return rv.StealNSResult();
     492             : }
     493             : 
     494             : bool
     495           0 : nsXULTreeBuilder::HasNextSibling(int32_t aRow, int32_t aAfterIndex,
     496             :                                  ErrorResult& aError)
     497             : {
     498           0 :     if (!IsValidRowIndex(aRow)) {
     499           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     500           0 :         return false;
     501             :     }
     502             : 
     503             :     // Construct a path to the row
     504           0 :     nsTreeRows::iterator iter = mRows[aRow];
     505             : 
     506             :     // The parent of the row will be at the top of the path
     507           0 :     nsTreeRows::Subtree* parent = iter.GetParent();
     508             : 
     509             :     // We have a next sibling if the child is not the last in the
     510             :     // subtree.
     511           0 :     return iter.GetChildIndex() != parent->Count() - 1;
     512             : }
     513             : 
     514             : NS_IMETHODIMP
     515           0 : nsXULTreeBuilder::HasNextSibling(int32_t aRowIndex, int32_t aAfterIndex, bool* aResult)
     516             : {
     517           0 :     ErrorResult rv;
     518           0 :     *aResult = HasNextSibling(aRowIndex, aAfterIndex, rv);
     519           0 :     return rv.StealNSResult();
     520             : }
     521             : 
     522             : int32_t
     523           0 : nsXULTreeBuilder::GetLevel(int32_t aRow, ErrorResult& aError)
     524             : {
     525           0 :     if (!IsValidRowIndex(aRow)) {
     526           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     527           0 :         return -1;
     528             :     }
     529             : 
     530             :     // Construct a path to the row; the ``level'' is the path length
     531             :     // less one.
     532           0 :     nsTreeRows::iterator iter = mRows[aRow];
     533           0 :     return iter.GetDepth() - 1;
     534             : }
     535             : 
     536             : NS_IMETHODIMP
     537           0 : nsXULTreeBuilder::GetLevel(int32_t aRowIndex, int32_t* aResult)
     538             : {
     539           0 :     ErrorResult rv;
     540           0 :     *aResult = GetLevel(aRowIndex, rv);
     541           0 :     return rv.StealNSResult();
     542             : }
     543             : 
     544             : void
     545           0 : nsXULTreeBuilder::GetImageSrc(int32_t aRow, nsTreeColumn& aColumn,
     546             :                               nsAString& aSrc, ErrorResult& aError)
     547             : {
     548           0 :     if (!IsValidRowIndex(aRow)) {
     549           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     550           0 :         return;
     551             :     }
     552             : 
     553             :     // Find the <cell> that corresponds to the column we want.
     554           0 :     nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
     555           0 :     if (cell) {
     556           0 :         nsAutoString raw;
     557           0 :         cell->GetAttr(kNameSpaceID_None, nsGkAtoms::src, raw);
     558             : 
     559           0 :         SubstituteText(mRows[aRow]->mMatch->mResult, raw, aSrc);
     560             :     } else {
     561           0 :         aSrc.Truncate();
     562             :     }
     563             : }
     564             : 
     565             : NS_IMETHODIMP
     566           0 : nsXULTreeBuilder::GetImageSrc(int32_t aRow, nsITreeColumn* aCol, nsAString& aResult)
     567             : {
     568           0 :     RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     569           0 :     NS_ENSURE_ARG(col);
     570             : 
     571           0 :     ErrorResult rv;
     572           0 :     GetImageSrc(aRow, *col, aResult, rv);
     573           0 :     return rv.StealNSResult();
     574             : }
     575             : 
     576             : int32_t
     577           0 : nsXULTreeBuilder::GetProgressMode(int32_t aRow, nsTreeColumn& aColumn,
     578             :                                   ErrorResult& aError)
     579             : {
     580           0 :     if (!IsValidRowIndex(aRow)) {
     581           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     582           0 :         return -1;
     583             :     }
     584             : 
     585             :     // Find the <cell> that corresponds to the column we want.
     586           0 :     nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
     587           0 :     if (cell) {
     588           0 :         nsAutoString raw;
     589           0 :         cell->GetAttr(kNameSpaceID_None, nsGkAtoms::mode, raw);
     590             : 
     591           0 :         nsAutoString mode;
     592           0 :         SubstituteText(mRows[aRow]->mMatch->mResult, raw, mode);
     593             : 
     594           0 :         if (mode.EqualsLiteral("normal")) {
     595           0 :             return nsITreeView::PROGRESS_NORMAL;
     596             :         }
     597             : 
     598           0 :         if (mode.EqualsLiteral("undetermined")) {
     599           0 :             return nsITreeView::PROGRESS_UNDETERMINED;
     600             :         }
     601             :     }
     602             : 
     603           0 :     return nsITreeView::PROGRESS_NONE;
     604             : }
     605             : 
     606             : NS_IMETHODIMP
     607           0 : nsXULTreeBuilder::GetProgressMode(int32_t aRow, nsITreeColumn* aCol, int32_t* aResult)
     608             : {
     609           0 :     RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     610           0 :     NS_ENSURE_ARG(col);
     611             : 
     612           0 :     ErrorResult rv;
     613           0 :     *aResult = GetProgressMode(aRow, *col, rv);
     614           0 :     return rv.StealNSResult();
     615             : }
     616             : 
     617             : void
     618           0 : nsXULTreeBuilder::GetCellValue(int32_t aRow, nsTreeColumn& aColumn,
     619             :                                nsAString& aValue, ErrorResult& aError)
     620             : {
     621           0 :     if (!IsValidRowIndex(aRow)) {
     622           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     623           0 :         return;
     624             :     }
     625             : 
     626             :     // Find the <cell> that corresponds to the column we want.
     627           0 :     nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
     628           0 :     if (cell) {
     629           0 :         nsAutoString raw;
     630           0 :         cell->GetAttr(kNameSpaceID_None, nsGkAtoms::value, raw);
     631             : 
     632           0 :         SubstituteText(mRows[aRow]->mMatch->mResult, raw, aValue);
     633             :     } else {
     634           0 :         aValue.Truncate();
     635             :     }
     636             : }
     637             : 
     638             : NS_IMETHODIMP
     639           0 : nsXULTreeBuilder::GetCellValue(int32_t aRow, nsITreeColumn* aCol, nsAString& aResult)
     640             : {
     641           0 :     RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     642           0 :     NS_ENSURE_ARG(col);
     643             : 
     644           0 :     ErrorResult rv;
     645           0 :     GetCellValue(aRow, *col, aResult, rv);
     646           0 :     return rv.StealNSResult();
     647             : }
     648             : 
     649             : void
     650           0 : nsXULTreeBuilder::GetCellText(int32_t aRow, nsTreeColumn& aColumn,
     651             :                               nsAString& aText, ErrorResult& aError)
     652             : {
     653           0 :     if (!IsValidRowIndex(aRow)) {
     654           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     655           0 :         return;
     656             :     }
     657             : 
     658             :     // Find the <cell> that corresponds to the column we want.
     659           0 :     nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
     660           0 :     if (cell) {
     661           0 :         nsAutoString raw;
     662           0 :         cell->GetAttr(kNameSpaceID_None, nsGkAtoms::label, raw);
     663             : 
     664           0 :         SubstituteText(mRows[aRow]->mMatch->mResult, raw, aText);
     665             :     } else {
     666           0 :         aText.Truncate();
     667             :     }
     668             : }
     669             : 
     670             : NS_IMETHODIMP
     671           0 : nsXULTreeBuilder::GetCellText(int32_t aRow, nsITreeColumn* aCol, nsAString& aResult)
     672             : {
     673           0 :     RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     674           0 :     NS_ENSURE_ARG(col);
     675             : 
     676           0 :     ErrorResult rv;
     677           0 :     GetCellText(aRow, *col, aResult, rv);
     678           0 :     return rv.StealNSResult();
     679             : }
     680             : 
     681             : void
     682           0 : nsXULTreeBuilder::SetTree(TreeBoxObject* aTree, ErrorResult& aError)
     683             : {
     684           0 :     aError = SetTree(aTree);
     685           0 : }
     686             : 
     687             : NS_IMETHODIMP
     688           0 : nsXULTreeBuilder::SetTree(nsITreeBoxObject* aTree)
     689             : {
     690           0 :     mBoxObject = aTree;
     691             : 
     692             :     // If this is teardown time, then we're done.
     693           0 :     if (!mBoxObject) {
     694           0 :         Uninit(false);
     695           0 :         return NS_OK;
     696             :     }
     697           0 :     NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED);
     698             : 
     699             :     // Only use the XUL store if the root's principal is trusted.
     700           0 :     bool isTrusted = false;
     701           0 :     nsresult rv = IsSystemPrincipal(mRoot->NodePrincipal(), &isTrusted);
     702           0 :     if (NS_SUCCEEDED(rv) && isTrusted) {
     703           0 :         mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
     704           0 :         if(NS_WARN_IF(!mLocalStore)){
     705           0 :             return NS_ERROR_NOT_INITIALIZED;
     706             :         }
     707             :     }
     708             : 
     709           0 :     Rebuild();
     710             : 
     711           0 :     EnsureSortVariables();
     712           0 :     if (mSortVariable)
     713           0 :         SortSubtree(mRows.GetRoot());
     714             : 
     715           0 :     return NS_OK;
     716             : }
     717             : 
     718             : void
     719           0 : nsXULTreeBuilder::ToggleOpenState(int32_t aRow, ErrorResult& aError)
     720             : {
     721           0 :     if (!IsValidRowIndex(aRow)) {
     722           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     723           0 :         return;
     724             :     }
     725             : 
     726           0 :     nsIXULTemplateResult* result = mRows[aRow]->mMatch->mResult;
     727           0 :     if (!result) {
     728           0 :         aError.Throw(NS_ERROR_FAILURE);
     729           0 :         return;
     730             :     }
     731             : 
     732           0 :     if (mFlags & eDontRecurse) {
     733           0 :         return;
     734             :     }
     735             : 
     736           0 :     if (result && result != mRootResult) {
     737             :         // don't open containers if child processing isn't allowed
     738             :         bool mayProcessChildren;
     739           0 :         aError = result->GetMayProcessChildren(&mayProcessChildren);
     740           0 :         if (aError.Failed() || !mayProcessChildren) {
     741           0 :             return;
     742             :         }
     743             :     }
     744             : 
     745           0 :     uint32_t count = mObservers.Length();
     746           0 :     for (uint32_t i = 0; i < count; ++i) {
     747           0 :         nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
     748           0 :         if (observer)
     749           0 :             observer->OnToggleOpenState(aRow);
     750             :     }
     751             : 
     752           0 :     if (mLocalStore && mRoot) {
     753             :         bool isOpen;
     754           0 :         IsContainerOpen(aRow, &isOpen);
     755             : 
     756           0 :         nsIDocument* doc = mRoot->GetComposedDoc();
     757           0 :         if (!doc) {
     758           0 :             aError.Throw(NS_ERROR_FAILURE);
     759           0 :             return;
     760             :         }
     761             : 
     762           0 :         nsIURI* docURI = doc->GetDocumentURI();
     763           0 :         nsTreeRows::Row& row = *(mRows[aRow]);
     764           0 :         nsAutoString nodeid;
     765           0 :         aError = row.mMatch->mResult->GetId(nodeid);
     766           0 :         if (aError.Failed()) {
     767           0 :             return;
     768             :         }
     769             : 
     770           0 :         nsAutoCString utf8uri;
     771           0 :         aError = docURI->GetSpec(utf8uri);
     772           0 :         if (NS_WARN_IF(aError.Failed())) {
     773           0 :             return;
     774             :         }
     775           0 :         NS_ConvertUTF8toUTF16 uri(utf8uri);
     776             : 
     777           0 :         if (isOpen) {
     778           0 :             mLocalStore->RemoveValue(uri, nodeid, NS_LITERAL_STRING("open"));
     779           0 :             CloseContainer(aRow);
     780             :         } else {
     781           0 :             mLocalStore->SetValue(uri, nodeid, NS_LITERAL_STRING("open"),
     782           0 :                 NS_LITERAL_STRING("true"));
     783             : 
     784           0 :             OpenContainer(aRow, result);
     785             :         }
     786             :     }
     787             : }
     788             : 
     789             : NS_IMETHODIMP
     790           0 : nsXULTreeBuilder::ToggleOpenState(int32_t aIndex)
     791             : {
     792           0 :     ErrorResult rv;
     793           0 :     ToggleOpenState(aIndex, rv);
     794           0 :     return rv.StealNSResult();
     795             : }
     796             : 
     797             : void
     798           0 : nsXULTreeBuilder::CycleHeader(nsTreeColumn& aColumn, ErrorResult& aError)
     799             : {
     800           0 :     nsCOMPtr<nsIDOMElement> element;
     801           0 :     aColumn.GetElement(getter_AddRefs(element));
     802             : 
     803           0 :     nsAutoString id;
     804           0 :     aColumn.GetId(id);
     805             : 
     806           0 :     uint32_t count = mObservers.Length();
     807           0 :     for (uint32_t i = 0; i < count; ++i) {
     808           0 :         nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
     809           0 :         if (observer)
     810           0 :             observer->OnCycleHeader(id.get(), element);
     811             :     }
     812             : 
     813           0 :     aError = Sort(element);
     814           0 : }
     815             : 
     816             : NS_IMETHODIMP
     817           0 : nsXULTreeBuilder::CycleHeader(nsITreeColumn* aCol)
     818             : {
     819           0 :     RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     820           0 :     NS_ENSURE_ARG(col);
     821             : 
     822           0 :     ErrorResult rv;
     823           0 :     CycleHeader(*col, rv);
     824           0 :     return rv.StealNSResult();
     825             : }
     826             : 
     827             : NS_IMETHODIMP
     828           0 : nsXULTreeBuilder::SelectionChanged()
     829             : {
     830           0 :     uint32_t count = mObservers.Length();
     831           0 :     for (uint32_t i = 0; i < count; ++i) {
     832           0 :         nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
     833           0 :         if (observer)
     834           0 :             observer->OnSelectionChanged();
     835             :     }
     836             : 
     837           0 :     return NS_OK;
     838             : }
     839             : 
     840             : void
     841           0 : nsXULTreeBuilder::CycleCell(int32_t aRow, nsTreeColumn& aColumn)
     842             : {
     843           0 :     nsAutoString id;
     844           0 :     aColumn.GetId(id);
     845             : 
     846           0 :     uint32_t count = mObservers.Length();
     847           0 :     for (uint32_t i = 0; i < count; ++i) {
     848           0 :         nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
     849           0 :         if (observer)
     850           0 :             observer->OnCycleCell(aRow, id.get());
     851             :     }
     852           0 : }
     853             : 
     854             : NS_IMETHODIMP
     855           0 : nsXULTreeBuilder::CycleCell(int32_t aRow, nsITreeColumn* aCol)
     856             : {
     857           0 :     RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     858           0 :     NS_ENSURE_ARG(col);
     859             : 
     860           0 :     CycleCell(aRow, *col);
     861           0 :     return NS_OK;
     862             : }
     863             : 
     864             : bool
     865           0 : nsXULTreeBuilder::IsEditable(int32_t aRow, nsTreeColumn& aColumn,
     866             :                              ErrorResult& aError)
     867             : {
     868           0 :     if (!IsValidRowIndex(aRow)) {
     869           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     870           0 :         return false;
     871             :     }
     872             : 
     873             :     // Find the <cell> that corresponds to the column we want.
     874           0 :     nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
     875           0 :     if (!cell) {
     876           0 :         return true;
     877             :     }
     878             : 
     879           0 :     nsAutoString raw;
     880           0 :     cell->GetAttr(kNameSpaceID_None, nsGkAtoms::editable, raw);
     881             : 
     882           0 :     nsAutoString editable;
     883           0 :     SubstituteText(mRows[aRow]->mMatch->mResult, raw, editable);
     884             : 
     885           0 :     return !editable.EqualsLiteral("false");
     886             : }
     887             : 
     888             : NS_IMETHODIMP
     889           0 : nsXULTreeBuilder::IsEditable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
     890             : {
     891           0 :     RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     892           0 :     NS_ENSURE_ARG(col);
     893             : 
     894           0 :     ErrorResult rv;
     895           0 :     *_retval = IsEditable(aRow, *col, rv);
     896           0 :     return rv.StealNSResult();
     897             : }
     898             : 
     899             : bool
     900           0 : nsXULTreeBuilder::IsSelectable(int32_t aRow, nsTreeColumn& aColumn,
     901             :                                ErrorResult& aError)
     902             : {
     903           0 :     if (!IsValidRowIndex(aRow)) {
     904           0 :         aError.Throw(NS_ERROR_INVALID_ARG);
     905           0 :         return false;
     906             :     }
     907             : 
     908             :     // Find the <cell> that corresponds to the column we want.
     909           0 :     nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
     910           0 :     if (!cell) {
     911           0 :         return true;
     912             :     }
     913             : 
     914           0 :     nsAutoString raw;
     915           0 :     cell->GetAttr(kNameSpaceID_None, nsGkAtoms::selectable, raw);
     916             : 
     917           0 :     nsAutoString selectable;
     918           0 :     SubstituteText(mRows[aRow]->mMatch->mResult, raw, selectable);
     919             : 
     920           0 :     return !selectable.EqualsLiteral("false");
     921             : }
     922             : 
     923             : NS_IMETHODIMP
     924           0 : nsXULTreeBuilder::IsSelectable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
     925             : {
     926           0 :     RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
     927           0 :     NS_ENSURE_ARG(col);
     928             : 
     929           0 :     ErrorResult rv;
     930           0 :     *_retval = IsSelectable(aRow, *col, rv);
     931           0 :     return rv.StealNSResult();
     932             : }
     933             : 
     934             : NS_IMETHODIMP
     935           0 : nsXULTreeBuilder::SetCellValue(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
     936             : {
     937           0 :     NS_ENSURE_ARG_POINTER(aCol);
     938           0 :     return NS_OK;
     939             : }
     940             : 
     941             : NS_IMETHODIMP
     942           0 : nsXULTreeBuilder::SetCellText(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
     943             : {
     944           0 :     NS_ENSURE_ARG_POINTER(aCol);
     945           0 :     return NS_OK;
     946             : }
     947             : 
     948             : void
     949           0 : nsXULTreeBuilder::PerformAction(const nsAString& aAction)
     950             : {
     951           0 :     uint32_t count = mObservers.Length();
     952           0 :     for (uint32_t i = 0; i < count; ++i) {
     953           0 :         nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
     954           0 :         if (observer) {
     955           0 :             observer->OnPerformAction(PromiseFlatString(aAction).get());
     956             :         }
     957             :     }
     958           0 : }
     959             : 
     960             : NS_IMETHODIMP
     961           0 : nsXULTreeBuilder::PerformAction(const char16_t* aAction)
     962             : {
     963           0 :     PerformAction(aAction ? nsDependentString(aAction) : EmptyString());
     964             : 
     965           0 :     return NS_OK;
     966             : }
     967             : 
     968             : void
     969           0 : nsXULTreeBuilder::PerformActionOnRow(const nsAString& aAction, int32_t aRow)
     970             : {
     971           0 :     uint32_t count = mObservers.Length();
     972           0 :     for (uint32_t i = 0; i < count; ++i) {
     973           0 :         nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
     974           0 :         if (observer) {
     975           0 :             observer->OnPerformActionOnRow(PromiseFlatString(aAction).get(), aRow);
     976             :         }
     977             :     }
     978           0 : }
     979             : 
     980             : NS_IMETHODIMP
     981           0 : nsXULTreeBuilder::PerformActionOnRow(const char16_t* aAction, int32_t aRow)
     982             : {
     983           0 :     PerformActionOnRow(aAction ? nsDependentString(aAction) : EmptyString(), aRow);
     984             : 
     985           0 :     return NS_OK;
     986             : }
     987             : 
     988             : void
     989           0 : nsXULTreeBuilder::PerformActionOnCell(const nsAString& aAction, int32_t aRow,
     990             :                                       nsTreeColumn& aColumn)
     991             : {
     992           0 :     nsAutoString id;
     993           0 :     aColumn.GetId(id);
     994             : 
     995           0 :     uint32_t count = mObservers.Length();
     996           0 :     for (uint32_t i = 0; i < count; ++i) {
     997           0 :         nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
     998           0 :         if (observer) {
     999           0 :             observer->OnPerformActionOnCell(PromiseFlatString(aAction).get(), aRow, id.get());
    1000             :         }
    1001             :     }
    1002           0 : }
    1003             : 
    1004             : NS_IMETHODIMP
    1005           0 : nsXULTreeBuilder::PerformActionOnCell(const char16_t* aAction, int32_t aRow, nsITreeColumn* aCol)
    1006             : {
    1007           0 :     RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
    1008           0 :     NS_ENSURE_ARG(col);
    1009             : 
    1010           0 :     PerformActionOnCell(aAction ? nsDependentString(aAction) : EmptyString(), aRow, *col);
    1011             : 
    1012           0 :     return NS_OK;
    1013             : }
    1014             : 
    1015             : 
    1016             : void
    1017           0 : nsXULTreeBuilder::NodeWillBeDestroyed(const nsINode* aNode)
    1018             : {
    1019           0 :     nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    1020           0 :     mObservers.Clear();
    1021             : 
    1022           0 :     nsXULTemplateBuilder::NodeWillBeDestroyed(aNode);
    1023           0 : }
    1024             : 
    1025             : bool
    1026           0 : nsXULTreeBuilder::HasGeneratedContent(nsIRDFResource* aResource,
    1027             :                                       const nsAString& aTag,
    1028             :                                       ErrorResult& aError)
    1029             : {
    1030           0 :     if (!aResource) {
    1031           0 :         aError.Throw(NS_ERROR_INVALID_POINTER);
    1032           0 :         return false;
    1033             :     }
    1034             : 
    1035           0 :     if (!mRootResult) {
    1036           0 :         return false;
    1037             :     }
    1038             : 
    1039           0 :     nsCOMPtr<nsIRDFResource> rootresource;
    1040           0 :     aError = mRootResult->GetResource(getter_AddRefs(rootresource));
    1041           0 :     if (aError.Failed()) {
    1042           0 :         return false;
    1043             :     }
    1044             : 
    1045           0 :     return aResource == rootresource ||
    1046           0 :            mRows.FindByResource(aResource) != mRows.Last();
    1047             : }
    1048             : 
    1049             : bool
    1050           0 : nsXULTreeBuilder::GetInsertionLocations(nsIXULTemplateResult* aResult,
    1051             :                                         nsCOMArray<nsIContent>** aLocations)
    1052             : {
    1053           0 :     *aLocations = nullptr;
    1054             : 
    1055             :     // Get the reference point and check if it is an open container. Rows
    1056             :     // should not be generated otherwise.
    1057             : 
    1058           0 :     nsAutoString ref;
    1059           0 :     nsresult rv = aResult->GetBindingFor(mRefVariable, ref);
    1060           0 :     if (NS_FAILED(rv) || ref.IsEmpty())
    1061           0 :         return false;
    1062             : 
    1063           0 :     nsCOMPtr<nsIRDFResource> container;
    1064           0 :     rv = gRDFService->GetUnicodeResource(ref, getter_AddRefs(container));
    1065           0 :     if (NS_FAILED(rv))
    1066           0 :         return false;
    1067             : 
    1068             :     // Can always insert into the root resource
    1069           0 :     if (container == mRows.GetRootResource())
    1070           0 :         return true;
    1071             : 
    1072           0 :     nsTreeRows::iterator iter = mRows.FindByResource(container);
    1073           0 :     if (iter == mRows.Last())
    1074           0 :         return false;
    1075             : 
    1076           0 :     return (iter->mContainerState == nsTreeRows::eContainerState_Open);
    1077             : }
    1078             : 
    1079             : struct ResultComparator
    1080             : {
    1081             :     nsXULTreeBuilder* const mTreebuilder;
    1082             :     nsIXULTemplateResult* const mResult;
    1083           0 :     ResultComparator(nsXULTreeBuilder* aTreebuilder, nsIXULTemplateResult* aResult)
    1084           0 :       : mTreebuilder(aTreebuilder), mResult(aResult) {}
    1085           0 :     int operator()(const nsTreeRows::Row& aSubtree) const {
    1086           0 :         return mTreebuilder->CompareResults(mResult, aSubtree.mMatch->mResult);
    1087             :     }
    1088             : };
    1089             : 
    1090             : nsresult
    1091           0 : nsXULTreeBuilder::ReplaceMatch(nsIXULTemplateResult* aOldResult,
    1092             :                                nsTemplateMatch* aNewMatch,
    1093             :                                nsTemplateRule* aNewMatchRule,
    1094             :                                void *aLocation)
    1095             : {
    1096           0 :     if (! mBoxObject)
    1097           0 :         return NS_OK;
    1098             : 
    1099           0 :     if (aOldResult) {
    1100             :         // Grovel through the rows looking for oldresult.
    1101           0 :         nsTreeRows::iterator iter = mRows.Find(aOldResult);
    1102             : 
    1103           0 :         NS_ASSERTION(iter != mRows.Last(), "couldn't find row");
    1104           0 :         if (iter == mRows.Last())
    1105           0 :             return NS_ERROR_FAILURE;
    1106             : 
    1107             :         // Remove the rows from the view
    1108           0 :         int32_t row = iter.GetRowIndex();
    1109             : 
    1110             :         // If the row contains children, remove the matches from the
    1111             :         // children so that they can be regenerated again if the element
    1112             :         // gets added back.
    1113           0 :         int32_t delta = mRows.GetSubtreeSizeFor(iter);
    1114           0 :         if (delta)
    1115           0 :             RemoveMatchesFor(*(iter->mSubtree));
    1116             : 
    1117           0 :         if (mRows.RemoveRowAt(iter) == 0 && iter.GetRowIndex() >= 0) {
    1118             : 
    1119             :             // In this case iter now points to its parent
    1120             :             // Invalidate the row's cached fill state
    1121           0 :             iter->mContainerFill = nsTreeRows::eContainerFill_Unknown;
    1122             : 
    1123           0 :             nsCOMPtr<nsITreeColumns> cols;
    1124           0 :             mBoxObject->GetColumns(getter_AddRefs(cols));
    1125           0 :             if (cols) {
    1126           0 :                 nsCOMPtr<nsITreeColumn> primaryCol;
    1127           0 :                 cols->GetPrimaryColumn(getter_AddRefs(primaryCol));
    1128           0 :                 if (primaryCol)
    1129           0 :                     mBoxObject->InvalidateCell(iter.GetRowIndex(), primaryCol);
    1130             :             }
    1131             :         }
    1132             : 
    1133             :         // Notify the box object
    1134           0 :         mBoxObject->RowCountChanged(row, -delta - 1);
    1135             :     }
    1136             : 
    1137           0 :     if (aNewMatch && aNewMatch->mResult) {
    1138             :         // Insertion.
    1139           0 :         int32_t row = -1;
    1140           0 :         nsTreeRows::Subtree* parent = nullptr;
    1141           0 :         nsIXULTemplateResult* result = aNewMatch->mResult;
    1142             : 
    1143           0 :         nsAutoString ref;
    1144           0 :         nsresult rv = result->GetBindingFor(mRefVariable, ref);
    1145           0 :         if (NS_FAILED(rv) || ref.IsEmpty())
    1146           0 :             return rv;
    1147             : 
    1148           0 :         nsCOMPtr<nsIRDFResource> container;
    1149           0 :         rv = gRDFService->GetUnicodeResource(ref, getter_AddRefs(container));
    1150           0 :         if (NS_FAILED(rv))
    1151           0 :             return rv;
    1152             : 
    1153           0 :         if (container != mRows.GetRootResource()) {
    1154           0 :             nsTreeRows::iterator iter = mRows.FindByResource(container);
    1155           0 :             row = iter.GetRowIndex();
    1156             : 
    1157           0 :             NS_ASSERTION(iter != mRows.Last(), "couldn't find container row");
    1158           0 :             if (iter == mRows.Last())
    1159           0 :                 return NS_ERROR_FAILURE;
    1160             : 
    1161             :             // Use the persist store to remember if the container
    1162             :             // is open or closed.
    1163           0 :             bool open = false;
    1164           0 :             IsContainerOpen(row, &open);
    1165             : 
    1166             :             // If it's open, make sure that we've got a subtree structure ready.
    1167           0 :             if (open)
    1168           0 :                 parent = mRows.EnsureSubtreeFor(iter);
    1169             : 
    1170             :             // We know something has just been inserted into the
    1171             :             // container, so whether its open or closed, make sure
    1172             :             // that we've got our tree row's state correct.
    1173           0 :             if ((iter->mContainerType != nsTreeRows::eContainerType_Container) ||
    1174           0 :                 (iter->mContainerFill != nsTreeRows::eContainerFill_Nonempty)) {
    1175           0 :                 iter->mContainerType  = nsTreeRows::eContainerType_Container;
    1176           0 :                 iter->mContainerFill = nsTreeRows::eContainerFill_Nonempty;
    1177           0 :                 mBoxObject->InvalidateRow(iter.GetRowIndex());
    1178             :             }
    1179             :         }
    1180             :         else {
    1181           0 :             parent = mRows.GetRoot();
    1182             :         }
    1183             : 
    1184           0 :         if (parent) {
    1185             :             // If we get here, then we're inserting into an open
    1186             :             // container. By default, place the new element at the
    1187             :             // end of the container
    1188           0 :             size_t index = parent->Count();
    1189             : 
    1190           0 :             if (mSortVariable) {
    1191             :                 // Figure out where to put the new element through
    1192             :                 // binary search.
    1193           0 :                 mozilla::BinarySearchIf(*parent, 0, parent->Count(),
    1194           0 :                                         ResultComparator(this, result), &index);
    1195             :             }
    1196             : 
    1197             :             nsTreeRows::iterator iter =
    1198           0 :                 mRows.InsertRowAt(aNewMatch, parent, index);
    1199             : 
    1200           0 :             mBoxObject->RowCountChanged(iter.GetRowIndex(), +1);
    1201             : 
    1202             :             // See if this newly added row is open; in which case,
    1203             :             // recursively add its children to the tree, too.
    1204             : 
    1205           0 :             if (mFlags & eDontRecurse)
    1206           0 :                 return NS_OK;
    1207             : 
    1208           0 :             if (result != mRootResult) {
    1209             :                 // don't open containers if child processing isn't allowed
    1210             :                 bool mayProcessChildren;
    1211           0 :                 nsresult rv = result->GetMayProcessChildren(&mayProcessChildren);
    1212           0 :                 if (NS_FAILED(rv) || ! mayProcessChildren) return NS_OK;
    1213             :             }
    1214             : 
    1215           0 :             if (IsContainerOpen(result)) {
    1216           0 :                 OpenContainer(iter.GetRowIndex(), result);
    1217             :             }
    1218             :         }
    1219             :     }
    1220             : 
    1221           0 :     return NS_OK;
    1222             : }
    1223             : 
    1224             : nsresult
    1225           0 : nsXULTreeBuilder::SynchronizeResult(nsIXULTemplateResult* aResult)
    1226             : {
    1227           0 :     if (mBoxObject) {
    1228             :         // XXX we could be more conservative and just invalidate the cells
    1229             :         // that got whacked...
    1230             : 
    1231           0 :         nsTreeRows::iterator iter = mRows.Find(aResult);
    1232             : 
    1233           0 :         NS_ASSERTION(iter != mRows.Last(), "couldn't find row");
    1234           0 :         if (iter == mRows.Last())
    1235           0 :             return NS_ERROR_FAILURE;
    1236             : 
    1237           0 :         int32_t row = iter.GetRowIndex();
    1238           0 :         if (row >= 0)
    1239           0 :             mBoxObject->InvalidateRow(row);
    1240             : 
    1241           0 :         MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
    1242             :                ("xultemplate[%p]   => row %d", this, row));
    1243             :     }
    1244             : 
    1245           0 :     return NS_OK;
    1246             : }
    1247             : 
    1248             : //----------------------------------------------------------------------
    1249             : 
    1250             : nsresult
    1251           0 : nsXULTreeBuilder::EnsureSortVariables()
    1252             : {
    1253             :     // Grovel through <treecols> kids to find the <treecol>
    1254             :     // with the sort attributes.
    1255           0 :     nsCOMPtr<nsIContent> treecols;
    1256             : 
    1257           0 :     nsXULContentUtils::FindChildByTag(mRoot, kNameSpaceID_XUL,
    1258             :                                       nsGkAtoms::treecols,
    1259           0 :                                       getter_AddRefs(treecols));
    1260             : 
    1261           0 :     if (!treecols)
    1262           0 :         return NS_OK;
    1263             : 
    1264           0 :     for (nsIContent* child = treecols->GetFirstChild();
    1265           0 :          child;
    1266           0 :          child = child->GetNextSibling()) {
    1267             : 
    1268           0 :         if (child->NodeInfo()->Equals(nsGkAtoms::treecol,
    1269             :                                       kNameSpaceID_XUL)) {
    1270           0 :             if (child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::sortActive,
    1271             :                                    nsGkAtoms::_true, eCaseMatters)) {
    1272           0 :                 nsAutoString sort;
    1273           0 :                 child->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort);
    1274           0 :                 if (! sort.IsEmpty()) {
    1275           0 :                     mSortVariable = NS_Atomize(sort);
    1276             : 
    1277             :                     static nsIContent::AttrValuesArray strings[] =
    1278             :                       {&nsGkAtoms::ascending, &nsGkAtoms::descending, nullptr};
    1279           0 :                     switch (child->FindAttrValueIn(kNameSpaceID_None,
    1280             :                                                    nsGkAtoms::sortDirection,
    1281           0 :                                                    strings, eCaseMatters)) {
    1282           0 :                        case 0: mSortDirection = eDirection_Ascending; break;
    1283           0 :                        case 1: mSortDirection = eDirection_Descending; break;
    1284           0 :                        default: mSortDirection = eDirection_Natural; break;
    1285             :                     }
    1286             :                 }
    1287           0 :                 break;
    1288             :             }
    1289             :         }
    1290             :     }
    1291             : 
    1292           0 :     return NS_OK;
    1293             : }
    1294             : 
    1295             : nsresult
    1296           0 : nsXULTreeBuilder::RebuildAll()
    1297             : {
    1298           0 :     NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED);
    1299             : 
    1300           0 :     nsCOMPtr<nsIDocument> doc = mRoot->GetComposedDoc();
    1301             : 
    1302             :     // Bail out early if we are being torn down.
    1303           0 :     if (!doc)
    1304           0 :         return NS_OK;
    1305             : 
    1306           0 :     if (! mQueryProcessor)
    1307           0 :         return NS_OK;
    1308             : 
    1309           0 :     if (mBoxObject) {
    1310           0 :         mBoxObject->BeginUpdateBatch();
    1311             :     }
    1312             : 
    1313           0 :     if (mQueriesCompiled) {
    1314           0 :         Uninit(false);
    1315             :     }
    1316           0 :     else if (mBoxObject) {
    1317           0 :         int32_t count = mRows.Count();
    1318           0 :         mRows.Clear();
    1319           0 :         mBoxObject->RowCountChanged(0, -count);
    1320             :     }
    1321             : 
    1322           0 :     nsresult rv = CompileQueries();
    1323           0 :     if (NS_SUCCEEDED(rv) && mQuerySets.Length() > 0) {
    1324             :         // Seed the rule network with assignments for the tree row variable
    1325           0 :         nsAutoString ref;
    1326           0 :         mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, ref);
    1327           0 :         if (!ref.IsEmpty()) {
    1328           0 :             rv = mQueryProcessor->TranslateRef(mDataSource, ref,
    1329           0 :                                                getter_AddRefs(mRootResult));
    1330           0 :             if (NS_SUCCEEDED(rv) && mRootResult) {
    1331           0 :                 OpenContainer(-1, mRootResult);
    1332             : 
    1333           0 :                 nsCOMPtr<nsIRDFResource> rootResource;
    1334           0 :                 GetResultResource(mRootResult, getter_AddRefs(rootResource));
    1335             : 
    1336           0 :                 mRows.SetRootResource(rootResource);
    1337             :             }
    1338             :         }
    1339             :     }
    1340             : 
    1341           0 :     if (mBoxObject) {
    1342           0 :         mBoxObject->EndUpdateBatch();
    1343             :     }
    1344             : 
    1345           0 :     return rv;
    1346             : }
    1347             : 
    1348             : nsresult
    1349           0 : nsXULTreeBuilder::GetTemplateActionRowFor(int32_t aRow, nsIContent** aResult)
    1350             : {
    1351             :     // Get the template in the DOM from which we're supposed to
    1352             :     // generate text
    1353           0 :     nsTreeRows::Row& row = *(mRows[aRow]);
    1354             : 
    1355             :     // The match stores the indices of the rule and query to use. Use these
    1356             :     // to look up the right nsTemplateRule and use that rule's action to get
    1357             :     // the treerow in the template.
    1358           0 :     int16_t ruleindex = row.mMatch->RuleIndex();
    1359           0 :     if (ruleindex >= 0) {
    1360           0 :         nsTemplateQuerySet* qs = mQuerySets[row.mMatch->QuerySetPriority()];
    1361           0 :         nsTemplateRule* rule = qs->GetRuleAt(ruleindex);
    1362           0 :         if (rule) {
    1363           0 :             nsCOMPtr<nsIContent> children;
    1364           0 :             nsXULContentUtils::FindChildByTag(rule->GetAction(), kNameSpaceID_XUL,
    1365             :                                               nsGkAtoms::treechildren,
    1366           0 :                                               getter_AddRefs(children));
    1367           0 :             if (children) {
    1368           0 :                 nsCOMPtr<nsIContent> item;
    1369           0 :                 nsXULContentUtils::FindChildByTag(children, kNameSpaceID_XUL,
    1370             :                                                   nsGkAtoms::treeitem,
    1371           0 :                                                   getter_AddRefs(item));
    1372           0 :                 if (item)
    1373           0 :                     return nsXULContentUtils::FindChildByTag(item,
    1374             :                                                              kNameSpaceID_XUL,
    1375             :                                                              nsGkAtoms::treerow,
    1376           0 :                                                              aResult);
    1377             :             }
    1378             :         }
    1379             :     }
    1380             : 
    1381           0 :     *aResult = nullptr;
    1382           0 :     return NS_OK;
    1383             : }
    1384             : 
    1385             : nsIContent*
    1386           0 : nsXULTreeBuilder::GetTemplateActionCellFor(int32_t aRow, nsTreeColumn& aCol)
    1387             : {
    1388           0 :     nsCOMPtr<nsIContent> row;
    1389           0 :     GetTemplateActionRowFor(aRow, getter_AddRefs(row));
    1390           0 :     if (!row) {
    1391           0 :         return nullptr;
    1392             :     }
    1393             : 
    1394           0 :     nsCOMPtr<nsIAtom> colAtom(aCol.GetAtom());
    1395           0 :     int32_t colIndex(aCol.GetIndex());
    1396             : 
    1397           0 :     nsIContent* result = nullptr;
    1398           0 :     uint32_t j = 0;
    1399           0 :     for (nsIContent* child = row->GetFirstChild();
    1400           0 :          child;
    1401           0 :          child = child->GetNextSibling()) {
    1402           0 :         if (child->NodeInfo()->Equals(nsGkAtoms::treecell, kNameSpaceID_XUL)) {
    1403           0 :             if (colAtom &&
    1404           0 :                 child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::ref, colAtom,
    1405           0 :                                    eCaseMatters)) {
    1406           0 :                 return child;
    1407             :             }
    1408             : 
    1409           0 :             if (j == (uint32_t)colIndex) {
    1410           0 :                 result = child;
    1411             :             }
    1412           0 :             ++j;
    1413             :         }
    1414             :     }
    1415           0 :     return result;
    1416             : }
    1417             : 
    1418             : nsresult
    1419           0 : nsXULTreeBuilder::GetResourceFor(int32_t aRow, nsIRDFResource** aResource)
    1420             : {
    1421           0 :     nsTreeRows::Row& row = *(mRows[aRow]);
    1422           0 :     return GetResultResource(row.mMatch->mResult, aResource);
    1423             : }
    1424             : 
    1425             : nsresult
    1426           0 : nsXULTreeBuilder::OpenContainer(int32_t aIndex, nsIXULTemplateResult* aResult)
    1427             : {
    1428             :     // A row index of -1 in this case means ``open tree body''
    1429           0 :     NS_ASSERTION(aIndex >= -1 && aIndex < mRows.Count(), "bad row");
    1430           0 :     if (aIndex < -1 || aIndex >= mRows.Count())
    1431           0 :         return NS_ERROR_INVALID_ARG;
    1432             : 
    1433             :     nsTreeRows::Subtree* container;
    1434             : 
    1435           0 :     if (aIndex >= 0) {
    1436           0 :         nsTreeRows::iterator iter = mRows[aIndex];
    1437           0 :         container = mRows.EnsureSubtreeFor(iter.GetParent(),
    1438           0 :                                            iter.GetChildIndex());
    1439             : 
    1440           0 :         iter->mContainerState = nsTreeRows::eContainerState_Open;
    1441             :     }
    1442             :     else
    1443           0 :         container = mRows.GetRoot();
    1444             : 
    1445           0 :     if (! container)
    1446           0 :         return NS_ERROR_OUT_OF_MEMORY;
    1447             : 
    1448             :     int32_t count;
    1449           0 :     OpenSubtreeOf(container, aIndex, aResult, &count);
    1450             : 
    1451             :     // Notify the box object
    1452           0 :     if (mBoxObject) {
    1453           0 :         if (aIndex >= 0)
    1454           0 :             mBoxObject->InvalidateRow(aIndex);
    1455             : 
    1456           0 :         if (count)
    1457           0 :             mBoxObject->RowCountChanged(aIndex + 1, count);
    1458             :     }
    1459             : 
    1460           0 :     return NS_OK;
    1461             : }
    1462             : 
    1463             : nsresult
    1464           0 : nsXULTreeBuilder::OpenSubtreeOf(nsTreeRows::Subtree* aSubtree,
    1465             :                                 int32_t aIndex,
    1466             :                                 nsIXULTemplateResult *aResult,
    1467             :                                 int32_t* aDelta)
    1468             : {
    1469           0 :     AutoTArray<int32_t, 8> open;
    1470           0 :     int32_t count = 0;
    1471             : 
    1472           0 :     int32_t rulecount = mQuerySets.Length();
    1473             : 
    1474           0 :     for (int32_t r = 0; r < rulecount; r++) {
    1475           0 :         nsTemplateQuerySet* queryset = mQuerySets[r];
    1476           0 :         OpenSubtreeForQuerySet(aSubtree, aIndex, aResult, queryset, &count, open);
    1477             :     }
    1478             : 
    1479             :     // Now recursively deal with any open sub-containers that just got
    1480             :     // inserted. We need to do this back-to-front to avoid skewing offsets.
    1481           0 :     for (int32_t i = open.Length() - 1; i >= 0; --i) {
    1482           0 :         int32_t index = open[i];
    1483             : 
    1484             :         nsTreeRows::Subtree* child =
    1485           0 :             mRows.EnsureSubtreeFor(aSubtree, index);
    1486             : 
    1487           0 :         nsIXULTemplateResult* result = (*aSubtree)[index].mMatch->mResult;
    1488             : 
    1489             :         int32_t delta;
    1490           0 :         OpenSubtreeOf(child, aIndex + index, result, &delta);
    1491           0 :         count += delta;
    1492             :     }
    1493             : 
    1494             :     // Sort the container.
    1495           0 :     if (mSortVariable) {
    1496           0 :         NS_QuickSort(mRows.GetRowsFor(aSubtree),
    1497           0 :                      aSubtree->Count(),
    1498             :                      sizeof(nsTreeRows::Row),
    1499             :                      Compare,
    1500           0 :                      this);
    1501             :     }
    1502             : 
    1503           0 :     *aDelta = count;
    1504           0 :     return NS_OK;
    1505             : }
    1506             : 
    1507             : nsresult
    1508           0 : nsXULTreeBuilder::OpenSubtreeForQuerySet(nsTreeRows::Subtree* aSubtree,
    1509             :                                          int32_t aIndex,
    1510             :                                          nsIXULTemplateResult* aResult,
    1511             :                                          nsTemplateQuerySet* aQuerySet,
    1512             :                                          int32_t* aDelta,
    1513             :                                          nsTArray<int32_t>& open)
    1514             : {
    1515           0 :     int32_t count = *aDelta;
    1516             : 
    1517           0 :     nsCOMPtr<nsISimpleEnumerator> results;
    1518           0 :     nsresult rv = mQueryProcessor->GenerateResults(mDataSource, aResult,
    1519             :                                                    aQuerySet->mCompiledQuery,
    1520           0 :                                                    getter_AddRefs(results));
    1521           0 :     if (NS_FAILED(rv))
    1522           0 :         return rv;
    1523             : 
    1524             :     bool hasMoreResults;
    1525           0 :     rv = results->HasMoreElements(&hasMoreResults);
    1526             : 
    1527           0 :     for (; NS_SUCCEEDED(rv) && hasMoreResults;
    1528           0 :            rv = results->HasMoreElements(&hasMoreResults)) {
    1529           0 :         nsCOMPtr<nsISupports> nr;
    1530           0 :         rv = results->GetNext(getter_AddRefs(nr));
    1531           0 :         if (NS_FAILED(rv))
    1532           0 :             return rv;
    1533             : 
    1534           0 :         nsCOMPtr<nsIXULTemplateResult> nextresult = do_QueryInterface(nr);
    1535           0 :         if (!nextresult)
    1536           0 :             return NS_ERROR_UNEXPECTED;
    1537             : 
    1538           0 :         nsCOMPtr<nsIRDFResource> resultid;
    1539           0 :         rv = GetResultResource(nextresult, getter_AddRefs(resultid));
    1540           0 :         if (NS_FAILED(rv))
    1541           0 :             return rv;
    1542             : 
    1543           0 :         if (! resultid)
    1544           0 :             continue;
    1545             : 
    1546             :         // check if there is already an existing match. If so, a previous
    1547             :         // query already generated content so the match is just added to the
    1548             :         // end of the set of matches.
    1549             : 
    1550           0 :         bool generateContent = true;
    1551             : 
    1552           0 :         nsTemplateMatch* prevmatch = nullptr;
    1553           0 :         nsTemplateMatch* existingmatch = nullptr;
    1554           0 :         if (mMatchMap.Get(resultid, &existingmatch)){
    1555             :             // check if there is an existing match that matched a rule
    1556           0 :             while (existingmatch) {
    1557           0 :                 if (existingmatch->IsActive())
    1558           0 :                     generateContent = false;
    1559           0 :                 prevmatch = existingmatch;
    1560           0 :                 existingmatch = existingmatch->mNext;
    1561             :             }
    1562             :         }
    1563             : 
    1564             :         nsTemplateMatch *newmatch =
    1565           0 :             nsTemplateMatch::Create(aQuerySet->Priority(), nextresult, nullptr);
    1566           0 :         if (!newmatch)
    1567           0 :             return NS_ERROR_OUT_OF_MEMORY;
    1568             : 
    1569           0 :         if (generateContent) {
    1570             :             // Don't allow cyclic graphs to get our knickers in a knot.
    1571           0 :             bool cyclic = false;
    1572             : 
    1573           0 :             if (aIndex >= 0) {
    1574           0 :                 for (nsTreeRows::iterator iter = mRows[aIndex]; iter.GetDepth() > 0; iter.Pop()) {
    1575           0 :                     nsCOMPtr<nsIRDFResource> parentid;
    1576           0 :                     rv = GetResultResource(iter->mMatch->mResult, getter_AddRefs(parentid));
    1577           0 :                     if (NS_FAILED(rv)) {
    1578           0 :                         nsTemplateMatch::Destroy(newmatch, false);
    1579           0 :                         return rv;
    1580             :                     }
    1581             : 
    1582           0 :                     if (resultid == parentid) {
    1583           0 :                         cyclic = true;
    1584           0 :                         break;
    1585             :                     }
    1586             :                 }
    1587             :             }
    1588             : 
    1589           0 :             if (cyclic) {
    1590           0 :                 NS_WARNING("tree cannot handle cyclic graphs");
    1591           0 :                 nsTemplateMatch::Destroy(newmatch, false);
    1592           0 :                 continue;
    1593             :             }
    1594             : 
    1595             :             int16_t ruleindex;
    1596           0 :             nsTemplateRule* matchedrule = nullptr;
    1597           0 :             rv = DetermineMatchedRule(nullptr, nextresult, aQuerySet,
    1598           0 :                                       &matchedrule, &ruleindex);
    1599           0 :             if (NS_FAILED(rv)) {
    1600           0 :                 nsTemplateMatch::Destroy(newmatch, false);
    1601           0 :                 return rv;
    1602             :             }
    1603             : 
    1604           0 :             if (matchedrule) {
    1605           0 :                 rv = newmatch->RuleMatched(aQuerySet, matchedrule, ruleindex,
    1606           0 :                                            nextresult);
    1607           0 :                 if (NS_FAILED(rv)) {
    1608           0 :                     nsTemplateMatch::Destroy(newmatch, false);
    1609           0 :                     return rv;
    1610             :                 }
    1611             : 
    1612             :                 // Remember that this match applied to this row
    1613           0 :                 mRows.InsertRowAt(newmatch, aSubtree, count);
    1614             : 
    1615             :                 // If this is open, then remember it so we can recursively add
    1616             :                 // *its* rows to the tree.
    1617           0 :                 if (IsContainerOpen(nextresult)) {
    1618           0 :                     if (open.AppendElement(count) == nullptr)
    1619           0 :                         return NS_ERROR_OUT_OF_MEMORY;
    1620             :                 }
    1621             : 
    1622           0 :                 ++count;
    1623             :             }
    1624             : 
    1625           0 :             if (mFlags & eLoggingEnabled)
    1626           0 :                 OutputMatchToLog(resultid, newmatch, true);
    1627             : 
    1628             :         }
    1629             : 
    1630           0 :         if (prevmatch) {
    1631           0 :             prevmatch->mNext = newmatch;
    1632             :         }
    1633             :         else {
    1634           0 :             mMatchMap.Put(resultid, newmatch);
    1635             :         }
    1636             :     }
    1637             : 
    1638           0 :     *aDelta = count;
    1639           0 :     return rv;
    1640             : }
    1641             : 
    1642             : nsresult
    1643           0 : nsXULTreeBuilder::CloseContainer(int32_t aIndex)
    1644             : {
    1645           0 :     NS_ASSERTION(aIndex >= 0 && aIndex < mRows.Count(), "bad row");
    1646           0 :     if (aIndex < 0 || aIndex >= mRows.Count())
    1647           0 :         return NS_ERROR_INVALID_ARG;
    1648             : 
    1649           0 :     nsTreeRows::iterator iter = mRows[aIndex];
    1650             : 
    1651           0 :     if (iter->mSubtree)
    1652           0 :         RemoveMatchesFor(*iter->mSubtree);
    1653             : 
    1654             : 
    1655           0 :     int32_t count = mRows.GetSubtreeSizeFor(iter);
    1656           0 :     mRows.RemoveSubtreeFor(iter);
    1657             : 
    1658           0 :     iter->mContainerState = nsTreeRows::eContainerState_Closed;
    1659             : 
    1660           0 :     if (mBoxObject) {
    1661           0 :         mBoxObject->InvalidateRow(aIndex);
    1662             : 
    1663           0 :         if (count)
    1664           0 :             mBoxObject->RowCountChanged(aIndex + 1, -count);
    1665             :     }
    1666             : 
    1667           0 :     return NS_OK;
    1668             : }
    1669             : 
    1670             : nsresult
    1671           0 : nsXULTreeBuilder::RemoveMatchesFor(nsTreeRows::Subtree& subtree)
    1672             : {
    1673           0 :     for (int32_t i = subtree.Count() - 1; i >= 0; --i) {
    1674           0 :         nsTreeRows::Row& row = subtree[i];
    1675             : 
    1676           0 :         nsTemplateMatch* match = row.mMatch;
    1677             : 
    1678           0 :         nsCOMPtr<nsIRDFResource> id;
    1679           0 :         nsresult rv = GetResultResource(match->mResult, getter_AddRefs(id));
    1680           0 :         if (NS_FAILED(rv))
    1681           0 :             return rv;
    1682             : 
    1683             :         nsTemplateMatch* existingmatch;
    1684           0 :         if (mMatchMap.Get(id, &existingmatch)) {
    1685           0 :             while (existingmatch) {
    1686           0 :                 nsTemplateMatch* nextmatch = existingmatch->mNext;
    1687           0 :                 nsTemplateMatch::Destroy(existingmatch, true);
    1688           0 :                 existingmatch = nextmatch;
    1689             :             }
    1690             : 
    1691           0 :             mMatchMap.Remove(id);
    1692             :         }
    1693             : 
    1694           0 :         if ((row.mContainerState == nsTreeRows::eContainerState_Open) && row.mSubtree)
    1695           0 :             RemoveMatchesFor(*(row.mSubtree));
    1696             :     }
    1697             : 
    1698           0 :     return NS_OK;
    1699             : }
    1700             : 
    1701             : 
    1702             : bool
    1703           0 : nsXULTreeBuilder::IsContainerOpen(nsIXULTemplateResult *aResult)
    1704             : {
    1705             :   // items are never open if recursion is disabled
    1706           0 :   if ((mFlags & eDontRecurse) && aResult != mRootResult) {
    1707           0 :     return false;
    1708             :   }
    1709             : 
    1710           0 :   if (!mLocalStore) {
    1711           0 :     return false;
    1712             :   }
    1713             : 
    1714           0 :   nsIDocument* doc = mRoot->GetComposedDoc();
    1715           0 :   if (!doc) {
    1716           0 :     return false;
    1717             :   }
    1718             : 
    1719           0 :   nsIURI* docURI = doc->GetDocumentURI();
    1720             : 
    1721           0 :   nsAutoString nodeid;
    1722           0 :   nsresult rv = aResult->GetId(nodeid);
    1723           0 :   if (NS_FAILED(rv)) {
    1724           0 :     return false;
    1725             :   }
    1726             : 
    1727           0 :   nsAutoCString utf8uri;
    1728           0 :   rv = docURI->GetSpec(utf8uri);
    1729           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1730           0 :       return false;
    1731             :   }
    1732           0 :   NS_ConvertUTF8toUTF16 uri(utf8uri);
    1733             : 
    1734           0 :   nsAutoString val;
    1735           0 :   mLocalStore->GetValue(uri, nodeid, NS_LITERAL_STRING("open"), val);
    1736           0 :   return val.EqualsLiteral("true");
    1737             : }
    1738             : 
    1739             : int
    1740           0 : nsXULTreeBuilder::Compare(const void* aLeft, const void* aRight, void* aClosure)
    1741             : {
    1742           0 :     nsXULTreeBuilder* self = static_cast<nsXULTreeBuilder*>(aClosure);
    1743             : 
    1744             :     nsTreeRows::Row* left = static_cast<nsTreeRows::Row*>
    1745           0 :                                        (const_cast<void*>(aLeft));
    1746             : 
    1747             :     nsTreeRows::Row* right = static_cast<nsTreeRows::Row*>
    1748           0 :                                         (const_cast<void*>(aRight));
    1749             : 
    1750           0 :     return self->CompareResults(left->mMatch->mResult, right->mMatch->mResult);
    1751             : }
    1752             : 
    1753             : int32_t
    1754           0 : nsXULTreeBuilder::CompareResults(nsIXULTemplateResult* aLeft, nsIXULTemplateResult* aRight)
    1755             : {
    1756             :     // this is an extra check done for RDF queries such that results appear in
    1757             :     // the order they appear in their containing Seq
    1758           0 :     if (mSortDirection == eDirection_Natural && mDB) {
    1759             :         // If the sort order is ``natural'', then see if the container
    1760             :         // is an RDF sequence. If so, we'll try to use the ordinal
    1761             :         // properties to determine order.
    1762             :         //
    1763             :         // XXX the problem with this is, it doesn't always get the
    1764             :         // *real* container; e.g.,
    1765             :         //
    1766             :         //  <treerow uri="?uri" />
    1767             :         //
    1768             :         //  <triple subject="?uri"
    1769             :         //          predicate="http://home.netscape.com/NC-rdf#subheadings"
    1770             :         //          object="?subheadings" />
    1771             :         //
    1772             :         //  <member container="?subheadings" child="?subheading" />
    1773             :         //
    1774             :         // In this case mRefVariable is bound to ?uri, not
    1775             :         // ?subheadings. (The ``container'' in the template sense !=
    1776             :         // container in the RDF sense.)
    1777             : 
    1778           0 :         nsCOMPtr<nsISupports> ref;
    1779           0 :         nsresult rv = aLeft->GetBindingObjectFor(mRefVariable, getter_AddRefs(ref));
    1780           0 :         if (NS_FAILED(rv))
    1781           0 :             return 0;
    1782             : 
    1783           0 :         nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref);
    1784           0 :         if (container) {
    1785           0 :             bool isSequence = false;
    1786           0 :             gRDFContainerUtils->IsSeq(mDB, container, &isSequence);
    1787           0 :             if (isSequence) {
    1788             :                 // Determine the indices of the left and right elements
    1789             :                 // in the container.
    1790           0 :                 int32_t lindex = 0, rindex = 0;
    1791             : 
    1792           0 :                 nsCOMPtr<nsIRDFResource> leftitem;
    1793           0 :                 aLeft->GetResource(getter_AddRefs(leftitem));
    1794           0 :                 if (leftitem) {
    1795           0 :                     gRDFContainerUtils->IndexOf(mDB, container, leftitem, &lindex);
    1796           0 :                     if (lindex < 0)
    1797           0 :                         return 0;
    1798             :                 }
    1799             : 
    1800           0 :                 nsCOMPtr<nsIRDFResource> rightitem;
    1801           0 :                 aRight->GetResource(getter_AddRefs(rightitem));
    1802           0 :                 if (rightitem) {
    1803           0 :                     gRDFContainerUtils->IndexOf(mDB, container, rightitem, &rindex);
    1804           0 :                     if (rindex < 0)
    1805           0 :                         return 0;
    1806             :                 }
    1807             : 
    1808           0 :                 return lindex - rindex;
    1809             :             }
    1810             :         }
    1811             :     }
    1812             : 
    1813             :     int32_t sortorder;
    1814           0 :     if (!mQueryProcessor)
    1815           0 :         return 0;
    1816             : 
    1817           0 :     mQueryProcessor->CompareResults(aLeft, aRight, mSortVariable, mSortHints, &sortorder);
    1818             : 
    1819           0 :     if (sortorder)
    1820           0 :         sortorder = sortorder * mSortDirection;
    1821           0 :     return sortorder;
    1822             : }
    1823             : 
    1824             : nsresult
    1825           0 : nsXULTreeBuilder::SortSubtree(nsTreeRows::Subtree* aSubtree)
    1826             : {
    1827           0 :     NS_QuickSort(mRows.GetRowsFor(aSubtree),
    1828           0 :                  aSubtree->Count(),
    1829             :                  sizeof(nsTreeRows::Row),
    1830             :                  Compare,
    1831           0 :                  this);
    1832             : 
    1833           0 :     for (int32_t i = aSubtree->Count() - 1; i >= 0; --i) {
    1834           0 :         nsTreeRows::Subtree* child = (*aSubtree)[i].mSubtree;
    1835           0 :         if (child)
    1836           0 :             SortSubtree(child);
    1837             :     }
    1838             : 
    1839           0 :     return NS_OK;
    1840             : }
    1841             : 
    1842             : bool
    1843           0 : nsXULTreeBuilder::CanDrop(int32_t aRow, int32_t aOrientation,
    1844             :                           DataTransfer* aDataTransfer, ErrorResult& aError)
    1845             : {
    1846           0 :     uint32_t count = mObservers.Length();
    1847           0 :     for (uint32_t i = 0; i < count; ++i) {
    1848           0 :         nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
    1849           0 :         if (observer) {
    1850           0 :             bool canDrop = false;
    1851           0 :             observer->CanDrop(aRow, aOrientation, aDataTransfer, &canDrop);
    1852           0 :             if (canDrop) {
    1853           0 :                 return true;
    1854             :             }
    1855             :         }
    1856             :     }
    1857             : 
    1858           0 :     return false;
    1859             : }
    1860             : 
    1861             : NS_IMETHODIMP
    1862           0 : nsXULTreeBuilder::CanDrop(int32_t index, int32_t orientation,
    1863             :                           nsIDOMDataTransfer* dataTransfer, bool *_retval)
    1864             : {
    1865           0 :     ErrorResult rv;
    1866           0 :     *_retval = CanDrop(index, orientation, DataTransfer::Cast(dataTransfer),
    1867             :                        rv);
    1868           0 :     return rv.StealNSResult();
    1869             : }
    1870             : 
    1871             : void
    1872           0 : nsXULTreeBuilder::Drop(int32_t aRow, int32_t aOrientation,
    1873             :                        DataTransfer* aDataTransfer, ErrorResult& aError)
    1874             : {
    1875           0 :     uint32_t count = mObservers.Length();
    1876           0 :     for (uint32_t i = 0; i < count; ++i) {
    1877           0 :         nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
    1878           0 :         if (observer) {
    1879           0 :             bool canDrop = false;
    1880           0 :             observer->CanDrop(aRow, aOrientation, aDataTransfer, &canDrop);
    1881           0 :             if (canDrop)
    1882           0 :                 observer->OnDrop(aRow, aOrientation, aDataTransfer);
    1883             :         }
    1884             :     }
    1885           0 : }
    1886             : 
    1887             : NS_IMETHODIMP
    1888           0 : nsXULTreeBuilder::Drop(int32_t row, int32_t orient, nsIDOMDataTransfer* dataTransfer)
    1889             : {
    1890           0 :     ErrorResult rv;
    1891           0 :     Drop(row, orient, DataTransfer::Cast(dataTransfer), rv);
    1892           0 :     return rv.StealNSResult();
    1893             : }
    1894             : 
    1895             : NS_IMETHODIMP
    1896           0 : nsXULTreeBuilder::IsSorted(bool *_retval)
    1897             : {
    1898           0 :   *_retval = (mSortVariable != nullptr);
    1899           0 :   return NS_OK;
    1900             : }
    1901             : 
    1902             : bool
    1903           0 : nsXULTreeBuilder::IsValidRowIndex(int32_t aRowIndex)
    1904             : {
    1905           0 :     return aRowIndex >= 0 && aRowIndex < int32_t(mRows.Count());
    1906             : }

Generated by: LCOV version 1.13