Added row/column selection in tables: Bug 26833. r=kin, a=beppe

This commit is contained in:
cmanske%netscape.com 2000-05-31 00:07:58 +00:00
parent 74406f96a3
commit c28f13972f
7 changed files with 1121 additions and 710 deletions

View File

@ -356,9 +356,12 @@ private:
nsresult GetParentTable(nsIContent *aCellNode, nsIContent **aTableNode);
nsresult SelectCellElement(nsIDOMElement* aCellElement);
nsresult CreateAndAddRange(nsIDOMNode *aParentNode, PRInt32 aOffset);
nsresult ClearNormalSelection();
nsCOMPtr<nsIContent> mStartSelectedCell;
nsCOMPtr<nsIContent> mEndSelectedCell;
nsCOMPtr<nsIContent> mAppendStartSelectedCell;
nsCOMPtr<nsIContent> mUnselectCellOnMouseUp;
PRBool mSelectingTableCells;
PRUint32 mSelectingTableCellMode;
PRInt32 mSelectedCellIndex;
@ -1555,7 +1558,6 @@ nsSelection::HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset,
// Don't take focus when dragging off of a table
if (!mSelectingTableCells)
{
mSelectingTableCellMode = 0;
return TakeFocus(aNewFocus, aContentOffset, aContentEndOffset, aContinueSelection, aMultipleSelection);
}
@ -1726,7 +1728,10 @@ nsSelection::SetMouseDownState(PRBool aState)
mMouseDownState = aState;
if (!mMouseDownState)
{
// Mouse up kills table selection
// Mouse up kills dragging-table cell selection
#ifdef DEBUG_cmanske
printf("SetMouseDownState to FALSE - stopping cell selection\n");
#endif
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
@ -2040,6 +2045,13 @@ nsSelection::GetTableLayout(nsIContent *aTableContent)
return tableLayoutObject;
}
nsresult
nsSelection::ClearNormalSelection()
{
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
return mDomSelections[index]->ClearSelection();
}
nsresult
nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOffset, PRUint32 aTarget, nsMouseEvent *aMouseEvent)
{
@ -2054,13 +2066,13 @@ nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOf
nsCOMPtr<nsIDOMNode> parentNode = do_QueryInterface(aParentContent);
if (!parentNode) return NS_ERROR_FAILURE;
nsCOMPtr<nsIContent> selectedContent;
nsresult result = aParentContent->ChildAt(aContentOffset, *getter_AddRefs(selectedContent));
nsCOMPtr<nsIContent> childContent;
nsresult result = aParentContent->ChildAt(aContentOffset, *getter_AddRefs(childContent));
if (NS_FAILED(result)) return result;
if (!selectedContent) return NS_ERROR_FAILURE;
if (!childContent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> selectedNode = do_QueryInterface(selectedContent);
if (!selectedNode) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> childNode = do_QueryInterface(childContent);
if (!childNode) return NS_ERROR_FAILURE;
// When doing table selection, always set the direction to next
// so we can be sure that anchorNode's offset always points to the selected cell
@ -2071,39 +2083,79 @@ nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOf
// BeginBatchChanges() / EndBatchChanges()
nsSelectionBatcher selectionBatcher(mDomSelections[index]);
PRInt32 startRowIndex, startColIndex, curRowIndex, curColIndex;
if (mSelectingTableCells)
{
// We are drag-selecting
if (aTarget != TABLESELECTION_TABLE)
{
// If dragging in the same cell as last event, do nothing
if (mEndSelectedCell == childContent)
return NS_OK;
// aTarget can be any "cell mode",
// so we can easily drag-select rows and columns
// Once user gets the col or row hit area onclick,
// they can drift into any cell to stay in col/row mode
// (aTarget will be TABLESELECTION_CELL)
// If dragging in the same cell as last event, do nothing
if (mEndSelectedCell == selectedContent)
return NS_OK;
// Once we are in row or column mode,
// we can drift into any cell to stay in that mode
// even if aTarget = TABLESELECTION_CELL
if (mSelectingTableCellMode == TABLESELECTION_ROW ||
mSelectingTableCellMode == TABLESELECTION_COLUMN)
{
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Dragged into a new column or row\n");
if (mEndSelectedCell)
{
// Also check if cell is in same row/col
result = GetCellIndexes(mEndSelectedCell, startRowIndex, startColIndex);
if (NS_FAILED(result)) return result;
result = GetCellIndexes(childContent, curRowIndex, curColIndex);
if (NS_FAILED(result)) return result;
if ((mSelectingTableCellMode == TABLESELECTION_ROW && startRowIndex == curRowIndex) ||
(mSelectingTableCellMode == TABLESELECTION_COLUMN && startColIndex == curColIndex))
return NS_OK;
}
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Dragged into a new column or row\n");
#endif
// Append anthor row or columns to the selection
return SelectRowOrColumn(selectedContent, mSelectingTableCellMode);
// Continue dragging row or column selection
return SelectRowOrColumn(childContent, mSelectingTableCellMode);
}
else if (mSelectingTableCellMode == TABLESELECTION_CELL)
{
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Dragged into a new cell\n");
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Dragged into a new cell\n");
#endif
// Clear this to be sure SelectBlockOfCells works correctly
mAppendStartSelectedCell = nsnull;
// Trick for quick selection of rows and columns
// Hold down shift, then start selecting in one direction
// If next cell dragged into is in same row, select entire row,
// if next cell is in same column, select entire column
if (mStartSelectedCell && aMouseEvent->isShift)
{
result = GetCellIndexes(mStartSelectedCell, startRowIndex, startColIndex);
if (NS_FAILED(result)) return result;
result = GetCellIndexes(childContent, curRowIndex, curColIndex);
if (NS_FAILED(result)) return result;
if (startRowIndex == curRowIndex ||
startColIndex == curColIndex)
{
// Force new selection block
mStartSelectedCell = nsnull;
mDomSelections[index]->ClearSelection();
mSelectingTableCellMode =
(startRowIndex == curRowIndex) ? TABLESELECTION_ROW : TABLESELECTION_COLUMN;
return SelectRowOrColumn(childContent, mSelectingTableCellMode);
}
}
// Reselect block of cells to new end location
return SelectBlockOfCells(selectedContent);
return SelectBlockOfCells(childContent);
}
}
// Do nothing if dragging in table, but outside a cell
@ -2111,153 +2163,189 @@ nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOf
}
else
{
// Not dragging -- mouse event is a click
// Not dragging -- mouse event is down or up
if (mMouseDownState)
{
#ifdef DEBUG_cmanske
//#ifdef DEBUG_TABLE
printf("HandleTableSelection: CLICK event\n");
printf("HandleTableSelection: Selecting Table\n");
{
nsIFrame *frame = nsnull;
result = GetTracker()->GetPrimaryFrameFor(selectedContent, &frame);
if (frame)
{
nsRect rect1;
frame->GetRect(rect1);
printf("Frame rect: x=%d, y=%d, right=%d, bottom=%d\n", rect1.x, rect1.y, rect1.XMost(), rect1.YMost());
nsRect rect2 = rect1;
mDomSelections[index]->GetFrameToRootViewOffset(frame, &rect2.x, &rect2.y);
printf("Translated frame orgin: x=%d, y=%d\n", rect2.x, rect2.y);
printf("Mouse was clicked at: x=%d, y=%d\n", aMouseEvent->point.x, aMouseEvent->point.y);
printf("*** Widget-relative (refPoint): x=%d, y=%d\n", aMouseEvent->refPoint.x, aMouseEvent->refPoint.y);
}
/*
Useful frame methods:
GetRect(nsRect& aRect)
GetSize(nsSize& aSize)
*/
}
//#endif
printf("HandleTableSelection: Mouse down event\n");
#endif
if (aTarget == TABLESELECTION_ROW || aTarget == TABLESELECTION_COLUMN)
{
// Start drag-selecting mode so multiple rows/cols can be selected
mSelectingTableCells = PR_TRUE;
mSelectingTableCellMode = aTarget; //only shut off on mouse up.
// Clear cell we stored in mouse-down
mUnselectCellOnMouseUp = nsnull;
// Force new selection block
mStartSelectedCell = nsnull;
mDomSelections[index]->ClearSelection();
return SelectRowOrColumn(selectedContent, aTarget);
}
else if (aTarget == TABLESELECTION_TABLE)
{
//TODO: We currently select entire table when clicked between cells,
// should we restrict to only around border?
// *** How do we get location data for cell and click?
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
// Select the table
mDomSelections[index]->ClearSelection();
return CreateAndAddRange(parentNode, aContentOffset);
}
// We are already selecting cells
// Check if cell clicked on is already selected
PRInt32 rangeCount;
result = mDomSelections[index]->GetRangeCount(&rangeCount);
if (NS_FAILED(result)) return result;
if (rangeCount > 0 && aMouseEvent->isShift && selectedContent != mStartSelectedCell)
{
// If Shift is down as well, do a block selection
return SelectBlockOfCells(selectedContent);
}
nsCOMPtr<nsIDOMNode> previousCellParent;
nsCOMPtr<nsIDOMRange> range;
PRInt32 offset;
for( PRInt32 i = 0; i < rangeCount; i++)
{
result = mDomSelections[index]->GetRangeAt(i, getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (!range) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> parent;
result = range->GetStartParent(getter_AddRefs(parent));
if (NS_FAILED(result)) return result;
if (!parent) return NS_ERROR_NULL_POINTER;
range->GetStartOffset(&offset);
// Be sure previous selection is a table cell
nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);
nsCOMPtr<nsIContent> childContent;
result = parentContent->ChildAt(offset, *getter_AddRefs(childContent));
if (NS_FAILED(result)) return result;
if (childContent && IsCell(childContent))
previousCellParent = parent;
// We're done if we didn't find parent of a previously-selected cell
if (!previousCellParent) break;
if (previousCellParent == parentNode && offset == aContentOffset)
if (aTarget == TABLESELECTION_CELL)
{
// Cell is already selected
if (rangeCount == 1)
PRBool isSelected = PR_FALSE;
// Check if we have other selected cells
nsCOMPtr<nsIDOMNode> previousCellNode;
GetFirstSelectedCellAndRange(getter_AddRefs(previousCellNode), nsnull);
if (previousCellNode)
{
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Unselecting single selected cell\n");
#endif
// This was the only cell selected.
// Collapse to "normal" selection inside the cell
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
//TODO: We need a "Collapse to just before deepest child" routine
// Even better, should we collapse to just after the LAST deepest child
// (i.e., at the end of the cell's contents)?
return mDomSelections[index]->Collapse(selectedNode, 0);
// We have at least 1 other selected cell
// Check if new cell is already selected
nsIFrame *cellFrame = nsnull;
result = GetTracker()->GetPrimaryFrameFor(childContent, &cellFrame);
if (NS_FAILED(result)) return result;
if (!cellFrame) return NS_ERROR_NULL_POINTER;
result = cellFrame->GetSelected(&isSelected);
if (NS_FAILED(result)) return result;
}
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Removing cell from multi-cell selection\n");
else
{
// No cells selected -- remove non-cell selection
mDomSelections[index]->ClearSelection();
}
mSelectingTableCells = PR_TRUE; // Signal to start drag-cell-selection
mSelectingTableCellMode = aTarget;
// Set start for new drag-selection block (not appended)
mStartSelectedCell = childContent;
// The initial block end is same as the start
mEndSelectedCell = childContent;
if (isSelected)
{
// Remember this cell to (possibly) unselect it on mouseup
mUnselectCellOnMouseUp = childContent;
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Saving mUnselectCellOnMouseUp\n");
#endif
//TODO: Should we try to reassign to a different existing cell?
//mStartSelectedCell = nsnull;
//mEndSelectedCell = nsnull;
// Other cells are selected:
// Deselect cell by removing its range from selection
return mDomSelections[index]->RemoveRange(range);
}
else
{
// Select an unselected cell
// but first remove existing selection if not in same table
nsCOMPtr<nsIContent> previousCellContent = do_QueryInterface(previousCellNode);
if (!IsInSameTable(previousCellContent, childContent, nsnull))
mDomSelections[index]->ClearSelection();
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(childContent);
return SelectCellElement(cellElement);
}
return NS_OK;
}
else if (aTarget == TABLESELECTION_TABLE)
{
//TODO: We currently select entire table when clicked between cells,
// should we restrict to only around border?
// *** How do we get location data for cell and click?
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
// Remove existing selection and select the table
mDomSelections[index]->ClearSelection();
return CreateAndAddRange(parentNode, aContentOffset);
}
else if (aTarget == TABLESELECTION_ROW || aTarget == TABLESELECTION_COLUMN)
{
// Start drag-selecting mode so multiple rows/cols can be selected
// Note: Currently, nsFrame::GetDataForTableSelection
// will never call us for row or column selection on mouse down
mSelectingTableCells = PR_TRUE;
mSelectingTableCellMode = aTarget;
// Force new selection block
mStartSelectedCell = nsnull;
mDomSelections[index]->ClearSelection();
return SelectRowOrColumn(childContent, aTarget);
}
}
if (previousCellParent)
else
{
// If new cell in a different table is selected, trigger clearing the selection
nsCOMPtr<nsIContent> previousParentContent = do_QueryInterface(previousCellParent);
if (!IsInSameTable(selectedContent, previousParentContent, nsnull))
previousCellParent = nsnull;
}
if (!previousCellParent)
// There was no cell selected in the same table - clear selection
mDomSelections[index]->ClearSelection();
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Adding new selected cell range\n");
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Mouse UP event\n");
#endif
// Append a new selection range that surrounds the cell
// It would be nice to make the order of ranges
// map to the order of cells in table,
// but AddRange doesn't allow that
result = CreateAndAddRange(parentNode, aContentOffset);
if (NS_SUCCEEDED(result))
{
mSelectingTableCells = PR_TRUE;
mSelectingTableCellMode = TABLESELECTION_CELL;//only shut off on mouse up
// First check if we are extending a block selection
PRInt32 rangeCount;
result = mDomSelections[index]->GetRangeCount(&rangeCount);
if (NS_FAILED(result)) return result;
mStartSelectedCell = selectedContent;
mEndSelectedCell = selectedContent;
if (rangeCount > 0 && aMouseEvent->isShift &&
mAppendStartSelectedCell && mAppendStartSelectedCell != childContent)
{
// If Shift is down as well, append a block selection
return SelectBlockOfCells(childContent);
}
// Unselect a cell only if it wasn't
// just selected on mousedown
if( childContent == mUnselectCellOnMouseUp)
{
// Scan ranges to find the cell to unselect (the selection range to remove)
nsCOMPtr<nsIDOMNode> previousCellParent;
nsCOMPtr<nsIDOMRange> range;
PRInt32 offset;
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Unselecting mUnselectCellOnMouseUp; rangeCount=%d\n", rangeCount);
#endif
for( PRInt32 i = 0; i < rangeCount; i++)
{
result = mDomSelections[index]->GetRangeAt(i, getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (!range) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> parent;
result = range->GetStartParent(getter_AddRefs(parent));
if (NS_FAILED(result)) return result;
if (!parent) return NS_ERROR_NULL_POINTER;
range->GetStartOffset(&offset);
// Be sure previous selection is a table cell
nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);
nsCOMPtr<nsIContent> childContent;
result = parentContent->ChildAt(offset, *getter_AddRefs(childContent));
if (NS_FAILED(result)) return result;
if (childContent && IsCell(childContent))
previousCellParent = parent;
// We're done if we didn't find parent of a previously-selected cell
if (!previousCellParent) break;
if (previousCellParent == parentNode && offset == aContentOffset)
{
// Cell is already selected
if (rangeCount == 1)
{
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Unselecting single selected cell\n");
#endif
// This was the only cell selected.
// Collapse to "normal" selection inside the cell
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
mSelectingTableCellMode = 0;
//TODO: We need a "Collapse to just before deepest child" routine
// Even better, should we collapse to just after the LAST deepest child
// (i.e., at the end of the cell's contents)?
return mDomSelections[index]->Collapse(childNode, 0);
}
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Removing cell from multi-cell selection\n");
#endif
//TODO: Should we try to reassign to a different existing cell?
//mStartSelectedCell = nsnull;
//mEndSelectedCell = nsnull;
// Other cells are selected:
// Deselect cell by removing its range from selection
return mDomSelections[index]->RemoveRange(range);
}
}
mUnselectCellOnMouseUp = nsnull;
// Should we just return here?
// (we failed to unselect the cell)
}
// We have mouse up in a cell that was just selected on mouse down,
// (and no drag or shift-extend action intervened)
// Use it as the start of a block that
// we may append by using Shift+click in another cell
mAppendStartSelectedCell = childContent;
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Setting mAppendStartSelectedCell for append block\n");
#endif
}
}
return result;
@ -2269,57 +2357,88 @@ nsSelection::SelectBlockOfCells(nsIContent *aEndCell)
if (!aEndCell) return NS_ERROR_NULL_POINTER;
mEndSelectedCell = aEndCell;
nsCOMPtr<nsIDOMNode> cellNode;
nsCOMPtr<nsIDOMRange> range;
nsresult result = GetFirstSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (!cellNode || !range) return NS_OK;
nsCOMPtr<nsIContent> startCell;
nsresult result = NS_OK;
mStartSelectedCell = do_QueryInterface(cellNode);
if (mAppendStartSelectedCell)
{
// We are appending a new block
#ifdef DEBUG_cmanske
printf("SelectBlockOfCells -- using mAppendStartSelectedCell\n");
#endif
startCell = mAppendStartSelectedCell;
}
else if (mStartSelectedCell)
{
startCell = mStartSelectedCell;
#ifdef DEBUG_cmanske
printf("SelectBlockOfCells -- using mStartSelectedCell\n");
#endif
}
if (!startCell)
{
#ifdef DEBUG_cmanske
printf("SelectBlockOfCells -- NO START CELL!\n");
#endif
return NS_OK;
}
// If new end cell is in a different table, do nothing
nsCOMPtr<nsIContent> table;
if (!IsInSameTable(startCell, aEndCell, getter_AddRefs(table)))
return NS_OK;
// Get starting and ending cells' location in the cellmap
PRInt32 startRowIndex, startColIndex, endRowIndex, endColIndex;
result = GetCellIndexes(mStartSelectedCell, startRowIndex, startColIndex);
result = GetCellIndexes(startCell, startRowIndex, startColIndex);
if(NS_FAILED(result)) return result;
result = GetCellIndexes(aEndCell, endRowIndex, endColIndex);
if(NS_FAILED(result)) return result;
// Get parent table, and don't allow selection if start
// and end are not in same table
nsCOMPtr<nsIContent> table;
if (!IsInSameTable(mStartSelectedCell, aEndCell, getter_AddRefs(table)))
return NS_OK;
// Get TableLayout interface to access cell data based on cellmap location
// frames are not ref counted, so don't use an nsCOMPtr
nsITableLayout *tableLayoutObject = GetTableLayout(table);
if (!tableLayoutObject) return NS_ERROR_FAILURE;
// Remove selected cells outside of new block limits
PRInt32 minRowIndex = PR_MIN(startRowIndex, endRowIndex);
PRInt32 maxRowIndex = PR_MAX(startRowIndex, endRowIndex);
PRInt32 minColIndex = PR_MIN(startColIndex, endColIndex);
PRInt32 maxColIndex = PR_MAX(startColIndex, endColIndex);
PRInt32 curRowIndex, curColIndex;
// Examine all cell nodes, starting with first one found above
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
while (cellNode)
if (!mAppendStartSelectedCell)
{
nsCOMPtr<nsIContent> cellContent = do_QueryInterface(cellNode);
result = GetCellIndexes(cellContent, curRowIndex, curColIndex);
// Not appending - remove selected cells outside of new block limits
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
nsCOMPtr<nsIDOMNode> cellNode;
nsCOMPtr<nsIDOMRange> range;
result = GetFirstSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (curRowIndex < minRowIndex || curRowIndex > maxRowIndex ||
curColIndex < minColIndex || curColIndex > maxColIndex)
PRInt32 minRowIndex = PR_MIN(startRowIndex, endRowIndex);
PRInt32 maxRowIndex = PR_MAX(startRowIndex, endRowIndex);
PRInt32 minColIndex = PR_MIN(startColIndex, endColIndex);
PRInt32 maxColIndex = PR_MAX(startColIndex, endColIndex);
while (cellNode)
{
mDomSelections[index]->RemoveRange(range);
// Since we've removed the range, decrement pointer to next range
mSelectedCellIndex--;
}
result = GetNextSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
nsCOMPtr<nsIContent> childContent = do_QueryInterface(cellNode);
result = GetCellIndexes(childContent, curRowIndex, curColIndex);
if (NS_FAILED(result)) return result;
#ifdef DEBUG_cmanske
if (!range)
printf("SelectBlockOfCells -- range is null\n");
#endif
if (range &&
(curRowIndex < minRowIndex || curRowIndex > maxRowIndex ||
curColIndex < minColIndex || curColIndex > maxColIndex))
{
mDomSelections[index]->RemoveRange(range);
// Since we've removed the range, decrement pointer to next range
mSelectedCellIndex--;
}
result = GetNextSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
}
}
nsCOMPtr<nsIDOMElement> cellElement;
@ -2362,7 +2481,6 @@ nsSelection::SelectBlockOfCells(nsIContent *aEndCell)
else
row--;
};
return result;
}
@ -2410,6 +2528,7 @@ nsSelection::SelectRowOrColumn(nsIContent *aCellContent, PRUint32 aTarget)
if (NS_FAILED(result)) return result;
if (cellElement)
{
NS_ASSERTION(actualRowSpan > 0 && actualColSpan> 0, "SelectRowOrColumn: Bad rowspan or colspan\n");
if (!firstCell)
firstCell = cellElement;
@ -2434,6 +2553,7 @@ nsSelection::SelectRowOrColumn(nsIContent *aCellContent, PRUint32 aTarget)
// We are starting a new block, so select the first cell
result = SelectCellElement(firstCell);
if (NS_FAILED(result)) return result;
mStartSelectedCell = do_QueryInterface(firstCell);
}
nsCOMPtr<nsIContent> lastCellContent = do_QueryInterface(lastCell);
return SelectBlockOfCells(lastCellContent);
@ -2510,9 +2630,12 @@ nsSelection::GetFirstCellNodeInRange(nsIDOMRange *aRange, nsIDOMNode **aCellNode
nsresult
nsSelection::GetFirstSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRange)
{
if (!aCell || !aRange) return NS_ERROR_NULL_POINTER;
if (!aCell) return NS_ERROR_NULL_POINTER;
*aCell = nsnull;
*aRange = nsnull;
// aRange is optional
if (aRange)
*aRange = nsnull;
nsCOMPtr<nsIDOMRange> firstRange;
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
@ -2527,8 +2650,11 @@ nsSelection::GetFirstSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRan
*aCell = cellNode;
NS_ADDREF(*aCell);
*aRange = firstRange;
NS_ADDREF(*aRange);
if (aRange)
{
*aRange = firstRange;
NS_ADDREF(*aRange);
}
// Setup for next cell
mSelectedCellIndex = 1;
@ -2539,9 +2665,12 @@ nsSelection::GetFirstSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRan
nsresult
nsSelection::GetNextSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRange)
{
if (!aCell || !aRange) return NS_ERROR_NULL_POINTER;
if (!aCell) return NS_ERROR_NULL_POINTER;
*aCell = nsnull;
*aRange = nsnull;
// aRange is optional
if (aRange)
*aRange = nsnull;
PRInt32 rangeCount;
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
@ -2571,8 +2700,11 @@ nsSelection::GetNextSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRang
*aCell = cellNode;
NS_ADDREF(*aCell);
*aRange = range;
NS_ADDREF(*aRange);
if (aRange)
{
*aRange = range;
NS_ADDREF(*aRange);
}
// Setup for next cell
mSelectedCellIndex++;
@ -2657,9 +2789,10 @@ nsSelection::SelectCellElement(nsIDOMElement *aCellElement)
if (NS_FAILED(result)) return result;
if (!parent) return NS_ERROR_FAILURE;
// Get child offset
nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);
nsCOMPtr<nsIContent> cellContent = do_QueryInterface(aCellElement);
// Get child offset
PRInt32 offset;
result = parentContent->IndexOf(cellContent, offset);
if (NS_FAILED(result)) return result;

