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

Generated by: LCOV version 1.10