Fix for 57139. a=ben

This commit is contained in:
hyatt%netscape.com 2000-10-30 09:26:53 +00:00
parent 86fe4426e1
commit 85a1b3c0cd
15 changed files with 335 additions and 113 deletions

View File

@ -8262,8 +8262,10 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext,
if (aContainer) {
nsCOMPtr<nsIAtom> tag;
aContainer->GetTag(*getter_AddRefs(tag));
if (tag && (tag.get() == nsXULAtoms::treechildren ||
tag.get() == nsXULAtoms::treeitem)) {
PRBool treeChildren = tag && tag.get() == nsXULAtoms::treechildren;
PRBool treeItem = tag && tag.get() == nsXULAtoms::treeitem;
if (treeChildren || treeItem) {
// Walk up to the outermost tree row group frame and tell it that
// content was added.
nsCOMPtr<nsIContent> parent;
@ -8287,15 +8289,40 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext,
// Get the primary frame for the parent of the child that's being added.
nsIFrame* innerFrame = GetFrameFor(shell, aPresContext, aContainer);
treeRowGroup->ClearRowGroupInfo();
nsBoxLayoutState state(aPresContext);
nsXULTreeGroupFrame* innerGroup = (nsXULTreeGroupFrame*) innerFrame;
if (innerGroup) {
nsBoxLayoutState state(aPresContext);
innerGroup->MarkDirtyChildren(state);
}
shell->FlushPendingNotifications();
else {
treeRowGroup->MarkDirtyChildren(state);
// Resolve our style context to find out if we need to clear out our
// undisplayed content.
if (treeChildren) {
nsCOMPtr<nsIContent> parent;
aContainer->GetParent(*getter_AddRefs(parent));
if (parent) {
nsAutoString open;
parent->GetAttribute(kNameSpaceID_None, nsXULAtoms::open, open);
if (open.EqualsIgnoreCase("true")) {
// Clear our undisplayed content.
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
nsCOMPtr<nsIFrameManager> frameManager;
shell->GetFrameManager(getter_AddRefs(frameManager));
frameManager->ClearUndisplayedContentIn(aContainer, parent);
}
}
}
}
treeRowGroup->RegenerateRowGroupInfo(0);
if (!treeRowGroup->IsBatching())
shell->FlushPendingNotifications();
return NS_OK;
}
@ -8567,8 +8594,9 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext,
if (aContainer) {
nsCOMPtr<nsIAtom> tag;
aContainer->GetTag(*getter_AddRefs(tag));
if (tag && (tag.get() == nsXULAtoms::treechildren ||
tag.get() == nsXULAtoms::treeitem)) {
PRBool treeChildren = tag && tag.get() == nsXULAtoms::treechildren;
PRBool treeItem = tag && tag.get() == nsXULAtoms::treeitem;
if (treeChildren || treeItem) {
// Walk up to the outermost tree row group frame and tell it that
// content was added.
nsCOMPtr<nsIContent> parent;
@ -8600,7 +8628,7 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext,
nsIFrame* prevSibling = FindPreviousSibling(shell,
aContainer,
aIndexInContainer);
if (prevSibling || innerFrame) {
if (innerFrame) {
// We're onscreen, but because of the fact that we can be called to
// "kill" a displayed frame (e.g., when you close a tree node), we
// have to see if this slaying is taking place. If so, then we don't
@ -8617,16 +8645,18 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext,
const nsStyleDisplay* display = (const nsStyleDisplay*)
styleContext->GetStyleData(eStyleStruct_Display);
if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
nsFrameConstructorState state(aPresContext, mFixedContainingBlock,
nsFrameConstructorState state(aPresContext, mFixedContainingBlock,
GetAbsoluteContainingBlock(aPresContext, innerFrame),
GetFloaterContainingBlock(aPresContext, innerFrame),
aFrameState);
if (NS_STYLE_DISPLAY_NONE == display->mDisplay && treeItem) {
state.mFrameManager->SetUndisplayedContent(aChild, styleContext);
return NS_OK;
}
}
if (prevSibling || innerFrame) {
nsXULTreeGroupFrame* innerGroup = (nsXULTreeGroupFrame*) innerFrame;
nsBoxLayoutState state(aPresContext);
@ -8638,11 +8668,12 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext,
else innerGroup->MarkDirtyChildren(state);
}
treeRowGroup->ClearRowGroupInfo();
treeRowGroup->RegenerateRowGroupInfo(0);
treeRowGroup->MarkDirtyChildren(state);
}
shell->FlushPendingNotifications();
if (!treeRowGroup->IsBatching())
shell->FlushPendingNotifications();
return NS_OK;
}
}
@ -9236,15 +9267,18 @@ nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext,
if (aContainer) {
nsCOMPtr<nsIAtom> tag;
aContainer->GetTag(*getter_AddRefs(tag));
if (tag.get() == nsXULAtoms::treechildren ||
tag.get() == nsXULAtoms::treeitem) {
PRBool treeChildren = tag && tag.get() == nsXULAtoms::treechildren;
PRBool treeItem = tag && tag.get() == nsXULAtoms::treeitem;
if (treeChildren || treeItem) {
PRInt32 onScreenDelta = 0;
if (childFrame) {
// Convert to a tree row group frame.
nsIFrame* parentFrame;
childFrame->GetParent(&parentFrame);
nsXULTreeGroupFrame* treeRowGroup = (nsXULTreeGroupFrame*)parentFrame;
if (treeRowGroup) {
treeRowGroup->OnContentRemoved(aPresContext, childFrame, aIndexInContainer);
treeRowGroup->OnContentRemoved(aPresContext, childFrame, aIndexInContainer, onScreenDelta);
}
}
{
@ -9270,10 +9304,16 @@ nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext,
// Convert to a tree row group frame.
nsXULTreeOuterGroupFrame* treeRowGroup = (nsXULTreeOuterGroupFrame*)parentFrame;
if (treeRowGroup) {
// If a tree item is removed, try to find an item we can use
// to detect if the removed item was above our current scroll
// position.
treeRowGroup->RegenerateRowGroupInfo(onScreenDelta);
nsBoxLayoutState state(aPresContext);
treeRowGroup->MarkDirtyChildren(state);
treeRowGroup->ClearRowGroupInfo();
shell->FlushPendingNotifications();
if (!treeRowGroup->IsBatching())
shell->FlushPendingNotifications();
}
return NS_OK;
}

View File

@ -3127,9 +3127,7 @@ PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand)
(!gAsyncReflowDuringDocLoad && !mBatchReflows && !mDocumentLoading)) {
// If we're in the middle of a drag, process it right away (needed for mac,
// might as well do it on all platforms just to keep the code paths the same).
if ( IsDragInProgress() )
FlushPendingNotifications();
else
if ( !IsDragInProgress() )
PostReflowEvent();
}

View File

@ -3127,9 +3127,7 @@ PresShell::AppendReflowCommand(nsIReflowCommand* aReflowCommand)
(!gAsyncReflowDuringDocLoad && !mBatchReflows && !mDocumentLoading)) {
// If we're in the middle of a drag, process it right away (needed for mac,
// might as well do it on all platforms just to keep the code paths the same).
if ( IsDragInProgress() )
FlushPendingNotifications();
else
if ( !IsDragInProgress() )
PostReflowEvent();
}

View File

@ -8262,8 +8262,10 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext,
if (aContainer) {
nsCOMPtr<nsIAtom> tag;
aContainer->GetTag(*getter_AddRefs(tag));
if (tag && (tag.get() == nsXULAtoms::treechildren ||
tag.get() == nsXULAtoms::treeitem)) {
PRBool treeChildren = tag && tag.get() == nsXULAtoms::treechildren;
PRBool treeItem = tag && tag.get() == nsXULAtoms::treeitem;
if (treeChildren || treeItem) {
// Walk up to the outermost tree row group frame and tell it that
// content was added.
nsCOMPtr<nsIContent> parent;
@ -8287,15 +8289,40 @@ nsCSSFrameConstructor::ContentAppended(nsIPresContext* aPresContext,
// Get the primary frame for the parent of the child that's being added.
nsIFrame* innerFrame = GetFrameFor(shell, aPresContext, aContainer);
treeRowGroup->ClearRowGroupInfo();
nsBoxLayoutState state(aPresContext);
nsXULTreeGroupFrame* innerGroup = (nsXULTreeGroupFrame*) innerFrame;
if (innerGroup) {
nsBoxLayoutState state(aPresContext);
innerGroup->MarkDirtyChildren(state);
}
shell->FlushPendingNotifications();
else {
treeRowGroup->MarkDirtyChildren(state);
// Resolve our style context to find out if we need to clear out our
// undisplayed content.
if (treeChildren) {
nsCOMPtr<nsIContent> parent;
aContainer->GetParent(*getter_AddRefs(parent));
if (parent) {
nsAutoString open;
parent->GetAttribute(kNameSpaceID_None, nsXULAtoms::open, open);
if (open.EqualsIgnoreCase("true")) {
// Clear our undisplayed content.
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
nsCOMPtr<nsIFrameManager> frameManager;
shell->GetFrameManager(getter_AddRefs(frameManager));
frameManager->ClearUndisplayedContentIn(aContainer, parent);
}
}
}
}
treeRowGroup->RegenerateRowGroupInfo(0);
if (!treeRowGroup->IsBatching())
shell->FlushPendingNotifications();
return NS_OK;
}
@ -8567,8 +8594,9 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext,
if (aContainer) {
nsCOMPtr<nsIAtom> tag;
aContainer->GetTag(*getter_AddRefs(tag));
if (tag && (tag.get() == nsXULAtoms::treechildren ||
tag.get() == nsXULAtoms::treeitem)) {
PRBool treeChildren = tag && tag.get() == nsXULAtoms::treechildren;
PRBool treeItem = tag && tag.get() == nsXULAtoms::treeitem;
if (treeChildren || treeItem) {
// Walk up to the outermost tree row group frame and tell it that
// content was added.
nsCOMPtr<nsIContent> parent;
@ -8600,7 +8628,7 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext,
nsIFrame* prevSibling = FindPreviousSibling(shell,
aContainer,
aIndexInContainer);
if (prevSibling || innerFrame) {
if (innerFrame) {
// We're onscreen, but because of the fact that we can be called to
// "kill" a displayed frame (e.g., when you close a tree node), we
// have to see if this slaying is taking place. If so, then we don't
@ -8617,16 +8645,18 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext,
const nsStyleDisplay* display = (const nsStyleDisplay*)
styleContext->GetStyleData(eStyleStruct_Display);
if (NS_STYLE_DISPLAY_NONE == display->mDisplay) {
nsFrameConstructorState state(aPresContext, mFixedContainingBlock,
nsFrameConstructorState state(aPresContext, mFixedContainingBlock,
GetAbsoluteContainingBlock(aPresContext, innerFrame),
GetFloaterContainingBlock(aPresContext, innerFrame),
aFrameState);
if (NS_STYLE_DISPLAY_NONE == display->mDisplay && treeItem) {
state.mFrameManager->SetUndisplayedContent(aChild, styleContext);
return NS_OK;
}
}
if (prevSibling || innerFrame) {
nsXULTreeGroupFrame* innerGroup = (nsXULTreeGroupFrame*) innerFrame;
nsBoxLayoutState state(aPresContext);
@ -8638,11 +8668,12 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext,
else innerGroup->MarkDirtyChildren(state);
}
treeRowGroup->ClearRowGroupInfo();
treeRowGroup->RegenerateRowGroupInfo(0);
treeRowGroup->MarkDirtyChildren(state);
}
shell->FlushPendingNotifications();
if (!treeRowGroup->IsBatching())
shell->FlushPendingNotifications();
return NS_OK;
}
}
@ -9236,15 +9267,18 @@ nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext,
if (aContainer) {
nsCOMPtr<nsIAtom> tag;
aContainer->GetTag(*getter_AddRefs(tag));
if (tag.get() == nsXULAtoms::treechildren ||
tag.get() == nsXULAtoms::treeitem) {
PRBool treeChildren = tag && tag.get() == nsXULAtoms::treechildren;
PRBool treeItem = tag && tag.get() == nsXULAtoms::treeitem;
if (treeChildren || treeItem) {
PRInt32 onScreenDelta = 0;
if (childFrame) {
// Convert to a tree row group frame.
nsIFrame* parentFrame;
childFrame->GetParent(&parentFrame);
nsXULTreeGroupFrame* treeRowGroup = (nsXULTreeGroupFrame*)parentFrame;
if (treeRowGroup) {
treeRowGroup->OnContentRemoved(aPresContext, childFrame, aIndexInContainer);
treeRowGroup->OnContentRemoved(aPresContext, childFrame, aIndexInContainer, onScreenDelta);
}
}
{
@ -9270,10 +9304,16 @@ nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext,
// Convert to a tree row group frame.
nsXULTreeOuterGroupFrame* treeRowGroup = (nsXULTreeOuterGroupFrame*)parentFrame;
if (treeRowGroup) {
// If a tree item is removed, try to find an item we can use
// to detect if the removed item was above our current scroll
// position.
treeRowGroup->RegenerateRowGroupInfo(onScreenDelta);
nsBoxLayoutState state(aPresContext);
treeRowGroup->MarkDirtyChildren(state);
treeRowGroup->ClearRowGroupInfo();
shell->FlushPendingNotifications();
if (!treeRowGroup->IsBatching())
shell->FlushPendingNotifications();
}
return NS_OK;
}

View File

@ -38,6 +38,9 @@ interface nsITreeBoxObject : nsISupports
long getNumberOfVisibleRows();
long getIndexOfFirstVisibleRow();
long getRowCount();
void beginBatch();
void endBatch();
};
%{C++

View File

@ -46,6 +46,8 @@ public:
NS_IMETHOD GetNumberOfVisibleRows(PRInt32* aResult) = 0;
NS_IMETHOD GetIndexOfFirstVisibleRow(PRInt32* aResult) = 0;
NS_IMETHOD GetRowCount(PRInt32* aResult) = 0;
NS_IMETHOD BeginBatch()=0;
NS_IMETHOD EndBatch()=0;
};
#endif

View File

@ -201,10 +201,6 @@ nsSliderFrame::AttributeChanged(nsIPresContext* aPresContext,
scrollbarFrame->GetScrollbarMediator(getter_AddRefs(mediator));
if (mediator) {
mediator->PositionChanged(GetCurrentPosition(scrollbar), current);
char ch[100];
sprintf(ch,"%d", current);
scrollbar->SetAttribute(kNameSpaceID_None, nsXULAtoms::curpos, NS_ConvertASCIItoUCS2(ch), PR_FALSE);
return NS_OK;
}
}

View File

@ -133,7 +133,7 @@ NS_IMETHODIMP nsTreeBoxObject::GetItemAtIndex(PRInt32 index, nsIDOMElement **_re
/* long getIndexOfItem (in nsIDOMElement item); */
NS_IMETHODIMP nsTreeBoxObject::GetIndexOfItem(nsIDOMElement* aElement, PRInt32 *aResult)
{
*aResult = -1;
*aResult = 0;
nsIFrame* frame = GetFrame();
if (!frame)
@ -177,6 +177,26 @@ NS_IMETHODIMP nsTreeBoxObject::GetRowCount(PRInt32 *aResult)
return treeFrame->GetRowCount(aResult);
}
NS_IMETHODIMP nsTreeBoxObject::BeginBatch()
{
nsIFrame* frame = GetFrame();
if (!frame)
return NS_OK;
nsCOMPtr<nsITreeFrame> treeFrame(do_QueryInterface(frame));
return treeFrame->BeginBatch();
}
NS_IMETHODIMP nsTreeBoxObject::EndBatch()
{
nsIFrame* frame = GetFrame();
if (!frame)
return NS_OK;
nsCOMPtr<nsITreeFrame> treeFrame(do_QueryInterface(frame));
return treeFrame->EndBatch();
}
// Creation Routine ///////////////////////////////////////////////////////////////////////
nsresult

View File

@ -260,7 +260,7 @@ nsTreeLayout::LayoutInternal(nsIBox* aBox, nsBoxLayoutState& aState)
box->GetNextBox(&box);
}
if (group && (group == outer) && availableHeight > 0) {
if (group && (group == outer)) {
// We have enough available height left to add some more rows
// Since we can't do this during layout, we post a callback
// that will be processed after the reflow completes.
@ -354,6 +354,8 @@ nsTreeLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState)
if (isOuterGroup) {
nsXULTreeOuterGroupFrame* outer = (nsXULTreeOuterGroupFrame*) frame;
if (outer->IsBatching())
return NS_OK;
// Always ensure an accurate scrollview position
// This is an edge case that was caused by the row height

View File

@ -245,7 +245,6 @@ nsXULTreeFrame::GetIndexOfItem(nsIPresContext* aPresContext, nsIDOMElement* aEle
if (!treeOuterGroup)
return NS_OK; // No tree body. Just bail.
*aResult = 0;
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
nsCOMPtr<nsIContent> root;
treeOuterGroup->GetContent(getter_AddRefs(root));
@ -290,6 +289,32 @@ nsXULTreeFrame::GetRowCount(PRInt32 *aResult)
return XULTreeOuterGroup->GetRowCount(aResult);
}
NS_IMETHODIMP
nsXULTreeFrame::BeginBatch()
{
// Get our treechildren child frame.
nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull;
GetTreeBody(&treeOuterGroup);
if (!treeOuterGroup)
return NS_OK; // No tree body. Just bail.
return treeOuterGroup->BeginBatch();
}
NS_IMETHODIMP
nsXULTreeFrame::EndBatch()
{
// Get our treechildren child frame.
nsXULTreeOuterGroupFrame* treeOuterGroup = nsnull;
GetTreeBody(&treeOuterGroup);
if (!treeOuterGroup)
return NS_OK; // No tree body. Just bail.
return treeOuterGroup->EndBatch();
}
void
nsXULTreeFrame::GetTreeBody(nsXULTreeOuterGroupFrame** aResult)
{

View File

@ -51,6 +51,8 @@ public:
NS_IMETHOD GetNumberOfVisibleRows(PRInt32 *aResult);
NS_IMETHOD GetIndexOfFirstVisibleRow(PRInt32 *aResult);
NS_IMETHOD GetRowCount(PRInt32* aResult);
NS_IMETHOD BeginBatch();
NS_IMETHOD EndBatch();
protected:
nsXULTreeFrame(nsIPresShell* aPresShell, PRBool aIsRoot = nsnull, nsIBoxLayout* aLayoutManager = nsnull, PRBool aDefaultHorizontal = PR_TRUE);

View File

@ -418,17 +418,26 @@ nsXULTreeGroupFrame::OnContentInserted(nsIPresContext* aPresContext, nsIFrame* a
// 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 we're inserting the item before the first visible content,
// then ignore it because it will end up 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
if (aIndex > 0) // We aren't at the front, so we have to be offscreen.
return; // Just bail.
nsCOMPtr<nsIContent> content;
aNextSibling->GetContent(getter_AddRefs(content));
PRInt32 siblingIndex;
mContent->IndexOf(content, siblingIndex);
if (siblingIndex == 1 && mOuterFrame->GetYPosition() == 0)
// We just inserted an item in front of the first of our children
// and we're at the top, such that we have to show the row.
// This item is our new visible top row.
mTopFrame = nsnull;
else
// it's not visible, nothing to do
// The newly inserted row is offscreen. We can just bail.
return;
}
@ -450,7 +459,7 @@ nsXULTreeGroupFrame::OnContentInserted(nsIPresContext* aPresContext, nsIFrame* a
void nsXULTreeGroupFrame::OnContentRemoved(nsIPresContext* aPresContext,
nsIFrame* aChildFrame,
PRInt32 aIndex)
PRInt32 aIndex, PRInt32& aOnScreenRowCount)
{
// if we're removing the top row, the new top row is the next row
if (mTopFrame && mTopFrame == aChildFrame)
@ -459,34 +468,14 @@ void nsXULTreeGroupFrame::OnContentRemoved(nsIPresContext* aPresContext,
// Go ahead and delete the frame.
nsBoxLayoutState state(aPresContext);
if (aChildFrame) {
nsCOMPtr<nsIXULTreeSlice> slice(do_QueryInterface(aChildFrame));
if (slice)
slice->GetOnScreenRowCount(&aOnScreenRowCount);
mFrameConstructor->RemoveMappingsForFrameSubtree(aPresContext, aChildFrame, nsnull);
Remove(state, aChildFrame);
mFrames.DestroyFrame(aPresContext, aChildFrame);
MarkDirtyChildren(state);
// Get our old row count.
PRInt32 rowCount = mOuterFrame->GetRowCount();
// See if the last row is visible. If it is, we need to pull back
// by the amount of rows that we lose.
PRInt32 index;
mOuterFrame->GetIndexOfFirstVisibleRow(&index);
PRInt32 vis;
mOuterFrame->GetNumberOfVisibleRows(&vis);
if (index > 0 && index + vis >= rowCount) {
// Danger, Will Robinson, danger! We need to scroll backwards.
mOuterFrame->ClearRowGroupInfo();
PRInt32 newCount = mOuterFrame->GetRowCount();
PRInt32 delta = rowCount - newCount;
mOuterFrame->ScrollToIndex(index-delta);
if (index-delta <= 0) {
// Repaint the world.
mOuterFrame->Redraw(state, nsnull, PR_FALSE);
}
return;
}
}
MarkDirtyChildren(state);

View File

@ -86,7 +86,7 @@ public:
// Responses to changes
void OnContentInserted(nsIPresContext* aPresContext, nsIFrame* aNextSibling, PRInt32 aIndex);
void OnContentRemoved(nsIPresContext* aPresContext, nsIFrame* aChildFrame, PRInt32 aIndex);
void OnContentRemoved(nsIPresContext* aPresContext, nsIFrame* aChildFrame, PRInt32 aIndex, PRInt32& aOnScreenRowCount);
// nsIXULTreeSlice
NS_IMETHOD IsOutermostFrame(PRBool* aResult) { *aResult = PR_FALSE; return NS_OK; };

View File

@ -230,7 +230,7 @@ NS_NewXULTreeOuterGroupFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRB
// Constructor
nsXULTreeOuterGroupFrame::nsXULTreeOuterGroupFrame(nsIPresShell* aPresShell, PRBool aIsRoot, nsIBoxLayout* aLayoutManager, PRBool aIsHorizontal)
:nsXULTreeGroupFrame(aPresShell, aIsRoot, aLayoutManager, aIsHorizontal),
mRowGroupInfo(nsnull), mRowHeight(0), mCurrentIndex(0),
mBatchCount(0), mRowGroupInfo(nsnull), mRowHeight(0), mCurrentIndex(0), mOldIndex(0),
mTreeIsSorted(PR_FALSE), mDragOverListener(nsnull), mCanDropBetweenRows(PR_TRUE),
mRowHeightWasSet(PR_FALSE), mReflowCallbackPosted(PR_FALSE), mYPosition(0), mScrolling(PR_FALSE),
mScrollSmoother(nsnull), mTimePerRow(TIME_PER_ROW_INITAL), mAdjustScroll(PR_FALSE)
@ -545,6 +545,9 @@ nsXULTreeOuterGroupFrame::ScrollbarButtonPressed(PRInt32 aOldIndex, PRInt32 aNew
NS_IMETHODIMP
nsXULTreeOuterGroupFrame::PositionChanged(PRInt32 aOldIndex, PRInt32& aNewIndex)
{
if (mScrolling)
return NS_OK;
PRInt32 oldTwipIndex, newTwipIndex;
oldTwipIndex = mCurrentIndex*mRowHeight;
newTwipIndex = (aNewIndex*mOnePixel);
@ -627,31 +630,26 @@ nsXULTreeOuterGroupFrame::InternalPositionChangedCallback()
}
NS_IMETHODIMP
nsXULTreeOuterGroupFrame::InternalPositionChanged(PRBool aUp, PRInt32 aDelta)
nsXULTreeOuterGroupFrame::InternalPositionChanged(PRBool aUp, PRInt32 aDelta, PRBool aForceDestruct)
{
if (aDelta == 0)
return NS_OK;
// begin timing how long it takes to scroll a row
PRTime start = PR_Now();
// begin timing how long it takes to scroll a row
PRTime start = PR_Now();
//printf("Actually doing scroll mCurrentIndex=%d, delta=%d!\n", mCurrentIndex, aDelta);
//printf("Actually doing scroll mCurrentIndex=%d, delta=%d!\n", mCurrentIndex, aDelta);
//if (mContentChain) {
// XXX 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 and make sure we're dirty.
nsCOMPtr<nsIPresShell> shell;
mPresContext->GetShell(getter_AddRefs(shell));
shell->FlushPendingNotifications();
// }
nsCOMPtr<nsIPresShell> shell;
mPresContext->GetShell(getter_AddRefs(shell));
shell->FlushPendingNotifications();
PRInt32 visibleRows = 0;
if (mRowHeight)
visibleRows = GetAvailableHeight()/mRowHeight;
// Get our presentation context.
if (aDelta < visibleRows) {
if (aDelta < visibleRows && !aForceDestruct) {
PRInt32 loseRows = aDelta;
// scrolling down
@ -710,15 +708,16 @@ nsXULTreeOuterGroupFrame::InternalPositionChanged(PRBool aUp, PRInt32 aDelta)
mYPosition = mCurrentIndex*mRowHeight;
nsBoxLayoutState state(mPresContext);
nsCOMPtr<nsIBoxLayout> layout;
GetLayoutManager(getter_AddRefs(layout));
nsTreeLayout* treeLayout = (nsTreeLayout*)layout.get();
treeLayout->LazyRowCreator(state, this);
mScrolling = PR_TRUE;
MarkDirtyChildren(state);
shell->FlushPendingNotifications();
mScrolling = PR_FALSE;
VerticalScroll(mYPosition);
if (aForceDestruct)
Redraw(state, nsnull, PR_FALSE);
PRTime end = PR_Now();
PRTime difTime;
@ -1092,6 +1091,10 @@ nsXULTreeOuterGroupFrame::FindNextRowContent(PRInt32& aDelta, nsIContent* aUpwar
void
nsXULTreeOuterGroupFrame::EnsureRowIsVisible(PRInt32 aRowIndex)
{
NS_ASSERTION(aRowIndex >= 0, "Ensure row is visible called with a negative number!");
if (aRowIndex < 0)
return;
PRInt32 rows = 0;
if (mRowHeight)
rows = GetAvailableHeight()/mRowHeight;
@ -1106,8 +1109,8 @@ nsXULTreeOuterGroupFrame::EnsureRowIsVisible(PRInt32 aRowIndex)
PRBool up = aRowIndex < mCurrentIndex;
if (up) {
mCurrentIndex = aRowIndex;
delta = mCurrentIndex - aRowIndex;
mCurrentIndex = aRowIndex;
}
else {
// Bring it just into view.
@ -1119,7 +1122,7 @@ nsXULTreeOuterGroupFrame::EnsureRowIsVisible(PRInt32 aRowIndex)
}
void
nsXULTreeOuterGroupFrame::ScrollToIndex(PRInt32 aRowIndex)
nsXULTreeOuterGroupFrame::ScrollToIndex(PRInt32 aRowIndex, PRBool aForceDestruct)
{
if (( aRowIndex < 0 ) || (mRowHeight == 0))
return;
@ -1130,11 +1133,14 @@ nsXULTreeOuterGroupFrame::ScrollToIndex(PRInt32 aRowIndex)
// Check to be sure we're not scrolling off the bottom of the tree
PRInt32 lastPageTopRow = GetRowCount() - (GetAvailableHeight() / mRowHeight);
if (lastPageTopRow < 0)
lastPageTopRow = 0;
if (aRowIndex > lastPageTopRow)
return;
mCurrentIndex = newIndex;
InternalPositionChanged(up, delta);
InternalPositionChanged(up, delta, aForceDestruct);
// This change has to happen immediately.
// Flush any pending reflow commands.
@ -1206,6 +1212,24 @@ nsXULTreeOuterGroupFrame::IndexOfItem(nsIContent* aRoot, nsIContent* aContent,
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsXULTreeOuterGroupFrame::EndBatch()
{
NS_ASSERTION(mBatchCount, "EndBatch called on a tree that isn't batching!\n");
if (mBatchCount == 0)
return NS_OK;
mBatchCount--;
if (mBatchCount == 0) {
if (mCurrentIndex == mOldIndex) {
nsBoxLayoutState state(mPresContext);
MarkDirtyChildren(state);
}
else ScrollToIndex(mCurrentIndex, PR_TRUE);
}
return NS_OK;
}
NS_IMETHODIMP
nsXULTreeOuterGroupFrame::ReflowFinished(nsIPresShell* aPresShell, PRBool* aFlushFlag)
{
@ -1251,6 +1275,82 @@ nsXULTreeOuterGroupFrame::ReflowFinished(nsIPresShell* aPresShell, PRBool* aFlus
return NS_OK;
}
void
nsXULTreeOuterGroupFrame::RegenerateRowGroupInfo(PRBool aOnScreenCount)
{
NeedsRecalc();
PRInt32 oldRowCount = GetRowCount();
if (mRowGroupInfo)
mRowGroupInfo->Clear();
PRInt32 newRowCount = GetRowCount();
if (mRowHeight <= 0)
return;
// For removal only, we need to know how many rows are onscreen. These subtract
// from the amount that we need to adjust. For example, if the tree widget is
// scrolled to index 40, and if a folder that is offscreen at index 0
// is deleted, and it contains 9 kids, then a total of 10 rows are vanishing.
// newRowCount - oldRowCount will be -10 following the removal. However, if 4 of those
// 10 rows were onscreen, then the tree widget's index only needs to be adjusted by
// -6 (-10 + 4).
PRInt32 delta = newRowCount-oldRowCount+aOnScreenCount;
PRInt32 newIndex = mCurrentIndex + delta;
PRBool adjust = PR_FALSE;
// Check to be sure we're not scrolling off the bottom of the tree
PRInt32 lastPageTopRow = newRowCount - (GetAvailableHeight() / mRowHeight);
if (lastPageTopRow < 0) {
if (aOnScreenCount > 0)
adjust = PR_TRUE;
lastPageTopRow = 0;
}
if (newIndex > lastPageTopRow) {
newIndex = lastPageTopRow;
if (aOnScreenCount > 0)
adjust = PR_TRUE;
}
if (newIndex < 0)
newIndex = 0;
if (!adjust) {
if (mCurrentIndex == 0 || delta == 0)
return; // Just a simple update or we aren't scrolled, so bail.
nsCOMPtr<nsIContent> row;
GetFirstRowContent(getter_AddRefs(row));
NS_ASSERTION(row, "No row in regen check!");
if (!row)
return;
// An element was passed in that was either removed or added.
// We need to adjust our scroll position if this element's index
// is < our current scrolled index.
PRInt32 index = 0;
nsCOMPtr<nsIContent> item;
row->GetParent(*getter_AddRefs(item));
IndexOfItem(mContent, item, PR_FALSE, PR_TRUE, &index);
if (index == -1 || index == mCurrentIndex)
return;
}
// We mark the outer row group dirty and force a comprehensive
// rebuild of all tree widget frames. This ensures that we
// stay precisely in sync whenever we lose content from above.
if (IsBatching())
mCurrentIndex = newIndex;
else ScrollToIndex(newIndex, !adjust);
if (adjust) {
// Force a full redraw.
nsBoxLayoutState state(mPresContext);
Redraw(state, nsnull, PR_FALSE);
}
}
//
// Paint
//
@ -1261,6 +1361,7 @@ nsXULTreeOuterGroupFrame :: Paint ( nsIPresContext* aPresContext, nsIRenderingCo
const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer)
{
nsresult res = NS_OK;
res = nsBoxFrame::Paint ( aPresContext, aRenderingContext, aDirtyRect, aWhichLayer );
if ( (aWhichLayer == eFramePaintLayer_Content) &&

View File

@ -130,7 +130,7 @@ public:
return mRowHeight;
}
void ClearRowGroupInfo() { if (mRowGroupInfo) mRowGroupInfo->Clear(); NeedsRecalc(); };
void RegenerateRowGroupInfo(PRInt32 aOnscreenCount);
void SetRowHeight(PRInt32 aRowHeight);
PRBool IsFixedRowSize();
@ -147,6 +147,9 @@ public:
NS_IMETHOD GetRowCount(PRInt32* aResult) { *aResult = GetRowCount(); return NS_OK; }
NS_IMETHOD BeginBatch() { mBatchCount++; mOldIndex = mCurrentIndex; return NS_OK; }
NS_IMETHOD EndBatch();
NS_IMETHOD PositionChanged(PRInt32 aOldIndex, PRInt32& aNewIndex);
NS_IMETHOD ScrollbarButtonPressed(PRInt32 aOldIndex, PRInt32 aNewIndex);
NS_IMETHOD VisibilityChanged(PRBool aVisible);
@ -172,14 +175,14 @@ public:
// that the row is at the top of the screen (if the row was offscreen to start with).
void EnsureRowIsVisible(PRInt32 aRowIndex);
void ScrollToIndex(PRInt32 aRowIndex);
void ScrollToIndex(PRInt32 aRowIndex, PRBool aForceDestruct=PR_FALSE);
NS_IMETHOD IndexOfItem(nsIContent* aRoot, nsIContent* aContent,
PRBool aDescendIntoRows, // Invariant
PRBool aParentIsOpen,
PRInt32 *aResult);
NS_IMETHOD InternalPositionChanged(PRBool aUp, PRInt32 aDelta);
NS_IMETHOD InternalPositionChanged(PRBool aUp, PRInt32 aDelta, PRBool aForceDestruct=PR_FALSE);
NS_IMETHOD InternalPositionChangedCallback();
NS_IMETHOD Destroy(nsIPresContext* aPresContext);
@ -189,6 +192,7 @@ public:
void PostReflowCallback();
PRBool IsBatching() const { return mBatchCount > 0; };
protected:
@ -203,10 +207,12 @@ protected:
nsresult StopScrollTracking();
#endif
PRUint32 mBatchCount;
nsXULTreeRowGroupInfo* mRowGroupInfo;
PRInt32 mRowHeight;
nscoord mOnePixel;
PRInt32 mCurrentIndex; // Row-based
PRInt32 mOldIndex;
PRPackedBool mTreeIsSorted;
PRPackedBool mCanDropBetweenRows; // is the user allowed to drop between rows