fix for 178264: nsRangeUpdater bugs and enhancements. precursor to 143338 landing. r=brade; sr=kin

This commit is contained in:
jfrancis%netscape.com 2002-11-10 15:11:08 +00:00
Родитель dc251d0042
Коммит 31794c188d
10 изменённых файлов: 98 добавлений и 82 удалений

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

@ -40,6 +40,7 @@
#include "nsCRT.h"
#include "DeleteElementTxn.h"
#include "nsSelectionState.h"
#ifdef NS_DEBUG
#include "nsIDOMElement.h"
#endif
@ -52,17 +53,20 @@ static const PRBool gNoisy = PR_FALSE;
DeleteElementTxn::DeleteElementTxn()
: EditTxn()
: EditTxn()
,mElement()
,mParent()
,mRefNode()
,mRangeUpdater(nsnull)
{
}
NS_IMETHODIMP DeleteElementTxn::Init(nsIDOMNode *aElement)
NS_IMETHODIMP DeleteElementTxn::Init(nsIDOMNode *aElement,
nsRangeUpdater *aRangeUpdater)
{
if (nsnull!=aElement) {
mElement = do_QueryInterface(aElement);
}
else
return NS_ERROR_NULL_POINTER;
if (!aElement) return NS_ERROR_NULL_POINTER;
mElement = do_QueryInterface(aElement);
mRangeUpdater = aRangeUpdater;
return NS_OK;
}
@ -108,8 +112,14 @@ NS_IMETHODIMP DeleteElementTxn::DoTransaction(void)
// remember which child mElement was (by remembering which child was next)
result = mElement->GetNextSibling(getter_AddRefs(mRefNode)); // can return null mRefNode
// give range updater a chance. SelAdjDeleteNode() needs to be called *before*
// we do the action, unlike some of the other nsRangeStore update methods.
if (mRangeUpdater)
mRangeUpdater->SelAdjDeleteNode(mElement);
nsCOMPtr<nsIDOMNode> resultNode;
result = mParent->RemoveChild(mElement, getter_AddRefs(resultNode));
return result;
}
@ -155,6 +165,9 @@ NS_IMETHODIMP DeleteElementTxn::RedoTransaction(void)
if (!mParent) { return NS_OK; } // this is a legal state, the txn is a no-op
if (!mElement) { return NS_ERROR_NULL_POINTER; }
if (mRangeUpdater)
mRangeUpdater->SelAdjDeleteNode(mElement);
nsCOMPtr<nsIDOMNode> resultNode;
nsresult result = mParent->RemoveChild(mElement, getter_AddRefs(resultNode));
return result;

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

@ -40,6 +40,7 @@
#define DeleteElementTxn_h__
#include "EditTxn.h"
#include "nsIDOMNode.h"
#include "nsCOMPtr.h"
@ -48,6 +49,8 @@
0x6fd77770, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
class nsRangeUpdater;
/**
* A transaction that deletes a single element
*/
@ -60,7 +63,7 @@ public:
/** initialize the transaction.
* @param aElement the node to delete
*/
NS_IMETHOD Init(nsIDOMNode *aElement);
NS_IMETHOD Init(nsIDOMNode *aElement, nsRangeUpdater *aRangeUpdater);
private:
DeleteElementTxn();
@ -84,15 +87,15 @@ protected:
/** the element to delete */
nsCOMPtr<nsIDOMNode> mElement;
/** the node into which the new node will be inserted */
/** parent of node to delete */
nsCOMPtr<nsIDOMNode> mParent;
/** the index in mParent for the new node */
PRUint32 mOffsetInParent;
/** the node we will insert mNewNode before. We compute this ourselves. */
/** next sibling to remember for undo/redo purposes */
nsCOMPtr<nsIDOMNode> mRefNode;
/** range updater object */
nsRangeUpdater *mRangeUpdater;
friend class TransactionFactory;
};

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

