bump product version to 7.2.5.1
[LibreOffice.git] / starmath / inc / cursor.hxx
blob4b670e61cb8c3ec0d0c90bb9d55431dfe0551de8
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 */
10 #pragma once
12 #include "caret.hxx"
14 /** Factor to multiple the squared horizontal distance with
15 * Used for Up and Down movement.
17 #define HORIZONTICAL_DISTANCE_FACTOR 10
19 /** Enum of direction for movement */
20 enum SmMovementDirection
22 MoveUp,
23 MoveDown,
24 MoveLeft,
25 MoveRight
28 /** Enum of elements that can inserted into a formula */
29 enum SmFormulaElement
31 BlankElement,
32 FactorialElement,
33 PlusElement,
34 MinusElement,
35 CDotElement,
36 EqualElement,
37 LessThanElement,
38 GreaterThanElement,
39 PercentElement
42 /** Bracket types that can be inserted */
43 enum class SmBracketType
45 /** Round brackets, left command "(" */
46 Round,
47 /**Square brackets, left command "[" */
48 Square,
49 /** Curly brackets, left command "lbrace" */
50 Curly,
53 /** A list of nodes */
54 typedef std::list<SmNode*> SmNodeList;
56 typedef std::list<std::unique_ptr<SmNode>> SmClipboard;
58 class SmDocShell;
60 /** Formula cursor
62 * This class is used to represent a cursor in a formula, which can be used to manipulate
63 * a formula programmatically.
64 * @remarks This class is a very intimate friend of SmDocShell.
66 class SmCursor
68 public:
69 SmCursor(SmNode* tree, SmDocShell* pShell)
70 : mpAnchor(nullptr)
71 , mpPosition(nullptr)
72 , mpTree(tree)
73 , mpDocShell(pShell)
74 , mnEditSections(0)
75 , mbIsEnabledSetModifiedSmDocShell(false)
77 //Build graph
78 BuildGraph();
81 /** Get position */
82 const SmCaretPos& GetPosition() const { return mpPosition->CaretPos; }
84 /** True, if the cursor has a selection */
85 bool HasSelection() const { return mpAnchor != mpPosition; }
87 /** Move the position of this cursor */
88 void Move(OutputDevice* pDev, SmMovementDirection direction, bool bMoveAnchor = true);
90 /** Move to the caret position closest to a given point */
91 void MoveTo(OutputDevice* pDev, const Point& pos, bool bMoveAnchor);
93 /** Delete the current selection or do nothing */
94 void Delete();
96 /** Delete selection, previous element or merge lines
98 * This method implements the behaviour of backspace.
100 void DeletePrev(OutputDevice* pDev);
102 /** Insert text at the current position */
103 void InsertText(const OUString& aString);
105 /** Insert an element into the formula */
106 void InsertElement(SmFormulaElement element);
108 /** Insert command text translated into line entries at position
110 * Note: This method uses the parser to translate a command text into a
111 * tree, then it copies line entries from this tree into the current tree.
112 * Will not work for commands such as newline or ##, if position is in a matrix.
113 * This will work for stuff like "A intersection B". But stuff spanning multiple lines
114 * or dependent on the context which position is placed in will not work!
116 void InsertCommandText(const OUString& aCommandText);
118 /** Insert a special node created from aString
120 * Used for handling insert request from the "catalog" dialog.
121 * The provided string should be formatted as the desired command: %phi
122 * Note: this method ONLY supports commands defined in Math.xcu
124 * For more complex expressions use InsertCommandText, this method doesn't
125 * use SmParser, this means that it's faster, but not as strong.
127 void InsertSpecial(std::u16string_view aString);
129 /** Create sub-/super script
131 * If there's a selection, it will be move into the appropriate sub-/super scription
132 * of the node in front of it. If there's no node in front of position (or the selection),
133 * a sub-/super scription of a new SmPlaceNode will be made.
135 * If there's is an existing subscription of the node, the caret will be moved into it,
136 * and any selection will replace it.
138 void InsertSubSup(SmSubSup eSubSup);
140 /** Insert a new row or newline
142 * Inserts a new row if position is in a matrix or stack command.
143 * Otherwise a newline is inserted if we're in a toplevel line.
145 * @returns True, if a new row/line could be inserted.
147 * @remarks If the caret is placed in a subline of a command that doesn't support
148 * this operator the method returns FALSE, and doesn't do anything.
150 bool InsertRow();
152 /** Insert a fraction, use selection as numerator */
153 void InsertFraction();
155 /** Create brackets around current selection, or new SmPlaceNode */
156 void InsertBrackets(SmBracketType eBracketType);
158 /** Copy the current selection */
159 void Copy();
160 /** Cut the current selection */
161 void Cut()
163 Copy();
164 Delete();
166 /** Paste the clipboard */
167 void Paste();
169 /** Returns true if more than one node is selected
171 * This method is used for implementing backspace and delete.
172 * If one of these causes a complex selection, e.g. a node with
173 * subnodes or similar, this should not be deleted immediately.
175 bool HasComplexSelection();
177 /** Finds the topmost node in a visual line
179 * If MoveUpIfSelected is true, this will move up to the parent line
180 * if the parent of the current line is selected.
182 static SmNode* FindTopMostNodeInLine(SmNode* pSNode, bool MoveUpIfSelected = false);
184 /** Draw the caret */
185 void Draw(OutputDevice& pDev, Point Offset, bool isCaretVisible);
187 bool IsAtTailOfBracket(SmBracketType eBracketType) const;
189 private:
190 friend class SmDocShell;
192 SmCaretPosGraphEntry *mpAnchor, *mpPosition;
193 /** Formula tree */
194 SmNode* mpTree;
195 /** Owner of the formula tree */
196 SmDocShell* mpDocShell;
197 /** Graph over caret position in the current tree */
198 std::unique_ptr<SmCaretPosGraph> mpGraph;
199 /** Clipboard holder */
200 SmClipboard maClipboard;
202 /** Returns a node that is selected, if any could be found */
203 SmNode* FindSelectedNode(SmNode* pNode);
205 /** Is this one of the nodes used to compose a line
207 * These are SmExpression, SmBinHorNode, SmUnHorNode etc.
209 static bool IsLineCompositionNode(SmNode const* pNode);
211 /** Count number of selected nodes, excluding line composition nodes
213 * Note this function doesn't count line composition nodes and it
214 * does count all subnodes as well as the owner nodes.
216 * Used by SmCursor::HasComplexSelection()
218 int CountSelectedNodes(SmNode* pNode);
220 /** Convert a visual line to a list
222 * Note this method will delete all the nodes that will no longer be needed.
223 * that includes pLine!
224 * This method also deletes SmErrorNode's as they're just meta info in the line.
226 static void LineToList(SmStructureNode* pLine, SmNodeList& rList);
228 /** Auxiliary function for calling LineToList on a node
230 * This method sets pNode = NULL and remove it from its parent.
231 * (Assuming it has a parent, and is a child of it).
233 static void NodeToList(SmNode*& rpNode, SmNodeList& rList)
235 //Remove from parent and NULL rpNode
236 SmNode* pNode = rpNode;
237 if (rpNode && rpNode->GetParent())
238 { //Don't remove this, correctness relies on it
239 int index = rpNode->GetParent()->IndexOfSubNode(rpNode);
240 assert(index >= 0);
241 rpNode->GetParent()->SetSubNode(index, nullptr);
243 rpNode = nullptr;
244 //Create line from node
245 if (pNode && IsLineCompositionNode(pNode))
247 LineToList(static_cast<SmStructureNode*>(pNode), rList);
248 return;
250 if (pNode)
251 rList.push_front(pNode);
254 /** Clone a visual line to a clipboard
256 * ... but the selected part only.
257 * Doesn't clone SmErrorNodes, which are ignored as they are context dependent metadata.
259 static void CloneLineToClipboard(SmStructureNode* pLine, SmClipboard* pClipboard);
261 /** Build pGraph over caret positions */
262 void BuildGraph();
264 /** Insert new nodes in the tree after position */
265 void InsertNodes(std::unique_ptr<SmNodeList> pNewNodes);
267 /** tries to set position to a specific SmCaretPos
269 * @returns false on failure to find the position in pGraph.
271 bool SetCaretPosition(SmCaretPos pos);
273 /** Set selected on nodes of the tree */
274 void AnnotateSelection();
276 /** Clone list of nodes in a clipboard (creates a deep clone) */
277 static std::unique_ptr<SmNodeList> CloneList(SmClipboard& rClipboard);
279 /** Find an iterator pointing to the node in pLineList following rCaretPos
281 * If rCaretPos.pSelectedNode cannot be found it is assumed that it's in front of pLineList,
282 * thus not an element in pLineList. In this case this method returns an iterator to the
283 * first element in pLineList.
285 * If the current position is inside an SmTextNode, this node will be split in two, for this
286 * reason you should beaware that iterators to elements in pLineList may be invalidated, and
287 * that you should call PatchLineList() with this iterator if no action is taken.
289 static SmNodeList::iterator FindPositionInLineList(SmNodeList* pLineList,
290 const SmCaretPos& rCaretPos);
292 /** Patch a line list after modification, merge SmTextNode, remove SmPlaceNode etc.
294 * @param pLineList The line list to patch
295 * @param aIter Iterator pointing to the element that needs to be patched with its previous.
297 * When the list is patched text nodes before and after aIter will be merged.
298 * If there's an, in the context, inappropriate SmPlaceNode before or after aIter it will also be
299 * removed.
301 * @returns A caret position equivalent to one selecting the node before aIter, the method returns
302 * an invalid SmCaretPos to indicate placement in front of the line.
304 static SmCaretPos PatchLineList(SmNodeList* pLineList, SmNodeList::iterator aIter);
306 /** Take selected nodes from a list
308 * Puts the selected nodes into pSelectedNodes, or if pSelectedNodes is NULL deletes
309 * the selected nodes.
310 * Note: If there's a selection inside an SmTextNode this node will be split, and it
311 * will not be merged when the selection have been taken. Use PatchLineList on the
312 * iterator returns to fix this.
314 * @returns An iterator pointing to the element following the selection taken.
316 static SmNodeList::iterator TakeSelectedNodesFromList(SmNodeList* pLineList,
317 SmNodeList* pSelectedNodes = nullptr);
319 /** Create an instance of SmMathSymbolNode usable for brackets */
320 static SmNode* CreateBracket(SmBracketType eBracketType, bool bIsLeft);
322 /** The number of times BeginEdit have been called
323 * Used to allow nesting of BeginEdit() and EndEdit() sections
325 int mnEditSections;
326 /** Holds data for BeginEdit() and EndEdit() */
327 bool mbIsEnabledSetModifiedSmDocShell;
328 /** Begin edit section where the tree will be modified */
329 void BeginEdit();
330 /** End edit section where the tree will be modified */
331 void EndEdit();
332 /** Finish editing
334 * Finishes editing by parsing pLineList and inserting back into pParent at nParentIndex.
335 * This method also rebuilds the graph, annotates the selection, sets caret position and
336 * Calls EndEdit.
338 * @remarks Please note that this method will delete pLineList, as the elements are taken.
340 * @param pLineList List the constitutes the edited line.
341 * @param pParent Parent to which the line should be inserted.
342 * @param nParentIndex Index in parent where the line should be inserted.
343 * @param PosAfterEdit Caret position to look for after rebuilding graph.
344 * @param pStartLine Line to take first position in, if PosAfterEdit cannot be found,
345 * leave it NULL for pLineList.
347 void FinishEdit(std::unique_ptr<SmNodeList> pLineList, SmStructureNode* pParent,
348 int nParentIndex, SmCaretPos PosAfterEdit, SmNode* pStartLine = nullptr);
349 /** Request the formula is repainted */
350 void RequestRepaint();
353 /** Minimalistic recursive decent SmNodeList parser
355 * This parser is used to take a list of nodes that constitutes a line
356 * and parse them to a tree of SmBinHorNode, SmUnHorNode and SmExpression.
358 * Please note, this will not handle all kinds of nodes, only nodes that
359 * constitutes and entry in a line.
361 * Below is an EBNF representation of the grammar used for this parser:
362 * \code
363 * Expression -> Relation*
364 * Relation -> Sum [(=|<|>|...) Sum]*
365 * Sum -> Product [(+|-) Product]*
366 * Product -> Factor [(*|/) Factor]*
367 * Factor -> [+|-|-+|...]* Factor | Postfix
368 * Postfix -> node [!]*
369 * \endcode
371 class SmNodeListParser
373 public:
374 /** Create an instance of SmNodeListParser */
375 SmNodeListParser() { pList = nullptr; }
376 /** Parse a list of nodes to an expression.
378 * Old error nodes will be deleted.
380 SmNode* Parse(SmNodeList* list);
381 /** True, if the token is an operator */
382 static bool IsOperator(const SmToken& token);
383 /** True, if the token is a relation operator */
384 static bool IsRelationOperator(const SmToken& token);
385 /** True, if the token is a sum operator */
386 static bool IsSumOperator(const SmToken& token);
387 /** True, if the token is a product operator */
388 static bool IsProductOperator(const SmToken& token);
389 /** True, if the token is a unary operator */
390 static bool IsUnaryOperator(const SmToken& token);
391 /** True, if the token is a postfix operator */
392 static bool IsPostfixOperator(const SmToken& token);
394 private:
395 SmNodeList* pList;
396 /** Get the current terminal */
397 SmNode* Terminal()
399 if (!pList->empty())
400 return pList->front();
401 return nullptr;
403 /** Move to next terminal */
404 SmNode* Next()
406 pList->pop_front();
407 return Terminal();
409 /** Take the current terminal */
410 SmNode* Take()
412 SmNode* pRetVal = Terminal();
413 Next();
414 return pRetVal;
416 SmNode* Expression();
417 SmNode* Relation();
418 SmNode* Sum();
419 SmNode* Product();
420 SmNode* Factor();
421 SmNode* Postfix();
422 static SmNode* Error();
425 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */