From cd2edf3e7cacaf7d122cd611484286b4afa9c3f2 Mon Sep 17 00:00:00 2001 From: "buster%netscape.com" Date: Fri, 22 Jan 1999 22:58:15 +0000 Subject: [PATCH] added some basic tree navigation methods. implemented part of backspacing from the beginning of a text node. git-svn-id: svn://10.0.0.236/trunk@18363 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/editor/base/editor.cpp | 165 +++++++++++++++++++++++++++++---- mozilla/editor/base/editor.h | 13 +++ mozilla/editor/core/editor.cpp | 165 +++++++++++++++++++++++++++++---- mozilla/editor/core/editor.h | 13 +++ 4 files changed, 320 insertions(+), 36 deletions(-) diff --git a/mozilla/editor/base/editor.cpp b/mozilla/editor/base/editor.cpp index d995da2318c..9bf4e4e0efd 100644 --- a/mozilla/editor/base/editor.cpp +++ b/mozilla/editor/base/editor.cpp @@ -878,24 +878,7 @@ nsresult nsEditor::CreateTxnForDeleteSelection(nsIEditor::Direction aDir, } else { // we have an insertion point. delete the thing in front of it or behind it, depending on aDir - nsCOMPtr node; - PRInt32 offset; - PRInt32 length=1; - result = range->GetStartParent(getter_AddRefs(node)); - result = range->GetStartOffset(&offset); - nsCOMPtr text(node); - if (node) - { // we have text, so delete a char at the proper offset - // XXX: doesn't handle beginning/end of text node, which needs to jump to next|prev node - if (nsIEditor::eRTL==aDir) - { - if (0!=offset) - offset --; - } - DeleteTextTxn *txn; - result = CreateTxnForDeleteText(text, offset, length, &txn); - (*aTxn)->AppendChild(txn); - } + result = CreateTxnForDeleteInsertionPoint(range, aDir, *aTxn); } } } @@ -919,6 +902,152 @@ nsresult nsEditor::CreateTxnForDeleteSelection(nsIEditor::Direction aDir, return result; } + +//XXX: currently, this doesn't handle edge conditions because GetNext/GetPrior are not implemented +nsresult +nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange, + nsIEditor::Direction aDir, + EditAggregateTxn *aTxn) +{ + nsCOMPtr node; + PRBool isFirst; + PRBool isLast; + PRInt32 offset; + PRInt32 length=1; + + // get the node and offset of the insertion point + nsresult result = aRange->GetStartParent(getter_AddRefs(node)); + aRange->GetStartOffset(&offset); + + // determine if the insertion point is at the beginning, middle, or end of the node + nsCOMPtr nodeAsText(node); + if (nodeAsText) + { + PRUint32 count; + nodeAsText->GetLength(&count); + isFirst = PRBool(0==offset); + isLast = PRBool(count==offset); + } + else + { + nsCOMPtr sibling; + result = node->GetPreviousSibling(getter_AddRefs(sibling)); + if ((NS_SUCCEEDED(result)) && sibling) + isFirst = PR_FALSE; + else + isFirst = PR_TRUE; + result = node->GetNextSibling(getter_AddRefs(sibling)); + if ((NS_SUCCEEDED(result)) && sibling) + isLast = PR_FALSE; + else + isLast = PR_TRUE; + } + + // build a transaction for deleting the appropriate data + if ((nsIEditor::eRTL==aDir) && (PR_TRUE==isFirst)) + { // we're backspacing from the beginning of the node. Delete the first thing to our left + nsCOMPtr priorNode; + result = GetPriorNode(node, getter_AddRefs(priorNode)); + if ((NS_SUCCEEDED(result)) && priorNode) + { // 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(priorNode); + if (priorNodeAsText) + { + PRUint32 length=0; + priorNodeAsText->GetLength(&length); + if (0AppendChild(txn); + } + else + { // XXX: can you have an empty text node? If so, what do you do? + printf("ERROR: found a text node with 0 characters\n"); + result = NS_ERROR_UNEXPECTED; + } + } + else + { // priorNode is not text, so tell it's parent to delete it + } + } + } + else if ((nsIEditor::eLTR==aDir) && (PR_TRUE==isLast)) + { + } + else + { + if (nodeAsText) + { // we have text, so delete a char at the proper offset + if (nsIEditor::eRTL==aDir) { + offset --; + } + DeleteTextTxn *txn; + result = CreateTxnForDeleteText(nodeAsText, offset, length, &txn); + aTxn->AppendChild(txn); + } + else + { // we're deleting a node + } + } + return result; +} + +nsresult +nsEditor::GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode) +{ + nsresult result; + *aResultNode = nsnull; + // if aCurrentNode has a left sibling, return that sibling's rightmost child (or itself if it has no children) + result = aCurrentNode->GetPreviousSibling(aResultNode); + if ((NS_SUCCEEDED(result)) && *aResultNode) + return GetRightmostChild(*aResultNode, aResultNode); + + // otherwise, walk up the parent change until there is a child that comes before + // the ancestor of aCurrentNode. Then return that node's rightmost child + + nsCOMPtr parent(aCurrentNode); + do { + nsCOMPtr node(parent); + result = node->GetParentNode(getter_AddRefs(parent)); + if ((NS_SUCCEEDED(result)) && parent) + { + result = parent->GetPreviousSibling(getter_AddRefs(node)); + if ((NS_SUCCEEDED(result)) && node) + { + return GetRightmostChild(node, aResultNode); + } + } + } while ((NS_SUCCEEDED(result)) && parent); + + return result; +} + +nsresult +nsEditor::GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode) +{ + nsresult result; + return result; +} + +nsresult +nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode) +{ + nsresult result = NS_OK; + *aResultNode = aCurrentNode; + return result; +} + +nsresult +nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode) +{ + nsresult result = NS_OK; + *aResultNode = aCurrentNode; + return result; +} + + nsresult nsEditor::SplitNode(nsIDOMNode * aExistingRightNode, PRInt32 aOffset, diff --git a/mozilla/editor/base/editor.h b/mozilla/editor/base/editor.h index 4e4c25c3835..6550c10d6a5 100644 --- a/mozilla/editor/base/editor.h +++ b/mozilla/editor/base/editor.h @@ -32,6 +32,7 @@ //#include "nsISelection.h" class nsIDOMCharacterData; +class nsIDOMRange; class nsIPresShell; class nsIViewManager; class ChangeAttributeTxn; @@ -218,6 +219,18 @@ protected: nsresult CreateTxnForDeleteSelection(nsIEditor::Direction aDir, EditAggregateTxn ** aTxn); + nsresult CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange, + nsIEditor::Direction aDir, + EditAggregateTxn *aTxn); + + nsresult GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode); + + nsresult GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode); + + nsresult GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode); + + nsresult GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode); + }; diff --git a/mozilla/editor/core/editor.cpp b/mozilla/editor/core/editor.cpp index d995da2318c..9bf4e4e0efd 100644 --- a/mozilla/editor/core/editor.cpp +++ b/mozilla/editor/core/editor.cpp @@ -878,24 +878,7 @@ nsresult nsEditor::CreateTxnForDeleteSelection(nsIEditor::Direction aDir, } else { // we have an insertion point. delete the thing in front of it or behind it, depending on aDir - nsCOMPtr node; - PRInt32 offset; - PRInt32 length=1; - result = range->GetStartParent(getter_AddRefs(node)); - result = range->GetStartOffset(&offset); - nsCOMPtr text(node); - if (node) - { // we have text, so delete a char at the proper offset - // XXX: doesn't handle beginning/end of text node, which needs to jump to next|prev node - if (nsIEditor::eRTL==aDir) - { - if (0!=offset) - offset --; - } - DeleteTextTxn *txn; - result = CreateTxnForDeleteText(text, offset, length, &txn); - (*aTxn)->AppendChild(txn); - } + result = CreateTxnForDeleteInsertionPoint(range, aDir, *aTxn); } } } @@ -919,6 +902,152 @@ nsresult nsEditor::CreateTxnForDeleteSelection(nsIEditor::Direction aDir, return result; } + +//XXX: currently, this doesn't handle edge conditions because GetNext/GetPrior are not implemented +nsresult +nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange, + nsIEditor::Direction aDir, + EditAggregateTxn *aTxn) +{ + nsCOMPtr node; + PRBool isFirst; + PRBool isLast; + PRInt32 offset; + PRInt32 length=1; + + // get the node and offset of the insertion point + nsresult result = aRange->GetStartParent(getter_AddRefs(node)); + aRange->GetStartOffset(&offset); + + // determine if the insertion point is at the beginning, middle, or end of the node + nsCOMPtr nodeAsText(node); + if (nodeAsText) + { + PRUint32 count; + nodeAsText->GetLength(&count); + isFirst = PRBool(0==offset); + isLast = PRBool(count==offset); + } + else + { + nsCOMPtr sibling; + result = node->GetPreviousSibling(getter_AddRefs(sibling)); + if ((NS_SUCCEEDED(result)) && sibling) + isFirst = PR_FALSE; + else + isFirst = PR_TRUE; + result = node->GetNextSibling(getter_AddRefs(sibling)); + if ((NS_SUCCEEDED(result)) && sibling) + isLast = PR_FALSE; + else + isLast = PR_TRUE; + } + + // build a transaction for deleting the appropriate data + if ((nsIEditor::eRTL==aDir) && (PR_TRUE==isFirst)) + { // we're backspacing from the beginning of the node. Delete the first thing to our left + nsCOMPtr priorNode; + result = GetPriorNode(node, getter_AddRefs(priorNode)); + if ((NS_SUCCEEDED(result)) && priorNode) + { // 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(priorNode); + if (priorNodeAsText) + { + PRUint32 length=0; + priorNodeAsText->GetLength(&length); + if (0AppendChild(txn); + } + else + { // XXX: can you have an empty text node? If so, what do you do? + printf("ERROR: found a text node with 0 characters\n"); + result = NS_ERROR_UNEXPECTED; + } + } + else + { // priorNode is not text, so tell it's parent to delete it + } + } + } + else if ((nsIEditor::eLTR==aDir) && (PR_TRUE==isLast)) + { + } + else + { + if (nodeAsText) + { // we have text, so delete a char at the proper offset + if (nsIEditor::eRTL==aDir) { + offset --; + } + DeleteTextTxn *txn; + result = CreateTxnForDeleteText(nodeAsText, offset, length, &txn); + aTxn->AppendChild(txn); + } + else + { // we're deleting a node + } + } + return result; +} + +nsresult +nsEditor::GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode) +{ + nsresult result; + *aResultNode = nsnull; + // if aCurrentNode has a left sibling, return that sibling's rightmost child (or itself if it has no children) + result = aCurrentNode->GetPreviousSibling(aResultNode); + if ((NS_SUCCEEDED(result)) && *aResultNode) + return GetRightmostChild(*aResultNode, aResultNode); + + // otherwise, walk up the parent change until there is a child that comes before + // the ancestor of aCurrentNode. Then return that node's rightmost child + + nsCOMPtr parent(aCurrentNode); + do { + nsCOMPtr node(parent); + result = node->GetParentNode(getter_AddRefs(parent)); + if ((NS_SUCCEEDED(result)) && parent) + { + result = parent->GetPreviousSibling(getter_AddRefs(node)); + if ((NS_SUCCEEDED(result)) && node) + { + return GetRightmostChild(node, aResultNode); + } + } + } while ((NS_SUCCEEDED(result)) && parent); + + return result; +} + +nsresult +nsEditor::GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode) +{ + nsresult result; + return result; +} + +nsresult +nsEditor::GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode) +{ + nsresult result = NS_OK; + *aResultNode = aCurrentNode; + return result; +} + +nsresult +nsEditor::GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode) +{ + nsresult result = NS_OK; + *aResultNode = aCurrentNode; + return result; +} + + nsresult nsEditor::SplitNode(nsIDOMNode * aExistingRightNode, PRInt32 aOffset, diff --git a/mozilla/editor/core/editor.h b/mozilla/editor/core/editor.h index 4e4c25c3835..6550c10d6a5 100644 --- a/mozilla/editor/core/editor.h +++ b/mozilla/editor/core/editor.h @@ -32,6 +32,7 @@ //#include "nsISelection.h" class nsIDOMCharacterData; +class nsIDOMRange; class nsIPresShell; class nsIViewManager; class ChangeAttributeTxn; @@ -218,6 +219,18 @@ protected: nsresult CreateTxnForDeleteSelection(nsIEditor::Direction aDir, EditAggregateTxn ** aTxn); + nsresult CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange, + nsIEditor::Direction aDir, + EditAggregateTxn *aTxn); + + nsresult GetPriorNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode); + + nsresult GetNextNode(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode); + + nsresult GetRightmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode); + + nsresult GetLeftmostChild(nsIDOMNode *aCurrentNode, nsIDOMNode **aResultNode); + };