Tree/grid work. Bug#30511. r=danm

This commit is contained in:
hyatt%netscape.com 2000-06-06 23:13:05 +00:00
Родитель bf84b6aaa4
Коммит 330c612d46
19 изменённых файлов: 1852 добавлений и 9 удалений

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

@ -30,6 +30,10 @@ MODULE = layout
LIBRARY_NAME = raptorxulbase_s
CPPSRCS = \
nsTreeLayout.cpp \
nsXULTreeSliceFrame.cpp \
nsXULTreeGroupFrame.cpp \
nsXULTreeOuterGroupFrame.cpp \
nsBrowserBoxObject.cpp \
nsIFrameBoxObject.cpp \
nsEditorBoxObject.cpp \

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

@ -78,8 +78,10 @@ CPPSRCS= \
nsTreeItemDragCapturer.cpp \
nsXULTreeFrame.cpp \
nsXULTreeGroupFrame.cpp \
nsXULTreeOuterGroupFrame.cpp \
nsXULTreeSliceFrame.cpp \
nsXULTreeCellFrame.cpp \
nsTreeLayout.cpp \
nsSpinnerFrame.cpp \
nsScrollbarFrame.cpp \
nsScrollbarButtonFrame.cpp \
@ -147,8 +149,10 @@ CPP_OBJS= \
.\$(OBJDIR)\nsTreeItemDragCapturer.obj \
.\$(OBJDIR)\nsXULTreeFrame.obj \
.\$(OBJDIR)\nsXULTreeGroupFrame.obj \
.\$(OBJDIR)\nsXULTreeOuterGroupFrame.obj \
.\$(OBJDIR)\nsXULTreeSliceFrame.obj \
.\$(OBJDIR)\nsXULTreeCellFrame.obj \
.\$(OBJDIR)\nsTreeLayout.obj \
.\$(OBJDIR)\nsSpinnerFrame.obj \
.\$(OBJDIR)\nsScrollbarFrame.obj \
.\$(OBJDIR)\nsScrollbarButtonFrame.obj \

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

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Original Author: David W. Hyatt (hyatt@netscape.com)
*
* Contributor(s):
*/
#ifndef nsIScrollbarFrame_h___
#define nsIScrollbarFrame_h___
// {9A6B0416-4A5D-4550-BEB5-C94D18A69A94}
#define NS_ISCROLLBARFRAME_IID \
{ 0x9a6b0416, 0x4a5d, 0x4550, { 0xbe, 0xb5, 0xc9, 0x4d, 0x18, 0xa6, 0x9a, 0x94 } }
static NS_DEFINE_IID(kIScrollbarFrameIID, NS_ISCROLLBARFRAME_IID);
class nsIScrollbarMediator;
class nsIScrollbarFrame : public nsISupports {
public:
static const nsIID& GetIID() { static nsIID iid = NS_ISCROLLBARFRAME_IID; return iid; }
NS_IMETHOD GetScrollbarMediator(nsIScrollbarMediator** aResult) = 0;
NS_IMETHOD SetScrollbarMediator(nsIScrollbarMediator* aMediator) = 0;
};
#endif

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

@ -0,0 +1,44 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Original Author: David W. Hyatt (hyatt@netscape.com)
*
* Contributor(s):
*/
#ifndef nsIScrollbarMediator_h___
#define nsIScrollbarMediator_h___
// {351C003A-E8F7-4d10-8BFA-635C9860D650}
#define NS_ISCROLLBARMEDIATOR_IID \
{ 0x351c003a, 0xe8f7, 0x4d10, { 0x8b, 0xfa, 0x63, 0x5c, 0x98, 0x60, 0xd6, 0x50 } }
static NS_DEFINE_IID(kIScrollbarMediatorIID, NS_ISCROLLBARMEDIATOR_IID);
class nsIScrollbarMediator : public nsISupports {
public:
static const nsIID& GetIID() { static nsIID iid = NS_ISCROLLBARMEDIATOR_IID; return iid; }
NS_IMETHOD PositionChanged(PRInt32 aOldIndex, PRInt32 aNewIndex) = 0;
NS_IMETHOD ScrollbarButtonPressed(PRInt32 aOldIndex, PRInt32 aNewIndex) = 0;
};
#endif

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

@ -0,0 +1,44 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Original Author: David W. Hyatt (hyatt@netscape.com)
*
* Contributor(s):
*/
#ifndef nsIXULTreeSlice_h___
#define nsIXULTreeSlice_h___
#include "nsISupports.h"
// {B74EA9FF-0B55-413f-8DBF-AA5FE431731F}
#define NS_ITREESLICE_IID { 0xb74ea9ff, 0xb55, 0x413f, { 0x8d, 0xbf, 0xaa, 0x5f, 0xe4, 0x31, 0x73, 0x1f } }
class nsIXULTreeSlice : public nsISupports
{
public:
static const nsIID& GetIID() { static nsIID iid = NS_ITREESLICE_IID; return iid; }
NS_IMETHOD IsOutermostFrame(PRBool* aResult) = 0;
NS_IMETHOD IsGroupFrame(PRBool* aResult) = 0;
NS_IMETHOD IsRowFrame(PRBool* aResult) = 0;
}; // class nsIXULTreeSlice
#endif

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

@ -39,6 +39,8 @@
#include "nsXULAtoms.h"
#include "nsIReflowCommand.h"
#include "nsSliderFrame.h"
#include "nsIScrollbarFrame.h"
#include "nsIScrollbarMediator.h"
#include "nsRepeatService.h"
//
@ -145,6 +147,7 @@ nsScrollbarButtonFrame::MouseClicked()
// get the current pos
PRInt32 curpos = nsSliderFrame::GetCurrentPosition(content);
PRInt32 oldpos = curpos;
// get the max pos
PRInt32 maxpos = nsSliderFrame::GetMaxPosition(content);
@ -168,6 +171,16 @@ nsScrollbarButtonFrame::MouseClicked()
else if (curpos > maxpos)
curpos = maxpos;
nsCOMPtr<nsIScrollbarFrame> sb(do_QueryInterface(scrollbar));
if (sb) {
nsCOMPtr<nsIScrollbarMediator> m;
sb->GetScrollbarMediator(getter_AddRefs(m));
if (m) {
m->ScrollbarButtonPressed(oldpos, curpos);
return;
}
}
// set the current position of the slider.
char v[100];
sprintf(v, "%d", curpos);

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

@ -266,6 +266,7 @@ NS_NewScrollbarFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame )
// QueryInterface
//
NS_INTERFACE_MAP_BEGIN(nsScrollbarFrame)
NS_INTERFACE_MAP_ENTRY(nsIScrollbarFrame)
NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)

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

@ -29,15 +29,17 @@
#include "nsBoxFrame.h"
#include "nsIScrollbarFrame.h"
class nsISupportsArray;
class nsIScrollbarMediator;
nsresult NS_NewScrollbarFrame(nsIPresShell* aPresShell, nsIFrame** aResult) ;
class nsScrollbarFrame : public nsBoxFrame
class nsScrollbarFrame : public nsBoxFrame, public nsIScrollbarFrame
{
public:
nsScrollbarFrame(nsIPresShell* aShell):nsBoxFrame(aShell) {}
nsScrollbarFrame(nsIPresShell* aShell):nsBoxFrame(aShell), mScrollbarMediator(nsnull) {}
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsString& aResult) const {
@ -79,6 +81,12 @@ public:
nsIFrame* aPrevInFlow);
// nsIScrollbarFrame
NS_IMETHOD SetScrollbarMediator(nsIScrollbarMediator* aMediator) { mScrollbarMediator = aMediator; return NS_OK; };
NS_IMETHOD GetScrollbarMediator(nsIScrollbarMediator** aResult) { *aResult = mScrollbarMediator; return NS_OK; };
private:
nsIScrollbarMediator* mScrollbarMediator;
}; // class nsScrollbarFrame
#endif

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

