summaryrefslogtreecommitdiff
path: root/patches/dev300/vEdit-13-August.diff
diff options
context:
space:
mode:
authorMichael Stahl <mstahl@redhat.com>2012-01-28 21:26:09 +0100
committerMichael Stahl <mstahl@redhat.com>2012-01-28 21:26:09 +0100
commit7947d959db2a84860cdfd479d95ea5b30fdba051 (patch)
tree4cc2ec4d16ee75d338f85d966b089ca5a0240097 /patches/dev300/vEdit-13-August.diff
parent2786d0238b25d7bcc1408bb1a45a8f7f4bd1febd (diff)
replace obsolete "master" branch with README that points at new repoHEADmaster-deletedmaster
Diffstat (limited to 'patches/dev300/vEdit-13-August.diff')
-rw-r--r--patches/dev300/vEdit-13-August.diff7896
1 files changed, 0 insertions, 7896 deletions
diff --git a/patches/dev300/vEdit-13-August.diff b/patches/dev300/vEdit-13-August.diff
deleted file mode 100644
index 117a75742..000000000
--- a/patches/dev300/vEdit-13-August.diff
+++ /dev/null
@@ -1,7896 +0,0 @@
-diff --git starmath/inc/caret.hxx starmath/inc/caret.hxx
-new file mode 100644
-index 0000000..b1ff954
---- /dev/null
-+++ starmath/inc/caret.hxx
-@@ -0,0 +1,445 @@
-+#ifndef CARET_H
-+#define CARET_H
-+
-+#include "node.hxx"
-+
-+/** Representation of caret position with an equantion */
-+struct SmCaretPos{
-+ SmCaretPos(SmNode* selectedNode = NULL, int iIndex = 0) {
-+ pSelectedNode = selectedNode;
-+ Index = iIndex;
-+ }
-+ /** Selected node */
-+ SmNode* pSelectedNode;
-+ /** Index within the selected node
-+ *
-+ * 0: Position infront of a node
-+ * 1: Position after a node or after first char in SmTextNode
-+ * n: Position after n char in SmTextNode
-+ *
-+ * Notice how there's special cases for SmTextNode.
-+ */
-+ //TODO: Special cases for SmBlankNode is needed
-+ //TODO: Consider forgetting about the todo above... As it's really unpleasent.
-+ int Index;
-+ /** True, if this is a valid caret position */
-+ bool IsValid() { return pSelectedNode != NULL; }
-+ bool operator!=(SmCaretPos pos) const {
-+ return pos.pSelectedNode != pSelectedNode || Index != pos.Index;
-+ }
-+ bool operator==(SmCaretPos pos) const {
-+ return pos.pSelectedNode == pSelectedNode && Index == pos.Index;
-+ }
-+ /** Get the caret position after pNode, regardless of pNode
-+ *
-+ * Gets the caret position following pNode, this is SmCaretPos(pNode, 1).
-+ * Unless pNode is an instance of SmTextNode, then the index is the text length.
-+ */
-+ static SmCaretPos GetPosAfter(SmNode* pNode) {
-+ if(pNode && pNode->GetType() == NTEXT)
-+ return SmCaretPos(pNode, ((SmTextNode*)pNode)->GetText().Len());
-+ return SmCaretPos(pNode, 1);
-+ }
-+};
-+
-+/** A line that represents a caret */
-+class SmCaretLine{
-+public:
-+ SmCaretLine(long left = 0, long top = 0, long height = 0) {
-+ _top = top;
-+ _left = left;
-+ _height = height;
-+ }
-+ long GetTop() const {return _top;}
-+ long GetLeft() const {return _left;}
-+ long GetHeight() const {return _height;}
-+ long SquaredDistanceX(SmCaretLine line) const{
-+ return (GetLeft() - line.GetLeft()) * (GetLeft() - line.GetLeft());
-+ }
-+ long SquaredDistanceX(Point pos) const{
-+ return (GetLeft() - pos.X()) * (GetLeft() - pos.X());
-+ }
-+ long SquaredDistanceY(SmCaretLine line) const{
-+ long d = GetTop() - line.GetTop();
-+ if(d < 0)
-+ d = (d * -1) - GetHeight();
-+ else
-+ d = d - line.GetHeight();
-+ if(d < 0)
-+ return 0;
-+ return d * d;
-+ }
-+ long SquaredDistanceY(Point pos) const{
-+ long d = GetTop() - pos.Y();
-+ if(d < 0)
-+ d = (d * -1) - GetHeight();
-+ if(d < 0)
-+ return 0;
-+ return d * d;
-+ }
-+private:
-+ long _top;
-+ long _left;
-+ long _height;
-+};
-+
-+/////////////////////////////// SmCaretPosGraph////////////////////////////////
-+
-+/** An entry in SmCaretPosGraph */
-+struct SmCaretPosGraphEntry{
-+ SmCaretPosGraphEntry(SmCaretPos pos = SmCaretPos(),
-+ SmCaretPosGraphEntry* left = NULL,
-+ SmCaretPosGraphEntry* right = NULL){
-+ CaretPos = pos;
-+ Left = left;
-+ Right = right;
-+ }
-+ /** Caret position */
-+ SmCaretPos CaretPos;
-+ /** Entry to the left visually */
-+ SmCaretPosGraphEntry* Left;
-+ /** Entry to the right visually */
-+ SmCaretPosGraphEntry* Right;
-+ void SetRight(SmCaretPosGraphEntry* right){
-+ Right = right;
-+ }
-+ void SetLeft(SmCaretPosGraphEntry* left){
-+ Left = left;
-+ }
-+};
-+
-+/** Define SmCaretPosGraph to be less than one page 4096 */
-+#define SmCaretPosGraphSize 255
-+
-+class SmCaretPosGraph;
-+
-+/** Iterator for SmCaretPosGraph */
-+class SmCaretPosGraphIterator{
-+public:
-+ SmCaretPosGraphIterator(SmCaretPosGraph* graph){
-+ pGraph = graph;
-+ nOffset = 0;
-+ pEntry = NULL;
-+ }
-+ /** Get the next entry, NULL if none */
-+ SmCaretPosGraphEntry* Next();
-+ /** Get the current entry, NULL if none */
-+ SmCaretPosGraphEntry* Current(){
-+ return pEntry;
-+ }
-+ /** Get the current entry, NULL if none */
-+ SmCaretPosGraphEntry* operator->(){
-+ return pEntry;
-+ }
-+private:
-+ /** Next entry to return */
-+ int nOffset;
-+ /** Current graph */
-+ SmCaretPosGraph* pGraph;
-+ /** Current entry */
-+ SmCaretPosGraphEntry* pEntry;
-+};
-+
-+
-+/** A graph over all caret positions
-+ * @remarks Graphs can only grow, entries cannot be removed!
-+ */
-+class SmCaretPosGraph{
-+public:
-+ SmCaretPosGraph(){
-+ pNext = NULL;
-+ nOffset = 0;
-+ }
-+ ~SmCaretPosGraph();
-+ SmCaretPosGraphEntry* Add(SmCaretPosGraphEntry entry);
-+ SmCaretPosGraphEntry* Add(SmCaretPos pos,
-+ SmCaretPosGraphEntry* left = NULL,
-+ SmCaretPosGraphEntry* right = NULL){
-+ j_assert(pos.Index >= 0, "Index shouldn't be -1!");
-+ return Add(SmCaretPosGraphEntry(pos, left, right));
-+ }
-+ /** Get an iterator for this graph */
-+ SmCaretPosGraphIterator GetIterator(){
-+ return SmCaretPosGraphIterator(this);
-+ }
-+ friend class SmCaretPosGraphIterator;
-+private:
-+ /** Next graph, to be used when this graph is full */
-+ SmCaretPosGraph* pNext;
-+ /** Next free entry in graph */
-+ int nOffset;
-+ /** Entries in this graph segment */
-+ SmCaretPosGraphEntry Graph[SmCaretPosGraphSize];
-+};
-+
-+/** \page visual_formula_editing Visual Formula Editing
-+ * A visual formula editor allows users to easily edit formulas without having to learn and
-+ * use complicated commands. A visual formula editor is a WYSIWYG editor. For OpenOffice Math
-+ * this essentially means that you can click on the formula image, to get a caret, which you
-+ * can move with arrow keys, and use to modify the formula by entering text, clicking buttons
-+ * or using shortcuts.
-+ *
-+ * \subsection formula_trees Formula Trees
-+ * A formula in OpenOffice Math is a tree of nodes, take for instance the formula
-+ * "A + {B cdot C} over D", it looks like this
-+ * \f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$. The tree for this formula
-+ * looks like this:
-+ *
-+ * \dot
-+ * digraph {
-+ * labelloc = "t";
-+ * label= "Equation: \"A + {B cdot C} over D\"";
-+ * size = "9,9";
-+ * n0 [label="SmTableNode (1)"];
-+ * n0 -> n1 [label="0"];
-+ * n1 [label="SmLineNode (2)"];
-+ * n1 -> n2 [label="0"];
-+ * n2 [label="SmExpressionNode (3)"];
-+ * n2 -> n3 [label="0"];
-+ * n3 [label="SmBinHorNode (4)"];
-+ * n3 -> n4 [label="0"];
-+ * n4 [label="SmTextNode: A (5)"];
-+ * n3 -> n5 [label="1"];
-+ * n5 [label="SmMathSymbolNode:  (6)"];
-+ * n3 -> n6 [label="2"];
-+ * n6 [label="SmBinVerNode (7)"];
-+ * n6 -> n7 [label="0"];
-+ * n7 [label="SmExpressionNode (8)"];
-+ * n7 -> n8 [label="0"];
-+ * n8 [label="SmBinHorNode (9)"];
-+ * n8 -> n9 [label="0"];
-+ * n9 [label="SmTextNode: B (10)"];
-+ * n8 -> n10 [label="1"];
-+ * n10 [label="SmMathSymbolNode: ⋅ (11)"];
-+ * n8 -> n11 [label="2"];
-+ * n11 [label="SmTextNode: C (12)"];
-+ * n6 -> n12 [label="1"];
-+ * n12 [label="SmRectangleNode (13)"];
-+ * n6 -> n13 [label="2"];
-+ * n13 [label="SmTextNode: D (14)"];
-+ * }
-+ * \enddot
-+ *
-+ * The vertices are nodes, their label says what kind of node and the number in parentheses is
-+ * the identifier of the node (In practices a pointer is used instead of the id). The direction
-+ * of the edges tells which node is parent and which is child. The label of the edges are the
-+ * child node index number, given to SmNode::GetSubNode() of the parent to get the child node.
-+ *
-+ *
-+ * \subsection visual_lines Visual Lines
-+ *
-+ * Inorder to do caret movement in visual lines, we need a definition of caret position and
-+ * visual line. In a tree such as the above there are three visual lines. There's the outer most
-+ * line, with entries such as
-+ * \f$\mbox{A}\f$, \f$ + \f$ and \f$ \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$. Then there's
-+ * the numerator line of the fraction it has entries \f$ \mbox{B} \f$, \f$ \cdot \f$ and \f$ \mbox{C} \f$.
-+ * And last by not least there's the denominator line of the fraction it's only entry is \f$ \mbox{D} \f$.
-+ *
-+ * For visual editing it should be possible to place a caret on both sides of any line entry,
-+ * consider a line entry a character or construction that in a line is treated as a character.
-+ * Imagine the caret is placed to the right of the plus sign (id: 6), now if user presses
-+ * backspace this should delete the plus sign (id: 6), and if the user presses delete this
-+ * should delete the entire fraction (id: 7). This is because the caret is in the outer most
-+ * line where the fraction is considered a line entry.
-+ *
-+ * However, inorder to prevent users from accidentally deleting large subtrees, just because
-+ * they logically placed there caret a in the wrong line, require that complex constructions
-+ * such as a fraction is selected before it is deleted. Thus in this case it wouldn't be
-+ * deleted, but only selected and then deleted if the user hit delete again. Anyway, this is
-+ * slightly off topic for now.
-+ *
-+ * Important about visual lines is that they don't always have an SmExpressionNode as root
-+ * and the entries in a visual line is all the nodes of a subtree ordered left to right that
-+ * isn't either an SmExpressionNode, SmBinHorNode or SmUnHorNode.
-+ *
-+ *
-+ * \subsection caret_positions Caret Positions
-+ *
-+ * A caret position in OpenOffice Math is representated by an instance of SmCaretPos.
-+ * That is a caret position is a node and an index related to this node. For most nodes the
-+ * index 0, means caret is infront of this node, the index 1 means caret is after this node.
-+ * For SmTextNode the index is the caret position after the specified number of characters,
-+ * imagine an SmTextNode with the number 1337. The index 3 in such SmTextNode would mean a
-+ * caret placed right before 7, e.g. "133|7".
-+ *
-+ * For SmExpressionNode, SmBinHorNode and SmUnHorNode the only legal index is 0, which means
-+ * infront of the node. Actually the index 0 may only because for the first caret position
-+ * in a visual line. From the example above, consider the following subtree that constitutes
-+ * a visual line:
-+ *
-+ * \dot
-+ * digraph {
-+ * labelloc = "t";
-+ * label= "Subtree that constitutes a visual line";
-+ * size = "7,5";
-+ * n7 [label="SmExpressionNode (8)"];
-+ * n7 -> n8 [label="0"];
-+ * n8 [label="SmBinHorNode (9)"];
-+ * n8 -> n9 [label="0"];
-+ * n9 [label="SmTextNode: B (10)"];
-+ * n8 -> n10 [label="1"];
-+ * n10 [label="SmMathSymbolNode: ⋅ (11)"];
-+ * n8 -> n11 [label="2"];
-+ * n11 [label="SmTextNode: C (12)"];
-+ * }
-+ * \enddot
-+ * Here the caret positions are:
-+ *
-+ * <TABLE>
-+ * <TR><TD><B>Caret position:</B></TD><TD><B>Example:</B></TD>
-+ * </TR><TR>
-+ * <TD>{id: 8, index: 0}</TD>
-+ * <TD>\f$ \mid \mbox{C} \cdot \mbox{C} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 10, index: 1}</TD>
-+ * <TD>\f$ \mbox{C} \mid \cdot \mbox{C} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 11, index: 1}</TD>
-+ * <TD>\f$ \mbox{C} \cdot \mid \mbox{C} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 12, index: 1}</TD>
-+ * <TD>\f$ \mbox{C} \cdot \mbox{C} \mid \f$</TD>
-+ * </TR><TR>
-+ * </TABLE>
-+ *
-+ * Where \f$ \mid \f$ is used to denote caret position.
-+ *
-+ * With these exceptions included in the definition the id and index: {id: 11, index: 0} does
-+ * \b not constitute a caret position in the given context. Note the method
-+ * SmCaretPos::IsValid() does not check if this invariant holds true, but code in SmCaret,
-+ * SmSetSelectionVisitor and other places depends on this invariant to hold.
-+ *
-+ *
-+ * \subsection caret_movement Caret Movement
-+ *
-+ * As the placement of caret positions depends very much on the context within which a node
-+ * appears it is not trivial to find all caret positions and determine which follows which.
-+ * In OpenOffice Math this is done by the SmCaretPosGraphBuildingVisitor. This visitor builds
-+ * graph (an instnce of SmCaretPosGraph) over the caret positions. For details on how this
-+ * graph is build, and how new methods should be implemented see SmCaretPosGraphBuildingVisitor.
-+ *
-+ * The result of the SmCaretPosGraphBuildingVisitor is a graph over the caret positions in a
-+ * formula, representated by an instance of SmCaretPosGraph. Each entry (instances of SmCaretPosGraphEntry)
-+ * has a pointer to the entry to the left and right of itself. This way we can easily find
-+ * the caret position to a right or left of a given caret position. Note each caret position
-+ * only appears once in this graph.
-+ *
-+ * When searching for a caret position after a left click on the formula this map is also used.
-+ * We simply iterate over all entries, uses the SmCaretPos2LineVisitor to find a line for each
-+ * caret position. Then the distance from the click to the line is computed and we choose the
-+ * caret position closest to the click.
-+ *
-+ * For up and down movement, we also iterator over all caret positions and use SmCaretPos2LineVisitor
-+ * to find a line for each caret position. Then we compute the distance from the current
-+ * caret position to every other caret position and chooses the one closest that is either
-+ * above or below the current caret position, depending on wether we're doing up or down movement.
-+ *
-+ * This result of this approach to caret movement is that we have logically predictable
-+ * movement for left and right, whilst leftclick, up and down movement depends on the sizes
-+ * and placement of all node and may be less logically predictable. This solution also means
-+ * that we only have one complex visitor generating the graph, imagine the nightmare if we
-+ * had a visitor for movement in each direction.
-+ *
-+ * Making up and down movement independent of node sizes and placement wouldn't necessarily
-+ * be a good thing either. Consider the formula \f$ \frac{1+2+3+4+5}{6} \f$, if the caret is
-+ * placed as displayed here: \f$ \frac{1+2+3+4+5}{6 \mid} \f$, up movement should move to right
-+ * after "3": \f$ \frac{1+2+3|+4+5}{6} \f$. However, such a move depends on the sizes and placement
-+ * of all nodes in the fraction.
-+ *
-+ *
-+ * \subsubsection caretpos_graph_example Example of Caret Position Graph
-+ *
-+ * If we consider the formula
-+ * \f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$ from \ref formula_trees.
-+ * It has the following caret positions:
-+ *
-+ * <TABLE>
-+ * <TR>
-+ * <TD><B>Caret position:</B></TD>
-+ * <TD><B>Example:</B></TD>
-+ * </TR><TR>
-+ * <TD>{id: 3, index: 0}</TD>
-+ * <TD>\f$ \mid\mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 5, index: 1}</TD>
-+ * <TD>\f$ \mbox{A}\mid + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 6, index: 1}</TD>
-+ * <TD>\f$ \mbox{A} + \mid \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 8, index: 0}</TD>
-+ * <TD>\f$ \mbox{A} + \frac{ \mid \mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 10, index: 1}</TD>
-+ * <TD>\f$ \mbox{A} + \frac{\mbox{B} \mid \cdot \mbox{C}}{\mbox{D}} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 11, index: 1}</TD>
-+ * <TD>\f$ \mbox{A} + \frac{\mbox{B} \cdot \mid \mbox{C}}{\mbox{D}} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 12, index: 1}</TD>
-+ * <TD>\f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C} \mid}{\mbox{D}} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 14, index: 0}</TD>
-+ * <TD>\f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mid \mbox{D}} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 14, index: 1}</TD>
-+ * <TD>\f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D} \mid} \f$</TD>
-+ * </TR><TR>
-+ * <TD>{id: 7, index: 1}</TD>
-+ * <TD>\f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \mid \f$</TD>
-+ * </TR>
-+ * </TABLE>
-+ *
-+ * Below is a directed graph over the caret postions and how you can move between them.
-+ * \dot
-+ * digraph {
-+ * labelloc = "t";
-+ * label= "Caret Position Graph";
-+ * size = "4,6";
-+ * p0 [label = "{id: 3, index: 0}"];
-+ * p0 -> p1 [fontsize = 10.0, label = "right"];
-+ * p1 [label = "{id: 5, index: 1}"];
-+ * p1 -> p0 [fontsize = 10.0, label = "left"];
-+ * p1 -> p2 [fontsize = 10.0, label = "right"];
-+ * p2 [label = "{id: 6, index: 1}"];
-+ * p2 -> p1 [fontsize = 10.0, label = "left"];
-+ * p2 -> p3 [fontsize = 10.0, label = "right"];
-+ * p3 [label = "{id: 8, index: 0}"];
-+ * p3 -> p2 [fontsize = 10.0, label = "left"];
-+ * p3 -> p4 [fontsize = 10.0, label = "right"];
-+ * p4 [label = "{id: 10, index: 1}"];
-+ * p4 -> p3 [fontsize = 10.0, label = "left"];
-+ * p4 -> p5 [fontsize = 10.0, label = "right"];
-+ * p5 [label = "{id: 11, index: 1}"];
-+ * p5 -> p4 [fontsize = 10.0, label = "left"];
-+ * p5 -> p6 [fontsize = 10.0, label = "right"];
-+ * p6 [label = "{id: 12, index: 1}"];
-+ * p6 -> p5 [fontsize = 10.0, label = "left"];
-+ * p6 -> p9 [fontsize = 10.0, label = "right"];
-+ * p7 [label = "{id: 14, index: 0}"];
-+ * p7 -> p2 [fontsize = 10.0, label = "left"];
-+ * p7 -> p8 [fontsize = 10.0, label = "right"];
-+ * p8 [label = "{id: 14, index: 1}"];
-+ * p8 -> p7 [fontsize = 10.0, label = "left"];
-+ * p8 -> p9 [fontsize = 10.0, label = "right"];
-+ * p9 [label = "{id: 7, index: 1}"];
-+ * p9 -> p6 [fontsize = 10.0, label = "left"];
-+ * }
-+ * \enddot
-+ */
-+
-+/* TODO: Write documentation about the following keywords:
-+ *
-+ * Visual Selections:
-+ * - Show images
-+ * - Talk about how the visitor does this
-+ *
-+ * Modifying a Visual Line:
-+ * - Find top most non-compo of the line (e.g. The subtree that constitutes a line)
-+ * - Make the line into a list
-+ * - Edit the list, add/remove/modify nodes
-+ * - Parse the list back into a subtree
-+ * - Insert the new subtree where the old was taken
-+ */
-+
-+#endif /* CARET_H */
-diff --git starmath/inc/cursor.hxx starmath/inc/cursor.hxx
-new file mode 100644
-index 0000000..ff865a8
---- /dev/null
-+++ starmath/inc/cursor.hxx
-@@ -0,0 +1,404 @@
-+#ifndef SMCURSOR_H
-+#define SMCURSOR_H
-+
-+#include "node.hxx"
-+#include "caret.hxx"
-+
-+/** Factor to multiple the squared horizontical distance with
-+ * Used for Up and Down movement.
-+ */
-+#define HORIZONTICAL_DISTANCE_FACTOR 10
-+
-+/** Enum of direction for movement */
-+enum SmMovementDirection{
-+ MoveUp,
-+ MoveDown,
-+ MoveLeft,
-+ MoveRight
-+};
-+
-+/** Enum of elements that can inserted into a formula */
-+enum SmFormulaElement{
-+ BlankElement,
-+ FactorialElement,
-+ PlusElement,
-+ MinusElement,
-+ CDotElement,
-+ EqualElement,
-+ LessThanElement,
-+ GreaterThanElement
-+};
-+
-+/** Bracket types that can be inserted */
-+enum SmBracketType {
-+ /** None brackets, left command "none" */
-+ NoneBrackets,
-+ /** Round brackets, left command "(" */
-+ RoundBrackets,
-+ /**Square brackets, left command "[" */
-+ SquareBrackets,
-+ /** Double square brackets, left command "ldbracket" */
-+ DoubleSquareBrackets,
-+ /** Line brackets, left command "lline" */
-+ LineBrackets,
-+ /** Double line brackets, left command "ldline" */
-+ DoubleLineBrackets,
-+ /** Curly brackets, left command "lbrace" */
-+ CurlyBrackets,
-+ /** Angle brackets, left command "langle" */
-+ AngleBrackets,
-+ /** Ceiling brackets, left command "lceil" */
-+ CeilBrackets,
-+ /** Floor brackets, left command "lfloor" */
-+ FloorBrackets
-+};
-+
-+/** A list of nodes */
-+typedef std::list<SmNode*> SmNodeList;
-+
-+class SmDocShell;
-+
-+/** Formula cursor
-+ *
-+ * This class is used to represent a cursor in a formula, which can be used to manipulate
-+ * an formula programmatically.
-+ * @remarks This class is a very intimite friend of SmDocShell.
-+ */
-+class SmCursor{
-+public:
-+ SmCursor(SmNode* tree, SmDocShell* pShell){
-+ //Initialize members
-+ pTree = tree;
-+ anchor = NULL;
-+ position = NULL;
-+ pGraph = NULL;
-+ pDocShell = pShell;
-+ pClipboard = NULL;
-+ nEditSections = 0;
-+ //Build graph
-+ BuildGraph();
-+ }
-+
-+ ~SmCursor(){
-+ SetClipboard();
-+ if(pGraph)
-+ delete pGraph;
-+ pGraph = NULL;
-+ }
-+
-+ /** Gets the anchor */
-+ SmCaretPos GetAnchor(){ return anchor->CaretPos; }
-+
-+ /** Get position */
-+ SmCaretPos GetPosition() { return position->CaretPos; }
-+
-+ /** True, if the cursor has a selection */
-+ bool HasSelection() { return anchor != position; }
-+
-+ /** Move the position of this cursor */
-+ void Move(OutputDevice* pDev, SmMovementDirection direction, bool bMoveAnchor = true);
-+
-+ /** Move to the caret position closet to a given point */
-+ void MoveTo(OutputDevice* pDev, Point pos, bool bMoveAnchor = true);
-+
-+ /** Delete the current selection or do nothing */
-+ void Delete();
-+
-+ /** Insert text at the current position */
-+ void InsertText(XubString aString);
-+
-+ /** Insert an element into the formula */
-+ void InsertElement(SmFormulaElement element);
-+
-+ /** Insert a command specified in commands.src*/
-+ void InsertCommand(USHORT nCommand);
-+
-+ /** Insert command text translated into line entries at position
-+ *
-+ * Note: This method uses the parser to translate a command text into a
-+ * tree, then it copies line entries from this tree into the current tree.
-+ * Will not work for commands such as newline or ##, if position is in a matrix.
-+ * This will work for stuff like "A intersection B". But stuff spaning multiple lines
-+ * or dependent on the context which position is placed in will not work!
-+ */
-+ void InsertCommandText(String aCommandText);
-+
-+ /** Insert a special node created from aString
-+ *
-+ * Used for handling insert request from the "catalog" dialog.
-+ * The provided string should be formatet as the desired command: %phi
-+ * Note: this method ONLY supports commands defined in Math.xcu
-+ *
-+ * For more complex expressions use InsertCommandText, this method doesn't
-+ * use SmParser, this means that it's faster, but not as strong.
-+ */
-+ void InsertSpecial(XubString aString);
-+
-+ /** Create sub-/super script
-+ *
-+ * If there's a selection, it will be move into the appropriate sub-/super scription
-+ * of the node infront of it. If there's no node infront of position (or the selection),
-+ * a sub-/super scription of a new SmPlaceNode will be made.
-+ *
-+ * If there's is an existing subscription of the node, the caret will be moved into it,
-+ * and any selection will replace it.
-+ */
-+ void InsertSubSup(SmSubSup eSubSup);
-+
-+ /** Create a limit on an SmOperNode
-+ *
-+ * This this method only work if the caret is inside an SmOperNode, or to the right of one.
-+ * Notice also that this method ignores any selection made.
-+ *
-+ * @param bMoveCaret If true that caret will be moved into the limit.
-+ *
-+ * @returns True, if the caret was in a context where this operation was possible.
-+ */
-+ BOOL InsertLimit(SmSubSup eSubSup, BOOL bMoveCaret = TRUE);
-+
-+ /** Insert a new row or newline
-+ *
-+ * Inserts a new row if position is in an matrix or stack command.
-+ * Otherwise a newline is inserted if we're in a toplevel line.
-+ *
-+ * @returns True, if a new row/line could be inserted.
-+ *
-+ * @remarks If the caret is placed in a subline of a command that doesn't support
-+ * this operator the method returns FALSE, and doesn't do anything.
-+ */
-+ BOOL InsertRow();
-+
-+ /** Insert a fraction, use selection as numerator */
-+ void InsertFraction();
-+
-+ /** Create brackets around current selection, or new SmPlaceNode */
-+ void InsertBrackets(SmBracketType eBracketType);
-+
-+ /** Copy the current selection */
-+ void Copy();
-+ /** Cut the current selection */
-+ void Cut(){
-+ Copy();
-+ Delete();
-+ }
-+ /** Paste the clipboard */
-+ void Paste();
-+
-+ /** Returns true if more than one node is selected
-+ *
-+ * This method is used for implementing backspace and delete.
-+ * If one of these causes a complex selection, e.g. a node with
-+ * subnodes or similar, this should not be deleted imidiately.
-+ */
-+ bool HasComplexSelection();
-+
-+ /** Finds the topmost node in a visual line
-+ *
-+ * If MoveUpIfSelected is true, this will move up to the parent line
-+ * if the parent of the current line is selected.
-+ */
-+ static SmNode* FindTopMostNodeInLine(SmNode* pSNode, bool MoveUpIfSelected = false);
-+
-+ /** Draw the caret */
-+ void Draw(OutputDevice& pDev, Point Offset);
-+
-+private:
-+ friend class SmDocShell;
-+
-+ SmCaretPosGraphEntry *anchor,
-+ *position;
-+ /** Formula tree */
-+ SmNode* pTree;
-+ /** Owner of the formula tree */
-+ SmDocShell* pDocShell;
-+ /** Graph over caret position in the current tree */
-+ SmCaretPosGraph* pGraph;
-+ /** Clipboard holder */
-+ SmNodeList* pClipboard;
-+
-+ /** Returns a node that is selected, if any could be found */
-+ SmNode* FindSelectedNode(SmNode* pNode);
-+
-+ /** Is this one of the nodes used to compose a line
-+ *
-+ * These are SmExpression, SmBinHorNode, SmUnHorNode etc.
-+ */
-+ static bool IsLineCompositionNode(SmNode* pNode);
-+
-+ /** Count number of selected nodes, excluding line composition nodes
-+ *
-+ * Note this function doesn't count line composition nodes and it
-+ * does count all subnodes as well as the owner nodes.
-+ *
-+ * Used by SmCursor::HasComplexSelection()
-+ */
-+ int CountSelectedNodes(SmNode* pNode);
-+
-+ /** Convert a visual line to a list
-+ *
-+ * Note this method will delete all the nodes that will no longer be needed.
-+ * that includes pLine!
-+ * This method also deletes SmErrorNode's as they're just meta info in the line.
-+ */
-+ static SmNodeList* LineToList(SmStructureNode* pLine, SmNodeList* pList = new SmNodeList());
-+
-+ /** Clone a visual line to a list
-+ *
-+ * Doesn't clone SmErrorNode's these are ignored, as they are context dependent metadata.
-+ */
-+ static SmNodeList* CloneLineToList(SmStructureNode* pLine,
-+ bool bOnlyIfSelected = false,
-+ SmNodeList* pList = new SmNodeList());
-+
-+ /** Build pGraph over caret positions */
-+ void BuildGraph();
-+
-+ /** Insert new nodes in the tree after position */
-+ void InsertNodes(SmNodeList* pNewNodes);
-+
-+ /** tries to set position to a specific SmCaretPos
-+ *
-+ * @returns false on failure to find the position in pGraph.
-+ */
-+ bool SetCaretPosition(SmCaretPos pos, bool moveAnchor = false);
-+
-+ /** Set selected on nodes of the tree */
-+ void AnnotateSelection();
-+
-+ /** Set the clipboard, and release current clipboard
-+ *
-+ * Call this method with NULL to reset the clipboard
-+ * @remarks: This method takes ownership of pList.
-+ */
-+ void SetClipboard(SmNodeList* pList = NULL);
-+
-+ /** Clone list of nodes (creates a deep clone) */
-+ static SmNodeList* CloneList(SmNodeList* pList);
-+
-+ /** Find an iterator pointing to the node in pLineList following aCaretPos
-+ *
-+ * If aCaretPos::pSelectedNode cannot be found it is assumed that it's infront of pLineList,
-+ * thus not an element in pLineList. In this case this method returns an iterator to the
-+ * first element in pLineList.
-+ *
-+ * If the current position is inside an SmTextNode, this node will be split in two, for this
-+ * reason you should beaware that iterators to elements in pLineList may be invalidated, and
-+ * that you should call PatchLineList() with this iterator if no action is taken.
-+ */
-+ static SmNodeList::iterator FindPositionInLineList(SmNodeList* pLineList, SmCaretPos aCaretPos);
-+
-+ /** Patch a line list after modification, merge SmTextNode, remove SmPlaceNode etc.
-+ *
-+ * @param pLineList The line list to patch
-+ * @param aIter Iterator pointing to the element that needs to be patched with it's previous.
-+ *
-+ * When the list is patched text nodes before and after aIter will be merged.
-+ * If there's an, in the context, inappropriate SmPlaceNode before or after aIter it will also be
-+ * removed.
-+ *
-+ * @returns A caret position equivalent to one selecting the node before aIter, the method returns
-+ * an invalid SmCaretPos to indicate placement infront of the line.
-+ */
-+ static SmCaretPos PatchLineList(SmNodeList* pLineList, SmNodeList::iterator aIter);
-+
-+ /** Take selected nodes from a list
-+ *
-+ * Puts the selected nodes into pSelectedNodes, or if pSelectedNodes is NULL deletes
-+ * the selected nodes.
-+ * Note: If there's a selection inside an SmTextNode this node will be split, and it
-+ * will not be merged when the selection have been taken. Use PatchLineList on the
-+ * iterator returns to fix this.
-+ *
-+ * @returns An iterator pointing to the element following the selection taken.
-+ */
-+ static SmNodeList::iterator TakeSelectedNodesFromList(SmNodeList *pLineList,
-+ SmNodeList *pSelectedNodes = NULL);
-+
-+ /** Create an instance of SmMathSymbolNode usable for brackets */
-+ static SmNode *CreateBracket(SmBracketType eBracketType, BOOL bIsLeft);
-+
-+ /** The number of times BeginEdit have been called
-+ * Used to allow nesting of BeginEdit() and EndEdit() sections
-+ */
-+ int nEditSections;
-+ /** Holds data for BeginEdit() and EndEdit() */
-+ BOOL bIsEnabledSetModifiedSmDocShell;
-+ /** Begin section where the tree will be modified */
-+ void BeginEdit();
-+ /** End section where the tree will be modified */
-+ void EndEdit();
-+ /** Request the formula is repainted */
-+ void RequestRepaint();
-+};
-+
-+/** Minimalistic recursive decent SmNodeList parser
-+ *
-+ * This parser is used to take a list of nodes that constitues a line
-+ * and parse them to a tree of SmBinHorNode, SmUnHorNode and SmExpression.
-+ *
-+ * Please note, this will not handle all kinds of nodes, only nodes that
-+ * constitues and entry in a line.
-+ *
-+ * Below is an EBNF representation of the grammar used for this parser:
-+ * \code
-+ * Expression -> Relation*
-+ * Relation -> Sum [(=|<|>|...) Sum]*
-+ * Sum -> Product [(+|-) Product]*
-+ * Product -> Factor [(*|/) Factor]*
-+ * Factor -> [+|-|-+|...]* Factor | Postfix
-+ * Postfix -> node [!]*
-+ * \endcode
-+ */
-+class SmNodeListParser{
-+public:
-+ /** Create an instance of SmNodeListParser */
-+ SmNodeListParser(){
-+ pList = NULL;
-+ }
-+ /** Parse a list of nodes to an expression
-+ *
-+ * If bDeleteErrorNodes is true, old error nodes will be deleted.
-+ */
-+ SmNode* Parse(SmNodeList* list, bool bDeleteErrorNodes = true);
-+ /** True, if the token is an operator */
-+ static BOOL IsOperator(const SmToken &token);
-+ /** True, if the token is a relation operator */
-+ static BOOL IsRelationOperator(const SmToken &token);
-+ /** True, if the token is a sum operator */
-+ static BOOL IsSumOperator(const SmToken &token);
-+ /** True, if the token is a product operator */
-+ static BOOL IsProductOperator(const SmToken &token);
-+ /** True, if the token is a unary operator */
-+ static BOOL IsUnaryOperator(const SmToken &token);
-+ /** True, if the token is a postfix operator */
-+ static BOOL IsPostfixOperator(const SmToken &token);
-+private:
-+ SmNodeList* pList;
-+ /** Get the current terminal */
-+ SmNode* Terminal(){
-+ if(pList->size() > 0)
-+ return pList->front();
-+ return NULL;
-+ }
-+ /** Move to next terminal */
-+ SmNode* Next(){
-+ pList->pop_front();
-+ return Terminal();
-+ }
-+ /** Take the current terminal */
-+ SmNode* Take(){
-+ SmNode* pRetVal = Terminal();
-+ Next();
-+ return pRetVal;
-+ }
-+ SmNode* Expression();
-+ SmNode* Relation();
-+ SmNode* Sum();
-+ SmNode* Product();
-+ SmNode* Factor();
-+ SmNode* Postfix();
-+ SmNode* Error();
-+};
-+
-+
-+#endif /* SMCURSOR_H */
-diff --git starmath/inc/document.hxx starmath/inc/document.hxx
-index 364eff2..1e7cd62 100644
---- starmath/inc/document.hxx
-+++ starmath/inc/document.hxx
-@@ -47,6 +47,7 @@ class SmNode;
- class SfxMenuBarManager;
- class SfxPrinter;
- class Printer;
-+class SmCursor;
-
- #define HINT_DATACHANGED 1004
-
-@@ -105,6 +106,7 @@ class SmDocShell : public SfxObjectShell, public SfxListener
- {
- friend class SmPrinterAccess;
- friend class SmModel;
-+ friend class SmCursor;
-
- String aText;
- SmFormat aFormat;
-@@ -122,6 +124,7 @@ class SmDocShell : public SfxObjectShell, public SfxListener
- nBottomBorder;
- USHORT nModifyCount;
- BOOL bIsFormulaArranged;
-+ SmCursor *pCursor;
-
-
-
-@@ -157,10 +160,15 @@ class SmDocShell : public SfxObjectShell, public SfxListener
- OutputDevice* GetRefDev();
-
- BOOL IsFormulaArranged() const { return bIsFormulaArranged; }
-- void SetFormulaArranged(BOOL bVal) { bIsFormulaArranged = bVal; }
-+ void SetFormulaArranged(BOOL bVal) { bIsFormulaArranged = bVal; }
-
- virtual BOOL ConvertFrom(SfxMedium &rMedium);
-
-+ /** Called whenever the formula is changed
-+ * Deletes the current cursor
-+ */
-+ void InvalidateCursor();
-+
- public:
- TYPEINFO();
- SFX_DECL_INTERFACE(SFX_INTERFACE_SMA_START+1)
-@@ -204,7 +212,7 @@ public:
- EditEngine & GetEditEngine();
- SfxItemPool & GetEditEngineItemPool();
-
-- void Draw(OutputDevice &rDev, Point &rPosition);
-+ void DrawFormula(OutputDevice &rDev, Point &rPosition, BOOL bDrawSelection = FALSE);
- Size GetSize();
-
- void Repaint();
-@@ -218,6 +226,15 @@ public:
-
- virtual void SetVisArea (const Rectangle & rVisArea);
- virtual void SetModified(BOOL bModified);
-+
-+ /** Get a cursor for modifying this document
-+ * @remarks Don't store this reference, a new cursor may be made...
-+ */
-+ SmCursor& GetCursor();
-+ /** True, if cursor have previously been requested and thus
-+ * has some sort of position.
-+ */
-+ BOOL HasCursor() { return pCursor != NULL; }
- };
-
-
-diff --git starmath/inc/edit.hxx starmath/inc/edit.hxx
-index 595564f..56bafab 100644
---- starmath/inc/edit.hxx
-+++ starmath/inc/edit.hxx
-@@ -68,15 +68,13 @@ class SmEditWindow : public Window, public DropTargetHelper
- ScrollBar *pHScrollBar,
- *pVScrollBar;
- ScrollBarBox *pScrollBox;
-- Timer aModifyTimer,
-- aCursorMoveTimer;
-+ Timer aModifyTimer;
- ESelection aOldSelection;
-
- virtual void KeyInput(const KeyEvent& rKEvt);
- virtual void Command(const CommandEvent& rCEvt);
- DECL_LINK(MenuSelectHdl, Menu *);
- DECL_LINK(ModifyTimerHdl, Timer *);
-- DECL_LINK(CursorMoveTimerHdl, Timer *);
-
- virtual void DataChanged( const DataChangedEvent& );
- virtual void Resize();
-diff --git starmath/inc/node.hxx starmath/inc/node.hxx
-index dabb503..7a19b6a 100644
---- starmath/inc/node.hxx
-+++ starmath/inc/node.hxx
-@@ -31,6 +31,24 @@
-
-
- #include <vector>
-+#include <fstream>
-+#include <iostream>
-+#include <stdio.h>
-+
-+//My special assert macro
-+//TODO: replace this with DBG_ASSERT when this patch moves to production, can be done using search/replace
-+#define j_assert(cond, msg) do{ \
-+ if(!(cond)) \
-+ { \
-+ std::cerr<<"Failed assertion: "<<msg<<", at line "; \
-+ char* f = (char*)__FILE__; \
-+ f += strlen(f); \
-+ do f--; while(*f != '/'); \
-+ do f--; while(*f != '/'); \
-+ do f--; while(*f != '/'); \
-+ fprintf(stderr, "%d in %s\n", __LINE__, f + 1); \
-+ } \
-+ } while(false)
-
- #include "parse.hxx"
- #include "types.hxx"
-@@ -41,6 +59,7 @@
- #define ATTR_BOLD 0x0001
- #define ATTR_ITALIC 0x0002
-
-+
- #define FNTSIZ_ABSOLUT 1
- #define FNTSIZ_PLUS 2
- #define FNTSIZ_MINUS 3
-@@ -59,6 +78,7 @@
-
- extern SmFormat *pActiveFormat;
-
-+class SmVisitor;
- class SmDocShell;
- class SmNode;
- class SmStructureNode;
-@@ -97,6 +117,8 @@ class SmNode : public SmRect
- nAttributes;
- BOOL bIsPhantom,
- bIsDebug;
-+
-+ BOOL bIsSelected;
- protected:
- SmNode(SmNodeType eNodeType, const SmToken &rNodeToken);
-
-@@ -160,7 +182,6 @@ public:
- #ifdef SM_RECT_DEBUG
- using SmRect::Draw;
- #endif
-- virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
-
- virtual void GetAccessibleText( String &rText ) const;
- sal_Int32 GetAccessibleIndex() const { return nAccIndex; }
-@@ -180,12 +201,126 @@ public:
-
- const SmNode * FindTokenAt(USHORT nRow, USHORT nCol) const;
- const SmNode * FindRectClosestTo(const Point &rPoint) const;
--};
-+
-+ /** Accept a visitor
-+ * Calls the method for this class on the visitor
-+ */
-+ virtual void Accept(SmVisitor* pVisitor);
-+
-+ /** True if this node is selected */
-+ BOOL IsSelected() const {return bIsSelected;}
-+ void SetSelected(BOOL Selected = true) {bIsSelected = Selected;}
-+
-+ /** The tree as dot graph for graphviz, usable for debugging
-+ * Convert the output to a image using $ dot graph.gv -Tpng > graph.png
-+ */
-+ inline void DumpAsDot(std::ostream &out, String* label = NULL) const{
-+ int id = 0;
-+ DumpAsDot(out, label, -1, id, -1);
-+ }
-
-+ /** Get the parent node of this node */
-+ SmStructureNode* GetParent(){ return aParentNode; }
-+ /** Set the parent node */
-+ void SetParent(SmStructureNode* parent){
-+ aParentNode = parent;
-+ }
-+
-+ /** Get the index of a child node
-+ *
-+ * Returns -1, if pSubNode isn't a subnode of this.
-+ */
-+ int IndexOfSubNode(SmNode* pSubNode){
-+ USHORT nSize = GetNumSubNodes();
-+ for(USHORT i = 0; i < nSize; i++)
-+ if(pSubNode == GetSubNode(i))
-+ return i;
-+ return -1;
-+ }
-+ /** Set the token for this node */
-+ void SetToken(SmToken& token){
-+ aNodeToken = token;
-+ }
-+protected:
-+ /** Sets parent on children of this node */
-+ void ClaimPaternity(){
-+ SmNode* pNode;
-+ USHORT nSize = GetNumSubNodes();
-+ for (USHORT i = 0; i < nSize; i++)
-+ if (NULL != (pNode = GetSubNode(i)))
-+ pNode->SetParent((SmStructureNode*)this); //Cast is valid if we have children
-+ }
-+private:
-+ SmStructureNode* aParentNode;
-+ void DumpAsDot(std::ostream &out, String* label, int number, int& id, int parent) const;
-+};
-
- ////////////////////////////////////////////////////////////////////////////////
-
-+/** A simple auxiliary iterator class for SmNode
-+ *
-+ * Example of iteration over children of pMyNode:
-+ * \code
-+ * //Node to iterate over:
-+ * SmNode* pMyNode = 0;// A pointer from somewhere
-+ * //The iterator:
-+ * SmNodeIterator it(pMyNode);
-+ * //The iteration:
-+ * while(it.Next()) {
-+ * it->SetSelected(true);
-+ * }
-+ * \endcode
-+ */
-+class SmNodeIterator{
-+public:
-+ SmNodeIterator(SmNode* node, bool bReverse = false){
-+ pNode = node;
-+ nSize = pNode->GetNumSubNodes();
-+ nIndex = 0;
-+ pChildNode = NULL;
-+ bIsReverse = bReverse;
-+ }
-+ /** Get the subnode or NULL if none */
-+ SmNode* Next(){
-+ while(!bIsReverse && nIndex < nSize){
-+ if(NULL != (pChildNode = pNode->GetSubNode(nIndex++)))
-+ return pChildNode;
-+ }
-+ while(bIsReverse && nSize > 0){
-+ if(NULL != (pChildNode = pNode->GetSubNode((nSize--)-1)))
-+ return pChildNode;
-+ }
-+ pChildNode = NULL;
-+ return NULL;
-+ }
-+ /** Get the current child node, NULL if none */
-+ SmNode* Current(){
-+ return pChildNode;
-+ }
-+ /** Get the current child node, NULL if none */
-+ SmNode* operator->(){
-+ return pChildNode;
-+ }
-+private:
-+ /** Current child */
-+ SmNode* pChildNode;
-+ /** Node whos children we're iterating over */
-+ SmNode* pNode;
-+ /** Size of the node */
-+ USHORT nSize;
-+ /** Current index in the node */
-+ USHORT nIndex;
-+ /** Move reverse */
-+ bool bIsReverse;
-+};
-+
-+////////////////////////////////////////////////////////////////////////////////
-
-+/** Abstract baseclass for all composite node
-+ *
-+ * Subclasses of this class can have subnodes. Nodes that doesn't derivate from
-+ * this class does not have subnodes.
-+ */
- class SmStructureNode : public SmNode
- {
- SmNodeArray aSubNodes;
-@@ -212,12 +347,29 @@ public:
- virtual SmStructureNode & operator = ( const SmStructureNode &rNode );
-
- virtual void GetAccessibleText( String &rText ) const;
-+
-+ void SetSubNode(USHORT nIndex, SmNode* pNode){
-+ int size = aSubNodes.size();
-+ if(size <= nIndex){
-+ //Resize subnodes array
-+ aSubNodes.resize(nIndex + 1);
-+ //Set new slots to NULL
-+ for(int i = size; i < nIndex+1; i++)
-+ aSubNodes[i] = NULL;
-+ }
-+ aSubNodes[nIndex] = pNode;
-+ ClaimPaternity();
-+ }
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Abstract base class for all visible node
-+ *
-+ * Nodes that doesn't derivate from this class doesn't draw anything, but their
-+ * children.
-+ */
- class SmVisibleNode : public SmNode
- {
- protected:
-@@ -252,7 +404,10 @@ public:
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Draws a rectangle
-+ *
-+ * Used for drawing the line in the OVER and OVERSTRIKE commands.
-+ */
- class SmRectangleNode : public SmGraphicNode
- {
- Size aToSize;
-@@ -270,15 +425,19 @@ public:
- #ifdef SM_RECT_DEBUG
- using SmRect::Draw;
- #endif
-- virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
-+
-
- void CreateTextFromNode(String &rText);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Polygon line node
-+ *
-+ * Used to draw the slash of the WIDESLASH command by SmBinDiagonalNode.
-+ */
- class SmPolyLineNode : public SmGraphicNode
- {
- Polygon aPoly;
-@@ -289,6 +448,8 @@ public:
- SmPolyLineNode(const SmToken &rNodeToken);
-
- long GetWidth() const { return nWidth; }
-+ Size GetToSize() const { return aToSize; }
-+ Polygon &GetPolygon() { return aPoly; }
-
- virtual void AdaptToX(const OutputDevice &rDev, ULONG nWidth);
- virtual void AdaptToY(const OutputDevice &rDev, ULONG nHeight);
-@@ -298,17 +459,29 @@ public:
- #ifdef SM_RECT_DEBUG
- using SmRect::Draw;
- #endif
-- virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
-+
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Text node
-+ *
-+ * @remarks This class also serves as baseclass for all nodes that contains text.
-+ */
- class SmTextNode : public SmVisibleNode
- {
- XubString aText;
- USHORT nFontDesc;
-+ /** Index within text where the selection starts
-+ * @remarks Only valid if SmNode::IsSelected() is true
-+ */
-+ xub_StrLen nSelectionStart;
-+ /** Index within text where the selection ends
-+ * @remarks Only valid if SmNode::IsSelected() is true
-+ */
-+ xub_StrLen nSelectionEnd;
-
- protected:
- SmTextNode(SmNodeType eNodeType, const SmToken &rNodeToken, USHORT nFontDescP)
-@@ -328,6 +501,25 @@ public:
- USHORT GetFontDesc() const { return nFontDesc; }
- void SetText(const XubString &rText) { aText = rText; }
- const XubString & GetText() const { return aText; }
-+ /** Change the text of this node, including the underlying token */
-+ void ChangeText(const XubString &rText) {
-+ aText = rText;
-+ SmToken token = GetToken();
-+ token.aText = rText;
-+ SetToken(token);
-+ }
-+ /** Index within GetText() where the selection starts
-+ * @remarks Only valid of SmNode::IsSelected() is true
-+ */
-+ xub_StrLen GetSelectionStart() const {return nSelectionStart;}
-+ /** Index within GetText() where the selection end
-+ * @remarks Only valid of SmNode::IsSelected() is true
-+ */
-+ xub_StrLen GetSelectionEnd() const {return nSelectionEnd;}
-+ /** Set the index within GetText() where the selection starts */
-+ void SetSelectionStart(xub_StrLen index) {nSelectionStart = index;}
-+ /** Set the index within GetText() where the selection end */
-+ void SetSelectionEnd(xub_StrLen index) {nSelectionEnd = index;}
-
- virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-@@ -336,15 +528,22 @@ public:
- #ifdef SM_RECT_DEBUG
- using SmRect::Draw;
- #endif
-- virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
-+
-
- virtual void GetAccessibleText( String &rText ) const;
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Special node for user defined characters
-+ *
-+ * Node used for pre- and user-defined characters from:
-+ * officecfg/registry/data/org/openoffice/Office/Math.xcu
-+ *
-+ * This is just single characters, I think.
-+ */
- class SmSpecialNode : public SmTextNode
- {
- protected:
-@@ -363,13 +562,22 @@ public:
- #ifdef SM_RECT_DEBUG
- using SmRect::Draw;
- #endif
-- virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
-+
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Glyph node for custom operators
-+ *
-+ * This node is used with commands: oper, uoper and boper.
-+ * E.g. in "A boper op B", "op" will be an instance of SmGlyphSpecialNode.
-+ * "boper" simply inteprets "op", the following token, as an binary operator.
-+ * The command "uoper" interprets the following token as unary operator.
-+ * For these commands an instance of SmGlyphSpecialNode is used for the
-+ * operator token, following the command.
-+ */
- class SmGlyphSpecialNode : public SmSpecialNode
- {
- public:
-@@ -378,12 +586,16 @@ public:
- {}
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Math symbol node
-+ *
-+ * Use for math symbols such as plus, minus and integrale in the INT command.
-+ */
- class SmMathSymbolNode : public SmSpecialNode
- {
- protected:
-@@ -404,12 +616,18 @@ public:
- virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
- void CreateTextFromNode(String &rText);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Root symbol node
-+ *
-+ * Root symbol node used by SmRootNode to create the root symbol, infront of
-+ * the line with the line above. I don't think this node should be used for
-+ * anything else.
-+ */
- class SmRootSymbolNode : public SmMathSymbolNode
- {
- ULONG nBodyWidth; // width of body (argument) of root sign
-@@ -419,19 +637,26 @@ public:
- : SmMathSymbolNode(NROOTSYMBOL, rNodeToken)
- {}
-
-+ ULONG GetBodyWidth() const {return nBodyWidth;};
- virtual void AdaptToX(const OutputDevice &rDev, ULONG nWidth);
- virtual void AdaptToY(const OutputDevice &rDev, ULONG nHeight);
-
- #ifdef SM_RECT_DEBUG
- using SmRect::Draw;
- #endif
-- virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
-+
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Place node
-+ *
-+ * Used to create the <?> command, that denotes place where something can be
-+ * written.
-+ * It is drawn as a square with a shadow.
-+ */
- class SmPlaceNode : public SmMathSymbolNode
- {
- public:
-@@ -439,15 +664,21 @@ public:
- : SmMathSymbolNode(NPLACE, rNodeToken)
- {
- }
-+ SmPlaceNode() : SmMathSymbolNode(NPLACE, SmToken(TPLACE, MS_PLACE, "<?>")) {};
-
- virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Error node, for parsing errors
-+ *
-+ * This node is used for parsing errors and draws an questionmark turned upside
-+ * down (inverted question mark).
-+ */
- class SmErrorNode : public SmMathSymbolNode
- {
- public:
-@@ -459,12 +690,19 @@ public:
-
- virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Table node
-+ *
-+ * This is the root node for the formula tree. This node is also used for the
-+ * STACK and BINOM commands. When used for root node, its
-+ * children are instances of SmLineNode, and in some obscure cases the a child
-+ * can be an instance of SmExpressionNode, mainly when errors occur.
-+ */
- class SmTableNode : public SmStructureNode
- {
- public:
-@@ -476,12 +714,17 @@ public:
- virtual SmNode * GetLeftMost();
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** A line
-+ *
-+ * Used as child of SmTableNode when the SmTableNode is the root node of the
-+ * formula tree.
-+ */
- class SmLineNode : public SmStructureNode
- {
- protected:
-@@ -496,12 +739,18 @@ public:
-
- virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Expression node
-+ *
-+ * Used whenever you have an expression such as "A OVER {B + C}", here there is
-+ * an expression node that allows "B + C" to be the denominator of the
-+ * SmBinVerNode, that the OVER command creates.
-+ */
- class SmExpressionNode : public SmLineNode
- {
- public:
-@@ -511,12 +760,16 @@ public:
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
- void CreateTextFromNode(String &rText);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Unary horizontical node
-+ *
-+ * The same as SmBinHorNode except this is for unary operators.
-+ */
- class SmUnHorNode : public SmStructureNode
- {
- public:
-@@ -527,12 +780,23 @@ public:
- }
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Root node
-+ *
-+ * Used for create square roots and other roots, example:
-+ * \f$ \sqrt[\mbox{[Argument]}]{\mbox{[Body]}} \f$.
-+ *
-+ * Children:<BR>
-+ * 0: Argument (optional)<BR>
-+ * 1: Symbol (instance of SmRootSymbolNode)<BR>
-+ * 2: Body<BR>
-+ * Where argument is optinal and may be NULL.
-+ */
- class SmRootNode : public SmStructureNode
- {
- protected:
-@@ -549,12 +813,23 @@ public:
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
- void CreateTextFromNode(String &rText);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Binary horizontial node
-+ *
-+ * This node is used for binary operators. In a formula such as "A + B".
-+ *
-+ * Children:<BR>
-+ * 0: Left operand<BR>
-+ * 1: Binary operator<BR>
-+ * 2: Right operand<BR>
-+ *
-+ * None of the children may be NULL.
-+ */
- class SmBinHorNode : public SmStructureNode
- {
- public:
-@@ -565,12 +840,24 @@ public:
- }
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Binary horizontical node
-+ *
-+ * This node is used for creating the OVER command, consider the formula:
-+ * "numerator OVER denominator", which looks like
-+ * \f$ \frac{\mbox{numerator}}{\mbox{denominator}} \f$
-+ *
-+ * Children:<BR>
-+ * 0: Numerator<BR>
-+ * 1: Line (instance of SmRectangleNode)<BR>
-+ * 2: Denominator<BR>
-+ * None of the children may be NULL.
-+ */
- class SmBinVerNode : public SmStructureNode
- {
- public:
-@@ -585,12 +872,22 @@ public:
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
- void CreateTextFromNode(String &rText);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Binary diagonal node
-+ *
-+ * Used for implementing the WIDESLASH command, example: "A WIDESLASH B".
-+ *
-+ * Children:<BR>
-+ * 0: Left operand<BR>
-+ * 1: right operand<BR>
-+ * 2: Line (instance of SmPolyLineNode).<BR>
-+ * None of the children may be NULL.
-+ */
- class SmBinDiagonalNode : public SmStructureNode
- {
- BOOL bAscending;
-@@ -605,35 +902,53 @@ public:
- void SetAscending(BOOL bVal) { bAscending = bVal; }
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
-
--// enums used to index sub-/supscripts in the 'aSubNodes' array
--// in 'SmSubSupNode'
--// See graphic for positions at char:
--//
--// CSUP
--//
--// LSUP H H RSUP
--// H H
--// HHHH
--// H H
--// LSUB H H RSUB
--//
--// CSUB
--//
-+/** Enum used to index sub-/supscripts in the 'aSubNodes' array
-+ * in 'SmSubSupNode'
-+ *
-+ * See graphic for positions at char:
-+ *
-+ * \code
-+ * CSUP
-+ *
-+ * LSUP H H RSUP
-+ * H H
-+ * HHHH
-+ * H H
-+ * LSUB H H RSUB
-+ *
-+ * CSUB
-+ * \endcode
-+ */
- enum SmSubSup
- { CSUB, CSUP, RSUB, RSUP, LSUB, LSUP
- };
-
--// numbers of entries in the above enum (that is: the number of possible
--// sub-/supscripts)
-+/** numbers of entries in the above enum (that is: the number of possible
-+ * sub-/supscripts)
-+ */
- #define SUBSUP_NUM_ENTRIES 6
-
--
-+/** Super- and subscript node
-+ *
-+ * Used for creating super- and subscripts for commands such as:
-+ * "^", "_", "lsup", "lsub", "csup" and "csub".
-+ * Example: "A^2" which looks like: \f$ A^2 \f$
-+ *
-+ * This node is also used for creating limits on SmOperNode, when
-+ * "FROM" and "TO" commands are used with "INT", "SUM" or similar.
-+ *
-+ * Children of this node can be enumerated using the SmSubSup enum.
-+ * Please note that children may be NULL, except for the body.
-+ * It is recommended that you access children using GetBody() and
-+ * GetSubSup().
-+ */
- class SmSubSupNode : public SmStructureNode
- {
- BOOL bUseLimits;
-@@ -646,7 +961,9 @@ public:
- bUseLimits = FALSE;
- }
-
-+ /** Get body (Not NULL) */
- SmNode * GetBody() { return GetSubNode(0); }
-+ /** Get body (Not NULL) */
- const SmNode * GetBody() const
- {
- return ((SmSubSupNode *) this)->GetBody();
-@@ -655,17 +972,39 @@ public:
- void SetUseLimits(BOOL bVal) { bUseLimits = bVal; }
- BOOL IsUseLimits() const { return bUseLimits; };
-
-+ /** Get super- or subscript
-+ * @remarks this method may return NULL.
-+ */
- SmNode * GetSubSup(SmSubSup eSubSup) { return GetSubNode( sal::static_int_cast< USHORT >(1 + eSubSup) ); };
-
-+ /** Set the body */
-+ void SetBody(SmNode* pBody) { SetSubNode(0, pBody); }
-+ void SetSubSup(SmSubSup eSubSup, SmNode* pScript) { SetSubNode( 1 + eSubSup, pScript); }
-+
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
- void CreateTextFromNode(String &rText);
-+ void Accept(SmVisitor* pVisitor);
-
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Node for brace construction
-+ *
-+ * Used for "lbrace [body] rbrace" and similar constructions.
-+ * Should look like \f$ \{\mbox{[body]}\} \f$
-+ *
-+ * Children:<BR>
-+ * 0: Opening brace<BR>
-+ * 1: Body (usually SmBracebodyNode)<BR>
-+ * 2: Closing brace<BR>
-+ * None of the children can be NULL.
-+ *
-+ * Note that child 1 (Body) is usually SmBracebodyNode, I don't know if it can
-+ * be an SmExpressionNode, haven't seen the case. But didn't quite read parser.cxx
-+ * enought to exclude this possibility.
-+ */
- class SmBraceNode : public SmStructureNode
- {
- public:
-@@ -677,12 +1016,21 @@ public:
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
- void CreateTextFromNode(String &rText);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Body of an SmBraceNode
-+ *
-+ * This usually only has one child an SmExpressionNode, however, it can also
-+ * have other children.
-+ * Consider the formula "lbrace [body1] mline [body2] rbrace", looks like:
-+ * \f$ \{\mbox{[body1] | [body2]}\} \f$.
-+ * In this case SmBracebodyNode will have three children, "[body1]", "|" and
-+ * [body2].
-+ */
- class SmBracebodyNode : public SmStructureNode
- {
- long nBodyHeight;
-@@ -692,6 +1040,7 @@ public:
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
- long GetBodyHeight() const { return nBodyHeight; }
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
-@@ -704,13 +1053,25 @@ inline SmBracebodyNode::SmBracebodyNode(const SmToken &rNodeToken) :
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Node for vertical brace construction
-+ *
-+ * Used to implement commands "[body] underbrace [script]" and
-+ * "[body] overbrace [script]".
-+ * Underbrace should look like this \f$ \underbrace{\mbox{body}}_{\mbox{script}}\f$.
-+ *
-+ * Children:<BR>
-+ * 0: body<BR>
-+ * 1: brace<BR>
-+ * 2: script<BR>
-+ * (None of these children are optional, e.g. they must all be not NULL).
-+ */
- class SmVerticalBraceNode : public SmStructureNode
- {
- public:
- inline SmVerticalBraceNode(const SmToken &rNodeToken);
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
-@@ -724,6 +1085,18 @@ inline SmVerticalBraceNode::SmVerticalBraceNode(const SmToken &rNodeToken) :
- ////////////////////////////////////////////////////////////////////////////////
-
-
-+/** Operation Node
-+ *
-+ * Used for commands like SUM, INT and similar.
-+ *
-+ * Children:<BR>
-+ * 0: Operation (instance of SmMathSymbolNode)<BR>
-+ * 1: Body<BR>
-+ * None of the children may be NULL.
-+ *
-+ * If there are boundaries on the operation the body will an instance of
-+ * SmSubSupNode.
-+ */
- class SmOperNode : public SmStructureNode
- {
- public:
-@@ -742,12 +1115,14 @@ public:
- long CalcSymbolHeight(const SmNode &rSymbol, const SmFormat &rFormat) const;
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Node used for alignment
-+ */
- class SmAlignNode : public SmStructureNode
- {
- public:
-@@ -756,12 +1131,22 @@ public:
- {}
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Attribute node
-+ *
-+ * Used to give an attribute to another node. Used for commands such as:
-+ * UNDERLINE, OVERLINE, OVERSTRIKE, WIDEVEC, WIDEHAT and WIDETILDE.
-+ *
-+ * Children:<BR>
-+ * 0: Attribute<BR>
-+ * 1: Body<BR>
-+ * None of these may be NULL.
-+ */
- class SmAttributNode : public SmStructureNode
- {
- public:
-@@ -771,12 +1156,16 @@ public:
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
- void CreateTextFromNode(String &rText);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Font node
-+ *
-+ * Used to change the font of it's children.
-+ */
- class SmFontNode : public SmStructureNode
- {
- USHORT nSizeType;
-@@ -797,12 +1186,17 @@ public:
- virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
- void CreateTextFromNode(String &rText);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Matrix node
-+ *
-+ * Used to implement the MATRIX command, example:
-+ * "matrix{ 1 # 2 ## 3 # 4}".
-+ */
- class SmMatrixNode : public SmStructureNode
- {
- USHORT nNumRows,
-@@ -824,12 +1218,16 @@ public:
-
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
- void CreateTextFromNode(String &rText);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
- ////////////////////////////////////////////////////////////////////////////////
-
--
-+/** Node for whitespace
-+ *
-+ * Used to implement the "~" command. This node is just a blank space.
-+ */
- class SmBlankNode : public SmGraphicNode
- {
- USHORT nNum;
-@@ -843,9 +1241,12 @@ public:
-
- void IncreaseBy(const SmToken &rToken);
- void Clear() { nNum = 0; }
-+ USHORT GetBlankNum() const { return nNum; }
-+ void SetBlankNum(USHORT nNumber) { nNum = nNumber; }
-
- virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
- virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
-+ void Accept(SmVisitor* pVisitor);
- };
-
-
-diff --git starmath/inc/parse.hxx starmath/inc/parse.hxx
-index 0211d97..97a7413 100644
---- starmath/inc/parse.hxx
-+++ starmath/inc/parse.hxx
-@@ -117,7 +117,7 @@ struct SmToken
- String aText;
- // token info
- SmTokenType eType;
-- sal_Unicode cMathChar;
-+ sal_Unicode cMathChar;
- // parse-help info
- ULONG nGroup;
- USHORT nLevel;
-@@ -126,6 +126,11 @@ struct SmToken
- xub_StrLen nCol;
-
- SmToken();
-+ SmToken(SmTokenType eTokenType,
-+ sal_Unicode cMath,
-+ const sal_Char* pText,
-+ ULONG nTokenGroup = 0,
-+ USHORT nTokenLevel = 0);
- };
-
-
-@@ -239,7 +244,10 @@ protected:
- public:
- SmParser();
-
-+ /** Parse rBuffer to formula tree */
- SmNode *Parse(const String &rBuffer);
-+ /** Parse rBuffer to formula subtree that constitutes an expression */
-+ SmNode *ParseExpression(const String &rBuffer);
-
- const String & GetText() const { return BufferString; };
-
-diff --git starmath/inc/starmath.hrc starmath/inc/starmath.hrc
-index 0f9aec4..cb3cbe5 100644
---- starmath/inc/starmath.hrc
-+++ starmath/inc/starmath.hrc
-@@ -62,7 +62,9 @@
- #define SID_TEXT (SID_SMA_START + 100)
- #define SID_GAPHIC_SM (SID_SMA_START + 101)
- #define SID_FITINWINDOW (SID_SMA_START + 103)
--#define SID_INSERTTEXT (SID_SMA_START + 104)
-+/** Command for inserting a symbol specified by a string (Inserts an SmSpecialNode) */
-+#define SID_INSERTSYMBOL (SID_SMA_START + 104)
-+/** Command for inserting a math construction specified in commands.src */
- #define SID_INSERTCOMMAND (SID_SMA_START + 105)
-
- #define SID_LOADSYMBOLS (SID_SMA_START + 107)
-diff --git starmath/inc/view.hxx starmath/inc/view.hxx
-index eab2444..45d3990 100644
---- starmath/inc/view.hxx
-+++ starmath/inc/view.hxx
-@@ -50,7 +50,6 @@ class SmViewShell;
- class SmGraphicWindow : public ScrollableWindow
- {
- Point aFormulaDrawPos;
-- Rectangle aCursorRect;
-
- ::com::sun::star::uno::Reference<
- ::com::sun::star::accessibility::XAccessible > xAccessible;
-@@ -59,14 +58,9 @@ class SmGraphicWindow : public ScrollableWindow
- SmViewShell *pViewShell;
- USHORT nZoom;
- short nModifyCount;
-- BOOL bIsCursorVisible;
-
- protected:
- void SetFormulaDrawPos(const Point &rPos) { aFormulaDrawPos = rPos; }
-- void SetIsCursorVisible(BOOL bVis) { bIsCursorVisible = bVis; }
-- using Window::SetCursor;
-- void SetCursor(const SmNode *pNode);
-- void SetCursor(const Rectangle &rRect);
-
- virtual void DataChanged( const DataChangedEvent& );
- virtual void Paint(const Rectangle&);
-@@ -97,10 +91,6 @@ public:
- using ScrollableWindow::SetTotalSize;
- void SetTotalSize();
-
-- BOOL IsCursorVisible() const { return bIsCursorVisible; }
-- void ShowCursor(BOOL bShow);
-- const SmNode * SetCursorPos(USHORT nRow, USHORT nCol);
--
- void ApplyColorConfigValues( const svtools::ColorConfig &rColorCfg );
-
- // for Accessibility
-@@ -228,6 +218,11 @@ class SmViewShell: public SfxViewShell
- DECL_LINK( DialogClosedHdl, sfx2::FileDialogHelper* );
- virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
-
-+ /** Used to determine whether insertions using SID_INSERTSYMBOL and SID_INSERTCOMMAND
-+ * should be inserted into SmEditWindow or directly into the SmDocShell as done if the
-+ * visual editor was last to have focus.
-+ */
-+ BOOL bInsertIntoEditWindow;
- protected:
-
- Size GetTextLineSize(OutputDevice& rDevice,
-@@ -291,6 +286,16 @@ public:
-
- void Impl_Print( OutputDevice &rOutDev, const SmPrintSize ePrintSize,
- Rectangle aOutRect, Point aZeroPoint );
-+
-+ /** Set bInsertIntoEditWindow so we know where to insert
-+ *
-+ * This method is called whenever SmGraphicWindow or SmEditWindow gets focus,
-+ * so that when text is inserted from catalog or elsewhere we know whether to
-+ * insert for the visual editor, or the text editor.
-+ */
-+ void SetInsertIntoEditWindow(BOOL bEditWindowHadFocusLast = TRUE){
-+ bInsertIntoEditWindow = bEditWindowHadFocusLast;
-+ }
- };
-
- #endif
-diff --git starmath/inc/visitors.hxx starmath/inc/visitors.hxx
-new file mode 100644
-index 0000000..5a61dd0
---- /dev/null
-+++ starmath/inc/visitors.hxx
-@@ -0,0 +1,471 @@
-+#ifndef SMVISITORS_H
-+#define SMVISITORS_H
-+
-+#include "node.hxx"
-+#include "caret.hxx"
-+
-+/** Base class for visitors that visits a tree of SmNodes
-+ * @remarks all methods have been left abstract to ensure that implementers
-+ * don't forget to implement one.
-+ */
-+class SmVisitor
-+{
-+public:
-+ virtual void Visit( SmTableNode* pNode ) = 0;
-+ virtual void Visit( SmBraceNode* pNode ) = 0;
-+ virtual void Visit( SmBracebodyNode* pNode ) = 0;
-+ virtual void Visit( SmOperNode* pNode ) = 0;
-+ virtual void Visit( SmAlignNode* pNode ) = 0;
-+ virtual void Visit( SmAttributNode* pNode ) = 0;
-+ virtual void Visit( SmFontNode* pNode ) = 0;
-+ virtual void Visit( SmUnHorNode* pNode ) = 0;
-+ virtual void Visit( SmBinHorNode* pNode ) = 0;
-+ virtual void Visit( SmBinVerNode* pNode ) = 0;
-+ virtual void Visit( SmBinDiagonalNode* pNode ) = 0;
-+ virtual void Visit( SmSubSupNode* pNode ) = 0;
-+ virtual void Visit( SmMatrixNode* pNode ) = 0;
-+ virtual void Visit( SmPlaceNode* pNode ) = 0;
-+ virtual void Visit( SmTextNode* pNode ) = 0;
-+ virtual void Visit( SmSpecialNode* pNode ) = 0;
-+ virtual void Visit( SmGlyphSpecialNode* pNode ) = 0;
-+ virtual void Visit( SmMathSymbolNode* pNode ) = 0;
-+ virtual void Visit( SmBlankNode* pNode ) = 0;
-+ virtual void Visit( SmErrorNode* pNode ) = 0;
-+ virtual void Visit( SmLineNode* pNode ) = 0;
-+ virtual void Visit( SmExpressionNode* pNode ) = 0;
-+ virtual void Visit( SmPolyLineNode* pNode ) = 0;
-+ virtual void Visit( SmRootNode* pNode ) = 0;
-+ virtual void Visit( SmRootSymbolNode* pNode ) = 0;
-+ virtual void Visit( SmRectangleNode* pNode ) = 0;
-+ virtual void Visit( SmVerticalBraceNode* pNode ) = 0;
-+};
-+
-+/** Simple visitor for testing SmVisitor */
-+class SmVisitorTest : public SmVisitor
-+{
-+public:
-+ void Visit( SmTableNode* pNode );
-+ void Visit( SmBraceNode* pNode );
-+ void Visit( SmBracebodyNode* pNode );
-+ void Visit( SmOperNode* pNode );
-+ void Visit( SmAlignNode* pNode );
-+ void Visit( SmAttributNode* pNode );
-+ void Visit( SmFontNode* pNode );
-+ void Visit( SmUnHorNode* pNode );
-+ void Visit( SmBinHorNode* pNode );
-+ void Visit( SmBinVerNode* pNode );
-+ void Visit( SmBinDiagonalNode* pNode );
-+ void Visit( SmSubSupNode* pNode );
-+ void Visit( SmMatrixNode* pNode );
-+ void Visit( SmPlaceNode* pNode );
-+ void Visit( SmTextNode* pNode );
-+ void Visit( SmSpecialNode* pNode );
-+ void Visit( SmGlyphSpecialNode* pNode );
-+ void Visit( SmMathSymbolNode* pNode );
-+ void Visit( SmBlankNode* pNode );
-+ void Visit( SmErrorNode* pNode );
-+ void Visit( SmLineNode* pNode );
-+ void Visit( SmExpressionNode* pNode );
-+ void Visit( SmPolyLineNode* pNode );
-+ void Visit( SmRootNode* pNode );
-+ void Visit( SmRootSymbolNode* pNode );
-+ void Visit( SmRectangleNode* pNode );
-+ void Visit( SmVerticalBraceNode* pNode );
-+private:
-+ /** Auxiliary method for visiting the children of a pNode */
-+ void VisitChildren( SmNode* pNode );
-+};
-+
-+/////////////////////////////// SmDefaultingVisitor ////////////////////////////////
-+
-+
-+/** Visitor that uses DefaultVisit for handling visits by default
-+ *
-+ * This abstract baseclass is useful for visitors where many methods share the same
-+ * implementation.
-+ */
-+class SmDefaultingVisitor : public SmVisitor
-+{
-+public:
-+ void Visit( SmTableNode* pNode );
-+ void Visit( SmBraceNode* pNode );
-+ void Visit( SmBracebodyNode* pNode );
-+ void Visit( SmOperNode* pNode );
-+ void Visit( SmAlignNode* pNode );
-+ void Visit( SmAttributNode* pNode );
-+ void Visit( SmFontNode* pNode );
-+ void Visit( SmUnHorNode* pNode );
-+ void Visit( SmBinHorNode* pNode );
-+ void Visit( SmBinVerNode* pNode );
-+ void Visit( SmBinDiagonalNode* pNode );
-+ void Visit( SmSubSupNode* pNode );
-+ void Visit( SmMatrixNode* pNode );
-+ void Visit( SmPlaceNode* pNode );
-+ void Visit( SmTextNode* pNode );
-+ void Visit( SmSpecialNode* pNode );
-+ void Visit( SmGlyphSpecialNode* pNode );
-+ void Visit( SmMathSymbolNode* pNode );
-+ void Visit( SmBlankNode* pNode );
-+ void Visit( SmErrorNode* pNode );
-+ void Visit( SmLineNode* pNode );
-+ void Visit( SmExpressionNode* pNode );
-+ void Visit( SmPolyLineNode* pNode );
-+ void Visit( SmRootNode* pNode );
-+ void Visit( SmRootSymbolNode* pNode );
-+ void Visit( SmRectangleNode* pNode );
-+ void Visit( SmVerticalBraceNode* pNode );
-+protected:
-+ /** Method invoked by Visit methods by default */
-+ virtual void DefaultVisit( SmNode* pNode ) = 0;
-+};
-+
-+/////////////////////////////// SmCaretDrawingVisitor ////////////////////////////////
-+
-+/** Visitor for drawing a caret position */
-+class SmCaretDrawingVisitor : public SmDefaultingVisitor
-+{
-+public:
-+ /** Given position and device this constructor will draw the caret */
-+ SmCaretDrawingVisitor( OutputDevice& rDevice, SmCaretPos position, Point offset );
-+ void Visit( SmTextNode* pNode );
-+private:
-+ OutputDevice &rDev;
-+ SmCaretPos pos;
-+ /** Offset to draw from */
-+ Point Offset;
-+protected:
-+ /** Default method for drawing pNodes */
-+ void DefaultVisit( SmNode* pNode );
-+};
-+
-+/////////////////////////////// SmCaretPos2LineVisitor ////////////////////////////////
-+
-+/** Visitor getting a line from a caret position */
-+class SmCaretPos2LineVisitor : public SmDefaultingVisitor
-+{
-+public:
-+ /** Given position and device this constructor will compute a line for the caret */
-+ SmCaretPos2LineVisitor( OutputDevice *pDevice, SmCaretPos position ) {
-+ pDev = pDevice;
-+ pos = position;
-+ j_assert( position.IsValid( ), "Cannot draw invalid position!" );
-+
-+ pos.pSelectedNode->Accept( this );
-+ }
-+ void Visit( SmTextNode* pNode );
-+ SmCaretLine GetResult( ){
-+ return line;
-+ }
-+private:
-+ SmCaretLine line;
-+ OutputDevice *pDev;
-+ SmCaretPos pos;
-+protected:
-+ /** Default method for computing lines for pNodes */
-+ void DefaultVisit( SmNode* pNode );
-+};
-+
-+/////////////////////////////// DrawingVisitor ////////////////////////////////
-+
-+/** Visitor for drawing SmNodes to OutputDevice */
-+class DrawingVisitor : public SmVisitor
-+{
-+public:
-+ /** Create an instance of DrawingVisitor, and use it to draw a formula
-+ * @param rDevice Device to draw on
-+ * @param position Offset on device to draw the formula
-+ * @param pTree Formula tree to draw
-+ * @remarks This constructor will do the drawing, no need to anything more.
-+ */
-+ DrawingVisitor( OutputDevice &rDevice, Point position, SmNode* pTree )
-+ : rDev( rDevice ) {
-+ this->Position = position;
-+ pTree->Accept( this );
-+ }
-+ void Visit( SmTableNode* pNode );
-+ void Visit( SmBraceNode* pNode );
-+ void Visit( SmBracebodyNode* pNode );
-+ void Visit( SmOperNode* pNode );
-+ void Visit( SmAlignNode* pNode );
-+ void Visit( SmAttributNode* pNode );
-+ void Visit( SmFontNode* pNode );
-+ void Visit( SmUnHorNode* pNode );
-+ void Visit( SmBinHorNode* pNode );
-+ void Visit( SmBinVerNode* pNode );
-+ void Visit( SmBinDiagonalNode* pNode );
-+ void Visit( SmSubSupNode* pNode );
-+ void Visit( SmMatrixNode* pNode );
-+ void Visit( SmPlaceNode* pNode );
-+ void Visit( SmTextNode* pNode );
-+ void Visit( SmSpecialNode* pNode );
-+ void Visit( SmGlyphSpecialNode* pNode );
-+ void Visit( SmMathSymbolNode* pNode );
-+ void Visit( SmBlankNode* pNode );
-+ void Visit( SmErrorNode* pNode );
-+ void Visit( SmLineNode* pNode );
-+ void Visit( SmExpressionNode* pNode );
-+ void Visit( SmPolyLineNode* pNode );
-+ void Visit( SmRootNode* pNode );
-+ void Visit( SmRootSymbolNode* pNode );
-+ void Visit( SmRectangleNode* pNode );
-+ void Visit( SmVerticalBraceNode* pNode );
-+private:
-+ /** Draw the children of a pNode
-+ * This the default method, use by most pNodes
-+ */
-+ void DrawChildren( SmNode* pNode );
-+
-+ /** Draw an SmTextNode or a subclass of this */
-+ void DrawTextNode( SmTextNode* pNode );
-+ /** Draw an SmSpecialNode or a subclass of this */
-+ void DrawSpecialNode( SmSpecialNode* pNode );
-+ /** OutputDevice to draw on */
-+ OutputDevice& rDev;
-+ /** Position to draw on the rDev
-+ * @remarks This variable is used to pass parameters in DrawChildren( ), this means
-+ that after a call to DrawChildren( ) the contents of this method is undefined
-+ so if needed cache it locally on the stack.
-+ */
-+ Point Position;
-+};
-+
-+/////////////////////////////// SetSelectionVisitor ////////////////////////////////
-+
-+/** Set Selection Visitor
-+ * Sets the IsSelected( ) property on all SmNodes of the tree
-+ */
-+class SetSelectionVisitor : public SmDefaultingVisitor
-+{
-+public:
-+ SetSelectionVisitor( SmCaretPos startPos,
-+ SmCaretPos endPos ){
-+ StartPos = startPos;
-+ EndPos = endPos;
-+ IsSelecting = false;
-+ }
-+ void Visit( SmBinHorNode* pNode );
-+ void Visit( SmUnHorNode* pNode );
-+ void Visit( SmFontNode* pNode );
-+ void Visit( SmTextNode* pNode );
-+ void Visit( SmExpressionNode* pNode );
-+ void Visit( SmBracebodyNode* pNode );
-+ void Visit( SmAlignNode* pNode );
-+ /** Set IsSelected on all pNodes of pSubTree */
-+ static void SetSelectedOnAll( SmNode* pSubTree, bool IsSelected = true );
-+private:
-+ /** Visit a selectable pNode
-+ * Can be used to handle pNodes that can be selected, that doesn't have more SmCaretPos'
-+ * than 0 and 1 inside them. SmTextNode should be handle seperately!
-+ * Also note that pNodes such as SmBinVerNode cannot be selected, don't this method for
-+ * it.
-+ */
-+ void DefaultVisit( SmNode* pNode );
-+ void VisitCompositionNode( SmNode* pNode );
-+ /** Caret position where the selection starts */
-+ SmCaretPos StartPos;
-+ /** Caret position where the selection ends */
-+ SmCaretPos EndPos;
-+ /** The current state of this visitor
-+ * This property changes when the visitor meets either StartPos
-+ * or EndPos. This means that anything visited in between will be
-+ * selected.
-+ */
-+ BOOL IsSelecting;
-+};
-+
-+
-+/////////////////////////////// SmCaretPosGraphBuildingVisitor ////////////////////////////////
-+
-+
-+/** A visitor for building a SmCaretPosGraph */
-+class SmCaretPosGraphBuildingVisitor : public SmVisitor
-+{
-+public:
-+ SmCaretPosGraphBuildingVisitor( ){
-+ pRightMost = NULL;
-+ pGraph = new SmCaretPosGraph( );
-+ }
-+ /* Visit invariant:
-+ * Each pNode, except SmExpressionNode, SmBinHorNode and a few others, constitues an entry
-+ * in a line. Consider the line entry "H", this entry creates one carat position, here
-+ * denoted by | in "H|".
-+ *
-+ * Parameter variables:
-+ * The following variables are used to transfer parameters in to calls and results out
-+ * of calls.
-+ * pRightMost : SmCaretPosGraphEntry*
-+ *
-+ * Prior to a Visit call:
-+ * pRightMost: A pointer to right most position infront of the current line entry.
-+ *
-+ * After a Visit call:
-+ * pRightMost: A pointer to the right most position in the called line entry, if no there's
-+ * no caret positions in called line entry don't change this variable.
-+ */
-+ void Visit( SmTableNode* pNode );
-+ void Visit( SmBraceNode* pNode );
-+ void Visit( SmBracebodyNode* pNode );
-+ void Visit( SmOperNode* pNode );
-+ void Visit( SmAlignNode* pNode );
-+ void Visit( SmAttributNode* pNode );
-+ void Visit( SmFontNode* pNode );
-+ void Visit( SmUnHorNode* pNode );
-+ void Visit( SmBinHorNode* pNode );
-+ void Visit( SmBinVerNode* pNode );
-+ void Visit( SmBinDiagonalNode* pNode );
-+ void Visit( SmSubSupNode* pNode );
-+ void Visit( SmMatrixNode* pNode );
-+ void Visit( SmPlaceNode* pNode );
-+ void Visit( SmTextNode* pNode );
-+ void Visit( SmSpecialNode* pNode );
-+ void Visit( SmGlyphSpecialNode* pNode );
-+ void Visit( SmMathSymbolNode* pNode );
-+ void Visit( SmBlankNode* pNode );
-+ void Visit( SmErrorNode* pNode );
-+ void Visit( SmLineNode* pNode );
-+ void Visit( SmExpressionNode* pNode );
-+ void Visit( SmPolyLineNode* pNode );
-+ void Visit( SmRootNode* pNode );
-+ void Visit( SmRootSymbolNode* pNode );
-+ void Visit( SmRectangleNode* pNode );
-+ void Visit( SmVerticalBraceNode* pNode );
-+ SmCaretPosGraph* Graph( ){
-+ return pGraph;
-+ }
-+private:
-+ SmCaretPosGraphEntry* pRightMost;
-+ SmCaretPosGraph* pGraph;
-+};
-+
-+/////////////////////////////// SmCloningVisitor ///////////////////////////////
-+
-+/** Visitor for cloning a pNode
-+ *
-+ * This visitor creates deep clones.
-+ */
-+class SmCloningVisitor : public SmVisitor
-+{
-+public:
-+ SmCloningVisitor( ){ pResult = NULL; }
-+ void Visit( SmTableNode* pNode );
-+ void Visit( SmBraceNode* pNode );
-+ void Visit( SmBracebodyNode* pNode );
-+ void Visit( SmOperNode* pNode );
-+ void Visit( SmAlignNode* pNode );
-+ void Visit( SmAttributNode* pNode );
-+ void Visit( SmFontNode* pNode );
-+ void Visit( SmUnHorNode* pNode );
-+ void Visit( SmBinHorNode* pNode );
-+ void Visit( SmBinVerNode* pNode );
-+ void Visit( SmBinDiagonalNode* pNode );
-+ void Visit( SmSubSupNode* pNode );
-+ void Visit( SmMatrixNode* pNode );
-+ void Visit( SmPlaceNode* pNode );
-+ void Visit( SmTextNode* pNode );
-+ void Visit( SmSpecialNode* pNode );
-+ void Visit( SmGlyphSpecialNode* pNode );
-+ void Visit( SmMathSymbolNode* pNode );
-+ void Visit( SmBlankNode* pNode );
-+ void Visit( SmErrorNode* pNode );
-+ void Visit( SmLineNode* pNode );
-+ void Visit( SmExpressionNode* pNode );
-+ void Visit( SmPolyLineNode* pNode );
-+ void Visit( SmRootNode* pNode );
-+ void Visit( SmRootSymbolNode* pNode );
-+ void Visit( SmRectangleNode* pNode );
-+ void Visit( SmVerticalBraceNode* pNode );
-+ /** Clone a pNode */
-+ SmNode* Clone( SmNode* pNode );
-+private:
-+ SmNode* pResult;
-+ /** Clone children of pSource and give them to pTarget */
-+ void CloneKids( SmStructureNode* pSource, SmStructureNode* pTarget );
-+ /** Clone attributes on a pNode */
-+ void CloneNodeAttr( SmNode* pSource, SmNode* pTarget );
-+};
-+
-+
-+/////////////////////////////// SmSelectionDrawingVisitor ///////////////////////////////
-+
-+class SmSelectionDrawingVisitor : public SmDefaultingVisitor
-+{
-+public:
-+ /** Draws a selection on rDevice for the selection on pTree */
-+ SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, Point Offset );
-+ void Visit( SmTextNode* pNode );
-+private:
-+ /** Reference to drawing device */
-+ OutputDevice& rDev;
-+ /** True if aSelectionArea have been initialized */
-+ BOOL bHasSelectionArea;
-+ /** The current area that is selected */
-+ Rectangle aSelectionArea;
-+ /** Extend the area that must be selected */
-+ void ExtendSelectionArea( Rectangle aArea );
-+ /** Default visiting method */
-+ void DefaultVisit( SmNode* pNode );
-+ /** Visit the children of a given pNode */
-+ void VisitChildren( SmNode* pNode );
-+};
-+
-+/////////////////////////////// SmNodeToTextVisitor ///////////////////////////////
-+
-+/** Extract command text from pNodes */
-+class SmNodeToTextVisitor : public SmVisitor
-+{
-+public:
-+ SmNodeToTextVisitor( SmNode* pNode, String &rText )
-+ : rCmdText( rText ) {
-+ pNode->Accept( this );
-+ }
-+ void Visit( SmTableNode* pNode );
-+ void Visit( SmBraceNode* pNode );
-+ void Visit( SmBracebodyNode* pNode );
-+ void Visit( SmOperNode* pNode );
-+ void Visit( SmAlignNode* pNode );
-+ void Visit( SmAttributNode* pNode );
-+ void Visit( SmFontNode* pNode );
-+ void Visit( SmUnHorNode* pNode );
-+ void Visit( SmBinHorNode* pNode );
-+ void Visit( SmBinVerNode* pNode );
-+ void Visit( SmBinDiagonalNode* pNode );
-+ void Visit( SmSubSupNode* pNode );
-+ void Visit( SmMatrixNode* pNode );
-+ void Visit( SmPlaceNode* pNode );
-+ void Visit( SmTextNode* pNode );
-+ void Visit( SmSpecialNode* pNode );
-+ void Visit( SmGlyphSpecialNode* pNode );
-+ void Visit( SmMathSymbolNode* pNode );
-+ void Visit( SmBlankNode* pNode );
-+ void Visit( SmErrorNode* pNode );
-+ void Visit( SmLineNode* pNode );
-+ void Visit( SmExpressionNode* pNode );
-+ void Visit( SmPolyLineNode* pNode );
-+ void Visit( SmRootNode* pNode );
-+ void Visit( SmRootSymbolNode* pNode );
-+ void Visit( SmRectangleNode* pNode );
-+ void Visit( SmVerticalBraceNode* pNode );
-+private:
-+ /** Extract text from a pNode that constitues a line */
-+ void LineToText( SmNode* pNode ) {
-+ Separate( );
-+ if( pNode )
-+ pNode->Accept( this );
-+ Separate( );
-+ }
-+ inline void Append( const sal_Char* pCharStr ) {
-+ rCmdText.AppendAscii( pCharStr );
-+ }
-+ inline void Append( const String &rText ) {
-+ rCmdText.Append( rText );
-+ }
-+ /** Append a blank for separation, if needed */
-+ inline void Separate( ){
-+ if( rCmdText.GetChar( rCmdText.Len( ) - 1 ) != ' ' )
-+ rCmdText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " " ) );
-+ }
-+ /** Output text generated from the pNodes */
-+ String &rCmdText;
-+};
-+
-+#endif /* SMVISITORS_H */
-diff --git starmath/sdi/smath.sdi starmath/sdi/smath.sdi
-index a8fb305..8682f08 100644
---- starmath/sdi/smath.sdi
-+++ starmath/sdi/smath.sdi
-@@ -378,7 +378,7 @@ SfxVoidItem InsertCommand SID_INSERTCOMMAND
- ]
-
- //--------------------------------------------------------------------------
--SfxVoidItem InsertConfigName SID_INSERTTEXT
-+SfxVoidItem InsertConfigName SID_INSERTSYMBOL
- ()
- [
- /* flags: */
-diff --git starmath/sdi/smslots.sdi starmath/sdi/smslots.sdi
-index b8494c6..518b8b1 100644
---- starmath/sdi/smslots.sdi
-+++ starmath/sdi/smslots.sdi
-@@ -267,17 +267,17 @@ interface FormulaView : View
- StateMethod = GetState ;
- ]
- //idlpp kein Menueeintrag , also keine Texte
-- SID_INSERTTEXT //idlpp ole : no , status : no
-+ SID_INSERTSYMBOL //idlpp ole : no , status : no
- [
- ExecMethod = Execute ;
- StateMethod = GetState ;
- ]
-- SID_INSERT_FORMULA //idlpp ole : no , status : no
-- [
-- ExecMethod = Execute ;
-- StateMethod = GetState ;
-- Export = FALSE ;
-- ]
-+ SID_INSERT_FORMULA //idlpp ole : no , status : no
-+ [
-+ ExecMethod = Execute ;
-+ StateMethod = GetState ;
-+ Export = FALSE ;
-+ ]
- //idlpp kein Menueeintrag , also keine Texte
- SID_ATTR_ZOOM //idlpp ole : no , status : no
- [
-diff --git starmath/source/caret.cxx starmath/source/caret.cxx
-new file mode 100644
-index 0000000..bb312ef
---- /dev/null
-+++ starmath/source/caret.cxx
-@@ -0,0 +1,35 @@
-+#include "caret.hxx"
-+
-+/////////////////////////////// SmCaretPosGraph ////////////////////////////////
-+
-+SmCaretPosGraphEntry* SmCaretPosGraphIterator::Next(){
-+ if(nOffset >= pGraph->nOffset){
-+ if(pGraph->pNext){
-+ pGraph = pGraph->pNext;
-+ nOffset = 0;
-+ pEntry = Next();
-+ }else
-+ pEntry = NULL;
-+ }else
-+ pEntry = pGraph->Graph + nOffset++;
-+ return pEntry;
-+}
-+
-+SmCaretPosGraphEntry* SmCaretPosGraph::Add(SmCaretPosGraphEntry entry){
-+ if(nOffset >= SmCaretPosGraphSize){
-+ if(!pNext)
-+ pNext = new SmCaretPosGraph();
-+ return pNext->Add(entry);
-+ }else{
-+ Graph[nOffset] = entry;
-+ return Graph + nOffset++;
-+ }
-+}
-+
-+SmCaretPosGraph::~SmCaretPosGraph(){
-+ if(pNext)
-+ delete pNext;
-+ pNext = NULL;
-+}
-+
-+
-diff --git starmath/source/cursor.cxx starmath/source/cursor.cxx
-new file mode 100644
-index 0000000..3c3cba6
---- /dev/null
-+++ starmath/source/cursor.cxx
-@@ -0,0 +1,1615 @@
-+#include "cursor.hxx"
-+#include "parse.hxx"
-+#include "visitors.hxx"
-+#include "document.hxx"
-+#include "view.hxx"
-+
-+void SmCursor::Move(OutputDevice* pDev, SmMovementDirection direction, bool bMoveAnchor){
-+ SmCaretPosGraphEntry* NewPos = NULL;
-+ switch(direction){
-+ case MoveLeft:
-+ {
-+ //If position->Left is NULL, we want NewPos = NULL anyway...
-+ NewPos = position->Left;
-+ }break;
-+ case MoveRight:
-+ {
-+ //If position->Right is NULL, we want NewPos = NULL anyway...
-+ NewPos = position->Right;
-+ }break;
-+ case MoveUp:
-+ //Implementation is practically identical to MoveDown, except for a single if statement
-+ //so I've implemented them together and added a direction == MoveDown to the if statements.
-+ case MoveDown:
-+ {
-+ SmCaretLine from_line = SmCaretPos2LineVisitor(pDev, position->CaretPos).GetResult(),
-+ best_line, //Best approximated line found so far
-+ curr_line; //Current line
-+ long dbp_sq; //Distance squared to best line
-+ SmCaretPosGraphIterator it = pGraph->GetIterator();
-+ while(it.Next()){
-+ //Reject it if it's the current position
-+ if(it->CaretPos == position->CaretPos) continue;
-+ //Compute caret line
-+ curr_line = SmCaretPos2LineVisitor(pDev, it->CaretPos).GetResult();
-+ //Reject anything above if we're moving down
-+ if(curr_line.GetTop() <= from_line.GetTop() && direction == MoveDown) continue;
-+ //Reject anything below if we're moving up
-+ if(curr_line.GetTop() + curr_line.GetHeight() >= from_line.GetTop() + from_line.GetHeight()
-+ && direction == MoveUp) continue;
-+ //Compare if it to what we have, if we have anything yet
-+ if(NewPos){
-+ //Compute distance to current line squared, multiplied with a horizontial factor
-+ long dp_sq = curr_line.SquaredDistanceX(from_line) * HORIZONTICAL_DISTANCE_FACTOR +
-+ curr_line.SquaredDistanceY(from_line);
-+ //Discard current line if best line is closer
-+ if(dbp_sq <= dp_sq) continue;
-+ }
-+ //Take current line as the best
-+ best_line = curr_line;
-+ NewPos = it.Current();
-+ //Update distance to best line
-+ dbp_sq = best_line.SquaredDistanceX(from_line) * HORIZONTICAL_DISTANCE_FACTOR +
-+ best_line.SquaredDistanceY(from_line);
-+ }
-+ }break;
-+ default:
-+ j_assert(false, "Movement direction not supported!");
-+ }
-+ if(NewPos){
-+ position = NewPos;
-+ if(bMoveAnchor)
-+ anchor = NewPos;
-+ RequestRepaint();
-+ }
-+}
-+
-+void SmCursor::MoveTo(OutputDevice* pDev, Point pos, bool bMoveAnchor){
-+ SmCaretLine best_line, //Best line found so far, when iterating
-+ curr_line; //Current line, when iterating
-+ SmCaretPosGraphEntry* NewPos = NULL;
-+ long dp_sq, //Distance to current line squared
-+ dbp_sq; //Distance to best line squared
-+ SmCaretPosGraphIterator it = pGraph->GetIterator();
-+ while(it.Next()){
-+ j_assert(it->CaretPos.IsValid(), "The caret position graph may not have invalid positions!");
-+ //Compute current line
-+ curr_line = SmCaretPos2LineVisitor(pDev, it->CaretPos).GetResult();
-+ //If we have a position compare to it
-+ if(NewPos){
-+ //Compute squared distance to current line
-+ dp_sq = curr_line.SquaredDistanceX(pos) + curr_line.SquaredDistanceY(pos);
-+ //If best line is closer, reject current line
-+ if(dbp_sq <= dp_sq) continue;
-+ }
-+ //Accept current position as the best
-+ best_line = curr_line;
-+ NewPos = it.Current();
-+ //Update distance to best line
-+ dbp_sq = best_line.SquaredDistanceX(pos) + best_line.SquaredDistanceY(pos);
-+ }
-+ if(NewPos){
-+ position = NewPos;
-+ if(bMoveAnchor)
-+ anchor = NewPos;
-+ RequestRepaint();
-+ }
-+}
-+
-+void SmCursor::BuildGraph(){
-+ //Save the current anchor and position
-+ SmCaretPos _anchor, _position;
-+ //Release pGraph if allocated
-+ if(pGraph){
-+ if(anchor)
-+ _anchor = anchor->CaretPos;
-+ if(position)
-+ _position = position->CaretPos;
-+ delete pGraph;
-+ //Reset anchor and position as they point into an old graph
-+ anchor = NULL;
-+ position = NULL;
-+ }
-+ pGraph = NULL;
-+
-+ //Build the new graph
-+ SmCaretPosGraphBuildingVisitor builder;
-+ pTree->Accept(&builder);
-+ pGraph = builder.Graph();
-+
-+ //Restore anchor and position pointers
-+ if(_anchor.IsValid() || _position.IsValid()){
-+ SmCaretPosGraphIterator it = pGraph->GetIterator();
-+ while(it.Next()){
-+ if(_anchor == it->CaretPos)
-+ anchor = it.Current();
-+ if(_position == it->CaretPos)
-+ position = it.Current();
-+ }
-+ }
-+ //Set position and anchor to first caret position
-+ SmCaretPosGraphIterator it = pGraph->GetIterator();
-+ if(!position)
-+ position = it.Next();
-+ if(!anchor)
-+ anchor = position;
-+
-+ j_assert(position->CaretPos.IsValid(), "Position must be valid");
-+ j_assert(anchor->CaretPos.IsValid(), "Anchor must be valid");
-+}
-+
-+bool SmCursor::SetCaretPosition(SmCaretPos pos, bool moveAnchor){
-+ SmCaretPosGraphIterator it = pGraph->GetIterator();
-+ while(it.Next()){
-+ if(it->CaretPos == pos){
-+ position = it.Current();
-+ if(moveAnchor)
-+ anchor = it.Current();
-+ return true;
-+ }
-+ }
-+ return false;
-+}
-+
-+void SmCursor::AnnotateSelection(){
-+ //TODO: Manage a state, reset it upon modification and optimize this call
-+ SetSelectionVisitor SSV(anchor->CaretPos, position->CaretPos);
-+ pTree->Accept(&SSV);
-+}
-+
-+void SmCursor::Draw(OutputDevice& pDev, Point Offset){
-+ SmCaretDrawingVisitor(pDev, GetPosition(), Offset);
-+}
-+
-+void SmCursor::Delete(){
-+ //Return if we don't have a selection to delete
-+ if(!HasSelection())
-+ return;
-+
-+ //Enter edit setion
-+ BeginEdit();
-+
-+ //Set selected on nodes
-+ AnnotateSelection();
-+
-+ //Find an arbitrary selected node
-+ SmNode* pSNode = FindSelectedNode(pTree);
-+ j_assert(pSNode != NULL, "There must be a selection when HasSelection is true!");
-+
-+ //Find the topmost node of the line that holds the selection
-+ SmNode* pLine = FindTopMostNodeInLine(pSNode, true);
-+
-+ //Get the parent of the line
-+ SmStructureNode* pLineParent = pLine->GetParent();
-+ //Find line offset in parent
-+ int nLineOffset = pLineParent->IndexOfSubNode(pLine);
-+ j_assert(nLineOffset != -1, "pLine must be a child of it's parent!");
-+
-+ //Position after delete
-+ SmCaretPos PosAfterDelete;
-+
-+ SmNodeList* pLineList;
-+ if(IsLineCompositionNode(pLine))
-+ pLineList = LineToList((SmStructureNode*)pLine);
-+ else {
-+ pLineList = new SmNodeList();
-+ pLineList->push_back(pLine);
-+ }
-+
-+ //Take the selected nodes and delete them...
-+ SmNodeList::iterator patchIt = TakeSelectedNodesFromList(pLineList);
-+
-+ //Get teh position to set after delete
-+ PosAfterDelete = PatchLineList(pLineList, patchIt);
-+
-+ //Parse list of nodes to a tree
-+ SmNodeListParser parser;
-+ pLine = parser.Parse(pLineList);
-+ delete pLineList;
-+
-+ //Insert it back into the parent
-+ pLineParent->SetSubNode(nLineOffset, pLine);
-+
-+ //Rebuild graph of caret position
-+ anchor = NULL;
-+ position = NULL;
-+ BuildGraph();
-+ AnnotateSelection(); //Update selection annotation!
-+
-+ //Set caret position
-+ if(!SetCaretPosition(PosAfterDelete, true))
-+ SetCaretPosition(SmCaretPos(pLine, 0), true);
-+
-+ //End edit section
-+ EndEdit();
-+}
-+
-+void SmCursor::InsertNodes(SmNodeList* pNewNodes){
-+ if(pNewNodes->size() == 0){
-+ delete pNewNodes;
-+ return;
-+ }
-+
-+ //Begin edit section
-+ BeginEdit();
-+
-+ //Position after insert should be after pNewNode
-+ SmCaretPos PosAfterInsert = SmCaretPos(pNewNodes->back(), 1);
-+
-+ //Get the current position
-+ const SmCaretPos pos = position->CaretPos;
-+
-+ //Find top most of line that holds position
-+ SmNode* pLine = FindTopMostNodeInLine(pos.pSelectedNode, false);
-+
-+ //Find line parent and line index in parent
-+ SmStructureNode* pLineParent = pLine->GetParent();
-+ int nParentIndex = pLineParent->IndexOfSubNode(pLine);
-+ j_assert(nParentIndex != -1, "pLine must be a subnode of pLineParent!");
-+
-+ //Convert line to list
-+ SmNodeList* pLineList;
-+ if(IsLineCompositionNode(pLine))
-+ pLineList = LineToList((SmStructureNode*)pLine);
-+ else {
-+ pLineList = new SmNodeList();
-+ pLineList->push_front(pLine);
-+ }
-+
-+ //Find iterator for place to insert nodes
-+ SmNodeList::iterator it = FindPositionInLineList(pLineList, pos);
-+
-+ //Insert all new nodes
-+ SmNodeList::iterator newIt, patchIt, insIt;
-+ for(newIt = pNewNodes->begin(); newIt != pNewNodes->end(); newIt++){
-+ insIt = pLineList->insert(it, *newIt);
-+ if(newIt == pNewNodes->begin())
-+ patchIt = insIt;
-+ if((*newIt)->GetType() == NTEXT)
-+ PosAfterInsert = SmCaretPos(*newIt, ((SmTextNode*)*newIt)->GetText().Len());
-+ else
-+ PosAfterInsert = SmCaretPos(*newIt, 1);
-+ }
-+ //Patch the places we've changed stuff
-+ PatchLineList(pLineList, patchIt);
-+ PosAfterInsert = PatchLineList(pLineList, it);
-+ //Release list, we've taken the nodes
-+ delete pNewNodes;
-+ pNewNodes = NULL;
-+
-+ //Parse line
-+ SmNodeListParser parser;
-+ pLine = parser.Parse(pLineList);
-+ delete pLineList;
-+
-+ //Insert it back into the parent
-+ pLineParent->SetSubNode(nParentIndex, pLine);
-+
-+ //Rebuild graph of caret position
-+ anchor = NULL;
-+ position = NULL;
-+ BuildGraph();
-+ AnnotateSelection(); //Update selection annotation!
-+
-+ //Set caret position
-+ if(!SetCaretPosition(PosAfterInsert, true))
-+ SetCaretPosition(SmCaretPos(pLine, 0), true);
-+
-+ //End edit section
-+ EndEdit();
-+}
-+
-+SmNodeList::iterator SmCursor::FindPositionInLineList(SmNodeList* pLineList, SmCaretPos aCaretPos) {
-+ //Find iterator for position
-+ SmNodeList::iterator it;
-+ for(it = pLineList->begin(); it != pLineList->end(); it++){
-+ if(*it == aCaretPos.pSelectedNode){
-+ if((*it)->GetType() == NTEXT){
-+ //Split textnode if needed
-+ if(aCaretPos.Index > 0){
-+ SmTextNode* pText = (SmTextNode*)aCaretPos.pSelectedNode;
-+ XubString str1 = pText->GetText().Copy(0, aCaretPos.Index);
-+ XubString str2 = pText->GetText().Copy(aCaretPos.Index);
-+ pText->ChangeText(str1);
-+ ++it;
-+ //Insert str2 as new text node
-+ if(str2.Len() > 0){
-+ SmTextNode* pNewText = new SmTextNode(pText->GetToken(), pText->GetFontDesc());
-+ pNewText->ChangeText(str2);
-+ it = pLineList->insert(it, pNewText);
-+ }
-+ }
-+ }else
-+ ++it;
-+ //it now pointer to the node following pos, so pLineList->insert(it, ...) will insert correctly
-+ return it;
-+
-+ }
-+ }
-+ //If we didn't find pSelectedNode, it must be because the caret is infront of the line
-+ return pLineList->begin();
-+}
-+
-+SmCaretPos SmCursor::PatchLineList(SmNodeList* pLineList, SmNodeList::iterator aIter) {
-+ //The nodes we should consider merging
-+ SmNode *prev = NULL,
-+ *next = NULL;
-+ if(aIter != pLineList->end())
-+ next = *aIter;
-+ if(aIter != pLineList->begin()) {
-+ aIter--;
-+ prev = *aIter;
-+ aIter++;
-+ }
-+
-+ //Check if there's textnodes to merge
-+ if(prev && next && prev->GetType() == NTEXT && next->GetType() == NTEXT){
-+ SmTextNode *pText = (SmTextNode*)prev,
-+ *pOldN = (SmTextNode*)next;
-+ SmCaretPos retval(pText, pText->GetText().Len());
-+ String newText;
-+ newText += pText->GetText();
-+ newText += pOldN->GetText();
-+ pText->ChangeText(newText);
-+ delete pOldN;
-+ pLineList->erase(aIter);
-+ return retval;
-+ }
-+
-+ //Check if there's a SmPlaceNode to remove:
-+ if(prev && next && prev->GetType() == NPLACE && !SmNodeListParser::IsOperator(next->GetToken())){
-+ aIter--;
-+ aIter = pLineList->erase(aIter);
-+ delete prev;
-+ //Return caret pos infront of aIter
-+ if(aIter != pLineList->begin())
-+ aIter--; //Thus find node before aIter
-+ if(aIter == pLineList->begin())
-+ return SmCaretPos();
-+ if((*aIter)->GetType() == NTEXT)
-+ return SmCaretPos(*aIter, ((SmTextNode*)*aIter)->GetText().Len());
-+ return SmCaretPos(*aIter, 1);
-+ }
-+ if(prev && next && next->GetType() == NPLACE && !SmNodeListParser::IsOperator(prev->GetToken())){
-+ aIter = pLineList->erase(aIter);
-+ delete next;
-+ if(prev->GetType() == NTEXT)
-+ return SmCaretPos(prev, ((SmTextNode*)prev)->GetText().Len());
-+ return SmCaretPos(prev, 1);
-+ }
-+
-+ //If we didn't do anything return
-+ if(!prev) //return an invalid to indicate we're infront of line
-+ return SmCaretPos();
-+ if(prev->GetType() == NTEXT)
-+ return SmCaretPos(prev, ((SmTextNode*)prev)->GetText().Len());
-+ return SmCaretPos(prev, 1);
-+}
-+
-+SmNodeList::iterator SmCursor::TakeSelectedNodesFromList(SmNodeList *pLineList,
-+ SmNodeList *pSelectedNodes) {
-+ SmNodeList::iterator retval;
-+ SmNodeList::iterator it = pLineList->begin();
-+ while(it != pLineList->end()){
-+ if((*it)->IsSelected()){
-+ //Split text nodes
-+ if((*it)->GetType() == NTEXT) {
-+ SmTextNode* pText = (SmTextNode*)*it;
-+ String aText = pText->GetText();
-+ //Start and lengths of the segments, 2 is the selected segment
-+ int start1 = 0,
-+ start2 = pText->GetSelectionStart(),
-+ start3 = pText->GetSelectionEnd(),
-+ len1 = start2 - 0,
-+ len2 = start3 - start2,
-+ len3 = aText.Len() - start3;
-+ SmToken aToken = pText->GetToken();
-+ USHORT eFontDesc = pText->GetFontDesc();
-+ //If we need make segment 1
-+ if(len1 > 0) {
-+ String str = aText.Copy(start1, len1);
-+ pText->ChangeText(str);
-+ it++;
-+ } else {//Remove it if not needed
-+ it = pLineList->erase(it);
-+ delete pText;
-+ }
-+ //Set retval to be right after the selection
-+ retval = it;
-+ //if we need make segment 3
-+ if(len3 > 0) {
-+ String str = aText.Copy(start3, len3);
-+ SmTextNode* pSeg3 = new SmTextNode(aToken, eFontDesc);
-+ pSeg3->ChangeText(str);
-+ retval = pLineList->insert(it, pSeg3);
-+ }
-+ //If we need to save the selected text
-+ if(pSelectedNodes && len2 > 0) {
-+ String str = aText.Copy(start2, len2);
-+ SmTextNode* pSeg2 = new SmTextNode(aToken, eFontDesc);
-+ pSeg2->ChangeText(str);
-+ pSelectedNodes->push_back(pSeg2);
-+ }
-+ } else { //if it's not textnode
-+ SmNode* pNode = *it;
-+ retval = it = pLineList->erase(it);
-+ if(pSelectedNodes)
-+ pSelectedNodes->push_back(pNode);
-+ else
-+ delete pNode;
-+ }
-+ } else
-+ it++;
-+ }
-+ return retval;
-+}
-+
-+void SmCursor::InsertSubSup(SmSubSup eSubSup) {
-+ AnnotateSelection();
-+
-+ //Find line
-+ SmNode *pLine;
-+ if(HasSelection()) {
-+ SmNode *pSNode = FindSelectedNode(pTree);
-+ j_assert(pSNode != NULL, "There must be a selected node when HasSelection is true!");
-+ pLine = FindTopMostNodeInLine(pSNode, TRUE);
-+ } else
-+ pLine = FindTopMostNodeInLine(position->CaretPos.pSelectedNode, FALSE);
-+
-+ //Find Parent and offset in parent
-+ SmStructureNode *pLineParent = pLine->GetParent();
-+ int nParentIndex = pLineParent->IndexOfSubNode(pLine);
-+ j_assert(nParentIndex != -1, "pLine must be a subnode of pLineParent!");
-+
-+ //TODO: Consider handling special cases where parent is an SmOperNode,
-+ // Maybe this method should be able to add limits to an SmOperNode...
-+
-+ //We begin modifying the tree here
-+ BeginEdit();
-+
-+ //Convert line to list
-+ SmNodeList* pLineList;
-+ if(IsLineCompositionNode(pLine))
-+ pLineList = LineToList((SmStructureNode*)pLine);
-+ else {
-+ pLineList = new SmNodeList();
-+ pLineList->push_front(pLine);
-+ }
-+
-+ //Take the selection, and/or find iterator for current position
-+ SmNodeList* pSelectedNodesList = new SmNodeList();
-+ SmNodeList::iterator it;
-+ if(HasSelection())
-+ it = TakeSelectedNodesFromList(pLineList, pSelectedNodesList);
-+ else
-+ it = FindPositionInLineList(pLineList, position->CaretPos);
-+
-+ //Find node that this should be applied to
-+ SmNode* pSubject;
-+ BOOL bPatchLine = pSelectedNodesList->size() > 0; //If the line should be patched later
-+ if(it != pLineList->begin()) {
-+ it--;
-+ pSubject = *it;
-+ it++;
-+ } else {
-+ //Create a new place node
-+ pSubject = new SmPlaceNode();
-+ pSubject->Prepare(pDocShell->GetFormat(), *pDocShell);
-+ it = pLineList->insert(it, pSubject);
-+ it++;
-+ bPatchLine = TRUE; //We've modified the line it should be patched later.
-+ }
-+
-+ //Wrap the subject in a SmSubSupNode
-+ SmSubSupNode* pSubSup;
-+ if(pSubject->GetType() != NSUBSUP){
-+ SmToken token;
-+ token.nGroup = TGPOWER;
-+ pSubSup = new SmSubSupNode(token);
-+ pSubSup->SetBody(pSubject);
-+ *(--it) = pSubSup;
-+ it++;
-+ }else
-+ pSubSup = (SmSubSupNode*)pSubject;
-+ //pSubject shouldn't be referenced anymore, pSubSup is the SmSubSupNode in pLineList we wish to edit.
-+ //and it pointer to the element following pSubSup in pLineList.
-+ pSubject = NULL;
-+
-+ //Patch the line if we noted that was needed previously
-+ if(bPatchLine)
-+ PatchLineList(pLineList, it);
-+
-+ //Convert existing, if any, sub-/superscript line to list
-+ SmNode *pScriptLine = pSubSup->GetSubSup(eSubSup);
-+ SmNodeList* pScriptLineList;
-+ if(pScriptLine && IsLineCompositionNode(pScriptLine))
-+ pScriptLineList = LineToList((SmStructureNode*)pScriptLine);
-+ else{
-+ pScriptLineList = new SmNodeList();
-+ if(pScriptLine)
-+ pScriptLineList->push_front(pScriptLine);
-+ }
-+
-+ //Add selection to pScriptLineList
-+ unsigned int nOldSize = pScriptLineList->size();
-+ pScriptLineList->insert(pScriptLineList->end(), pSelectedNodesList->begin(), pSelectedNodesList->end());
-+ delete pSelectedNodesList;
-+ pSelectedNodesList = NULL;
-+
-+ //Patch pScriptLineList if needed
-+ if(0 < nOldSize && nOldSize < pScriptLineList->size()) {
-+ SmNodeList::iterator iPatchPoint = pScriptLineList->begin();
-+ std::advance(iPatchPoint, nOldSize);
-+ PatchLineList(pScriptLineList, iPatchPoint);
-+ }
-+
-+ //Find caret pos, that should be used after sub-/superscription.
-+ SmCaretPos PosAfterScript; //Leave invalid for first position
-+ if(pScriptLineList->size() > 0)
-+ PosAfterScript = SmCaretPos::GetPosAfter(pScriptLineList->back());
-+
-+ //Parse pScriptLineList
-+ pScriptLine = SmNodeListParser().Parse(pScriptLineList);
-+ delete pScriptLineList;
-+ pScriptLineList = NULL;
-+
-+ //Insert pScriptLine back into the tree
-+ pSubSup->SetSubSup(eSubSup, pScriptLine);
-+
-+ //Parse pLineList
-+ pLine = SmNodeListParser().Parse(pLineList);
-+ delete pLineList;
-+ pLineList = NULL;
-+
-+ //Insert pLineList back into the tree
-+ pLineParent->SetSubNode(nParentIndex, pLine);
-+
-+ //Rebuild graph of caret positions
-+ anchor = NULL;
-+ position = NULL;
-+ BuildGraph();
-+ AnnotateSelection();
-+
-+ //Set caret position
-+ if(!SetCaretPosition(PosAfterScript, true))
-+ SetCaretPosition(SmCaretPos(pScriptLine, 0), true);
-+
-+ EndEdit();
-+}
-+
-+BOOL SmCursor::InsertLimit(SmSubSup eSubSup, BOOL bMoveCaret) {
-+ //Find a subject to set limits on
-+ SmOperNode *pSubject = NULL;
-+ //Check if pSelectedNode might be a subject
-+ if(position->CaretPos.pSelectedNode->GetType() == NOPER)
-+ pSubject = (SmOperNode*)position->CaretPos.pSelectedNode;
-+ else {
-+ //If not, check if parent of the current line is a SmOperNode
-+ SmNode *pLineNode = FindTopMostNodeInLine(position->CaretPos.pSelectedNode, FALSE);
-+ if(pLineNode->GetParent() && pLineNode->GetParent()->GetType() == NOPER)
-+ pSubject = (SmOperNode*)pLineNode->GetParent();
-+ }
-+
-+ //Abort operation if we're not in the appropriate context
-+ if(!pSubject)
-+ return FALSE;
-+
-+ BeginEdit();
-+
-+ //Find the sub sup node
-+ SmSubSupNode *pSubSup = NULL;
-+ //Check if there's already one there...
-+ if(pSubject->GetSubNode(0)->GetType() == NSUBSUP)
-+ pSubSup = (SmSubSupNode*)pSubject->GetSubNode(0);
-+ else { //if not create a new SmSubSupNode
-+ SmToken token;
-+ token.nGroup = TGLIMIT;
-+ pSubSup = new SmSubSupNode(token);
-+ //Set it's body
-+ pSubSup->SetBody(pSubject->GetSubNode(0));
-+ //Replace the operation of the SmOperNode
-+ pSubject->SetSubNode(0, pSubSup);
-+ }
-+
-+ //Create the limit, if needed
-+ SmCaretPos PosAfterLimit;
-+ SmNode *pLine;
-+ if(!pSubSup->GetSubSup(eSubSup)){
-+ pLine = new SmPlaceNode();
-+ pSubSup->SetSubSup(eSubSup, pLine);
-+ PosAfterLimit = SmCaretPos(pLine, 1);
-+ //If it's already there... let's move the caret
-+ } else if(bMoveCaret){
-+ pLine = pSubSup->GetSubSup(eSubSup);
-+ SmNodeList* pLineList;
-+ if(IsLineCompositionNode(pLine))
-+ pLineList = LineToList((SmStructureNode*)pLine);
-+ else {
-+ pLineList = new SmNodeList();
-+ pLineList->push_front(pLine);
-+ }
-+ if(pLineList->size() > 0)
-+ PosAfterLimit = SmCaretPos::GetPosAfter(pLineList->back());
-+ pLine = SmNodeListParser().Parse(pLineList);
-+ delete pLineList;
-+ pSubSup->SetSubSup(eSubSup, pLine);
-+ }
-+
-+ //Rebuild graph of caret positions
-+ BuildGraph();
-+ AnnotateSelection();
-+
-+ //Set caret position
-+ if(bMoveCaret)
-+ if(!SetCaretPosition(PosAfterLimit, true))
-+ SetCaretPosition(SmCaretPos(pLine, 0), true);
-+
-+ EndEdit();
-+
-+ return TRUE;
-+}
-+
-+void SmCursor::InsertBrackets(SmBracketType eBracketType) {
-+ BeginEdit();
-+
-+ AnnotateSelection();
-+
-+ //Find line
-+ SmNode *pLine;
-+ if(HasSelection()) {
-+ SmNode *pSNode = FindSelectedNode(pTree);
-+ j_assert(pSNode != NULL, "There must be a selected node if HasSelection()");
-+ pLine = FindTopMostNodeInLine(pSNode, TRUE);
-+ } else
-+ pLine = FindTopMostNodeInLine(position->CaretPos.pSelectedNode, FALSE);
-+
-+ //Find parent and offset in parent
-+ SmStructureNode *pLineParent = pLine->GetParent();
-+ int nParentIndex = pLineParent->IndexOfSubNode(pLine);
-+ j_assert( nParentIndex != -1, "pLine must be a subnode of pLineParent!");
-+
-+ //Convert line to list
-+ SmNodeList *pLineList;
-+ if(IsLineCompositionNode(pLine))
-+ pLineList = LineToList((SmStructureNode*)pLine);
-+ else {
-+ pLineList = new SmNodeList();
-+ pLineList->push_front(pLine);
-+ }
-+
-+ //Take the selection, and/or find iterator for current position
-+ SmNodeList *pSelectedNodesList = new SmNodeList();
-+ SmNodeList::iterator it;
-+ if(HasSelection())
-+ it = TakeSelectedNodesFromList(pLineList, pSelectedNodesList);
-+ else
-+ it = FindPositionInLineList(pLineList, position->CaretPos);
-+
-+ //If there's no selected nodes, create a place node
-+ if(pSelectedNodesList->size() == 0)
-+ pSelectedNodesList->push_front(new SmPlaceNode());
-+
-+ //Parse body nodes
-+ SmNode *pBodyNode = SmNodeListParser().Parse(pSelectedNodesList);
-+ delete pSelectedNodesList;
-+
-+ //Create SmBraceNode
-+ SmToken aTok(TLEFT, '\0', "left", 0, 5);
-+ SmBraceNode *pBrace = new SmBraceNode(aTok);
-+ pBrace->SetScaleMode(SCALE_HEIGHT);
-+ SmNode *pLeft = CreateBracket(eBracketType, true),
-+ *pRight = CreateBracket(eBracketType, false);
-+ SmBracebodyNode *pBody = new SmBracebodyNode(SmToken());
-+ pBody->SetSubNodes(pBodyNode, NULL);
-+ pBrace->SetSubNodes(pLeft, pBody, pRight);
-+ pBrace->Prepare(pDocShell->GetFormat(), *pDocShell);
-+
-+ //Insert into line
-+ pLineList->insert(it, pBrace);
-+ //Patch line (I think this is good enough)
-+ SmCaretPos PosAfterInsert = PatchLineList(pLineList, it);
-+
-+ //Parse line
-+ pLine = SmNodeListParser().Parse(pLineList);
-+ delete pLineList;
-+
-+ //Insert line back into tree
-+ pLineParent->SetSubNode(nParentIndex, pLine);
-+
-+ //Rebuild graph of caret positions
-+ anchor = NULL;
-+ position = NULL;
-+ BuildGraph();
-+ AnnotateSelection();
-+
-+ //Set caret position
-+ if(!SetCaretPosition(PosAfterInsert, true))
-+ SetCaretPosition(SmCaretPos(pLine, 0), true);
-+
-+ EndEdit();
-+}
-+
-+SmNode *SmCursor::CreateBracket(SmBracketType eBracketType, BOOL bIsLeft) {
-+ SmToken aTok;
-+ if(bIsLeft){
-+ switch(eBracketType){
-+ case NoneBrackets:
-+ aTok = SmToken(TNONE, '\0', "none", TGLBRACES | TGRBRACES, 0);
-+ break;
-+ case RoundBrackets:
-+ aTok = SmToken(TLPARENT, MS_LPARENT, "(", TGLBRACES, 5);
-+ break;
-+ case SquareBrackets:
-+ aTok = SmToken(TLBRACKET, MS_LBRACKET, "[", TGLBRACES, 5);
-+ break;
-+ case DoubleSquareBrackets:
-+ aTok = SmToken(TLDBRACKET, MS_LDBRACKET, "ldbracket", TGLBRACES, 5);
-+ break;
-+ case LineBrackets:
-+ aTok = SmToken(TLLINE, MS_LINE, "lline", TGLBRACES, 5);
-+ break;
-+ case DoubleLineBrackets:
-+ aTok = SmToken(TLDLINE, MS_DLINE, "ldline", TGLBRACES, 5);
-+ break;
-+ case CurlyBrackets:
-+ aTok = SmToken(TLBRACE, MS_LBRACE, "lbrace", TGLBRACES, 5);
-+ break;
-+ case AngleBrackets:
-+ aTok = SmToken(TLANGLE, MS_LANGLE, "langle", TGLBRACES, 5);
-+ break;
-+ case CeilBrackets:
-+ aTok = SmToken(TLCEIL, MS_LCEIL, "lceil", TGLBRACES, 5);
-+ break;
-+ case FloorBrackets:
-+ aTok = SmToken(TLFLOOR, MS_LFLOOR, "lfloor", TGLBRACES, 5);
-+ break;
-+ }
-+ } else {
-+ switch(eBracketType) {
-+ case NoneBrackets:
-+ aTok = SmToken(TNONE, '\0', "none", TGLBRACES | TGRBRACES, 0);
-+ break;
-+ case RoundBrackets:
-+ aTok = SmToken(TRPARENT, MS_RPARENT, ")", TGRBRACES, 5);
-+ break;
-+ case SquareBrackets:
-+ aTok = SmToken(TRBRACKET, MS_RBRACKET, "]", TGRBRACES, 5);
-+ break;
-+ case DoubleSquareBrackets:
-+ aTok = SmToken(TRDBRACKET, MS_RDBRACKET, "rdbracket", TGRBRACES, 5);
-+ break;
-+ case LineBrackets:
-+ aTok = SmToken(TRLINE, MS_LINE, "rline", TGRBRACES, 5);
-+ break;
-+ case DoubleLineBrackets:
-+ aTok = SmToken(TRDLINE, MS_DLINE, "rdline", TGRBRACES, 5);
-+ break;
-+ case CurlyBrackets:
-+ aTok = SmToken(TRBRACE, MS_RBRACE, "rbrace", TGRBRACES, 5);
-+ break;
-+ case AngleBrackets:
-+ aTok = SmToken(TRANGLE, MS_RANGLE, "rangle", TGRBRACES, 5);
-+ break;
-+ case CeilBrackets:
-+ aTok = SmToken(TRCEIL, MS_RCEIL, "rceil", TGRBRACES, 5);
-+ break;
-+ case FloorBrackets:
-+ aTok = SmToken(TRFLOOR, MS_RFLOOR, "rfloor", TGRBRACES, 5);
-+ break;
-+ }
-+ }
-+ SmNode* pRetVal = new SmMathSymbolNode(aTok);
-+ pRetVal->SetScaleMode(SCALE_HEIGHT);
-+ return pRetVal;
-+}
-+
-+BOOL SmCursor::InsertRow() {
-+ AnnotateSelection();
-+
-+ //Find line
-+ SmNode *pLine;
-+ if(HasSelection()) {
-+ SmNode *pSNode = FindSelectedNode(pTree);
-+ j_assert(pSNode != NULL, "There must be a selected node if HasSelection()");
-+ pLine = FindTopMostNodeInLine(pSNode, TRUE);
-+ } else
-+ pLine = FindTopMostNodeInLine(position->CaretPos.pSelectedNode, FALSE);
-+
-+ //Find parent and offset in parent
-+ SmStructureNode *pLineParent = pLine->GetParent();
-+ int nParentIndex = pLineParent->IndexOfSubNode(pLine);
-+ j_assert( nParentIndex != -1, "pLine must be a subnode of pLineParent!");
-+
-+ //Discover the context of this command
-+ SmTableNode *pTable = NULL;
-+ SmMatrixNode *pMatrix = NULL;
-+ int nTableIndex = nParentIndex;
-+ if(pLineParent->GetType() == NTABLE)
-+ pTable = (SmTableNode*)pLineParent;
-+ //If it's warped in a SmLineNode, we can still insert a newline
-+ else if(pLineParent->GetType() == NLINE &&
-+ pLineParent->GetParent() &&
-+ pLineParent->GetParent()->GetType() == NTABLE) {
-+ //NOTE: This hack might give problems if we stop ignoring SmAlignNode
-+ pTable = (SmTableNode*)pLineParent->GetParent();
-+ nTableIndex = pTable->IndexOfSubNode(pLineParent);
-+ j_assert(nTableIndex != -1, "pLineParent must be a child of its parent!");
-+ }
-+ if(pLineParent->GetType() == NMATRIX)
-+ pMatrix = (SmMatrixNode*)pLineParent;
-+
-+ //If we're not in a context that supports InsertRow, return FALSE
-+ if(!pTable && !pMatrix)
-+ return FALSE;
-+
-+ //Now we start editing
-+ BeginEdit();
-+
-+ //Convert line to list
-+ SmNodeList *pLineList;
-+ if(IsLineCompositionNode(pLine))
-+ pLineList = LineToList((SmStructureNode*)pLine);
-+ else {
-+ pLineList = new SmNodeList();
-+ pLineList->push_front(pLine);
-+ }
-+
-+ //Find position in line
-+ SmNodeList::iterator it;
-+ if(HasSelection()) {
-+ //Take the selected nodes and delete them...
-+ it = TakeSelectedNodesFromList(pLineList);
-+ } else
-+ it = FindPositionInLineList(pLineList, position->CaretPos);
-+
-+ //New caret position after inserting the newline/row in whatever context
-+ SmCaretPos PosAfterInsert;
-+
-+ //If we're in the context of a table
-+ if(pTable) {
-+ SmNodeList *pNewLineList = new SmNodeList();
-+ //Move elements from pLineList to pNewLineList
-+ pNewLineList->splice(pNewLineList->begin(), *pLineList, it, pLineList->end());
-+ //Make sure it is valid again
-+ it = pLineList->end();
-+ if(it != pLineList->begin())
-+ it--;
-+ if(pNewLineList->size() == 0)
-+ pNewLineList->push_front(new SmPlaceNode());
-+ //Parse new line
-+ SmNode *pNewLine = SmNodeListParser().Parse(pNewLineList);
-+ delete pNewLineList;
-+ //Get position before we wrap in SmLineNode
-+ //NOTE: This should be done after, if SmLineNode ever becomes a line composition node
-+ PosAfterInsert = SmCaretPos(pNewLine, 0);
-+ //Wrap pNewLine in SmLineNode if needed
-+ if(pLineParent->GetType() == NLINE) {
-+ SmLineNode *pNewLineNode = new SmLineNode(SmToken(TNEWLINE, '\0', "newline"));
-+ pNewLineNode->SetSubNodes(pNewLine, NULL);
-+ pNewLine = pNewLineNode;
-+ }
-+ //Move other nodes if needed
-+ for( int i = pTable->GetNumSubNodes(); i > nTableIndex + 1; i--)
-+ pTable->SetSubNode(i, pTable->GetSubNode(i-1));
-+ //Insert new line
-+ pTable->SetSubNode(nTableIndex + 1, pNewLine);
-+ //Check if we need to change token type:
-+ if(pTable->GetNumSubNodes() > 2 && pTable->GetToken().eType == TBINOM) {
-+ SmToken tok = pTable->GetToken();
-+ tok.eType = TSTACK;
-+ pTable->SetToken(tok);
-+ }
-+ }
-+ //If we're in the context of a matrix
-+ else if(pMatrix) {
-+ //Find position after insert and patch the list
-+ PosAfterInsert = PatchLineList(pLineList, it);
-+ //Move other children
-+ USHORT rows = pMatrix->GetNumRows();
-+ USHORT cols = pMatrix->GetNumCols();
-+ int nRowStart = (nParentIndex - nParentIndex % cols) + cols;
-+ for( int i = pMatrix->GetNumSubNodes() + cols - 1; i >= nRowStart + cols; i--)
-+ pMatrix->SetSubNode(i, pMatrix->GetSubNode(i - cols));
-+ for( int i = nRowStart; i < nRowStart + cols; i++) {
-+ SmPlaceNode *pNewLine = new SmPlaceNode();
-+ if(i == nParentIndex + cols)
-+ PosAfterInsert = SmCaretPos(pNewLine, 0);
-+ pMatrix->SetSubNode(i, pNewLine);
-+ }
-+ pMatrix->SetRowCol(rows + 1, cols);
-+ } else
-+ j_assert(FALSE, "We must be either the context of a table or matrix!");
-+
-+ //Parse and put line back where it came from...
-+ pLine = SmNodeListParser().Parse(pLineList);
-+ delete pLineList;
-+ pLineList = NULL;
-+ pLineParent->SetSubNode(nParentIndex, pLine);
-+
-+ //Rebuild graph of caret positions
-+ anchor = NULL;
-+ position = NULL;
-+ BuildGraph();
-+ AnnotateSelection();
-+
-+ //Set caret position
-+ if(!SetCaretPosition(PosAfterInsert, true))
-+ SetCaretPosition(SmCaretPos(pLine, 0), true);
-+
-+ EndEdit();
-+ return TRUE;
-+}
-+
-+void SmCursor::InsertFraction() {
-+ AnnotateSelection();
-+
-+ //Find line
-+ SmNode *pLine;
-+ if(HasSelection()) {
-+ SmNode *pSNode = FindSelectedNode(pTree);
-+ j_assert(pSNode != NULL, "There must be a selected node when HasSelection is true!");
-+ pLine = FindTopMostNodeInLine(pSNode, TRUE);
-+ } else
-+ pLine = FindTopMostNodeInLine(position->CaretPos.pSelectedNode, FALSE);
-+
-+ //Find Parent and offset in parent
-+ SmStructureNode *pLineParent = pLine->GetParent();
-+ int nParentIndex = pLineParent->IndexOfSubNode(pLine);
-+ j_assert(nParentIndex != -1, "pLine must be a subnode of pLineParent!");
-+
-+ //We begin modifying the tree here
-+ BeginEdit();
-+
-+ //Convert line to list
-+ SmNodeList* pLineList;
-+ if(IsLineCompositionNode(pLine))
-+ pLineList = LineToList((SmStructureNode*)pLine);
-+ else {
-+ pLineList = new SmNodeList();
-+ pLineList->push_front(pLine);
-+ }
-+
-+ //Take the selection, and/or find iterator for current position
-+ SmNodeList* pSelectedNodesList = new SmNodeList();
-+ SmNodeList::iterator it;
-+ if(HasSelection())
-+ it = TakeSelectedNodesFromList(pLineList, pSelectedNodesList);
-+ else
-+ it = FindPositionInLineList(pLineList, position->CaretPos);
-+
-+ //Create pNum, and pDenom
-+ if(pSelectedNodesList->size() == 0)
-+ pSelectedNodesList->push_front(new SmPlaceNode());
-+ SmNode *pNum = SmNodeListParser().Parse(pSelectedNodesList),
-+ *pDenom = new SmPlaceNode();
-+ delete pSelectedNodesList;
-+ pSelectedNodesList = NULL;
-+
-+ //Create new fraction
-+ SmBinVerNode *pFrac = new SmBinVerNode(SmToken(TOVER, '\0', "over", TGPRODUCT, 0));
-+ SmNode *pRect = new SmRectangleNode(SmToken());
-+ pFrac->SetSubNodes(pNum, pRect, pDenom);
-+
-+ //Insert in pLineList
-+ SmNodeList::iterator patchIt = pLineList->insert(it, pFrac);
-+ PatchLineList(pLineList, patchIt);
-+ PatchLineList(pLineList, it);
-+
-+ //Parse the line
-+ pLine = SmNodeListParser().Parse(pLineList);
-+ delete pLineList;
-+
-+ //Insert pLine back into parent
-+ pLineParent->SetSubNode(nParentIndex, pLine);
-+
-+ //Rebuild graph of caret position
-+ anchor = NULL;
-+ position = NULL;
-+ BuildGraph();
-+ AnnotateSelection(); //Update selection annotation!
-+
-+ //Set caret position
-+ if(!SetCaretPosition(SmCaretPos(pDenom, 1), true))
-+ SetCaretPosition(SmCaretPos(pLine, 0), true);
-+
-+ EndEdit();
-+}
-+
-+
-+void SmCursor::InsertText(XubString aString){
-+ BeginEdit();
-+
-+ Delete();
-+
-+ //TODO: Use other values than FNT_VARIABLE for numbers and functions
-+
-+ SmToken token;
-+ token.eType = TIDENT;
-+ token.cMathChar = '\0';
-+ token.nGroup = 0;
-+ token.nLevel = 5;
-+ token.aText = aString;
-+
-+ SmTextNode* pText = new SmTextNode(token, FNT_VARIABLE);
-+
-+ //Prepare the new node
-+ pText->Prepare(pDocShell->GetFormat(), *pDocShell);
-+
-+ SmNodeList* pList = new SmNodeList();
-+ pList->push_front(pText);
-+ InsertNodes(pList);
-+
-+ EndEdit();
-+}
-+
-+void SmCursor::InsertElement(SmFormulaElement element){
-+ BeginEdit();
-+
-+ Delete();
-+
-+ //Create new node
-+ SmNode* pNewNode = NULL;
-+ switch(element){
-+ case BlankElement:
-+ {
-+ SmToken token;
-+ token.nGroup = TGBLANK;
-+ token.aText.AssignAscii("~");
-+ pNewNode = new SmBlankNode(token);
-+ }break;
-+ case FactorialElement:
-+ {
-+ SmToken token(TFACT, MS_FACT, "fact", TGUNOPER, 5);
-+ pNewNode = new SmMathSymbolNode(token);
-+ }break;
-+ case PlusElement:
-+ {
-+ SmToken token;
-+ token.eType = TPLUS;
-+ token.cMathChar = MS_PLUS;
-+ token.nGroup = TGUNOPER | TGSUM;
-+ token.nLevel = 5;
-+ token.aText.AssignAscii("+");
-+ pNewNode = new SmMathSymbolNode(token);
-+ }break;
-+ case MinusElement:
-+ {
-+ SmToken token;
-+ token.eType = TMINUS;
-+ token.cMathChar = MS_MINUS;
-+ token.nGroup = MS_PLUS;
-+ token.nLevel = 5;
-+ token.aText.AssignAscii("-");
-+ pNewNode = new SmMathSymbolNode(token);
-+ }break;
-+ case CDotElement:
-+ {
-+ SmToken token;
-+ token.eType = TCDOT;
-+ token.cMathChar = MS_CDOT;
-+ token.nGroup = TGPRODUCT;
-+ token.aText.AssignAscii("cdot");
-+ pNewNode = new SmMathSymbolNode(token);
-+ }break;
-+ case EqualElement:
-+ {
-+ SmToken token;
-+ token.eType = TASSIGN;
-+ token.cMathChar = MS_ASSIGN;
-+ token.nGroup = TGRELATION;
-+ token.aText.AssignAscii("=");
-+ pNewNode = new SmMathSymbolNode(token);
-+ }break;
-+ case LessThanElement:
-+ {
-+ SmToken token;
-+ token.eType = TLT;
-+ token.cMathChar = MS_LT;
-+ token.nGroup = TGRELATION;
-+ token.aText.AssignAscii("<");
-+ pNewNode = new SmMathSymbolNode(token);
-+ }break;
-+ case GreaterThanElement:
-+ {
-+ SmToken token;
-+ token.eType = TGT;
-+ token.cMathChar = MS_GT;
-+ token.nGroup = TGRELATION;
-+ token.aText.AssignAscii(">");
-+ pNewNode = new SmMathSymbolNode(token);
-+ }break;
-+ default:
-+ j_assert(false, "Element unknown!");
-+ }
-+ j_assert(pNewNode != NULL, "No new node was created!");
-+ if(!pNewNode)
-+ return;
-+
-+ //Prepare the new node
-+ pNewNode->Prepare(pDocShell->GetFormat(), *pDocShell);
-+
-+ //Insert new node
-+ SmNodeList* pList = new SmNodeList();
-+ pList->push_front(pNewNode);
-+ InsertNodes(pList);
-+
-+ EndEdit();
-+}
-+
-+void SmCursor::InsertSpecial(XubString aString) {
-+ BeginEdit();
-+ Delete();
-+
-+ aString.EraseLeadingAndTrailingChars();
-+ aString.EraseLeadingChars('%');
-+
-+ //Create instance of special node
-+ SmToken token;
-+ token.eType = TSPECIAL;
-+ token.cMathChar = '\0';
-+ token.nGroup = 0;
-+ token.nLevel = 5;
-+ token.aText = aString; //Don't know if leading "%" should be removed
-+ SmSpecialNode* pSpecial = new SmSpecialNode(token);
-+
-+ //Prepare the special node
-+ pSpecial->Prepare(pDocShell->GetFormat(), *pDocShell);
-+
-+ //Insert the node
-+ SmNodeList* pList = new SmNodeList();
-+ pList->push_front(pSpecial);
-+ InsertNodes(pList);
-+
-+ EndEdit();
-+}
-+
-+void SmCursor::InsertCommand(USHORT nCommand) {
-+ switch(nCommand){
-+ case RID_NEWLINE:
-+ InsertRow();
-+ break;
-+ case RID_FROMX:
-+ InsertLimit(CSUB, TRUE);
-+ break;
-+ case RID_TOX:
-+ InsertLimit(CSUP, TRUE);
-+ break;
-+ case RID_FROMXTOY:
-+ if(InsertLimit(CSUB, FALSE))
-+ InsertLimit(CSUP, TRUE);
-+ break;
-+ default:
-+ InsertCommandText(SmResId(nCommand));
-+ break;
-+ }
-+}
-+
-+void SmCursor::InsertCommandText(XubString aCommandText) {
-+ //Parse the the sub expression
-+ SmNode* pSubExpr = SmParser().ParseExpression(aCommandText);
-+
-+ //Prepare the subtree
-+ pSubExpr->Prepare(pDocShell->GetFormat(), *pDocShell);
-+
-+ //Convert subtree to list
-+ SmNodeList* pLineList;
-+ if(IsLineCompositionNode(pSubExpr))
-+ pLineList = LineToList((SmStructureNode*)pSubExpr);
-+ else {
-+ pLineList = new SmNodeList();
-+ pLineList->push_front(pSubExpr);
-+ }
-+
-+ BeginEdit();
-+
-+ //Delete any selection
-+ Delete();
-+
-+ //Insert it
-+ InsertNodes(pLineList);
-+
-+ EndEdit();
-+}
-+
-+void SmCursor::Copy(){
-+ if(!HasSelection())
-+ return;
-+
-+ //Find selected node
-+ SmNode* pSNode = FindSelectedNode(pTree);
-+ //Find visual line
-+ SmNode* pLine = FindTopMostNodeInLine(pSNode, true);
-+
-+ //Clone selected nodes
-+ SmNodeList* pList;
-+ if(IsLineCompositionNode(pLine))
-+ pList = CloneLineToList((SmStructureNode*)pLine, true);
-+ else{
-+ pList = new SmNodeList();
-+ //Special care to only clone selected text
-+ if(pLine->GetType() == NTEXT) {
-+ SmTextNode *pText = (SmTextNode*)pLine;
-+ SmTextNode *pClone = new SmTextNode( pText->GetToken(), pText->GetFontDesc() );
-+ int start = pText->GetSelectionStart(),
-+ length = pText->GetSelectionEnd() - pText->GetSelectionStart();
-+ pClone->ChangeText(pText->GetText().Copy(start, length));
-+ pClone->SetScaleMode(pText->GetScaleMode());
-+ pList->push_front(pClone);
-+ } else {
-+ SmCloningVisitor aCloneFactory;
-+ pList->push_front(aCloneFactory.Clone(pLine));
-+ }
-+ }
-+
-+ //Set clipboard
-+ if(pList->size() > 0)
-+ SetClipboard(pList);
-+}
-+
-+void SmCursor::Paste() {
-+ BeginEdit();
-+ Delete();
-+
-+ if(pClipboard && pClipboard->size() > 0)
-+ InsertNodes(CloneList(pClipboard));
-+
-+ EndEdit();
-+}
-+
-+SmNodeList* SmCursor::CloneList(SmNodeList* pList){
-+ SmCloningVisitor aCloneFactory;
-+ SmNodeList* pClones = new SmNodeList();
-+
-+ SmNodeList::iterator it;
-+ for(it = pList->begin(); it != pList->end(); it++){
-+ SmNode *pClone = aCloneFactory.Clone(*it);
-+ pClones->push_back(pClone);
-+ }
-+
-+ return pClones;
-+}
-+
-+
-+void SmCursor::SetClipboard(SmNodeList* pList){
-+ if(pClipboard){
-+ //Delete all nodes on the clipboard
-+ SmNodeList::iterator it;
-+ for(it = pClipboard->begin(); it != pClipboard->end(); it++)
-+ delete (*it);
-+ delete pClipboard;
-+ }
-+ pClipboard = pList;
-+}
-+
-+SmNode* SmCursor::FindTopMostNodeInLine(SmNode* pSNode, bool MoveUpIfSelected){
-+ //If we haven't got a subnode
-+ if(!pSNode)
-+ return NULL;
-+
-+ //Move up parent untill we find a node who's
-+ //parent isn't selected and not a type of:
-+ // SmExpressionNode
-+ // SmBinHorNode
-+ // SmUnHorNode
-+ // SmAlignNode
-+ // SmFontNode
-+ while((MoveUpIfSelected && pSNode->GetParent()->IsSelected()) ||
-+ IsLineCompositionNode(pSNode->GetParent())){
-+ pSNode = pSNode->GetParent();
-+ j_assert(pSNode, "pSNode shouldn't be NULL, have we hit root node if so, this is bad!");
-+ if(!pSNode) //I've got to do something, nothing is probably the best solution :)
-+ return NULL;
-+ }
-+ //Now we have the selection line node
-+ return pSNode;
-+}
-+
-+SmNode* SmCursor::FindSelectedNode(SmNode* pNode){
-+ SmNodeIterator it(pNode);
-+ while(it.Next()){
-+ if(it->IsSelected())
-+ return it.Current();
-+ SmNode* pRetVal = FindSelectedNode(it.Current());
-+ if(pRetVal)
-+ return pRetVal;
-+ }
-+ return NULL;
-+}
-+
-+SmNodeList* SmCursor::LineToList(SmStructureNode* pLine, SmNodeList* list){
-+ SmNodeIterator it(pLine);
-+ while(it.Next()){
-+ switch(it->GetType()){
-+ case NUNHOR:
-+ case NEXPRESSION:
-+ case NBINHOR:
-+ case NALIGN:
-+ case NFONT:
-+ LineToList((SmStructureNode*)it.Current(), list);
-+ break;
-+ case NERROR:
-+ delete it.Current();
-+ break;
-+ default:
-+ list->push_back(it.Current());
-+ }
-+ }
-+ SmNodeArray emptyArray(0);
-+ pLine->SetSubNodes(emptyArray);
-+ delete pLine;
-+ return list;
-+}
-+
-+SmNodeList* SmCursor::CloneLineToList(SmStructureNode* pLine, bool bOnlyIfSelected, SmNodeList* pList){
-+ SmCloningVisitor aCloneFactory;
-+ SmNodeIterator it(pLine);
-+ while(it.Next()){
-+ if( IsLineCompositionNode( it.Current() ) )
-+ CloneLineToList( (SmStructureNode*)it.Current(), bOnlyIfSelected, pList );
-+ else if( (!bOnlyIfSelected || it->IsSelected()) && it->GetType() != NERROR ) {
-+ //Only clone selected text from SmTextNode
-+ if(it->GetType() == NTEXT) {
-+ SmTextNode *pText = (SmTextNode*)it.Current();
-+ SmTextNode *pClone = new SmTextNode( it->GetToken(), pText->GetFontDesc() );
-+ int start = pText->GetSelectionStart(),
-+ length = pText->GetSelectionEnd() - pText->GetSelectionStart();
-+ pClone->ChangeText(pText->GetText().Copy(start, length));
-+ pClone->SetScaleMode(pText->GetScaleMode());
-+ pList->push_back(pClone);
-+ } else
-+ pList->push_back(aCloneFactory.Clone(it.Current()));
-+ }
-+ }
-+ return pList;
-+}
-+
-+bool SmCursor::IsLineCompositionNode(SmNode* pNode){
-+ switch(pNode->GetType()){
-+ case NUNHOR:
-+ case NEXPRESSION:
-+ case NBINHOR:
-+ case NALIGN:
-+ case NFONT:
-+ return true;
-+ default:
-+ return false;
-+ }
-+ return false;
-+}
-+
-+int SmCursor::CountSelectedNodes(SmNode* pNode){
-+ int nCount = 0;
-+ SmNodeIterator it(pNode);
-+ while(it.Next()){
-+ if(it->IsSelected() && !IsLineCompositionNode(it.Current()))
-+ nCount++;
-+ nCount += CountSelectedNodes(it.Current());
-+ }
-+ return nCount;
-+}
-+
-+bool SmCursor::HasComplexSelection(){
-+ if(!HasSelection())
-+ return false;
-+ AnnotateSelection();
-+
-+ return CountSelectedNodes(pTree) > 1;
-+}
-+
-+void SmCursor::BeginEdit(){
-+ if(nEditSections++ > 0) return;
-+
-+ bIsEnabledSetModifiedSmDocShell = pDocShell->IsEnableSetModified();
-+ if( bIsEnabledSetModifiedSmDocShell )
-+ pDocShell->EnableSetModified( FALSE );
-+}
-+
-+void SmCursor::EndEdit(){
-+ if(--nEditSections > 0) return;
-+
-+ pDocShell->SetFormulaArranged(FALSE);
-+ //Okay, I don't know what this does... :)
-+ //It's used in SmDocShell::SetText and with places where everything is modified.
-+ //I think it does some magic, with sfx, but everything is totally undocumented so
-+ //it's kinda hard to tell...
-+ if ( bIsEnabledSetModifiedSmDocShell )
-+ pDocShell->EnableSetModified( bIsEnabledSetModifiedSmDocShell );
-+ //I think this notifies people around us that we've modified this document...
-+ pDocShell->SetModified(TRUE);
-+ //I think SmDocShell uses this value when it sends an update graphics event
-+ //Anyway comments elsewhere suggests it need to be updated...
-+ pDocShell->nModifyCount++;
-+
-+ //TODO: Consider copying the update accessability code from SmDocShell::SetText in here...
-+ //This somehow updates the size of SmGraphicView if it is running in embedded mode
-+ if( pDocShell->GetCreateMode() == SFX_CREATE_MODE_EMBEDDED )
-+ pDocShell->OnDocumentPrinterChanged(0);
-+
-+ //Request a replaint...
-+ RequestRepaint();
-+
-+ //Update the edit engine and text of the document
-+ String formula;
-+ SmNodeToTextVisitor(pTree, formula);
-+ //pTree->CreateTextFromNode(formula);
-+ pDocShell->aText = formula;
-+ pDocShell->GetEditEngine().SetText(formula);
-+}
-+
-+void SmCursor::RequestRepaint(){
-+ SmViewShell *pViewSh = SmGetActiveView();
-+ if( pViewSh ) {
-+ if ( SFX_CREATE_MODE_EMBEDDED == pDocShell->GetCreateMode() )
-+ pDocShell->Repaint();
-+ else
-+ pViewSh->GetGraphicWindow().Invalidate();
-+ }
-+}
-+
-+/////////////////////////////////////// SmNodeListParser ///////////////////////////////////////
-+
-+SmNode* SmNodeListParser::Parse(SmNodeList* list, bool bDeleteErrorNodes){
-+ pList = list;
-+ if(bDeleteErrorNodes){
-+ //Delete error nodes
-+ SmNodeList::iterator it = pList->begin();
-+ while(it != pList->end()) {
-+ if((*it)->GetType() == NERROR){
-+ //Delete and erase
-+ delete *it;
-+ it = pList->erase(it);
-+ }else
-+ it++;
-+ }
-+ }
-+ SmNode* retval = Expression();
-+ pList = NULL;
-+ return retval;
-+}
-+
-+SmNode* SmNodeListParser::Expression(){
-+ SmNodeArray NodeArray;
-+ //Accept as many relations as there is
-+ while(Terminal())
-+ NodeArray.push_back(Relation());
-+
-+ //Create SmExpressionNode, I hope SmToken() will do :)
-+ SmStructureNode* pExpr = new SmExpressionNode(SmToken());
-+ pExpr->SetSubNodes(NodeArray);
-+ return pExpr;
-+}
-+
-+SmNode* SmNodeListParser::Relation(){
-+ //Read a sum
-+ SmNode* pLeft = Sum();
-+ //While we have tokens and the next is a relation
-+ while(Terminal() && IsRelationOperator(Terminal()->GetToken())){
-+ //Take the operator
-+ SmNode* pOper = Take();
-+ //Find the right side of the relation
-+ SmNode* pRight = Sum();
-+ //Create new SmBinHorNode
-+ SmStructureNode* pNewNode = new SmBinHorNode(SmToken());
-+ pNewNode->SetSubNodes(pLeft, pOper, pRight);
-+ pLeft = pNewNode;
-+ }
-+ return pLeft;
-+}
-+
-+SmNode* SmNodeListParser::Sum(){
-+ //Read a product
-+ SmNode* pLeft = Product();
-+ //While we have tokens and the next is a sum
-+ while(Terminal() && IsSumOperator(Terminal()->GetToken())){
-+ //Take the operator
-+ SmNode* pOper = Take();
-+ //Find the right side of the sum
-+ SmNode* pRight = Product();
-+ //Create new SmBinHorNode
-+ SmStructureNode* pNewNode = new SmBinHorNode(SmToken());
-+ pNewNode->SetSubNodes(pLeft, pOper, pRight);
-+ pLeft = pNewNode;
-+ }
-+ return pLeft;
-+}
-+
-+SmNode* SmNodeListParser::Product(){
-+ //Read a Factor
-+ SmNode* pLeft = Factor();
-+ //While we have tokens and the next is a product
-+ while(Terminal() && IsProductOperator(Terminal()->GetToken())){
-+ //Take the operator
-+ SmNode* pOper = Take();
-+ //Find the right side of the operation
-+ SmNode* pRight = Factor();
-+ //Create new SmBinHorNode
-+ SmStructureNode* pNewNode = new SmBinHorNode(SmToken());
-+ pNewNode->SetSubNodes(pLeft, pOper, pRight);
-+ pLeft = pNewNode;
-+ }
-+ return pLeft;
-+}
-+
-+SmNode* SmNodeListParser::Factor(){
-+ //Read unary operations
-+ if(!Terminal())
-+ return Error();
-+ //Take care of unary operators
-+ else if(IsUnaryOperator(Terminal()->GetToken()))
-+ {
-+ SmStructureNode *pUnary = new SmUnHorNode(SmToken());
-+ SmNode *pOper = Terminal(),
-+ *pArg;
-+
-+ if(Next())
-+ pArg = Factor();
-+ else
-+ pArg = Error();
-+
-+ pUnary->SetSubNodes(pOper, pArg);
-+ return pUnary;
-+ }
-+ return Postfix();
-+}
-+
-+SmNode* SmNodeListParser::Postfix(){
-+ if(!Terminal())
-+ return Error();
-+ SmNode *pArg = NULL;
-+ if(IsPostfixOperator(Terminal()->GetToken()))
-+ pArg = Error();
-+ else if(IsOperator(Terminal()->GetToken()))
-+ return Error();
-+ else
-+ pArg = Take();
-+ while(Terminal() && IsPostfixOperator(Terminal()->GetToken())) {
-+ SmStructureNode *pUnary = new SmUnHorNode(SmToken());
-+ SmNode *pOper = Take();
-+ pUnary->SetSubNodes(pArg, pOper);
-+ pArg = pUnary;
-+ }
-+ return pArg;
-+}
-+
-+SmNode* SmNodeListParser::Error(){
-+ return new SmErrorNode(PE_UNEXPECTED_TOKEN, SmToken());
-+}
-+
-+BOOL SmNodeListParser::IsOperator(const SmToken &token) {
-+ return IsRelationOperator(token) ||
-+ IsSumOperator(token) ||
-+ IsProductOperator(token) ||
-+ IsUnaryOperator(token) ||
-+ IsPostfixOperator(token);
-+}
-+
-+BOOL SmNodeListParser::IsRelationOperator(const SmToken &token) {
-+ return token.nGroup & TGRELATION;
-+}
-+
-+BOOL SmNodeListParser::IsSumOperator(const SmToken &token) {
-+ return token.nGroup & TGSUM;
-+}
-+
-+BOOL SmNodeListParser::IsProductOperator(const SmToken &token) {
-+ return token.nGroup & TGPRODUCT &&
-+ token.eType != TWIDESLASH &&
-+ token.eType != TWIDEBACKSLASH &&
-+ token.eType != TUNDERBRACE &&
-+ token.eType != TOVERBRACE &&
-+ token.eType != TOVER;
-+}
-+
-+BOOL SmNodeListParser::IsUnaryOperator(const SmToken &token) {
-+ return token.nGroup & TGUNOPER &&
-+ (token.eType == TPLUS ||
-+ token.eType == TMINUS ||
-+ token.eType == TPLUSMINUS ||
-+ token.eType == TMINUSPLUS ||
-+ token.eType == TNEG ||
-+ token.eType == TUOPER);
-+}
-+
-+BOOL SmNodeListParser::IsPostfixOperator(const SmToken &token) {
-+ return token.eType == TFACT;
-+}
-diff --git starmath/source/dialog.cxx starmath/source/dialog.cxx
-index f8b8f7e..82e386a 100644
---- starmath/source/dialog.cxx
-+++ starmath/source/dialog.cxx
-@@ -1477,8 +1477,8 @@ IMPL_LINK( SmSymbolDialog, GetClickHdl, Button *, EMPTYARG pButton )
- aText += pSym->GetName();
-
- rViewSh.GetViewFrame()->GetDispatcher()->Execute(
-- SID_INSERTTEXT, SFX_CALLMODE_STANDARD,
-- new SfxStringItem(SID_INSERTTEXT, aText), 0L);
-+ SID_INSERTSYMBOL, SFX_CALLMODE_STANDARD,
-+ new SfxStringItem(SID_INSERTSYMBOL, aText), 0L);
- }
-
- return 0;
-diff --git starmath/source/document.cxx starmath/source/document.cxx
-index 259c26d..5985aa2 100644
---- starmath/source/document.cxx
-+++ starmath/source/document.cxx
-@@ -94,7 +94,7 @@
- #include "mathtype.hxx"
- #include "mathmlimport.hxx"
- #include "mathmlexport.hxx"
--
-+#include "cursor.hxx"
-
-
- using namespace ::com::sun::star;
-@@ -248,6 +248,7 @@ void SmDocShell::Parse()
- pTree = aInterpreter.Parse(aText);
- nModifyCount++;
- SetFormulaArranged( FALSE );
-+ InvalidateCursor();
- }
-
-
-@@ -434,9 +435,10 @@ SfxItemPool& SmDocShell::GetEditEngineItemPool()
- DBG_ASSERT( pEditEngineItemPool, "EditEngineItemPool missing" );
- return *pEditEngineItemPool;
- }
-+//TODO: Move to the top of the file...
-+#include "visitors.hxx"
-
--
--void SmDocShell::Draw(OutputDevice &rDev, Point &rPosition)
-+void SmDocShell::DrawFormula(OutputDevice &rDev, Point &rPosition, BOOL bDrawSelection)
- {
- RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::Draw" );
-
-@@ -477,8 +479,16 @@ void SmDocShell::Draw(OutputDevice &rDev, Point &rPosition)
- rDev.SetLayoutMode( TEXT_LAYOUT_BIDI_LTR );
- INT16 nDigitLang = rDev.GetDigitLanguage();
- rDev.SetDigitLanguage( LANGUAGE_ENGLISH );
-- //
-- pTree->Draw(rDev, rPosition);
-+
-+ //Set selection if any
-+ if(pCursor && bDrawSelection){
-+ pCursor->AnnotateSelection();
-+ SmSelectionDrawingVisitor(rDev, pTree, rPosition);
-+ }
-+
-+ //Drawing using visitor
-+ DrawingVisitor(rDev, rPosition, pTree);
-+
- //
- rDev.SetLayoutMode( nLayoutMode );
- rDev.SetDigitLanguage( nDigitLang );
-@@ -519,6 +529,18 @@ Size SmDocShell::GetSize()
- return aRet;
- }
-
-+void SmDocShell::InvalidateCursor(){
-+ if(pCursor)
-+ delete pCursor;
-+ pCursor = NULL;
-+}
-+
-+SmCursor& SmDocShell::GetCursor(){
-+ if(!pCursor)
-+ pCursor = new SmCursor(pTree, this);
-+ return *pCursor;
-+}
-+
- ////////////////////////////////////////
-
- SmPrinterAccess::SmPrinterAccess( SmDocShell &rDocShell )
-@@ -691,6 +713,7 @@ SmDocShell::SmDocShell(SfxObjectCreateMode eMode,const sal_Bool _bScriptSupport)
- nModifyCount ( 0 ),
- bIsFormulaArranged ( FALSE )
- {
-+ pCursor = NULL;
- RTL_LOGFILE_CONTEXT( aLog, "starmath: SmDocShell::SmDocShell" );
-
- SetPool(&SFX_APP()->GetPool());
-@@ -720,6 +743,11 @@ SmDocShell::~SmDocShell()
- EndListening(aFormat);
- EndListening(*pp->GetConfig());
-
-+
-+ if(pCursor)
-+ delete pCursor;
-+ pCursor = NULL;
-+
- delete pEditEngine;
- SfxItemPool::Free(pEditEngineItemPool);
- delete pTree;
-@@ -751,6 +779,7 @@ BOOL SmDocShell::ConvertFrom(SfxMedium &rMedium)
- {
- delete pTree;
- pTree = 0;
-+ InvalidateCursor();
- }
- Reference<com::sun::star::frame::XModel> xModel(GetModel());
- SmXMLImportWrapper aEquation(xModel);
-@@ -1313,7 +1342,7 @@ void SmDocShell::Draw(OutputDevice *pDevice,
-
- pDevice->IntersectClipRegion(GetVisArea());
- Point atmppoint;
-- Draw(*pDevice, atmppoint);
-+ DrawFormula(*pDevice, atmppoint);
- }
-
- SfxItemPool& SmDocShell::GetPool() const
-diff --git starmath/source/edit.cxx starmath/source/edit.cxx
-index 1994271..62905b4 100644
---- starmath/source/edit.cxx
-+++ starmath/source/edit.cxx
-@@ -122,9 +122,6 @@ SmEditWindow::SmEditWindow( SmCmdBoxWindow &rMyCmdBoxWin ) :
- aModifyTimer.SetTimeout(2000);
- aModifyTimer.Start();
-
-- aCursorMoveTimer.SetTimeoutHdl(LINK(this, SmEditWindow, CursorMoveTimerHdl));
-- aCursorMoveTimer.SetTimeout(500);
--
- // if not called explicitly the this edit window within the
- // command window will just show an empty gray panel.
- Show();
-@@ -133,7 +130,6 @@ SmEditWindow::SmEditWindow( SmCmdBoxWindow &rMyCmdBoxWin ) :
-
- SmEditWindow::~SmEditWindow()
- {
-- aCursorMoveTimer.Stop();
- aModifyTimer.Stop();
-
-
-@@ -257,35 +253,6 @@ IMPL_LINK( SmEditWindow, ModifyTimerHdl, Timer *, EMPTYARG /*pTimer*/ )
- return 0;
- }
-
--
--IMPL_LINK(SmEditWindow, CursorMoveTimerHdl, Timer *, EMPTYARG /*pTimer*/)
-- // every once in a while check cursor position (selection) of edit
-- // window and if it has changed (try to) set the formula-cursor
-- // according to that.
--{
-- ESelection aNewSelection (GetSelection());
--
-- if (!aNewSelection.IsEqual(aOldSelection))
-- { SmViewShell *pView = rCmdBox.GetView();
--
-- if (pView)
-- {
-- // get row and column to look for
-- USHORT nRow, nCol;
-- SmGetLeftSelectionPart(aNewSelection, nRow, nCol);
-- nRow++;
-- nCol++;
--
-- pView->GetGraphicWindow().SetCursorPos(nRow, nCol);
--
-- aOldSelection = aNewSelection;
-- }
-- }
--
-- return 0;
--}
--
--
- void SmEditWindow::Resize()
- {
- if (!pEditView)
-@@ -319,8 +286,6 @@ void SmEditWindow::MouseButtonUp(const MouseEvent &rEvt)
- else
- Window::MouseButtonUp (rEvt);
-
-- // ggf FormulaCursor neu positionieren
-- CursorMoveTimerHdl(&aCursorMoveTimer);
- InvalidateSlots();
- }
-
-@@ -425,10 +390,6 @@ void SmEditWindow::KeyInput(const KeyEvent& rKEvt)
- }
- else
- {
-- // Timer neu starten, um den Handler (auch bei laengeren Eingaben)
-- // moeglichst nur einmal am Ende aufzurufen.
-- aCursorMoveTimer.Start();
--
- DBG_ASSERT( pEditView, "EditView missing (NULL pointer)" );
- if (!pEditView)
- CreateEditView();
-@@ -631,7 +592,6 @@ void SmEditWindow::SetText(const XubString& rText)
- //! Hier die Timer neu zu starten verhindert, dass die Handler fuer andere
- //! (im Augenblick nicht mehr aktive) Math Tasks aufgerufen werden.
- aModifyTimer.Start();
-- aCursorMoveTimer.Start();
-
- pEditView->SetSelection(eSelection);
- }
-@@ -655,6 +615,10 @@ void SmEditWindow::GetFocus()
- EditEngine *pEditEngine = GetEditEngine();
- if (pEditEngine)
- pEditEngine->SetStatusEventHdl( LINK(this, SmEditWindow, EditStatusHdl) );
-+
-+ //Let SmViewShell know we got focus
-+ if(GetView())
-+ GetView()->SetInsertIntoEditWindow(TRUE);
- }
-
-
-@@ -925,13 +889,6 @@ void SmEditWindow::Flush()
- SID_TEXT, SFX_CALLMODE_STANDARD,
- new SfxStringItem(SID_TEXT, GetText()), 0L);
- }
--
-- if (aCursorMoveTimer.IsActive())
-- {
-- aCursorMoveTimer.Stop();
-- // ggf noch die (neue) FormulaCursor Position setzen
-- CursorMoveTimerHdl(&aCursorMoveTimer);
-- }
- }
-
-
-diff --git starmath/source/makefile.mk starmath/source/makefile.mk
-index 912e6e6..da8046e 100644
---- starmath/source/makefile.mk
-+++ starmath/source/makefile.mk
-@@ -63,6 +63,9 @@ SLO1FILES = \
- $(SLO)$/mathmlexport.obj \
- $(SLO)$/format.obj \
- $(SLO)$/node.obj \
-+ $(SLO)$/visitors.obj \
-+ $(SLO)$/caret.obj \
-+ $(SLO)$/cursor.obj \
- $(SLO)$/parse.obj \
- $(SLO)$/utility.obj \
- $(SLO)$/smdll.obj \
-diff --git starmath/source/node.cxx starmath/source/node.cxx
-index b243ced..cd68767 100644
---- starmath/source/node.cxx
-+++ starmath/source/node.cxx
-@@ -45,6 +45,7 @@
- #include "smmod.hxx"
- #include <document.hxx>
- #include <view.hxx>
-+#include "visitors.hxx"
- #ifndef _MATHTYPE_HXX
- #include "mathtype.hxx"
- #endif
-@@ -144,6 +145,8 @@ SmNode::SmNode(SmNodeType eNodeType, const SmToken &rNodeToken)
- eScaleMode = SCALE_NONE;
- aNodeToken = rNodeToken;
- nAccIndex = -1;
-+ SetSelected(false);
-+ aParentNode = NULL;
- }
-
-
-@@ -448,28 +451,6 @@ void SmNode::AdaptToY(const OutputDevice &/*rDev*/, ULONG /*nHeight*/)
- }
-
-
--void SmNode::Draw(OutputDevice &rDev, const Point &rPosition) const
--{
-- if (IsPhantom())
-- return;
--
-- const SmNode *pNode;
-- USHORT nSize = GetNumSubNodes();
-- for (USHORT i = 0; i < nSize; i++)
-- if (NULL != (pNode = GetSubNode(i)))
-- { Point aOffset (pNode->GetTopLeft() - GetTopLeft());
-- pNode->Draw(rDev, rPosition + aOffset);
-- }
--
--#ifdef SM_RECT_DEBUG
-- if (!IsDebug())
-- return;
--
-- int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
-- SmRect::Draw(rDev, rPosition, nRFlags);
--#endif
--}
--
- const SmNode * SmNode::FindTokenAt(USHORT nRow, USHORT nCol) const
- // returns (first) ** visible ** (sub)node with the tokens text at
- // position 'nRow', 'nCol'.
-@@ -570,6 +551,98 @@ const SmNode * SmNode::FindNodeWithAccessibleIndex(xub_StrLen nAccIdx) const
- return pResult;
- }
-
-+void SmNode::DumpAsDot(std::ostream &out, String* label, int number, int& id, int parent) const
-+{
-+ //If this is the root start the file
-+ if(number == -1){
-+ out<<"digraph {"<<std::endl;
-+ if(label){
-+ out<<"labelloc = \"t\";"<<std::endl;
-+ String eq(*label);
-+ //CreateTextFromNode(eq);
-+ eq.SearchAndReplaceAll(String::CreateFromAscii("\n"), String::CreateFromAscii(" "));
-+ eq.SearchAndReplaceAll(String::CreateFromAscii("\\"), String::CreateFromAscii("\\\\"));
-+ eq.SearchAndReplaceAll(String::CreateFromAscii("\""), String::CreateFromAscii("\\\""));
-+ out<<"label= \"Equation: \\\"";
-+ out<<ByteString( eq, RTL_TEXTENCODING_UTF8).GetBuffer();
-+ out<<"\\\"\";"<<std::endl;
-+ }
-+ }
-+
-+ //Some how out<<(int)this; doesn't work... So we do this nasty workaround...
-+ char strid[100];
-+ sprintf(strid, "%i", id);
-+
-+ char strnr[100];
-+ sprintf(strnr, "%i", number);
-+
-+ //Dump connection to this node
-+ if( parent != -1 ){
-+ char pid[100];
-+ sprintf(pid, "%i", parent);
-+ out<<"n"<<pid<<" -> n"<<strid<<" [label=\""<<strnr<<"\"];"<<std::endl;
-+ //If doesn't have parent and isn't a rootnode:
-+ } else if(number != -1) {
-+ out<<"orphaned -> n"<<strid<<" [label=\""<<strnr<<"\"];"<<std::endl;
-+ }
-+
-+ //Dump this node
-+ out<<"n"<< strid<<" [label=\"";
-+ switch( GetType() ) {
-+ case NTABLE: out<<"SmTableNode"; break;
-+ case NBRACE: out<<"SmBraceNode"; break;
-+ case NBRACEBODY: out<<"SmBracebodyNode"; break;
-+ case NOPER: out<<"SmOperNode"; break;
-+ case NALIGN: out<<"SmAlignNode"; break;
-+ case NATTRIBUT: out<<"SmAttributNode"; break;
-+ case NFONT: out<<"SmFontNode"; break;
-+ case NUNHOR: out<<"SmUnHorNode"; break;
-+ case NBINHOR: out<<"SmBinHorNode"; break;
-+ case NBINVER: out<<"SmBinVerNode"; break;
-+ case NBINDIAGONAL: out<<"SmBinDiagonalNode"; break;
-+ case NSUBSUP: out<<"SmSubSupNode"; break;
-+ case NMATRIX: out<<"SmMatrixNode"; break;
-+ case NPLACE: out<<"SmPlaceNode"; break;
-+ case NTEXT:
-+ out<<"SmTextNode: ";
-+ out<< ByteString( ((SmTextNode*)this)->GetText(), RTL_TEXTENCODING_UTF8).GetBuffer();
-+ break;
-+ case NSPECIAL: out<<"SmSpecialNode"; break;
-+ case NGLYPH_SPECIAL: out<<"SmGlyphSpecialNode"; break;
-+ case NMATH:
-+ out<<"SmMathSymbolNode: ";
-+ out<< ByteString( ((SmMathSymbolNode*)this)->GetText(), RTL_TEXTENCODING_UTF8).GetBuffer();
-+ break;
-+ case NBLANK: out<<"SmBlankNode"; break;
-+ case NERROR: out<<"SmErrorNode"; break;
-+ case NLINE: out<<"SmLineNode"; break;
-+ case NEXPRESSION: out<<"SmExpressionNode"; break;
-+ case NPOLYLINE: out<<"SmPolyLineNode"; break;
-+ case NROOT: out<<"SmRootNode"; break;
-+ case NROOTSYMBOL: out<<"SmRootSymbolNode"; break;
-+ case NRECTANGLE: out<<"SmRectangleNode"; break;
-+ case NVERTICAL_BRACE: out<<"SmVerticalBraceNode"; break;
-+ default:
-+ out<<"Unknown Node";
-+ }
-+ out<<"\"";
-+ if(IsSelected())
-+ out<<", style=dashed";
-+ out<<"];"<<std::endl;
-+
-+ //Dump subnodes
-+ int myid = id;
-+ const SmNode *pNode;
-+ USHORT nSize = GetNumSubNodes();
-+ for (USHORT i = 0; i < nSize; i++)
-+ if (NULL != (pNode = GetSubNode(i)))
-+ pNode->DumpAsDot(out, NULL, i, ++id, myid);
-+
-+ //If this is the root end the file
-+ if( number == -1 )
-+ out<<"}"<<std::endl;
-+}
-+
- ///////////////////////////////////////////////////////////////////////////
-
- SmStructureNode::SmStructureNode( const SmStructureNode &rNode ) :
-@@ -587,6 +660,7 @@ SmStructureNode::SmStructureNode( const SmStructureNode &rNode ) :
- SmNode *pNode = rNode.aSubNodes[i];
- aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0;
- }
-+ ClaimPaternity();
- }
-
-
-@@ -617,6 +691,8 @@ SmStructureNode & SmStructureNode::operator = ( const SmStructureNode &rNode )
- aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0;
- }
-
-+ ClaimPaternity();
-+
- return *this;
- }
-
-@@ -631,12 +707,15 @@ void SmStructureNode::SetSubNodes(SmNode *pFirst, SmNode *pSecond, SmNode *pThir
- aSubNodes[1] = pSecond;
- if (pThird)
- aSubNodes[2] = pThird;
-+
-+ ClaimPaternity();
- }
-
-
- void SmStructureNode::SetSubNodes(const SmNodeArray &rNodeArray)
- {
- aSubNodes = rNodeArray;
-+ ClaimPaternity();
- }
-
-
-@@ -2181,36 +2260,6 @@ void SmPolyLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
- }
-
-
--void SmPolyLineNode::Draw(OutputDevice &rDev, const Point &rPosition) const
--{
-- if (IsPhantom())
-- return;
--
-- long nBorderwidth = GetFont().GetBorderWidth();
--
-- LineInfo aInfo;
-- aInfo.SetWidth(nWidth - 2 * nBorderwidth);
--
-- Point aOffset (Point() - aPoly.GetBoundRect().TopLeft()
-- + Point(nBorderwidth, nBorderwidth)),
-- aPos (rPosition + aOffset);
-- ((Polygon &) aPoly).Move(aPos.X(), aPos.Y());
--
-- SmTmpDevice aTmpDev ((OutputDevice &) rDev, FALSE);
-- aTmpDev.SetLineColor( GetFont().GetColor() );
--
-- rDev.DrawPolyLine(aPoly, aInfo);
--
--#ifdef SM_RECT_DEBUG
-- if (!IsDebug())
-- return;
--
-- int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
-- SmRect::Draw(rDev, rPosition, nRFlags);
--#endif
--}
--
--
- /**************************************************************************/
-
- void SmRootSymbolNode::AdaptToX(const OutputDevice &/*rDev*/, ULONG nWidth)
-@@ -2227,48 +2276,6 @@ void SmRootSymbolNode::AdaptToY(const OutputDevice &rDev, ULONG nHeight)
- }
-
-
--void SmRootSymbolNode::Draw(OutputDevice &rDev, const Point &rPosition) const
--{
-- if (IsPhantom())
-- return;
--
-- // draw root-sign itself
-- SmMathSymbolNode::Draw(rDev, rPosition);
--
-- SmTmpDevice aTmpDev( (OutputDevice &) rDev, TRUE );
-- aTmpDev.SetFillColor(GetFont().GetColor());
-- rDev.SetLineColor();
-- aTmpDev.SetFont( GetFont() );
--
-- // since the width is always unscaled it corresponds ot the _original_
-- // _unscaled_ font height to be used, we use that to calculate the
-- // bar height. Thus it is independent of the arguments height.
-- // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
-- long nBarHeight = GetWidth() * 7L / 100L;
-- long nBarWidth = nBodyWidth + GetBorderWidth();
-- Point aBarOffset( GetWidth(), +GetBorderWidth() );
-- Point aBarPos( rPosition + aBarOffset );
--
-- Rectangle aBar(aBarPos, Size( nBarWidth, nBarHeight) );
-- //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
-- //! increasing zoomfactor.
-- // This is done by shifting it's output-position to a point that
-- // corresponds exactly to a pixel on the output device.
-- Point aDrawPos( rDev.PixelToLogic(rDev.LogicToPixel(aBar.TopLeft())) );
-- //aDrawPos.X() = aBar.Left(); //! don't change X position
-- aBar.SetPos( aDrawPos );
--
-- rDev.DrawRect( aBar );
--
--#ifdef SM_RECT_DEBUG
-- if (!IsDebug())
-- return;
--
-- int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
-- SmRect::Draw(rDev, rPosition, nRFlags);
--#endif
--}
--
-
- /**************************************************************************/
-
-@@ -2310,47 +2317,6 @@ void SmRectangleNode::Arrange(const OutputDevice &rDev, const SmFormat &/*rForma
- }
-
-
--void SmRectangleNode::Draw(OutputDevice &rDev, const Point &rPosition) const
--{
-- if (IsPhantom())
-- return;
--
-- SmTmpDevice aTmpDev ((OutputDevice &) rDev, FALSE);
-- aTmpDev.SetFillColor(GetFont().GetColor());
-- rDev.SetLineColor();
-- aTmpDev.SetFont(GetFont());
--
-- ULONG nTmpBorderWidth = GetFont().GetBorderWidth();
--
-- // get rectangle and remove borderspace
-- Rectangle aTmp (AsRectangle() + rPosition - GetTopLeft());
-- aTmp.Left() += nTmpBorderWidth;
-- aTmp.Right() -= nTmpBorderWidth;
-- aTmp.Top() += nTmpBorderWidth;
-- aTmp.Bottom() -= nTmpBorderWidth;
--
-- DBG_ASSERT(aTmp.GetHeight() > 0 && aTmp.GetWidth() > 0,
-- "Sm: leeres Rechteck");
--
-- //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
-- //! increasing zoomfactor.
-- // This is done by shifting it's output-position to a point that
-- // corresponds exactly to a pixel on the output device.
-- Point aPos (rDev.PixelToLogic(rDev.LogicToPixel(aTmp.TopLeft())));
-- aTmp.SetPos(aPos);
--
-- rDev.DrawRect(aTmp);
--
--#ifdef SM_RECT_DEBUG
-- if (!IsDebug())
-- return;
--
-- int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
-- SmRect::Draw(rDev, rPosition, nRFlags);
--#endif
--}
--
--
- /**************************************************************************/
-
-
-@@ -2445,29 +2411,6 @@ void SmTextNode::CreateTextFromNode(String &rText)
- rText.Append(' ');
- }
-
--void SmTextNode::Draw(OutputDevice &rDev, const Point& rPosition) const
--{
-- if (IsPhantom() || aText.Len() == 0 || aText.GetChar(0) == xub_Unicode('\0'))
-- return;
--
-- SmTmpDevice aTmpDev ((OutputDevice &) rDev, FALSE);
-- aTmpDev.SetFont(GetFont());
--
-- Point aPos (rPosition);
-- aPos.Y() += GetBaselineOffset();
-- // auf Pixelkoordinaten runden
-- aPos = rDev.PixelToLogic( rDev.LogicToPixel(aPos) );
--
-- rDev.DrawStretchText(aPos, GetWidth(), aText);
--
--#ifdef SM_RECT_DEBUG
-- if (!IsDebug())
-- return;
--
-- int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
-- SmRect::Draw(rDev, rPosition, nRFlags);
--#endif
--}
-
- void SmTextNode::GetAccessibleText( String &rText ) const
- {
-@@ -2804,7 +2747,7 @@ void SmSpecialNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell
-
- const SmSym *pSym;
- SmModule *pp = SM_MOD1();
--
-+
- if (NULL != (pSym = pp->GetSymSetManager().GetSymbolByName(GetToken().aText)))
- {
- SetText( pSym->GetCharacter() );
-@@ -2844,17 +2787,6 @@ void SmSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
- SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
- }
-
--
--void SmSpecialNode::Draw(OutputDevice &rDev, const Point& rPosition) const
--{
-- //! since this chars might come from any font, that we may not have
-- //! set to ALIGN_BASELINE yet, we do it now.
-- ((SmSpecialNode *)this)->GetFont().SetAlign(ALIGN_BASELINE);
--
-- SmTextNode::Draw(rDev, rPosition);
--}
--
--
- /**************************************************************************/
-
-
-@@ -2965,5 +2897,122 @@ void SmBlankNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
- SetWidth(nSpace);
- }
-
-+/**************************************************************************/
-+//Implementation of all accept methods for SmVisitor
-+
-+void SmNode::Accept(SmVisitor*){
-+ //This method is only implemented to avoid making SmNode abstract because an
-+ //obscure copy constructor is used... I can't find it's implementation, and
-+ //don't want to figure out how to fix it... If you want to, just delete this
-+ //method, making SmNode abstract, and see where you can an problem with that.
-+ j_assert(false, "SmNode should not be visitable!");
-+}
-+
-+void SmTableNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmBraceNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmBracebodyNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmOperNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmAlignNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmAttributNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmFontNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmUnHorNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmBinHorNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-
-+void SmBinVerNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmBinDiagonalNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmSubSupNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmMatrixNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmPlaceNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmTextNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmSpecialNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmGlyphSpecialNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmMathSymbolNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmBlankNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmErrorNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmLineNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmExpressionNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmPolyLineNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmRootNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmRootSymbolNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmRectangleNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-+
-+void SmVerticalBraceNode::Accept(SmVisitor* pVisitor) {
-+ pVisitor->Visit(this);
-+}
-
-diff --git starmath/source/parse.cxx starmath/source/parse.cxx
-index aab3502..0bda46c 100644
---- starmath/source/parse.cxx
-+++ starmath/source/parse.cxx
-@@ -84,6 +84,19 @@ SmToken::SmToken() :
- nGroup = nCol = nRow = nLevel = 0;
- }
-
-+SmToken::SmToken(SmTokenType eTokenType,
-+ sal_Unicode cMath,
-+ const sal_Char* pText,
-+ ULONG nTokenGroup,
-+ USHORT nTokenLevel) {
-+ eType = eTokenType;
-+ cMathChar = cMath;
-+ aText.AssignAscii(pText);
-+ nGroup = nTokenGroup;
-+ nLevel = nTokenLevel;
-+ nCol = nRow = 0;
-+}
-+
- ///////////////////////////////////////////////////////////////////////////
-
- struct SmTokenTableEntry
-@@ -1124,6 +1137,13 @@ void SmParser::Line()
- ExpressionArray[n - 1] = NodeStack.Pop();
- }
-
-+ //If there's no expression, add an empty one.
-+ //this is to avoid a formula tree without any caret
-+ //positions, in visual formula editor.
-+ if(ExpressionArray.size() == 0)
-+ ExpressionArray.push_back(new SmExpressionNode(SmToken()));
-+
-+
- SmStructureNode *pSNode = new SmLineNode(CurToken);
- pSNode->SetSubNodes(ExpressionArray);
- NodeStack.Push(pSNode);
-@@ -1215,6 +1235,10 @@ void SmParser::Product()
-
- NextToken();
-
-+ //Let the glyph node know it's a binary operation
-+ CurToken.eType = TBOPER;
-+ CurToken.nGroup = TGPRODUCT;
-+
- GlyphSpecial();
- pOper = NodeStack.Pop();
- break;
-@@ -1704,6 +1728,9 @@ void SmParser::UnOper()
-
- case TUOPER :
- NextToken();
-+ //Let the glyph know what it is...
-+ CurToken.eType = TUOPER;
-+ CurToken.nGroup = TGUNOPER;
- GlyphSpecial();
- pOper = NodeStack.Pop();
- break;
-@@ -2203,7 +2230,11 @@ void SmParser::Stack()
-
- NextToken();
-
-- SmStructureNode *pSNode = new SmTableNode(CurToken);
-+ //We need to let the table node know it context
-+ //it's used in SmNodeToTextVisitor
-+ SmToken aTok = CurToken;
-+ aTok.eType = TSTACK;
-+ SmStructureNode *pSNode = new SmTableNode(aTok);
- pSNode->SetSubNodes(ExpressionArray);
- NodeStack.Push(pSNode);
- }
-@@ -2382,7 +2413,7 @@ SmNode *SmParser::Parse(const String &rBuffer)
- {
- BufferString = rBuffer;
- BufferString.ConvertLineEnd( LINEEND_LF );
-- BufferIndex =
-+ BufferIndex = 0;
- nTokenIndex = 0;
- Row = 1;
- ColOff = 0;
-@@ -2402,6 +2433,30 @@ SmNode *SmParser::Parse(const String &rBuffer)
- return NodeStack.Pop();
- }
-
-+SmNode *SmParser::ParseExpression(const String &rBuffer)
-+{
-+ BufferString = rBuffer;
-+ BufferString.ConvertLineEnd( LINEEND_LF );
-+ BufferIndex = 0;
-+ nTokenIndex = 0;
-+ Row = 1;
-+ ColOff = 0;
-+ CurError = -1;
-+
-+ for (USHORT i = 0; i < ErrDescList.Count(); i++)
-+ delete ErrDescList.Remove(i);
-+
-+ ErrDescList.Clear();
-+
-+ NodeStack.Clear();
-+
-+ SetLanguage( Application::GetSettings().GetUILanguage() );
-+ NextToken();
-+ Expression();
-+
-+ return NodeStack.Pop();
-+}
-+
-
- USHORT SmParser::AddError(SmParseError Type, SmNode *pNode)
- {
-diff --git starmath/source/view.cxx starmath/source/view.cxx
-index f00036f..24e51a0 100644
---- starmath/source/view.cxx
-+++ starmath/source/view.cxx
-@@ -65,6 +65,7 @@
- #include <vcl/menu.hxx>
- #include <vcl/msgbox.hxx>
- #include <vcl/wrkwin.hxx>
-+#include <fstream>
-
- #include "view.hxx"
- #include "config.hxx"
-@@ -73,7 +74,7 @@
- #include "starmath.hrc"
- #include "toolbox.hxx"
- #include "mathmlimport.hxx"
--
-+#include "cursor.hxx"
-
- #define MINWIDTH 200
- #define MINHEIGHT 200
-@@ -98,8 +99,7 @@ SmGraphicWindow::SmGraphicWindow(SmViewShell* pShell):
- ScrollableWindow(&pShell->GetViewFrame()->GetWindow(), 0),
- pAccessible(0),
- pViewShell(pShell),
-- nZoom(100),
-- bIsCursorVisible(FALSE)
-+ nZoom(100)
- {
- // docking windows are usually hidden (often already done in the
- // resource) and will be shown by the sfx framework.
-@@ -156,65 +156,32 @@ void SmGraphicWindow::MouseButtonDown(const MouseEvent& rMEvt)
- {
- ScrollableWindow::MouseButtonDown(rMEvt);
-
-+ GrabFocus();
-+
- //
- // set formula-cursor and selection of edit window according to the
- // position clicked at
- //
- DBG_ASSERT(rMEvt.GetClicks() > 0, "Sm : 0 clicks");
-- if ( rMEvt.IsLeft() && pViewShell->GetEditWindow() )
-+ if ( rMEvt.IsLeft() )
- {
-- const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree();
-- //! kann NULL sein! ZB wenn bereits beim laden des Dokuments (bevor der
-- //! Parser angeworfen wurde) ins Fenster geklickt wird.
-- if (!pTree)
-- return;
--
- // get click position relativ to formula
- Point aPos (PixelToLogic(rMEvt.GetPosPixel())
- - GetFormulaDrawPos());
-
-+ const SmNode* pTree = pViewShell->GetDoc()->GetFormulaTree();
-+
- // if it was clicked inside the formula then get the appropriate node
-- const SmNode *pNode = 0;
- if (pTree->OrientedDist(aPos) <= 0)
-- pNode = pTree->FindRectClosestTo(aPos);
--
-- if (pNode)
-- { SmEditWindow *pEdit = pViewShell->GetEditWindow();
-- const SmToken aToken (pNode->GetToken());
--
--#ifdef notnow
-- // include introducing symbols of special char and text
-- // (ie '%' and '"')
-- USHORT nExtra = (aToken.eType == TSPECIAL || aToken.eType == TTEXT) ? 1 : 0;
--
-- // set selection to the beginning of the token
-- ESelection aSel (aToken.nRow - 1, aToken.nCol - 1 - nExtra);
--
-- if (rMEvt.GetClicks() != 1)
-- { // select whole token
-- // for text include terminating symbol (ie '"')
-- aSel.nEndPos += aToken.aText.Len() + nExtra
-- + (aToken.eType == TTEXT ? 1 : 0);
-- }
--#endif
-- // set selection to the beginning of the token
-- ESelection aSel (aToken.nRow - 1, aToken.nCol - 1);
--
-- if (rMEvt.GetClicks() != 1 || aToken.eType == TPLACE)
-- aSel.nEndPos = aSel.nEndPos + sal::static_int_cast< USHORT >(aToken.aText.Len());
--
-- pEdit->SetSelection(aSel);
-- SetCursor(pNode);
--
-- // allow for immediate editing and
-- //! implicitly synchronize the cursor position mark in this window
-- pEdit->GrabFocus();
-- }
-+ pViewShell->GetDoc()->GetCursor().MoveTo(this, aPos, !rMEvt.IsShift());
- }
- }
-
- void SmGraphicWindow::GetFocus()
- {
-+ pViewShell->GetEditWindow()->Flush();
-+ //Let view shell know what insertions should be done in visual editor
-+ pViewShell->SetInsertIntoEditWindow(FALSE);
- /*
- if (xAccessible.is())
- {
-@@ -240,69 +207,6 @@ void SmGraphicWindow::LoseFocus()
- }
- }
-
--void SmGraphicWindow::ShowCursor(BOOL bShow)
-- // shows or hides the formula-cursor depending on 'bShow' is TRUE or not
--{
-- BOOL bInvert = bShow != IsCursorVisible();
--
-- if (bInvert)
-- InvertTracking(aCursorRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW);
--
-- SetIsCursorVisible(bShow);
--}
--
--
--void SmGraphicWindow::SetCursor(const SmNode *pNode)
--{
-- const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree();
--
-- // get appropriate rectangle
-- Point aOffset (pNode->GetTopLeft() - pTree->GetTopLeft()),
-- aTLPos (GetFormulaDrawPos() + aOffset);
-- aTLPos.X() -= pNode->GetItalicLeftSpace();
-- Size aSize (pNode->GetItalicSize());
-- Point aBRPos (aTLPos.X() + aSize.Width(), aTLPos.Y() + aSize.Height());
--
-- SetCursor(Rectangle(aTLPos, aSize));
--}
--
--void SmGraphicWindow::SetCursor(const Rectangle &rRect)
-- // sets cursor to new position (rectangle) 'rRect'.
-- // The old cursor will be removed, and the new one will be shown if
-- // that is activated in the ConfigItem
--{
-- SmModule *pp = SM_MOD1();
--
-- if (IsCursorVisible())
-- ShowCursor(FALSE); // clean up remainings of old cursor
-- aCursorRect = rRect;
-- if (pp->GetConfig()->IsShowFormulaCursor())
-- ShowCursor(TRUE); // draw new cursor
--}
--
--const SmNode * SmGraphicWindow::SetCursorPos(USHORT nRow, USHORT nCol)
-- // looks for a VISIBLE node in the formula tree with it's token at
-- // (or around) the position 'nRow', 'nCol' in the edit window
-- // (row and column numbering starts with 1 there!).
-- // If there is such a node the formula-cursor is set to cover that nodes
-- // rectangle. If not the formula-cursor will be hidden.
-- // In any case the search result is being returned.
--{
-- // find visible node with token at nRow, nCol
-- const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree(),
-- *pNode = 0;
-- if (pTree)
-- pNode = pTree->FindTokenAt(nRow, nCol);
--
-- if (pNode)
-- SetCursor(pNode);
-- else
-- ShowCursor(FALSE);
--
-- return pNode;
--}
--
--
- void SmGraphicWindow::Paint(const Rectangle&)
- {
- DBG_ASSERT(pViewShell, "Sm : NULL pointer");
-@@ -310,25 +214,12 @@ void SmGraphicWindow::Paint(const Rectangle&)
- SmDocShell &rDoc = *pViewShell->GetDoc();
- Point aPoint;
-
-- rDoc.Draw(*this, aPoint); //! modifies aPoint to be the topleft
-+ rDoc.DrawFormula(*this, aPoint, TRUE); //! modifies aPoint to be the topleft
- //! corner of the formula
- SetFormulaDrawPos(aPoint);
--
-- SetIsCursorVisible(FALSE); // (old) cursor must be drawn again
--
-- const SmEditWindow *pEdit = pViewShell->GetEditWindow();
-- if (pEdit)
-- { // get new position for formula-cursor (for possible altered formula)
-- USHORT nRow, nCol;
-- SmGetLeftSelectionPart(pEdit->GetSelection(), nRow, nCol);
-- nRow++;
-- nCol++;
-- const SmNode *pFound = SetCursorPos(nRow, nCol);
--
-- SmModule *pp = SM_MOD1();
-- if (pFound && pp->GetConfig()->IsShowFormulaCursor())
-- ShowCursor(TRUE);
-- }
-+ //Draw cursor if any...
-+ if(pViewShell->GetDoc()->HasCursor())
-+ pViewShell->GetDoc()->GetCursor().Draw(*this, aPoint);
- }
-
-
-@@ -340,11 +231,111 @@ void SmGraphicWindow::SetTotalSize ()
- ScrollableWindow::SetTotalSize( aTmp );
- }
-
--
- void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt)
- {
-- if (! (GetView() && GetView()->KeyInput(rKEvt)) )
-- ScrollableWindow::KeyInput(rKEvt);
-+ USHORT nCode = rKEvt.GetKeyCode().GetCode();
-+ SmCursor& rCursor = pViewShell->GetDoc()->GetCursor();
-+ switch(nCode)
-+ {
-+ case KEY_LEFT:
-+ {
-+ rCursor.Move(this, MoveLeft, !rKEvt.GetKeyCode().IsShift());
-+ }break;
-+ case KEY_RIGHT:
-+ {
-+ rCursor.Move(this, MoveRight, !rKEvt.GetKeyCode().IsShift());
-+ }break;
-+ case KEY_UP:
-+ {
-+ rCursor.Move(this, MoveUp, !rKEvt.GetKeyCode().IsShift());
-+ }break;
-+ case KEY_DOWN:
-+ {
-+ rCursor.Move(this, MoveDown, !rKEvt.GetKeyCode().IsShift());
-+ }break;
-+ case KEY_RETURN:
-+ {
-+ if(!rKEvt.GetKeyCode().IsShift())
-+ rCursor.InsertRow();
-+ else {
-+ SmNode *pTree = (SmNode*)pViewShell->GetDoc()->GetFormulaTree();
-+ std::fstream file("/tmp/smath-dump.gv", std::fstream::out);
-+ String label(pViewShell->GetDoc()->GetText());
-+ pTree->DumpAsDot(file, &label);
-+ file.close();
-+ }
-+ }break;
-+ case KEY_DELETE:
-+ case KEY_BACKSPACE:
-+ {
-+ if(!rCursor.HasSelection()){
-+ rCursor.Move(this, nCode == KEY_DELETE ? MoveRight : MoveLeft, false);
-+ if(rCursor.HasComplexSelection()) break;
-+ }
-+ rCursor.Delete();
-+ }break;
-+ case KEY_ADD:
-+ rCursor.InsertElement(PlusElement);
-+ break;
-+ case KEY_SUBTRACT:
-+ if(rKEvt.GetKeyCode().IsShift())
-+ rCursor.InsertSubSup(RSUB);
-+ else
-+ rCursor.InsertElement(MinusElement);
-+ break;
-+ case KEY_MULTIPLY:
-+ rCursor.InsertElement(CDotElement);
-+ break;
-+ case KEY_DIVIDE:
-+ rCursor.InsertFraction();
-+ break;
-+ case KEY_LESS:
-+ rCursor.InsertElement(LessThanElement);
-+ break;
-+ case KEY_GREATER:
-+ rCursor.InsertElement(GreaterThanElement);
-+ break;
-+ case KEY_EQUAL:
-+ rCursor.InsertElement(EqualElement);
-+ break;
-+ case KEY_COPY:
-+ rCursor.Copy();
-+ break;
-+ case KEY_CUT:
-+ rCursor.Cut();
-+ break;
-+ case KEY_PASTE:
-+ rCursor.Paste();
-+ break;
-+ default:
-+ {
-+ sal_Unicode code = rKEvt.GetCharCode();
-+ if(code == ' ') {
-+ rCursor.InsertElement(BlankElement);
-+ }else if(code == 'c' && rKEvt.GetKeyCode().IsMod1()) {
-+ rCursor.Copy();
-+ }else if(code == 'x' && rKEvt.GetKeyCode().IsMod1()) {
-+ rCursor.Cut();
-+ }else if(code == 'v' && rKEvt.GetKeyCode().IsMod1()) {
-+ rCursor.Paste();
-+ }else if(code == '^') {
-+ rCursor.InsertSubSup(RSUP);
-+ }else if(code == '(') {
-+ rCursor.InsertBrackets(RoundBrackets);
-+ }else if(code == '[') {
-+ rCursor.InsertBrackets(SquareBrackets);
-+ }else if(code == '{') {
-+ rCursor.InsertBrackets(CurlyBrackets);
-+ }else if(code == '!') {
-+ rCursor.InsertElement(FactorialElement);
-+ }else{
-+ if(code != 0){
-+ rCursor.InsertText(code);
-+ }else if (! (GetView() && GetView()->KeyInput(rKEvt)) )
-+ ScrollableWindow::KeyInput(rKEvt);
-+ }
-+ }
-+ }
- }
-
-
-@@ -1146,7 +1137,7 @@ void SmViewShell::Impl_Print(
-
- rOutDev.SetMapMode(OutputMapMode);
- rOutDev.SetClipRegion(Region(aOutRect));
-- GetDoc()->Draw(rOutDev, aPos);
-+ GetDoc()->DrawFormula(rOutDev, aPos, FALSE);
- rOutDev.SetClipRegion();
-
- rOutDev.Pop();
-@@ -1418,7 +1409,8 @@ void SmViewShell::Execute(SfxRequest& rReq)
- bVal = !pp->GetConfig()->IsShowFormulaCursor();
-
- pp->GetConfig()->SetShowFormulaCursor(bVal);
-- GetGraphicWindow().ShowCursor(bVal);
-+ //GetGraphicWindow().ShowCursor(bVal);
-+ //TODO Consider disabling this option!!!
- break;
- }
- case SID_DRAW:
-@@ -1563,18 +1555,24 @@ void SmViewShell::Execute(SfxRequest& rReq)
- const SfxInt16Item& rItem =
- (const SfxInt16Item&)rReq.GetArgs()->Get(SID_INSERTCOMMAND);
-
-- if (pWin)
-+ if (pWin && bInsertIntoEditWindow)
- pWin->InsertCommand(rItem.GetValue());
-+ if (GetDoc() && !bInsertIntoEditWindow) {
-+ GetDoc()->GetCursor().InsertCommand(rItem.GetValue());
-+ GetGraphicWindow().GrabFocus();
-+ }
- break;
- }
-
-- case SID_INSERTTEXT:
-+ case SID_INSERTSYMBOL:
- {
- const SfxStringItem& rItem =
-- (const SfxStringItem&)rReq.GetArgs()->Get(SID_INSERTTEXT);
-+ (const SfxStringItem&)rReq.GetArgs()->Get(SID_INSERTSYMBOL);
-
-- if (pWin)
-+ if (pWin && bInsertIntoEditWindow)
- pWin->InsertText(rItem.GetValue());
-+ if(GetDoc() && !bInsertIntoEditWindow)
-+ GetDoc()->GetCursor().InsertSpecial(rItem.GetValue());
- break;
- }
-
-diff --git starmath/source/visitors.cxx starmath/source/visitors.cxx
-new file mode 100644
-index 0000000..c7e886d
---- /dev/null
-+++ starmath/source/visitors.cxx
-@@ -0,0 +1,2466 @@
-+#include "visitors.hxx"
-+#include "cursor.hxx"
-+
-+///////////////////////////////////// SmVisitorTest /////////////////////////////////////
-+
-+void SmVisitorTest::Visit( SmTableNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NTABLE, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmBraceNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NBRACE, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmBracebodyNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NBRACEBODY, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmOperNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NOPER, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmAlignNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NALIGN, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmAttributNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NATTRIBUT, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmFontNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NFONT, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmUnHorNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NUNHOR, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmBinHorNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NBINHOR, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmBinVerNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NBINVER, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmBinDiagonalNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NBINDIAGONAL, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmSubSupNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NSUBSUP, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmMatrixNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NMATRIX, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmPlaceNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NPLACE, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmTextNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NTEXT, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmSpecialNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NSPECIAL, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmGlyphSpecialNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NGLYPH_SPECIAL, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmMathSymbolNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NMATH, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmBlankNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NBLANK, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmErrorNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NERROR, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmLineNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NLINE, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmExpressionNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NEXPRESSION, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmPolyLineNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NPOLYLINE, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmRootNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NROOT, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmRootSymbolNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NROOTSYMBOL, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmRectangleNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NRECTANGLE, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::Visit( SmVerticalBraceNode* pNode )
-+{
-+ j_assert( pNode->GetType( ) == NVERTICAL_BRACE, "the visitor-patterns isn't implemented correctly" );
-+ VisitChildren( pNode );
-+}
-+
-+void SmVisitorTest::VisitChildren( SmNode* pNode )
-+{
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ it->Accept( this );
-+}
-+
-+/////////////////////////////// SmDefaultingVisitor ////////////////////////////////
-+
-+void SmDefaultingVisitor::Visit( SmTableNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmBraceNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmBracebodyNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmOperNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmAlignNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmAttributNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmFontNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmUnHorNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmBinHorNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmBinVerNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmBinDiagonalNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmSubSupNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmMatrixNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmPlaceNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmTextNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmSpecialNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmGlyphSpecialNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmMathSymbolNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmBlankNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmErrorNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmLineNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmExpressionNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmPolyLineNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmRootNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmRootSymbolNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmRectangleNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+void SmDefaultingVisitor::Visit( SmVerticalBraceNode* pNode )
-+{
-+ DefaultVisit( pNode );
-+}
-+
-+
-+/////////////////////////////// SmCaretDrawingVisitor ////////////////////////////////
-+
-+SmCaretDrawingVisitor::SmCaretDrawingVisitor( OutputDevice& rDevice,
-+ SmCaretPos position,
-+ Point offset )
-+ : rDev( rDevice )
-+{
-+ pos = position;
-+ Offset = offset;
-+ j_assert( position.IsValid( ), "Cannot draw invalid position!" );
-+ if( !position.IsValid( ) )
-+ return;
-+
-+ //Save device state
-+ rDev.Push( PUSH_FONT | PUSH_MAPMODE | PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR );
-+
-+ pos.pSelectedNode->Accept( this );
-+ //Restore device state
-+ rDev.Pop( );
-+}
-+
-+void SmCaretDrawingVisitor::Visit( SmTextNode* pNode )
-+{
-+ long i = pos.Index;
-+
-+ rDev.SetFont( pNode->GetFont( ) );
-+
-+ //Find the line
-+ SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
-+
-+ //Find coordinates
-+ long left = pNode->GetLeft( ) + rDev.GetTextWidth( pNode->GetText( ), 0, i ) + Offset.X( );
-+ long top = pLine->GetTop( ) + Offset.Y( );
-+ long height = pLine->GetHeight( );
-+
-+ //Set color
-+ rDev.SetLineColor( Color( COL_BLACK ) );
-+
-+ //Draw vertical line
-+ Point p1( left, top );
-+ Point p2( left, top + height );
-+ rDev.DrawLine( p1, p2 );
-+}
-+
-+void SmCaretDrawingVisitor::DefaultVisit( SmNode* pNode )
-+{
-+ rDev.SetLineColor( Color( COL_BLACK ) );
-+
-+ //Find the line
-+ SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
-+
-+ //Find coordinates
-+ long left = pNode->GetLeft( ) + Offset.X( ) + ( pos.Index == 1 ? pNode->GetWidth( ) : 0 );
-+ long top = pLine->GetTop( ) + Offset.Y( );
-+ long height = pLine->GetHeight( );
-+
-+ //Set color
-+ rDev.SetLineColor( Color( COL_BLACK ) );
-+
-+ //Draw vertical line
-+ Point p1( left, top );
-+ Point p2( left, top + height );
-+ rDev.DrawLine( p1, p2 );
-+}
-+
-+/////////////////////////////// SmCaretPos2LineVisitor ////////////////////////////////
-+
-+void SmCaretPos2LineVisitor::Visit( SmTextNode* pNode )
-+{
-+ //Save device state
-+ pDev->Push( PUSH_FONT | PUSH_TEXTCOLOR );
-+
-+ long i = pos.Index;
-+
-+ pDev->SetFont( pNode->GetFont( ) );
-+
-+ //Find coordinates
-+ long left = pNode->GetLeft( ) + pDev->GetTextWidth( pNode->GetText( ), 0, i );
-+ long top = pNode->GetTop( );
-+ long height = pNode->GetHeight( );
-+
-+ line = SmCaretLine( left, top, height );
-+
-+ //Restore device state
-+ pDev->Pop( );
-+}
-+
-+void SmCaretPos2LineVisitor::DefaultVisit( SmNode* pNode )
-+{
-+ //Vertical line ( code from SmCaretDrawingVisitor )
-+ Point p1 = pNode->GetTopLeft( );
-+ if( pos.Index == 1 )
-+ p1.Move( pNode->GetWidth( ), 0 );
-+
-+ line = SmCaretLine( p1.X( ), p1.Y( ), pNode->GetHeight( ) );
-+}
-+
-+/////////////////////////////// Nasty temporary device!!! ////////////////////////////////
-+
-+
-+#include <tools/gen.hxx>
-+#include <tools/fract.hxx>
-+#include <rtl/math.hxx>
-+#include <tools/color.hxx>
-+#include <vcl/metric.hxx>
-+#include <vcl/lineinfo.hxx>
-+#include <vcl/outdev.hxx>
-+#include <sfx2/module.hxx>
-+#include "symbol.hxx"
-+#include "smmod.hxx"
-+
-+class SmTmpDevice2
-+{
-+ OutputDevice &rOutDev;
-+
-+ // disallow use of copy-constructor and assignment-operator
-+ SmTmpDevice2( const SmTmpDevice2 &rTmpDev );
-+ SmTmpDevice2 & operator = ( const SmTmpDevice2 &rTmpDev );
-+
-+ Color Impl_GetColor( const Color& rColor );
-+
-+public:
-+ SmTmpDevice2( OutputDevice &rTheDev, BOOL bUseMap100th_mm );
-+ ~SmTmpDevice2( ) { rOutDev.Pop( ); }
-+
-+ void SetFont( const Font &rNewFont );
-+
-+ void SetLineColor( const Color& rColor ) { rOutDev.SetLineColor( Impl_GetColor( rColor ) ); }
-+ void SetFillColor( const Color& rColor ) { rOutDev.SetFillColor( Impl_GetColor( rColor ) ); }
-+ void SetTextColor( const Color& rColor ) { rOutDev.SetTextColor( Impl_GetColor( rColor ) ); }
-+
-+ operator OutputDevice & ( ) { return rOutDev; }
-+};
-+
-+
-+SmTmpDevice2::SmTmpDevice2( OutputDevice &rTheDev, BOOL bUseMap100th_mm ) :
-+ rOutDev( rTheDev )
-+{
-+ rOutDev.Push( PUSH_FONT | PUSH_MAPMODE |
-+ PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR );
-+ if ( bUseMap100th_mm && MAP_100TH_MM != rOutDev.GetMapMode( ).GetMapUnit( ) )
-+ {
-+ DBG_ERROR( "incorrect MapMode?" );
-+ rOutDev.SetMapMode( MAP_100TH_MM ); //Immer fuer 100% fomatieren
-+ }
-+}
-+
-+
-+Color SmTmpDevice2::Impl_GetColor( const Color& rColor )
-+{
-+ ColorData nNewCol = rColor.GetColor( );
-+ if ( COL_AUTO == nNewCol )
-+ {
-+ if ( OUTDEV_PRINTER == rOutDev.GetOutDevType( ) )
-+ nNewCol = COL_BLACK;
-+ else
-+ {
-+ Color aBgCol( rOutDev.GetBackground( ).GetColor( ) );
-+ if ( OUTDEV_WINDOW == rOutDev.GetOutDevType( ) )
-+ aBgCol = ( ( Window & ) rOutDev ).GetDisplayBackground( ).GetColor( );
-+
-+ nNewCol = SM_MOD1( )->GetColorConfig( ).GetColorValue( svtools::FONTCOLOR ).nColor;
-+
-+ Color aTmpColor( nNewCol );
-+ if ( aBgCol.IsDark( ) && aTmpColor.IsDark( ) )
-+ nNewCol = COL_WHITE;
-+ else if ( aBgCol.IsBright( ) && aTmpColor.IsBright( ) )
-+ nNewCol = COL_BLACK;
-+ }
-+ }
-+ return Color( nNewCol );
-+}
-+
-+
-+void SmTmpDevice2::SetFont( const Font &rNewFont )
-+{
-+ rOutDev.SetFont( rNewFont );
-+ rOutDev.SetTextColor( Impl_GetColor( rNewFont.GetColor( ) ) );
-+}
-+
-+/////////////////////////////// DrawingVisitor ////////////////////////////////
-+
-+void DrawingVisitor::Visit( SmTableNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmBraceNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmBracebodyNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmOperNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmAlignNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmAttributNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmFontNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmUnHorNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmBinHorNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmBinVerNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmBinDiagonalNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmSubSupNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmMatrixNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmPlaceNode* pNode )
-+{
-+ DrawSpecialNode( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmTextNode* pNode )
-+{
-+ DrawTextNode( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmSpecialNode* pNode )
-+{
-+ DrawSpecialNode( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmGlyphSpecialNode* pNode )
-+{
-+ DrawSpecialNode( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmMathSymbolNode* pNode )
-+{
-+ DrawSpecialNode( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmBlankNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmErrorNode* pNode )
-+{
-+ DrawSpecialNode( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmLineNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmExpressionNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmRootNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmVerticalBraceNode* pNode )
-+{
-+ DrawChildren( pNode );
-+}
-+
-+void DrawingVisitor::Visit( SmRootSymbolNode* pNode )
-+{
-+ if ( pNode->IsPhantom( ) )
-+ return;
-+
-+ // draw root-sign itself
-+ DrawSpecialNode( pNode );
-+
-+
-+ SmTmpDevice2 aTmpDev( ( OutputDevice & ) rDev, TRUE );
-+ aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
-+ rDev.SetLineColor( );
-+ aTmpDev.SetFont( pNode->GetFont( ) );
-+
-+ // since the width is always unscaled it corresponds ot the _original_
-+ // _unscaled_ font height to be used, we use that to calculate the
-+ // bar height. Thus it is independent of the arguments height.
-+ // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
-+ long nBarHeight = pNode->GetWidth( ) * 7L / 100L;
-+ long nBarWidth = pNode->GetBodyWidth( ) + pNode->GetBorderWidth( );
-+ Point aBarOffset( pNode->GetWidth( ), +pNode->GetBorderWidth( ) );
-+ Point aBarPos( Position + aBarOffset );
-+
-+ Rectangle aBar( aBarPos, Size( nBarWidth, nBarHeight ) );
-+ //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
-+ //! increasing zoomfactor.
-+ // This is done by shifting it's output-position to a point that
-+ // corresponds exactly to a pixel on the output device.
-+ Point aDrawPos( rDev.PixelToLogic( rDev.LogicToPixel( aBar.TopLeft( ) ) ) );
-+ //aDrawPos.X( ) = aBar.Left( ); //! don't change X position
-+ aBar.SetPos( aDrawPos );
-+
-+ rDev.DrawRect( aBar );
-+
-+#ifdef SM_RECT_DEBUG
-+ if ( !pNode->IsDebug( ) )
-+ return;
-+
-+ int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
-+ pNode->SmRect::Draw( rDev, Position, nRFlags );
-+#endif
-+}
-+
-+void DrawingVisitor::Visit( SmPolyLineNode* pNode )
-+{
-+ if ( pNode->IsPhantom( ) )
-+ return;
-+
-+ long nBorderwidth = pNode->GetFont( ).GetBorderWidth( );
-+
-+ LineInfo aInfo;
-+ aInfo.SetWidth( pNode->GetWidth( ) - 2 * nBorderwidth );
-+
-+ Point aOffset ( Point( ) - pNode->GetPolygon( ).GetBoundRect( ).TopLeft( )
-+ + Point( nBorderwidth, nBorderwidth ) ),
-+ aPos ( Position + aOffset );
-+ pNode->GetPolygon( ).Move( aPos.X( ), aPos.Y( ) ); //Works because Polygon wraps a pointer
-+
-+ SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, FALSE );
-+ aTmpDev.SetLineColor( pNode->GetFont( ).GetColor( ) );
-+
-+ rDev.DrawPolyLine( pNode->GetPolygon( ), aInfo );
-+
-+#ifdef SM_RECT_DEBUG
-+ if ( !pNode->IsDebug( ) )
-+ return;
-+
-+ int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
-+ pNode->SmRect::Draw( rDev, Position, nRFlags );
-+#endif
-+}
-+
-+void DrawingVisitor::Visit( SmRectangleNode* pNode )
-+{
-+ if ( pNode->IsPhantom( ) )
-+ return;
-+
-+ SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, FALSE );
-+ aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
-+ rDev.SetLineColor( );
-+ aTmpDev.SetFont( pNode->GetFont( ) );
-+
-+ ULONG nTmpBorderWidth = pNode->GetFont( ).GetBorderWidth( );
-+
-+ // get rectangle and remove borderspace
-+ Rectangle aTmp ( pNode->AsRectangle( ) + Position - pNode->GetTopLeft( ) );
-+ aTmp.Left( ) += nTmpBorderWidth;
-+ aTmp.Right( ) -= nTmpBorderWidth;
-+ aTmp.Top( ) += nTmpBorderWidth;
-+ aTmp.Bottom( ) -= nTmpBorderWidth;
-+
-+ DBG_ASSERT( aTmp.GetHeight( ) > 0 && aTmp.GetWidth( ) > 0,
-+ "Sm: leeres Rechteck" );
-+
-+ //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
-+ //! increasing zoomfactor.
-+ // This is done by shifting it's output-position to a point that
-+ // corresponds exactly to a pixel on the output device.
-+ Point aPos ( rDev.PixelToLogic( rDev.LogicToPixel( aTmp.TopLeft( ) ) ) );
-+ aTmp.SetPos( aPos );
-+
-+ rDev.DrawRect( aTmp );
-+
-+#ifdef SM_RECT_DEBUG
-+ if ( !pNode->IsDebug( ) )
-+ return;
-+
-+ int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
-+ pNode->SmRect::Draw( rDev, rPosition, nRFlags );
-+#endif
-+}
-+
-+void DrawingVisitor::DrawTextNode( SmTextNode* pNode )
-+{
-+ if ( pNode->IsPhantom( ) || pNode->GetText( ).Len( ) == 0 || pNode->GetText( ).GetChar( 0 ) == xub_Unicode( '\0' ) )
-+ return;
-+
-+ SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, FALSE );
-+ aTmpDev.SetFont( pNode->GetFont( ) );
-+
-+ Point aPos ( Position );
-+ aPos.Y( ) += pNode->GetBaselineOffset( );
-+ // auf Pixelkoordinaten runden
-+ aPos = rDev.PixelToLogic( rDev.LogicToPixel( aPos ) );
-+
-+ rDev.DrawStretchText( aPos, pNode->GetWidth( ), pNode->GetText( ) );
-+
-+#ifdef SM_RECT_DEBUG
-+ if ( !pNode->IsDebug( ) )
-+ return;
-+
-+ int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
-+ pNode->SmRect::Draw( rDev, Position, nRFlags );
-+#endif
-+}
-+
-+void DrawingVisitor::DrawSpecialNode( SmSpecialNode* pNode )
-+{
-+ //! since this chars might come from any font, that we may not have
-+ //! set to ALIGN_BASELINE yet, we do it now.
-+ pNode->GetFont( ).SetAlign( ALIGN_BASELINE );
-+
-+ DrawTextNode( pNode );
-+}
-+
-+void DrawingVisitor::DrawChildren( SmNode* pNode )
-+{
-+ if ( pNode->IsPhantom( ) )
-+ return;
-+
-+ Point rPosition = Position;
-+
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ {
-+ Point aOffset ( it->GetTopLeft( ) - pNode->GetTopLeft( ) );
-+ Position = rPosition + aOffset;
-+ it->Accept( this );
-+ }
-+
-+#ifdef SM_RECT_DEBUG
-+ if ( !pNode->IsDebug( ) )
-+ return;
-+
-+ int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
-+ pNode->SmRect::Draw( rDev, rPosition, nRFlags );
-+#endif
-+}
-+
-+/////////////////////////////// SetSelectionVisitor ////////////////////////////////
-+
-+void SetSelectionVisitor::SetSelectedOnAll( SmNode* pSubTree, bool IsSelected )
-+{
-+ pSubTree->SetSelected( IsSelected );
-+
-+ //Quick BFS to set all selections
-+ SmNodeIterator it( pSubTree );
-+ while( it.Next( ) )
-+ SetSelectedOnAll( it.Current( ), IsSelected );
-+}
-+
-+void SetSelectionVisitor::DefaultVisit( SmNode* pNode )
-+{
-+ //Change state if StartPos is infront of this node
-+ if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
-+ IsSelecting = !IsSelecting;
-+ //Change state if EndPos is infront of this node
-+ if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
-+ IsSelecting = !IsSelecting;
-+
-+ //Cache current state
-+ BOOL WasSelecting = IsSelecting;
-+ BOOL ChangedState = FALSE;
-+
-+ //Set selected
-+ pNode->SetSelected( IsSelecting );
-+
-+ //Visit children
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ {
-+ it->Accept( this );
-+ ChangedState = ( WasSelecting != IsSelecting ) || ChangedState;
-+ }
-+
-+ //If state changed
-+ if( ChangedState )
-+ {
-+ //Select this node and all of it's children
-+ SetSelectedOnAll( pNode, true );
-+ /* If the equation is: sqrt{2 + 4} + 5
-+ * And the selection is: sqrt{2 + [4} +] 5
-+ * Where [ denotes StartPos and ] denotes EndPos
-+ * Then the sqrt node should be selected, so that the
-+ * effective selection is: [sqrt{2 + 4} +] 5
-+ * The same is the case if we swap StartPos and EndPos.
-+ */
-+ }
-+
-+ //Change state if StartPos is after this node
-+ if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
-+ {
-+ IsSelecting = !IsSelecting;
-+ }
-+ //Change state if EndPos is after of this node
-+ if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
-+ {
-+ IsSelecting = !IsSelecting;
-+ }
-+}
-+
-+void SetSelectionVisitor::VisitCompositionNode( SmNode* pNode )
-+{
-+ //Change state if StartPos is infront of this node
-+ if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
-+ IsSelecting = !IsSelecting;
-+ //Change state if EndPos is infront of this node
-+ if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
-+ IsSelecting = !IsSelecting;
-+
-+ //Cache current state
-+ bool WasSelecting = IsSelecting;
-+
-+ //Visit children
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ it->Accept( this );
-+
-+ //Set selected, if everything was selected
-+ pNode->SetSelected( WasSelecting && IsSelecting );
-+
-+ //Change state if StartPos is after this node
-+ if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
-+ IsSelecting = !IsSelecting;
-+ //Change state if EndPos is after of this node
-+ if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
-+ IsSelecting = !IsSelecting;
-+}
-+
-+void SetSelectionVisitor::Visit( SmTextNode* pNode )
-+{
-+ long i1 = -1,
-+ i2 = -1;
-+ if( StartPos.pSelectedNode == pNode )
-+ i1 = StartPos.Index;
-+ if( EndPos.pSelectedNode == pNode )
-+ i2 = EndPos.Index;
-+
-+ long start, end;
-+ pNode->SetSelected( true );
-+ if( i1 != -1 && i2 != -1 ) {
-+ start = i1 < i2 ? i1 : i2; //MIN
-+ end = i1 > i2 ? i1 : i2; //MAX
-+ } else if( IsSelecting && i1 != -1 ) {
-+ start = 0;
-+ end = i1;
-+ IsSelecting = false;
-+ } else if( IsSelecting && i2 != -1 ) {
-+ start = 0;
-+ end = i2;
-+ IsSelecting = false;
-+ } else if( !IsSelecting && i1 != -1 ) {
-+ start = i1;
-+ end = pNode->GetText( ).Len( );
-+ IsSelecting = true;
-+ } else if( !IsSelecting && i2 != -1 ) {
-+ start = i2;
-+ end = pNode->GetText( ).Len( );
-+ IsSelecting = true;
-+ } else if( IsSelecting ) {
-+ start = 0;
-+ end = pNode->GetText( ).Len( );
-+ } else {
-+ pNode->SetSelected( false );
-+ start = 0;
-+ end = 0;
-+ }
-+ pNode->SetSelected( start != end );
-+ pNode->SetSelectionStart( start );
-+ pNode->SetSelectionEnd( end );
-+}
-+
-+void SetSelectionVisitor::Visit( SmExpressionNode* pNode )
-+{
-+ VisitCompositionNode( pNode );
-+}
-+
-+void SetSelectionVisitor::Visit( SmBracebodyNode* pNode )
-+{
-+ VisitCompositionNode( pNode );
-+}
-+
-+void SetSelectionVisitor::Visit( SmAlignNode* pNode )
-+{
-+ VisitCompositionNode( pNode );
-+}
-+
-+void SetSelectionVisitor::Visit( SmBinHorNode* pNode )
-+{
-+ VisitCompositionNode( pNode );
-+}
-+
-+void SetSelectionVisitor::Visit( SmUnHorNode* pNode )
-+{
-+ VisitCompositionNode( pNode );
-+}
-+
-+void SetSelectionVisitor::Visit( SmFontNode* pNode )
-+{
-+ VisitCompositionNode( pNode );
-+}
-+
-+
-+
-+/////////////////////////////// SmCaretPosGraphBuildingVisitor ////////////////////////////////
-+
-+
-+//Needs special care:
-+void SmCaretPosGraphBuildingVisitor::Visit( SmTableNode* pNode )
-+{
-+ //Children are SmLineNodes
-+ //Or so I thought... Aparently, the children can be instances of SmExpression
-+ //especially if there's a error in the formula... So he we go, a simple work around.
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) ){
-+ //There's a special invariant between this method and the Visit( SmLineNode* )
-+ //Usually pRightMost may not be NULL, to avoid this pRightMost should here be
-+ //set to a new SmCaretPos infront of it.Current( ), however, if it.Current( ) is
-+ //an instance of SmLineNode we let SmLineNode create this position infront of
-+ //the visual line.
-+ //The argument for doing this is that we now don't have to worry about SmLineNode
-+ //being a visual line composition node. Thus no need for yet another special case
-+ //in SmCursor::IsLineCompositionNode and everywhere this method is used.
-+ if( it->GetType( ) != NLINE )
-+ pRightMost = pGraph->Add( SmCaretPos( it.Current( ), 0 ) );
-+ it->Accept( this );
-+ }
-+}
-+void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode* pNode ){
-+ pRightMost = NULL;
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) ){
-+ if( !pRightMost )
-+ pRightMost = pGraph->Add( SmCaretPos( it.Current( ), 0 ) );
-+ it->Accept( this );
-+ }
-+}
-+
-+/** Build SmCaretPosGraph for SmSubSupNode
-+ *
-+ * The child positions in a SubSupNode, where H is the body:
-+ * \code
-+ * CSUP
-+ *
-+ * LSUP H H RSUP
-+ * H H
-+ * HHHH
-+ * H H
-+ * LSUB H H RSUB
-+ *
-+ * CSUB
-+ * \endcode
-+ *
-+ * Graph over these, where "left" is before the SmSubSupNode and "right" is after:
-+ * \dot
-+ * digraph Graph{
-+ * left -> H;
-+ * H -> right;
-+ * LSUP -> H;
-+ * LSUB -> H;
-+ * CSUP -> right;
-+ * CSUB -> right;
-+ * RSUP -> right;
-+ * RSUB -> right;
-+ * };
-+ * \enddot
-+ *
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode* pNode )
-+{
-+ SmCaretPosGraphEntry *left,
-+ *right,
-+ *bodyLeft,
-+ *bodyRight;
-+
-+ left = pRightMost;
-+ j_assert( pRightMost, "pRightMost shouldn't be NULL here!" );
-+
-+ //Create bodyLeft
-+ j_assert( pNode->GetBody( ), "SmSubSupNode Doesn't have a body!" );
-+ bodyLeft = pGraph->Add( SmCaretPos( pNode->GetBody( ), 0 ), left );
-+ left->SetRight( bodyLeft ); //TODO: Don't make this if LSUP or LSUB are NULL ( not sure??? )
-+
-+ //Create right
-+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
-+
-+ //Visit the body, to get bodyRight
-+ pRightMost = bodyLeft;
-+ pNode->GetBody( )->Accept( this );
-+ bodyRight = pRightMost;
-+ bodyRight->SetRight( right );
-+ right->SetLeft( bodyRight );
-+
-+ SmNode* pChild;
-+ //If there's an LSUP
-+ if( ( pChild = pNode->GetSubSup( LSUP ) ) ){
-+ SmCaretPosGraphEntry *cLeft; //Child left
-+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
-+
-+ pRightMost = cLeft;
-+ pChild->Accept( this );
-+
-+ pRightMost->SetRight( bodyLeft );
-+ }
-+ //If there's an LSUB
-+ if( ( pChild = pNode->GetSubSup( LSUB ) ) ){
-+ SmCaretPosGraphEntry *cLeft; //Child left
-+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
-+
-+ pRightMost = cLeft;
-+ pChild->Accept( this );
-+
-+ pRightMost->SetRight( bodyLeft );
-+ }
-+ //If there's an CSUP
-+ if( ( pChild = pNode->GetSubSup( CSUP ) ) ){
-+ SmCaretPosGraphEntry *cLeft; //Child left
-+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
-+
-+ pRightMost = cLeft;
-+ pChild->Accept( this );
-+
-+ pRightMost->SetRight( right );
-+ }
-+ //If there's an CSUB
-+ if( ( pChild = pNode->GetSubSup( CSUB ) ) ){
-+ SmCaretPosGraphEntry *cLeft; //Child left
-+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
-+
-+ pRightMost = cLeft;
-+ pChild->Accept( this );
-+
-+ pRightMost->SetRight( right );
-+ }
-+ //If there's an RSUP
-+ if( ( pChild = pNode->GetSubSup( RSUP ) ) ){
-+ SmCaretPosGraphEntry *cLeft; //Child left
-+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
-+
-+ pRightMost = cLeft;
-+ pChild->Accept( this );
-+
-+ pRightMost->SetRight( right );
-+ }
-+ //If there's an RSUB
-+ if( ( pChild = pNode->GetSubSup( RSUB ) ) ){
-+ SmCaretPosGraphEntry *cLeft; //Child left
-+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
-+
-+ pRightMost = cLeft;
-+ pChild->Accept( this );
-+
-+ pRightMost->SetRight( right );
-+ }
-+
-+ //Set return parameters
-+ pRightMost = right;
-+}
-+
-+/** Build caret position for SmOperNode
-+ *
-+ * If first child is an SmSubSupNode we will ignore it's
-+ * body, as this body is a SmMathSymbol, for SUM, INT or similar
-+ * that shouldn't be subject to modification.
-+ * If first child is not a SmSubSupNode, ignore it completely
-+ * as it is a SmMathSymbol.
-+ *
-+ * The child positions in a SmOperNode, where H is symbol, e.g. int, sum or similar:
-+ * \code
-+ * TO
-+ *
-+ * LSUP H H RSUP BBB BB BBB B B
-+ * H H B B B B B B B B
-+ * HHHH BBB B B B B B
-+ * H H B B B B B B B
-+ * LSUB H H RSUB BBB BB BBB B
-+ *
-+ * FROM
-+ * \endcode
-+ * Notice, CSUP, etc. are actually granchildren, but inorder to ignore H, these are visited
-+ * from here. If they are present, that is if pOper is an instance of SmSubSupNode.
-+ *
-+ * Graph over these, where "left" is before the SmOperNode and "right" is after:
-+ * \dot
-+ * digraph Graph{
-+ * left -> BODY;
-+ * BODY -> right;
-+ * LSUP -> BODY;
-+ * LSUB -> BODY;
-+ * TO -> BODY;
-+ * FROM -> BODY;
-+ * RSUP -> BODY;
-+ * RSUB -> BODY;
-+ * };
-+ * \enddot
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode* pNode )
-+{
-+ SmNode *pOper = pNode->GetSubNode( 0 ),
-+ *pBody = pNode->GetSubNode( 1 );
-+
-+ SmCaretPosGraphEntry *left = pRightMost,
-+ *bodyLeft,
-+ *bodyRight,
-+ *right;
-+ //Create body left
-+ bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
-+ left->SetRight( bodyLeft );
-+
-+ //Visit body, get bodyRight
-+ pRightMost = bodyLeft;
-+ pBody->Accept( this );
-+ bodyRight = pRightMost;
-+
-+ //Create right
-+ right = pGraph->Add( SmCaretPos( pNode, 1 ), bodyRight );
-+ bodyRight->SetRight( right );
-+
-+ //Get subsup pNode if any
-+ SmSubSupNode* pSubSup = pOper->GetType( ) == NSUBSUP ? ( SmSubSupNode* )pOper : NULL;
-+
-+ SmNode* pChild;
-+ SmCaretPosGraphEntry *childLeft;
-+ if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
-+ //Create position infront of pChild
-+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
-+ //Visit pChild
-+ pRightMost = childLeft;
-+ pChild->Accept( this );
-+ //Set right on pRightMost from pChild
-+ pRightMost->SetRight( bodyLeft );
-+ }
-+ if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
-+ //Create position infront of pChild
-+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
-+ //Visit pChild
-+ pRightMost = childLeft;
-+ pChild->Accept( this );
-+ //Set right on pRightMost from pChild
-+ pRightMost->SetRight( bodyLeft );
-+ }
-+ if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {//TO
-+ //Create position infront of pChild
-+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
-+ //Visit pChild
-+ pRightMost = childLeft;
-+ pChild->Accept( this );
-+ //Set right on pRightMost from pChild
-+ pRightMost->SetRight( bodyLeft );
-+ }
-+ if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUB ) ) ) { //FROM
-+ //Create position infront of pChild
-+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
-+ //Visit pChild
-+ pRightMost = childLeft;
-+ pChild->Accept( this );
-+ //Set right on pRightMost from pChild
-+ pRightMost->SetRight( bodyLeft );
-+ }
-+ if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
-+ //Create position infront of pChild
-+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
-+ //Visit pChild
-+ pRightMost = childLeft;
-+ pChild->Accept( this );
-+ //Set right on pRightMost from pChild
-+ pRightMost->SetRight( bodyLeft );
-+ }
-+ if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
-+ //Create position infront of pChild
-+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
-+ //Visit pChild
-+ pRightMost = childLeft;
-+ pChild->Accept( this );
-+ //Set right on pRightMost from pChild
-+ pRightMost->SetRight( bodyLeft );
-+ }
-+
-+ //Return right
-+ pRightMost = right;
-+}
-+
-+void SmCaretPosGraphBuildingVisitor::Visit( SmMatrixNode* pNode )
-+{
-+ SmCaretPosGraphEntry *left = pRightMost,
-+ *right = pGraph->Add( SmCaretPos( pNode, 1 ) );
-+
-+ for ( USHORT i = 0; i < pNode->GetNumRows( ); i++ ) {
-+ SmCaretPosGraphEntry* r = left;
-+ for ( USHORT j = 0; j < pNode->GetNumCols( ); j++ ){
-+ SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
-+
-+ pRightMost = pGraph->Add( SmCaretPos( pSubNode, 0 ), r );
-+ if( j != 0 || ( pNode->GetNumRows( ) - 1 ) / 2 == i )
-+ r->SetRight( pRightMost );
-+
-+ pSubNode->Accept( this );
-+
-+ r = pRightMost;
-+ }
-+ pRightMost->SetRight( right );
-+ if( ( pNode->GetNumRows( ) - 1 ) / 2 == i )
-+ right->SetLeft( pRightMost );
-+ }
-+
-+ pRightMost = right;
-+}
-+
-+/** Build SmCaretPosGraph for SmTextNode
-+ *
-+ * Lines in an SmTextNode:
-+ * \code
-+ * A B C
-+ * \endcode
-+ * Where A B and C are characters in the text.
-+ *
-+ * Graph over these, where "left" is before the SmTextNode and "right" is after:
-+ * \dot
-+ * digraph Graph{
-+ * left -> A;
-+ * A -> B
-+ * B -> right;
-+ * };
-+ * \enddot
-+ * Notice that C and right is the same position here.
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmTextNode* pNode )
-+{
-+ j_assert( pNode->GetText( ).Len( ) > 0, "Empty SmTextNode is bad" );
-+
-+ int size = pNode->GetText( ).Len( );
-+ for( int i = 1; i <= size; i++ ){
-+ SmCaretPosGraphEntry* pRight = pRightMost;
-+ pRightMost = pGraph->Add( SmCaretPos( pNode, i ), pRight );
-+ pRight->SetRight( pRightMost );
-+ }
-+}
-+
-+/** Build SmCaretPosGraph for SmBinVerNode
-+ *
-+ * Lines in an SmBinVerNode:
-+ * \code
-+ * A
-+ * -----
-+ * B
-+ * \endcode
-+ *
-+ * Graph over these, where "left" is before the SmBinVerNode and "right" is after:
-+ * \dot
-+ * digraph Graph{
-+ * left -> A;
-+ * A -> right;
-+ * B -> right;
-+ * };
-+ * \enddot
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmBinVerNode* pNode )
-+{
-+ //None if these children can be NULL, see SmBinVerNode::Arrange
-+ SmNode *pNum = pNode->GetSubNode( 0 ),
-+ *pDenom = pNode->GetSubNode( 2 );
-+
-+ SmCaretPosGraphEntry *left,
-+ *right,
-+ *numLeft,
-+ *denomLeft;
-+
-+ //Set left
-+ left = pRightMost;
-+ j_assert( pRightMost, "There must be a position infront of this" );
-+
-+ //Create right
-+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
-+
-+ //Create numLeft
-+ numLeft = pGraph->Add( SmCaretPos( pNum, 0 ), left );
-+ left->SetRight( numLeft );
-+
-+ //Visit pNum
-+ pRightMost = numLeft;
-+ pNum->Accept( this );
-+ pRightMost->SetRight( right );
-+ right->SetLeft( pRightMost );
-+
-+ //Create denomLeft
-+ denomLeft = pGraph->Add( SmCaretPos( pDenom, 0 ), left );
-+
-+ //Visit pDenom
-+ pRightMost = denomLeft;
-+ pDenom->Accept( this );
-+ pRightMost->SetRight( right );
-+
-+ //Set return parameter
-+ pRightMost = right;
-+}
-+
-+/** Build SmCaretPosGraph for SmVerticalBraceNode
-+ *
-+ * Lines in an SmVerticalBraceNode:
-+ * \code
-+ * pScript
-+ * ________
-+ * / \
-+ * pBody
-+ * \endcode
-+ *
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmVerticalBraceNode* pNode )
-+{
-+ SmNode *pBody = pNode->GetSubNode( 0 ),
-+ *pScript = pNode->GetSubNode( 2 );
-+ //None of these children can be NULL
-+
-+ SmCaretPosGraphEntry *left,
-+ *bodyLeft,
-+ *scriptLeft,
-+ *right;
-+
-+ left = pRightMost;
-+
-+ //Create right
-+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
-+
-+ //Create bodyLeft
-+ bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
-+ left->SetRight( bodyLeft );
-+ pRightMost = bodyLeft;
-+ pBody->Accept( this );
-+ pRightMost->SetRight( right );
-+ right->SetLeft( pRightMost );
-+
-+ //Create script
-+ scriptLeft = pGraph->Add( SmCaretPos( pScript, 0 ), left );
-+ pRightMost = scriptLeft;
-+ pScript->Accept( this );
-+ pRightMost->SetRight( right );
-+
-+ //Set return value
-+ pRightMost = right;
-+}
-+
-+/** Build SmCaretPosGraph for SmBinDiagonalNode
-+ *
-+ * Lines in an SmBinDiagonalNode:
-+ * \code
-+ * A /
-+ * /
-+ * / B
-+ * \endcode
-+ * Where A and B are lines.
-+ *
-+ * Used in formulas such as "A wideslash B"
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmBinDiagonalNode* pNode )
-+{
-+ SmNode *A = pNode->GetSubNode( 0 ),
-+ *B = pNode->GetSubNode( 1 );
-+
-+ SmCaretPosGraphEntry *left,
-+ *leftA,
-+ *rightA,
-+ *leftB,
-+ *right;
-+ left = pRightMost;
-+
-+ //Create right
-+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
-+
-+ //Create left A
-+ leftA = pGraph->Add( SmCaretPos( A, 0 ), left );
-+ left->SetRight( leftA );
-+
-+ //Visit A
-+ pRightMost = leftA;
-+ A->Accept( this );
-+ rightA = pRightMost;
-+
-+ //Create left B
-+ leftB = pGraph->Add( SmCaretPos( B, 0 ), rightA );
-+ rightA->SetRight( leftB );
-+
-+ //Visit B
-+ pRightMost = leftB;
-+ B->Accept( this );
-+ pRightMost->SetRight( right );
-+ right->SetLeft( pRightMost );
-+
-+ //Set return value
-+ pRightMost = right;
-+}
-+
-+
-+//Straigt forward ( I think )
-+void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode* pNode )
-+{
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ it->Accept( this );
-+}
-+void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode* pNode )
-+{
-+ // Unary operator node
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ it->Accept( this );
-+
-+}
-+
-+void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode* pNode )
-+{
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ it->Accept( this );
-+}
-+
-+void SmCaretPosGraphBuildingVisitor::Visit( SmFontNode* pNode )
-+{
-+ //Has only got one child, should act as an expression if possible
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ it->Accept( this );
-+}
-+
-+/** Build SmCaretPosGraph for SmBracebodyNode
-+ * Acts as an SmExpressionNode
-+ *
-+ * Below is an example of a formula tree that has multiple children for SmBracebodyNode
-+ * \dot
-+ * digraph {
-+ * labelloc = "t";
-+ * label= "Equation: \"lbrace i mline i in setZ rbrace\"";
-+ * n0 [label="SmTableNode"];
-+ * n0 -> n1 [label="0"];
-+ * n1 [label="SmLineNode"];
-+ * n1 -> n2 [label="0"];
-+ * n2 [label="SmExpressionNode"];
-+ * n2 -> n3 [label="0"];
-+ * n3 [label="SmBraceNode"];
-+ * n3 -> n4 [label="0"];
-+ * n4 [label="SmMathSymbolNode: {"];
-+ * n3 -> n5 [label="1"];
-+ * n5 [label="SmBracebodyNode"];
-+ * n5 -> n6 [label="0"];
-+ * n6 [label="SmExpressionNode"];
-+ * n6 -> n7 [label="0"];
-+ * n7 [label="SmTextNode: i"];
-+ * n5 -> n8 [label="1"];
-+ * n8 [label="SmMathSymbolNode: ∣"];
-+ * n5 -> n9 [label="2"];
-+ * n9 [label="SmExpressionNode"];
-+ * n9 -> n10 [label="0"];
-+ * n10 [label="SmBinHorNode"];
-+ * n10 -> n11 [label="0"];
-+ * n11 [label="SmTextNode: i"];
-+ * n10 -> n12 [label="1"];
-+ * n12 [label="SmMathSymbolNode: ∈"];
-+ * n10 -> n13 [label="2"];
-+ * n13 [label="SmMathSymbolNode: ℤ"];
-+ * n3 -> n14 [label="2"];
-+ * n14 [label="SmMathSymbolNode: }"];
-+ * }
-+ * \enddot
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode* pNode )
-+{
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ it->Accept( this );
-+}
-+
-+/** Build SmCaretPosGraph for SmAlignNode
-+ * Acts as an SmExpressionNode, as it only has one child this okay
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmAlignNode* pNode )
-+{
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ it->Accept( this );
-+}
-+
-+/** Build SmCaretPosGraph for SmRootNode
-+ *
-+ * Lines in an SmRootNode:
-+ * \code
-+ * _________
-+ * A/
-+ * \/ B
-+ *
-+ * \endcode
-+ * A: pExtra ( optional, can be NULL ),
-+ * B: pBody
-+ *
-+ * Graph over these, where "left" is before the SmRootNode and "right" is after:
-+ * \dot
-+ * digraph Graph{
-+ * left -> B;
-+ * B -> right;
-+ * A -> B;
-+ * }
-+ * \enddot
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode* pNode )
-+{
-+ SmNode *pExtra = pNode->GetSubNode( 0 ), //Argument, NULL for sqrt, and SmTextNode if cubicroot
-+ *pBody = pNode->GetSubNode( 2 ); //Body of the root
-+ j_assert( pBody, "pBody cannot be NULL" );
-+
-+ SmCaretPosGraphEntry *left,
-+ *right,
-+ *bodyLeft,
-+ *bodyRight;
-+
-+ //Get left and save it
-+ j_assert( pRightMost, "There must be a position infront of this" );
-+ left = pRightMost;
-+
-+ //Create body left
-+ bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
-+ left->SetRight( bodyLeft );
-+
-+ //Create right
-+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
-+
-+ //Visit body
-+ pRightMost = bodyLeft;
-+ pBody->Accept( this );
-+ bodyRight = pRightMost;
-+ bodyRight->SetRight( right );
-+ right->SetLeft( bodyRight );
-+
-+ //Visit pExtra
-+ if( pExtra ){
-+ pRightMost = pGraph->Add( SmCaretPos( pExtra, 0 ), left );
-+ pExtra->Accept( this );
-+ pRightMost->SetRight( bodyLeft );
-+ }
-+
-+ pRightMost = right;
-+}
-+
-+/** Build SmCaretPosGraph for SmPlaceNode
-+ * Consider this a single character.
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmPlaceNode* pNode )
-+{
-+ SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
-+ pRightMost->SetRight( right );
-+ pRightMost = right;
-+}
-+
-+/** SmErrorNode is context dependent metadata, it can't be selected
-+ *
-+ * @remarks There's no point in deleting, copying and/or moving an instance
-+ * of SmErrorNode as it may not exist in an other context! Thus there are no
-+ * positions to select an SmErrorNode.
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmErrorNode* )
-+{
-+}
-+
-+/** Build SmCaretPosGraph for SmBlankNode
-+ * Consider this a single character, as it is only a blank space
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmBlankNode* pNode )
-+{
-+ SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
-+ pRightMost->SetRight( right );
-+ pRightMost = right;
-+}
-+
-+/** Build SmCaretPosGraph for SmBraceNode
-+ *
-+ * Lines in an SmBraceNode:
-+ * \code
-+ * | |
-+ * | B |
-+ * | |
-+ * \endcode
-+ * B: Body
-+ *
-+ * Graph over these, where "left" is before the SmBraceNode and "right" is after:
-+ * \dot
-+ * digraph Graph{
-+ * left -> B;
-+ * B -> right;
-+ * }
-+ * \enddot
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmBraceNode* pNode )
-+{
-+ SmNode* pBody = pNode->GetSubNode( 1 );
-+
-+ SmCaretPosGraphEntry *left = pRightMost,
-+ *right = pGraph->Add( SmCaretPos( pNode, 1 ) );
-+
-+ pRightMost = pGraph->Add( SmCaretPos( pBody, 0 ), left );
-+ left->SetRight( pRightMost );
-+
-+ pBody->Accept( this );
-+ pRightMost->SetRight( right );
-+ right->SetLeft( pRightMost );
-+
-+ pRightMost = right;
-+}
-+
-+/** Build SmCaretPosGraph for SmAttributNode
-+ *
-+ * Lines in an SmAttributNode:
-+ * \code
-+ * Attr
-+ * Body
-+ * \endcode
-+ *
-+ * There's a body and an attribute, the construction is used for "widehat A", where "A" is the body
-+ * and "^" is the attribute ( note GetScaleMode( ) on SmAttributNode tells how the attribute should be
-+ * scaled ).
-+ */
-+void SmCaretPosGraphBuildingVisitor::Visit( SmAttributNode* pNode )
-+{
-+ SmNode *pAttr = pNode->GetSubNode( 0 ),
-+ *pBody = pNode->GetSubNode( 1 );
-+ //None of the children can be NULL
-+
-+ SmCaretPosGraphEntry *left = pRightMost,
-+ *attrLeft,
-+ *bodyLeft,
-+ *bodyRight,
-+ *right;
-+
-+ //Creating bodyleft
-+ bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
-+ left->SetRight( bodyLeft );
-+
-+ //Creating right
-+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
-+
-+ //Visit the body
-+ pRightMost = bodyLeft;
-+ pBody->Accept( this );
-+ bodyRight = pRightMost;
-+ bodyRight->SetRight( right );
-+ right->SetLeft( bodyRight );
-+
-+ //Create attrLeft
-+ attrLeft = pGraph->Add( SmCaretPos( pAttr, 0 ), left );
-+
-+ //Visit attribute
-+ pRightMost = attrLeft;
-+ pAttr->Accept( this );
-+ pRightMost->SetRight( right );
-+
-+ //Set return value
-+ pRightMost = right;
-+}
-+
-+//Consider these single symboles
-+void SmCaretPosGraphBuildingVisitor::Visit( SmSpecialNode* pNode )
-+{
-+ SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
-+ pRightMost->SetRight( right );
-+ pRightMost = right;
-+}
-+void SmCaretPosGraphBuildingVisitor::Visit( SmGlyphSpecialNode* pNode )
-+{
-+ SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
-+ pRightMost->SetRight( right );
-+ pRightMost = right;
-+}
-+void SmCaretPosGraphBuildingVisitor::Visit( SmMathSymbolNode* pNode )
-+{
-+ SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
-+ pRightMost->SetRight( right );
-+ pRightMost = right;
-+}
-+
-+void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode* )
-+{
-+ //Do nothing
-+}
-+void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode* )
-+{
-+ //Do nothing
-+}
-+void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode* )
-+{
-+ //Do nothing
-+}
-+
-+/////////////////////////////// SmCloningVisitor ///////////////////////////////
-+
-+SmNode* SmCloningVisitor::Clone( SmNode* pNode )
-+{
-+ SmNode* pCurrResult = pResult;
-+ pNode->Accept( this );
-+ SmNode* pClone = pResult;
-+ pResult = pCurrResult;
-+ return pClone;
-+}
-+
-+void SmCloningVisitor::CloneNodeAttr( SmNode* pSource, SmNode* pTarget )
-+{
-+ pTarget->SetScaleMode( pSource->GetScaleMode( ) );
-+ //Other attributes are set when prepare or arrange is executed
-+ //and may depend on stuff not being cloned here.
-+}
-+
-+void SmCloningVisitor::CloneKids( SmStructureNode* pSource, SmStructureNode* pTarget )
-+{
-+ //Cache current result
-+ SmNode* pCurrResult = pResult;
-+
-+ //Create array for holding clones
-+ USHORT nSize = pSource->GetNumSubNodes( );
-+ SmNodeArray aNodes( nSize );
-+
-+ //Clone children
-+ SmNode* pKid;
-+ for( USHORT i = 0; i < nSize; i++ ){
-+ if( NULL != ( pKid = pSource->GetSubNode( i ) ) )
-+ pKid->Accept( this );
-+ else
-+ pResult = NULL;
-+ aNodes[i] = pResult;
-+ }
-+
-+ //Set subnodes of pTarget
-+ pTarget->SetSubNodes( aNodes );
-+
-+ //Restore result as where prior to call
-+ pResult = pCurrResult;
-+}
-+
-+void SmCloningVisitor::Visit( SmTableNode* pNode )
-+{
-+ SmTableNode* pClone = new SmTableNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmBraceNode* pNode )
-+{
-+ SmBraceNode* pClone = new SmBraceNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+
-+void SmCloningVisitor::Visit( SmBracebodyNode* pNode )
-+{
-+ SmBracebodyNode* pClone = new SmBracebodyNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmOperNode* pNode )
-+{
-+ SmOperNode* pClone = new SmOperNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmAlignNode* pNode )
-+{
-+ SmAlignNode* pClone = new SmAlignNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmAttributNode* pNode )
-+{
-+ SmAttributNode* pClone = new SmAttributNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmFontNode* pNode )
-+{
-+ SmFontNode* pClone = new SmFontNode( pNode->GetToken( ) );
-+ pClone->SetSizeParameter( pNode->GetSizeParameter( ), pNode->GetSizeType( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmUnHorNode* pNode )
-+{
-+ SmUnHorNode* pClone = new SmUnHorNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmBinHorNode* pNode )
-+{
-+ SmBinHorNode* pClone = new SmBinHorNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmBinVerNode* pNode )
-+{
-+ SmBinVerNode* pClone = new SmBinVerNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmBinDiagonalNode* pNode )
-+{
-+ SmBinDiagonalNode *pClone = new SmBinDiagonalNode( pNode->GetToken( ) );
-+ pClone->SetAscending( pNode->IsAscending( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmSubSupNode* pNode )
-+{
-+ SmSubSupNode *pClone = new SmSubSupNode( pNode->GetToken( ) );
-+ pClone->SetUseLimits( pNode->IsUseLimits( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmMatrixNode* pNode )
-+{
-+ SmMatrixNode *pClone = new SmMatrixNode( pNode->GetToken( ) );
-+ pClone->SetRowCol( pNode->GetNumRows( ), pNode->GetNumCols( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmPlaceNode* pNode )
-+{
-+ pResult = new SmPlaceNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pResult );
-+}
-+
-+void SmCloningVisitor::Visit( SmTextNode* pNode )
-+{
-+ SmTextNode* pClone = new SmTextNode( pNode->GetToken( ), pNode->GetFontDesc( ) );
-+ pClone->ChangeText( pNode->GetText( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmSpecialNode* pNode )
-+{
-+ pResult = new SmSpecialNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pResult );
-+}
-+
-+void SmCloningVisitor::Visit( SmGlyphSpecialNode* pNode )
-+{
-+ pResult = new SmGlyphSpecialNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pResult );
-+}
-+
-+void SmCloningVisitor::Visit( SmMathSymbolNode* pNode )
-+{
-+ pResult = new SmMathSymbolNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pResult );
-+}
-+
-+void SmCloningVisitor::Visit( SmBlankNode* pNode )
-+{
-+ SmBlankNode* pClone = new SmBlankNode( pNode->GetToken( ) );
-+ pClone->SetBlankNum( pNode->GetBlankNum( ) );
-+ pResult = pClone;
-+ CloneNodeAttr( pNode, pResult );
-+}
-+
-+void SmCloningVisitor::Visit( SmErrorNode* pNode )
-+{
-+ //PE_NONE is used the information have been discarded and isn't used
-+ pResult = new SmErrorNode( PE_NONE, pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pResult );
-+}
-+
-+void SmCloningVisitor::Visit( SmLineNode* pNode )
-+{
-+ SmLineNode* pClone = new SmLineNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmExpressionNode* pNode )
-+{
-+ SmExpressionNode* pClone = new SmExpressionNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmPolyLineNode* pNode )
-+{
-+ pResult = new SmPolyLineNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pResult );
-+}
-+
-+void SmCloningVisitor::Visit( SmRootNode* pNode )
-+{
-+ SmRootNode* pClone = new SmRootNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+void SmCloningVisitor::Visit( SmRootSymbolNode* pNode )
-+{
-+ pResult = new SmRootSymbolNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pResult );
-+}
-+
-+void SmCloningVisitor::Visit( SmRectangleNode* pNode )
-+{
-+ pResult = new SmRectangleNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pResult );
-+}
-+
-+void SmCloningVisitor::Visit( SmVerticalBraceNode* pNode )
-+{
-+ SmVerticalBraceNode* pClone = new SmVerticalBraceNode( pNode->GetToken( ) );
-+ CloneNodeAttr( pNode, pClone );
-+ CloneKids( pNode, pClone );
-+ pResult = pClone;
-+}
-+
-+/////////////////////////////// SmSelectionDrawingVisitor ///////////////////////////////
-+
-+SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, Point Offset )
-+ : rDev( rDevice ) {
-+ bHasSelectionArea = FALSE;
-+
-+ //Visit everything
-+ j_assert( pTree, "pTree can't be null!" );
-+ if( pTree )
-+ pTree->Accept( this );
-+
-+ //Draw selection if there's any
-+ if( bHasSelectionArea ){
-+ aSelectionArea.Move( Offset.X( ), Offset.Y( ) );
-+
-+ //Save device state
-+ rDev.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
-+ //Change colors
-+ rDev.SetLineColor( );
-+ rDev.SetFillColor( Color( COL_LIGHTGRAY ) );
-+
-+ //Draw rectangle
-+ rDev.DrawRect( aSelectionArea );
-+
-+ //Restore device state
-+ rDev.Pop( );
-+ }
-+}
-+
-+void SmSelectionDrawingVisitor::ExtendSelectionArea( Rectangle aArea )
-+{
-+ if ( ! bHasSelectionArea ) {
-+ aSelectionArea = aArea;
-+ bHasSelectionArea = true;
-+ } else
-+ aSelectionArea.Union( aArea );
-+}
-+
-+void SmSelectionDrawingVisitor::DefaultVisit( SmNode* pNode )
-+{
-+ if( pNode->IsSelected( ) )
-+ ExtendSelectionArea( pNode->AsRectangle( ) );
-+ VisitChildren( pNode );
-+}
-+
-+void SmSelectionDrawingVisitor::VisitChildren( SmNode* pNode )
-+{
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) )
-+ it->Accept( this );
-+}
-+
-+void SmSelectionDrawingVisitor::Visit( SmTextNode* pNode )
-+{
-+ if( pNode->IsSelected( ) ){
-+ rDev.Push( PUSH_TEXTCOLOR | PUSH_FONT );
-+
-+ rDev.SetFont( pNode->GetFont( ) );
-+ Point Position = pNode->GetTopLeft( );
-+ long left = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionStart( ) );
-+ long right = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionEnd( ) );
-+ long top = Position.getY( );
-+ long bottom = top + pNode->GetHeight( );
-+ Rectangle rect( left, top, right, bottom );
-+
-+ ExtendSelectionArea( rect );
-+
-+ rDev.Pop( );
-+ }
-+}
-+
-+
-+/////////////////////////////// SmNodeToTextVisitor ///////////////////////////////
-+
-+void SmNodeToTextVisitor::Visit( SmTableNode* pNode )
-+{
-+ if( pNode->GetToken( ).eType == TBINOM ) {
-+ Append( "binom" );
-+ LineToText( pNode->GetSubNode( 0 ) );
-+ LineToText( pNode->GetSubNode( 1 ) );
-+ } else if( pNode->GetToken( ).eType == TSTACK ) {
-+ Append( "stack{ " );
-+ SmNodeIterator it( pNode );
-+ it.Next( );
-+ while( true ) {
-+ LineToText( it.Current( ) );
-+ if( it.Next( ) ) {
-+ Separate( );
-+ Append( "## " );
-+ }else
-+ break;
-+ }
-+ Separate( );
-+ Append( "}" );
-+ } else { //Assume it's a toplevel table, containing lines
-+ SmNodeIterator it( pNode );
-+ it.Next( );
-+ while( true ) {
-+ Separate( );
-+ it->Accept( this );
-+ if( it.Next( ) ) {
-+ Separate( );
-+ Append( "newline" );
-+ }else
-+ break;
-+ }
-+ }
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmBraceNode* pNode )
-+{
-+ SmNode *pLeftBrace = pNode->GetSubNode( 0 ),
-+ *pBody = pNode->GetSubNode( 1 ),
-+ *pRightBrace = pNode->GetSubNode( 2 );
-+ //Handle special case where it's absolute function
-+ if( pNode->GetToken( ).eType == TABS ) {
-+ Append( "abs" );
-+ LineToText( pBody );
-+ } else {
-+ if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
-+ Append( "left " );
-+ pLeftBrace->Accept( this );
-+ Separate( );
-+ pBody->Accept( this );
-+ Separate( );
-+ if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
-+ Append( "right " );
-+ pRightBrace->Accept( this );
-+ }
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmBracebodyNode* pNode )
-+{
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) ){
-+ Separate( );
-+ it->Accept( this );
-+ }
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmOperNode* pNode )
-+{
-+ Append( pNode->GetToken( ).aText );
-+ Separate( );
-+ if( pNode->GetToken( ).eType == TOPER ){
-+ //There's an SmGlyphSpecialNode if eType == TOPER
-+ if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP )
-+ Append( pNode->GetSubNode( 0 )->GetSubNode( 0 )->GetToken( ).aText );
-+ else
-+ Append( pNode->GetSubNode( 0 )->GetToken( ).aText );
-+ }
-+ if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP ) {
-+ SmSubSupNode *pSubSup = ( SmSubSupNode* )pNode->GetSubNode( 0 );
-+ SmNode* pChild;
-+ if( ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
-+ Separate( );
-+ Append( "lsup " );
-+ LineToText( pChild );
-+ }
-+ if( ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
-+ Separate( );
-+ Append( "lsub " );
-+ LineToText( pChild );
-+ }
-+ if( ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
-+ Separate( );
-+ Append( "rsup " );
-+ LineToText( pChild );
-+ }
-+ if( ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
-+ Separate( );
-+ Append( "rsub " );
-+ LineToText( pChild );
-+ }
-+ if( ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {
-+ Separate( );
-+ Append( "csup " );
-+ LineToText( pChild );
-+ }
-+ if( ( pChild = pSubSup->GetSubSup( CSUB ) ) ) {
-+ Separate( );
-+ Append( "csub " );
-+ LineToText( pChild );
-+ }
-+ }
-+ LineToText( pNode->GetSubNode( 1 ) );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmAlignNode* pNode )
-+{
-+ Append( pNode->GetToken( ).aText );
-+ LineToText( pNode->GetSubNode( 0 ) );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmAttributNode* pNode )
-+{
-+ Append( pNode->GetToken( ).aText );
-+ LineToText( pNode->GetSubNode( 1 ) );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmFontNode* pNode )
-+{
-+ switch ( pNode->GetToken( ).eType )
-+ {
-+ case TBOLD:
-+ Append( "bold " );
-+ break;
-+ case TNBOLD:
-+ Append( "nbold " );
-+ break;
-+ case TITALIC:
-+ Append( "italic " );
-+ break;
-+ case TNITALIC:
-+ Append( "nitalic " );
-+ break;
-+ case TPHANTOM:
-+ Append( "phantom " );
-+ break;
-+ case TSIZE:
-+ {
-+ Append( "size " );
-+ switch ( pNode->GetSizeType( ) )
-+ {
-+ case FNTSIZ_PLUS:
-+ Append( "+" );
-+ break;
-+ case FNTSIZ_MINUS:
-+ Append( "-" );
-+ break;
-+ case FNTSIZ_MULTIPLY:
-+ Append( "*" );
-+ break;
-+ case FNTSIZ_DIVIDE:
-+ Append( "/" );
-+ break;
-+ case FNTSIZ_ABSOLUT:
-+ default:
-+ break;
-+ }
-+ Append( String( ::rtl::math::doubleToUString(
-+ static_cast<double>( pNode->GetSizeParameter( ) ),
-+ rtl_math_StringFormat_Automatic,
-+ rtl_math_DecimalPlaces_Max, '.', sal_True ) ) );
-+ Append( " " );
-+ }
-+ break;
-+ case TBLACK:
-+ Append( "color black " );
-+ break;
-+ case TWHITE:
-+ Append( "color white " );
-+ break;
-+ case TRED:
-+ Append( "color red " );
-+ break;
-+ case TGREEN:
-+ Append( "color green " );
-+ break;
-+ case TBLUE:
-+ Append( "color blue " );
-+ break;
-+ case TCYAN:
-+ Append( "color cyan " );
-+ break;
-+ case TMAGENTA:
-+ Append( "color magenta " );
-+ break;
-+ case TYELLOW:
-+ Append( "color yellow " );
-+ break;
-+ case TSANS:
-+ Append( "font sans " );
-+ break;
-+ case TSERIF:
-+ Append( "font serif " );
-+ break;
-+ case TFIXED:
-+ Append( "font fixed " );
-+ break;
-+ default:
-+ break;
-+ }
-+ LineToText( pNode->GetSubNode( 1 ) );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmUnHorNode* pNode )
-+{
-+ Append( "{" );
-+ SmNodeIterator it( pNode, pNode->GetSubNode( 1 )->GetToken( ).eType == TFACT );
-+ while( it.Next( ) ) {
-+ Separate( );
-+ it->Accept( this );
-+ }
-+ Append( " }" );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmBinHorNode* pNode )
-+{
-+ Append( "{" );
-+ SmNode *pLeft = pNode->GetSubNode( 0 ),
-+ *pOper = pNode->GetSubNode( 1 ),
-+ *pRight = pNode->GetSubNode( 2 );
-+ Separate( );
-+ pLeft->Accept( this );
-+ Separate( );
-+ pOper->Accept( this );
-+ Separate( );
-+ pRight->Accept( this );
-+ Separate( );
-+ Append( "}" );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmBinVerNode* pNode )
-+{
-+ SmNode *pNum = pNode->GetSubNode( 0 ),
-+ *pDenom = pNode->GetSubNode( 2 );
-+ LineToText( pNum );
-+ Append( "over" );
-+ LineToText( pDenom );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmBinDiagonalNode* pNode )
-+{
-+ SmNode *pLeftOperand = pNode->GetSubNode( 0 ),
-+ *pRightOperand = pNode->GetSubNode( 1 );
-+ LineToText( pLeftOperand );
-+ Separate( );
-+ Append( "wideslash " );
-+ LineToText( pRightOperand );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmSubSupNode* pNode )
-+{
-+ LineToText( pNode->GetBody( ) );
-+ SmNode *pChild;
-+ if( ( pChild = pNode->GetSubSup( LSUP ) ) ) {
-+ Separate( );
-+ Append( "lsup " );
-+ LineToText( pChild );
-+ }
-+ if( ( pChild = pNode->GetSubSup( LSUB ) ) ) {
-+ Separate( );
-+ Append( "lsub " );
-+ LineToText( pChild );
-+ }
-+ if( ( pChild = pNode->GetSubSup( RSUP ) ) ) {
-+ Separate( );
-+ Append( "rsup " );
-+ LineToText( pChild );
-+ }
-+ if( ( pChild = pNode->GetSubSup( RSUB ) ) ) {
-+ Separate( );
-+ Append( "rsub " );
-+ LineToText( pChild );
-+ }
-+ if( ( pChild = pNode->GetSubSup( CSUP ) ) ) {
-+ Separate( );
-+ Append( "csup " );
-+ LineToText( pChild );
-+ }
-+ if( ( pChild = pNode->GetSubSup( CSUB ) ) ) {
-+ Separate( );
-+ Append( "csub " );
-+ LineToText( pChild );
-+ }
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmMatrixNode* pNode )
-+{
-+ Append( "matrix{" );
-+ for ( USHORT i = 0; i < pNode->GetNumRows( ); i++ ) {
-+ for ( USHORT j = 0; j < pNode->GetNumCols( ); j++ ) {
-+ SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
-+ Separate( );
-+ pSubNode->Accept( this );
-+ Separate( );
-+ if( j != pNode->GetNumCols( ) - 1 )
-+ Append( "#" );
-+ }
-+ Separate( );
-+ if( i != pNode->GetNumRows( ) - 1 )
-+ Append( "##" );
-+ }
-+ Append( "}" );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmPlaceNode* )
-+{
-+ Append( "<?>" );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmTextNode* pNode )
-+{
-+ //TODO: This method might need improvements, see SmTextNode::CreateTextFromNode
-+ if( pNode->GetToken( ).eType == TTEXT )
-+ Append( "\"" );
-+ Append( pNode->GetText( ) );
-+ if( pNode->GetToken( ).eType == TTEXT )
-+ Append( "\"" );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmSpecialNode* pNode )
-+{
-+ Append( "%" );
-+ Append( pNode->GetToken( ).aText );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode* pNode )
-+{
-+ if( pNode->GetToken( ).eType == TBOPER )
-+ Append( "boper " );
-+ else
-+ Append( "uoper " );
-+ Append( pNode->GetToken( ).aText );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
-+{
-+ Append( pNode->GetToken( ).aText );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmBlankNode* pNode )
-+{
-+ Append( pNode->GetToken( ).aText );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmErrorNode* )
-+{
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmLineNode* pNode )
-+{
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) ){
-+ Separate( );
-+ it->Accept( this );
-+ }
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmExpressionNode* pNode )
-+{
-+ Append( "{ " );
-+ SmNodeIterator it( pNode );
-+ while( it.Next( ) ) {
-+ it->Accept( this );
-+ Separate( );
-+ }
-+ Append( "}" );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmPolyLineNode* )
-+{
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmRootNode* pNode )
-+{
-+ SmNode *pExtra = pNode->GetSubNode( 0 ),
-+ *pBody = pNode->GetSubNode( 2 );
-+ if( pExtra ) {
-+ Append( "nroot" );
-+ LineToText( pExtra );
-+ } else
-+ Append( "sqrt" );
-+ LineToText( pBody );
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmRootSymbolNode* )
-+{
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmRectangleNode* )
-+{
-+}
-+
-+void SmNodeToTextVisitor::Visit( SmVerticalBraceNode* pNode )
-+{
-+ SmNode *pBody = pNode->GetSubNode( 0 ),
-+ *pScript = pNode->GetSubNode( 2 );
-+ LineToText( pBody );
-+ Append( pNode->GetToken( ).aText );
-+ LineToText( pScript );
-+}
-+