nsXULTreeBuilder.cpp 55 KB

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