bump product version to 5.0.4.1
[LibreOffice.git] / starmath / inc / cursor.hxx
blob188c0984324924830d227508ebc7a1ebdbcdbd43
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9 #ifndef INCLUDED_STARMATH_INC_CURSOR_HXX
10 #define INCLUDED_STARMATH_INC_CURSOR_HXX
12 #include "node.hxx"
13 #include "caret.hxx"
15 #include <list>
17 /** Factor to multiple the squared horizontal distance with
18 * Used for Up and Down movement.
20 #define HORIZONTICAL_DISTANCE_FACTOR 10
22 /** Enum of direction for movement */
23 enum SmMovementDirection{
24 MoveUp,
25 MoveDown,
26 MoveLeft,
27 MoveRight
30 /** Enum of elements that can inserted into a formula */
31 enum SmFormulaElement{
32 BlankElement,
33 FactorialElement,
34 PlusElement,
35 MinusElement,
36 CDotElement,
37 EqualElement,
38 LessThanElement,
39 GreaterThanElement,
40 PercentElement
43 /** Bracket types that can be inserted */
44 enum SmBracketType {
45 /** None brackets, left command "none" */
46 NoneBrackets,
47 /** Round brackets, left command "(" */
48 RoundBrackets,
49 /**Square brackets, left command "[" */
50 SquareBrackets,
51 /** Double square brackets, left command "ldbracket" */
52 DoubleSquareBrackets,
53 /** Line brackets, left command "lline" */
54 LineBrackets,
55 /** Double line brackets, left command "ldline" */
56 DoubleLineBrackets,
57 /** Curly brackets, left command "lbrace" */
58 CurlyBrackets,
59 /** Angle brackets, left command "langle" */
60 AngleBrackets,
61 /** Ceiling brackets, left command "lceil" */
62 CeilBrackets,
63 /** Floor brackets, left command "lfloor" */
64 FloorBrackets
67 /** A list of nodes */
68 typedef std::list<SmNode*> SmNodeList;
70 class SmDocShell;
72 /** Formula cursor
74 * This class is used to represent a cursor in a formula, which can be used to manipulate
75 * an formula programmatically.
76 * @remarks This class is a very intimite friend of SmDocShell.
78 class SmCursor{
79 public:
80 SmCursor(SmNode* tree, SmDocShell* pShell)
81 : anchor(NULL)
82 , position(NULL)
83 , pTree(tree)
84 , pDocShell(pShell)
85 , pGraph(NULL)
86 , pClipboard(NULL)
87 , nEditSections(0)
88 , bIsEnabledSetModifiedSmDocShell(false)
90 //Build graph
91 BuildGraph();
94 ~SmCursor()
96 SetClipboard();
97 delete pGraph;
98 pGraph = NULL;
101 /** Gets the anchor */
102 SmCaretPos GetAnchor(){ return anchor->CaretPos; }
104 /** Get position */
105 SmCaretPos GetPosition() const { return position->CaretPos; }
107 /** True, if the cursor has a selection */
108 bool HasSelection() { return anchor != position; }
110 /** Move the position of this cursor */
111 void Move(OutputDevice* pDev, SmMovementDirection direction, bool bMoveAnchor = true);
113 /** Move to the caret position closet to a given point */
114 void MoveTo(OutputDevice* pDev, Point pos, bool bMoveAnchor = true);
116 /** Delete the current selection or do nothing */
117 void Delete();
119 /** Delete selection, previous element or merge lines
121 * This method implements the behaviour of backspace.
123 void DeletePrev(OutputDevice* pDev);
125 /** Insert text at the current position */
126 void InsertText(const OUString& aString);
128 /** Insert an element into the formula */
129 void InsertElement(SmFormulaElement element);
131 /** Insert a command specified in commands.src*/
132 void InsertCommand(sal_uInt16 nCommand);
134 /** Insert command text translated into line entries at position
136 * Note: This method uses the parser to translate a command text into a
137 * tree, then it copies line entries from this tree into the current tree.
138 * Will not work for commands such as newline or ##, if position is in a matrix.
139 * This will work for stuff like "A intersection B". But stuff spaning multiple lines
140 * or dependent on the context which position is placed in will not work!
142 void InsertCommandText(const OUString& aCommandText);
144 /** Insert a special node created from aString
146 * Used for handling insert request from the "catalog" dialog.
147 * The provided string should be formatted as the desired command: %phi
148 * Note: this method ONLY supports commands defined in Math.xcu
150 * For more complex expressions use InsertCommandText, this method doesn't
151 * use SmParser, this means that it's faster, but not as strong.
153 void InsertSpecial(const OUString& aString);
155 /** Create sub-/super script
157 * If there's a selection, it will be move into the appropriate sub-/super scription
158 * of the node in front of it. If there's no node in front of position (or the selection),
159 * a sub-/super scription of a new SmPlaceNode will be made.
161 * If there's is an existing subscription of the node, the caret will be moved into it,
162 * and any selection will replace it.
164 void InsertSubSup(SmSubSup eSubSup);
166 /** Create a limit on an SmOperNode
168 * This method only work if the caret is inside an SmOperNode, or to the right of one.
169 * Notice also that this method ignores any selection made.
171 * @param bMoveCaret If true that caret will be moved into the limit.
173 * @returns True, if the caret was in a context where this operation was possible.
175 bool InsertLimit(SmSubSup eSubSup, bool bMoveCaret = true);
177 /** Insert a new row or newline
179 * Inserts a new row if position is in an matrix or stack command.
180 * Otherwise a newline is inserted if we're in a toplevel line.
182 * @returns True, if a new row/line could be inserted.
184 * @remarks If the caret is placed in a subline of a command that doesn't support
185 * this operator the method returns FALSE, and doesn't do anything.
187 bool InsertRow();
189 /** Insert a fraction, use selection as numerator */
190 void InsertFraction();
192 /** Create brackets around current selection, or new SmPlaceNode */
193 void InsertBrackets(SmBracketType eBracketType);
195 /** Copy the current selection */
196 void Copy();
197 /** Cut the current selection */
198 void Cut(){
199 Copy();
200 Delete();
202 /** Paste the clipboard */
203 void Paste();
205 /** Returns true if more than one node is selected
207 * This method is used for implementing backspace and delete.
208 * If one of these causes a complex selection, e.g. a node with
209 * subnodes or similar, this should not be deleted imidiately.
211 bool HasComplexSelection();
213 /** Finds the topmost node in a visual line
215 * If MoveUpIfSelected is true, this will move up to the parent line
216 * if the parent of the current line is selected.
218 static SmNode* FindTopMostNodeInLine(SmNode* pSNode, bool MoveUpIfSelected = false);
220 /** Draw the caret */
221 void Draw(OutputDevice& pDev, Point Offset, bool isCaretVisible);
223 bool IsAtTailOfBracket(SmBracketType eBracketType, SmBraceNode** ppBraceNode = NULL) const;
224 void MoveAfterBracket(SmBraceNode* pBraceNode, bool bMoveAnchor = true);
226 private:
227 friend class SmDocShell;
229 SmCaretPosGraphEntry *anchor,
230 *position;
231 /** Formula tree */
232 SmNode* pTree;
233 /** Owner of the formula tree */
234 SmDocShell* pDocShell;
235 /** Graph over caret position in the current tree */
236 SmCaretPosGraph* pGraph;
237 /** Clipboard holder */
238 SmNodeList* pClipboard;
240 /** Returns a node that is selected, if any could be found */
241 SmNode* FindSelectedNode(SmNode* pNode);
243 /** Is this one of the nodes used to compose a line
245 * These are SmExpression, SmBinHorNode, SmUnHorNode etc.
247 static bool IsLineCompositionNode(SmNode* pNode);
249 /** Count number of selected nodes, excluding line composition nodes
251 * Note this function doesn't count line composition nodes and it
252 * does count all subnodes as well as the owner nodes.
254 * Used by SmCursor::HasComplexSelection()
256 int CountSelectedNodes(SmNode* pNode);
258 /** Convert a visual line to a list
260 * Note this method will delete all the nodes that will no longer be needed.
261 * that includes pLine!
262 * This method also deletes SmErrorNode's as they're just meta info in the line.
264 static SmNodeList* LineToList(SmStructureNode* pLine, SmNodeList* pList = new SmNodeList());
266 /** Auxiliary function for calling LineToList on a node
268 * This method sets pNode = NULL and remove it from its parent.
269 * (Assuming it has a parent, and is a child of it).
271 static SmNodeList* NodeToList(SmNode*& rpNode, SmNodeList* pList = new SmNodeList()){
272 //Remove from parent and NULL rpNode
273 SmNode* pNode = rpNode;
274 if(rpNode && rpNode->GetParent()){ //Don't remove this, correctness relies on it
275 int index = rpNode->GetParent()->IndexOfSubNode(rpNode);
276 if(index != -1)
277 rpNode->GetParent()->SetSubNode(index, NULL);
279 rpNode = NULL;
280 //Create line from node
281 if(pNode && IsLineCompositionNode(pNode))
282 return LineToList(static_cast<SmStructureNode*>(pNode), pList);
283 if(pNode)
284 pList->push_front(pNode);
285 return pList;
288 /** Clone a visual line to a list
290 * Doesn't clone SmErrorNode's these are ignored, as they are context dependent metadata.
292 static SmNodeList* CloneLineToList(SmStructureNode* pLine,
293 bool bOnlyIfSelected = false,
294 SmNodeList* pList = new SmNodeList());
296 /** Build pGraph over caret positions */
297 void BuildGraph();
299 /** Insert new nodes in the tree after position */
300 void InsertNodes(SmNodeList* pNewNodes);
302 /** tries to set position to a specific SmCaretPos
304 * @returns false on failure to find the position in pGraph.
306 bool SetCaretPosition(SmCaretPos pos, bool moveAnchor = false);
308 /** Set selected on nodes of the tree */
309 void AnnotateSelection();
311 /** Set the clipboard, and release current clipboard
313 * Call this method with NULL to reset the clipboard
314 * @remarks: This method takes ownership of pList.
316 void SetClipboard(SmNodeList* pList = NULL);
318 /** Clone list of nodes (creates a deep clone) */
319 static SmNodeList* CloneList(SmNodeList* pList);
321 /** Find an iterator pointing to the node in pLineList following aCaretPos
323 * If aCaretPos::pSelectedNode cannot be found it is assumed that it's in front of pLineList,
324 * thus not an element in pLineList. In this case this method returns an iterator to the
325 * first element in pLineList.
327 * If the current position is inside an SmTextNode, this node will be split in two, for this
328 * reason you should beaware that iterators to elements in pLineList may be invalidated, and
329 * that you should call PatchLineList() with this iterator if no action is taken.
331 static SmNodeList::iterator FindPositionInLineList(SmNodeList* pLineList, SmCaretPos aCaretPos);
333 /** Patch a line list after modification, merge SmTextNode, remove SmPlaceNode etc.
335 * @param pLineList The line list to patch
336 * @param aIter Iterator pointing to the element that needs to be patched with it's previous.
338 * When the list is patched text nodes before and after aIter will be merged.
339 * If there's an, in the context, inappropriate SmPlaceNode before or after aIter it will also be
340 * removed.
342 * @returns A caret position equivalent to one selecting the node before aIter, the method returns
343 * an invalid SmCaretPos to indicate placement in front of the line.
345 static SmCaretPos PatchLineList(SmNodeList* pLineList, SmNodeList::iterator aIter);
347 /** Take selected nodes from a list
349 * Puts the selected nodes into pSelectedNodes, or if pSelectedNodes is NULL deletes
350 * the selected nodes.
351 * Note: If there's a selection inside an SmTextNode this node will be split, and it
352 * will not be merged when the selection have been taken. Use PatchLineList on the
353 * iterator returns to fix this.
355 * @returns An iterator pointing to the element following the selection taken.
357 static SmNodeList::iterator TakeSelectedNodesFromList(SmNodeList *pLineList,
358 SmNodeList *pSelectedNodes = NULL);
360 /** Create an instance of SmMathSymbolNode usable for brackets */
361 static SmNode *CreateBracket(SmBracketType eBracketType, bool bIsLeft);
363 /** The number of times BeginEdit have been called
364 * Used to allow nesting of BeginEdit() and EndEdit() sections
366 int nEditSections;
367 /** Holds data for BeginEdit() and EndEdit() */
368 bool bIsEnabledSetModifiedSmDocShell;
369 /** Begin edit section where the tree will be modified */
370 void BeginEdit();
371 /** End edit section where the tree will be modified */
372 void EndEdit();
373 /** Finish editing
375 * Finishes editing by parsing pLineList and inserting back into pParent at nParentIndex.
376 * This method also rebuilts the graph, annotates the selection, sets caret position and
377 * Calls EndEdit.
379 * @remarks Please note that this method will delete pLineList, as the elements are taken.
381 * @param pLineList List the constitutes the edited line.
382 * @param pParent Parent to which the line should be inserted.
383 * @param nParentIndex Index in parent where the line should be inserted.
384 * @param PosAfterEdit Caret position to look for after rebuilding graph.
385 * @param pStartLine Line to take first position in, if PosAfterEdit cannot be found,
386 * leave it NULL for pLineList.
388 void FinishEdit(SmNodeList* pLineList,
389 SmStructureNode* pParent,
390 int nParentIndex,
391 SmCaretPos PosAfterEdit,
392 SmNode* pStartLine = NULL);
393 /** Request the formula is repainted */
394 void RequestRepaint();
397 /** Minimalistic recursive decent SmNodeList parser
399 * This parser is used to take a list of nodes that constitutes a line
400 * and parse them to a tree of SmBinHorNode, SmUnHorNode and SmExpression.
402 * Please note, this will not handle all kinds of nodes, only nodes that
403 * constitutes and entry in a line.
405 * Below is an EBNF representation of the grammar used for this parser:
406 * \code
407 * Expression -> Relation*
408 * Relation -> Sum [(=|<|>|...) Sum]*
409 * Sum -> Product [(+|-) Product]*
410 * Product -> Factor [(*|/) Factor]*
411 * Factor -> [+|-|-+|...]* Factor | Postfix
412 * Postfix -> node [!]*
413 * \endcode
415 class SmNodeListParser{
416 public:
417 /** Create an instance of SmNodeListParser */
418 SmNodeListParser(){
419 pList = NULL;
421 /** Parse a list of nodes to an expression
423 * If bDeleteErrorNodes is true, old error nodes will be deleted.
425 SmNode* Parse(SmNodeList* list, bool bDeleteErrorNodes = true);
426 /** True, if the token is an operator */
427 static bool IsOperator(const SmToken &token);
428 /** True, if the token is a relation operator */
429 static bool IsRelationOperator(const SmToken &token);
430 /** True, if the token is a sum operator */
431 static bool IsSumOperator(const SmToken &token);
432 /** True, if the token is a product operator */
433 static bool IsProductOperator(const SmToken &token);
434 /** True, if the token is a unary operator */
435 static bool IsUnaryOperator(const SmToken &token);
436 /** True, if the token is a postfix operator */
437 static bool IsPostfixOperator(const SmToken &token);
438 private:
439 SmNodeList* pList;
440 /** Get the current terminal */
441 SmNode* Terminal(){
442 if(pList->size() > 0)
443 return pList->front();
444 return NULL;
446 /** Move to next terminal */
447 SmNode* Next(){
448 pList->pop_front();
449 return Terminal();
451 /** Take the current terminal */
452 SmNode* Take(){
453 SmNode* pRetVal = Terminal();
454 Next();
455 return pRetVal;
457 SmNode* Expression();
458 SmNode* Relation();
459 SmNode* Sum();
460 SmNode* Product();
461 SmNode* Factor();
462 SmNode* Postfix();
463 static SmNode* Error();
467 #endif // INCLUDED_STARMATH_INC_CURSOR_HXX
469 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */