Fix for 116739. Many assertions when moving over the blank area of outliners.

Fix for 118632. file picker can display all column arrows.
r=bryner, sr=hyatt

- getCellAt() now checks for correct mouse coordinates and sets row value
  to -1 for invalid coordinates.
- added bail out checks to all callers.
This commit is contained in:
varga%utcru.sk 2002-01-10 04:47:52 +00:00
parent 07dff3093b
commit 728727cafd
19 changed files with 194 additions and 175 deletions

View File

@ -85,6 +85,9 @@ function onOutlinerResort (e, view)
var obo = view.outliner;
obo.getCellAt(e.clientX, e.clientY, rowIndex, colID, childElt);
if (row.value == -1)
return;
var prop;
switch (colID.value.substr(4))
{

View File

@ -847,6 +847,8 @@ function con_sourcesel (e)
var outliner = console.sourceView.outliner;
outliner.getCellAt(e.clientX, e.clientY, row, colID, childElt);
if (row.value == -1)
return;
console.sourceView.selectedIndex = row.value;
}
}
@ -864,6 +866,8 @@ function con_sourceclick (e)
var outliner = console.sourceView.outliner;
outliner.getCellAt(e.clientX, e.clientY, row, colID, childElt);
if (row.value == -1)
return;
colID = colID.value;
row = row.value;

View File

@ -67,9 +67,9 @@
// save off the last selected row
this._lastSelectedRow = row.value;
try {
if (row.value >= b.view.rowCount) return;
} catch (e) { return; }
if (row.value == -1)
return;
if (!b.selection.isSelected(row.value)) {
b.selection.select(row.value);
}
@ -88,9 +88,8 @@
var b = this.parentNode.parentNode.parentNode.outlinerBoxObject;
b.getCellAt(event.clientX, event.clientY, row, col, obj);
try {
if (row.value >= b.view.rowCount) return;
} catch (e) { return; }
if (row.value == -1)
return;
var augment = event.ctrlKey || event.metaKey;
if (event.shiftKey)

View File

@ -67,9 +67,9 @@
// save off the last selected row
this._lastSelectedRow = row.value;
try {
if (row.value >= b.view.rowCount) return;
} catch (e) { return; }
if (row.value == -1)
return;
if (!b.selection.isSelected(row.value)) {
b.selection.select(row.value);
}
@ -88,9 +88,8 @@
var b = this.parentNode.parentNode.parentNode.outlinerBoxObject;
b.getCellAt(event.clientX, event.clientY, row, col, obj);
try {
if (row.value >= b.view.rowCount) return;
} catch (e) { return; }
if (row.value == -1)
return;
var augment = event.ctrlKey || event.metaKey;
if (event.shiftKey)

View File

