diff options
Diffstat (limited to 'khtml/xml/dom2_traversalimpl.cpp')
-rw-r--r-- | khtml/xml/dom2_traversalimpl.cpp | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/khtml/xml/dom2_traversalimpl.cpp b/khtml/xml/dom2_traversalimpl.cpp new file mode 100644 index 000000000..2abdadead --- /dev/null +++ b/khtml/xml/dom2_traversalimpl.cpp @@ -0,0 +1,667 @@ +/** + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "dom/dom_exception.h" +#include "xml/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; + + m_doc = m_root->getDocument(); + 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( m_root == n) + return 0; + + if( n->nextSibling() ) + return n->nextSibling(); + + NodeImpl *parent = n->parentNode(); + while( parent ) + { + if( m_root == parent ) + return 0; + + n = parent->nextSibling(); + if( n ) + return n; + + 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 || m_root == n ) + return 0; + + _tempCurrent = n->previousSibling(); + if( _tempCurrent ) + { + if( _tempCurrent->lastChild() ) + { + while( _tempCurrent->lastChild() ) + _tempCurrent = _tempCurrent->lastChild(); + return _tempCurrent; + } + else + return _tempCurrent; + } + + 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(NodeImpl *n, long _whatToShow, NodeFilterImpl *f, + bool entityReferenceExpansion) +{ + m_currentNode = n; + m_rootNode = n; + m_whatToShow = _whatToShow; + m_filter = f; + if ( m_filter ) + m_filter->ref(); + m_expandEntityReferences = entityReferenceExpansion; + m_doc = m_rootNode->getDocument(); + m_doc->ref(); +} + +TreeWalkerImpl::~TreeWalkerImpl() +{ + m_doc->deref(); + if ( m_filter ) + m_filter->deref(); +} + +NodeImpl *TreeWalkerImpl::getRoot() const +{ + return m_rootNode; +} + +unsigned long TreeWalkerImpl::getWhatToShow() const +{ + return m_whatToShow; +} + +NodeFilterImpl *TreeWalkerImpl::getFilter() const +{ + return m_filter; +} + +bool TreeWalkerImpl::getExpandEntityReferences() const +{ + return m_expandEntityReferences; +} + +NodeImpl *TreeWalkerImpl::getCurrentNode() const +{ + return m_currentNode; +} + +void TreeWalkerImpl::setWhatToShow(long _whatToShow) +{ + // do some testing wether this is an accepted value + m_whatToShow = _whatToShow; +} + +void TreeWalkerImpl::setFilter(NodeFilterImpl *_filter) +{ + m_filter->deref(); + m_filter = _filter; + if ( m_filter ) + m_filter->ref(); +} + +void TreeWalkerImpl::setExpandEntityReferences(bool value) +{ + m_expandEntityReferences = value; +} + +void TreeWalkerImpl::setCurrentNode( NodeImpl *n ) +{ + if ( n ) + { + //m_rootNode = n; + m_currentNode = n; + } +// else +// throw( DOMException::NOT_SUPPORTED_ERR ); +} + +NodeImpl *TreeWalkerImpl::parentNode( ) +{ + NodeImpl *n = getParentNode( m_currentNode ); + if ( n ) + m_currentNode = n; + return n; +} + + +NodeImpl *TreeWalkerImpl::firstChild( ) +{ + NodeImpl *n = getFirstChild( m_currentNode ); + if ( n ) + m_currentNode = n; + return n; +} + + +NodeImpl *TreeWalkerImpl::lastChild( ) +{ + NodeImpl *n = getLastChild(m_currentNode); + if( n ) + m_currentNode = n; + return n; +} + +NodeImpl *TreeWalkerImpl::previousSibling( ) +{ + NodeImpl *n = getPreviousSibling( m_currentNode ); + if( n ) + m_currentNode = n; + return n; +} + +NodeImpl *TreeWalkerImpl::nextSibling( ) +{ + NodeImpl *n = getNextSibling( m_currentNode ); + if( n ) + m_currentNode = n; + return n; +} + +NodeImpl *TreeWalkerImpl::previousNode( ) +{ +/* 1. my previous sibling.lastchild + * 2. my previous sibling + * 3. my parent + */ + + NodeImpl *n = getPreviousSibling( m_currentNode ); + if( !n ) + { + n = getParentNode( m_currentNode ); + if( n ) //parent + { + m_currentNode = n; + return m_currentNode; + } + else // parent failed.. no previous node + return 0; + } + + NodeImpl *child = getLastChild( n ); + if( child ) // previous siblings last child + { + m_currentNode = child; + return m_currentNode; + } + else // previous sibling + { + m_currentNode = n; + return m_currentNode; + } + return 0; // should never get here! +} + +NodeImpl *TreeWalkerImpl::nextNode( ) +{ +/* 1. my first child + * 2. my next sibling + * 3. my parents sibling, or their parents sibling (loop) + * 4. not found + */ + + NodeImpl *n = getFirstChild( m_currentNode ); + if( n ) // my first child + { + m_currentNode = n; + return n; + } + + n = getNextSibling( m_currentNode ); // my next sibling + if( n ) + { + m_currentNode = n; + return m_currentNode; + } + NodeImpl *parent = getParentNode( m_currentNode ); + while( parent ) // parents sibling + { + n = getNextSibling( parent ); + if( n ) + { + m_currentNode = n; + return m_currentNode; + } + else + parent = getParentNode( parent ); + } + return 0; +} + +short TreeWalkerImpl::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) + return m_filter->acceptNode(n); + else + return NodeFilter::FILTER_ACCEPT; + } + return NodeFilter::FILTER_SKIP; +} + +NodeImpl *TreeWalkerImpl::getParentNode(NodeImpl *n) +{ + short _result = NodeFilter::FILTER_ACCEPT; + + if( n == m_rootNode /*|| !n*/ ) + return 0; + + NodeImpl *_tempCurrent = n->parentNode(); + + if( !_tempCurrent ) + return 0; + + _result = isAccepted( _tempCurrent ); + if ( _result == NodeFilter::FILTER_ACCEPT ) + return _tempCurrent; // match found + + return getParentNode( _tempCurrent ); +} + +NodeImpl *TreeWalkerImpl::getFirstChild(NodeImpl *n) +{ + short _result; + + if( !n || !n->firstChild() ) + return 0; + 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 0; // should never get here! +} + +NodeImpl *TreeWalkerImpl::getLastChild(NodeImpl *n) +{ + short _result; + + if( !n || !n->lastChild() ) + return 0; + 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 0; +} + +NodeImpl *TreeWalkerImpl::getPreviousSibling(NodeImpl *n) +{ + short _result; + NodeImpl *_tempCurrent; + + if( !n ) + return 0; + //first the cases if we have a previousSibling + _tempCurrent = n->previousSibling(); + if( _tempCurrent ) + { + _result = isAccepted( _tempCurrent ); + switch ( _result ) + { + case NodeFilter::FILTER_ACCEPT: + return _tempCurrent; + break; + + case NodeFilter::FILTER_SKIP: + { + NodeImpl *nskip = getLastChild( _tempCurrent ); + if( nskip ) + 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 = n->parentNode(); + if( !_tempCurrent || _tempCurrent == m_rootNode) + return 0; + _result = isAccepted( _tempCurrent ); + if ( _result == NodeFilter::FILTER_SKIP ) + return getPreviousSibling( _tempCurrent ); + + return 0; + + } + return 0; // should never get here! +} + +NodeImpl *TreeWalkerImpl::getNextSibling(NodeImpl *n) +{ + NodeImpl *_tempCurrent = 0; + short _result; + + if( !n ) + return 0; + + _tempCurrent = n->nextSibling(); + if( _tempCurrent ) + { + _result = isAccepted( _tempCurrent ); + switch ( _result ) + { + case NodeFilter::FILTER_ACCEPT: + return _tempCurrent; + break; + + case NodeFilter::FILTER_SKIP: + { + NodeImpl *nskip = getFirstChild( _tempCurrent ); + if( nskip ) + return nskip; + return getNextSibling( _tempCurrent ); + break; + } + + case NodeFilter::FILTER_REJECT: + return getNextSibling( _tempCurrent ); + break; + } + } + else + { + _tempCurrent = n->parentNode(); + if( !_tempCurrent || _tempCurrent == m_rootNode) + return 0; + _result = isAccepted( _tempCurrent ); + if( _result == NodeFilter::FILTER_SKIP ) + return getNextSibling( _tempCurrent ); + + return 0; + } + return 0; +} + |