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