@ -54,6 +54,8 @@
#include "nsTitledButtonFrame.h"
#include "nsScrollbarButtonFrame.h"
#include "nsIScrollbarListener.h"
#include "nsIScrollbarMediator.h"
#include "nsIScrollbarFrame.h"
#include "nsISupportsArray.h"
#include "nsIXMLContent.h"
#include "nsXULAtoms.h"
@ -679,6 +681,18 @@ nsSliderFrame::SetCurrentPosition(nsIContent* scrollbar, nsIFrame* aThumbFrame,
else if (newpos < 0)
newpos = 0;
nsIBox* scrollbarBox = GetScrollbar();
nsCOMPtr<nsIScrollbarFrame> scrollbarFrame(do_QueryInterface(scrollbarBox));
if (scrollbarFrame) {
// See if we have a mediator.
nsCOMPtr<nsIScrollbarMediator> mediator;
scrollbarFrame->GetScrollbarMediator(getter_AddRefs(mediator));
if (mediator) {
mediator->PositionChanged(GetCurrentPosition(scrollbar), newpos);
return;
}
}
char ch[100];
sprintf(ch,"%d", newpos);

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

@ -163,7 +163,7 @@ nsTempleLayout::BuildBoxSizeList(nsIBox* aBox, nsBoxLayoutState& aState, nsBoxSi
if (count == 0)
aFirst = first;
else
else if (aLast)
(aLast)->next = first;
aLast = last;
}
@ -192,8 +192,11 @@ nsTempleLayout::BuildBoxSizeList(nsIBox* aBox, nsBoxLayoutState& aState, nsBoxSi
PRBool isHorizontal = PR_FALSE;
aBox->GetOrientation(isHorizontal);
aFirst->Add(leftMargin,isHorizontal);
aLast->Add(rightMargin,isHorizontal);
if (aFirst)
aFirst->Add(leftMargin,isHorizontal);
if (aLast)
aLast->Add(rightMargin,isHorizontal);
return NS_OK;
}

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

@ -123,6 +123,7 @@ PRBool nsTreeFrame::IsAutoLayout(const nsHTMLReflowState* aReflowState)
void nsTreeFrame::SetSelection(nsIPresContext* aPresContext, nsTreeCellFrame* aFrame)
{
/*
nsCOMPtr<nsIContent> cellContent;
aFrame->GetContent(getter_AddRefs(cellContent));
@ -143,10 +144,12 @@ void nsTreeFrame::SetSelection(nsIPresContext* aPresContext, nsTreeCellFrame* aF
treeElement->SelectItem(itemElement);
mContent->UnsetAttribute(kNameSpaceID_None, kSuppressSelectChange, PR_FALSE);
treeElement->SelectCell(cellElement);
*/
}
void nsTreeFrame::ToggleSelection(nsIPresContext* aPresContext, nsTreeCellFrame* aFrame)
{
/*
nsCOMPtr<nsIContent> cellContent;
aFrame->GetContent(getter_AddRefs(cellContent));
@ -165,10 +168,12 @@ void nsTreeFrame::ToggleSelection(nsIPresContext* aPresContext, nsTreeCellFrame*
treeElement->ToggleItemSelection(itemElement);
mContent->UnsetAttribute(kNameSpaceID_None, kSuppressSelectChange, PR_FALSE);
treeElement->ToggleCellSelection(cellElement);
*/
}
void nsTreeFrame::RangedSelection(nsIPresContext* aPresContext, nsTreeCellFrame* aEndFrame)
{
/*
nsCOMPtr<nsIContent> endCellContent;
aEndFrame->GetContent(getter_AddRefs(endCellContent));
if (!endCellContent)
@ -188,6 +193,7 @@ void nsTreeFrame::RangedSelection(nsIPresContext* aPresContext, nsTreeCellFrame*
nsCOMPtr<nsIDOMXULElement> endElement = do_QueryInterface(endItemContent);
treeElement->SelectItemRange(nsnull, endElement);
*/
}
void

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

@ -0,0 +1,208 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
// Original Author:
// David W Hyatt (hyatt@netscape.com)
// Netscape Communications
//
// See documentation in associated header file
//
#include "nsTreeLayout.h"
#include "nsBoxLayoutState.h"
#include "nsIBox.h"
#include "nsIScrollableFrame.h"
#include "nsBox.h"
// ------ nsTreeLayout ------
nsresult
NS_NewTreeLayout( nsIPresShell* aPresShell, nsCOMPtr<nsIBoxLayout>& aNewLayout)
{
aNewLayout = new nsTreeLayout(aPresShell);
return NS_OK;
}
nsTreeLayout::nsTreeLayout(nsIPresShell* aPresShell):nsTempleLayout(aPresShell)
{
}
nsXULTreeOuterGroupFrame* nsTreeLayout::GetOuterFrame(nsIBox* aBox)
{
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(aBox));
if (slice) {
PRBool outer;
slice->IsOutermostFrame(&outer);
if (outer)
return (nsXULTreeOuterGroupFrame*) aBox;
}
return nsnull;
}
nsXULTreeGroupFrame* nsTreeLayout::GetGroupFrame(nsIBox* aBox)
{
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(aBox));
if (slice) {
PRBool group;
slice->IsGroupFrame(&group);
if (group)
return (nsXULTreeGroupFrame*) aBox;
}
return nsnull;
}
nsXULTreeSliceFrame* nsTreeLayout::GetRowFrame(nsIBox* aBox)
{
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(aBox));
if (slice) {
PRBool row;
slice->IsRowFrame(&row);
if (row)
return (nsXULTreeSliceFrame*) aBox;
}
return nsnull;
}
NS_IMETHODIMP
nsTreeLayout::GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState, nsSize& aSize)
{
nsresult rv = nsTempleLayout::GetPrefSize(aBox, aBoxLayoutState, aSize);
nsXULTreeOuterGroupFrame* frame = GetOuterFrame(aBox);
if (frame)
aSize.height = frame->GetRowCount() * frame->GetRowHeightTwips();
return rv;
}
NS_IMETHODIMP
nsTreeLayout::GetMinSize(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState, nsSize& aSize)
{
nsresult rv = nsTempleLayout::GetMinSize(aBox, aBoxLayoutState, aSize);
nsXULTreeOuterGroupFrame* frame = GetOuterFrame(aBox);
if (frame)
aSize.height = frame->GetRowCount() * frame->GetRowHeightTwips();
return rv;
}
NS_IMETHODIMP
nsTreeLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState, nsSize& aSize)
{
nsresult rv = nsTempleLayout::GetMaxSize(aBox, aBoxLayoutState, aSize);
nsXULTreeOuterGroupFrame* frame = GetOuterFrame(aBox);
if (frame)
aSize.height = frame->GetRowCount() * frame->GetRowHeightTwips();
return rv;
}
NS_IMETHODIMP
nsTreeLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState)
{
// Get the start y position.
nsXULTreeGroupFrame* frame = GetGroupFrame(aBox);
if (!frame) {
NS_ERROR("Frame encountered that isn't a tree row group!\n");
return NS_ERROR_FAILURE;
}
// Get our client rect.
nsRect clientRect;
aBox->GetClientRect(clientRect);
// Get the starting y position and the remaining available
// height.
nscoord availableHeight = frame->GetAvailableHeight();
nscoord yOffset = frame->GetYPosition();
nscoord currY = 0;
if (availableHeight <= 0)
return NS_OK;
// Walk our frames, building them dynamically as needed.
nsIBox* box = frame->GetFirstTreeBox();
while (box) {
// If this box is dirty or if it has dirty children, we
// call layout on it.
PRBool dirty = PR_FALSE;
PRBool dirtyChildren = PR_FALSE;
box->IsDirty(dirty);
box->HasDirtyChildren(dirtyChildren);
PRBool sizeChanged = PR_FALSE;
nsRect childRect;
box->GetContentRect(childRect);
nsMargin margin(0,0,0,0);
box->GetMargin(margin);
childRect.Inflate(margin);
nsSize size;
box->NeedsRecalc();
box->GetPrefSize(aState, size);
if (clientRect.width != childRect.width || size.height != childRect.height)
sizeChanged = PR_TRUE;
if (sizeChanged || dirty || dirtyChildren || aState.GetLayoutReason() == nsBoxLayoutState::Initial) {
PRBool isRow = PR_TRUE;
nsXULTreeGroupFrame* childGroup = GetGroupFrame(box);
if (childGroup) {
// Set the available height.
childGroup->SetAvailableHeight(availableHeight);
isRow = PR_FALSE;
}
childRect.width = clientRect.width;
box->GetMargin(margin);
childRect.Deflate(margin);
box->SetBounds(aState, childRect);
box->Layout(aState);
// Get the prefsize.
nsSize size;
box->NeedsRecalc();
box->GetPrefSize(aState, size);
childRect.height = size.height;
box->SetBounds(aState, childRect);
if (isRow) {
frame->GetOuterFrame()->SetRowHeight(size.height);
}
}
// Place the child by just grabbing its rect and adjusting the x,y.
box->GetContentRect(childRect);
childRect.x = 0;
childRect.y = currY + yOffset;
yOffset += childRect.height;
availableHeight -= childRect.height;
box->GetMargin(margin);
childRect.Deflate(margin);
childRect.width < 0 ? 0 : childRect.width;
childRect.height < 0 ? 0 : childRect.height;
box->SetBounds(aState, childRect);
if (!frame->ContinueReflow(availableHeight))
break;
box = frame->GetNextTreeBox(box);
}
return NS_OK;
}

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

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/**
Original Author:
David W. Hyatt(hyatt@netscape.com)
**/
#ifndef nsTreeLayout_h___
#define nsTreeLayout_h___
#include "nsTempleLayout.h"
#include "nsXULTreeOuterGroupFrame.h"
#include "nsXULTreeSliceFrame.h"
class nsTreeLayout : public nsTempleLayout
{
public:
nsTreeLayout(nsIPresShell* aShell);
NS_IMETHOD GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState, nsSize& aSize);
NS_IMETHOD GetMinSize(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState, nsSize& aSize);
NS_IMETHOD GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aBoxLayoutState, nsSize& aSize);
NS_IMETHOD Layout(nsIBox* aBox, nsBoxLayoutState& aState);
protected:
nsXULTreeOuterGroupFrame* GetOuterFrame(nsIBox* aBox);
nsXULTreeGroupFrame* GetGroupFrame(nsIBox* aBox);
nsXULTreeSliceFrame* GetRowFrame(nsIBox* aBox);
};
#endif

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

@ -24,6 +24,9 @@
#include "nsCOMPtr.h"
#include "nsXULTreeGroupFrame.h"
#include "nsCSSFrameConstructor.h"
#include "nsBoxLayoutState.h"
#include "nsISupportsArray.h"
//
// NS_NewXULTreeGroupFrame
@ -47,13 +50,477 @@ NS_NewXULTreeGroupFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRBool a
} // NS_NewXULTreeGroupFrame
NS_IMETHODIMP_(nsrefcnt)
nsXULTreeGroupFrame::AddRef(void)
{
return NS_OK;
}
NS_IMETHODIMP_(nsrefcnt)
nsXULTreeGroupFrame::Release(void)
{
return NS_OK;
}
//
// QueryInterface
//
NS_INTERFACE_MAP_BEGIN(nsXULTreeGroupFrame)
NS_INTERFACE_MAP_ENTRY(nsIXULTreeSlice)
NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
// Constructor
nsXULTreeGroupFrame::nsXULTreeGroupFrame(nsIPresShell* aPresShell, PRBool aIsRoot, nsIBoxLayout* aLayoutManager, PRBool aIsHorizontal)
:nsBoxFrame(aPresShell, aIsRoot, aLayoutManager, aIsHorizontal)
:nsBoxFrame(aPresShell, aIsRoot, aLayoutManager, aIsHorizontal), mFrameConstructor(nsnull), mPresContext(nsnull),
mOuterFrame(nsnull), mAvailableHeight(10000), mTopFrame(nsnull), mBottomFrame(nsnull), mLinkupFrame(nsnull),
mContentChain(nsnull)
{}
// Destructor
nsXULTreeGroupFrame::~nsXULTreeGroupFrame()
{
}
void nsXULTreeGroupFrame::LocateFrame(nsIFrame* aStartFrame, nsIFrame** aResult)
{
if (aStartFrame == nsnull)
*aResult = mFrames.FirstChild();
else aStartFrame->GetNextSibling(aResult);
}
nsIFrame*
nsXULTreeGroupFrame::GetFirstFrame()
{
LocateFrame(nsnull, &mTopFrame);
return mTopFrame;
}
nsIFrame*
nsXULTreeGroupFrame::GetNextFrame(nsIFrame* aPrevFrame)
{
nsIFrame* result;
LocateFrame(aPrevFrame, &result);
return result;
}
nsIFrame*
nsXULTreeGroupFrame::GetLastFrame()
{
return mFrames.LastChild();
}
nsIBox*
nsXULTreeGroupFrame::GetFirstTreeBox()
{
// Clear ourselves out.
mLinkupFrame = nsnull;
mBottomFrame = mTopFrame;
// If we have a frame and no content chain (e.g., unresolved/uncreated content)
if (mTopFrame && !mContentChain) {
nsCOMPtr<nsIBox> box(do_QueryInterface(mTopFrame));
return box;
}
// See if we have any frame whatsoever.
LocateFrame(nsnull, &mTopFrame);
mBottomFrame = mTopFrame;
nsCOMPtr<nsIContent> startContent;
if (mContentChain) {
nsCOMPtr<nsISupports> supports;
mContentChain->GetElementAt(0, getter_AddRefs(supports));
nsCOMPtr<nsIContent> chainContent = do_QueryInterface(supports);
startContent = chainContent;
if (mTopFrame) {
// We have a content chain. If the top frame is the same as our content
// chain, we can go ahead and destroy our content chain and return the
// top frame.
nsCOMPtr<nsIContent> topContent;
mTopFrame->GetContent(getter_AddRefs(topContent));
if (chainContent.get() == topContent.get()) {
// The two content nodes are the same. Our content chain has
// been synched up, and we can now remove our element and
// pass the content chain inwards.
InitSubContentChain((nsXULTreeGroupFrame*)mTopFrame);
nsCOMPtr<nsIBox> box(do_QueryInterface(mTopFrame));
return box;
}
else mLinkupFrame = mTopFrame; // We have some frames that we'll eventually catch up with.
// Cache the pointer to the first of these frames, so
// we'll know it when we hit it.
}
}
else if (mTopFrame) {
nsCOMPtr<nsIBox> box(do_QueryInterface(mTopFrame));
return box;
}
// We don't have a top frame instantiated. Let's
// try to make one.
// If startContent is initialized, we have a content chain, and
// we're using that content node to make our frame.
// Otherwise we have nothing, and we should just try to grab the first child.
if (!startContent) {
PRInt32 childCount;
mContent->ChildCount(childCount);
nsCOMPtr<nsIContent> childContent;
if (childCount > 0) {
mContent->ChildAt(0, *getter_AddRefs(childContent));
startContent = childContent;
}
}
if (startContent) {
PRBool isAppend = (mLinkupFrame == nsnull);
mFrameConstructor->CreateTreeWidgetContent(mPresContext, this, nsnull, startContent,
&mTopFrame, isAppend, PR_FALSE,
nsnull);
mBottomFrame = mTopFrame;
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(mTopFrame));
PRBool isGroup = PR_FALSE;
if (slice)
slice->IsGroupFrame(&isGroup);
if (isGroup && mContentChain) {
// We have just instantiated a row group, and we have a content chain. This
// means we need to potentially pass a sub-content chain to the instantiated
// frame, so that it can also sync up with its children.
InitSubContentChain((nsXULTreeGroupFrame*)mTopFrame);
}
SetContentChain(nsnull);
nsCOMPtr<nsIBox> box(do_QueryInterface(mTopFrame));
return box;
}
return nsnull;
}
nsIBox*
nsXULTreeGroupFrame::GetNextTreeBox(nsIBox* aBox)
{
// We're ultra-cool. We build our frames on the fly.
nsIFrame* result;
nsIFrame* frame;
aBox->GetFrame(&frame);
LocateFrame(frame, &result);
if (result && (result == mLinkupFrame)) {
// We haven't really found a result. We've only found a result if
// the linkup frame is really the next frame following the
// previous frame.
nsCOMPtr<nsIContent> prevContent;
frame->GetContent(getter_AddRefs(prevContent));
nsCOMPtr<nsIContent> linkupContent;
mLinkupFrame->GetContent(getter_AddRefs(linkupContent));
PRInt32 i, j;
mContent->IndexOf(prevContent, i);
mContent->IndexOf(linkupContent, j);
if (i+1==j) {
// We have found a match and successfully linked back up with our
// old frame.
mBottomFrame = mLinkupFrame;
mLinkupFrame = nsnull;
nsCOMPtr<nsIBox> box(do_QueryInterface(result));
return box;
}
else result = nsnull; // No true linkup. We need to make a frame.
}
if (!result) {
// No result found. See if there's a content node that wants a frame.
PRInt32 i, childCount;
nsCOMPtr<nsIContent> prevContent;
frame->GetContent(getter_AddRefs(prevContent));
nsCOMPtr<nsIContent> parentContent;
mContent->IndexOf(prevContent, i);
mContent->ChildCount(childCount);
if (i+1 < childCount) {
// There is a content node that wants a frame.
nsCOMPtr<nsIContent> nextContent;
mContent->ChildAt(i+1, *getter_AddRefs(nextContent));
nsIFrame* prevFrame = nsnull; // Default is to append
PRBool isAppend = PR_TRUE;
if (mLinkupFrame) {
// This will be an insertion, since we have frames on the end.
aBox->GetFrame(&prevFrame);
isAppend = PR_FALSE;
}
mFrameConstructor->CreateTreeWidgetContent(mPresContext, this, prevFrame, nextContent,
&result, isAppend, PR_FALSE,
nsnull);
}
}
mBottomFrame = result;
nsCOMPtr<nsIBox> box(do_QueryInterface(result));
return box;
}
NS_IMETHODIMP
nsXULTreeGroupFrame::TreeInsertFrames(nsIFrame* aPrevFrame, nsIFrame* aFrameList)
{
// insert the frames to our info list
nsBoxLayoutState state(mPresContext);
Insert(state, aPrevFrame, aFrameList);
mFrames.InsertFrames(nsnull, aPrevFrame, aFrameList);
return NS_OK;
}
NS_IMETHODIMP
nsXULTreeGroupFrame::TreeAppendFrames(nsIFrame* aFrameList)
{
// append them after
nsBoxLayoutState state(mPresContext);
Append(state,aFrameList);
mFrames.AppendFrames(nsnull, aFrameList);
return NS_OK;
}
void
nsXULTreeGroupFrame::OnContentInserted(nsIPresContext* aPresContext, nsIFrame* aNextSibling, PRInt32 aIndex)
{
nsIFrame* currFrame = aNextSibling;
// this will probably never happen -
// if we haven't created the topframe, it doesn't matter if
// content was inserted
if (mTopFrame == nsnull) return;
// if we're inserting content at the top of visible content,
// then ignore it because it would go off-screen
// except of course in the case of the first row, where we're
// actually adding visible content
if(aNextSibling == mTopFrame) {
if (aIndex == 0)
// it's the first row, blow away mTopFrame so it can be
// crecreated later
mTopFrame = nsnull;
else
// it's not visible, nothing to do
return;
}
while (currFrame) {
nsIFrame* nextFrame;
currFrame->GetNextSibling(&nextFrame);
mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, currFrame, nsnull);
nsBoxLayoutState state(aPresContext);
Remove(state, currFrame);
mFrames.DestroyFrame(aPresContext, currFrame);
currFrame = nextFrame;
}
nsBoxLayoutState state(aPresContext);
MarkDirtyChildren(state);
}
void nsXULTreeGroupFrame::OnContentRemoved(nsIPresContext* aPresContext,
nsIFrame* aChildFrame,
PRInt32 aIndex)
{
// if we're removing the top row, the new top row is the next row
if (mTopFrame && mTopFrame == aChildFrame)
mTopFrame->GetNextSibling(&mTopFrame);
// if we're removing the last frame in this rowgroup and if we have
// a scrollbar, we have to yank in some rows from above
/* if (!mTopFrame && mScrollbar && mCurrentIndex > 0) {
// sync up the scrollbar, now that we've scrolled one row
mCurrentIndex--;
nsAutoString indexStr;
PRInt32 pixelIndex = mCurrentIndex * SCROLL_FACTOR;
indexStr.AppendInt(pixelIndex);
nsCOMPtr<nsIContent> scrollbarContent;
mScrollbar->GetContent(getter_AddRefs(scrollbarContent));
scrollbarContent->SetAttribute(kNameSpaceID_None, nsXULAtoms::curpos,
indexStr, PR_TRUE);
// Now force the reflow to happen immediately, because we need to
// deal with cleaning out the content chain.
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
shell->FlushPendingNotifications();
return; // All frames got deleted anyway by the pos change.
}
*/
// Go ahead and delete the frame.
nsBoxLayoutState state(aPresContext);
if (aChildFrame) {
Remove(state, aChildFrame);
mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, aChildFrame, nsnull);
mFrames.DestroyFrame(aPresContext, aChildFrame);
}
MarkDirtyChildren(state);
}
PRBool nsXULTreeGroupFrame::ContinueReflow(nscoord height)
{
if (height <= 0) {
nsIFrame* lastChild = GetLastFrame();
nsIFrame* startingPoint = mBottomFrame;
if (startingPoint == nsnull) {
// We just want to delete everything but the first item.
startingPoint = GetFirstFrame();
}
if (lastChild != startingPoint) {
// We have some hangers on (probably caused by shrinking the size of the window).
// Nuke them.
nsIFrame* currFrame;
startingPoint->GetNextSibling(&currFrame);
while (currFrame) {
nsIFrame* nextFrame;
currFrame->GetNextSibling(&nextFrame);
mFrameConstructor->RemoveMappingsForFrameSubtree(mPresContext, currFrame, nsnull);
nsBoxLayoutState state(mPresContext);
Remove(state, currFrame);
mFrames.DestroyFrame(mPresContext, currFrame);
currFrame = nextFrame;
}
}
return PR_FALSE;
}
else
return PR_TRUE;
}
void nsXULTreeGroupFrame::DestroyRows(PRInt32& aRowsToLose)
{
// We need to destroy frames until our row count has been properly
// reduced. A reflow will then pick up and create the new frames.
nsIFrame* childFrame = GetFirstFrame();
while (childFrame && aRowsToLose > 0) {
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(childFrame));
if (!slice) continue;
PRBool isRowGroup;
slice->IsGroupFrame(&isRowGroup);
if (isRowGroup)
{
nsXULTreeGroupFrame* childGroup = (nsXULTreeGroupFrame*)childFrame;
childGroup->DestroyRows(aRowsToLose);
if (aRowsToLose == 0) {
nsIBox* box = nsnull;
childGroup->GetChildBox(&box);
if (box) // Still have kids. Just return.
return;
}
}
else
{
// Lost a row.
aRowsToLose--;
}
nsIFrame* nextFrame = GetNextFrame(childFrame);
mFrameConstructor->RemoveMappingsForFrameSubtree(mPresContext, childFrame, nsnull);
nsBoxLayoutState state(mPresContext);
Remove(state, childFrame);
mFrames.DestroyFrame(mPresContext, childFrame);
mTopFrame = childFrame = nextFrame;
}
}
void nsXULTreeGroupFrame::ReverseDestroyRows(PRInt32& aRowsToLose)
{
// We need to destroy frames until our row count has been properly
// reduced. A reflow will then pick up and create the new frames.
nsIFrame* childFrame = GetLastFrame();
while (childFrame && aRowsToLose > 0) {
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(childFrame));
if (!slice) continue;
PRBool isRowGroup;
slice->IsGroupFrame(&isRowGroup);
if (isRowGroup)
{
nsXULTreeGroupFrame* childGroup = (nsXULTreeGroupFrame*)childFrame;
childGroup->ReverseDestroyRows(aRowsToLose);
if (aRowsToLose == 0) {
nsIBox* box = nsnull;
childGroup->GetChildBox(&box);
if (box) // Still have kids. Just return.
return;
}
}
else
{
// Lost a row.
aRowsToLose--;
}
nsIFrame* prevFrame;
prevFrame = mFrames.GetPrevSiblingFor(childFrame);
mFrameConstructor->RemoveMappingsForFrameSubtree(mPresContext, childFrame, nsnull);
nsBoxLayoutState state(mPresContext);
Remove(state, childFrame);
mFrames.DestroyFrame(mPresContext, childFrame);
mBottomFrame = childFrame = prevFrame;
}
}
void
nsXULTreeGroupFrame::GetFirstRowContent(nsIContent** aResult)
{
*aResult = nsnull;
nsIFrame* kid = GetFirstFrame();
while (kid) {
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(kid));
if (!slice)
continue;
PRBool isRowGroup;
slice->IsGroupFrame(&isRowGroup);
if (isRowGroup) {
((nsXULTreeGroupFrame*)kid)->GetFirstRowContent(aResult);
if (*aResult)
return;
}
else {
kid->GetContent(aResult); // The ADDREF happens here.
return;
}
kid = GetNextFrame(kid);
}
}
void nsXULTreeGroupFrame::SetContentChain(nsISupportsArray* aContentChain)
{
NS_IF_RELEASE(mContentChain);
mContentChain = aContentChain;
NS_IF_ADDREF(mContentChain);
}
void nsXULTreeGroupFrame::InitSubContentChain(nsXULTreeGroupFrame* aRowGroupFrame)
{
if (mContentChain) {
mContentChain->RemoveElementAt(0);
PRUint32 chainSize;
mContentChain->Count(&chainSize);
if (chainSize > 0 && aRowGroupFrame) {
aRowGroupFrame->SetContentChain(mContentChain);
}
// The chain is dead. Long live the chain.
SetContentChain(nsnull);
}
}

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

