michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIBoxObject.h" michael@0: #include "nsTreeColumns.h" michael@0: #include "nsTreeUtils.h" michael@0: #include "nsStyleContext.h" michael@0: #include "nsDOMClassInfoID.h" michael@0: #include "nsINodeInfo.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsTreeBodyFrame.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "mozilla/dom/TreeColumnsBinding.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: // Column class that caches all the info about our column. michael@0: nsTreeColumn::nsTreeColumn(nsTreeColumns* aColumns, nsIContent* aContent) michael@0: : mContent(aContent), michael@0: mColumns(aColumns), michael@0: mPrevious(nullptr) michael@0: { michael@0: NS_ASSERTION(aContent && michael@0: aContent->NodeInfo()->Equals(nsGkAtoms::treecol, michael@0: kNameSpaceID_XUL), michael@0: "nsTreeColumn's content must be a "); michael@0: michael@0: Invalidate(); michael@0: } michael@0: michael@0: nsTreeColumn::~nsTreeColumn() michael@0: { michael@0: if (mNext) { michael@0: mNext->SetPrevious(nullptr); michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(nsTreeColumn) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsTreeColumn) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent) michael@0: if (tmp->mNext) { michael@0: tmp->mNext->SetPrevious(nullptr); michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mNext) michael@0: } michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTreeColumn) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNext) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeColumn) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeColumn) michael@0: michael@0: DOMCI_DATA(TreeColumn, nsTreeColumn) michael@0: michael@0: // QueryInterface implementation for nsTreeColumn michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeColumn) michael@0: NS_INTERFACE_MAP_ENTRY(nsITreeColumn) michael@0: NS_INTERFACE_MAP_ENTRY(nsISupports) michael@0: NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TreeColumn) michael@0: if (aIID.Equals(NS_GET_IID(nsTreeColumn))) { michael@0: AddRef(); michael@0: *aInstancePtr = this; michael@0: return NS_OK; michael@0: } michael@0: else michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: nsIFrame* michael@0: nsTreeColumn::GetFrame() michael@0: { michael@0: NS_ENSURE_TRUE(mContent, nullptr); michael@0: michael@0: return mContent->GetPrimaryFrame(); michael@0: } michael@0: michael@0: bool michael@0: nsTreeColumn::IsLastVisible(nsTreeBodyFrame* aBodyFrame) michael@0: { michael@0: NS_ASSERTION(GetFrame(), "should have checked for this already"); michael@0: michael@0: // cyclers are fixed width, don't adjust them michael@0: if (IsCycler()) michael@0: return false; michael@0: michael@0: // we're certainly not the last visible if we're not visible michael@0: if (GetFrame()->GetRect().width == 0) michael@0: return false; michael@0: michael@0: // try to find a visible successor michael@0: for (nsTreeColumn *next = GetNext(); next; next = next->GetNext()) { michael@0: nsIFrame* frame = next->GetFrame(); michael@0: if (frame && frame->GetRect().width > 0) michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: nsresult michael@0: nsTreeColumn::GetRect(nsTreeBodyFrame* aBodyFrame, nscoord aY, nscoord aHeight, nsRect* aResult) michael@0: { michael@0: nsIFrame* frame = GetFrame(); michael@0: if (!frame) { michael@0: *aResult = nsRect(); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: bool isRTL = aBodyFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL; michael@0: *aResult = frame->GetRect(); michael@0: aResult->y = aY; michael@0: aResult->height = aHeight; michael@0: if (isRTL) michael@0: aResult->x += aBodyFrame->mAdjustWidth; michael@0: else if (IsLastVisible(aBodyFrame)) michael@0: aResult->width += aBodyFrame->mAdjustWidth; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsTreeColumn::GetXInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult) michael@0: { michael@0: nsIFrame* frame = GetFrame(); michael@0: if (!frame) { michael@0: *aResult = 0; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: *aResult = frame->GetRect().x; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsTreeColumn::GetWidthInTwips(nsTreeBodyFrame* aBodyFrame, nscoord* aResult) michael@0: { michael@0: nsIFrame* frame = GetFrame(); michael@0: if (!frame) { michael@0: *aResult = 0; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: *aResult = frame->GetRect().width; michael@0: if (IsLastVisible(aBodyFrame)) michael@0: *aResult += aBodyFrame->mAdjustWidth; michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetElement(nsIDOMElement** aElement) michael@0: { michael@0: if (mContent) { michael@0: return CallQueryInterface(mContent, aElement); michael@0: } michael@0: *aElement = nullptr; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetColumns(nsITreeColumns** aColumns) michael@0: { michael@0: NS_IF_ADDREF(*aColumns = mColumns); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetX(int32_t* aX) michael@0: { michael@0: nsIFrame* frame = GetFrame(); michael@0: NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); michael@0: michael@0: *aX = nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().x); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetWidth(int32_t* aWidth) michael@0: { michael@0: nsIFrame* frame = GetFrame(); michael@0: NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); michael@0: michael@0: *aWidth = nsPresContext::AppUnitsToIntCSSPixels(frame->GetRect().width); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetId(nsAString& aId) michael@0: { michael@0: aId = GetId(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetIdConst(const char16_t** aIdConst) michael@0: { michael@0: *aIdConst = mId.get(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetAtom(nsIAtom** aAtom) michael@0: { michael@0: NS_IF_ADDREF(*aAtom = GetAtom()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetIndex(int32_t* aIndex) michael@0: { michael@0: *aIndex = GetIndex(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetPrimary(bool* aPrimary) michael@0: { michael@0: *aPrimary = IsPrimary(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetCycler(bool* aCycler) michael@0: { michael@0: *aCycler = IsCycler(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetEditable(bool* aEditable) michael@0: { michael@0: *aEditable = IsEditable(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetSelectable(bool* aSelectable) michael@0: { michael@0: *aSelectable = IsSelectable(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetType(int16_t* aType) michael@0: { michael@0: *aType = GetType(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetNext(nsITreeColumn** _retval) michael@0: { michael@0: NS_IF_ADDREF(*_retval = GetNext()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::GetPrevious(nsITreeColumn** _retval) michael@0: { michael@0: NS_IF_ADDREF(*_retval = GetPrevious()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumn::Invalidate() michael@0: { michael@0: nsIFrame* frame = GetFrame(); michael@0: NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); michael@0: michael@0: // Fetch the Id. michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mId); michael@0: michael@0: // If we have an Id, cache the Id as an atom. michael@0: if (!mId.IsEmpty()) { michael@0: mAtom = do_GetAtom(mId); michael@0: } michael@0: michael@0: // Cache our index. michael@0: nsTreeUtils::GetColumnIndex(mContent, &mIndex); michael@0: michael@0: const nsStyleVisibility* vis = frame->StyleVisibility(); michael@0: michael@0: // Cache our text alignment policy. michael@0: const nsStyleText* textStyle = frame->StyleText(); michael@0: michael@0: mTextAlignment = textStyle->mTextAlign; michael@0: // DEFAULT or END alignment sometimes means RIGHT michael@0: if ((mTextAlignment == NS_STYLE_TEXT_ALIGN_DEFAULT && michael@0: vis->mDirection == NS_STYLE_DIRECTION_RTL) || michael@0: (mTextAlignment == NS_STYLE_TEXT_ALIGN_END && michael@0: vis->mDirection == NS_STYLE_DIRECTION_LTR)) { michael@0: mTextAlignment = NS_STYLE_TEXT_ALIGN_RIGHT; michael@0: } else if (mTextAlignment == NS_STYLE_TEXT_ALIGN_DEFAULT || michael@0: mTextAlignment == NS_STYLE_TEXT_ALIGN_END) { michael@0: mTextAlignment = NS_STYLE_TEXT_ALIGN_LEFT; michael@0: } michael@0: michael@0: // Figure out if we're the primary column (that has to have indentation michael@0: // and twisties drawn. michael@0: mIsPrimary = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::primary, michael@0: nsGkAtoms::_true, eCaseMatters); michael@0: michael@0: // Figure out if we're a cycling column (one that doesn't cause a selection michael@0: // to happen). michael@0: mIsCycler = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::cycler, michael@0: nsGkAtoms::_true, eCaseMatters); michael@0: michael@0: mIsEditable = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::editable, michael@0: nsGkAtoms::_true, eCaseMatters); michael@0: michael@0: mIsSelectable = !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::selectable, michael@0: nsGkAtoms::_false, eCaseMatters); michael@0: michael@0: mOverflow = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::overflow, michael@0: nsGkAtoms::_true, eCaseMatters); michael@0: michael@0: // Figure out our column type. Default type is text. michael@0: mType = nsITreeColumn::TYPE_TEXT; michael@0: static nsIContent::AttrValuesArray typestrings[] = michael@0: {&nsGkAtoms::checkbox, &nsGkAtoms::progressmeter, nullptr}; michael@0: switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type, michael@0: typestrings, eCaseMatters)) { michael@0: case 0: mType = nsITreeColumn::TYPE_CHECKBOX; break; michael@0: case 1: mType = nsITreeColumn::TYPE_PROGRESSMETER; break; michael@0: } michael@0: michael@0: // Fetch the crop style. michael@0: mCropStyle = 0; michael@0: static nsIContent::AttrValuesArray cropstrings[] = michael@0: {&nsGkAtoms::center, &nsGkAtoms::left, &nsGkAtoms::start, nullptr}; michael@0: switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::crop, michael@0: cropstrings, eCaseMatters)) { michael@0: case 0: michael@0: mCropStyle = 1; michael@0: break; michael@0: case 1: michael@0: case 2: michael@0: mCropStyle = 2; michael@0: break; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: nsTreeColumns::nsTreeColumns(nsTreeBodyFrame* aTree) michael@0: : mTree(aTree), michael@0: mFirstColumn(nullptr) michael@0: { michael@0: SetIsDOMBinding(); michael@0: } michael@0: michael@0: nsTreeColumns::~nsTreeColumns() michael@0: { michael@0: nsTreeColumns::InvalidateColumns(); michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsTreeColumns) michael@0: michael@0: // QueryInterface implementation for nsTreeColumns michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTreeColumns) michael@0: NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY michael@0: NS_INTERFACE_MAP_ENTRY(nsITreeColumns) michael@0: NS_INTERFACE_MAP_ENTRY(nsISupports) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTreeColumns) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTreeColumns) michael@0: michael@0: nsIContent* michael@0: nsTreeColumns::GetParentObject() const michael@0: { michael@0: return mTree ? mTree->GetBaseElement() : nullptr; michael@0: } michael@0: michael@0: /* virtual */ JSObject* michael@0: nsTreeColumns::WrapObject(JSContext* aCx) michael@0: { michael@0: return dom::TreeColumnsBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: nsITreeBoxObject* michael@0: nsTreeColumns::GetTree() const michael@0: { michael@0: return mTree ? mTree->GetTreeBoxObject() : nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetTree(nsITreeBoxObject** _retval) michael@0: { michael@0: NS_IF_ADDREF(*_retval = GetTree()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint32_t michael@0: nsTreeColumns::Count() michael@0: { michael@0: EnsureColumns(); michael@0: uint32_t count = 0; michael@0: for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) { michael@0: ++count; michael@0: } michael@0: return count; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetCount(int32_t* _retval) michael@0: { michael@0: *_retval = Count(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetLength(int32_t* _retval) michael@0: { michael@0: *_retval = Length(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetFirstColumn(nsITreeColumn** _retval) michael@0: { michael@0: NS_IF_ADDREF(*_retval = GetFirstColumn()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsTreeColumn* michael@0: nsTreeColumns::GetLastColumn() michael@0: { michael@0: EnsureColumns(); michael@0: nsTreeColumn* currCol = mFirstColumn; michael@0: while (currCol) { michael@0: nsTreeColumn* next = currCol->GetNext(); michael@0: if (!next) { michael@0: return currCol; michael@0: } michael@0: currCol = next; michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetLastColumn(nsITreeColumn** _retval) michael@0: { michael@0: NS_IF_ADDREF(*_retval = GetLastColumn()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetPrimaryColumn(nsITreeColumn** _retval) michael@0: { michael@0: NS_IF_ADDREF(*_retval = GetPrimaryColumn()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsTreeColumn* michael@0: nsTreeColumns::GetSortedColumn() michael@0: { michael@0: EnsureColumns(); michael@0: for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) { michael@0: if (currCol->mContent && michael@0: nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None, michael@0: nsGkAtoms::sortDirection)) { michael@0: return currCol; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetSortedColumn(nsITreeColumn** _retval) michael@0: { michael@0: NS_IF_ADDREF(*_retval = GetSortedColumn()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsTreeColumn* michael@0: nsTreeColumns::GetKeyColumn() michael@0: { michael@0: EnsureColumns(); michael@0: michael@0: nsTreeColumn* first = nullptr; michael@0: nsTreeColumn* primary = nullptr; michael@0: nsTreeColumn* sorted = nullptr; michael@0: michael@0: for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) { michael@0: // Skip hidden columns. michael@0: if (!currCol->mContent || michael@0: currCol->mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden, michael@0: nsGkAtoms::_true, eCaseMatters)) michael@0: continue; michael@0: michael@0: // Skip non-text column michael@0: if (currCol->GetType() != nsITreeColumn::TYPE_TEXT) michael@0: continue; michael@0: michael@0: if (!first) michael@0: first = currCol; michael@0: michael@0: if (nsContentUtils::HasNonEmptyAttr(currCol->mContent, kNameSpaceID_None, michael@0: nsGkAtoms::sortDirection)) { michael@0: // Use sorted column as the key. michael@0: sorted = currCol; michael@0: break; michael@0: } michael@0: michael@0: if (currCol->IsPrimary()) michael@0: if (!primary) michael@0: primary = currCol; michael@0: } michael@0: michael@0: if (sorted) michael@0: return sorted; michael@0: if (primary) michael@0: return primary; michael@0: return first; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetKeyColumn(nsITreeColumn** _retval) michael@0: { michael@0: NS_IF_ADDREF(*_retval = GetKeyColumn()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsTreeColumn* michael@0: nsTreeColumns::GetColumnFor(dom::Element* aElement) michael@0: { michael@0: EnsureColumns(); michael@0: for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) { michael@0: if (currCol->mContent == aElement) { michael@0: return currCol; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetColumnFor(nsIDOMElement* aElement, nsITreeColumn** _retval) michael@0: { michael@0: nsCOMPtr element = do_QueryInterface(aElement); michael@0: NS_ADDREF(*_retval = GetColumnFor(element)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsTreeColumn* michael@0: nsTreeColumns::NamedGetter(const nsAString& aId, bool& aFound) michael@0: { michael@0: EnsureColumns(); michael@0: for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) { michael@0: if (currCol->GetId().Equals(aId)) { michael@0: aFound = true; michael@0: return currCol; michael@0: } michael@0: } michael@0: aFound = false; michael@0: return nullptr; michael@0: } michael@0: michael@0: bool michael@0: nsTreeColumns::NameIsEnumerable(const nsAString& aName) michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: nsTreeColumn* michael@0: nsTreeColumns::GetNamedColumn(const nsAString& aId) michael@0: { michael@0: bool dummy; michael@0: return NamedGetter(aId, dummy); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetNamedColumn(const nsAString& aId, nsITreeColumn** _retval) michael@0: { michael@0: NS_IF_ADDREF(*_retval = GetNamedColumn(aId)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsTreeColumns::GetSupportedNames(unsigned, nsTArray& aNames) michael@0: { michael@0: for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) { michael@0: aNames.AppendElement(currCol->GetId()); michael@0: } michael@0: } michael@0: michael@0: michael@0: nsTreeColumn* michael@0: nsTreeColumns::IndexedGetter(uint32_t aIndex, bool& aFound) michael@0: { michael@0: EnsureColumns(); michael@0: for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) { michael@0: if (currCol->GetIndex() == static_cast(aIndex)) { michael@0: aFound = true; michael@0: return currCol; michael@0: } michael@0: } michael@0: aFound = false; michael@0: return nullptr; michael@0: } michael@0: michael@0: nsTreeColumn* michael@0: nsTreeColumns::GetColumnAt(uint32_t aIndex) michael@0: { michael@0: bool dummy; michael@0: return IndexedGetter(aIndex, dummy); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::GetColumnAt(int32_t aIndex, nsITreeColumn** _retval) michael@0: { michael@0: NS_IF_ADDREF(*_retval = GetColumnAt(static_cast(aIndex))); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::InvalidateColumns() michael@0: { michael@0: for (nsTreeColumn* currCol = mFirstColumn; currCol; michael@0: currCol = currCol->GetNext()) { michael@0: currCol->SetColumns(nullptr); michael@0: } michael@0: NS_IF_RELEASE(mFirstColumn); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsTreeColumns::RestoreNaturalOrder() michael@0: { michael@0: if (!mTree) michael@0: return NS_OK; michael@0: michael@0: nsIContent* content = mTree->GetBaseElement(); michael@0: michael@0: // Strong ref, since we'll be setting attributes michael@0: nsCOMPtr colsContent = michael@0: nsTreeUtils::GetImmediateChild(content, nsGkAtoms::treecols); michael@0: if (!colsContent) michael@0: return NS_OK; michael@0: michael@0: for (uint32_t i = 0; i < colsContent->GetChildCount(); ++i) { michael@0: nsCOMPtr child = colsContent->GetChildAt(i); michael@0: nsAutoString ordinal; michael@0: ordinal.AppendInt(i); michael@0: child->SetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, ordinal, true); michael@0: } michael@0: michael@0: nsTreeColumns::InvalidateColumns(); michael@0: michael@0: if (mTree) { michael@0: mTree->Invalidate(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsTreeColumn* michael@0: nsTreeColumns::GetPrimaryColumn() michael@0: { michael@0: EnsureColumns(); michael@0: for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) { michael@0: if (currCol->IsPrimary()) { michael@0: return currCol; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: nsTreeColumns::EnsureColumns() michael@0: { michael@0: if (mTree && !mFirstColumn) { michael@0: nsIContent* treeContent = mTree->GetBaseElement(); michael@0: nsIContent* colsContent = michael@0: nsTreeUtils::GetDescendantChild(treeContent, nsGkAtoms::treecols); michael@0: if (!colsContent) michael@0: return; michael@0: michael@0: nsIContent* colContent = michael@0: nsTreeUtils::GetDescendantChild(colsContent, nsGkAtoms::treecol); michael@0: if (!colContent) michael@0: return; michael@0: michael@0: nsIFrame* colFrame = colContent->GetPrimaryFrame(); michael@0: if (!colFrame) michael@0: return; michael@0: michael@0: colFrame = colFrame->GetParent(); michael@0: if (!colFrame) michael@0: return; michael@0: michael@0: colFrame = colFrame->GetFirstPrincipalChild(); michael@0: if (!colFrame) michael@0: return; michael@0: michael@0: // Now that we have the first visible column, michael@0: // we can enumerate the columns in visible order michael@0: nsTreeColumn* currCol = nullptr; michael@0: while (colFrame) { michael@0: nsIContent* colContent = colFrame->GetContent(); michael@0: michael@0: if (colContent->NodeInfo()->Equals(nsGkAtoms::treecol, michael@0: kNameSpaceID_XUL)) { michael@0: // Create a new column structure. michael@0: nsTreeColumn* col = new nsTreeColumn(this, colContent); michael@0: if (!col) michael@0: return; michael@0: michael@0: if (currCol) { michael@0: currCol->SetNext(col); michael@0: col->SetPrevious(currCol); michael@0: } michael@0: else { michael@0: NS_ADDREF(mFirstColumn = col); michael@0: } michael@0: currCol = col; michael@0: } michael@0: michael@0: colFrame = colFrame->GetNextSibling(); michael@0: } michael@0: } michael@0: }