nsTreeColumns.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  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 "nsNameSpaceManager.h"
  6. #include "nsGkAtoms.h"
  7. #include "nsIDOMElement.h"
  8. #include "nsIBoxObject.h"
  9. #include "nsTreeColumns.h"
  10. #include "nsTreeUtils.h"
  11. #include "nsStyleContext.h"
  12. #include "nsDOMClassInfoID.h"
  13. #include "nsContentUtils.h"
  14. #include "nsTreeBodyFrame.h"
  15. #include "mozilla/dom/Element.h"
  16. #include "mozilla/dom/TreeBoxObject.h"
  17. #include "mozilla/dom/TreeColumnBinding.h"
  18. #include "mozilla/dom/TreeColumnsBinding.h"
  19. using namespace mozilla;
  20. // Column class that caches all the info about our column.
  21. nsTreeColumn::nsTreeColumn(nsTreeColumns* aColumns, nsIContent* aContent)
  22. : mContent(aContent),
  23. mColumns(aColumns),
  24. mPrevious(nullptr)
  25. {
  26. NS_ASSERTION(aContent &&
  27. aContent->NodeInfo()->Equals(nsGkAtoms::treecol,
  28. kNameSpaceID_XUL),
  29. "nsTreeColumn's content must be a <xul:treecol>");
  30. Invalidate();
  31. }
  32. nsTreeColumn::~nsTreeColumn()
  33. {
  34. if (mNext) {
  35. mNext->SetPrevious(nullptr);
  36. }
  37. }
  38. NS_IMPL_CYCLE_COLLECTION_CLASS(nsTreeColumn)
  39. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsTreeColumn)
  40. NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  41. NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent)
  42. if (tmp->mNext) {
  43. tmp->mNext->SetPrevious(nullptr);
  44. NS_IMPL_CYCLE_COLLECTION_UNLINK(mNext)
  45. }
  46. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  47. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTreeColumn)
  48. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
  49. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNext)
  50. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  51. NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsTreeColumn)
  52. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeColumn)
  53. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeColumn)
  54. // QueryInterface implementation for nsTreeColumn
  55. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeColumn)
  56. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  57. NS_INTERFACE_MAP_ENTRY(nsITreeColumn)
  58. NS_INTERFACE_MAP_ENTRY(nsISupports)
  59. if (aIID.Equals(NS_GET_IID(nsTreeColumn))) {
  60. AddRef();
  61. *aInstancePtr = this;
  62. return NS_OK;
  63. }
  64. else
  65. NS_INTERFACE_MAP_END
  66. nsIFrame*
  67. nsTreeColumn::GetFrame()
  68. {
  69. NS_ENSURE_TRUE(mContent, nullptr);
  70. return mContent->GetPrimaryFrame();
  71. }
  72. bool
  73. nsTreeColumn::IsLastVisible(nsTreeBodyFrame* aBodyFrame)
  74. {
  75. NS_ASSERTION(GetFrame(), "should have checked for this already");
  76. // cyclers are fixed width, don't adjust them
  77. if (IsCycler())
  78. return false;
  79. // we're certainly not the last visible if we're not visible
  80. if (GetFrame()->GetRect().width == 0)
  81. return false;
  82. // try to find a visible successor
  83. for (nsTreeColumn *next = GetNext(); next; next = next->GetNext()) {
  84. nsIFrame* frame = next->GetFrame();
  85. if (frame && frame->GetRect().width > 0)
  86. return false;
  87. }
  88. return true;
  89. }
  90. nsresult
  91. nsTreeColumn::GetRect(nsTreeBodyFrame* aBodyFrame, nscoord aY, nscoord aHeight, nsRect* aResult)
  92. {
  93. nsIFrame* frame = GetFrame();
  94. if (!frame) {
  95. *aResult = nsRect();
  96. return NS_ERROR_FAILURE;
  97. }
  98. bool isRTL = aBodyFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
  99. *aResult = frame->GetRect();
  100. aResult->y = aY;
  101. aResult->height = aHeight;
  102. if (isRTL)
  103. aResult->x += aBodyFrame->mAdjustWidth;
  104. else if (IsLastVisible(aBodyFrame))
  105. aResult->width += aBodyFrame->mAdjustWidth;
  106. return NS_OK;
  107. }
  108. nsresult
  109. nsTreeColumn::GetXInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult)
  110. {
  111. nsIFrame* frame = GetFrame();
  112. if (!frame) {
  113. *aResult = 0;
  114. return NS_ERROR_FAILURE;
  115. }
  116. *aResult = frame->GetRect().x;
  117. return NS_OK;
  118. }
  119. nsresult
  120. nsTreeColumn::GetWidthInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult)
  121. {
  122. nsIFrame* frame = GetFrame();
  123. if (!frame) {
  124. *aResult = 0;
  125. return NS_ERROR_FAILURE;
  126. }
  127. *aResult = frame->GetRect().width;
  128. if (IsLastVisible(aBodyFrame))
  129. *aResult += aBodyFrame->mAdjustWidth;
  130. return NS_OK;
  131. }
  132. NS_IMETHODIMP
  133. nsTreeColumn::GetElement(nsIDOMElement** aElement)
  134. {
  135. if (mContent) {
  136. return CallQueryInterface(mContent, aElement);
  137. }
  138. *aElement = nullptr;
  139. return NS_ERROR_FAILURE;
  140. }
  141. NS_IMETHODIMP
  142. nsTreeColumn::GetColumns(nsITreeColumns** aColumns)
  143. {
  144. NS_IF_ADDREF(*aColumns = mColumns);
  145. return NS_OK;
  146. }
  147. NS_IMETHODIMP
  148. nsTreeColumn::GetX(int32_t* aX)
  149. {
  150. nsIFrame* frame = GetFrame();
  151. NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
  152. *aX = nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().x);
  153. return NS_OK;
  154. }
  155. NS_IMETHODIMP
  156. nsTreeColumn::GetWidth(int32_t* aWidth)
  157. {
  158. nsIFrame* frame = GetFrame();
  159. NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
  160. *aWidth = nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().width);
  161. return NS_OK;
  162. }
  163. NS_IMETHODIMP
  164. nsTreeColumn::GetId(nsAString& aId)
  165. {
  166. aId = GetId();
  167. return NS_OK;
  168. }
  169. NS_IMETHODIMP
  170. nsTreeColumn::GetIdConst(const char16_t** aIdConst)
  171. {
  172. *aIdConst = mId.get();
  173. return NS_OK;
  174. }
  175. NS_IMETHODIMP
  176. nsTreeColumn::GetAtom(nsIAtom** aAtom)
  177. {
  178. NS_IF_ADDREF(*aAtom = GetAtom());
  179. return NS_OK;
  180. }
  181. NS_IMETHODIMP
  182. nsTreeColumn::GetIndex(int32_t* aIndex)
  183. {
  184. *aIndex = GetIndex();
  185. return NS_OK;
  186. }
  187. NS_IMETHODIMP
  188. nsTreeColumn::GetPrimary(bool* aPrimary)
  189. {
  190. *aPrimary = IsPrimary();
  191. return NS_OK;
  192. }
  193. NS_IMETHODIMP
  194. nsTreeColumn::GetCycler(bool* aCycler)
  195. {
  196. *aCycler = IsCycler();
  197. return NS_OK;
  198. }
  199. NS_IMETHODIMP
  200. nsTreeColumn::GetEditable(bool* aEditable)
  201. {
  202. *aEditable = IsEditable();
  203. return NS_OK;
  204. }
  205. NS_IMETHODIMP
  206. nsTreeColumn::GetSelectable(bool* aSelectable)
  207. {
  208. *aSelectable = IsSelectable();
  209. return NS_OK;
  210. }
  211. NS_IMETHODIMP
  212. nsTreeColumn::GetType(int16_t* aType)
  213. {
  214. *aType = GetType();
  215. return NS_OK;
  216. }
  217. NS_IMETHODIMP
  218. nsTreeColumn::GetNext(nsITreeColumn** _retval)
  219. {
  220. NS_IF_ADDREF(*_retval = GetNext());
  221. return NS_OK;
  222. }
  223. NS_IMETHODIMP
  224. nsTreeColumn::GetPrevious(nsITreeColumn** _retval)
  225. {
  226. NS_IF_ADDREF(*_retval = GetPrevious());
  227. return NS_OK;
  228. }
  229. NS_IMETHODIMP
  230. nsTreeColumn::Invalidate()
  231. {
  232. nsIFrame* frame = GetFrame();
  233. NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
  234. // Fetch the Id.
  235. mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mId);
  236. // If we have an Id, cache the Id as an atom.
  237. if (!mId.IsEmpty()) {
  238. mAtom = NS_Atomize(mId);
  239. }
  240. // Cache our index.
  241. nsTreeUtils::GetColumnIndex(mContent, &mIndex);
  242. const nsStyleVisibility* vis = frame->StyleVisibility();
  243. // Cache our text alignment policy.
  244. const nsStyleText* textStyle = frame->StyleText();
  245. mTextAlignment = textStyle->mTextAlign;
  246. // START or END alignment sometimes means RIGHT
  247. if ((mTextAlignment == NS_STYLE_TEXT_ALIGN_START &&
  248. vis->mDirection == NS_STYLE_DIRECTION_RTL) ||
  249. (mTextAlignment == NS_STYLE_TEXT_ALIGN_END &&
  250. vis->mDirection == NS_STYLE_DIRECTION_LTR)) {
  251. mTextAlignment = NS_STYLE_TEXT_ALIGN_RIGHT;
  252. } else if (mTextAlignment == NS_STYLE_TEXT_ALIGN_START ||
  253. mTextAlignment == NS_STYLE_TEXT_ALIGN_END) {
  254. mTextAlignment = NS_STYLE_TEXT_ALIGN_LEFT;
  255. }
  256. // Figure out if we're the primary column (that has to have indentation
  257. // and twisties drawn.
  258. mIsPrimary = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary,
  259. nsGkAtoms::_true, eCaseMatters);
  260. // Figure out if we're a cycling column (one that doesn't cause a selection
  261. // to happen).
  262. mIsCycler = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::cycler,
  263. nsGkAtoms::_true, eCaseMatters);
  264. mIsEditable = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable,
  265. nsGkAtoms::_true, eCaseMatters);
  266. mIsSelectable = !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable,
  267. nsGkAtoms::_false, eCaseMatters);
  268. mOverflow = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::overflow,
  269. nsGkAtoms::_true, eCaseMatters);
  270. // Figure out our column type. Default type is text.
  271. mType = nsITreeColumn::TYPE_TEXT;
  272. static nsIContent::AttrValuesArray typestrings[] =
  273. {&nsGkAtoms::checkbox, &nsGkAtoms::progressmeter, &nsGkAtoms::password,
  274. nullptr};
  275. switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
  276. typestrings, eCaseMatters)) {
  277. case 0: mType = nsITreeColumn::TYPE_CHECKBOX; break;
  278. case 1: mType = nsITreeColumn::TYPE_PROGRESSMETER; break;
  279. case 2: mType = nsITreeColumn::TYPE_PASSWORD; break;
  280. }
  281. // Fetch the crop style.
  282. mCropStyle = 0;
  283. static nsIContent::AttrValuesArray cropstrings[] =
  284. {&nsGkAtoms::center, &nsGkAtoms::left, &nsGkAtoms::start, nullptr};
  285. switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::crop,
  286. cropstrings, eCaseMatters)) {
  287. case 0:
  288. mCropStyle = 1;
  289. break;
  290. case 1:
  291. case 2:
  292. mCropStyle = 2;
  293. break;
  294. }
  295. return NS_OK;
  296. }
  297. nsIContent*
  298. nsTreeColumn::GetParentObject() const
  299. {
  300. return mContent;
  301. }
  302. /* virtual */ JSObject*
  303. nsTreeColumn::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  304. {
  305. return dom::TreeColumnBinding::Wrap(aCx, this, aGivenProto);
  306. }
  307. mozilla::dom::Element*
  308. nsTreeColumn::GetElement(mozilla::ErrorResult& aRv)
  309. {
  310. nsCOMPtr<nsIDOMElement> element;
  311. aRv = GetElement(getter_AddRefs(element));
  312. if (aRv.Failed()) {
  313. return nullptr;
  314. }
  315. nsCOMPtr<nsINode> node = do_QueryInterface(element);
  316. return node->AsElement();
  317. }
  318. int32_t
  319. nsTreeColumn::GetX(mozilla::ErrorResult& aRv)
  320. {
  321. int32_t x;
  322. aRv = GetX(&x);
  323. return x;
  324. }
  325. int32_t
  326. nsTreeColumn::GetWidth(mozilla::ErrorResult& aRv)
  327. {
  328. int32_t width;
  329. aRv = GetWidth(&width);
  330. return width;
  331. }
  332. void
  333. nsTreeColumn::Invalidate(mozilla::ErrorResult& aRv)
  334. {
  335. aRv = Invalidate();
  336. }
  337. nsTreeColumns::nsTreeColumns(nsTreeBodyFrame* aTree)
  338. : mTree(aTree)
  339. {
  340. }
  341. nsTreeColumns::~nsTreeColumns()
  342. {
  343. nsTreeColumns::InvalidateColumns();
  344. }
  345. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsTreeColumns)
  346. // QueryInterface implementation for nsTreeColumns
  347. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeColumns)
  348. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  349. NS_INTERFACE_MAP_ENTRY(nsITreeColumns)
  350. NS_INTERFACE_MAP_ENTRY(nsISupports)
  351. NS_INTERFACE_MAP_END
  352. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeColumns)
  353. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeColumns)
  354. nsIContent*
  355. nsTreeColumns::GetParentObject() const
  356. {
  357. return mTree ? mTree->GetBaseElement() : nullptr;
  358. }
  359. /* virtual */ JSObject*
  360. nsTreeColumns::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  361. {
  362. return dom::TreeColumnsBinding::Wrap(aCx, this, aGivenProto);
  363. }
  364. dom::TreeBoxObject*
  365. nsTreeColumns::GetTree() const
  366. {
  367. return mTree ? static_cast<mozilla::dom::TreeBoxObject*>(mTree->GetTreeBoxObject()) : nullptr;
  368. }
  369. NS_IMETHODIMP
  370. nsTreeColumns::GetTree(nsITreeBoxObject** _retval)
  371. {
  372. NS_IF_ADDREF(*_retval = GetTree());
  373. return NS_OK;
  374. }
  375. uint32_t
  376. nsTreeColumns::Count()
  377. {
  378. EnsureColumns();
  379. uint32_t count = 0;
  380. for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
  381. ++count;
  382. }
  383. return count;
  384. }
  385. NS_IMETHODIMP
  386. nsTreeColumns::GetCount(int32_t* _retval)
  387. {
  388. *_retval = Count();
  389. return NS_OK;
  390. }
  391. NS_IMETHODIMP
  392. nsTreeColumns::GetLength(int32_t* _retval)
  393. {
  394. *_retval = Length();
  395. return NS_OK;
  396. }
  397. NS_IMETHODIMP
  398. nsTreeColumns::GetFirstColumn(nsITreeColumn** _retval)
  399. {
  400. NS_IF_ADDREF(*_retval = GetFirstColumn());
  401. return NS_OK;
  402. }
  403. nsTreeColumn*
  404. nsTreeColumns::GetLastColumn()
  405. {
  406. EnsureColumns();
  407. nsTreeColumn* currCol = mFirstColumn;
  408. while (currCol) {
  409. nsTreeColumn* next = currCol->GetNext();
  410. if (!next) {
  411. return currCol;
  412. }
  413. currCol = next;
  414. }
  415. return nullptr;
  416. }
  417. NS_IMETHODIMP
  418. nsTreeColumns::GetLastColumn(nsITreeColumn** _retval)
  419. {
  420. NS_IF_ADDREF(*_retval = GetLastColumn());
  421. return NS_OK;
  422. }
  423. NS_IMETHODIMP
  424. nsTreeColumns::GetPrimaryColumn(nsITreeColumn** _retval)
  425. {
  426. NS_IF_ADDREF(*_retval = GetPrimaryColumn());
  427. return NS_OK;
  428. }
  429. nsTreeColumn*
  430. nsTreeColumns::GetSortedColumn()
  431. {
  432. EnsureColumns();
  433. for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
  434. if (currCol->mContent &&
  435. nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
  436. nsGkAtoms::sortDirection)) {
  437. return currCol;
  438. }
  439. }
  440. return nullptr;
  441. }
  442. NS_IMETHODIMP
  443. nsTreeColumns::GetSortedColumn(nsITreeColumn** _retval)
  444. {
  445. NS_IF_ADDREF(*_retval = GetSortedColumn());
  446. return NS_OK;
  447. }
  448. nsTreeColumn*
  449. nsTreeColumns::GetKeyColumn()
  450. {
  451. EnsureColumns();
  452. nsTreeColumn* first = nullptr;
  453. nsTreeColumn* primary = nullptr;
  454. nsTreeColumn* sorted = nullptr;
  455. for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
  456. // Skip hidden columns.
  457. if (!currCol->mContent ||
  458. currCol->mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
  459. nsGkAtoms::_true, eCaseMatters))
  460. continue;
  461. // Skip non-text column
  462. if (currCol->GetType() != nsITreeColumn::TYPE_TEXT)
  463. continue;
  464. if (!first)
  465. first = currCol;
  466. if (nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None,
  467. nsGkAtoms::sortDirection)) {
  468. // Use sorted column as the key.
  469. sorted = currCol;
  470. break;
  471. }
  472. if (currCol->IsPrimary())
  473. if (!primary)
  474. primary = currCol;
  475. }
  476. if (sorted)
  477. return sorted;
  478. if (primary)
  479. return primary;
  480. return first;
  481. }
  482. NS_IMETHODIMP
  483. nsTreeColumns::GetKeyColumn(nsITreeColumn** _retval)
  484. {
  485. NS_IF_ADDREF(*_retval = GetKeyColumn());
  486. return NS_OK;
  487. }
  488. nsTreeColumn*
  489. nsTreeColumns::GetColumnFor(dom::Element* aElement)
  490. {
  491. EnsureColumns();
  492. for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
  493. if (currCol->mContent == aElement) {
  494. return currCol;
  495. }
  496. }
  497. return nullptr;
  498. }
  499. NS_IMETHODIMP
  500. nsTreeColumns::GetColumnFor(nsIDOMElement* aElement, nsITreeColumn** _retval)
  501. {
  502. nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
  503. NS_ADDREF(*_retval = GetColumnFor(element));
  504. return NS_OK;
  505. }
  506. nsTreeColumn*
  507. nsTreeColumns::NamedGetter(const nsAString& aId, bool& aFound)
  508. {
  509. EnsureColumns();
  510. for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
  511. if (currCol->GetId().Equals(aId)) {
  512. aFound = true;
  513. return currCol;
  514. }
  515. }
  516. aFound = false;
  517. return nullptr;
  518. }
  519. nsTreeColumn*
  520. nsTreeColumns::GetNamedColumn(const nsAString& aId)
  521. {
  522. bool dummy;
  523. return NamedGetter(aId, dummy);
  524. }
  525. NS_IMETHODIMP
  526. nsTreeColumns::GetNamedColumn(const nsAString& aId, nsITreeColumn** _retval)
  527. {
  528. NS_IF_ADDREF(*_retval = GetNamedColumn(aId));
  529. return NS_OK;
  530. }
  531. void
  532. nsTreeColumns::GetSupportedNames(nsTArray<nsString>& aNames)
  533. {
  534. for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
  535. aNames.AppendElement(currCol->GetId());
  536. }
  537. }
  538. nsTreeColumn*
  539. nsTreeColumns::IndexedGetter(uint32_t aIndex, bool& aFound)
  540. {
  541. EnsureColumns();
  542. for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
  543. if (currCol->GetIndex() == static_cast<int32_t>(aIndex)) {
  544. aFound = true;
  545. return currCol;
  546. }
  547. }
  548. aFound = false;
  549. return nullptr;
  550. }
  551. nsTreeColumn*
  552. nsTreeColumns::GetColumnAt(uint32_t aIndex)
  553. {
  554. bool dummy;
  555. return IndexedGetter(aIndex, dummy);
  556. }
  557. NS_IMETHODIMP
  558. nsTreeColumns::GetColumnAt(int32_t aIndex, nsITreeColumn** _retval)
  559. {
  560. NS_IF_ADDREF(*_retval = GetColumnAt(static_cast<uint32_t>(aIndex)));
  561. return NS_OK;
  562. }
  563. NS_IMETHODIMP
  564. nsTreeColumns::InvalidateColumns()
  565. {
  566. for (nsTreeColumn* currCol = mFirstColumn; currCol;
  567. currCol = currCol->GetNext()) {
  568. currCol->SetColumns(nullptr);
  569. }
  570. mFirstColumn = nullptr;
  571. return NS_OK;
  572. }
  573. NS_IMETHODIMP
  574. nsTreeColumns::RestoreNaturalOrder()
  575. {
  576. if (!mTree)
  577. return NS_OK;
  578. nsIContent* content = mTree->GetBaseElement();
  579. // Strong ref, since we'll be setting attributes
  580. nsCOMPtr<nsIContent> colsContent =
  581. nsTreeUtils::GetImmediateChild(content, nsGkAtoms::treecols);
  582. if (!colsContent)
  583. return NS_OK;
  584. for (uint32_t i = 0; i < colsContent->GetChildCount(); ++i) {
  585. nsCOMPtr<nsIContent> child = colsContent->GetChildAt(i);
  586. nsAutoString ordinal;
  587. ordinal.AppendInt(i);
  588. child->SetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, ordinal, true);
  589. }
  590. nsTreeColumns::InvalidateColumns();
  591. if (mTree) {
  592. mTree->Invalidate();
  593. }
  594. return NS_OK;
  595. }
  596. nsTreeColumn*
  597. nsTreeColumns::GetPrimaryColumn()
  598. {
  599. EnsureColumns();
  600. for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
  601. if (currCol->IsPrimary()) {
  602. return currCol;
  603. }
  604. }
  605. return nullptr;
  606. }
  607. void
  608. nsTreeColumns::EnsureColumns()
  609. {
  610. if (mTree && !mFirstColumn) {
  611. nsIContent* treeContent = mTree->GetBaseElement();
  612. nsIContent* colsContent =
  613. nsTreeUtils::GetDescendantChild(treeContent, nsGkAtoms::treecols);
  614. if (!colsContent)
  615. return;
  616. nsIContent* colContent =
  617. nsTreeUtils::GetDescendantChild(colsContent, nsGkAtoms::treecol);
  618. if (!colContent)
  619. return;
  620. nsIFrame* colFrame = colContent->GetPrimaryFrame();
  621. if (!colFrame)
  622. return;
  623. colFrame = colFrame->GetParent();
  624. if (!colFrame)
  625. return;
  626. colFrame = colFrame->PrincipalChildList().FirstChild();
  627. if (!colFrame)
  628. return;
  629. // Now that we have the first visible column,
  630. // we can enumerate the columns in visible order
  631. nsTreeColumn* currCol = nullptr;
  632. while (colFrame) {
  633. nsIContent* colContent = colFrame->GetContent();
  634. if (colContent->NodeInfo()->Equals(nsGkAtoms::treecol,
  635. kNameSpaceID_XUL)) {
  636. // Create a new column structure.
  637. nsTreeColumn* col = new nsTreeColumn(this, colContent);
  638. if (!col)
  639. return;
  640. if (currCol) {
  641. currCol->SetNext(col);
  642. col->SetPrevious(currCol);
  643. }
  644. else {
  645. mFirstColumn = col;
  646. }
  647. currCol = col;
  648. }
  649. colFrame = colFrame->GetNextSibling();
  650. }
  651. }
  652. }