@ -339,16 +339,12 @@ nsXULTooltipListener::CheckOutlinerBodyMove(nsIDOMMouseEvent* aMouseEvent)
// XXX check the disabletitletips attribute on the outliner content
mNeedTitletip = PR_FALSE;
#ifdef DEBUG_crap
if (obj.Equals(NS_LITERAL_STRING("text"))) {
if (row >= 0 && obj.Equals(NS_LITERAL_STRING("text"))) {
nsCOMPtr<nsIOutlinerView> view;
mOutlinerBox->GetView(getter_AddRefs(view));
PRInt32 rowCount;
view->GetRowCount(&rowCount);
if (row < rowCount) {
PRBool isCropped;
mOutlinerBox->IsCellCropped(row, colId, &isCropped);
mNeedTitletip = isCropped;
}
PRBool isCropped;
mOutlinerBox->IsCellCropped(row, colId, &isCropped);
mNeedTitletip = isCropped;
}
#endif

View File

@ -131,8 +131,9 @@ interface nsIOutlinerBoxObject : nsISupports
/**
* A hit test that can tell you what cell the mouse is over. Row is the row index
* hit. ColID is the column hit. ChildElt is the pseudoelement hit: this can have
* values of "cell", "twisty", "image", and "text".
* hit, returns -1 for invalid mouse coordinates. ColID is the column hit.
* ChildElt is the pseudoelement hit: this can have values of
* "cell", "twisty", "image", and "text".
*/
void getCellAt(in long x, in long y, out long row, out wstring colID, out wstring childElt);

View File

@ -978,6 +978,9 @@ nsOutlinerBodyFrame :: AdjustEventCoordsToBoxCoordSpace ( PRInt32 inX, PRInt32 i
NS_IMETHODIMP nsOutlinerBodyFrame::GetCellAt(PRInt32 aX, PRInt32 aY, PRInt32* aRow, PRUnichar** aColID,
PRUnichar** aChildElt)
{
if (!mView)
return NS_OK;
// Ensure we have a row height.
if (mRowHeight == 0)
mRowHeight = GetRowHeight();
@ -988,6 +991,14 @@ NS_IMETHODIMP nsOutlinerBodyFrame::GetCellAt(PRInt32 aX, PRInt32 aY, PRInt32* aR
// Now just mod by our total inner box height and add to our top row index.
*aRow = (y/mRowHeight)+mTopRowIndex;
// Check if the coordinates are actually in our space.
PRInt32 rowCount;
mView->GetRowCount(&rowCount);
if (*aRow < 0 || *aRow >= rowCount) {
*aRow = -1;
return NS_OK;
}
// Determine the column hit.
nscoord currX = mInnerBox.x;
for (nsOutlinerColumn* currCol = mColumns; currCol && currX < mInnerBox.x+mInnerBox.width;
@ -2921,38 +2932,43 @@ nsOutlinerBodyFrame :: OnDragOver ( nsIDOMEvent* inEvent )
mOpenTimerRow = -1;
}
if (!mOpenTimer) {
// either there wasn't a timer running or it was just killed above.
// if over a folder, start up a timer to open the folder.
PRBool isContainer = PR_FALSE;
mView->IsContainer(newRow, &isContainer);
if (isContainer) {
PRBool isOpen = PR_FALSE;
mView->IsContainerOpen(newRow, &isOpen);
if (!isOpen) {
// this node isn't expanded - set a timer to expand it
mOpenTimerRow = newRow;
mOpenTimer = do_CreateInstance("@mozilla.org/timer;1");
mOpenTimer->Init(this, 1000, NS_PRIORITY_HIGHEST);
}
}
}
// cache the new row and orientation regardless so we can check if it changed
// for next time.
mDropRow = newRow;
mDropOrient = newOrient;
PRBool canDropAtNewLocation = PR_FALSE;
if ( newOrient == kOnRow )
mView->CanDropOn ( newRow, &canDropAtNewLocation );
else
mView->CanDropBeforeAfter ( newRow, newOrient == kBeforeRow ? PR_TRUE : PR_FALSE, &canDropAtNewLocation );
if ( canDropAtNewLocation )
DrawDropFeedback ( newRow, newOrient, kDrawFeedback ); // draw it at old loc, if we are allowed
mDropAllowed = PR_FALSE;
mDropAllowed = canDropAtNewLocation;
if (mDropRow >= 0) {
if (!mOpenTimer) {
// either there wasn't a timer running or it was just killed above.
// if over a folder, start up a timer to open the folder.
PRBool isContainer = PR_FALSE;
mView->IsContainer(mDropRow, &isContainer);
if (isContainer) {
PRBool isOpen = PR_FALSE;
mView->IsContainerOpen(mDropRow, &isOpen);
if (!isOpen) {
// this node isn't expanded - set a timer to expand it
mOpenTimerRow = mDropRow;
mOpenTimer = do_CreateInstance("@mozilla.org/timer;1");
mOpenTimer->Init(this, 1000, NS_PRIORITY_HIGHEST);
}
}
}
PRBool canDropAtNewLocation = PR_FALSE;
if ( mDropOrient == kOnRow )
mView->CanDropOn ( mDropRow, &canDropAtNewLocation );
else
mView->CanDropBeforeAfter ( mDropRow, mDropOrient == kBeforeRow ? PR_TRUE : PR_FALSE, &canDropAtNewLocation );
if ( canDropAtNewLocation ) {
DrawDropFeedback ( mDropRow, mDropOrient, kDrawFeedback ); // draw it at old loc, if we are allowed
mDropAllowed = canDropAtNewLocation;
}
}
}
// alert the drag session we accept the drop. We have to do this every time
@ -3060,49 +3076,38 @@ nsOutlinerBodyFrame :: ComputeDropPosition ( nsIDOMEvent* inEvent, PRInt32* outR
PRInt32 x = 0, y = 0;
mouseEvent->GetClientX(&x); mouseEvent->GetClientY(&y);
PRInt32 row = kIllegalRow;
nsXPIDLString colID, child;
GetCellAt ( x, y, &row, getter_Copies(colID), getter_Copies(child) );
// GetCellAt() will just blindly report a row even if there is no content there
// (ie, dragging below the end of the tree). If that's the case, set the reported row
// to after the final row. If we're not off the end, then check the coords w/in the cell
// to see if we are dropping before/on/after.
PRInt32 totalNumRows = 0;
mView->GetRowCount ( &totalNumRows );
if ( row > totalNumRows - 1 ) { // doh, we're off the end of the tree
row = (totalNumRows-1) - mTopRowIndex;
*outOrient = kAfterRow;
GetCellAt ( x, y, outRow, getter_Copies(colID), getter_Copies(child) );
if (*outRow == -1) {
*outOrient = kNoOrientation;
return;
}
else { // w/in a cell, check above/below/on
// Compute the top/bottom of the row in question. We need to convert
// our y coord to twips since |mRowHeight| is in twips.
PRInt32 yTwips, xTwips;
AdjustEventCoordsToBoxCoordSpace ( x, y, &xTwips, &yTwips );
PRInt32 rowTop = mRowHeight * (row - mTopRowIndex);
PRInt32 yOffset = yTwips - rowTop;
// Compute the top/bottom of the row in question. We need to convert
// our y coord to twips since |mRowHeight| is in twips.
PRInt32 yTwips, xTwips;
AdjustEventCoordsToBoxCoordSpace ( x, y, &xTwips, &yTwips );
PRInt32 rowTop = mRowHeight * (*outRow - mTopRowIndex);
PRInt32 yOffset = yTwips - rowTop;
PRBool isContainer = PR_FALSE;
mView->IsContainer ( row, &isContainer );
if ( isContainer ) {
// for a container, use a 25%/50%/25% breakdown
if ( yOffset < mRowHeight / 4 )
*outOrient = kBeforeRow;
else if ( yOffset > mRowHeight - (mRowHeight / 4) )
*outOrient = kAfterRow;
else
*outOrient = kOnRow;
}
else {
// for a non-container use a 50%/50% breakdown
if ( yOffset < mRowHeight / 2 )
*outOrient = kBeforeRow;
else
*outOrient = kAfterRow;
}
PRBool isContainer = PR_FALSE;
mView->IsContainer ( *outRow, &isContainer );
if ( isContainer ) {
// for a container, use a 25%/50%/25% breakdown
if ( yOffset < mRowHeight / 4 )
*outOrient = kBeforeRow;
else if ( yOffset > mRowHeight - (mRowHeight / 4) )
*outOrient = kAfterRow;
else
*outOrient = kOnRow;
}
else {
// for a non-container use a 50%/50% breakdown
if ( yOffset < mRowHeight / 2 )
*outOrient = kBeforeRow;
else
*outOrient = kAfterRow;
}
*outRow = row;
}
} // ComputeDropPosition

View File

@ -131,8 +131,9 @@ interface nsIOutlinerBoxObject : nsISupports
/**
* A hit test that can tell you what cell the mouse is over. Row is the row index
* hit. ColID is the column hit. ChildElt is the pseudoelement hit: this can have
* values of "cell", "twisty", "image", and "text".
* hit, returns -1 for invalid mouse coordinates. ColID is the column hit.
* ChildElt is the pseudoelement hit: this can have values of
* "cell", "twisty", "image", and "text".
*/
void getCellAt(in long x, in long y, out long row, out wstring colID, out wstring childElt);

View File

@ -978,6 +978,9 @@ nsOutlinerBodyFrame :: AdjustEventCoordsToBoxCoordSpace ( PRInt32 inX, PRInt32 i
NS_IMETHODIMP nsOutlinerBodyFrame::GetCellAt(PRInt32 aX, PRInt32 aY, PRInt32* aRow, PRUnichar** aColID,
PRUnichar** aChildElt)
{
if (!mView)
return NS_OK;
// Ensure we have a row height.
if (mRowHeight == 0)
mRowHeight = GetRowHeight();
@ -988,6 +991,14 @@ NS_IMETHODIMP nsOutlinerBodyFrame::GetCellAt(PRInt32 aX, PRInt32 aY, PRInt32* aR
// Now just mod by our total inner box height and add to our top row index.
*aRow = (y/mRowHeight)+mTopRowIndex;
// Check if the coordinates are actually in our space.
PRInt32 rowCount;
mView->GetRowCount(&rowCount);
if (*aRow < 0 || *aRow >= rowCount) {
*aRow = -1;
return NS_OK;
}
// Determine the column hit.
nscoord currX = mInnerBox.x;
for (nsOutlinerColumn* currCol = mColumns; currCol && currX < mInnerBox.x+mInnerBox.width;
@ -2921,38 +2932,43 @@ nsOutlinerBodyFrame :: OnDragOver ( nsIDOMEvent* inEvent )
mOpenTimerRow = -1;
}
if (!mOpenTimer) {
// either there wasn't a timer running or it was just killed above.
// if over a folder, start up a timer to open the folder.
PRBool isContainer = PR_FALSE;
mView->IsContainer(newRow, &isContainer);
if (isContainer) {
PRBool isOpen = PR_FALSE;
mView->IsContainerOpen(newRow, &isOpen);
if (!isOpen) {
// this node isn't expanded - set a timer to expand it
mOpenTimerRow = newRow;
mOpenTimer = do_CreateInstance("@mozilla.org/timer;1");
mOpenTimer->Init(this, 1000, NS_PRIORITY_HIGHEST);
}
}
}
// cache the new row and orientation regardless so we can check if it changed
// for next time.
mDropRow = newRow;
mDropOrient = newOrient;
PRBool canDropAtNewLocation = PR_FALSE;
if ( newOrient == kOnRow )
mView->CanDropOn ( newRow, &canDropAtNewLocation );
else
mView->CanDropBeforeAfter ( newRow, newOrient == kBeforeRow ? PR_TRUE : PR_FALSE, &canDropAtNewLocation );
if ( canDropAtNewLocation )
DrawDropFeedback ( newRow, newOrient, kDrawFeedback ); // draw it at old loc, if we are allowed
mDropAllowed = PR_FALSE;
mDropAllowed = canDropAtNewLocation;
if (mDropRow >= 0) {
if (!mOpenTimer) {
// either there wasn't a timer running or it was just killed above.
// if over a folder, start up a timer to open the folder.
PRBool isContainer = PR_FALSE;
mView->IsContainer(mDropRow, &isContainer);
if (isContainer) {
PRBool isOpen = PR_FALSE;
mView->IsContainerOpen(mDropRow, &isOpen);
if (!isOpen) {
// this node isn't expanded - set a timer to expand it
mOpenTimerRow = mDropRow;
mOpenTimer = do_CreateInstance("@mozilla.org/timer;1");
mOpenTimer->Init(this, 1000, NS_PRIORITY_HIGHEST);
}
}
}
PRBool canDropAtNewLocation = PR_FALSE;
if ( mDropOrient == kOnRow )
mView->CanDropOn ( mDropRow, &canDropAtNewLocation );
else
mView->CanDropBeforeAfter ( mDropRow, mDropOrient == kBeforeRow ? PR_TRUE : PR_FALSE, &canDropAtNewLocation );
if ( canDropAtNewLocation ) {
DrawDropFeedback ( mDropRow, mDropOrient, kDrawFeedback ); // draw it at old loc, if we are allowed
mDropAllowed = canDropAtNewLocation;
}
}
}
// alert the drag session we accept the drop. We have to do this every time
@ -3060,49 +3076,38 @@ nsOutlinerBodyFrame :: ComputeDropPosition ( nsIDOMEvent* inEvent, PRInt32* outR
PRInt32 x = 0, y = 0;
mouseEvent->GetClientX(&x); mouseEvent->GetClientY(&y);
PRInt32 row = kIllegalRow;
nsXPIDLString colID, child;
GetCellAt ( x, y, &row, getter_Copies(colID), getter_Copies(child) );
// GetCellAt() will just blindly report a row even if there is no content there
// (ie, dragging below the end of the tree). If that's the case, set the reported row
// to after the final row. If we're not off the end, then check the coords w/in the cell
// to see if we are dropping before/on/after.
PRInt32 totalNumRows = 0;
mView->GetRowCount ( &totalNumRows );
if ( row > totalNumRows - 1 ) { // doh, we're off the end of the tree
row = (totalNumRows-1) - mTopRowIndex;
*outOrient = kAfterRow;
GetCellAt ( x, y, outRow, getter_Copies(colID), getter_Copies(child) );
if (*outRow == -1) {
*outOrient = kNoOrientation;
return;
}
else { // w/in a cell, check above/below/on
// Compute the top/bottom of the row in question. We need to convert
// our y coord to twips since |mRowHeight| is in twips.
PRInt32 yTwips, xTwips;
AdjustEventCoordsToBoxCoordSpace ( x, y, &xTwips, &yTwips );
PRInt32 rowTop = mRowHeight * (row - mTopRowIndex);
PRInt32 yOffset = yTwips - rowTop;
// Compute the top/bottom of the row in question. We need to convert
// our y coord to twips since |mRowHeight| is in twips.
PRInt32 yTwips, xTwips;
AdjustEventCoordsToBoxCoordSpace ( x, y, &xTwips, &yTwips );
PRInt32 rowTop = mRowHeight * (*outRow - mTopRowIndex);
PRInt32 yOffset = yTwips - rowTop;
PRBool isContainer = PR_FALSE;
mView->IsContainer ( row, &isContainer );
if ( isContainer ) {
// for a container, use a 25%/50%/25% breakdown
if ( yOffset < mRowHeight / 4 )
*outOrient = kBeforeRow;
else if ( yOffset > mRowHeight - (mRowHeight / 4) )
*outOrient = kAfterRow;
else
*outOrient = kOnRow;
}
else {
// for a non-container use a 50%/50% breakdown
if ( yOffset < mRowHeight / 2 )
*outOrient = kBeforeRow;
else
*outOrient = kAfterRow;
}
PRBool isContainer = PR_FALSE;
mView->IsContainer ( *outRow, &isContainer );
if ( isContainer ) {
// for a container, use a 25%/50%/25% breakdown
if ( yOffset < mRowHeight / 4 )
*outOrient = kBeforeRow;
else if ( yOffset > mRowHeight - (mRowHeight / 4) )
*outOrient = kAfterRow;
else
*outOrient = kOnRow;
}
else {
// for a non-container use a 50%/50% breakdown
if ( yOffset < mRowHeight / 2 )
*outOrient = kBeforeRow;
else
*outOrient = kAfterRow;
}
*outRow = row;
}
} // ComputeDropPosition

View File

@ -69,6 +69,8 @@ function AbResultsPaneOnClick(event)
var outliner = GetAbResultsOutliner();
// figure out what cell the click was in
outliner.boxObject.QueryInterface(Components.interfaces.nsIOutlinerBoxObject).getCellAt(event.clientX, event.clientY, row, colID, childElt);
if (row.value == -1)
return;
if (event.detail == 2) {
AbResultsPaneDoubleClick(gAbView.getCardFromRow(row.value));

View File

@ -344,6 +344,9 @@ function BeginDragFolderOutliner(event)
var col = {};
var elt = {};
folderOutliner.outlinerBoxObject.getCellAt(event.clientX, event.clientY, row, col, elt);
if (row.value == -1)
return;
var folderResource = GetFolderResource(folderOutliner, row.value);
if (GetFolderAttribute(folderOutliner, folderResource, "IsServer") == "true")

View File

@ -862,6 +862,8 @@ function FolderPaneOnClick(event)
var col = {};
var elt = {};
folderOutliner.outlinerBoxObject.getCellAt(event.clientX, event.clientY, row, col, elt);
if (row.value == -1)
return;
if (elt.value == "twisty")
{

View File

@ -146,6 +146,8 @@ function onSynchronizeClick(event)
var elt = {}
gSynchronizeOutliner.outlinerBoxObject.getCellAt(event.clientX, event.clientY, row, col, elt);
if (row.value == -1)
return;
if (elt.value == "twisty") {
var folderResource = GetFolderResource(gSynchronizeOutliner, row.value);

View File

@ -313,6 +313,8 @@ function SearchOnClick(event)
var childElt = new Object;
gSearchOutlinerBoxObject.getCellAt(event.clientX, event.clientY, row, colID, childElt);
if (row.value == -1)
return;
// if they are clicking on empty rows, drop the event
if (row.value + 1 > gSearchView.rowCount) return;

View File

@ -48,6 +48,8 @@ function ThreadPaneOnClick(event)
var outliner = GetThreadOutliner();
// figure out what cell the click was in
outliner.boxObject.QueryInterface(Components.interfaces.nsIOutlinerBoxObject).getCellAt(event.clientX, event.clientY, row, colID, childElt);
if (row.value == -1)
return;
// if the cell is in a "cycler" column
// or if the user double clicked on the twisty,

View File

@ -1405,7 +1405,7 @@
var x = aEvent.screenX - this.boxObject.screenX + this.boxObject.x;
var y = aEvent.screenY - this.boxObject.screenY + this.boxObject.y;
this.textbox.view.outlinerBoxObject.getCellAt(x, y, row, col, obj);
if (row.value >= 0 && row.value < this.textbox.view.rowCount)
if (row.value >= 0)
return {row: row.value, column: col.value};
else
return null;

View File

@ -1589,7 +1589,7 @@
var col = {};
var obj = {};
this.outlinerBoxObject.getCellAt(aEvent.clientX, aEvent.clientY, row, col, obj);
if (obj.value == "twisty")
if (row.value == -1 || obj.value == "twisty")
return false;
return true;
]]></body>

View File

@ -375,16 +375,11 @@ function handleColumnClick(columnID) {
}
// remove the sort indicator from the rest of the columns
var currCol = document.getElementById("directoryOutliner").firstChild;
var currCol = sortedColumn.parentNode.firstChild;
while (currCol) {
while (currCol && currCol.localName != "outlinercol")
currCol = currCol.nextSibling;
if (currCol) {
if (currCol != sortedColumn) {
currCol.removeAttribute("sortDirection");
}
currCol = currCol.nextSibling;
}
if (currCol != sortedColumn && currCol.localName == "outlinercol")
currCol.removeAttribute("sortDirection");
currCol = currCol.nextSibling;
}
}

View File

@ -620,10 +620,9 @@
// save off the last selected row
this._lastSelectedRow = row.value;
try {
if (row.value >= b.view.rowCount) return;
} catch (e) { return; }
if (row.value == -1)
return;
if (obj.value != "twisty") {
var column = document.getElementById(col.value);
var cycler = column.hasAttribute('cycler');
@ -649,9 +648,8 @@
var b = this.parentNode.outlinerBoxObject;
b.getCellAt(event.clientX, event.clientY, row, col, obj);
try {
if (row.value >= b.view.rowCount) return;
} catch (e) { return; }
if (row.value == -1)
return;
if (obj.value == "twisty") {
b.view.toggleOpenState(row.value);
@ -692,9 +690,9 @@
var b = this.parentNode.outlinerBoxObject;
b.getCellAt(event.clientX, event.clientY, row, col, obj);
try {
if (row.value >= b.view.rowCount) return;
} catch (e) { return; }
if (row.value == -1)
return;
var column = document.getElementById(col.value);
var cycler = column.hasAttribute('cycler');