layout/xul/tree/nsTreeColumns.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial