From 3c2f906370aa3f8422a8436387ae15fc32244051 Mon Sep 17 00:00:00 2001 From: "buster%netscape.com" Date: Fri, 16 Apr 1999 18:29:12 +0000 Subject: [PATCH] factored out re-parenting of content into MoveContentIntoNewParent WIP on font handling. --- editor/base/ChangeAttributeTxn.cpp | 8 +- editor/base/TypeInState.h | 29 ++- editor/base/nsEditProperty.cpp | 15 ++ editor/base/nsEditorEventListeners.cpp | 4 +- editor/base/nsIEditProperty.h | 5 + editor/base/nsTextEditRules.cpp | 46 +++- editor/base/nsTextEditRules.h | 9 +- editor/base/nsTextEditor.cpp | 224 +++++++++++++----- editor/base/nsTextEditor.h | 57 ++++- editor/libeditor/base/ChangeAttributeTxn.cpp | 8 +- editor/libeditor/base/nsIEditProperty.h | 5 + editor/libeditor/html/TypeInState.h | 29 ++- editor/libeditor/html/nsEditProperty.cpp | 15 ++ .../libeditor/text/nsEditorEventListeners.cpp | 4 +- editor/libeditor/text/nsTextEditRules.cpp | 46 +++- editor/libeditor/text/nsTextEditRules.h | 9 +- 16 files changed, 370 insertions(+), 143 deletions(-) diff --git a/editor/base/ChangeAttributeTxn.cpp b/editor/base/ChangeAttributeTxn.cpp index 8f37b19645bf..f308c194d760 100644 --- a/editor/base/ChangeAttributeTxn.cpp +++ b/editor/base/ChangeAttributeTxn.cpp @@ -30,10 +30,10 @@ ChangeAttributeTxn::~ChangeAttributeTxn() } NS_IMETHODIMP ChangeAttributeTxn::Init(nsIEditor *aEditor, - nsIDOMElement *aElement, - const nsString& aAttribute, - const nsString& aValue, - PRBool aRemoveAttribute) + nsIDOMElement *aElement, + const nsString& aAttribute, + const nsString& aValue, + PRBool aRemoveAttribute) { if (nsnull!=aEditor && nsnull!=aElement) { diff --git a/editor/base/TypeInState.h b/editor/base/TypeInState.h index 7953d86fdcfa..81635f763f80 100644 --- a/editor/base/TypeInState.h +++ b/editor/base/TypeInState.h @@ -20,8 +20,6 @@ #define ChangeAttributeTxn_h__ #include "nsIDOMSelectionListener.h" -#include "nsColor.h" -#include "nsCoord.h" class TypeInState : public nsIDOMSelectionListener { @@ -51,19 +49,19 @@ public: void SetFontFace(nsString aFace); nsString GetFontFace(); - void SetFontColor(nscolor aColor); - nscolor GetFontColor(); + void SetFontColor(nsString aColor); + nsString GetFontColor(); - void SetFontSize(nscoord aFontSize); - nscoord GetFontSize(); + void SetFontSize(nsString aFontSize); + nsString GetFontSize(); protected: PRBool mBold; PRBool mItalic; PRBool mUnderline; nsString mFontFace; - nscolor mFontColor; - nscoord mFontSize; + nsString mFontColor; + nsString mFontSize; PRUint32 mIsSet; }; @@ -81,8 +79,6 @@ void TypeInState::Reset() mBold = PR_FALSE; mItalic = PR_FALSE; mUnderline = PR_FALSE; - mFontColor = NS_RGB(0,0,0); - mFontSize = 0; mIsSet = 0; }; @@ -96,7 +92,10 @@ TypeInState::TypeInState() inline PRBool TypeInState::IsSet(PRUint32 aStyle) { - return (PRBool)(mIsSet & aStyle); + if ((PRBool)(mIsSet & aStyle)) + return PR_TRUE; + else + return PR_FALSE; }; inline @@ -156,25 +155,25 @@ nsString TypeInState::GetFontFace() { return mFontFace; }; inline -void TypeInState::SetFontColor(nscolor aColor) +void TypeInState::SetFontColor(nsString aColor) { mFontColor = aColor; mIsSet |= NS_TYPEINSTATE_FONTCOLOR; }; inline -nscolor TypeInState::GetFontColor() +nsString TypeInState::GetFontColor() { return mFontColor; }; inline -void TypeInState::SetFontSize(nscoord aSize) +void TypeInState::SetFontSize(nsString aSize) { mFontSize = aSize; mIsSet |= NS_TYPEINSTATE_FONTSIZE; }; inline -nscoord TypeInState::GetFontSize() +nsString TypeInState::GetFontSize() { return mFontSize; }; diff --git a/editor/base/nsEditProperty.cpp b/editor/base/nsEditProperty.cpp index cb5d034fe551..10ac12452ff6 100644 --- a/editor/base/nsEditProperty.cpp +++ b/editor/base/nsEditProperty.cpp @@ -41,6 +41,11 @@ nsIAtom * nsIEditProperty::sub; nsIAtom * nsIEditProperty::sup; nsIAtom * nsIEditProperty::tt; nsIAtom * nsIEditProperty::u; +// properties +nsIAtom * nsIEditProperty::color; +nsIAtom * nsIEditProperty::face; +nsIAtom * nsIEditProperty::size; +// special nsString * nsIEditProperty::allProperties; void @@ -59,6 +64,11 @@ nsEditProperty::InstanceInit() nsIEditProperty::sup = NS_NewAtom("SUP"); nsIEditProperty::tt = NS_NewAtom("TT"); nsIEditProperty::u = NS_NewAtom("U"); + // properties + nsIEditProperty::color= NS_NewAtom("COLOR"); + nsIEditProperty::face = NS_NewAtom("FACE"); + nsIEditProperty::size = NS_NewAtom("SIZE"); + // special nsIEditProperty::allProperties = new nsString("moz_AllProperties"); } @@ -78,6 +88,11 @@ nsEditProperty::InstanceShutdown() NS_IF_RELEASE(nsIEditProperty::sup); NS_IF_RELEASE(nsIEditProperty::tt); NS_IF_RELEASE(nsIEditProperty::u); + // properties + NS_IF_RELEASE(nsIEditProperty::color); + NS_IF_RELEASE(nsIEditProperty::face); + NS_IF_RELEASE(nsIEditProperty::size); + // special if (nsIEditProperty::allProperties) { delete (nsIEditProperty::allProperties); } diff --git a/editor/base/nsEditorEventListeners.cpp b/editor/base/nsEditorEventListeners.cpp index eb42d0ce72cd..22211dbe3eb2 100644 --- a/editor/base/nsEditorEventListeners.cpp +++ b/editor/base/nsEditorEventListeners.cpp @@ -428,7 +428,7 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr PRBool any = PR_FALSE; PRBool all = PR_FALSE; PRBool first = PR_FALSE; - nsAutoString color = "color"; + nsAutoString color = "COLOR"; nsAutoString value = "red"; mEditor->SetTextProperty(nsIEditProperty::font, &color, &value); } @@ -447,7 +447,7 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr PRBool any = PR_FALSE; PRBool all = PR_FALSE; PRBool first = PR_FALSE; - nsAutoString color = "color"; + nsAutoString color = "COLOR"; nsAutoString value = "green"; mEditor->SetTextProperty(nsIEditProperty::font, &color, &value); } diff --git a/editor/base/nsIEditProperty.h b/editor/base/nsIEditProperty.h index 502a26a4f89f..b7c0875ec7e1 100644 --- a/editor/base/nsIEditProperty.h +++ b/editor/base/nsIEditProperty.h @@ -71,6 +71,11 @@ SUB places text in subscript style SUP places text in superscript style */ + /** properties */ + static nsIAtom *color; + static nsIAtom *face; + static nsIAtom *size; + /** special strings */ static nsString *allProperties; // this magic string represents the union of all inline style tags diff --git a/editor/base/nsTextEditRules.cpp b/editor/base/nsTextEditRules.cpp index 66ced789f283..f048b5e699dc 100644 --- a/editor/base/nsTextEditRules.cpp +++ b/editor/base/nsTextEditRules.cpp @@ -297,10 +297,11 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta // create style nodes or move it up the content hierarchy as needed. if ((NS_SUCCEEDED(result)) && newTextNode) { + nsCOMPtrnewStyleNode; if (aTypeInState.IsSet(NS_TYPEINSTATE_BOLD)) { if (PR_TRUE==aTypeInState.GetBold()) { - InsertStyleNode(newTextNode, nsIEditProperty::b, aSelection); + result = InsertStyleNode(newTextNode, nsIEditProperty::b, aSelection, getter_AddRefs(newStyleNode)); } else { printf("not yet implemented, make not bold in a bold context\n"); @@ -309,7 +310,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta if (aTypeInState.IsSet(NS_TYPEINSTATE_ITALIC)) { if (PR_TRUE==aTypeInState.GetItalic()) { - InsertStyleNode(newTextNode, nsIEditProperty::i, aSelection); + result = InsertStyleNode(newTextNode, nsIEditProperty::i, aSelection, getter_AddRefs(newStyleNode)); } else { @@ -318,14 +319,36 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta } if (aTypeInState.IsSet(NS_TYPEINSTATE_UNDERLINE)) { - if (PR_TRUE==aTypeInState.GetUnderline()) { - InsertStyleNode(newTextNode, nsIEditProperty::u, aSelection); + if (PR_TRUE==aTypeInState.GetUnderline()) { + result = InsertStyleNode(newTextNode, nsIEditProperty::u, aSelection, getter_AddRefs(newStyleNode)); } else { printf("not yet implemented, make not underline in an underline context\n"); } } + if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTCOLOR)) + { + nsAutoString fontColor; + fontColor = aTypeInState.GetFontColor(); + if (0!=fontColor.Length()) { + result = InsertStyleNode(newTextNode, nsIEditProperty::font, aSelection, getter_AddRefs(newStyleNode)); + if (NS_SUCCEEDED(result) && newStyleNode) + { + nsCOMPtrelement = do_QueryInterface(newStyleNode); + if (element) + { + nsAutoString attr; + nsIEditProperty::color->ToString(attr); + result = mEditor->SetAttribute(element, attr, fontColor); + } + } + } + else + { + printf("not yet implemented, make not font in an font context\n"); + } + } } } else @@ -374,7 +397,10 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta } nsresult -nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode, nsIAtom *aTag, nsIDOMSelection *aSelection) +nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode, + nsIAtom *aTag, + nsIDOMSelection *aSelection, + nsIDOMNode **aNewNode) { NS_ASSERTION(aNode && aTag, "bad args"); if (!aNode || !aTag) { return NS_ERROR_NULL_POINTER; } @@ -386,14 +412,13 @@ nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode, nsIAtom *aTag, nsIDOMSelecti nsIEditorSupport::GetChildOffset(aNode, parent, offsetInParent); nsAutoString tag; aTag->ToString(tag); - nsCOMPtrnewStyleNode; - result = mEditor->CreateNode(tag, parent, offsetInParent, getter_AddRefs(newStyleNode)); - if ((NS_SUCCEEDED(result)) && newStyleNode) + result = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode); + if ((NS_SUCCEEDED(result)) && *aNewNode) { result = mEditor->DeleteNode(aNode); if (NS_SUCCEEDED(result)) { - result = mEditor->InsertNode(aNode, newStyleNode, 0); + result = mEditor->InsertNode(aNode, *aNewNode, 0); if (NS_SUCCEEDED(result)) { if (aSelection) { aSelection->Collapse(aNode, 0); @@ -424,7 +449,8 @@ nsTextEditRules::InsertStyleAndNewTextNode(nsIDOMNode *aParentNode, nsIAtom *aTa anchorAsText = do_QueryInterface(anchor); if (anchorAsText) { - result = InsertStyleNode(anchor, aTag, aSelection); + nsCOMPtr newStyleNode; + result = InsertStyleNode(anchor, aTag, aSelection, getter_AddRefs(newStyleNode)); return result; } } diff --git a/editor/base/nsTextEditRules.h b/editor/base/nsTextEditRules.h index af6a28de626c..d23533e92f06 100644 --- a/editor/base/nsTextEditRules.h +++ b/editor/base/nsTextEditRules.h @@ -91,10 +91,13 @@ protected: /** insert aNode into a new style node of type aTag. * aSelection is optional. If provided, aSelection is set to (aNode, 0) * if aNode was successfully placed in a new style node + * @param aNewStyleNode [OUT] The newly created style node, if result is successful + * undefined if result is a failure. */ - nsresult InsertStyleNode(nsIDOMNode *aNode, - nsIAtom *aTag, - nsIDOMSelection *aSelection); + nsresult InsertStyleNode(nsIDOMNode *aNode, + nsIAtom *aTag, + nsIDOMSelection *aSelection, + nsIDOMNode **aNewStyleNode); /** create a new style node of type aTag in aParentNode, and put a new text node * in the new style node. diff --git a/editor/base/nsTextEditor.cpp b/editor/base/nsTextEditor.cpp index 528ac8cd065c..afd3f0cae32e 100644 --- a/editor/base/nsTextEditor.cpp +++ b/editor/base/nsTextEditor.cpp @@ -331,7 +331,7 @@ NS_IMETHODIMP nsTextEditor::SetTextProperty(nsIAtom *aProperty, if (PR_TRUE==isCollapsed) { // manipulating text attributes on a collapsed selection only sets state for the next text insertion - SetTypeInStateForProperty(mTypeInState, aProperty, aAttribute); + SetTypeInStateForProperty(mTypeInState, aProperty, aAttribute, aValue); } else { @@ -393,7 +393,7 @@ NS_IMETHODIMP nsTextEditor::SetTextProperty(nsIAtom *aProperty, { result = IntermediateNodesAreInline(range, startParent, startOffset, endParent, endOffset, - startGrandParent, canCollapseStyleNode); + canCollapseStyleNode); } if (NS_SUCCEEDED(result)) { @@ -464,6 +464,8 @@ NS_IMETHODIMP nsTextEditor::GetTextProperty(nsIAtom *aProperty, result = nsEditor::GetSelection(getter_AddRefs(selection)); if ((NS_SUCCEEDED(result)) && selection) { + PRBool isCollapsed; + selection->GetIsCollapsed(&isCollapsed); nsCOMPtr enumerator; enumerator = do_QueryInterface(selection); if (enumerator) @@ -497,7 +499,7 @@ NS_IMETHODIMP nsTextEditor::GetTextProperty(nsIAtom *aProperty, if (text) { PRBool skipNode = PR_FALSE; - if (PR_TRUE==first && PR_TRUE==firstNodeInRange) + if (PR_FALSE==isCollapsed && PR_TRUE==first && PR_TRUE==firstNodeInRange) { firstNodeInRange = PR_FALSE; PRInt32 startOffset; @@ -540,6 +542,9 @@ NS_IMETHODIMP nsTextEditor::GetTextProperty(nsIAtom *aProperty, } } } + if (PR_FALSE==aAny) { // make sure that if none of the selection is set, we don't report all is set + aAll = PR_FALSE; + } if (gNoisy) { printf(" returning first=%d any=%d all=%d\n", aFirst, aAny, aAll); } return result; } @@ -653,7 +658,7 @@ NS_IMETHODIMP nsTextEditor::RemoveTextProperty(nsIAtom *aProperty, const nsStrin if (PR_TRUE==isCollapsed) { // manipulating text attributes on a collapsed selection only sets state for the next text insertion - SetTypeInStateForProperty(mTypeInState, aProperty, aAttribute); + SetTypeInStateForProperty(mTypeInState, aProperty, aAttribute, nsnull); } else { @@ -699,7 +704,7 @@ NS_IMETHODIMP nsTextEditor::RemoveTextProperty(nsIAtom *aProperty, const nsStrin { result = IntermediateNodesAreInline(range, startParent, startOffset, endParent, endOffset, - startGrandParent, canCollapseStyleNode); + canCollapseStyleNode); } if (NS_SUCCEEDED(result)) { @@ -713,8 +718,7 @@ NS_IMETHODIMP nsTextEditor::RemoveTextProperty(nsIAtom *aProperty, const nsStrin } else { // the range is between 2 nodes that have no simple relationship - result = RemoveTextPropertiesForNodeWithDifferentParents(range, - startParent,startOffset, + result = RemoveTextPropertiesForNodeWithDifferentParents(startParent,startOffset, endParent, endOffset, commonParent, aProperty, nsnull); @@ -1126,6 +1130,7 @@ NS_IMETHODIMP nsTextEditor::SetTextPropertiesForNode(nsIDOMNode *aNode, { if (gNoisy) { printf("nsTextEditor::SetTextPropertyForNode\n"); } nsresult result=NS_OK; + // verify that aNode is a text node nsCOMPtrnodeAsChar; nodeAsChar = do_QueryInterface(aNode); if (!nodeAsChar) @@ -1136,90 +1141,118 @@ NS_IMETHODIMP nsTextEditor::SetTextPropertiesForNode(nsIDOMNode *aNode, IsTextPropertySetByContent(aNode, aPropName, aAttribute, aValue, textPropertySet, getter_AddRefs(resultNode)); if (PR_FALSE==textPropertySet) { - PRUint32 count; - nodeAsChar->GetLength(&count); + nsAutoString tag; + aPropName->ToString(tag); + if (NS_SUCCEEDED(result)) + { + nsCOMPtrnewStyleNode; + result = MoveContentIntoNewParent(aNode, aParent, aStartOffset, aEndOffset, tag, getter_AddRefs(newStyleNode)); + if (NS_SUCCEEDED(result) && newStyleNode) + { + if (aAttribute) + { + nsCOMPtr newStyleElement; + newStyleElement = do_QueryInterface(newStyleNode); + nsAutoString value; + if (aValue) { + value = *aValue; + } + // XXX should be a call to editor to change attribute! + result = newStyleElement->SetAttribute(*aAttribute, value); + } + } + } + } + return result; +} - nsCOMPtrnewTextNode; // this will be the text node we move into the new style node +NS_IMETHODIMP nsTextEditor::MoveContentIntoNewParent(nsIDOMNode *aNode, + nsIDOMNode *aOldParentNode, + PRInt32 aStartOffset, + PRInt32 aEndOffset, + nsString aTag, + nsIDOMNode **aNewNode) +{ + if (gNoisy) { printf("nsTextEditor::MoveContentIntoNewParent\n"); } + nsresult result=NS_OK; + + PRUint32 count; + result = GetLengthOfDOMNode(aNode, count); + + if (NS_SUCCEEDED(result)) + { + nsCOMPtrnewChildNode; // this will be the child node we move into the new style node // split the node at the start offset unless the split would create an empty node if (aStartOffset!=0) { - result = nsEditor::SplitNode(aNode, aStartOffset, getter_AddRefs(newTextNode)); - if (gNoisy) { printf("* split created left node %p\n", newTextNode.get());} + result = nsEditor::SplitNode(aNode, aStartOffset, getter_AddRefs(newChildNode)); + if (gNoisy) { printf("* split created left node %p\n", newChildNode.get());} if (gNoisy) {DebugDumpContent(); } // DEBUG } if (NS_SUCCEEDED(result)) { if (aEndOffset!=(PRInt32)count) { - result = nsEditor::SplitNode(aNode, aEndOffset-aStartOffset, getter_AddRefs(newTextNode)); - if (gNoisy) { printf("* split created left node %p\n", newTextNode.get());} + result = nsEditor::SplitNode(aNode, aEndOffset-aStartOffset, getter_AddRefs(newChildNode)); + if (gNoisy) { printf("* split created left node %p\n", newChildNode.get());} if (gNoisy) {DebugDumpContent(); } // DEBUG } else { - newTextNode = do_QueryInterface(aNode); - if (gNoisy) { printf("* second split not required, new text node set to aNode = %p\n", newTextNode.get());} + newChildNode = do_QueryInterface(aNode); + if (gNoisy) { printf("* second split not required, new text node set to aNode = %p\n", newChildNode.get());} } if (NS_SUCCEEDED(result)) { // optimization: if all we're doing is changing a value for an existing attribute for the // entire selection, then just twiddle the existing style node PRBool done = PR_FALSE; // set to true in optimized case if we can really do the optimization + /* if (aAttribute && aValue && (0==aStartOffset) && (aEndOffset==(PRInt32)count)) { // ??? can we really compute this? } + */ if (PR_FALSE==done) { - nsCOMPtrnewTextNodeAsChar; - newTextNodeAsChar = do_QueryInterface(newTextNode); - PRUint32 newTextNodeLength; - newTextNodeAsChar->GetLength(&newTextNodeLength); - if (0==newTextNodeLength) + // if we've ended up with an empty text node, just delete it and we're done + nsCOMPtrnewChildNodeAsChar; + newChildNodeAsChar = do_QueryInterface(newChildNode); + PRUint32 newChildNodeLength; + if (newChildNodeAsChar) { - result = nsEditor::DeleteNode(newTextNode); + newChildNodeAsChar->GetLength(&newChildNodeLength); + if (0==newChildNodeLength) + { + result = nsEditor::DeleteNode(newChildNode); + done = PR_TRUE; + } } - else + // move the new child node into the new parent + if (PR_FALSE==done) { - nsAutoString tag; - aPropName->ToString(tag); PRInt32 offsetInParent; - result = nsIEditorSupport::GetChildOffset(aNode, aParent, offsetInParent); + result = nsIEditorSupport::GetChildOffset(aNode, aOldParentNode, offsetInParent); if (NS_SUCCEEDED(result)) { - nsCOMPtrnewStyleNode; - result = nsEditor::CreateNode(tag, aParent, offsetInParent, getter_AddRefs(newStyleNode)); - if (NS_SUCCEEDED(result) && newStyleNode) + result = nsEditor::CreateNode(aTag, aOldParentNode, offsetInParent, aNewNode); + if (NS_SUCCEEDED(result) && *aNewNode) { - if (gNoisy) { printf("* created new style node %p\n", newStyleNode.get());} + if (gNoisy) { printf("* created new style node %p\n", *aNewNode);} if (gNoisy) {DebugDumpContent(); } // DEBUG - if (aAttribute) + result = nsEditor::DeleteNode(newChildNode); + if (NS_SUCCEEDED(result)) { - nsCOMPtr newStyleElement; - newStyleElement = do_QueryInterface(newStyleNode); - nsAutoString value; - if (aValue) { - value = *aValue; - } - // XXX should be a call to editor to change attribute! - result = newStyleElement->SetAttribute(*aAttribute, value); - } - if (NS_SUCCEEDED(result)) - { - result = nsEditor::DeleteNode(newTextNode); + result = nsEditor::InsertNode(newChildNode, *aNewNode, 0); if (NS_SUCCEEDED(result)) - { - result = nsEditor::InsertNode(newTextNode, newStyleNode, 0); + { // set the selection + nsCOMPtrselection; + result = nsEditor::GetSelection(getter_AddRefs(selection)); if (NS_SUCCEEDED(result)) - { // set the selection - nsCOMPtrselection; - result = nsEditor::GetSelection(getter_AddRefs(selection)); - if (NS_SUCCEEDED(result)) - { - selection->Collapse(newTextNode, 0); - PRInt32 endOffset = aEndOffset-aStartOffset; - selection->Extend(newTextNode, endOffset); - } + { + selection->Collapse(newChildNode, 0); + PRInt32 endOffset = aEndOffset-aStartOffset; + selection->Extend(newChildNode, endOffset); } } } @@ -1233,6 +1266,34 @@ NS_IMETHODIMP nsTextEditor::SetTextPropertiesForNode(nsIDOMNode *aNode, return result; } +// returns the number of things inside aNode. +// If aNode is text, returns number of characters. If not, returns number of children nodes. +NS_IMETHODIMP nsTextEditor::GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount) const +{ + aCount = 0; + if (!aNode) { return NS_ERROR_NULL_POINTER; } + nsresult result=NS_OK; + nsCOMPtrnodeAsChar; + nodeAsChar = do_QueryInterface(aNode); + if (nodeAsChar) { + nodeAsChar->GetLength(&aCount); + } + else + { + PRBool hasChildNodes; + aNode->HasChildNodes(&hasChildNodes); + if (PR_TRUE==hasChildNodes) + { + nsCOMPtrnodeList; + result = aNode->GetChildNodes(getter_AddRefs(nodeList)); + if (NS_SUCCEEDED(result) && nodeList) { + nodeList->GetLength(&aCount); + } + } + } + return result; +} + // content-based inline vs. block query NS_IMETHODIMP nsTextEditor::IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline) const { @@ -1277,11 +1338,10 @@ nsTextEditor::IntermediateNodesAreInline(nsIDOMRange *aRange, PRInt32 aStartOffset, nsIDOMNode *aEndNode, PRInt32 aEndOffset, - nsIDOMNode *aParent, PRBool &aResult) const { aResult = PR_TRUE; // init out param. we assume the condition is true unless we find a node that violates it - if (!aStartNode || !aEndNode || !aParent) { return NS_ERROR_NULL_POINTER; } + if (!aStartNode || !aEndNode || !aRange) { return NS_ERROR_NULL_POINTER; } nsCOMPtriter; nsresult result; @@ -1852,8 +1912,7 @@ nsTextEditor::RemoveTextPropertiesForNodesWithSameParent(nsIDOMNode *aStartNode, } NS_IMETHODIMP -nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, - nsIDOMNode *aStartNode, +nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStartNode, PRInt32 aStartOffset, nsIDOMNode *aEndNode, PRInt32 aEndOffset, @@ -1863,7 +1922,7 @@ nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRang { if (gNoisy) { printf("nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents\n"); } nsresult result=NS_OK; - if (!aRange || !aStartNode || !aEndNode || !aParent || !aPropName) + if (!aStartNode || !aEndNode || !aParent || !aPropName) return NS_ERROR_NULL_POINTER; PRInt32 rangeStartOffset = aStartOffset; // used to construct a range for the nodes between @@ -2041,7 +2100,8 @@ nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRang NS_IMETHODIMP nsTextEditor::SetTypeInStateForProperty(TypeInState &aTypeInState, nsIAtom *aPropName, - const nsString *aAttribute) + const nsString *aAttribute, + const nsString *aValue) { if (!aPropName) { return NS_ERROR_NULL_POINTER; @@ -2068,7 +2128,7 @@ nsTextEditor::SetTypeInStateForProperty(TypeInState &aTypeInState, aTypeInState.UnSet(NS_TYPEINSTATE_ITALIC); } else - { // get the current style and set boldness to the opposite of the current state + { // get the current style and set italic proper to the opposite of the current state PRBool any = PR_FALSE; PRBool all = PR_FALSE; PRBool first = PR_FALSE; @@ -2076,14 +2136,14 @@ nsTextEditor::SetTypeInStateForProperty(TypeInState &aTypeInState, aTypeInState.SetItalic(!any); } } - else if (nsIEditProperty::u==aPropName) + else if (nsIEditProperty::u==aPropName) { if (PR_TRUE==aTypeInState.IsSet(NS_TYPEINSTATE_UNDERLINE)) { // toggle currently set italicness aTypeInState.UnSet(NS_TYPEINSTATE_UNDERLINE); } else - { // get the current style and set boldness to the opposite of the current state + { // get the current style and set underline prop to the opposite of the current state PRBool any = PR_FALSE; PRBool all = PR_FALSE; PRBool first = PR_FALSE; @@ -2091,8 +2151,42 @@ nsTextEditor::SetTypeInStateForProperty(TypeInState &aTypeInState, aTypeInState.SetUnderline(!any); } } - else { - return NS_ERROR_FAILURE; + else if (nsIEditProperty::font==aPropName) + { + if (!aAttribute) { return NS_ERROR_NULL_POINTER; } + nsIAtom *attribute = NS_NewAtom(*aAttribute); + if (!attribute) { return NS_ERROR_NULL_POINTER; } + if (nsIEditProperty::color==attribute) + { + if (PR_TRUE==aTypeInState.IsSet(NS_TYPEINSTATE_FONTCOLOR)) + { + if (nsnull==aValue) { + aTypeInState.UnSet(NS_TYPEINSTATE_FONTCOLOR); + } + else { // we're just changing the value of color + aTypeInState.SetFontColor(*aValue); + } + } + else + { // get the current style and set font color if it's needed + if (!aValue) { return NS_ERROR_NULL_POINTER; } + PRBool any = PR_FALSE; + PRBool all = PR_FALSE; + PRBool first = PR_FALSE; + GetTextProperty(aPropName, aAttribute, aValue, first, any, all); // operates on current selection + if (PR_FALSE==all) { + aTypeInState.SetFontColor(*aValue); + } + } + } + else if (nsIEditProperty::face==attribute) + { + } + if (nsIEditProperty::size==attribute) + { + } + else { return NS_ERROR_FAILURE; } } + else { return NS_ERROR_FAILURE; } return NS_OK; } diff --git a/editor/base/nsTextEditor.h b/editor/base/nsTextEditor.h index e43267672c00..550d3b2a9de4 100644 --- a/editor/base/nsTextEditor.h +++ b/editor/base/nsTextEditor.h @@ -103,28 +103,67 @@ protected: // Utility Methods - virtual void IsTextPropertySetByContent(nsIDOMNode *aNode, - nsIAtom *aProperty, + /** content-based query returns PR_TRUE if effects aNode + * If contains aNode, + * but also contains aNode and the second is + * more deeply nested than the first, then the first does not effect aNode. + * + * @param aNode The target of the query + * @param aProperty The property that we are querying for + * @param aAttribute The attribute of aProperty, example: color in + * May be null. + * @param aValue The value of aAttribute, example: blue in + * May be null. Ignored if aAttribute is null. + * @param aIsSet [OUT] PR_TRUE if effects aNode. + * @param aStyleNode [OUT] set to the node representing , if found. + * null if aIsSet is returned as PR_FALSE; + */ + virtual void IsTextPropertySetByContent(nsIDOMNode *aNode, + nsIAtom *aProperty, const nsString *aAttribute, const nsString *aValue, - PRBool &aIsSet, - nsIDOMNode **aStyleNode) const; + PRBool &aIsSet, + nsIDOMNode **aStyleNode) const; + /** style-based query returns PR_TRUE if (aProperty, aAttribute) is set in aSC. + * WARNING: not well tested yet since we don't do style-based queries anywhere. + */ virtual void IsTextStyleSet(nsIStyleContext *aSC, nsIAtom *aProperty, const nsString *aAttributes, PRBool &aIsSet) const; + /** returns PR_TRUE in out-param aIsInline if aNode is inline as defined by HTML DTD */ NS_IMETHOD IsNodeInline(nsIDOMNode *aNode, PRBool &aIsInline) const; + /** returns PR_TRUE in out-param aResult if all nodes between (aStartNode, aStartOffset) + * and (aEndNode, aEndOffset) are inline as defined by HTML DTD. + */ NS_IMETHOD IntermediateNodesAreInline(nsIDOMRange *aRange, nsIDOMNode *aStartNode, PRInt32 aStartOffset, nsIDOMNode *aEndNode, PRInt32 aEndOffset, - nsIDOMNode *aParent, PRBool &aResult) const; + /** returns the number of things inside aNode in the out-param aCount. + * If aNode is text, returns number of characters. + * If not, returns number of children nodes. + */ + NS_IMETHOD GetLengthOfDOMNode(nsIDOMNode *aNode, PRUint32 &aCount) const; + + /** Moves the content between (aNode, aStartOffset) and (aNode, aEndOffset) + * into aNewParentNode, splitting aNode as necessary to maintain the relative + * position of all leaf content. + */ + NS_IMETHOD nsTextEditor::MoveContentIntoNewParent(nsIDOMNode *aNode, + nsIDOMNode *aOldParentNode, + PRInt32 aStartOffset, + PRInt32 aEndOffset, + nsString aTag, + nsIDOMNode **aNewNode); + + NS_IMETHOD SetTextPropertiesForNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aStartOffset, @@ -167,8 +206,7 @@ protected: nsIAtom *aPropName, const nsString *aAttribute); - NS_IMETHOD RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMRange *aRange, - nsIDOMNode *aStartNode, + NS_IMETHOD RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStartNode, PRInt32 aStartOffset, nsIDOMNode *aEndNode, PRInt32 aEndOffset, @@ -176,11 +214,10 @@ protected: nsIAtom *aPropName, const nsString *aAttribute); - - NS_IMETHOD SetTypeInStateForProperty(TypeInState &aTypeInState, nsIAtom *aPropName, - const nsString *aAttribute); + const nsString *aAttribute, + const nsString *aValue); TypeInState GetTypeInState() { return mTypeInState;} diff --git a/editor/libeditor/base/ChangeAttributeTxn.cpp b/editor/libeditor/base/ChangeAttributeTxn.cpp index 8f37b19645bf..f308c194d760 100644 --- a/editor/libeditor/base/ChangeAttributeTxn.cpp +++ b/editor/libeditor/base/ChangeAttributeTxn.cpp @@ -30,10 +30,10 @@ ChangeAttributeTxn::~ChangeAttributeTxn() } NS_IMETHODIMP ChangeAttributeTxn::Init(nsIEditor *aEditor, - nsIDOMElement *aElement, - const nsString& aAttribute, - const nsString& aValue, - PRBool aRemoveAttribute) + nsIDOMElement *aElement, + const nsString& aAttribute, + const nsString& aValue, + PRBool aRemoveAttribute) { if (nsnull!=aEditor && nsnull!=aElement) { diff --git a/editor/libeditor/base/nsIEditProperty.h b/editor/libeditor/base/nsIEditProperty.h index 502a26a4f89f..b7c0875ec7e1 100644 --- a/editor/libeditor/base/nsIEditProperty.h +++ b/editor/libeditor/base/nsIEditProperty.h @@ -71,6 +71,11 @@ SUB places text in subscript style SUP places text in superscript style */ + /** properties */ + static nsIAtom *color; + static nsIAtom *face; + static nsIAtom *size; + /** special strings */ static nsString *allProperties; // this magic string represents the union of all inline style tags diff --git a/editor/libeditor/html/TypeInState.h b/editor/libeditor/html/TypeInState.h index 7953d86fdcfa..81635f763f80 100644 --- a/editor/libeditor/html/TypeInState.h +++ b/editor/libeditor/html/TypeInState.h @@ -20,8 +20,6 @@ #define ChangeAttributeTxn_h__ #include "nsIDOMSelectionListener.h" -#include "nsColor.h" -#include "nsCoord.h" class TypeInState : public nsIDOMSelectionListener { @@ -51,19 +49,19 @@ public: void SetFontFace(nsString aFace); nsString GetFontFace(); - void SetFontColor(nscolor aColor); - nscolor GetFontColor(); + void SetFontColor(nsString aColor); + nsString GetFontColor(); - void SetFontSize(nscoord aFontSize); - nscoord GetFontSize(); + void SetFontSize(nsString aFontSize); + nsString GetFontSize(); protected: PRBool mBold; PRBool mItalic; PRBool mUnderline; nsString mFontFace; - nscolor mFontColor; - nscoord mFontSize; + nsString mFontColor; + nsString mFontSize; PRUint32 mIsSet; }; @@ -81,8 +79,6 @@ void TypeInState::Reset() mBold = PR_FALSE; mItalic = PR_FALSE; mUnderline = PR_FALSE; - mFontColor = NS_RGB(0,0,0); - mFontSize = 0; mIsSet = 0; }; @@ -96,7 +92,10 @@ TypeInState::TypeInState() inline PRBool TypeInState::IsSet(PRUint32 aStyle) { - return (PRBool)(mIsSet & aStyle); + if ((PRBool)(mIsSet & aStyle)) + return PR_TRUE; + else + return PR_FALSE; }; inline @@ -156,25 +155,25 @@ nsString TypeInState::GetFontFace() { return mFontFace; }; inline -void TypeInState::SetFontColor(nscolor aColor) +void TypeInState::SetFontColor(nsString aColor) { mFontColor = aColor; mIsSet |= NS_TYPEINSTATE_FONTCOLOR; }; inline -nscolor TypeInState::GetFontColor() +nsString TypeInState::GetFontColor() { return mFontColor; }; inline -void TypeInState::SetFontSize(nscoord aSize) +void TypeInState::SetFontSize(nsString aSize) { mFontSize = aSize; mIsSet |= NS_TYPEINSTATE_FONTSIZE; }; inline -nscoord TypeInState::GetFontSize() +nsString TypeInState::GetFontSize() { return mFontSize; }; diff --git a/editor/libeditor/html/nsEditProperty.cpp b/editor/libeditor/html/nsEditProperty.cpp index cb5d034fe551..10ac12452ff6 100644 --- a/editor/libeditor/html/nsEditProperty.cpp +++ b/editor/libeditor/html/nsEditProperty.cpp @@ -41,6 +41,11 @@ nsIAtom * nsIEditProperty::sub; nsIAtom * nsIEditProperty::sup; nsIAtom * nsIEditProperty::tt; nsIAtom * nsIEditProperty::u; +// properties +nsIAtom * nsIEditProperty::color; +nsIAtom * nsIEditProperty::face; +nsIAtom * nsIEditProperty::size; +// special nsString * nsIEditProperty::allProperties; void @@ -59,6 +64,11 @@ nsEditProperty::InstanceInit() nsIEditProperty::sup = NS_NewAtom("SUP"); nsIEditProperty::tt = NS_NewAtom("TT"); nsIEditProperty::u = NS_NewAtom("U"); + // properties + nsIEditProperty::color= NS_NewAtom("COLOR"); + nsIEditProperty::face = NS_NewAtom("FACE"); + nsIEditProperty::size = NS_NewAtom("SIZE"); + // special nsIEditProperty::allProperties = new nsString("moz_AllProperties"); } @@ -78,6 +88,11 @@ nsEditProperty::InstanceShutdown() NS_IF_RELEASE(nsIEditProperty::sup); NS_IF_RELEASE(nsIEditProperty::tt); NS_IF_RELEASE(nsIEditProperty::u); + // properties + NS_IF_RELEASE(nsIEditProperty::color); + NS_IF_RELEASE(nsIEditProperty::face); + NS_IF_RELEASE(nsIEditProperty::size); + // special if (nsIEditProperty::allProperties) { delete (nsIEditProperty::allProperties); } diff --git a/editor/libeditor/text/nsEditorEventListeners.cpp b/editor/libeditor/text/nsEditorEventListeners.cpp index eb42d0ce72cd..22211dbe3eb2 100644 --- a/editor/libeditor/text/nsEditorEventListeners.cpp +++ b/editor/libeditor/text/nsEditorEventListeners.cpp @@ -428,7 +428,7 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr PRBool any = PR_FALSE; PRBool all = PR_FALSE; PRBool first = PR_FALSE; - nsAutoString color = "color"; + nsAutoString color = "COLOR"; nsAutoString value = "red"; mEditor->SetTextProperty(nsIEditProperty::font, &color, &value); } @@ -447,7 +447,7 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr PRBool any = PR_FALSE; PRBool all = PR_FALSE; PRBool first = PR_FALSE; - nsAutoString color = "color"; + nsAutoString color = "COLOR"; nsAutoString value = "green"; mEditor->SetTextProperty(nsIEditProperty::font, &color, &value); } diff --git a/editor/libeditor/text/nsTextEditRules.cpp b/editor/libeditor/text/nsTextEditRules.cpp index 66ced789f283..f048b5e699dc 100644 --- a/editor/libeditor/text/nsTextEditRules.cpp +++ b/editor/libeditor/text/nsTextEditRules.cpp @@ -297,10 +297,11 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta // create style nodes or move it up the content hierarchy as needed. if ((NS_SUCCEEDED(result)) && newTextNode) { + nsCOMPtrnewStyleNode; if (aTypeInState.IsSet(NS_TYPEINSTATE_BOLD)) { if (PR_TRUE==aTypeInState.GetBold()) { - InsertStyleNode(newTextNode, nsIEditProperty::b, aSelection); + result = InsertStyleNode(newTextNode, nsIEditProperty::b, aSelection, getter_AddRefs(newStyleNode)); } else { printf("not yet implemented, make not bold in a bold context\n"); @@ -309,7 +310,7 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta if (aTypeInState.IsSet(NS_TYPEINSTATE_ITALIC)) { if (PR_TRUE==aTypeInState.GetItalic()) { - InsertStyleNode(newTextNode, nsIEditProperty::i, aSelection); + result = InsertStyleNode(newTextNode, nsIEditProperty::i, aSelection, getter_AddRefs(newStyleNode)); } else { @@ -318,14 +319,36 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta } if (aTypeInState.IsSet(NS_TYPEINSTATE_UNDERLINE)) { - if (PR_TRUE==aTypeInState.GetUnderline()) { - InsertStyleNode(newTextNode, nsIEditProperty::u, aSelection); + if (PR_TRUE==aTypeInState.GetUnderline()) { + result = InsertStyleNode(newTextNode, nsIEditProperty::u, aSelection, getter_AddRefs(newStyleNode)); } else { printf("not yet implemented, make not underline in an underline context\n"); } } + if (aTypeInState.IsSet(NS_TYPEINSTATE_FONTCOLOR)) + { + nsAutoString fontColor; + fontColor = aTypeInState.GetFontColor(); + if (0!=fontColor.Length()) { + result = InsertStyleNode(newTextNode, nsIEditProperty::font, aSelection, getter_AddRefs(newStyleNode)); + if (NS_SUCCEEDED(result) && newStyleNode) + { + nsCOMPtrelement = do_QueryInterface(newStyleNode); + if (element) + { + nsAutoString attr; + nsIEditProperty::color->ToString(attr); + result = mEditor->SetAttribute(element, attr, fontColor); + } + } + } + else + { + printf("not yet implemented, make not font in an font context\n"); + } + } } } else @@ -374,7 +397,10 @@ nsTextEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInSta } nsresult -nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode, nsIAtom *aTag, nsIDOMSelection *aSelection) +nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode, + nsIAtom *aTag, + nsIDOMSelection *aSelection, + nsIDOMNode **aNewNode) { NS_ASSERTION(aNode && aTag, "bad args"); if (!aNode || !aTag) { return NS_ERROR_NULL_POINTER; } @@ -386,14 +412,13 @@ nsTextEditRules::InsertStyleNode(nsIDOMNode *aNode, nsIAtom *aTag, nsIDOMSelecti nsIEditorSupport::GetChildOffset(aNode, parent, offsetInParent); nsAutoString tag; aTag->ToString(tag); - nsCOMPtrnewStyleNode; - result = mEditor->CreateNode(tag, parent, offsetInParent, getter_AddRefs(newStyleNode)); - if ((NS_SUCCEEDED(result)) && newStyleNode) + result = mEditor->CreateNode(tag, parent, offsetInParent, aNewNode); + if ((NS_SUCCEEDED(result)) && *aNewNode) { result = mEditor->DeleteNode(aNode); if (NS_SUCCEEDED(result)) { - result = mEditor->InsertNode(aNode, newStyleNode, 0); + result = mEditor->InsertNode(aNode, *aNewNode, 0); if (NS_SUCCEEDED(result)) { if (aSelection) { aSelection->Collapse(aNode, 0); @@ -424,7 +449,8 @@ nsTextEditRules::InsertStyleAndNewTextNode(nsIDOMNode *aParentNode, nsIAtom *aTa anchorAsText = do_QueryInterface(anchor); if (anchorAsText) { - result = InsertStyleNode(anchor, aTag, aSelection); + nsCOMPtr newStyleNode; + result = InsertStyleNode(anchor, aTag, aSelection, getter_AddRefs(newStyleNode)); return result; } } diff --git a/editor/libeditor/text/nsTextEditRules.h b/editor/libeditor/text/nsTextEditRules.h index af6a28de626c..d23533e92f06 100644 --- a/editor/libeditor/text/nsTextEditRules.h +++ b/editor/libeditor/text/nsTextEditRules.h @@ -91,10 +91,13 @@ protected: /** insert aNode into a new style node of type aTag. * aSelection is optional. If provided, aSelection is set to (aNode, 0) * if aNode was successfully placed in a new style node + * @param aNewStyleNode [OUT] The newly created style node, if result is successful + * undefined if result is a failure. */ - nsresult InsertStyleNode(nsIDOMNode *aNode, - nsIAtom *aTag, - nsIDOMSelection *aSelection); + nsresult InsertStyleNode(nsIDOMNode *aNode, + nsIAtom *aTag, + nsIDOMSelection *aSelection, + nsIDOMNode **aNewStyleNode); /** create a new style node of type aTag in aParentNode, and put a new text node * in the new style node.