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