@ -61,17 +61,28 @@ static const PRBool gNoisy = PR_FALSE;
// note that aEditor is not refcounted
DeleteRangeTxn::DeleteRangeTxn()
: EditAggregateTxn()
: EditAggregateTxn()
,mRange()
,mStartParent()
,mStartOffset(0)
,mEndParent()
,mCommonParent()
,mEndOffset(0)
,mEditor(nsnull)
,mRangeUpdater(nsnull)
{
}
NS_IMETHODIMP DeleteRangeTxn::Init(nsIEditor *aEditor, nsIDOMRange *aRange)
NS_IMETHODIMP DeleteRangeTxn::Init(nsIEditor *aEditor,
nsIDOMRange *aRange,
nsRangeUpdater *aRangeUpdater)
{
NS_ASSERTION(aEditor && aRange, "bad state");
if (!aEditor || !aRange) { return NS_ERROR_NOT_INITIALIZED; }
mEditor = aEditor;
mRange = do_QueryInterface(aRange);
mRangeUpdater = aRangeUpdater;
nsresult result = aRange->GetStartContainer(getter_AddRefs(mStartParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetStartParent failed.");
@ -235,7 +246,7 @@ DeleteRangeTxn::CreateTxnsToDeleteBetween(nsIDOMNode *aStartParent,
numToDel = 1;
else
numToDel = aEndOffset-aStartOffset;
txn->Init(mEditor, textNode, aStartOffset, numToDel);
txn->Init(mEditor, textNode, aStartOffset, numToDel, mRangeUpdater);
AppendChild(txn);
NS_RELEASE(txn);
}
@ -262,7 +273,7 @@ DeleteRangeTxn::CreateTxnsToDeleteBetween(nsIDOMNode *aStartParent,
if (NS_FAILED(result)) return result;
if (!txn) return NS_ERROR_NULL_POINTER;
txn->Init(child);
txn->Init(child, mRangeUpdater);
AppendChild(txn);
NS_RELEASE(txn);
}
@ -300,7 +311,7 @@ NS_IMETHODIMP DeleteRangeTxn::CreateTxnsToDeleteContent(nsIDOMNode *aParent,
if (NS_FAILED(result)) return result;
if (!txn) return NS_ERROR_NULL_POINTER;
txn->Init(mEditor, textNode, start, numToDelete);
txn->Init(mEditor, textNode, start, numToDelete, mRangeUpdater);
AppendChild(txn);
NS_RELEASE(txn);
}
@ -341,7 +352,7 @@ NS_IMETHODIMP DeleteRangeTxn::CreateTxnsToDeleteNodesBetween()
if (NS_FAILED(result)) return result;
if (!txn) return NS_ERROR_NULL_POINTER;
txn->Init(node);
txn->Init(node, mRangeUpdater);
AppendChild(txn);
NS_RELEASE(txn);
iter->Next();

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

@ -54,6 +54,7 @@ class nsIDOMDocument;
class nsIDOMRange;
class nsIEditor;
class nsRangeUpdater;
/**
* A transaction that deletes an entire range in the content tree
@ -68,7 +69,9 @@ public:
* @param aEditor the object providing basic editing operations
* @param aRange the range to delete
*/
NS_IMETHOD Init(nsIEditor *aEditor, nsIDOMRange *aRange);
NS_IMETHOD Init(nsIEditor *aEditor,
nsIDOMRange *aRange,
nsRangeUpdater *aRangeUpdater);
private:
DeleteRangeTxn();
@ -122,6 +125,9 @@ protected:
/** the editor for this transaction */
nsIEditor* mEditor;
/** range updater object */
nsRangeUpdater *mRangeUpdater;
friend class TransactionFactory;
};

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

@ -39,6 +39,7 @@
#include "DeleteTextTxn.h"
#include "nsIDOMCharacterData.h"
#include "nsISelection.h"
#include "nsSelectionState.h"
#ifdef NS_DEBUG
static PRBool gNoisy = PR_FALSE;
@ -47,7 +48,13 @@ static const PRBool gNoisy = PR_FALSE;
#endif
DeleteTextTxn::DeleteTextTxn()
: EditTxn()
: EditTxn()
,mEditor(nsnull)
,mElement()
,mOffset(0)
,mNumCharsToDelete(0)
,mDeletedText(0)
,mRangeUpdater(nsnull)
{
}
@ -58,7 +65,8 @@ DeleteTextTxn::~DeleteTextTxn()
NS_IMETHODIMP DeleteTextTxn::Init(nsIEditor *aEditor,
nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete)
PRUint32 aNumCharsToDelete,
nsRangeUpdater *aRangeUpdater)
{
NS_ASSERTION(aEditor&&aElement, "bad arg");
if (!aEditor || !aElement) { return NS_ERROR_NULL_POINTER; }
@ -73,6 +81,7 @@ NS_IMETHODIMP DeleteTextTxn::Init(nsIEditor *aEditor,
NS_ASSERTION(count>=aNumCharsToDelete, "bad arg, numCharsToDelete. Not enough characters in node");
NS_ASSERTION(count>=aOffset+aNumCharsToDelete, "bad arg, numCharsToDelete. Not enough characters in node");
mDeletedText.SetLength(0);
mRangeUpdater = aRangeUpdater;
return NS_OK;
}
@ -87,6 +96,9 @@ NS_IMETHODIMP DeleteTextTxn::DoTransaction(void)
result = mElement->DeleteData(mOffset, mNumCharsToDelete);
if (NS_FAILED(result)) return result;
if (mRangeUpdater)
mRangeUpdater->SelAdjDeleteText(mElement, mOffset, mNumCharsToDelete);
// only set selection to deletion point if editor gives permission
PRBool bAdjustSelection;
mEditor->ShouldTxnSetSelection(&bAdjustSelection);

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

@ -49,6 +49,8 @@
0x4d3a2720, 0xac49, 0x11d2, \
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
class nsRangeUpdater;
/**
* A transaction that removes text from a content node.
*/
@ -67,7 +69,8 @@ public:
NS_IMETHOD Init(nsIEditor *aEditor,
nsIDOMCharacterData *aElement,
PRUint32 aOffset,
PRUint32 aNumCharsToDelete);
PRUint32 aNumCharsToDelete,
nsRangeUpdater *aRangeUpdater);
private:
DeleteTextTxn();
@ -100,6 +103,9 @@ protected:
/** the text that was deleted */
nsString mDeletedText;
/** range updater object */
nsRangeUpdater *mRangeUpdater;
friend class TransactionFactory;
};

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

