You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdewebdev/quanta/parts/kafka/kafkacommon.h

1178 lines
53 KiB

/***************************************************************************
kafkacommon.h
-------------------
copyright : (C) 2003, 2004 - Nicolas Deschildre
email : ndeschildre@tdewebdev.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 <tqvaluelist.h>
#include <dom/dom_node.h>
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<int>& commonParentStartChildLocation,
TQValueList<int>& commonParentEndChildLocation, Node* nodeSubtree);
/**
* Same as above, only that the common parent can be inline.
*/
static Node* DTDGetCommonParent(Node* startNode, Node* endNode,
TQValueList<int>& commonParentStartChildLocation,
TQValueList<int>& 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:
* <body>Text</body>
* else:
* <body>
* Text
* </body>
*/
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<int>
* 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 <?xml ... ?> 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.
* <TEMPORARY> : 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.
* </TEMPORARY>
* @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.
* <a href="<? boo ?>" > : 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.
* <TEMPORARY> : 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.
* </TEMPORARY>
* @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:
* <body>
* <b> --> commonParent
* <i> --> commonParentStartChild
* select|
* here --> startNode
* </i>
* continue
* <u> --> commonParentEndChild
* stop| --> endNode
* more
* </u>
* text
* </b>
* <body>
* Is changed to:
* <body>
* <b>
* <i>
* select|
* </i>
* </b>
* <b>
* <i>
* here
* </i>
* continue
* <u>
* stop
* </u>
* </b>
* <b>
* <u>
* more
* </u>
* text
* </b>
* </body>
* @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<int>& commonParentStartChildLocation,
TQValueList<int>& 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.
* <TEMPORARY> : 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.
* </TEMPORARY>
*/
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<int> getLocation(Node* node);
/**
* It behaves essentially like the above function except that it operate on DOM::Nodes.
*/
static TQValueList<int> 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<int> 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<int> 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<int> 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<int> loc, int locOffset);
static Node* getNodeFromSubLocation(TQValueList<int> 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<int> pos1, TQValueList<int> 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:
* <body>
* <b> --> commonParent
* <i> --> commonParentStartChild
* select|
* here --> startNode
* </i>
* continue
* <u>
* stop|more
* </u>
* text
* </b>
* <body>
* Is changed to:
* <body>
* <b>
* <i>
* select|
* </i>
* </b>
* <b>
* <i>
* here
* </i>
* continue
* <u>
* stop|more
* </u>
* text
* </b>
* </body>
* @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<int>& commonParentStartChildLocation, NodeModifsSet* modifs);
/**
* Split the last valid start parent (commonParentStartChild) into two.
* The following tree:
* <body>
* <b> --> commonParent
* <i> --> commonParentStartChild
* select|
* here
* </i>
* continue
* <u> --> commonParentEndChild
* stop| --> endNode
* more
* </u>
* text
* </b>
* <body>
* Is changed to:
* <body>
* <b>
* <i>
* select|here
* </i>
* continue
* <u>
* stop|
* </u>
* </b>
* <b>
* <u>
* more
* </u>
* text
* </b>
* </body>
* @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<int>& commonParentStartChildLocation,
TQValueList<int>& commonParentEndChildLocation,
bool subTree, NodeModifsSet* modifs);
};
#endif