зеркало из https://github.com/mozilla/gecko-dev.git
Removed tableselection listener -- all selection now done in layout. Also added more table selection support for row, col from menu. r=mjudge
This commit is contained in:
Родитель
2824049212
Коммит
235ce19d67
|
@ -56,9 +56,3 @@ NS_IMETHODIMP TypeInState::NotifySelectionChanged()
|
|||
Reset();
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP TypeInState::TableCellNotification(nsIDOMNode* aNode, PRInt32 aOffset)
|
||||
{
|
||||
//stub
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ public:
|
|||
virtual ~TypeInState();
|
||||
|
||||
NS_IMETHOD NotifySelectionChanged();
|
||||
NS_IMETHOD TableCellNotification(nsIDOMNode* aNode, PRInt32 aOffset);
|
||||
|
||||
void GetEnumForName(nsIAtom *aPropName, PRUint32 &aEnum);
|
||||
void GetPropertyIsString(PRUint32 aProp, PRUint32 &aIsString);
|
||||
|
|
|
@ -211,7 +211,7 @@ nsEditorShell::nsEditorShell()
|
|||
nsEditorShell::~nsEditorShell()
|
||||
{
|
||||
NS_IF_RELEASE(mStateMaintainer);
|
||||
|
||||
|
||||
// the only other references we hold are in nsCOMPtrs, so they'll take
|
||||
// care of themselves.
|
||||
}
|
||||
|
@ -302,7 +302,6 @@ nsEditorShell::PrepareDocumentForEditing(nsIURI *aUrl)
|
|||
NS_IF_RELEASE(mStateMaintainer);
|
||||
}
|
||||
}
|
||||
|
||||
mEditorType = eUninitializedEditorType;
|
||||
mEditor = 0; // clear out the nsCOMPtr
|
||||
|
||||
|
@ -365,8 +364,8 @@ nsEditorShell::PrepareDocumentForEditing(nsIURI *aUrl)
|
|||
{
|
||||
txnMgr->AddListener(NS_STATIC_CAST(nsITransactionListener*, mStateMaintainer));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (NS_SUCCEEDED(rv) && mContentWindow)
|
||||
{
|
||||
nsCOMPtr<nsIController> controller;
|
||||
|
@ -3149,6 +3148,26 @@ nsEditorShell::SelectTableCell()
|
|||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditorShell::SelectBlockOfCells(nsIDOMElement *aStartCell, nsIDOMElement *aEndCell)
|
||||
{
|
||||
nsresult result = NS_NOINTERFACE;
|
||||
switch (mEditorType)
|
||||
{
|
||||
case eHTMLTextEditorType:
|
||||
{
|
||||
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
||||
if (tableEditor)
|
||||
result = tableEditor->SelectBlockOfCells(aStartCell, aEndCell);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result = NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditorShell::SelectTableRow()
|
||||
{
|
||||
|
|
|
@ -138,7 +138,7 @@ class nsEditorShell : public nsIEditorShell,
|
|||
|
||||
nsCOMPtr<nsISupports> mSearchContext; // context used for search and replace. Owned by the appshell.
|
||||
|
||||
nsInterfaceState* mStateMaintainer; // we hold the owning ref to this.
|
||||
nsInterfaceState* mStateMaintainer; // we hold the owning ref to this.
|
||||
|
||||
PRInt32 mWrapColumn; // can't actually set this 'til the editor is created, so we may have to hold on to it for a while
|
||||
|
||||
|
|
|
@ -217,6 +217,7 @@ nsHTMLEditor::nsHTMLEditor()
|
|||
, mRules(nsnull)
|
||||
, mIsComposing(PR_FALSE)
|
||||
, mMaxTextLength(-1)
|
||||
, mSelectingTableCells(PR_FALSE)
|
||||
{
|
||||
// Done in nsEditor
|
||||
// NS_INIT_REFCNT();
|
||||
|
|
|
@ -184,6 +184,7 @@ public:
|
|||
NS_IMETHOD DeleteTableColumn(PRInt32 aNumber);
|
||||
NS_IMETHOD DeleteTableRow(PRInt32 aNumber);
|
||||
NS_IMETHOD SelectTableCell();
|
||||
NS_IMETHOD SelectBlockOfCells(nsIDOMElement *aStartCell, nsIDOMElement *aEndCell);
|
||||
NS_IMETHOD SelectTableRow();
|
||||
NS_IMETHOD SelectTableColumn();
|
||||
NS_IMETHOD SelectTable();
|
||||
|
@ -363,6 +364,8 @@ protected:
|
|||
// failed to set selection to some other content in the document
|
||||
NS_IMETHOD SetSelectionAtDocumentStart(nsIDOMSelection *aSelection);
|
||||
|
||||
// end of table editing utilities
|
||||
|
||||
NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode,
|
||||
nsString &aParentTag,
|
||||
BlockTransformationType aTranformation);
|
||||
|
@ -603,6 +606,14 @@ protected:
|
|||
PRBool mCachedUnderlineStyle;
|
||||
nsString mCachedFontName;
|
||||
|
||||
// True when selection consists of table cell(s)
|
||||
PRBool mSelectingTableCells;
|
||||
|
||||
// Used to monitor block of cells selected
|
||||
// by dragging mouse across the table
|
||||
nsCOMPtr<nsIDOMElement> mStartSelectedCell;
|
||||
nsCOMPtr<nsIDOMElement> mCurrentSelectedCell;
|
||||
|
||||
public:
|
||||
static nsIAtom *gTypingTxnName;
|
||||
static nsIAtom *gIMETxnName;
|
||||
|
|
|
@ -90,13 +90,6 @@ nsInterfaceState::NotifyDocumentCreated()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsInterfaceState::TableCellNotification(nsIDOMNode* aNode, PRInt32 aOffset)
|
||||
{
|
||||
//stub
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsInterfaceState::NotifyDocumentWillBeDestroyed()
|
||||
{
|
||||
|
@ -335,25 +328,89 @@ nsInterfaceState::SelectionIsCollapsed()
|
|||
nsresult
|
||||
nsInterfaceState::UpdateParagraphState(const char* observerName, const char* attributeName, nsString& ioParaFormat)
|
||||
{
|
||||
nsStringArray tagList;
|
||||
|
||||
mEditor->GetParagraphTags(&tagList);
|
||||
nsCOMPtr<nsIDOMSelection> domSelection;
|
||||
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
||||
// Get the nsIEditor pointer (mEditor is nsIHTMLEditor)
|
||||
if (!editor) return NS_ERROR_NULL_POINTER;
|
||||
nsresult rv = editor->GetSelection(getter_AddRefs(domSelection));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 numTags = tagList.Count();
|
||||
nsAutoString thisTag;
|
||||
//Note: If numTags == 0, we probably have a text node not in a container
|
||||
// (directly under <body>). Consider it normal
|
||||
if (numTags > 0)
|
||||
PRBool selectionCollapsed = PR_FALSE;
|
||||
rv = domSelection->GetIsCollapsed(&selectionCollapsed);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Get anchor and focus nodes:
|
||||
nsCOMPtr<nsIDOMNode> anchorNode;
|
||||
rv = domSelection->GetAnchorNode(getter_AddRefs(anchorNode));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!anchorNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> focusNode;
|
||||
rv = domSelection->GetFocusNode(getter_AddRefs(focusNode));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!focusNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> anchorNodeBlockParent;
|
||||
PRBool isBlock;
|
||||
rv = editor->NodeIsBlock(anchorNode, isBlock);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (isBlock)
|
||||
{
|
||||
// This will never show the "mixed state"
|
||||
// TODO: Scan list of tags and if any are different, set to "mixed"
|
||||
tagList.StringAt(0, thisTag);
|
||||
anchorNodeBlockParent = anchorNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get block parent of anchorNode node
|
||||
// We could simply use this if it was in nsIEditor interface!
|
||||
//rv = editor->GetBlockParent(anchorNode, getter_AddRefs(anchorNodeBlockParent));
|
||||
// if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
nsCOMPtr<nsIDOMNode>temp;
|
||||
rv = anchorNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (NS_SUCCEEDED(rv) && parent)
|
||||
{
|
||||
rv = editor->NodeIsBlock(parent, isBlock);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (isBlock)
|
||||
{
|
||||
anchorNodeBlockParent = parent;
|
||||
break;
|
||||
}
|
||||
rv = parent->GetParentNode(getter_AddRefs(temp));
|
||||
parent = do_QueryInterface(temp);
|
||||
}
|
||||
}
|
||||
if (thisTag != mParagraphFormat)
|
||||
if (!anchorNodeBlockParent) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsAutoString tagName;
|
||||
|
||||
// Check if we have a selection that extends into multiple nodes,
|
||||
// so we can check for "mixed" selection state
|
||||
if (selectionCollapsed || focusNode == anchorNode)
|
||||
{
|
||||
nsresult rv = SetNodeAttribute(observerName, attributeName, thisTag);
|
||||
// Entire selection is within one block
|
||||
anchorNodeBlockParent->GetNodeName(tagName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We may have different block parent node types WITHIN the selection,
|
||||
// even if the anchor and focus parents are the same type.
|
||||
// Getting the list of all block, e.g., by using GetParagraphTags(&tagList)
|
||||
// is too inefficient for long documents.
|
||||
// TODO: Change to use selection iterator to detect each block node in the
|
||||
// selection and if different from the anchorNodeBlockParent, use "mixed" state
|
||||
// *** Not doing this now reduces risk for Beta1 -- simply assume mixed state
|
||||
// Note that "mixed" displays as "normal" in UI as of 3/6.
|
||||
tagName = "mixed";
|
||||
}
|
||||
|
||||
if (tagName != mParagraphFormat)
|
||||
{
|
||||
rv = SetNodeAttribute(observerName, attributeName, tagName);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mParagraphFormat = thisTag;
|
||||
mParagraphFormat = tagName;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ public:
|
|||
|
||||
// nsIDOMSelectionListener interface
|
||||
NS_IMETHOD NotifySelectionChanged();
|
||||
NS_IMETHOD TableCellNotification(nsIDOMNode* aNode, PRInt32 aOffset);
|
||||
|
||||
NS_DECL_NSIDOCUMENTSTATELISTENER
|
||||
|
||||
|
|
|
@ -43,8 +43,11 @@
|
|||
|
||||
#include "nsEditorUtils.h"
|
||||
|
||||
//#define DEBUG_TABLE 1
|
||||
|
||||
static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* stack based helper class for restoring selection after table edit
|
||||
*/
|
||||
|
@ -75,6 +78,22 @@ class nsSetCaretAfterTableEdit
|
|||
void CancelSetCaret() {mEd = nsnull; mTable = nsnull;}
|
||||
};
|
||||
|
||||
// Stack-class to turn on/off selection batching for table selection
|
||||
class nsSelectionBatcher
|
||||
{
|
||||
private:
|
||||
nsCOMPtr<nsIDOMSelection> mSelection;
|
||||
public:
|
||||
nsSelectionBatcher(nsIDOMSelection *aSelection) : mSelection(aSelection)
|
||||
{
|
||||
if (mSelection) mSelection->StartBatchChanges();
|
||||
}
|
||||
virtual ~nsSelectionBatcher()
|
||||
{
|
||||
if (mSelection) mSelection->EndBatchChanges();
|
||||
}
|
||||
};
|
||||
|
||||
// Table Editing helper utilities (not exposed in IDL)
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -319,7 +338,7 @@ nsHTMLEditor::GetNextRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow)
|
|||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_cmanske
|
||||
printf("GetNextRow: firstChild of row's parent's sibling is not a TR!\n");
|
||||
#endif
|
||||
// We arrive here only if a table section has no children
|
||||
|
@ -963,8 +982,7 @@ NS_IMETHODIMP
|
|||
nsHTMLEditor::SelectTableCell()
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> cell;
|
||||
nsresult res = NS_ERROR_FAILURE;
|
||||
res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(cell));
|
||||
nsresult res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(cell));
|
||||
if (NS_FAILED(res)) return res;
|
||||
// Don't fail if we didn't find a table
|
||||
if (!cell) return NS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
|
@ -979,24 +997,280 @@ nsHTMLEditor::SelectTableCell()
|
|||
return res;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::SelectBlockOfCells(nsIDOMElement *aStartCell, nsIDOMElement *aEndCell)
|
||||
{
|
||||
if (!aStartCell || !aEndCell) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
nsresult res = nsEditor::GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!selection) return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> table;
|
||||
res = GetElementOrParentByTagName("table", aStartCell, getter_AddRefs(table));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!table) return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> endTable;
|
||||
res = GetElementOrParentByTagName("table", aEndCell, getter_AddRefs(endTable));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!endTable) return NS_ERROR_FAILURE;
|
||||
|
||||
// We can only select a block if within the same table,
|
||||
// so do nothing if not within one table
|
||||
if (table != endTable) return NS_OK;
|
||||
|
||||
PRInt32 startRowIndex, startColIndex, endRowIndex, endColIndex;
|
||||
|
||||
// Get starting and ending cells' location in the cellmap
|
||||
res = GetCellIndexes(aStartCell, startRowIndex, startColIndex);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = GetCellIndexes(aEndCell, endRowIndex, endColIndex);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
// Suppress nsIDOMSelectionListener notification
|
||||
// until all selection changes are finished
|
||||
nsSelectionBatcher selectionBatcher(selection);
|
||||
|
||||
// It is now safe to clear the selection
|
||||
// BE SURE TO RESET IT BEFORE LEAVING!
|
||||
selection->ClearSelection();
|
||||
nsCOMPtr<nsIDOMNode> cellNode;
|
||||
PRBool cellSelected = PR_FALSE;
|
||||
|
||||
PRInt32 startColumn = PR_MIN(startColIndex, endColIndex);
|
||||
PRInt32 startRow = PR_MIN(startRowIndex, endRowIndex);
|
||||
PRInt32 maxColumn = PR_MAX(startColIndex, endColIndex);
|
||||
PRInt32 maxRow = PR_MAX(startRowIndex, endRowIndex);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> cell;
|
||||
PRInt32 rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
|
||||
PRBool isSelected;
|
||||
for (PRInt32 row = startRow; row <= maxRow; row++)
|
||||
{
|
||||
for(PRInt32 col = startColumn; col <= maxColumn; col += actualColSpan)
|
||||
{
|
||||
res = GetCellDataAt(table, row, col, *getter_AddRefs(cell),
|
||||
currentRowIndex, currentColIndex, rowSpan, colSpan,
|
||||
actualRowSpan, actualColSpan, isSelected);
|
||||
if (NS_FAILED(res)) break;
|
||||
// Skip cells that are spanned from previous locations
|
||||
if (cell && row == currentRowIndex && col == currentColIndex)
|
||||
{
|
||||
cellNode = do_QueryInterface(cell);
|
||||
res = nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
if (NS_FAILED(res)) break;
|
||||
cellSelected = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Safety code to select starting cell if nothing else was selected
|
||||
if (!cellSelected)
|
||||
{
|
||||
cellNode = do_QueryInterface(aStartCell);
|
||||
return nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::SelectAllTableCells()
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMElement> cell;
|
||||
nsresult res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(cell));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// Don't fail if we didn't find a cell
|
||||
if (!cell) return NS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> cellNode = do_QueryInterface(cell);
|
||||
if (!cellNode) return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDOMElement> startCell = cell;
|
||||
|
||||
// Get location of cell:
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
nsCOMPtr<nsIDOMElement> table;
|
||||
nsCOMPtr<nsIDOMNode> cellParent;
|
||||
PRInt32 cellOffset, startRowIndex, startColIndex;
|
||||
|
||||
res = GetCellContext(selection, table, cell, cellParent, cellOffset, startRowIndex, startColIndex);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if(!cell) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRInt32 rowCount, colCount;
|
||||
res = GetTableSize(table, rowCount, colCount);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// Suppress nsIDOMSelectionListener notification
|
||||
// until all selection changes are finished
|
||||
nsSelectionBatcher selectionBatcher(selection);
|
||||
|
||||
// It is now safe to clear the selection
|
||||
// BE SURE TO RESET IT BEFORE LEAVING!
|
||||
res = ClearSelection();
|
||||
|
||||
// Select all cells in the same column as current cell
|
||||
PRBool cellSelected = PR_FALSE;
|
||||
PRInt32 rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
|
||||
PRBool isSelected;
|
||||
for(PRInt32 row = 0; row < rowCount; row++)
|
||||
{
|
||||
for(PRInt32 col = 0; col < colCount; col += actualColSpan)
|
||||
{
|
||||
res = GetCellDataAt(table, row, col, *getter_AddRefs(cell),
|
||||
currentRowIndex, currentColIndex, rowSpan, colSpan,
|
||||
actualRowSpan, actualColSpan, isSelected);
|
||||
if (NS_FAILED(res)) break;
|
||||
// Skip cells that are spanned from previous rows or columns
|
||||
if (cell && row == currentRowIndex && col == currentColIndex)
|
||||
{
|
||||
cellNode = do_QueryInterface(cell);
|
||||
res = nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
if (NS_FAILED(res)) break;
|
||||
cellSelected = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Safety code to select starting cell if nothing else was selected
|
||||
if (!cellSelected)
|
||||
{
|
||||
cellNode = do_QueryInterface(startCell);
|
||||
return nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::SelectTableRow()
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMElement> cell;
|
||||
nsresult res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(cell));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// Don't fail if we didn't find a cell
|
||||
if (!cell) return NS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
nsCOMPtr<nsIDOMElement> startCell = cell;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> cellNode = do_QueryInterface(cell);
|
||||
if (!cellNode) return NS_ERROR_FAILURE;
|
||||
|
||||
// Get location of cell:
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
nsCOMPtr<nsIDOMElement> table;
|
||||
nsCOMPtr<nsIDOMNode> cellParent;
|
||||
PRInt32 cellOffset, startRowIndex, startColIndex;
|
||||
|
||||
res = GetCellContext(selection, table, cell, cellParent, cellOffset, startRowIndex, startColIndex);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if(!cell) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRInt32 rowCount, colCount;
|
||||
res = GetTableSize(table, rowCount, colCount);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
//Note: At this point, we could get first and last cells in row,
|
||||
// then call SelectBlockOfCells, but that would take just
|
||||
// a little less code, so the following is more efficient
|
||||
|
||||
// Suppress nsIDOMSelectionListener notification
|
||||
// until all selection changes are finished
|
||||
nsSelectionBatcher selectionBatcher(selection);
|
||||
|
||||
// It is now safe to clear the selection
|
||||
// BE SURE TO RESET IT BEFORE LEAVING!
|
||||
res = ClearSelection();
|
||||
|
||||
// Select all cells in the same row as current cell
|
||||
PRBool cellSelected = PR_FALSE;
|
||||
PRInt32 rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
|
||||
PRBool isSelected;
|
||||
for(PRInt32 col = 0; col < colCount; col += actualColSpan)
|
||||
{
|
||||
res = GetCellDataAt(table, startRowIndex, col, *getter_AddRefs(cell),
|
||||
currentRowIndex, currentColIndex, rowSpan, colSpan,
|
||||
actualRowSpan, actualColSpan, isSelected);
|
||||
if (NS_FAILED(res)) break;
|
||||
// Skip cells that are spanned from previous rows or columns
|
||||
if (cell && currentRowIndex == startRowIndex && currentColIndex == startColIndex)
|
||||
{
|
||||
cellNode = do_QueryInterface(cell);
|
||||
res = nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
if (NS_FAILED(res)) break;
|
||||
cellSelected = PR_TRUE;
|
||||
}
|
||||
}
|
||||
// Safety code to select starting cell if nothing else was selected
|
||||
if (!cellSelected)
|
||||
{
|
||||
cellNode = do_QueryInterface(startCell);
|
||||
return nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::SelectTableColumn()
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMElement> cell;
|
||||
nsresult res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(cell));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// Don't fail if we didn't find a cell
|
||||
if (!cell) return NS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> cellNode = do_QueryInterface(cell);
|
||||
if (!cellNode) return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDOMElement> startCell = cell;
|
||||
|
||||
// Get location of cell:
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
nsCOMPtr<nsIDOMElement> table;
|
||||
nsCOMPtr<nsIDOMNode> cellParent;
|
||||
PRInt32 cellOffset, startRowIndex, startColIndex;
|
||||
|
||||
res = GetCellContext(selection, table, cell, cellParent, cellOffset, startRowIndex, startColIndex);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if(!cell) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRInt32 rowCount, colCount;
|
||||
res = GetTableSize(table, rowCount, colCount);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// Suppress nsIDOMSelectionListener notification
|
||||
// until all selection changes are finished
|
||||
nsSelectionBatcher selectionBatcher(selection);
|
||||
|
||||
// It is now safe to clear the selection
|
||||
// BE SURE TO RESET IT BEFORE LEAVING!
|
||||
res = ClearSelection();
|
||||
|
||||
// Select all cells in the same column as current cell
|
||||
PRBool cellSelected = PR_FALSE;
|
||||
PRInt32 rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
|
||||
PRBool isSelected;
|
||||
for(PRInt32 row = 0; row < rowCount; row += actualRowSpan)
|
||||
{
|
||||
res = GetCellDataAt(table, row, startColIndex, *getter_AddRefs(cell),
|
||||
currentRowIndex, currentColIndex, rowSpan, colSpan,
|
||||
actualRowSpan, actualColSpan, isSelected);
|
||||
if (NS_FAILED(res)) break;
|
||||
// Skip cells that are spanned from previous rows or columns
|
||||
if (cell && currentRowIndex == startRowIndex && currentColIndex == startColIndex)
|
||||
{
|
||||
cellNode = do_QueryInterface(cell);
|
||||
res = nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
if (NS_FAILED(res)) break;
|
||||
cellSelected = PR_TRUE;
|
||||
}
|
||||
}
|
||||
// Safety code to select starting cell if nothing else was selected
|
||||
if (!cellSelected)
|
||||
{
|
||||
cellNode = do_QueryInterface(startCell);
|
||||
return nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -1217,22 +1491,16 @@ nsHTMLEditor::GetCellIndexes(nsIDOMElement *aCell, PRInt32 &aRowIndex, PRInt32 &
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
res = NS_ERROR_FAILURE; // we return an error unless we get the index
|
||||
nsISupports *layoutObject=nsnull; // frames are not ref counted, so don't use an nsCOMPtr
|
||||
|
||||
res = nsHTMLEditor::GetLayoutObject(aCell, &layoutObject);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!layoutObject) return NS_ERROR_FAILURE;
|
||||
|
||||
if ((NS_SUCCEEDED(res)) && (nsnull!=layoutObject))
|
||||
{ // get the table cell interface from the frame
|
||||
nsITableCellLayout *cellLayoutObject=nsnull; // again, frames are not ref-counted
|
||||
|
||||
res = layoutObject->QueryInterface(NS_GET_IID(nsITableCellLayout), (void**)(&cellLayoutObject));
|
||||
if ((NS_SUCCEEDED(res)) && (nsnull!=cellLayoutObject))
|
||||
{
|
||||
res = cellLayoutObject->GetCellIndexes(aRowIndex, aColIndex);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
nsITableCellLayout *cellLayoutObject=nsnull; // again, frames are not ref-counted
|
||||
res = layoutObject->QueryInterface(NS_GET_IID(nsITableCellLayout), (void**)(&cellLayoutObject));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!cellLayoutObject) return NS_ERROR_FAILURE;
|
||||
return cellLayoutObject->GetCellIndexes(aRowIndex, aColIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1245,13 +1513,10 @@ nsHTMLEditor::GetTableLayoutObject(nsIDOMElement* aTable, nsITableLayout **table
|
|||
// frames are not ref counted, so don't use an nsCOMPtr
|
||||
nsISupports *layoutObject=nsnull;
|
||||
nsresult res = nsHTMLEditor::GetLayoutObject(aTable, &layoutObject);
|
||||
if ((NS_SUCCEEDED(res)) && (nsnull!=layoutObject))
|
||||
{ // get the table interface from the frame
|
||||
|
||||
res = layoutObject->QueryInterface(NS_GET_IID(nsITableLayout),
|
||||
(void**)(tableLayoutObject));
|
||||
}
|
||||
return res;
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!layoutObject) return NS_ERROR_FAILURE;
|
||||
return layoutObject->QueryInterface(NS_GET_IID(nsITableLayout),
|
||||
(void**)(tableLayoutObject));
|
||||
}
|
||||
|
||||
//Return actual number of cells (a cell with colspan > 1 counts as just 1)
|
||||
|
|
|
@ -211,7 +211,7 @@ nsEditorShell::nsEditorShell()
|
|||
nsEditorShell::~nsEditorShell()
|
||||
{
|
||||
NS_IF_RELEASE(mStateMaintainer);
|
||||
|
||||
|
||||
// the only other references we hold are in nsCOMPtrs, so they'll take
|
||||
// care of themselves.
|
||||
}
|
||||
|
@ -302,7 +302,6 @@ nsEditorShell::PrepareDocumentForEditing(nsIURI *aUrl)
|
|||
NS_IF_RELEASE(mStateMaintainer);
|
||||
}
|
||||
}
|
||||
|
||||
mEditorType = eUninitializedEditorType;
|
||||
mEditor = 0; // clear out the nsCOMPtr
|
||||
|
||||
|
@ -365,8 +364,8 @@ nsEditorShell::PrepareDocumentForEditing(nsIURI *aUrl)
|
|||
{
|
||||
txnMgr->AddListener(NS_STATIC_CAST(nsITransactionListener*, mStateMaintainer));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (NS_SUCCEEDED(rv) && mContentWindow)
|
||||
{
|
||||
nsCOMPtr<nsIController> controller;
|
||||
|
@ -3149,6 +3148,26 @@ nsEditorShell::SelectTableCell()
|
|||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditorShell::SelectBlockOfCells(nsIDOMElement *aStartCell, nsIDOMElement *aEndCell)
|
||||
{
|
||||
nsresult result = NS_NOINTERFACE;
|
||||
switch (mEditorType)
|
||||
{
|
||||
case eHTMLTextEditorType:
|
||||
{
|
||||
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
||||
if (tableEditor)
|
||||
result = tableEditor->SelectBlockOfCells(aStartCell, aEndCell);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result = NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditorShell::SelectTableRow()
|
||||
{
|
||||
|
|
|
@ -138,7 +138,7 @@ class nsEditorShell : public nsIEditorShell,
|
|||
|
||||
nsCOMPtr<nsISupports> mSearchContext; // context used for search and replace. Owned by the appshell.
|
||||
|
||||
nsInterfaceState* mStateMaintainer; // we hold the owning ref to this.
|
||||
nsInterfaceState* mStateMaintainer; // we hold the owning ref to this.
|
||||
|
||||
PRInt32 mWrapColumn; // can't actually set this 'til the editor is created, so we may have to hold on to it for a while
|
||||
|
||||
|
|
|
@ -90,13 +90,6 @@ nsInterfaceState::NotifyDocumentCreated()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsInterfaceState::TableCellNotification(nsIDOMNode* aNode, PRInt32 aOffset)
|
||||
{
|
||||
//stub
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsInterfaceState::NotifyDocumentWillBeDestroyed()
|
||||
{
|
||||
|
@ -335,25 +328,89 @@ nsInterfaceState::SelectionIsCollapsed()
|
|||
nsresult
|
||||
nsInterfaceState::UpdateParagraphState(const char* observerName, const char* attributeName, nsString& ioParaFormat)
|
||||
{
|
||||
nsStringArray tagList;
|
||||
|
||||
mEditor->GetParagraphTags(&tagList);
|
||||
nsCOMPtr<nsIDOMSelection> domSelection;
|
||||
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
||||
// Get the nsIEditor pointer (mEditor is nsIHTMLEditor)
|
||||
if (!editor) return NS_ERROR_NULL_POINTER;
|
||||
nsresult rv = editor->GetSelection(getter_AddRefs(domSelection));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 numTags = tagList.Count();
|
||||
nsAutoString thisTag;
|
||||
//Note: If numTags == 0, we probably have a text node not in a container
|
||||
// (directly under <body>). Consider it normal
|
||||
if (numTags > 0)
|
||||
PRBool selectionCollapsed = PR_FALSE;
|
||||
rv = domSelection->GetIsCollapsed(&selectionCollapsed);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Get anchor and focus nodes:
|
||||
nsCOMPtr<nsIDOMNode> anchorNode;
|
||||
rv = domSelection->GetAnchorNode(getter_AddRefs(anchorNode));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!anchorNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> focusNode;
|
||||
rv = domSelection->GetFocusNode(getter_AddRefs(focusNode));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!focusNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> anchorNodeBlockParent;
|
||||
PRBool isBlock;
|
||||
rv = editor->NodeIsBlock(anchorNode, isBlock);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (isBlock)
|
||||
{
|
||||
// This will never show the "mixed state"
|
||||
// TODO: Scan list of tags and if any are different, set to "mixed"
|
||||
tagList.StringAt(0, thisTag);
|
||||
anchorNodeBlockParent = anchorNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get block parent of anchorNode node
|
||||
// We could simply use this if it was in nsIEditor interface!
|
||||
//rv = editor->GetBlockParent(anchorNode, getter_AddRefs(anchorNodeBlockParent));
|
||||
// if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
nsCOMPtr<nsIDOMNode>temp;
|
||||
rv = anchorNode->GetParentNode(getter_AddRefs(parent));
|
||||
while (NS_SUCCEEDED(rv) && parent)
|
||||
{
|
||||
rv = editor->NodeIsBlock(parent, isBlock);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (isBlock)
|
||||
{
|
||||
anchorNodeBlockParent = parent;
|
||||
break;
|
||||
}
|
||||
rv = parent->GetParentNode(getter_AddRefs(temp));
|
||||
parent = do_QueryInterface(temp);
|
||||
}
|
||||
}
|
||||
if (thisTag != mParagraphFormat)
|
||||
if (!anchorNodeBlockParent) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsAutoString tagName;
|
||||
|
||||
// Check if we have a selection that extends into multiple nodes,
|
||||
// so we can check for "mixed" selection state
|
||||
if (selectionCollapsed || focusNode == anchorNode)
|
||||
{
|
||||
nsresult rv = SetNodeAttribute(observerName, attributeName, thisTag);
|
||||
// Entire selection is within one block
|
||||
anchorNodeBlockParent->GetNodeName(tagName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We may have different block parent node types WITHIN the selection,
|
||||
// even if the anchor and focus parents are the same type.
|
||||
// Getting the list of all block, e.g., by using GetParagraphTags(&tagList)
|
||||
// is too inefficient for long documents.
|
||||
// TODO: Change to use selection iterator to detect each block node in the
|
||||
// selection and if different from the anchorNodeBlockParent, use "mixed" state
|
||||
// *** Not doing this now reduces risk for Beta1 -- simply assume mixed state
|
||||
// Note that "mixed" displays as "normal" in UI as of 3/6.
|
||||
tagName = "mixed";
|
||||
}
|
||||
|
||||
if (tagName != mParagraphFormat)
|
||||
{
|
||||
rv = SetNodeAttribute(observerName, attributeName, tagName);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mParagraphFormat = thisTag;
|
||||
mParagraphFormat = tagName;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ public:
|
|||
|
||||
// nsIDOMSelectionListener interface
|
||||
NS_IMETHOD NotifySelectionChanged();
|
||||
NS_IMETHOD TableCellNotification(nsIDOMNode* aNode, PRInt32 aOffset);
|
||||
|
||||
NS_DECL_NSIDOCUMENTSTATELISTENER
|
||||
|
||||
|
|
|
@ -303,6 +303,11 @@ interface nsIEditorShell : nsISupports
|
|||
* selects all cells (not TR in the case of rows)
|
||||
*/
|
||||
void SelectTableCell();
|
||||
/** Select a rectangular block of cells:
|
||||
* all cells falling within the row/column index of startCell
|
||||
* to through the row/column index of the endCell
|
||||
*/
|
||||
void SelectBlockOfCells(in nsIDOMElement startCell, in nsIDOMElement endCell);
|
||||
void SelectTableRow();
|
||||
void SelectTableColumn();
|
||||
void SelectTable();
|
||||
|
|
|
@ -56,9 +56,3 @@ NS_IMETHODIMP TypeInState::NotifySelectionChanged()
|
|||
Reset();
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP TypeInState::TableCellNotification(nsIDOMNode* aNode, PRInt32 aOffset)
|
||||
{
|
||||
//stub
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ public:
|
|||
virtual ~TypeInState();
|
||||
|
||||
NS_IMETHOD NotifySelectionChanged();
|
||||
NS_IMETHOD TableCellNotification(nsIDOMNode* aNode, PRInt32 aOffset);
|
||||
|
||||
void GetEnumForName(nsIAtom *aPropName, PRUint32 &aEnum);
|
||||
void GetPropertyIsString(PRUint32 aProp, PRUint32 &aIsString);
|
||||
|
|
|
@ -217,6 +217,7 @@ nsHTMLEditor::nsHTMLEditor()
|
|||
, mRules(nsnull)
|
||||
, mIsComposing(PR_FALSE)
|
||||
, mMaxTextLength(-1)
|
||||
, mSelectingTableCells(PR_FALSE)
|
||||
{
|
||||
// Done in nsEditor
|
||||
// NS_INIT_REFCNT();
|
||||
|
|
|
@ -184,6 +184,7 @@ public:
|
|||
NS_IMETHOD DeleteTableColumn(PRInt32 aNumber);
|
||||
NS_IMETHOD DeleteTableRow(PRInt32 aNumber);
|
||||
NS_IMETHOD SelectTableCell();
|
||||
NS_IMETHOD SelectBlockOfCells(nsIDOMElement *aStartCell, nsIDOMElement *aEndCell);
|
||||
NS_IMETHOD SelectTableRow();
|
||||
NS_IMETHOD SelectTableColumn();
|
||||
NS_IMETHOD SelectTable();
|
||||
|
@ -363,6 +364,8 @@ protected:
|
|||
// failed to set selection to some other content in the document
|
||||
NS_IMETHOD SetSelectionAtDocumentStart(nsIDOMSelection *aSelection);
|
||||
|
||||
// end of table editing utilities
|
||||
|
||||
NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode,
|
||||
nsString &aParentTag,
|
||||
BlockTransformationType aTranformation);
|
||||
|
@ -603,6 +606,14 @@ protected:
|
|||
PRBool mCachedUnderlineStyle;
|
||||
nsString mCachedFontName;
|
||||
|
||||
// True when selection consists of table cell(s)
|
||||
PRBool mSelectingTableCells;
|
||||
|
||||
// Used to monitor block of cells selected
|
||||
// by dragging mouse across the table
|
||||
nsCOMPtr<nsIDOMElement> mStartSelectedCell;
|
||||
nsCOMPtr<nsIDOMElement> mCurrentSelectedCell;
|
||||
|
||||
public:
|
||||
static nsIAtom *gTypingTxnName;
|
||||
static nsIAtom *gIMETxnName;
|
||||
|
|
|
@ -43,8 +43,11 @@
|
|||
|
||||
#include "nsEditorUtils.h"
|
||||
|
||||
//#define DEBUG_TABLE 1
|
||||
|
||||
static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* stack based helper class for restoring selection after table edit
|
||||
*/
|
||||
|
@ -75,6 +78,22 @@ class nsSetCaretAfterTableEdit
|
|||
void CancelSetCaret() {mEd = nsnull; mTable = nsnull;}
|
||||
};
|
||||
|
||||
// Stack-class to turn on/off selection batching for table selection
|
||||
class nsSelectionBatcher
|
||||
{
|
||||
private:
|
||||
nsCOMPtr<nsIDOMSelection> mSelection;
|
||||
public:
|
||||
nsSelectionBatcher(nsIDOMSelection *aSelection) : mSelection(aSelection)
|
||||
{
|
||||
if (mSelection) mSelection->StartBatchChanges();
|
||||
}
|
||||
virtual ~nsSelectionBatcher()
|
||||
{
|
||||
if (mSelection) mSelection->EndBatchChanges();
|
||||
}
|
||||
};
|
||||
|
||||
// Table Editing helper utilities (not exposed in IDL)
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -319,7 +338,7 @@ nsHTMLEditor::GetNextRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow)
|
|||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_cmanske
|
||||
printf("GetNextRow: firstChild of row's parent's sibling is not a TR!\n");
|
||||
#endif
|
||||
// We arrive here only if a table section has no children
|
||||
|
@ -963,8 +982,7 @@ NS_IMETHODIMP
|
|||
nsHTMLEditor::SelectTableCell()
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement> cell;
|
||||
nsresult res = NS_ERROR_FAILURE;
|
||||
res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(cell));
|
||||
nsresult res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(cell));
|
||||
if (NS_FAILED(res)) return res;
|
||||
// Don't fail if we didn't find a table
|
||||
if (!cell) return NS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
|
@ -979,24 +997,280 @@ nsHTMLEditor::SelectTableCell()
|
|||
return res;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::SelectBlockOfCells(nsIDOMElement *aStartCell, nsIDOMElement *aEndCell)
|
||||
{
|
||||
if (!aStartCell || !aEndCell) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
nsresult res = nsEditor::GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!selection) return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> table;
|
||||
res = GetElementOrParentByTagName("table", aStartCell, getter_AddRefs(table));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!table) return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> endTable;
|
||||
res = GetElementOrParentByTagName("table", aEndCell, getter_AddRefs(endTable));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!endTable) return NS_ERROR_FAILURE;
|
||||
|
||||
// We can only select a block if within the same table,
|
||||
// so do nothing if not within one table
|
||||
if (table != endTable) return NS_OK;
|
||||
|
||||
PRInt32 startRowIndex, startColIndex, endRowIndex, endColIndex;
|
||||
|
||||
// Get starting and ending cells' location in the cellmap
|
||||
res = GetCellIndexes(aStartCell, startRowIndex, startColIndex);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = GetCellIndexes(aEndCell, endRowIndex, endColIndex);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
// Suppress nsIDOMSelectionListener notification
|
||||
// until all selection changes are finished
|
||||
nsSelectionBatcher selectionBatcher(selection);
|
||||
|
||||
// It is now safe to clear the selection
|
||||
// BE SURE TO RESET IT BEFORE LEAVING!
|
||||
selection->ClearSelection();
|
||||
nsCOMPtr<nsIDOMNode> cellNode;
|
||||
PRBool cellSelected = PR_FALSE;
|
||||
|
||||
PRInt32 startColumn = PR_MIN(startColIndex, endColIndex);
|
||||
PRInt32 startRow = PR_MIN(startRowIndex, endRowIndex);
|
||||
PRInt32 maxColumn = PR_MAX(startColIndex, endColIndex);
|
||||
PRInt32 maxRow = PR_MAX(startRowIndex, endRowIndex);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> cell;
|
||||
PRInt32 rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
|
||||
PRBool isSelected;
|
||||
for (PRInt32 row = startRow; row <= maxRow; row++)
|
||||
{
|
||||
for(PRInt32 col = startColumn; col <= maxColumn; col += actualColSpan)
|
||||
{
|
||||
res = GetCellDataAt(table, row, col, *getter_AddRefs(cell),
|
||||
currentRowIndex, currentColIndex, rowSpan, colSpan,
|
||||
actualRowSpan, actualColSpan, isSelected);
|
||||
if (NS_FAILED(res)) break;
|
||||
// Skip cells that are spanned from previous locations
|
||||
if (cell && row == currentRowIndex && col == currentColIndex)
|
||||
{
|
||||
cellNode = do_QueryInterface(cell);
|
||||
res = nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
if (NS_FAILED(res)) break;
|
||||
cellSelected = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Safety code to select starting cell if nothing else was selected
|
||||
if (!cellSelected)
|
||||
{
|
||||
cellNode = do_QueryInterface(aStartCell);
|
||||
return nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::SelectAllTableCells()
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMElement> cell;
|
||||
nsresult res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(cell));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// Don't fail if we didn't find a cell
|
||||
if (!cell) return NS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> cellNode = do_QueryInterface(cell);
|
||||
if (!cellNode) return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDOMElement> startCell = cell;
|
||||
|
||||
// Get location of cell:
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
nsCOMPtr<nsIDOMElement> table;
|
||||
nsCOMPtr<nsIDOMNode> cellParent;
|
||||
PRInt32 cellOffset, startRowIndex, startColIndex;
|
||||
|
||||
res = GetCellContext(selection, table, cell, cellParent, cellOffset, startRowIndex, startColIndex);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if(!cell) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRInt32 rowCount, colCount;
|
||||
res = GetTableSize(table, rowCount, colCount);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// Suppress nsIDOMSelectionListener notification
|
||||
// until all selection changes are finished
|
||||
nsSelectionBatcher selectionBatcher(selection);
|
||||
|
||||
// It is now safe to clear the selection
|
||||
// BE SURE TO RESET IT BEFORE LEAVING!
|
||||
res = ClearSelection();
|
||||
|
||||
// Select all cells in the same column as current cell
|
||||
PRBool cellSelected = PR_FALSE;
|
||||
PRInt32 rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
|
||||
PRBool isSelected;
|
||||
for(PRInt32 row = 0; row < rowCount; row++)
|
||||
{
|
||||
for(PRInt32 col = 0; col < colCount; col += actualColSpan)
|
||||
{
|
||||
res = GetCellDataAt(table, row, col, *getter_AddRefs(cell),
|
||||
currentRowIndex, currentColIndex, rowSpan, colSpan,
|
||||
actualRowSpan, actualColSpan, isSelected);
|
||||
if (NS_FAILED(res)) break;
|
||||
// Skip cells that are spanned from previous rows or columns
|
||||
if (cell && row == currentRowIndex && col == currentColIndex)
|
||||
{
|
||||
cellNode = do_QueryInterface(cell);
|
||||
res = nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
if (NS_FAILED(res)) break;
|
||||
cellSelected = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Safety code to select starting cell if nothing else was selected
|
||||
if (!cellSelected)
|
||||
{
|
||||
cellNode = do_QueryInterface(startCell);
|
||||
return nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::SelectTableRow()
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMElement> cell;
|
||||
nsresult res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(cell));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// Don't fail if we didn't find a cell
|
||||
if (!cell) return NS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
nsCOMPtr<nsIDOMElement> startCell = cell;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> cellNode = do_QueryInterface(cell);
|
||||
if (!cellNode) return NS_ERROR_FAILURE;
|
||||
|
||||
// Get location of cell:
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
nsCOMPtr<nsIDOMElement> table;
|
||||
nsCOMPtr<nsIDOMNode> cellParent;
|
||||
PRInt32 cellOffset, startRowIndex, startColIndex;
|
||||
|
||||
res = GetCellContext(selection, table, cell, cellParent, cellOffset, startRowIndex, startColIndex);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if(!cell) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRInt32 rowCount, colCount;
|
||||
res = GetTableSize(table, rowCount, colCount);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
//Note: At this point, we could get first and last cells in row,
|
||||
// then call SelectBlockOfCells, but that would take just
|
||||
// a little less code, so the following is more efficient
|
||||
|
||||
// Suppress nsIDOMSelectionListener notification
|
||||
// until all selection changes are finished
|
||||
nsSelectionBatcher selectionBatcher(selection);
|
||||
|
||||
// It is now safe to clear the selection
|
||||
// BE SURE TO RESET IT BEFORE LEAVING!
|
||||
res = ClearSelection();
|
||||
|
||||
// Select all cells in the same row as current cell
|
||||
PRBool cellSelected = PR_FALSE;
|
||||
PRInt32 rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
|
||||
PRBool isSelected;
|
||||
for(PRInt32 col = 0; col < colCount; col += actualColSpan)
|
||||
{
|
||||
res = GetCellDataAt(table, startRowIndex, col, *getter_AddRefs(cell),
|
||||
currentRowIndex, currentColIndex, rowSpan, colSpan,
|
||||
actualRowSpan, actualColSpan, isSelected);
|
||||
if (NS_FAILED(res)) break;
|
||||
// Skip cells that are spanned from previous rows or columns
|
||||
if (cell && currentRowIndex == startRowIndex && currentColIndex == startColIndex)
|
||||
{
|
||||
cellNode = do_QueryInterface(cell);
|
||||
res = nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
if (NS_FAILED(res)) break;
|
||||
cellSelected = PR_TRUE;
|
||||
}
|
||||
}
|
||||
// Safety code to select starting cell if nothing else was selected
|
||||
if (!cellSelected)
|
||||
{
|
||||
cellNode = do_QueryInterface(startCell);
|
||||
return nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::SelectTableColumn()
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMElement> cell;
|
||||
nsresult res = GetElementOrParentByTagName("td", nsnull, getter_AddRefs(cell));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// Don't fail if we didn't find a cell
|
||||
if (!cell) return NS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> cellNode = do_QueryInterface(cell);
|
||||
if (!cellNode) return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDOMElement> startCell = cell;
|
||||
|
||||
// Get location of cell:
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
nsCOMPtr<nsIDOMElement> table;
|
||||
nsCOMPtr<nsIDOMNode> cellParent;
|
||||
PRInt32 cellOffset, startRowIndex, startColIndex;
|
||||
|
||||
res = GetCellContext(selection, table, cell, cellParent, cellOffset, startRowIndex, startColIndex);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if(!cell) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRInt32 rowCount, colCount;
|
||||
res = GetTableSize(table, rowCount, colCount);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// Suppress nsIDOMSelectionListener notification
|
||||
// until all selection changes are finished
|
||||
nsSelectionBatcher selectionBatcher(selection);
|
||||
|
||||
// It is now safe to clear the selection
|
||||
// BE SURE TO RESET IT BEFORE LEAVING!
|
||||
res = ClearSelection();
|
||||
|
||||
// Select all cells in the same column as current cell
|
||||
PRBool cellSelected = PR_FALSE;
|
||||
PRInt32 rowSpan, colSpan, actualRowSpan, actualColSpan, currentRowIndex, currentColIndex;
|
||||
PRBool isSelected;
|
||||
for(PRInt32 row = 0; row < rowCount; row += actualRowSpan)
|
||||
{
|
||||
res = GetCellDataAt(table, row, startColIndex, *getter_AddRefs(cell),
|
||||
currentRowIndex, currentColIndex, rowSpan, colSpan,
|
||||
actualRowSpan, actualColSpan, isSelected);
|
||||
if (NS_FAILED(res)) break;
|
||||
// Skip cells that are spanned from previous rows or columns
|
||||
if (cell && currentRowIndex == startRowIndex && currentColIndex == startColIndex)
|
||||
{
|
||||
cellNode = do_QueryInterface(cell);
|
||||
res = nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
if (NS_FAILED(res)) break;
|
||||
cellSelected = PR_TRUE;
|
||||
}
|
||||
}
|
||||
// Safety code to select starting cell if nothing else was selected
|
||||
if (!cellSelected)
|
||||
{
|
||||
cellNode = do_QueryInterface(startCell);
|
||||
return nsEditor::AppendNodeToSelectionAsRange(cellNode);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -1217,22 +1491,16 @@ nsHTMLEditor::GetCellIndexes(nsIDOMElement *aCell, PRInt32 &aRowIndex, PRInt32 &
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
res = NS_ERROR_FAILURE; // we return an error unless we get the index
|
||||
nsISupports *layoutObject=nsnull; // frames are not ref counted, so don't use an nsCOMPtr
|
||||
|
||||
res = nsHTMLEditor::GetLayoutObject(aCell, &layoutObject);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!layoutObject) return NS_ERROR_FAILURE;
|
||||
|
||||
if ((NS_SUCCEEDED(res)) && (nsnull!=layoutObject))
|
||||
{ // get the table cell interface from the frame
|
||||
nsITableCellLayout *cellLayoutObject=nsnull; // again, frames are not ref-counted
|
||||
|
||||
res = layoutObject->QueryInterface(NS_GET_IID(nsITableCellLayout), (void**)(&cellLayoutObject));
|
||||
if ((NS_SUCCEEDED(res)) && (nsnull!=cellLayoutObject))
|
||||
{
|
||||
res = cellLayoutObject->GetCellIndexes(aRowIndex, aColIndex);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
nsITableCellLayout *cellLayoutObject=nsnull; // again, frames are not ref-counted
|
||||
res = layoutObject->QueryInterface(NS_GET_IID(nsITableCellLayout), (void**)(&cellLayoutObject));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!cellLayoutObject) return NS_ERROR_FAILURE;
|
||||
return cellLayoutObject->GetCellIndexes(aRowIndex, aColIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1245,13 +1513,10 @@ nsHTMLEditor::GetTableLayoutObject(nsIDOMElement* aTable, nsITableLayout **table
|
|||
// frames are not ref counted, so don't use an nsCOMPtr
|
||||
nsISupports *layoutObject=nsnull;
|
||||
nsresult res = nsHTMLEditor::GetLayoutObject(aTable, &layoutObject);
|
||||
if ((NS_SUCCEEDED(res)) && (nsnull!=layoutObject))
|
||||
{ // get the table interface from the frame
|
||||
|
||||
res = layoutObject->QueryInterface(NS_GET_IID(nsITableLayout),
|
||||
(void**)(tableLayoutObject));
|
||||
}
|
||||
return res;
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!layoutObject) return NS_ERROR_FAILURE;
|
||||
return layoutObject->QueryInterface(NS_GET_IID(nsITableLayout),
|
||||
(void**)(tableLayoutObject));
|
||||
}
|
||||
|
||||
//Return actual number of cells (a cell with colspan > 1 counts as just 1)
|
||||
|
|
|
@ -82,6 +82,17 @@ public:
|
|||
* selects all cells (not TR in the case of rows)
|
||||
*/
|
||||
NS_IMETHOD SelectTableCell()=0;
|
||||
|
||||
/** Select a rectangular block of cells:
|
||||
* all cells falling within the row/column index of aStartCell
|
||||
* to through the row/column index of the aEndCell
|
||||
* aStartCell can be any location relative to aEndCell,
|
||||
* as long as they are in the same table
|
||||
* @param aStartCell starting cell in block
|
||||
* @param aEndCell ending cell in block
|
||||
*/
|
||||
NS_IMETHOD SelectBlockOfCells(nsIDOMElement *aStartCell, nsIDOMElement *aEndCell)=0;
|
||||
|
||||
NS_IMETHOD SelectTableRow()=0;
|
||||
NS_IMETHOD SelectTableColumn()=0;
|
||||
NS_IMETHOD SelectTable()=0;
|
||||
|
|
|
@ -284,30 +284,37 @@ text.color-caption {
|
|||
}
|
||||
|
||||
div#ColorButtons {
|
||||
/* Width needs to be >= 2x color button width
|
||||
(color.gif=14px + 2 for border)
|
||||
for initial layout.
|
||||
Then use relative position to move buttons
|
||||
to desired overlapping locations
|
||||
/* Width needs to be enough for overlapping
|
||||
buttons. Note: color.gif=14px + 2 for borders.
|
||||
We use relative position to move buttons
|
||||
to desired positions
|
||||
*/
|
||||
width: 32px;
|
||||
max-width: 32px;
|
||||
height: 19px;
|
||||
/* This compensates for remaining gap
|
||||
on right after relative button positioning
|
||||
width: 30px;
|
||||
max-width: 30px;
|
||||
/* Other toolbar buttons are 16px high (+border and margin),
|
||||
so limit total height of color buttons
|
||||
region to a compatable height
|
||||
*/
|
||||
margin-right: -3px;
|
||||
height: 22px;
|
||||
max-height: 22px;
|
||||
}
|
||||
|
||||
/* The initial layout of these buttons is:
|
||||
BackColorPopupButton appears above TextColorPopupButton.
|
||||
BackColorPopupButton must be 1st in XUL so that
|
||||
TextColorPopupButton is on top after relative positioning,
|
||||
which places TextColorPopupButton button in upper left and
|
||||
BackColorPopupButton button at lower right of the ColorButtons div
|
||||
*/
|
||||
|
||||
titledbutton#TextColorPopupButton {
|
||||
list-style-image:url("chrome://editor/skin/images/color.gif");
|
||||
border: 1px solid #CCCCCC;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
position: relative;
|
||||
/* Position top left */
|
||||
top: 1px;
|
||||
left: -14px;
|
||||
top: -15px;
|
||||
left: 1px;
|
||||
|
||||
/* TEMP: Set color here. TODO: Set color from page */
|
||||
background-color: #AA0000;
|
||||
|
@ -323,8 +330,7 @@ titledbutton#BackColorPopupButton {
|
|||
padding: 0px;
|
||||
margin: 0px;
|
||||
position: relative;
|
||||
/* Position lower right */
|
||||
top: 8px;
|
||||
top: 7px;
|
||||
left: 12px;
|
||||
|
||||
/* TEMP: Set color here. TODO: Set color from page */
|
||||
|
|
Загрузка…
Ссылка в новой задаче