@ -23,10 +23,16 @@
*/
#include "nsBoxFrame.h"
#include "nsIXULTreeSlice.h"
class nsXULTreeGroupFrame : public nsBoxFrame
class nsCSSFrameConstructor;
class nsXULTreeOuterGroupFrame;
class nsXULTreeGroupFrame : public nsBoxFrame, public nsIXULTreeSlice
{
public:
NS_DECL_ISUPPORTS
friend nsresult NS_NewXULTreeGroupFrame(nsIPresShell* aPresShell,
nsIFrame** aNewFrame,
PRBool aIsRoot = PR_FALSE,
@ -37,6 +43,60 @@ protected:
nsXULTreeGroupFrame(nsIPresShell* aPresShell, PRBool aIsRoot = nsnull, nsIBoxLayout* aLayoutManager = nsnull, PRBool aDefaultHorizontal = PR_TRUE);
virtual ~nsXULTreeGroupFrame();
protected: // Data Members
void LocateFrame(nsIFrame* aStartFrame, nsIFrame** aResult);
public:
void InitGroup(nsCSSFrameConstructor* aFC, nsIPresContext* aContext, nsXULTreeOuterGroupFrame* aOuterFrame)
{
mFrameConstructor = aFC;
mPresContext = aContext;
mOuterFrame = aOuterFrame;
}
nsXULTreeOuterGroupFrame* GetOuterFrame() { return mOuterFrame; };
nsIBox* GetFirstTreeBox();
nsIBox* GetNextTreeBox(nsIBox* aBox);
nsIFrame* GetFirstFrame();
nsIFrame* GetNextFrame(nsIFrame* aCurrFrame);
nsIFrame* GetLastFrame();
NS_IMETHOD IsDirty(PRBool& aDirtyFlag) { aDirtyFlag = PR_TRUE; return NS_OK; };
NS_IMETHOD TreeAppendFrames(nsIFrame* aFrameList);
NS_IMETHOD TreeInsertFrames(nsIFrame* aPrevFrame,
nsIFrame* aFrameList);
// Responses to changes
void OnContentInserted(nsIPresContext* aPresContext, nsIFrame* aNextSibling, PRInt32 aIndex);
void OnContentRemoved(nsIPresContext* aPresContext, nsIFrame* aChildFrame, PRInt32 aIndex);
// nsIXULTreeSlice
NS_IMETHOD IsOutermostFrame(PRBool* aResult) { *aResult = PR_FALSE; return NS_OK; };
NS_IMETHOD IsGroupFrame(PRBool* aResult) { *aResult = PR_TRUE; return NS_OK; };
NS_IMETHOD IsRowFrame(PRBool* aResult) { *aResult = PR_FALSE; return NS_OK; };
virtual nscoord GetAvailableHeight() { return mAvailableHeight; };
void SetAvailableHeight(nscoord aHeight) { mAvailableHeight = aHeight; };
virtual nscoord GetYPosition() { return 0; };
PRBool ContinueReflow(nscoord height);
void DestroyRows(PRInt32& aRowsToLose);
void ReverseDestroyRows(PRInt32& aRowsToLose);
void GetFirstRowContent(nsIContent** aResult);
void SetContentChain(nsISupportsArray* aContentChain);
void InitSubContentChain(nsXULTreeGroupFrame* aRowGroupFrame);
protected: // Data Members
nsCSSFrameConstructor* mFrameConstructor; // We don't own this. (No addref/release allowed, punk.)
nsIPresContext* mPresContext;
nsXULTreeOuterGroupFrame* mOuterFrame;
nscoord mAvailableHeight;
nsIFrame* mTopFrame;
nsIFrame* mBottomFrame;
nsIFrame* mLinkupFrame;
nsISupportsArray* mContentChain; // Our content chain
}; // class nsXULTreeGroupFrame

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

@ -0,0 +1,700 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Original Author: David W. Hyatt (hyatt@netscape.com)
*
* Contributor(s):
*/
#include "nsCOMPtr.h"
#include "nsXULTreeOuterGroupFrame.h"
#include "nsXULAtoms.h"
#include "nsIContent.h"
#include "nsINameSpaceManager.h"
#include "nsIScrollableFrame.h"
#include "nsIScrollbarFrame.h"
#include "nsISupportsArray.h"
#include "nsCSSFrameConstructor.h"
#define TICK_FACTOR 50
//
// NS_NewXULTreeOuterGroupFrame
//
// Creates a new TreeOuterGroup frame
//
nsresult
NS_NewXULTreeOuterGroupFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRBool aIsRoot,
nsIBoxLayout* aLayoutManager, PRBool aIsHorizontal)
{
NS_PRECONDITION(aNewFrame, "null OUT ptr");
if (nsnull == aNewFrame) {
return NS_ERROR_NULL_POINTER;
}
nsXULTreeOuterGroupFrame* it = new (aPresShell) nsXULTreeOuterGroupFrame(aPresShell, aIsRoot, aLayoutManager, aIsHorizontal);
if (!it)
return NS_ERROR_OUT_OF_MEMORY;
*aNewFrame = it;
return NS_OK;
} // NS_NewXULTreeOuterGroupFrame
// Constructor
nsXULTreeOuterGroupFrame::nsXULTreeOuterGroupFrame(nsIPresShell* aPresShell, PRBool aIsRoot, nsIBoxLayout* aLayoutManager, PRBool aIsHorizontal)
:nsXULTreeGroupFrame(aPresShell, aIsRoot, aLayoutManager, aIsHorizontal),
mRowGroupInfo(nsnull), mRowHeight(TREE_LINE_HEIGHT), mCurrentIndex(0), mTwipIndex(0)
{}
// Destructor
nsXULTreeOuterGroupFrame::~nsXULTreeOuterGroupFrame()
{
delete mRowGroupInfo;
}
NS_IMETHODIMP_(nsrefcnt)
nsXULTreeOuterGroupFrame::AddRef(void)
{
return NS_OK;
}
NS_IMETHODIMP_(nsrefcnt)
nsXULTreeOuterGroupFrame::Release(void)
{
return NS_OK;
}
//
// QueryInterface
//
NS_INTERFACE_MAP_BEGIN(nsXULTreeOuterGroupFrame)
NS_INTERFACE_MAP_ENTRY(nsIScrollbarMediator)
NS_INTERFACE_MAP_END_INHERITING(nsXULTreeGroupFrame)
NS_IMETHODIMP
nsXULTreeOuterGroupFrame::Init(nsIPresContext* aPresContext, nsIContent* aContent,
nsIFrame* aParent, nsIStyleContext* aContext, nsIFrame* aPrevInFlow)
{
nsresult rv = nsXULTreeGroupFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
float p2t;
aPresContext->GetScaledPixelsToTwips(&p2t);
mOnePixel = NSIntPixelsToTwips(1, p2t);
nsIFrame* box;
aParent->GetParent(&box);
if (!box)
return rv;
nsCOMPtr<nsIScrollableFrame> scrollFrame(do_QueryInterface(box));
if (!scrollFrame)
return rv;
nsIBox* verticalScrollbar;
scrollFrame->GetScrollbarBox(PR_TRUE, &verticalScrollbar);
if (!verticalScrollbar) {
NS_ERROR("Unable to install the scrollbar mediator on the tree widget. You must be using GFX scrollbars.");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIScrollbarFrame> scrollbarFrame(do_QueryInterface(verticalScrollbar));
scrollbarFrame->SetScrollbarMediator(this);
return rv;
} // Init
nscoord
nsXULTreeOuterGroupFrame::GetYPosition()
{
nsIBox* box;
GetParentBox(&box);
if (!box)
return 0;
box->GetParentBox(&box);
if (!box)
return 0;
nsCOMPtr<nsIScrollableFrame> scrollFrame(do_QueryInterface(box));
if (!scrollFrame)
return 0;
nscoord x, y;
scrollFrame->GetScrollPosition(mPresContext, x, y);
return y;
}
void
nsXULTreeOuterGroupFrame::VerticalScroll(PRInt32 aDelta)
{
nsIBox* box;
GetParentBox(&box);
if (!box)
return;
box->GetParentBox(&box);
if (!box)
return;
nsCOMPtr<nsIScrollableFrame> scrollFrame(do_QueryInterface(box));
if (!scrollFrame)
return;
nscoord x, y;
scrollFrame->GetScrollPosition(mPresContext, x, y);
scrollFrame->ScrollTo(mPresContext, x, aDelta);
}
nscoord
nsXULTreeOuterGroupFrame::GetAvailableHeight()
{
nsIBox* box;
GetParentBox(&box);
if (!box)
return 0;
box->GetParentBox(&box);
if (!box)
return 0;
nsCOMPtr<nsIScrollableFrame> scrollFrame(do_QueryInterface(box));
if (!scrollFrame)
return 0;
nscoord x, y;
scrollFrame->GetClipSize(mPresContext, &x, &y);
return y;
}
void
nsXULTreeOuterGroupFrame::ComputeTotalRowCount(PRInt32& aCount, nsIContent* aParent)
{
if (!mRowGroupInfo) {
mRowGroupInfo = new nsXULTreeRowGroupInfo();
}
PRInt32 childCount;
aParent->ChildCount(childCount);
for (PRInt32 i = 0; i < childCount; i++) {
nsCOMPtr<nsIContent> childContent;
aParent->ChildAt(i, *getter_AddRefs(childContent));
nsCOMPtr<nsIAtom> tag;
childContent->GetTag(*getter_AddRefs(tag));
if (tag.get() == nsXULAtoms::treerow) {
if ((aCount%TICK_FACTOR) == 0)
mRowGroupInfo->Add(childContent);
mRowGroupInfo->mLastChild = childContent;
aCount++;
}
else if (tag.get() == nsXULAtoms::treeitem) {
// Descend into this row group and try to find the next row.
ComputeTotalRowCount(aCount, childContent);
}
else if (tag.get() == nsXULAtoms::treechildren) {
// If it's open, descend into its treechildren.
nsCOMPtr<nsIAtom> openAtom = dont_AddRef(NS_NewAtom("open"));
nsAutoString isOpen;
nsCOMPtr<nsIContent> parent;
childContent->GetParent(*getter_AddRefs(parent));
parent->GetAttribute(kNameSpaceID_None, openAtom, isOpen);
if (isOpen.EqualsWithConversion("true"))
ComputeTotalRowCount(aCount, childContent);
}
}
}
NS_IMETHODIMP
nsXULTreeOuterGroupFrame::ScrollbarButtonPressed(PRInt32 aOldIndex, PRInt32 aNewIndex)
{
if (aOldIndex == aNewIndex)
return NS_OK;
if (aNewIndex < aOldIndex)
mCurrentIndex--;
else mCurrentIndex++;
if (mCurrentIndex < 0) {
mCurrentIndex = 0;
return NS_OK;
}
InternalPositionChanged(aNewIndex < aOldIndex, 1);
return NS_OK;
}
NS_IMETHODIMP
nsXULTreeOuterGroupFrame::PositionChanged(PRInt32 aOldIndex, PRInt32 aNewIndex)
{
if (aOldIndex == aNewIndex)
return NS_OK;
printf("Old Index: %d, New Index: %d\n", aOldIndex, aNewIndex);
PRInt32 oldTwipIndex, newTwipIndex;
oldTwipIndex = (aOldIndex*mOnePixel);
newTwipIndex = (aNewIndex*mOnePixel);
PRInt32 twipDelta = newTwipIndex > oldTwipIndex ? newTwipIndex - oldTwipIndex : oldTwipIndex - newTwipIndex;
PRInt32 delta = twipDelta / mRowHeight;
PRInt32 remainder = twipDelta % mRowHeight;
if (remainder > (mRowHeight/2))
delta++;
if (delta == 0)
return NS_OK;
mCurrentIndex = newTwipIndex > oldTwipIndex ? mCurrentIndex + delta : mCurrentIndex - delta;
if (mCurrentIndex < 0) {
mCurrentIndex = 0;
return NS_OK;
}
return InternalPositionChanged(newTwipIndex < oldTwipIndex, delta);
}
NS_IMETHODIMP
nsXULTreeOuterGroupFrame::InternalPositionChanged(PRBool aUp, PRInt32 aDelta)
{
PRInt32 visibleRows = GetAvailableHeight()/mRowHeight;
// Get our presentation context.
if (aDelta < visibleRows) {
if (mContentChain) {
// XXX This could cause problems because of async reflow.
// Eventually we need to make the code smart enough to look at a content chain
// when building ANOTHER content chain.
// Ensure all reflows happen first.
nsCOMPtr<nsIPresShell> shell;
mPresContext->GetShell(getter_AddRefs(shell));
shell->FlushPendingNotifications();
}
PRInt32 loseRows = aDelta;
// scrolling down
if (!aUp) {
// Figure out how many rows we have to lose off the top.
DestroyRows(loseRows);
}
// scrolling up
else {
// Get our first row content.
nsCOMPtr<nsIContent> rowContent;
GetFirstRowContent(getter_AddRefs(rowContent));
// Figure out how many rows we have to lose off the bottom.
ReverseDestroyRows(loseRows);
// Now that we've lost some rows, we need to create a
// content chain that provides a hint for moving forward.
nsCOMPtr<nsIContent> topRowContent;
PRInt32 findContent = aDelta;
FindPreviousRowContent(findContent, rowContent, nsnull, getter_AddRefs(topRowContent));
ConstructContentChain(topRowContent);
//Now construct the chain for the old top row so its content chain gets
//set up correctly.
ConstructOldContentChain(rowContent);
}
}
else {
// Just blow away all our frames, but keep a content chain
// as a hint to figure out how to build the frames.
// Remove the scrollbar first.
// get the starting row index and row count
mFrameConstructor->RemoveMappingsForFrameSubtree(mPresContext, this, nsnull);
nsBoxLayoutState state(mPresContext);
mFirstChild = mLastChild = nsnull;
mFrames.DestroyFrames(mPresContext);
nsCOMPtr<nsIContent> topRowContent;
FindRowContentAtIndex(mCurrentIndex, mContent, getter_AddRefs(topRowContent));
if (topRowContent)
ConstructContentChain(topRowContent);
}
mTopFrame = mBottomFrame = nsnull; // Make sure everything is cleared out.
nsBoxLayoutState state(mPresContext);
MarkDirtyChildren(state);
VerticalScroll(mCurrentIndex*mRowHeight);
return NS_OK;
}
void
nsXULTreeOuterGroupFrame::ConstructContentChain(nsIContent* aRowContent)
{
// Create the content chain array.
NS_IF_RELEASE(mContentChain);
NS_NewISupportsArray(&mContentChain);
// Move up the chain until we hit our content node.
nsCOMPtr<nsIContent> currContent = dont_QueryInterface(aRowContent);
while (currContent && (currContent.get() != mContent)) {
mContentChain->InsertElementAt(currContent, 0);
nsCOMPtr<nsIContent> otherContent = currContent;
otherContent->GetParent(*getter_AddRefs(currContent));
}
NS_ASSERTION(currContent.get() == mContent, "Disaster! Content not contained in our tree!\n");
}
void
nsXULTreeOuterGroupFrame::ConstructOldContentChain(nsIContent* aOldRowContent)
{
nsCOMPtr<nsIContent> childOfCommonAncestor;
//Find the first child of the common ancestor between the new top row's content chain
//and the old top row. Everything between this child and the old top row potentially need
//to have their content chains reset.
FindChildOfCommonContentChainAncestor(aOldRowContent, getter_AddRefs(childOfCommonAncestor));
if (childOfCommonAncestor) {
//Set up the old top rows content chian.
CreateOldContentChain(aOldRowContent, childOfCommonAncestor);
}
}
void
nsXULTreeOuterGroupFrame::FindChildOfCommonContentChainAncestor(nsIContent *startContent, nsIContent **child)
{
PRUint32 count;
if (mContentChain)
{
nsresult rv = mContentChain->Count(&count);
if (NS_SUCCEEDED(rv) && (count >0)) {
for (PRInt32 curItem = count - 1; curItem >= 0; curItem--) {
nsCOMPtr<nsISupports> supports;
mContentChain->GetElementAt(curItem, getter_AddRefs(supports));
nsCOMPtr<nsIContent> curContent = do_QueryInterface(supports);
//See if curContent is an ancestor of startContent.
if (IsAncestor(curContent, startContent, child))
return;
}
}
}
//mContent isn't actually put in the content chain, so we need to
//check it separately.
if (IsAncestor(mContent, startContent, child))
return;
*child = nsnull;
}
// if oldRowContent is an ancestor of rowContent, return true,
// and return the previous ancestor if requested
PRBool
nsXULTreeOuterGroupFrame::IsAncestor(nsIContent *aRowContent, nsIContent *aOldRowContent, nsIContent** firstDescendant)
{
nsCOMPtr<nsIContent> prevContent;
nsCOMPtr<nsIContent> currContent = dont_QueryInterface(aOldRowContent);
while (currContent) {
if (aRowContent == currContent.get()) {
if (firstDescendant) {
*firstDescendant = prevContent;
NS_IF_ADDREF(*firstDescendant);
}
return PR_TRUE;
}
prevContent = currContent;
prevContent->GetParent(*getter_AddRefs(currContent));
}
return PR_FALSE;
}
void
nsXULTreeOuterGroupFrame::CreateOldContentChain(nsIContent* aOldRowContent, nsIContent* topOfChain)
{
nsCOMPtr<nsIContent> currContent = dont_QueryInterface(aOldRowContent);
nsCOMPtr<nsIContent> prevContent;
nsCOMPtr<nsIPresShell> shell;
mPresContext->GetShell(getter_AddRefs(shell));
//For each item between the (oldtoprow) and
// (the new first child of common ancestry between new top row and old top row)
// we need to see if the content chain has to be reset.
while (currContent.get() != topOfChain) {
nsIFrame* primaryFrame = nsnull;
shell->GetPrimaryFrameFor(currContent, &primaryFrame);
if (primaryFrame) {
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(primaryFrame));
PRBool isRowGroup = PR_FALSE;
if (slice)
slice->IsGroupFrame(&isRowGroup);
if (isRowGroup) {
//Get the current content's parent's first child
nsCOMPtr<nsIContent> parent;
currContent->GetParent(*getter_AddRefs(parent));
nsCOMPtr<nsIContent> firstChild;
parent->ChildAt(0, *getter_AddRefs(firstChild));
nsIFrame* parentFrame;
primaryFrame->GetParent(&parentFrame);
PRBool isParentRowGroup = PR_FALSE;
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(parentFrame));
if (slice)
slice->IsGroupFrame(&isParentRowGroup);
if (isParentRowGroup) {
//Get the current content's parent's first frame.
nsXULTreeGroupFrame *parentRowGroupFrame =
(nsXULTreeGroupFrame*)parentFrame;
nsIFrame *currentTopFrame = parentRowGroupFrame->GetFirstFrame();
nsCOMPtr<nsIContent> topContent;
currentTopFrame->GetContent(getter_AddRefs(topContent));
// If the current content's parent's first child is different
// than the current frame's parent's first child then we know
// they are out of synch and we need to set the content
// chain correctly.
if(topContent.get() != firstChild.get()) {
nsCOMPtr<nsISupportsArray> contentChain;
NS_NewISupportsArray(getter_AddRefs(contentChain));
contentChain->InsertElementAt(firstChild, 0);
parentRowGroupFrame->SetContentChain(contentChain);
}
}
}
}
prevContent = currContent;
prevContent->GetParent(*getter_AddRefs(currContent));
}
}
void
nsXULTreeOuterGroupFrame::FindRowContentAtIndex(PRInt32& aIndex,
nsIContent* aParent,
nsIContent** aResult)
{
// Init to nsnull.
*aResult = nsnull;
// Walk over the tick array.
if (mRowGroupInfo == nsnull)
return;
PRUint32 index = 0;
PRUint32 arrayCount;
mRowGroupInfo->mTickArray->Count(&arrayCount);
nsCOMPtr<nsIContent> startContent;
PRUint32 location = aIndex/TICK_FACTOR + 1;
PRUint32 point = location*TICK_FACTOR;
if (location >= arrayCount) {
startContent = mRowGroupInfo->mLastChild;
point = mRowGroupInfo->mRowCount-1;
}
else {
nsCOMPtr<nsISupports> supp = getter_AddRefs(mRowGroupInfo->mTickArray->ElementAt(location));
startContent = do_QueryInterface(supp);
}
if (!startContent) {
NS_ERROR("The tree's tick array is confused!");
return;
}
PRInt32 delta = (PRInt32)(point-aIndex);
FindPreviousRowContent(delta, startContent, nsnull, aResult);
}
void
nsXULTreeOuterGroupFrame::FindPreviousRowContent(PRInt32& aDelta, nsIContent* aUpwardHint,
nsIContent* aDownwardHint,
nsIContent** aResult)
{
// Init to nsnull.
*aResult = nsnull;
// It disappoints me that this function is completely tied to the content nodes,
// but I can't see any other way to handle this. I don't have the frames, so I have nothing
// else to fall back on but the content nodes.
PRInt32 index = 0;
nsCOMPtr<nsIContent> parentContent;
if (aUpwardHint) {
aUpwardHint->GetParent(*getter_AddRefs(parentContent));
if (!parentContent) {
NS_ERROR("Parent content should not be NULL!");
return;
}
parentContent->IndexOf(aUpwardHint, index);
}
else if (aDownwardHint) {
parentContent = dont_QueryInterface(aDownwardHint);
parentContent->ChildCount(index);
}
/* Let me see inside the damn nsCOMptrs
nsIAtom* aAtom;
parentContent->GetTag(aAtom);
nsAutoString result;
aAtom->ToString(result);
*/
for (PRInt32 i = index-1; i >= 0; i--) {
nsCOMPtr<nsIContent> childContent;
parentContent->ChildAt(i, *getter_AddRefs(childContent));
nsCOMPtr<nsIAtom> tag;
childContent->GetTag(*getter_AddRefs(tag));
if (tag.get() == nsXULAtoms::treerow) {
aDelta--;
if (aDelta == 0) {
*aResult = childContent;
NS_IF_ADDREF(*aResult);
return;
}
}
else if (tag.get() == nsXULAtoms::treeitem) {
// If it's open, descend into its treechildren node first.
nsCOMPtr<nsIAtom> openAtom = dont_AddRef(NS_NewAtom("open"));
nsAutoString isOpen;
childContent->GetAttribute(kNameSpaceID_None, openAtom, isOpen);
if (isOpen.EqualsWithConversion("true")) {
// Find the <treechildren> node.
PRInt32 childContentCount;
nsCOMPtr<nsIContent> grandChild;
childContent->ChildCount(childContentCount);
PRInt32 j;
for (j = childContentCount-1; j >= 0; j--) {
childContent->ChildAt(j, *getter_AddRefs(grandChild));
nsCOMPtr<nsIAtom> grandChildTag;
grandChild->GetTag(*getter_AddRefs(grandChildTag));
if (grandChildTag.get() == nsXULAtoms::treechildren)
break;
}
if (j >= 0 && grandChild)
FindPreviousRowContent(aDelta, nsnull, grandChild, aResult);
if (aDelta == 0)
return;
}
// Descend into this row group and try to find a previous row.
FindPreviousRowContent(aDelta, nsnull, childContent, aResult);
if (aDelta == 0)
return;
}
}
nsCOMPtr<nsIAtom> tag;
parentContent->GetTag(*getter_AddRefs(tag));
if (tag && tag.get() == nsXULAtoms::tree) {
// Hopeless. It ain't in there.
return;
}
else if (!aDownwardHint) // We didn't find it here. We need to go up to our parent, using ourselves as a hint.
FindPreviousRowContent(aDelta, parentContent, nsnull, aResult);
// Bail. There's nothing else we can do.
}
void
nsXULTreeOuterGroupFrame::FindNextRowContent(PRInt32& aDelta, nsIContent* aUpwardHint,
nsIContent* aDownwardHint,
nsIContent** aResult)
{
// Init to nsnull.
*aResult = nsnull;
// It disappoints me that this function is completely tied to the content nodes,
// but I can't see any other way to handle this. I don't have the frames, so I have nothing
// else to fall back on but the content nodes.
PRInt32 index = -1;
nsCOMPtr<nsIContent> parentContent;
if (aUpwardHint) {
aUpwardHint->GetParent(*getter_AddRefs(parentContent));
if (!parentContent) {
NS_ERROR("Parent content should not be NULL!");
return;
}
parentContent->IndexOf(aUpwardHint, index);
}
else if (aDownwardHint) {
parentContent = dont_QueryInterface(aDownwardHint);
}
PRInt32 childCount;
parentContent->ChildCount(childCount);
for (PRInt32 i = index+1; i < childCount; i++) {
nsCOMPtr<nsIContent> childContent;
parentContent->ChildAt(i, *getter_AddRefs(childContent));
nsCOMPtr<nsIAtom> tag;
childContent->GetTag(*getter_AddRefs(tag));
if (tag.get() == nsXULAtoms::treerow) {
aDelta--;
if (aDelta == 0) {
*aResult = childContent;
NS_IF_ADDREF(*aResult);
return;
}
}
else if (tag.get() == nsXULAtoms::treeitem) {
// Descend into this row group and try to find a next row.
FindNextRowContent(aDelta, nsnull, childContent, aResult);
if (aDelta == 0)
return;
}
else if (tag.get() == nsXULAtoms::treechildren) {
// If it's open, descend into its treechildren node first.
nsCOMPtr<nsIAtom> openAtom = dont_AddRef(NS_NewAtom("open"));
nsAutoString isOpen;
parentContent->GetAttribute(kNameSpaceID_None, openAtom, isOpen);
if (isOpen.EqualsWithConversion("true")) {
FindNextRowContent(aDelta, nsnull, childContent, aResult);
if (aDelta == 0)
return;
}
}
}
nsCOMPtr<nsIAtom> tag;
parentContent->GetTag(*getter_AddRefs(tag));
if (tag && tag.get() == nsXULAtoms::tree) {
// Hopeless. It ain't in there.
return;
}
else if (!aDownwardHint) // We didn't find it here. We need to go up to our parent, using ourselves as a hint.
FindNextRowContent(aDelta, parentContent, nsnull, aResult);
// Bail. There's nothing else we can do.
}

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

