зеркало из https://github.com/mozilla/pjs.git
* 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:
Родитель
5d9c7b3a64
Коммит
83a4e325ce
|
@ -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);
|
||||
|
||||
|
@ -55,8 +66,11 @@ public:
|
|||
|
||||
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,10 +36,14 @@ 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);
|
||||
|
||||
|
@ -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(¤tItem);
|
||||
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(¤tItem);
|
||||
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(¤tItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 Do(nsITransaction *aTxn);
|
||||
|
||||
virtual nsresult Commit(PRBool aCtrlKey);
|
||||
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);
|
||||
|
||||
|
@ -55,8 +66,11 @@ public:
|
|||
|
||||
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,10 +36,14 @@ 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);
|
||||
|
||||
|
@ -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(¤tItem);
|
||||
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(¤tItem);
|
||||
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(¤tItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 Do(nsITransaction *aTxn);
|
||||
|
||||
virtual nsresult Commit(PRBool aCtrlKey);
|
||||
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);
|
||||
|
||||
|
@ -55,8 +66,11 @@ public:
|
|||
|
||||
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,10 +36,14 @@ 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);
|
||||
|
||||
|
@ -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
|
Загрузка…
Ссылка в новой задаче