LCOV - code coverage report
Current view: top level - starmath/source - cursor.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 1 984 0.1 %
Date: 2012-08-25 Functions: 2 56 3.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 2 1633 0.1 %

           Branch data     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                 :            : #include "cursor.hxx"
      29                 :            : #include "parse.hxx"
      30                 :            : #include "visitors.hxx"
      31                 :            : #include "document.hxx"
      32                 :            : #include "view.hxx"
      33                 :            : #include "accessibility.hxx"
      34                 :            : #include <comphelper/string.hxx>
      35                 :            : 
      36                 :          0 : void SmCursor::Move(OutputDevice* pDev, SmMovementDirection direction, bool bMoveAnchor){
      37                 :          0 :     SmCaretPosGraphEntry* NewPos = NULL;
      38   [ #  #  #  # ]:          0 :     switch(direction){
      39                 :            :         case MoveLeft:
      40                 :            :         {
      41                 :          0 :             NewPos = position->Left;
      42                 :            :             OSL_ENSURE(NewPos, "NewPos shouldn't be NULL here!");
      43                 :          0 :         }break;
      44                 :            :         case MoveRight:
      45                 :            :         {
      46                 :          0 :             NewPos = position->Right;
      47                 :            :             OSL_ENSURE(NewPos, "NewPos shouldn't be NULL here!");
      48                 :          0 :         }break;
      49                 :            :         case MoveUp:
      50                 :            :             //Implementation is practically identical to MoveDown, except for a single if statement
      51                 :            :             //so I've implemented them together and added a direction == MoveDown to the if statements.
      52                 :            :         case MoveDown:
      53                 :            :         {
      54         [ #  # ]:          0 :             SmCaretLine from_line = SmCaretPos2LineVisitor(pDev, position->CaretPos).GetResult(),
      55                 :          0 :                         best_line,  //Best approximated line found so far
      56                 :          0 :                         curr_line;  //Current line
      57                 :          0 :             long dbp_sq = 0;        //Distance squared to best line
      58                 :          0 :             SmCaretPosGraphIterator it = pGraph->GetIterator();
      59 [ #  # ][ #  # ]:          0 :             while(it.Next()){
      60                 :            :                 //Reject it if it's the current position
      61         [ #  # ]:          0 :                 if(it->CaretPos == position->CaretPos) continue;
      62                 :            :                 //Compute caret line
      63         [ #  # ]:          0 :                 curr_line = SmCaretPos2LineVisitor(pDev, it->CaretPos).GetResult();
      64                 :            :                 //Reject anything above if we're moving down
      65 [ #  # ][ #  # ]:          0 :                 if(curr_line.GetTop() <= from_line.GetTop() && direction == MoveDown) continue;
                 [ #  # ]
      66                 :            :                 //Reject anything below if we're moving up
      67 [ #  # ][ #  # ]:          0 :                 if(curr_line.GetTop() + curr_line.GetHeight() >= from_line.GetTop() + from_line.GetHeight()
                 [ #  # ]
      68                 :          0 :                         && direction == MoveUp) continue;
      69                 :            :                 //Compare if it to what we have, if we have anything yet
      70         [ #  # ]:          0 :                 if(NewPos){
      71                 :            :                     //Compute distance to current line squared, multiplied with a horizontial factor
      72                 :          0 :                     long dp_sq = curr_line.SquaredDistanceX(from_line) * HORIZONTICAL_DISTANCE_FACTOR +
      73                 :          0 :                                  curr_line.SquaredDistanceY(from_line);
      74                 :            :                     //Discard current line if best line is closer
      75         [ #  # ]:          0 :                     if(dbp_sq <= dp_sq) continue;
      76                 :            :                 }
      77                 :            :                 //Take current line as the best
      78                 :          0 :                 best_line = curr_line;
      79                 :          0 :                 NewPos = it.Current();
      80                 :            :                 //Update distance to best line
      81                 :          0 :                 dbp_sq = best_line.SquaredDistanceX(from_line) * HORIZONTICAL_DISTANCE_FACTOR +
      82                 :          0 :                          best_line.SquaredDistanceY(from_line);
      83                 :            :             }
      84                 :          0 :         }break;
      85                 :            :         default:
      86                 :            :             OSL_FAIL("Movement direction not supported!");
      87                 :            :     }
      88         [ #  # ]:          0 :     if(NewPos){
      89                 :          0 :         position = NewPos;
      90         [ #  # ]:          0 :         if(bMoveAnchor)
      91                 :          0 :             anchor = NewPos;
      92                 :          0 :         RequestRepaint();
      93                 :            :     }
      94                 :          0 : }
      95                 :            : 
      96                 :          0 : void SmCursor::MoveTo(OutputDevice* pDev, Point pos, bool bMoveAnchor){
      97                 :          0 :     SmCaretLine best_line,  //Best line found so far, when iterating
      98                 :          0 :                 curr_line;  //Current line, when iterating
      99                 :          0 :     SmCaretPosGraphEntry* NewPos = NULL;
     100                 :          0 :     long dp_sq = 0,     //Distance to current line squared
     101                 :          0 :          dbp_sq = 1;    //Distance to best line squared
     102                 :          0 :     SmCaretPosGraphIterator it = pGraph->GetIterator();
     103 [ #  # ][ #  # ]:          0 :     while(it.Next()){
     104                 :            :         OSL_ENSURE(it->CaretPos.IsValid(), "The caret position graph may not have invalid positions!");
     105                 :            :         //Compute current line
     106         [ #  # ]:          0 :         curr_line = SmCaretPos2LineVisitor(pDev, it->CaretPos).GetResult();
     107                 :            :         //If we have a position compare to it
     108         [ #  # ]:          0 :         if(NewPos){
     109                 :            :             //Compute squared distance to current line
     110                 :          0 :             dp_sq = curr_line.SquaredDistanceX(pos) + curr_line.SquaredDistanceY(pos);
     111                 :            :             //If best line is closer, reject current line
     112         [ #  # ]:          0 :             if(dbp_sq <= dp_sq) continue;
     113                 :            :         }
     114                 :            :         //Accept current position as the best
     115                 :          0 :         best_line = curr_line;
     116                 :          0 :         NewPos = it.Current();
     117                 :            :         //Update distance to best line
     118                 :          0 :         dbp_sq = best_line.SquaredDistanceX(pos) + best_line.SquaredDistanceY(pos);
     119                 :            :     }
     120         [ #  # ]:          0 :     if(NewPos){
     121                 :          0 :         position = NewPos;
     122         [ #  # ]:          0 :         if(bMoveAnchor)
     123                 :          0 :             anchor = NewPos;
     124         [ #  # ]:          0 :         RequestRepaint();
     125                 :            :     }
     126                 :          0 : }
     127                 :            : 
     128                 :          0 : void SmCursor::BuildGraph(){
     129                 :            :     //Save the current anchor and position
     130                 :          0 :     SmCaretPos _anchor, _position;
     131                 :            :     //Release pGraph if allocated
     132         [ #  # ]:          0 :     if(pGraph){
     133         [ #  # ]:          0 :         if(anchor)
     134                 :          0 :             _anchor = anchor->CaretPos;
     135         [ #  # ]:          0 :         if(position)
     136                 :          0 :             _position = position->CaretPos;
     137 [ #  # ][ #  # ]:          0 :         delete pGraph;
     138                 :            :         //Reset anchor and position as they point into an old graph
     139                 :          0 :         anchor = NULL;
     140                 :          0 :         position = NULL;
     141                 :            :     }
     142                 :          0 :     pGraph = NULL;
     143                 :            : 
     144                 :            :     //Build the new graph
     145         [ #  # ]:          0 :     pGraph = SmCaretPosGraphBuildingVisitor(pTree).Graph();
     146                 :            : 
     147                 :            :     //Restore anchor and position pointers
     148 [ #  # ][ #  # ]:          0 :     if(_anchor.IsValid() || _position.IsValid()){
                 [ #  # ]
     149                 :          0 :         SmCaretPosGraphIterator it = pGraph->GetIterator();
     150 [ #  # ][ #  # ]:          0 :         while(it.Next()){
     151         [ #  # ]:          0 :             if(_anchor == it->CaretPos)
     152                 :          0 :                 anchor = it.Current();
     153         [ #  # ]:          0 :             if(_position == it->CaretPos)
     154                 :          0 :                 position = it.Current();
     155                 :            :         }
     156                 :            :     }
     157                 :            :     //Set position and anchor to first caret position
     158                 :          0 :     SmCaretPosGraphIterator it = pGraph->GetIterator();
     159         [ #  # ]:          0 :     if(!position)
     160         [ #  # ]:          0 :         position = it.Next();
     161         [ #  # ]:          0 :     if(!anchor)
     162                 :          0 :         anchor = position;
     163                 :            : 
     164                 :            :     OSL_ENSURE(position->CaretPos.IsValid(), "Position must be valid");
     165                 :            :     OSL_ENSURE(anchor->CaretPos.IsValid(), "Anchor must be valid");
     166                 :          0 : }
     167                 :            : 
     168                 :          0 : bool SmCursor::SetCaretPosition(SmCaretPos pos, bool moveAnchor){
     169                 :          0 :     SmCaretPosGraphIterator it = pGraph->GetIterator();
     170 [ #  # ][ #  # ]:          0 :     while(it.Next()){
     171         [ #  # ]:          0 :         if(it->CaretPos == pos){
     172                 :          0 :             position = it.Current();
     173         [ #  # ]:          0 :             if(moveAnchor)
     174                 :          0 :                 anchor = it.Current();
     175                 :          0 :             return true;
     176                 :            :         }
     177                 :            :     }
     178                 :          0 :     return false;
     179                 :            : }
     180                 :            : 
     181                 :          0 : void SmCursor::AnnotateSelection(){
     182                 :            :     //TODO: Manage a state, reset it upon modification and optimize this call
     183                 :          0 :     SmSetSelectionVisitor(anchor->CaretPos, position->CaretPos, pTree);
     184                 :          0 : }
     185                 :            : 
     186                 :          0 : void SmCursor::Draw(OutputDevice& pDev, Point Offset, bool isCaretVisible){
     187                 :          0 :     SmCaretDrawingVisitor(pDev, GetPosition(), Offset, isCaretVisible);
     188                 :          0 : }
     189                 :            : 
     190                 :          0 : void SmCursor::DeletePrev(OutputDevice* pDev){
     191                 :            :     //Delete only a selection if there's a selection
     192         [ #  # ]:          0 :     if(HasSelection()){
     193         [ #  # ]:          0 :         Delete();
     194                 :          0 :         return;
     195                 :            :     }
     196                 :            : 
     197         [ #  # ]:          0 :     SmNode* pLine = FindTopMostNodeInLine(position->CaretPos.pSelectedNode);
     198                 :          0 :     SmStructureNode* pLineParent = pLine->GetParent();
     199         [ #  # ]:          0 :     int nLineOffset = pLineParent->IndexOfSubNode(pLine);
     200                 :            : 
     201                 :            :     //If we're in front of a node who's parent is a TABLE
     202 [ #  # ][ #  # ]:          0 :     if(pLineParent->GetType() == NTABLE && position->CaretPos.Index == 0 && nLineOffset > 0){
         [ #  # ][ #  # ]
     203                 :            :         //Now we can merge with nLineOffset - 1
     204         [ #  # ]:          0 :         BeginEdit();
     205                 :            :         //Line to merge things into, so we can delete pLine
     206         [ #  # ]:          0 :         SmNode* pMergeLine = pLineParent->GetSubNode(nLineOffset-1);
     207                 :            :         OSL_ENSURE(pMergeLine, "pMergeLine cannot be NULL!");
     208                 :            :         //Convert first line to list
     209 [ #  # ][ #  # ]:          0 :         SmNodeList *pLineList = NodeToList(pMergeLine);
                 [ #  # ]
     210                 :            :         //Find iterator to patch
     211                 :          0 :         SmNodeList::iterator patchPoint = pLineList->end();
     212                 :          0 :         --patchPoint;
     213                 :            :         //Convert second line to list
     214         [ #  # ]:          0 :         NodeToList(pLine, pLineList);
     215                 :            :         //Patch the line list
     216                 :          0 :         ++patchPoint;
     217         [ #  # ]:          0 :         SmCaretPos PosAfterDelete = PatchLineList(pLineList, patchPoint);
     218                 :            :         //Parse the line
     219         [ #  # ]:          0 :         pLine = SmNodeListParser().Parse(pLineList);
     220         [ #  # ]:          0 :         delete pLineList;
     221         [ #  # ]:          0 :         pLineParent->SetSubNode(nLineOffset-1, pLine);
     222                 :            :         //Delete the removed line slot
     223 [ #  # ][ #  # ]:          0 :         SmNodeArray lines(pLineParent->GetNumSubNodes()-1);
     224 [ #  # ][ #  # ]:          0 :         for(int i = 0; i < pLineParent->GetNumSubNodes(); i++){
     225         [ #  # ]:          0 :             if(i < nLineOffset)
     226         [ #  # ]:          0 :                 lines[i] = pLineParent->GetSubNode(i);
     227         [ #  # ]:          0 :             else if(i > nLineOffset)
     228         [ #  # ]:          0 :                 lines[i-1] = pLineParent->GetSubNode(i);
     229                 :            :         }
     230         [ #  # ]:          0 :         pLineParent->SetSubNodes(lines);
     231                 :            :         //Rebuild graph
     232                 :          0 :         anchor = NULL;
     233                 :          0 :         position = NULL;
     234         [ #  # ]:          0 :         BuildGraph();
     235         [ #  # ]:          0 :         AnnotateSelection();
     236                 :            :         //Set caret position
     237 [ #  # ][ #  # ]:          0 :         if(!SetCaretPosition(PosAfterDelete, true))
     238         [ #  # ]:          0 :             SetCaretPosition(SmCaretPos(pLine, 0), true);
     239                 :            :         //Finish editing
     240         [ #  # ]:          0 :         EndEdit();
     241                 :            : 
     242                 :            :     //TODO: If we're in an empty (sub/super/*) script
     243                 :            :     /*}else if(pLineParent->GetType() == NSUBSUP &&
     244                 :            :              nLineOffset != 0 &&
     245                 :            :              pLine->GetType() == NEXPRESSION &&
     246                 :            :              pLine->GetNumSubNodes() == 0){
     247                 :            :         //There's a (sub/super) script we can delete
     248                 :            :     //Consider selecting the entire script if GetNumSubNodes() != 0 or pLine->GetType() != NEXPRESSION
     249                 :            :     //TODO: Handle case where we delete a limit
     250                 :            :     */
     251                 :            : 
     252                 :            :     //Else move select, and delete if not complex
     253                 :            :     }else{
     254         [ #  # ]:          0 :         this->Move(pDev, MoveLeft, false);
     255 [ #  # ][ #  # ]:          0 :         if(!this->HasComplexSelection())
     256         [ #  # ]:          0 :             Delete();
     257                 :            :     }
     258                 :            : }
     259                 :            : 
     260                 :          0 : void SmCursor::Delete(){
     261                 :            :     //Return if we don't have a selection to delete
     262         [ #  # ]:          0 :     if(!HasSelection())
     263                 :          0 :         return;
     264                 :            : 
     265                 :            :     //Enter edit setion
     266         [ #  # ]:          0 :     BeginEdit();
     267                 :            : 
     268                 :            :     //Set selected on nodes
     269         [ #  # ]:          0 :     AnnotateSelection();
     270                 :            : 
     271                 :            :     //Find an arbitrary selected node
     272         [ #  # ]:          0 :     SmNode* pSNode = FindSelectedNode(pTree);
     273                 :            :     OSL_ENSURE(pSNode != NULL, "There must be a selection when HasSelection is true!");
     274                 :            : 
     275                 :            :     //Find the topmost node of the line that holds the selection
     276         [ #  # ]:          0 :     SmNode* pLine = FindTopMostNodeInLine(pSNode, true);
     277                 :            :     OSL_ENSURE(pLine != pTree, "Shouldn't be able to select the entire tree");
     278                 :            : 
     279                 :            :     //Get the parent of the line
     280                 :          0 :     SmStructureNode* pLineParent = pLine->GetParent();
     281                 :            :     //Find line offset in parent
     282         [ #  # ]:          0 :     int nLineOffset = pLineParent->IndexOfSubNode(pLine);
     283                 :            :     OSL_ENSURE(nLineOffset != -1, "pLine must be a child of it's parent!");
     284                 :            : 
     285                 :            :     //Position after delete
     286                 :          0 :     SmCaretPos PosAfterDelete;
     287                 :            : 
     288 [ #  # ][ #  # ]:          0 :     SmNodeList* pLineList = NodeToList(pLine);
                 [ #  # ]
     289                 :            : 
     290                 :            :     //Take the selected nodes and delete them...
     291         [ #  # ]:          0 :     SmNodeList::iterator patchIt = TakeSelectedNodesFromList(pLineList);
     292                 :            : 
     293                 :            :     //Get teh position to set after delete
     294         [ #  # ]:          0 :     PosAfterDelete = PatchLineList(pLineList, patchIt);
     295                 :            : 
     296                 :            :     //Finish editing
     297         [ #  # ]:          0 :     FinishEdit(pLineList, pLineParent, nLineOffset, PosAfterDelete);
     298                 :            : }
     299                 :            : 
     300                 :          0 : void SmCursor::InsertNodes(SmNodeList* pNewNodes){
     301         [ #  # ]:          0 :     if(pNewNodes->empty()){
     302         [ #  # ]:          0 :         delete pNewNodes;
     303                 :          0 :         return;
     304                 :            :     }
     305                 :            : 
     306                 :            :     //Begin edit section
     307         [ #  # ]:          0 :     BeginEdit();
     308                 :            : 
     309                 :            :     //Position after insert should be after pNewNode
     310         [ #  # ]:          0 :     SmCaretPos PosAfterInsert = SmCaretPos(pNewNodes->back(), 1);
     311                 :            : 
     312                 :            :     //Get the current position
     313                 :          0 :     const SmCaretPos pos = position->CaretPos;
     314                 :            : 
     315                 :            :     //Find top most of line that holds position
     316         [ #  # ]:          0 :     SmNode* pLine = FindTopMostNodeInLine(pos.pSelectedNode, false);
     317                 :            : 
     318                 :            :     //Find line parent and line index in parent
     319                 :          0 :     SmStructureNode* pLineParent = pLine->GetParent();
     320         [ #  # ]:          0 :     int nParentIndex = pLineParent->IndexOfSubNode(pLine);
     321                 :            :     OSL_ENSURE(nParentIndex != -1, "pLine must be a subnode of pLineParent!");
     322                 :            : 
     323                 :            :     //Convert line to list
     324 [ #  # ][ #  # ]:          0 :     SmNodeList* pLineList = NodeToList(pLine);
                 [ #  # ]
     325                 :            : 
     326                 :            :     //Find iterator for place to insert nodes
     327         [ #  # ]:          0 :     SmNodeList::iterator it = FindPositionInLineList(pLineList, pos);
     328                 :            : 
     329                 :            :     //Insert all new nodes
     330                 :          0 :     SmNodeList::iterator newIt,
     331                 :          0 :                          patchIt = it, // (pointless default value, fixes compiler warnings)
     332                 :          0 :                          insIt;
     333         [ #  # ]:          0 :     for(newIt = pNewNodes->begin(); newIt != pNewNodes->end(); ++newIt){
     334         [ #  # ]:          0 :         insIt = pLineList->insert(it, *newIt);
     335         [ #  # ]:          0 :         if(newIt == pNewNodes->begin())
     336                 :          0 :             patchIt = insIt;
     337         [ #  # ]:          0 :         if((*newIt)->GetType() == NTEXT)
     338                 :          0 :             PosAfterInsert = SmCaretPos(*newIt, ((SmTextNode*)*newIt)->GetText().Len());
     339                 :            :         else
     340                 :          0 :             PosAfterInsert = SmCaretPos(*newIt, 1);
     341                 :            :     }
     342                 :            :     //Patch the places we've changed stuff
     343         [ #  # ]:          0 :                         PatchLineList(pLineList, patchIt);
     344         [ #  # ]:          0 :     PosAfterInsert =    PatchLineList(pLineList, it);
     345                 :            :     //Release list, we've taken the nodes
     346         [ #  # ]:          0 :     delete pNewNodes;
     347                 :          0 :     pNewNodes = NULL;
     348                 :            : 
     349                 :            :     //Finish editing
     350         [ #  # ]:          0 :     FinishEdit(pLineList, pLineParent, nParentIndex, PosAfterInsert);
     351                 :            : }
     352                 :            : 
     353                 :          0 : SmNodeList::iterator SmCursor::FindPositionInLineList(SmNodeList* pLineList, SmCaretPos aCaretPos) {
     354                 :            :     //Find iterator for position
     355                 :          0 :     SmNodeList::iterator it;
     356         [ #  # ]:          0 :     for(it = pLineList->begin(); it != pLineList->end(); ++it){
     357         [ #  # ]:          0 :         if(*it == aCaretPos.pSelectedNode){
     358         [ #  # ]:          0 :             if((*it)->GetType() == NTEXT){
     359                 :            :                 //Split textnode if needed
     360         [ #  # ]:          0 :                 if(aCaretPos.Index > 0){
     361                 :          0 :                     SmTextNode* pText = (SmTextNode*)aCaretPos.pSelectedNode;
     362         [ #  # ]:          0 :                     XubString str1 = pText->GetText().Copy(0, aCaretPos.Index);
     363         [ #  # ]:          0 :                     XubString str2 = pText->GetText().Copy(aCaretPos.Index);
     364         [ #  # ]:          0 :                     pText->ChangeText(str1);
     365                 :          0 :                     ++it;
     366                 :            :                     //Insert str2 as new text node
     367         [ #  # ]:          0 :                     if(str2.Len() > 0){
     368 [ #  # ][ #  # ]:          0 :                         SmTextNode* pNewText = new SmTextNode(pText->GetToken(), pText->GetFontDesc());
     369         [ #  # ]:          0 :                         pNewText->ChangeText(str2);
     370         [ #  # ]:          0 :                         it = pLineList->insert(it, pNewText);
     371 [ #  # ][ #  # ]:          0 :                     }
     372                 :            :                 }
     373                 :            :             }else
     374                 :          0 :                 ++it;
     375                 :            :             //it now pointer to the node following pos, so pLineList->insert(it, ...) will insert correctly
     376                 :          0 :             return it;
     377                 :            : 
     378                 :            :         }
     379                 :            :     }
     380                 :            :     //If we didn't find pSelectedNode, it must be because the caret is in front of the line
     381                 :          0 :     return pLineList->begin();
     382                 :            : }
     383                 :            : 
     384                 :          0 : SmCaretPos SmCursor::PatchLineList(SmNodeList* pLineList, SmNodeList::iterator aIter) {
     385                 :            :     //The nodes we should consider merging
     386                 :          0 :     SmNode *prev = NULL,
     387                 :          0 :            *next = NULL;
     388         [ #  # ]:          0 :     if(aIter != pLineList->end())
     389                 :          0 :         next = *aIter;
     390         [ #  # ]:          0 :     if(aIter != pLineList->begin()) {
     391                 :          0 :         --aIter;
     392                 :          0 :         prev = *aIter;
     393                 :          0 :         ++aIter;
     394                 :            :     }
     395                 :            : 
     396                 :            :     //Check if there's textnodes to merge
     397 [ #  # ][ #  #  :          0 :     if( prev &&
          #  #  #  #  #  
                #  #  # ]
                 [ #  # ]
     398                 :            :         next &&
     399                 :          0 :         prev->GetType() == NTEXT &&
     400                 :          0 :         next->GetType() == NTEXT &&
     401                 :          0 :         ( prev->GetToken().eType != TNUMBER ||
     402                 :          0 :           next->GetToken().eType == TNUMBER) ){
     403                 :          0 :         SmTextNode *pText = (SmTextNode*)prev,
     404                 :          0 :                    *pOldN = (SmTextNode*)next;
     405                 :          0 :         SmCaretPos retval(pText, pText->GetText().Len());
     406         [ #  # ]:          0 :         String newText;
     407         [ #  # ]:          0 :         newText += pText->GetText();
     408         [ #  # ]:          0 :         newText += pOldN->GetText();
     409         [ #  # ]:          0 :         pText->ChangeText(newText);
     410 [ #  # ][ #  # ]:          0 :         delete pOldN;
     411         [ #  # ]:          0 :         pLineList->erase(aIter);
     412         [ #  # ]:          0 :         return retval;
     413                 :            :     }
     414                 :            : 
     415                 :            :     //Check if there's a SmPlaceNode to remove:
     416 [ #  # ][ #  # ]:          0 :     if(prev && next && prev->GetType() == NPLACE && !SmNodeListParser::IsOperator(next->GetToken())){
         [ #  # ][ #  # ]
                 [ #  # ]
     417                 :          0 :         --aIter;
     418                 :          0 :         aIter = pLineList->erase(aIter);
     419         [ #  # ]:          0 :         delete prev;
     420                 :            :         //Return caret pos in front of aIter
     421         [ #  # ]:          0 :         if(aIter != pLineList->begin())
     422                 :          0 :             --aIter; //Thus find node before aIter
     423         [ #  # ]:          0 :         if(aIter == pLineList->begin())
     424                 :          0 :             return SmCaretPos();
     425         [ #  # ]:          0 :         if((*aIter)->GetType() == NTEXT)
     426                 :          0 :             return SmCaretPos(*aIter, ((SmTextNode*)*aIter)->GetText().Len());
     427                 :          0 :         return SmCaretPos(*aIter, 1);
     428                 :            :     }
     429 [ #  # ][ #  # ]:          0 :     if(prev && next && next->GetType() == NPLACE && !SmNodeListParser::IsOperator(prev->GetToken())){
         [ #  # ][ #  # ]
                 [ #  # ]
     430                 :          0 :         aIter = pLineList->erase(aIter);
     431         [ #  # ]:          0 :         delete next;
     432         [ #  # ]:          0 :         if(prev->GetType() == NTEXT)
     433                 :          0 :             return SmCaretPos(prev, ((SmTextNode*)prev)->GetText().Len());
     434                 :          0 :         return SmCaretPos(prev, 1);
     435                 :            :     }
     436                 :            : 
     437                 :            :     //If we didn't do anything return
     438         [ #  # ]:          0 :     if(!prev) //return an invalid to indicate we're in front of line
     439                 :          0 :         return SmCaretPos();
     440         [ #  # ]:          0 :     if(prev->GetType() == NTEXT)
     441                 :          0 :         return SmCaretPos(prev, ((SmTextNode*)prev)->GetText().Len());
     442                 :          0 :     return SmCaretPos(prev, 1);
     443                 :            : }
     444                 :            : 
     445                 :          0 : SmNodeList::iterator SmCursor::TakeSelectedNodesFromList(SmNodeList *pLineList,
     446                 :            :                                                          SmNodeList *pSelectedNodes) {
     447                 :          0 :     SmNodeList::iterator retval;
     448                 :          0 :     SmNodeList::iterator it = pLineList->begin();
     449         [ #  # ]:          0 :     while(it != pLineList->end()){
     450         [ #  # ]:          0 :         if((*it)->IsSelected()){
     451                 :            :             //Split text nodes
     452         [ #  # ]:          0 :             if((*it)->GetType() == NTEXT) {
     453                 :          0 :                 SmTextNode* pText = (SmTextNode*)*it;
     454         [ #  # ]:          0 :                 String aText = pText->GetText();
     455                 :            :                 //Start and lengths of the segments, 2 is the selected segment
     456                 :          0 :                 int start2 = pText->GetSelectionStart(),
     457                 :          0 :                     start3 = pText->GetSelectionEnd(),
     458                 :          0 :                     len1 = start2 - 0,
     459                 :          0 :                     len2 = start3 - start2,
     460                 :          0 :                     len3 = aText.Len() - start3;
     461         [ #  # ]:          0 :                 SmToken aToken = pText->GetToken();
     462                 :          0 :                 sal_uInt16 eFontDesc = pText->GetFontDesc();
     463                 :            :                 //If we need make segment 1
     464         [ #  # ]:          0 :                 if(len1 > 0) {
     465                 :          0 :                     int start1 = 0;
     466         [ #  # ]:          0 :                     String str = aText.Copy(start1, len1);
     467         [ #  # ]:          0 :                     pText->ChangeText(str);
     468         [ #  # ]:          0 :                     ++it;
     469                 :            :                 } else {//Remove it if not needed
     470         [ #  # ]:          0 :                     it = pLineList->erase(it);
     471 [ #  # ][ #  # ]:          0 :                     delete pText;
     472                 :            :                 }
     473                 :            :                 //Set retval to be right after the selection
     474                 :          0 :                 retval = it;
     475                 :            :                 //if we need make segment 3
     476         [ #  # ]:          0 :                 if(len3 > 0) {
     477         [ #  # ]:          0 :                     String str = aText.Copy(start3, len3);
     478 [ #  # ][ #  # ]:          0 :                     SmTextNode* pSeg3 = new SmTextNode(aToken, eFontDesc);
     479         [ #  # ]:          0 :                     pSeg3->ChangeText(str);
     480 [ #  # ][ #  # ]:          0 :                     retval = pLineList->insert(it, pSeg3);
     481                 :            :                 }
     482                 :            :                 //If we need to save the selected text
     483 [ #  # ][ #  # ]:          0 :                 if(pSelectedNodes && len2 > 0) {
     484         [ #  # ]:          0 :                     String str = aText.Copy(start2, len2);
     485 [ #  # ][ #  # ]:          0 :                     SmTextNode* pSeg2 = new SmTextNode(aToken, eFontDesc);
     486         [ #  # ]:          0 :                     pSeg2->ChangeText(str);
     487 [ #  # ][ #  # ]:          0 :                     pSelectedNodes->push_back(pSeg2);
     488 [ #  # ][ #  # ]:          0 :                 }
     489                 :            :             } else { //if it's not textnode
     490                 :          0 :                 SmNode* pNode = *it;
     491         [ #  # ]:          0 :                 retval = it = pLineList->erase(it);
     492         [ #  # ]:          0 :                 if(pSelectedNodes)
     493         [ #  # ]:          0 :                     pSelectedNodes->push_back(pNode);
     494                 :            :                 else
     495 [ #  # ][ #  # ]:          0 :                     delete pNode;
     496                 :            :             }
     497                 :            :         } else
     498                 :          0 :             ++it;
     499                 :            :     }
     500                 :          0 :     return retval;
     501                 :            : }
     502                 :            : 
     503                 :          0 : void SmCursor::InsertSubSup(SmSubSup eSubSup) {
     504         [ #  # ]:          0 :     AnnotateSelection();
     505                 :            : 
     506                 :            :     //Find line
     507                 :            :     SmNode *pLine;
     508         [ #  # ]:          0 :     if(HasSelection()) {
     509         [ #  # ]:          0 :         SmNode *pSNode = FindSelectedNode(pTree);
     510                 :            :         OSL_ENSURE(pSNode != NULL, "There must be a selected node when HasSelection is true!");
     511         [ #  # ]:          0 :         pLine = FindTopMostNodeInLine(pSNode, sal_True);
     512                 :            :     } else
     513         [ #  # ]:          0 :         pLine = FindTopMostNodeInLine(position->CaretPos.pSelectedNode, sal_False);
     514                 :            : 
     515                 :            :     //Find Parent and offset in parent
     516                 :          0 :     SmStructureNode *pLineParent = pLine->GetParent();
     517         [ #  # ]:          0 :     int nParentIndex = pLineParent->IndexOfSubNode(pLine);
     518                 :            :     OSL_ENSURE(nParentIndex != -1, "pLine must be a subnode of pLineParent!");
     519                 :            : 
     520                 :            :     //TODO: Consider handling special cases where parent is an SmOperNode,
     521                 :            :     //      Maybe this method should be able to add limits to an SmOperNode...
     522                 :            : 
     523                 :            :     //We begin modifying the tree here
     524         [ #  # ]:          0 :     BeginEdit();
     525                 :            : 
     526                 :            :     //Convert line to list
     527 [ #  # ][ #  # ]:          0 :     SmNodeList* pLineList = NodeToList(pLine);
                 [ #  # ]
     528                 :            : 
     529                 :            :     //Take the selection, and/or find iterator for current position
     530 [ #  # ][ #  # ]:          0 :     SmNodeList* pSelectedNodesList = new SmNodeList();
     531                 :          0 :     SmNodeList::iterator it;
     532         [ #  # ]:          0 :     if(HasSelection())
     533         [ #  # ]:          0 :         it = TakeSelectedNodesFromList(pLineList, pSelectedNodesList);
     534                 :            :     else
     535         [ #  # ]:          0 :         it = FindPositionInLineList(pLineList, position->CaretPos);
     536                 :            : 
     537                 :            :     //Find node that this should be applied to
     538                 :            :     SmNode* pSubject;
     539                 :          0 :     bool bPatchLine = pSelectedNodesList->size() > 0; //If the line should be patched later
     540         [ #  # ]:          0 :     if(it != pLineList->begin()) {
     541                 :          0 :         --it;
     542                 :          0 :         pSubject = *it;
     543                 :          0 :         ++it;
     544                 :            :     } else {
     545                 :            :         //Create a new place node
     546 [ #  # ][ #  # ]:          0 :         pSubject = new SmPlaceNode();
     547         [ #  # ]:          0 :         pSubject->Prepare(pDocShell->GetFormat(), *pDocShell);
     548         [ #  # ]:          0 :         it = pLineList->insert(it, pSubject);
     549                 :          0 :         ++it;
     550                 :          0 :         bPatchLine = true;  //We've modified the line it should be patched later.
     551                 :            :     }
     552                 :            : 
     553                 :            :     //Wrap the subject in a SmSubSupNode
     554                 :            :     SmSubSupNode* pSubSup;
     555         [ #  # ]:          0 :     if(pSubject->GetType() != NSUBSUP){
     556         [ #  # ]:          0 :         SmToken token;
     557                 :          0 :         token.nGroup = TGPOWER;
     558 [ #  # ][ #  # ]:          0 :         pSubSup = new SmSubSupNode(token);
     559         [ #  # ]:          0 :         pSubSup->SetBody(pSubject);
     560                 :          0 :         *(--it) = pSubSup;
     561         [ #  # ]:          0 :         ++it;
     562                 :            :     }else
     563                 :          0 :         pSubSup = (SmSubSupNode*)pSubject;
     564                 :            :     //pSubject shouldn't be referenced anymore, pSubSup is the SmSubSupNode in pLineList we wish to edit.
     565                 :            :     //and it pointer to the element following pSubSup in pLineList.
     566                 :          0 :     pSubject = NULL;
     567                 :            : 
     568                 :            :     //Patch the line if we noted that was needed previously
     569         [ #  # ]:          0 :     if(bPatchLine)
     570         [ #  # ]:          0 :         PatchLineList(pLineList, it);
     571                 :            : 
     572                 :            :     //Convert existing, if any, sub-/superscript line to list
     573         [ #  # ]:          0 :     SmNode *pScriptLine = pSubSup->GetSubSup(eSubSup);
     574 [ #  # ][ #  # ]:          0 :     SmNodeList* pScriptLineList = NodeToList(pScriptLine);
                 [ #  # ]
     575                 :            : 
     576                 :            :     //Add selection to pScriptLineList
     577                 :          0 :     unsigned int nOldSize = pScriptLineList->size();
     578         [ #  # ]:          0 :     pScriptLineList->insert(pScriptLineList->end(), pSelectedNodesList->begin(), pSelectedNodesList->end());
     579         [ #  # ]:          0 :     delete pSelectedNodesList;
     580                 :          0 :     pSelectedNodesList = NULL;
     581                 :            : 
     582                 :            :     //Patch pScriptLineList if needed
     583 [ #  # ][ #  # ]:          0 :     if(0 < nOldSize && nOldSize < pScriptLineList->size()) {
                 [ #  # ]
     584                 :          0 :         SmNodeList::iterator iPatchPoint = pScriptLineList->begin();
     585         [ #  # ]:          0 :         std::advance(iPatchPoint, nOldSize);
     586         [ #  # ]:          0 :         PatchLineList(pScriptLineList, iPatchPoint);
     587                 :            :     }
     588                 :            : 
     589                 :            :     //Find caret pos, that should be used after sub-/superscription.
     590                 :          0 :     SmCaretPos PosAfterScript; //Leave invalid for first position
     591         [ #  # ]:          0 :     if(pScriptLineList->size() > 0)
     592         [ #  # ]:          0 :         PosAfterScript = SmCaretPos::GetPosAfter(pScriptLineList->back());
     593                 :            : 
     594                 :            :     //Parse pScriptLineList
     595         [ #  # ]:          0 :     pScriptLine = SmNodeListParser().Parse(pScriptLineList);
     596         [ #  # ]:          0 :     delete pScriptLineList;
     597                 :          0 :     pScriptLineList = NULL;
     598                 :            : 
     599                 :            :     //Insert pScriptLine back into the tree
     600         [ #  # ]:          0 :     pSubSup->SetSubSup(eSubSup, pScriptLine);
     601                 :            : 
     602                 :            :     //Finish editing
     603         [ #  # ]:          0 :     FinishEdit(pLineList, pLineParent, nParentIndex, PosAfterScript, pScriptLine);
     604                 :          0 : }
     605                 :            : 
     606                 :          0 : bool SmCursor::InsertLimit(SmSubSup eSubSup, bool bMoveCaret) {
     607                 :            :     //Find a subject to set limits on
     608                 :          0 :     SmOperNode *pSubject = NULL;
     609                 :            :     //Check if pSelectedNode might be a subject
     610         [ #  # ]:          0 :     if(position->CaretPos.pSelectedNode->GetType() == NOPER)
     611                 :          0 :         pSubject = (SmOperNode*)position->CaretPos.pSelectedNode;
     612                 :            :     else {
     613                 :            :         //If not, check if parent of the current line is a SmOperNode
     614         [ #  # ]:          0 :         SmNode *pLineNode = FindTopMostNodeInLine(position->CaretPos.pSelectedNode, sal_False);
     615 [ #  # ][ #  # ]:          0 :         if(pLineNode->GetParent() && pLineNode->GetParent()->GetType() == NOPER)
                 [ #  # ]
     616                 :          0 :             pSubject = (SmOperNode*)pLineNode->GetParent();
     617                 :            :     }
     618                 :            : 
     619                 :            :     //Abort operation if we're not in the appropriate context
     620         [ #  # ]:          0 :     if(!pSubject)
     621                 :          0 :         return false;
     622                 :            : 
     623         [ #  # ]:          0 :     BeginEdit();
     624                 :            : 
     625                 :            :     //Find the sub sup node
     626                 :          0 :     SmSubSupNode *pSubSup = NULL;
     627                 :            :     //Check if there's already one there...
     628 [ #  # ][ #  # ]:          0 :     if(pSubject->GetSubNode(0)->GetType() == NSUBSUP)
     629         [ #  # ]:          0 :         pSubSup = (SmSubSupNode*)pSubject->GetSubNode(0);
     630                 :            :     else { //if not create a new SmSubSupNode
     631         [ #  # ]:          0 :         SmToken token;
     632                 :          0 :         token.nGroup = TGLIMIT;
     633 [ #  # ][ #  # ]:          0 :         pSubSup = new SmSubSupNode(token);
     634                 :            :         //Set it's body
     635 [ #  # ][ #  # ]:          0 :         pSubSup->SetBody(pSubject->GetSubNode(0));
     636                 :            :         //Replace the operation of the SmOperNode
     637 [ #  # ][ #  # ]:          0 :         pSubject->SetSubNode(0, pSubSup);
     638                 :            :     }
     639                 :            : 
     640                 :            :     //Create the limit, if needed
     641                 :          0 :     SmCaretPos PosAfterLimit;
     642                 :          0 :     SmNode *pLine = NULL;
     643 [ #  # ][ #  # ]:          0 :     if(!pSubSup->GetSubSup(eSubSup)){
     644 [ #  # ][ #  # ]:          0 :         pLine = new SmPlaceNode();
     645         [ #  # ]:          0 :         pSubSup->SetSubSup(eSubSup, pLine);
     646                 :          0 :         PosAfterLimit = SmCaretPos(pLine, 1);
     647                 :            :     //If it's already there... let's move the caret
     648         [ #  # ]:          0 :     } else if(bMoveCaret){
     649         [ #  # ]:          0 :         pLine = pSubSup->GetSubSup(eSubSup);
     650 [ #  # ][ #  # ]:          0 :         SmNodeList* pLineList = NodeToList(pLine);
                 [ #  # ]
     651         [ #  # ]:          0 :         if(pLineList->size() > 0)
     652         [ #  # ]:          0 :             PosAfterLimit = SmCaretPos::GetPosAfter(pLineList->back());
     653         [ #  # ]:          0 :         pLine = SmNodeListParser().Parse(pLineList);
     654         [ #  # ]:          0 :         delete pLineList;
     655         [ #  # ]:          0 :         pSubSup->SetSubSup(eSubSup, pLine);
     656                 :            :     }
     657                 :            : 
     658                 :            :     //Rebuild graph of caret positions
     659         [ #  # ]:          0 :     BuildGraph();
     660         [ #  # ]:          0 :     AnnotateSelection();
     661                 :            : 
     662                 :            :     //Set caret position
     663         [ #  # ]:          0 :     if(bMoveCaret)
     664 [ #  # ][ #  # ]:          0 :         if(!SetCaretPosition(PosAfterLimit, true))
     665         [ #  # ]:          0 :             SetCaretPosition(SmCaretPos(pLine, 0), true);
     666                 :            : 
     667         [ #  # ]:          0 :     EndEdit();
     668                 :            : 
     669                 :          0 :     return true;
     670                 :            : }
     671                 :            : 
     672                 :          0 : void SmCursor::InsertBrackets(SmBracketType eBracketType) {
     673         [ #  # ]:          0 :     BeginEdit();
     674                 :            : 
     675         [ #  # ]:          0 :     AnnotateSelection();
     676                 :            : 
     677                 :            :     //Find line
     678                 :            :     SmNode *pLine;
     679         [ #  # ]:          0 :     if(HasSelection()) {
     680         [ #  # ]:          0 :         SmNode *pSNode = FindSelectedNode(pTree);
     681                 :            :         OSL_ENSURE(pSNode != NULL, "There must be a selected node if HasSelection()");
     682         [ #  # ]:          0 :         pLine = FindTopMostNodeInLine(pSNode, sal_True);
     683                 :            :     } else
     684         [ #  # ]:          0 :         pLine = FindTopMostNodeInLine(position->CaretPos.pSelectedNode, sal_False);
     685                 :            : 
     686                 :            :     //Find parent and offset in parent
     687                 :          0 :     SmStructureNode *pLineParent = pLine->GetParent();
     688         [ #  # ]:          0 :     int nParentIndex = pLineParent->IndexOfSubNode(pLine);
     689                 :            :     OSL_ENSURE( nParentIndex != -1, "pLine must be a subnode of pLineParent!");
     690                 :            : 
     691                 :            :     //Convert line to list
     692 [ #  # ][ #  # ]:          0 :     SmNodeList *pLineList = NodeToList(pLine);
                 [ #  # ]
     693                 :            : 
     694                 :            :     //Take the selection, and/or find iterator for current position
     695 [ #  # ][ #  # ]:          0 :     SmNodeList *pSelectedNodesList = new SmNodeList();
     696                 :          0 :     SmNodeList::iterator it;
     697         [ #  # ]:          0 :     if(HasSelection())
     698         [ #  # ]:          0 :         it = TakeSelectedNodesFromList(pLineList, pSelectedNodesList);
     699                 :            :     else
     700         [ #  # ]:          0 :         it = FindPositionInLineList(pLineList, position->CaretPos);
     701                 :            : 
     702                 :            :     //If there's no selected nodes, create a place node
     703                 :            :     SmNode *pBodyNode;
     704                 :          0 :     SmCaretPos PosAfterInsert;
     705         [ #  # ]:          0 :     if(pSelectedNodesList->empty()) {
     706 [ #  # ][ #  # ]:          0 :         pBodyNode = new SmPlaceNode();
     707                 :          0 :         PosAfterInsert = SmCaretPos(pBodyNode, 1);
     708                 :            :     } else
     709         [ #  # ]:          0 :         pBodyNode = SmNodeListParser().Parse(pSelectedNodesList);
     710                 :            : 
     711         [ #  # ]:          0 :     delete pSelectedNodesList;
     712                 :            : 
     713                 :            :     //Create SmBraceNode
     714         [ #  # ]:          0 :     SmToken aTok(TLEFT, '\0', "left", 0, 5);
     715 [ #  # ][ #  # ]:          0 :     SmBraceNode *pBrace = new SmBraceNode(aTok);
     716                 :          0 :     pBrace->SetScaleMode(SCALE_HEIGHT);
     717         [ #  # ]:          0 :     SmNode *pLeft = CreateBracket(eBracketType, true),
     718         [ #  # ]:          0 :            *pRight = CreateBracket(eBracketType, false);
     719 [ #  # ][ #  # ]:          0 :     SmBracebodyNode *pBody = new SmBracebodyNode(SmToken());
         [ #  # ][ #  # ]
     720         [ #  # ]:          0 :     pBody->SetSubNodes(pBodyNode, NULL);
     721         [ #  # ]:          0 :     pBrace->SetSubNodes(pLeft, pBody, pRight);
     722         [ #  # ]:          0 :     pBrace->Prepare(pDocShell->GetFormat(), *pDocShell);
     723                 :            : 
     724                 :            :     //Insert into line
     725         [ #  # ]:          0 :     pLineList->insert(it, pBrace);
     726                 :            :     //Patch line (I think this is good enough)
     727         [ #  # ]:          0 :     SmCaretPos pAfter = PatchLineList(pLineList, it);
     728         [ #  # ]:          0 :     if( !PosAfterInsert.IsValid() )
     729                 :          0 :         PosAfterInsert = pAfter;
     730                 :            : 
     731                 :            :     //Finish editing
     732 [ #  # ][ #  # ]:          0 :     FinishEdit(pLineList, pLineParent, nParentIndex, PosAfterInsert);
     733                 :          0 : }
     734                 :            : 
     735                 :          0 : SmNode *SmCursor::CreateBracket(SmBracketType eBracketType, bool bIsLeft) {
     736         [ #  # ]:          0 :     SmToken aTok;
     737         [ #  # ]:          0 :     if(bIsLeft){
     738   [ #  #  #  #  :          0 :         switch(eBracketType){
          #  #  #  #  #  
                   #  # ]
     739                 :            :             case NoneBrackets:
     740 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TNONE, '\0', "none", TGLBRACES | TGRBRACES, 0);
                 [ #  # ]
     741                 :          0 :                 break;
     742                 :            :             case RoundBrackets:
     743 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TLPARENT, MS_LPARENT, "(", TGLBRACES, 5);
                 [ #  # ]
     744                 :          0 :                 break;
     745                 :            :             case SquareBrackets:
     746 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TLBRACKET, MS_LBRACKET, "[", TGLBRACES, 5);
                 [ #  # ]
     747                 :          0 :                 break;
     748                 :            :             case DoubleSquareBrackets:
     749 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TLDBRACKET, MS_LDBRACKET, "ldbracket", TGLBRACES, 5);
                 [ #  # ]
     750                 :          0 :                 break;
     751                 :            :             case LineBrackets:
     752 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TLLINE, MS_LINE, "lline", TGLBRACES, 5);
                 [ #  # ]
     753                 :          0 :                 break;
     754                 :            :             case DoubleLineBrackets:
     755 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TLDLINE, MS_DLINE, "ldline", TGLBRACES, 5);
                 [ #  # ]
     756                 :          0 :                 break;
     757                 :            :             case CurlyBrackets:
     758 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TLBRACE, MS_LBRACE, "lbrace", TGLBRACES, 5);
                 [ #  # ]
     759                 :          0 :                 break;
     760                 :            :             case AngleBrackets:
     761 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TLANGLE, MS_LANGLE, "langle", TGLBRACES, 5);
                 [ #  # ]
     762                 :          0 :                 break;
     763                 :            :             case CeilBrackets:
     764 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TLCEIL, MS_LCEIL, "lceil", TGLBRACES, 5);
                 [ #  # ]
     765                 :          0 :                 break;
     766                 :            :             case FloorBrackets:
     767 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TLFLOOR, MS_LFLOOR, "lfloor", TGLBRACES, 5);
                 [ #  # ]
     768                 :          0 :                 break;
     769                 :            :         }
     770                 :            :     } else {
     771   [ #  #  #  #  :          0 :         switch(eBracketType) {
          #  #  #  #  #  
                   #  # ]
     772                 :            :             case NoneBrackets:
     773 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TNONE, '\0', "none", TGLBRACES | TGRBRACES, 0);
                 [ #  # ]
     774                 :          0 :                 break;
     775                 :            :             case RoundBrackets:
     776 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TRPARENT, MS_RPARENT, ")", TGRBRACES, 5);
                 [ #  # ]
     777                 :          0 :                 break;
     778                 :            :             case SquareBrackets:
     779 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TRBRACKET, MS_RBRACKET, "]", TGRBRACES, 5);
                 [ #  # ]
     780                 :          0 :                 break;
     781                 :            :             case DoubleSquareBrackets:
     782 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TRDBRACKET, MS_RDBRACKET, "rdbracket", TGRBRACES, 5);
                 [ #  # ]
     783                 :          0 :                 break;
     784                 :            :             case LineBrackets:
     785 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TRLINE, MS_LINE, "rline", TGRBRACES, 5);
                 [ #  # ]
     786                 :          0 :                 break;
     787                 :            :             case DoubleLineBrackets:
     788 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TRDLINE, MS_DLINE, "rdline", TGRBRACES, 5);
                 [ #  # ]
     789                 :          0 :                 break;
     790                 :            :             case CurlyBrackets:
     791 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TRBRACE, MS_RBRACE, "rbrace", TGRBRACES, 5);
                 [ #  # ]
     792                 :          0 :                 break;
     793                 :            :             case AngleBrackets:
     794 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TRANGLE, MS_RANGLE, "rangle", TGRBRACES, 5);
                 [ #  # ]
     795                 :          0 :                 break;
     796                 :            :             case CeilBrackets:
     797 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TRCEIL, MS_RCEIL, "rceil", TGRBRACES, 5);
                 [ #  # ]
     798                 :          0 :                 break;
     799                 :            :             case FloorBrackets:
     800 [ #  # ][ #  # ]:          0 :                 aTok = SmToken(TRFLOOR, MS_RFLOOR, "rfloor", TGRBRACES, 5);
                 [ #  # ]
     801                 :          0 :                 break;
     802                 :            :         }
     803                 :            :     }
     804 [ #  # ][ #  # ]:          0 :     SmNode* pRetVal = new SmMathSymbolNode(aTok);
     805                 :          0 :     pRetVal->SetScaleMode(SCALE_HEIGHT);
     806         [ #  # ]:          0 :     return pRetVal;
     807                 :            : }
     808                 :            : 
     809                 :          0 : bool SmCursor::InsertRow() {
     810         [ #  # ]:          0 :     AnnotateSelection();
     811                 :            : 
     812                 :            :     //Find line
     813                 :            :     SmNode *pLine;
     814         [ #  # ]:          0 :     if(HasSelection()) {
     815         [ #  # ]:          0 :         SmNode *pSNode = FindSelectedNode(pTree);
     816                 :            :         OSL_ENSURE(pSNode != NULL, "There must be a selected node if HasSelection()");
     817         [ #  # ]:          0 :         pLine = FindTopMostNodeInLine(pSNode, sal_True);
     818                 :            :     } else
     819         [ #  # ]:          0 :         pLine = FindTopMostNodeInLine(position->CaretPos.pSelectedNode, sal_False);
     820                 :            : 
     821                 :            :     //Find parent and offset in parent
     822                 :          0 :     SmStructureNode *pLineParent = pLine->GetParent();
     823         [ #  # ]:          0 :     int nParentIndex = pLineParent->IndexOfSubNode(pLine);
     824                 :            :     OSL_ENSURE( nParentIndex != -1, "pLine must be a subnode of pLineParent!");
     825                 :            : 
     826                 :            :     //Discover the context of this command
     827                 :          0 :     SmTableNode  *pTable  = NULL;
     828                 :          0 :     SmMatrixNode *pMatrix = NULL;
     829                 :          0 :     int nTableIndex = nParentIndex;
     830         [ #  # ]:          0 :     if(pLineParent->GetType() == NTABLE)
     831                 :          0 :         pTable = (SmTableNode*)pLineParent;
     832                 :            :     //If it's warped in a SmLineNode, we can still insert a newline
     833   [ #  #  #  #  :          0 :     else if(pLineParent->GetType() == NLINE &&
           #  # ][ #  # ]
     834                 :          0 :             pLineParent->GetParent() &&
     835                 :          0 :             pLineParent->GetParent()->GetType() == NTABLE) {
     836                 :            :         //NOTE: This hack might give problems if we stop ignoring SmAlignNode
     837                 :          0 :         pTable = (SmTableNode*)pLineParent->GetParent();
     838         [ #  # ]:          0 :         nTableIndex = pTable->IndexOfSubNode(pLineParent);
     839                 :            :         OSL_ENSURE(nTableIndex != -1, "pLineParent must be a child of its parent!");
     840                 :            :     }
     841         [ #  # ]:          0 :     if(pLineParent->GetType() == NMATRIX)
     842                 :          0 :         pMatrix = (SmMatrixNode*)pLineParent;
     843                 :            : 
     844                 :            :     //If we're not in a context that supports InsertRow, return sal_False
     845 [ #  # ][ #  # ]:          0 :     if(!pTable && !pMatrix)
     846                 :          0 :         return false;
     847                 :            : 
     848                 :            :     //Now we start editing
     849         [ #  # ]:          0 :     BeginEdit();
     850                 :            : 
     851                 :            :     //Convert line to list
     852 [ #  # ][ #  # ]:          0 :     SmNodeList *pLineList = NodeToList(pLine);
                 [ #  # ]
     853                 :            : 
     854                 :            :     //Find position in line
     855                 :          0 :     SmNodeList::iterator it;
     856         [ #  # ]:          0 :     if(HasSelection()) {
     857                 :            :         //Take the selected nodes and delete them...
     858         [ #  # ]:          0 :         it = TakeSelectedNodesFromList(pLineList);
     859                 :            :     } else
     860         [ #  # ]:          0 :         it = FindPositionInLineList(pLineList, position->CaretPos);
     861                 :            : 
     862                 :            :     //New caret position after inserting the newline/row in whatever context
     863                 :          0 :     SmCaretPos PosAfterInsert;
     864                 :            : 
     865                 :            :     //If we're in the context of a table
     866         [ #  # ]:          0 :     if(pTable) {
     867 [ #  # ][ #  # ]:          0 :         SmNodeList *pNewLineList = new SmNodeList();
     868                 :            :         //Move elements from pLineList to pNewLineList
     869         [ #  # ]:          0 :         pNewLineList->splice(pNewLineList->begin(), *pLineList, it, pLineList->end());
     870                 :            :         //Make sure it is valid again
     871                 :          0 :         it = pLineList->end();
     872         [ #  # ]:          0 :         if(it != pLineList->begin())
     873                 :          0 :             --it;
     874         [ #  # ]:          0 :         if(pNewLineList->empty())
     875 [ #  # ][ #  # ]:          0 :             pNewLineList->push_front(new SmPlaceNode());
                 [ #  # ]
     876                 :            :         //Parse new line
     877         [ #  # ]:          0 :         SmNode *pNewLine = SmNodeListParser().Parse(pNewLineList);
     878         [ #  # ]:          0 :         delete pNewLineList;
     879                 :            :         //Wrap pNewLine in SmLineNode if needed
     880         [ #  # ]:          0 :         if(pLineParent->GetType() == NLINE) {
     881 [ #  # ][ #  # ]:          0 :             SmLineNode *pNewLineNode = new SmLineNode(SmToken(TNEWLINE, '\0', "newline"));
         [ #  # ][ #  # ]
     882         [ #  # ]:          0 :             pNewLineNode->SetSubNodes(pNewLine, NULL);
     883                 :          0 :             pNewLine = pNewLineNode;
     884                 :            :         }
     885                 :            :         //Get position
     886                 :          0 :         PosAfterInsert = SmCaretPos(pNewLine, 0);
     887                 :            :         //Move other nodes if needed
     888 [ #  # ][ #  # ]:          0 :         for( int i = pTable->GetNumSubNodes(); i > nTableIndex + 1; i--)
     889 [ #  # ][ #  # ]:          0 :             pTable->SetSubNode(i, pTable->GetSubNode(i-1));
     890                 :            : 
     891                 :            :         //Insert new line
     892         [ #  # ]:          0 :         pTable->SetSubNode(nTableIndex + 1, pNewLine);
     893                 :            : 
     894                 :            :         //Check if we need to change token type:
     895 [ #  # ][ #  # ]:          0 :         if(pTable->GetNumSubNodes() > 2 && pTable->GetToken().eType == TBINOM) {
         [ #  # ][ #  # ]
     896         [ #  # ]:          0 :             SmToken tok = pTable->GetToken();
     897                 :          0 :             tok.eType = TSTACK;
     898 [ #  # ][ #  # ]:          0 :             pTable->SetToken(tok);
     899                 :            :         }
     900                 :            :     }
     901                 :            :     //If we're in the context of a matrix
     902         [ #  # ]:          0 :     else if(pMatrix) {
     903                 :            :         //Find position after insert and patch the list
     904         [ #  # ]:          0 :         PosAfterInsert = PatchLineList(pLineList, it);
     905                 :            :         //Move other children
     906                 :          0 :         sal_uInt16 rows = pMatrix->GetNumRows();
     907                 :          0 :         sal_uInt16 cols = pMatrix->GetNumCols();
     908                 :          0 :         int nRowStart = (nParentIndex - nParentIndex % cols) + cols;
     909 [ #  # ][ #  # ]:          0 :         for( int i = pMatrix->GetNumSubNodes() + cols - 1; i >= nRowStart + cols; i--)
     910 [ #  # ][ #  # ]:          0 :             pMatrix->SetSubNode(i, pMatrix->GetSubNode(i - cols));
     911         [ #  # ]:          0 :         for( int i = nRowStart; i < nRowStart + cols; i++) {
     912 [ #  # ][ #  # ]:          0 :             SmPlaceNode *pNewLine = new SmPlaceNode();
     913         [ #  # ]:          0 :             if(i == nParentIndex + cols)
     914                 :          0 :                 PosAfterInsert = SmCaretPos(pNewLine, 0);
     915         [ #  # ]:          0 :             pMatrix->SetSubNode(i, pNewLine);
     916                 :            :         }
     917         [ #  # ]:          0 :         pMatrix->SetRowCol(rows + 1, cols);
     918                 :            :     } else
     919                 :            :         OSL_FAIL("We must be either the context of a table or matrix!");
     920                 :            : 
     921                 :            :     //Finish editing
     922         [ #  # ]:          0 :     FinishEdit(pLineList, pLineParent, nParentIndex, PosAfterInsert);
     923                 :            :     //FinishEdit is actually used to handle siturations where parent is an instance of
     924                 :            :     //SmSubSupNode. In this case parent should always be a table or matrix, however, for
     925                 :            :     //code reuse we just use FinishEdit() here too.
     926                 :          0 :     return true;
     927                 :            : }
     928                 :            : 
     929                 :          0 : void SmCursor::InsertFraction() {
     930         [ #  # ]:          0 :     AnnotateSelection();
     931                 :            : 
     932                 :            :     //Find line
     933                 :            :     SmNode *pLine;
     934         [ #  # ]:          0 :     if(HasSelection()) {
     935         [ #  # ]:          0 :         SmNode *pSNode = FindSelectedNode(pTree);
     936                 :            :         OSL_ENSURE(pSNode != NULL, "There must be a selected node when HasSelection is true!");
     937         [ #  # ]:          0 :         pLine = FindTopMostNodeInLine(pSNode, sal_True);
     938                 :            :     } else
     939         [ #  # ]:          0 :         pLine = FindTopMostNodeInLine(position->CaretPos.pSelectedNode, sal_False);
     940                 :            : 
     941                 :            :     //Find Parent and offset in parent
     942                 :          0 :     SmStructureNode *pLineParent = pLine->GetParent();
     943         [ #  # ]:          0 :     int nParentIndex = pLineParent->IndexOfSubNode(pLine);
     944                 :            :     OSL_ENSURE(nParentIndex != -1, "pLine must be a subnode of pLineParent!");
     945                 :            : 
     946                 :            :     //We begin modifying the tree here
     947         [ #  # ]:          0 :     BeginEdit();
     948                 :            : 
     949                 :            :     //Convert line to list
     950 [ #  # ][ #  # ]:          0 :     SmNodeList* pLineList = NodeToList(pLine);
                 [ #  # ]
     951                 :            : 
     952                 :            :     //Take the selection, and/or find iterator for current position
     953 [ #  # ][ #  # ]:          0 :     SmNodeList* pSelectedNodesList = new SmNodeList();
     954                 :          0 :     SmNodeList::iterator it;
     955         [ #  # ]:          0 :     if(HasSelection())
     956         [ #  # ]:          0 :         it = TakeSelectedNodesFromList(pLineList, pSelectedNodesList);
     957                 :            :     else
     958         [ #  # ]:          0 :         it = FindPositionInLineList(pLineList, position->CaretPos);
     959                 :            : 
     960                 :            :     //Create pNum, and pDenom
     961                 :          0 :     bool bEmptyFraction = pSelectedNodesList->empty();
     962                 :            :     SmNode *pNum = bEmptyFraction
     963                 :          0 :         ? new SmPlaceNode()
     964 [ #  # ][ #  # ]:          0 :         : SmNodeListParser().Parse(pSelectedNodesList);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     965 [ #  # ][ #  # ]:          0 :     SmNode *pDenom = new SmPlaceNode();
     966         [ #  # ]:          0 :     delete pSelectedNodesList;
     967                 :          0 :     pSelectedNodesList = NULL;
     968                 :            : 
     969                 :            :     //Create new fraction
     970 [ #  # ][ #  # ]:          0 :     SmBinVerNode *pFrac = new SmBinVerNode(SmToken(TOVER, '\0', "over", TGPRODUCT, 0));
         [ #  # ][ #  # ]
     971 [ #  # ][ #  # ]:          0 :     SmNode *pRect = new SmRectangleNode(SmToken());
         [ #  # ][ #  # ]
     972         [ #  # ]:          0 :     pFrac->SetSubNodes(pNum, pRect, pDenom);
     973                 :            : 
     974                 :            :     //Insert in pLineList
     975         [ #  # ]:          0 :     SmNodeList::iterator patchIt = pLineList->insert(it, pFrac);
     976         [ #  # ]:          0 :     PatchLineList(pLineList, patchIt);
     977         [ #  # ]:          0 :     PatchLineList(pLineList, it);
     978                 :            : 
     979                 :            :     //Finish editing
     980         [ #  # ]:          0 :     SmNode *pSelectedNode = bEmptyFraction ? pNum : pDenom;
     981         [ #  # ]:          0 :     FinishEdit(pLineList, pLineParent, nParentIndex, SmCaretPos(pSelectedNode, 1));
     982                 :          0 : }
     983                 :            : 
     984                 :          0 : void SmCursor::InsertText(rtl::OUString aString)
     985                 :            : {
     986         [ #  # ]:          0 :     BeginEdit();
     987                 :            : 
     988         [ #  # ]:          0 :     Delete();
     989                 :            : 
     990         [ #  # ]:          0 :     SmToken token;
     991                 :          0 :     token.eType = TIDENT;
     992                 :          0 :     token.cMathChar = '\0';
     993                 :          0 :     token.nGroup = 0;
     994                 :          0 :     token.nLevel = 5;
     995         [ #  # ]:          0 :     token.aText = aString;
     996                 :            : 
     997 [ #  # ][ #  # ]:          0 :     SmTextNode* pText = new SmTextNode(token, FNT_VARIABLE);
     998                 :            : 
     999                 :            :     //Prepare the new node
    1000         [ #  # ]:          0 :     pText->Prepare(pDocShell->GetFormat(), *pDocShell);
    1001         [ #  # ]:          0 :     pText->AdjustFontDesc();
    1002                 :            : 
    1003 [ #  # ][ #  # ]:          0 :     SmNodeList* pList = new SmNodeList();
    1004         [ #  # ]:          0 :     pList->push_front(pText);
    1005         [ #  # ]:          0 :     InsertNodes(pList);
    1006                 :            : 
    1007 [ #  # ][ #  # ]:          0 :     EndEdit();
    1008                 :          0 : }
    1009                 :            : 
    1010                 :          0 : void SmCursor::InsertElement(SmFormulaElement element){
    1011         [ #  # ]:          0 :     BeginEdit();
    1012                 :            : 
    1013         [ #  # ]:          0 :     Delete();
    1014                 :            : 
    1015                 :            :     //Create new node
    1016                 :          0 :     SmNode* pNewNode = NULL;
    1017   [ #  #  #  #  :          0 :     switch(element){
          #  #  #  #  #  
                      # ]
    1018                 :            :         case BlankElement:
    1019                 :            :         {
    1020         [ #  # ]:          0 :             SmToken token;
    1021                 :          0 :             token.nGroup = TGBLANK;
    1022         [ #  # ]:          0 :             token.aText.AssignAscii("~");
    1023 [ #  # ][ #  # ]:          0 :             pNewNode = new SmBlankNode(token);
                 [ #  # ]
    1024                 :          0 :         }break;
    1025                 :            :         case FactorialElement:
    1026                 :            :         {
    1027         [ #  # ]:          0 :             SmToken token(TFACT, MS_FACT, "fact", TGUNOPER, 5);
    1028 [ #  # ][ #  # ]:          0 :             pNewNode = new SmMathSymbolNode(token);
                 [ #  # ]
    1029                 :          0 :         }break;
    1030                 :            :         case PlusElement:
    1031                 :            :         {
    1032         [ #  # ]:          0 :             SmToken token;
    1033                 :          0 :             token.eType = TPLUS;
    1034                 :          0 :             token.cMathChar = MS_PLUS;
    1035                 :          0 :             token.nGroup = TGUNOPER | TGSUM;
    1036                 :          0 :             token.nLevel = 5;
    1037         [ #  # ]:          0 :             token.aText.AssignAscii("+");
    1038 [ #  # ][ #  # ]:          0 :             pNewNode = new SmMathSymbolNode(token);
                 [ #  # ]
    1039                 :          0 :         }break;
    1040                 :            :         case MinusElement:
    1041                 :            :         {
    1042         [ #  # ]:          0 :             SmToken token;
    1043                 :          0 :             token.eType = TMINUS;
    1044                 :          0 :             token.cMathChar = MS_MINUS;
    1045                 :          0 :             token.nGroup = TGUNOPER | TGSUM;
    1046                 :          0 :             token.nLevel = 5;
    1047         [ #  # ]:          0 :             token.aText.AssignAscii("-");
    1048 [ #  # ][ #  # ]:          0 :             pNewNode = new SmMathSymbolNode(token);
                 [ #  # ]
    1049                 :          0 :         }break;
    1050                 :            :         case CDotElement:
    1051                 :            :         {
    1052         [ #  # ]:          0 :             SmToken token;
    1053                 :          0 :             token.eType = TCDOT;
    1054                 :          0 :             token.cMathChar = MS_CDOT;
    1055                 :          0 :             token.nGroup = TGPRODUCT;
    1056         [ #  # ]:          0 :             token.aText.AssignAscii("cdot");
    1057 [ #  # ][ #  # ]:          0 :             pNewNode = new SmMathSymbolNode(token);
                 [ #  # ]
    1058                 :          0 :         }break;
    1059                 :            :         case EqualElement:
    1060                 :            :         {
    1061         [ #  # ]:          0 :             SmToken token;
    1062                 :          0 :             token.eType = TASSIGN;
    1063                 :          0 :             token.cMathChar = MS_ASSIGN;
    1064                 :          0 :             token.nGroup = TGRELATION;
    1065         [ #  # ]:          0 :             token.aText.AssignAscii("=");
    1066 [ #  # ][ #  # ]:          0 :             pNewNode = new SmMathSymbolNode(token);
                 [ #  # ]
    1067                 :          0 :         }break;
    1068                 :            :         case LessThanElement:
    1069                 :            :         {
    1070         [ #  # ]:          0 :             SmToken token;
    1071                 :          0 :             token.eType = TLT;
    1072                 :          0 :             token.cMathChar = MS_LT;
    1073                 :          0 :             token.nGroup = TGRELATION;
    1074         [ #  # ]:          0 :             token.aText.AssignAscii("<");
    1075 [ #  # ][ #  # ]:          0 :             pNewNode = new SmMathSymbolNode(token);
                 [ #  # ]
    1076                 :          0 :         }break;
    1077                 :            :         case GreaterThanElement:
    1078                 :            :         {
    1079         [ #  # ]:          0 :             SmToken token;
    1080                 :          0 :             token.eType = TGT;
    1081                 :          0 :             token.cMathChar = MS_GT;
    1082                 :          0 :             token.nGroup = TGRELATION;
    1083         [ #  # ]:          0 :             token.aText.AssignAscii(">");
    1084 [ #  # ][ #  # ]:          0 :             pNewNode = new SmMathSymbolNode(token);
                 [ #  # ]
    1085                 :          0 :         }break;
    1086                 :            :         case PercentElement:
    1087                 :            :         {
    1088         [ #  # ]:          0 :             SmToken token;
    1089                 :          0 :             token.eType = TTEXT;
    1090                 :          0 :             token.cMathChar = MS_PERCENT;
    1091                 :          0 :             token.nGroup = 0;
    1092         [ #  # ]:          0 :             token.aText.AssignAscii("\"%\"");
    1093 [ #  # ][ #  # ]:          0 :             pNewNode = new SmMathSymbolNode(token);
                 [ #  # ]
    1094                 :          0 :         }break;
    1095                 :            :         default:
    1096                 :            :             OSL_FAIL("Element unknown!");
    1097                 :            :     }
    1098                 :            :     OSL_ENSURE(pNewNode != NULL, "No new node was created!");
    1099         [ #  # ]:          0 :     if(!pNewNode)
    1100                 :          0 :         return;
    1101                 :            : 
    1102                 :            :     //Prepare the new node
    1103         [ #  # ]:          0 :     pNewNode->Prepare(pDocShell->GetFormat(), *pDocShell);
    1104                 :            : 
    1105                 :            :     //Insert new node
    1106 [ #  # ][ #  # ]:          0 :     SmNodeList* pList = new SmNodeList();
    1107         [ #  # ]:          0 :     pList->push_front(pNewNode);
    1108         [ #  # ]:          0 :     InsertNodes(pList);
    1109                 :            : 
    1110         [ #  # ]:          0 :     EndEdit();
    1111                 :            : }
    1112                 :            : 
    1113                 :          0 : void SmCursor::InsertSpecial(rtl::OUString aString)
    1114                 :            : {
    1115         [ #  # ]:          0 :     BeginEdit();
    1116         [ #  # ]:          0 :     Delete();
    1117                 :            : 
    1118         [ #  # ]:          0 :     aString = comphelper::string::strip(aString, ' ');
    1119                 :            : 
    1120                 :            :     //Create instance of special node
    1121         [ #  # ]:          0 :     SmToken token;
    1122                 :          0 :     token.eType = TSPECIAL;
    1123                 :          0 :     token.cMathChar = '\0';
    1124                 :          0 :     token.nGroup = 0;
    1125                 :          0 :     token.nLevel = 5;
    1126         [ #  # ]:          0 :     token.aText = aString;
    1127 [ #  # ][ #  # ]:          0 :     SmSpecialNode* pSpecial = new SmSpecialNode(token);
    1128                 :            : 
    1129                 :            :     //Prepare the special node
    1130         [ #  # ]:          0 :     pSpecial->Prepare(pDocShell->GetFormat(), *pDocShell);
    1131                 :            : 
    1132                 :            :     //Insert the node
    1133 [ #  # ][ #  # ]:          0 :     SmNodeList* pList = new SmNodeList();
    1134         [ #  # ]:          0 :     pList->push_front(pSpecial);
    1135         [ #  # ]:          0 :     InsertNodes(pList);
    1136                 :            : 
    1137 [ #  # ][ #  # ]:          0 :     EndEdit();
    1138                 :          0 : }
    1139                 :            : 
    1140                 :          0 : void SmCursor::InsertCommand(sal_uInt16 nCommand) {
    1141   [ #  #  #  #  :          0 :     switch(nCommand){
                      # ]
    1142                 :            :         case RID_NEWLINE:
    1143                 :          0 :             InsertRow();
    1144                 :          0 :             break;
    1145                 :            :         case RID_FROMX:
    1146                 :          0 :             InsertLimit(CSUB, true);
    1147                 :          0 :             break;
    1148                 :            :         case RID_TOX:
    1149                 :          0 :             InsertLimit(CSUP, true);
    1150                 :          0 :             break;
    1151                 :            :         case RID_FROMXTOY:
    1152         [ #  # ]:          0 :             if(InsertLimit(CSUB, true))
    1153                 :          0 :                 InsertLimit(CSUP, true);
    1154                 :          0 :             break;
    1155                 :            :         default:
    1156 [ #  # ][ #  # ]:          0 :             InsertCommandText(SmResId(nCommand));
                 [ #  # ]
    1157                 :          0 :             break;
    1158                 :            :     }
    1159                 :          0 : }
    1160                 :            : 
    1161                 :          0 : void SmCursor::InsertCommandText(XubString aCommandText) {
    1162                 :            :     //Parse the the sub expression
    1163 [ #  # ][ #  # ]:          0 :     SmNode* pSubExpr = SmParser().ParseExpression(aCommandText);
                 [ #  # ]
    1164                 :            : 
    1165                 :            :     //Prepare the subtree
    1166         [ #  # ]:          0 :     pSubExpr->Prepare(pDocShell->GetFormat(), *pDocShell);
    1167                 :            : 
    1168                 :            :     //Convert subtree to list
    1169 [ #  # ][ #  # ]:          0 :     SmNodeList* pLineList = NodeToList(pSubExpr);
                 [ #  # ]
    1170                 :            : 
    1171         [ #  # ]:          0 :     BeginEdit();
    1172                 :            : 
    1173                 :            :     //Delete any selection
    1174         [ #  # ]:          0 :     Delete();
    1175                 :            : 
    1176                 :            :     //Insert it
    1177         [ #  # ]:          0 :     InsertNodes(pLineList);
    1178                 :            : 
    1179         [ #  # ]:          0 :     EndEdit();
    1180                 :          0 : }
    1181                 :            : 
    1182                 :          0 : void SmCursor::Copy(){
    1183         [ #  # ]:          0 :     if(!HasSelection())
    1184                 :          0 :         return;
    1185                 :            : 
    1186                 :            :     //Find selected node
    1187                 :          0 :     SmNode* pSNode = FindSelectedNode(pTree);
    1188                 :            :     //Find visual line
    1189                 :          0 :     SmNode* pLine = FindTopMostNodeInLine(pSNode, true);
    1190                 :            : 
    1191                 :            :     //Clone selected nodes
    1192                 :            :     SmNodeList* pList;
    1193         [ #  # ]:          0 :     if(IsLineCompositionNode(pLine))
    1194         [ #  # ]:          0 :         pList = CloneLineToList((SmStructureNode*)pLine, true);
    1195                 :            :     else{
    1196         [ #  # ]:          0 :         pList = new SmNodeList();
    1197                 :            :         //Special care to only clone selected text
    1198         [ #  # ]:          0 :         if(pLine->GetType() == NTEXT) {
    1199                 :          0 :             SmTextNode *pText = (SmTextNode*)pLine;
    1200         [ #  # ]:          0 :             SmTextNode *pClone = new SmTextNode( pText->GetToken(), pText->GetFontDesc() );
    1201                 :          0 :             int start  = pText->GetSelectionStart(),
    1202                 :          0 :                 length = pText->GetSelectionEnd() - pText->GetSelectionStart();
    1203         [ #  # ]:          0 :             pClone->ChangeText(pText->GetText().Copy(start, length));
    1204                 :          0 :             pClone->SetScaleMode(pText->GetScaleMode());
    1205         [ #  # ]:          0 :             pList->push_front(pClone);
    1206                 :            :         } else {
    1207                 :          0 :             SmCloningVisitor aCloneFactory;
    1208 [ #  # ][ #  # ]:          0 :             pList->push_front(aCloneFactory.Clone(pLine));
    1209                 :            :         }
    1210                 :            :     }
    1211                 :            : 
    1212                 :            :     //Set clipboard
    1213         [ #  # ]:          0 :     if(pList->size() > 0)
    1214                 :          0 :         SetClipboard(pList);
    1215                 :            : }
    1216                 :            : 
    1217                 :          0 : void SmCursor::Paste() {
    1218                 :          0 :     BeginEdit();
    1219                 :          0 :     Delete();
    1220                 :            : 
    1221 [ #  # ][ #  # ]:          0 :     if(pClipboard && pClipboard->size() > 0)
                 [ #  # ]
    1222                 :          0 :         InsertNodes(CloneList(pClipboard));
    1223                 :            : 
    1224                 :          0 :     EndEdit();
    1225                 :          0 : }
    1226                 :            : 
    1227                 :          0 : SmNodeList* SmCursor::CloneList(SmNodeList* pList){
    1228                 :          0 :     SmCloningVisitor aCloneFactory;
    1229 [ #  # ][ #  # ]:          0 :     SmNodeList* pClones = new SmNodeList();
    1230                 :            : 
    1231                 :          0 :     SmNodeList::iterator it;
    1232         [ #  # ]:          0 :     for(it = pList->begin(); it != pList->end(); ++it){
    1233         [ #  # ]:          0 :         SmNode *pClone = aCloneFactory.Clone(*it);
    1234         [ #  # ]:          0 :         pClones->push_back(pClone);
    1235                 :            :     }
    1236                 :            : 
    1237                 :          0 :     return pClones;
    1238                 :            : }
    1239                 :            : 
    1240                 :          0 : void SmCursor::SetClipboard(SmNodeList* pList){
    1241         [ #  # ]:          0 :     if(pClipboard){
    1242                 :            :         //Delete all nodes on the clipboard
    1243                 :          0 :         SmNodeList::iterator it;
    1244         [ #  # ]:          0 :         for(it = pClipboard->begin(); it != pClipboard->end(); ++it)
    1245 [ #  # ][ #  # ]:          0 :             delete (*it);
    1246         [ #  # ]:          0 :         delete pClipboard;
    1247                 :            :     }
    1248                 :          0 :     pClipboard = pList;
    1249                 :          0 : }
    1250                 :            : 
    1251                 :          0 : SmNode* SmCursor::FindTopMostNodeInLine(SmNode* pSNode, bool MoveUpIfSelected){
    1252                 :            :     //If we haven't got a subnode
    1253         [ #  # ]:          0 :     if(!pSNode)
    1254                 :          0 :         return NULL;
    1255                 :            : 
    1256                 :            :     //Move up parent untill we find a node who's
    1257                 :            :     //parent is NULL or isn't selected and not a type of:
    1258                 :            :     //      SmExpressionNode
    1259                 :            :     //      SmLineNode
    1260                 :            :     //      SmBinHorNode
    1261                 :            :     //      SmUnHorNode
    1262                 :            :     //      SmAlignNode
    1263                 :            :     //      SmFontNode
    1264 [ #  # ][ #  #  :          0 :     while(pSNode->GetParent() &&
             #  #  #  # ]
                 [ #  # ]
    1265                 :            :           ((MoveUpIfSelected &&
    1266                 :          0 :             pSNode->GetParent()->IsSelected()) ||
    1267                 :          0 :            IsLineCompositionNode(pSNode->GetParent())))
    1268                 :          0 :         pSNode = pSNode->GetParent();
    1269                 :            :     //Now we have the selection line node
    1270                 :          0 :     return pSNode;
    1271                 :            : }
    1272                 :            : 
    1273                 :          0 : SmNode* SmCursor::FindSelectedNode(SmNode* pNode){
    1274         [ #  # ]:          0 :     SmNodeIterator it(pNode);
    1275 [ #  # ][ #  # ]:          0 :     while(it.Next()){
    1276         [ #  # ]:          0 :         if(it->IsSelected())
    1277                 :          0 :             return it.Current();
    1278         [ #  # ]:          0 :         SmNode* pRetVal = FindSelectedNode(it.Current());
    1279         [ #  # ]:          0 :         if(pRetVal)
    1280                 :          0 :             return pRetVal;
    1281                 :            :     }
    1282                 :          0 :     return NULL;
    1283                 :            : }
    1284                 :            : 
    1285                 :          0 : SmNodeList* SmCursor::LineToList(SmStructureNode* pLine, SmNodeList* list){
    1286         [ #  # ]:          0 :     SmNodeIterator it(pLine);
    1287 [ #  # ][ #  # ]:          0 :     while(it.Next()){
    1288      [ #  #  # ]:          0 :         switch(it->GetType()){
    1289                 :            :             case NLINE:
    1290                 :            :             case NUNHOR:
    1291                 :            :             case NEXPRESSION:
    1292                 :            :             case NBINHOR:
    1293                 :            :             case NALIGN:
    1294                 :            :             case NFONT:
    1295         [ #  # ]:          0 :                 LineToList((SmStructureNode*)it.Current(), list);
    1296                 :          0 :                 break;
    1297                 :            :             case NERROR:
    1298 [ #  # ][ #  # ]:          0 :                 delete it.Current();
    1299                 :          0 :                 break;
    1300                 :            :             default:
    1301         [ #  # ]:          0 :                 list->push_back(it.Current());
    1302                 :            :         }
    1303                 :            :     }
    1304         [ #  # ]:          0 :     SmNodeArray emptyArray(0);
    1305         [ #  # ]:          0 :     pLine->SetSubNodes(emptyArray);
    1306 [ #  # ][ #  # ]:          0 :     delete pLine;
    1307                 :          0 :     return list;
    1308                 :            : }
    1309                 :            : 
    1310                 :          0 : SmNodeList* SmCursor::CloneLineToList(SmStructureNode* pLine, bool bOnlyIfSelected, SmNodeList* pList){
    1311                 :          0 :     SmCloningVisitor aCloneFactory;
    1312         [ #  # ]:          0 :     SmNodeIterator it(pLine);
    1313 [ #  # ][ #  # ]:          0 :     while(it.Next()){
    1314         [ #  # ]:          0 :         if( IsLineCompositionNode( it.Current() ) )
    1315         [ #  # ]:          0 :             CloneLineToList( (SmStructureNode*)it.Current(), bOnlyIfSelected, pList );
    1316 [ #  # ][ #  # ]:          0 :         else if( (!bOnlyIfSelected || it->IsSelected()) && it->GetType() != NERROR ) {
         [ #  # ][ #  # ]
    1317                 :            :             //Only clone selected text from SmTextNode
    1318         [ #  # ]:          0 :             if(it->GetType() == NTEXT) {
    1319                 :          0 :                 SmTextNode *pText = (SmTextNode*)it.Current();
    1320 [ #  # ][ #  # ]:          0 :                 SmTextNode *pClone = new SmTextNode( it->GetToken(), pText->GetFontDesc() );
    1321                 :          0 :                 int start = pText->GetSelectionStart(),
    1322                 :          0 :                     length = pText->GetSelectionEnd() - pText->GetSelectionStart();
    1323 [ #  # ][ #  # ]:          0 :                 pClone->ChangeText(pText->GetText().Copy(start, length));
                 [ #  # ]
    1324                 :          0 :                 pClone->SetScaleMode(pText->GetScaleMode());
    1325         [ #  # ]:          0 :                 pList->push_back(pClone);
    1326                 :            :             } else
    1327 [ #  # ][ #  # ]:          0 :                 pList->push_back(aCloneFactory.Clone(it.Current()));
    1328                 :            :         }
    1329                 :            :     }
    1330                 :          0 :     return pList;
    1331                 :            : }
    1332                 :            : 
    1333                 :          0 : bool SmCursor::IsLineCompositionNode(SmNode* pNode){
    1334         [ #  # ]:          0 :     switch(pNode->GetType()){
    1335                 :            :         case NLINE:
    1336                 :            :         case NUNHOR:
    1337                 :            :         case NEXPRESSION:
    1338                 :            :         case NBINHOR:
    1339                 :            :         case NALIGN:
    1340                 :            :         case NFONT:
    1341                 :          0 :             return true;
    1342                 :            :         default:
    1343                 :          0 :             return false;
    1344                 :            :     }
    1345                 :            : }
    1346                 :            : 
    1347                 :          0 : int SmCursor::CountSelectedNodes(SmNode* pNode){
    1348                 :          0 :     int nCount = 0;
    1349         [ #  # ]:          0 :     SmNodeIterator it(pNode);
    1350 [ #  # ][ #  # ]:          0 :     while(it.Next()){
    1351 [ #  # ][ #  # ]:          0 :         if(it->IsSelected() && !IsLineCompositionNode(it.Current()))
                 [ #  # ]
    1352                 :          0 :             nCount++;
    1353         [ #  # ]:          0 :         nCount += CountSelectedNodes(it.Current());
    1354                 :            :     }
    1355                 :          0 :     return nCount;
    1356                 :            : }
    1357                 :            : 
    1358                 :          0 : bool SmCursor::HasComplexSelection(){
    1359         [ #  # ]:          0 :     if(!HasSelection())
    1360                 :          0 :         return false;
    1361                 :          0 :     AnnotateSelection();
    1362                 :            : 
    1363                 :          0 :     return CountSelectedNodes(pTree) > 1;
    1364                 :            : }
    1365                 :            : 
    1366                 :          0 : void SmCursor::FinishEdit(SmNodeList* pLineList,
    1367                 :            :                           SmStructureNode* pParent,
    1368                 :            :                           int nParentIndex,
    1369                 :            :                           SmCaretPos PosAfterEdit,
    1370                 :            :                           SmNode* pStartLine) {
    1371                 :            :     //Store number of nodes in line for later
    1372                 :          0 :     int entries = pLineList->size();
    1373                 :            : 
    1374                 :            :     //Parse list of nodes to a tree
    1375                 :          0 :     SmNodeListParser parser;
    1376         [ #  # ]:          0 :     SmNode* pLine = parser.Parse(pLineList);
    1377         [ #  # ]:          0 :     delete pLineList;
    1378                 :            : 
    1379                 :            :     //Check if we're making the body of a subsup node bigger than one
    1380 [ #  # ][ #  # ]:          0 :     if(pParent->GetType() == NSUBSUP &&
         [ #  # ][ #  # ]
    1381                 :            :        nParentIndex == 0 &&
    1382                 :            :        entries > 1) {
    1383                 :            :         //Wrap pLine in scalable round brackets
    1384         [ #  # ]:          0 :         SmToken aTok(TLEFT, '\0', "left", 0, 5);
    1385 [ #  # ][ #  # ]:          0 :         SmBraceNode *pBrace = new SmBraceNode(aTok);
    1386                 :          0 :         pBrace->SetScaleMode(SCALE_HEIGHT);
    1387         [ #  # ]:          0 :         SmNode *pLeft  = CreateBracket(RoundBrackets, true),
    1388         [ #  # ]:          0 :                *pRight = CreateBracket(RoundBrackets, false);
    1389 [ #  # ][ #  # ]:          0 :         SmBracebodyNode *pBody = new SmBracebodyNode(SmToken());
         [ #  # ][ #  # ]
    1390         [ #  # ]:          0 :         pBody->SetSubNodes(pLine, NULL);
    1391         [ #  # ]:          0 :         pBrace->SetSubNodes(pLeft, pBody, pRight);
    1392         [ #  # ]:          0 :         pBrace->Prepare(pDocShell->GetFormat(), *pDocShell);
    1393         [ #  # ]:          0 :         pLine = pBrace;
    1394                 :            :         //TODO: Consider the following alternative behavior:
    1395                 :            :         //Consider the line: A + {B + C}^D lsub E
    1396                 :            :         //Here pLineList is B, + and C and pParent is a subsup node with
    1397                 :            :         //both RSUP and LSUB set. Imagine the user just inserted "B +" in
    1398                 :            :         //the body of the subsup node...
    1399                 :            :         //The most natural thing to do would be to make the line like this:
    1400                 :            :         //A + B lsub E + C ^ D
    1401                 :            :         //E.g. apply LSUB and LSUP to the first element in pLineList and RSUP
    1402                 :            :         //and RSUB to the last eleent in pLineList. But how should this act
    1403                 :            :         //for CSUP and CSUB ???
    1404                 :            :         //For this reason and because brackets was faster to implement, this solution
    1405                 :            :         //have been choosen. It might be worth working on the other solution later...
    1406                 :            :     }
    1407                 :            : 
    1408                 :            :     //Set pStartLine if NULL
    1409         [ #  # ]:          0 :     if(!pStartLine)
    1410                 :          0 :         pStartLine = pLine;
    1411                 :            : 
    1412                 :            :     //Insert it back into the parent
    1413         [ #  # ]:          0 :     pParent->SetSubNode(nParentIndex, pLine);
    1414                 :            : 
    1415                 :            :     //Rebuild graph of caret position
    1416                 :          0 :     anchor = NULL;
    1417                 :          0 :     position = NULL;
    1418         [ #  # ]:          0 :     BuildGraph();
    1419         [ #  # ]:          0 :     AnnotateSelection(); //Update selection annotation!
    1420                 :            : 
    1421                 :            :     //Set caret position
    1422 [ #  # ][ #  # ]:          0 :     if(!SetCaretPosition(PosAfterEdit, true))
    1423         [ #  # ]:          0 :         SetCaretPosition(SmCaretPos(pStartLine, 0), true);
    1424                 :            : 
    1425                 :            :     //End edit section
    1426         [ #  # ]:          0 :     EndEdit();
    1427                 :          0 : }
    1428                 :            : 
    1429                 :          0 : void SmCursor::BeginEdit(){
    1430         [ #  # ]:          0 :     if(nEditSections++ > 0) return;
    1431                 :            : 
    1432                 :          0 :     bIsEnabledSetModifiedSmDocShell = pDocShell->IsEnableSetModified();
    1433         [ #  # ]:          0 :     if( bIsEnabledSetModifiedSmDocShell )
    1434                 :          0 :         pDocShell->EnableSetModified( sal_False );
    1435                 :            : }
    1436                 :            : 
    1437                 :          0 : void SmCursor::EndEdit(){
    1438         [ #  # ]:          0 :     if(--nEditSections > 0) return;
    1439                 :            : 
    1440                 :          0 :     pDocShell->SetFormulaArranged(sal_False);
    1441                 :            :     //Okay, I don't know what this does... :)
    1442                 :            :     //It's used in SmDocShell::SetText and with places where everything is modified.
    1443                 :            :     //I think it does some magic, with sfx, but everything is totally undocumented so
    1444                 :            :     //it's kinda hard to tell...
    1445         [ #  # ]:          0 :     if ( bIsEnabledSetModifiedSmDocShell )
    1446         [ #  # ]:          0 :         pDocShell->EnableSetModified( bIsEnabledSetModifiedSmDocShell );
    1447                 :            :     //I think this notifies people around us that we've modified this document...
    1448         [ #  # ]:          0 :     pDocShell->SetModified(sal_True);
    1449                 :            :     //I think SmDocShell uses this value when it sends an update graphics event
    1450                 :            :     //Anyway comments elsewhere suggests it need to be updated...
    1451                 :          0 :     pDocShell->nModifyCount++;
    1452                 :            : 
    1453                 :            :     //TODO: Consider copying the update accessability code from SmDocShell::SetText in here...
    1454                 :            :     //This somehow updates the size of SmGraphicView if it is running in embedded mode
    1455         [ #  # ]:          0 :     if( pDocShell->GetCreateMode() == SFX_CREATE_MODE_EMBEDDED )
    1456         [ #  # ]:          0 :         pDocShell->OnDocumentPrinterChanged(0);
    1457                 :            : 
    1458                 :            :     //Request a replaint...
    1459         [ #  # ]:          0 :     RequestRepaint();
    1460                 :            : 
    1461                 :            :     //Update the edit engine and text of the document
    1462         [ #  # ]:          0 :     String formula;
    1463         [ #  # ]:          0 :     SmNodeToTextVisitor(pTree, formula);
    1464                 :            :     //pTree->CreateTextFromNode(formula);
    1465         [ #  # ]:          0 :     pDocShell->aText = formula;
    1466 [ #  # ][ #  # ]:          0 :     pDocShell->GetEditEngine().QuickInsertText( formula, ESelection( 0, 0, EE_PARA_ALL, EE_PARA_ALL ) );
    1467 [ #  # ][ #  # ]:          0 :     pDocShell->GetEditEngine().QuickFormatDoc();
                 [ #  # ]
    1468                 :            : }
    1469                 :            : 
    1470                 :          0 : void SmCursor::RequestRepaint(){
    1471                 :          0 :     SmViewShell *pViewSh = SmGetActiveView();
    1472         [ #  # ]:          0 :     if( pViewSh ) {
    1473         [ #  # ]:          0 :         if ( SFX_CREATE_MODE_EMBEDDED == pDocShell->GetCreateMode() )
    1474                 :          0 :             pDocShell->Repaint();
    1475                 :            :         else
    1476                 :          0 :             pViewSh->GetGraphicWindow().Invalidate();
    1477                 :            :     }
    1478                 :          0 : }
    1479                 :            : 
    1480                 :          0 : bool SmCursor::IsAtTailOfBracket(SmBracketType eBracketType, SmBraceNode** ppBraceNode) const {
    1481                 :          0 :     const SmCaretPos pos = GetPosition();
    1482         [ #  # ]:          0 :     if (!pos.IsValid()) {
    1483                 :          0 :         return false;
    1484                 :            :     }
    1485                 :            : 
    1486                 :          0 :     SmNode* pNode = pos.pSelectedNode;
    1487                 :            : 
    1488         [ #  # ]:          0 :     if (pNode->GetType() == NTEXT) {
    1489                 :          0 :         SmTextNode* pTextNode = static_cast<SmTextNode*>(pNode);
    1490         [ #  # ]:          0 :         if (pos.Index < pTextNode->GetText().Len()) {
    1491                 :            :             // The cursor is on a text node and at the middle of it.
    1492                 :          0 :             return false;
    1493                 :            :         }
    1494                 :            :     } else {
    1495         [ #  # ]:          0 :         if (pos.Index < 1) {
    1496                 :          0 :             return false;
    1497                 :            :         }
    1498                 :            :     }
    1499                 :            : 
    1500                 :          0 :     while (true) {
    1501                 :          0 :         SmStructureNode* pParentNode = pNode->GetParent();
    1502         [ #  # ]:          0 :         if (!pParentNode) {
    1503                 :            :             // There's no brace body node in the ancestors.
    1504                 :          0 :             return false;
    1505                 :            :         }
    1506                 :            : 
    1507         [ #  # ]:          0 :         sal_uInt16 index = pNode->FindIndex();
    1508 [ #  # ][ #  # ]:          0 :         if (index + 1 != pParentNode->GetNumSubNodes()) {
    1509                 :            :             // The cursor is not at the tail at one of ancestor nodes.
    1510                 :          0 :             return false;
    1511                 :            :         }
    1512                 :            : 
    1513                 :          0 :         pNode = pParentNode;
    1514         [ #  # ]:          0 :         if (pNode->GetType() == NBRACEBODY) {
    1515                 :            :             // Found the brace body node.
    1516                 :          0 :             break;
    1517                 :            :         }
    1518                 :            :     }
    1519                 :            : 
    1520                 :          0 :     SmStructureNode* pBraceNodeTmp = pNode->GetParent();
    1521 [ #  # ][ #  # ]:          0 :     if (!pBraceNodeTmp || pBraceNodeTmp->GetType() != NBRACE) {
                 [ #  # ]
    1522                 :            :         // Brace node is invalid.
    1523                 :          0 :         return false;
    1524                 :            :     }
    1525                 :            : 
    1526                 :          0 :     SmBraceNode* pBraceNode = static_cast<SmBraceNode*>(pBraceNodeTmp);
    1527         [ #  # ]:          0 :     SmMathSymbolNode* pClosingNode = pBraceNode->ClosingBrace();
    1528         [ #  # ]:          0 :     if (!pClosingNode) {
    1529                 :            :         // Couldn't get closing symbol node.
    1530                 :          0 :         return false;
    1531                 :            :     }
    1532                 :            : 
    1533                 :            :     // Check if the closing brace matches eBracketType.
    1534                 :          0 :     SmTokenType eClosingTokenType = pClosingNode->GetToken().eType;
    1535   [ #  #  #  #  :          0 :     switch (eBracketType) {
          #  #  #  #  #  
                   #  # ]
    1536         [ #  # ]:          0 :     case NoneBrackets:         if (eClosingTokenType != TNONE)      { return false; } break;
    1537         [ #  # ]:          0 :     case RoundBrackets:        if (eClosingTokenType != TRPARENT)   { return false; } break;
    1538         [ #  # ]:          0 :     case SquareBrackets:       if (eClosingTokenType != TRBRACKET)  { return false; } break;
    1539         [ #  # ]:          0 :     case DoubleSquareBrackets: if (eClosingTokenType != TRDBRACKET) { return false; } break;
    1540         [ #  # ]:          0 :     case LineBrackets:         if (eClosingTokenType != TRLINE)     { return false; } break;
    1541         [ #  # ]:          0 :     case DoubleLineBrackets:   if (eClosingTokenType != TRDLINE)    { return false; } break;
    1542         [ #  # ]:          0 :     case CurlyBrackets:        if (eClosingTokenType != TRBRACE)    { return false; } break;
    1543         [ #  # ]:          0 :     case AngleBrackets:        if (eClosingTokenType != TRANGLE)    { return false; } break;
    1544         [ #  # ]:          0 :     case CeilBrackets:         if (eClosingTokenType != TRCEIL)     { return false; } break;
    1545         [ #  # ]:          0 :     case FloorBrackets:        if (eClosingTokenType != TRFLOOR)    { return false; } break;
    1546                 :            :     default:
    1547                 :          0 :         return false;
    1548                 :            :     }
    1549                 :            : 
    1550         [ #  # ]:          0 :     if (ppBraceNode) {
    1551                 :          0 :         *ppBraceNode = static_cast<SmBraceNode*>(pBraceNode);
    1552                 :            :     }
    1553                 :            : 
    1554                 :          0 :     return true;
    1555                 :            : }
    1556                 :            : 
    1557                 :          0 : void SmCursor::MoveAfterBracket(SmBraceNode* pBraceNode, bool bMoveAnchor)
    1558                 :            : {
    1559                 :          0 :     position->CaretPos.pSelectedNode = pBraceNode;
    1560                 :          0 :     position->CaretPos.Index = 1;
    1561         [ #  # ]:          0 :     if (bMoveAnchor) {
    1562                 :          0 :         anchor->CaretPos.pSelectedNode = pBraceNode;
    1563                 :          0 :         anchor->CaretPos.Index = 1;
    1564                 :            :     }
    1565                 :          0 :     RequestRepaint();
    1566                 :          0 : }
    1567                 :            : 
    1568                 :            : 
    1569                 :            : /////////////////////////////////////// SmNodeListParser ///////////////////////////////////////
    1570                 :            : 
    1571                 :          0 : SmNode* SmNodeListParser::Parse(SmNodeList* list, bool bDeleteErrorNodes){
    1572                 :          0 :     pList = list;
    1573         [ #  # ]:          0 :     if(bDeleteErrorNodes){
    1574                 :            :         //Delete error nodes
    1575                 :          0 :         SmNodeList::iterator it = pList->begin();
    1576         [ #  # ]:          0 :         while(it != pList->end()) {
    1577         [ #  # ]:          0 :             if((*it)->GetType() == NERROR){
    1578                 :            :                 //Delete and erase
    1579 [ #  # ][ #  # ]:          0 :                 delete *it;
    1580         [ #  # ]:          0 :                 it = pList->erase(it);
    1581                 :            :             }else
    1582                 :          0 :                 ++it;
    1583                 :            :         }
    1584                 :            :     }
    1585                 :          0 :     SmNode* retval = Expression();
    1586                 :          0 :     pList = NULL;
    1587                 :          0 :     return retval;
    1588                 :            : }
    1589                 :            : 
    1590                 :          0 : SmNode* SmNodeListParser::Expression(){
    1591         [ #  # ]:          0 :     SmNodeArray NodeArray;
    1592                 :            :     //Accept as many relations as there is
    1593 [ #  # ][ #  # ]:          0 :     while(Terminal())
    1594 [ #  # ][ #  # ]:          0 :         NodeArray.push_back(Relation());
    1595                 :            : 
    1596                 :            :     //Create SmExpressionNode, I hope SmToken() will do :)
    1597 [ #  # ][ #  # ]:          0 :     SmStructureNode* pExpr = new SmExpressionNode(SmToken());
         [ #  # ][ #  # ]
    1598         [ #  # ]:          0 :     pExpr->SetSubNodes(NodeArray);
    1599                 :          0 :     return pExpr;
    1600                 :            : }
    1601                 :            : 
    1602                 :          0 : SmNode* SmNodeListParser::Relation(){
    1603                 :            :     //Read a sum
    1604                 :          0 :     SmNode* pLeft = Sum();
    1605                 :            :     //While we have tokens and the next is a relation
    1606 [ #  # ][ #  # ]:          0 :     while(Terminal() && IsRelationOperator(Terminal()->GetToken())){
                 [ #  # ]
    1607                 :            :         //Take the operator
    1608                 :          0 :         SmNode* pOper = Take();
    1609                 :            :         //Find the right side of the relation
    1610                 :          0 :         SmNode* pRight = Sum();
    1611                 :            :         //Create new SmBinHorNode
    1612 [ #  # ][ #  # ]:          0 :         SmStructureNode* pNewNode = new SmBinHorNode(SmToken());
    1613                 :          0 :         pNewNode->SetSubNodes(pLeft, pOper, pRight);
    1614                 :          0 :         pLeft = pNewNode;
    1615                 :            :     }
    1616                 :          0 :     return pLeft;
    1617                 :            : }
    1618                 :            : 
    1619                 :          0 : SmNode* SmNodeListParser::Sum(){
    1620                 :            :     //Read a product
    1621                 :          0 :     SmNode* pLeft = Product();
    1622                 :            :     //While we have tokens and the next is a sum
    1623 [ #  # ][ #  # ]:          0 :     while(Terminal() && IsSumOperator(Terminal()->GetToken())){
                 [ #  # ]
    1624                 :            :         //Take the operator
    1625                 :          0 :         SmNode* pOper = Take();
    1626                 :            :         //Find the right side of the sum
    1627                 :          0 :         SmNode* pRight = Product();
    1628                 :            :         //Create new SmBinHorNode
    1629 [ #  # ][ #  # ]:          0 :         SmStructureNode* pNewNode = new SmBinHorNode(SmToken());
    1630                 :          0 :         pNewNode->SetSubNodes(pLeft, pOper, pRight);
    1631                 :          0 :         pLeft = pNewNode;
    1632                 :            :     }
    1633                 :          0 :     return pLeft;
    1634                 :            : }
    1635                 :            : 
    1636                 :          0 : SmNode* SmNodeListParser::Product(){
    1637                 :            :     //Read a Factor
    1638                 :          0 :     SmNode* pLeft = Factor();
    1639                 :            :     //While we have tokens and the next is a product
    1640 [ #  # ][ #  # ]:          0 :     while(Terminal() && IsProductOperator(Terminal()->GetToken())){
                 [ #  # ]
    1641                 :            :         //Take the operator
    1642                 :          0 :         SmNode* pOper = Take();
    1643                 :            :         //Find the right side of the operation
    1644                 :          0 :         SmNode* pRight = Factor();
    1645                 :            :         //Create new SmBinHorNode
    1646 [ #  # ][ #  # ]:          0 :         SmStructureNode* pNewNode = new SmBinHorNode(SmToken());
    1647                 :          0 :         pNewNode->SetSubNodes(pLeft, pOper, pRight);
    1648                 :          0 :         pLeft = pNewNode;
    1649                 :            :     }
    1650                 :          0 :     return pLeft;
    1651                 :            : }
    1652                 :            : 
    1653                 :          0 : SmNode* SmNodeListParser::Factor(){
    1654                 :            :     //Read unary operations
    1655         [ #  # ]:          0 :     if(!Terminal())
    1656                 :          0 :         return Error();
    1657                 :            :     //Take care of unary operators
    1658         [ #  # ]:          0 :     else if(IsUnaryOperator(Terminal()->GetToken()))
    1659                 :            :     {
    1660 [ #  # ][ #  # ]:          0 :         SmStructureNode *pUnary = new SmUnHorNode(SmToken());
    1661                 :          0 :         SmNode *pOper = Terminal(),
    1662                 :            :                *pArg;
    1663                 :            : 
    1664         [ #  # ]:          0 :         if(Next())
    1665                 :          0 :             pArg = Factor();
    1666                 :            :         else
    1667                 :          0 :             pArg = Error();
    1668                 :            : 
    1669                 :          0 :         pUnary->SetSubNodes(pOper, pArg);
    1670                 :          0 :         return pUnary;
    1671                 :            :     }
    1672                 :          0 :     return Postfix();
    1673                 :            : }
    1674                 :            : 
    1675                 :          0 : SmNode* SmNodeListParser::Postfix(){
    1676         [ #  # ]:          0 :     if(!Terminal())
    1677                 :          0 :         return Error();
    1678                 :          0 :     SmNode *pArg = NULL;
    1679         [ #  # ]:          0 :     if(IsPostfixOperator(Terminal()->GetToken()))
    1680                 :          0 :         pArg = Error();
    1681         [ #  # ]:          0 :     else if(IsOperator(Terminal()->GetToken()))
    1682                 :          0 :         return Error();
    1683                 :            :     else
    1684                 :          0 :         pArg = Take();
    1685 [ #  # ][ #  # ]:          0 :     while(Terminal() && IsPostfixOperator(Terminal()->GetToken())) {
                 [ #  # ]
    1686 [ #  # ][ #  # ]:          0 :         SmStructureNode *pUnary = new SmUnHorNode(SmToken());
    1687                 :          0 :         SmNode *pOper = Take();
    1688                 :          0 :         pUnary->SetSubNodes(pArg, pOper);
    1689                 :          0 :         pArg = pUnary;
    1690                 :            :     }
    1691                 :          0 :     return pArg;
    1692                 :            : }
    1693                 :            : 
    1694                 :          0 : SmNode* SmNodeListParser::Error(){
    1695 [ #  # ][ #  # ]:          0 :     return new SmErrorNode(PE_UNEXPECTED_TOKEN, SmToken());
    1696                 :            : }
    1697                 :            : 
    1698                 :          0 : bool SmNodeListParser::IsOperator(const SmToken &token) {
    1699                 :          0 :     return  IsRelationOperator(token) ||
    1700                 :          0 :             IsSumOperator(token) ||
    1701                 :          0 :             IsProductOperator(token) ||
    1702                 :          0 :             IsUnaryOperator(token) ||
    1703 [ #  # ][ #  #  :          0 :             IsPostfixOperator(token);
          #  #  #  #  #  
                      # ]
    1704                 :            : }
    1705                 :            : 
    1706                 :          0 : bool SmNodeListParser::IsRelationOperator(const SmToken &token) {
    1707                 :          0 :     return token.nGroup & TGRELATION;
    1708                 :            : }
    1709                 :            : 
    1710                 :          0 : bool SmNodeListParser::IsSumOperator(const SmToken &token) {
    1711                 :          0 :     return token.nGroup & TGSUM;
    1712                 :            : }
    1713                 :            : 
    1714                 :          0 : bool SmNodeListParser::IsProductOperator(const SmToken &token) {
    1715                 :            :     return token.nGroup & TGPRODUCT &&
    1716                 :            :            token.eType != TWIDESLASH &&
    1717                 :            :            token.eType != TWIDEBACKSLASH &&
    1718                 :            :            token.eType != TUNDERBRACE &&
    1719                 :            :            token.eType != TOVERBRACE &&
    1720 [ #  # ][ #  # ]:          0 :            token.eType != TOVER;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1721                 :            : }
    1722                 :            : 
    1723                 :          0 : bool SmNodeListParser::IsUnaryOperator(const SmToken &token) {
    1724                 :            :     return  token.nGroup & TGUNOPER &&
    1725                 :            :             (token.eType == TPLUS ||
    1726                 :            :              token.eType == TMINUS ||
    1727                 :            :              token.eType == TPLUSMINUS ||
    1728                 :            :              token.eType == TMINUSPLUS ||
    1729                 :            :              token.eType == TNEG ||
    1730 [ #  # ][ #  # ]:          0 :              token.eType == TUOPER);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1731                 :            : }
    1732                 :            : 
    1733                 :          0 : bool SmNodeListParser::IsPostfixOperator(const SmToken &token) {
    1734                 :          0 :     return token.eType == TFACT;
    1735 [ +  - ][ +  - ]:         30 : }
    1736                 :            : 
    1737                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10