blob: b1707ee8e9c275f62ceb460cd33cab1e85c1e38c [file] [log] [blame]
/**
* This file is part of the DOM implementation for KDE.
*
* (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
* (C) 2001 Peter Kelly (pmk@post.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* $Id$
*/
#include "dom2_traversal.h"
#include "dom_node.h"
#include "dom_exception.h"
#include "dom2_traversalimpl.h"
#include "dom_docimpl.h"
using namespace DOM;
NodeIteratorImpl::NodeIteratorImpl(NodeImpl *_root, unsigned long _whatToShow,
NodeFilter _filter, bool _entityReferenceExpansion)
{
m_root = _root;
m_whatToShow = _whatToShow;
m_filter = _filter;
m_expandEntityReferences = _entityReferenceExpansion;
m_referenceNode = _root;
m_inFront = false;
if (_root->nodeType() == Node::DOCUMENT_NODE)
m_doc = static_cast<DocumentImpl*>(m_root);
else
m_doc = m_root->ownerDocument();
m_doc->attachNodeIterator(this);
m_doc->ref();
m_detached = false;
}
NodeIteratorImpl::~NodeIteratorImpl()
{
m_doc->detachNodeIterator(this);
m_doc->deref();
}
NodeImpl *NodeIteratorImpl::root()
{
return m_root;
}
unsigned long NodeIteratorImpl::whatToShow()
{
return m_whatToShow;
}
NodeFilter NodeIteratorImpl::filter()
{
return m_filter;
}
bool NodeIteratorImpl::expandEntityReferences()
{
return m_expandEntityReferences;
}
NodeImpl *NodeIteratorImpl::nextNode( int &exceptioncode )
{
if (m_detached) {
exceptioncode = DOMException::INVALID_STATE_ERR;
return 0;
}
if (!m_referenceNode) {
m_inFront = true;
return 0;
}
if (!m_inFront) {
m_inFront = true;
if (isAccepted(m_referenceNode) == NodeFilter::FILTER_ACCEPT)
return m_referenceNode;
}
NodeImpl *_tempCurrent = getNextNode(m_referenceNode);
while( _tempCurrent ) {
m_referenceNode = _tempCurrent;
if(isAccepted(_tempCurrent) == NodeFilter::FILTER_ACCEPT)
return m_referenceNode;
_tempCurrent = getNextNode(_tempCurrent);
}
return 0;
}
NodeImpl *NodeIteratorImpl::getNextNode(NodeImpl *n)
{
/* 1. my first child
* 2. my next sibling
* 3. my parents sibling, or their parents sibling (loop)
* 4. not found
*/
if( !n )
return 0;
if( n->hasChildNodes() )
return n->firstChild();
if( n->nextSibling() )
return n->nextSibling();
if( m_root == n)
return 0;
NodeImpl *parent = n->parentNode();
while( parent )
{
n = parent->nextSibling();
if( n )
return n;
if( m_root == parent )
return 0;
parent = parent->parentNode();
}
return 0;
}
NodeImpl *NodeIteratorImpl::previousNode( int &exceptioncode )
{
if (m_detached) {
exceptioncode = DOMException::INVALID_STATE_ERR;
return 0;
}
if (!m_referenceNode) {
m_inFront = false;
return 0;
}
if (m_inFront) {
m_inFront = false;
if (isAccepted(m_referenceNode) == NodeFilter::FILTER_ACCEPT)
return m_referenceNode;
}
NodeImpl *_tempCurrent = getPreviousNode(m_referenceNode);
while( _tempCurrent ) {
m_referenceNode = _tempCurrent;
if(isAccepted(_tempCurrent) == NodeFilter::FILTER_ACCEPT)
return m_referenceNode;
_tempCurrent = getPreviousNode(_tempCurrent);
}
return 0;
}
NodeImpl *NodeIteratorImpl::getPreviousNode(NodeImpl *n)
{
/* 1. my previous sibling.lastchild
* 2. my previous sibling
* 3. my parent
*/
NodeImpl *_tempCurrent;
if( !n )
return 0;
_tempCurrent = n->previousSibling();
if( _tempCurrent )
{
if( _tempCurrent->lastChild() )
{
while( _tempCurrent->lastChild() )
_tempCurrent = _tempCurrent->lastChild();
return _tempCurrent;
}
else
return _tempCurrent;
}
if(n == m_root)
return 0;
return n->parentNode();
}
void NodeIteratorImpl::detach(int &/*exceptioncode*/)
{
m_doc->detachNodeIterator(this);
m_detached = true;
}
void NodeIteratorImpl::notifyBeforeNodeRemoval(NodeImpl *removed)
{
// make sure the deleted node is with the root (but not the root itself)
if (removed == m_root)
return;
NodeImpl *maybeRoot = removed->parentNode();
while (maybeRoot && maybeRoot != m_root)
maybeRoot = maybeRoot->parentNode();
if (!maybeRoot)
return;
// did I get deleted, or one of my parents?
NodeImpl *_tempDeleted = m_referenceNode;
while( _tempDeleted && _tempDeleted != removed)
_tempDeleted = _tempDeleted->parentNode();
if( !_tempDeleted ) // someone that didn't consern me got deleted
return;
if( !m_inFront)
{
NodeImpl *_next = getNextNode(_tempDeleted);
if( _next )
m_referenceNode = _next;
else
{
// deleted node was at end of list
m_inFront = true;
m_referenceNode = getPreviousNode(_tempDeleted);
}
}
else {
NodeImpl *_prev = getPreviousNode(_tempDeleted);
if ( _prev )
m_referenceNode = _prev;
else
{
// deleted node was at start of list
m_inFront = false;
m_referenceNode = getNextNode(_tempDeleted);
}
}
}
short NodeIteratorImpl::isAccepted(NodeImpl *n)
{
// if XML is implemented we have to check expandEntityRerefences in this function
if( ( ( 1 << n->nodeType()-1) & m_whatToShow) != 0 )
{
if(!m_filter.isNull())
return m_filter.acceptNode(n);
else
return NodeFilter::FILTER_ACCEPT;
}
return NodeFilter::FILTER_SKIP;
}
// --------------------------------------------------------------
NodeFilterImpl::NodeFilterImpl()
{
m_customNodeFilter = 0;
}
NodeFilterImpl::~NodeFilterImpl()
{
if (m_customNodeFilter)
m_customNodeFilter->deref();
}
short NodeFilterImpl::acceptNode(const Node &n)
{
if (m_customNodeFilter)
return m_customNodeFilter->acceptNode(n);
else
return NodeFilter::FILTER_ACCEPT;
}
void NodeFilterImpl::setCustomNodeFilter(CustomNodeFilter *custom)
{
m_customNodeFilter = custom;
if (m_customNodeFilter)
m_customNodeFilter->ref();
}
CustomNodeFilter *NodeFilterImpl::customNodeFilter()
{
return m_customNodeFilter;
}
// --------------------------------------------------------------
TreeWalkerImpl::TreeWalkerImpl()
{
filter = 0;
whatToShow = 0x0000FFFF;
expandEntityReferences = true;
}
TreeWalkerImpl::TreeWalkerImpl(const TreeWalkerImpl &other) : DomShared()
{
expandEntityReferences = other.expandEntityReferences;
filter = other.filter;
whatToShow = other.whatToShow;
currentNode = other.currentNode;
rootNode = other.rootNode;
}
TreeWalkerImpl::TreeWalkerImpl(Node n, NodeFilter *f)
{
currentNode = n;
rootNode = n;
whatToShow = 0x0000FFFF;
filter = f;
}
TreeWalkerImpl::TreeWalkerImpl(Node n, long _whatToShow, NodeFilter *f)
{
currentNode = n;
rootNode = n;
whatToShow = _whatToShow;
filter = f;
}
TreeWalkerImpl &TreeWalkerImpl::operator = (const TreeWalkerImpl &other)
{
expandEntityReferences = other.expandEntityReferences;
filter = other.filter;
whatToShow = other.whatToShow;
currentNode = other.currentNode;
return *this;
}
TreeWalkerImpl::~TreeWalkerImpl()
{
if(filter)
{
delete filter;
filter = 0;
}
}
Node TreeWalkerImpl::getRoot()
{
// ###
return 0;
}
unsigned long TreeWalkerImpl::getWhatToShow()
{
// ###
return 0;
}
NodeFilter TreeWalkerImpl::getFilter()
{
// ###
return 0;
}
bool TreeWalkerImpl::getExpandEntityReferences()
{
// ###
return 0;
}
Node TreeWalkerImpl::getCurrentNode()
{
return currentNode;
}
void TreeWalkerImpl::setWhatToShow(long _whatToShow)
{
// do some testing wether this is an accepted value
whatToShow = _whatToShow;
}
void TreeWalkerImpl::setFilter(NodeFilter *_filter)
{
if(_filter)
filter = _filter;
}
void TreeWalkerImpl::setExpandEntityReferences(bool value)
{
expandEntityReferences = value;
}
void TreeWalkerImpl::setCurrentNode( const Node n )
{
if( !n.isNull() )
{
rootNode = n;
currentNode = n;
}
// else
// throw( DOMException::NOT_SUPPORTED_ERR );
}
Node TreeWalkerImpl::parentNode( )
{
Node n = getParentNode(currentNode);
if( !n.isNull() )
currentNode = n;
return n;
}
Node TreeWalkerImpl::firstChild( )
{
Node n = getFirstChild(currentNode);
if( !n.isNull() )
currentNode = n;
return n;
}
Node TreeWalkerImpl::lastChild( )
{
Node n = getLastChild(currentNode);
if( !n.isNull() )
currentNode = n;
return n;
}
Node TreeWalkerImpl::previousSibling( )
{
Node n = getPreviousSibling(currentNode);
if( !n.isNull() )
currentNode = n;
return n;
}
Node TreeWalkerImpl::nextSibling( )
{
Node n = getNextSibling(currentNode);
if( !n.isNull() )
currentNode = n;
return n;
}
Node TreeWalkerImpl::previousNode( )
{
/* 1. my previous sibling.lastchild
* 2. my previous sibling
* 3. my parent
*/
Node n = getPreviousSibling(currentNode);
if( n.isNull() )
{
n = getParentNode(currentNode);
if( !n.isNull() ) //parent
{
currentNode = n;
return currentNode;
}
else // parent failed.. no previous node
return Node();
}
Node child = getLastChild(n);
if( !child.isNull() ) // previous siblings last child
{
currentNode = child;
return currentNode;
}
else // previous sibling
{
currentNode = n;
return currentNode;
}
return Node(); // should never get here!
}
Node TreeWalkerImpl::nextNode( )
{
/* 1. my first child
* 2. my next sibling
* 3. my parents sibling, or their parents sibling (loop)
* 4. not found
*/
Node n = getFirstChild(currentNode);
if( !n.isNull() ) // my first child
{
currentNode = n;
return n;
}
n = getNextSibling(currentNode); // my next sibling
if( !n.isNull() )
{
currentNode = n;
return currentNode;
}
Node parent = getParentNode(currentNode);
while( !parent.isNull() ) // parents sibling
{
n = getNextSibling(parent);
if( !n.isNull() )
{
currentNode = n;
return currentNode;
}
else
parent = getParentNode(parent);
}
return Node();
}
short TreeWalkerImpl::isAccepted(Node n)
{
// if XML is implemented we have to check expandEntityRerefences in this function
if( ( ( 1 << n.nodeType()-1 ) & whatToShow) != 0 )
{
if(filter)
return filter->acceptNode(n);
else
return NodeFilter::FILTER_ACCEPT;
}
return NodeFilter::FILTER_SKIP;
}
Node TreeWalkerImpl::getParentNode(Node n)
{
short _result = NodeFilter::FILTER_ACCEPT;
if( n == rootNode /*|| n.isNull()*/ )
return Node();
Node _tempCurrent = n.parentNode();
if( _tempCurrent.isNull() )
return Node();
_result = isAccepted(_tempCurrent );
if(_result == NodeFilter::FILTER_ACCEPT)
return _tempCurrent; // match found
return getParentNode(_tempCurrent);
}
Node TreeWalkerImpl::getFirstChild(Node n)
{
short _result;
if( n.isNull() || n.firstChild().isNull() )
return Node();
n = n.firstChild();
_result = isAccepted(n);
switch(_result)
{
case NodeFilter::FILTER_ACCEPT:
return n;
break;
case NodeFilter::FILTER_SKIP:
if( n.hasChildNodes() )
return getFirstChild(n);
else
return getNextSibling(n);
break;
case NodeFilter::FILTER_REJECT:
return getNextSibling(n);
break;
}
return Node(); // should never get here!
}
Node TreeWalkerImpl::getLastChild(Node n)
{
short _result;
if( n.isNull() || n.lastChild().isNull() )
return Node();
n = n.lastChild();
_result = isAccepted(n);
switch(_result)
{
case NodeFilter::FILTER_ACCEPT:
return n;
break;
case NodeFilter::FILTER_SKIP:
if( n.hasChildNodes() )
return getLastChild(n);
else
return getPreviousSibling(n);
break;
case NodeFilter::FILTER_REJECT:
return getPreviousSibling(n);
break;
}
return Node();
}
Node TreeWalkerImpl::getPreviousSibling(Node n)
{
short _result;
Node _tempCurrent;
if( n.isNull() )
return Node();
//first the cases if we have a previousSibling
_tempCurrent = n.previousSibling();
if( !_tempCurrent.isNull() )
{
_result = isAccepted(_tempCurrent);
switch(_result)
{
case NodeFilter::FILTER_ACCEPT:
return _tempCurrent;
break;
case NodeFilter::FILTER_SKIP:
{
Node nskip = getLastChild(_tempCurrent);
if( !nskip.isNull() )
return nskip;
return getPreviousSibling(_tempCurrent);
break;
}
case NodeFilter::FILTER_REJECT:
return getPreviousSibling(_tempCurrent);
break;
}
}
// now the case if we don't have previous sibling
else
{
_tempCurrent = _tempCurrent.parentNode();
if(_tempCurrent.isNull() || _tempCurrent == rootNode)
return Node();
_result = isAccepted(_tempCurrent);
if(_result == NodeFilter::FILTER_SKIP)
return getPreviousSibling(_tempCurrent);
return Node();
}
return Node(); // should never get here!
}
Node TreeWalkerImpl::getNextSibling(Node n)
{
Node _tempCurrent;
short _result;
if( n.isNull() || _tempCurrent == rootNode)
return Node();
_tempCurrent = n.nextSibling();
if( !_tempCurrent.isNull() )
{
_result = isAccepted(_tempCurrent);
switch(_result)
{
case NodeFilter::FILTER_ACCEPT:
return _tempCurrent;
break;
case NodeFilter::FILTER_SKIP:
{
Node nskip = getFirstChild(_tempCurrent);
if( !nskip.isNull() )
return nskip;
return getNextSibling(_tempCurrent);
break;
}
case NodeFilter::FILTER_REJECT:
return getNextSibling(_tempCurrent);
break;
}
}
else
{
_tempCurrent = _tempCurrent.parentNode();
if(_tempCurrent.isNull() || _tempCurrent == rootNode)
return Node();
_result = isAccepted(_tempCurrent);
if(_result == NodeFilter::FILTER_SKIP)
return getNextSibling(_tempCurrent);
return Node();
}
return Node();
}