update credits
[LibreOffice.git] / starmath / inc / cursor.hxx
blob9f15e05ec9857792b2df2ee9930540e38e441bb0
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 SMCURSOR_H
10 #define SMCURSOR_H
12 #include "node.hxx"
13 #include "caret.hxx"
15 /** Factor to multiple the squared horizontical distance with
16 * Used for Up and Down movement.
18 #define HORIZONTICAL_DISTANCE_FACTOR 10
20 /** Enum of direction for movement */
21 enum SmMovementDirection{
22 MoveUp,
23 MoveDown,
24 MoveLeft,
25 MoveRight
28 /** Enum of elements that can inserted into a formula */
29 enum SmFormulaElement{
30 BlankElement,
31 FactorialElement,
32 PlusElement,
33 MinusElement,
34 CDotElement,
35 EqualElement,
36 LessThanElement,
37 GreaterThanElement,
38 PercentElement
41 /** Bracket types that can be inserted */
42 enum SmBracketType {
43 /** None brackets, left command "none" */
44 NoneBrackets,
45 /** Round brackets, left command "(" */
46 RoundBrackets,
47 /**Square brackets, left command "[" */
48 SquareBrackets,
49 /** Double square brackets, left command "ldbracket" */
50 DoubleSquareBrackets,
51 /** Line brackets, left command "lline" */
52 LineBrackets,
53 /** Double line brackets, left command "ldline" */
54 DoubleLineBrackets,
55 /** Curly brackets, left command "lbrace" */
56 CurlyBrackets,
57 /** Angle brackets, left command "langle" */
58 AngleBrackets,
59 /** Ceiling brackets, left command "lceil" */
60 CeilBrackets,
61 /** Floor brackets, left command "lfloor" */
62 FloorBrackets
65 /** A list of nodes */
66 typedef std::list<SmNode*> SmNodeList;
68 class SmDocShell;
70 /** Formula cursor
72 * This class is used to represent a cursor in a formula, which can be used to manipulate
73 * an formula programmatically.
74 * @remarks This class is a very intimite friend of SmDocShell.
76 class SmCursor{
77 public:
78 SmCursor(SmNode* tree, SmDocShell* pShell){
79 //Initialize members
80 pTree = tree;
81 anchor = NULL;
82 position = NULL;
83 pGraph = NULL;
84 pDocShell = pShell;
85 pClipboard = NULL;
86 nEditSections = 0;
87 //Build graph
88 BuildGraph();
91 ~SmCursor(){
92 SetClipboard();
93 if(pGraph)
94 delete pGraph;
95 pGraph = NULL;
98 /** Gets the anchor */
99 SmCaretPos GetAnchor(){ return anchor->CaretPos; }
101 /** Get position */
102 SmCaretPos GetPosition() const { return position->CaretPos; }
104 /** True, if the cursor has a selection */
105 bool HasSelection() { return anchor != position; }
107 /** Move the position of this cursor */
108 void Move(OutputDevice* pDev, SmMovementDirection direction, bool bMoveAnchor = true);
110 /** Move to the caret position closet to a given point */
111 void MoveTo(OutputDevice* pDev, Point pos, bool bMoveAnchor = true);
113 /** Delete the current selection or do nothing */
114 void Delete();
116 /** Delete selection, previous element or merge lines
118 * This method implements the behaviour of backspace.
120 void DeletePrev(OutputDevice* pDev);
122 /** Insert text at the current position */
123 void InsertText(OUString aString);
125 /** Insert an element into the formula */
126 void InsertElement(SmFormulaElement element);
128 /** Insert a command specified in commands.src*/
129 void InsertCommand(sal_uInt16 nCommand);
131 /** Insert command text translated into line entries at position
133 * Note: This method uses the parser to translate a command text into a
134 * tree, then it copies line entries from this tree into the current tree.
135 * Will not work for commands such as newline or ##, if position is in a matrix.
136 * This will work for stuff like "A intersection B". But stuff spaning multiple lines
137 * or dependent on the context which position is placed in will not work!
139 void InsertCommandText(OUString aCommandText);
141 /** Insert a special node created from aString
143 * Used for handling insert request from the "catalog" dialog.
144 * The provided string should be formatet as the desired command: %phi
145 * Note: this method ONLY supports commands defined in Math.xcu
147 * For more complex expressions use InsertCommandText, this method doesn't
148 * use SmParser, this means that it's faster, but not as strong.
150 void InsertSpecial(OUString aString);
152 /** Create sub-/super script
154 * If there's a selection, it will be move into the appropriate sub-/super scription
155 * of the node in front of it. If there's no node in front of position (or the selection),
156 * a sub-/super scription of a new SmPlaceNode will be made.
158 * If there's is an existing subscription of the node, the caret will be moved into it,
159 * and any selection will replace it.
161 void InsertSubSup(SmSubSup eSubSup);
163 /** Create a limit on an SmOperNode
165 * This this method only work if the caret is inside an SmOperNode, or to the right of one.
166 * Notice also that this method ignores any selection made.
168 * @param bMoveCaret If true that caret will be moved into the limit.
170 * @returns True, if the caret was in a context where this operation was possible.
172 bool InsertLimit(SmSubSup eSubSup, bool bMoveCaret = true);
174 /** Insert a new row or newline
176 * Inserts a new row if position is in an matrix or stack command.
177 * Otherwise a newline is inserted if we're in a toplevel line.
179 * @returns True, if a new row/line could be inserted.
181 * @remarks If the caret is placed in a subline of a command that doesn't support
182 * this operator the method returns FALSE, and doesn't do anything.
184 bool InsertRow();
186 /** Insert a fraction, use selection as numerator */
187 void InsertFraction();
189 /** Create brackets around current selection, or new SmPlaceNode */
190 void InsertBrackets(SmBracketType eBracketType);
192 /** Copy the current selection */
193 void Copy();
194 /** Cut the current selection */
195 void Cut(){
196 Copy();
197 Delete();
199 /** Paste the clipboard */
200 void Paste();
202 /** Returns true if more than one node is selected
204 * This method is used for implementing backspace and delete.
205 * If one of these causes a complex selection, e.g. a node with
206 * subnodes or similar, this should not be deleted imidiately.
208 bool HasComplexSelection();
210 /** Finds the topmost node in a visual line
212 * If MoveUpIfSelected is true, this will move up to the parent line
213 * if the parent of the current line is selected.
215 static SmNode* FindTopMostNodeInLine(SmNode* pSNode, bool MoveUpIfSelected = false);
217 /** Draw the caret */
218 void Draw(OutputDevice& pDev, Point Offset, bool isCaretVisible);
220 bool IsAtTailOfBracket(SmBracketType eBracketType, SmBraceNode** ppBraceNode = NULL) const;
221 void MoveAfterBracket(SmBraceNode* pBraceNode, bool bMoveAnchor = true);
223 private:
224 friend class SmDocShell;
226 SmCaretPosGraphEntry *anchor,
227 *position;
228 /** Formula tree */
229 SmNode* pTree;
230 /** Owner of the formula tree */
231 SmDocShell* pDocShell;
232 /** Graph over caret position in the current tree */
233 SmCaretPosGraph* pGraph;
234 /** Clipboard holder */
235 SmNodeList* pClipboard;
237 /** Returns a node that is selected, if any could be found */
238 SmNode* FindSelectedNode(SmNode* pNode);
240 /** Is this one of the nodes used to compose a line
242 * These are SmExpression, SmBinHorNode, SmUnHorNode etc.
244 static bool IsLineCompositionNode(SmNode* pNode);
246 /** Count number of selected nodes, excluding line composition nodes
248 * Note this function doesn't count line composition nodes and it
249 * does count all subnodes as well as the owner nodes.
251 * Used by SmCursor::HasComplexSelection()
253 int CountSelectedNodes(SmNode* pNode);
255 /** Convert a visual line to a list
257 * Note this method will delete all the nodes that will no longer be needed.
258 * that includes pLine!
259 * This method also deletes SmErrorNode's as they're just meta info in the line.
261 static SmNodeList* LineToList(SmStructureNode* pLine, SmNodeList* pList = new SmNodeList());
263 /** Auxiliary function for calling LineToList on a node
265 * This method sets pNode = NULL and remove it from it's parent.
266 * (Assuming it has a parent, and is a child of it).
268 static SmNodeList* NodeToList(SmNode*& rpNode, SmNodeList* pList = new SmNodeList()){
269 //Remove from parent and NULL rpNode
270 SmNode* pNode = rpNode;
271 if(rpNode && rpNode->GetParent()){ //Don't remove this, correctness relies on it
272 int index = rpNode->GetParent()->IndexOfSubNode(rpNode);
273 if(index != -1)
274 rpNode->GetParent()->SetSubNode(index, NULL);
276 rpNode = NULL;
277 //Create line from node
278 if(pNode && IsLineCompositionNode(pNode))
279 return LineToList((SmStructureNode*)pNode, pList);
280 if(pNode)
281 pList->push_front(pNode);
282 return pList;
285 /** Clone a visual line to a list
287 * Doesn't clone SmErrorNode's these are ignored, as they are context dependent metadata.
289 static SmNodeList* CloneLineToList(SmStructureNode* pLine,
290 bool bOnlyIfSelected = false,
291 SmNodeList* pList = new SmNodeList());
293 /** Build pGraph over caret positions */
294 void BuildGraph();
296 /** Insert new nodes in the tree after position */
297 void InsertNodes(SmNodeList* pNewNodes);
299 /** tries to set position to a specific SmCaretPos
301 * @returns false on failure to find the position in pGraph.
303 bool SetCaretPosition(SmCaretPos pos, bool moveAnchor = false);
305 /** Set selected on nodes of the tree */
306 void AnnotateSelection();
308 /** Set the clipboard, and release current clipboard
310 * Call this method with NULL to reset the clipboard
311 * @remarks: This method takes ownership of pList.
313 void SetClipboard(SmNodeList* pList = NULL);
315 /** Clone list of nodes (creates a deep clone) */
316 static SmNodeList* CloneList(SmNodeList* pList);
318 /** Find an iterator pointing to the node in pLineList following aCaretPos
320 * If aCaretPos::pSelectedNode cannot be found it is assumed that it's in front of pLineList,
321 * thus not an element in pLineList. In this case this method returns an iterator to the
322 * first element in pLineList.
324 * If the current position is inside an SmTextNode, this node will be split in two, for this
325 * reason you should beaware that iterators to elements in pLineList may be invalidated, and
326 * that you should call PatchLineList() with this iterator if no action is taken.
328 static SmNodeList::iterator FindPositionInLineList(SmNodeList* pLineList, SmCaretPos aCaretPos);
330 /** Patch a line list after modification, merge SmTextNode, remove SmPlaceNode etc.
332 * @param pLineList The line list to patch
333 * @param aIter Iterator pointing to the element that needs to be patched with it's previous.
335 * When the list is patched text nodes before and after aIter will be merged.
336 * If there's an, in the context, inappropriate SmPlaceNode before or after aIter it will also be
337 * removed.
339 * @returns A caret position equivalent to one selecting the node before aIter, the method returns
340 * an invalid SmCaretPos to indicate placement in front of the line.
342 static SmCaretPos PatchLineList(SmNodeList* pLineList, SmNodeList::iterator aIter);
344 /** Take selected nodes from a list
346 * Puts the selected nodes into pSelectedNodes, or if pSelectedNodes is NULL deletes
347 * the selected nodes.
348 * Note: If there's a selection inside an SmTextNode this node will be split, and it
349 * will not be merged when the selection have been taken. Use PatchLineList on the
350 * iterator returns to fix this.
352 * @returns An iterator pointing to the element following the selection taken.
354 static SmNodeList::iterator TakeSelectedNodesFromList(SmNodeList *pLineList,
355 SmNodeList *pSelectedNodes = NULL);
357 /** Create an instance of SmMathSymbolNode usable for brackets */
358 static SmNode *CreateBracket(SmBracketType eBracketType, bool bIsLeft);
360 /** The number of times BeginEdit have been called
361 * Used to allow nesting of BeginEdit() and EndEdit() sections
363 int nEditSections;
364 /** Holds data for BeginEdit() and EndEdit() */
365 bool bIsEnabledSetModifiedSmDocShell;
366 /** Begin edit section where the tree will be modified */
367 void BeginEdit();
368 /** End edit section where the tree will be modified */
369 void EndEdit();
370 /** Finish editing
372 * Finishes editing by parsing pLineList and inserting back into pParent at nParentIndex.
373 * This method also rebuilts the graph, annotates the selection, sets caret position and
374 * Calls EndEdit.
376 * @remarks Please note that this method will delete pLineList, as the elements are taken.
378 * @param pLineList List the constitutes the edited line.
379 * @param pParent Parent to which the line should be inserted.
380 * @param nParentIndex Index in parent where the line should be inserted.
381 * @param PosAfterEdit Caret position to look for after rebuilding graph.
382 * @param pStartLine Line to take first position in, if PosAfterEdit cannot be found,
383 * leave it NULL for pLineList.
385 void FinishEdit(SmNodeList* pLineList,
386 SmStructureNode* pParent,
387 int nParentIndex,
388 SmCaretPos PosAfterEdit,
389 SmNode* pStartLine = NULL);
390 /** Request the formula is repainted */
391 void RequestRepaint();
394 /** Minimalistic recursive decent SmNodeList parser
396 * This parser is used to take a list of nodes that constitues a line
397 * and parse them to a tree of SmBinHorNode, SmUnHorNode and SmExpression.
399 * Please note, this will not handle all kinds of nodes, only nodes that
400 * constitues and entry in a line.
402 * Below is an EBNF representation of the grammar used for this parser:
403 * \code
404 * Expression -> Relation*
405 * Relation -> Sum [(=|<|>|...) Sum]*
406 * Sum -> Product [(+|-) Product]*
407 * Product -> Factor [(*|/) Factor]*
408 * Factor -> [+|-|-+|...]* Factor | Postfix
409 * Postfix -> node [!]*
410 * \endcode
412 class SmNodeListParser{
413 public:
414 /** Create an instance of SmNodeListParser */
415 SmNodeListParser(){
416 pList = NULL;
418 /** Parse a list of nodes to an expression
420 * If bDeleteErrorNodes is true, old error nodes will be deleted.
422 SmNode* Parse(SmNodeList* list, bool bDeleteErrorNodes = true);
423 /** True, if the token is an operator */
424 static bool IsOperator(const SmToken &token);
425 /** True, if the token is a relation operator */
426 static bool IsRelationOperator(const SmToken &token);
427 /** True, if the token is a sum operator */
428 static bool IsSumOperator(const SmToken &token);
429 /** True, if the token is a product operator */
430 static bool IsProductOperator(const SmToken &token);
431 /** True, if the token is a unary operator */
432 static bool IsUnaryOperator(const SmToken &token);
433 /** True, if the token is a postfix operator */
434 static bool IsPostfixOperator(const SmToken &token);
435 private:
436 SmNodeList* pList;
437 /** Get the current terminal */
438 SmNode* Terminal(){
439 if(pList->size() > 0)
440 return pList->front();
441 return NULL;
443 /** Move to next terminal */
444 SmNode* Next(){
445 pList->pop_front();
446 return Terminal();
448 /** Take the current terminal */
449 SmNode* Take(){
450 SmNode* pRetVal = Terminal();
451 Next();
452 return pRetVal;
454 SmNode* Expression();
455 SmNode* Relation();
456 SmNode* Sum();
457 SmNode* Product();
458 SmNode* Factor();
459 SmNode* Postfix();
460 SmNode* Error();
464 #endif /* SMCURSOR_H */
466 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */