зеркало из https://github.com/mozilla/pjs.git
Tree/grid work. Bug#30511. r=danm
This commit is contained in:
Родитель
bf84b6aaa4
Коммит
330c612d46
|
@ -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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче