From baaca59f79f75c98b7e2510e865504603d295d00 Mon Sep 17 00:00:00 2001 From: "buster%netscape.com" Date: Sun, 4 Apr 1999 18:01:35 +0000 Subject: [PATCH] implemented simple cases of RemoveTextProperty. other cases are no-op'd now. added aFirst out param to GetTextProperty, so the caller can know if the first character has the property in the case of aAny=true and aAll=false. fixed a bunch of places where result was being used incorrectly as a return val from do_QueryInterface some minor undo/redo fixes to split and join of interior nodes. git-svn-id: svn://10.0.0.236/trunk@26218 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/editor/base/DeleteElementTxn.cpp | 37 +- mozilla/editor/base/DeleteRangeTxn.cpp | 4 +- mozilla/editor/base/DeleteTextTxn.cpp | 10 +- mozilla/editor/base/InsertElementTxn.cpp | 8 +- mozilla/editor/base/InsertTextTxn.cpp | 2 +- mozilla/editor/base/SplitElementTxn.cpp | 44 +- mozilla/editor/base/nsEditor.cpp | 60 ++- mozilla/editor/base/nsEditor.h | 8 +- .../editor/base/nsEditorEventListeners.cpp | 40 +- mozilla/editor/base/nsHTMLEditor.cpp | 4 +- mozilla/editor/base/nsHTMLEditor.h | 2 +- mozilla/editor/base/nsTextEditor.cpp | 506 +++++++++++++++++- mozilla/editor/base/nsTextEditor.h | 24 +- .../libeditor/base/DeleteElementTxn.cpp | 37 +- .../editor/libeditor/base/DeleteRangeTxn.cpp | 4 +- .../editor/libeditor/base/DeleteTextTxn.cpp | 10 +- .../libeditor/base/InsertElementTxn.cpp | 8 +- .../editor/libeditor/base/InsertTextTxn.cpp | 2 +- .../editor/libeditor/base/SplitElementTxn.cpp | 44 +- mozilla/editor/libeditor/base/nsEditor.cpp | 60 ++- mozilla/editor/libeditor/base/nsEditor.h | 8 +- .../editor/libeditor/html/nsHTMLEditor.cpp | 4 +- mozilla/editor/libeditor/html/nsHTMLEditor.h | 2 +- .../libeditor/text/nsEditorEventListeners.cpp | 40 +- 24 files changed, 853 insertions(+), 115 deletions(-) diff --git a/mozilla/editor/base/DeleteElementTxn.cpp b/mozilla/editor/base/DeleteElementTxn.cpp index 15b9bd004f8..8f59206fcce 100644 --- a/mozilla/editor/base/DeleteElementTxn.cpp +++ b/mozilla/editor/base/DeleteElementTxn.cpp @@ -50,7 +50,7 @@ DeleteElementTxn::~DeleteElementTxn() NS_IMETHODIMP DeleteElementTxn::Do(void) { - if (gNoisy) { printf("Do Delete Element element = %p\n", mElement.get()); } + if (gNoisy) { printf("%p Do Delete Element element = %p\n", this, mElement.get()); } if (!mElement) return NS_ERROR_NULL_POINTER; @@ -65,12 +65,12 @@ NS_IMETHODIMP DeleteElementTxn::Do(void) #ifdef NS_DEBUG // begin debug output nsCOMPtr element; - element = do_QueryInterface(mElement, &result); + element = do_QueryInterface(mElement); nsAutoString elementTag="text node"; if (element) element->GetTagName(elementTag); nsCOMPtr parentElement; - parentElement = do_QueryInterface(mParent, &result); + parentElement = do_QueryInterface(mParent); nsAutoString parentElementTag="text node"; if (parentElement) parentElement->GetTagName(parentElementTag); @@ -80,7 +80,7 @@ NS_IMETHODIMP DeleteElementTxn::Do(void) if (c&&p) { if (gNoisy) - printf("DeleteElementTxn: deleting child %s from parent %s\n", c, p); + printf(" DeleteElementTxn: deleting child %s from parent %s\n", c, p); delete [] c; delete [] p; } @@ -97,10 +97,35 @@ NS_IMETHODIMP DeleteElementTxn::Do(void) NS_IMETHODIMP DeleteElementTxn::Undo(void) { - if (gNoisy) { printf("Do Delete Element element = %p, parent = %p\n", mElement.get(), mParent.get()); } + if (gNoisy) { printf("%p Undo Delete Element element = %p, parent = %p\n", this, mElement.get(), mParent.get()); } if (!mParent || !mElement) return NS_ERROR_NULL_POINTER; +#ifdef NS_DEBUG + // begin debug output + nsCOMPtr element; + element = do_QueryInterface(mElement); + nsAutoString elementTag="text node"; + if (element) + element->GetTagName(elementTag); + nsCOMPtr parentElement; + parentElement = do_QueryInterface(mParent); + nsAutoString parentElementTag="text node"; + if (parentElement) + parentElement->GetTagName(parentElementTag); + char *c, *p; + c = elementTag.ToNewCString(); + p = parentElementTag.ToNewCString(); + if (c&&p) + { + if (gNoisy) + printf(" DeleteElementTxn: inserting child %s back into parent %s\n", c, p); + delete [] c; + delete [] p; + } + // end debug output +#endif + nsCOMPtr resultNode; nsresult result = mParent->InsertBefore(mElement, mRefNode, getter_AddRefs(resultNode)); return result; @@ -108,7 +133,7 @@ NS_IMETHODIMP DeleteElementTxn::Undo(void) NS_IMETHODIMP DeleteElementTxn::Redo(void) { - if (gNoisy) { printf("Redo Delete Element\n"); } + if (gNoisy) { printf("%p Redo Delete Element element = %p, parent = %p\n", this, mElement.get(), mParent.get()); } if (!mParent || !mElement) return NS_ERROR_NULL_POINTER; diff --git a/mozilla/editor/base/DeleteRangeTxn.cpp b/mozilla/editor/base/DeleteRangeTxn.cpp index c0014792e15..26e781e9479 100644 --- a/mozilla/editor/base/DeleteRangeTxn.cpp +++ b/mozilla/editor/base/DeleteRangeTxn.cpp @@ -69,7 +69,7 @@ NS_IMETHODIMP DeleteRangeTxn::Init(nsIEditor *aEditor, nsIDOMRange *aRange) { PRUint32 count; nsCOMPtr textNode; - textNode = do_QueryInterface(mStartParent, &result); + textNode = do_QueryInterface(mStartParent); if (textNode) textNode->GetLength(&count); else @@ -81,7 +81,7 @@ NS_IMETHODIMP DeleteRangeTxn::Init(nsIEditor *aEditor, nsIDOMRange *aRange) } NS_ASSERTION(mStartOffset<=(PRInt32)count, "bad start offset"); - textNode = do_QueryInterface(mEndParent, &result); + textNode = do_QueryInterface(mEndParent); if (textNode) textNode->GetLength(&count); else diff --git a/mozilla/editor/base/DeleteTextTxn.cpp b/mozilla/editor/base/DeleteTextTxn.cpp index 8f5b0114fdf..dd70ce357f2 100644 --- a/mozilla/editor/base/DeleteTextTxn.cpp +++ b/mozilla/editor/base/DeleteTextTxn.cpp @@ -36,9 +36,9 @@ DeleteTextTxn::~DeleteTextTxn() } NS_IMETHODIMP DeleteTextTxn::Init(nsIEditor *aEditor, - nsIDOMCharacterData *aElement, - PRUint32 aOffset, - PRUint32 aNumCharsToDelete) + nsIDOMCharacterData *aElement, + PRUint32 aOffset, + PRUint32 aNumCharsToDelete) { NS_ASSERTION(aEditor&&aElement, "bad arg"); mEditor = do_QueryInterface(aEditor); @@ -46,6 +46,10 @@ NS_IMETHODIMP DeleteTextTxn::Init(nsIEditor *aEditor, mOffset = aOffset; mNumCharsToDelete = aNumCharsToDelete; NS_ASSERTION(0!=aNumCharsToDelete, "bad arg, numCharsToDelete"); + PRUint32 count; + aElement->GetLength(&count); + NS_ASSERTION(countrefNode; - if (0!=mOffset) + //if (0!=mOffset) { // get a ref node PRInt32 i=0; result = mParent->GetFirstChild(getter_AddRefs(refNode)); @@ -94,7 +95,8 @@ NS_IMETHODIMP InsertElementTxn::Do(void) NS_IMETHODIMP InsertElementTxn::Undo(void) { - if (gNoisy) { printf("Undo Insert Element\n"); } + if (gNoisy) { printf("%p Undo Insert Element of %p into parent %p at offset %d\n", + this, mNode, mParent, mOffset); } if (!mNode || !mParent) return NS_ERROR_NULL_POINTER; diff --git a/mozilla/editor/base/InsertTextTxn.cpp b/mozilla/editor/base/InsertTextTxn.cpp index 11e9fc0ff2c..53815377329 100644 --- a/mozilla/editor/base/InsertTextTxn.cpp +++ b/mozilla/editor/base/InsertTextTxn.cpp @@ -135,7 +135,7 @@ NS_IMETHODIMP InsertTextTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransacti if (childTxn) { nsCOMPtr otherInsertTxn; - otherInsertTxn = do_QueryInterface(childTxn, &result); + otherInsertTxn = do_QueryInterface(childTxn); if (otherInsertTxn) { if (PR_TRUE==IsSequentialInsert(otherInsertTxn)) diff --git a/mozilla/editor/base/SplitElementTxn.cpp b/mozilla/editor/base/SplitElementTxn.cpp index 3c9aa43e843..045213087ca 100644 --- a/mozilla/editor/base/SplitElementTxn.cpp +++ b/mozilla/editor/base/SplitElementTxn.cpp @@ -23,7 +23,7 @@ #include "nsIEditorSupport.h" #ifdef NS_DEBUG -static PRBool gNoisy = PR_TRUE; +static PRBool gNoisy = PR_FALSE; #else static const PRBool gNoisy = PR_FALSE; #endif @@ -63,7 +63,7 @@ NS_IMETHODIMP SplitElementTxn::Do(void) if ((NS_SUCCEEDED(result)) && (mNewLeftNode)) { - if (gNoisy) { printf(" created left node = %p\n", this, mNewLeftNode.get()); } + if (gNoisy) { printf(" created left node = %p\n", mNewLeftNode.get()); } // get the parent node result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent)); // insert the new node @@ -103,21 +103,6 @@ NS_IMETHODIMP SplitElementTxn::Undo(void) return NS_ERROR_NOT_INITIALIZED; } -#ifdef NS_DEBUG - // sanity check - nsCOMPtrparent; - nsresult debugResult = mExistingRightNode->GetParentNode(getter_AddRefs(parent)); - NS_ASSERTION((NS_SUCCEEDED(debugResult)), "bad GetParentNode result for right child"); - NS_ASSERTION(parent, "bad GetParentNode for right child"); - NS_ASSERTION(parent==mParent, "bad GetParentNode for right child, parents don't match"); - - debugResult = mNewLeftNode->GetParentNode(getter_AddRefs(parent)); - NS_ASSERTION((NS_SUCCEEDED(debugResult)), "bad GetParentNode result for left child"); - NS_ASSERTION(parent, "bad GetParentNode for left child"); - NS_ASSERTION(parent==mParent, "bad GetParentNode for right child, left don't match"); - -#endif - // this assumes Do inserted the new node in front of the prior existing node nsresult result; nsCOMPtr editor; @@ -125,6 +110,11 @@ NS_IMETHODIMP SplitElementTxn::Undo(void) if (NS_SUCCEEDED(result) && editor) { result = editor->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE); + if (gNoisy) + { + printf("** after join left child node %p into right node %p\n", mNewLeftNode.get(), mExistingRightNode.get()); + if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG + } if (NS_SUCCEEDED(result)) { if (gNoisy) { printf(" left node = %p removed\n", this, mNewLeftNode.get()); } @@ -154,6 +144,7 @@ NS_IMETHODIMP SplitElementTxn::Redo(void) if (gNoisy) { printf("%p Redo Split of existing node %p and new node %p offset %d\n", this, mExistingRightNode.get(), mNewLeftNode.get(), mOffset); + if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG } nsresult result; nsCOMPtrresultNode; @@ -163,6 +154,11 @@ NS_IMETHODIMP SplitElementTxn::Redo(void) if (rightNodeAsText) { result = rightNodeAsText->DeleteData(0, mOffset); + if (gNoisy) + { + printf("** after delete of text in right text node %p offset %d\n", rightNodeAsText.get(), mOffset); + if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG + } } else { @@ -176,11 +172,25 @@ NS_IMETHODIMP SplitElementTxn::Redo(void) if (!child) {return NS_ERROR_NULL_POINTER;} child->GetNextSibling(getter_AddRefs(nextSibling)); result = mExistingRightNode->RemoveChild(child, getter_AddRefs(resultNode)); + if (NS_SUCCEEDED(result)) + { + result = mNewLeftNode->AppendChild(child, getter_AddRefs(resultNode)); + if (gNoisy) + { + printf("** move child node %p from right node %p to left node %p\n", child.get(), mExistingRightNode.get(), mNewLeftNode.get()); + if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG + } + } child = do_QueryInterface(nextSibling); } } // second, re-insert the left node into the tree result = mParent->InsertBefore(mNewLeftNode, mExistingRightNode, getter_AddRefs(resultNode)); + if (gNoisy) + { + printf("** reinsert left child node %p before right node %p\n", mNewLeftNode.get(), mExistingRightNode.get()); + if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG + } return result; } diff --git a/mozilla/editor/base/nsEditor.cpp b/mozilla/editor/base/nsEditor.cpp index d52d5f5aa78..1ecdd6bd249 100644 --- a/mozilla/editor/base/nsEditor.cpp +++ b/mozilla/editor/base/nsEditor.cpp @@ -1128,7 +1128,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForInsertText(const nsString & aStringToInsert, { result = NS_ERROR_UNEXPECTED; nsCOMPtr enumerator; - enumerator = do_QueryInterface(selection,&result); + enumerator = do_QueryInterface(selection); if (enumerator) { enumerator->First(); @@ -1144,8 +1144,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForInsertText(const nsString & aStringToInsert, result = range->GetStartParent(getter_AddRefs(node)); if ((NS_SUCCEEDED(result)) && (node)) { - result = NS_ERROR_UNEXPECTED; - nodeAsText = do_QueryInterface(node,&result); + nodeAsText = do_QueryInterface(node); range->GetStartOffset(&offset); if (!nodeAsText) { result = NS_ERROR_EDITOR_NO_TEXTNODE; @@ -1451,7 +1450,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForDeleteSelection(nsIEditor::Direction aDir, if ((NS_SUCCEEDED(result)) && selection) { nsCOMPtr enumerator; - enumerator = do_QueryInterface(selection,&result); + enumerator = do_QueryInterface(selection); if (enumerator) { for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next()) @@ -1553,7 +1552,7 @@ nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange, { // there is a priorNode, so delete it's last child (if text content, delete the last char.) // if it has no children, delete it nsCOMPtr priorNodeAsText; - priorNodeAsText = do_QueryInterface(priorNode, &result); + priorNodeAsText = do_QueryInterface(priorNode); if (priorNodeAsText) { PRUint32 length=0; @@ -1590,7 +1589,7 @@ nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange, { // there is a priorNode, so delete it's last child (if text content, delete the last char.) // if it has no children, delete it nsCOMPtr nextNodeAsText; - nextNodeAsText = do_QueryInterface(nextNode,&result); + nextNodeAsText = do_QueryInterface(nextNode); if (nextNodeAsText) { PRUint32 length=0; @@ -1815,6 +1814,9 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, nsIDOMNode* aNewLeftNode, nsIDOMNode* aParent) { + +printf("SplitNodeImpl: left=%p, right=%p, offset=%d\n", aNewLeftNode, aExistingRightNode, aOffset); + nsresult result; NS_ASSERTION(((nsnull!=aExistingRightNode) && (nsnull!=aNewLeftNode) && @@ -1826,6 +1828,7 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, { nsCOMPtr resultNode; result = aParent->InsertBefore(aNewLeftNode, aExistingRightNode, getter_AddRefs(resultNode)); + //printf(" after insert\n"); content->List(); // DEBUG if (NS_SUCCEEDED(result)) { // split the children between the 2 nodes @@ -1847,21 +1850,26 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, } else { // otherwise it's an interior node, so shuffle around the children + // go through list backwards so deletes don't interfere with the iteration nsCOMPtr childNodes; result = aExistingRightNode->GetChildNodes(getter_AddRefs(childNodes)); if ((NS_SUCCEEDED(result)) && (childNodes)) { - PRInt32 i=0; - for ( ; ((NS_SUCCEEDED(result)) && (i childNode; result = childNodes->Item(i, getter_AddRefs(childNode)); if ((NS_SUCCEEDED(result)) && (childNode)) { result = aExistingRightNode->RemoveChild(childNode, getter_AddRefs(resultNode)); + //printf(" after remove\n"); content->List(); // DEBUG if (NS_SUCCEEDED(result)) { - result = aNewLeftNode->AppendChild(childNode, getter_AddRefs(resultNode)); + nsCOMPtr firstChild; + aNewLeftNode->GetFirstChild(getter_AddRefs(firstChild)); + result = aNewLeftNode->InsertBefore(childNode, firstChild, getter_AddRefs(resultNode)); + //printf(" after append\n"); content->List(); // DEBUG } } } @@ -1917,7 +1925,7 @@ nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, result = aNodeToJoin->GetChildNodes(getter_AddRefs(childNodes)); if ((NS_SUCCEEDED(result)) && (childNodes)) { - PRUint32 i; + PRInt32 i; // must be signed int! PRUint32 childCount=0; childNodes->GetLength(&childCount); nsCOMPtr firstNode; //only used if aNodeToKeepIsFirst is false @@ -1927,7 +1935,9 @@ nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, // GetFirstChild returns nsnull firstNode if aNodeToKeep has no children, that's ok. } nsCOMPtr resultNode; - for (i=0; ((NS_SUCCEEDED(result)) && (i previousChild; + for (i=childCount-1; ((NS_SUCCEEDED(result)) && (0<=i)); i--) { nsCOMPtr childNode; result = childNodes->Item(i, getter_AddRefs(childNode)); @@ -1935,11 +1945,15 @@ nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, { if (PR_TRUE==aNodeToKeepIsFirst) { // append children of aNodeToJoin - result = aNodeToKeep->AppendChild(childNode, getter_AddRefs(resultNode)); + //was result = aNodeToKeep->AppendChild(childNode, getter_AddRefs(resultNode)); + result = aNodeToKeep->InsertBefore(childNode, previousChild, getter_AddRefs(resultNode)); + previousChild = do_QueryInterface(childNode); } else { // prepend children of aNodeToJoin + //was result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode)); result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode)); + firstNode = do_QueryInterface(childNode); } } } @@ -2047,6 +2061,28 @@ NS_IMETHODIMP nsEditor::GetLayoutObject(nsIDOMNode *aNode, nsISupports **aLayout return result; } +NS_IMETHODIMP +nsEditor::DebugDumpContent() const +{ + nsCOMPtrcontent; + nsCOMPtrnodeList; + nsAutoString bodyTag = "body"; + mDoc->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList)); + if (nodeList) + { + PRUint32 count; + nodeList->GetLength(&count); + NS_ASSERTION(1==count, "there is not exactly 1 body in the document!"); + nsCOMPtrbodyNode; + nodeList->Item(0, getter_AddRefs(bodyNode)); + if (bodyNode) { + content = do_QueryInterface(bodyNode); + } + } + content->List(); + return NS_OK; +} + //END nsEditor Private methods diff --git a/mozilla/editor/base/nsEditor.h b/mozilla/editor/base/nsEditor.h index 4fdd84d79eb..93529ea5cdf 100644 --- a/mozilla/editor/base/nsEditor.h +++ b/mozilla/editor/base/nsEditor.h @@ -60,13 +60,15 @@ private: nsIPresShell *mPresShell; nsIViewManager *mViewManager; PRUint32 mUpdateCount; - nsCOMPtr mDoc; nsCOMPtr mTxnMgr; friend PRBool NSCanUnload(nsISupports* serviceMgr); static PRInt32 gInstanceCount; +protected: + nsCOMPtr mDoc; + public: /** The default constructor. This should suffice. the setting of the interfaces is done * after the construction of the editor class. @@ -278,8 +280,6 @@ protected: NS_IMETHOD GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode); -//Methods not exposed in nsIEditor - /** Create an aggregate transaction for deleting current selection * Used by all methods that need to delete current selection, * then insert something new to replace it @@ -290,6 +290,8 @@ protected: */ NS_IMETHOD CreateAggregateTxnForDeleteSelection(nsIAtom *aTxnName, EditAggregateTxn **aAggTxn); + NS_IMETHOD DebugDumpContent() const; + protected: // XXXX: Horrible hack! We are doing this because // of an error in Gecko which is not rendering the diff --git a/mozilla/editor/base/nsEditorEventListeners.cpp b/mozilla/editor/base/nsEditorEventListeners.cpp index 2e548a9157c..964451b6ea2 100644 --- a/mozilla/editor/base/nsEditorEventListeners.cpp +++ b/mozilla/editor/base/nsEditorEventListeners.cpp @@ -310,7 +310,18 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr aProcessed=PR_TRUE; if (mEditor) { - mEditor->SetTextProperty(nsIEditProperty::i); + // XXX: move this logic down into texteditor rules delegate + // should just call mEditor->ChangeTextProperty(prop) + PRBool any = PR_FALSE; + PRBool all = PR_FALSE; + PRBool first = PR_FALSE; + mEditor->GetTextProperty(nsIEditProperty::i, first, any, all); + if (PR_FALSE==first) { + mEditor->SetTextProperty(nsIEditProperty::i); + } + else { + mEditor->RemoveTextProperty(nsIEditProperty::i); + } } } @@ -336,7 +347,18 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr aProcessed=PR_TRUE; if (mEditor) { - mEditor->SetTextProperty(nsIEditProperty::b); + // XXX: move this logic down into texteditor rules delegate + // should just call mEditor->ChangeTextProperty(prop) + PRBool any = PR_FALSE; + PRBool all = PR_FALSE; + PRBool first = PR_FALSE; + mEditor->GetTextProperty(nsIEditProperty::b, first, any, all); + if (PR_FALSE==first) { + mEditor->SetTextProperty(nsIEditProperty::b); + } + else { + mEditor->RemoveTextProperty(nsIEditProperty::b); + } } } break; @@ -348,7 +370,19 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr aProcessed=PR_TRUE; if (mEditor) { - mEditor->SetTextProperty(nsIEditProperty::u); + // XXX: move this logic down into texteditor rules delegate + // should just call mEditor->ChangeTextProperty(prop) + PRBool any = PR_FALSE; + PRBool all = PR_FALSE; + PRBool first = PR_FALSE; + mEditor->GetTextProperty(nsIEditProperty::u, first, any, all); + if (PR_FALSE==first) { + mEditor->SetTextProperty(nsIEditProperty::u); + } + else { + mEditor->RemoveTextProperty(nsIEditProperty::u); + } + } } break; diff --git a/mozilla/editor/base/nsHTMLEditor.cpp b/mozilla/editor/base/nsHTMLEditor.cpp index 1255cda6236..772c876bdc4 100644 --- a/mozilla/editor/base/nsHTMLEditor.cpp +++ b/mozilla/editor/base/nsHTMLEditor.cpp @@ -113,9 +113,9 @@ NS_IMETHODIMP nsHTMLEditor::SetTextProperty(nsIAtom *aProperty) return nsTextEditor::SetTextProperty(aProperty); } -NS_IMETHODIMP nsHTMLEditor::GetTextProperty(nsIAtom *aProperty, PRBool &aAny, PRBool &aAll) +NS_IMETHODIMP nsHTMLEditor::GetTextProperty(nsIAtom *aProperty, PRBool &aFirst, PRBool &aAny, PRBool &aAll) { - return nsTextEditor::GetTextProperty(aProperty, aAny, aAll); + return nsTextEditor::GetTextProperty(aProperty, aFirst, aAny, aAll); } NS_IMETHODIMP nsHTMLEditor::RemoveTextProperty(nsIAtom *aProperty) diff --git a/mozilla/editor/base/nsHTMLEditor.h b/mozilla/editor/base/nsHTMLEditor.h index dae03c1308f..f2d9d111281 100644 --- a/mozilla/editor/base/nsHTMLEditor.h +++ b/mozilla/editor/base/nsHTMLEditor.h @@ -51,7 +51,7 @@ public: // Editing Operations NS_IMETHOD SetTextProperty(nsIAtom *aProperty); - NS_IMETHOD GetTextProperty(nsIAtom *aProperty, PRBool &aAny, PRBool &aAll); + NS_IMETHOD GetTextProperty(nsIAtom *aProperty, PRBool &aFirst, PRBool &aAny, PRBool &aAll); NS_IMETHOD RemoveTextProperty(nsIAtom *aProperty); NS_IMETHOD DeleteSelection(nsIEditor::Direction aDir); NS_IMETHOD InsertText(const nsString& aStringToInsert); diff --git a/mozilla/editor/base/nsTextEditor.cpp b/mozilla/editor/base/nsTextEditor.cpp index 1625a0c32dc..63ad3f34356 100644 --- a/mozilla/editor/base/nsTextEditor.cpp +++ b/mozilla/editor/base/nsTextEditor.cpp @@ -96,6 +96,11 @@ static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID); static NS_DEFINE_IID(kIContentIteratorIID, NS_ICONTENTITERTOR_IID); static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID); +#ifdef NS_DEBUG +static PRBool gNoisy = PR_FALSE; +#else +static const PRBool gNoisy = PR_FALSE; +#endif /* ---------- TypeInState implementation ---------- */ // most methods are defined inline in TypeInState.h @@ -317,8 +322,8 @@ NS_IMETHODIMP nsTextEditor::SetTextProperty(nsIAtom *aProperty) { nsEditor::BeginTransaction(); nsCOMPtr enumerator; - enumerator = do_QueryInterface(selection, &result); - if ((NS_SUCCEEDED(result)) && enumerator) + enumerator = do_QueryInterface(selection); + if (enumerator) { enumerator->First(); nsISupports *currentItem; @@ -401,7 +406,7 @@ NS_IMETHODIMP nsTextEditor::SetTextProperty(nsIAtom *aProperty) return result; } -NS_IMETHODIMP nsTextEditor::GetTextProperty(nsIAtom *aProperty, PRBool &aAny, PRBool &aAll) +NS_IMETHODIMP nsTextEditor::GetTextProperty(nsIAtom *aProperty, PRBool &aFirst, PRBool &aAny, PRBool &aAll) { if (!aProperty) return NS_ERROR_NULL_POINTER; @@ -409,13 +414,15 @@ NS_IMETHODIMP nsTextEditor::GetTextProperty(nsIAtom *aProperty, PRBool &aAny, PR nsresult result=NS_ERROR_NOT_INITIALIZED; aAny=PR_FALSE; aAll=PR_TRUE; + aFirst=PR_FALSE; + PRBool first=PR_TRUE; nsCOMPtrselection; result = nsEditor::GetSelection(getter_AddRefs(selection)); if ((NS_SUCCEEDED(result)) && selection) { nsCOMPtr enumerator; - enumerator = do_QueryInterface(selection, &result); - if ((NS_SUCCEEDED(result)) && enumerator) + enumerator = do_QueryInterface(selection); + if (enumerator) { enumerator->First(); nsISupports *currentItem; @@ -448,6 +455,11 @@ NS_IMETHODIMP nsTextEditor::GetTextProperty(nsIAtom *aProperty, PRBool &aAny, PR { PRBool isSet; IsTextPropertySetByContent(node, aProperty, isSet); + if (PR_TRUE==first) + { + aFirst = isSet; + first = PR_FALSE; + } if (PR_TRUE==isSet) { aAny = PR_TRUE; } @@ -523,7 +535,107 @@ void nsTextEditor::IsTextPropertySetByContent(nsIDOMNode *aNode, NS_IMETHODIMP nsTextEditor::RemoveTextProperty(nsIAtom *aProperty) { - return NS_ERROR_NOT_IMPLEMENTED; + if (!aProperty) + return NS_ERROR_NULL_POINTER; + + nsresult result=NS_ERROR_NOT_INITIALIZED; + nsCOMPtrselection; + result = nsEditor::GetSelection(getter_AddRefs(selection)); + if ((NS_SUCCEEDED(result)) && selection) + { + PRBool isCollapsed; + selection->IsCollapsed(&isCollapsed); + if (PR_TRUE==isCollapsed) + { + // manipulating text attributes on a collapsed selection only sets state for the next text insertion + SetTypeInStateForProperty(mTypeInState, aProperty); + } + else + { + nsEditor::BeginTransaction(); + nsCOMPtr enumerator; + enumerator = do_QueryInterface(selection); + if (enumerator) + { + enumerator->First(); + nsISupports *currentItem; + result = enumerator->CurrentItem(¤tItem); + if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) + { + nsCOMPtr range( do_QueryInterface(currentItem) ); + nsCOMPtrcommonParent; + result = range->GetCommonParent(getter_AddRefs(commonParent)); + if ((NS_SUCCEEDED(result)) && commonParent) + { + PRInt32 startOffset, endOffset; + range->GetStartOffset(&startOffset); + range->GetEndOffset(&endOffset); + nsCOMPtr startParent; nsCOMPtr endParent; + range->GetStartParent(getter_AddRefs(startParent)); + range->GetEndParent(getter_AddRefs(endParent)); + if (startParent.get()==endParent.get()) + { // the range is entirely contained within a single text node + // commonParent==aStartParent, so get the "real" parent of the selection + startParent->GetParentNode(getter_AddRefs(commonParent)); + result = RemoveTextPropertiesForNode(startParent, commonParent, + startOffset, endOffset, + aProperty); + } + else + { + nsCOMPtr startGrandParent; + startParent->GetParentNode(getter_AddRefs(startGrandParent)); + nsCOMPtr endGrandParent; + endParent->GetParentNode(getter_AddRefs(endGrandParent)); + if (NS_SUCCEEDED(result)) + { + PRBool canCollapseStyleNode = PR_FALSE; + if (endGrandParent.get()==startGrandParent.get()) + { + result = IntermediateNodesAreInline(range, startParent, startOffset, + endParent, endOffset, + startGrandParent, canCollapseStyleNode); + } + if (NS_SUCCEEDED(result)) + { + if (PR_TRUE==canCollapseStyleNode) + { // the range is between 2 nodes that have a common (immediate) grandparent, + // and any intermediate nodes are just inline style nodes + result = RemoveTextPropertiesForNodesWithSameParent(startParent,startOffset, + endParent, endOffset, + commonParent, + aProperty); + } + else + { // the range is between 2 nodes that have no simple relationship + result = RemoveTextPropertiesForNodeWithDifferentParents(range, + startParent,startOffset, + endParent, endOffset, + commonParent, + aProperty); + } + } + } + } + if (NS_SUCCEEDED(result)) + { // compute a range for the selection + // don't want to actually do anything with selection, because + // we are still iterating through it. Just want to create and remember + // an nsIDOMRange, and later add the range to the selection after clearing it. + // XXX: I'm blocked here because nsIDOMSelection doesn't provide a mechanism + // for setting a compound selection yet. + } + } + } + } + nsEditor::EndTransaction(); + } + if (NS_SUCCEEDED(result)) + { // set the selection + // XXX: can't do anything until I can create ranges + } + } + return result; } NS_IMETHODIMP nsTextEditor::DeleteSelection(nsIEditor::Direction aDir) @@ -1255,6 +1367,382 @@ nsTextEditor::SetTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, return result; } +NS_IMETHODIMP nsTextEditor::RemoveTextPropertiesForNode(nsIDOMNode *aNode, + nsIDOMNode *aParent, + PRInt32 aStartOffset, + PRInt32 aEndOffset, + nsIAtom *aPropName) +{ + nsresult result=NS_OK; + nsCOMPtrnodeAsChar; + nodeAsChar = do_QueryInterface(aNode); + if (!nodeAsChar) + return NS_ERROR_FAILURE; + + PRBool textPropertySet; + IsTextPropertySetByContent(aNode, aPropName, textPropertySet); + if (PR_TRUE==textPropertySet) + { + PRUint32 count; + nodeAsChar->GetLength(&count); + // split the node, and all parent nodes up to the style node + // then promote the selected content to the parent of the style node + nsCOMPtrnewLeftNode; // this will be the leftmost node, + // the node being split will be rightmost + if (0!=aStartOffset) { + printf("* splitting text node %p at %d\n", aNode, aStartOffset); + result = nsEditor::SplitNode(aNode, aStartOffset, getter_AddRefs(newLeftNode)); + printf("* split created left node %p\n", newLeftNode.get()); + if (gNoisy) {DebugDumpContent(); } // DEBUG + } + if (NS_SUCCEEDED(result)) + { + nsCOMPtrnewMiddleNode; // this will be the middle node + if ((PRInt32)count!=aEndOffset) { + printf("* splitting text node (right node) %p at %d\n", aNode, aEndOffset-aStartOffset); + result = nsEditor::SplitNode(aNode, aEndOffset-aStartOffset, getter_AddRefs(newMiddleNode)); + printf("* split created middle node %p\n", newMiddleNode.get()); + if (gNoisy) {DebugDumpContent(); } // DEBUG + } + else { + printf("* no need to split text node\n"); + newMiddleNode = do_QueryInterface(aNode); + } + NS_ASSERTION(newMiddleNode, "no middle node created"); + // now that the text node is split, split parent nodes until we get to the style node + nsCOMPtrparent; + parent = do_QueryInterface(aParent); // we know this has to succeed, no need to check + if (NS_SUCCEEDED(result) && newMiddleNode) + { + // split every ancestor until we find the node that is giving us the style we want to remove + // then split the style node and promote the selected content to the style node's parent + while (NS_SUCCEEDED(result) && parent) + { + printf("* looking at parent %p\n", parent); + // get the tag from parent and see if we're done + nsCOMPtrtemp; + nsCOMPtrelement; + element = do_QueryInterface(parent); + if (element) + { + nsAutoString tag; + result = element->GetTagName(tag); + printf("* parent has tag %s\n", tag.ToNewCString()); // leak! + if (NS_SUCCEEDED(result)) + { + if (PR_FALSE==tag.Equals(aPropName)) + { + printf("* this is not the style node\n"); + PRInt32 offsetInParent; + result = nsIEditorSupport::GetChildOffset(newMiddleNode, parent, offsetInParent); + if (NS_SUCCEEDED(result)) + { + if (0!=offsetInParent) { + printf("* splitting parent %p at offset %d\n", parent, offsetInParent); + result = nsEditor::SplitNode(parent, offsetInParent, getter_AddRefs(newLeftNode)); + printf("* split created left node %p sibling of parent\n", newLeftNode.get()); + if (gNoisy) {DebugDumpContent(); } // DEBUG + } + if (NS_SUCCEEDED(result)) + { + nsCOMPtrchildNodes; + result = parent->GetChildNodes(getter_AddRefs(childNodes)); + if (NS_SUCCEEDED(result) && childNodes) + { + childNodes->GetLength(&count); + NS_ASSERTION(count>0, "bad child count in newly split node"); + if ((PRInt32)count!=1) + { + printf("* splitting parent %p at offset %d\n", parent, 1); + result = nsEditor::SplitNode(parent, 1, getter_AddRefs(newMiddleNode)); + printf("* split created middle node %p sibling of parent\n", newMiddleNode.get()); + if (gNoisy) {DebugDumpContent(); } // DEBUG + } + else { + printf("* no need to split parent, newMiddleNode=parent\n"); + newMiddleNode = do_QueryInterface(parent); + } + NS_ASSERTION(newMiddleNode, "no middle node created"); + parent->GetParentNode(getter_AddRefs(temp)); + parent = do_QueryInterface(temp); + } + } + } + } + // else we've found the style tag (referred to by "parent") + // nwMiddleNode is the node that is an ancestor to the selection + else + { + printf("* this is the style node\n"); + PRInt32 offsetInParent; + result = nsIEditorSupport::GetChildOffset(newMiddleNode, parent, offsetInParent); + if (NS_SUCCEEDED(result)) + { + nsCOMPtrchildNodes; + result = parent->GetChildNodes(getter_AddRefs(childNodes)); + if (NS_SUCCEEDED(result) && childNodes) + { + childNodes->GetLength(&count); + if (0!=offsetInParent && ((PRInt32)count!=offsetInParent+1)) { + printf("* splitting parent %p at offset %d\n", parent, offsetInParent); + result = nsEditor::SplitNode(parent, offsetInParent, getter_AddRefs(newLeftNode)); + printf("* split created left node %p sibling of parent\n", newLeftNode.get()); + if (gNoisy) {DebugDumpContent(); } // DEBUG + } + if (NS_SUCCEEDED(result)) + { // promote the selection to the grandparent + nsCOMPtrgrandParent; + result = parent->GetParentNode(getter_AddRefs(grandParent)); + if (NS_SUCCEEDED(result) && grandParent) + { + printf("* deleting middle node %p\n", newMiddleNode.get()); + result = nsEditor::DeleteNode(newMiddleNode); + if (gNoisy) {DebugDumpContent(); } // DEBUG + if (NS_SUCCEEDED(result)) + { + PRInt32 position; + result = nsIEditorSupport::GetChildOffset(parent, grandParent, position); + if (NS_SUCCEEDED(result)) + { + printf("* inserting node %p in grandparent %p at offset %d\n", + newMiddleNode.get(), grandParent.get(), position); + result = nsEditor::InsertNode(newMiddleNode, grandParent, position); + if (gNoisy) {DebugDumpContent(); } // DEBUG + if (NS_SUCCEEDED(result)) + { + PRBool hasChildren=PR_TRUE; + parent->HasChildNodes(&hasChildren); + if (PR_FALSE==hasChildren) { + printf("* deleting empty style node %p\n", parent.get()); + result = nsEditor::DeleteNode(parent); + if (gNoisy) {DebugDumpContent(); } // DEBUG + } + } + } + } + } + } + } + } + break; + } + } + } + } + } + } + } + return result; +} + +/* this should only get called if the only intervening nodes are inline style nodes */ +NS_IMETHODIMP +nsTextEditor::RemoveTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, + PRInt32 aStartOffset, + nsIDOMNode *aEndNode, + PRInt32 aEndOffset, + nsIDOMNode *aParent, + nsIAtom *aPropName) +{ + printf("not yet implemented\n"); + return NS_OK; + nsresult result=NS_OK; + PRBool textPropertySet; + IsTextPropertySetByContent(aStartNode, aPropName, textPropertySet); + if (PR_FALSE==textPropertySet) + { + nsCOMPtrnewLeftTextNode; // this will be the middle text node + if (0!=aStartOffset) { + result = nsEditor::SplitNode(aStartNode, aStartOffset, getter_AddRefs(newLeftTextNode)); + } + if (NS_SUCCEEDED(result)) + { + nsCOMPtrendNodeAsChar; + endNodeAsChar = do_QueryInterface(aEndNode); + if (!endNodeAsChar) + return NS_ERROR_FAILURE; + PRUint32 count; + endNodeAsChar->GetLength(&count); + nsCOMPtrnewRightTextNode; // this will be the middle text node + if ((PRInt32)count!=aEndOffset) { + result = nsEditor::SplitNode(aEndNode, aEndOffset, getter_AddRefs(newRightTextNode)); + } + else { + newRightTextNode = do_QueryInterface(aEndNode); + } + if (NS_SUCCEEDED(result)) + { + PRInt32 offsetInParent; + if (newLeftTextNode) { + result = nsIEditorSupport::GetChildOffset(newLeftTextNode, aParent, offsetInParent); + } + else { + offsetInParent = -1; // relies on +1 below in call to CreateNode + } + if (NS_SUCCEEDED(result)) + { + nsAutoString tag; + aPropName->ToString(tag); + // create the new style node, which will be the new parent for the selected nodes + nsCOMPtrnewStyleNode; + result = nsEditor::CreateNode(tag, aParent, offsetInParent+1, getter_AddRefs(newStyleNode)); + if (NS_SUCCEEDED(result)) + { // move the right half of the start node into the new style node + nsCOMPtrintermediateNode; + result = aStartNode->GetNextSibling(getter_AddRefs(intermediateNode)); + if (NS_SUCCEEDED(result)) + { + result = nsEditor::DeleteNode(aStartNode); + if (NS_SUCCEEDED(result)) + { + PRInt32 childIndex=0; + result = nsEditor::InsertNode(aStartNode, newStyleNode, childIndex); + childIndex++; + if (NS_SUCCEEDED(result)) + { // move all the intermediate nodes into the new style node + nsCOMPtrnextSibling; + while (intermediateNode.get() != aEndNode) + { + if (!intermediateNode) + result = NS_ERROR_NULL_POINTER; + if (NS_FAILED(result)) { + break; + } + // get the next sibling before moving the current child!!! + intermediateNode->GetNextSibling(getter_AddRefs(nextSibling)); + result = nsEditor::DeleteNode(intermediateNode); + if (NS_SUCCEEDED(result)) { + result = nsEditor::InsertNode(intermediateNode, newStyleNode, childIndex); + childIndex++; + } + intermediateNode = do_QueryInterface(nextSibling); + } + if (NS_SUCCEEDED(result)) + { // move the left half of the end node into the new style node + result = nsEditor::DeleteNode(newRightTextNode); + if (NS_SUCCEEDED(result)) + { + result = nsEditor::InsertNode(newRightTextNode, newStyleNode, childIndex); + } + } + } + } + } + } + } + } + } + } + return result; +} + +NS_IMETHODIMP +nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, + nsIDOMNode *aStartNode, + PRInt32 aStartOffset, + nsIDOMNode *aEndNode, + PRInt32 aEndOffset, + nsIDOMNode *aParent, + nsIAtom *aPropName) +{ + printf("not yet implemented\n"); + return NS_OK; + nsresult result=NS_OK; + if (!aRange || !aStartNode || !aEndNode || !aParent || !aPropName) + return NS_ERROR_NULL_POINTER; + // create a style node for the text in the start parent + nsCOMPtrparent; + result = aStartNode->GetParentNode(getter_AddRefs(parent)); + if (NS_FAILED(result)) { + return result; + } + + // create style nodes for all the content between the start and end nodes + nsCOMPtriter; + result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, + kIContentIteratorIID, getter_AddRefs(iter)); + if ((NS_SUCCEEDED(result)) && iter) + { + nsCOMPtrstartContent; + startContent = do_QueryInterface(aStartNode); + nsCOMPtrendContent; + endContent = do_QueryInterface(aEndNode); + if (startContent && endContent) + { + iter->Init(aRange); + nsCOMPtr content; + iter->CurrentNode(getter_AddRefs(content)); + nsAutoString tag; + aPropName->ToString(tag); + while (NS_COMFALSE == iter->IsDone()) + { + if ((content.get() != startContent.get()) && + (content.get() != endContent.get())) + { + nsCOMPtrcharNode; + charNode = do_QueryInterface(content); + if (charNode) + { + // only want to wrap the text node in a new style node if it doesn't already have that style + nsCOMPtrnode; + node = do_QueryInterface(content); + PRBool textPropertySet; + IsTextPropertySetByContent(node, aPropName, textPropertySet); + if (PR_FALSE==textPropertySet) + { + nsCOMPtrparent; + charNode->GetParentNode(getter_AddRefs(parent)); + if (!parent) { + return NS_ERROR_NULL_POINTER; + } + nsCOMPtrparentContent; + parentContent = do_QueryInterface(parent); + + PRInt32 offsetInParent; + parentContent->IndexOf(content, offsetInParent); + + nsCOMPtrnewStyleNode; + result = nsEditor::CreateNode(tag, parent, offsetInParent, getter_AddRefs(newStyleNode)); + if (NS_SUCCEEDED(result) && newStyleNode) { + nsCOMPtrcontentNode; + contentNode = do_QueryInterface(content); + result = nsEditor::DeleteNode(contentNode); + if (NS_SUCCEEDED(result)) { + result = nsEditor::InsertNode(contentNode, newStyleNode, 0); + } + } + } + } + } + // note we don't check the result, we just rely on iter->IsDone + iter->Next(); + result = iter->CurrentNode(getter_AddRefs(content)); + } + } + } + + nsCOMPtrnodeAsChar; + nodeAsChar = do_QueryInterface(aStartNode); + if (!nodeAsChar) + return NS_ERROR_FAILURE; + PRUint32 count; + nodeAsChar->GetLength(&count); + result = SetTextPropertiesForNode(aStartNode, parent, aStartOffset, count, aPropName); + + // create a style node for the text in the end parent + result = aEndNode->GetParentNode(getter_AddRefs(parent)); + if (NS_FAILED(result)) { + return result; + } + nodeAsChar = do_QueryInterface(aEndNode); + if (!nodeAsChar) + return NS_ERROR_FAILURE; + nodeAsChar->GetLength(&count); + result = SetTextPropertiesForNode(aEndNode, parent, 0, aEndOffset, aPropName); + + return result; +} + NS_IMETHODIMP nsTextEditor::SetTypeInStateForProperty(TypeInState &aTypeInState, nsIAtom *aPropName) { @@ -1271,7 +1759,8 @@ nsTextEditor::SetTypeInStateForProperty(TypeInState &aTypeInState, nsIAtom *aPro { // get the current style and set boldness to the opposite of the current state PRBool any = PR_FALSE; PRBool all = PR_FALSE; - GetTextProperty(aPropName, any, all); // operates on current selection + PRBool first = PR_FALSE; + GetTextProperty(aPropName, first, any, all); // operates on current selection aTypeInState.SetBold(!any); } } @@ -1285,7 +1774,8 @@ nsTextEditor::SetTypeInStateForProperty(TypeInState &aTypeInState, nsIAtom *aPro { // get the current style and set boldness to the opposite of the current state PRBool any = PR_FALSE; PRBool all = PR_FALSE; - GetTextProperty(aPropName, any, all); // operates on current selection + PRBool first = PR_FALSE; + GetTextProperty(aPropName, first, any, all); // operates on current selection aTypeInState.SetItalic(!any); } } diff --git a/mozilla/editor/base/nsTextEditor.h b/mozilla/editor/base/nsTextEditor.h index 10e050ef46c..bd25b189b02 100644 --- a/mozilla/editor/base/nsTextEditor.h +++ b/mozilla/editor/base/nsTextEditor.h @@ -52,7 +52,7 @@ public: // Editing Operations NS_IMETHOD SetTextProperty(nsIAtom *aProperty); - NS_IMETHOD GetTextProperty(nsIAtom *aProperty, PRBool &aAny, PRBool &aAll); + NS_IMETHOD GetTextProperty(nsIAtom *aProperty, PRBool &aFirst, PRBool &aAny, PRBool &aAll); NS_IMETHOD RemoveTextProperty(nsIAtom *aProperty); NS_IMETHOD DeleteSelection(nsIEditor::Direction aDir); NS_IMETHOD InsertText(const nsString& aStringToInsert); @@ -137,6 +137,28 @@ protected: nsIDOMNode *aParent, nsIAtom *aPropName); + NS_IMETHOD RemoveTextPropertiesForNode(nsIDOMNode *aNode, + nsIDOMNode *aParent, + PRInt32 aStartOffset, + PRInt32 aEndOffset, + nsIAtom *aPropName); + + NS_IMETHOD RemoveTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, + PRInt32 aStartOffset, + nsIDOMNode *aEndNode, + PRInt32 aEndOffset, + nsIDOMNode *aParent, + nsIAtom *aPropName); + + NS_IMETHOD RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, + nsIDOMNode *aStartNode, + PRInt32 aStartOffset, + nsIDOMNode *aEndNode, + PRInt32 aEndOffset, + nsIDOMNode *aParent, + nsIAtom *aPropName); + + NS_IMETHOD SetTypeInStateForProperty(TypeInState &aTypeInState, nsIAtom *aPropName); diff --git a/mozilla/editor/libeditor/base/DeleteElementTxn.cpp b/mozilla/editor/libeditor/base/DeleteElementTxn.cpp index 15b9bd004f8..8f59206fcce 100644 --- a/mozilla/editor/libeditor/base/DeleteElementTxn.cpp +++ b/mozilla/editor/libeditor/base/DeleteElementTxn.cpp @@ -50,7 +50,7 @@ DeleteElementTxn::~DeleteElementTxn() NS_IMETHODIMP DeleteElementTxn::Do(void) { - if (gNoisy) { printf("Do Delete Element element = %p\n", mElement.get()); } + if (gNoisy) { printf("%p Do Delete Element element = %p\n", this, mElement.get()); } if (!mElement) return NS_ERROR_NULL_POINTER; @@ -65,12 +65,12 @@ NS_IMETHODIMP DeleteElementTxn::Do(void) #ifdef NS_DEBUG // begin debug output nsCOMPtr element; - element = do_QueryInterface(mElement, &result); + element = do_QueryInterface(mElement); nsAutoString elementTag="text node"; if (element) element->GetTagName(elementTag); nsCOMPtr parentElement; - parentElement = do_QueryInterface(mParent, &result); + parentElement = do_QueryInterface(mParent); nsAutoString parentElementTag="text node"; if (parentElement) parentElement->GetTagName(parentElementTag); @@ -80,7 +80,7 @@ NS_IMETHODIMP DeleteElementTxn::Do(void) if (c&&p) { if (gNoisy) - printf("DeleteElementTxn: deleting child %s from parent %s\n", c, p); + printf(" DeleteElementTxn: deleting child %s from parent %s\n", c, p); delete [] c; delete [] p; } @@ -97,10 +97,35 @@ NS_IMETHODIMP DeleteElementTxn::Do(void) NS_IMETHODIMP DeleteElementTxn::Undo(void) { - if (gNoisy) { printf("Do Delete Element element = %p, parent = %p\n", mElement.get(), mParent.get()); } + if (gNoisy) { printf("%p Undo Delete Element element = %p, parent = %p\n", this, mElement.get(), mParent.get()); } if (!mParent || !mElement) return NS_ERROR_NULL_POINTER; +#ifdef NS_DEBUG + // begin debug output + nsCOMPtr element; + element = do_QueryInterface(mElement); + nsAutoString elementTag="text node"; + if (element) + element->GetTagName(elementTag); + nsCOMPtr parentElement; + parentElement = do_QueryInterface(mParent); + nsAutoString parentElementTag="text node"; + if (parentElement) + parentElement->GetTagName(parentElementTag); + char *c, *p; + c = elementTag.ToNewCString(); + p = parentElementTag.ToNewCString(); + if (c&&p) + { + if (gNoisy) + printf(" DeleteElementTxn: inserting child %s back into parent %s\n", c, p); + delete [] c; + delete [] p; + } + // end debug output +#endif + nsCOMPtr resultNode; nsresult result = mParent->InsertBefore(mElement, mRefNode, getter_AddRefs(resultNode)); return result; @@ -108,7 +133,7 @@ NS_IMETHODIMP DeleteElementTxn::Undo(void) NS_IMETHODIMP DeleteElementTxn::Redo(void) { - if (gNoisy) { printf("Redo Delete Element\n"); } + if (gNoisy) { printf("%p Redo Delete Element element = %p, parent = %p\n", this, mElement.get(), mParent.get()); } if (!mParent || !mElement) return NS_ERROR_NULL_POINTER; diff --git a/mozilla/editor/libeditor/base/DeleteRangeTxn.cpp b/mozilla/editor/libeditor/base/DeleteRangeTxn.cpp index c0014792e15..26e781e9479 100644 --- a/mozilla/editor/libeditor/base/DeleteRangeTxn.cpp +++ b/mozilla/editor/libeditor/base/DeleteRangeTxn.cpp @@ -69,7 +69,7 @@ NS_IMETHODIMP DeleteRangeTxn::Init(nsIEditor *aEditor, nsIDOMRange *aRange) { PRUint32 count; nsCOMPtr textNode; - textNode = do_QueryInterface(mStartParent, &result); + textNode = do_QueryInterface(mStartParent); if (textNode) textNode->GetLength(&count); else @@ -81,7 +81,7 @@ NS_IMETHODIMP DeleteRangeTxn::Init(nsIEditor *aEditor, nsIDOMRange *aRange) } NS_ASSERTION(mStartOffset<=(PRInt32)count, "bad start offset"); - textNode = do_QueryInterface(mEndParent, &result); + textNode = do_QueryInterface(mEndParent); if (textNode) textNode->GetLength(&count); else diff --git a/mozilla/editor/libeditor/base/DeleteTextTxn.cpp b/mozilla/editor/libeditor/base/DeleteTextTxn.cpp index 8f5b0114fdf..dd70ce357f2 100644 --- a/mozilla/editor/libeditor/base/DeleteTextTxn.cpp +++ b/mozilla/editor/libeditor/base/DeleteTextTxn.cpp @@ -36,9 +36,9 @@ DeleteTextTxn::~DeleteTextTxn() } NS_IMETHODIMP DeleteTextTxn::Init(nsIEditor *aEditor, - nsIDOMCharacterData *aElement, - PRUint32 aOffset, - PRUint32 aNumCharsToDelete) + nsIDOMCharacterData *aElement, + PRUint32 aOffset, + PRUint32 aNumCharsToDelete) { NS_ASSERTION(aEditor&&aElement, "bad arg"); mEditor = do_QueryInterface(aEditor); @@ -46,6 +46,10 @@ NS_IMETHODIMP DeleteTextTxn::Init(nsIEditor *aEditor, mOffset = aOffset; mNumCharsToDelete = aNumCharsToDelete; NS_ASSERTION(0!=aNumCharsToDelete, "bad arg, numCharsToDelete"); + PRUint32 count; + aElement->GetLength(&count); + NS_ASSERTION(countrefNode; - if (0!=mOffset) + //if (0!=mOffset) { // get a ref node PRInt32 i=0; result = mParent->GetFirstChild(getter_AddRefs(refNode)); @@ -94,7 +95,8 @@ NS_IMETHODIMP InsertElementTxn::Do(void) NS_IMETHODIMP InsertElementTxn::Undo(void) { - if (gNoisy) { printf("Undo Insert Element\n"); } + if (gNoisy) { printf("%p Undo Insert Element of %p into parent %p at offset %d\n", + this, mNode, mParent, mOffset); } if (!mNode || !mParent) return NS_ERROR_NULL_POINTER; diff --git a/mozilla/editor/libeditor/base/InsertTextTxn.cpp b/mozilla/editor/libeditor/base/InsertTextTxn.cpp index 11e9fc0ff2c..53815377329 100644 --- a/mozilla/editor/libeditor/base/InsertTextTxn.cpp +++ b/mozilla/editor/libeditor/base/InsertTextTxn.cpp @@ -135,7 +135,7 @@ NS_IMETHODIMP InsertTextTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransacti if (childTxn) { nsCOMPtr otherInsertTxn; - otherInsertTxn = do_QueryInterface(childTxn, &result); + otherInsertTxn = do_QueryInterface(childTxn); if (otherInsertTxn) { if (PR_TRUE==IsSequentialInsert(otherInsertTxn)) diff --git a/mozilla/editor/libeditor/base/SplitElementTxn.cpp b/mozilla/editor/libeditor/base/SplitElementTxn.cpp index 3c9aa43e843..045213087ca 100644 --- a/mozilla/editor/libeditor/base/SplitElementTxn.cpp +++ b/mozilla/editor/libeditor/base/SplitElementTxn.cpp @@ -23,7 +23,7 @@ #include "nsIEditorSupport.h" #ifdef NS_DEBUG -static PRBool gNoisy = PR_TRUE; +static PRBool gNoisy = PR_FALSE; #else static const PRBool gNoisy = PR_FALSE; #endif @@ -63,7 +63,7 @@ NS_IMETHODIMP SplitElementTxn::Do(void) if ((NS_SUCCEEDED(result)) && (mNewLeftNode)) { - if (gNoisy) { printf(" created left node = %p\n", this, mNewLeftNode.get()); } + if (gNoisy) { printf(" created left node = %p\n", mNewLeftNode.get()); } // get the parent node result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent)); // insert the new node @@ -103,21 +103,6 @@ NS_IMETHODIMP SplitElementTxn::Undo(void) return NS_ERROR_NOT_INITIALIZED; } -#ifdef NS_DEBUG - // sanity check - nsCOMPtrparent; - nsresult debugResult = mExistingRightNode->GetParentNode(getter_AddRefs(parent)); - NS_ASSERTION((NS_SUCCEEDED(debugResult)), "bad GetParentNode result for right child"); - NS_ASSERTION(parent, "bad GetParentNode for right child"); - NS_ASSERTION(parent==mParent, "bad GetParentNode for right child, parents don't match"); - - debugResult = mNewLeftNode->GetParentNode(getter_AddRefs(parent)); - NS_ASSERTION((NS_SUCCEEDED(debugResult)), "bad GetParentNode result for left child"); - NS_ASSERTION(parent, "bad GetParentNode for left child"); - NS_ASSERTION(parent==mParent, "bad GetParentNode for right child, left don't match"); - -#endif - // this assumes Do inserted the new node in front of the prior existing node nsresult result; nsCOMPtr editor; @@ -125,6 +110,11 @@ NS_IMETHODIMP SplitElementTxn::Undo(void) if (NS_SUCCEEDED(result) && editor) { result = editor->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE); + if (gNoisy) + { + printf("** after join left child node %p into right node %p\n", mNewLeftNode.get(), mExistingRightNode.get()); + if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG + } if (NS_SUCCEEDED(result)) { if (gNoisy) { printf(" left node = %p removed\n", this, mNewLeftNode.get()); } @@ -154,6 +144,7 @@ NS_IMETHODIMP SplitElementTxn::Redo(void) if (gNoisy) { printf("%p Redo Split of existing node %p and new node %p offset %d\n", this, mExistingRightNode.get(), mNewLeftNode.get(), mOffset); + if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG } nsresult result; nsCOMPtrresultNode; @@ -163,6 +154,11 @@ NS_IMETHODIMP SplitElementTxn::Redo(void) if (rightNodeAsText) { result = rightNodeAsText->DeleteData(0, mOffset); + if (gNoisy) + { + printf("** after delete of text in right text node %p offset %d\n", rightNodeAsText.get(), mOffset); + if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG + } } else { @@ -176,11 +172,25 @@ NS_IMETHODIMP SplitElementTxn::Redo(void) if (!child) {return NS_ERROR_NULL_POINTER;} child->GetNextSibling(getter_AddRefs(nextSibling)); result = mExistingRightNode->RemoveChild(child, getter_AddRefs(resultNode)); + if (NS_SUCCEEDED(result)) + { + result = mNewLeftNode->AppendChild(child, getter_AddRefs(resultNode)); + if (gNoisy) + { + printf("** move child node %p from right node %p to left node %p\n", child.get(), mExistingRightNode.get(), mNewLeftNode.get()); + if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG + } + } child = do_QueryInterface(nextSibling); } } // second, re-insert the left node into the tree result = mParent->InsertBefore(mNewLeftNode, mExistingRightNode, getter_AddRefs(resultNode)); + if (gNoisy) + { + printf("** reinsert left child node %p before right node %p\n", mNewLeftNode.get(), mExistingRightNode.get()); + if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG + } return result; } diff --git a/mozilla/editor/libeditor/base/nsEditor.cpp b/mozilla/editor/libeditor/base/nsEditor.cpp index d52d5f5aa78..1ecdd6bd249 100644 --- a/mozilla/editor/libeditor/base/nsEditor.cpp +++ b/mozilla/editor/libeditor/base/nsEditor.cpp @@ -1128,7 +1128,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForInsertText(const nsString & aStringToInsert, { result = NS_ERROR_UNEXPECTED; nsCOMPtr enumerator; - enumerator = do_QueryInterface(selection,&result); + enumerator = do_QueryInterface(selection); if (enumerator) { enumerator->First(); @@ -1144,8 +1144,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForInsertText(const nsString & aStringToInsert, result = range->GetStartParent(getter_AddRefs(node)); if ((NS_SUCCEEDED(result)) && (node)) { - result = NS_ERROR_UNEXPECTED; - nodeAsText = do_QueryInterface(node,&result); + nodeAsText = do_QueryInterface(node); range->GetStartOffset(&offset); if (!nodeAsText) { result = NS_ERROR_EDITOR_NO_TEXTNODE; @@ -1451,7 +1450,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForDeleteSelection(nsIEditor::Direction aDir, if ((NS_SUCCEEDED(result)) && selection) { nsCOMPtr enumerator; - enumerator = do_QueryInterface(selection,&result); + enumerator = do_QueryInterface(selection); if (enumerator) { for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next()) @@ -1553,7 +1552,7 @@ nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange, { // there is a priorNode, so delete it's last child (if text content, delete the last char.) // if it has no children, delete it nsCOMPtr priorNodeAsText; - priorNodeAsText = do_QueryInterface(priorNode, &result); + priorNodeAsText = do_QueryInterface(priorNode); if (priorNodeAsText) { PRUint32 length=0; @@ -1590,7 +1589,7 @@ nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange, { // there is a priorNode, so delete it's last child (if text content, delete the last char.) // if it has no children, delete it nsCOMPtr nextNodeAsText; - nextNodeAsText = do_QueryInterface(nextNode,&result); + nextNodeAsText = do_QueryInterface(nextNode); if (nextNodeAsText) { PRUint32 length=0; @@ -1815,6 +1814,9 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, nsIDOMNode* aNewLeftNode, nsIDOMNode* aParent) { + +printf("SplitNodeImpl: left=%p, right=%p, offset=%d\n", aNewLeftNode, aExistingRightNode, aOffset); + nsresult result; NS_ASSERTION(((nsnull!=aExistingRightNode) && (nsnull!=aNewLeftNode) && @@ -1826,6 +1828,7 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, { nsCOMPtr resultNode; result = aParent->InsertBefore(aNewLeftNode, aExistingRightNode, getter_AddRefs(resultNode)); + //printf(" after insert\n"); content->List(); // DEBUG if (NS_SUCCEEDED(result)) { // split the children between the 2 nodes @@ -1847,21 +1850,26 @@ nsEditor::SplitNodeImpl(nsIDOMNode * aExistingRightNode, } else { // otherwise it's an interior node, so shuffle around the children + // go through list backwards so deletes don't interfere with the iteration nsCOMPtr childNodes; result = aExistingRightNode->GetChildNodes(getter_AddRefs(childNodes)); if ((NS_SUCCEEDED(result)) && (childNodes)) { - PRInt32 i=0; - for ( ; ((NS_SUCCEEDED(result)) && (i childNode; result = childNodes->Item(i, getter_AddRefs(childNode)); if ((NS_SUCCEEDED(result)) && (childNode)) { result = aExistingRightNode->RemoveChild(childNode, getter_AddRefs(resultNode)); + //printf(" after remove\n"); content->List(); // DEBUG if (NS_SUCCEEDED(result)) { - result = aNewLeftNode->AppendChild(childNode, getter_AddRefs(resultNode)); + nsCOMPtr firstChild; + aNewLeftNode->GetFirstChild(getter_AddRefs(firstChild)); + result = aNewLeftNode->InsertBefore(childNode, firstChild, getter_AddRefs(resultNode)); + //printf(" after append\n"); content->List(); // DEBUG } } } @@ -1917,7 +1925,7 @@ nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, result = aNodeToJoin->GetChildNodes(getter_AddRefs(childNodes)); if ((NS_SUCCEEDED(result)) && (childNodes)) { - PRUint32 i; + PRInt32 i; // must be signed int! PRUint32 childCount=0; childNodes->GetLength(&childCount); nsCOMPtr firstNode; //only used if aNodeToKeepIsFirst is false @@ -1927,7 +1935,9 @@ nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, // GetFirstChild returns nsnull firstNode if aNodeToKeep has no children, that's ok. } nsCOMPtr resultNode; - for (i=0; ((NS_SUCCEEDED(result)) && (i previousChild; + for (i=childCount-1; ((NS_SUCCEEDED(result)) && (0<=i)); i--) { nsCOMPtr childNode; result = childNodes->Item(i, getter_AddRefs(childNode)); @@ -1935,11 +1945,15 @@ nsEditor::JoinNodesImpl(nsIDOMNode * aNodeToKeep, { if (PR_TRUE==aNodeToKeepIsFirst) { // append children of aNodeToJoin - result = aNodeToKeep->AppendChild(childNode, getter_AddRefs(resultNode)); + //was result = aNodeToKeep->AppendChild(childNode, getter_AddRefs(resultNode)); + result = aNodeToKeep->InsertBefore(childNode, previousChild, getter_AddRefs(resultNode)); + previousChild = do_QueryInterface(childNode); } else { // prepend children of aNodeToJoin + //was result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode)); result = aNodeToKeep->InsertBefore(childNode, firstNode, getter_AddRefs(resultNode)); + firstNode = do_QueryInterface(childNode); } } } @@ -2047,6 +2061,28 @@ NS_IMETHODIMP nsEditor::GetLayoutObject(nsIDOMNode *aNode, nsISupports **aLayout return result; } +NS_IMETHODIMP +nsEditor::DebugDumpContent() const +{ + nsCOMPtrcontent; + nsCOMPtrnodeList; + nsAutoString bodyTag = "body"; + mDoc->GetElementsByTagName(bodyTag, getter_AddRefs(nodeList)); + if (nodeList) + { + PRUint32 count; + nodeList->GetLength(&count); + NS_ASSERTION(1==count, "there is not exactly 1 body in the document!"); + nsCOMPtrbodyNode; + nodeList->Item(0, getter_AddRefs(bodyNode)); + if (bodyNode) { + content = do_QueryInterface(bodyNode); + } + } + content->List(); + return NS_OK; +} + //END nsEditor Private methods diff --git a/mozilla/editor/libeditor/base/nsEditor.h b/mozilla/editor/libeditor/base/nsEditor.h index 4fdd84d79eb..93529ea5cdf 100644 --- a/mozilla/editor/libeditor/base/nsEditor.h +++ b/mozilla/editor/libeditor/base/nsEditor.h @@ -60,13 +60,15 @@ private: nsIPresShell *mPresShell; nsIViewManager *mViewManager; PRUint32 mUpdateCount; - nsCOMPtr mDoc; nsCOMPtr mTxnMgr; friend PRBool NSCanUnload(nsISupports* serviceMgr); static PRInt32 gInstanceCount; +protected: + nsCOMPtr mDoc; + public: /** The default constructor. This should suffice. the setting of the interfaces is done * after the construction of the editor class. @@ -278,8 +280,6 @@ protected: NS_IMETHOD GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode); -//Methods not exposed in nsIEditor - /** Create an aggregate transaction for deleting current selection * Used by all methods that need to delete current selection, * then insert something new to replace it @@ -290,6 +290,8 @@ protected: */ NS_IMETHOD CreateAggregateTxnForDeleteSelection(nsIAtom *aTxnName, EditAggregateTxn **aAggTxn); + NS_IMETHOD DebugDumpContent() const; + protected: // XXXX: Horrible hack! We are doing this because // of an error in Gecko which is not rendering the diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp index 1255cda6236..772c876bdc4 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp @@ -113,9 +113,9 @@ NS_IMETHODIMP nsHTMLEditor::SetTextProperty(nsIAtom *aProperty) return nsTextEditor::SetTextProperty(aProperty); } -NS_IMETHODIMP nsHTMLEditor::GetTextProperty(nsIAtom *aProperty, PRBool &aAny, PRBool &aAll) +NS_IMETHODIMP nsHTMLEditor::GetTextProperty(nsIAtom *aProperty, PRBool &aFirst, PRBool &aAny, PRBool &aAll) { - return nsTextEditor::GetTextProperty(aProperty, aAny, aAll); + return nsTextEditor::GetTextProperty(aProperty, aFirst, aAny, aAll); } NS_IMETHODIMP nsHTMLEditor::RemoveTextProperty(nsIAtom *aProperty) diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h index dae03c1308f..f2d9d111281 100644 --- a/mozilla/editor/libeditor/html/nsHTMLEditor.h +++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h @@ -51,7 +51,7 @@ public: // Editing Operations NS_IMETHOD SetTextProperty(nsIAtom *aProperty); - NS_IMETHOD GetTextProperty(nsIAtom *aProperty, PRBool &aAny, PRBool &aAll); + NS_IMETHOD GetTextProperty(nsIAtom *aProperty, PRBool &aFirst, PRBool &aAny, PRBool &aAll); NS_IMETHOD RemoveTextProperty(nsIAtom *aProperty); NS_IMETHOD DeleteSelection(nsIEditor::Direction aDir); NS_IMETHOD InsertText(const nsString& aStringToInsert); diff --git a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp index 2e548a9157c..964451b6ea2 100644 --- a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp +++ b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp @@ -310,7 +310,18 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr aProcessed=PR_TRUE; if (mEditor) { - mEditor->SetTextProperty(nsIEditProperty::i); + // XXX: move this logic down into texteditor rules delegate + // should just call mEditor->ChangeTextProperty(prop) + PRBool any = PR_FALSE; + PRBool all = PR_FALSE; + PRBool first = PR_FALSE; + mEditor->GetTextProperty(nsIEditProperty::i, first, any, all); + if (PR_FALSE==first) { + mEditor->SetTextProperty(nsIEditProperty::i); + } + else { + mEditor->RemoveTextProperty(nsIEditProperty::i); + } } } @@ -336,7 +347,18 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr aProcessed=PR_TRUE; if (mEditor) { - mEditor->SetTextProperty(nsIEditProperty::b); + // XXX: move this logic down into texteditor rules delegate + // should just call mEditor->ChangeTextProperty(prop) + PRBool any = PR_FALSE; + PRBool all = PR_FALSE; + PRBool first = PR_FALSE; + mEditor->GetTextProperty(nsIEditProperty::b, first, any, all); + if (PR_FALSE==first) { + mEditor->SetTextProperty(nsIEditProperty::b); + } + else { + mEditor->RemoveTextProperty(nsIEditProperty::b); + } } } break; @@ -348,7 +370,19 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr aProcessed=PR_TRUE; if (mEditor) { - mEditor->SetTextProperty(nsIEditProperty::u); + // XXX: move this logic down into texteditor rules delegate + // should just call mEditor->ChangeTextProperty(prop) + PRBool any = PR_FALSE; + PRBool all = PR_FALSE; + PRBool first = PR_FALSE; + mEditor->GetTextProperty(nsIEditProperty::u, first, any, all); + if (PR_FALSE==first) { + mEditor->SetTextProperty(nsIEditProperty::u); + } + else { + mEditor->RemoveTextProperty(nsIEditProperty::u); + } + } } break;