1998-12-14 23:16:31 +00:00
|
|
|
/* -*- 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* nsContentIterator.cpp: Implementation of the nsContentIterator object.
|
1999-02-12 05:28:12 +00:00
|
|
|
* This ite
|
1998-12-14 23:16:31 +00:00
|
|
|
*/
|
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
#include "nsISupports.h"
|
|
|
|
#include "nsIEnumerator.h"
|
|
|
|
#include "nsIContentIterator.h"
|
1998-12-14 23:16:31 +00:00
|
|
|
#include "nsIDOMRange.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIDOMText.h"
|
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
#include "nsCOMPtr.h"
|
1998-12-14 23:16:31 +00:00
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A simple iterator class for traversing the content in "close tag" order
|
|
|
|
*/
|
|
|
|
class nsContentIterator : public nsIContentIterator, public nsIEnumerator
|
1998-12-14 23:16:31 +00:00
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
nsContentIterator();
|
|
|
|
virtual ~nsContentIterator();
|
|
|
|
|
|
|
|
// nsIContentIterator interface methods ------------------------------
|
|
|
|
|
|
|
|
NS_IMETHOD Init(nsIContent* aRoot);
|
|
|
|
|
|
|
|
NS_IMETHOD Init(nsIDOMRange* aRange);
|
|
|
|
|
|
|
|
NS_IMETHOD First();
|
|
|
|
|
|
|
|
NS_IMETHOD Last();
|
|
|
|
|
|
|
|
NS_IMETHOD Next();
|
|
|
|
|
|
|
|
NS_IMETHOD Prev();
|
|
|
|
|
|
|
|
NS_IMETHOD CurrentNode(nsIContent **aNode);
|
|
|
|
|
|
|
|
NS_IMETHOD IsDone();
|
|
|
|
|
|
|
|
// nsIEnumertor interface methods ------------------------------
|
|
|
|
|
|
|
|
NS_IMETHOD CurrentItem(nsISupports **aItem);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
static nsIContent* GetDeepFirstChild(nsIContent* aRoot);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> mCurNode;
|
|
|
|
nsCOMPtr<nsIContent> mFirst;
|
|
|
|
nsCOMPtr<nsIContent> mLast;
|
|
|
|
|
|
|
|
PRBool mIsDone;
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
// no copy's or assigns FIX ME
|
|
|
|
nsContentIterator(const nsContentIterator&);
|
|
|
|
nsContentIterator& operator=(const nsContentIterator&);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************
|
|
|
|
* repository cruft
|
|
|
|
******************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult)
|
|
|
|
{
|
|
|
|
nsContentIterator * iter = new nsContentIterator();
|
|
|
|
return iter->QueryInterface(nsIContentIterator::IID(), (void**) aInstancePtrResult);
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
/******************************************************
|
|
|
|
* XPCOM cruft
|
|
|
|
******************************************************/
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(nsContentIterator)
|
|
|
|
NS_IMPL_RELEASE(nsContentIterator)
|
|
|
|
|
|
|
|
nsresult nsContentIterator::QueryInterface(const nsIID& aIID,
|
|
|
|
void** aInstancePtrResult)
|
1998-12-14 23:16:31 +00:00
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
|
|
|
if (nsnull == aInstancePtrResult) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
1999-02-12 05:28:12 +00:00
|
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
|
|
*aInstancePtrResult = (void*)(nsISupports*)(nsIContentIterator*)this;
|
|
|
|
NS_ADDREF_THIS();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (aIID.Equals(nsIEnumerator::IID())) {
|
|
|
|
*aInstancePtrResult = (void*)(nsIEnumerator*)this;
|
|
|
|
NS_ADDREF_THIS();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (aIID.Equals(nsIContentIterator::IID())) {
|
|
|
|
*aInstancePtrResult = (void*)(nsIContentIterator*)this;
|
|
|
|
NS_ADDREF_THIS();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return !NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************
|
|
|
|
* constructor/destructor
|
|
|
|
******************************************************/
|
|
|
|
|
|
|
|
nsContentIterator::nsContentIterator() :
|
|
|
|
mCurNode(nsnull),
|
|
|
|
mFirst(nsnull),
|
|
|
|
mLast(nsnull),
|
|
|
|
mIsDone(PR_FALSE)
|
|
|
|
{
|
|
|
|
NS_INIT_REFCNT();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsContentIterator::~nsContentIterator()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************
|
|
|
|
* Init routines
|
|
|
|
******************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
nsresult nsContentIterator::Init(nsIContent* aRoot)
|
|
|
|
{
|
|
|
|
if (!aRoot) return NS_ERROR_NULL_POINTER;
|
1998-12-14 23:16:31 +00:00
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
mFirst = GetDeepFirstChild(aRoot);
|
1998-12-14 23:16:31 +00:00
|
|
|
mLast = aRoot;
|
|
|
|
mCurNode = mFirst;
|
1999-02-12 05:28:12 +00:00
|
|
|
return NS_OK;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
nsresult nsContentIterator::Init(nsIDOMRange* aRange)
|
1998-12-14 23:16:31 +00:00
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
if (!aRange) return NS_ERROR_NULL_POINTER;
|
1998-12-14 23:16:31 +00:00
|
|
|
|
|
|
|
// get the start node and offset, convert to nsIContent
|
1999-02-12 05:28:12 +00:00
|
|
|
nsCOMPtr<nsIContent> cN;
|
|
|
|
nsCOMPtr<nsIDOMNode> dN;
|
|
|
|
aRange->GetStartParent(getter_AddRefs(dN));
|
|
|
|
if (!dN) return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
cN = dN;
|
|
|
|
if (!cN) return NS_ERROR_FAILURE;
|
|
|
|
|
1998-12-14 23:16:31 +00:00
|
|
|
PRInt32 indx;
|
|
|
|
aRange->GetStartOffset(&indx);
|
|
|
|
|
|
|
|
// find first node in range
|
1999-02-12 05:28:12 +00:00
|
|
|
nsCOMPtr<nsIContent> cChild;
|
|
|
|
cN->ChildAt(0,*getter_AddRefs(cChild));
|
1998-12-14 23:16:31 +00:00
|
|
|
if (!cChild) // no children, must be a text node
|
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
mFirst = cN;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
cN->ChildAt(indx,*getter_AddRefs(cChild));
|
1998-12-14 23:16:31 +00:00
|
|
|
if (!cChild) // offset after last child, parent is first node
|
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
mFirst = cN;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
mFirst = GetDeepFirstChild(cChild);
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
aRange->GetEndParent(getter_AddRefs(dN));
|
|
|
|
if (!dN) return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
cN = dN;
|
|
|
|
if (!cN) return NS_ERROR_FAILURE;
|
|
|
|
|
1998-12-14 23:16:31 +00:00
|
|
|
aRange->GetEndOffset(&indx);
|
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
cN->ChildAt(0,*getter_AddRefs(cChild));
|
1998-12-14 23:16:31 +00:00
|
|
|
if (!cChild) // no children, must be a text node
|
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
mLast = cN;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
else if (indx == 0) // before first child, parent is last node
|
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
mLast = cN;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
cN->ChildAt(indx,*getter_AddRefs(cChild));
|
1998-12-14 23:16:31 +00:00
|
|
|
if (!cChild) // offset after last child, last child is last node
|
|
|
|
{
|
|
|
|
cN->ChildCount(indx);
|
1999-02-12 05:28:12 +00:00
|
|
|
cN->ChildAt(indx,*getter_AddRefs(cChild)); // XXX off by one???
|
1998-12-14 23:16:31 +00:00
|
|
|
if (!cChild)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("nsContentIterator::nsContentIterator");
|
1999-02-12 05:28:12 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
1999-02-12 05:28:12 +00:00
|
|
|
mLast = cChild;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
else // child just before indx is last node
|
|
|
|
{
|
|
|
|
--indx;
|
1999-02-12 05:28:12 +00:00
|
|
|
cN->ChildAt(indx,*getter_AddRefs(cChild));
|
|
|
|
mLast = cChild;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mCurNode = mFirst;
|
1999-02-12 05:28:12 +00:00
|
|
|
return NS_OK;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
/******************************************************
|
|
|
|
* Private helper routines
|
|
|
|
******************************************************/
|
|
|
|
|
|
|
|
nsIContent* nsContentIterator::GetDeepFirstChild(nsIContent* aRoot)
|
1998-12-14 23:16:31 +00:00
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
// THIS ROUTINE DOES NOT ADDREF
|
|
|
|
if (!aRoot) return nsnull;
|
|
|
|
nsIContent *cN = aRoot;
|
|
|
|
nsIContent *cChild;
|
|
|
|
cN->ChildAt(0,cChild);
|
|
|
|
while ( cChild )
|
|
|
|
{
|
|
|
|
NS_IF_RELEASE(cN); // balance addref inside ChildAt()
|
|
|
|
cN = cChild;
|
|
|
|
cN->ChildAt(0,cChild);
|
|
|
|
}
|
|
|
|
return cN;
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
/******************************************************
|
|
|
|
* ContentIterator routines
|
|
|
|
******************************************************/
|
1998-12-14 23:16:31 +00:00
|
|
|
|
|
|
|
nsresult nsContentIterator::First()
|
|
|
|
{
|
|
|
|
if (!mFirst) return NS_ERROR_FAILURE;
|
1999-01-28 23:55:53 +00:00
|
|
|
mIsDone = false;
|
1998-12-14 23:16:31 +00:00
|
|
|
if (mFirst == mCurNode) return NS_OK;
|
|
|
|
mCurNode = mFirst;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult nsContentIterator::Last()
|
|
|
|
{
|
|
|
|
if (!mLast) return NS_ERROR_FAILURE;
|
1999-01-28 23:55:53 +00:00
|
|
|
mIsDone = false;
|
1998-12-14 23:16:31 +00:00
|
|
|
if (mLast == mCurNode) return NS_OK;
|
|
|
|
mCurNode = mLast;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult nsContentIterator::Next()
|
|
|
|
{
|
1999-01-28 23:55:53 +00:00
|
|
|
if (mIsDone) return NS_ERROR_FAILURE;
|
1998-12-14 23:16:31 +00:00
|
|
|
if (!mCurNode) return NS_OK;
|
1999-01-28 23:55:53 +00:00
|
|
|
if (mCurNode == mLast)
|
|
|
|
{
|
|
|
|
mIsDone = true;
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
1998-12-14 23:16:31 +00:00
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
nsCOMPtr<nsIContent> cParent;
|
|
|
|
nsCOMPtr<nsIContent> cSibling;
|
1998-12-14 23:16:31 +00:00
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
mCurNode->GetParent(*getter_AddRefs(cParent));
|
1998-12-14 23:16:31 +00:00
|
|
|
// no parent and we are not done? something is wrong
|
1999-02-12 05:28:12 +00:00
|
|
|
if (!cParent) return NS_ERROR_UNEXPECTED;
|
|
|
|
|
1998-12-14 23:16:31 +00:00
|
|
|
// get next sibling
|
|
|
|
PRInt32 indx;
|
|
|
|
cParent->IndexOf(mCurNode,indx);
|
|
|
|
indx++;
|
1999-02-12 05:28:12 +00:00
|
|
|
cParent->ChildAt(indx,*getter_AddRefs(cSibling));
|
1998-12-14 23:16:31 +00:00
|
|
|
if (!cSibling)
|
|
|
|
{
|
|
|
|
// curent node has no next sibling, so parent is next node
|
|
|
|
mCurNode = cParent;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// else next node is siblings "deep left" child
|
1999-02-12 05:28:12 +00:00
|
|
|
mCurNode = GetDeepFirstChild(cSibling);
|
1998-12-14 23:16:31 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult nsContentIterator::Prev()
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
nsresult nsContentIterator::IsDone()
|
|
|
|
{
|
|
|
|
if (mIsDone) return NS_OK;
|
|
|
|
else return NS_COMFALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-12-14 23:16:31 +00:00
|
|
|
nsresult nsContentIterator::CurrentNode(nsIContent **aNode)
|
|
|
|
{
|
|
|
|
if (!mCurNode) return NS_ERROR_FAILURE;
|
1999-01-28 23:55:53 +00:00
|
|
|
if (mIsDone) return NS_ERROR_FAILURE;
|
1999-02-12 05:28:12 +00:00
|
|
|
return mCurNode->QueryInterface(nsIContent::IID(), (void**) aNode);
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-12 05:28:12 +00:00
|
|
|
/******************************************************
|
|
|
|
* Enumerator routines
|
|
|
|
******************************************************/
|
|
|
|
|
|
|
|
nsresult nsContentIterator::CurrentItem(nsISupports **aNode)
|
1998-12-14 23:16:31 +00:00
|
|
|
{
|
1999-02-12 05:28:12 +00:00
|
|
|
if (!mCurNode) return NS_ERROR_FAILURE;
|
|
|
|
if (mIsDone) return NS_ERROR_FAILURE;
|
|
|
|
return mCurNode->QueryInterface(kISupportsIID, (void**) aNode);
|
1998-12-14 23:16:31 +00:00
|
|
|
}
|
|
|
|
|