* added TransactionFactory. Editor no longer allocates its own transactions. This gives us an oppurtunity for a recycler.

* added DeleteSelection to editor.  Doesn't work very well yet because selection is giving me random offsets into text content.
* lots of work in the various transactions.
This commit is contained in:
buster%netscape.com 1999-01-21 01:51:09 +00:00
Родитель 5d9c7b3a64
Коммит 83a4e325ce
76 изменённых файлов: 3803 добавлений и 1054 удалений

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

@ -17,23 +17,33 @@
*/
#include "ChangeAttributeTxn.h"
#include "editor.h"
#include "nsIDOMElement.h"
#include "editor.h"
// note that aEditor is not refcounted
ChangeAttributeTxn::ChangeAttributeTxn(nsEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute)
: EditTxn(aEditor)
ChangeAttributeTxn::ChangeAttributeTxn()
: EditTxn()
{
mElement = aElement;
mAttribute = aAttribute;
mValue = aValue;
mRemoveAttribute = aRemoveAttribute;
mAttributeWasSet=PR_FALSE;
mUndoValue="";
}
nsresult ChangeAttributeTxn::Init(nsIEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute)
{
if (nsnull!=aEditor && nsnull!=aElement)
{
mEditor = aEditor;
mElement = aElement;
mAttribute = aAttribute;
mValue = aValue;
mRemoveAttribute = aRemoveAttribute;
mAttributeWasSet=PR_FALSE;
mUndoValue="";
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
nsresult ChangeAttributeTxn::Do(void)

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

@ -20,8 +20,14 @@
#define ChangeAttributeTxn_h__
#include "EditTxn.h"
#include "nsCOMPtr.h"
#include "nsIDOMElement.h"
#include "nsIEditor.h"
class nsIDOMElement;
#define CHANGE_ATTRIBUTE_TXN_IID \
{/* 97818860-ac48-11d2-86d8-000064657374 */ \
0x97818860, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that changes an attribute of a content node.
@ -31,11 +37,16 @@ class ChangeAttributeTxn : public EditTxn
{
public:
ChangeAttributeTxn(nsEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute);
virtual nsresult Init(nsIEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute);
private:
ChangeAttributeTxn();
public:
virtual nsresult Do(void);
@ -54,9 +65,12 @@ public:
virtual nsresult GetRedoString(nsString **aString);
protected:
/** the editor that created this transaction */
nsCOMPtr<nsIEditor> mEditor;
/** the element to operate upon */
nsIDOMElement *mElement;
nsCOMPtr<nsIDOMElement> mElement;
/** the attribute to change */
nsString mAttribute;
@ -72,6 +86,8 @@ protected:
/** PR_TRUE if the operation is to remove mAttribute from mElement */
PRBool mRemoveAttribute;
friend class TransactionFactory;
};
#endif

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

@ -17,52 +17,50 @@
*/
#include "CreateElementTxn.h"
#include "editor.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
// note that aEditor is not refcounted
CreateElementTxn::CreateElementTxn(nsEditor *aEditor,
nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent)
: EditTxn(aEditor)
CreateElementTxn::CreateElementTxn()
: EditTxn()
{
mDoc = aDoc;
NS_ADDREF(mDoc);
mTag = aTag;
mParent = aParent;
NS_ADDREF(mParent);
mOffsetInParent = aOffsetInParent;
mNewNode = nsnull;
mRefNode = nsnull;
}
nsresult CreateElementTxn::Init(nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent)
{
if ((nsnull!=aDoc) && (nsnull!=aParent))
{
mDoc = aDoc;
mTag = aTag;
mParent = aParent;
mOffsetInParent = aOffsetInParent;
mNewNode = nsnull;
mRefNode = nsnull;
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
CreateElementTxn::~CreateElementTxn()
{
NS_IF_RELEASE(mDoc);
NS_IF_RELEASE(mParent);
NS_IF_RELEASE(mNewNode);
}
nsresult CreateElementTxn::Do(void)
{
// create a new node
nsresult result = mDoc->CreateElement(mTag, &mNewNode);
NS_ASSERTION(((NS_SUCCEEDED(result)) && (nsnull!=mNewNode)), "could not create element.");
nsresult result = mDoc->CreateElement(mTag, getter_AddRefs(mNewNode));
NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewNode)), "could not create element.");
if ((NS_SUCCEEDED(result)) && (nsnull!=mNewNode))
if ((NS_SUCCEEDED(result)) && (mNewNode))
{
// insert the new node
nsIDOMNode *resultNode=nsnull;
nsCOMPtr<nsIDOMNode> resultNode;
if (CreateElementTxn::eAppend==mOffsetInParent)
{
result = mParent->AppendChild(mNewNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode); // this object already holds a ref from CreateElement
result = mParent->AppendChild(mNewNode, getter_AddRefs(resultNode));
}
else
{
@ -70,12 +68,10 @@ nsresult CreateElementTxn::Do(void)
result = mParent->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
result = childNodes->Item(mOffsetInParent, &mRefNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=mRefNode))
result = childNodes->Item(mOffsetInParent, getter_AddRefs(mRefNode));
if ((NS_SUCCEEDED(result)) && (mRefNode))
{
result = mParent->InsertBefore(mNewNode, mRefNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode); // this object already holds a ref from CreateElement
result = mParent->InsertBefore(mNewNode, mRefNode, getter_AddRefs(resultNode));
}
}
}
@ -85,20 +81,16 @@ nsresult CreateElementTxn::Do(void)
nsresult CreateElementTxn::Undo(void)
{
nsIDOMNode *resultNode=nsnull;
nsresult result = mParent->RemoveChild(mNewNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode);
nsCOMPtr<nsIDOMNode> resultNode;
nsresult result = mParent->RemoveChild(mNewNode, getter_AddRefs(resultNode));
return result;
}
nsresult CreateElementTxn::Redo(void)
{
nsIDOMNode *resultNode=nsnull;
nsresult result = mParent->InsertBefore(mNewNode, mRefNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode);
return result;
nsCOMPtr<nsIDOMNode> resultNode;
nsresult result = mParent->InsertBefore(mNewNode, mRefNode, getter_AddRefs(resultNode));
return result;
}
nsresult CreateElementTxn::GetIsTransient(PRBool *aIsTransient)

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

@ -20,10 +20,15 @@
#define CreateElementTxn_h__
#include "EditTxn.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "nsCOMPtr.h"
class nsIDOMDocument;
class nsIDOMNode;
class nsIDOMElement;
#define CREATE_ELEMENT_TXN_IID \
{/* 7a6393c0-ac48-11d2-86d8-000064657374 */ \
0x7a6393c0, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that creates a new node in the content tree.
@ -34,11 +39,15 @@ public:
enum { eAppend=-1 };
CreateElementTxn(nsEditor *aEditor,
nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent);
virtual nsresult Init(nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent);
private:
CreateElementTxn();
public:
virtual ~CreateElementTxn();
@ -61,22 +70,24 @@ public:
protected:
/** the document into which the new node will be inserted */
nsIDOMDocument *mDoc;
nsCOMPtr<nsIDOMDocument> mDoc;
/** the tag (mapping to object type) for the new element */
nsString mTag;
/** the node into which the new node will be inserted */
nsIDOMNode *mParent;
nsCOMPtr<nsIDOMNode> mParent;
/** the index in mParent for the new node */
PRUint32 mOffsetInParent;
/** the new node to insert */
nsIDOMElement *mNewNode;
nsCOMPtr<nsIDOMElement> mNewNode;
/** the node we will insert mNewNode before. We compute this ourselves. */
nsIDOMNode *mRefNode;
nsCOMPtr<nsIDOMNode> mRefNode;
friend class TransactionFactory;
};

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

@ -17,30 +17,32 @@
*/
#include "DeleteElementTxn.h"
#include "editor.h"
#include "nsIDOMDocument.h"
#ifdef NS_DEBUG
#include "nsIDOMElement.h"
#endif
// note that aEditor is not refcounted
DeleteElementTxn::DeleteElementTxn(nsEditor * aEditor,
nsIDOMDocument *aDoc,
nsIDOMNode * aElement,
nsIDOMNode * aParent)
: EditTxn(aEditor)
DeleteElementTxn::DeleteElementTxn()
: EditTxn()
{
mDoc = aDoc;
NS_ADDREF(mDoc);
mElement = aElement;
NS_ADDREF(mElement);
mParent = aParent;
NS_ADDREF(mParent);
}
nsresult DeleteElementTxn::Init(nsIDOMNode *aElement,
nsIDOMNode *aParent)
{
if ((nsnull!=aElement) && (nsnull!=aParent))
{
mElement = aElement;
mParent = aParent;
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
DeleteElementTxn::~DeleteElementTxn()
{
NS_IF_RELEASE(mDoc);
NS_IF_RELEASE(mParent);
NS_IF_RELEASE(mElement);
}
nsresult DeleteElementTxn::Do(void)
@ -48,11 +50,32 @@ nsresult DeleteElementTxn::Do(void)
if (!mParent || !mElement)
return NS_ERROR_NULL_POINTER;
#ifdef NS_DEBUG
// begin debug output
nsCOMPtr<nsIDOMElement> element=mElement;
nsAutoString elementTag="text node";
if (element)
element->GetTagName(elementTag);
nsCOMPtr<nsIDOMElement> parentElement=mParent;
nsAutoString parentElementTag="text node";
if (parentElement)
parentElement->GetTagName(parentElementTag);
char *c, *p;
c = elementTag.ToNewCString();
p = parentElementTag.ToNewCString();
if (c&&p)
{
printf("DeleteElementTxn: deleting child %s from parent %s\n", c, p);
delete [] c;
delete [] p;
}
// end debug output
// begin sanity check 1: parent-child relationship
nsresult testResult;
nsCOMPtr<nsIDOMNode> parentNode;
testResult = mElement->GetParentNode(getter_AddRefs(parentNode));
NS_ASSERTION((NS_SUCCEEDED(testResult)), "bad mElement, couldn't get parent");
NS_ASSERTION((parentNode==mParent), "bad mParent, mParent!=mElement->GetParent() ");
// end sanity check 1.
#endif
// remember which child mElement was (by remembering which child was next)

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

@ -23,8 +23,10 @@
#include "nsIDOMNode.h"
#include "nsCOMPtr.h"
class nsIDOMDocument;
class nsIDOMElement;
#define DELETE_ELEMENT_TXN_IID \
{/* 6fd77770-ac49-11d2-86d8-000064657374 */ \
0x6fd77770, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that deletes a single element
@ -33,10 +35,13 @@ class DeleteElementTxn : public EditTxn
{
public:
DeleteElementTxn(nsEditor *aEditor,
nsIDOMDocument *aDoc,
nsIDOMNode *aElement,
nsIDOMNode *aParent);
virtual nsresult Init(nsIDOMNode *aElement,
nsIDOMNode *aParent);
private:
DeleteElementTxn();
public:
virtual ~DeleteElementTxn();
@ -58,14 +63,11 @@ public:
protected:
/** the document into which the new node will be inserted */
nsIDOMDocument *mDoc;
/** the element to delete */
nsIDOMNode *mElement;
nsCOMPtr<nsIDOMNode> mElement;
/** the node into which the new node will be inserted */
nsIDOMNode *mParent;
nsCOMPtr<nsIDOMNode> mParent;
/** the index in mParent for the new node */
PRUint32 mOffsetInParent;
@ -73,6 +75,8 @@ protected:
/** the node we will insert mNewNode before. We compute this ourselves. */
nsCOMPtr<nsIDOMNode> mRefNode;
friend class TransactionFactory;
};
#endif

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

@ -17,18 +17,73 @@
*/
#include "DeleteRangeTxn.h"
#include "editor.h"
#include "nsIDOMRange.h"
#include "nsIDOMCharacterData.h"
#include "nsIDOMNodeList.h"
#include "DeleteTextTxn.h"
#include "DeleteElementTxn.h"
#include "TransactionFactory.h"
#include "nsISupportsArray.h"
static NS_DEFINE_IID(kDeleteTextTxnIID, DELETE_TEXT_TXN_IID);
static NS_DEFINE_IID(kDeleteElementTxnIID, DELETE_ELEMENT_TXN_IID);
// note that aEditor is not refcounted
DeleteRangeTxn::DeleteRangeTxn(nsEditor *aEditor,
nsIDOMRange *aRange)
: EditTxn(aEditor)
DeleteRangeTxn::DeleteRangeTxn()
: EditAggregateTxn()
{
aRange->GetStartParent(getter_AddRefs(mStartParent));
aRange->GetEndParent(getter_AddRefs(mEndParent));
aRange->GetStartOffset(&mStartOffset);
aRange->GetEndOffset(&mEndOffset);
}
nsresult DeleteRangeTxn::Init(nsIDOMRange *aRange)
{
if (nsnull!=aRange)
{
nsresult result = aRange->GetStartParent(getter_AddRefs(mStartParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetStartParent failed.");
result = aRange->GetEndParent(getter_AddRefs(mEndParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetEndParent failed.");
result = aRange->GetStartOffset(&mStartOffset);
NS_ASSERTION((NS_SUCCEEDED(result)), "GetStartOffset failed.");
result = aRange->GetEndOffset(&mEndOffset);
NS_ASSERTION((NS_SUCCEEDED(result)), "GetEndOffset failed.");
result = aRange->GetCommonParent(getter_AddRefs(mCommonParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetCommonParent failed.");
#ifdef NS_DEBUG
PRUint32 count;
nsCOMPtr<nsIDOMCharacterData> textNode;
textNode = mStartParent;
if (textNode)
textNode->GetLength(&count);
else
{
nsCOMPtr<nsIDOMNodeList> children;
result = mStartParent->GetChildNodes(getter_AddRefs(children));
NS_ASSERTION(((NS_SUCCEEDED(result)) && children), "bad start child list");
children->GetLength(&count);
}
NS_ASSERTION(mStartOffset<count, "bad start offset");
textNode = mEndParent;
if (textNode)
textNode->GetLength(&count);
else
{
nsCOMPtr<nsIDOMNodeList> children;
result = mEndParent->GetChildNodes(getter_AddRefs(children));
NS_ASSERTION(((NS_SUCCEEDED(result)) && children), "bad end child list");
children->GetLength(&count);
}
NS_ASSERTION(mEndOffset<count, "bad end offset");
printf ("DeleteRange: %d of %p to %d of %p\n",
mStartOffset, (void *)mStartParent, mEndOffset, (void *)mEndParent);
#endif
return result;
}
else
return NS_ERROR_NULL_POINTER;
}
DeleteRangeTxn::~DeleteRangeTxn()
@ -37,28 +92,59 @@ DeleteRangeTxn::~DeleteRangeTxn()
nsresult DeleteRangeTxn::Do(void)
{
if (!mStartParent || !mEndParent)
if (!mStartParent || !mEndParent || !mCommonParent)
return NS_ERROR_NULL_POINTER;
nsresult result;
// build the child transactions
if (mStartParent==mEndParent)
{ // the selection begins and ends in the same node
result = CreateTxnsToDeleteBetween(mStartParent, mStartOffset, mEndOffset);
}
else
{ // the selection ends in a different node from where it started
// delete the relevant content in the start node
result = CreateTxnsToDeleteContent(mStartParent, mStartOffset, nsIEditor::eLTR);
if (NS_SUCCEEDED(result))
{
// delete the intervening nodes
result = CreateTxnsToDeleteNodesBetween(mCommonParent, mStartParent, mEndParent);
if (NS_SUCCEEDED(result))
{
// delete the relevant content in the end node
result = CreateTxnsToDeleteContent(mEndParent, mEndOffset, nsIEditor::eRTL);
if (NS_SUCCEEDED(result))
{ // now we have all our child transactions, do them
result = EditAggregateTxn::Do();
}
}
}
}
// if we've successfully built this aggregate transaction, then do it.
if (NS_SUCCEEDED(result))
result = EditAggregateTxn::Do();
return result;
}
nsresult DeleteRangeTxn::Undo(void)
{
if (!mStartParent || !mEndParent)
if (!mStartParent || !mEndParent || !mCommonParent)
return NS_ERROR_NULL_POINTER;
nsresult result;
nsresult result = EditAggregateTxn::Undo();
return result;
}
nsresult DeleteRangeTxn::Redo(void)
{
if (!mStartParent || !mEndParent)
if (!mStartParent || !mEndParent || !mCommonParent)
return NS_ERROR_NULL_POINTER;
nsresult result;
nsresult result = EditAggregateTxn::Redo();
return result;
}
@ -98,3 +184,265 @@ nsresult DeleteRangeTxn::GetRedoString(nsString **aString)
}
return NS_OK;
}
nsresult DeleteRangeTxn::CreateTxnsToDeleteBetween(nsIDOMNode *aStartParent,
PRUint32 aStartOffset,
PRUint32 aEndOffset)
{
nsresult result;
// see what kind of node we have
nsCOMPtr<nsIDOMCharacterData> textNode;
textNode = aStartParent; // this uses implicit nsCOMPtr QI
if (textNode)
{ // if the node is a text node, then delete text content
DeleteTextTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteTextTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(textNode, aStartOffset, (aEndOffset-aStartOffset)+1);
AppendChild(txn);
}
}
else
{
PRUint32 childCount;
nsCOMPtr<nsIDOMNodeList> children;
result = aStartParent->GetChildNodes(getter_AddRefs(children));
if ((NS_SUCCEEDED(result)) && children)
{
children->GetLength(&childCount);
NS_ASSERTION(aEndOffset<childCount, "bad aEndOffset");
PRUint32 i;
for (i=aStartOffset; i<=aEndOffset; i++)
{
nsCOMPtr<nsIDOMNode> child;
result = children->Item(i, getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, aStartParent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
}
}
return result;
}
nsresult DeleteRangeTxn::CreateTxnsToDeleteContent(nsIDOMNode *aParent,
PRUint32 aOffset,
nsIEditor::Direction aDir)
{
nsresult result;
// see what kind of node we have
nsCOMPtr<nsIDOMCharacterData> textNode;
textNode = aParent; // this uses implicit nsCOMPtr QI
if (textNode)
{ // if the node is a text node, then delete text content
PRUint32 start, numToDelete;
if (nsIEditor::eLTR==aDir)
{
start=aOffset;
textNode->GetLength(&numToDelete);
numToDelete -= (aOffset+1);
}
else
{
start=0;
numToDelete=aOffset;
}
DeleteTextTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteTextTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(textNode, start, numToDelete);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
else
{ // we have an interior node, so delete some of its children
if (nsIEditor::eLTR==aDir)
{ // delete from aOffset to end
PRUint32 childCount;
nsCOMPtr<nsIDOMNodeList> children;
result = aParent->GetChildNodes(getter_AddRefs(children));
if ((NS_SUCCEEDED(result)) && children)
{
children->GetLength(&childCount);
PRUint32 i;
for (i=aOffset; i<childCount; i++)
{
nsCOMPtr<nsIDOMNode> child;
result = children->Item(i, getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, aParent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
}
}
else
{ // delete from 0 to aOffset
nsCOMPtr<nsIDOMNode> child;
result = aParent->GetFirstChild(getter_AddRefs(child));
for (PRUint32 i=0; i<aOffset; i++)
{
if ((NS_SUCCEEDED(result)) && child)
{
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, aParent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIDOMNode> temp = child;
result = temp->GetNextSibling(getter_AddRefs(child));
}
}
}
return result;
}
nsresult DeleteRangeTxn::CreateTxnsToDeleteNodesBetween(nsIDOMNode *aCommonParent,
nsIDOMNode *aFirstChild,
nsIDOMNode *aLastChild)
{
nsresult result;
PRBool needToProcessLastChild=PR_TRUE; // set to false if we discover we can delete all required nodes by just walking up aFirstChild's parent list
nsCOMPtr<nsIDOMNode> parent; // the current parent in the iteration up the ancestors
nsCOMPtr<nsIDOMNode> child; // the current child of parent
nsISupportsArray *ancestorList; // the ancestorList of the other endpoint, used to gate deletion
NS_NewISupportsArray(&ancestorList);
if (nsnull==ancestorList)
return NS_ERROR_NULL_POINTER;
// Walk up the parent list of aFirstChild to aCommonParent,
// deleting all siblings to the right of the ancestors of aFirstChild.
BuildAncestorList(aLastChild, ancestorList);
child = aFirstChild;
result = child->GetParentNode(getter_AddRefs(parent));
while ((NS_SUCCEEDED(result)) && parent)
{
while ((NS_SUCCEEDED(result)) && child)
{ // this loop starts with the first sibling of an ancestor of aFirstChild
nsCOMPtr<nsIDOMNode> temp = child;
result = temp->GetNextSibling(getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
if (child==aLastChild)
{ // aFirstChild and aLastChild have the same parent, and we've reached aLastChild
needToProcessLastChild = PR_FALSE;
break;
}
// test if child is an ancestor of the other node. If it is, don't process this parent anymore
PRInt32 index;
index = ancestorList->IndexOf((nsISupports*)child);
if (-1!=index)
break;
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, parent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
if (parent==aCommonParent)
break;
child = parent;
nsCOMPtr<nsIDOMNode> temp=parent;
result = temp->GetParentNode(getter_AddRefs(parent));
}
// Walk up the parent list of aLastChild to aCommonParent,
// deleting all siblings to the left of the ancestors of aLastChild.
BuildAncestorList(aFirstChild, ancestorList);
if (PR_TRUE==needToProcessLastChild)
{
child = aLastChild;
result = child->GetParentNode(getter_AddRefs(parent));
while ((NS_SUCCEEDED(result)) && parent)
{
while ((NS_SUCCEEDED(result)) && child)
{ // this loop starts with the first sibling of an ancestor of aFirstChild
nsCOMPtr<nsIDOMNode> temp = child;
result = temp->GetPreviousSibling(getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
// test if child is an ancestor of the other node. If it is, don't process this parent anymore
PRInt32 index;
index = ancestorList->IndexOf((nsISupports*)child);
if (-1!=index)
break;
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, parent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
if (parent==aCommonParent)
break;
child = parent;
nsCOMPtr<nsIDOMNode> temp=parent;
result = temp->GetParentNode(getter_AddRefs(parent));
}
}
NS_RELEASE(ancestorList);
return result;
}
nsresult DeleteRangeTxn::BuildAncestorList(nsIDOMNode *aNode, nsISupportsArray *aList)
{
nsresult result=NS_OK;
if (nsnull!=aNode && nsnull!=aList)
{
aList->Clear();
nsCOMPtr<nsIDOMNode> parent;
nsCOMPtr<nsIDOMNode> child = aNode;
result = child->GetParentNode(getter_AddRefs(parent));
while ((NS_SUCCEEDED(result)) && child && parent)
{
nsISupports * parentAsISupports;
parent->QueryInterface(nsISupports::IID(), (void **)&parentAsISupports);
aList->AppendElement(parentAsISupports);
child = parent;
nsCOMPtr<nsIDOMNode> temp=parent;
result = temp->GetParentNode(getter_AddRefs(parent));
}
}
else
result = NS_ERROR_NULL_POINTER;
return result;
}

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

@ -19,22 +19,33 @@
#ifndef DeleteRangeTxn_h__
#define DeleteRangeTxn_h__
#include "EditTxn.h"
#include "EditAggregateTxn.h"
#include "nsIDOMNode.h"
#include "nsIEditor.h"
#include "nsCOMPtr.h"
class nsIDOMDocument;
class nsIDOMRange;
class nsISupportsArray;
#define DELETE_RANGE_TXN_IID \
{/* 5ec6b260-ac49-11d2-86d8-000064657374 */ \
0x5ec6b260, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that deletes an entire range in the content tree
*/
class DeleteRangeTxn : public EditTxn
class DeleteRangeTxn : public EditAggregateTxn
{
public:
DeleteRangeTxn(nsEditor *aEditor,
nsIDOMRange *aRange);
virtual nsresult Init(nsIDOMRange *aRange);
private:
DeleteRangeTxn();
public:
virtual ~DeleteRangeTxn();
@ -54,6 +65,23 @@ public:
virtual nsresult GetRedoString(nsString **aString);
protected:
virtual nsresult CreateTxnsToDeleteBetween(nsIDOMNode *aStartParent,
PRUint32 aStartOffset,
PRUint32 aEndOffset);
virtual nsresult CreateTxnsToDeleteNodesBetween(nsIDOMNode *aParent,
nsIDOMNode *aFirstChild,
nsIDOMNode *aLastChild);
virtual nsresult CreateTxnsToDeleteContent(nsIDOMNode *aParent,
PRUint32 aOffset,
nsIEditor::Direction aDir);
virtual nsresult BuildAncestorList(nsIDOMNode *aNode,
nsISupportsArray *aList);
protected:
/** p1 in the range */
@ -65,9 +93,14 @@ protected:
/** p2 in the range */
nsCOMPtr<nsIDOMNode> mEndParent;
/** the closest common parent of p1 and p2 */
nsCOMPtr<nsIDOMNode> mCommonParent;
/** p2 offset */
PRInt32 mEndOffset;
friend class TransactionFactory;
};
#endif

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

@ -17,20 +17,23 @@
*/
#include "DeleteTextTxn.h"
#include "editor.h"
#include "nsIDOMCharacterData.h"
// note that aEditor is not refcounted
DeleteTextTxn::DeleteTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
DeleteTextTxn::DeleteTextTxn()
: EditTxn()
{
}
nsresult DeleteTextTxn::Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete)
: EditTxn(aEditor)
{
mElement = aElement;
mOffset = aOffset;
mNumCharsToDelete = aNumCharsToDelete;
mDeletedText = "";
return NS_OK;
}
nsresult DeleteTextTxn::Do(void)

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

@ -20,8 +20,13 @@
#define DeleteTextTxn_h__
#include "EditTxn.h"
#include "nsIDOMCharacterData.h"
#include "nsCOMPtr.h"
class nsIDOMCharacterData;
#define DELETE_TEXT_TXN_IID \
{/* 4d3a2720-ac49-11d2-86d8-000064657374 */ \
0x4d3a2720, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that changes an attribute of a content node.
@ -31,11 +36,15 @@ class DeleteTextTxn : public EditTxn
{
public:
DeleteTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete);
virtual nsresult Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete);
private:
DeleteTextTxn();
public:
virtual nsresult Do(void);
virtual nsresult Undo(void);
@ -53,7 +62,7 @@ public:
protected:
/** the text element to operate upon */
nsIDOMCharacterData *mElement;
nsCOMPtr<nsIDOMCharacterData> mElement;
/** the offset into mElement where the deletion is to take place */
PRUint32 mOffset;
@ -64,6 +73,8 @@ protected:
/** the text that was deleted */
nsString mDeletedText;
friend class TransactionFactory;
};
#endif

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

@ -0,0 +1,145 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL") you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "EditAggregateTxn.h"
#include "nsCOMPtr.h"
#include "nsIDOMNode.h"
#include "nsVoidArray.h"
EditAggregateTxn::EditAggregateTxn()
: EditTxn()
{
mChildren = new nsVoidArray();
}
EditAggregateTxn::~EditAggregateTxn()
{
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
for (i=0; i<count; i++)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
NS_IF_RELEASE(txn);
}
delete mChildren;
}
}
nsresult EditAggregateTxn::Do(void)
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
for (i=0; i<count; i++)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
result = txn->Do();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult EditAggregateTxn::Undo(void)
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
// undo goes through children backwards
for (i=count-1; i>=0; i--)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
result = txn->Undo();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult EditAggregateTxn::Redo(void)
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
for (i=0; i<count; i++)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
result = txn->Redo();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult EditAggregateTxn::GetIsTransient(PRBool *aIsTransient)
{
if (nsnull!=aIsTransient)
*aIsTransient = PR_TRUE;
return NS_OK;
}
nsresult EditAggregateTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
{
return NS_OK;
}
nsresult EditAggregateTxn::Write(nsIOutputStream *aOutputStream)
{
return NS_OK;
}
nsresult EditAggregateTxn::GetUndoString(nsString **aString)
{
if (nsnull!=aString)
*aString=nsnull;
return NS_OK;
}
nsresult EditAggregateTxn::GetRedoString(nsString **aString)
{
if (nsnull!=aString)
*aString=nsnull;
return NS_OK;
}
nsresult EditAggregateTxn::AppendChild(EditTxn *aTxn)
{
if ((nsnull!=mChildren) && (nsnull!=aTxn))
{
mChildren->AppendElement(aTxn);
return NS_OK;
}
return NS_ERROR_NULL_POINTER;
}

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

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef EditAggregateTxn_h__
#define EditAggregateTxn_h__
#include "EditTxn.h"
#define EDIT_AGGREGATE_TXN_IID \
{/* 345921a0-ac49-11d2-86d8-000064657374 */ \
0x345921a0, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
class nsVoidArray;
/**
* base class for all document editing transactions that require aggregation.
* provides a list of child transactions.
*/
class EditAggregateTxn : public EditTxn
{
public:
EditAggregateTxn();
virtual ~EditAggregateTxn();
virtual nsresult Do(void);
virtual nsresult Undo(void);
virtual nsresult Redo(void);
virtual nsresult GetIsTransient(PRBool *aIsTransient);
virtual nsresult Merge(PRBool *aDidMerge, nsITransaction *aTransaction);
virtual nsresult Write(nsIOutputStream *aOutputStream);
virtual nsresult GetUndoString(nsString **aString);
virtual nsresult GetRedoString(nsString **aString);
virtual nsresult AppendChild(EditTxn *aTxn);
protected:
nsVoidArray *mChildren;
};
#endif

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

@ -28,10 +28,8 @@ NS_IMPL_ADDREF(EditTxn)
NS_IMPL_RELEASE(EditTxn)
// note that aEditor is not refcounted
EditTxn::EditTxn(nsEditor *aEditor)
EditTxn::EditTxn()
{
NS_ASSERTION(nsnull!=aEditor, "null aEditor arg to EditTxn constructor");
mEditor = aEditor;
}
nsresult EditTxn::Do(void)

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

@ -20,13 +20,17 @@
#define EditTxn_h__
#include "nsITransaction.h"
class nsEditor;
class nsIDOMNode;
#define EDIT_TXN_IID \
{/* c5ea31b0-ac48-11d2-86d8-000064657374 */ \
0xc5ea31b0, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* base class for all document editing transactions.
* provides access to the nsEditor that created this transaction.
* provides default concrete behavior for all nsITransaction methods.
*/
class EditTxn : public nsITransaction
{
@ -34,7 +38,7 @@ public:
NS_DECL_ISUPPORTS
EditTxn(nsEditor *aEditor);
EditTxn();
virtual nsresult Do(void);
@ -52,10 +56,6 @@ public:
virtual nsresult GetRedoString(nsString **aString);
protected:
nsEditor *mEditor;
};
#endif

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

@ -20,18 +20,22 @@
#include "editor.h"
#include "nsIDOMCharacterData.h"
static NS_DEFINE_IID(kInsertTextTxnIID, INSERTTEXTTXN_IID);
static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID);
// note that aEditor is not refcounted
InsertTextTxn::InsertTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
InsertTextTxn::InsertTextTxn()
: EditTxn()
{
}
nsresult InsertTextTxn::Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert)
: EditTxn(aEditor)
{
mElement = aElement;
mOffset = aOffset;
mStringToInsert = aStringToInsert;
return NS_OK;
}
nsresult InsertTextTxn::Do(void)
@ -60,11 +64,11 @@ nsresult InsertTextTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
if ((nsnull!=aDidMerge) && (nsnull!=aTransaction))
{
// if aTransaction isa InsertTextTxn, absorb it
nsCOMPtr<InsertTextTxn> otherTxn;
nsresult result = aTransaction->QueryInterface(kInsertTextTxnIID, getter_AddRefs(otherTxn));
nsCOMPtr<InsertTextTxn> otherTxn = aTransaction;
nsresult result=NS_OK;// = aTransaction->QueryInterface(kInsertTextTxnIID, getter_AddRefs(otherTxn));
if (NS_SUCCEEDED(result) && (otherTxn))
{
nsString otherData;
nsAutoString otherData;
otherTxn->GetData(otherData);
mStringToInsert += otherData;
}

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

@ -20,14 +20,14 @@
#define InsertTextTxn_h__
#include "EditTxn.h"
#include "nsIDOMCharacterData.h"
#include "nsCOMPtr.h"
#define INSERTTEXTTXN_IID \
#define INSERT_TEXT_TXN_IID \
{/* 93276f00-ab2c-11d2-8f4b-006008159b0c*/ \
0x93276f00, 0xab2c, 0x11d2, \
{0x8f, 0xb4, 0x0, 0x60, 0x8, 0x15, 0x9b, 0xc} }
class nsIDOMCharacterData;
/**
* A transaction that changes an attribute of a content node.
* This transaction covers add, remove, and change attribute.
@ -36,15 +36,13 @@ class InsertTextTxn : public EditTxn
{
public:
InsertTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert);
virtual nsresult Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert);
private:
// default ctor so that nsCOMPtr is happy
InsertTextTxn() : EditTxn(nsnull) {}
InsertTextTxn();
public:
@ -67,7 +65,7 @@ public:
// override QueryInterface to handle InsertTextTxn request
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
static const nsIID& IID() { static nsIID iid = INSERTTEXTTXN_IID; return iid; }
static const nsIID& IID() { static nsIID iid = INSERT_TEXT_TXN_IID; return iid; }
virtual nsresult GetData(nsString& aResult);
@ -75,7 +73,7 @@ public:
protected:
/** the text element to operate upon */
nsIDOMCharacterData *mElement;
nsCOMPtr<nsIDOMCharacterData> mElement;
/** the offset into mElement where the insertion is to take place */
PRUint32 mOffset;
@ -86,6 +84,8 @@ protected:
/** the text to insert into mElement at mOffset */
nsString mStringToInsert;
friend class TransactionFactory;
};
#endif

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

@ -0,0 +1,122 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "JoinElementTxn.h"
#include "nsIDOMNodeList.h"
#include "editor.h"
JoinElementTxn::JoinElementTxn()
: EditTxn()
{
}
nsresult JoinElementTxn::Init(nsIDOMNode *aLeftNode,
nsIDOMNode *aRightNode)
{
mLeftNode = aLeftNode;
mRightNode = aRightNode;
mOffset=0;
return NS_OK;
}
JoinElementTxn::~JoinElementTxn()
{
}
nsresult JoinElementTxn::Do(void)
{
nsresult result;
if ((mLeftNode) && (mRightNode))
{ // get the parent node
nsCOMPtr<nsIDOMNode>leftParent;
result = mLeftNode->GetParentNode(getter_AddRefs(leftParent));
if ((NS_SUCCEEDED(result)) && (leftParent))
{ // verify that mLeftNode and mRightNode have the same parent
nsCOMPtr<nsIDOMNode>rightParent;
result = mRightNode->GetParentNode(getter_AddRefs(rightParent));
if ((NS_SUCCEEDED(result)) && (rightParent))
{
if (leftParent==rightParent)
{
mParent=leftParent; // set this instance mParent.
// Other methods see a non-null mParent and know all is well
nsCOMPtr<nsIDOMNodeList> childNodes;
result = mLeftNode->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
childNodes->GetLength(&mOffset);
}
result = nsEditor::JoinNodes(mLeftNode, mRightNode, mParent, PR_FALSE);
}
}
}
}
return result;
}
nsresult JoinElementTxn::Undo(void)
{
nsresult result = nsEditor::SplitNode(mRightNode, mOffset, mLeftNode, mParent);
return result;
}
nsresult JoinElementTxn::Redo(void)
{
nsresult result = nsEditor::JoinNodes(mLeftNode, mRightNode, mParent, PR_FALSE);
return result;
}
nsresult JoinElementTxn::GetIsTransient(PRBool *aIsTransient)
{
if (nsnull!=aIsTransient)
*aIsTransient = PR_FALSE;
return NS_OK;
}
nsresult JoinElementTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
{
if (nsnull!=aDidMerge)
*aDidMerge=PR_FALSE;
return NS_OK;
}
nsresult JoinElementTxn::Write(nsIOutputStream *aOutputStream)
{
return NS_OK;
}
nsresult JoinElementTxn::GetUndoString(nsString **aString)
{
if (nsnull!=aString)
{
**aString="Join Element";
}
return NS_OK;
}
nsresult JoinElementTxn::GetRedoString(nsString **aString)
{
if (nsnull!=aString)
{
**aString="Split Element";
}
return NS_OK;
}

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

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef JoinElementTxn_h__
#define JoinElementTxn_h__
#include "EditTxn.h"
#include "nsIDOMNode.h"
#include "nsCOMPtr.h"
#define JOIN_ELEMENT_TXN_IID \
{/* 9bc5f9f0-ac48-11d2-86d8-000064657374 */ \
0x9bc5f9f0, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that joins two elements E1 and E2 into a single node E.
* The children of E are the children of E1 followed by the children of E2.
*/
class JoinElementTxn : public EditTxn
{
public:
virtual nsresult Init(nsIDOMNode *aLeftNode,
nsIDOMNode *aRightNode);
protected:
JoinElementTxn();
public:
virtual ~JoinElementTxn();
virtual nsresult Do(void);
virtual nsresult Undo(void);
virtual nsresult Redo(void);
virtual nsresult GetIsTransient(PRBool *aIsTransient);
virtual nsresult Merge(PRBool *aDidMerge, nsITransaction *aTransaction);
virtual nsresult Write(nsIOutputStream *aOutputStream);
virtual nsresult GetUndoString(nsString **aString);
virtual nsresult GetRedoString(nsString **aString);
protected:
/** the elements to operate upon.
* After the merge, mRightNode remains and mLeftNode is removed from the content tree.
*/
nsCOMPtr<nsIDOMNode> mLeftNode;
nsCOMPtr<nsIDOMNode> mRightNode;
/** the offset into mNode where the children of mElement are split (for undo).<BR>
* mOffset is the index of the last child in the left node.
* -1 means the left node gets no children.
*/
PRUint32 mOffset;
/** the parent node containing mLeftNode and mRightNode */
nsCOMPtr<nsIDOMNode> mParent;
friend class TransactionFactory;
};
#endif

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

@ -30,12 +30,15 @@ CPPSRCS = \
nsEditFactory.cpp \
ChangeAttributeTxn.cpp \
EditTxn.cpp \
EditAggregateTxn.cpp \
InsertTextTxn.cpp \
DeleteTextTxn.cpp \
CreateElementTxn.cpp \
DeleteElementTxn.cpp \
DeleteRangeTxn.cpp \
SplitElementTxn.cpp \
JoinElementTxn.cpp \
TransactionFactory.cpp \
$(NULL)
MODULE = editor

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

@ -17,44 +17,42 @@
*/
#include "SplitElementTxn.h"
#include "editor.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "editor.h"
// note that aEditor is not refcounted
SplitElementTxn::SplitElementTxn(nsEditor *aEditor,
nsIDOMNode *aNode,
PRInt32 aOffset)
: EditTxn(aEditor)
SplitElementTxn::SplitElementTxn()
: EditTxn()
{
mNode = aNode;
NS_ADDREF(mNode);
}
nsresult SplitElementTxn::Init(nsIDOMNode *aNode,
PRInt32 aOffset)
{
mExistingRightNode = aNode;
mOffset = aOffset;
mNewNode = nsnull;
mParent = nsnull;
return NS_OK;
}
SplitElementTxn::~SplitElementTxn()
{
NS_IF_RELEASE(mNode);
NS_IF_RELEASE(mNewNode);
NS_IF_RELEASE(mParent);
}
nsresult SplitElementTxn::Do(void)
{
// create a new node
nsresult result = mNode->CloneNode(PR_FALSE, &mNewNode);
NS_ASSERTION(((NS_SUCCEEDED(result)) && (nsnull!=mNewNode)), "could not create element.");
nsresult result = mExistingRightNode->CloneNode(PR_FALSE, getter_AddRefs(mNewLeftNode));
NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewLeftNode)), "could not create element.");
if ((NS_SUCCEEDED(result)) && (nsnull!=mNewNode))
if ((NS_SUCCEEDED(result)) && (mNewLeftNode))
{
// get the parent node
result = mNode->GetParentNode(&mParent);
result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent));
// insert the new node
if ((NS_SUCCEEDED(result)) && (nsnull!=mParent))
if ((NS_SUCCEEDED(result)) && (mParent))
{
result = mEditor->SplitNode(mNode, mOffset, mNewNode, mParent);
result = nsEditor::SplitNode(mExistingRightNode, mOffset, mNewLeftNode, mParent);
}
}
return result;
@ -63,13 +61,13 @@ nsresult SplitElementTxn::Do(void)
nsresult SplitElementTxn::Undo(void)
{
// this assumes Do inserted the new node in front of the prior existing node
nsresult result = mEditor->JoinNodes(mNode, mNewNode, mParent, PR_FALSE);
nsresult result = nsEditor::JoinNodes(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE);
return result;
}
nsresult SplitElementTxn::Redo(void)
{
nsresult result = mEditor->SplitNode(mNode, mOffset, mNewNode, mParent);
nsresult result = nsEditor::SplitNode(mExistingRightNode, mOffset, mNewLeftNode, mParent);
return result;
}

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

@ -20,10 +20,13 @@
#define SplitElementTxn_h__
#include "EditTxn.h"
#include "nsIDOMNode.h"
#include "nsCOMPtr.h"
class nsIDOMNode;
class nsIDOMElement;
class nsIDOMDocument;
#define SPLIT_ELEMENT_TXN_IID \
{/* 690c6290-ac48-11d2-86d8-000064657374 */ \
0x690c6290, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that splits an element E into two identical nodes, E1 and E2
@ -33,10 +36,12 @@ class SplitElementTxn : public EditTxn
{
public:
SplitElementTxn(nsEditor *aEditor,
nsIDOMNode *aNode,
PRInt32 aOffset);
virtual nsresult Init (nsIDOMNode *aNode,
PRInt32 aOffset);
protected:
SplitElementTxn();
public:
virtual ~SplitElementTxn();
virtual nsresult Do(void);
@ -58,7 +63,7 @@ public:
protected:
/** the element to operate upon */
nsIDOMNode *mNode;
nsCOMPtr<nsIDOMNode> mExistingRightNode;
/** the offset into mElement where the children of mElement are split.<BR>
* mOffset is the index of the last child in the left node.
@ -67,8 +72,12 @@ protected:
PRInt32 mOffset;
/** the element we create when splitting mElement */
nsIDOMNode *mNewNode;
nsIDOMNode *mParent;
nsCOMPtr<nsIDOMNode> mNewLeftNode;
/** the parent shared by mExistingRightNode and mNewLeftNode */
nsCOMPtr<nsIDOMNode> mParent;
friend class TransactionFactory;
};

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

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "TransactionFactory.h"
// transactions this factory knows how to build
#include "InsertTextTxn.h"
#include "DeleteTextTxn.h"
#include "CreateElementTxn.h"
#include "DeleteElementTxn.h"
#include "DeleteRangeTxn.h"
#include "ChangeAttributeTxn.h"
#include "SplitElementTxn.h"
#include "JoinElementTxn.h"
static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID);
static NS_DEFINE_IID(kDeleteTextTxnIID, DELETE_TEXT_TXN_IID);
static NS_DEFINE_IID(kCreateElementTxnIID, CREATE_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kDeleteElementTxnIID, DELETE_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kDeleteRangeTxnIID, DELETE_RANGE_TXN_IID);
static NS_DEFINE_IID(kChangeAttributeTxnIID,CHANGE_ATTRIBUTE_TXN_IID);
static NS_DEFINE_IID(kSplitElementTxnIID, SPLIT_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kJoinElementTxnIID, JOIN_ELEMENT_TXN_IID);
TransactionFactory::TransactionFactory()
{
}
TransactionFactory::~TransactionFactory()
{
}
nsresult
TransactionFactory::GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult)
{
nsresult result = NS_OK;
*aResult = nsnull;
if (aTxnType.Equals(kInsertTextTxnIID))
*aResult = new InsertTextTxn();
else if (aTxnType.Equals(kDeleteTextTxnIID))
*aResult = new DeleteTextTxn();
else if (aTxnType.Equals(kCreateElementTxnIID))
*aResult = new CreateElementTxn();
else if (aTxnType.Equals(kDeleteElementTxnIID))
*aResult = new DeleteElementTxn();
else if (aTxnType.Equals(kDeleteRangeTxnIID))
*aResult = new DeleteRangeTxn();
else if (aTxnType.Equals(kChangeAttributeTxnIID))
*aResult = new ChangeAttributeTxn();
else if (aTxnType.Equals(kSplitElementTxnIID))
*aResult = new SplitElementTxn();
else if (aTxnType.Equals(kJoinElementTxnIID))
*aResult = new JoinElementTxn();
if (nsnull==*aResult)
result = NS_ERROR_INVALID_ARG;
return result;
}

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

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef TransactionFactory_h__
#define TransactionFactory_h__
#include "nsISupports.h"
class EditTxn;
/**
* This class instantiates and optionally recycles edit transactions
* A recycler would be a separate static object, since this class does not get instantiated
*/
class TransactionFactory
{
protected:
TransactionFactory();
virtual ~TransactionFactory();
public:
static nsresult GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult);
};
#endif

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

@ -33,16 +33,22 @@
#include "nsTransactionManagerCID.h"
#include "nsITransactionManager.h"
#include "nsIPresShell.h"
#include "nsIViewManager.h"
#include "nsISelection.h"
#include "nsICollection.h"
#include "nsIEnumerator.h"
#include "nsIAtom.h"
// transactions the editor knows how to build
#include "TransactionFactory.h"
#include "ChangeAttributeTxn.h"
#include "CreateElementTxn.h"
#include "DeleteElementTxn.h"
#include "InsertTextTxn.h"
#include "DeleteTextTxn.h"
#include "DeleteRangeTxn.h"
#include "SplitElementTxn.h"
#include "JoinElementTxn.h"
static NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID);
@ -58,8 +64,18 @@ static NS_DEFINE_IID(kIEditFactoryIID, NS_IEDITORFACTORY_IID);
static NS_DEFINE_IID(kIEditorIID, NS_IEDITOR_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kEditorCID, NS_EDITOR_CID);
// transaction manager
static NS_DEFINE_IID(kITransactionManagerIID, NS_ITRANSACTIONMANAGER_IID);
static NS_DEFINE_CID(kCTransactionManagerFactoryCID, NS_TRANSACTION_MANAGER_FACTORY_CID);
// transactions
static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID);
static NS_DEFINE_IID(kDeleteTextTxnIID, DELETE_TEXT_TXN_IID);
static NS_DEFINE_IID(kCreateElementTxnIID, CREATE_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kDeleteElementTxnIID, DELETE_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kDeleteRangeTxnIID, DELETE_RANGE_TXN_IID);
static NS_DEFINE_IID(kChangeAttributeTxnIID,CHANGE_ATTRIBUTE_TXN_IID);
static NS_DEFINE_IID(kSplitElementTxnIID, SPLIT_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kJoinElementTxnIID, JOIN_ELEMENT_TXN_IID);
#ifdef XP_PC
@ -165,6 +181,7 @@ nsEditor::nsEditor()
nsEditor::~nsEditor()
{
NS_IF_RELEASE(mPresShell);
NS_IF_RELEASE(mViewManager);
NS_IF_RELEASE(mTxnMgr);
//the autopointers will clear themselves up.
@ -229,6 +246,8 @@ nsEditor::Init(nsIDOMDocument *aDomInterface, nsIPresShell* aPresShell)
mDomInterfaceP = aDomInterface;
mPresShell = aPresShell;
NS_ADDREF(mPresShell);
mViewManager = mPresShell->GetViewManager();
mUpdateCount=0;
nsresult t_result = NS_NewEditorKeyListener(getter_AddRefs(mKeyListenerP), this);
if (NS_OK != t_result)
@ -308,13 +327,13 @@ nsEditor::Init(nsIDOMDocument *aDomInterface, nsIPresShell* aPresShell)
nsresult
nsEditor::InsertString(nsString *aString)
{
return AppendText(aString);
return NS_OK;
}
nsresult
nsEditor::SetProperties(PROPERTIES aProperty)
nsEditor::SetProperties(Properties aProperties)
{
return NS_OK;
}
@ -322,7 +341,7 @@ nsEditor::SetProperties(PROPERTIES aProperty)
nsresult
nsEditor::GetProperties(PROPERTIES **)
nsEditor::GetProperties(Properties **aProperties)
{
return NS_OK;
}
@ -334,9 +353,13 @@ nsEditor::SetAttribute(nsIDOMElement *aElement, const nsString& aAttribute, cons
nsresult result;
if (nsnull != aElement)
{
ChangeAttributeTxn *txn = new ChangeAttributeTxn(this, aElement, aAttribute, aValue, PR_FALSE);
ChangeAttributeTxn *txn;
result = TransactionFactory::GetNewTransaction(kChangeAttributeTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
{
txn->Init(this, aElement, aAttribute, aValue, PR_FALSE);
result = Do(txn);
}
}
return result;
}
@ -369,10 +392,14 @@ nsEditor::RemoveAttribute(nsIDOMElement *aElement, const nsString& aAttribute)
nsresult result;
if (nsnull != aElement)
{
nsString value;
ChangeAttributeTxn *txn = new ChangeAttributeTxn(this, aElement, aAttribute, value, PR_TRUE);
ChangeAttributeTxn *txn;
result = TransactionFactory::GetNewTransaction(kChangeAttributeTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
{
nsAutoString value;
txn->Init(this, aElement, aAttribute, value, PR_TRUE);
result = Do(txn);
}
}
return result;
}
@ -420,26 +447,6 @@ nsEditor::MouseClick(int aX,int aY)
//BEGIN nsEditor Private methods
nsresult
nsEditor::AppendText(nsString *aStr)
{
nsCOMPtr<nsIDOMNode> currentNode;
nsCOMPtr<nsIDOMNode> textNode;
nsCOMPtr<nsIDOMText> text;
if (!aStr)
return NS_ERROR_NULL_POINTER;
if (NS_SUCCEEDED(GetCurrentNode(getter_AddRefs(currentNode))) &&
NS_SUCCEEDED(GetFirstTextNode(currentNode,getter_AddRefs(textNode))) &&
NS_SUCCEEDED(textNode->QueryInterface(kIDOMTextIID, getter_AddRefs(text)))) {
text->AppendData(*aStr);
}
return NS_OK;
}
nsresult
nsEditor::GetCurrentNode(nsIDOMNode ** aNode)
{
@ -485,7 +492,7 @@ nsEditor::GetFirstNodeOfType(nsIDOMNode *aStartNode, const nsString &aTag, nsIDO
while (childNode)
{
result = childNode->QueryInterface(kIDOMNodeIID,getter_AddRefs(element));
nsString tag;
nsAutoString tag;
if (NS_SUCCEEDED(result) && (element))
{
element->GetTagName(tag);
@ -500,9 +507,8 @@ nsEditor::GetFirstNodeOfType(nsIDOMNode *aStartNode, const nsString &aTag, nsIDO
return result;
}
}
nsCOMPtr<nsIDOMNode> xNode;
childNode->GetNextSibling(getter_AddRefs(xNode));
childNode=xNode;
nsCOMPtr<nsIDOMNode> temp = childNode;
temp->GetNextSibling(getter_AddRefs(childNode));
}
return NS_ERROR_FAILURE;
@ -559,7 +565,7 @@ nsEditor::GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode)
}
nsresult
nsEditor::ExecuteTransaction(nsITransaction *aTxn)
nsEditor::Do(nsITransaction *aTxn)
{
nsresult result = NS_OK;
if (nsnull!=aTxn)
@ -577,27 +583,65 @@ nsEditor::ExecuteTransaction(nsITransaction *aTxn)
}
nsresult
nsEditor::Undo()
nsEditor::Undo(PRUint32 aCount)
{
nsresult result = NS_OK;
if (nsnull!=mTxnMgr)
{
result = mTxnMgr->Undo();
PRUint32 i=0;
for ( ; i<aCount; i++)
{
result = mTxnMgr->Undo();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult
nsEditor::Redo()
nsEditor::Redo(PRUint32 aCount)
{
nsresult result = NS_OK;
if (nsnull!=mTxnMgr)
{
result = mTxnMgr->Redo();
PRUint32 i=0;
for ( ; i<aCount; i++)
{
result = mTxnMgr->Redo();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult
nsEditor::BeginUpdate()
{
NS_PRECONDITION(mUpdateCount>=0, "bad state");
if (nsnull!=mViewManager)
{
if (0==mUpdateCount)
mViewManager->DisableRefresh();
mUpdateCount++;
}
return NS_OK;
}
nsresult
nsEditor::EndUpdate()
{
NS_PRECONDITION(mUpdateCount>0, "bad state");
if (nsnull!=mViewManager)
{
mUpdateCount--;
if (0==mUpdateCount)
mViewManager->EnableRefresh();
}
return NS_OK;
}
nsresult nsEditor::Delete(PRBool aForward, PRUint32 aCount)
{
return NS_OK;
@ -610,9 +654,13 @@ nsresult nsEditor::CreateElement(const nsString& aTag,
nsresult result;
if (nsnull != aParent)
{
CreateElementTxn *txn = new CreateElementTxn(this, mDomInterfaceP, aTag, aParent, aPosition);
CreateElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kCreateElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
{
txn->Init(mDomInterfaceP, aTag, aParent, aPosition);
result = Do(txn);
}
else
result = NS_ERROR_OUT_OF_MEMORY;
}
@ -628,9 +676,13 @@ nsresult nsEditor::DeleteElement(nsIDOMNode * aParent,
nsresult result;
if ((nsnull != aParent) && (nsnull != aElement))
{
DeleteElementTxn *txn = new DeleteElementTxn(this, mDomInterfaceP, aElement, aParent);
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
{
txn->Init(aElement, aParent);
result = Do(txn);
}
else
result = NS_ERROR_OUT_OF_MEMORY;
}
@ -640,18 +692,51 @@ nsresult nsEditor::DeleteElement(nsIDOMNode * aParent,
return result;
}
nsresult nsEditor::InsertText(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert)
// XXX; factor -- should call BuildInsertTextTransaction to do most of the work
nsresult nsEditor::InsertText(const nsString& aStringToInsert)
{
nsresult result;
if (nsnull != aElement)
nsISelection* selection;
result = mPresShell->GetSelection(&selection);
if ((NS_SUCCEEDED(result)) && (nsnull!=selection))
{
InsertTextTxn *txn = new InsertTextTxn(this, aElement, aOffset, aStringToInsert);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
else
result = NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsIEnumerator> enumerator;
enumerator = selection;
if (enumerator)
{
enumerator->First();
nsISupports *currentItem;
result = enumerator->CurrentItem(&currentItem);
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{
// XXX: we'll want to deleteRange if the selection isn't just an insertion point
// for now, just insert text after the start of the first node
nsCOMPtr<nsIDOMRange> range = currentItem;
if (range)
{
nsCOMPtr<nsIDOMNode> node;
result = range->GetStartParent(getter_AddRefs(node));
if ((NS_SUCCEEDED(result)) && (node))
{
nsCOMPtr<nsIDOMCharacterData> nodeAsText = node;
if (nodeAsText)
{
PRInt32 offset;
range->GetStartOffset(&offset);
InsertTextTxn *txn;
result = TransactionFactory::GetNewTransaction(kInsertTextTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(nodeAsText, offset, aStringToInsert);
result = Do(txn);
}
else
result = NS_ERROR_OUT_OF_MEMORY;
}
}
}
}
}
}
else
result = NS_ERROR_INVALID_ARG;
@ -659,6 +744,7 @@ nsresult nsEditor::InsertText(nsIDOMCharacterData *aElement,
return result;
}
// XXX; factor -- should call BuildDeleteTextTransaction to do most of the work
nsresult nsEditor::DeleteText(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aLength)
@ -666,9 +752,13 @@ nsresult nsEditor::DeleteText(nsIDOMCharacterData *aElement,
nsresult result=NS_OK;
if (nsnull != aElement)
{
DeleteTextTxn *txn = new DeleteTextTxn(this, aElement, aOffset, aLength);
DeleteTextTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteTextTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
{
txn->Init(aElement, aOffset, aLength);
result = Do(txn);
}
else
result = NS_ERROR_OUT_OF_MEMORY;
}
@ -678,6 +768,10 @@ nsresult nsEditor::DeleteText(nsIDOMCharacterData *aElement,
return result;
}
// XXX; factor -- should call DeleteSelectionTransaction to do most of the work
// XXX: these should get wrapped up in a single composite transaction
// rather than executing each individually, maybe I should alloc a generic aggregate
// and stick each in there, then execute the aggregate
nsresult nsEditor::DeleteSelection()
{
nsresult result;
@ -685,15 +779,34 @@ nsresult nsEditor::DeleteSelection()
result = mPresShell->GetSelection(&selection);
if ((NS_SUCCEEDED(result)) && (nsnull!=selection))
{
nsCOMPtr<nsIDOMRange> range;
result = selection->QueryInterface(kIDOMRangeIID, getter_AddRefs(range));
if ((NS_SUCCEEDED(result)) && (range))
nsCOMPtr<nsIEnumerator> enumerator;
enumerator = selection;
if (enumerator)
{
DeleteRangeTxn *txn = new DeleteRangeTxn(this, range);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
else
result = NS_ERROR_OUT_OF_MEMORY;
enumerator->First();
nsISupports *currentItem;
result = enumerator->CurrentItem(&currentItem);
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{
nsCOMPtr<nsIDOMRange> range = currentItem;
DeleteRangeTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteRangeTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(range);
result = Do(txn);
}
else
result = NS_ERROR_OUT_OF_MEMORY;
if (NS_SUCCEEDED(result))
{
nsresult nextResult = enumerator->Next();
if (NS_SUCCEEDED(nextResult))
{
result = enumerator->CurrentItem(&currentItem);
}
}
}
}
}
else
@ -703,30 +816,31 @@ nsresult nsEditor::DeleteSelection()
}
nsresult
nsEditor::SplitNode(nsIDOMNode * aNode,
nsEditor::SplitNode(nsIDOMNode * aExistingRightNode,
PRInt32 aOffset,
nsIDOMNode* aNewNode,
nsIDOMNode* aNewLeftNode,
nsIDOMNode* aParent)
{
nsresult result;
NS_ASSERTION(((nsnull!=aNode) &&
(nsnull!=aNewNode) &&
NS_ASSERTION(((nsnull!=aExistingRightNode) &&
(nsnull!=aNewLeftNode) &&
(nsnull!=aParent)),
"null arg");
if ((nsnull!=aNode) &&
(nsnull!=aNewNode) &&
if ((nsnull!=aExistingRightNode) &&
(nsnull!=aNewLeftNode) &&
(nsnull!=aParent))
{
nsCOMPtr<nsIDOMNode> resultNode;
result = aParent->InsertBefore(aNewNode, aNode, getter_AddRefs(resultNode));
result = aParent->InsertBefore(aNewLeftNode, aExistingRightNode, getter_AddRefs(resultNode));
if (NS_SUCCEEDED(result))
{
// split the children between the 2 nodes
// at this point, nNode has all the children
// at this point, aExistingRightNode has all the children
// move all the children whose index is < aOffset to aNewLeftNode
if (0<=aOffset) // don't bother unless we're going to move at least one child
{
nsCOMPtr<nsIDOMNodeList> childNodes;
result = aParent->GetChildNodes(getter_AddRefs(childNodes));
result = aExistingRightNode->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
PRInt32 i=0;
@ -736,10 +850,10 @@ nsEditor::SplitNode(nsIDOMNode * aNode,
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = aNode->RemoveChild(childNode, getter_AddRefs(resultNode));
result = aExistingRightNode->RemoveChild(childNode, getter_AddRefs(resultNode));
if (NS_SUCCEEDED(result))
{
result = aNewNode->AppendChild(childNode, getter_AddRefs(resultNode));
result = aNewLeftNode->AppendChild(childNode, getter_AddRefs(resultNode));
}
}
}

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

@ -16,6 +16,9 @@
* Reserved.
*/
#ifndef __editor_h__
#define __editor_h__
#include "prmon.h"
#include "nsIEditor.h"
#include "nsIContextLoader.h"
@ -24,11 +27,13 @@
#include "nsCOMPtr.h"
#include "editorInterfaces.h"
#include "nsITransactionManager.h"
#include "TransactionFactory.h"
#include "nsRepository.h"
//#include "nsISelection.h"
class nsIDOMCharacterData;
class nsIPresShell;
class nsIViewManager;
//This is the monitor for the editor.
PRMonitor *getEditorMonitor();
@ -42,15 +47,19 @@ PRMonitor *getEditorMonitor();
class nsEditor : public nsIEditor
{
private:
nsIPresShell *mPresShell;
nsIPresShell *mPresShell;
nsIViewManager *mViewManager;
PRUint32 mUpdateCount;
nsCOMPtr<nsIDOMDocument> mDomInterfaceP;
nsCOMPtr<nsIDOMEventListener> mKeyListenerP;
nsCOMPtr<nsIDOMEventListener> mMouseListenerP;
// nsCOMPtr<nsISelection> mSelectionP;
//nsCOMPtr<nsITransactionManager> mTxnMgrP;
nsITransactionManager * mTxnMgr;
friend PRBool NSCanUnload(void);
static PRInt32 gInstanceCount;
public:
/** The default constructor. This should suffice. the setting of the interfaces is done
* after the construction of the editor class.
@ -70,9 +79,9 @@ public:
virtual nsresult GetDomInterface(nsIDOMDocument **aDomInterface);
virtual nsresult SetProperties(PROPERTIES aProperty);
virtual nsresult SetProperties(Properties aProperties);
virtual nsresult GetProperties(PROPERTIES **);
virtual nsresult GetProperties(Properties **aProperties);
virtual nsresult SetAttribute(nsIDOMElement * aElement,
const nsString& aAttribute,
@ -85,11 +94,15 @@ public:
virtual nsresult RemoveAttribute(nsIDOMElement *aElement, const nsString& aAttribute);
virtual nsresult InsertString(nsString *aString);
virtual nsresult Commit(PRBool aCtrlKey);
virtual nsresult Do(nsITransaction *aTxn);
virtual nsresult Undo(PRUint32 aCount);
virtual nsresult Redo(PRUint32 aCount);
virtual nsresult BeginUpdate();
virtual nsresult EndUpdate();
/*END nsIEditor interfaces*/
@ -113,12 +126,6 @@ public:
/*BEGIN private methods used by the implementations of the above functions*/
/** AppendText is a private method that accepts a pointer to a string
* and will append it to the current node. this will be depricated
* @param nsString *aStr is the pointer to the valid string
*/
nsresult AppendText(nsString *aStr);
/** GetCurrentNode ADDREFFS and will get the current node from selection.
* now it simply returns the first node in the dom
* @param nsIDOMNode **aNode is the return location of the dom node
@ -142,33 +149,6 @@ public:
*/
nsresult GetFirstNodeOfType(nsIDOMNode *aStartNode, const nsString &aTag, nsIDOMNode **aResult);
/** ExecuteTransaction fires a transaction. It is provided here so
* clients need no knowledge of whether the editor has a transaction manager or not.
* If a transaction manager is present, it is used.
* Otherwise, the transaction is just executed directly.
*
* @param aTxn the transaction to execute
*/
nsresult ExecuteTransaction(nsITransaction *aTxn);
/** Undo reverses the effects of the last ExecuteTransaction operation
* It is provided here so clients need no knowledge of whether the editor has a transaction manager or not.
* If a transaction manager is present, it is told to undo and the result of
* that undo is returned.
* Otherwise, the Undo request is ignored.
*
*/
nsresult Undo();
/** Redo reverses the effects of the last Undo operation
* It is provided here so clients need no knowledge of whether the editor has a transaction manager or not.
* If a transaction manager is present, it is told to redo and the result of
* that redo is returned.
* Otherwise, the Redo request is ignored.
*
*/
nsresult Redo();
nsresult CreateElement(const nsString& aTag,
nsIDOMNode * aParent,
PRInt32 aPosition);
@ -178,17 +158,15 @@ public:
nsresult DeleteSelection();
nsresult InsertText(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert);
nsresult InsertText(const nsString& aStringToInsert);
nsresult DeleteText(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aLength);
static nsresult SplitNode(nsIDOMNode * aNode,
static nsresult SplitNode(nsIDOMNode * aExistingRightNode,
PRInt32 aOffset,
nsIDOMNode * aNewNode,
nsIDOMNode * aNewLeftNode,
nsIDOMNode * aParent);
static nsresult JoinNodes(nsIDOMNode * aNodeToKeep,
@ -198,6 +176,10 @@ public:
nsresult Delete(PRBool aForward, PRUint32 aCount);
virtual nsresult InsertString(nsString *aString);
virtual nsresult Commit(PRBool aCtrlKey);
/*END private methods of nsEditor*/
};
@ -207,3 +189,6 @@ factory method(s)
*/
nsresult NS_MakeEditorLoader(nsIContextLoader **aResult);
#endif

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

@ -19,7 +19,6 @@
#include "editor.h"
#include "CreateElementTxn.h"
#include "SplitElementTxn.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
@ -178,7 +177,7 @@ nsEditorKeyListener::KeyDown(nsIDOMEvent* aKeyEvent)
}
else
{ // XXX: delete the first P we find
nsString pTag("P");
nsAutoString pTag("P");
nsCOMPtr<nsIDOMNode> currentNode;
nsCOMPtr<nsIDOMNode> parentNode;
nsCOMPtr<nsIDOMElement> element;
@ -199,25 +198,12 @@ nsEditorKeyListener::KeyDown(nsIDOMEvent* aKeyEvent)
{
// XXX Replace with x-platform NS-virtkeycode transform.
if (NS_OK == GetCharFromKeyCode(keyCode, isShift, & character)) {
nsString key;
nsAutoString key;
key += character;
if (!isShift) {
key.ToLowerCase();
}
// XXX: for now, just grab the first text node
nsCOMPtr<nsIDOMNode> currentNode;
nsCOMPtr<nsIDOMNode> textNode;
nsCOMPtr<nsIDOMCharacterData> text;
if (NS_SUCCEEDED(mEditor->GetCurrentNode(getter_AddRefs(currentNode))) &&
NS_SUCCEEDED(mEditor->GetFirstTextNode(currentNode,getter_AddRefs(textNode))) &&
NS_SUCCEEDED(textNode->QueryInterface(kIDOMCharacterDataIID, getter_AddRefs(text))))
{
// XXX: for now, just append the text
PRUint32 offset;
text->GetLength(&offset);
mEditor->InsertText(text, offset, key);
}
mEditor->InsertText(key);
}
}
break;
@ -244,6 +230,10 @@ nsEditorKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
return NS_OK;
}
/* these includes are for debug only. this module should never instantiate it's own transactions */
#include "SplitElementTxn.h"
#include "TransactionFactory.h"
static NS_DEFINE_IID(kSplitElementTxnIID, SPLIT_ELEMENT_TXN_IID);
nsresult
nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProcessed)
{
@ -265,7 +255,7 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
if (PR_TRUE==ctrlKey)
{
if (nsnull!=mEditor)
mEditor->Undo();
mEditor->Undo(1);
}
aProcessed=PR_TRUE;
break;
@ -275,7 +265,7 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
if (PR_TRUE==ctrlKey)
{
if (nsnull!=mEditor)
mEditor->Redo();
mEditor->Redo(1);
}
aProcessed=PR_TRUE;
break;
@ -283,17 +273,27 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
// hard-coded split node test: works on first <P> in the document
case nsIDOMEvent::VK_S:
{
nsString pTag("P");
nsAutoString pTag("P");
nsCOMPtr<nsIDOMNode> currentNode;
nsCOMPtr<nsIDOMElement> element;
if (NS_SUCCEEDED(mEditor->GetFirstNodeOfType(nsnull, pTag, getter_AddRefs(currentNode))))
{
nsresult result;
SplitElementTxn *txn;
if (PR_FALSE==isShift) // split the element so there are 0 children in the first half
txn = new SplitElementTxn(mEditor, currentNode, -1);
{
result = TransactionFactory::GetNewTransaction(kSplitElementTxnIID, (EditTxn **)&txn);
if (txn)
txn->Init(currentNode, -1);
}
else // split the element so there are 2 children in the first half
txn = new SplitElementTxn(mEditor, currentNode, 1);
mEditor->ExecuteTransaction(txn);
{
result = TransactionFactory::GetNewTransaction(kSplitElementTxnIID, (EditTxn **)&txn);
if (txn)
txn->Init(currentNode, 1);
}
if (txn)
mEditor->Do(txn);
}
}
aProcessed=PR_TRUE;
@ -305,10 +305,10 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
{
//XXX: should be from a factory
//XXX: should manage the refcount of txn
nsString attribute("width");
nsString value("400");
nsAutoString attribute("width");
nsAutoString value("400");
nsString tableTag("TABLE");
nsAutoString tableTag("TABLE");
nsCOMPtr<nsIDOMNode> currentNode;
nsCOMPtr<nsIDOMElement> element;
if (NS_SUCCEEDED(mEditor->GetFirstNodeOfType(nsnull, tableTag, getter_AddRefs(currentNode))))
@ -331,11 +331,11 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
nsresult result;
//XXX: should be from a factory
//XXX: should manage the refcount of txn
nsString attribute("src");
nsString value("resource:/res/samples/raptor.jpg");
nsAutoString attribute("src");
nsAutoString value("resource:/res/samples/raptor.jpg");
nsString imgTag("HR");
nsString bodyTag("BODY");
nsAutoString imgTag("HR");
nsAutoString bodyTag("BODY");
nsCOMPtr<nsIDOMNode> currentNode;
result = mEditor->GetFirstNodeOfType(nsnull, bodyTag, getter_AddRefs(currentNode));
if (NS_SUCCEEDED(result))
@ -356,7 +356,7 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
{
ChangeAttributeTxn *txn;
txn = new ChangeAttributeTxn(mEditor, element, attribute, value, PR_FALSE);
mEditor->ExecuteTransaction(txn);
mEditor->Do(txn);
}
}
*/
@ -523,3 +523,4 @@ NS_NewEditorMouseListener(nsIDOMEventListener ** aInstancePtrResult, nsEditor *a
return it->QueryInterface(kIDOMEventListenerIID, (void **) aInstancePtrResult);
}

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

@ -25,6 +25,7 @@ CPPSRCS = \
editorInterfaces.cpp \
nsEditFactory.cpp \
EditTxn.cpp \
EditAggregateTxn.cpp \
ChangeAttributeTxn.cpp \
InsertTextTxn.cpp \
DeleteTextTxn.cpp \
@ -32,6 +33,8 @@ CPPSRCS = \
DeleteElementTxn.cpp \
DeleteRangeTxn.cpp \
SplitElementTxn.cpp \
JoinElementTxn.cpp \
TransactionFactory.cpp \
$(NULL)
CPP_OBJS = \
@ -39,6 +42,7 @@ CPP_OBJS = \
.\$(OBJDIR)\nsEditFactory.obj \
.\$(OBJDIR)\editorInterfaces.obj \
.\$(OBJDIR)\EditTxn.obj \
.\$(OBJDIR)\EditAggregateTxn.obj \
.\$(OBJDIR)\ChangeAttributeTxn.obj \
.\$(OBJDIR)\InsertTextTxn.obj \
.\$(OBJDIR)\DeleteTextTxn.obj \
@ -46,6 +50,8 @@ CPP_OBJS = \
.\$(OBJDIR)\DeleteElementTxn.obj \
.\$(OBJDIR)\DeleteRangeTxn.obj \
.\$(OBJDIR)\SplitElementTxn.obj \
.\$(OBJDIR)\JoinElementTxn.obj \
.\$(OBJDIR)\TransactionFactory.obj \
$(NULL)
MODULE=editor

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

@ -17,23 +17,33 @@
*/
#include "ChangeAttributeTxn.h"
#include "editor.h"
#include "nsIDOMElement.h"
#include "editor.h"
// note that aEditor is not refcounted
ChangeAttributeTxn::ChangeAttributeTxn(nsEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute)
: EditTxn(aEditor)
ChangeAttributeTxn::ChangeAttributeTxn()
: EditTxn()
{
mElement = aElement;
mAttribute = aAttribute;
mValue = aValue;
mRemoveAttribute = aRemoveAttribute;
mAttributeWasSet=PR_FALSE;
mUndoValue="";
}
nsresult ChangeAttributeTxn::Init(nsIEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute)
{
if (nsnull!=aEditor && nsnull!=aElement)
{
mEditor = aEditor;
mElement = aElement;
mAttribute = aAttribute;
mValue = aValue;
mRemoveAttribute = aRemoveAttribute;
mAttributeWasSet=PR_FALSE;
mUndoValue="";
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
nsresult ChangeAttributeTxn::Do(void)

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

@ -20,8 +20,14 @@
#define ChangeAttributeTxn_h__
#include "EditTxn.h"
#include "nsCOMPtr.h"
#include "nsIDOMElement.h"
#include "nsIEditor.h"
class nsIDOMElement;
#define CHANGE_ATTRIBUTE_TXN_IID \
{/* 97818860-ac48-11d2-86d8-000064657374 */ \
0x97818860, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that changes an attribute of a content node.
@ -31,11 +37,16 @@ class ChangeAttributeTxn : public EditTxn
{
public:
ChangeAttributeTxn(nsEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute);
virtual nsresult Init(nsIEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute);
private:
ChangeAttributeTxn();
public:
virtual nsresult Do(void);
@ -54,9 +65,12 @@ public:
virtual nsresult GetRedoString(nsString **aString);
protected:
/** the editor that created this transaction */
nsCOMPtr<nsIEditor> mEditor;
/** the element to operate upon */
nsIDOMElement *mElement;
nsCOMPtr<nsIDOMElement> mElement;
/** the attribute to change */
nsString mAttribute;
@ -72,6 +86,8 @@ protected:
/** PR_TRUE if the operation is to remove mAttribute from mElement */
PRBool mRemoveAttribute;
friend class TransactionFactory;
};
#endif

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

@ -17,52 +17,50 @@
*/
#include "CreateElementTxn.h"
#include "editor.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
// note that aEditor is not refcounted
CreateElementTxn::CreateElementTxn(nsEditor *aEditor,
nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent)
: EditTxn(aEditor)
CreateElementTxn::CreateElementTxn()
: EditTxn()
{
mDoc = aDoc;
NS_ADDREF(mDoc);
mTag = aTag;
mParent = aParent;
NS_ADDREF(mParent);
mOffsetInParent = aOffsetInParent;
mNewNode = nsnull;
mRefNode = nsnull;
}
nsresult CreateElementTxn::Init(nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent)
{
if ((nsnull!=aDoc) && (nsnull!=aParent))
{
mDoc = aDoc;
mTag = aTag;
mParent = aParent;
mOffsetInParent = aOffsetInParent;
mNewNode = nsnull;
mRefNode = nsnull;
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
CreateElementTxn::~CreateElementTxn()
{
NS_IF_RELEASE(mDoc);
NS_IF_RELEASE(mParent);
NS_IF_RELEASE(mNewNode);
}
nsresult CreateElementTxn::Do(void)
{
// create a new node
nsresult result = mDoc->CreateElement(mTag, &mNewNode);
NS_ASSERTION(((NS_SUCCEEDED(result)) && (nsnull!=mNewNode)), "could not create element.");
nsresult result = mDoc->CreateElement(mTag, getter_AddRefs(mNewNode));
NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewNode)), "could not create element.");
if ((NS_SUCCEEDED(result)) && (nsnull!=mNewNode))
if ((NS_SUCCEEDED(result)) && (mNewNode))
{
// insert the new node
nsIDOMNode *resultNode=nsnull;
nsCOMPtr<nsIDOMNode> resultNode;
if (CreateElementTxn::eAppend==mOffsetInParent)
{
result = mParent->AppendChild(mNewNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode); // this object already holds a ref from CreateElement
result = mParent->AppendChild(mNewNode, getter_AddRefs(resultNode));
}
else
{
@ -70,12 +68,10 @@ nsresult CreateElementTxn::Do(void)
result = mParent->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
result = childNodes->Item(mOffsetInParent, &mRefNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=mRefNode))
result = childNodes->Item(mOffsetInParent, getter_AddRefs(mRefNode));
if ((NS_SUCCEEDED(result)) && (mRefNode))
{
result = mParent->InsertBefore(mNewNode, mRefNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode); // this object already holds a ref from CreateElement
result = mParent->InsertBefore(mNewNode, mRefNode, getter_AddRefs(resultNode));
}
}
}
@ -85,20 +81,16 @@ nsresult CreateElementTxn::Do(void)
nsresult CreateElementTxn::Undo(void)
{
nsIDOMNode *resultNode=nsnull;
nsresult result = mParent->RemoveChild(mNewNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode);
nsCOMPtr<nsIDOMNode> resultNode;
nsresult result = mParent->RemoveChild(mNewNode, getter_AddRefs(resultNode));
return result;
}
nsresult CreateElementTxn::Redo(void)
{
nsIDOMNode *resultNode=nsnull;
nsresult result = mParent->InsertBefore(mNewNode, mRefNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode);
return result;
nsCOMPtr<nsIDOMNode> resultNode;
nsresult result = mParent->InsertBefore(mNewNode, mRefNode, getter_AddRefs(resultNode));
return result;
}
nsresult CreateElementTxn::GetIsTransient(PRBool *aIsTransient)

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

@ -20,10 +20,15 @@
#define CreateElementTxn_h__
#include "EditTxn.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "nsCOMPtr.h"
class nsIDOMDocument;
class nsIDOMNode;
class nsIDOMElement;
#define CREATE_ELEMENT_TXN_IID \
{/* 7a6393c0-ac48-11d2-86d8-000064657374 */ \
0x7a6393c0, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that creates a new node in the content tree.
@ -34,11 +39,15 @@ public:
enum { eAppend=-1 };
CreateElementTxn(nsEditor *aEditor,
nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent);
virtual nsresult Init(nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent);
private:
CreateElementTxn();
public:
virtual ~CreateElementTxn();
@ -61,22 +70,24 @@ public:
protected:
/** the document into which the new node will be inserted */
nsIDOMDocument *mDoc;
nsCOMPtr<nsIDOMDocument> mDoc;
/** the tag (mapping to object type) for the new element */
nsString mTag;
/** the node into which the new node will be inserted */
nsIDOMNode *mParent;
nsCOMPtr<nsIDOMNode> mParent;
/** the index in mParent for the new node */
PRUint32 mOffsetInParent;
/** the new node to insert */
nsIDOMElement *mNewNode;
nsCOMPtr<nsIDOMElement> mNewNode;
/** the node we will insert mNewNode before. We compute this ourselves. */
nsIDOMNode *mRefNode;
nsCOMPtr<nsIDOMNode> mRefNode;
friend class TransactionFactory;
};

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

@ -17,30 +17,32 @@
*/
#include "DeleteElementTxn.h"
#include "editor.h"
#include "nsIDOMDocument.h"
#ifdef NS_DEBUG
#include "nsIDOMElement.h"
#endif
// note that aEditor is not refcounted
DeleteElementTxn::DeleteElementTxn(nsEditor * aEditor,
nsIDOMDocument *aDoc,
nsIDOMNode * aElement,
nsIDOMNode * aParent)
: EditTxn(aEditor)
DeleteElementTxn::DeleteElementTxn()
: EditTxn()
{
mDoc = aDoc;
NS_ADDREF(mDoc);
mElement = aElement;
NS_ADDREF(mElement);
mParent = aParent;
NS_ADDREF(mParent);
}
nsresult DeleteElementTxn::Init(nsIDOMNode *aElement,
nsIDOMNode *aParent)
{
if ((nsnull!=aElement) && (nsnull!=aParent))
{
mElement = aElement;
mParent = aParent;
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
DeleteElementTxn::~DeleteElementTxn()
{
NS_IF_RELEASE(mDoc);
NS_IF_RELEASE(mParent);
NS_IF_RELEASE(mElement);
}
nsresult DeleteElementTxn::Do(void)
@ -48,11 +50,32 @@ nsresult DeleteElementTxn::Do(void)
if (!mParent || !mElement)
return NS_ERROR_NULL_POINTER;
#ifdef NS_DEBUG
// begin debug output
nsCOMPtr<nsIDOMElement> element=mElement;
nsAutoString elementTag="text node";
if (element)
element->GetTagName(elementTag);
nsCOMPtr<nsIDOMElement> parentElement=mParent;
nsAutoString parentElementTag="text node";
if (parentElement)
parentElement->GetTagName(parentElementTag);
char *c, *p;
c = elementTag.ToNewCString();
p = parentElementTag.ToNewCString();
if (c&&p)
{
printf("DeleteElementTxn: deleting child %s from parent %s\n", c, p);
delete [] c;
delete [] p;
}
// end debug output
// begin sanity check 1: parent-child relationship
nsresult testResult;
nsCOMPtr<nsIDOMNode> parentNode;
testResult = mElement->GetParentNode(getter_AddRefs(parentNode));
NS_ASSERTION((NS_SUCCEEDED(testResult)), "bad mElement, couldn't get parent");
NS_ASSERTION((parentNode==mParent), "bad mParent, mParent!=mElement->GetParent() ");
// end sanity check 1.
#endif
// remember which child mElement was (by remembering which child was next)

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

@ -23,8 +23,10 @@
#include "nsIDOMNode.h"
#include "nsCOMPtr.h"
class nsIDOMDocument;
class nsIDOMElement;
#define DELETE_ELEMENT_TXN_IID \
{/* 6fd77770-ac49-11d2-86d8-000064657374 */ \
0x6fd77770, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that deletes a single element
@ -33,10 +35,13 @@ class DeleteElementTxn : public EditTxn
{
public:
DeleteElementTxn(nsEditor *aEditor,
nsIDOMDocument *aDoc,
nsIDOMNode *aElement,
nsIDOMNode *aParent);
virtual nsresult Init(nsIDOMNode *aElement,
nsIDOMNode *aParent);
private:
DeleteElementTxn();
public:
virtual ~DeleteElementTxn();
@ -58,14 +63,11 @@ public:
protected:
/** the document into which the new node will be inserted */
nsIDOMDocument *mDoc;
/** the element to delete */
nsIDOMNode *mElement;
nsCOMPtr<nsIDOMNode> mElement;
/** the node into which the new node will be inserted */
nsIDOMNode *mParent;
nsCOMPtr<nsIDOMNode> mParent;
/** the index in mParent for the new node */
PRUint32 mOffsetInParent;
@ -73,6 +75,8 @@ protected:
/** the node we will insert mNewNode before. We compute this ourselves. */
nsCOMPtr<nsIDOMNode> mRefNode;
friend class TransactionFactory;
};
#endif

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

@ -17,18 +17,73 @@
*/
#include "DeleteRangeTxn.h"
#include "editor.h"
#include "nsIDOMRange.h"
#include "nsIDOMCharacterData.h"
#include "nsIDOMNodeList.h"
#include "DeleteTextTxn.h"
#include "DeleteElementTxn.h"
#include "TransactionFactory.h"
#include "nsISupportsArray.h"
static NS_DEFINE_IID(kDeleteTextTxnIID, DELETE_TEXT_TXN_IID);
static NS_DEFINE_IID(kDeleteElementTxnIID, DELETE_ELEMENT_TXN_IID);
// note that aEditor is not refcounted
DeleteRangeTxn::DeleteRangeTxn(nsEditor *aEditor,
nsIDOMRange *aRange)
: EditTxn(aEditor)
DeleteRangeTxn::DeleteRangeTxn()
: EditAggregateTxn()
{
aRange->GetStartParent(getter_AddRefs(mStartParent));
aRange->GetEndParent(getter_AddRefs(mEndParent));
aRange->GetStartOffset(&mStartOffset);
aRange->GetEndOffset(&mEndOffset);
}
nsresult DeleteRangeTxn::Init(nsIDOMRange *aRange)
{
if (nsnull!=aRange)
{
nsresult result = aRange->GetStartParent(getter_AddRefs(mStartParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetStartParent failed.");
result = aRange->GetEndParent(getter_AddRefs(mEndParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetEndParent failed.");
result = aRange->GetStartOffset(&mStartOffset);
NS_ASSERTION((NS_SUCCEEDED(result)), "GetStartOffset failed.");
result = aRange->GetEndOffset(&mEndOffset);
NS_ASSERTION((NS_SUCCEEDED(result)), "GetEndOffset failed.");
result = aRange->GetCommonParent(getter_AddRefs(mCommonParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetCommonParent failed.");
#ifdef NS_DEBUG
PRUint32 count;
nsCOMPtr<nsIDOMCharacterData> textNode;
textNode = mStartParent;
if (textNode)
textNode->GetLength(&count);
else
{
nsCOMPtr<nsIDOMNodeList> children;
result = mStartParent->GetChildNodes(getter_AddRefs(children));
NS_ASSERTION(((NS_SUCCEEDED(result)) && children), "bad start child list");
children->GetLength(&count);
}
NS_ASSERTION(mStartOffset<count, "bad start offset");
textNode = mEndParent;
if (textNode)
textNode->GetLength(&count);
else
{
nsCOMPtr<nsIDOMNodeList> children;
result = mEndParent->GetChildNodes(getter_AddRefs(children));
NS_ASSERTION(((NS_SUCCEEDED(result)) && children), "bad end child list");
children->GetLength(&count);
}
NS_ASSERTION(mEndOffset<count, "bad end offset");
printf ("DeleteRange: %d of %p to %d of %p\n",
mStartOffset, (void *)mStartParent, mEndOffset, (void *)mEndParent);
#endif
return result;
}
else
return NS_ERROR_NULL_POINTER;
}
DeleteRangeTxn::~DeleteRangeTxn()
@ -37,28 +92,59 @@ DeleteRangeTxn::~DeleteRangeTxn()
nsresult DeleteRangeTxn::Do(void)
{
if (!mStartParent || !mEndParent)
if (!mStartParent || !mEndParent || !mCommonParent)
return NS_ERROR_NULL_POINTER;
nsresult result;
// build the child transactions
if (mStartParent==mEndParent)
{ // the selection begins and ends in the same node
result = CreateTxnsToDeleteBetween(mStartParent, mStartOffset, mEndOffset);
}
else
{ // the selection ends in a different node from where it started
// delete the relevant content in the start node
result = CreateTxnsToDeleteContent(mStartParent, mStartOffset, nsIEditor::eLTR);
if (NS_SUCCEEDED(result))
{
// delete the intervening nodes
result = CreateTxnsToDeleteNodesBetween(mCommonParent, mStartParent, mEndParent);
if (NS_SUCCEEDED(result))
{
// delete the relevant content in the end node
result = CreateTxnsToDeleteContent(mEndParent, mEndOffset, nsIEditor::eRTL);
if (NS_SUCCEEDED(result))
{ // now we have all our child transactions, do them
result = EditAggregateTxn::Do();
}
}
}
}
// if we've successfully built this aggregate transaction, then do it.
if (NS_SUCCEEDED(result))
result = EditAggregateTxn::Do();
return result;
}
nsresult DeleteRangeTxn::Undo(void)
{
if (!mStartParent || !mEndParent)
if (!mStartParent || !mEndParent || !mCommonParent)
return NS_ERROR_NULL_POINTER;
nsresult result;
nsresult result = EditAggregateTxn::Undo();
return result;
}
nsresult DeleteRangeTxn::Redo(void)
{
if (!mStartParent || !mEndParent)
if (!mStartParent || !mEndParent || !mCommonParent)
return NS_ERROR_NULL_POINTER;
nsresult result;
nsresult result = EditAggregateTxn::Redo();
return result;
}
@ -98,3 +184,265 @@ nsresult DeleteRangeTxn::GetRedoString(nsString **aString)
}
return NS_OK;
}
nsresult DeleteRangeTxn::CreateTxnsToDeleteBetween(nsIDOMNode *aStartParent,
PRUint32 aStartOffset,
PRUint32 aEndOffset)
{
nsresult result;
// see what kind of node we have
nsCOMPtr<nsIDOMCharacterData> textNode;
textNode = aStartParent; // this uses implicit nsCOMPtr QI
if (textNode)
{ // if the node is a text node, then delete text content
DeleteTextTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteTextTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(textNode, aStartOffset, (aEndOffset-aStartOffset)+1);
AppendChild(txn);
}
}
else
{
PRUint32 childCount;
nsCOMPtr<nsIDOMNodeList> children;
result = aStartParent->GetChildNodes(getter_AddRefs(children));
if ((NS_SUCCEEDED(result)) && children)
{
children->GetLength(&childCount);
NS_ASSERTION(aEndOffset<childCount, "bad aEndOffset");
PRUint32 i;
for (i=aStartOffset; i<=aEndOffset; i++)
{
nsCOMPtr<nsIDOMNode> child;
result = children->Item(i, getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, aStartParent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
}
}
return result;
}
nsresult DeleteRangeTxn::CreateTxnsToDeleteContent(nsIDOMNode *aParent,
PRUint32 aOffset,
nsIEditor::Direction aDir)
{
nsresult result;
// see what kind of node we have
nsCOMPtr<nsIDOMCharacterData> textNode;
textNode = aParent; // this uses implicit nsCOMPtr QI
if (textNode)
{ // if the node is a text node, then delete text content
PRUint32 start, numToDelete;
if (nsIEditor::eLTR==aDir)
{
start=aOffset;
textNode->GetLength(&numToDelete);
numToDelete -= (aOffset+1);
}
else
{
start=0;
numToDelete=aOffset;
}
DeleteTextTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteTextTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(textNode, start, numToDelete);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
else
{ // we have an interior node, so delete some of its children
if (nsIEditor::eLTR==aDir)
{ // delete from aOffset to end
PRUint32 childCount;
nsCOMPtr<nsIDOMNodeList> children;
result = aParent->GetChildNodes(getter_AddRefs(children));
if ((NS_SUCCEEDED(result)) && children)
{
children->GetLength(&childCount);
PRUint32 i;
for (i=aOffset; i<childCount; i++)
{
nsCOMPtr<nsIDOMNode> child;
result = children->Item(i, getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, aParent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
}
}
else
{ // delete from 0 to aOffset
nsCOMPtr<nsIDOMNode> child;
result = aParent->GetFirstChild(getter_AddRefs(child));
for (PRUint32 i=0; i<aOffset; i++)
{
if ((NS_SUCCEEDED(result)) && child)
{
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, aParent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIDOMNode> temp = child;
result = temp->GetNextSibling(getter_AddRefs(child));
}
}
}
return result;
}
nsresult DeleteRangeTxn::CreateTxnsToDeleteNodesBetween(nsIDOMNode *aCommonParent,
nsIDOMNode *aFirstChild,
nsIDOMNode *aLastChild)
{
nsresult result;
PRBool needToProcessLastChild=PR_TRUE; // set to false if we discover we can delete all required nodes by just walking up aFirstChild's parent list
nsCOMPtr<nsIDOMNode> parent; // the current parent in the iteration up the ancestors
nsCOMPtr<nsIDOMNode> child; // the current child of parent
nsISupportsArray *ancestorList; // the ancestorList of the other endpoint, used to gate deletion
NS_NewISupportsArray(&ancestorList);
if (nsnull==ancestorList)
return NS_ERROR_NULL_POINTER;
// Walk up the parent list of aFirstChild to aCommonParent,
// deleting all siblings to the right of the ancestors of aFirstChild.
BuildAncestorList(aLastChild, ancestorList);
child = aFirstChild;
result = child->GetParentNode(getter_AddRefs(parent));
while ((NS_SUCCEEDED(result)) && parent)
{
while ((NS_SUCCEEDED(result)) && child)
{ // this loop starts with the first sibling of an ancestor of aFirstChild
nsCOMPtr<nsIDOMNode> temp = child;
result = temp->GetNextSibling(getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
if (child==aLastChild)
{ // aFirstChild and aLastChild have the same parent, and we've reached aLastChild
needToProcessLastChild = PR_FALSE;
break;
}
// test if child is an ancestor of the other node. If it is, don't process this parent anymore
PRInt32 index;
index = ancestorList->IndexOf((nsISupports*)child);
if (-1!=index)
break;
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, parent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
if (parent==aCommonParent)
break;
child = parent;
nsCOMPtr<nsIDOMNode> temp=parent;
result = temp->GetParentNode(getter_AddRefs(parent));
}
// Walk up the parent list of aLastChild to aCommonParent,
// deleting all siblings to the left of the ancestors of aLastChild.
BuildAncestorList(aFirstChild, ancestorList);
if (PR_TRUE==needToProcessLastChild)
{
child = aLastChild;
result = child->GetParentNode(getter_AddRefs(parent));
while ((NS_SUCCEEDED(result)) && parent)
{
while ((NS_SUCCEEDED(result)) && child)
{ // this loop starts with the first sibling of an ancestor of aFirstChild
nsCOMPtr<nsIDOMNode> temp = child;
result = temp->GetPreviousSibling(getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
// test if child is an ancestor of the other node. If it is, don't process this parent anymore
PRInt32 index;
index = ancestorList->IndexOf((nsISupports*)child);
if (-1!=index)
break;
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, parent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
if (parent==aCommonParent)
break;
child = parent;
nsCOMPtr<nsIDOMNode> temp=parent;
result = temp->GetParentNode(getter_AddRefs(parent));
}
}
NS_RELEASE(ancestorList);
return result;
}
nsresult DeleteRangeTxn::BuildAncestorList(nsIDOMNode *aNode, nsISupportsArray *aList)
{
nsresult result=NS_OK;
if (nsnull!=aNode && nsnull!=aList)
{
aList->Clear();
nsCOMPtr<nsIDOMNode> parent;
nsCOMPtr<nsIDOMNode> child = aNode;
result = child->GetParentNode(getter_AddRefs(parent));
while ((NS_SUCCEEDED(result)) && child && parent)
{
nsISupports * parentAsISupports;
parent->QueryInterface(nsISupports::IID(), (void **)&parentAsISupports);
aList->AppendElement(parentAsISupports);
child = parent;
nsCOMPtr<nsIDOMNode> temp=parent;
result = temp->GetParentNode(getter_AddRefs(parent));
}
}
else
result = NS_ERROR_NULL_POINTER;
return result;
}

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

@ -19,22 +19,33 @@
#ifndef DeleteRangeTxn_h__
#define DeleteRangeTxn_h__
#include "EditTxn.h"
#include "EditAggregateTxn.h"
#include "nsIDOMNode.h"
#include "nsIEditor.h"
#include "nsCOMPtr.h"
class nsIDOMDocument;
class nsIDOMRange;
class nsISupportsArray;
#define DELETE_RANGE_TXN_IID \
{/* 5ec6b260-ac49-11d2-86d8-000064657374 */ \
0x5ec6b260, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that deletes an entire range in the content tree
*/
class DeleteRangeTxn : public EditTxn
class DeleteRangeTxn : public EditAggregateTxn
{
public:
DeleteRangeTxn(nsEditor *aEditor,
nsIDOMRange *aRange);
virtual nsresult Init(nsIDOMRange *aRange);
private:
DeleteRangeTxn();
public:
virtual ~DeleteRangeTxn();
@ -54,6 +65,23 @@ public:
virtual nsresult GetRedoString(nsString **aString);
protected:
virtual nsresult CreateTxnsToDeleteBetween(nsIDOMNode *aStartParent,
PRUint32 aStartOffset,
PRUint32 aEndOffset);
virtual nsresult CreateTxnsToDeleteNodesBetween(nsIDOMNode *aParent,
nsIDOMNode *aFirstChild,
nsIDOMNode *aLastChild);
virtual nsresult CreateTxnsToDeleteContent(nsIDOMNode *aParent,
PRUint32 aOffset,
nsIEditor::Direction aDir);
virtual nsresult BuildAncestorList(nsIDOMNode *aNode,
nsISupportsArray *aList);
protected:
/** p1 in the range */
@ -65,9 +93,14 @@ protected:
/** p2 in the range */
nsCOMPtr<nsIDOMNode> mEndParent;
/** the closest common parent of p1 and p2 */
nsCOMPtr<nsIDOMNode> mCommonParent;
/** p2 offset */
PRInt32 mEndOffset;
friend class TransactionFactory;
};
#endif

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

@ -17,20 +17,23 @@
*/
#include "DeleteTextTxn.h"
#include "editor.h"
#include "nsIDOMCharacterData.h"
// note that aEditor is not refcounted
DeleteTextTxn::DeleteTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
DeleteTextTxn::DeleteTextTxn()
: EditTxn()
{
}
nsresult DeleteTextTxn::Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete)
: EditTxn(aEditor)
{
mElement = aElement;
mOffset = aOffset;
mNumCharsToDelete = aNumCharsToDelete;
mDeletedText = "";
return NS_OK;
}
nsresult DeleteTextTxn::Do(void)

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

@ -20,8 +20,13 @@
#define DeleteTextTxn_h__
#include "EditTxn.h"
#include "nsIDOMCharacterData.h"
#include "nsCOMPtr.h"
class nsIDOMCharacterData;
#define DELETE_TEXT_TXN_IID \
{/* 4d3a2720-ac49-11d2-86d8-000064657374 */ \
0x4d3a2720, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that changes an attribute of a content node.
@ -31,11 +36,15 @@ class DeleteTextTxn : public EditTxn
{
public:
DeleteTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete);
virtual nsresult Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete);
private:
DeleteTextTxn();
public:
virtual nsresult Do(void);
virtual nsresult Undo(void);
@ -53,7 +62,7 @@ public:
protected:
/** the text element to operate upon */
nsIDOMCharacterData *mElement;
nsCOMPtr<nsIDOMCharacterData> mElement;
/** the offset into mElement where the deletion is to take place */
PRUint32 mOffset;
@ -64,6 +73,8 @@ protected:
/** the text that was deleted */
nsString mDeletedText;
friend class TransactionFactory;
};
#endif

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

@ -0,0 +1,145 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL") you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "EditAggregateTxn.h"
#include "nsCOMPtr.h"
#include "nsIDOMNode.h"
#include "nsVoidArray.h"
EditAggregateTxn::EditAggregateTxn()
: EditTxn()
{
mChildren = new nsVoidArray();
}
EditAggregateTxn::~EditAggregateTxn()
{
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
for (i=0; i<count; i++)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
NS_IF_RELEASE(txn);
}
delete mChildren;
}
}
nsresult EditAggregateTxn::Do(void)
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
for (i=0; i<count; i++)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
result = txn->Do();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult EditAggregateTxn::Undo(void)
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
// undo goes through children backwards
for (i=count-1; i>=0; i--)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
result = txn->Undo();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult EditAggregateTxn::Redo(void)
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
for (i=0; i<count; i++)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
result = txn->Redo();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult EditAggregateTxn::GetIsTransient(PRBool *aIsTransient)
{
if (nsnull!=aIsTransient)
*aIsTransient = PR_TRUE;
return NS_OK;
}
nsresult EditAggregateTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
{
return NS_OK;
}
nsresult EditAggregateTxn::Write(nsIOutputStream *aOutputStream)
{
return NS_OK;
}
nsresult EditAggregateTxn::GetUndoString(nsString **aString)
{
if (nsnull!=aString)
*aString=nsnull;
return NS_OK;
}
nsresult EditAggregateTxn::GetRedoString(nsString **aString)
{
if (nsnull!=aString)
*aString=nsnull;
return NS_OK;
}
nsresult EditAggregateTxn::AppendChild(EditTxn *aTxn)
{
if ((nsnull!=mChildren) && (nsnull!=aTxn))
{
mChildren->AppendElement(aTxn);
return NS_OK;
}
return NS_ERROR_NULL_POINTER;
}

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

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef EditAggregateTxn_h__
#define EditAggregateTxn_h__
#include "EditTxn.h"
#define EDIT_AGGREGATE_TXN_IID \
{/* 345921a0-ac49-11d2-86d8-000064657374 */ \
0x345921a0, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
class nsVoidArray;
/**
* base class for all document editing transactions that require aggregation.
* provides a list of child transactions.
*/
class EditAggregateTxn : public EditTxn
{
public:
EditAggregateTxn();
virtual ~EditAggregateTxn();
virtual nsresult Do(void);
virtual nsresult Undo(void);
virtual nsresult Redo(void);
virtual nsresult GetIsTransient(PRBool *aIsTransient);
virtual nsresult Merge(PRBool *aDidMerge, nsITransaction *aTransaction);
virtual nsresult Write(nsIOutputStream *aOutputStream);
virtual nsresult GetUndoString(nsString **aString);
virtual nsresult GetRedoString(nsString **aString);
virtual nsresult AppendChild(EditTxn *aTxn);
protected:
nsVoidArray *mChildren;
};
#endif

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

@ -28,10 +28,8 @@ NS_IMPL_ADDREF(EditTxn)
NS_IMPL_RELEASE(EditTxn)
// note that aEditor is not refcounted
EditTxn::EditTxn(nsEditor *aEditor)
EditTxn::EditTxn()
{
NS_ASSERTION(nsnull!=aEditor, "null aEditor arg to EditTxn constructor");
mEditor = aEditor;
}
nsresult EditTxn::Do(void)

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

@ -1,61 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef EditTxn_h__
#define EditTxn_h__
#include "nsITransaction.h"
class nsEditor;
class nsIDOMNode;
/**
* base class for all document editing transactions.
* provides access to the nsEditor that created this transaction.
*/
class EditTxn : public nsITransaction
{
public:
NS_DECL_ISUPPORTS
EditTxn(nsEditor *aEditor);
virtual nsresult Do(void);
virtual nsresult Undo(void);
virtual nsresult Redo(void);
virtual nsresult GetIsTransient(PRBool *aIsTransient);
virtual nsresult Merge(PRBool *aDidMerge, nsITransaction *aTransaction);
virtual nsresult Write(nsIOutputStream *aOutputStream);
virtual nsresult GetUndoString(nsString **aString);
virtual nsresult GetRedoString(nsString **aString);
protected:
nsEditor *mEditor;
};
#endif

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

@ -20,18 +20,22 @@
#include "editor.h"
#include "nsIDOMCharacterData.h"
static NS_DEFINE_IID(kInsertTextTxnIID, INSERTTEXTTXN_IID);
static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID);
// note that aEditor is not refcounted
InsertTextTxn::InsertTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
InsertTextTxn::InsertTextTxn()
: EditTxn()
{
}
nsresult InsertTextTxn::Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert)
: EditTxn(aEditor)
{
mElement = aElement;
mOffset = aOffset;
mStringToInsert = aStringToInsert;
return NS_OK;
}
nsresult InsertTextTxn::Do(void)
@ -60,11 +64,11 @@ nsresult InsertTextTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
if ((nsnull!=aDidMerge) && (nsnull!=aTransaction))
{
// if aTransaction isa InsertTextTxn, absorb it
nsCOMPtr<InsertTextTxn> otherTxn;
nsresult result = aTransaction->QueryInterface(kInsertTextTxnIID, getter_AddRefs(otherTxn));
nsCOMPtr<InsertTextTxn> otherTxn = aTransaction;
nsresult result=NS_OK;// = aTransaction->QueryInterface(kInsertTextTxnIID, getter_AddRefs(otherTxn));
if (NS_SUCCEEDED(result) && (otherTxn))
{
nsString otherData;
nsAutoString otherData;
otherTxn->GetData(otherData);
mStringToInsert += otherData;
}

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

@ -20,14 +20,14 @@
#define InsertTextTxn_h__
#include "EditTxn.h"
#include "nsIDOMCharacterData.h"
#include "nsCOMPtr.h"
#define INSERTTEXTTXN_IID \
#define INSERT_TEXT_TXN_IID \
{/* 93276f00-ab2c-11d2-8f4b-006008159b0c*/ \
0x93276f00, 0xab2c, 0x11d2, \
{0x8f, 0xb4, 0x0, 0x60, 0x8, 0x15, 0x9b, 0xc} }
class nsIDOMCharacterData;
/**
* A transaction that changes an attribute of a content node.
* This transaction covers add, remove, and change attribute.
@ -36,15 +36,13 @@ class InsertTextTxn : public EditTxn
{
public:
InsertTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert);
virtual nsresult Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert);
private:
// default ctor so that nsCOMPtr is happy
InsertTextTxn() : EditTxn(nsnull) {}
InsertTextTxn();
public:
@ -67,7 +65,7 @@ public:
// override QueryInterface to handle InsertTextTxn request
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
static const nsIID& IID() { static nsIID iid = INSERTTEXTTXN_IID; return iid; }
static const nsIID& IID() { static nsIID iid = INSERT_TEXT_TXN_IID; return iid; }
virtual nsresult GetData(nsString& aResult);
@ -75,7 +73,7 @@ public:
protected:
/** the text element to operate upon */
nsIDOMCharacterData *mElement;
nsCOMPtr<nsIDOMCharacterData> mElement;
/** the offset into mElement where the insertion is to take place */
PRUint32 mOffset;
@ -86,6 +84,8 @@ protected:
/** the text to insert into mElement at mOffset */
nsString mStringToInsert;
friend class TransactionFactory;
};
#endif

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

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

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

@ -1,48 +0,0 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH=../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
LIBRARY_NAME = ender
CPPSRCS = \
editor.cpp \
editorInterfaces.cpp \
nsEditFactory.cpp \
ChangeAttributeTxn.cpp \
EditTxn.cpp \
InsertTextTxn.cpp \
DeleteTextTxn.cpp \
CreateElementTxn.cpp \
DeleteElementTxn.cpp \
DeleteRangeTxn.cpp \
SplitElementTxn.cpp \
$(NULL)
MODULE = editor
REQUIRES = xpcom raptor dom base
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/config/rules.mk

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

@ -17,44 +17,42 @@
*/
#include "SplitElementTxn.h"
#include "editor.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "editor.h"
// note that aEditor is not refcounted
SplitElementTxn::SplitElementTxn(nsEditor *aEditor,
nsIDOMNode *aNode,
PRInt32 aOffset)
: EditTxn(aEditor)
SplitElementTxn::SplitElementTxn()
: EditTxn()
{
mNode = aNode;
NS_ADDREF(mNode);
}
nsresult SplitElementTxn::Init(nsIDOMNode *aNode,
PRInt32 aOffset)
{
mExistingRightNode = aNode;
mOffset = aOffset;
mNewNode = nsnull;
mParent = nsnull;
return NS_OK;
}
SplitElementTxn::~SplitElementTxn()
{
NS_IF_RELEASE(mNode);
NS_IF_RELEASE(mNewNode);
NS_IF_RELEASE(mParent);
}
nsresult SplitElementTxn::Do(void)
{
// create a new node
nsresult result = mNode->CloneNode(PR_FALSE, &mNewNode);
NS_ASSERTION(((NS_SUCCEEDED(result)) && (nsnull!=mNewNode)), "could not create element.");
nsresult result = mExistingRightNode->CloneNode(PR_FALSE, getter_AddRefs(mNewLeftNode));
NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewLeftNode)), "could not create element.");
if ((NS_SUCCEEDED(result)) && (nsnull!=mNewNode))
if ((NS_SUCCEEDED(result)) && (mNewLeftNode))
{
// get the parent node
result = mNode->GetParentNode(&mParent);
result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent));
// insert the new node
if ((NS_SUCCEEDED(result)) && (nsnull!=mParent))
if ((NS_SUCCEEDED(result)) && (mParent))
{
result = mEditor->SplitNode(mNode, mOffset, mNewNode, mParent);
result = nsEditor::SplitNode(mExistingRightNode, mOffset, mNewLeftNode, mParent);
}
}
return result;
@ -63,13 +61,13 @@ nsresult SplitElementTxn::Do(void)
nsresult SplitElementTxn::Undo(void)
{
// this assumes Do inserted the new node in front of the prior existing node
nsresult result = mEditor->JoinNodes(mNode, mNewNode, mParent, PR_FALSE);
nsresult result = nsEditor::JoinNodes(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE);
return result;
}
nsresult SplitElementTxn::Redo(void)
{
nsresult result = mEditor->SplitNode(mNode, mOffset, mNewNode, mParent);
nsresult result = nsEditor::SplitNode(mExistingRightNode, mOffset, mNewLeftNode, mParent);
return result;
}

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

@ -20,10 +20,13 @@
#define SplitElementTxn_h__
#include "EditTxn.h"
#include "nsIDOMNode.h"
#include "nsCOMPtr.h"
class nsIDOMNode;
class nsIDOMElement;
class nsIDOMDocument;
#define SPLIT_ELEMENT_TXN_IID \
{/* 690c6290-ac48-11d2-86d8-000064657374 */ \
0x690c6290, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that splits an element E into two identical nodes, E1 and E2
@ -33,10 +36,12 @@ class SplitElementTxn : public EditTxn
{
public:
SplitElementTxn(nsEditor *aEditor,
nsIDOMNode *aNode,
PRInt32 aOffset);
virtual nsresult Init (nsIDOMNode *aNode,
PRInt32 aOffset);
protected:
SplitElementTxn();
public:
virtual ~SplitElementTxn();
virtual nsresult Do(void);
@ -58,7 +63,7 @@ public:
protected:
/** the element to operate upon */
nsIDOMNode *mNode;
nsCOMPtr<nsIDOMNode> mExistingRightNode;
/** the offset into mElement where the children of mElement are split.<BR>
* mOffset is the index of the last child in the left node.
@ -67,8 +72,12 @@ protected:
PRInt32 mOffset;
/** the element we create when splitting mElement */
nsIDOMNode *mNewNode;
nsIDOMNode *mParent;
nsCOMPtr<nsIDOMNode> mNewLeftNode;
/** the parent shared by mExistingRightNode and mNewLeftNode */
nsCOMPtr<nsIDOMNode> mParent;
friend class TransactionFactory;
};

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

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "TransactionFactory.h"
// transactions this factory knows how to build
#include "InsertTextTxn.h"
#include "DeleteTextTxn.h"
#include "CreateElementTxn.h"
#include "DeleteElementTxn.h"
#include "DeleteRangeTxn.h"
#include "ChangeAttributeTxn.h"
#include "SplitElementTxn.h"
#include "JoinElementTxn.h"
static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID);
static NS_DEFINE_IID(kDeleteTextTxnIID, DELETE_TEXT_TXN_IID);
static NS_DEFINE_IID(kCreateElementTxnIID, CREATE_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kDeleteElementTxnIID, DELETE_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kDeleteRangeTxnIID, DELETE_RANGE_TXN_IID);
static NS_DEFINE_IID(kChangeAttributeTxnIID,CHANGE_ATTRIBUTE_TXN_IID);
static NS_DEFINE_IID(kSplitElementTxnIID, SPLIT_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kJoinElementTxnIID, JOIN_ELEMENT_TXN_IID);
TransactionFactory::TransactionFactory()
{
}
TransactionFactory::~TransactionFactory()
{
}
nsresult
TransactionFactory::GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult)
{
nsresult result = NS_OK;
*aResult = nsnull;
if (aTxnType.Equals(kInsertTextTxnIID))
*aResult = new InsertTextTxn();
else if (aTxnType.Equals(kDeleteTextTxnIID))
*aResult = new DeleteTextTxn();
else if (aTxnType.Equals(kCreateElementTxnIID))
*aResult = new CreateElementTxn();
else if (aTxnType.Equals(kDeleteElementTxnIID))
*aResult = new DeleteElementTxn();
else if (aTxnType.Equals(kDeleteRangeTxnIID))
*aResult = new DeleteRangeTxn();
else if (aTxnType.Equals(kChangeAttributeTxnIID))
*aResult = new ChangeAttributeTxn();
else if (aTxnType.Equals(kSplitElementTxnIID))
*aResult = new SplitElementTxn();
else if (aTxnType.Equals(kJoinElementTxnIID))
*aResult = new JoinElementTxn();
if (nsnull==*aResult)
result = NS_ERROR_INVALID_ARG;
return result;
}

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

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

@ -33,16 +33,22 @@
#include "nsTransactionManagerCID.h"
#include "nsITransactionManager.h"
#include "nsIPresShell.h"
#include "nsIViewManager.h"
#include "nsISelection.h"
#include "nsICollection.h"
#include "nsIEnumerator.h"
#include "nsIAtom.h"
// transactions the editor knows how to build
#include "TransactionFactory.h"
#include "ChangeAttributeTxn.h"
#include "CreateElementTxn.h"
#include "DeleteElementTxn.h"
#include "InsertTextTxn.h"
#include "DeleteTextTxn.h"
#include "DeleteRangeTxn.h"
#include "SplitElementTxn.h"
#include "JoinElementTxn.h"
static NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID);
@ -58,8 +64,18 @@ static NS_DEFINE_IID(kIEditFactoryIID, NS_IEDITORFACTORY_IID);
static NS_DEFINE_IID(kIEditorIID, NS_IEDITOR_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kEditorCID, NS_EDITOR_CID);
// transaction manager
static NS_DEFINE_IID(kITransactionManagerIID, NS_ITRANSACTIONMANAGER_IID);
static NS_DEFINE_CID(kCTransactionManagerFactoryCID, NS_TRANSACTION_MANAGER_FACTORY_CID);
// transactions
static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID);
static NS_DEFINE_IID(kDeleteTextTxnIID, DELETE_TEXT_TXN_IID);
static NS_DEFINE_IID(kCreateElementTxnIID, CREATE_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kDeleteElementTxnIID, DELETE_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kDeleteRangeTxnIID, DELETE_RANGE_TXN_IID);
static NS_DEFINE_IID(kChangeAttributeTxnIID,CHANGE_ATTRIBUTE_TXN_IID);
static NS_DEFINE_IID(kSplitElementTxnIID, SPLIT_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kJoinElementTxnIID, JOIN_ELEMENT_TXN_IID);
#ifdef XP_PC
@ -165,6 +181,7 @@ nsEditor::nsEditor()
nsEditor::~nsEditor()
{
NS_IF_RELEASE(mPresShell);
NS_IF_RELEASE(mViewManager);
NS_IF_RELEASE(mTxnMgr);
//the autopointers will clear themselves up.
@ -229,6 +246,8 @@ nsEditor::Init(nsIDOMDocument *aDomInterface, nsIPresShell* aPresShell)
mDomInterfaceP = aDomInterface;
mPresShell = aPresShell;
NS_ADDREF(mPresShell);
mViewManager = mPresShell->GetViewManager();
mUpdateCount=0;
nsresult t_result = NS_NewEditorKeyListener(getter_AddRefs(mKeyListenerP), this);
if (NS_OK != t_result)
@ -308,13 +327,13 @@ nsEditor::Init(nsIDOMDocument *aDomInterface, nsIPresShell* aPresShell)
nsresult
nsEditor::InsertString(nsString *aString)
{
return AppendText(aString);
return NS_OK;
}
nsresult
nsEditor::SetProperties(PROPERTIES aProperty)
nsEditor::SetProperties(Properties aProperties)
{
return NS_OK;
}
@ -322,7 +341,7 @@ nsEditor::SetProperties(PROPERTIES aProperty)
nsresult
nsEditor::GetProperties(PROPERTIES **)
nsEditor::GetProperties(Properties **aProperties)
{
return NS_OK;
}
@ -334,9 +353,13 @@ nsEditor::SetAttribute(nsIDOMElement *aElement, const nsString& aAttribute, cons
nsresult result;
if (nsnull != aElement)
{
ChangeAttributeTxn *txn = new ChangeAttributeTxn(this, aElement, aAttribute, aValue, PR_FALSE);
ChangeAttributeTxn *txn;
result = TransactionFactory::GetNewTransaction(kChangeAttributeTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
{
txn->Init(this, aElement, aAttribute, aValue, PR_FALSE);
result = Do(txn);
}
}
return result;
}
@ -369,10 +392,14 @@ nsEditor::RemoveAttribute(nsIDOMElement *aElement, const nsString& aAttribute)
nsresult result;
if (nsnull != aElement)
{
nsString value;
ChangeAttributeTxn *txn = new ChangeAttributeTxn(this, aElement, aAttribute, value, PR_TRUE);
ChangeAttributeTxn *txn;
result = TransactionFactory::GetNewTransaction(kChangeAttributeTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
{
nsAutoString value;
txn->Init(this, aElement, aAttribute, value, PR_TRUE);
result = Do(txn);
}
}
return result;
}
@ -420,26 +447,6 @@ nsEditor::MouseClick(int aX,int aY)
//BEGIN nsEditor Private methods
nsresult
nsEditor::AppendText(nsString *aStr)
{
nsCOMPtr<nsIDOMNode> currentNode;
nsCOMPtr<nsIDOMNode> textNode;
nsCOMPtr<nsIDOMText> text;
if (!aStr)
return NS_ERROR_NULL_POINTER;
if (NS_SUCCEEDED(GetCurrentNode(getter_AddRefs(currentNode))) &&
NS_SUCCEEDED(GetFirstTextNode(currentNode,getter_AddRefs(textNode))) &&
NS_SUCCEEDED(textNode->QueryInterface(kIDOMTextIID, getter_AddRefs(text)))) {
text->AppendData(*aStr);
}
return NS_OK;
}
nsresult
nsEditor::GetCurrentNode(nsIDOMNode ** aNode)
{
@ -485,7 +492,7 @@ nsEditor::GetFirstNodeOfType(nsIDOMNode *aStartNode, const nsString &aTag, nsIDO
while (childNode)
{
result = childNode->QueryInterface(kIDOMNodeIID,getter_AddRefs(element));
nsString tag;
nsAutoString tag;
if (NS_SUCCEEDED(result) && (element))
{
element->GetTagName(tag);
@ -500,9 +507,8 @@ nsEditor::GetFirstNodeOfType(nsIDOMNode *aStartNode, const nsString &aTag, nsIDO
return result;
}
}
nsCOMPtr<nsIDOMNode> xNode;
childNode->GetNextSibling(getter_AddRefs(xNode));
childNode=xNode;
nsCOMPtr<nsIDOMNode> temp = childNode;
temp->GetNextSibling(getter_AddRefs(childNode));
}
return NS_ERROR_FAILURE;
@ -559,7 +565,7 @@ nsEditor::GetFirstTextNode(nsIDOMNode *aNode, nsIDOMNode **aRetNode)
}
nsresult
nsEditor::ExecuteTransaction(nsITransaction *aTxn)
nsEditor::Do(nsITransaction *aTxn)
{
nsresult result = NS_OK;
if (nsnull!=aTxn)
@ -577,27 +583,65 @@ nsEditor::ExecuteTransaction(nsITransaction *aTxn)
}
nsresult
nsEditor::Undo()
nsEditor::Undo(PRUint32 aCount)
{
nsresult result = NS_OK;
if (nsnull!=mTxnMgr)
{
result = mTxnMgr->Undo();
PRUint32 i=0;
for ( ; i<aCount; i++)
{
result = mTxnMgr->Undo();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult
nsEditor::Redo()
nsEditor::Redo(PRUint32 aCount)
{
nsresult result = NS_OK;
if (nsnull!=mTxnMgr)
{
result = mTxnMgr->Redo();
PRUint32 i=0;
for ( ; i<aCount; i++)
{
result = mTxnMgr->Redo();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult
nsEditor::BeginUpdate()
{
NS_PRECONDITION(mUpdateCount>=0, "bad state");
if (nsnull!=mViewManager)
{
if (0==mUpdateCount)
mViewManager->DisableRefresh();
mUpdateCount++;
}
return NS_OK;
}
nsresult
nsEditor::EndUpdate()
{
NS_PRECONDITION(mUpdateCount>0, "bad state");
if (nsnull!=mViewManager)
{
mUpdateCount--;
if (0==mUpdateCount)
mViewManager->EnableRefresh();
}
return NS_OK;
}
nsresult nsEditor::Delete(PRBool aForward, PRUint32 aCount)
{
return NS_OK;
@ -610,9 +654,13 @@ nsresult nsEditor::CreateElement(const nsString& aTag,
nsresult result;
if (nsnull != aParent)
{
CreateElementTxn *txn = new CreateElementTxn(this, mDomInterfaceP, aTag, aParent, aPosition);
CreateElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kCreateElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
{
txn->Init(mDomInterfaceP, aTag, aParent, aPosition);
result = Do(txn);
}
else
result = NS_ERROR_OUT_OF_MEMORY;
}
@ -628,9 +676,13 @@ nsresult nsEditor::DeleteElement(nsIDOMNode * aParent,
nsresult result;
if ((nsnull != aParent) && (nsnull != aElement))
{
DeleteElementTxn *txn = new DeleteElementTxn(this, mDomInterfaceP, aElement, aParent);
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
{
txn->Init(aElement, aParent);
result = Do(txn);
}
else
result = NS_ERROR_OUT_OF_MEMORY;
}
@ -640,18 +692,51 @@ nsresult nsEditor::DeleteElement(nsIDOMNode * aParent,
return result;
}
nsresult nsEditor::InsertText(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert)
// XXX; factor -- should call BuildInsertTextTransaction to do most of the work
nsresult nsEditor::InsertText(const nsString& aStringToInsert)
{
nsresult result;
if (nsnull != aElement)
nsISelection* selection;
result = mPresShell->GetSelection(&selection);
if ((NS_SUCCEEDED(result)) && (nsnull!=selection))
{
InsertTextTxn *txn = new InsertTextTxn(this, aElement, aOffset, aStringToInsert);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
else
result = NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsIEnumerator> enumerator;
enumerator = selection;
if (enumerator)
{
enumerator->First();
nsISupports *currentItem;
result = enumerator->CurrentItem(&currentItem);
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{
// XXX: we'll want to deleteRange if the selection isn't just an insertion point
// for now, just insert text after the start of the first node
nsCOMPtr<nsIDOMRange> range = currentItem;
if (range)
{
nsCOMPtr<nsIDOMNode> node;
result = range->GetStartParent(getter_AddRefs(node));
if ((NS_SUCCEEDED(result)) && (node))
{
nsCOMPtr<nsIDOMCharacterData> nodeAsText = node;
if (nodeAsText)
{
PRInt32 offset;
range->GetStartOffset(&offset);
InsertTextTxn *txn;
result = TransactionFactory::GetNewTransaction(kInsertTextTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(nodeAsText, offset, aStringToInsert);
result = Do(txn);
}
else
result = NS_ERROR_OUT_OF_MEMORY;
}
}
}
}
}
}
else
result = NS_ERROR_INVALID_ARG;
@ -659,6 +744,7 @@ nsresult nsEditor::InsertText(nsIDOMCharacterData *aElement,
return result;
}
// XXX; factor -- should call BuildDeleteTextTransaction to do most of the work
nsresult nsEditor::DeleteText(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aLength)
@ -666,9 +752,13 @@ nsresult nsEditor::DeleteText(nsIDOMCharacterData *aElement,
nsresult result=NS_OK;
if (nsnull != aElement)
{
DeleteTextTxn *txn = new DeleteTextTxn(this, aElement, aOffset, aLength);
DeleteTextTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteTextTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
{
txn->Init(aElement, aOffset, aLength);
result = Do(txn);
}
else
result = NS_ERROR_OUT_OF_MEMORY;
}
@ -678,6 +768,10 @@ nsresult nsEditor::DeleteText(nsIDOMCharacterData *aElement,
return result;
}
// XXX; factor -- should call DeleteSelectionTransaction to do most of the work
// XXX: these should get wrapped up in a single composite transaction
// rather than executing each individually, maybe I should alloc a generic aggregate
// and stick each in there, then execute the aggregate
nsresult nsEditor::DeleteSelection()
{
nsresult result;
@ -685,15 +779,34 @@ nsresult nsEditor::DeleteSelection()
result = mPresShell->GetSelection(&selection);
if ((NS_SUCCEEDED(result)) && (nsnull!=selection))
{
nsCOMPtr<nsIDOMRange> range;
result = selection->QueryInterface(kIDOMRangeIID, getter_AddRefs(range));
if ((NS_SUCCEEDED(result)) && (range))
nsCOMPtr<nsIEnumerator> enumerator;
enumerator = selection;
if (enumerator)
{
DeleteRangeTxn *txn = new DeleteRangeTxn(this, range);
if (nsnull!=txn)
result = ExecuteTransaction(txn);
else
result = NS_ERROR_OUT_OF_MEMORY;
enumerator->First();
nsISupports *currentItem;
result = enumerator->CurrentItem(&currentItem);
if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem))
{
nsCOMPtr<nsIDOMRange> range = currentItem;
DeleteRangeTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteRangeTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(range);
result = Do(txn);
}
else
result = NS_ERROR_OUT_OF_MEMORY;
if (NS_SUCCEEDED(result))
{
nsresult nextResult = enumerator->Next();
if (NS_SUCCEEDED(nextResult))
{
result = enumerator->CurrentItem(&currentItem);
}
}
}
}
}
else
@ -703,30 +816,31 @@ nsresult nsEditor::DeleteSelection()
}
nsresult
nsEditor::SplitNode(nsIDOMNode * aNode,
nsEditor::SplitNode(nsIDOMNode * aExistingRightNode,
PRInt32 aOffset,
nsIDOMNode* aNewNode,
nsIDOMNode* aNewLeftNode,
nsIDOMNode* aParent)
{
nsresult result;
NS_ASSERTION(((nsnull!=aNode) &&
(nsnull!=aNewNode) &&
NS_ASSERTION(((nsnull!=aExistingRightNode) &&
(nsnull!=aNewLeftNode) &&
(nsnull!=aParent)),
"null arg");
if ((nsnull!=aNode) &&
(nsnull!=aNewNode) &&
if ((nsnull!=aExistingRightNode) &&
(nsnull!=aNewLeftNode) &&
(nsnull!=aParent))
{
nsCOMPtr<nsIDOMNode> resultNode;
result = aParent->InsertBefore(aNewNode, aNode, getter_AddRefs(resultNode));
result = aParent->InsertBefore(aNewLeftNode, aExistingRightNode, getter_AddRefs(resultNode));
if (NS_SUCCEEDED(result))
{
// split the children between the 2 nodes
// at this point, nNode has all the children
// at this point, aExistingRightNode has all the children
// move all the children whose index is < aOffset to aNewLeftNode
if (0<=aOffset) // don't bother unless we're going to move at least one child
{
nsCOMPtr<nsIDOMNodeList> childNodes;
result = aParent->GetChildNodes(getter_AddRefs(childNodes));
result = aExistingRightNode->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
PRInt32 i=0;
@ -736,10 +850,10 @@ nsEditor::SplitNode(nsIDOMNode * aNode,
result = childNodes->Item(i, getter_AddRefs(childNode));
if ((NS_SUCCEEDED(result)) && (childNode))
{
result = aNode->RemoveChild(childNode, getter_AddRefs(resultNode));
result = aExistingRightNode->RemoveChild(childNode, getter_AddRefs(resultNode));
if (NS_SUCCEEDED(result))
{
result = aNewNode->AppendChild(childNode, getter_AddRefs(resultNode));
result = aNewLeftNode->AppendChild(childNode, getter_AddRefs(resultNode));
}
}
}

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

@ -16,6 +16,9 @@
* Reserved.
*/
#ifndef __editor_h__
#define __editor_h__
#include "prmon.h"
#include "nsIEditor.h"
#include "nsIContextLoader.h"
@ -24,11 +27,13 @@
#include "nsCOMPtr.h"
#include "editorInterfaces.h"
#include "nsITransactionManager.h"
#include "TransactionFactory.h"
#include "nsRepository.h"
//#include "nsISelection.h"
class nsIDOMCharacterData;
class nsIPresShell;
class nsIViewManager;
//This is the monitor for the editor.
PRMonitor *getEditorMonitor();
@ -42,15 +47,19 @@ PRMonitor *getEditorMonitor();
class nsEditor : public nsIEditor
{
private:
nsIPresShell *mPresShell;
nsIPresShell *mPresShell;
nsIViewManager *mViewManager;
PRUint32 mUpdateCount;
nsCOMPtr<nsIDOMDocument> mDomInterfaceP;
nsCOMPtr<nsIDOMEventListener> mKeyListenerP;
nsCOMPtr<nsIDOMEventListener> mMouseListenerP;
// nsCOMPtr<nsISelection> mSelectionP;
//nsCOMPtr<nsITransactionManager> mTxnMgrP;
nsITransactionManager * mTxnMgr;
friend PRBool NSCanUnload(void);
static PRInt32 gInstanceCount;
public:
/** The default constructor. This should suffice. the setting of the interfaces is done
* after the construction of the editor class.
@ -70,9 +79,9 @@ public:
virtual nsresult GetDomInterface(nsIDOMDocument **aDomInterface);
virtual nsresult SetProperties(PROPERTIES aProperty);
virtual nsresult SetProperties(Properties aProperties);
virtual nsresult GetProperties(PROPERTIES **);
virtual nsresult GetProperties(Properties **aProperties);
virtual nsresult SetAttribute(nsIDOMElement * aElement,
const nsString& aAttribute,
@ -85,11 +94,15 @@ public:
virtual nsresult RemoveAttribute(nsIDOMElement *aElement, const nsString& aAttribute);
virtual nsresult InsertString(nsString *aString);
virtual nsresult Commit(PRBool aCtrlKey);
virtual nsresult Do(nsITransaction *aTxn);
virtual nsresult Undo(PRUint32 aCount);
virtual nsresult Redo(PRUint32 aCount);
virtual nsresult BeginUpdate();
virtual nsresult EndUpdate();
/*END nsIEditor interfaces*/
@ -113,12 +126,6 @@ public:
/*BEGIN private methods used by the implementations of the above functions*/
/** AppendText is a private method that accepts a pointer to a string
* and will append it to the current node. this will be depricated
* @param nsString *aStr is the pointer to the valid string
*/
nsresult AppendText(nsString *aStr);
/** GetCurrentNode ADDREFFS and will get the current node from selection.
* now it simply returns the first node in the dom
* @param nsIDOMNode **aNode is the return location of the dom node
@ -142,33 +149,6 @@ public:
*/
nsresult GetFirstNodeOfType(nsIDOMNode *aStartNode, const nsString &aTag, nsIDOMNode **aResult);
/** ExecuteTransaction fires a transaction. It is provided here so
* clients need no knowledge of whether the editor has a transaction manager or not.
* If a transaction manager is present, it is used.
* Otherwise, the transaction is just executed directly.
*
* @param aTxn the transaction to execute
*/
nsresult ExecuteTransaction(nsITransaction *aTxn);
/** Undo reverses the effects of the last ExecuteTransaction operation
* It is provided here so clients need no knowledge of whether the editor has a transaction manager or not.
* If a transaction manager is present, it is told to undo and the result of
* that undo is returned.
* Otherwise, the Undo request is ignored.
*
*/
nsresult Undo();
/** Redo reverses the effects of the last Undo operation
* It is provided here so clients need no knowledge of whether the editor has a transaction manager or not.
* If a transaction manager is present, it is told to redo and the result of
* that redo is returned.
* Otherwise, the Redo request is ignored.
*
*/
nsresult Redo();
nsresult CreateElement(const nsString& aTag,
nsIDOMNode * aParent,
PRInt32 aPosition);
@ -178,17 +158,15 @@ public:
nsresult DeleteSelection();
nsresult InsertText(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert);
nsresult InsertText(const nsString& aStringToInsert);
nsresult DeleteText(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aLength);
static nsresult SplitNode(nsIDOMNode * aNode,
static nsresult SplitNode(nsIDOMNode * aExistingRightNode,
PRInt32 aOffset,
nsIDOMNode * aNewNode,
nsIDOMNode * aNewLeftNode,
nsIDOMNode * aParent);
static nsresult JoinNodes(nsIDOMNode * aNodeToKeep,
@ -198,6 +176,10 @@ public:
nsresult Delete(PRBool aForward, PRUint32 aCount);
virtual nsresult InsertString(nsString *aString);
virtual nsresult Commit(PRBool aCtrlKey);
/*END private methods of nsEditor*/
};
@ -207,3 +189,6 @@ factory method(s)
*/
nsresult NS_MakeEditorLoader(nsIContextLoader **aResult);
#endif

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

@ -19,7 +19,6 @@
#include "editor.h"
#include "CreateElementTxn.h"
#include "SplitElementTxn.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
@ -178,7 +177,7 @@ nsEditorKeyListener::KeyDown(nsIDOMEvent* aKeyEvent)
}
else
{ // XXX: delete the first P we find
nsString pTag("P");
nsAutoString pTag("P");
nsCOMPtr<nsIDOMNode> currentNode;
nsCOMPtr<nsIDOMNode> parentNode;
nsCOMPtr<nsIDOMElement> element;
@ -199,25 +198,12 @@ nsEditorKeyListener::KeyDown(nsIDOMEvent* aKeyEvent)
{
// XXX Replace with x-platform NS-virtkeycode transform.
if (NS_OK == GetCharFromKeyCode(keyCode, isShift, & character)) {
nsString key;
nsAutoString key;
key += character;
if (!isShift) {
key.ToLowerCase();
}
// XXX: for now, just grab the first text node
nsCOMPtr<nsIDOMNode> currentNode;
nsCOMPtr<nsIDOMNode> textNode;
nsCOMPtr<nsIDOMCharacterData> text;
if (NS_SUCCEEDED(mEditor->GetCurrentNode(getter_AddRefs(currentNode))) &&
NS_SUCCEEDED(mEditor->GetFirstTextNode(currentNode,getter_AddRefs(textNode))) &&
NS_SUCCEEDED(textNode->QueryInterface(kIDOMCharacterDataIID, getter_AddRefs(text))))
{
// XXX: for now, just append the text
PRUint32 offset;
text->GetLength(&offset);
mEditor->InsertText(text, offset, key);
}
mEditor->InsertText(key);
}
}
break;
@ -244,6 +230,10 @@ nsEditorKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
return NS_OK;
}
/* these includes are for debug only. this module should never instantiate it's own transactions */
#include "SplitElementTxn.h"
#include "TransactionFactory.h"
static NS_DEFINE_IID(kSplitElementTxnIID, SPLIT_ELEMENT_TXN_IID);
nsresult
nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProcessed)
{
@ -265,7 +255,7 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
if (PR_TRUE==ctrlKey)
{
if (nsnull!=mEditor)
mEditor->Undo();
mEditor->Undo(1);
}
aProcessed=PR_TRUE;
break;
@ -275,7 +265,7 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
if (PR_TRUE==ctrlKey)
{
if (nsnull!=mEditor)
mEditor->Redo();
mEditor->Redo(1);
}
aProcessed=PR_TRUE;
break;
@ -283,17 +273,27 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
// hard-coded split node test: works on first <P> in the document
case nsIDOMEvent::VK_S:
{
nsString pTag("P");
nsAutoString pTag("P");
nsCOMPtr<nsIDOMNode> currentNode;
nsCOMPtr<nsIDOMElement> element;
if (NS_SUCCEEDED(mEditor->GetFirstNodeOfType(nsnull, pTag, getter_AddRefs(currentNode))))
{
nsresult result;
SplitElementTxn *txn;
if (PR_FALSE==isShift) // split the element so there are 0 children in the first half
txn = new SplitElementTxn(mEditor, currentNode, -1);
{
result = TransactionFactory::GetNewTransaction(kSplitElementTxnIID, (EditTxn **)&txn);
if (txn)
txn->Init(currentNode, -1);
}
else // split the element so there are 2 children in the first half
txn = new SplitElementTxn(mEditor, currentNode, 1);
mEditor->ExecuteTransaction(txn);
{
result = TransactionFactory::GetNewTransaction(kSplitElementTxnIID, (EditTxn **)&txn);
if (txn)
txn->Init(currentNode, 1);
}
if (txn)
mEditor->Do(txn);
}
}
aProcessed=PR_TRUE;
@ -305,10 +305,10 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
{
//XXX: should be from a factory
//XXX: should manage the refcount of txn
nsString attribute("width");
nsString value("400");
nsAutoString attribute("width");
nsAutoString value("400");
nsString tableTag("TABLE");
nsAutoString tableTag("TABLE");
nsCOMPtr<nsIDOMNode> currentNode;
nsCOMPtr<nsIDOMElement> element;
if (NS_SUCCEEDED(mEditor->GetFirstNodeOfType(nsnull, tableTag, getter_AddRefs(currentNode))))
@ -331,11 +331,11 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
nsresult result;
//XXX: should be from a factory
//XXX: should manage the refcount of txn
nsString attribute("src");
nsString value("resource:/res/samples/raptor.jpg");
nsAutoString attribute("src");
nsAutoString value("resource:/res/samples/raptor.jpg");
nsString imgTag("HR");
nsString bodyTag("BODY");
nsAutoString imgTag("HR");
nsAutoString bodyTag("BODY");
nsCOMPtr<nsIDOMNode> currentNode;
result = mEditor->GetFirstNodeOfType(nsnull, bodyTag, getter_AddRefs(currentNode));
if (NS_SUCCEEDED(result))
@ -356,7 +356,7 @@ nsEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aProces
{
ChangeAttributeTxn *txn;
txn = new ChangeAttributeTxn(mEditor, element, attribute, value, PR_FALSE);
mEditor->ExecuteTransaction(txn);
mEditor->Do(txn);
}
}
*/
@ -523,3 +523,4 @@ NS_NewEditorMouseListener(nsIDOMEventListener ** aInstancePtrResult, nsEditor *a
return it->QueryInterface(kIDOMEventListenerIID, (void **) aInstancePtrResult);
}

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

@ -1,90 +0,0 @@
#!nmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH=..\..
IGNORE_MANIFEST=1
LIBRARY_NAME=ender
CPPSRCS = \
editor.cpp \
editorInterfaces.cpp \
nsEditFactory.cpp \
EditTxn.cpp \
ChangeAttributeTxn.cpp \
InsertTextTxn.cpp \
DeleteTextTxn.cpp \
CreateElementTxn.cpp \
DeleteElementTxn.cpp \
DeleteRangeTxn.cpp \
SplitElementTxn.cpp \
$(NULL)
CPP_OBJS = \
.\$(OBJDIR)\editor.obj \
.\$(OBJDIR)\nsEditFactory.obj \
.\$(OBJDIR)\editorInterfaces.obj \
.\$(OBJDIR)\EditTxn.obj \
.\$(OBJDIR)\ChangeAttributeTxn.obj \
.\$(OBJDIR)\InsertTextTxn.obj \
.\$(OBJDIR)\DeleteTextTxn.obj \
.\$(OBJDIR)\CreateElementTxn.obj \
.\$(OBJDIR)\DeleteElementTxn.obj \
.\$(OBJDIR)\DeleteRangeTxn.obj \
.\$(OBJDIR)\SplitElementTxn.obj \
$(NULL)
MODULE=editor
REQUIRES=xpcom raptor dom base
LINCS=-I$(PUBLIC)\editor \
-I$(PUBLIC)\xpcom \
-I$(PUBLIC)\raptor \
-I$(PUBLIC)\js \
-I$(PUBLIC)\txmgr \
-I$(PUBLIC)\dom
MAKE_OBJ_TYPE = DLL
DLLNAME = ender
DLL=.\$(OBJDIR)\$(DLLNAME).dll
LCFLAGS = \
$(LCFLAGS) \
$(DEFINES) \
$(NULL)
# These are the libraries we need to link with to create the dll
LLIBS= \
$(DIST)\lib\xpcom32.lib \
$(DIST)\lib\libplc21.lib \
$(DIST)\lib\raptorbase.lib \
$(LIBNSPR)
!if "$(MOZ_BITS)"=="32" && defined(MOZ_DEBUG) && defined(GLOWCODE)
LLIBS=$(LLIBS) $(GLOWDIR)\glowcode.lib
!endif
include <$(DEPTH)\config\rules.mak>
libs:: $(DLL)
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib
clobber::
rm -f $(DIST)\bin\$(DLLNAME).dll
rm -f $(DIST)\lib\$(DLLNAME).lib

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

@ -17,23 +17,33 @@
*/
#include "ChangeAttributeTxn.h"
#include "editor.h"
#include "nsIDOMElement.h"
#include "editor.h"
// note that aEditor is not refcounted
ChangeAttributeTxn::ChangeAttributeTxn(nsEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute)
: EditTxn(aEditor)
ChangeAttributeTxn::ChangeAttributeTxn()
: EditTxn()
{
mElement = aElement;
mAttribute = aAttribute;
mValue = aValue;
mRemoveAttribute = aRemoveAttribute;
mAttributeWasSet=PR_FALSE;
mUndoValue="";
}
nsresult ChangeAttributeTxn::Init(nsIEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute)
{
if (nsnull!=aEditor && nsnull!=aElement)
{
mEditor = aEditor;
mElement = aElement;
mAttribute = aAttribute;
mValue = aValue;
mRemoveAttribute = aRemoveAttribute;
mAttributeWasSet=PR_FALSE;
mUndoValue="";
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
nsresult ChangeAttributeTxn::Do(void)

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

@ -20,8 +20,14 @@
#define ChangeAttributeTxn_h__
#include "EditTxn.h"
#include "nsCOMPtr.h"
#include "nsIDOMElement.h"
#include "nsIEditor.h"
class nsIDOMElement;
#define CHANGE_ATTRIBUTE_TXN_IID \
{/* 97818860-ac48-11d2-86d8-000064657374 */ \
0x97818860, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that changes an attribute of a content node.
@ -31,11 +37,16 @@ class ChangeAttributeTxn : public EditTxn
{
public:
ChangeAttributeTxn(nsEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute);
virtual nsresult Init(nsIEditor *aEditor,
nsIDOMElement *aElement,
const nsString& aAttribute,
const nsString& aValue,
PRBool aRemoveAttribute);
private:
ChangeAttributeTxn();
public:
virtual nsresult Do(void);
@ -54,9 +65,12 @@ public:
virtual nsresult GetRedoString(nsString **aString);
protected:
/** the editor that created this transaction */
nsCOMPtr<nsIEditor> mEditor;
/** the element to operate upon */
nsIDOMElement *mElement;
nsCOMPtr<nsIDOMElement> mElement;
/** the attribute to change */
nsString mAttribute;
@ -72,6 +86,8 @@ protected:
/** PR_TRUE if the operation is to remove mAttribute from mElement */
PRBool mRemoveAttribute;
friend class TransactionFactory;
};
#endif

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

@ -17,52 +17,50 @@
*/
#include "CreateElementTxn.h"
#include "editor.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
// note that aEditor is not refcounted
CreateElementTxn::CreateElementTxn(nsEditor *aEditor,
nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent)
: EditTxn(aEditor)
CreateElementTxn::CreateElementTxn()
: EditTxn()
{
mDoc = aDoc;
NS_ADDREF(mDoc);
mTag = aTag;
mParent = aParent;
NS_ADDREF(mParent);
mOffsetInParent = aOffsetInParent;
mNewNode = nsnull;
mRefNode = nsnull;
}
nsresult CreateElementTxn::Init(nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent)
{
if ((nsnull!=aDoc) && (nsnull!=aParent))
{
mDoc = aDoc;
mTag = aTag;
mParent = aParent;
mOffsetInParent = aOffsetInParent;
mNewNode = nsnull;
mRefNode = nsnull;
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
CreateElementTxn::~CreateElementTxn()
{
NS_IF_RELEASE(mDoc);
NS_IF_RELEASE(mParent);
NS_IF_RELEASE(mNewNode);
}
nsresult CreateElementTxn::Do(void)
{
// create a new node
nsresult result = mDoc->CreateElement(mTag, &mNewNode);
NS_ASSERTION(((NS_SUCCEEDED(result)) && (nsnull!=mNewNode)), "could not create element.");
nsresult result = mDoc->CreateElement(mTag, getter_AddRefs(mNewNode));
NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewNode)), "could not create element.");
if ((NS_SUCCEEDED(result)) && (nsnull!=mNewNode))
if ((NS_SUCCEEDED(result)) && (mNewNode))
{
// insert the new node
nsIDOMNode *resultNode=nsnull;
nsCOMPtr<nsIDOMNode> resultNode;
if (CreateElementTxn::eAppend==mOffsetInParent)
{
result = mParent->AppendChild(mNewNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode); // this object already holds a ref from CreateElement
result = mParent->AppendChild(mNewNode, getter_AddRefs(resultNode));
}
else
{
@ -70,12 +68,10 @@ nsresult CreateElementTxn::Do(void)
result = mParent->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
result = childNodes->Item(mOffsetInParent, &mRefNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=mRefNode))
result = childNodes->Item(mOffsetInParent, getter_AddRefs(mRefNode));
if ((NS_SUCCEEDED(result)) && (mRefNode))
{
result = mParent->InsertBefore(mNewNode, mRefNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode); // this object already holds a ref from CreateElement
result = mParent->InsertBefore(mNewNode, mRefNode, getter_AddRefs(resultNode));
}
}
}
@ -85,20 +81,16 @@ nsresult CreateElementTxn::Do(void)
nsresult CreateElementTxn::Undo(void)
{
nsIDOMNode *resultNode=nsnull;
nsresult result = mParent->RemoveChild(mNewNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode);
nsCOMPtr<nsIDOMNode> resultNode;
nsresult result = mParent->RemoveChild(mNewNode, getter_AddRefs(resultNode));
return result;
}
nsresult CreateElementTxn::Redo(void)
{
nsIDOMNode *resultNode=nsnull;
nsresult result = mParent->InsertBefore(mNewNode, mRefNode, &resultNode);
if ((NS_SUCCEEDED(result)) && (nsnull!=resultNode))
NS_RELEASE(resultNode);
return result;
nsCOMPtr<nsIDOMNode> resultNode;
nsresult result = mParent->InsertBefore(mNewNode, mRefNode, getter_AddRefs(resultNode));
return result;
}
nsresult CreateElementTxn::GetIsTransient(PRBool *aIsTransient)

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

@ -20,10 +20,15 @@
#define CreateElementTxn_h__
#include "EditTxn.h"
#include "nsIDOMDocument.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "nsCOMPtr.h"
class nsIDOMDocument;
class nsIDOMNode;
class nsIDOMElement;
#define CREATE_ELEMENT_TXN_IID \
{/* 7a6393c0-ac48-11d2-86d8-000064657374 */ \
0x7a6393c0, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that creates a new node in the content tree.
@ -34,11 +39,15 @@ public:
enum { eAppend=-1 };
CreateElementTxn(nsEditor *aEditor,
nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent);
virtual nsresult Init(nsIDOMDocument *aDoc,
const nsString& aTag,
nsIDOMNode *aParent,
PRUint32 aOffsetInParent);
private:
CreateElementTxn();
public:
virtual ~CreateElementTxn();
@ -61,22 +70,24 @@ public:
protected:
/** the document into which the new node will be inserted */
nsIDOMDocument *mDoc;
nsCOMPtr<nsIDOMDocument> mDoc;
/** the tag (mapping to object type) for the new element */
nsString mTag;
/** the node into which the new node will be inserted */
nsIDOMNode *mParent;
nsCOMPtr<nsIDOMNode> mParent;
/** the index in mParent for the new node */
PRUint32 mOffsetInParent;
/** the new node to insert */
nsIDOMElement *mNewNode;
nsCOMPtr<nsIDOMElement> mNewNode;
/** the node we will insert mNewNode before. We compute this ourselves. */
nsIDOMNode *mRefNode;
nsCOMPtr<nsIDOMNode> mRefNode;
friend class TransactionFactory;
};

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

@ -17,30 +17,32 @@
*/
#include "DeleteElementTxn.h"
#include "editor.h"
#include "nsIDOMDocument.h"
#ifdef NS_DEBUG
#include "nsIDOMElement.h"
#endif
// note that aEditor is not refcounted
DeleteElementTxn::DeleteElementTxn(nsEditor * aEditor,
nsIDOMDocument *aDoc,
nsIDOMNode * aElement,
nsIDOMNode * aParent)
: EditTxn(aEditor)
DeleteElementTxn::DeleteElementTxn()
: EditTxn()
{
mDoc = aDoc;
NS_ADDREF(mDoc);
mElement = aElement;
NS_ADDREF(mElement);
mParent = aParent;
NS_ADDREF(mParent);
}
nsresult DeleteElementTxn::Init(nsIDOMNode *aElement,
nsIDOMNode *aParent)
{
if ((nsnull!=aElement) && (nsnull!=aParent))
{
mElement = aElement;
mParent = aParent;
return NS_OK;
}
else
return NS_ERROR_NULL_POINTER;
}
DeleteElementTxn::~DeleteElementTxn()
{
NS_IF_RELEASE(mDoc);
NS_IF_RELEASE(mParent);
NS_IF_RELEASE(mElement);
}
nsresult DeleteElementTxn::Do(void)
@ -48,11 +50,32 @@ nsresult DeleteElementTxn::Do(void)
if (!mParent || !mElement)
return NS_ERROR_NULL_POINTER;
#ifdef NS_DEBUG
// begin debug output
nsCOMPtr<nsIDOMElement> element=mElement;
nsAutoString elementTag="text node";
if (element)
element->GetTagName(elementTag);
nsCOMPtr<nsIDOMElement> parentElement=mParent;
nsAutoString parentElementTag="text node";
if (parentElement)
parentElement->GetTagName(parentElementTag);
char *c, *p;
c = elementTag.ToNewCString();
p = parentElementTag.ToNewCString();
if (c&&p)
{
printf("DeleteElementTxn: deleting child %s from parent %s\n", c, p);
delete [] c;
delete [] p;
}
// end debug output
// begin sanity check 1: parent-child relationship
nsresult testResult;
nsCOMPtr<nsIDOMNode> parentNode;
testResult = mElement->GetParentNode(getter_AddRefs(parentNode));
NS_ASSERTION((NS_SUCCEEDED(testResult)), "bad mElement, couldn't get parent");
NS_ASSERTION((parentNode==mParent), "bad mParent, mParent!=mElement->GetParent() ");
// end sanity check 1.
#endif
// remember which child mElement was (by remembering which child was next)

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

@ -23,8 +23,10 @@
#include "nsIDOMNode.h"
#include "nsCOMPtr.h"
class nsIDOMDocument;
class nsIDOMElement;
#define DELETE_ELEMENT_TXN_IID \
{/* 6fd77770-ac49-11d2-86d8-000064657374 */ \
0x6fd77770, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that deletes a single element
@ -33,10 +35,13 @@ class DeleteElementTxn : public EditTxn
{
public:
DeleteElementTxn(nsEditor *aEditor,
nsIDOMDocument *aDoc,
nsIDOMNode *aElement,
nsIDOMNode *aParent);
virtual nsresult Init(nsIDOMNode *aElement,
nsIDOMNode *aParent);
private:
DeleteElementTxn();
public:
virtual ~DeleteElementTxn();
@ -58,14 +63,11 @@ public:
protected:
/** the document into which the new node will be inserted */
nsIDOMDocument *mDoc;
/** the element to delete */
nsIDOMNode *mElement;
nsCOMPtr<nsIDOMNode> mElement;
/** the node into which the new node will be inserted */
nsIDOMNode *mParent;
nsCOMPtr<nsIDOMNode> mParent;
/** the index in mParent for the new node */
PRUint32 mOffsetInParent;
@ -73,6 +75,8 @@ protected:
/** the node we will insert mNewNode before. We compute this ourselves. */
nsCOMPtr<nsIDOMNode> mRefNode;
friend class TransactionFactory;
};
#endif

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

@ -17,18 +17,73 @@
*/
#include "DeleteRangeTxn.h"
#include "editor.h"
#include "nsIDOMRange.h"
#include "nsIDOMCharacterData.h"
#include "nsIDOMNodeList.h"
#include "DeleteTextTxn.h"
#include "DeleteElementTxn.h"
#include "TransactionFactory.h"
#include "nsISupportsArray.h"
static NS_DEFINE_IID(kDeleteTextTxnIID, DELETE_TEXT_TXN_IID);
static NS_DEFINE_IID(kDeleteElementTxnIID, DELETE_ELEMENT_TXN_IID);
// note that aEditor is not refcounted
DeleteRangeTxn::DeleteRangeTxn(nsEditor *aEditor,
nsIDOMRange *aRange)
: EditTxn(aEditor)
DeleteRangeTxn::DeleteRangeTxn()
: EditAggregateTxn()
{
aRange->GetStartParent(getter_AddRefs(mStartParent));
aRange->GetEndParent(getter_AddRefs(mEndParent));
aRange->GetStartOffset(&mStartOffset);
aRange->GetEndOffset(&mEndOffset);
}
nsresult DeleteRangeTxn::Init(nsIDOMRange *aRange)
{
if (nsnull!=aRange)
{
nsresult result = aRange->GetStartParent(getter_AddRefs(mStartParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetStartParent failed.");
result = aRange->GetEndParent(getter_AddRefs(mEndParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetEndParent failed.");
result = aRange->GetStartOffset(&mStartOffset);
NS_ASSERTION((NS_SUCCEEDED(result)), "GetStartOffset failed.");
result = aRange->GetEndOffset(&mEndOffset);
NS_ASSERTION((NS_SUCCEEDED(result)), "GetEndOffset failed.");
result = aRange->GetCommonParent(getter_AddRefs(mCommonParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetCommonParent failed.");
#ifdef NS_DEBUG
PRUint32 count;
nsCOMPtr<nsIDOMCharacterData> textNode;
textNode = mStartParent;
if (textNode)
textNode->GetLength(&count);
else
{
nsCOMPtr<nsIDOMNodeList> children;
result = mStartParent->GetChildNodes(getter_AddRefs(children));
NS_ASSERTION(((NS_SUCCEEDED(result)) && children), "bad start child list");
children->GetLength(&count);
}
NS_ASSERTION(mStartOffset<count, "bad start offset");
textNode = mEndParent;
if (textNode)
textNode->GetLength(&count);
else
{
nsCOMPtr<nsIDOMNodeList> children;
result = mEndParent->GetChildNodes(getter_AddRefs(children));
NS_ASSERTION(((NS_SUCCEEDED(result)) && children), "bad end child list");
children->GetLength(&count);
}
NS_ASSERTION(mEndOffset<count, "bad end offset");
printf ("DeleteRange: %d of %p to %d of %p\n",
mStartOffset, (void *)mStartParent, mEndOffset, (void *)mEndParent);
#endif
return result;
}
else
return NS_ERROR_NULL_POINTER;
}
DeleteRangeTxn::~DeleteRangeTxn()
@ -37,28 +92,59 @@ DeleteRangeTxn::~DeleteRangeTxn()
nsresult DeleteRangeTxn::Do(void)
{
if (!mStartParent || !mEndParent)
if (!mStartParent || !mEndParent || !mCommonParent)
return NS_ERROR_NULL_POINTER;
nsresult result;
// build the child transactions
if (mStartParent==mEndParent)
{ // the selection begins and ends in the same node
result = CreateTxnsToDeleteBetween(mStartParent, mStartOffset, mEndOffset);
}
else
{ // the selection ends in a different node from where it started
// delete the relevant content in the start node
result = CreateTxnsToDeleteContent(mStartParent, mStartOffset, nsIEditor::eLTR);
if (NS_SUCCEEDED(result))
{
// delete the intervening nodes
result = CreateTxnsToDeleteNodesBetween(mCommonParent, mStartParent, mEndParent);
if (NS_SUCCEEDED(result))
{
// delete the relevant content in the end node
result = CreateTxnsToDeleteContent(mEndParent, mEndOffset, nsIEditor::eRTL);
if (NS_SUCCEEDED(result))
{ // now we have all our child transactions, do them
result = EditAggregateTxn::Do();
}
}
}
}
// if we've successfully built this aggregate transaction, then do it.
if (NS_SUCCEEDED(result))
result = EditAggregateTxn::Do();
return result;
}
nsresult DeleteRangeTxn::Undo(void)
{
if (!mStartParent || !mEndParent)
if (!mStartParent || !mEndParent || !mCommonParent)
return NS_ERROR_NULL_POINTER;
nsresult result;
nsresult result = EditAggregateTxn::Undo();
return result;
}
nsresult DeleteRangeTxn::Redo(void)
{
if (!mStartParent || !mEndParent)
if (!mStartParent || !mEndParent || !mCommonParent)
return NS_ERROR_NULL_POINTER;
nsresult result;
nsresult result = EditAggregateTxn::Redo();
return result;
}
@ -98,3 +184,265 @@ nsresult DeleteRangeTxn::GetRedoString(nsString **aString)
}
return NS_OK;
}
nsresult DeleteRangeTxn::CreateTxnsToDeleteBetween(nsIDOMNode *aStartParent,
PRUint32 aStartOffset,
PRUint32 aEndOffset)
{
nsresult result;
// see what kind of node we have
nsCOMPtr<nsIDOMCharacterData> textNode;
textNode = aStartParent; // this uses implicit nsCOMPtr QI
if (textNode)
{ // if the node is a text node, then delete text content
DeleteTextTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteTextTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(textNode, aStartOffset, (aEndOffset-aStartOffset)+1);
AppendChild(txn);
}
}
else
{
PRUint32 childCount;
nsCOMPtr<nsIDOMNodeList> children;
result = aStartParent->GetChildNodes(getter_AddRefs(children));
if ((NS_SUCCEEDED(result)) && children)
{
children->GetLength(&childCount);
NS_ASSERTION(aEndOffset<childCount, "bad aEndOffset");
PRUint32 i;
for (i=aStartOffset; i<=aEndOffset; i++)
{
nsCOMPtr<nsIDOMNode> child;
result = children->Item(i, getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, aStartParent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
}
}
return result;
}
nsresult DeleteRangeTxn::CreateTxnsToDeleteContent(nsIDOMNode *aParent,
PRUint32 aOffset,
nsIEditor::Direction aDir)
{
nsresult result;
// see what kind of node we have
nsCOMPtr<nsIDOMCharacterData> textNode;
textNode = aParent; // this uses implicit nsCOMPtr QI
if (textNode)
{ // if the node is a text node, then delete text content
PRUint32 start, numToDelete;
if (nsIEditor::eLTR==aDir)
{
start=aOffset;
textNode->GetLength(&numToDelete);
numToDelete -= (aOffset+1);
}
else
{
start=0;
numToDelete=aOffset;
}
DeleteTextTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteTextTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(textNode, start, numToDelete);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
else
{ // we have an interior node, so delete some of its children
if (nsIEditor::eLTR==aDir)
{ // delete from aOffset to end
PRUint32 childCount;
nsCOMPtr<nsIDOMNodeList> children;
result = aParent->GetChildNodes(getter_AddRefs(children));
if ((NS_SUCCEEDED(result)) && children)
{
children->GetLength(&childCount);
PRUint32 i;
for (i=aOffset; i<childCount; i++)
{
nsCOMPtr<nsIDOMNode> child;
result = children->Item(i, getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, aParent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
}
}
else
{ // delete from 0 to aOffset
nsCOMPtr<nsIDOMNode> child;
result = aParent->GetFirstChild(getter_AddRefs(child));
for (PRUint32 i=0; i<aOffset; i++)
{
if ((NS_SUCCEEDED(result)) && child)
{
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, aParent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIDOMNode> temp = child;
result = temp->GetNextSibling(getter_AddRefs(child));
}
}
}
return result;
}
nsresult DeleteRangeTxn::CreateTxnsToDeleteNodesBetween(nsIDOMNode *aCommonParent,
nsIDOMNode *aFirstChild,
nsIDOMNode *aLastChild)
{
nsresult result;
PRBool needToProcessLastChild=PR_TRUE; // set to false if we discover we can delete all required nodes by just walking up aFirstChild's parent list
nsCOMPtr<nsIDOMNode> parent; // the current parent in the iteration up the ancestors
nsCOMPtr<nsIDOMNode> child; // the current child of parent
nsISupportsArray *ancestorList; // the ancestorList of the other endpoint, used to gate deletion
NS_NewISupportsArray(&ancestorList);
if (nsnull==ancestorList)
return NS_ERROR_NULL_POINTER;
// Walk up the parent list of aFirstChild to aCommonParent,
// deleting all siblings to the right of the ancestors of aFirstChild.
BuildAncestorList(aLastChild, ancestorList);
child = aFirstChild;
result = child->GetParentNode(getter_AddRefs(parent));
while ((NS_SUCCEEDED(result)) && parent)
{
while ((NS_SUCCEEDED(result)) && child)
{ // this loop starts with the first sibling of an ancestor of aFirstChild
nsCOMPtr<nsIDOMNode> temp = child;
result = temp->GetNextSibling(getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
if (child==aLastChild)
{ // aFirstChild and aLastChild have the same parent, and we've reached aLastChild
needToProcessLastChild = PR_FALSE;
break;
}
// test if child is an ancestor of the other node. If it is, don't process this parent anymore
PRInt32 index;
index = ancestorList->IndexOf((nsISupports*)child);
if (-1!=index)
break;
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, parent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
if (parent==aCommonParent)
break;
child = parent;
nsCOMPtr<nsIDOMNode> temp=parent;
result = temp->GetParentNode(getter_AddRefs(parent));
}
// Walk up the parent list of aLastChild to aCommonParent,
// deleting all siblings to the left of the ancestors of aLastChild.
BuildAncestorList(aFirstChild, ancestorList);
if (PR_TRUE==needToProcessLastChild)
{
child = aLastChild;
result = child->GetParentNode(getter_AddRefs(parent));
while ((NS_SUCCEEDED(result)) && parent)
{
while ((NS_SUCCEEDED(result)) && child)
{ // this loop starts with the first sibling of an ancestor of aFirstChild
nsCOMPtr<nsIDOMNode> temp = child;
result = temp->GetPreviousSibling(getter_AddRefs(child));
if ((NS_SUCCEEDED(result)) && child)
{
// test if child is an ancestor of the other node. If it is, don't process this parent anymore
PRInt32 index;
index = ancestorList->IndexOf((nsISupports*)child);
if (-1!=index)
break;
DeleteElementTxn *txn;
result = TransactionFactory::GetNewTransaction(kDeleteElementTxnIID, (EditTxn **)&txn);
if (nsnull!=txn)
{
txn->Init(child, parent);
AppendChild(txn);
}
else
return NS_ERROR_NULL_POINTER;
}
}
if (parent==aCommonParent)
break;
child = parent;
nsCOMPtr<nsIDOMNode> temp=parent;
result = temp->GetParentNode(getter_AddRefs(parent));
}
}
NS_RELEASE(ancestorList);
return result;
}
nsresult DeleteRangeTxn::BuildAncestorList(nsIDOMNode *aNode, nsISupportsArray *aList)
{
nsresult result=NS_OK;
if (nsnull!=aNode && nsnull!=aList)
{
aList->Clear();
nsCOMPtr<nsIDOMNode> parent;
nsCOMPtr<nsIDOMNode> child = aNode;
result = child->GetParentNode(getter_AddRefs(parent));
while ((NS_SUCCEEDED(result)) && child && parent)
{
nsISupports * parentAsISupports;
parent->QueryInterface(nsISupports::IID(), (void **)&parentAsISupports);
aList->AppendElement(parentAsISupports);
child = parent;
nsCOMPtr<nsIDOMNode> temp=parent;
result = temp->GetParentNode(getter_AddRefs(parent));
}
}
else
result = NS_ERROR_NULL_POINTER;
return result;
}

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

@ -19,22 +19,33 @@
#ifndef DeleteRangeTxn_h__
#define DeleteRangeTxn_h__
#include "EditTxn.h"
#include "EditAggregateTxn.h"
#include "nsIDOMNode.h"
#include "nsIEditor.h"
#include "nsCOMPtr.h"
class nsIDOMDocument;
class nsIDOMRange;
class nsISupportsArray;
#define DELETE_RANGE_TXN_IID \
{/* 5ec6b260-ac49-11d2-86d8-000064657374 */ \
0x5ec6b260, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that deletes an entire range in the content tree
*/
class DeleteRangeTxn : public EditTxn
class DeleteRangeTxn : public EditAggregateTxn
{
public:
DeleteRangeTxn(nsEditor *aEditor,
nsIDOMRange *aRange);
virtual nsresult Init(nsIDOMRange *aRange);
private:
DeleteRangeTxn();
public:
virtual ~DeleteRangeTxn();
@ -54,6 +65,23 @@ public:
virtual nsresult GetRedoString(nsString **aString);
protected:
virtual nsresult CreateTxnsToDeleteBetween(nsIDOMNode *aStartParent,
PRUint32 aStartOffset,
PRUint32 aEndOffset);
virtual nsresult CreateTxnsToDeleteNodesBetween(nsIDOMNode *aParent,
nsIDOMNode *aFirstChild,
nsIDOMNode *aLastChild);
virtual nsresult CreateTxnsToDeleteContent(nsIDOMNode *aParent,
PRUint32 aOffset,
nsIEditor::Direction aDir);
virtual nsresult BuildAncestorList(nsIDOMNode *aNode,
nsISupportsArray *aList);
protected:
/** p1 in the range */
@ -65,9 +93,14 @@ protected:
/** p2 in the range */
nsCOMPtr<nsIDOMNode> mEndParent;
/** the closest common parent of p1 and p2 */
nsCOMPtr<nsIDOMNode> mCommonParent;
/** p2 offset */
PRInt32 mEndOffset;
friend class TransactionFactory;
};
#endif

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

@ -17,20 +17,23 @@
*/
#include "DeleteTextTxn.h"
#include "editor.h"
#include "nsIDOMCharacterData.h"
// note that aEditor is not refcounted
DeleteTextTxn::DeleteTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
DeleteTextTxn::DeleteTextTxn()
: EditTxn()
{
}
nsresult DeleteTextTxn::Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete)
: EditTxn(aEditor)
{
mElement = aElement;
mOffset = aOffset;
mNumCharsToDelete = aNumCharsToDelete;
mDeletedText = "";
return NS_OK;
}
nsresult DeleteTextTxn::Do(void)

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

@ -20,8 +20,13 @@
#define DeleteTextTxn_h__
#include "EditTxn.h"
#include "nsIDOMCharacterData.h"
#include "nsCOMPtr.h"
class nsIDOMCharacterData;
#define DELETE_TEXT_TXN_IID \
{/* 4d3a2720-ac49-11d2-86d8-000064657374 */ \
0x4d3a2720, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that changes an attribute of a content node.
@ -31,11 +36,15 @@ class DeleteTextTxn : public EditTxn
{
public:
DeleteTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete);
virtual nsresult Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete);
private:
DeleteTextTxn();
public:
virtual nsresult Do(void);
virtual nsresult Undo(void);
@ -53,7 +62,7 @@ public:
protected:
/** the text element to operate upon */
nsIDOMCharacterData *mElement;
nsCOMPtr<nsIDOMCharacterData> mElement;
/** the offset into mElement where the deletion is to take place */
PRUint32 mOffset;
@ -64,6 +73,8 @@ protected:
/** the text that was deleted */
nsString mDeletedText;
friend class TransactionFactory;
};
#endif

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

@ -0,0 +1,145 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL") you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "EditAggregateTxn.h"
#include "nsCOMPtr.h"
#include "nsIDOMNode.h"
#include "nsVoidArray.h"
EditAggregateTxn::EditAggregateTxn()
: EditTxn()
{
mChildren = new nsVoidArray();
}
EditAggregateTxn::~EditAggregateTxn()
{
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
for (i=0; i<count; i++)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
NS_IF_RELEASE(txn);
}
delete mChildren;
}
}
nsresult EditAggregateTxn::Do(void)
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
for (i=0; i<count; i++)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
result = txn->Do();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult EditAggregateTxn::Undo(void)
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
// undo goes through children backwards
for (i=count-1; i>=0; i--)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
result = txn->Undo();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult EditAggregateTxn::Redo(void)
{
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
if (nsnull!=mChildren)
{
PRInt32 i;
PRInt32 count = mChildren->Count();
for (i=0; i<count; i++)
{
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
result = txn->Redo();
if (NS_FAILED(result))
break;
}
}
return result;
}
nsresult EditAggregateTxn::GetIsTransient(PRBool *aIsTransient)
{
if (nsnull!=aIsTransient)
*aIsTransient = PR_TRUE;
return NS_OK;
}
nsresult EditAggregateTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
{
return NS_OK;
}
nsresult EditAggregateTxn::Write(nsIOutputStream *aOutputStream)
{
return NS_OK;
}
nsresult EditAggregateTxn::GetUndoString(nsString **aString)
{
if (nsnull!=aString)
*aString=nsnull;
return NS_OK;
}
nsresult EditAggregateTxn::GetRedoString(nsString **aString)
{
if (nsnull!=aString)
*aString=nsnull;
return NS_OK;
}
nsresult EditAggregateTxn::AppendChild(EditTxn *aTxn)
{
if ((nsnull!=mChildren) && (nsnull!=aTxn))
{
mChildren->AppendElement(aTxn);
return NS_OK;
}
return NS_ERROR_NULL_POINTER;
}

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

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef EditAggregateTxn_h__
#define EditAggregateTxn_h__
#include "EditTxn.h"
#define EDIT_AGGREGATE_TXN_IID \
{/* 345921a0-ac49-11d2-86d8-000064657374 */ \
0x345921a0, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
class nsVoidArray;
/**
* base class for all document editing transactions that require aggregation.
* provides a list of child transactions.
*/
class EditAggregateTxn : public EditTxn
{
public:
EditAggregateTxn();
virtual ~EditAggregateTxn();
virtual nsresult Do(void);
virtual nsresult Undo(void);
virtual nsresult Redo(void);
virtual nsresult GetIsTransient(PRBool *aIsTransient);
virtual nsresult Merge(PRBool *aDidMerge, nsITransaction *aTransaction);
virtual nsresult Write(nsIOutputStream *aOutputStream);
virtual nsresult GetUndoString(nsString **aString);
virtual nsresult GetRedoString(nsString **aString);
virtual nsresult AppendChild(EditTxn *aTxn);
protected:
nsVoidArray *mChildren;
};
#endif

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

@ -28,10 +28,8 @@ NS_IMPL_ADDREF(EditTxn)
NS_IMPL_RELEASE(EditTxn)
// note that aEditor is not refcounted
EditTxn::EditTxn(nsEditor *aEditor)
EditTxn::EditTxn()
{
NS_ASSERTION(nsnull!=aEditor, "null aEditor arg to EditTxn constructor");
mEditor = aEditor;
}
nsresult EditTxn::Do(void)

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

@ -20,13 +20,17 @@
#define EditTxn_h__
#include "nsITransaction.h"
class nsEditor;
class nsIDOMNode;
#define EDIT_TXN_IID \
{/* c5ea31b0-ac48-11d2-86d8-000064657374 */ \
0xc5ea31b0, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* base class for all document editing transactions.
* provides access to the nsEditor that created this transaction.
* provides default concrete behavior for all nsITransaction methods.
*/
class EditTxn : public nsITransaction
{
@ -34,7 +38,7 @@ public:
NS_DECL_ISUPPORTS
EditTxn(nsEditor *aEditor);
EditTxn();
virtual nsresult Do(void);
@ -52,10 +56,6 @@ public:
virtual nsresult GetRedoString(nsString **aString);
protected:
nsEditor *mEditor;
};
#endif

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

@ -20,18 +20,22 @@
#include "editor.h"
#include "nsIDOMCharacterData.h"
static NS_DEFINE_IID(kInsertTextTxnIID, INSERTTEXTTXN_IID);
static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID);
// note that aEditor is not refcounted
InsertTextTxn::InsertTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
InsertTextTxn::InsertTextTxn()
: EditTxn()
{
}
nsresult InsertTextTxn::Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert)
: EditTxn(aEditor)
{
mElement = aElement;
mOffset = aOffset;
mStringToInsert = aStringToInsert;
return NS_OK;
}
nsresult InsertTextTxn::Do(void)
@ -60,11 +64,11 @@ nsresult InsertTextTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
if ((nsnull!=aDidMerge) && (nsnull!=aTransaction))
{
// if aTransaction isa InsertTextTxn, absorb it
nsCOMPtr<InsertTextTxn> otherTxn;
nsresult result = aTransaction->QueryInterface(kInsertTextTxnIID, getter_AddRefs(otherTxn));
nsCOMPtr<InsertTextTxn> otherTxn = aTransaction;
nsresult result=NS_OK;// = aTransaction->QueryInterface(kInsertTextTxnIID, getter_AddRefs(otherTxn));
if (NS_SUCCEEDED(result) && (otherTxn))
{
nsString otherData;
nsAutoString otherData;
otherTxn->GetData(otherData);
mStringToInsert += otherData;
}

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

@ -20,14 +20,14 @@
#define InsertTextTxn_h__
#include "EditTxn.h"
#include "nsIDOMCharacterData.h"
#include "nsCOMPtr.h"
#define INSERTTEXTTXN_IID \
#define INSERT_TEXT_TXN_IID \
{/* 93276f00-ab2c-11d2-8f4b-006008159b0c*/ \
0x93276f00, 0xab2c, 0x11d2, \
{0x8f, 0xb4, 0x0, 0x60, 0x8, 0x15, 0x9b, 0xc} }
class nsIDOMCharacterData;
/**
* A transaction that changes an attribute of a content node.
* This transaction covers add, remove, and change attribute.
@ -36,15 +36,13 @@ class InsertTextTxn : public EditTxn
{
public:
InsertTextTxn(nsEditor *aEditor,
nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert);
virtual nsresult Init(nsIDOMCharacterData *aElement,
PRUint32 aOffset,
const nsString& aStringToInsert);
private:
// default ctor so that nsCOMPtr is happy
InsertTextTxn() : EditTxn(nsnull) {}
InsertTextTxn();
public:
@ -67,7 +65,7 @@ public:
// override QueryInterface to handle InsertTextTxn request
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
static const nsIID& IID() { static nsIID iid = INSERTTEXTTXN_IID; return iid; }
static const nsIID& IID() { static nsIID iid = INSERT_TEXT_TXN_IID; return iid; }
virtual nsresult GetData(nsString& aResult);
@ -75,7 +73,7 @@ public:
protected:
/** the text element to operate upon */
nsIDOMCharacterData *mElement;
nsCOMPtr<nsIDOMCharacterData> mElement;
/** the offset into mElement where the insertion is to take place */
PRUint32 mOffset;
@ -86,6 +84,8 @@ protected:
/** the text to insert into mElement at mOffset */
nsString mStringToInsert;
friend class TransactionFactory;
};
#endif

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

@ -0,0 +1,122 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "JoinElementTxn.h"
#include "nsIDOMNodeList.h"
#include "editor.h"
JoinElementTxn::JoinElementTxn()
: EditTxn()
{
}
nsresult JoinElementTxn::Init(nsIDOMNode *aLeftNode,
nsIDOMNode *aRightNode)
{
mLeftNode = aLeftNode;
mRightNode = aRightNode;
mOffset=0;
return NS_OK;
}
JoinElementTxn::~JoinElementTxn()
{
}
nsresult JoinElementTxn::Do(void)
{
nsresult result;
if ((mLeftNode) && (mRightNode))
{ // get the parent node
nsCOMPtr<nsIDOMNode>leftParent;
result = mLeftNode->GetParentNode(getter_AddRefs(leftParent));
if ((NS_SUCCEEDED(result)) && (leftParent))
{ // verify that mLeftNode and mRightNode have the same parent
nsCOMPtr<nsIDOMNode>rightParent;
result = mRightNode->GetParentNode(getter_AddRefs(rightParent));
if ((NS_SUCCEEDED(result)) && (rightParent))
{
if (leftParent==rightParent)
{
mParent=leftParent; // set this instance mParent.
// Other methods see a non-null mParent and know all is well
nsCOMPtr<nsIDOMNodeList> childNodes;
result = mLeftNode->GetChildNodes(getter_AddRefs(childNodes));
if ((NS_SUCCEEDED(result)) && (childNodes))
{
childNodes->GetLength(&mOffset);
}
result = nsEditor::JoinNodes(mLeftNode, mRightNode, mParent, PR_FALSE);
}
}
}
}
return result;
}
nsresult JoinElementTxn::Undo(void)
{
nsresult result = nsEditor::SplitNode(mRightNode, mOffset, mLeftNode, mParent);
return result;
}
nsresult JoinElementTxn::Redo(void)
{
nsresult result = nsEditor::JoinNodes(mLeftNode, mRightNode, mParent, PR_FALSE);
return result;
}
nsresult JoinElementTxn::GetIsTransient(PRBool *aIsTransient)
{
if (nsnull!=aIsTransient)
*aIsTransient = PR_FALSE;
return NS_OK;
}
nsresult JoinElementTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransaction)
{
if (nsnull!=aDidMerge)
*aDidMerge=PR_FALSE;
return NS_OK;
}
nsresult JoinElementTxn::Write(nsIOutputStream *aOutputStream)
{
return NS_OK;
}
nsresult JoinElementTxn::GetUndoString(nsString **aString)
{
if (nsnull!=aString)
{
**aString="Join Element";
}
return NS_OK;
}
nsresult JoinElementTxn::GetRedoString(nsString **aString)
{
if (nsnull!=aString)
{
**aString="Split Element";
}
return NS_OK;
}

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

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef JoinElementTxn_h__
#define JoinElementTxn_h__
#include "EditTxn.h"
#include "nsIDOMNode.h"
#include "nsCOMPtr.h"
#define JOIN_ELEMENT_TXN_IID \
{/* 9bc5f9f0-ac48-11d2-86d8-000064657374 */ \
0x9bc5f9f0, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that joins two elements E1 and E2 into a single node E.
* The children of E are the children of E1 followed by the children of E2.
*/
class JoinElementTxn : public EditTxn
{
public:
virtual nsresult Init(nsIDOMNode *aLeftNode,
nsIDOMNode *aRightNode);
protected:
JoinElementTxn();
public:
virtual ~JoinElementTxn();
virtual nsresult Do(void);
virtual nsresult Undo(void);
virtual nsresult Redo(void);
virtual nsresult GetIsTransient(PRBool *aIsTransient);
virtual nsresult Merge(PRBool *aDidMerge, nsITransaction *aTransaction);
virtual nsresult Write(nsIOutputStream *aOutputStream);
virtual nsresult GetUndoString(nsString **aString);
virtual nsresult GetRedoString(nsString **aString);
protected:
/** the elements to operate upon.
* After the merge, mRightNode remains and mLeftNode is removed from the content tree.
*/
nsCOMPtr<nsIDOMNode> mLeftNode;
nsCOMPtr<nsIDOMNode> mRightNode;
/** the offset into mNode where the children of mElement are split (for undo).<BR>
* mOffset is the index of the last child in the left node.
* -1 means the left node gets no children.
*/
PRUint32 mOffset;
/** the parent node containing mLeftNode and mRightNode */
nsCOMPtr<nsIDOMNode> mParent;
friend class TransactionFactory;
};
#endif

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

@ -17,44 +17,42 @@
*/
#include "SplitElementTxn.h"
#include "editor.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "editor.h"
// note that aEditor is not refcounted
SplitElementTxn::SplitElementTxn(nsEditor *aEditor,
nsIDOMNode *aNode,
PRInt32 aOffset)
: EditTxn(aEditor)
SplitElementTxn::SplitElementTxn()
: EditTxn()
{
mNode = aNode;
NS_ADDREF(mNode);
}
nsresult SplitElementTxn::Init(nsIDOMNode *aNode,
PRInt32 aOffset)
{
mExistingRightNode = aNode;
mOffset = aOffset;
mNewNode = nsnull;
mParent = nsnull;
return NS_OK;
}
SplitElementTxn::~SplitElementTxn()
{
NS_IF_RELEASE(mNode);
NS_IF_RELEASE(mNewNode);
NS_IF_RELEASE(mParent);
}
nsresult SplitElementTxn::Do(void)
{
// create a new node
nsresult result = mNode->CloneNode(PR_FALSE, &mNewNode);
NS_ASSERTION(((NS_SUCCEEDED(result)) && (nsnull!=mNewNode)), "could not create element.");
nsresult result = mExistingRightNode->CloneNode(PR_FALSE, getter_AddRefs(mNewLeftNode));
NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewLeftNode)), "could not create element.");
if ((NS_SUCCEEDED(result)) && (nsnull!=mNewNode))
if ((NS_SUCCEEDED(result)) && (mNewLeftNode))
{
// get the parent node
result = mNode->GetParentNode(&mParent);
result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent));
// insert the new node
if ((NS_SUCCEEDED(result)) && (nsnull!=mParent))
if ((NS_SUCCEEDED(result)) && (mParent))
{
result = mEditor->SplitNode(mNode, mOffset, mNewNode, mParent);
result = nsEditor::SplitNode(mExistingRightNode, mOffset, mNewLeftNode, mParent);
}
}
return result;
@ -63,13 +61,13 @@ nsresult SplitElementTxn::Do(void)
nsresult SplitElementTxn::Undo(void)
{
// this assumes Do inserted the new node in front of the prior existing node
nsresult result = mEditor->JoinNodes(mNode, mNewNode, mParent, PR_FALSE);
nsresult result = nsEditor::JoinNodes(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE);
return result;
}
nsresult SplitElementTxn::Redo(void)
{
nsresult result = mEditor->SplitNode(mNode, mOffset, mNewNode, mParent);
nsresult result = nsEditor::SplitNode(mExistingRightNode, mOffset, mNewLeftNode, mParent);
return result;
}

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

@ -20,10 +20,13 @@
#define SplitElementTxn_h__
#include "EditTxn.h"
#include "nsIDOMNode.h"
#include "nsCOMPtr.h"
class nsIDOMNode;
class nsIDOMElement;
class nsIDOMDocument;
#define SPLIT_ELEMENT_TXN_IID \
{/* 690c6290-ac48-11d2-86d8-000064657374 */ \
0x690c6290, 0xac48, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
/**
* A transaction that splits an element E into two identical nodes, E1 and E2
@ -33,10 +36,12 @@ class SplitElementTxn : public EditTxn
{
public:
SplitElementTxn(nsEditor *aEditor,
nsIDOMNode *aNode,
PRInt32 aOffset);
virtual nsresult Init (nsIDOMNode *aNode,
PRInt32 aOffset);
protected:
SplitElementTxn();
public:
virtual ~SplitElementTxn();
virtual nsresult Do(void);
@ -58,7 +63,7 @@ public:
protected:
/** the element to operate upon */
nsIDOMNode *mNode;
nsCOMPtr<nsIDOMNode> mExistingRightNode;
/** the offset into mElement where the children of mElement are split.<BR>
* mOffset is the index of the last child in the left node.
@ -67,8 +72,12 @@ protected:
PRInt32 mOffset;
/** the element we create when splitting mElement */
nsIDOMNode *mNewNode;
nsIDOMNode *mParent;
nsCOMPtr<nsIDOMNode> mNewLeftNode;
/** the parent shared by mExistingRightNode and mNewLeftNode */
nsCOMPtr<nsIDOMNode> mParent;
friend class TransactionFactory;
};

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

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "TransactionFactory.h"
// transactions this factory knows how to build
#include "InsertTextTxn.h"
#include "DeleteTextTxn.h"
#include "CreateElementTxn.h"
#include "DeleteElementTxn.h"
#include "DeleteRangeTxn.h"
#include "ChangeAttributeTxn.h"
#include "SplitElementTxn.h"
#include "JoinElementTxn.h"
static NS_DEFINE_IID(kInsertTextTxnIID, INSERT_TEXT_TXN_IID);
static NS_DEFINE_IID(kDeleteTextTxnIID, DELETE_TEXT_TXN_IID);
static NS_DEFINE_IID(kCreateElementTxnIID, CREATE_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kDeleteElementTxnIID, DELETE_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kDeleteRangeTxnIID, DELETE_RANGE_TXN_IID);
static NS_DEFINE_IID(kChangeAttributeTxnIID,CHANGE_ATTRIBUTE_TXN_IID);
static NS_DEFINE_IID(kSplitElementTxnIID, SPLIT_ELEMENT_TXN_IID);
static NS_DEFINE_IID(kJoinElementTxnIID, JOIN_ELEMENT_TXN_IID);
TransactionFactory::TransactionFactory()
{
}
TransactionFactory::~TransactionFactory()
{
}
nsresult
TransactionFactory::GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult)
{
nsresult result = NS_OK;
*aResult = nsnull;
if (aTxnType.Equals(kInsertTextTxnIID))
*aResult = new InsertTextTxn();
else if (aTxnType.Equals(kDeleteTextTxnIID))
*aResult = new DeleteTextTxn();
else if (aTxnType.Equals(kCreateElementTxnIID))
*aResult = new CreateElementTxn();
else if (aTxnType.Equals(kDeleteElementTxnIID))
*aResult = new DeleteElementTxn();
else if (aTxnType.Equals(kDeleteRangeTxnIID))
*aResult = new DeleteRangeTxn();
else if (aTxnType.Equals(kChangeAttributeTxnIID))
*aResult = new ChangeAttributeTxn();
else if (aTxnType.Equals(kSplitElementTxnIID))
*aResult = new SplitElementTxn();
else if (aTxnType.Equals(kJoinElementTxnIID))
*aResult = new JoinElementTxn();
if (nsnull==*aResult)
result = NS_ERROR_INVALID_ARG;
return result;
}

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

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef TransactionFactory_h__
#define TransactionFactory_h__
#include "nsISupports.h"
class EditTxn;
/**
* This class instantiates and optionally recycles edit transactions
* A recycler would be a separate static object, since this class does not get instantiated
*/
class TransactionFactory
{
protected:
TransactionFactory();
virtual ~TransactionFactory();
public:
static nsresult GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult);
};
#endif