bug 66290: embedding work: refactor editor to allow smaller plaintext only library. Embedding clients may be interested inthis library if they want to embed a browser but not composer/mail-compose. Reduces library footprint for plaintext-only library by over 50% on all three platforms. r=fm; sr=kin

git-svn-id: svn://10.0.0.236/trunk@85666 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
jfrancis%netscape.com
2001-01-28 20:13:07 +00:00
parent b48ee3a7d2
commit 7cde2dddd5
58 changed files with 15114 additions and 11364 deletions

View File

@@ -59,6 +59,7 @@
#include "nsIKBStateControl.h"
#include "nsIWidget.h"
#include "nsIScrollbar.h"
#include "nsIPlaintextEditor.h"
#include "nsIFrame.h" // Needed by IME code
@@ -93,7 +94,7 @@
#include "JoinElementTxn.h"
#include "nsStyleSheetTxns.h"
#include "IMETextTxn.h"
#include "nsIHTMLEditor.h"
// included for nsEditor::CreateHTMLContent
#include "nsIElementFactory.h"
#include "nsINodeInfo.h"
@@ -148,738 +149,6 @@ const PRUnichar nbsp = 160;
PRInt32 nsEditor::gInstanceCount = 0;
/***************************************************************************
* class for recording selection info. stores selection as collection of
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Cant store
* ranges since dom gravity will possibly change the ranges.
*/
nsSelectionState::nsSelectionState() : mArray(){}
nsSelectionState::~nsSelectionState()
{
MakeEmpty();
}
nsresult
nsSelectionState::SaveSelection(nsISelection *aSel)
{
if (!aSel) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
PRInt32 i,rangeCount, arrayCount = mArray.Count();
nsRangeStore *item;
aSel->GetRangeCount(&rangeCount);
// if we need more items in the array, new them
if (arrayCount<rangeCount)
{
PRInt32 count = rangeCount-arrayCount;
for (i=0; i<count; i++)
{
item = new nsRangeStore;
mArray.AppendElement(item);
}
}
// else if we have too many, delete them
else if (rangeCount>arrayCount)
{
while ((item = (nsRangeStore*)mArray.ElementAt(rangeCount)))
{
delete item;
mArray.RemoveElementAt(rangeCount);
}
}
// now store the selection ranges
for (i=0; i<rangeCount; i++)
{
item = (nsRangeStore*)mArray.ElementAt(i);
if (!item) return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMRange> range;
res = aSel->GetRangeAt(i, getter_AddRefs(range));
item->StoreRange(range);
}
return res;
}
nsresult
nsSelectionState::RestoreSelection(nsISelection *aSel)
{
if (!aSel) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
PRInt32 i, arrayCount = mArray.Count();
nsRangeStore *item;
// clear out selection
aSel->RemoveAllRanges();
// set the selection ranges anew
for (i=0; i<arrayCount; i++)
{
item = (nsRangeStore*)mArray.ElementAt(i);
if (!item) return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMRange> range;
item->GetRange(address_of(range));
if (!range) return NS_ERROR_UNEXPECTED;
res = aSel->AddRange(range);
if(NS_FAILED(res)) return res;
}
return NS_OK;
}
PRBool
nsSelectionState::IsCollapsed()
{
if (1 != mArray.Count()) return PR_FALSE;
nsRangeStore *item;
item = (nsRangeStore*)mArray.ElementAt(0);
if (!item) return PR_FALSE;
nsCOMPtr<nsIDOMRange> range;
item->GetRange(address_of(range));
if (!range) return PR_FALSE;
PRBool bIsCollapsed;
range->GetCollapsed(&bIsCollapsed);
return bIsCollapsed;
}
PRBool
nsSelectionState::IsEqual(nsSelectionState *aSelState)
{
if (!aSelState) return NS_ERROR_NULL_POINTER;
PRInt32 i, myCount = mArray.Count(), itsCount = aSelState->mArray.Count();
if (myCount != itsCount) return PR_FALSE;
if (myCount < 1) return PR_FALSE;
nsRangeStore *myItem, *itsItem;
for (i=0; i<myCount; i++)
{
myItem = (nsRangeStore*)mArray.ElementAt(0);
itsItem = (nsRangeStore*)(aSelState->mArray.ElementAt(0));
if (!myItem || !itsItem) return PR_FALSE;
nsCOMPtr<nsIDOMRange> myRange, itsRange;
myItem->GetRange(address_of(myRange));
itsItem->GetRange(address_of(itsRange));
if (!myRange || !itsRange) return PR_FALSE;
PRInt32 compResult;
myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
if (compResult) return PR_FALSE;
myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
if (compResult) return PR_FALSE;
}
// if we got here, they are equal
return PR_TRUE;
}
void
nsSelectionState::MakeEmpty()
{
// free any items in the array
nsRangeStore *item;
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
{
delete item;
mArray.RemoveElementAt(0);
}
}
PRBool
nsSelectionState::IsEmpty()
{
return (mArray.Count() == 0);
}
/***************************************************************************
* nsRangeUpdater: class for updating nsIDOMRanges in response to editor actions.
*/
nsRangeUpdater::nsRangeUpdater() : mArray(), mLock(PR_FALSE) {}
nsRangeUpdater::~nsRangeUpdater()
{
// free any items in the array
nsRangeStore *item;
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
{
delete item;
mArray.RemoveElementAt(0);
}
}
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;
mArray.AppendElement(aRangeItem);
return;
}
void
nsRangeUpdater::DropRangeItem(nsRangeStore *aRangeItem)
{
if (!aRangeItem) return;
mArray.RemoveElement(aRangeItem);
return;
}
nsresult
nsRangeUpdater::RegisterSelectionState(nsSelectionState &aSelState)
{
PRInt32 i, theCount = aSelState.mArray.Count();
if (theCount < 1) return NS_ERROR_FAILURE;
nsRangeStore *item;
for (i=0; i<theCount; i++)
{
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
RegisterRangeItem(item);
}
return NS_OK;;
}
nsresult
nsRangeUpdater::DropSelectionState(nsSelectionState &aSelState)
{
PRInt32 i, theCount = aSelState.mArray.Count();
if (theCount < 1) return NS_ERROR_FAILURE;
nsRangeStore *item;
for (i=0; i<theCount; i++)
{
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
DropRangeItem(item);
}
return NS_OK;;
}
// gravity methods:
nsresult
nsRangeUpdater::SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition)
{
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
if (!aParent) return NS_ERROR_NULL_POINTER;
PRInt32 i, count = mArray.Count();
if (!count) return NS_OK;
nsRangeStore *item;
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 > aPosition))
item->startOffset++;
if ((item->endNode.get() == aParent) && (item->endOffset > aPosition))
item->endOffset++;
}
return NS_OK;
}
nsresult
nsRangeUpdater::SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition)
{
return SelAdjCreateNode(aParent, aPosition);
}
nsresult
nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset)
{
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;
nsRangeStore *item;
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))
item->startOffset--;
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
item->endOffset--;
}
// MOOSE: also check inside of aNode, expensive. But in theory, we shouldn't
// actually hit this case in the usage i forsee for this.
return NS_OK;
}
nsresult
nsRangeUpdater::SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode)
{
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
if (!aOldRightNode || !aNewLeftNode) return NS_ERROR_NULL_POINTER;
PRInt32 i, count = mArray.Count();
if (!count) return NS_OK;
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
nsresult result = nsEditor::GetNodeLocation(aOldRightNode, address_of(parent), &offset);
if (NS_FAILED(result)) return result;
// first part is same as inserting aNewLeftnode
result = SelAdjInsertNode(parent,offset-1);
if (NS_FAILED(result)) return result;
// next step is to check for range enpoints inside aOldRightNode
nsRangeStore *item;
for (i=0; i<count; i++)
{
item = (nsRangeStore*)mArray.ElementAt(i);
if (!item) return NS_ERROR_NULL_POINTER;
if (item->startNode.get() == aOldRightNode)
{
if (item->startOffset > aOffset)
{
item->startOffset -= aOffset;
}
else
{
item->startNode = aNewLeftNode;
}
}
if (item->endNode.get() == aOldRightNode)
{
if (item->endOffset > aOffset)
{
item->endOffset -= aOffset;
}
else
{
item->endNode = aNewLeftNode;
}
}
}
return NS_OK;
}
nsresult
nsRangeUpdater::SelAdjJoinNodes(nsIDOMNode *aLeftNode,
nsIDOMNode *aRightNode,
nsIDOMNode *aParent,
PRInt32 aOffset,
PRInt32 aOldLeftNodeLength)
{
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
if (!aLeftNode || !aRightNode || !aParent) return NS_ERROR_NULL_POINTER;
PRInt32 i, count = mArray.Count();
if (!count) return NS_OK;
nsRangeStore *item;
for (i=0; i<count; i++)
{
item = (nsRangeStore*)mArray.ElementAt(i);
if (!item) return NS_ERROR_NULL_POINTER;
// adjust endpoints in aParent
if (item->startNode.get() == aParent)
{
if (item->startOffset > aOffset)
{
item->startOffset--;
}
else if (item->startOffset == aOffset)
{
// join keeps right hand node
item->startNode = aRightNode;
item->startOffset = aOldLeftNodeLength;
}
}
if (item->endNode.get() == aParent)
{
if (item->endOffset > aOffset)
{
item->endOffset--;
}
else if (item->endOffset == aOffset)
{
// join keeps right hand node
item->endNode = aRightNode;
item->endOffset = aOldLeftNodeLength;
}
}
// adjust endpoints in aRightNode
if (item->startNode.get() == aRightNode)
item->startOffset += aOldLeftNodeLength;
if (item->endNode.get() == aRightNode)
item->endOffset += aOldLeftNodeLength;
}
return NS_OK;
}
nsresult
nsRangeUpdater::SelAdjInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString)
{
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
return NS_OK;
}
nsresult
nsRangeUpdater::SelAdjDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength)
{
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
return NS_OK;
}
nsresult
nsRangeUpdater::WillReplaceContainer()
{
if (mLock) return NS_ERROR_UNEXPECTED;
mLock = PR_TRUE;
return NS_OK;
}
nsresult
nsRangeUpdater::DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode)
{
if (!mLock) return NS_ERROR_UNEXPECTED;
mLock = PR_FALSE;
if (!aOriginalNode || !aNewNode) return NS_ERROR_NULL_POINTER;
PRInt32 i, count = mArray.Count();
if (!count) return NS_OK;
nsRangeStore *item;
for (i=0; i<count; i++)
{
item = (nsRangeStore*)mArray.ElementAt(i);
if (!item) return NS_ERROR_NULL_POINTER;
if (item->startNode.get() == aOriginalNode)
item->startNode = aNewNode;
if (item->endNode.get() == aOriginalNode)
item->endNode = aNewNode;
}
return NS_OK;
}
nsresult
nsRangeUpdater::WillRemoveContainer()
{
if (mLock) return NS_ERROR_UNEXPECTED;
mLock = PR_TRUE;
return NS_OK;
}
nsresult
nsRangeUpdater::DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen)
{
if (!mLock) return NS_ERROR_UNEXPECTED;
mLock = PR_FALSE;
if (!aNode || !aParent) return NS_ERROR_NULL_POINTER;
PRInt32 i, count = mArray.Count();
if (!count) return NS_OK;
nsRangeStore *item;
for (i=0; i<count; i++)
{
item = (nsRangeStore*)mArray.ElementAt(i);
if (!item) return NS_ERROR_NULL_POINTER;
if (item->startNode.get() == aNode)
{
item->startNode = aParent;
item->startOffset += aOffset;
}
if (item->endNode.get() == aNode)
{
item->endNode = aParent;
item->endOffset += aOffset;
}
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
item->startOffset += (PRInt32)aNodeOrigLen-1;
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
item->endOffset += (PRInt32)aNodeOrigLen-1;
}
return NS_OK;
}
nsresult
nsRangeUpdater::WillInsertContainer()
{
if (mLock) return NS_ERROR_UNEXPECTED;
mLock = PR_TRUE;
return NS_OK;
}
nsresult
nsRangeUpdater::DidInsertContainer()
{
if (!mLock) return NS_ERROR_UNEXPECTED;
mLock = PR_FALSE;
return NS_OK;
}
nsresult
nsRangeUpdater::WillMoveNode()
{
if (mLock) return NS_ERROR_UNEXPECTED;
mLock = PR_TRUE;
return NS_OK;
}
nsresult
nsRangeUpdater::DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset)
{
if (!mLock) return NS_ERROR_UNEXPECTED;
mLock = PR_FALSE;
if (!aOldParent || !aNewParent) return NS_ERROR_NULL_POINTER;
PRInt32 i, count = mArray.Count();
if (!count) return NS_OK;
nsRangeStore *item;
for (i=0; i<count; i++)
{
item = (nsRangeStore*)mArray.ElementAt(i);
if (!item) return NS_ERROR_NULL_POINTER;
// like a delete in aOldParent
if ((item->startNode.get() == aOldParent) && (item->startOffset > aOldOffset))
item->startOffset--;
if ((item->endNode.get() == aOldParent) && (item->endOffset > aOldOffset))
item->endOffset--;
// and like an insert in aNewParent
if ((item->startNode.get() == aNewParent) && (item->startOffset > aNewOffset))
item->startOffset++;
if ((item->endNode.get() == aNewParent) && (item->endOffset > aNewOffset))
item->endOffset++;
}
return NS_OK;
}
/***************************************************************************
* helper class for nsSelectionState. nsRangeStore stores range endpoints.
*/
// DEBUG: PRInt32 nsRangeStore::n = 0;
nsRangeStore::nsRangeStore()
{
// DEBUG: n++; printf("range store alloc count=%d\n", n);
}
nsRangeStore::~nsRangeStore()
{
// DEBUG: n--; printf("range store alloc count=%d\n", n);
}
nsresult nsRangeStore::StoreRange(nsIDOMRange *aRange)
{
if (!aRange) return NS_ERROR_NULL_POINTER;
aRange->GetStartContainer(getter_AddRefs(startNode));
aRange->GetEndContainer(getter_AddRefs(endNode));
aRange->GetStartOffset(&startOffset);
aRange->GetEndOffset(&endOffset);
return NS_OK;
}
nsresult nsRangeStore::GetRange(nsCOMPtr<nsIDOMRange> *outRange)
{
if (!outRange) return NS_ERROR_NULL_POINTER;
nsresult res = nsComponentManager::CreateInstance(kCRangeCID,
nsnull,
NS_GET_IID(nsIDOMRange),
getter_AddRefs(*outRange));
if(NS_FAILED(res)) return res;
res = (*outRange)->SetStart(startNode, startOffset);
if(NS_FAILED(res)) return res;
res = (*outRange)->SetEnd(endNode, endOffset);
return res;
}
/***************************************************************************
* another helper class for nsSelectionState. stack based class for doing
* Will/DidReplaceContainer()
*/
class nsAutoReplaceContainerSelNotify
{
private:
nsRangeUpdater &mRU;
nsIDOMNode *mOriginalNode;
nsIDOMNode *mNewNode;
public:
nsAutoReplaceContainerSelNotify(nsRangeUpdater &aRangeUpdater, nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode) :
mRU(aRangeUpdater)
,mOriginalNode(aOriginalNode)
,mNewNode(aNewNode)
{
mRU.WillReplaceContainer();
}
~nsAutoReplaceContainerSelNotify()
{
mRU.DidReplaceContainer(mOriginalNode, mNewNode);
}
};
/***************************************************************************
* another helper class for nsSelectionState. stack based class for doing
* Will/DidRemoveContainer()
*/
class nsAutoRemoveContainerSelNotify
{
private:
nsRangeUpdater &mRU;
nsIDOMNode *mNode;
nsIDOMNode *mParent;
PRInt32 mOffset;
PRUint32 mNodeOrigLen;
public:
nsAutoRemoveContainerSelNotify(nsRangeUpdater &aRangeUpdater,
nsIDOMNode *aNode,
nsIDOMNode *aParent,
PRInt32 aOffset,
PRUint32 aNodeOrigLen) :
mRU(aRangeUpdater)
,mNode(aNode)
,mParent(aParent)
,mOffset(aOffset)
,mNodeOrigLen(aNodeOrigLen)
{
mRU.WillRemoveContainer();
}
~nsAutoRemoveContainerSelNotify()
{
mRU.DidRemoveContainer(mNode, mParent, mOffset, mNodeOrigLen);
}
};
/***************************************************************************
* another helper class for nsSelectionState. stack based class for doing
* Will/DidInsertContainer()
*/
class nsAutoInsertContainerSelNotify
{
private:
nsRangeUpdater &mRU;
public:
nsAutoInsertContainerSelNotify(nsRangeUpdater &aRangeUpdater) :
mRU(aRangeUpdater)
{
mRU.WillInsertContainer();
}
~nsAutoInsertContainerSelNotify()
{
mRU.DidInsertContainer();
}
};
/***************************************************************************
* another helper class for nsSelectionState. stack based class for doing
* Will/DidMoveNode()
*/
class nsAutoMoveNodeSelNotify
{
private:
nsRangeUpdater &mRU;
nsIDOMNode *mOldParent;
nsIDOMNode *mNewParent;
PRInt32 mOldOffset;
PRInt32 mNewOffset;
public:
nsAutoMoveNodeSelNotify(nsRangeUpdater &aRangeUpdater,
nsIDOMNode *aOldParent,
PRInt32 aOldOffset,
nsIDOMNode *aNewParent,
PRInt32 aNewOffset) :
mRU(aRangeUpdater)
,mOldParent(aOldParent)
,mNewParent(aNewParent)
,mOldOffset(aOldOffset)
,mNewOffset(aNewOffset)
{
mRU.WillMoveNode();
}
~nsAutoMoveNodeSelNotify()
{
mRU.DidMoveNode(mOldParent, mOldOffset, mNewParent, mNewOffset);
}
};
//---------------------------------------------------------------------------
//
// nsEditor: base editor class implementation
@@ -2606,7 +1875,7 @@ nsEditor::ForceCompositionEnd()
#endif
#ifdef XP_UNIX
if(mFlags & nsIHTMLEditor::eEditorPasswordMask)
if(mFlags & nsIPlaintextEditor::eEditorPasswordMask)
return NS_OK;
#endif
@@ -5059,7 +4328,6 @@ nsEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode,
textNode->GetLength(&strLength);
if (strLength)
{
// you could use nsITextContent::IsOnlyWhitespace here
textNode->SubstringData(0,1,tempString);
*outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
*outIsNBSP = (tempString.First() == nbsp);
@@ -5391,7 +4659,7 @@ nsresult nsEditor::EndUpdateViewBatch()
PRBool forceReflow = PR_TRUE;
if (flags & nsIHTMLEditor::eEditorDisableForcedReflowsMask)
if (flags & nsIPlaintextEditor::eEditorDisableForcedReflowsMask)
forceReflow = PR_FALSE;
nsCOMPtr<nsIPresShell> presShell;
@@ -5401,7 +4669,7 @@ nsresult nsEditor::EndUpdateViewBatch()
PRUint32 updateFlag = NS_VMREFRESH_IMMEDIATE;
if (flags & nsIHTMLEditor::eEditorDisableForcedUpdatesMask)
if (flags & nsIPlaintextEditor::eEditorDisableForcedUpdatesMask)
updateFlag = NS_VMREFRESH_NO_SYNC;
#ifdef HACK_FORCE_REDRAW
@@ -5482,9 +4750,129 @@ nsEditor::DeleteSelectionImpl(nsIEditor::EDirection aAction)
return res;
}
// XXX: error handling in this routine needs to be cleaned up!
NS_IMETHODIMP
nsEditor::DeleteSelectionAndCreateNode(const nsString& aTag,
nsIDOMNode ** aNewNode)
{
nsCOMPtr<nsIDOMNode> parentSelectedNode;
PRInt32 offsetOfNewNode;
nsresult result = DeleteSelectionAndPrepareToCreateNode(parentSelectedNode,
offsetOfNewNode);
if (!NS_SUCCEEDED(result))
return result;
nsCOMPtr<nsIDOMNode> newNode;
result = CreateNode(aTag, parentSelectedNode, offsetOfNewNode,
getter_AddRefs(newNode));
// XXX: ERROR_HANDLING check result, and make sure aNewNode is set correctly in success/failure cases
*aNewNode = newNode;
NS_IF_ADDREF(*aNewNode);
// we want the selection to be just after the new node
nsCOMPtr<nsISelection> selection;
result = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(result)) return result;
if (!selection) return NS_ERROR_NULL_POINTER;
result = selection->Collapse(parentSelectedNode, offsetOfNewNode+1);
return result;
}
/* Non-interface, protected methods */
NS_IMETHODIMP
nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode)
{
nsresult result=NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsISelection> selection;
result = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(result)) return result;
if (!selection) return NS_ERROR_NULL_POINTER;
PRBool collapsed;
result = selection->GetIsCollapsed(&collapsed);
if (NS_SUCCEEDED(result) && !collapsed)
{
result = DeleteSelection(nsIEditor::eNone);
if (NS_FAILED(result)) {
return result;
}
// get the new selection
result = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(result)) {
return result;
}
#ifdef NS_DEBUG
nsCOMPtr<nsIDOMNode>testSelectedNode;
nsresult debugResult = selection->GetAnchorNode(getter_AddRefs(testSelectedNode));
// no selection is ok.
// if there is a selection, it must be collapsed
if (testSelectedNode)
{
PRBool testCollapsed;
debugResult = selection->GetIsCollapsed(&testCollapsed);
NS_ASSERTION((NS_SUCCEEDED(result)), "couldn't get a selection after deletion");
NS_ASSERTION(testCollapsed, "selection not reset after deletion");
}
#endif
}
// split the selected node
PRInt32 offsetOfSelectedNode;
result = selection->GetAnchorNode(getter_AddRefs(parentSelectedNode));
if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetOfSelectedNode)) && parentSelectedNode)
{
nsCOMPtr<nsIDOMNode> selectedNode;
PRUint32 selectedNodeContentCount=0;
nsCOMPtr<nsIDOMCharacterData>selectedParentNodeAsText;
selectedParentNodeAsText = do_QueryInterface(parentSelectedNode);
offsetOfNewNode = offsetOfSelectedNode;
/* if the selection is a text node, split the text node if necesary
and compute where to put the new node
*/
if (selectedParentNodeAsText)
{
PRInt32 indexOfTextNodeInParent;
selectedNode = do_QueryInterface(parentSelectedNode);
selectedNode->GetParentNode(getter_AddRefs(parentSelectedNode));
selectedParentNodeAsText->GetLength(&selectedNodeContentCount);
GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent);
if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount))
{
nsCOMPtr<nsIDOMNode> newSiblingNode;
result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode));
// now get the node's offset in it's parent, and insert the new tag there
if (NS_SUCCEEDED(result)) {
result = GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
}
}
else
{ // determine where to insert the new node
if (0==offsetOfSelectedNode) {
offsetOfNewNode = indexOfTextNodeInParent; // insert new node as previous sibling to selection parent
}
else { // insert new node as last child
GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node
}
}
}
// Here's where the new node was inserted
}
#ifdef DEBUG
else {
printf("InsertLineBreak into an empty document is not yet supported\n");
}
#endif
return result;
}
NS_IMETHODIMP
nsEditor::DoAfterDoTransaction(nsITransaction *aTxn)
{