LCOV - code coverage report
Current view: top level - starmath/inc - cursor.hxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 36 42 85.7 %
Date: 2015-06-13 12:38:46 Functions: 8 10 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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
      11             : 
      12             : #include "node.hxx"
      13             : #include "caret.hxx"
      14             : 
      15             : #include <list>
      16             : 
      17             : /** Factor to multiple the squared horizontal distance with
      18             :  * Used for Up and Down movement.
      19             :  */
      20             : #define HORIZONTICAL_DISTANCE_FACTOR        10
      21             : 
      22             : /** Enum of direction for movement */
      23             : enum SmMovementDirection{
      24             :     MoveUp,
      25             :     MoveDown,
      26             :     MoveLeft,
      27             :     MoveRight
      28             : };
      29             : 
      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
      41             : };
      42             : 
      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
      65             : };
      66             : 
      67             : /** A list of nodes */
      68             : typedef std::list<SmNode*> SmNodeList;
      69             : 
      70             : class SmDocShell;
      71             : 
      72             : /** Formula cursor
      73             :  *
      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.
      77             :  */
      78             : class SmCursor{
      79             : public:
      80           4 :     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           4 :         , bIsEnabledSetModifiedSmDocShell(false)
      89             :     {
      90             :         //Build graph
      91           4 :         BuildGraph();
      92           4 :     }
      93             : 
      94           4 :     ~SmCursor()
      95             :     {
      96           4 :         SetClipboard();
      97           4 :         delete pGraph;
      98           4 :         pGraph = NULL;
      99           4 :     }
     100             : 
     101             :     /** Gets the anchor */
     102             :     SmCaretPos GetAnchor(){ return anchor->CaretPos; }
     103             : 
     104             :     /** Get position */
     105           0 :     SmCaretPos GetPosition() const { return position->CaretPos; }
     106             : 
     107             :     /** True, if the cursor has a selection */
     108          19 :     bool HasSelection() { return anchor != position; }
     109             : 
     110             :     /** Move the position of this cursor */
     111             :     void Move(OutputDevice* pDev, SmMovementDirection direction, bool bMoveAnchor = true);
     112             : 
     113             :     /** Move to the caret position closet to a given point */
     114             :     void MoveTo(OutputDevice* pDev, Point pos, bool bMoveAnchor = true);
     115             : 
     116             :     /** Delete the current selection or do nothing */
     117             :     void Delete();
     118             : 
     119             :     /** Delete selection, previous element or merge lines
     120             :      *
     121             :      * This method implements the behaviour of backspace.
     122             :      */
     123             :     void DeletePrev(OutputDevice* pDev);
     124             : 
     125             :     /** Insert text at the current position */
     126             :     void InsertText(const OUString& aString);
     127             : 
     128             :     /** Insert an element into the formula */
     129             :     void InsertElement(SmFormulaElement element);
     130             : 
     131             :     /** Insert a command specified in commands.src*/
     132             :     void InsertCommand(sal_uInt16 nCommand);
     133             : 
     134             :     /** Insert command text translated into line entries at position
     135             :      *
     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!
     141             :      */
     142             :     void InsertCommandText(const OUString& aCommandText);
     143             : 
     144             :     /** Insert a special node created from aString
     145             :      *
     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
     149             :      *
     150             :      * For more complex expressions use InsertCommandText, this method doesn't
     151             :      * use SmParser, this means that it's faster, but not as strong.
     152             :      */
     153             :     void InsertSpecial(const OUString& aString);
     154             : 
     155             :     /** Create sub-/super script
     156             :      *
     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.
     160             :      *
     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.
     163             :      */
     164             :     void InsertSubSup(SmSubSup eSubSup);
     165             : 
     166             :     /** Create a limit on an SmOperNode
     167             :      *
     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.
     170             :      *
     171             :      * @param bMoveCaret If true that caret will be moved into the limit.
     172             :      *
     173             :      * @returns True, if the caret was in a context where this operation was possible.
     174             :      */
     175             :     bool InsertLimit(SmSubSup eSubSup, bool bMoveCaret = true);
     176             : 
     177             :     /** Insert a new row or newline
     178             :      *
     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.
     181             :      *
     182             :      * @returns True, if a new row/line could be inserted.
     183             :      *
     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.
     186             :      */
     187             :     bool InsertRow();
     188             : 
     189             :     /** Insert a fraction, use selection as numerator */
     190             :     void InsertFraction();
     191             : 
     192             :     /** Create brackets around current selection, or new SmPlaceNode */
     193             :     void InsertBrackets(SmBracketType eBracketType);
     194             : 
     195             :     /** Copy the current selection */
     196             :     void Copy();
     197             :     /** Cut the current selection */
     198           0 :     void Cut(){
     199           0 :         Copy();
     200           0 :         Delete();
     201           0 :     }
     202             :     /** Paste the clipboard */
     203             :     void Paste();
     204             : 
     205             :     /** Returns true if more than one node is selected
     206             :      *
     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.
     210             :      */
     211             :     bool HasComplexSelection();
     212             : 
     213             :     /** Finds the topmost node in a visual line
     214             :      *
     215             :      * If MoveUpIfSelected is true, this will move up to the parent line
     216             :      * if the parent of the current line is selected.
     217             :      */
     218             :     static SmNode* FindTopMostNodeInLine(SmNode* pSNode, bool MoveUpIfSelected = false);
     219             : 
     220             :     /** Draw the caret */
     221             :     void Draw(OutputDevice& pDev, Point Offset, bool isCaretVisible);
     222             : 
     223             :     bool IsAtTailOfBracket(SmBracketType eBracketType, SmBraceNode** ppBraceNode = NULL) const;
     224             :     void MoveAfterBracket(SmBraceNode* pBraceNode, bool bMoveAnchor = true);
     225             : 
     226             : private:
     227             :     friend class SmDocShell;
     228             : 
     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;
     239             : 
     240             :     /** Returns a node that is selected, if any could be found */
     241             :     SmNode* FindSelectedNode(SmNode* pNode);
     242             : 
     243             :     /** Is this one of the nodes used to compose a line
     244             :      *
     245             :      * These are SmExpression, SmBinHorNode, SmUnHorNode etc.
     246             :      */
     247             :     static bool IsLineCompositionNode(SmNode* pNode);
     248             : 
     249             :     /** Count number of selected nodes, excluding line composition nodes
     250             :      *
     251             :      * Note this function doesn't count line composition nodes and it
     252             :      * does count all subnodes as well as the owner nodes.
     253             :      *
     254             :      * Used by SmCursor::HasComplexSelection()
     255             :      */
     256             :     int CountSelectedNodes(SmNode* pNode);
     257             : 
     258             :     /** Convert a visual line to a list
     259             :      *
     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.
     263             :      */
     264             :     static SmNodeList* LineToList(SmStructureNode* pLine, SmNodeList* pList = new SmNodeList());
     265             : 
     266             :     /** Auxiliary function for calling LineToList on a node
     267             :      *
     268             :      * This method sets pNode = NULL and remove it from its parent.
     269             :      * (Assuming it has a parent, and is a child of it).
     270             :      */
     271          17 :     static SmNodeList* NodeToList(SmNode*& rpNode, SmNodeList* pList = new SmNodeList()){
     272             :         //Remove from parent and NULL rpNode
     273          17 :         SmNode* pNode = rpNode;
     274          17 :         if(rpNode && rpNode->GetParent()){    //Don't remove this, correctness relies on it
     275          16 :             int index = rpNode->GetParent()->IndexOfSubNode(rpNode);
     276          16 :             if(index != -1)
     277          16 :                 rpNode->GetParent()->SetSubNode(index, NULL);
     278             :         }
     279          17 :         rpNode = NULL;
     280             :         //Create line from node
     281          17 :         if(pNode && IsLineCompositionNode(pNode))
     282          14 :             return LineToList(static_cast<SmStructureNode*>(pNode), pList);
     283           3 :         if(pNode)
     284           2 :             pList->push_front(pNode);
     285           3 :         return pList;
     286             :     }
     287             : 
     288             :     /** Clone a visual line to a list
     289             :      *
     290             :      * Doesn't clone SmErrorNode's these are ignored, as they are context dependent metadata.
     291             :      */
     292             :     static SmNodeList* CloneLineToList(SmStructureNode* pLine,
     293             :                                        bool bOnlyIfSelected = false,
     294           0 :                                        SmNodeList* pList = new SmNodeList());
     295             : 
     296             :     /** Build pGraph over caret positions */
     297             :     void BuildGraph();
     298             : 
     299             :     /** Insert new nodes in the tree after position */
     300             :     void InsertNodes(SmNodeList* pNewNodes);
     301             : 
     302             :     /** tries to set position to a specific SmCaretPos
     303             :      *
     304             :      * @returns false on failure to find the position in pGraph.
     305             :      */
     306             :     bool SetCaretPosition(SmCaretPos pos, bool moveAnchor = false);
     307             : 
     308             :     /** Set selected on nodes of the tree */
     309             :     void AnnotateSelection();
     310             : 
     311             :     /** Set the clipboard, and release current clipboard
     312             :      *
     313             :      * Call this method with NULL to reset the clipboard
     314             :      * @remarks: This method takes ownership of pList.
     315             :      */
     316             :     void SetClipboard(SmNodeList* pList = NULL);
     317             : 
     318             :     /** Clone list of nodes (creates a deep clone) */
     319             :     static SmNodeList* CloneList(SmNodeList* pList);
     320             : 
     321             :     /** Find an iterator pointing to the node in pLineList following aCaretPos
     322             :      *
     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.
     326             :      *
     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.
     330             :      */
     331             :     static SmNodeList::iterator FindPositionInLineList(SmNodeList* pLineList, SmCaretPos aCaretPos);
     332             : 
     333             :     /** Patch a line list after modification, merge SmTextNode, remove SmPlaceNode etc.
     334             :      *
     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.
     337             :      *
     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.
     341             :      *
     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.
     344             :      */
     345             :      static SmCaretPos PatchLineList(SmNodeList* pLineList, SmNodeList::iterator aIter);
     346             : 
     347             :     /** Take selected nodes from a list
     348             :      *
     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.
     354             :      *
     355             :      * @returns An iterator pointing to the element following the selection taken.
     356             :      */
     357             :     static SmNodeList::iterator TakeSelectedNodesFromList(SmNodeList *pLineList,
     358             :                                                          SmNodeList *pSelectedNodes = NULL);
     359             : 
     360             :     /** Create an instance of SmMathSymbolNode usable for brackets */
     361             :     static SmNode *CreateBracket(SmBracketType eBracketType, bool bIsLeft);
     362             : 
     363             :     /** The number of times BeginEdit have been called
     364             :      * Used to allow nesting of BeginEdit() and EndEdit() sections
     365             :      */
     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
     374             :      *
     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.
     378             :      *
     379             :      * @remarks Please note that this method will delete pLineList, as the elements are taken.
     380             :      *
     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.
     387             :      */
     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();
     395             : };
     396             : 
     397             : /** Minimalistic recursive decent SmNodeList parser
     398             :  *
     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.
     401             :  *
     402             :  * Please note, this will not handle all kinds of nodes, only nodes that
     403             :  * constitutes and entry in a line.
     404             :  *
     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
     414             :  */
     415             : class SmNodeListParser{
     416             : public:
     417             :     /** Create an instance of SmNodeListParser */
     418          19 :     SmNodeListParser(){
     419          19 :         pList = NULL;
     420          19 :     }
     421             :     /** Parse a list of nodes to an expression
     422             :      *
     423             :      * If bDeleteErrorNodes is true, old error nodes will be deleted.
     424             :      */
     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         383 :     SmNode* Terminal(){
     442         383 :         if(pList->size() > 0)
     443         274 :             return pList->front();
     444         109 :         return NULL;
     445             :     }
     446             :     /** Move to next terminal */
     447          35 :     SmNode* Next(){
     448          35 :         pList->pop_front();
     449          35 :         return Terminal();
     450             :     }
     451             :     /** Take the current terminal */
     452          33 :     SmNode* Take(){
     453          33 :         SmNode* pRetVal = Terminal();
     454          33 :         Next();
     455          33 :         return pRetVal;
     456             :     }
     457             :     SmNode* Expression();
     458             :     SmNode* Relation();
     459             :     SmNode* Sum();
     460             :     SmNode* Product();
     461             :     SmNode* Factor();
     462             :     SmNode* Postfix();
     463             :     static SmNode* Error();
     464             : };
     465             : 
     466             : 
     467             : #endif // INCLUDED_STARMATH_INC_CURSOR_HXX
     468             : 
     469             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11