diff --git a/layout/xul/base/src/nsTreeBoxObject.cpp b/layout/xul/base/src/nsTreeBoxObject.cpp index 532ad2466ed..2a06b8369b3 100644 --- a/layout/xul/base/src/nsTreeBoxObject.cpp +++ b/layout/xul/base/src/nsTreeBoxObject.cpp @@ -33,6 +33,8 @@ #include "nsIPresContext.h" #include "nsIFrame.h" +//#define XULTREE + // XXX Hack #include "nsTreeOuterFrame.h" @@ -84,6 +86,9 @@ nsTreeBoxObject::~nsTreeBoxObject() nsIFrame* nsTreeBoxObject::GetFrame() { +#ifdef XULTREE + return nsBoxObject::GetFrame(); +#else nsIFrame* frame = nsBoxObject::GetFrame(); if (!frame) return nsnull; @@ -97,6 +102,7 @@ nsTreeBoxObject::GetFrame() return nsnull; return (nsIFrame*)treeFrame; +#endif } /* void ensureIndexIsVisible (in long rowIndex); */ @@ -106,7 +112,7 @@ NS_IMETHODIMP nsTreeBoxObject::EnsureIndexIsVisible(PRInt32 aRowIndex) if (!frame) return NS_OK; - nsITreeFrame* treeFrame = (nsITreeFrame*)frame; + nsCOMPtr treeFrame(do_QueryInterface(frame)); return treeFrame->EnsureRowIsVisible(aRowIndex); } @@ -123,7 +129,7 @@ NS_IMETHODIMP nsTreeBoxObject::GetNextItem(nsIDOMElement *aStartItem, PRInt32 aD if (!frame) return NS_OK; - nsITreeFrame* treeFrame = (nsITreeFrame*)frame; + nsCOMPtr treeFrame(do_QueryInterface(frame)); return treeFrame->GetNextItem(aStartItem, aDelta, aResult); } @@ -135,7 +141,7 @@ NS_IMETHODIMP nsTreeBoxObject::GetPreviousItem(nsIDOMElement *aStartItem, PRInt3 if (!frame) return NS_OK; - nsITreeFrame* treeFrame = (nsITreeFrame*)frame; + nsCOMPtr treeFrame(do_QueryInterface(frame)); return treeFrame->GetPreviousItem(aStartItem, aDelta, aResult); } @@ -154,8 +160,7 @@ NS_IMETHODIMP nsTreeBoxObject::GetIndexOfItem(nsIDOMElement* aElement, PRInt32 * if (!frame) return NS_OK; - nsITreeFrame* treeFrame = (nsITreeFrame*)frame; - + nsCOMPtr treeFrame(do_QueryInterface(frame)); nsCOMPtr presContext; mPresShell->GetPresContext(getter_AddRefs(presContext)); return treeFrame->GetIndexOfItem(presContext, aElement, aResult); diff --git a/layout/xul/base/src/nsXULTreeFrame.cpp b/layout/xul/base/src/nsXULTreeFrame.cpp index 6e3e80dd891..09e37fff1ed 100644 --- a/layout/xul/base/src/nsXULTreeFrame.cpp +++ b/layout/xul/base/src/nsXULTreeFrame.cpp @@ -24,6 +24,10 @@ #include "nsCOMPtr.h" #include "nsXULTreeFrame.h" +#include "nsIScrollableFrame.h" +#include "nsIDOMElement.h" +#include "nsXULTreeOuterGroupFrame.h" +#include "nsXULAtoms.h" // // NS_NewXULTreeFrame @@ -51,9 +55,219 @@ NS_NewXULTreeFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRBool aIsRoo // Constructor nsXULTreeFrame::nsXULTreeFrame(nsIPresShell* aPresShell, PRBool aIsRoot, nsIBoxLayout* aLayoutManager, PRBool aIsHorizontal) :nsBoxFrame(aPresShell, aIsRoot, aLayoutManager, aIsHorizontal) -{} +{ + mPresShell = aPresShell; +} // Destructor nsXULTreeFrame::~nsXULTreeFrame() { } + +NS_IMETHODIMP_(nsrefcnt) +nsXULTreeFrame::AddRef(void) +{ + return NS_OK; +} + +NS_IMETHODIMP_(nsrefcnt) +nsXULTreeFrame::Release(void) +{ + return NS_OK; +} + +// +// QueryInterface +// +NS_INTERFACE_MAP_BEGIN(nsXULTreeFrame) + NS_INTERFACE_MAP_ENTRY(nsITreeFrame) +NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame) + +static void +GetImmediateChild(nsIContent* aParent, nsIAtom* aTag, nsIContent** aResult) +{ + *aResult = nsnull; + PRInt32 childCount; + aParent->ChildCount(childCount); + for (PRInt32 i = 0; i < childCount; i++) { + nsCOMPtr child; + aParent->ChildAt(i, *getter_AddRefs(child)); + nsCOMPtr tag; + child->GetTag(*getter_AddRefs(tag)); + if (aTag == tag.get()) { + *aResult = child; + NS_ADDREF(*aResult); + return; + } + } + + return; +} + +NS_IMETHODIMP +nsXULTreeFrame::EnsureRowIsVisible(PRInt32 aRowIndex) +{ + // Get our treechildren child frame. + nsXULTreeOuterGroupFrame* XULTreeOuterGroup = nsnull; + GetTreeBody(&XULTreeOuterGroup); + + if (!XULTreeOuterGroup) return NS_OK; + + XULTreeOuterGroup->EnsureRowIsVisible(aRowIndex); + return NS_OK; +} + +/* void scrollToIndex (in long rowIndex); */ +NS_IMETHODIMP +nsXULTreeFrame::ScrollToIndex(PRInt32 rowIndex) +{ + // Get our treechildren child frame. + nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; + GetTreeBody(&treeOuterGroup); + + if (!treeOuterGroup) + return NS_OK; // No tree body. Just bail. + + // XXX IMPLEMENT! + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* nsIDOMElement getNextItem (in nsIDOMElement startItem, in long delta); */ +NS_IMETHODIMP +nsXULTreeFrame::GetNextItem(nsIDOMElement *aStartItem, PRInt32 aDelta, nsIDOMElement **aResult) +{ + // Get our treechildren child frame. + nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; + GetTreeBody(&treeOuterGroup); + + if (!treeOuterGroup) + return NS_OK; // No tree body. Just bail. + + nsCOMPtr start(do_QueryInterface(aStartItem)); + nsCOMPtr row; + GetImmediateChild(start, nsXULAtoms::treerow, getter_AddRefs(row)); + + nsCOMPtr result; + treeOuterGroup->FindNextRowContent(aDelta, row, nsnull, getter_AddRefs(result)); + if (!result) + return NS_OK; + + nsCOMPtr parent; + result->GetParent(*getter_AddRefs(parent)); + if (!parent) + return NS_OK; + + nsCOMPtr item(do_QueryInterface(parent)); + *aResult = item; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + +/* nsIDOMElement getPreviousItem (in nsIDOMElement startItem, in long delta); */ +NS_IMETHODIMP +nsXULTreeFrame::GetPreviousItem(nsIDOMElement* aStartItem, PRInt32 aDelta, nsIDOMElement** aResult) +{ + // Get our treechildren child frame. + nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; + GetTreeBody(&treeOuterGroup); + + if (!treeOuterGroup) + return NS_OK; // No tree body. Just bail. + + nsCOMPtr start(do_QueryInterface(aStartItem)); + nsCOMPtr row; + GetImmediateChild(start, nsXULAtoms::treerow, getter_AddRefs(row)); + + nsCOMPtr result; + treeOuterGroup->FindPreviousRowContent(aDelta, row, nsnull, getter_AddRefs(result)); + if (!result) + return NS_OK; + + nsCOMPtr parent; + result->GetParent(*getter_AddRefs(parent)); + if (!parent) + return NS_OK; + + nsCOMPtr item(do_QueryInterface(parent)); + *aResult = item; + NS_IF_ADDREF(*aResult); + + return NS_OK; +} + +/* nsIDOMElement getItemAtIndex (in long index); */ +NS_IMETHODIMP +nsXULTreeFrame::GetItemAtIndex(PRInt32 aIndex, nsIDOMElement **aResult) +{ + *aResult = nsnull; + + // Get our treechildren child frame. + nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; + GetTreeBody(&treeOuterGroup); + + if (!treeOuterGroup) + return NS_OK; // No tree body. Just bail. + + nsCOMPtr result; + treeOuterGroup->FindRowContentAtIndex(aIndex, nsnull, getter_AddRefs(result)); + if (!result) + return NS_OK; + + nsCOMPtr parent; + result->GetParent(*getter_AddRefs(parent)); + if (!parent) + return NS_OK; + + nsCOMPtr item(do_QueryInterface(parent)); + *aResult = item; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + +/* long getIndexOfItem (in nsIDOMElement item); */ +NS_IMETHODIMP +nsXULTreeFrame::GetIndexOfItem(nsIPresContext* aPresContext, nsIDOMElement* aElement, PRInt32* aResult) +{ + // Get our treechildren child frame. + nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull; + GetTreeBody(&treeOuterGroup); + + if (!treeOuterGroup) + return NS_OK; // No tree body. Just bail. + + *aResult = 0; + nsCOMPtr content(do_QueryInterface(aElement)); + nsCOMPtr root; + treeOuterGroup->GetContent(getter_AddRefs(root)); + return treeOuterGroup->IndexOfItem(root, content, PR_TRUE, PR_TRUE, aResult); +} + +void +nsXULTreeFrame::GetTreeBody(nsXULTreeOuterGroupFrame** aResult) +{ + nsCOMPtr child; + PRInt32 count; + mContent->ChildCount(count); + for (PRInt32 i = 0; i < count; i++) { + mContent->ChildAt(i, *getter_AddRefs(child)); + if (child) { + nsCOMPtr tag; + child->GetTag(*getter_AddRefs(tag)); + if (tag && tag.get() == nsXULAtoms::treechildren) { + // This is our actual treechildren frame. + nsIFrame* frame; + mPresShell->GetPrimaryFrameFor(child, &frame); + if (frame) { + nsCOMPtr scroll(do_QueryInterface(frame)); + if (scroll) { + scroll->GetScrolledFrame(nsnull, frame); + } + *aResult = (nsXULTreeOuterGroupFrame*)frame; + return; + } + } + } + } + *aResult = nsnull; +} + diff --git a/layout/xul/base/src/nsXULTreeFrame.h b/layout/xul/base/src/nsXULTreeFrame.h index e5e9cc8d681..eeccd446acc 100644 --- a/layout/xul/base/src/nsXULTreeFrame.h +++ b/layout/xul/base/src/nsXULTreeFrame.h @@ -23,8 +23,12 @@ */ #include "nsBoxFrame.h" +#include "nsITreeFrame.h" -class nsXULTreeFrame : public nsBoxFrame +class nsXULTreeOuterGroupFrame; +class nsIPresShell; + +class nsXULTreeFrame : public nsBoxFrame, public nsITreeFrame { public: friend nsresult NS_NewXULTreeFrame(nsIPresShell* aPresShell, @@ -33,10 +37,22 @@ public: nsIBoxLayout* aLayoutManager = nsnull, PRBool aDefaultHorizontal = PR_TRUE); + NS_DECL_ISUPPORTS + + // nsITreeFrame + NS_IMETHOD EnsureRowIsVisible(PRInt32 aRowIndex); + NS_IMETHOD GetNextItem(nsIDOMElement* aStartItem, PRInt32 aDelta, nsIDOMElement** aResult); + NS_IMETHOD GetPreviousItem(nsIDOMElement* aStartItem, PRInt32 aDelta, nsIDOMElement** aResult); + NS_IMETHOD ScrollToIndex(PRInt32 aRowIndex); + NS_IMETHOD GetItemAtIndex(PRInt32 aIndex, nsIDOMElement** aResult); + NS_IMETHOD GetIndexOfItem(nsIPresContext* aPresContext, nsIDOMElement* aElement, PRInt32* aResult); + protected: nsXULTreeFrame(nsIPresShell* aPresShell, PRBool aIsRoot = nsnull, nsIBoxLayout* aLayoutManager = nsnull, PRBool aDefaultHorizontal = PR_TRUE); virtual ~nsXULTreeFrame(); + void GetTreeBody(nsXULTreeOuterGroupFrame** aResult); + protected: // Data Members - + nsIPresShell* mPresShell; }; // class nsXULTreeFrame diff --git a/layout/xul/base/src/nsXULTreeOuterGroupFrame.cpp b/layout/xul/base/src/nsXULTreeOuterGroupFrame.cpp index 136462f47c3..bf3dbf174d5 100644 --- a/layout/xul/base/src/nsXULTreeOuterGroupFrame.cpp +++ b/layout/xul/base/src/nsXULTreeOuterGroupFrame.cpp @@ -31,6 +31,7 @@ #include "nsIScrollbarFrame.h" #include "nsISupportsArray.h" #include "nsCSSFrameConstructor.h" +#include "nsIDocument.h" #define TICK_FACTOR 50 @@ -698,3 +699,93 @@ nsXULTreeOuterGroupFrame::FindNextRowContent(PRInt32& aDelta, nsIContent* aUpwar // Bail. There's nothing else we can do. } + +void +nsXULTreeOuterGroupFrame::EnsureRowIsVisible(PRInt32 aRowIndex) +{ + PRInt32 rows = GetAvailableHeight()/mRowHeight; + PRInt32 bottomIndex = mCurrentIndex + rows - 1; + + // if row is visible, ignore + if (mCurrentIndex <= aRowIndex && aRowIndex <= bottomIndex) + return; + + // Try to center the new index. + PRInt32 newIndex = aRowIndex - rows/2; + if (newIndex < 0) + newIndex = 0; + + PRInt32 delta = mCurrentIndex > newIndex ? mCurrentIndex - newIndex : newIndex - mCurrentIndex; + PRInt32 up = newIndex < mCurrentIndex; + mCurrentIndex = newIndex; + InternalPositionChanged(up, delta); + + // This change has to happen immediately. + // Flush any pending reflow commands. + nsCOMPtr doc; + mContent->GetDocument(*getter_AddRefs(doc)); + doc->FlushPendingNotifications(); +} + +// walks the DOM to get the zero-based row index of the current content +// note that aContent can be any element, this will get the index of the +// element's parent +NS_IMETHODIMP +nsXULTreeOuterGroupFrame::IndexOfItem(nsIContent* aRoot, nsIContent* aContent, + PRBool aDescendIntoRows, // Invariant + PRBool aParentIsOpen, + PRInt32 *aResult) +{ + PRInt32 childCount=0; + aRoot->ChildCount(childCount); + + nsresult rv; + + PRInt32 childIndex; + for (childIndex=0; childIndex child; + aRoot->ChildAt(childIndex, *getter_AddRefs(child)); + + nsCOMPtr childTag; + child->GetTag(*getter_AddRefs(childTag)); + + // is this it? + if (child.get() == aContent) + return NS_OK; + + // we hit a treerow, count it + if (childTag.get() == nsXULAtoms::treeitem) + (*aResult)++; + + PRBool descend = PR_TRUE; + PRBool parentIsOpen = aParentIsOpen; + + // don't descend into closed children + if (childTag.get() == nsXULAtoms::treechildren && !parentIsOpen) + descend = PR_FALSE; + + // speed optimization - descend into rows only when told + else if (childTag.get() == nsXULAtoms::treerow && !aDescendIntoRows) + descend = PR_FALSE; + + // descend as normally, but remember that the parent is closed! + else if (childTag.get() == nsXULAtoms::treeitem) { + nsAutoString isOpen; + rv = child->GetAttribute(kNameSpaceID_None, nsXULAtoms::open, isOpen); + + if (!isOpen.EqualsWithConversion("true")) + parentIsOpen=PR_FALSE; + } + + // now that we've analyzed the tags, recurse + if (descend) { + rv = IndexOfItem(child, aContent, + aDescendIntoRows, parentIsOpen, aResult); + if (NS_SUCCEEDED(rv)) + return NS_OK; + } + } + + // not found + return NS_ERROR_FAILURE; +} \ No newline at end of file diff --git a/layout/xul/base/src/nsXULTreeOuterGroupFrame.h b/layout/xul/base/src/nsXULTreeOuterGroupFrame.h index fe3b75ca788..d5c111cc13e 100644 --- a/layout/xul/base/src/nsXULTreeOuterGroupFrame.h +++ b/layout/xul/base/src/nsXULTreeOuterGroupFrame.h @@ -127,6 +127,15 @@ public: void FindRowContentAtIndex(PRInt32& aIndex, nsIContent* aParent, nsIContent** aResult); + // This method ensures that a row is onscreen. It will scroll the tree widget such + // that the row is at the top of the screen (if the row was offscreen to start with). + void EnsureRowIsVisible(PRInt32 aRowIndex); + + NS_IMETHOD IndexOfItem(nsIContent* aRoot, nsIContent* aContent, + PRBool aDescendIntoRows, // Invariant + PRBool aParentIsOpen, + PRInt32 *aResult); + NS_IMETHOD InternalPositionChanged(PRBool aUp, PRInt32 aDelta); protected: // Data Members