Not part of build.

This commit is contained in:
hyatt%netscape.com 2001-02-15 09:43:11 +00:00
parent f2a5ae0bb5
commit 19bd97bd08
23 changed files with 760 additions and 111 deletions

View File

@ -78,10 +78,13 @@ XUL_ATOM(open, "open") // Whether or not a menu, tree, etc. is open
XUL_ATOM(outliner, "outliner") XUL_ATOM(outliner, "outliner")
XUL_ATOM(outlinerbody, "outlinerbody") XUL_ATOM(outlinerbody, "outlinerbody")
XUL_ATOM(outlinercol, "outlinercol") XUL_ATOM(outlinercol, "outlinercol")
XUL_ATOM(mozoutlinerrow, ":moz-outliner-row") XUL_ATOM(cycler, "cycler")
XUL_ATOM(mozoutlinercell, ":moz-outliner-cell") XUL_ATOM(primary, "primary")
XUL_ATOM(mozoutlinertwisty, ":moz-outliner-twisty") XUL_ATOM(mozoutlinerrow, ":-moz-outliner-row")
XUL_ATOM(mozoutlinerindentation, ":moz-outliner-indentation") XUL_ATOM(mozoutlinercell, ":-moz-outliner-cell")
XUL_ATOM(mozoutlinercelltext, ":-moz-outliner-cell-text")
XUL_ATOM(mozoutlinertwisty, ":-moz-outliner-twisty")
XUL_ATOM(mozoutlinerindentation, ":-moz-outliner-indentation")
XUL_ATOM(menubar, "menubar") // An XP menu bar. XUL_ATOM(menubar, "menubar") // An XP menu bar.
XUL_ATOM(menu, "menu") // Represents an XP menu XUL_ATOM(menu, "menu") // Represents an XP menu

View File

@ -1,19 +1,24 @@
outlinerbody { outlinerbody {
background-color: white; background-color: white;
color: black; color: black;
-moz-user-select: none;
} }
:-moz-outliner-row :-moz-outliner-row(selected)
{ {
height: 19px; background-color: blue;
} }
:-moz-outliner-cell :-moz-outliner-cell(selected)
{ {
} }
:-moz-outliner-cell-text :-moz-outliner-cell-text
{ {
color: inherit;
} }
:-moz-outliner-cell-text(selected)
{
color: white;
}

View File

@ -32,7 +32,7 @@
<outlinercol id="Col2" value="Col2" flex="1"/> <outlinercol id="Col2" value="Col2" flex="1"/>
<outlinercol id="Col3" value="Col3" flex="1"/> <outlinercol id="Col3" value="Col3" flex="1"/>
<outlinercol id="Col4" value="Col4" flex="1"/> <outlinercol id="Col4" value="Col4" flex="1"/>
<outlinerbody flex="1"/> <outlinerbody flex="1" onselect="alert('sel changed!')"/>
</outliner> </outliner>
<hbox> <hbox>

View File

@ -29,9 +29,7 @@ include $(DEPTH)/config/autoconf.mk
MODULE = layout MODULE = layout
XPIDL_MODULE = layout_xul_outliner XPIDL_MODULE = layout_xul_outliner
XPIDLSRCS= nsIOutlinerRangeList.idl \ XPIDLSRCS= nsIOutlinerView.idl \
nsIOutlinerRange.idl \
nsIOutlinerView.idl \
nsIOutlinerSelection.idl \ nsIOutlinerSelection.idl \
nsIOutlinerBoxObject.idl \ nsIOutlinerBoxObject.idl \
nsIOutlinerColFrame.idl \ nsIOutlinerColFrame.idl \

View File

@ -21,9 +21,7 @@
DEPTH=..\..\..\..\..\.. DEPTH=..\..\..\..\..\..
XPIDLSRCS= .\nsIOutlinerRangeList.idl \ XPIDLSRCS= .\nsIOutlinerView.idl \
.\nsIOutlinerRange.idl \
.\nsIOutlinerView.idl \
.\nsIOutlinerSelection.idl \ .\nsIOutlinerSelection.idl \
.\nsIOutlinerBoxObject.idl \ .\nsIOutlinerBoxObject.idl \
.\nsIOutlinerColFrame.idl \ .\nsIOutlinerColFrame.idl \

View File

@ -23,8 +23,10 @@
*/ */
#include "nsISupports.idl" #include "nsISupports.idl"
#include "domstubs.idl"
interface nsIOutlinerView; interface nsIOutlinerView;
interface nsIOutlinerSelection;
[scriptable, uuid(8398C757-6387-480c-82B2-C914E15CE00D)] [scriptable, uuid(8398C757-6387-480c-82B2-C914E15CE00D)]
interface nsIOutlinerBoxObject : nsISupports interface nsIOutlinerBoxObject : nsISupports
@ -34,6 +36,12 @@ interface nsIOutlinerBoxObject : nsISupports
// outliner tag or by setting this attribute to a new value. // outliner tag or by setting this attribute to a new value.
attribute nsIOutlinerView view; attribute nsIOutlinerView view;
// Obtain the outlinerbody content node
readonly attribute nsIDOMElement outlinerBody;
// Obtains the selection from the view.
readonly attribute nsIOutlinerSelection selection;
// Get the index of the first visible row. // Get the index of the first visible row.
long getIndexOfVisibleRow(); long getIndexOfVisibleRow();

View File