@ -0,0 +1,138 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Original Author: David W. Hyatt (hyatt@netscape.com)
*
* Contributor(s):
*/
#include "nsCOMPtr.h"
#include "nsBoxLayoutState.h"
#include "nsISupportsArray.h"
#include "nsXULTreeGroupFrame.h"
#include "nsIScrollbarMediator.h"
#include "nsIPresContext.h"
class nsCSSFrameConstructor;
#define TREE_LINE_HEIGHT 225
class nsXULTreeRowGroupInfo {
public:
PRInt32 mRowCount;
nsCOMPtr<nsISupportsArray> mTickArray;
nsIContent* mLastChild;
nsXULTreeRowGroupInfo() :mRowCount(-1),mLastChild(nsnull)
{
NS_NewISupportsArray(getter_AddRefs(mTickArray));
};
~nsXULTreeRowGroupInfo() { Clear(); };
void Add(nsIContent* aContent) {
mTickArray->AppendElement(aContent);
}
void Clear() {
mLastChild = nsnull;
mRowCount = -1;
mTickArray->Clear();
}
};
class nsXULTreeOuterGroupFrame : public nsXULTreeGroupFrame, public nsIScrollbarMediator
{
public:
NS_DECL_ISUPPORTS
friend nsresult NS_NewXULTreeOuterGroupFrame(nsIPresShell* aPresShell,
nsIFrame** aNewFrame,
PRBool aIsRoot = PR_FALSE,
nsIBoxLayout* aLayoutManager = nsnull,
PRBool aDefaultHorizontal = PR_TRUE);
NS_IMETHOD Init(nsIPresContext* aPresContext, nsIContent* aContent,
nsIFrame* aParent, nsIStyleContext* aContext, nsIFrame* aPrevInFlow);
protected:
nsXULTreeOuterGroupFrame(nsIPresShell* aPresShell, PRBool aIsRoot = nsnull, nsIBoxLayout* aLayoutManager = nsnull, PRBool aDefaultHorizontal = PR_TRUE);
virtual ~nsXULTreeOuterGroupFrame();
void ComputeTotalRowCount(PRInt32& aRowCount, nsIContent* aParent);
public:
NS_IMETHOD GetPrefSize(nsBoxLayoutState& aBoxLayoutState, nsSize& aSize)
{
NeedsRecalc();
return nsXULTreeGroupFrame::GetPrefSize(aBoxLayoutState, aSize);
};
NS_IMETHOD IsOutermostFrame(PRBool *aResult) { *aResult = PR_TRUE; return NS_OK; };
PRInt32 GetRowCount() { if (mRowGroupInfo && (mRowGroupInfo->mRowCount != -1)) return mRowGroupInfo->mRowCount; PRInt32 count = 0;
ComputeTotalRowCount(count, mContent); mRowGroupInfo->mRowCount = count; return count; };
PRInt32 GetRowHeightTwips() {
return mRowHeight;
}
void ClearRowGroupInfo() { if (mRowGroupInfo) mRowGroupInfo->Clear(); NeedsRecalc(); };
void SetRowHeight(PRInt32 aRowHeight)
{
if (mRowHeight != aRowHeight) {
mRowHeight = aRowHeight;
nsBoxLayoutState state(mPresContext);
MarkDirtyChildren(state);
}
};
nscoord GetYPosition();
nscoord GetAvailableHeight();
NS_IMETHOD PositionChanged(PRInt32 aOldIndex, PRInt32 aNewIndex);
NS_IMETHOD ScrollbarButtonPressed(PRInt32 aOldIndex, PRInt32 aNewIndex);
void VerticalScroll(PRInt32 aDelta);
void ConstructContentChain(nsIContent* aRowContent);
void ConstructOldContentChain(nsIContent* aOldRowContent);
void CreateOldContentChain(nsIContent* aOldRowContent, nsIContent* topOfChain);
void FindChildOfCommonContentChainAncestor(nsIContent *startContent, nsIContent **child);
PRBool IsAncestor(nsIContent *aRowContent, nsIContent *aOldRowContent, nsIContent **firstDescendant);
void FindPreviousRowContent(PRInt32& aDelta, nsIContent* aUpwardHint,
nsIContent* aDownwardHint, nsIContent** aResult);
void FindNextRowContent(PRInt32& aDelta, nsIContent* aUpwardHint,
nsIContent* aDownwardHint, nsIContent** aResult);
void FindRowContentAtIndex(PRInt32& aIndex, nsIContent* aParent,
nsIContent** aResult);
NS_IMETHOD InternalPositionChanged(PRBool aUp, PRInt32 aDelta);
protected: // Data Members
nsXULTreeRowGroupInfo* mRowGroupInfo;
PRInt32 mRowHeight;
nscoord mOnePixel;
PRInt32 mCurrentIndex; // Row-based
PRInt32 mTwipIndex; // Not really accurate. Used to handle thumb dragging
}; // class nsXULTreeOuterGroupFrame

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

