/*************************************************************************** kafkacommon.h ------------------- copyright : (C) 2003, 2004 - Nicolas Deschildre email : ndeschildre@kdewebdev.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KAFKACOMMON_H #define KAFKACOMMON_H #include #include namespace DOM { class Document; } class Node; class NodeModifsSet; class NodeSelection; class NodeSelectionInd; class Document; struct DTDStruct; /** * For heavy debug including Node Tree in stdout printing, a DOM::Node tree widget. */ //#define HEAVY_DEBUG /** * Light debugging, including functions name in stdout printing. */ //#define LIGHT_DEBUG /** This class gathers all the basic functions needed by kafka. * It's very useful for manipulating nodes. */ class kafkaCommon { public: kafkaCommon() {} ~kafkaCommon() {} /** ----------------------- NODE & DOM::NODE TREE NAVIGATION -------------------------------------*/ /** * This function returns the next Node after node : the first child of * node if available, else its next sibling if available, else the next * available next sibling of a parent of node. * @param _node It is the Node from which we want the next Node. * @param goUp This boolean specifies if we should go up (torwards the root Node) * i.e. not looking at the childs of node, or make a standart iteration. * For a normal use, It must be set to false at the * beginning and then the same boolean must be used when using * several times this function. * @param endNode Specifies at which Node the search should end. * @return Returns the next Node. */ static Node* getNextNode(Node *node, bool &goUp, Node *endNode = 0L); /** * It behaves essentially like the above function except that it will skip empty Nodes. */ static Node* getNextNodeNE(Node *node, bool &goUp, Node *endNode = 0L); /** * This function returns the prev Node after node. */ static Node* getPrevNode(Node *node, Node *endNode = 0L); /** * It behaves essentially like the above function except that it will skip empty Nodes. */ static Node* getPrevNodeNE(Node *node, Node *endNode = 0L); /** * Returns the first common parent to startNode and endNode that isn't inline. * @param startNode Start node. * @param endNode End node. * @param commonParentStartChildLocation Is the child of commonParent which is parent of startNode * @param commonParentEndChildLocation Is the child of commonParent which is parent of endNode * @param nodeSubtree When startNode and endNode doesn't belong to the current document tree. Pass 0 if they do. * @return The first, non inline, common parent of startNode and endNode. */ static Node* DTDGetNonInlineCommonParent(Node* startNode, Node* endNode, TQValueList& commonParentStartChildLocation, TQValueList& commonParentEndChildLocation, Node* nodeSubtree); /** * Same as above, only that the common parent can be inline. */ static Node* DTDGetCommonParent(Node* startNode, Node* endNode, TQValueList& commonParentStartChildLocation, TQValueList& commonParentEndChildLocation, Node* nodeSubtree); /** * This function returns the next DOM::Node after node : the first child of * DOM::Node if available, else its next sibling if available, else the next * available next sibling of a parent of node. * @param node The DOM::Node the search starts from. * @param goUp This boolean specifies if we should go up or down in the tree. * For a normal use, It must be set to false at the * beginning and then the same boolean must be used when using * several times this function. * @param returnParentNode Specifies if there are no child and next sibling, if * we should return the parent. * @param endNode Specifies at which DOM::Node the search should end. It is useful * when setting returnParentNode to false. * @return the next Node. */ static DOM::Node getNextDomNode(DOM::Node node, bool &goUp, bool returnParentNode = false, DOM::Node endNode = DOM::Node()); /** * This function returns the previous Node after node. * @return Returns the previous DOM::Node of node. */ static DOM::Node getPrevDomNode(DOM::Node node, DOM::Node endNode = DOM::Node()); /** * If node is not a text node or the cursor is at the end of node's tag string, this method return the next * text node at offset 0, or a null pointer. * This is particular useful when finding start and end nodes of a selection, because you can have a closing node * as the start node, etc. * @param startNode The current start node. startNode isn't changed inside the method. * @param startOffset The current start offset. startOffset is changed inside the method. * @return The next text node or a null pointer. */ static Node* getCorrectStartNode(Node* startNode, int& startOffset); /** * If node is not a text node or the cursor is at the beggining of node's tag string, this method return the previous * text node at offset at the end of the tag string, or a null pointer. * This is particular useful when finding start and end nodes of a selection, because you can have a closing node * as the start node, etc. * @param endNode The current start node. * @param endOffset The current start offset. * @return The next text node or a null pointer. */ static Node* getCorrectEndNode(Node* endNode, int& endOffset); /** * Get the first child of commonParent which is parent of node * @param node * @param commonParent * @return */ static Node* getCommonParentChild(Node* node, Node* commonParent); /** ----------------------- NODE INDENTATION STUFF -------------------------------------*/ /** * This function takes care to modify the current node or/and the next sibling in order to have a nice * indentation. WARNING it doesn't create the necessary Nodes. Call fitIndentationNodes first. * @param node Apply nice indentation to this Node. * @param nbOfSpaces Specifies the number of spaces the minimal indentation must be. * @param nbOfTabs Specifies the number of tabs the minimal indentation must be. * @param modifs The changes made are logged into modifs. * @param inlineNodeIndentation * If true: * Text * else: * * Text * */ static void applyIndentation(Node *node, int nbOfSpaces, int nbOfTabs, NodeModifsSet *modifs, bool inlineNodeIndentation = false); /** * Create/Delete the necessary Empty Nodes between n1 and n2 so that a nice indentation can be * generated by the undoRedo system. The undoRedo system can't create itself these Nodes * because it will create them only during the synchronization, making all the TQValueList * Nodes location wrong. * WARNING n1 and n2 must be siblings or parent-child. If there are sibling and n1 is a XmlTag, * n1 should not have non empty childs. * @param n1 The start node. * @param n2 The end node. * @param modifs The changes made are logged into modifs. */ static void fitIndentationNodes(Node *n1, Node *n2, NodeModifsSet *modifs); /** * Fits the Nodes positions after a change in the Node tree. * @param startNode The Node where the update of the Node positions starts. * @param colMovement The number of columns that should be * added/retrieved from the column position. It is the difference of the new last char col position and the * old last char col position. * @param lineMovement The number of lines that should be * added/retrieved from the line position. It is the difference of the number of lines of the new tag string * and the number of lines of the old tag string. * @param colEnd The column position where the update should stop. * @param lineEnd The line position where the update should stop. */ static void fitsNodesPosition(Node* startNode, int colMovement, int lineMovement = 0, int colEnd = -2, int lineEnd = -2); /** * Get the display type of a Node. NOT an official list, more a little hack to * handle the indentation. Text are inline. The rest return an error. * @param closingNodeToo Specifies if we consider that closing Node have the same type as * their opening tag. * @return Returns the type. */ static int getNodeDisplay(Node *node, bool closingNodeToo); //the enumeration of the different display types enum nodeDisplay { noneDisplay = 0, inlineDisplay, blockDisplay, errorDisplay }; /** * Remove the indentation whitespaces in a string * e.g. this function returns : " a b cd " for parameter: " a b cd " * @param string The text to modify. * @param removeAllSpacesAtTheLeft Specifies if it should remove ALL spaces in the left * unlike the above example. * @param removeAllSpacesAtTheRight Specifies if it should remove ALL spaces in the right * unlike the above example. * @return Returns the modified string. */ static TQString removeUnnecessaryWhitespaces(const TQString &string, bool removeAllSpacesAtTheLeft = false, bool removeAllSpacesAtTheRight = false); /** ----------------------- NODE TREE MODIFICATIONS -------------------------------------*/ /** * Create a simple Node, without taking care of building the closing Node. * @param nodeName The name of the Node. * @param tagString The String of the tag as it will appears in the editor. * @param nodeType The node type, cf Tag::TokenType * @param doc The document the Node will belong to. * @return Returns the newly created node. */ static Node* createNode(const TQString &nodeName, const TQString &tagString, int nodeType, Document *doc); /** * Restore a Node that has been pasted, i.e., his doc and dtd pointers. * @param node The Node to be restored. * @param doc The document the Node will belong to. */ static void restorePastedNode(Node* node, Document* doc); /** * Create a !doctype Node with all the necessary attributes. It has a child and a closing Node. * @param doc It needs the document where the !doctype node will be inserted in order to * build the right attributes. */ static Node *createDoctypeNode(Document *doc); /** * Create a Node. It has a child and a closing Node. * @param doc It needs the document where the xml node will be inserted. * @param encoding The encoding to use (usually get it with quantaApp->defaultEncoding()) */ static Node *createXmlDeclarationNode(Document *doc, const TQString &encoding); /** * Create a node subtree which contains the mandatory Nodes in order to be DTD compliant. * e.g. TABLE alone isn't DTD compliant, this function will return TABLE->TR->TD. * WARNING : it won't log change thus node must NOT be in the Node tree. * @param node The root Node of the Node subtree. * @param doc The document the Node subtree will belong to. * @return Returns the last Node of the subtree or node if there was nothing to add. */ static Node* createMandatoryNodeSubtree(Node *node, Document *doc); /** * Insert node in the tree. WARNING This function will log that node was added. * WARNING : baseNode is used as the rootNode. * It will also try to merge text/Empty Nodes. * @param node The node to insert. * @param parentNode This Node will be the parent of node. * @param nextSibling This Node will be the next Sibling of Node. If null, node will be appended at * the child list of parentNode. * TODO: @param rootNode The rootNode of the tree we want to insert the Node (usually &baseNode). * @param modifs The changes made are logged into modifs. Put 0L if you don't want to log * and if you know what you're doing! * @param merge Try to merge with the siblings if possible. * @return Returns a pointer to the node inserted. */ static Node* insertNode(Node *node, Node* parentNode, Node* nextSibling, NodeModifsSet *modifs/**, Node **rootNode*/, bool merge = true); static Node* insertNode(Node *node, Node* parentNode, Node* nextSibling, NodeSelection& selection, NodeModifsSet *modifs, bool merge = true); /** * It behaves essentially like the above function except that it can "surround" a set of Nodes with the * new Node. Thus, the closing Node is created if necessary. * nextSibling and nextEndSibling MUST have the same parent. If not, use the * DTDinsertNode. * This function does not try to know if the location of the new Node is DTD valid. * @param newNode The new Node to insert. * @param parent The parent of the Node. * @param nextSibling The next sibling of the Node. * @param nextEndSibling The next sibling of the closing Node if created. If nextEndSibling == * nextSibling, the closing Node will be placed at the right of the newly created Node. * All the Nodes between the new Node and its closing Tag will be moved as childs of the new Node. * @param modifs The changes made are logged into modifs. * @return Returns a pointer to the node inserted. */ static Node *insertNode(Node *newNode, Node *parent, Node *nextSibling, Node *nextEndSibling, NodeModifsSet *modifs, bool merge = true); /** * It behaves essentially like the above function except that it can split the endNodeToSurround and * startNodeToSurround if necessary, according to the offsets. * startNodeToSurround et endNodeToSurround MUST have the same parent. If not, use the last * DTDinsertNode. * This function does not try to know if the location of the new Node is valid. * @param startNodeToSurround The first Node which will be enclosed by the new Node. * @param endNodeToSurround The last Node which will be enclosed by the new Node. * @param startOffset The first Node will be splitted at offset startOffset, the right part will be enclosed. * @param endOffset The last Node will be splitted at offset endOffset, the left part will be enclosed. */ static Node* insertNode(Node *newNode, Node *parent, Node *startNodeToSurround, Node *endNodeToSurround, int startOffset, int endOffset, NodeModifsSet *modifs); /** * It behaves essentially like the above function except that it will insert the new Node only * if the DTD allows it. The new Tag can surround any subtree. If * necessary, several copies of the Node will be used. * This function takes care of the DTD validity of the Nodes created. * It will build the necessary mandatory Nodes (e.g. insertion of TABLE will also insert TR and TD). * This is the key function making the toolbars working. * @param startNode The first Node which must be surrounded by the new Node. * @param startOffset If firstNode is a text, specify at which offset the new Node must begin to surround. * @param endNode The last Node which must be surrounded by the new Node. * @param endOffset If endNode is a text, specify at which offset the new Node must stop to surround. * @param doc The document is needed in order to build the mandatory Node tree if necessary. * : We want to keep track of the cursor position. TODO : cursor class * @param cursorNode The cursor is inside cursorNode. * @param cursorOffset The offset of the cursor inside cursorNode. * * @return Returns false if it wasn't possible to insert the tag because e.g. of an invalid parent. */ static bool DTDinsertNode(Node *newNode, Node *startNode, int startOffset, Node *endNode, int endOffset, Document *doc, Node **cursorNode, long &cursorOffset, NodeModifsSet *modifs); /** * It behaves essentially like the above function except that it will try first to remove newNode * from the area, by calling DTDExtractNode. If newNode wasn't present, it will then insert it by * calling DTDinsertNode. * This is the key function making the toolbars working. * @return Returns true if a modification was done (Node inserted/removed) */ static bool DTDinsertRemoveNode(Node *newNode, Node *startNode, int startOffset, Node *endNode, int endOffset, Document *doc, Node **cursorNode, long &cursorOffset, NodeModifsSet *modifs); /** * Insert a node subtree in the tree. WARNING This function will log that the nodes were added. * WARNING : baseNode is used as the rootNode. * It will also try to merge text/Empty Nodes. * @param node The root node of the Node subtree to insert. * @param parentNode This Node will be the parent of node. * @param nextSibling This Node will be the next Sibling of Node. If null, node will be appended at * the child list of parentNode. * @param modifs The changes made are logged into modifs. Put 0L if you don't want to log * and if you know what you're doing! * @param merge Try to merge with the siblings if possible. * @return Returns a pointer to the node inserted. */ static Node* insertNodeSubtree(Node *node, Node* parentNode, Node* nextSibling, NodeModifsSet *modifs, bool merge = true); /** * It behaves essentially like the above function except that it can "surround" a set of Nodes with the * new Node. Thus, the closing Node is created if necessary. * nextSibling and nextEndSibling MUST have the same parent. If not, use the * DTDinsertNode. * The Node Subtree MUST be a single-Node-per-parent subtree. * This function does not try to know if the location of the new Node is DTD valid. * @param node The root node of the Node subtree to insert. * @param parent The parent of the Node. * @param nextSibling The next sibling of the Node. * @param nextEndSibling The next sibling of the closing Node if created. If nextEndSibling == * nextSibling, the closing Node will be placed at the right of the newly created Node. * All the Nodes between the new Node and its closing Tag will be moved as childs of the * last Node of the Node subtree.. * @param modifs The changes made are logged into modifs. * @return Returns a pointer to the node inserted. */ static Node* insertNodeSubtree(Node *node, Node* parentNode, Node* nextSibling, Node* nextEndSibling, NodeModifsSet *modifs, bool merge = true); /** * Split the Nodes as necessary, then check that the subtree is allowed to be inserted * and then insert the subtree. * @param node The root node of the Node subtree to insert. * @param selection contains the cursor Node where the insertion will take place. * @param modifs The changes made are logged into modifs. */ static Node* DTDInsertNodeSubtree(Node *node, NodeSelectionInd& selection, Node **cursorNode, long& cursorOffset, NodeModifsSet *modifs); static Node* DTDInsertNodeSubtree(Node* newNode, Node* parentNode, Node* nextSibling, NodeSelection& cursorHolder, NodeModifsSet *modifs); /** * Create a Node of name nodeName, of type nodeType, (see tag.h) connected to the document doc, * and nextSibling as Node's next sibling. * This function does not try to know if the location of the new Node is valid. * @param nodeName The node's name of the node to create. * @param tagString The string of the tag. * @param nodeType The type of the Node cf Tag::TokenType. * @param doc The Node belongs to this Document. * @param parent The parent of the Node. * @param nextSibling The next sibling of the Node. * @return Returns a pointer to the newly created Node. */ static Node *createAndInsertNode(const TQString &nodeName, const TQString &tagString, int nodeType, Document *doc, Node* parent, Node* nextSibling, NodeModifsSet *modifs, bool merge = true); /** * It behaves essentially like the above function except that it reate its closing Node if necessary * and then insert them with parent as Node's parent. * nextSibling and nextEndSibling MUST have the same parent. If not, use the * DTDcreateAndInsertNode. * @param nextEndSibling The next sibling of the closing Node if created. If nextEndSibling == * nextSibling, the closing Node will be placed at the right of the newly created Node. * All the Nodes between the new Node and its closing Tag will be moved as childs of the new Node. * @param modifs The changes made are logged into modifs. */ static Node *createAndInsertNode(const TQString &nodeName, const TQString &tagString, int nodeType, Document *doc, Node *parent, Node *nextSibling, Node *nextEndSibling, NodeModifsSet *modifs); /** * It behaves essentially like the above function except that if necessary, it will split the Nodes. * startNodeToSurround et endNodeToSurround MUST have the same parent. If not, use the * DTDcreateAndInsertNode. * This function does not try to know if the location of the new Node is valid. * @param startNodeToSurround The first Node which will be enclosed by the new Node. * @param endNodeToSurround The last Node which will be enclosed by the new Node. * @param startOffset The first Node will be splitted at offset startOffset, the right part will be enclosed. * @param endOffset The last Node will be splitted at offset endOffset, the left part will be enclosed. */ static Node *createAndInsertNode(const TQString &nodeName, const TQString &tagString, int nodeType, Document *doc, Node *parent, Node *startNodeToSurround, Node *endNodeToSurround, int startOffset, int endOffset, NodeModifsSet *modifs); /** * It behaves essentially like the above function except that it will insert the new Node only * if the DTD allows it. The new Tag can surround any subtree. If * necessary, several copies of the Node will be used. * This function takes care of the DTD validity of the Nodes created. * It will build the necessary mandatory Nodes (e.g. insertion of TABLE will also insert TR and TD). * This is the key function making the toolbars working. * @param startNode The first Node which must be surrounded by the new Node. * @param startOffset If firstNode is a text, specify at which offset the new Node must begin to surround. * @param endNode The last Node which must be surrounded by the new Node. * @param endOffset If endNode is a text, specify at which offset the new Node must stop to surround. * @return Returns false if it wasn't possible to insert the tag because e.g. of an invalid parent. */ static bool DTDcreateAndInsertNode(const TQString &nodeName, const TQString &tagString, int nodeType, Document *doc, Node *startNode, int startOffset, Node *endNode, int endOffset, Node **cursorNode, long &cursorOffset, NodeModifsSet *modifs); /** * For internal use. From startNode to endNode, it add where possible/necessary a new Node in order * to surround the maximum of Nodes. This is used by the above function. This function calls itself. * @param newNode The root Node of the node subtree to insert. * @param leafNode The leaf Node of the node subtree to insert. * @param startExaminationNode It will start examine Nodes from startExaminationNode. * @param endExaminationNode It will stop examine Nodes from endExaminationNode. * @param startNode This function will start adding newNode from startNode. * @param endNode This function will stop adding newNode at endNode. * @param currentNode This node is currently examined. * @param examinationStarted Specifies if we have begun to examine the Nodes. * @param addingStarted Specifies if we have begun to add the new Node. * @param nodeInserted Returns true if newNode was inserted at least once. Set to false before calling the function. * @level The relative level of the current Node Sibling (level 0 : root Node, level 1 : childs, and so on...) * MUST BE set to 0. */ static bool addNodeRecursively(Node *newNode, Node *leafNode, Node *startExaminationNode, Node *endExaminationNode, Node* startNode, Node *endNode, Node* currentNode, bool &examinationStarted, bool &addingStarted, bool &nodeInserted, int level, NodeModifsSet *modifs); /** * Create a copy of Node. It use the Node copy operator and add some kafka-specific flags : * It set the node->tag->cleanStrBuilt and node->tag->indentationDone to false; * @param node The node to duplicate. * @return Returns the duplicated Node. I wonder if i should always write so obvious things ;-) */ static Node *duplicateNode(Node *node); /** * It behaves essentially like the above function except that it can handle a node Subtree. * INNEFICIENT for bi */ static Node *duplicateNodeSubtree(Node *node, bool childAndClosingTagOnly = false); /** * Returns the closing tag of node or its last child or itself. * @param node * @return */ static Node* getLastChild(Node* node); /** * Extract a Node from the Node Tree. WARNING this will log that the Node was removed. * This mean that the undo/redo system will delete it when necessary so don't reuse it!!!! * @param node The node to delete. * @param modifs The changes made are logged into modifs. * @param extractChilds If we extract or move up the children. WARNING: it don't check * if the children of node are legal childs of the parent of node. * @param removeClosingTag Extract the closingTag if node isn't single and is Tag::XmlTag. * TODO: @param removeEmbeddedTags Specifies if we delete the embedded Nodes e.g. * : the PHP block is an embedded block. * @return Returns the node extracted with its childs */ static Node* extractNode(Node *node, NodeModifsSet *modifs, bool extractChildren = true, bool extractClosingTag = false/**, bool removeEmbeddedTags = false*/); /** * It behaves essentially like the above function. * Extract and BUT NOT DELETE RIGHT NOW node from the Tree. The undo/redo system will delete it * when necessary. * TODO: remove it, and use extractNode instead. * @param deleteClosingTag Delete the closingTag if node isn't single. */ static void extractAndDeleteNode(Node *node, NodeModifsSet *modifs, bool deleteChildren = true, bool deleteClosingTag = true, bool mergeAndFormat = true); /** * Extract a node subtree in the tree. WARNING This function will log that the nodes were added. * This funtion not only extract the start node but also will extract inline parents. * @param startNode The node from which we start the removal. * @param startOffset The offset of startNode from which we start the removal. * @param endNode The node from which we end the removal. * @param endOffset The offset of endNode from which we end the removal. * @param cursorNode The cursor is inside cursorNode. * @param cursorOffset The offset of the cursor inside cursorNode. * @return Returns a pointer to the node inserted. */ static Node* DTDExtractNodeSubtree(Node *startNode, int startOffset, Node *endNode, int endOffset, Node **cursorNode, long &cursorOffset, NodeModifsSet *modifs, bool extractInlineParentNodes = true); /** * Similar to the above function but it operates on the given node tree. See DTDGetNodeSubtree. * @param nodeSubtree The Node tree on which we're going to make the removal. * @return Returns a pointer to the node inserted. */ static Node* DTDExtractNodeSubtree(Node *startNode, int startOffset, Node *endNode, int endOffset, Node* nodeSubtree, NodeModifsSet* modifs, bool extractInlineParentNodes = true); static Node* extractNodeSubtreeAux(Node* commonParentStartChild, Node* commonParentEndChild, NodeModifsSet* modifs); /** * It behaves essentially like the above function. Provided for convenience. */ static Node* DTDRemoveSelection(NodeSelectionInd& selection, Node **cursorNode, long& cursorOffset, NodeModifsSet *modifs, bool extractInlineParentNodes = true); /** * Get a node subtree from the tree. It is similar to extractNodeSubtree() * but it doesn't extract anything. * It's useful to get a copy of the Node subtree from a selection, for example. * This funtion not only extract the start node but also will extract inline parents. * @param startNode The starting Node. * @param startOffset If firstNode is a text, specify at which offset the new start Node will be splitted. * @param endNode The ending Node. * @param endOffset If endNode is a text, specify at which offset the new end Node will be splitted. * @return Returns a pointer to the Node subtree. */ static Node* getNodeSubtree(Node *startNode, int startOffset, Node *endNode, int endOffset, bool extractInlineParentNodes = true); /** * An enumeration of all the possible return states of DTDExtractNode */ enum extractNodeStatus { //The node to extract was not found. nothingExtracted = 0, //The extract operation stopped because of a DTD error : if the node was removed, the child //weren't able to be childs of the node's parent, according to the DTD. Should not occur //except really bad HTML. extractionStoppedDueToBadNodes, //everything has gone fine extractionDone, //Invalid start or end position, or the given Node was a block. extractionBadParameters }; /** * This function will try to extract the node nodeName (of type XmlTag) from a given subtree, * according to the DTD. If the DTD don't allow it, it won't remove it. * This function is only interesting for the removal of Inline Nodes thus it will return an error if * a block nodeName is submitted. * TODO: AVOID splitting of Node when the DTD don't allow the removal. * @param nodeName The name of the Node to remove (must be inline). * @param doc It is needed to get the DTD informations. * @param startNode The node from which we start the removal. * @param startOffset The offset of startNode from which we start the removal. * @param endNode The node from which we end the removal. * @param endOffset The offset of endNode from which we end the removal. * : We want to keep track of the cursor position. TODO : cursor class * @param cursorNode The cursor is inside cursorNode. * @param cursorOffset The offset of the cursor inside cursorNode. * * @param modifs The usual modifs to log the modifications made for the undo/redo system. * @return Returns a kafkaCommon::extractNodeStatus. */ static int DTDExtractNode(const TQString &nodeName, Document *doc, Node *startNode, int startOffset, Node *endNode, int endOffset, Node **cursorNode, long &cursorOffset, NodeModifsSet *modifs); /** * Moves a Node somewhere else. * @param nodeToMove The node to move :-) * @param newParent The new parent of nodeToMove. * @param newNextSibling The new next Sibling of nodeToMove. If null, node will be appended at * the child list of parentNode. * @param modifs The changes made are logged into modifs. * @param merge Specifies if it should try to merge the Node at its new location. */ static void moveNode(Node *nodeToMove, Node *newParent, Node *newNextSibling, NodeModifsSet *modifs, bool merge = true, bool moveClosingNode = false); static void moveNode(Node *nodeToMove, Node *newParent, Node *newNextSibling, NodeSelection& cursorHolder, NodeModifsSet *modifs, bool merge = true, bool moveClosingNode = false); /** * Split a Text Node at offset offset. If offset or n is invalid, nothing is done. * @param n The Node to split. * @param offset Where to split the node. * @param modifs The change made are logged into modifs. * @return Returns if the node was splitted. */ static bool splitNode(Node *n, int offset, NodeModifsSet *modifs); /** * This method takes care of spliting start and end nodes, if needed, finding the commonParent, * commonParentStartChild and commonParentEndChild and split the start and end node subtrees, * calling splitStartNodeSubtree and splitEndNodeSubtree. * The following tree: * * --> commonParent * --> commonParentStartChild * select| * here --> startNode * * continue * --> commonParentEndChild * stop| --> endNode * more * * text * * * Is changed to: * * * * select| * * * * * here * * continue * * stop * * * * * more * * text * * * @param startNode The node where a selection starts, for example. * @param startOffset * @param endNode The node where a selection ends, for example. * @param endOffset * @param commonParent This is the common parent between start and end node. * If 0, it tries to find the commonParent, else it uses the passed node. * @param commonParentStartChildLocation The first child of commonParent which is parent of startNode is stored here. * @param commonParentEndChildLocation The first child of commonParent which is parent of endNode is stored here. * @param cursorNode The cursor node is stored here. * @param cursorOffset The cursor offset is stored here. * @param subTree The node corresponding to the start of a subtree that doesn't belong to the current document, or 0. * @param modifs The changes made are logged into modifs. */ static void splitStartAndEndNodeSubtree(Node*& startNode, int startOffset, Node*& endNode, int endOffset, Node*& commonParent, TQValueList& commonParentStartChildLocation, TQValueList& commonParentEndChildLocation, NodeSelection& cursorHolder, Node* subTree, NodeModifsSet* modifs, bool extractInlineParentNodes = true); /** * If n and n2 are both Text or Empty Nodes, merge them into one. * WARNING if merging occurs, n2 is deleted. * @param modifs The changes made are logged into modifs. * @param mergeTextOnly Specify if we should only merge text Nodes, not empty ones. * @return Returns true if the Nodes were merged, else false. */ static bool mergeNodes(Node *n, Node *n2, NodeModifsSet *modifs, bool mergeTextOnly = false); static bool mergeNodes(Node *n, Node *n2, NodeSelection& cursorHolder, NodeModifsSet *modifs, bool mergeTextOnly = false); /** * This function will navigate through the Nodes from startNode to endNode and * merge identical inline Nodes as well as text Nodes. * @param startNode The node from which the merge starts. * @param endNode The node from which the merge ends. * @param modifs The usual modifs, to log the changes. * : We want to keep track of the cursor position. TODO : cursor class * @param cursorNode The cursor is inside cursorNode. * @param cursorOffset The offset of the cursor inside cursorNode. * */ static void mergeInlineNode(Node *startNode, Node *endNode, Node **cursorNode, long &cursorOffset, NodeModifsSet *modifs); /** ----------------------- NODE MODIFICATIONS -------------------------------------*/ /** * Computes the end position of a string starting at pos (bLine, bCol). * @param tagString The tagString, representing usually a tag string ;-) * @param bLine The line of the first letter of tagString. * @param bCol The column of the first letter of tagString. * @param eLine Returns the line of the last letter of tagString. * @param eCol Returns the col of the last letter of tagString. */ static void getEndPosition(const TQString & tagString, int bLine, int bCol, int &eLine, int &eCol); /** * It behaves essentially like the above function except that the string is the Tag String of Node. * @param node The tag string is taken from node. */ static void getEndPosition(Node *node, int bLine, int bCol, int &eLine, int &eCol); /** * Set the tag string of node, and update the start/end position of the Node. * @param node The node which get the new tag string. * @param newTagString The new tag String :-) * @param modifs The changes made are logged into modifs. */ static void setTagString(Node *node, const TQString &newTagString, NodeModifsSet* modifs); /** * This function behaves essentially like the above function except that all the others Nodes' position * are updated too. */ static void setTagStringAndFitsNodes(Node *node, const TQString &newTagString, NodeModifsSet* modifs); /** * This function behaves exactly like Node::editAttribute except that the change is logged inside a NodeModifsSet. */ static void editNodeAttribute(Node* node, const TQString& name, const TQString& value, NodeModifsSet* modifs); /** * Gets the location of a Node in a pointer-independant suit of ints e.g. 1,3,5 means * that the node is the fifth child of the third child of the root Node. Efficient when * deleting the Node tree and rebuilding it when switching between Documents. * @param node The Node we want the location. * @return Returns the location. */ static TQValueList getLocation(Node* node); /** * It behaves essentially like the above function except that it operate on DOM::Nodes. */ static TQValueList getLocation(DOM::Node domNode); /** * Get the node corresponding to a location. See the above function. * @param loc We want the Node from this location. * @return Returns the Node at location loc. */ static Node* getNodeFromLocation(TQValueList loc); /** * Similar to the above function but instead of using baseNode it uses the passes Node tree. * @param nodeTree Node tree where to get the location. */ static Node* getNodeFromLocation(TQValueList loc, Node* nodeTree); /** * It behaves essentially like the above function except that it operate on DOM::Nodes. * @rootNode It needs the root Node of the DOM::Node Tree i.e. the document() Node. */ static DOM::Node getNodeFromLocation(TQValueList loc, DOM::Node rootNode); /** * Get the node corresponding to a sublocation. * @param loc A location of a Node. * @locOffset We want the (totalNumberOfParent - locOffset)th parent of Node. * @return Returns a parent of the node pointed by loc. */ static Node* getNodeFromSubLocation(TQValueList loc, int locOffset); static Node* getNodeFromSubLocation(TQValueList loc, int locOffset, Node* nodeTree); /** * A enumeration for kafkaCommon::compareNodePosition(). */ enum position { //It means that it is a previous sibling (not the dom/dom_node.h definition, but rather // the node.h definition) isBefore = 0, //It is the same Node. isAtTheSamePosition, //It means that it is a next sibling (in the node.h way). isAfter, //guess what? positionError }; /** * Compare the position of two Nodes. * e.g. (pos1)->next = (pos2); compareNodePosition(n1, n2) == kafkaCommon::before. * @param pos1 The location of the Node to compare. * @param pos2 The location of the Node to be compared to. * @return Return a kafkaCommon::position flag. */ static int compareNodePosition(TQValueList pos1, TQValueList pos2); /** * It behave essentially like the above function except that it is based on Nodes. */ static int compareNodePosition(Node *n1, Node *n2); /** * Compare n1 and n2's node type, node name, and node attributes. * @return Returns true if there are indentical. */ static bool compareNodes(Node *n1, Node *n2); /** * Get the node's depth in the tree. * @param node The node we want the depth. * @return Returns the depth of node. It is basically the number of parents of node. * It will return 0 if node has no parent Nodes, and -1 if node doesn't exists. */ static int nodeDepth(Node *node); /** * Looks if node has a parent which is named name. * @return Returns the first parent which is named name or 0L if not found. */ static Node* hasParent(Node *node, const TQString &name); /** * Tries to find the common parent to startNode and endNode, in the same conditions as above. */ static Node* hasParent(Node* startNode, Node* endNode, const TQString &name); /** ----------------- DOM::NODE TREE MODIFICATIONS --------------------*/ /** * Insert a DOM::Node in the DOM::Node tree. It takes care to handle the exceptions. * WARNING : The postEnhancement is not done (cf htmlenhancer.h) * Prefer using KafkaDocument::insertDomNode() * @param node The node to insert. * @param parent The new parent of node. If null, insert node at the top level. * @param nextSibling The new next sibling of node. If null, append node at the end of the child list. * @param rootNode The root DOM::Node of the DOM::Node tree. Useful when no parent is provided. * @return Returns true if the operation was successfull. */ static bool insertDomNode(DOM::Node node, DOM::Node parent = DOM::Node(), DOM::Node nextSibling = DOM::Node(), DOM::Node rootNode = DOM::Node()); /** * Removes a DOM::Node from the DOM::Node Tree. It takes care to handle the exceptions. * WARNING : The postUnenhancement is not done (cf htmlenhancer.h) * Prefer using KafkaDocument::removeDomNode() * @param node The Node to remove from the tree. * @retun Returns true if the operation was successfull.. */ static bool removeDomNode(DOM::Node node); /** --------------------- DOM::NODE MODIFICATIONS ---------------------- */ /** * Create a new DOM::Node. It takes care to check if nodeName is valid. * @param nodeName The DOM::Node's name. * @param dtd The currently used dtd. * @param rootNode The rootNode is needed in order to create a new DOM::Node. * @return Returns the DOM::Node created or a null DOM::Node if nodeName is invalid. */ static DOM::Node createDomNode(const TQString &nodeName, const DTDStruct* dtd, DOM::Document rootNode); /** * It behaves essentially like the above function. * @param node The DOM::Node will be created with node's name. */ static DOM::Node createDomNode(Node *node, DOM::Document rootNode); /** * Create a new Text Node. * @param textString The text inside the new text DOM::Node. * @param rootNode The rootNode is needed in order to create a new Text DOM::Node. * @return a new text DOM::Node. */ static DOM::Node createTextDomNode(const TQString &textString, DOM::Document rootNode); /** * Create a new attribute and check if the attrName can have this attribute. * @param nodeName The node name of the DOM::Node which will get this attribute. * @param dtd The currently used dtd. * @param attrName The name of the new attribute. * @param attrValue The value of the new attribute. * @param rootNode The rootNode is needed in order to create a new Attribute. * @return Returns the new Attribute or a null DOM::Node if attrName is invalid. */ static DOM::Node createDomNodeAttribute(const TQString &nodeName, const DTDStruct* dtd, const TQString &attrName, const TQString &attrValue, DOM::Document rootNode); /** * It behaves essentially like the above function. * @param node The corresponding DOM::Node of node will get the attribute. It don't add the attribute. */ static DOM::Node createDomNodeAttribute(Node* node, const TQString &attrName, DOM::Document rootNode); /** * It behaves essentially like the above function except that it use the DOM::Node->Node* link to get the * corresponding Node. So be sure that the link is set. * @param node The node which will get the attribute. It don't add the attribute. */ //static DOM::node createDomNodeAttribute(DOM::Node node, const TQString &attrName, // DOM::Document rootNode); /** * Append a new attribute to a DOM::Node. * @param node The node which will get the new attribute. * @param attr The new attribute to add. * @return Returns if the operation was successfull. */ static bool insertDomNodeAttribute(DOM::Node node, DOM::Node attr); /** * It behaves essentially like the above function except that if the attribute doesn't exist, it will create it, * and then it fills the attribute with attrValue. * @param nodeName The name of the Node corresponding to node. * @param dtd The currently used DTD. * @param attrName The name of the (new) Attribute. * @param attrValue The value of the new Attribute. * @param rootNode The rootNode is needed in order to create a new Attribute. * @return Returns if the operation was successfull. */ static bool editDomNodeAttribute(DOM::Node node, const TQString &nodeName, const DTDStruct* dtd, const TQString &attrName, const TQString &attrValue, DOM::Document rootNode); /** * It behaves essentially like the above function. * @param node The DOM::Node comes from this node. */ static bool editDomNodeAttribute(DOM::Node domNode, Node* node, const TQString &attrName, const TQString &attrValue, DOM::Document rootNode); /** * Looks if domNode has a parent which is named name. * @return Returns the first parent which is named name or an empty DOM::Node if not found. */ static DOM::Node hasParent(DOM::Node domNode, const TQString &name); /** * Returns the position of the child domNode. * @param domNode This is the DOM::Node we want the position. * @return Returns the position of domNode inside domNode's parent's children or -1 if not found. */ static int childPosition(DOM::Node domNode); /** * Returns the position'th child of parentNode. * @param parentNode The parent Node of the node to return. * @param position We return the position'th child Node. * @param fallback If set to true, it will always return a valid Node (except if there is no child!!) */ static DOM::Node getChildNode(DOM::Node parentNode, int position, bool fallback = false); /** * Specify if a DOM::Node is inline (as specified in isInline()) or text. * @return true if it is an inline Node. */ static bool isInline(DOM::Node domNode); /** * Specify if parent supports the siblings DOM::Nodes starting from startNode to endNode * according to the DTD dtd. */ static bool parentSupports(DOM::Node parent, DOM::Node startNode, DOM::Node endNode, const DTDStruct* dtd); /** ----------------------- MISCELLANEOUS -------------------------------------*/ /** * TEMPORARY, HTML specific * @return Returns true if it is a inline Node. Official DTD List, unlike getNodeDisplay(). */ static bool isInline(const TQString &nodename); /** * Prints in stdout the current DOM::Node tree. * @param rootNode The root Node of the DOM::Node Tree (usually document()) * @param indent The indentation. */ static void coutDomTree(DOM::Node rootNode, int indent); /** * Prints in stdout the current Node tree. * @param node The startNode * @param indent The number of little dots per parent relationship. */ static void coutTree(Node *node, int indent); /** * Returns whether a range is surrounded by a tag. * @param start_node The start of the range to be checked. * @param end_node The end of the range to be checked. * @param tag_name The name of the tag, e.g., "strong". * @return -1 is not inside tag_name * 1 is inside tag_name * 0 mixed */ static int isInsideTag(Node* start_node, Node* end_node, TQString const& tag_name); static int isInsideTag(Node* start_node, Node* end_node, TQString const& tag_name, TQString const& attribute_name, TQString const& attribute_value); /** * Return whether the offset is placed between two words in a text node. * @pre node is a Node of type text. * @pre offset >= 0 * @param node The text node to be checked. * @param offset The position in text we want to see if it's between words. * @return true if is a space between words or if it's in the limit of a word. */ static bool isBetweenWords(Node* node, int offset); /** * Set node and offset to the beggining of the word * @pre node is a text node. * @pre isBetweenWords * @param node The text node, which will be changed (or not) to the start of the word. * @param offset The current offset of the text node which will be changed (or not) to the start of the word. * @return the offset of the beggining of the word */ static void getStartOfWord(Node*& node, int& offset); /** * Same as above, but will get the end of the word */ static void getEndOfWord(Node*& node, int& offset); /** * Set node and offset to the beggining of the paragraph. * The distinction between inline/block nodes is used here. * @param node * @param offset */ static void getStartOfParagraph(Node*& node, int& offset); static void getEndOfParagraph(Node*& node, int& offset); private: /** * Split the last valid start parent (commonParentStartChild) into two. * This and the method above are related and are used in sequence. * The following tree: * * --> commonParent * --> commonParentStartChild * select| * here --> startNode * * continue * * stop|more * * text * * * Is changed to: * * * * select| * * * * * here * * continue * * stop|more * * text * * * @param startNode The node where a selection starts, for example. * @param commonParent This is the common parent between start and end node. * @param commonParentStartChildLocation The first child of commonParent which is parent of startNode * @param modifs The changes made are logged into modifs. */ static void splitStartNodeSubtree(Node* startNode, Node* commonParent, TQValueList& commonParentStartChildLocation, NodeModifsSet* modifs); /** * Split the last valid start parent (commonParentStartChild) into two. * The following tree: * * --> commonParent * --> commonParentStartChild * select| * here * * continue * --> commonParentEndChild * stop| --> endNode * more * * text * * * Is changed to: * * * * select|here * * continue * * stop| * * * * * more * * text * * * @param endNode The node where a selection ends, for example. * @param commonParent This is the common parent between start and end node. * @param commonParentStartChildLocation The first child of commonParent which is parent of startNode. * @param commonParentEndChildLocation The first child of commonParent which is parent of endNode. * @param subTree True if we are dealing with a tree that doesn't belong to the current document. * @param modifs The changes made are logged into modifs. */ static void splitEndNodeSubtree(Node* endNode, Node* commonParent, TQValueList& commonParentStartChildLocation, TQValueList& commonParentEndChildLocation, bool subTree, NodeModifsSet* modifs); }; #endif