added WillUndo, DidUndo, WillRedo, DidRedo and some supporting code so

the text edit rule object can maintain it's own state more efficiently and correctly.
This commit is contained in:
buster%netscape.com 1999-03-15 05:08:30 +00:00
Родитель c149d1f5b8
Коммит 6ce58013c8
7 изменённых файлов: 243 добавлений и 11 удалений

Просмотреть файл

@ -1083,8 +1083,6 @@ NS_IMETHODIMP nsEditor::DoInitialInsert(const nsString & aStringToInsert)
return NS_ERROR_NOT_INITIALIZED;
}
BeginTransaction();
nsCOMPtr<nsIDOMNodeList>nodeList;
nsAutoString bodyTag = "body";
nsresult result = mDoc->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList));
@ -1128,7 +1126,6 @@ NS_IMETHODIMP nsEditor::DoInitialInsert(const nsString & aStringToInsert)
}
}
}
EndTransaction();
return result;
}

Просмотреть файл

@ -124,6 +124,10 @@ nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
mEditor->DeleteNode(mBogusNode);
mBogusNode = do_QueryInterface(nsnull);
// there is no longer any legit selection, so clear it.
// BEGIN HACK -- ClearSelection does not remove the anchor! Subsequent code depends on
// ClearSelection making it so IsCollapsed returns TRUE
aSelection->Collapse(mBogusNode, 0);
// END HACK
aSelection->ClearSelection();
}
@ -188,7 +192,7 @@ nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult)
NS_ASSERTION(PR_TRUE==isCollapsed, "selection not collapsed after insert break.");
// if the insert break resulted in consecutive BR tags,
// collapse the two BR tags into a single P
if (NS_SUCCEEDED(aResult)) // note we're checking aResult, the param that tells us if the insert break happened or not
if (NS_SUCCEEDED(result))
{
nsCOMPtr<nsIEnumerator> enumerator;
enumerator = do_QueryInterface(aSelection,&result);
@ -384,6 +388,103 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul
return result;
}
NS_IMETHODIMP
nsTextEditRules::WillUndo(nsIDOMSelection *aSelection, PRBool *aCancel)
{
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
// initialize out param
*aCancel = PR_FALSE;
return NS_OK;
}
/* the idea here is to see if the magic empty node has suddenly reappeared as the result of the undo.
* if it has, set our state so we remember it.
* There is a tradeoff between doing here and at redo, or doing it everywhere else that might care.
* Since undo and redo are relatively rare, it makes sense to take the (small) performance hit here.
*/
NS_IMETHODIMP
nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsresult result = aResult; // if aResult is an error, we return it.
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
if (NS_SUCCEEDED(result))
{
if (mBogusNode) {
mBogusNode = do_QueryInterface(nsnull);
}
else
{
nsCOMPtr<nsIDOMNode>node;
PRInt32 offset;
nsresult result = aSelection->GetAnchorNodeAndOffset(getter_AddRefs(node), &offset);
while ((NS_SUCCEEDED(result)) && node)
{
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(node);
if (element)
{
nsAutoString att(kMOZEditorBogusNodeAttr);
nsAutoString val;
nsresult result = element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) {
mBogusNode = do_QueryInterface(element);
}
}
nsCOMPtr<nsIDOMNode> temp;
result = node->GetParentNode(getter_AddRefs(temp));
node = do_QueryInterface(temp);
}
}
}
return result;
}
NS_IMETHODIMP
nsTextEditRules::WillRedo(nsIDOMSelection *aSelection, PRBool *aCancel)
{
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
// initialize out param
*aCancel = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsresult result = aResult; // if aResult is an error, we return it.
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
if (NS_SUCCEEDED(result))
{
if (mBogusNode) {
mBogusNode = do_QueryInterface(nsnull);
}
else
{
nsCOMPtr<nsIDOMNode>node;
PRInt32 offset;
nsresult result = aSelection->GetAnchorNodeAndOffset(getter_AddRefs(node), &offset);
while ((NS_SUCCEEDED(result)) && node)
{
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(node);
if (element)
{
nsAutoString att(kMOZEditorBogusNodeAttr);
nsAutoString val;
nsresult result = element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) {
mBogusNode = do_QueryInterface(element);
}
}
nsCOMPtr<nsIDOMNode> temp;
result = node->GetParentNode(getter_AddRefs(temp));
node = do_QueryInterface(temp);
}
}
}
return result;
}

