LCOV - code coverage report
Current view: top level - starmath/inc - cursor.hxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 36 41 87.8 %
Date: 2014-11-03 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             : /** Factor to multiple the squared horizontal distance with
      16             :  * Used for Up and Down movement.
      17             :  */
      18             : #define HORIZONTICAL_DISTANCE_FACTOR        10
      19             : 
      20             : /** Enum of direction for movement */
      21             : enum SmMovementDirection{
      22             :     MoveUp,
      23             :     MoveDown,
      24             :     MoveLeft,
      25             :     MoveRight
      26             : };
      27             : 
      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
      39             : };
      40             : 
      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
      63             : };
      64             : 
      65             : /** A list of nodes */
      66             : typedef std::list<SmNode*> SmNodeList;
      67             : 
      68             : class SmDocShell;
      69             : 
      70             : /** Formula cursor
      71             :  *
      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.
      75             :  */
      76             : class SmCursor{
      77             : public:
      78           8 :     SmCursor(SmNode* tree, SmDocShell* pShell)
      79             :         : anchor(NULL)
      80             :         , position(NULL)
      81             :         , pTree(tree)
      82             :         , pDocShell(pShell)
      83             :         , pGraph(NULL)
      84             :         , pClipboard(NULL)
      85             :         , nEditSections(0)
      86           8 :         , bIsEnabledSetModifiedSmDocShell(false)
      87             :     {
      88             :         //Build graph
      89           8 :         BuildGraph();
      90           8 :     }
      91             : 
      92           8 :     ~SmCursor()
      93             :     {
      94           8 :         SetClipboard();
      95           8 :         delete pGraph;
      96           8 :         pGraph = NULL;
      97           8 :     }
      98             : 
      99             :     /** Gets the anchor */
     100             :     SmCaretPos GetAnchor(){ return anchor->CaretPos; }
     101             : 
     102             :     /** Get position */
     103           0 :     SmCaretPos GetPosition() const { return position->CaretPos; }
     104             : 
     105             :     /** True, if the cursor has a selection */
     106          38 :     bool HasSelection() { return anchor != position; }
     107             : 
     108             :     /** Move the position of this cursor */
     109             :     void Move(OutputDevice* pDev, SmMovementDirection direction, bool bMoveAnchor = true);
     110             : 
     111             :     /** Move to the caret position closet to a given point */
     112             :     void MoveTo(OutputDevice* pDev, Point pos, bool bMoveAnchor = true);
     113             : 
     114             :     /** Delete the current selection or do nothing */
     115             :     void Delete();
     116             : 
     117             :     /** Delete selection, previous element or merge lines
     118             :      *
     119             :      * This method implements the behaviour of backspace.
     120             :      */
     121             :     void DeletePrev(OutputDevice* pDev);
     122             : 
     123             :     /** Insert text at the current position */
     124             :     void InsertText(const OUString& aString);
     125             : 
     126             :     /** Insert an element into the formula */
     127             :     void InsertElement(SmFormulaElement element);
     128             : 
     129             :     /** Insert a command specified in commands.src*/
     130             :     void InsertCommand(sal_uInt16 nCommand);
     131             : 
     132             :     /** Insert command text translated into line entries at position
     133             :      *
     134             :      * Note: This method uses the parser to translate a command text into a
     135             :      * tree, then it copies line entries from this tree into the current tree.
     136             :      * Will not work for commands such as newline or ##, if position is in a matrix.
     137             :      * This will work for stuff like "A intersection B". But stuff spaning multiple lines
     138             :      * or dependent on the context which position is placed in will not work!
     139             :      */
     140             :     void InsertCommandText(const OUString& aCommandText);
     141             : 
     142             :     /** Insert a special node created from aString
     143             :      *
     144             :      * Used for handling insert request from the "catalog" dialog.
     145             :      * The provided string should be formated as the desired command: %phi
     146             :      * Note: this method ONLY supports commands defined in Math.xcu
     147             :      *
     148             :      * For more complex expressions use InsertCommandText, this method doesn't
     149             :      * use SmParser, this means that it's faster, but not as strong.
     150             :      */
     151             :     void InsertSpecial(const OUString& aString);
     152             : 
     153             :     /** Create sub-/super script
     154             :      *
     155             :      * If there's a selection, it will be move into the appropriate sub-/super scription
     156             :      * of the node in front of it. If there's no node in front of position (or the selection),
     157             :      * a sub-/super scription of a new SmPlaceNode will be made.
     158             :      *
     159             :      * If there's is an existing subscription of the node, the caret will be moved into it,
     160             :      * and any selection will replace it.
     161             :      */
     162             :     void InsertSubSup(SmSubSup eSubSup);
     163             : 
     164             :     /** Create a limit on an SmOperNode
     165             :      *
     166             :      * This this method only work if the caret is inside an SmOperNode, or to the right of one.
     167             :      * Notice also that this method ignores any selection made.
     168             :      *
     169             :      * @param bMoveCaret If true that caret will be moved into the limit.
     170             :      *
     171             :      * @returns True, if the caret was in a context where this operation was possible.
     172             :      */
     173             :     bool InsertLimit(SmSubSup eSubSup, bool bMoveCaret = true);
     174             : 
     175             :     /** Insert a new row or newline
     176             :      *
     177             :      * Inserts a new row if position is in an matrix or stack command.
     178             :      * Otherwise a newline is inserted if we're in a toplevel line.
     179             :      *
     180             :      * @returns True, if a new row/line could be inserted.
     181             :      *
     182             :      * @remarks If the caret is placed in a subline of a command that doesn't support
     183             :      *          this operator the method returns FALSE, and doesn't do anything.
     184             :      */
     185             :     bool InsertRow();
     186             : 
     187             :     /** Insert a fraction, use selection as numerator */
     188             :     void InsertFraction();
     189             : 
     190             :     /** Create brackets around current selection, or new SmPlaceNode */
     191             :     void InsertBrackets(SmBracketType eBracketType);
     192             : 
     193             :     /** Copy the current selection */
     194             :     void Copy();
     195             :     /** Cut the current selection */
     196           0 :     void Cut(){
     197           0 :         Copy();
     198           0 :         Delete();
     199           0 :     }
     200             :     /** Paste the clipboard */
     201             :     void Paste();
     202             : 
     203             :     /** Returns true if more than one node is selected
     204             :      *
     205             :      * This method is used for implementing backspace and delete.
     206             :      * If one of these causes a complex selection, e.g. a node with
     207             :      * subnodes or similar, this should not be deleted imidiately.
     208             :      */
     209             :     bool HasComplexSelection();
     210             : 
     211             :     /** Finds the topmost node in a visual line
     212             :      *
     213             :      * If MoveUpIfSelected is true, this will move up to the parent line
     214             :      * if the parent of the current line is selected.
     215             :      */
     216             :     static SmNode* FindTopMostNodeInLine(SmNode* pSNode, bool MoveUpIfSelected = false);
     217             : 
     218             :     /** Draw the caret */
     219             :     void Draw(OutputDevice& pDev, Point Offset, bool isCaretVisible);
     220             : 
     221             :     bool IsAtTailOfBracket(SmBracketType eBracketType, SmBraceNode** ppBraceNode = NULL) const;
     222             :     void MoveAfterBracket(SmBraceNode* pBraceNode, bool bMoveAnchor = true);
     223             : 
     224             : private:
     225             :     friend class SmDocShell;
     226             : 
     227             :     SmCaretPosGraphEntry    *anchor,
     228             :                             *position;
     229             :     /** Formula tree */
     230             :     SmNode* pTree;
     231             :     /** Owner of the formula tree */
     232             :     SmDocShell* pDocShell;
     233             :     /** Graph over caret position in the current tree */
     234             :     SmCaretPosGraph* pGraph;
     235             :     /** Clipboard holder */
     236             :     SmNodeList* pClipboard;
     237             : 
     238             :     /** Returns a node that is selected, if any could be found */
     239             :     SmNode* FindSelectedNode(SmNode* pNode);
     240             : 
     241             :     /** Is this one of the nodes used to compose a line
     242             :      *
     243             :      * These are SmExpression, SmBinHorNode, SmUnHorNode etc.
     244             :      */
     245             :     static bool IsLineCompositionNode(SmNode* pNode);
     246             : 
     247             :     /** Count number of selected nodes, excluding line composition nodes
     248             :      *
     249             :      * Note this function doesn't count line composition nodes and it
     250             :      * does count all subnodes as well as the owner nodes.
     251             :      *
     252             :      * Used by SmCursor::HasComplexSelection()
     253             :      */
     254             :     int CountSelectedNodes(SmNode* pNode);
     255             : 
     256             :     /** Convert a visual line to a list
     257             :      *
     258             :      * Note this method will delete all the nodes that will no longer be needed.
     259             :      * that includes pLine!
     260             :      * This method also deletes SmErrorNode's as they're just meta info in the line.
     261             :      */
     262             :     static SmNodeList* LineToList(SmStructureNode* pLine, SmNodeList* pList = new SmNodeList());
     263             : 
     264             :     /** Auxiliary function for calling LineToList on a node
     265             :      *
     266             :      * This method sets pNode = NULL and remove it from its parent.
     267             :      * (Assuming it has a parent, and is a child of it).
     268             :      */
     269          34 :     static SmNodeList* NodeToList(SmNode*& rpNode, SmNodeList* pList = new SmNodeList()){
     270             :         //Remove from parent and NULL rpNode
     271          34 :         SmNode* pNode = rpNode;
     272          34 :         if(rpNode && rpNode->GetParent()){    //Don't remove this, correctness relies on it
     273          32 :             int index = rpNode->GetParent()->IndexOfSubNode(rpNode);
     274          32 :             if(index != -1)
     275          32 :                 rpNode->GetParent()->SetSubNode(index, NULL);
     276             :         }
     277          34 :         rpNode = NULL;
     278             :         //Create line from node
     279          34 :         if(pNode && IsLineCompositionNode(pNode))
     280          28 :             return LineToList((SmStructureNode*)pNode, pList);
     281           6 :         if(pNode)
     282           4 :             pList->push_front(pNode);
     283           6 :         return pList;
     284             :     }
     285             : 
     286             :     /** Clone a visual line to a list
     287             :      *
     288             :      * Doesn't clone SmErrorNode's these are ignored, as they are context dependent metadata.
     289             :      */
     290             :     static SmNodeList* CloneLineToList(SmStructureNode* pLine,
     291             :                                        bool bOnlyIfSelected = false,
     292             :                                        SmNodeList* pList = new SmNodeList());
     293             : 
     294             :     /** Build pGraph over caret positions */
     295             :     void BuildGraph();
     296             : 
     297             :     /** Insert new nodes in the tree after position */
     298             :     void InsertNodes(SmNodeList* pNewNodes);
     299             : 
     300             :     /** tries to set position to a specific SmCaretPos
     301             :      *
     302             :      * @returns false on failure to find the position in pGraph.
     303             :      */
     304             :     bool SetCaretPosition(SmCaretPos pos, bool moveAnchor = false);
     305             : 
     306             :     /** Set selected on nodes of the tree */
     307             :     void AnnotateSelection();
     308             : 
     309             :     /** Set the clipboard, and release current clipboard
     310             :      *
     311             :      * Call this method with NULL to reset the clipboard
     312             :      * @remarks: This method takes ownership of pList.
     313             :      */
     314             :     void SetClipboard(SmNodeList* pList = NULL);
     315             : 
     316             :     /** Clone list of nodes (creates a deep clone) */
     317             :     static SmNodeList* CloneList(SmNodeList* pList);
     318             : 
     319             :     /** Find an iterator pointing to the node in pLineList following aCaretPos
     320             :      *
     321             :      * If aCaretPos::pSelectedNode cannot be found it is assumed that it's in front of pLineList,
     322             :      * thus not an element in pLineList. In this case this method returns an iterator to the
     323             :      * first element in pLineList.
     324             :      *
     325             :      * If the current position is inside an SmTextNode, this node will be split in two, for this
     326             :      * reason you should beaware that iterators to elements in pLineList may be invalidated, and
     327             :      * that you should call PatchLineList() with this iterator if no action is taken.
     328             :      */
     329             :     static SmNodeList::iterator FindPositionInLineList(SmNodeList* pLineList, SmCaretPos aCaretPos);
     330             : 
     331             :     /** Patch a line list after modification, merge SmTextNode, remove SmPlaceNode etc.
     332             :      *
     333             :      * @param pLineList The line list to patch
     334             :      * @param aIter     Iterator pointing to the element that needs to be patched with it's previous.
     335             :      *
     336             :      * When the list is patched text nodes before and after aIter will be merged.
     337             :      * If there's an, in the context, inappropriate SmPlaceNode before or after aIter it will also be
     338             :      * removed.
     339             :      *
     340             :      * @returns A caret position equivalent to one selecting the node before aIter, the method returns
     341             :      *          an invalid SmCaretPos to indicate placement in front of the line.
     342             :      */
     343             :      static SmCaretPos PatchLineList(SmNodeList* pLineList, SmNodeList::iterator aIter);
     344             : 
     345             :     /** Take selected nodes from a list
     346             :      *
     347             :      * Puts the selected nodes into pSelectedNodes, or if pSelectedNodes is NULL deletes
     348             :      * the selected nodes.
     349             :      * Note: If there's a selection inside an SmTextNode this node will be split, and it
     350             :      * will not be merged when the selection have been taken. Use PatchLineList on the
     351             :      * iterator returns to fix this.
     352             :      *
     353             :      * @returns An iterator pointing to the element following the selection taken.
     354             :      */
     355             :     static SmNodeList::iterator TakeSelectedNodesFromList(SmNodeList *pLineList,
     356             :                                                          SmNodeList *pSelectedNodes = NULL);
     357             : 
     358             :     /** Create an instance of SmMathSymbolNode usable for brackets */
     359             :     static SmNode *CreateBracket(SmBracketType eBracketType, bool bIsLeft);
     360             : 
     361             :     /** The number of times BeginEdit have been called
     362             :      * Used to allow nesting of BeginEdit() and EndEdit() sections
     363             :      */
     364             :     int nEditSections;
     365             :     /** Holds data for BeginEdit() and EndEdit() */
     366             :     bool bIsEnabledSetModifiedSmDocShell;
     367             :     /** Begin edit section where the tree will be modified */
     368             :     void BeginEdit();
     369             :     /** End edit section where the tree will be modified */
     370             :     void EndEdit();
     371             :     /** Finish editing
     372             :      *
     373             :      * Finishes editing by parsing pLineList and inserting back into pParent at nParentIndex.
     374             :      * This method also rebuilts the graph, annotates the selection, sets caret position and
     375             :      * Calls EndEdit.
     376             :      *
     377             :      * @remarks Please note that this method will delete pLineList, as the elements are taken.
     378             :      *
     379             :      * @param pLineList     List the constitutes the edited line.
     380             :      * @param pParent       Parent to which the line should be inserted.
     381             :      * @param nParentIndex  Index in parent where the line should be inserted.
     382             :      * @param PosAfterEdit  Caret position to look for after rebuilding graph.
     383             :      * @param pStartLine    Line to take first position in, if PosAfterEdit cannot be found,
     384             :      *                      leave it NULL for pLineList.
     385             :      */
     386             :     void FinishEdit(SmNodeList* pLineList,
     387             :                     SmStructureNode* pParent,
     388             :                     int nParentIndex,
     389             :                     SmCaretPos PosAfterEdit,
     390             :                     SmNode* pStartLine = NULL);
     391             :     /** Request the formula is repainted */
     392             :     void RequestRepaint();
     393             : };
     394             : 
     395             : /** Minimalistic recursive decent SmNodeList parser
     396             :  *
     397             :  * This parser is used to take a list of nodes that constitutes a line
     398             :  * and parse them to a tree of SmBinHorNode, SmUnHorNode and SmExpression.
     399             :  *
     400             :  * Please note, this will not handle all kinds of nodes, only nodes that
     401             :  * constitutes and entry in a line.
     402             :  *
     403             :  * Below is an EBNF representation of the grammar used for this parser:
     404             :  * \code
     405             :  * Expression   -> Relation*
     406             :  * Relation     -> Sum [(=|<|>|...) Sum]*
     407             :  * Sum          -> Product [(+|-) Product]*
     408             :  * Product      -> Factor [(*|/) Factor]*
     409             :  * Factor       -> [+|-|-+|...]* Factor | Postfix
     410             :  * Postfix      -> node [!]*
     411             :  * \endcode
     412             :  */
     413             : class SmNodeListParser{
     414             : public:
     415             :     /** Create an instance of SmNodeListParser */
     416          38 :     SmNodeListParser(){
     417          38 :         pList = NULL;
     418          38 :     }
     419             :     /** Parse a list of nodes to an expression
     420             :      *
     421             :      * If bDeleteErrorNodes is true, old error nodes will be deleted.
     422             :      */
     423             :     SmNode* Parse(SmNodeList* list, bool bDeleteErrorNodes = true);
     424             :     /** True, if the token is an operator */
     425             :     static bool IsOperator(const SmToken &token);
     426             :     /** True, if the token is a relation operator */
     427             :     static bool IsRelationOperator(const SmToken &token);
     428             :     /** True, if the token is a sum operator */
     429             :     static bool IsSumOperator(const SmToken &token);
     430             :     /** True, if the token is a product operator */
     431             :     static bool IsProductOperator(const SmToken &token);
     432             :     /** True, if the token is a unary operator */
     433             :     static bool IsUnaryOperator(const SmToken &token);
     434             :     /** True, if the token is a postfix operator */
     435             :     static bool IsPostfixOperator(const SmToken &token);
     436             : private:
     437             :     SmNodeList* pList;
     438             :     /** Get the current terminal */
     439         766 :     SmNode* Terminal(){
     440         766 :         if(pList->size() > 0)
     441         548 :             return pList->front();
     442         218 :         return NULL;
     443             :     }
     444             :     /** Move to next terminal */
     445          70 :     SmNode* Next(){
     446          70 :         pList->pop_front();
     447          70 :         return Terminal();
     448             :     }
     449             :     /** Take the current terminal */
     450          66 :     SmNode* Take(){
     451          66 :         SmNode* pRetVal = Terminal();
     452          66 :         Next();
     453          66 :         return pRetVal;
     454             :     }
     455             :     SmNode* Expression();
     456             :     SmNode* Relation();
     457             :     SmNode* Sum();
     458             :     SmNode* Product();
     459             :     SmNode* Factor();
     460             :     SmNode* Postfix();
     461             :     SmNode* Error();
     462             : };
     463             : 
     464             : 
     465             : #endif // INCLUDED_STARMATH_INC_CURSOR_HXX
     466             : 
     467             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10