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