rangeimpl.cpp

来自「IBM的解析xml的工具Xerces的源代码」· C++ 代码 · 共 1,660 行 · 第 1/4 页

CPP
1,660
字号
                    clonedParent.getFirstChild()                );            }            isFullySelected = true;            next = prevSibling;        }        if ( parent==root )            return clonedParent;        next = parent.getPreviousSibling();        parent = parent.getParentNode();        DOM_Node clonedGrandParent = traverseNode( parent, false, false, how );        if ( how!=DELETE_CONTENTS )            clonedGrandParent.appendChild( clonedParent );        clonedParent = clonedGrandParent;    }    // should never occur    return null;}/** * Traverses the "left boundary" of this range and * operates on each "boundary node" according to the * how parameter.  It is a-priori assumed * by this method that the left boundary does * not contain the range's end container. * * A "left boundary" is best visualized by thinking * of a sample tree: * *                 A *                /|\ *               / | \ *              /  |  \ *             B   C   D *            /|\     /|\ *           E F G   H I J * * Imagine first a range that begins between the * "E" and "F" nodes and ends between the * "I" and "J" nodes.  The start container is * "B" and the end container is "D".  Given this setup, * the following applies: * * Partially Selected Nodes: B, D<br> * Fully Selected Nodes: F, G, C, H, I * * The "left boundary" is the highest subtree node * that contains the starting container.  The root of * this subtree is always partially selected. * * In this example, the nodes that are traversed * as "left boundary" nodes are: F, G, and B. * */DOM_Node RangeImpl::traverseLeftBoundary( DOM_Node root, int how ){    DOM_Node next = getSelectedNode( getStartContainer(), getStartOffset() );    bool isFullySelected = ( next!=getStartContainer() );    if ( next==root )        return traverseNode( next, isFullySelected, true, how );    DOM_Node parent = next.getParentNode();    DOM_Node clonedParent = traverseNode( parent, false, true, how );    while( parent!=null )    {        while( next!=null )        {            DOM_Node nextSibling = next.getNextSibling();            DOM_Node clonedChild =                traverseNode( next, isFullySelected, true, how );            if ( how!=DELETE_CONTENTS )                clonedParent.appendChild(clonedChild);            isFullySelected = true;            next = nextSibling;        }        if ( parent==root )            return clonedParent;        next = parent.getNextSibling();        parent = parent.getParentNode();        DOM_Node clonedGrandParent = traverseNode( parent, false, true, how );        if ( how!=DELETE_CONTENTS )            clonedGrandParent.appendChild( clonedParent );        clonedParent = clonedGrandParent;    }    // should never occur    return null;}/** * Utility method for traversing a single node. * Does not properly handle a text node containing both the * start and end offsets.  Such nodes should * have been previously detected and been routed to traverseTextNode. * */DOM_Node RangeImpl::traverseNode( DOM_Node n, bool isFullySelected, bool isLeft, int how ){    if ( isFullySelected )        return traverseFullySelected( n, how );    if ( n.getNodeType()== DOM_Node::TEXT_NODE )        return traverseTextNode( n, isLeft, how );    return traversePartiallySelected( n, how );}/** * Utility method for traversing a single node when * we know a-priori that the node if fully * selected. * */DOM_Node RangeImpl::traverseFullySelected( DOM_Node n, int how ){    switch( how )    {    case CLONE_CONTENTS:        return n.cloneNode( true );    case EXTRACT_CONTENTS:        if ( n.getNodeType()== DOM_Node::DOCUMENT_TYPE_NODE )        {            throw DOM_DOMException(                DOM_DOMException::HIERARCHY_REQUEST_ERR, null);        }        return n;    case DELETE_CONTENTS:        n.getParentNode().removeChild(n);        return null;    }    return null;}/** * Utility method for traversing a single node when * we know a-priori that the node if partially * selected and is not a text node. * */DOM_Node RangeImpl::traversePartiallySelected( DOM_Node n, int how ){    switch( how )    {    case DELETE_CONTENTS:        return null;    case CLONE_CONTENTS:    case EXTRACT_CONTENTS:        return n.cloneNode( false );    }    return null;}/** * Utility method for traversing a text node that we know * a-priori to be on a left or right boundary of the range. * This method does not properly handle text nodes that contain * both the start and end points of the range. * */DOM_Node RangeImpl::traverseTextNode( DOM_Node n, bool isLeft, int how ){    DOMString txtValue = n.getNodeValue();    DOMString newNodeValue;    DOMString oldNodeValue;    if ( isLeft )    {        int offset = getStartOffset();        newNodeValue = txtValue.substringData( offset , fStartContainer.getNodeValue().length()-offset);        oldNodeValue = txtValue.substringData( 0, offset );    }    else    {        int offset = getEndOffset();        newNodeValue = txtValue.substringData( 0, offset );        oldNodeValue = txtValue.substringData( offset , fEndContainer.getNodeValue().length()-offset );    }    if ( how != CLONE_CONTENTS )        n.setNodeValue( oldNodeValue );    if ( how==DELETE_CONTENTS )        return null;    DOM_Node newNode = n.cloneNode( false );    newNode.setNodeValue( newNodeValue );    return newNode;}/** * Utility method to retrieve a child node by index.  This method * assumes the caller is trying to find out which node is * selected by the given index.  Note that if the index is * greater than the number of children, this implies that the * first node selected is the parent node itself. * */DOM_Node RangeImpl::getSelectedNode( DOM_Node container, int offset ){    if ( container.getNodeType() == DOM_Node::TEXT_NODE )        return container;    // This case is an important convenience for    // traverseRightBoundary()    if ( offset<0 )        return container;    DOM_Node child = container.getFirstChild();    while( child!=null && offset > 0 )    {        --offset;        child = child.getNextSibling();    }    if ( child!=null )        return child;    return container;}void RangeImpl::checkReadOnly(DOM_Node& start, DOM_Node& end,                              unsigned int startOffset, unsigned int endOffset){    if ((start == null) || (end == null) ) return;    //if both start and end are text check and return    if (start.getNodeType() == DOM_Node::TEXT_NODE) {        if (start.fImpl->isReadOnly()) {            throw DOM_DOMException(                DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);        }        if (start == end)            return;    }    //set the start and end nodes to check    DOM_Node sNode = start.getFirstChild();    for(unsigned int i = 0; i<startOffset; i++)        sNode = sNode.getNextSibling();    DOM_Node eNode;    if (end.getNodeType() == DOM_Node::TEXT_NODE) {        eNode = end; //need to check only till this node    }    else { //need to check all the kids that fall before the end offset value        eNode = end.getFirstChild();        for (unsigned int i = 0; i<endOffset-1; i++)            eNode = eNode.getNextSibling();    }    //recursivly search if any node is readonly    recurseTreeAndCheck(sNode, eNode);}void RangeImpl::recurseTreeAndCheck(DOM_Node& start, DOM_Node& end){    for(DOM_Node node=start; node != null && node !=end; node=node.getNextSibling())    {        if (node.fImpl->isReadOnly()) {            throw DOM_DOMException(                DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);        }        if (node.hasChildNodes()) {            node = node.getFirstChild();            recurseTreeAndCheck(node, end);        }    }}DOM_Node RangeImpl::removeChild(DOM_Node& parent, DOM_Node& child){    fRemoveChild = child; //only a precaution measure not to update this range data before removal    DOM_Node n = parent.removeChild(child);    fRemoveChild = null;    return n;}//// Mutation functions///* This function is called from DOM.*  The  text has already beeen replaced.*  Fix-up any offsets.*/void RangeImpl::receiveReplacedText(NodeImpl* node){    if (node == null) return;    DOM_Node anode(node);    if (anode == fStartContainer        && fStartContainer.getNodeType() == DOM_Node::TEXT_NODE) {        fStartOffset = 0;    }    if (anode == fEndContainer        && fEndContainer.getNodeType() == DOM_Node::TEXT_NODE) {        fEndOffset = 0;    }}/** This function is called from DOM.*  The  text has already beeen inserted.*  Fix-up any offsets.*/void RangeImpl::updateRangeForDeletedText(DOM_Node& node, unsigned int offset, int count){    if (node == null) return;    if (node == fStartContainer        && fStartContainer.getNodeType() == DOM_Node::TEXT_NODE) {        if (fStartOffset > offset+count) {            fStartOffset = fStartOffset-count;        } else if (fStartOffset > offset) {            fStartOffset = offset;        }    }    if (node == fEndContainer        && fEndContainer.getNodeType() == DOM_Node::TEXT_NODE) {        if (fEndOffset > offset+count) {            fEndOffset = fEndOffset-count;        } else if (fEndOffset > offset) {            fEndOffset = offset;        }    }}/** This function must be called by the DOM _BEFORE_*  a node is deleted, because at that time it is*  connected in the DOM tree, which we depend on.*/void RangeImpl::updateRangeForDeletedNode(NodeImpl* node){    if (node == null) return;    if (fRemoveChild == node) return;    DOM_Node tNode(node);    if (node->getParentNode() == fStartContainer.fImpl) {        unsigned short index = indexOf(tNode, fStartContainer);        if ( fStartOffset > index) {            fStartOffset--;        }    }    if (node->getParentNode() == fEndContainer.fImpl) {        unsigned short index = indexOf(tNode, fEndContainer);        if ( fEndOffset > index) {            fEndOffset--;        }    }    if (node->getParentNode() != fStartContainer.fImpl        ||  node->getParentNode() != fEndContainer.fImpl) {        if (isAncestorOf(node, fStartContainer)) {            DOM_Node tpNode(node->getParentNode());            setStartContainer( tpNode );            fStartOffset = indexOf( tNode, tpNode);        }        if (isAncestorOf(node, fEndContainer)) {            DOM_Node tpNode(node->getParentNode());            setEndContainer( tpNode );            fEndOffset = indexOf( tNode, tpNode);        }    }}void RangeImpl::updateRangeForInsertedNode(NodeImpl* node) {    if (node == null) return;    if (node->getParentNode() == fStartContainer.fImpl) {        unsigned int index = indexOf(DOM_Node(node), fStartContainer);        if (index < fStartOffset) {            fStartOffset++;        }    }    if (node->getParentNode() == fEndContainer.fImpl) {        unsigned int index = indexOf(DOM_Node(node), fEndContainer);        if (index < fEndOffset) {            fEndOffset++;        }    }}void RangeImpl::updateSplitInfo(TextImpl* oldNode, TextImpl* startNode, unsigned int offset){    if (startNode == null) return;    DOM_Text oldText(oldNode);    DOM_Text newText(startNode);    if (fStartContainer == oldText && fStartOffset > offset) {          fStartOffset = fStartOffset - offset;        fStartContainer = newText;    }    if (fEndContainer == oldText && fEndOffset > offset) {            fEndContainer = newText;       fEndOffset = fEndOffset - offset;    }}XERCES_CPP_NAMESPACE_END

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?