View File

@ -356,9 +356,12 @@ private:
nsresult GetParentTable(nsIContent *aCellNode, nsIContent **aTableNode);
nsresult SelectCellElement(nsIDOMElement* aCellElement);
nsresult CreateAndAddRange(nsIDOMNode *aParentNode, PRInt32 aOffset);
nsresult ClearNormalSelection();
nsCOMPtr<nsIContent> mStartSelectedCell;
nsCOMPtr<nsIContent> mEndSelectedCell;
nsCOMPtr<nsIContent> mAppendStartSelectedCell;
nsCOMPtr<nsIContent> mUnselectCellOnMouseUp;
PRBool mSelectingTableCells;
PRUint32 mSelectingTableCellMode;
PRInt32 mSelectedCellIndex;
@ -1555,7 +1558,6 @@ nsSelection::HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset,
// Don't take focus when dragging off of a table
if (!mSelectingTableCells)
{
mSelectingTableCellMode = 0;
return TakeFocus(aNewFocus, aContentOffset, aContentEndOffset, aContinueSelection, aMultipleSelection);
}
@ -1726,7 +1728,10 @@ nsSelection::SetMouseDownState(PRBool aState)
mMouseDownState = aState;
if (!mMouseDownState)
{
// Mouse up kills table selection
// Mouse up kills dragging-table cell selection
#ifdef DEBUG_cmanske
printf("SetMouseDownState to FALSE - stopping cell selection\n");
#endif
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
@ -2040,6 +2045,13 @@ nsSelection::GetTableLayout(nsIContent *aTableContent)
return tableLayoutObject;
}
nsresult
nsSelection::ClearNormalSelection()
{
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
return mDomSelections[index]->ClearSelection();
}
nsresult
nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOffset, PRUint32 aTarget, nsMouseEvent *aMouseEvent)
{
@ -2054,13 +2066,13 @@ nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOf
nsCOMPtr<nsIDOMNode> parentNode = do_QueryInterface(aParentContent);
if (!parentNode) return NS_ERROR_FAILURE;
nsCOMPtr<nsIContent> selectedContent;
nsresult result = aParentContent->ChildAt(aContentOffset, *getter_AddRefs(selectedContent));
nsCOMPtr<nsIContent> childContent;
nsresult result = aParentContent->ChildAt(aContentOffset, *getter_AddRefs(childContent));
if (NS_FAILED(result)) return result;
if (!selectedContent) return NS_ERROR_FAILURE;
if (!childContent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> selectedNode = do_QueryInterface(selectedContent);
if (!selectedNode) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> childNode = do_QueryInterface(childContent);
if (!childNode) return NS_ERROR_FAILURE;
// When doing table selection, always set the direction to next
// so we can be sure that anchorNode's offset always points to the selected cell
@ -2071,39 +2083,79 @@ nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOf
// BeginBatchChanges() / EndBatchChanges()
nsSelectionBatcher selectionBatcher(mDomSelections[index]);
PRInt32 startRowIndex, startColIndex, curRowIndex, curColIndex;
if (mSelectingTableCells)
{
// We are drag-selecting
if (aTarget != TABLESELECTION_TABLE)
{
// If dragging in the same cell as last event, do nothing
if (mEndSelectedCell == childContent)
return NS_OK;
// aTarget can be any "cell mode",
// so we can easily drag-select rows and columns
// Once user gets the col or row hit area onclick,
// they can drift into any cell to stay in col/row mode
// (aTarget will be TABLESELECTION_CELL)
// If dragging in the same cell as last event, do nothing
if (mEndSelectedCell == selectedContent)
return NS_OK;
// Once we are in row or column mode,
// we can drift into any cell to stay in that mode
// even if aTarget = TABLESELECTION_CELL
if (mSelectingTableCellMode == TABLESELECTION_ROW ||
mSelectingTableCellMode == TABLESELECTION_COLUMN)
{
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Dragged into a new column or row\n");
if (mEndSelectedCell)
{
// Also check if cell is in same row/col
result = GetCellIndexes(mEndSelectedCell, startRowIndex, startColIndex);
if (NS_FAILED(result)) return result;
result = GetCellIndexes(childContent, curRowIndex, curColIndex);
if (NS_FAILED(result)) return result;
if ((mSelectingTableCellMode == TABLESELECTION_ROW && startRowIndex == curRowIndex) ||
(mSelectingTableCellMode == TABLESELECTION_COLUMN && startColIndex == curColIndex))
return NS_OK;
}
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Dragged into a new column or row\n");
#endif
// Append anthor row or columns to the selection
return SelectRowOrColumn(selectedContent, mSelectingTableCellMode);
// Continue dragging row or column selection
return SelectRowOrColumn(childContent, mSelectingTableCellMode);
}
else if (mSelectingTableCellMode == TABLESELECTION_CELL)
{
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Dragged into a new cell\n");
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Dragged into a new cell\n");
#endif
// Clear this to be sure SelectBlockOfCells works correctly
mAppendStartSelectedCell = nsnull;
// Trick for quick selection of rows and columns
// Hold down shift, then start selecting in one direction
// If next cell dragged into is in same row, select entire row,
// if next cell is in same column, select entire column
if (mStartSelectedCell && aMouseEvent->isShift)
{
result = GetCellIndexes(mStartSelectedCell, startRowIndex, startColIndex);
if (NS_FAILED(result)) return result;
result = GetCellIndexes(childContent, curRowIndex, curColIndex);
if (NS_FAILED(result)) return result;
if (startRowIndex == curRowIndex ||
startColIndex == curColIndex)
{
// Force new selection block
mStartSelectedCell = nsnull;
mDomSelections[index]->ClearSelection();
mSelectingTableCellMode =
(startRowIndex == curRowIndex) ? TABLESELECTION_ROW : TABLESELECTION_COLUMN;
return SelectRowOrColumn(childContent, mSelectingTableCellMode);
}
}
// Reselect block of cells to new end location
return SelectBlockOfCells(selectedContent);
return SelectBlockOfCells(childContent);
}
}
// Do nothing if dragging in table, but outside a cell
@ -2111,153 +2163,189 @@ nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOf
}
else
{
// Not dragging -- mouse event is a click
// Not dragging -- mouse event is down or up
if (mMouseDownState)
{
#ifdef DEBUG_cmanske
//#ifdef DEBUG_TABLE
printf("HandleTableSelection: CLICK event\n");
printf("HandleTableSelection: Selecting Table\n");
{
nsIFrame *frame = nsnull;
result = GetTracker()->GetPrimaryFrameFor(selectedContent, &frame);
if (frame)
{
nsRect rect1;
frame->GetRect(rect1);
printf("Frame rect: x=%d, y=%d, right=%d, bottom=%d\n", rect1.x, rect1.y, rect1.XMost(), rect1.YMost());
nsRect rect2 = rect1;
mDomSelections[index]->GetFrameToRootViewOffset(frame, &rect2.x, &rect2.y);
printf("Translated frame orgin: x=%d, y=%d\n", rect2.x, rect2.y);
printf("Mouse was clicked at: x=%d, y=%d\n", aMouseEvent->point.x, aMouseEvent->point.y);
printf("*** Widget-relative (refPoint): x=%d, y=%d\n", aMouseEvent->refPoint.x, aMouseEvent->refPoint.y);
}
/*
Useful frame methods:
GetRect(nsRect& aRect)
GetSize(nsSize& aSize)
*/
}
//#endif
printf("HandleTableSelection: Mouse down event\n");
#endif
if (aTarget == TABLESELECTION_ROW || aTarget == TABLESELECTION_COLUMN)
{
// Start drag-selecting mode so multiple rows/cols can be selected
mSelectingTableCells = PR_TRUE;
mSelectingTableCellMode = aTarget; //only shut off on mouse up.
// Clear cell we stored in mouse-down
mUnselectCellOnMouseUp = nsnull;
// Force new selection block
mStartSelectedCell = nsnull;
mDomSelections[index]->ClearSelection();
return SelectRowOrColumn(selectedContent, aTarget);
}
else if (aTarget == TABLESELECTION_TABLE)
{
//TODO: We currently select entire table when clicked between cells,
// should we restrict to only around border?
// *** How do we get location data for cell and click?
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
// Select the table
mDomSelections[index]->ClearSelection();
return CreateAndAddRange(parentNode, aContentOffset);
}
// We are already selecting cells
// Check if cell clicked on is already selected
PRInt32 rangeCount;
result = mDomSelections[index]->GetRangeCount(&rangeCount);
if (NS_FAILED(result)) return result;
if (rangeCount > 0 && aMouseEvent->isShift && selectedContent != mStartSelectedCell)
{
// If Shift is down as well, do a block selection
return SelectBlockOfCells(selectedContent);
}
nsCOMPtr<nsIDOMNode> previousCellParent;
nsCOMPtr<nsIDOMRange> range;
PRInt32 offset;
for( PRInt32 i = 0; i < rangeCount; i++)
{
result = mDomSelections[index]->GetRangeAt(i, getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (!range) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> parent;
result = range->GetStartParent(getter_AddRefs(parent));
if (NS_FAILED(result)) return result;
if (!parent) return NS_ERROR_NULL_POINTER;
range->GetStartOffset(&offset);
// Be sure previous selection is a table cell
nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);
nsCOMPtr<nsIContent> childContent;
result = parentContent->ChildAt(offset, *getter_AddRefs(childContent));
if (NS_FAILED(result)) return result;
if (childContent && IsCell(childContent))
previousCellParent = parent;
// We're done if we didn't find parent of a previously-selected cell
if (!previousCellParent) break;
if (previousCellParent == parentNode && offset == aContentOffset)
if (aTarget == TABLESELECTION_CELL)
{
// Cell is already selected
if (rangeCount == 1)
PRBool isSelected = PR_FALSE;
// Check if we have other selected cells
nsCOMPtr<nsIDOMNode> previousCellNode;
GetFirstSelectedCellAndRange(getter_AddRefs(previousCellNode), nsnull);
if (previousCellNode)
{
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Unselecting single selected cell\n");
#endif
// This was the only cell selected.
// Collapse to "normal" selection inside the cell
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
//TODO: We need a "Collapse to just before deepest child" routine
// Even better, should we collapse to just after the LAST deepest child
// (i.e., at the end of the cell's contents)?
return mDomSelections[index]->Collapse(selectedNode, 0);
// We have at least 1 other selected cell
// Check if new cell is already selected
nsIFrame *cellFrame = nsnull;
result = GetTracker()->GetPrimaryFrameFor(childContent, &cellFrame);
if (NS_FAILED(result)) return result;
if (!cellFrame) return NS_ERROR_NULL_POINTER;
result = cellFrame->GetSelected(&isSelected);
if (NS_FAILED(result)) return result;
}
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Removing cell from multi-cell selection\n");
else
{
// No cells selected -- remove non-cell selection
mDomSelections[index]->ClearSelection();
}
mSelectingTableCells = PR_TRUE; // Signal to start drag-cell-selection
mSelectingTableCellMode = aTarget;
// Set start for new drag-selection block (not appended)
mStartSelectedCell = childContent;
// The initial block end is same as the start
mEndSelectedCell = childContent;
if (isSelected)
{
// Remember this cell to (possibly) unselect it on mouseup
mUnselectCellOnMouseUp = childContent;
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Saving mUnselectCellOnMouseUp\n");
#endif
//TODO: Should we try to reassign to a different existing cell?
//mStartSelectedCell = nsnull;
//mEndSelectedCell = nsnull;
// Other cells are selected:
// Deselect cell by removing its range from selection
return mDomSelections[index]->RemoveRange(range);
}
else
{
// Select an unselected cell
// but first remove existing selection if not in same table
nsCOMPtr<nsIContent> previousCellContent = do_QueryInterface(previousCellNode);
if (!IsInSameTable(previousCellContent, childContent, nsnull))
mDomSelections[index]->ClearSelection();
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(childContent);
return SelectCellElement(cellElement);
}
return NS_OK;
}
else if (aTarget == TABLESELECTION_TABLE)
{
//TODO: We currently select entire table when clicked between cells,
// should we restrict to only around border?
// *** How do we get location data for cell and click?
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
// Remove existing selection and select the table
mDomSelections[index]->ClearSelection();
return CreateAndAddRange(parentNode, aContentOffset);
}
else if (aTarget == TABLESELECTION_ROW || aTarget == TABLESELECTION_COLUMN)
{
// Start drag-selecting mode so multiple rows/cols can be selected
// Note: Currently, nsFrame::GetDataForTableSelection
// will never call us for row or column selection on mouse down
mSelectingTableCells = PR_TRUE;
mSelectingTableCellMode = aTarget;
// Force new selection block
mStartSelectedCell = nsnull;
mDomSelections[index]->ClearSelection();
return SelectRowOrColumn(childContent, aTarget);
}
}
if (previousCellParent)
else
{
// If new cell in a different table is selected, trigger clearing the selection
nsCOMPtr<nsIContent> previousParentContent = do_QueryInterface(previousCellParent);
if (!IsInSameTable(selectedContent, previousParentContent, nsnull))
previousCellParent = nsnull;
}
if (!previousCellParent)
// There was no cell selected in the same table - clear selection
mDomSelections[index]->ClearSelection();
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Adding new selected cell range\n");
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Mouse UP event\n");
#endif
// Append a new selection range that surrounds the cell
// It would be nice to make the order of ranges
// map to the order of cells in table,
// but AddRange doesn't allow that
result = CreateAndAddRange(parentNode, aContentOffset);
if (NS_SUCCEEDED(result))
{
mSelectingTableCells = PR_TRUE;
mSelectingTableCellMode = TABLESELECTION_CELL;//only shut off on mouse up
// First check if we are extending a block selection
PRInt32 rangeCount;
result = mDomSelections[index]->GetRangeCount(&rangeCount);
if (NS_FAILED(result)) return result;
mStartSelectedCell = selectedContent;
mEndSelectedCell = selectedContent;
if (rangeCount > 0 && aMouseEvent->isShift &&
mAppendStartSelectedCell && mAppendStartSelectedCell != childContent)
{
// If Shift is down as well, append a block selection
return SelectBlockOfCells(childContent);
}
// Unselect a cell only if it wasn't
// just selected on mousedown
if( childContent == mUnselectCellOnMouseUp)
{
// Scan ranges to find the cell to unselect (the selection range to remove)
nsCOMPtr<nsIDOMNode> previousCellParent;
nsCOMPtr<nsIDOMRange> range;
PRInt32 offset;
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Unselecting mUnselectCellOnMouseUp; rangeCount=%d\n", rangeCount);
#endif
for( PRInt32 i = 0; i < rangeCount; i++)
{
result = mDomSelections[index]->GetRangeAt(i, getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (!range) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> parent;
result = range->GetStartParent(getter_AddRefs(parent));
if (NS_FAILED(result)) return result;
if (!parent) return NS_ERROR_NULL_POINTER;
range->GetStartOffset(&offset);
// Be sure previous selection is a table cell
nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);
nsCOMPtr<nsIContent> childContent;
result = parentContent->ChildAt(offset, *getter_AddRefs(childContent));
if (NS_FAILED(result)) return result;
if (childContent && IsCell(childContent))
previousCellParent = parent;
// We're done if we didn't find parent of a previously-selected cell
if (!previousCellParent) break;
if (previousCellParent == parentNode && offset == aContentOffset)
{
// Cell is already selected
if (rangeCount == 1)
{
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Unselecting single selected cell\n");
#endif
// This was the only cell selected.
// Collapse to "normal" selection inside the cell
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
mSelectingTableCellMode = 0;
//TODO: We need a "Collapse to just before deepest child" routine
// Even better, should we collapse to just after the LAST deepest child
// (i.e., at the end of the cell's contents)?
return mDomSelections[index]->Collapse(childNode, 0);
}
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Removing cell from multi-cell selection\n");
#endif
//TODO: Should we try to reassign to a different existing cell?
//mStartSelectedCell = nsnull;
//mEndSelectedCell = nsnull;
// Other cells are selected:
// Deselect cell by removing its range from selection
return mDomSelections[index]->RemoveRange(range);
}
}
mUnselectCellOnMouseUp = nsnull;
// Should we just return here?
// (we failed to unselect the cell)
}
// We have mouse up in a cell that was just selected on mouse down,
// (and no drag or shift-extend action intervened)
// Use it as the start of a block that
// we may append by using Shift+click in another cell
mAppendStartSelectedCell = childContent;
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Setting mAppendStartSelectedCell for append block\n");
#endif
}
}
return result;
@ -2269,57 +2357,88 @@ nsSelection::SelectBlockOfCells(nsIContent *aEndCell)
if (!aEndCell) return NS_ERROR_NULL_POINTER;
mEndSelectedCell = aEndCell;
nsCOMPtr<nsIDOMNode> cellNode;
nsCOMPtr<nsIDOMRange> range;
nsresult result = GetFirstSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (!cellNode || !range) return NS_OK;
nsCOMPtr<nsIContent> startCell;
nsresult result = NS_OK;
mStartSelectedCell = do_QueryInterface(cellNode);
if (mAppendStartSelectedCell)
{
// We are appending a new block
#ifdef DEBUG_cmanske
printf("SelectBlockOfCells -- using mAppendStartSelectedCell\n");
#endif
startCell = mAppendStartSelectedCell;
}
else if (mStartSelectedCell)
{
startCell = mStartSelectedCell;
#ifdef DEBUG_cmanske
printf("SelectBlockOfCells -- using mStartSelectedCell\n");
#endif
}
if (!startCell)
{
#ifdef DEBUG_cmanske
printf("SelectBlockOfCells -- NO START CELL!\n");
#endif
return NS_OK;
}
// If new end cell is in a different table, do nothing
nsCOMPtr<nsIContent> table;
if (!IsInSameTable(startCell, aEndCell, getter_AddRefs(table)))
return NS_OK;
// Get starting and ending cells' location in the cellmap
PRInt32 startRowIndex, startColIndex, endRowIndex, endColIndex;
result = GetCellIndexes(mStartSelectedCell, startRowIndex, startColIndex);
result = GetCellIndexes(startCell, startRowIndex, startColIndex);
if(NS_FAILED(result)) return result;
result = GetCellIndexes(aEndCell, endRowIndex, endColIndex);
if(NS_FAILED(result)) return result;
// Get parent table, and don't allow selection if start
// and end are not in same table
nsCOMPtr<nsIContent> table;
if (!IsInSameTable(mStartSelectedCell, aEndCell, getter_AddRefs(table)))
return NS_OK;
// Get TableLayout interface to access cell data based on cellmap location
// frames are not ref counted, so don't use an nsCOMPtr
nsITableLayout *tableLayoutObject = GetTableLayout(table);
if (!tableLayoutObject) return NS_ERROR_FAILURE;
// Remove selected cells outside of new block limits
PRInt32 minRowIndex = PR_MIN(startRowIndex, endRowIndex);
PRInt32 maxRowIndex = PR_MAX(startRowIndex, endRowIndex);
PRInt32 minColIndex = PR_MIN(startColIndex, endColIndex);
PRInt32 maxColIndex = PR_MAX(startColIndex, endColIndex);
PRInt32 curRowIndex, curColIndex;
// Examine all cell nodes, starting with first one found above
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
while (cellNode)
if (!mAppendStartSelectedCell)
{
nsCOMPtr<nsIContent> cellContent = do_QueryInterface(cellNode);
result = GetCellIndexes(cellContent, curRowIndex, curColIndex);
// Not appending - remove selected cells outside of new block limits
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
nsCOMPtr<nsIDOMNode> cellNode;
nsCOMPtr<nsIDOMRange> range;
result = GetFirstSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (curRowIndex < minRowIndex || curRowIndex > maxRowIndex ||
curColIndex < minColIndex || curColIndex > maxColIndex)
PRInt32 minRowIndex = PR_MIN(startRowIndex, endRowIndex);
PRInt32 maxRowIndex = PR_MAX(startRowIndex, endRowIndex);
PRInt32 minColIndex = PR_MIN(startColIndex, endColIndex);
PRInt32 maxColIndex = PR_MAX(startColIndex, endColIndex);
while (cellNode)
{
mDomSelections[index]->RemoveRange(range);
// Since we've removed the range, decrement pointer to next range
mSelectedCellIndex--;
}
result = GetNextSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
nsCOMPtr<nsIContent> childContent = do_QueryInterface(cellNode);
result = GetCellIndexes(childContent, curRowIndex, curColIndex);
if (NS_FAILED(result)) return result;
#ifdef DEBUG_cmanske
if (!range)
printf("SelectBlockOfCells -- range is null\n");
#endif
if (range &&
(curRowIndex < minRowIndex || curRowIndex > maxRowIndex ||
curColIndex < minColIndex || curColIndex > maxColIndex))
{
mDomSelections[index]->RemoveRange(range);
// Since we've removed the range, decrement pointer to next range
mSelectedCellIndex--;
}
result = GetNextSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
}
}
nsCOMPtr<nsIDOMElement> cellElement;
@ -2362,7 +2481,6 @@ nsSelection::SelectBlockOfCells(nsIContent *aEndCell)
else
row--;
};
return result;
}
@ -2410,6 +2528,7 @@ nsSelection::SelectRowOrColumn(nsIContent *aCellContent, PRUint32 aTarget)
if (NS_FAILED(result)) return result;
if (cellElement)
{
NS_ASSERTION(actualRowSpan > 0 && actualColSpan> 0, "SelectRowOrColumn: Bad rowspan or colspan\n");
if (!firstCell)
firstCell = cellElement;
@ -2434,6 +2553,7 @@ nsSelection::SelectRowOrColumn(nsIContent *aCellContent, PRUint32 aTarget)
// We are starting a new block, so select the first cell
result = SelectCellElement(firstCell);
if (NS_FAILED(result)) return result;
mStartSelectedCell = do_QueryInterface(firstCell);
}
nsCOMPtr<nsIContent> lastCellContent = do_QueryInterface(lastCell);
return SelectBlockOfCells(lastCellContent);
@ -2510,9 +2630,12 @@ nsSelection::GetFirstCellNodeInRange(nsIDOMRange *aRange, nsIDOMNode **aCellNode
nsresult
nsSelection::GetFirstSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRange)
{
if (!aCell || !aRange) return NS_ERROR_NULL_POINTER;
if (!aCell) return NS_ERROR_NULL_POINTER;
*aCell = nsnull;
*aRange = nsnull;
// aRange is optional
if (aRange)
*aRange = nsnull;
nsCOMPtr<nsIDOMRange> firstRange;
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
@ -2527,8 +2650,11 @@ nsSelection::GetFirstSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRan
*aCell = cellNode;
NS_ADDREF(*aCell);
*aRange = firstRange;
NS_ADDREF(*aRange);
if (aRange)
{
*aRange = firstRange;
NS_ADDREF(*aRange);
}
// Setup for next cell
mSelectedCellIndex = 1;
@ -2539,9 +2665,12 @@ nsSelection::GetFirstSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRan
nsresult
nsSelection::GetNextSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRange)
{
if (!aCell || !aRange) return NS_ERROR_NULL_POINTER;
if (!aCell) return NS_ERROR_NULL_POINTER;
*aCell = nsnull;
*aRange = nsnull;
// aRange is optional
if (aRange)
*aRange = nsnull;
PRInt32 rangeCount;
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
@ -2571,8 +2700,11 @@ nsSelection::GetNextSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRang
*aCell = cellNode;
NS_ADDREF(*aCell);
*aRange = range;
NS_ADDREF(*aRange);
if (aRange)
{
*aRange = range;
NS_ADDREF(*aRange);
}
// Setup for next cell
mSelectedCellIndex++;
@ -2657,9 +2789,10 @@ nsSelection::SelectCellElement(nsIDOMElement *aCellElement)
if (NS_FAILED(result)) return result;
if (!parent) return NS_ERROR_FAILURE;
// Get child offset
nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);
nsCOMPtr<nsIContent> cellContent = do_QueryInterface(aCellElement);
// Get child offset
PRInt32 offset;
result = parentContent->IndexOf(cellContent, offset);
if (NS_FAILED(result)) return result;

View File

@ -804,10 +804,10 @@ nsFrame::HandleEvent(nsIPresContext* aPresContext,
}
NS_IMETHODIMP
nsFrame::GetDataForTableSelection(nsMouseEvent *aMouseEvent, nsIContent **aParentContent,
PRInt32 *aContentOffset, PRUint32 *aTarget)
nsFrame::GetDataForTableSelection(nsIFrameSelection *aFrameSelection, nsMouseEvent *aMouseEvent,
nsIContent **aParentContent, PRInt32 *aContentOffset, PRUint32 *aTarget)
{
if (!aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
if (!aFrameSelection || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
return NS_ERROR_NULL_POINTER;
*aParentContent = nsnull;
@ -816,22 +816,33 @@ nsFrame::GetDataForTableSelection(nsMouseEvent *aMouseEvent, nsIContent **aParen
// Test if special 'table selection' key is pressed
PRBool doTableSelection;
#ifdef XP_MAC
doTableSelection = aMouseEvent->isMeta;
#else
doTableSelection = aMouseEvent->isControl;
#endif
if (!doTableSelection) return NS_OK;
if (!doTableSelection)
{
// We allow table selection when just Shift is pressed
// only if already in table/cell selection mode
if (aMouseEvent->isShift)
aFrameSelection->GetTableCellSelection(&doTableSelection);
if (!doTableSelection)
return NS_OK;
}
// Get the cell frame or table frame (or parent) of the current content node
nsIFrame *frame = this;
nsresult result = NS_OK;
PRBool foundCell = PR_FALSE;
PRBool foundTable = PR_FALSE;
PRBool selectColumn = PR_FALSE;
PRBool selectRow = PR_FALSE;
//We don't initiate row/col selection from here now,
// but we may in future
//PRBool selectColumn = PR_FALSE;
//PRBool selectRow = PR_FALSE;
while (frame && NS_SUCCEEDED(result))
{
@ -841,23 +852,8 @@ nsFrame::GetDataForTableSelection(nsMouseEvent *aMouseEvent, nsIContent **aParen
if (NS_SUCCEEDED(result) && cellElement)
{
foundCell = PR_TRUE;
PRInt32 colIndex, rowIndex;
result = cellElement->GetCellIndexes(rowIndex, colIndex);
// Give precedence to row over column
if (colIndex == 0)
{
//printf(" * SelRow: x=%d, y=%d\n", aMouseEvent->point.x, aMouseEvent->point.y);
//TODO: We need to test for proximity to top border
// For now, just go into row selection mode
selectRow = PR_TRUE;
}
else if (rowIndex == 0)
{
//printf(" * SelCol: x=%d, y=%d\n", aMouseEvent->point.x, aMouseEvent->point.y);
//TODO: We need to test for proximity to left border
// For now, just go into COLUMN selection mode
selectColumn = PR_TRUE;
}
//TODO: If we want to use proximity to top or left border
// for row and column selection, this is the place to do it
break;
}
else
@ -903,11 +899,14 @@ nsFrame::GetDataForTableSelection(nsMouseEvent *aMouseEvent, nsIContent **aParen
*aContentOffset = offset;
#if 0
if (selectRow)
*aTarget = TABLESELECTION_ROW;
else if (selectColumn)
*aTarget = TABLESELECTION_COLUMN;
else if (foundCell)
else
#endif
if (foundCell)
*aTarget = TABLESELECTION_CELL;
else if (foundTable)
*aTarget = TABLESELECTION_TABLE;
@ -1007,6 +1006,19 @@ nsFrame::HandlePress(nsIPresContext* aPresContext,
if (NS_FAILED(rv))
return rv;
// Let Ctrl/Cmd+mouse down do table selection instead of drag initiation
nsCOMPtr<nsIContent>parentContent;
PRInt32 contentOffset;
PRUint32 target;
rv = GetDataForTableSelection(frameselection, me, getter_AddRefs(parentContent), &contentOffset, &target);
if (NS_SUCCEEDED(rv) && parentContent)
{
rv = frameselection->SetMouseDownState( PR_TRUE );
if (NS_FAILED(rv)) return rv;
return frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
}
PRBool supportsDelay = PR_FALSE;
frameselection->GetDelayCaretOverExistingSelection(&supportsDelay);
@ -1071,19 +1083,7 @@ nsFrame::HandlePress(nsIPresContext* aPresContext,
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIContent>parentContent;
PRInt32 contentOffset;
PRUint32 target;
rv = GetDataForTableSelection(me, getter_AddRefs(parentContent), &contentOffset, &target);
if (NS_SUCCEEDED(rv) && parentContent)
rv = frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
else
rv = frameselection->HandleClick(content, startOffset , endOffset, me->isShift, PR_FALSE, beginFrameContent);
return rv;
return frameselection->HandleClick(content, startOffset , endOffset, me->isShift, PR_FALSE, beginFrameContent);
}
/**
@ -1269,7 +1269,7 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsIPresContext* aPresContext,
PRInt32 contentOffset;
PRUint32 target;
nsMouseEvent *me = (nsMouseEvent *)aEvent;
result = GetDataForTableSelection(me, getter_AddRefs(parentContent), &contentOffset, &target);
result = GetDataForTableSelection(frameselection, me, getter_AddRefs(parentContent), &contentOffset, &target);
if (NS_SUCCEEDED(result) && parentContent)
frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
else
@ -1342,31 +1342,34 @@ NS_IMETHODIMP nsFrame::HandleRelease(nsIPresContext* aPresContext,
if (NS_SUCCEEDED(result) && !mouseDown && me && me->clickCount < 2)
{
// We are doing this to simulate what we would have done on HandlePress
result = frameselection->SetMouseDownState( PR_TRUE );
nsCOMPtr<nsIContent> content;
PRInt32 startOffset = 0, endOffset = 0;
PRBool beginFrameContent = PR_FALSE;
result = GetContentAndOffsetsFromPoint(aPresContext, me->point, getter_AddRefs(content), startOffset, endOffset, beginFrameContent);
if (NS_FAILED(result)) return result;
result = frameselection->HandleClick(content, startOffset , endOffset, me->isShift, PR_FALSE, beginFrameContent);
if (NS_FAILED(result)) return result;
}
else
{
me = (nsMouseEvent *)aEvent;
nsCOMPtr<nsIContent>parentContent;
PRInt32 contentOffset;
PRUint32 target;
result = GetDataForTableSelection(me, getter_AddRefs(parentContent), &contentOffset, &target);
result = GetDataForTableSelection(frameselection, me, getter_AddRefs(parentContent), &contentOffset, &target);
if (NS_SUCCEEDED(result) && parentContent)
result = frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
else
{
nsCOMPtr<nsIContent> content;
PRInt32 startOffset = 0, endOffset = 0;
PRBool beginFrameContent = PR_FALSE;
result = GetContentAndOffsetsFromPoint(aPresContext, me->point, getter_AddRefs(content), startOffset, endOffset, beginFrameContent);
if (NS_FAILED(result))
return result;
result = frameselection->HandleClick(content, startOffset , endOffset, me->isShift, PR_FALSE, beginFrameContent);
frameselection->SetMouseDownState( PR_FALSE );
result = frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
if (NS_FAILED(result)) return result;
}
}
result = frameselection->SetDelayedCaretData(0);
}

View File

@ -33,6 +33,7 @@
#include "nsIPresShell.h"
#include "nsIReflowCommand.h"
#include "nsIFrameSelection.h"
/**
* nsFrame logging constants. We redefine the nspr
@ -418,13 +419,15 @@ protected:
static void GetFirstLeaf(nsIPresContext* aPresContext, nsIFrame **aFrame);
// Test if we are selecting a table object:
// First test if Ctrl (Cmd on Mac) key is down during a mouse click or drag
// If yes, get the parent content node and offset of the frame
// Most table/cell selection requires that Ctrl (Cmd on Mac) key is down
// during a mouse click or drag. Exception is using Shift+click when
// already in "table/cell selection mode" to extend a block selection
// Get the parent content node and offset of the frame
// of the enclosing cell or table (if not inside a cell)
// aTarget tells us what table element to select (currently only cell and table supported)
// (enums for this are defined in nsIFrame.h)
NS_IMETHOD GetDataForTableSelection(nsMouseEvent *aMouseEvent, nsIContent **aParentContent,
PRInt32 *aContentOffset, PRUint32 *aTarget);
NS_IMETHOD GetDataForTableSelection(nsIFrameSelection *aFrameSelection, nsMouseEvent *aMouseEvent,
nsIContent **aParentContent, PRInt32 *aContentOffset, PRUint32 *aTarget);
static void XMLQuote(nsString& aString);

View File

@ -356,9 +356,12 @@ private:
nsresult GetParentTable(nsIContent *aCellNode, nsIContent **aTableNode);
nsresult SelectCellElement(nsIDOMElement* aCellElement);
nsresult CreateAndAddRange(nsIDOMNode *aParentNode, PRInt32 aOffset);
nsresult ClearNormalSelection();
nsCOMPtr<nsIContent> mStartSelectedCell;
nsCOMPtr<nsIContent> mEndSelectedCell;
nsCOMPtr<nsIContent> mAppendStartSelectedCell;
nsCOMPtr<nsIContent> mUnselectCellOnMouseUp;
PRBool mSelectingTableCells;
PRUint32 mSelectingTableCellMode;
PRInt32 mSelectedCellIndex;
@ -1555,7 +1558,6 @@ nsSelection::HandleClick(nsIContent *aNewFocus, PRUint32 aContentOffset,
// Don't take focus when dragging off of a table
if (!mSelectingTableCells)
{
mSelectingTableCellMode = 0;
return TakeFocus(aNewFocus, aContentOffset, aContentEndOffset, aContinueSelection, aMultipleSelection);
}
@ -1726,7 +1728,10 @@ nsSelection::SetMouseDownState(PRBool aState)
mMouseDownState = aState;
if (!mMouseDownState)
{
// Mouse up kills table selection
// Mouse up kills dragging-table cell selection
#ifdef DEBUG_cmanske
printf("SetMouseDownState to FALSE - stopping cell selection\n");
#endif
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
@ -2040,6 +2045,13 @@ nsSelection::GetTableLayout(nsIContent *aTableContent)
return tableLayoutObject;
}
nsresult
nsSelection::ClearNormalSelection()
{
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
return mDomSelections[index]->ClearSelection();
}
nsresult
nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOffset, PRUint32 aTarget, nsMouseEvent *aMouseEvent)
{
@ -2054,13 +2066,13 @@ nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOf
nsCOMPtr<nsIDOMNode> parentNode = do_QueryInterface(aParentContent);
if (!parentNode) return NS_ERROR_FAILURE;
nsCOMPtr<nsIContent> selectedContent;
nsresult result = aParentContent->ChildAt(aContentOffset, *getter_AddRefs(selectedContent));
nsCOMPtr<nsIContent> childContent;
nsresult result = aParentContent->ChildAt(aContentOffset, *getter_AddRefs(childContent));
if (NS_FAILED(result)) return result;
if (!selectedContent) return NS_ERROR_FAILURE;
if (!childContent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> selectedNode = do_QueryInterface(selectedContent);
if (!selectedNode) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMNode> childNode = do_QueryInterface(childContent);
if (!childNode) return NS_ERROR_FAILURE;
// When doing table selection, always set the direction to next
// so we can be sure that anchorNode's offset always points to the selected cell
@ -2071,39 +2083,79 @@ nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOf
// BeginBatchChanges() / EndBatchChanges()
nsSelectionBatcher selectionBatcher(mDomSelections[index]);
PRInt32 startRowIndex, startColIndex, curRowIndex, curColIndex;
if (mSelectingTableCells)
{
// We are drag-selecting
if (aTarget != TABLESELECTION_TABLE)
{
// If dragging in the same cell as last event, do nothing
if (mEndSelectedCell == childContent)
return NS_OK;
// aTarget can be any "cell mode",
// so we can easily drag-select rows and columns
// Once user gets the col or row hit area onclick,
// they can drift into any cell to stay in col/row mode
// (aTarget will be TABLESELECTION_CELL)
// If dragging in the same cell as last event, do nothing
if (mEndSelectedCell == selectedContent)
return NS_OK;
// Once we are in row or column mode,
// we can drift into any cell to stay in that mode
// even if aTarget = TABLESELECTION_CELL
if (mSelectingTableCellMode == TABLESELECTION_ROW ||
mSelectingTableCellMode == TABLESELECTION_COLUMN)
{
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Dragged into a new column or row\n");
if (mEndSelectedCell)
{
// Also check if cell is in same row/col
result = GetCellIndexes(mEndSelectedCell, startRowIndex, startColIndex);
if (NS_FAILED(result)) return result;
result = GetCellIndexes(childContent, curRowIndex, curColIndex);
if (NS_FAILED(result)) return result;
if ((mSelectingTableCellMode == TABLESELECTION_ROW && startRowIndex == curRowIndex) ||
(mSelectingTableCellMode == TABLESELECTION_COLUMN && startColIndex == curColIndex))
return NS_OK;
}
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Dragged into a new column or row\n");
#endif
// Append anthor row or columns to the selection
return SelectRowOrColumn(selectedContent, mSelectingTableCellMode);
// Continue dragging row or column selection
return SelectRowOrColumn(childContent, mSelectingTableCellMode);
}
else if (mSelectingTableCellMode == TABLESELECTION_CELL)
{
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Dragged into a new cell\n");
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Dragged into a new cell\n");
#endif
// Clear this to be sure SelectBlockOfCells works correctly
mAppendStartSelectedCell = nsnull;
// Trick for quick selection of rows and columns
// Hold down shift, then start selecting in one direction
// If next cell dragged into is in same row, select entire row,
// if next cell is in same column, select entire column
if (mStartSelectedCell && aMouseEvent->isShift)
{
result = GetCellIndexes(mStartSelectedCell, startRowIndex, startColIndex);
if (NS_FAILED(result)) return result;
result = GetCellIndexes(childContent, curRowIndex, curColIndex);
if (NS_FAILED(result)) return result;
if (startRowIndex == curRowIndex ||
startColIndex == curColIndex)
{
// Force new selection block
mStartSelectedCell = nsnull;
mDomSelections[index]->ClearSelection();
mSelectingTableCellMode =
(startRowIndex == curRowIndex) ? TABLESELECTION_ROW : TABLESELECTION_COLUMN;
return SelectRowOrColumn(childContent, mSelectingTableCellMode);
}
}
// Reselect block of cells to new end location
return SelectBlockOfCells(selectedContent);
return SelectBlockOfCells(childContent);
}
}
// Do nothing if dragging in table, but outside a cell
@ -2111,153 +2163,189 @@ nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOf
}
else
{
// Not dragging -- mouse event is a click
// Not dragging -- mouse event is down or up
if (mMouseDownState)
{
#ifdef DEBUG_cmanske
//#ifdef DEBUG_TABLE
printf("HandleTableSelection: CLICK event\n");
printf("HandleTableSelection: Selecting Table\n");
{
nsIFrame *frame = nsnull;
result = GetTracker()->GetPrimaryFrameFor(selectedContent, &frame);
if (frame)
{
nsRect rect1;
frame->GetRect(rect1);
printf("Frame rect: x=%d, y=%d, right=%d, bottom=%d\n", rect1.x, rect1.y, rect1.XMost(), rect1.YMost());
nsRect rect2 = rect1;
mDomSelections[index]->GetFrameToRootViewOffset(frame, &rect2.x, &rect2.y);
printf("Translated frame orgin: x=%d, y=%d\n", rect2.x, rect2.y);
printf("Mouse was clicked at: x=%d, y=%d\n", aMouseEvent->point.x, aMouseEvent->point.y);
printf("*** Widget-relative (refPoint): x=%d, y=%d\n", aMouseEvent->refPoint.x, aMouseEvent->refPoint.y);
}
/*
Useful frame methods:
GetRect(nsRect& aRect)
GetSize(nsSize& aSize)
*/
}
//#endif
printf("HandleTableSelection: Mouse down event\n");
#endif
if (aTarget == TABLESELECTION_ROW || aTarget == TABLESELECTION_COLUMN)
{
// Start drag-selecting mode so multiple rows/cols can be selected
mSelectingTableCells = PR_TRUE;
mSelectingTableCellMode = aTarget; //only shut off on mouse up.
// Clear cell we stored in mouse-down
mUnselectCellOnMouseUp = nsnull;
// Force new selection block
mStartSelectedCell = nsnull;
mDomSelections[index]->ClearSelection();
return SelectRowOrColumn(selectedContent, aTarget);
}
else if (aTarget == TABLESELECTION_TABLE)
{
//TODO: We currently select entire table when clicked between cells,
// should we restrict to only around border?
// *** How do we get location data for cell and click?
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
// Select the table
mDomSelections[index]->ClearSelection();
return CreateAndAddRange(parentNode, aContentOffset);
}
// We are already selecting cells
// Check if cell clicked on is already selected
PRInt32 rangeCount;
result = mDomSelections[index]->GetRangeCount(&rangeCount);
if (NS_FAILED(result)) return result;
if (rangeCount > 0 && aMouseEvent->isShift && selectedContent != mStartSelectedCell)
{
// If Shift is down as well, do a block selection
return SelectBlockOfCells(selectedContent);
}
nsCOMPtr<nsIDOMNode> previousCellParent;
nsCOMPtr<nsIDOMRange> range;
PRInt32 offset;
for( PRInt32 i = 0; i < rangeCount; i++)
{
result = mDomSelections[index]->GetRangeAt(i, getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (!range) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> parent;
result = range->GetStartParent(getter_AddRefs(parent));
if (NS_FAILED(result)) return result;
if (!parent) return NS_ERROR_NULL_POINTER;
range->GetStartOffset(&offset);
// Be sure previous selection is a table cell
nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);
nsCOMPtr<nsIContent> childContent;
result = parentContent->ChildAt(offset, *getter_AddRefs(childContent));
if (NS_FAILED(result)) return result;
if (childContent && IsCell(childContent))
previousCellParent = parent;
// We're done if we didn't find parent of a previously-selected cell
if (!previousCellParent) break;
if (previousCellParent == parentNode && offset == aContentOffset)
if (aTarget == TABLESELECTION_CELL)
{
// Cell is already selected
if (rangeCount == 1)
PRBool isSelected = PR_FALSE;
// Check if we have other selected cells
nsCOMPtr<nsIDOMNode> previousCellNode;
GetFirstSelectedCellAndRange(getter_AddRefs(previousCellNode), nsnull);
if (previousCellNode)
{
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Unselecting single selected cell\n");
#endif
// This was the only cell selected.
// Collapse to "normal" selection inside the cell
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
//TODO: We need a "Collapse to just before deepest child" routine
// Even better, should we collapse to just after the LAST deepest child
// (i.e., at the end of the cell's contents)?
return mDomSelections[index]->Collapse(selectedNode, 0);
// We have at least 1 other selected cell
// Check if new cell is already selected
nsIFrame *cellFrame = nsnull;
result = GetTracker()->GetPrimaryFrameFor(childContent, &cellFrame);
if (NS_FAILED(result)) return result;
if (!cellFrame) return NS_ERROR_NULL_POINTER;
result = cellFrame->GetSelected(&isSelected);
if (NS_FAILED(result)) return result;
}
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Removing cell from multi-cell selection\n");
else
{
// No cells selected -- remove non-cell selection
mDomSelections[index]->ClearSelection();
}
mSelectingTableCells = PR_TRUE; // Signal to start drag-cell-selection
mSelectingTableCellMode = aTarget;
// Set start for new drag-selection block (not appended)
mStartSelectedCell = childContent;
// The initial block end is same as the start
mEndSelectedCell = childContent;
if (isSelected)
{
// Remember this cell to (possibly) unselect it on mouseup
mUnselectCellOnMouseUp = childContent;
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Saving mUnselectCellOnMouseUp\n");
#endif
//TODO: Should we try to reassign to a different existing cell?
//mStartSelectedCell = nsnull;
//mEndSelectedCell = nsnull;
// Other cells are selected:
// Deselect cell by removing its range from selection
return mDomSelections[index]->RemoveRange(range);
}
else
{
// Select an unselected cell
// but first remove existing selection if not in same table
nsCOMPtr<nsIContent> previousCellContent = do_QueryInterface(previousCellNode);
if (!IsInSameTable(previousCellContent, childContent, nsnull))
mDomSelections[index]->ClearSelection();
nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(childContent);
return SelectCellElement(cellElement);
}
return NS_OK;
}
else if (aTarget == TABLESELECTION_TABLE)
{
//TODO: We currently select entire table when clicked between cells,
// should we restrict to only around border?
// *** How do we get location data for cell and click?
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
// Remove existing selection and select the table
mDomSelections[index]->ClearSelection();
return CreateAndAddRange(parentNode, aContentOffset);
}
else if (aTarget == TABLESELECTION_ROW || aTarget == TABLESELECTION_COLUMN)
{
// Start drag-selecting mode so multiple rows/cols can be selected
// Note: Currently, nsFrame::GetDataForTableSelection
// will never call us for row or column selection on mouse down
mSelectingTableCells = PR_TRUE;
mSelectingTableCellMode = aTarget;
// Force new selection block
mStartSelectedCell = nsnull;
mDomSelections[index]->ClearSelection();
return SelectRowOrColumn(childContent, aTarget);
}
}
if (previousCellParent)
else
{
// If new cell in a different table is selected, trigger clearing the selection
nsCOMPtr<nsIContent> previousParentContent = do_QueryInterface(previousCellParent);
if (!IsInSameTable(selectedContent, previousParentContent, nsnull))
previousCellParent = nsnull;
}
if (!previousCellParent)
// There was no cell selected in the same table - clear selection
mDomSelections[index]->ClearSelection();
#ifdef DEBUG_TABLE
printf("HandleTableSelection: Adding new selected cell range\n");
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Mouse UP event\n");
#endif
// Append a new selection range that surrounds the cell
// It would be nice to make the order of ranges
// map to the order of cells in table,
// but AddRange doesn't allow that
result = CreateAndAddRange(parentNode, aContentOffset);
if (NS_SUCCEEDED(result))
{
mSelectingTableCells = PR_TRUE;
mSelectingTableCellMode = TABLESELECTION_CELL;//only shut off on mouse up
// First check if we are extending a block selection
PRInt32 rangeCount;
result = mDomSelections[index]->GetRangeCount(&rangeCount);
if (NS_FAILED(result)) return result;
mStartSelectedCell = selectedContent;
mEndSelectedCell = selectedContent;
if (rangeCount > 0 && aMouseEvent->isShift &&
mAppendStartSelectedCell && mAppendStartSelectedCell != childContent)
{
// If Shift is down as well, append a block selection
return SelectBlockOfCells(childContent);
}
// Unselect a cell only if it wasn't
// just selected on mousedown
if( childContent == mUnselectCellOnMouseUp)
{
// Scan ranges to find the cell to unselect (the selection range to remove)
nsCOMPtr<nsIDOMNode> previousCellParent;
nsCOMPtr<nsIDOMRange> range;
PRInt32 offset;
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Unselecting mUnselectCellOnMouseUp; rangeCount=%d\n", rangeCount);
#endif
for( PRInt32 i = 0; i < rangeCount; i++)
{
result = mDomSelections[index]->GetRangeAt(i, getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (!range) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> parent;
result = range->GetStartParent(getter_AddRefs(parent));
if (NS_FAILED(result)) return result;
if (!parent) return NS_ERROR_NULL_POINTER;
range->GetStartOffset(&offset);
// Be sure previous selection is a table cell
nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);
nsCOMPtr<nsIContent> childContent;
result = parentContent->ChildAt(offset, *getter_AddRefs(childContent));
if (NS_FAILED(result)) return result;
if (childContent && IsCell(childContent))
previousCellParent = parent;
// We're done if we didn't find parent of a previously-selected cell
if (!previousCellParent) break;
if (previousCellParent == parentNode && offset == aContentOffset)
{
// Cell is already selected
if (rangeCount == 1)
{
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Unselecting single selected cell\n");
#endif
// This was the only cell selected.
// Collapse to "normal" selection inside the cell
mSelectingTableCells = PR_FALSE;
mStartSelectedCell = nsnull;
mEndSelectedCell = nsnull;
mSelectingTableCellMode = 0;
//TODO: We need a "Collapse to just before deepest child" routine
// Even better, should we collapse to just after the LAST deepest child
// (i.e., at the end of the cell's contents)?
return mDomSelections[index]->Collapse(childNode, 0);
}
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Removing cell from multi-cell selection\n");
#endif
//TODO: Should we try to reassign to a different existing cell?
//mStartSelectedCell = nsnull;
//mEndSelectedCell = nsnull;
// Other cells are selected:
// Deselect cell by removing its range from selection
return mDomSelections[index]->RemoveRange(range);
}
}
mUnselectCellOnMouseUp = nsnull;
// Should we just return here?
// (we failed to unselect the cell)
}
// We have mouse up in a cell that was just selected on mouse down,
// (and no drag or shift-extend action intervened)
// Use it as the start of a block that
// we may append by using Shift+click in another cell
mAppendStartSelectedCell = childContent;
#ifdef DEBUG_cmanske
printf("HandleTableSelection: Setting mAppendStartSelectedCell for append block\n");
#endif
}
}
return result;
@ -2269,57 +2357,88 @@ nsSelection::SelectBlockOfCells(nsIContent *aEndCell)
if (!aEndCell) return NS_ERROR_NULL_POINTER;
mEndSelectedCell = aEndCell;
nsCOMPtr<nsIDOMNode> cellNode;
nsCOMPtr<nsIDOMRange> range;
nsresult result = GetFirstSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (!cellNode || !range) return NS_OK;
nsCOMPtr<nsIContent> startCell;
nsresult result = NS_OK;
mStartSelectedCell = do_QueryInterface(cellNode);
if (mAppendStartSelectedCell)
{
// We are appending a new block
#ifdef DEBUG_cmanske
printf("SelectBlockOfCells -- using mAppendStartSelectedCell\n");
#endif
startCell = mAppendStartSelectedCell;
}
else if (mStartSelectedCell)
{
startCell = mStartSelectedCell;
#ifdef DEBUG_cmanske
printf("SelectBlockOfCells -- using mStartSelectedCell\n");
#endif
}
if (!startCell)
{
#ifdef DEBUG_cmanske
printf("SelectBlockOfCells -- NO START CELL!\n");
#endif
return NS_OK;
}
// If new end cell is in a different table, do nothing
nsCOMPtr<nsIContent> table;
if (!IsInSameTable(startCell, aEndCell, getter_AddRefs(table)))
return NS_OK;
// Get starting and ending cells' location in the cellmap
PRInt32 startRowIndex, startColIndex, endRowIndex, endColIndex;
result = GetCellIndexes(mStartSelectedCell, startRowIndex, startColIndex);
result = GetCellIndexes(startCell, startRowIndex, startColIndex);
if(NS_FAILED(result)) return result;
result = GetCellIndexes(aEndCell, endRowIndex, endColIndex);
if(NS_FAILED(result)) return result;
// Get parent table, and don't allow selection if start
// and end are not in same table
nsCOMPtr<nsIContent> table;
if (!IsInSameTable(mStartSelectedCell, aEndCell, getter_AddRefs(table)))
return NS_OK;
// Get TableLayout interface to access cell data based on cellmap location
// frames are not ref counted, so don't use an nsCOMPtr
nsITableLayout *tableLayoutObject = GetTableLayout(table);
if (!tableLayoutObject) return NS_ERROR_FAILURE;
// Remove selected cells outside of new block limits
PRInt32 minRowIndex = PR_MIN(startRowIndex, endRowIndex);
PRInt32 maxRowIndex = PR_MAX(startRowIndex, endRowIndex);
PRInt32 minColIndex = PR_MIN(startColIndex, endColIndex);
PRInt32 maxColIndex = PR_MAX(startColIndex, endColIndex);
PRInt32 curRowIndex, curColIndex;
// Examine all cell nodes, starting with first one found above
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
while (cellNode)
if (!mAppendStartSelectedCell)
{
nsCOMPtr<nsIContent> cellContent = do_QueryInterface(cellNode);
result = GetCellIndexes(cellContent, curRowIndex, curColIndex);
// Not appending - remove selected cells outside of new block limits
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
nsCOMPtr<nsIDOMNode> cellNode;
nsCOMPtr<nsIDOMRange> range;
result = GetFirstSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
if (curRowIndex < minRowIndex || curRowIndex > maxRowIndex ||
curColIndex < minColIndex || curColIndex > maxColIndex)
PRInt32 minRowIndex = PR_MIN(startRowIndex, endRowIndex);
PRInt32 maxRowIndex = PR_MAX(startRowIndex, endRowIndex);
PRInt32 minColIndex = PR_MIN(startColIndex, endColIndex);
PRInt32 maxColIndex = PR_MAX(startColIndex, endColIndex);
while (cellNode)
{
mDomSelections[index]->RemoveRange(range);
// Since we've removed the range, decrement pointer to next range
mSelectedCellIndex--;
}
result = GetNextSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
nsCOMPtr<nsIContent> childContent = do_QueryInterface(cellNode);
result = GetCellIndexes(childContent, curRowIndex, curColIndex);
if (NS_FAILED(result)) return result;
#ifdef DEBUG_cmanske
if (!range)
printf("SelectBlockOfCells -- range is null\n");
#endif
if (range &&
(curRowIndex < minRowIndex || curRowIndex > maxRowIndex ||
curColIndex < minColIndex || curColIndex > maxColIndex))
{
mDomSelections[index]->RemoveRange(range);
// Since we've removed the range, decrement pointer to next range
mSelectedCellIndex--;
}
result = GetNextSelectedCellAndRange(getter_AddRefs(cellNode), getter_AddRefs(range));
if (NS_FAILED(result)) return result;
}
}
nsCOMPtr<nsIDOMElement> cellElement;
@ -2362,7 +2481,6 @@ nsSelection::SelectBlockOfCells(nsIContent *aEndCell)
else
row--;
};
return result;
}
@ -2410,6 +2528,7 @@ nsSelection::SelectRowOrColumn(nsIContent *aCellContent, PRUint32 aTarget)
if (NS_FAILED(result)) return result;
if (cellElement)
{
NS_ASSERTION(actualRowSpan > 0 && actualColSpan> 0, "SelectRowOrColumn: Bad rowspan or colspan\n");
if (!firstCell)
firstCell = cellElement;
@ -2434,6 +2553,7 @@ nsSelection::SelectRowOrColumn(nsIContent *aCellContent, PRUint32 aTarget)
// We are starting a new block, so select the first cell
result = SelectCellElement(firstCell);
if (NS_FAILED(result)) return result;
mStartSelectedCell = do_QueryInterface(firstCell);
}
nsCOMPtr<nsIContent> lastCellContent = do_QueryInterface(lastCell);
return SelectBlockOfCells(lastCellContent);
@ -2510,9 +2630,12 @@ nsSelection::GetFirstCellNodeInRange(nsIDOMRange *aRange, nsIDOMNode **aCellNode
nsresult
nsSelection::GetFirstSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRange)
{
if (!aCell || !aRange) return NS_ERROR_NULL_POINTER;
if (!aCell) return NS_ERROR_NULL_POINTER;
*aCell = nsnull;
*aRange = nsnull;
// aRange is optional
if (aRange)
*aRange = nsnull;
nsCOMPtr<nsIDOMRange> firstRange;
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
@ -2527,8 +2650,11 @@ nsSelection::GetFirstSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRan
*aCell = cellNode;
NS_ADDREF(*aCell);
*aRange = firstRange;
NS_ADDREF(*aRange);
if (aRange)
{
*aRange = firstRange;
NS_ADDREF(*aRange);
}
// Setup for next cell
mSelectedCellIndex = 1;
@ -2539,9 +2665,12 @@ nsSelection::GetFirstSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRan
nsresult
nsSelection::GetNextSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRange)
{
if (!aCell || !aRange) return NS_ERROR_NULL_POINTER;
if (!aCell) return NS_ERROR_NULL_POINTER;
*aCell = nsnull;
*aRange = nsnull;
// aRange is optional
if (aRange)
*aRange = nsnull;
PRInt32 rangeCount;
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
@ -2571,8 +2700,11 @@ nsSelection::GetNextSelectedCellAndRange(nsIDOMNode **aCell, nsIDOMRange **aRang
*aCell = cellNode;
NS_ADDREF(*aCell);
*aRange = range;
NS_ADDREF(*aRange);
if (aRange)
{
*aRange = range;
NS_ADDREF(*aRange);
}
// Setup for next cell
mSelectedCellIndex++;
@ -2657,9 +2789,10 @@ nsSelection::SelectCellElement(nsIDOMElement *aCellElement)
if (NS_FAILED(result)) return result;
if (!parent) return NS_ERROR_FAILURE;
// Get child offset
nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);
nsCOMPtr<nsIContent> cellContent = do_QueryInterface(aCellElement);
// Get child offset
PRInt32 offset;
result = parentContent->IndexOf(cellContent, offset);
if (NS_FAILED(result)) return result;

View File

@ -804,10 +804,10 @@ nsFrame::HandleEvent(nsIPresContext* aPresContext,
}
NS_IMETHODIMP
nsFrame::GetDataForTableSelection(nsMouseEvent *aMouseEvent, nsIContent **aParentContent,
PRInt32 *aContentOffset, PRUint32 *aTarget)
nsFrame::GetDataForTableSelection(nsIFrameSelection *aFrameSelection, nsMouseEvent *aMouseEvent,
nsIContent **aParentContent, PRInt32 *aContentOffset, PRUint32 *aTarget)
{
if (!aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
if (!aFrameSelection || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
return NS_ERROR_NULL_POINTER;
*aParentContent = nsnull;
@ -816,22 +816,33 @@ nsFrame::GetDataForTableSelection(nsMouseEvent *aMouseEvent, nsIContent **aParen
// Test if special 'table selection' key is pressed
PRBool doTableSelection;
#ifdef XP_MAC
doTableSelection = aMouseEvent->isMeta;
#else
doTableSelection = aMouseEvent->isControl;
#endif
if (!doTableSelection) return NS_OK;
if (!doTableSelection)
{
// We allow table selection when just Shift is pressed
// only if already in table/cell selection mode
if (aMouseEvent->isShift)
aFrameSelection->GetTableCellSelection(&doTableSelection);
if (!doTableSelection)
return NS_OK;
}
// Get the cell frame or table frame (or parent) of the current content node
nsIFrame *frame = this;
nsresult result = NS_OK;
PRBool foundCell = PR_FALSE;
PRBool foundTable = PR_FALSE;
PRBool selectColumn = PR_FALSE;
PRBool selectRow = PR_FALSE;
//We don't initiate row/col selection from here now,
// but we may in future
//PRBool selectColumn = PR_FALSE;
//PRBool selectRow = PR_FALSE;
while (frame && NS_SUCCEEDED(result))
{
@ -841,23 +852,8 @@ nsFrame::GetDataForTableSelection(nsMouseEvent *aMouseEvent, nsIContent **aParen
if (NS_SUCCEEDED(result) && cellElement)
{
foundCell = PR_TRUE;
PRInt32 colIndex, rowIndex;
result = cellElement->GetCellIndexes(rowIndex, colIndex);
// Give precedence to row over column
if (colIndex == 0)
{
//printf(" * SelRow: x=%d, y=%d\n", aMouseEvent->point.x, aMouseEvent->point.y);
//TODO: We need to test for proximity to top border
// For now, just go into row selection mode
selectRow = PR_TRUE;
}
else if (rowIndex == 0)
{
//printf(" * SelCol: x=%d, y=%d\n", aMouseEvent->point.x, aMouseEvent->point.y);
//TODO: We need to test for proximity to left border
// For now, just go into COLUMN selection mode
selectColumn = PR_TRUE;
}
//TODO: If we want to use proximity to top or left border
// for row and column selection, this is the place to do it
break;
}
else
@ -903,11 +899,14 @@ nsFrame::GetDataForTableSelection(nsMouseEvent *aMouseEvent, nsIContent **aParen
*aContentOffset = offset;
#if 0
if (selectRow)
*aTarget = TABLESELECTION_ROW;
else if (selectColumn)
*aTarget = TABLESELECTION_COLUMN;
else if (foundCell)
else
#endif
if (foundCell)
*aTarget = TABLESELECTION_CELL;
else if (foundTable)
*aTarget = TABLESELECTION_TABLE;
@ -1007,6 +1006,19 @@ nsFrame::HandlePress(nsIPresContext* aPresContext,
if (NS_FAILED(rv))
return rv;
// Let Ctrl/Cmd+mouse down do table selection instead of drag initiation
nsCOMPtr<nsIContent>parentContent;
PRInt32 contentOffset;
PRUint32 target;
rv = GetDataForTableSelection(frameselection, me, getter_AddRefs(parentContent), &contentOffset, &target);
if (NS_SUCCEEDED(rv) && parentContent)
{
rv = frameselection->SetMouseDownState( PR_TRUE );
if (NS_FAILED(rv)) return rv;
return frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
}
PRBool supportsDelay = PR_FALSE;
frameselection->GetDelayCaretOverExistingSelection(&supportsDelay);
@ -1071,19 +1083,7 @@ nsFrame::HandlePress(nsIPresContext* aPresContext,
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIContent>parentContent;
PRInt32 contentOffset;
PRUint32 target;
rv = GetDataForTableSelection(me, getter_AddRefs(parentContent), &contentOffset, &target);
if (NS_SUCCEEDED(rv) && parentContent)
rv = frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
else
rv = frameselection->HandleClick(content, startOffset , endOffset, me->isShift, PR_FALSE, beginFrameContent);
return rv;
return frameselection->HandleClick(content, startOffset , endOffset, me->isShift, PR_FALSE, beginFrameContent);
}
/**
@ -1269,7 +1269,7 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsIPresContext* aPresContext,
PRInt32 contentOffset;
PRUint32 target;
nsMouseEvent *me = (nsMouseEvent *)aEvent;
result = GetDataForTableSelection(me, getter_AddRefs(parentContent), &contentOffset, &target);
result = GetDataForTableSelection(frameselection, me, getter_AddRefs(parentContent), &contentOffset, &target);
if (NS_SUCCEEDED(result) && parentContent)
frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
else
@ -1342,31 +1342,34 @@ NS_IMETHODIMP nsFrame::HandleRelease(nsIPresContext* aPresContext,
if (NS_SUCCEEDED(result) && !mouseDown && me && me->clickCount < 2)
{
// We are doing this to simulate what we would have done on HandlePress
result = frameselection->SetMouseDownState( PR_TRUE );
nsCOMPtr<nsIContent> content;
PRInt32 startOffset = 0, endOffset = 0;
PRBool beginFrameContent = PR_FALSE;
result = GetContentAndOffsetsFromPoint(aPresContext, me->point, getter_AddRefs(content), startOffset, endOffset, beginFrameContent);
if (NS_FAILED(result)) return result;
result = frameselection->HandleClick(content, startOffset , endOffset, me->isShift, PR_FALSE, beginFrameContent);
if (NS_FAILED(result)) return result;
}
else
{
me = (nsMouseEvent *)aEvent;
nsCOMPtr<nsIContent>parentContent;
PRInt32 contentOffset;
PRUint32 target;
result = GetDataForTableSelection(me, getter_AddRefs(parentContent), &contentOffset, &target);
result = GetDataForTableSelection(frameselection, me, getter_AddRefs(parentContent), &contentOffset, &target);
if (NS_SUCCEEDED(result) && parentContent)
result = frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
else
{
nsCOMPtr<nsIContent> content;
PRInt32 startOffset = 0, endOffset = 0;
PRBool beginFrameContent = PR_FALSE;
result = GetContentAndOffsetsFromPoint(aPresContext, me->point, getter_AddRefs(content), startOffset, endOffset, beginFrameContent);
if (NS_FAILED(result))
return result;
result = frameselection->HandleClick(content, startOffset , endOffset, me->isShift, PR_FALSE, beginFrameContent);
frameselection->SetMouseDownState( PR_FALSE );
result = frameselection->HandleTableSelection(parentContent, contentOffset, target, me);
if (NS_FAILED(result)) return result;
}
}
result = frameselection->SetDelayedCaretData(0);
}

View File

@ -33,6 +33,7 @@
#include "nsIPresShell.h"
#include "nsIReflowCommand.h"
#include "nsIFrameSelection.h"
/**
* nsFrame logging constants. We redefine the nspr
@ -418,13 +419,15 @@ protected:
static void GetFirstLeaf(nsIPresContext* aPresContext, nsIFrame **aFrame);
// Test if we are selecting a table object:
// First test if Ctrl (Cmd on Mac) key is down during a mouse click or drag
// If yes, get the parent content node and offset of the frame
// Most table/cell selection requires that Ctrl (Cmd on Mac) key is down
// during a mouse click or drag. Exception is using Shift+click when
// already in "table/cell selection mode" to extend a block selection
// Get the parent content node and offset of the frame
// of the enclosing cell or table (if not inside a cell)
// aTarget tells us what table element to select (currently only cell and table supported)
// (enums for this are defined in nsIFrame.h)
NS_IMETHOD GetDataForTableSelection(nsMouseEvent *aMouseEvent, nsIContent **aParentContent,
PRInt32 *aContentOffset, PRUint32 *aTarget);
NS_IMETHOD GetDataForTableSelection(nsIFrameSelection *aFrameSelection, nsMouseEvent *aMouseEvent,
nsIContent **aParentContent, PRInt32 *aContentOffset, PRUint32 *aTarget);
static void XMLQuote(nsString& aString);