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 "nsCOMPtr.h" michael@0: #include "nsTreeColFrame.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsIContent.h" michael@0: #include "nsStyleContext.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsIBoxObject.h" michael@0: #include "nsTreeBoxObject.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsITreeBoxObject.h" michael@0: #include "nsITreeColumns.h" michael@0: #include "nsIDOMXULTreeElement.h" michael@0: #include "nsDisplayList.h" michael@0: #include "nsTreeBodyFrame.h" michael@0: michael@0: // michael@0: // NS_NewTreeColFrame michael@0: // michael@0: // Creates a new col frame michael@0: // michael@0: nsIFrame* michael@0: NS_NewTreeColFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsTreeColFrame(aPresShell, aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsTreeColFrame) michael@0: michael@0: // Destructor michael@0: nsTreeColFrame::~nsTreeColFrame() michael@0: { michael@0: } michael@0: michael@0: void michael@0: nsTreeColFrame::Init(nsIContent* aContent, michael@0: nsIFrame* aParent, michael@0: nsIFrame* aPrevInFlow) michael@0: { michael@0: nsBoxFrame::Init(aContent, aParent, aPrevInFlow); michael@0: InvalidateColumns(); michael@0: } michael@0: michael@0: void michael@0: nsTreeColFrame::DestroyFrom(nsIFrame* aDestructRoot) michael@0: { michael@0: InvalidateColumns(false); michael@0: nsBoxFrame::DestroyFrom(aDestructRoot); michael@0: } michael@0: michael@0: class nsDisplayXULTreeColSplitterTarget : public nsDisplayItem { michael@0: public: michael@0: nsDisplayXULTreeColSplitterTarget(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame) : michael@0: nsDisplayItem(aBuilder, aFrame) { michael@0: MOZ_COUNT_CTOR(nsDisplayXULTreeColSplitterTarget); michael@0: } michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: virtual ~nsDisplayXULTreeColSplitterTarget() { michael@0: MOZ_COUNT_DTOR(nsDisplayXULTreeColSplitterTarget); michael@0: } michael@0: #endif michael@0: michael@0: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, michael@0: nsTArray *aOutFrames) MOZ_OVERRIDE; michael@0: NS_DISPLAY_DECL_NAME("XULTreeColSplitterTarget", TYPE_XUL_TREE_COL_SPLITTER_TARGET) michael@0: }; michael@0: michael@0: void michael@0: nsDisplayXULTreeColSplitterTarget::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) michael@0: { michael@0: nsRect rect = aRect - ToReferenceFrame(); michael@0: // If we are in either in the first 4 pixels or the last 4 pixels, we're going to michael@0: // do something really strange. Check for an adjacent splitter. michael@0: bool left = false; michael@0: bool right = false; michael@0: if (mFrame->GetSize().width - nsPresContext::CSSPixelsToAppUnits(4) <= rect.XMost()) { michael@0: right = true; michael@0: } else if (nsPresContext::CSSPixelsToAppUnits(4) > rect.x) { michael@0: left = true; michael@0: } michael@0: michael@0: // Swap left and right for RTL trees in order to find the correct splitter michael@0: if (mFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) { michael@0: bool tmp = left; michael@0: left = right; michael@0: right = tmp; michael@0: } michael@0: michael@0: if (left || right) { michael@0: // We are a header. Look for the correct splitter. michael@0: nsIFrame* child; michael@0: if (left) michael@0: child = mFrame->GetPrevSibling(); michael@0: else michael@0: child = mFrame->GetNextSibling(); michael@0: michael@0: if (child && child->GetContent()->NodeInfo()->Equals(nsGkAtoms::splitter, michael@0: kNameSpaceID_XUL)) { michael@0: aOutFrames->AppendElement(child); michael@0: } michael@0: } michael@0: michael@0: } michael@0: michael@0: void michael@0: nsTreeColFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) michael@0: { michael@0: if (!aBuilder->IsForEventDelivery()) { michael@0: nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists); michael@0: return; michael@0: } michael@0: michael@0: nsDisplayListCollection set; michael@0: nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, set); michael@0: michael@0: WrapListsInRedirector(aBuilder, set, aLists); michael@0: michael@0: aLists.Content()->AppendNewToTop(new (aBuilder) michael@0: nsDisplayXULTreeColSplitterTarget(aBuilder, this)); michael@0: } michael@0: michael@0: nsresult michael@0: nsTreeColFrame::AttributeChanged(int32_t aNameSpaceID, michael@0: nsIAtom* aAttribute, michael@0: int32_t aModType) michael@0: { michael@0: nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, michael@0: aModType); michael@0: michael@0: if (aAttribute == nsGkAtoms::ordinal || aAttribute == nsGkAtoms::primary) { michael@0: InvalidateColumns(); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: void michael@0: nsTreeColFrame::SetBounds(nsBoxLayoutState& aBoxLayoutState, michael@0: const nsRect& aRect, michael@0: bool aRemoveOverflowArea) { michael@0: nscoord oldWidth = mRect.width; michael@0: michael@0: nsBoxFrame::SetBounds(aBoxLayoutState, aRect, aRemoveOverflowArea); michael@0: if (mRect.width != oldWidth) { michael@0: nsITreeBoxObject* treeBoxObject = GetTreeBoxObject(); michael@0: if (treeBoxObject) { michael@0: treeBoxObject->Invalidate(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsITreeBoxObject* michael@0: nsTreeColFrame::GetTreeBoxObject() michael@0: { michael@0: nsITreeBoxObject* result = nullptr; michael@0: michael@0: nsIContent* parent = mContent->GetParent(); michael@0: if (parent) { michael@0: nsIContent* grandParent = parent->GetParent(); michael@0: nsCOMPtr treeElement = do_QueryInterface(grandParent); michael@0: if (treeElement) { michael@0: nsCOMPtr boxObject; michael@0: treeElement->GetBoxObject(getter_AddRefs(boxObject)); michael@0: michael@0: nsCOMPtr treeBoxObject = do_QueryInterface(boxObject); michael@0: result = treeBoxObject.get(); michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: nsTreeColFrame::InvalidateColumns(bool aCanWalkFrameTree) michael@0: { michael@0: nsITreeBoxObject* treeBoxObject = GetTreeBoxObject(); michael@0: if (treeBoxObject) { michael@0: nsCOMPtr columns; michael@0: michael@0: if (aCanWalkFrameTree) { michael@0: treeBoxObject->GetColumns(getter_AddRefs(columns)); michael@0: } else { michael@0: nsTreeBodyFrame* body = static_cast(treeBoxObject)->GetCachedTreeBody(); michael@0: if (body) { michael@0: columns = body->Columns(); michael@0: } michael@0: } michael@0: michael@0: if (columns) michael@0: columns->InvalidateColumns(); michael@0: } michael@0: }