Keyboard navigation and ensurevisible support for new tree widget. Bug#30511, r=pav

This commit is contained in:
hyatt%netscape.com 2000-06-09 09:13:37 +00:00
Родитель 07f7e211e8
Коммит de97a71ea3
5 изменённых файлов: 343 добавлений и 8 удалений

Просмотреть файл

@ -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<nsITreeFrame> 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<nsITreeFrame> 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<nsITreeFrame> 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<nsITreeFrame> treeFrame(do_QueryInterface(frame));
nsCOMPtr<nsIPresContext> presContext;
mPresShell->GetPresContext(getter_AddRefs(presContext));
return treeFrame->GetIndexOfItem(presContext, aElement, aResult);

Просмотреть файл

@ -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<nsIContent> child;
aParent->ChildAt(i, *getter_AddRefs(child));
nsCOMPtr<nsIAtom> 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<nsIContent> start(do_QueryInterface(aStartItem));
nsCOMPtr<nsIContent> row;
GetImmediateChild(start, nsXULAtoms::treerow, getter_AddRefs(row));
nsCOMPtr<nsIContent> result;
treeOuterGroup->FindNextRowContent(aDelta, row, nsnull, getter_AddRefs(result));
if (!result)
return NS_OK;
nsCOMPtr<nsIContent> parent;
result->GetParent(*getter_AddRefs(parent));
if (!parent)
return NS_OK;
nsCOMPtr<nsIDOMElement> 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<nsIContent> start(do_QueryInterface(aStartItem));
nsCOMPtr<nsIContent> row;
GetImmediateChild(start, nsXULAtoms::treerow, getter_AddRefs(row));
nsCOMPtr<nsIContent> result;
treeOuterGroup->FindPreviousRowContent(aDelta, row, nsnull, getter_AddRefs(result));
if (!result)
return NS_OK;
nsCOMPtr<nsIContent> parent;
result->GetParent(*getter_AddRefs(parent));
if (!parent)
return NS_OK;
nsCOMPtr<nsIDOMElement> 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<nsIContent> result;
treeOuterGroup->FindRowContentAtIndex(aIndex, nsnull, getter_AddRefs(result));
if (!result)
return NS_OK;
nsCOMPtr<nsIContent> parent;
result->GetParent(*getter_AddRefs(parent));
if (!parent)
return NS_OK;
nsCOMPtr<nsIDOMElement> 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<nsIContent> content(do_QueryInterface(aElement));
nsCOMPtr<nsIContent> root;
treeOuterGroup->GetContent(getter_AddRefs(root));
return treeOuterGroup->IndexOfItem(root, content, PR_TRUE, PR_TRUE, aResult);
}
void
nsXULTreeFrame::GetTreeBody(nsXULTreeOuterGroupFrame** aResult)
{
nsCOMPtr<nsIContent> child;
PRInt32 count;
mContent->ChildCount(count);
for (PRInt32 i = 0; i < count; i++) {
mContent->ChildAt(i, *getter_AddRefs(child));
if (child) {
nsCOMPtr<nsIAtom> 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<nsIScrollableFrame> scroll(do_QueryInterface(frame));
if (scroll) {
scroll->GetScrolledFrame(nsnull, frame);
}
*aResult = (nsXULTreeOuterGroupFrame*)frame;
return;
}
}
}
}
*aResult = nsnull;
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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<nsIDocument> 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<childCount; childIndex++) {
nsCOMPtr<nsIContent> child;
aRoot->ChildAt(childIndex, *getter_AddRefs(child));
nsCOMPtr<nsIAtom> 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;
}

Просмотреть файл

@ -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