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