Просмотреть файл

@ -63,6 +63,12 @@ public:
NS_IMETHOD WillDeleteSelection(nsIDOMSelection *aSelection, PRBool *aCancel);
NS_IMETHOD DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResult);
NS_IMETHOD WillUndo(nsIDOMSelection *aSelection, PRBool *aCancel);
NS_IMETHOD DidUndo(nsIDOMSelection *aSelection, nsresult aResult);
NS_IMETHOD WillRedo(nsIDOMSelection *aSelection, PRBool *aCancel);
NS_IMETHOD DidRedo(nsIDOMSelection *aSelection, nsresult aResult);
protected:
nsTextEditor *mEditor; // note that we do not refcount the editor

Просмотреть файл

@ -440,7 +440,7 @@ NS_IMETHODIMP nsTextEditor::InsertText(const nsString& aStringToInsert)
nsAutoString stringToInsert;
PlaceholderTxn *placeholderTxn=nsnull;
nsresult result = mRules->WillInsertText(selection, aStringToInsert, &cancel, stringToInsert,
&placeholderTxn);
&placeholderTxn);
if ((PR_FALSE==cancel) && (NS_SUCCEEDED(result)))
{
result = nsEditor::InsertText(stringToInsert);
@ -519,7 +519,19 @@ NS_IMETHODIMP nsTextEditor::EnableUndo(PRBool aEnable)
NS_IMETHODIMP nsTextEditor::Undo(PRUint32 aCount)
{
return nsEditor::Undo(aCount);
nsCOMPtr<nsIDOMSelection> selection;
PRBool cancel= PR_FALSE;
// pre-process
nsEditor::GetSelection(getter_AddRefs(selection));
nsresult result = mRules->WillUndo(selection, &cancel);
if ((PR_FALSE==cancel) && (NS_SUCCEEDED(result)))
{
result = nsEditor::Undo(aCount);
nsEditor::GetSelection(getter_AddRefs(selection));
result = mRules->DidUndo(selection, result);
}
return result;
}
NS_IMETHODIMP nsTextEditor::CanUndo(PRBool &aIsEnabled, PRBool &aCanUndo)
@ -529,7 +541,19 @@ NS_IMETHODIMP nsTextEditor::CanUndo(PRBool &aIsEnabled, PRBool &aCanUndo)
NS_IMETHODIMP nsTextEditor::Redo(PRUint32 aCount)
{
return nsEditor::Redo(aCount);
nsCOMPtr<nsIDOMSelection> selection;
PRBool cancel= PR_FALSE;
// pre-process
nsEditor::GetSelection(getter_AddRefs(selection));
nsresult result = mRules->WillRedo(selection, &cancel);
if ((PR_FALSE==cancel) && (NS_SUCCEEDED(result)))
{
result = nsEditor::Redo(aCount);
nsEditor::GetSelection(getter_AddRefs(selection));
result = mRules->DidRedo(selection, result);
}
return result;
}
NS_IMETHODIMP nsTextEditor::CanRedo(PRBool &aIsEnabled, PRBool &aCanRedo)

Просмотреть файл

@ -1083,8 +1083,6 @@ NS_IMETHODIMP nsEditor::DoInitialInsert(const nsString & aStringToInsert)
return NS_ERROR_NOT_INITIALIZED;
}
BeginTransaction();
nsCOMPtr<nsIDOMNodeList>nodeList;
nsAutoString bodyTag = "body";
nsresult result = mDoc->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList));
@ -1128,7 +1126,6 @@ NS_IMETHODIMP nsEditor::DoInitialInsert(const nsString & aStringToInsert)
}
}
}
EndTransaction();
return result;
}

Просмотреть файл

@ -124,6 +124,10 @@ nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
mEditor->DeleteNode(mBogusNode);
mBogusNode = do_QueryInterface(nsnull);
// there is no longer any legit selection, so clear it.
// BEGIN HACK -- ClearSelection does not remove the anchor! Subsequent code depends on
// ClearSelection making it so IsCollapsed returns TRUE
aSelection->Collapse(mBogusNode, 0);
// END HACK
aSelection->ClearSelection();
}
@ -188,7 +192,7 @@ nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult)
NS_ASSERTION(PR_TRUE==isCollapsed, "selection not collapsed after insert break.");
// if the insert break resulted in consecutive BR tags,
// collapse the two BR tags into a single P
if (NS_SUCCEEDED(aResult)) // note we're checking aResult, the param that tells us if the insert break happened or not
if (NS_SUCCEEDED(result))
{
nsCOMPtr<nsIEnumerator> enumerator;
enumerator = do_QueryInterface(aSelection,&result);
@ -384,6 +388,103 @@ nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResul
return result;
}
NS_IMETHODIMP
nsTextEditRules::WillUndo(nsIDOMSelection *aSelection, PRBool *aCancel)
{
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
// initialize out param
*aCancel = PR_FALSE;
return NS_OK;
}
/* the idea here is to see if the magic empty node has suddenly reappeared as the result of the undo.
* if it has, set our state so we remember it.
* There is a tradeoff between doing here and at redo, or doing it everywhere else that might care.
* Since undo and redo are relatively rare, it makes sense to take the (small) performance hit here.
*/
NS_IMETHODIMP
nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsresult result = aResult; // if aResult is an error, we return it.
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
if (NS_SUCCEEDED(result))
{
if (mBogusNode) {
mBogusNode = do_QueryInterface(nsnull);
}
else
{
nsCOMPtr<nsIDOMNode>node;
PRInt32 offset;
nsresult result = aSelection->GetAnchorNodeAndOffset(getter_AddRefs(node), &offset);
while ((NS_SUCCEEDED(result)) && node)
{
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(node);
if (element)
{
nsAutoString att(kMOZEditorBogusNodeAttr);
nsAutoString val;
nsresult result = element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) {
mBogusNode = do_QueryInterface(element);
}
}
nsCOMPtr<nsIDOMNode> temp;
result = node->GetParentNode(getter_AddRefs(temp));
node = do_QueryInterface(temp);
}
}
}
return result;
}
NS_IMETHODIMP
nsTextEditRules::WillRedo(nsIDOMSelection *aSelection, PRBool *aCancel)
{
if (!aSelection || !aCancel) { return NS_ERROR_NULL_POINTER; }
// initialize out param
*aCancel = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
{
nsresult result = aResult; // if aResult is an error, we return it.
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
if (NS_SUCCEEDED(result))
{
if (mBogusNode) {
mBogusNode = do_QueryInterface(nsnull);
}
else
{
nsCOMPtr<nsIDOMNode>node;
PRInt32 offset;
nsresult result = aSelection->GetAnchorNodeAndOffset(getter_AddRefs(node), &offset);
while ((NS_SUCCEEDED(result)) && node)
{
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(node);
if (element)
{
nsAutoString att(kMOZEditorBogusNodeAttr);
nsAutoString val;
nsresult result = element->GetAttribute(att, val);
if (val.Equals(kMOZEditorBogusNodeValue)) {
mBogusNode = do_QueryInterface(element);
}
}
nsCOMPtr<nsIDOMNode> temp;
result = node->GetParentNode(getter_AddRefs(temp));
node = do_QueryInterface(temp);
}
}
}
return result;
}

Просмотреть файл

@ -63,6 +63,12 @@ public:
NS_IMETHOD WillDeleteSelection(nsIDOMSelection *aSelection, PRBool *aCancel);
NS_IMETHOD DidDeleteSelection(nsIDOMSelection *aSelection, nsresult aResult);
NS_IMETHOD WillUndo(nsIDOMSelection *aSelection, PRBool *aCancel);
NS_IMETHOD DidUndo(nsIDOMSelection *aSelection, nsresult aResult);
NS_IMETHOD WillRedo(nsIDOMSelection *aSelection, PRBool *aCancel);
NS_IMETHOD DidRedo(nsIDOMSelection *aSelection, nsresult aResult);
protected:
nsTextEditor *mEditor; // note that we do not refcount the editor