@ -24,10 +24,10 @@
interface nsIOutlinerBoxObject; interface nsIOutlinerBoxObject;
#include "nsISupports.idl" #include "nsISecurityCheckedComponent.idl"
[scriptable, uuid(F848D7CF-F3D6-4775-8C9F-135546E61E1E)] [scriptable, uuid(F848D7CF-F3D6-4775-8C9F-135546E61E1E)]
interface nsIOutlinerSelection : nsISupports interface nsIOutlinerSelection : nsISecurityCheckedComponent
{ {
// The outliner widget for this selection. // The outliner widget for this selection.
attribute nsIOutlinerBoxObject outliner; attribute nsIOutlinerBoxObject outliner;

View File

@ -75,6 +75,10 @@ interface nsIOutlinerView : nsISupports
// Called on the view when a header is clicked. // Called on the view when a header is clicked.
void cycleHeader(in nsIDOMElement elt); void cycleHeader(in nsIDOMElement elt);
// Should be called from a XUL onselect handler whenever the selection changes.
// XXX Should this be done automatically?
void selectionChanged();
// Called on the view when a cell in a non-selectable cycling column (e.g., unread/flag/etc.) is clicked. // Called on the view when a cell in a non-selectable cycling column (e.g., unread/flag/etc.) is clicked.
void cycleCell(in long row, in wstring colID); void cycleCell(in long row, in wstring colID);

View File

@ -36,8 +36,11 @@
#include "nsIContent.h" #include "nsIContent.h"
#include "nsIStyleContext.h" #include "nsIStyleContext.h"
#include "nsIBoxObject.h"
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "nsIDOMNodeList.h" #include "nsIDOMNodeList.h"
#include "nsIDOMNSDocument.h"
#include "nsIDocument.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "nsICSSStyleRule.h" #include "nsICSSStyleRule.h"
#include "nsCSSRendering.h" #include "nsCSSRendering.h"
@ -77,8 +80,8 @@ nsOutlinerStyleCache::GetStyleContext(nsICSSPseudoComparator* aComparator,
if (!currState) { if (!currState) {
// We had a miss. Make a new state and add it to our hash. // We had a miss. Make a new state and add it to our hash.
mNextState++;
currState = new nsDFAState(mNextState); currState = new nsDFAState(mNextState);
mNextState++;
mTransitionTable->Put(&key, currState); mTransitionTable->Put(&key, currState);
} }
@ -292,7 +295,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::SetView(nsIOutlinerView * aView)
mView->SetSelection(sel); mView->SetSelection(sel);
} }
// Changing the view causes us to refetch our data. This will // Changing the view causes us to refetch our data. This will
// necessarily entail a full invalidation of the outliner. // necessarily entail a full invalidation of the outliner.
mTopRowIndex = 0; mTopRowIndex = 0;
@ -303,6 +306,21 @@ NS_IMETHODIMP nsOutlinerBodyFrame::SetView(nsIOutlinerView * aView)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsOutlinerBodyFrame::GetOutlinerBody(nsIDOMElement** aElement)
{
return mContent->QueryInterface(NS_GET_IID(nsIDOMElement), (void**)aElement);
}
NS_IMETHODIMP nsOutlinerBodyFrame::GetSelection(nsIOutlinerSelection** aSelection)
{
if (mView)
return mView->GetSelection(aSelection);
*aSelection = nsnull;
return NS_OK;
}
NS_IMETHODIMP nsOutlinerBodyFrame::GetIndexOfVisibleRow(PRInt32 *_retval) NS_IMETHODIMP nsOutlinerBodyFrame::GetIndexOfVisibleRow(PRInt32 *_retval)
{ {
*_retval = mTopRowIndex; *_retval = mTopRowIndex;
@ -324,16 +342,37 @@ NS_IMETHODIMP nsOutlinerBodyFrame::Invalidate()
NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRow(PRInt32 aIndex) NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRow(PRInt32 aIndex)
{ {
if (aIndex < mTopRowIndex || aIndex > mTopRowIndex + mPageCount + 1)
return NS_OK;
nsRect rowRect(mInnerBox.x, mInnerBox.y+mRowHeight*(aIndex-mTopRowIndex), mInnerBox.width, mRowHeight);
nsLeafBoxFrame::Invalidate(mPresContext, rowRect, PR_FALSE);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateCell(PRInt32 aRow, const PRUnichar *aColID) NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateCell(PRInt32 aRow, const PRUnichar *aColID)
{ {
return NS_OK; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRange(PRInt32 aStart, PRInt32 aEnd) NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRange(PRInt32 aStart, PRInt32 aEnd)
{ {
if (aStart == aEnd)
return InvalidateRow(aStart);
if (aEnd < mTopRowIndex || aStart > mTopRowIndex + mPageCount + 1)
return NS_OK;
if (aStart < mTopRowIndex)
aStart = mTopRowIndex;
if (aEnd > mTopRowIndex + mPageCount + 1)
aEnd = mTopRowIndex + mPageCount + 1;
nsRect rangeRect(mInnerBox.x, mInnerBox.y+mRowHeight*(aStart-mTopRowIndex), mInnerBox.width, mRowHeight*(aEnd-aStart+1));
nsLeafBoxFrame::Invalidate(mPresContext, rangeRect, PR_FALSE);
return NS_OK; return NS_OK;
} }
@ -371,8 +410,47 @@ NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateScrollbar()
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsOutlinerBodyFrame::GetCellAt(PRInt32 x, PRInt32 y, PRInt32 *row, PRUnichar **colID) NS_IMETHODIMP nsOutlinerBodyFrame::GetCellAt(PRInt32 aX, PRInt32 aY, PRInt32* aRow, PRUnichar** aColID)
{ {
// Ensure we have a row height.
if (mRowHeight == 0)
mRowHeight = GetRowHeight();
// Convert our x and y coords to twips.
float pixelsToTwips = 0.0;
mPresContext->GetPixelsToTwips(&pixelsToTwips);
aX = NSToIntRound(aX * pixelsToTwips);
aY = NSToIntRound(aY * pixelsToTwips);
// Get our box object.
nsCOMPtr<nsIDocument> doc;
mContent->GetDocument(*getter_AddRefs(doc));
nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(doc));
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mContent));
nsCOMPtr<nsIBoxObject> boxObject;
nsDoc->GetBoxObjectFor(elt, getter_AddRefs(boxObject));
PRInt32 x;
PRInt32 y;
boxObject->GetX(&x);
boxObject->GetY(&y);
x = NSToIntRound(x * pixelsToTwips);
y = NSToIntRound(y * pixelsToTwips);
// Adjust into our coordinate space.
x = aX-x;
y = aY-y;
// Adjust y by the inner box y, so that we're in the inner box's
// coordinate space.
y += mInnerBox.y;
// Now just mod by our total inner box height and add to our top row index.
*aRow = (y/mRowHeight)+mTopRowIndex;
// XXX Determine the column hit!
return NS_OK; return NS_OK;
} }
@ -407,13 +485,13 @@ nsOutlinerBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, const PRUnichar* aC
} }
PRInt32 nsOutlinerBodyFrame::GetRowHeight(nsIPresContext* aPresContext) PRInt32 nsOutlinerBodyFrame::GetRowHeight()
{ {
// Look up the correct height. It is equal to the specified height // Look up the correct height. It is equal to the specified height
// + the specified margins. // + the specified margins.
nsCOMPtr<nsIStyleContext> rowContext; nsCOMPtr<nsIStyleContext> rowContext;
mScratchArray->Clear(); mScratchArray->Clear();
GetPseudoStyleContext(aPresContext, nsXULAtoms::mozoutlinerrow, getter_AddRefs(rowContext)); GetPseudoStyleContext(mPresContext, nsXULAtoms::mozoutlinerrow, getter_AddRefs(rowContext));
if (rowContext) { if (rowContext) {
const nsStylePosition* myPosition = (const nsStylePosition*) const nsStylePosition* myPosition = (const nsStylePosition*)
rowContext->GetStyleData(eStyleStruct_Position); rowContext->GetStyleData(eStyleStruct_Position);
@ -432,7 +510,7 @@ PRInt32 nsOutlinerBodyFrame::GetRowHeight(nsIPresContext* aPresContext)
return val; return val;
} }
} }
return 16; // As good a default as any. return 19*15; // As good a default as any.
} }
nsRect nsOutlinerBodyFrame::GetInnerBox() nsRect nsOutlinerBodyFrame::GetInnerBox()
@ -476,7 +554,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::Paint(nsIPresContext* aPresContext,
// Update our page count, our available height and our row height. // Update our page count, our available height and our row height.
PRInt32 oldRowHeight = mRowHeight; PRInt32 oldRowHeight = mRowHeight;
mRowHeight = GetRowHeight(aPresContext); mRowHeight = GetRowHeight();
mInnerBox = GetInnerBox(); mInnerBox = GetInnerBox();
mPageCount = mInnerBox.height/mRowHeight; mPageCount = mInnerBox.height/mRowHeight;
@ -487,11 +565,11 @@ NS_IMETHODIMP nsOutlinerBodyFrame::Paint(nsIPresContext* aPresContext,
mView->GetRowCount(&rowCount); mView->GetRowCount(&rowCount);
// Ensure our column info is built. // Ensure our column info is built.
EnsureColumns(aPresContext); EnsureColumns();
// Loop through our on-screen rows. // Loop through our on-screen rows.
for (PRInt32 i = mTopRowIndex; i < rowCount && i < mTopRowIndex+mPageCount+1; i++) { for (PRInt32 i = mTopRowIndex; i < rowCount && i < mTopRowIndex+mPageCount+1; i++) {
nsRect rowRect(0, mRowHeight*(i-mTopRowIndex), mInnerBox.width, mRowHeight); nsRect rowRect(mInnerBox.x, mInnerBox.y+mRowHeight*(i-mTopRowIndex), mInnerBox.width, mRowHeight);
nsRect dirtyRect; nsRect dirtyRect;
if (dirtyRect.IntersectRect(aDirtyRect, rowRect)) { if (dirtyRect.IntersectRect(aDirtyRect, rowRect)) {
PaintRow(i, rowRect, aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); PaintRow(i, rowRect, aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
@ -562,7 +640,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex,
{ {
// Now obtain the properties for our cell. // Now obtain the properties for our cell.
// XXX Automatically fill in the following props: open, container, selected, focused, and the col ID. // XXX Automatically fill in the following props: open, container, selected, focused, and the col ID.
mScratchArray->Clear(); PrefillPropertyArray(aRowIndex, NS_LITERAL_STRING(""));
mView->GetCellProperties(aRowIndex, aColumn->GetID(), mScratchArray); mView->GetCellProperties(aRowIndex, aColumn->GetID(), mScratchArray);
// Resolve style for the cell. It contains all the info we need to lay ourselves // Resolve style for the cell. It contains all the info we need to lay ourselves
@ -803,7 +881,7 @@ nsOutlinerBodyFrame::PseudoMatches(nsIAtom* aTag, nsCSSSelector* aSelector, PRBo
mScratchArray->GetIndexOf(curr->mAtom, &index); mScratchArray->GetIndexOf(curr->mAtom, &index);
if (index == -1) { if (index == -1) {
*aResult = PR_FALSE; *aResult = PR_FALSE;
break; return NS_OK;
} }
curr = curr->mNext; curr = curr->mNext;
} }
@ -816,7 +894,7 @@ nsOutlinerBodyFrame::PseudoMatches(nsIAtom* aTag, nsCSSSelector* aSelector, PRBo
} }
void void
nsOutlinerBodyFrame::EnsureColumns(nsIPresContext* aPresContext) nsOutlinerBodyFrame::EnsureColumns()
{ {
if (!mColumns) { if (!mColumns) {
nsCOMPtr<nsIContent> parent; nsCOMPtr<nsIContent> parent;
@ -827,7 +905,7 @@ nsOutlinerBodyFrame::EnsureColumns(nsIPresContext* aPresContext)
elt->GetElementsByTagName(NS_LITERAL_STRING("outlinercol"), getter_AddRefs(cols)); elt->GetElementsByTagName(NS_LITERAL_STRING("outlinercol"), getter_AddRefs(cols));
nsCOMPtr<nsIPresShell> shell; nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell)); mPresContext->GetShell(getter_AddRefs(shell));
PRUint32 count; PRUint32 count;
cols->GetLength(&count); cols->GetLength(&count);

View File

@ -25,7 +25,6 @@
#include "nsLeafBoxFrame.h" #include "nsLeafBoxFrame.h"
#include "nsIOutlinerBoxObject.h" #include "nsIOutlinerBoxObject.h"
#include "nsIOutlinerView.h" #include "nsIOutlinerView.h"
#include "nsIOutlinerRangeList.h"
#include "nsICSSPseudoComparator.h" #include "nsICSSPseudoComparator.h"
#include "nsIScrollbarMediator.h" #include "nsIScrollbarMediator.h"
#include "nsIWidget.h" #include "nsIWidget.h"
@ -212,7 +211,7 @@ protected:
virtual ~nsOutlinerBodyFrame(); virtual ~nsOutlinerBodyFrame();
// Returns the height of rows in the tree. // Returns the height of rows in the tree.
PRInt32 GetRowHeight(nsIPresContext* aPresContext); PRInt32 GetRowHeight();
// Returns our width/height once border and padding have been removed. // Returns our width/height once border and padding have been removed.
nsRect GetInnerBox(); nsRect GetInnerBox();
@ -222,7 +221,7 @@ protected:
nsresult GetPseudoStyleContext(nsIPresContext* aPresContext, nsIAtom* aPseudoElement, nsIStyleContext** aResult); nsresult GetPseudoStyleContext(nsIPresContext* aPresContext, nsIAtom* aPseudoElement, nsIStyleContext** aResult);
// Builds our cache of column info. // Builds our cache of column info.
void EnsureColumns(nsIPresContext* aContext); void EnsureColumns();
// Use to auto-fill some of the common properties without the view having to do it. // Use to auto-fill some of the common properties without the view having to do it.
// Examples include container, open, selected, and focused. // Examples include container, open, selected, and focused.

View File

@ -128,6 +128,22 @@ NS_IMETHODIMP nsOutlinerBoxObject::SetView(nsIOutlinerView * aView)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsOutlinerBoxObject::GetOutlinerBody(nsIDOMElement** aElement)
{
nsIOutlinerBoxObject* body = GetOutlinerBody();
if (body)
return body->GetOutlinerBody(aElement);
return NS_OK;
}
NS_IMETHODIMP nsOutlinerBoxObject::GetSelection(nsIOutlinerSelection * *aSelection)
{
nsIOutlinerBoxObject* body = GetOutlinerBody();
if (body)
return body->GetSelection(aSelection);
return NS_OK;
}
NS_IMETHODIMP nsOutlinerBoxObject::GetIndexOfVisibleRow(PRInt32 *_retval) NS_IMETHODIMP nsOutlinerBoxObject::GetIndexOfVisibleRow(PRInt32 *_retval)
{ {
nsIOutlinerBoxObject* body = GetOutlinerBody(); nsIOutlinerBoxObject* body = GetOutlinerBody();

View File

@ -24,6 +24,13 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsOutlinerSelection.h" #include "nsOutlinerSelection.h"
#include "nsIOutlinerBoxObject.h" #include "nsIOutlinerBoxObject.h"
#include "nsIOutlinerView.h"
#include "nsString.h"
#include "nsIDOMElement.h"
#include "nsIPresShell.h"
#include "nsIPresContext.h"
#include "nsIContent.h"
#include "nsIDocument.h"
// A helper class for managing our ranges of selection. // A helper class for managing our ranges of selection.
struct nsOutlinerRange struct nsOutlinerRange
@ -37,16 +44,76 @@ struct nsOutlinerRange
nsOutlinerSelection* mSelection; nsOutlinerSelection* mSelection;
nsOutlinerRange(nsOutlinerSelection* aSel, PRInt32 aSingleVal) nsOutlinerRange(nsOutlinerSelection* aSel, PRInt32 aSingleVal)
:mSelection(aSel), mNext(nsnull), mMin(aSingleVal), mMax(aSingleVal) {}; :mSelection(aSel), mPrev(nsnull), mNext(nsnull), mMin(aSingleVal), mMax(aSingleVal) {};
nsOutlinerRange(nsOutlinerSelection* aSel, PRInt32 aMin, PRInt32 aMax) :mNext(nsnull), mMin(aMin), mMax(aMax) {}; nsOutlinerRange(nsOutlinerSelection* aSel, PRInt32 aMin, PRInt32 aMax)
:mSelection(aSel), mPrev(nsnull), mNext(nsnull), mMin(aMin), mMax(aMax) {};
~nsOutlinerRange() { delete mNext; }; ~nsOutlinerRange() { delete mNext; };
void Connect(nsOutlinerRange* aPrev = nsnull, nsOutlinerRange* aNext = nsnull) { void Connect(nsOutlinerRange* aPrev = nsnull, nsOutlinerRange* aNext = nsnull) {
if (aPrev)
aPrev->mNext = this;
else
mSelection->mFirstRange = this;
if (aNext)
aNext->mPrev = this;
mPrev = aPrev; mPrev = aPrev;
mNext = aNext; mNext = aNext;
}; };
void Remove(PRInt32 aIndex) {
if (aIndex >= mMin && aIndex <= mMax) {
// We have found the range that contains us.
if (mMin == mMax) {
// Delete the whole range.
if (mPrev)
mPrev->mNext = mNext;
if (mNext)
mNext->mPrev = mPrev;
nsOutlinerRange* first = mSelection->mFirstRange;
if (first == this)
mSelection->mFirstRange = mNext;
mNext = mPrev = nsnull;
delete this;
}
else if (aIndex == mMin)
mMin++;
else if (aIndex == mMax)
mMax--;
}
else if (mNext)
mNext->Remove(aIndex);
};
void Add(PRInt32 aIndex) {
if (aIndex < mMin) {
// We have found a spot to insert.
if (aIndex + 1 == mMin)
mMin = aIndex;
else if (mPrev && mPrev->mMax+1 == aIndex)
mPrev->mMax = aIndex;
else {
// We have to create a new range.
nsOutlinerRange* newRange = new nsOutlinerRange(mSelection, aIndex);
newRange->Connect(mPrev, this);
}
}
else if (mNext)
mNext->Add(aIndex);
else {
// Insert on to the end.
if (mMax+1 == aIndex)
mMax = aIndex;
else {
// We have to create a new range.
nsOutlinerRange* newRange = new nsOutlinerRange(mSelection, aIndex);
newRange->Connect(this, nsnull);
}
}
};
PRBool Contains(PRInt32 aIndex) { PRBool Contains(PRInt32 aIndex) {
if (aIndex >= mMin && aIndex <= mMax) if (aIndex >= mMin && aIndex <= mMax)
return PR_TRUE; return PR_TRUE;
@ -72,6 +139,10 @@ struct nsOutlinerRange
void RemoveAllBut(PRInt32 aIndex) { void RemoveAllBut(PRInt32 aIndex) {
if (aIndex >= mMin && aIndex <= mMax) { if (aIndex >= mMin && aIndex <= mMax) {
// Invalidate everything in this list.
mSelection->mFirstRange->Invalidate();
mMin = aIndex; mMin = aIndex;
mMax = aIndex; mMax = aIndex;
@ -82,10 +153,10 @@ struct nsOutlinerRange
mNext->mPrev = mPrev; mNext->mPrev = mPrev;
mNext = mPrev = nsnull; mNext = mPrev = nsnull;
// Invalidate everything in this list. if (first != this) {
mSelection->mFirstRange->Invalidate(); delete mSelection->mFirstRange;
delete mSelection->mFirstRange; mSelection->mFirstRange = this;
mSelection->mFirstRange = this; }
} }
else if (mNext) else if (mNext)
mNext->RemoveAllBut(aIndex); mNext->RemoveAllBut(aIndex);
@ -105,7 +176,7 @@ nsOutlinerSelection::~nsOutlinerSelection()
delete mFirstRange; delete mFirstRange;
} }
NS_IMPL_ISUPPORTS1(nsOutlinerSelection, nsIOutlinerSelection) NS_IMPL_ISUPPORTS2(nsOutlinerSelection, nsIOutlinerSelection, nsISecurityCheckedComponent)
NS_IMETHODIMP nsOutlinerSelection::GetOutliner(nsIOutlinerBoxObject * *aOutliner) NS_IMETHODIMP nsOutlinerSelection::GetOutliner(nsIOutlinerBoxObject * *aOutliner)
{ {
@ -139,46 +210,116 @@ NS_IMETHODIMP nsOutlinerSelection::Select(PRInt32 aIndex)
if (count > 1) { if (count > 1) {
// We need to deselect everything but our item. // We need to deselect everything but our item.
mFirstRange->RemoveAllBut(aIndex); mFirstRange->RemoveAllBut(aIndex);
return NS_OK; FireOnSelectHandler();
} }
return NS_OK;
}
else {
// Clear out our selection.
mFirstRange->Invalidate();
delete mFirstRange;
} }
} }
delete mFirstRange; // Create our new selection.
mFirstRange = new nsOutlinerRange(this, aIndex); mFirstRange = new nsOutlinerRange(this, aIndex);
mFirstRange->Invalidate();
// XXX Fire the select event if not suppressed! // Fire the select event
FireOnSelectHandler();
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsOutlinerSelection::ToggleSelect(PRInt32 index) NS_IMETHODIMP nsOutlinerSelection::ToggleSelect(PRInt32 aIndex)
{ {
return NS_ERROR_NOT_IMPLEMENTED; // There are six cases that can occur on a ToggleSelect with our
// range code.
// (1) A new range should be made for a selection.
// (2) A single range is removed from the selection.
// (3) The item is added to an existing range.
// (4) The item is removed from an existing range.
// (5) The addition of the item causes two ranges to be merged.
// (6) The removal of the item causes two ranges to be split.
if (!mFirstRange)
Select(aIndex);
else {
if (!mFirstRange->Contains(aIndex))
mFirstRange->Add(aIndex);
else
mFirstRange->Remove(aIndex);
mOutliner->InvalidateRow(aIndex);
FireOnSelectHandler();
}
return NS_OK;
} }
NS_IMETHODIMP nsOutlinerSelection::RangedSelect(PRInt32 startIndex, PRInt32 endIndex) NS_IMETHODIMP nsOutlinerSelection::RangedSelect(PRInt32 aStartIndex, PRInt32 aEndIndex)
{ {
return NS_ERROR_NOT_IMPLEMENTED; // Clear our selection.
mFirstRange->Invalidate();
delete mFirstRange;
if (aStartIndex == -1)
aStartIndex = mCurrentIndex;
PRInt32 start = aStartIndex < aEndIndex ? aStartIndex : aEndIndex;
PRInt32 end = aStartIndex < aEndIndex ? aEndIndex : aStartIndex;
mFirstRange = new nsOutlinerRange(this, start, end);
mFirstRange->Invalidate();
FireOnSelectHandler();
return NS_OK;
} }
NS_IMETHODIMP nsOutlinerSelection::ClearSelection() NS_IMETHODIMP nsOutlinerSelection::ClearSelection()
{ {
return NS_ERROR_NOT_IMPLEMENTED; mFirstRange->Invalidate();
delete mFirstRange;
mFirstRange = nsnull;
FireOnSelectHandler();
return NS_OK;
} }
NS_IMETHODIMP nsOutlinerSelection::InvertSelection() NS_IMETHODIMP nsOutlinerSelection::InvertSelection()
{ {
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHODIMP nsOutlinerSelection::SelectAll() NS_IMETHODIMP nsOutlinerSelection::SelectAll()
{ {
return NS_ERROR_NOT_IMPLEMENTED; // Invalidate not necessary when clearing selection, since
// we're going to invalidate the world on the SelectAll.
delete mFirstRange;
nsCOMPtr<nsIOutlinerView> view;
mOutliner->GetView(getter_AddRefs(view));
if (!view)
return NS_OK;
PRInt32 rowCount;
view->GetRowCount(&rowCount);
if (rowCount == 0)
return NS_OK;
mFirstRange = new nsOutlinerRange(this, 0, rowCount-1);
mFirstRange->Invalidate();
FireOnSelectHandler();
return NS_OK;
} }
NS_IMETHODIMP nsOutlinerSelection::GetRangeCount(PRInt32 *_retval) NS_IMETHODIMP nsOutlinerSelection::GetRangeCount(PRInt32 *_retval)
{ {
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHODIMP nsOutlinerSelection::GetRangeAt(PRInt32 i, PRInt32 *min, PRInt32 *max) NS_IMETHODIMP nsOutlinerSelection::GetRangeAt(PRInt32 i, PRInt32 *min, PRInt32 *max)
@ -210,6 +351,72 @@ NS_IMETHODIMP nsOutlinerSelection::SetCurrentIndex(PRInt32 aCurrentIndex)
return NS_OK; return NS_OK;
} }
nsresult
nsOutlinerSelection::FireOnSelectHandler()
{
if (mSuppressed)
return NS_OK;
nsCOMPtr<nsIDOMElement> elt;
mOutliner->GetOutlinerBody(getter_AddRefs(elt));
nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
nsCOMPtr<nsIDocument> document;
content->GetDocument(*getter_AddRefs(document));
PRInt32 count = document->GetNumberOfShells();
for (PRInt32 i = 0; i < count; i++) {
nsCOMPtr<nsIPresShell> shell = getter_AddRefs(document->GetShellAt(i));
if (nsnull == shell)
continue;
// Retrieve the context in which our DOM event will fire.
nsCOMPtr<nsIPresContext> aPresContext;
shell->GetPresContext(getter_AddRefs(aPresContext));
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_FORM_SELECTED;
content->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
}
return NS_OK;
}
/* string canCreateWrapper (in nsIIDPtr iid); */
NS_IMETHODIMP nsOutlinerSelection::CanCreateWrapper(const nsIID * iid, char **_retval)
{
nsCAutoString str("AllAccess");
*_retval = str.ToNewCString();
return NS_OK;
}
/* string canCallMethod (in nsIIDPtr iid, in wstring methodName); */
NS_IMETHODIMP nsOutlinerSelection::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
{
nsCAutoString str("AllAccess");
*_retval = str.ToNewCString();
return NS_OK;
}
/* string canGetProperty (in nsIIDPtr iid, in wstring propertyName); */
NS_IMETHODIMP nsOutlinerSelection::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
{
nsCAutoString str("AllAccess");
*_retval = str.ToNewCString();
return NS_OK;
}
/* string canSetProperty (in nsIIDPtr iid, in wstring propertyName); */
NS_IMETHODIMP nsOutlinerSelection::CanSetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
{
nsCAutoString str("AllAccess");
*_retval = str.ToNewCString();
return NS_OK;
}
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
nsresult nsresult

View File

@ -36,9 +36,13 @@ public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_NSIOUTLINERSELECTION NS_DECL_NSIOUTLINERSELECTION
NS_DECL_NSISECURITYCHECKEDCOMPONENT
friend struct nsOutlinerRange; friend struct nsOutlinerRange;
protected:
nsresult FireOnSelectHandler();
protected: protected:
// Members // Members
nsIOutlinerBoxObject* mOutliner; // [Weak]. The outliner will hold on to us through the view and let go when it dies. nsIOutlinerBoxObject* mOutliner; // [Weak]. The outliner will hold on to us through the view and let go when it dies.

View File

@ -23,8 +23,10 @@
*/ */
#include "nsISupports.idl" #include "nsISupports.idl"
#include "domstubs.idl"
interface nsIOutlinerView; interface nsIOutlinerView;
interface nsIOutlinerSelection;
[scriptable, uuid(8398C757-6387-480c-82B2-C914E15CE00D)] [scriptable, uuid(8398C757-6387-480c-82B2-C914E15CE00D)]
interface nsIOutlinerBoxObject : nsISupports interface nsIOutlinerBoxObject : nsISupports
@ -34,6 +36,12 @@ interface nsIOutlinerBoxObject : nsISupports
// outliner tag or by setting this attribute to a new value. // outliner tag or by setting this attribute to a new value.
attribute nsIOutlinerView view; attribute nsIOutlinerView view;
// Obtain the outlinerbody content node
readonly attribute nsIDOMElement outlinerBody;
// Obtains the selection from the view.
readonly attribute nsIOutlinerSelection selection;
// Get the index of the first visible row. // Get the index of the first visible row.
long getIndexOfVisibleRow(); long getIndexOfVisibleRow();

View File

@ -24,10 +24,10 @@
interface nsIOutlinerBoxObject; interface nsIOutlinerBoxObject;
#include "nsISupports.idl" #include "nsISecurityCheckedComponent.idl"
[scriptable, uuid(F848D7CF-F3D6-4775-8C9F-135546E61E1E)] [scriptable, uuid(F848D7CF-F3D6-4775-8C9F-135546E61E1E)]
interface nsIOutlinerSelection : nsISupports interface nsIOutlinerSelection : nsISecurityCheckedComponent
{ {
// The outliner widget for this selection. // The outliner widget for this selection.
attribute nsIOutlinerBoxObject outliner; attribute nsIOutlinerBoxObject outliner;

View File

@ -75,6 +75,10 @@ interface nsIOutlinerView : nsISupports
// Called on the view when a header is clicked. // Called on the view when a header is clicked.
void cycleHeader(in nsIDOMElement elt); void cycleHeader(in nsIDOMElement elt);
// Should be called from a XUL onselect handler whenever the selection changes.
// XXX Should this be done automatically?
void selectionChanged();
// Called on the view when a cell in a non-selectable cycling column (e.g., unread/flag/etc.) is clicked. // Called on the view when a cell in a non-selectable cycling column (e.g., unread/flag/etc.) is clicked.
void cycleCell(in long row, in wstring colID); void cycleCell(in long row, in wstring colID);

View File

@ -36,8 +36,11 @@
#include "nsIContent.h" #include "nsIContent.h"
#include "nsIStyleContext.h" #include "nsIStyleContext.h"
#include "nsIBoxObject.h"
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "nsIDOMNodeList.h" #include "nsIDOMNodeList.h"
#include "nsIDOMNSDocument.h"
#include "nsIDocument.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "nsICSSStyleRule.h" #include "nsICSSStyleRule.h"
#include "nsCSSRendering.h" #include "nsCSSRendering.h"
@ -77,8 +80,8 @@ nsOutlinerStyleCache::GetStyleContext(nsICSSPseudoComparator* aComparator,
if (!currState) { if (!currState) {
// We had a miss. Make a new state and add it to our hash. // We had a miss. Make a new state and add it to our hash.
mNextState++;
currState = new nsDFAState(mNextState); currState = new nsDFAState(mNextState);
mNextState++;
mTransitionTable->Put(&key, currState); mTransitionTable->Put(&key, currState);
} }
@ -292,7 +295,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::SetView(nsIOutlinerView * aView)
mView->SetSelection(sel); mView->SetSelection(sel);
} }
// Changing the view causes us to refetch our data. This will // Changing the view causes us to refetch our data. This will
// necessarily entail a full invalidation of the outliner. // necessarily entail a full invalidation of the outliner.
mTopRowIndex = 0; mTopRowIndex = 0;
@ -303,6 +306,21 @@ NS_IMETHODIMP nsOutlinerBodyFrame::SetView(nsIOutlinerView * aView)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsOutlinerBodyFrame::GetOutlinerBody(nsIDOMElement** aElement)
{
return mContent->QueryInterface(NS_GET_IID(nsIDOMElement), (void**)aElement);
}
NS_IMETHODIMP nsOutlinerBodyFrame::GetSelection(nsIOutlinerSelection** aSelection)
{
if (mView)
return mView->GetSelection(aSelection);
*aSelection = nsnull;
return NS_OK;
}
NS_IMETHODIMP nsOutlinerBodyFrame::GetIndexOfVisibleRow(PRInt32 *_retval) NS_IMETHODIMP nsOutlinerBodyFrame::GetIndexOfVisibleRow(PRInt32 *_retval)
{ {
*_retval = mTopRowIndex; *_retval = mTopRowIndex;
@ -324,16 +342,37 @@ NS_IMETHODIMP nsOutlinerBodyFrame::Invalidate()
NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRow(PRInt32 aIndex) NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRow(PRInt32 aIndex)
{ {
if (aIndex < mTopRowIndex || aIndex > mTopRowIndex + mPageCount + 1)
return NS_OK;
nsRect rowRect(mInnerBox.x, mInnerBox.y+mRowHeight*(aIndex-mTopRowIndex), mInnerBox.width, mRowHeight);
nsLeafBoxFrame::Invalidate(mPresContext, rowRect, PR_FALSE);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateCell(PRInt32 aRow, const PRUnichar *aColID) NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateCell(PRInt32 aRow, const PRUnichar *aColID)
{ {
return NS_OK; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRange(PRInt32 aStart, PRInt32 aEnd) NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRange(PRInt32 aStart, PRInt32 aEnd)
{ {
if (aStart == aEnd)
return InvalidateRow(aStart);
if (aEnd < mTopRowIndex || aStart > mTopRowIndex + mPageCount + 1)
return NS_OK;
if (aStart < mTopRowIndex)
aStart = mTopRowIndex;
if (aEnd > mTopRowIndex + mPageCount + 1)
aEnd = mTopRowIndex + mPageCount + 1;
nsRect rangeRect(mInnerBox.x, mInnerBox.y+mRowHeight*(aStart-mTopRowIndex), mInnerBox.width, mRowHeight*(aEnd-aStart+1));
nsLeafBoxFrame::Invalidate(mPresContext, rangeRect, PR_FALSE);
return NS_OK; return NS_OK;
} }
@ -371,8 +410,47 @@ NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateScrollbar()
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsOutlinerBodyFrame::GetCellAt(PRInt32 x, PRInt32 y, PRInt32 *row, PRUnichar **colID) NS_IMETHODIMP nsOutlinerBodyFrame::GetCellAt(PRInt32 aX, PRInt32 aY, PRInt32* aRow, PRUnichar** aColID)
{ {
// Ensure we have a row height.
if (mRowHeight == 0)
mRowHeight = GetRowHeight();
// Convert our x and y coords to twips.
float pixelsToTwips = 0.0;
mPresContext->GetPixelsToTwips(&pixelsToTwips);
aX = NSToIntRound(aX * pixelsToTwips);
aY = NSToIntRound(aY * pixelsToTwips);
// Get our box object.
nsCOMPtr<nsIDocument> doc;
mContent->GetDocument(*getter_AddRefs(doc));
nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(doc));
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mContent));
nsCOMPtr<nsIBoxObject> boxObject;
nsDoc->GetBoxObjectFor(elt, getter_AddRefs(boxObject));
PRInt32 x;
PRInt32 y;
boxObject->GetX(&x);
boxObject->GetY(&y);
x = NSToIntRound(x * pixelsToTwips);
y = NSToIntRound(y * pixelsToTwips);
// Adjust into our coordinate space.
x = aX-x;
y = aY-y;
// Adjust y by the inner box y, so that we're in the inner box's
// coordinate space.
y += mInnerBox.y;
// Now just mod by our total inner box height and add to our top row index.
*aRow = (y/mRowHeight)+mTopRowIndex;
// XXX Determine the column hit!
return NS_OK; return NS_OK;
} }
@ -407,13 +485,13 @@ nsOutlinerBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, const PRUnichar* aC
} }
PRInt32 nsOutlinerBodyFrame::GetRowHeight(nsIPresContext* aPresContext) PRInt32 nsOutlinerBodyFrame::GetRowHeight()
{ {
// Look up the correct height. It is equal to the specified height // Look up the correct height. It is equal to the specified height
// + the specified margins. // + the specified margins.
nsCOMPtr<nsIStyleContext> rowContext; nsCOMPtr<nsIStyleContext> rowContext;
mScratchArray->Clear(); mScratchArray->Clear();
GetPseudoStyleContext(aPresContext, nsXULAtoms::mozoutlinerrow, getter_AddRefs(rowContext)); GetPseudoStyleContext(mPresContext, nsXULAtoms::mozoutlinerrow, getter_AddRefs(rowContext));
if (rowContext) { if (rowContext) {
const nsStylePosition* myPosition = (const nsStylePosition*) const nsStylePosition* myPosition = (const nsStylePosition*)
rowContext->GetStyleData(eStyleStruct_Position); rowContext->GetStyleData(eStyleStruct_Position);
@ -432,7 +510,7 @@ PRInt32 nsOutlinerBodyFrame::GetRowHeight(nsIPresContext* aPresContext)
return val; return val;
} }
} }
return 16; // As good a default as any. return 19*15; // As good a default as any.
} }
nsRect nsOutlinerBodyFrame::GetInnerBox() nsRect nsOutlinerBodyFrame::GetInnerBox()
@ -476,7 +554,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::Paint(nsIPresContext* aPresContext,
// Update our page count, our available height and our row height. // Update our page count, our available height and our row height.
PRInt32 oldRowHeight = mRowHeight; PRInt32 oldRowHeight = mRowHeight;
mRowHeight = GetRowHeight(aPresContext); mRowHeight = GetRowHeight();
mInnerBox = GetInnerBox(); mInnerBox = GetInnerBox();
mPageCount = mInnerBox.height/mRowHeight; mPageCount = mInnerBox.height/mRowHeight;
@ -487,11 +565,11 @@ NS_IMETHODIMP nsOutlinerBodyFrame::Paint(nsIPresContext* aPresContext,
mView->GetRowCount(&rowCount); mView->GetRowCount(&rowCount);
// Ensure our column info is built. // Ensure our column info is built.
EnsureColumns(aPresContext); EnsureColumns();
// Loop through our on-screen rows. // Loop through our on-screen rows.
for (PRInt32 i = mTopRowIndex; i < rowCount && i < mTopRowIndex+mPageCount+1; i++) { for (PRInt32 i = mTopRowIndex; i < rowCount && i < mTopRowIndex+mPageCount+1; i++) {
nsRect rowRect(0, mRowHeight*(i-mTopRowIndex), mInnerBox.width, mRowHeight); nsRect rowRect(mInnerBox.x, mInnerBox.y+mRowHeight*(i-mTopRowIndex), mInnerBox.width, mRowHeight);
nsRect dirtyRect; nsRect dirtyRect;
if (dirtyRect.IntersectRect(aDirtyRect, rowRect)) { if (dirtyRect.IntersectRect(aDirtyRect, rowRect)) {
PaintRow(i, rowRect, aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); PaintRow(i, rowRect, aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
@ -562,7 +640,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex,
{ {
// Now obtain the properties for our cell. // Now obtain the properties for our cell.
// XXX Automatically fill in the following props: open, container, selected, focused, and the col ID. // XXX Automatically fill in the following props: open, container, selected, focused, and the col ID.
mScratchArray->Clear(); PrefillPropertyArray(aRowIndex, NS_LITERAL_STRING(""));
mView->GetCellProperties(aRowIndex, aColumn->GetID(), mScratchArray); mView->GetCellProperties(aRowIndex, aColumn->GetID(), mScratchArray);
// Resolve style for the cell. It contains all the info we need to lay ourselves // Resolve style for the cell. It contains all the info we need to lay ourselves
@ -803,7 +881,7 @@ nsOutlinerBodyFrame::PseudoMatches(nsIAtom* aTag, nsCSSSelector* aSelector, PRBo
mScratchArray->GetIndexOf(curr->mAtom, &index); mScratchArray->GetIndexOf(curr->mAtom, &index);
if (index == -1) { if (index == -1) {
*aResult = PR_FALSE; *aResult = PR_FALSE;
break; return NS_OK;
} }
curr = curr->mNext; curr = curr->mNext;
} }
@ -816,7 +894,7 @@ nsOutlinerBodyFrame::PseudoMatches(nsIAtom* aTag, nsCSSSelector* aSelector, PRBo
} }
void void
nsOutlinerBodyFrame::EnsureColumns(nsIPresContext* aPresContext) nsOutlinerBodyFrame::EnsureColumns()
{ {
if (!mColumns) { if (!mColumns) {
nsCOMPtr<nsIContent> parent; nsCOMPtr<nsIContent> parent;
@ -827,7 +905,7 @@ nsOutlinerBodyFrame::EnsureColumns(nsIPresContext* aPresContext)
elt->GetElementsByTagName(NS_LITERAL_STRING("outlinercol"), getter_AddRefs(cols)); elt->GetElementsByTagName(NS_LITERAL_STRING("outlinercol"), getter_AddRefs(cols));
nsCOMPtr<nsIPresShell> shell; nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell)); mPresContext->GetShell(getter_AddRefs(shell));
PRUint32 count; PRUint32 count;
cols->GetLength(&count); cols->GetLength(&count);

View File

@ -25,7 +25,6 @@
#include "nsLeafBoxFrame.h" #include "nsLeafBoxFrame.h"
#include "nsIOutlinerBoxObject.h" #include "nsIOutlinerBoxObject.h"
#include "nsIOutlinerView.h" #include "nsIOutlinerView.h"
#include "nsIOutlinerRangeList.h"
#include "nsICSSPseudoComparator.h" #include "nsICSSPseudoComparator.h"
#include "nsIScrollbarMediator.h" #include "nsIScrollbarMediator.h"
#include "nsIWidget.h" #include "nsIWidget.h"
@ -212,7 +211,7 @@ protected:
virtual ~nsOutlinerBodyFrame(); virtual ~nsOutlinerBodyFrame();
// Returns the height of rows in the tree. // Returns the height of rows in the tree.
PRInt32 GetRowHeight(nsIPresContext* aPresContext); PRInt32 GetRowHeight();
// Returns our width/height once border and padding have been removed. // Returns our width/height once border and padding have been removed.
nsRect GetInnerBox(); nsRect GetInnerBox();
@ -222,7 +221,7 @@ protected:
nsresult GetPseudoStyleContext(nsIPresContext* aPresContext, nsIAtom* aPseudoElement, nsIStyleContext** aResult); nsresult GetPseudoStyleContext(nsIPresContext* aPresContext, nsIAtom* aPseudoElement, nsIStyleContext** aResult);
// Builds our cache of column info. // Builds our cache of column info.
void EnsureColumns(nsIPresContext* aContext); void EnsureColumns();
// Use to auto-fill some of the common properties without the view having to do it. // Use to auto-fill some of the common properties without the view having to do it.
// Examples include container, open, selected, and focused. // Examples include container, open, selected, and focused.

View File

@ -128,6 +128,22 @@ NS_IMETHODIMP nsOutlinerBoxObject::SetView(nsIOutlinerView * aView)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsOutlinerBoxObject::GetOutlinerBody(nsIDOMElement** aElement)
{
nsIOutlinerBoxObject* body = GetOutlinerBody();
if (body)
return body->GetOutlinerBody(aElement);
return NS_OK;
}
NS_IMETHODIMP nsOutlinerBoxObject::GetSelection(nsIOutlinerSelection * *aSelection)
{
nsIOutlinerBoxObject* body = GetOutlinerBody();
if (body)
return body->GetSelection(aSelection);
return NS_OK;
}
NS_IMETHODIMP nsOutlinerBoxObject::GetIndexOfVisibleRow(PRInt32 *_retval) NS_IMETHODIMP nsOutlinerBoxObject::GetIndexOfVisibleRow(PRInt32 *_retval)
{ {
nsIOutlinerBoxObject* body = GetOutlinerBody(); nsIOutlinerBoxObject* body = GetOutlinerBody();

View File

@ -24,6 +24,13 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsOutlinerSelection.h" #include "nsOutlinerSelection.h"
#include "nsIOutlinerBoxObject.h" #include "nsIOutlinerBoxObject.h"
#include "nsIOutlinerView.h"
#include "nsString.h"
#include "nsIDOMElement.h"
#include "nsIPresShell.h"
#include "nsIPresContext.h"
#include "nsIContent.h"
#include "nsIDocument.h"
// A helper class for managing our ranges of selection. // A helper class for managing our ranges of selection.
struct nsOutlinerRange struct nsOutlinerRange
@ -37,16 +44,76 @@ struct nsOutlinerRange
nsOutlinerSelection* mSelection; nsOutlinerSelection* mSelection;
nsOutlinerRange(nsOutlinerSelection* aSel, PRInt32 aSingleVal) nsOutlinerRange(nsOutlinerSelection* aSel, PRInt32 aSingleVal)
:mSelection(aSel), mNext(nsnull), mMin(aSingleVal), mMax(aSingleVal) {}; :mSelection(aSel), mPrev(nsnull), mNext(nsnull), mMin(aSingleVal), mMax(aSingleVal) {};
nsOutlinerRange(nsOutlinerSelection* aSel, PRInt32 aMin, PRInt32 aMax) :mNext(nsnull), mMin(aMin), mMax(aMax) {}; nsOutlinerRange(nsOutlinerSelection* aSel, PRInt32 aMin, PRInt32 aMax)
:mSelection(aSel), mPrev(nsnull), mNext(nsnull), mMin(aMin), mMax(aMax) {};
~nsOutlinerRange() { delete mNext; }; ~nsOutlinerRange() { delete mNext; };
void Connect(nsOutlinerRange* aPrev = nsnull, nsOutlinerRange* aNext = nsnull) { void Connect(nsOutlinerRange* aPrev = nsnull, nsOutlinerRange* aNext = nsnull) {
if (aPrev)
aPrev->mNext = this;
else
mSelection->mFirstRange = this;
if (aNext)
aNext->mPrev = this;
mPrev = aPrev; mPrev = aPrev;
mNext = aNext; mNext = aNext;
}; };
void Remove(PRInt32 aIndex) {
if (aIndex >= mMin && aIndex <= mMax) {
// We have found the range that contains us.
if (mMin == mMax) {
// Delete the whole range.
if (mPrev)
mPrev->mNext = mNext;
if (mNext)
mNext->mPrev = mPrev;
nsOutlinerRange* first = mSelection->mFirstRange;
if (first == this)
mSelection->mFirstRange = mNext;
mNext = mPrev = nsnull;
delete this;
}
else if (aIndex == mMin)
mMin++;
else if (aIndex == mMax)
mMax--;
}
else if (mNext)
mNext->Remove(aIndex);
};
void Add(PRInt32 aIndex) {
if (aIndex < mMin) {
// We have found a spot to insert.
if (aIndex + 1 == mMin)
mMin = aIndex;
else if (mPrev && mPrev->mMax+1 == aIndex)
mPrev->mMax = aIndex;
else {
// We have to create a new range.
nsOutlinerRange* newRange = new nsOutlinerRange(mSelection, aIndex);
newRange->Connect(mPrev, this);
}
}
else if (mNext)
mNext->Add(aIndex);
else {
// Insert on to the end.
if (mMax+1 == aIndex)
mMax = aIndex;
else {
// We have to create a new range.
nsOutlinerRange* newRange = new nsOutlinerRange(mSelection, aIndex);
newRange->Connect(this, nsnull);
}
}
};
PRBool Contains(PRInt32 aIndex) { PRBool Contains(PRInt32 aIndex) {
if (aIndex >= mMin && aIndex <= mMax) if (aIndex >= mMin && aIndex <= mMax)
return PR_TRUE; return PR_TRUE;
@ -72,6 +139,10 @@ struct nsOutlinerRange
void RemoveAllBut(PRInt32 aIndex) { void RemoveAllBut(PRInt32 aIndex) {
if (aIndex >= mMin && aIndex <= mMax) { if (aIndex >= mMin && aIndex <= mMax) {
// Invalidate everything in this list.
mSelection->mFirstRange->Invalidate();
mMin = aIndex; mMin = aIndex;
mMax = aIndex; mMax = aIndex;
@ -82,10 +153,10 @@ struct nsOutlinerRange
mNext->mPrev = mPrev; mNext->mPrev = mPrev;
mNext = mPrev = nsnull; mNext = mPrev = nsnull;
// Invalidate everything in this list. if (first != this) {
mSelection->mFirstRange->Invalidate(); delete mSelection->mFirstRange;
delete mSelection->mFirstRange; mSelection->mFirstRange = this;
mSelection->mFirstRange = this; }
} }
else if (mNext) else if (mNext)
mNext->RemoveAllBut(aIndex); mNext->RemoveAllBut(aIndex);
@ -105,7 +176,7 @@ nsOutlinerSelection::~nsOutlinerSelection()
delete mFirstRange; delete mFirstRange;
} }
NS_IMPL_ISUPPORTS1(nsOutlinerSelection, nsIOutlinerSelection) NS_IMPL_ISUPPORTS2(nsOutlinerSelection, nsIOutlinerSelection, nsISecurityCheckedComponent)
NS_IMETHODIMP nsOutlinerSelection::GetOutliner(nsIOutlinerBoxObject * *aOutliner) NS_IMETHODIMP nsOutlinerSelection::GetOutliner(nsIOutlinerBoxObject * *aOutliner)
{ {
@ -139,46 +210,116 @@ NS_IMETHODIMP nsOutlinerSelection::Select(PRInt32 aIndex)
if (count > 1) { if (count > 1) {
// We need to deselect everything but our item. // We need to deselect everything but our item.
mFirstRange->RemoveAllBut(aIndex); mFirstRange->RemoveAllBut(aIndex);
return NS_OK; FireOnSelectHandler();
} }
return NS_OK;
}
else {
// Clear out our selection.
mFirstRange->Invalidate();
delete mFirstRange;
} }
} }
delete mFirstRange; // Create our new selection.
mFirstRange = new nsOutlinerRange(this, aIndex); mFirstRange = new nsOutlinerRange(this, aIndex);
mFirstRange->Invalidate();
// XXX Fire the select event if not suppressed! // Fire the select event
FireOnSelectHandler();
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsOutlinerSelection::ToggleSelect(PRInt32 index) NS_IMETHODIMP nsOutlinerSelection::ToggleSelect(PRInt32 aIndex)
{ {
return NS_ERROR_NOT_IMPLEMENTED; // There are six cases that can occur on a ToggleSelect with our
// range code.
// (1) A new range should be made for a selection.
// (2) A single range is removed from the selection.
// (3) The item is added to an existing range.
// (4) The item is removed from an existing range.
// (5) The addition of the item causes two ranges to be merged.
// (6) The removal of the item causes two ranges to be split.
if (!mFirstRange)
Select(aIndex);
else {
if (!mFirstRange->Contains(aIndex))
mFirstRange->Add(aIndex);
else
mFirstRange->Remove(aIndex);
mOutliner->InvalidateRow(aIndex);
FireOnSelectHandler();
}
return NS_OK;
} }
NS_IMETHODIMP nsOutlinerSelection::RangedSelect(PRInt32 startIndex, PRInt32 endIndex) NS_IMETHODIMP nsOutlinerSelection::RangedSelect(PRInt32 aStartIndex, PRInt32 aEndIndex)
{ {
return NS_ERROR_NOT_IMPLEMENTED; // Clear our selection.
mFirstRange->Invalidate();
delete mFirstRange;
if (aStartIndex == -1)
aStartIndex = mCurrentIndex;
PRInt32 start = aStartIndex < aEndIndex ? aStartIndex : aEndIndex;
PRInt32 end = aStartIndex < aEndIndex ? aEndIndex : aStartIndex;
mFirstRange = new nsOutlinerRange(this, start, end);
mFirstRange->Invalidate();
FireOnSelectHandler();
return NS_OK;
} }
NS_IMETHODIMP nsOutlinerSelection::ClearSelection() NS_IMETHODIMP nsOutlinerSelection::ClearSelection()
{ {
return NS_ERROR_NOT_IMPLEMENTED; mFirstRange->Invalidate();
delete mFirstRange;
mFirstRange = nsnull;
FireOnSelectHandler();
return NS_OK;
} }
NS_IMETHODIMP nsOutlinerSelection::InvertSelection() NS_IMETHODIMP nsOutlinerSelection::InvertSelection()
{ {
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHODIMP nsOutlinerSelection::SelectAll() NS_IMETHODIMP nsOutlinerSelection::SelectAll()
{ {
return NS_ERROR_NOT_IMPLEMENTED; // Invalidate not necessary when clearing selection, since
// we're going to invalidate the world on the SelectAll.
delete mFirstRange;
nsCOMPtr<nsIOutlinerView> view;
mOutliner->GetView(getter_AddRefs(view));
if (!view)
return NS_OK;
PRInt32 rowCount;
view->GetRowCount(&rowCount);
if (rowCount == 0)
return NS_OK;
mFirstRange = new nsOutlinerRange(this, 0, rowCount-1);
mFirstRange->Invalidate();
FireOnSelectHandler();
return NS_OK;
} }
NS_IMETHODIMP nsOutlinerSelection::GetRangeCount(PRInt32 *_retval) NS_IMETHODIMP nsOutlinerSelection::GetRangeCount(PRInt32 *_retval)
{ {
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHODIMP nsOutlinerSelection::GetRangeAt(PRInt32 i, PRInt32 *min, PRInt32 *max) NS_IMETHODIMP nsOutlinerSelection::GetRangeAt(PRInt32 i, PRInt32 *min, PRInt32 *max)
@ -210,6 +351,72 @@ NS_IMETHODIMP nsOutlinerSelection::SetCurrentIndex(PRInt32 aCurrentIndex)
return NS_OK; return NS_OK;
} }
nsresult
nsOutlinerSelection::FireOnSelectHandler()
{
if (mSuppressed)
return NS_OK;
nsCOMPtr<nsIDOMElement> elt;
mOutliner->GetOutlinerBody(getter_AddRefs(elt));
nsCOMPtr<nsIContent> content(do_QueryInterface(elt));
nsCOMPtr<nsIDocument> document;
content->GetDocument(*getter_AddRefs(document));
PRInt32 count = document->GetNumberOfShells();
for (PRInt32 i = 0; i < count; i++) {
nsCOMPtr<nsIPresShell> shell = getter_AddRefs(document->GetShellAt(i));
if (nsnull == shell)
continue;
// Retrieve the context in which our DOM event will fire.
nsCOMPtr<nsIPresContext> aPresContext;
shell->GetPresContext(getter_AddRefs(aPresContext));
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event;
event.eventStructType = NS_EVENT;
event.message = NS_FORM_SELECTED;
content->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
}
return NS_OK;
}
/* string canCreateWrapper (in nsIIDPtr iid); */
NS_IMETHODIMP nsOutlinerSelection::CanCreateWrapper(const nsIID * iid, char **_retval)
{
nsCAutoString str("AllAccess");
*_retval = str.ToNewCString();
return NS_OK;
}
/* string canCallMethod (in nsIIDPtr iid, in wstring methodName); */
NS_IMETHODIMP nsOutlinerSelection::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval)
{
nsCAutoString str("AllAccess");
*_retval = str.ToNewCString();
return NS_OK;
}
/* string canGetProperty (in nsIIDPtr iid, in wstring propertyName); */
NS_IMETHODIMP nsOutlinerSelection::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
{
nsCAutoString str("AllAccess");
*_retval = str.ToNewCString();
return NS_OK;
}
/* string canSetProperty (in nsIIDPtr iid, in wstring propertyName); */
NS_IMETHODIMP nsOutlinerSelection::CanSetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval)
{
nsCAutoString str("AllAccess");
*_retval = str.ToNewCString();
return NS_OK;
}
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
nsresult nsresult

View File

@ -36,9 +36,13 @@ public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_NSIOUTLINERSELECTION NS_DECL_NSIOUTLINERSELECTION
NS_DECL_NSISECURITYCHECKEDCOMPONENT
friend struct nsOutlinerRange; friend struct nsOutlinerRange;
protected:
nsresult FireOnSelectHandler();
protected: protected:
// Members // Members
nsIOutlinerBoxObject* mOutliner; // [Weak]. The outliner will hold on to us through the view and let go when it dies. nsIOutlinerBoxObject* mOutliner; // [Weak]. The outliner will hold on to us through the view and let go when it dies.

View File

@ -78,10 +78,13 @@ XUL_ATOM(open, "open") // Whether or not a menu, tree, etc. is open
XUL_ATOM(outliner, "outliner") XUL_ATOM(outliner, "outliner")
XUL_ATOM(outlinerbody, "outlinerbody") XUL_ATOM(outlinerbody, "outlinerbody")
XUL_ATOM(outlinercol, "outlinercol") XUL_ATOM(outlinercol, "outlinercol")
XUL_ATOM(mozoutlinerrow, ":moz-outliner-row") XUL_ATOM(cycler, "cycler")
XUL_ATOM(mozoutlinercell, ":moz-outliner-cell") XUL_ATOM(primary, "primary")
XUL_ATOM(mozoutlinertwisty, ":moz-outliner-twisty") XUL_ATOM(mozoutlinerrow, ":-moz-outliner-row")
XUL_ATOM(mozoutlinerindentation, ":moz-outliner-indentation") XUL_ATOM(mozoutlinercell, ":-moz-outliner-cell")
XUL_ATOM(mozoutlinercelltext, ":-moz-outliner-cell-text")
XUL_ATOM(mozoutlinertwisty, ":-moz-outliner-twisty")
XUL_ATOM(mozoutlinerindentation, ":-moz-outliner-indentation")
XUL_ATOM(menubar, "menubar") // An XP menu bar. XUL_ATOM(menubar, "menubar") // An XP menu bar.
XUL_ATOM(menu, "menu") // Represents an XP menu XUL_ATOM(menu, "menu") // Represents an XP menu

View File

@ -14,6 +14,11 @@
<children/> <children/>
</xul:outlinerrows> </xul:outlinerrows>
</content> </content>
<implementation>
<property name="outlinerBoxObject"
onget="return this.boxObject.QueryInterface(Components.interfaces.nsIOutlinerBoxObject);"
readonly="true"/>
</implementation>
</binding> </binding>
<binding id="outlinerrows" extends="xul:box"> <binding id="outlinerrows" extends="xul:box">
@ -21,7 +26,10 @@
<children/> <children/>
<xul:scrollbar align="vertical" class="outliner-scrollbar"/> <xul:scrollbar align="vertical" class="outliner-scrollbar"/>
</content> </content>
<handlers> </binding>
<binding id="outlinerbody">
<handlers>
<!-- If there is no modifier key, we select on mousedown, not <!-- If there is no modifier key, we select on mousedown, not
click, so that drags work correctly. --> click, so that drags work correctly. -->
<handler event="mousedown"> <handler event="mousedown">
@ -29,15 +37,15 @@
if (!event.ctrlKey && !event.shiftKey && !event.metaKey) { if (!event.ctrlKey && !event.shiftKey && !event.metaKey) {
var row = {}; var row = {};
var col = {}; var col = {};
var v = this.parentNode.outlinerBoxObject.view; var b = this.parentNode.outlinerBoxObject;
v.getCellAt(event.x, event.y, row, col); b.getCellAt(event.clientX, event.clientY, row, col);
// XXX Check the col to see if it's a cycler. If so, // XXX Check the col to see if it's a cycler. If so,
// don't select. // don't select.
if (!v.selection.isSelected(row.value)) if (!b.selection.isSelected(row.value))
v.selection.select(row.value); b.selection.select(row.value);
v.selection.currentIndex = row.value; b.selection.currentIndex = row.value;
} }
]]> ]]>
</handler> </handler>
@ -50,15 +58,15 @@
if (event.button != 1) return; if (event.button != 1) return;
var row = {}; var row = {};
var col = {}; var col = {};
var v = this.parentNode.outlinerBoxObject.view; var b = this.parentNode.outlinerBoxObject;
v.getCellAt(event.x, event.y, row, col); b.getCellAt(event.clientX, event.clientY, row, col);
if (event.ctrlKey || event.metaKey) { if (event.ctrlKey || event.metaKey) {
v.selection.toggleSelect(row.value); b.selection.toggleSelect(row.value);
v.selection.currentIndex = row.value; b.selection.currentIndex = row.value;
} }
else if (event.shiftKey) { else if (event.shiftKey) {
v.selection.rangedSelect(null, row.value); b.selection.rangedSelect(-1, row.value);
v.currentIndex = row.value; b.currentIndex = row.value;
} }
else { else {
/* We want to deselect all the selected items except what was /* We want to deselect all the selected items except what was
@ -67,7 +75,7 @@
selected group of items */ selected group of items */
if (event.button == 1) if (event.button == 1)
v.selection.select(row.value); b.selection.select(row.value);
} }
]]> ]]>
</handler> </handler>
@ -78,16 +86,15 @@
var row = {}; var row = {};
var col = {}; var col = {};
// XXX Again, we need to check the cycler. // XXX Again, we need to check the cycler.
var v = this.parentNode.outlinerBoxObject.view; var b = this.parentNode.outlinerBoxObject;
v.getCellAt(event.x, event.y, row, col); b.getCellAt(event.clientX, event.clientY, row, col);
if (v.isContainer(row.value)) if (b.isContainer(row.value))
v.toggleOpenState(row.value); b.toggleOpenState(row.value);
]]> ]]>
</handler> </handler>
</handlers> </handlers>
</binding> </binding>
<binding id="outlinerbody"/>
<binding id="outlinercol"> <binding id="outlinercol">
<content autostretch="never"> <content autostretch="never">
@ -95,6 +102,9 @@
<xul:text class="outlinercol-text" inherits="crop,value" flex="1" crop="right"/> <xul:text class="outlinercol-text" inherits="crop,value" flex="1" crop="right"/>
<xul:image class="outlinercol-sortdirection"/> <xul:image class="outlinercol-sortdirection"/>
</content> </content>
<handlers>
<handler event="click" action="this.parentNode.outlinerBoxObject.view.cycleHeader(this)"/>
</handlers>
</binding> </binding>
</bindings> </bindings>