LCOV - code coverage report
Current view: top level - libreoffice/starmath/source - cursor.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 407 986 41.3 %
Date: 2012-12-27 Functions: 38 56 67.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10