@ -48,6 +48,25 @@ NS_NewXULTreeSliceFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRBool a
} // NS_NewXULTreeSliceFrame
NS_IMETHODIMP_(nsrefcnt)
nsXULTreeSliceFrame::AddRef(void)
{
return NS_OK;
}
NS_IMETHODIMP_(nsrefcnt)
nsXULTreeSliceFrame::Release(void)
{
return NS_OK;
}
//
// QueryInterface
//
NS_INTERFACE_MAP_BEGIN(nsXULTreeSliceFrame)
NS_INTERFACE_MAP_ENTRY(nsIXULTreeSlice)
NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
// Constructor
nsXULTreeSliceFrame::nsXULTreeSliceFrame(nsIPresShell* aPresShell, PRBool aIsRoot, nsIBoxLayout* aLayoutManager, PRBool aIsHorizontal)
:nsBoxFrame(aPresShell, aIsRoot, aLayoutManager, aIsHorizontal)

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

@ -23,16 +23,24 @@
*/
#include "nsBoxFrame.h"
#include "nsIXULTreeSlice.h"
class nsXULTreeSliceFrame : public nsBoxFrame
class nsXULTreeSliceFrame : public nsBoxFrame, public nsIXULTreeSlice
{
public:
NS_DECL_ISUPPORTS
friend nsresult NS_NewXULTreeSliceFrame(nsIPresShell* aPresShell,
nsIFrame** aNewFrame,
PRBool aIsRoot = PR_FALSE,
nsIBoxLayout* aLayoutManager = nsnull,
PRBool aDefaultHorizontal = PR_TRUE);
// nsIXULTreeSlice
NS_IMETHOD IsOutermostFrame(PRBool* aResult) { *aResult = PR_FALSE; return NS_OK; };
NS_IMETHOD IsGroupFrame(PRBool* aResult) { *aResult = PR_FALSE; return NS_OK; };
NS_IMETHOD IsRowFrame(PRBool* aResult) { *aResult = PR_TRUE; return NS_OK; };
protected:
nsXULTreeSliceFrame(nsIPresShell* aPresShell, PRBool aIsRoot = nsnull, nsIBoxLayout* aLayoutManager = nsnull, PRBool aDefaultHorizontal = PR_TRUE);
virtual ~nsXULTreeSliceFrame();