@ -1326,8 +1326,6 @@ NS_IMETHODIMP nsEditor::DeleteNode(nsIDOMNode * aElement)
// The transaction system (if any) has taken ownwership of txn
NS_IF_RELEASE(txn);
mRangeUpdater.SelAdjDeleteNode(aElement, parent, offset);
if (mActionListeners)
{
for (i = 0; i < mActionListeners->Count(); i++)
@ -2650,8 +2648,6 @@ NS_IMETHODIMP nsEditor::DeleteText(nsIDOMCharacterData *aElement,
result = Do(txn);
mRangeUpdater.SelAdjDeleteText(aElement, aOffset, aLength);
// let listeners know what happened
if (mActionListeners)
{
@ -2679,7 +2675,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForDeleteText(nsIDOMCharacterData *aElement,
{
result = TransactionFactory::GetNewTransaction(DeleteTextTxn::GetCID(), (EditTxn **)aTxn);
if (NS_SUCCEEDED(result)) {
result = (*aTxn)->Init(this, aElement, aOffset, aLength);
result = (*aTxn)->Init(this, aElement, aOffset, aLength, &mRangeUpdater);
}
}
return result;
@ -4641,7 +4637,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForDeleteElement(nsIDOMNode * aElement,
{
result = TransactionFactory::GetNewTransaction(DeleteElementTxn::GetCID(), (EditTxn **)aTxn);
if (NS_SUCCEEDED(result)) {
result = (*aTxn)->Init(aElement);
result = (*aTxn)->Init(aElement, &mRangeUpdater);
}
}
return result;
@ -4786,7 +4782,7 @@ nsEditor::CreateTxnForDeleteSelection(nsIEditor::EDirection aAction,
result = TransactionFactory::GetNewTransaction(DeleteRangeTxn::GetCID(), (EditTxn **)&txn);
if ((NS_SUCCEEDED(result)) && (nsnull!=txn))
{
txn->Init(this, range);
txn->Init(this, range, &mRangeUpdater);
(*aTxn)->AppendChild(txn);
NS_RELEASE(txn);
}
@ -4814,10 +4810,9 @@ nsEditor::CreateTxnForDeleteSelection(nsIEditor::EDirection aAction,
//XXX: currently, this doesn't handle edge conditions because GetNext/GetPrior are not implemented
NS_IMETHODIMP
nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange,
nsIEditor::EDirection
aAction,
EditAggregateTxn *aTxn)
nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange,
nsIEditor::EDirection aAction,
EditAggregateTxn *aTxn)
{
nsCOMPtr<nsIDOMNode> node;
PRBool isFirst;
@ -4852,8 +4847,8 @@ nsEditor::CreateTxnForDeleteInsertionPoint(nsIDOMRange *aRange,
isFirst = (0==offset);
isLast = (count==(PRUint32)offset);
// XXX: if isFirst && isLast, then we'll need to delete the node
// as well as the 1 child
// XXX: if isFirst && isLast, then we'll need to delete the node
// as well as the 1 child
// build a transaction for deleting the appropriate data
// XXX: this has to come from rule section

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

@ -576,6 +576,7 @@ protected:
friend class nsAutoTxnsConserveSelection;
friend class nsAutoSelectionReset;
friend class nsAutoRules;
friend class nsRangeUpdater;
};

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

@ -203,51 +203,18 @@ nsRangeUpdater::nsRangeUpdater() : mArray(), mLock(PR_FALSE) {}
nsRangeUpdater::~nsRangeUpdater()
{
// free any items in the array
nsRangeStore *item;
for (PRInt32 i = mArray.Count()-1; i >= 0; --i)
{
item = (nsRangeStore*)mArray.ElementAt(i);
delete item;
}
//mArray.Clear(); not really needed
// nothing to do, we don't own the items in our array.
}
void*
nsRangeUpdater::RegisterRange(nsIDOMRange *aRange)
{
nsRangeStore *item = new nsRangeStore;
if (!item) return nsnull;
item->StoreRange(aRange);
mArray.AppendElement(item);
return item;
}
nsCOMPtr<nsIDOMRange>
nsRangeUpdater::ReclaimRange(void *aCookie)
{
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
if (!item) return nsnull;
nsCOMPtr<nsIDOMRange> outRange;
item->GetRange(address_of(outRange));
mArray.RemoveElement(aCookie);
delete item;
return outRange;
}
void
nsRangeUpdater::DropRange(void *aCookie)
{
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
if (!item) return;
mArray.RemoveElement(aCookie);
delete item;
}
void
nsRangeUpdater::RegisterRangeItem(nsRangeStore *aRangeItem)
{
if (!aRangeItem) return;
if (mArray.IndexOf(aRangeItem) != -1)
{
NS_ERROR("tried to register an already registered range");
return; // don't register it again. It would get doubly adjusted.
}
mArray.AppendElement(aRangeItem);
return;
}
@ -327,23 +294,28 @@ nsRangeUpdater::SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition)
nsresult
nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset)
nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode)
{
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
if (!aNode) return NS_ERROR_NULL_POINTER;
PRInt32 i, count = mArray.Count();
if (!count) return NS_OK;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset = 0;
nsRangeStore *item;
nsresult res = nsEditor::GetNodeLocation(aNode, address_of(parent), &offset);
NS_ENSURE_SUCCESS(res, res);
for (i=0; i<count; i++)
{
item = (nsRangeStore*)mArray.ElementAt(i);
if (!item) return NS_ERROR_NULL_POINTER;
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
if ((item->startNode.get() == parent) && (item->startOffset > offset))
item->startOffset--;
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
if ((item->endNode.get() == parent) && (item->endOffset > offset))
item->endOffset--;
}
// MOOSE: also check inside of aNode, expensive. But in theory, we shouldn't

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

@ -94,9 +94,6 @@ class nsRangeUpdater
nsRangeUpdater();
~nsRangeUpdater();
void* RegisterRange(nsIDOMRange *aRange);
nsCOMPtr<nsIDOMRange> ReclaimRange(void *aCookie);
void DropRange(void *aCookie);
void RegisterRangeItem(nsRangeStore *aRangeItem);
void DropRangeItem(nsRangeStore *aRangeItem);
nsresult RegisterSelectionState(nsSelectionState &aSelState);
@ -109,7 +106,7 @@ class nsRangeUpdater
// which is not what you want if you know you are reinserting it.
nsresult SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition);
nsresult SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition);
nsresult SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset);
nsresult SelAdjDeleteNode(nsIDOMNode *aNode);
nsresult SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode);
nsresult SelAdjJoinNodes(nsIDOMNode *aLeftNode,
nsIDOMNode *aRightNode,