bump product version to 5.0.4.1
[LibreOffice.git] / starmath / source / visitors.cxx
blob285536e587abf6d1bc338706f242018fc253586d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <tools/gen.hxx>
11 #include <vcl/lineinfo.hxx>
12 #include "visitors.hxx"
13 #include "tmpdevice.hxx"
14 #include "cursor.hxx"
16 // SmDefaultingVisitor
18 void SmDefaultingVisitor::Visit( SmTableNode* pNode )
20 DefaultVisit( pNode );
23 void SmDefaultingVisitor::Visit( SmBraceNode* pNode )
25 DefaultVisit( pNode );
28 void SmDefaultingVisitor::Visit( SmBracebodyNode* pNode )
30 DefaultVisit( pNode );
33 void SmDefaultingVisitor::Visit( SmOperNode* pNode )
35 DefaultVisit( pNode );
38 void SmDefaultingVisitor::Visit( SmAlignNode* pNode )
40 DefaultVisit( pNode );
43 void SmDefaultingVisitor::Visit( SmAttributNode* pNode )
45 DefaultVisit( pNode );
48 void SmDefaultingVisitor::Visit( SmFontNode* pNode )
50 DefaultVisit( pNode );
53 void SmDefaultingVisitor::Visit( SmUnHorNode* pNode )
55 DefaultVisit( pNode );
58 void SmDefaultingVisitor::Visit( SmBinHorNode* pNode )
60 DefaultVisit( pNode );
63 void SmDefaultingVisitor::Visit( SmBinVerNode* pNode )
65 DefaultVisit( pNode );
68 void SmDefaultingVisitor::Visit( SmBinDiagonalNode* pNode )
70 DefaultVisit( pNode );
73 void SmDefaultingVisitor::Visit( SmSubSupNode* pNode )
75 DefaultVisit( pNode );
78 void SmDefaultingVisitor::Visit( SmMatrixNode* pNode )
80 DefaultVisit( pNode );
83 void SmDefaultingVisitor::Visit( SmPlaceNode* pNode )
85 DefaultVisit( pNode );
88 void SmDefaultingVisitor::Visit( SmTextNode* pNode )
90 DefaultVisit( pNode );
93 void SmDefaultingVisitor::Visit( SmSpecialNode* pNode )
95 DefaultVisit( pNode );
98 void SmDefaultingVisitor::Visit( SmGlyphSpecialNode* pNode )
100 DefaultVisit( pNode );
103 void SmDefaultingVisitor::Visit( SmMathSymbolNode* pNode )
105 DefaultVisit( pNode );
108 void SmDefaultingVisitor::Visit( SmBlankNode* pNode )
110 DefaultVisit( pNode );
113 void SmDefaultingVisitor::Visit( SmErrorNode* pNode )
115 DefaultVisit( pNode );
118 void SmDefaultingVisitor::Visit( SmLineNode* pNode )
120 DefaultVisit( pNode );
123 void SmDefaultingVisitor::Visit( SmExpressionNode* pNode )
125 DefaultVisit( pNode );
128 void SmDefaultingVisitor::Visit( SmPolyLineNode* pNode )
130 DefaultVisit( pNode );
133 void SmDefaultingVisitor::Visit( SmRootNode* pNode )
135 DefaultVisit( pNode );
138 void SmDefaultingVisitor::Visit( SmRootSymbolNode* pNode )
140 DefaultVisit( pNode );
143 void SmDefaultingVisitor::Visit( SmDynIntegralNode* pNode )
145 DefaultVisit( pNode );
148 void SmDefaultingVisitor::Visit( SmDynIntegralSymbolNode* pNode )
150 DefaultVisit( pNode );
153 void SmDefaultingVisitor::Visit( SmRectangleNode* pNode )
155 DefaultVisit( pNode );
158 void SmDefaultingVisitor::Visit( SmVerticalBraceNode* pNode )
160 DefaultVisit( pNode );
163 // SmCaretDrawingVisitor
165 SmCaretDrawingVisitor::SmCaretDrawingVisitor( OutputDevice& rDevice,
166 SmCaretPos position,
167 Point offset,
168 bool caretVisible )
169 : rDev( rDevice )
171 pos = position;
172 Offset = offset;
173 isCaretVisible = caretVisible;
174 SAL_WARN_IF( !position.IsValid(), "starmath", "Cannot draw invalid position!" );
175 if( !position.IsValid( ) )
176 return;
178 //Save device state
179 rDev.Push( PushFlags::FONT | PushFlags::MAPMODE | PushFlags::LINECOLOR | PushFlags::FILLCOLOR | PushFlags::TEXTCOLOR );
181 pos.pSelectedNode->Accept( this );
182 //Restore device state
183 rDev.Pop( );
186 void SmCaretDrawingVisitor::Visit( SmTextNode* pNode )
188 long i = pos.Index;
190 rDev.SetFont( pNode->GetFont( ) );
192 //Find the line
193 SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
195 //Find coordinates
196 long left = pNode->GetLeft( ) + rDev.GetTextWidth( pNode->GetText( ), 0, i ) + Offset.X( );
197 long top = pLine->GetTop( ) + Offset.Y( );
198 long height = pLine->GetHeight( );
199 long left_line = pLine->GetLeft( ) + Offset.X( );
200 long right_line = pLine->GetRight( ) + Offset.X( );
202 //Set color
203 rDev.SetLineColor( Color( COL_BLACK ) );
205 if ( isCaretVisible ) {
206 //Draw vertical line
207 Point p1( left, top );
208 Point p2( left, top + height );
209 rDev.DrawLine( p1, p2 );
212 //Underline the line
213 Point pLeft( left_line, top + height );
214 Point pRight( right_line, top + height );
215 rDev.DrawLine( pLeft, pRight );
218 void SmCaretDrawingVisitor::DefaultVisit( SmNode* pNode )
220 rDev.SetLineColor( Color( COL_BLACK ) );
222 //Find the line
223 SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
225 //Find coordinates
226 long left = pNode->GetLeft( ) + Offset.X( ) + ( pos.Index == 1 ? pNode->GetWidth( ) : 0 );
227 long top = pLine->GetTop( ) + Offset.Y( );
228 long height = pLine->GetHeight( );
229 long left_line = pLine->GetLeft( ) + Offset.X( );
230 long right_line = pLine->GetRight( ) + Offset.X( );
232 //Set color
233 rDev.SetLineColor( Color( COL_BLACK ) );
235 if ( isCaretVisible ) {
236 //Draw vertical line
237 Point p1( left, top );
238 Point p2( left, top + height );
239 rDev.DrawLine( p1, p2 );
242 //Underline the line
243 Point pLeft( left_line, top + height );
244 Point pRight( right_line, top + height );
245 rDev.DrawLine( pLeft, pRight );
248 // SmCaretPos2LineVisitor
250 void SmCaretPos2LineVisitor::Visit( SmTextNode* pNode )
252 //Save device state
253 pDev->Push( PushFlags::FONT | PushFlags::TEXTCOLOR );
255 long i = pos.Index;
257 pDev->SetFont( pNode->GetFont( ) );
259 //Find coordinates
260 long left = pNode->GetLeft( ) + pDev->GetTextWidth( pNode->GetText( ), 0, i );
261 long top = pNode->GetTop( );
262 long height = pNode->GetHeight( );
264 line = SmCaretLine( left, top, height );
266 //Restore device state
267 pDev->Pop( );
270 void SmCaretPos2LineVisitor::DefaultVisit( SmNode* pNode )
272 //Vertical line ( code from SmCaretDrawingVisitor )
273 Point p1 = pNode->GetTopLeft( );
274 if( pos.Index == 1 )
275 p1.Move( pNode->GetWidth( ), 0 );
277 line = SmCaretLine( p1.X( ), p1.Y( ), pNode->GetHeight( ) );
281 // SmDrawingVisitor
283 void SmDrawingVisitor::Visit( SmTableNode* pNode )
285 DrawChildren( pNode );
288 void SmDrawingVisitor::Visit( SmBraceNode* pNode )
290 DrawChildren( pNode );
293 void SmDrawingVisitor::Visit( SmBracebodyNode* pNode )
295 DrawChildren( pNode );
298 void SmDrawingVisitor::Visit( SmOperNode* pNode )
300 DrawChildren( pNode );
303 void SmDrawingVisitor::Visit( SmAlignNode* pNode )
305 DrawChildren( pNode );
308 void SmDrawingVisitor::Visit( SmAttributNode* pNode )
310 DrawChildren( pNode );
313 void SmDrawingVisitor::Visit( SmFontNode* pNode )
315 DrawChildren( pNode );
318 void SmDrawingVisitor::Visit( SmUnHorNode* pNode )
320 DrawChildren( pNode );
323 void SmDrawingVisitor::Visit( SmBinHorNode* pNode )
325 DrawChildren( pNode );
328 void SmDrawingVisitor::Visit( SmBinVerNode* pNode )
330 DrawChildren( pNode );
333 void SmDrawingVisitor::Visit( SmBinDiagonalNode* pNode )
335 DrawChildren( pNode );
338 void SmDrawingVisitor::Visit( SmSubSupNode* pNode )
340 DrawChildren( pNode );
343 void SmDrawingVisitor::Visit( SmMatrixNode* pNode )
345 DrawChildren( pNode );
348 void SmDrawingVisitor::Visit( SmPlaceNode* pNode )
350 DrawSpecialNode( pNode );
353 void SmDrawingVisitor::Visit( SmTextNode* pNode )
355 DrawTextNode( pNode );
358 void SmDrawingVisitor::Visit( SmSpecialNode* pNode )
360 DrawSpecialNode( pNode );
363 void SmDrawingVisitor::Visit( SmGlyphSpecialNode* pNode )
365 DrawSpecialNode( pNode );
368 void SmDrawingVisitor::Visit( SmMathSymbolNode* pNode )
370 DrawSpecialNode( pNode );
373 void SmDrawingVisitor::Visit( SmBlankNode* pNode )
375 DrawChildren( pNode );
378 void SmDrawingVisitor::Visit( SmErrorNode* pNode )
380 DrawSpecialNode( pNode );
383 void SmDrawingVisitor::Visit( SmLineNode* pNode )
385 DrawChildren( pNode );
388 void SmDrawingVisitor::Visit( SmExpressionNode* pNode )
390 DrawChildren( pNode );
393 void SmDrawingVisitor::Visit( SmRootNode* pNode )
395 DrawChildren( pNode );
398 void SmDrawingVisitor::Visit(SmDynIntegralNode* pNode)
400 DrawChildren( pNode );
403 void SmDrawingVisitor::Visit( SmVerticalBraceNode* pNode )
405 DrawChildren( pNode );
408 void SmDrawingVisitor::Visit( SmRootSymbolNode* pNode )
410 if ( pNode->IsPhantom( ) )
411 return;
413 // draw root-sign itself
414 DrawSpecialNode( pNode );
416 SmTmpDevice aTmpDev( ( OutputDevice & ) rDev, true );
417 aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
418 rDev.SetLineColor( );
419 aTmpDev.SetFont( pNode->GetFont( ) );
421 // since the width is always unscaled it corresponds ot the _original_
422 // _unscaled_ font height to be used, we use that to calculate the
423 // bar height. Thus it is independent of the arguments height.
424 // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
425 long nBarHeight = pNode->GetWidth( ) * 7L / 100L;
426 long nBarWidth = pNode->GetBodyWidth( ) + pNode->GetBorderWidth( );
427 Point aBarOffset( pNode->GetWidth( ), +pNode->GetBorderWidth( ) );
428 Point aBarPos( Position + aBarOffset );
430 Rectangle aBar( aBarPos, Size( nBarWidth, nBarHeight ) );
431 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
432 //! increasing zoomfactor.
433 // This is done by shifting its output-position to a point that
434 // corresponds exactly to a pixel on the output device.
435 Point aDrawPos( rDev.PixelToLogic( rDev.LogicToPixel( aBar.TopLeft( ) ) ) );
436 aBar.SetPos( aDrawPos );
438 rDev.DrawRect( aBar );
441 void SmDrawingVisitor::Visit( SmDynIntegralSymbolNode* pNode )
443 if ( pNode->IsPhantom( ) )
444 return;
446 // draw integral-sign itself
447 DrawSpecialNode( pNode );
449 //! the rest of this may not be needed at all
451 // this should be something like:
452 // instead of just drawing the node, take some information about the body.
453 // This is also how SmRootSymbol does it (probably by means of SmRootNode)
454 // NEXT: Check out SmRootNode
457 void SmDrawingVisitor::Visit( SmPolyLineNode* pNode )
459 if ( pNode->IsPhantom( ) )
460 return;
462 long nBorderwidth = pNode->GetFont( ).GetBorderWidth( );
464 LineInfo aInfo;
465 aInfo.SetWidth( pNode->GetWidth( ) - 2 * nBorderwidth );
467 Point aOffset ( Point( ) - pNode->GetPolygon( ).GetBoundRect( ).TopLeft( )
468 + Point( nBorderwidth, nBorderwidth ) ),
469 aPos ( Position + aOffset );
470 pNode->GetPolygon( ).Move( aPos.X( ), aPos.Y( ) ); //Works because Polygon wraps a pointer
472 SmTmpDevice aTmpDev ( ( OutputDevice & ) rDev, false );
473 aTmpDev.SetLineColor( pNode->GetFont( ).GetColor( ) );
475 rDev.DrawPolyLine( pNode->GetPolygon( ), aInfo );
478 void SmDrawingVisitor::Visit( SmRectangleNode* pNode )
480 if ( pNode->IsPhantom( ) )
481 return;
483 SmTmpDevice aTmpDev ( ( OutputDevice & ) rDev, false );
484 aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
485 rDev.SetLineColor( );
486 aTmpDev.SetFont( pNode->GetFont( ) );
488 sal_uLong nTmpBorderWidth = pNode->GetFont( ).GetBorderWidth( );
490 // get rectangle and remove borderspace
491 Rectangle aTmp ( pNode->AsRectangle( ) + Position - pNode->GetTopLeft( ) );
492 aTmp.Left( ) += nTmpBorderWidth;
493 aTmp.Right( ) -= nTmpBorderWidth;
494 aTmp.Top( ) += nTmpBorderWidth;
495 aTmp.Bottom( ) -= nTmpBorderWidth;
497 SAL_WARN_IF( aTmp.GetHeight() == 0 || aTmp.GetWidth() == 0,
498 "starmath", "Empty rectangle" );
500 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
501 //! increasing zoomfactor.
502 // This is done by shifting its output-position to a point that
503 // corresponds exactly to a pixel on the output device.
504 Point aPos ( rDev.PixelToLogic( rDev.LogicToPixel( aTmp.TopLeft( ) ) ) );
505 aTmp.SetPos( aPos );
507 rDev.DrawRect( aTmp );
510 void SmDrawingVisitor::DrawTextNode( SmTextNode* pNode )
512 if ( pNode->IsPhantom() || pNode->GetText().isEmpty() || pNode->GetText()[0] == '\0' )
513 return;
515 SmTmpDevice aTmpDev ( ( OutputDevice & ) rDev, false );
516 aTmpDev.SetFont( pNode->GetFont( ) );
518 Point aPos ( Position );
519 aPos.Y( ) += pNode->GetBaselineOffset( );
520 // auf Pixelkoordinaten runden
521 aPos = rDev.PixelToLogic( rDev.LogicToPixel( aPos ) );
523 rDev.DrawStretchText( aPos, pNode->GetWidth( ), pNode->GetText( ) );
526 void SmDrawingVisitor::DrawSpecialNode( SmSpecialNode* pNode )
528 //! since this chars might come from any font, that we may not have
529 //! set to ALIGN_BASELINE yet, we do it now.
530 pNode->GetFont( ).SetAlign( ALIGN_BASELINE );
532 DrawTextNode( pNode );
535 void SmDrawingVisitor::DrawChildren( SmNode* pNode )
537 if ( pNode->IsPhantom( ) )
538 return;
540 Point rPosition = Position;
542 SmNodeIterator it( pNode );
543 while( it.Next( ) )
545 Point aOffset ( it->GetTopLeft( ) - pNode->GetTopLeft( ) );
546 Position = rPosition + aOffset;
547 it->Accept( this );
551 // SmSetSelectionVisitor
553 SmSetSelectionVisitor::SmSetSelectionVisitor( SmCaretPos startPos, SmCaretPos endPos, SmNode* pTree) {
554 StartPos = startPos;
555 EndPos = endPos;
556 IsSelecting = false;
558 //Assume that pTree is a SmTableNode
559 SAL_WARN_IF(pTree->GetType() != NTABLE, "starmath", "pTree should be a SmTableNode!");
560 //Visit root node, this is special as this node cannot be selected, but its children can!
561 if(pTree->GetType() == NTABLE){
562 //Change state if StartPos is in front of this node
563 if( StartPos.pSelectedNode == pTree && StartPos.Index == 0 )
564 IsSelecting = !IsSelecting;
565 //Change state if EndPos is in front of this node
566 if( EndPos.pSelectedNode == pTree && EndPos.Index == 0 )
567 IsSelecting = !IsSelecting;
568 SAL_WARN_IF(IsSelecting, "starmath", "Caret positions needed to set IsSelecting about, shouldn't be possible!");
570 //Visit lines
571 SmNodeIterator it( pTree );
572 while( it.Next( ) ) {
573 it->Accept( this );
574 //If we started a selection in this line and it haven't ended, we do that now!
575 if(IsSelecting) {
576 IsSelecting = false;
577 SetSelectedOnAll(it.Current(), true);
578 //Set StartPos and EndPos to invalid positions, this ensures that an unused
579 //start or end (because we forced end above), doesn't start a new selection.
580 StartPos = EndPos = SmCaretPos();
583 //Check if pTree isn't selected
584 SAL_WARN_IF(pTree->IsSelected(), "starmath", "pTree should never be selected!");
585 //Discard the selection if there's a bug (it's better than crashing)
586 if(pTree->IsSelected())
587 SetSelectedOnAll(pTree, false);
588 }else //This shouldn't happen, but I don't see any reason to die if it does
589 pTree->Accept(this);
592 void SmSetSelectionVisitor::SetSelectedOnAll( SmNode* pSubTree, bool IsSelected ) {
593 pSubTree->SetSelected( IsSelected );
595 //Quick BFS to set all selections
596 SmNodeIterator it( pSubTree );
597 while( it.Next( ) )
598 SetSelectedOnAll( it.Current( ), IsSelected );
601 void SmSetSelectionVisitor::DefaultVisit( SmNode* pNode ) {
602 //Change state if StartPos is in front of this node
603 if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
604 IsSelecting = !IsSelecting;
605 //Change state if EndPos is in front of this node
606 if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
607 IsSelecting = !IsSelecting;
609 //Cache current state
610 bool WasSelecting = IsSelecting;
611 bool ChangedState = false;
613 //Set selected
614 pNode->SetSelected( IsSelecting );
616 //Visit children
617 SmNodeIterator it( pNode );
618 while( it.Next( ) )
620 it->Accept( this );
621 ChangedState = ( WasSelecting != IsSelecting ) || ChangedState;
624 //If state changed
625 if( ChangedState )
627 //Select this node and all of its children
628 //(Make exception for SmBracebodyNode)
629 if( pNode->GetType() != NBRACEBODY ||
630 !pNode->GetParent() ||
631 pNode->GetParent()->GetType() != NBRACE )
632 SetSelectedOnAll( pNode, true );
633 else
634 SetSelectedOnAll( pNode->GetParent(), true );
635 /* If the equation is: sqrt{2 + 4} + 5
636 * And the selection is: sqrt{2 + [4} +] 5
637 * Where [ denotes StartPos and ] denotes EndPos
638 * Then the sqrt node should be selected, so that the
639 * effective selection is: [sqrt{2 + 4} +] 5
640 * The same is the case if we swap StartPos and EndPos.
644 //Change state if StartPos is after this node
645 if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
647 IsSelecting = !IsSelecting;
649 //Change state if EndPos is after of this node
650 if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
652 IsSelecting = !IsSelecting;
656 void SmSetSelectionVisitor::VisitCompositionNode( SmNode* pNode ) {
657 //Change state if StartPos is in front of this node
658 if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
659 IsSelecting = !IsSelecting;
660 //Change state if EndPos is in front of this node
661 if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
662 IsSelecting = !IsSelecting;
664 //Cache current state
665 bool WasSelecting = IsSelecting;
667 //Visit children
668 SmNodeIterator it( pNode );
669 while( it.Next( ) )
670 it->Accept( this );
672 //Set selected, if everything was selected
673 pNode->SetSelected( WasSelecting && IsSelecting );
675 //Change state if StartPos is after this node
676 if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
677 IsSelecting = !IsSelecting;
678 //Change state if EndPos is after of this node
679 if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
680 IsSelecting = !IsSelecting;
683 void SmSetSelectionVisitor::Visit( SmTextNode* pNode ) {
684 long i1 = -1,
685 i2 = -1;
686 if( StartPos.pSelectedNode == pNode )
687 i1 = StartPos.Index;
688 if( EndPos.pSelectedNode == pNode )
689 i2 = EndPos.Index;
691 long start, end;
692 pNode->SetSelected( true );
693 if( i1 != -1 && i2 != -1 ) {
694 start = i1 < i2 ? i1 : i2; //MIN
695 end = i1 > i2 ? i1 : i2; //MAX
696 } else if( IsSelecting && i1 != -1 ) {
697 start = 0;
698 end = i1;
699 IsSelecting = false;
700 } else if( IsSelecting && i2 != -1 ) {
701 start = 0;
702 end = i2;
703 IsSelecting = false;
704 } else if( !IsSelecting && i1 != -1 ) {
705 start = i1;
706 end = pNode->GetText().getLength();
707 IsSelecting = true;
708 } else if( !IsSelecting && i2 != -1 ) {
709 start = i2;
710 end = pNode->GetText().getLength();
711 IsSelecting = true;
712 } else if( IsSelecting ) {
713 start = 0;
714 end = pNode->GetText().getLength();
715 } else {
716 pNode->SetSelected( false );
717 start = 0;
718 end = 0;
720 pNode->SetSelected( start != end );
721 pNode->SetSelectionStart( start );
722 pNode->SetSelectionEnd( end );
725 void SmSetSelectionVisitor::Visit( SmExpressionNode* pNode ) {
726 VisitCompositionNode( pNode );
729 void SmSetSelectionVisitor::Visit( SmLineNode* pNode ) {
730 VisitCompositionNode( pNode );
733 void SmSetSelectionVisitor::Visit( SmAlignNode* pNode ) {
734 VisitCompositionNode( pNode );
737 void SmSetSelectionVisitor::Visit( SmBinHorNode* pNode ) {
738 VisitCompositionNode( pNode );
741 void SmSetSelectionVisitor::Visit( SmUnHorNode* pNode ) {
742 VisitCompositionNode( pNode );
745 void SmSetSelectionVisitor::Visit( SmFontNode* pNode ) {
746 VisitCompositionNode( pNode );
749 // SmCaretPosGraphBuildingVisitor
751 SmCaretPosGraphBuildingVisitor::SmCaretPosGraphBuildingVisitor( SmNode* pRootNode )
752 : mpRightMost(nullptr)
753 , mpGraph(new SmCaretPosGraph)
755 //pRootNode should always be a table
756 SAL_WARN_IF( pRootNode->GetType( ) != NTABLE, "starmath", "pRootNode must be a table node");
757 //Handle the special case where NTABLE is used a rootnode
758 if( pRootNode->GetType( ) == NTABLE ){
759 //Children are SmLineNodes
760 //Or so I thought... Aparently, the children can be instances of SmExpression
761 //especially if there's a error in the formula... So he we go, a simple work around.
762 SmNodeIterator it( pRootNode );
763 while( it.Next( ) ){
764 //There's a special invariant between this method and the Visit( SmLineNode* )
765 //Usually mpRightMost may not be NULL, to avoid this mpRightMost should here be
766 //set to a new SmCaretPos in front of it.Current( ), however, if it.Current( ) is
767 //an instance of SmLineNode we let SmLineNode create this position in front of
768 //the visual line.
769 //The argument for doing this is that we now don't have to worry about SmLineNode
770 //being a visual line composition node. Thus, no need for yet another special case
771 //in SmCursor::IsLineCompositionNode and everywhere this method is used.
772 //if( it->GetType( ) != NLINE )
773 mpRightMost = mpGraph->Add( SmCaretPos( it.Current( ), 0 ) );
774 it->Accept( this );
776 }else
777 pRootNode->Accept(this);
780 SmCaretPosGraphBuildingVisitor::~SmCaretPosGraphBuildingVisitor()
784 void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode* pNode ){
785 SmNodeIterator it( pNode );
786 while( it.Next( ) ){
787 it->Accept( this );
791 /** Build SmCaretPosGraph for SmTableNode
792 * This method covers cases where SmTableNode is used in a binom or stack,
793 * the special case where it is used as root node for the entire formula is
794 * handled in the constructor.
796 void SmCaretPosGraphBuildingVisitor::Visit( SmTableNode* pNode ){
797 SmCaretPosGraphEntry *left = mpRightMost,
798 *right = mpGraph->Add( SmCaretPos( pNode, 1) );
799 bool bIsFirst = true;
800 SmNodeIterator it( pNode );
801 while( it.Next() ){
802 mpRightMost = mpGraph->Add( SmCaretPos( it.Current(), 0 ), left);
803 if(bIsFirst)
804 left->SetRight(mpRightMost);
805 it->Accept( this );
806 mpRightMost->SetRight(right);
807 if(bIsFirst)
808 right->SetLeft(mpRightMost);
809 bIsFirst = false;
811 mpRightMost = right;
814 /** Build SmCaretPosGraph for SmSubSupNode
816 * The child positions in a SubSupNode, where H is the body:
817 * \code
818 * CSUP
820 * LSUP H H RSUP
821 * H H
822 * HHHH
823 * H H
824 * LSUB H H RSUB
826 * CSUB
827 * \endcode
829 * Graph over these, where "left" is before the SmSubSupNode and "right" is after:
830 * \dot
831 * digraph Graph{
832 * left -> H;
833 * H -> right;
834 * LSUP -> H;
835 * LSUB -> H;
836 * CSUP -> right;
837 * CSUB -> right;
838 * RSUP -> right;
839 * RSUB -> right;
840 * };
841 * \enddot
844 void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode* pNode )
846 SmCaretPosGraphEntry *left,
847 *right,
848 *bodyLeft,
849 *bodyRight;
851 left = mpRightMost;
852 SAL_WARN_IF( !mpRightMost, "starmath", "mpRightMost shouldn't be NULL here!" );
854 //Create bodyLeft
855 SAL_WARN_IF( !pNode->GetBody(), "starmath", "SmSubSupNode Doesn't have a body!" );
856 bodyLeft = mpGraph->Add( SmCaretPos( pNode->GetBody( ), 0 ), left );
857 left->SetRight( bodyLeft ); //TODO: Don't make this if LSUP or LSUB are NULL ( not sure??? )
859 //Create right
860 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
862 //Visit the body, to get bodyRight
863 mpRightMost = bodyLeft;
864 pNode->GetBody( )->Accept( this );
865 bodyRight = mpRightMost;
866 bodyRight->SetRight( right );
867 right->SetLeft( bodyRight );
869 SmNode* pChild;
870 //If there's an LSUP
871 if( ( pChild = pNode->GetSubSup( LSUP ) ) ){
872 SmCaretPosGraphEntry *cLeft; //Child left
873 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
875 mpRightMost = cLeft;
876 pChild->Accept( this );
878 mpRightMost->SetRight( bodyLeft );
880 //If there's an LSUB
881 if( ( pChild = pNode->GetSubSup( LSUB ) ) ){
882 SmCaretPosGraphEntry *cLeft; //Child left
883 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
885 mpRightMost = cLeft;
886 pChild->Accept( this );
888 mpRightMost->SetRight( bodyLeft );
890 //If there's an CSUP
891 if( ( pChild = pNode->GetSubSup( CSUP ) ) ){
892 SmCaretPosGraphEntry *cLeft; //Child left
893 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
895 mpRightMost = cLeft;
896 pChild->Accept( this );
898 mpRightMost->SetRight( right );
900 //If there's an CSUB
901 if( ( pChild = pNode->GetSubSup( CSUB ) ) ){
902 SmCaretPosGraphEntry *cLeft; //Child left
903 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
905 mpRightMost = cLeft;
906 pChild->Accept( this );
908 mpRightMost->SetRight( right );
910 //If there's an RSUP
911 if( ( pChild = pNode->GetSubSup( RSUP ) ) ){
912 SmCaretPosGraphEntry *cLeft; //Child left
913 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
915 mpRightMost = cLeft;
916 pChild->Accept( this );
918 mpRightMost->SetRight( right );
920 //If there's an RSUB
921 if( ( pChild = pNode->GetSubSup( RSUB ) ) ){
922 SmCaretPosGraphEntry *cLeft; //Child left
923 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
925 mpRightMost = cLeft;
926 pChild->Accept( this );
928 mpRightMost->SetRight( right );
931 //Set return parameters
932 mpRightMost = right;
935 /** Build caret position for SmOperNode
937 * If first child is an SmSubSupNode we will ignore its
938 * body, as this body is a SmMathSymbol, for SUM, INT or similar
939 * that shouldn't be subject to modification.
940 * If first child is not a SmSubSupNode, ignore it completely
941 * as it is a SmMathSymbol.
943 * The child positions in a SmOperNode, where H is symbol, e.g. int, sum or similar:
944 * \code
945 * TO
947 * LSUP H H RSUP BBB BB BBB B B
948 * H H B B B B B B B B
949 * HHHH BBB B B B B B
950 * H H B B B B B B B
951 * LSUB H H RSUB BBB BB BBB B
953 * FROM
954 * \endcode
955 * Notice, CSUP, etc. are actually granchildren, but inorder to ignore H, these are visited
956 * from here. If they are present, that is if pOper is an instance of SmSubSupNode.
958 * Graph over these, where "left" is before the SmOperNode and "right" is after:
959 * \dot
960 * digraph Graph{
961 * left -> BODY;
962 * BODY -> right;
963 * LSUP -> BODY;
964 * LSUB -> BODY;
965 * TO -> BODY;
966 * FROM -> BODY;
967 * RSUP -> BODY;
968 * RSUB -> BODY;
969 * };
970 * \enddot
972 void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode* pNode )
974 SmNode *pOper = pNode->GetSubNode( 0 ),
975 *pBody = pNode->GetSubNode( 1 );
977 SmCaretPosGraphEntry *left = mpRightMost,
978 *bodyLeft,
979 *bodyRight,
980 *right;
981 //Create body left
982 bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
983 left->SetRight( bodyLeft );
985 //Visit body, get bodyRight
986 mpRightMost = bodyLeft;
987 pBody->Accept( this );
988 bodyRight = mpRightMost;
990 //Create right
991 right = mpGraph->Add( SmCaretPos( pNode, 1 ), bodyRight );
992 bodyRight->SetRight( right );
994 //Get subsup pNode if any
995 SmSubSupNode* pSubSup = pOper->GetType( ) == NSUBSUP ? static_cast<SmSubSupNode*>(pOper) : NULL;
997 SmNode* pChild;
998 SmCaretPosGraphEntry *childLeft;
999 if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
1000 //Create position in front of pChild
1001 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1002 //Visit pChild
1003 mpRightMost = childLeft;
1004 pChild->Accept( this );
1005 //Set right on mpRightMost from pChild
1006 mpRightMost->SetRight( bodyLeft );
1008 if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
1009 //Create position in front of pChild
1010 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1011 //Visit pChild
1012 mpRightMost = childLeft;
1013 pChild->Accept( this );
1014 //Set right on mpRightMost from pChild
1015 mpRightMost->SetRight( bodyLeft );
1017 if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {//TO
1018 //Create position in front of pChild
1019 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1020 //Visit pChild
1021 mpRightMost = childLeft;
1022 pChild->Accept( this );
1023 //Set right on mpRightMost from pChild
1024 mpRightMost->SetRight( bodyLeft );
1026 if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUB ) ) ) { //FROM
1027 //Create position in front of pChild
1028 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1029 //Visit pChild
1030 mpRightMost = childLeft;
1031 pChild->Accept( this );
1032 //Set right on mpRightMost from pChild
1033 mpRightMost->SetRight( bodyLeft );
1035 if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
1036 //Create position in front of pChild
1037 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1038 //Visit pChild
1039 mpRightMost = childLeft;
1040 pChild->Accept( this );
1041 //Set right on mpRightMost from pChild
1042 mpRightMost->SetRight( bodyLeft );
1044 if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
1045 //Create position in front of pChild
1046 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1047 //Visit pChild
1048 mpRightMost = childLeft;
1049 pChild->Accept( this );
1050 //Set right on mpRightMost from pChild
1051 mpRightMost->SetRight( bodyLeft );
1054 //Return right
1055 mpRightMost = right;
1058 void SmCaretPosGraphBuildingVisitor::Visit( SmMatrixNode* pNode )
1060 SmCaretPosGraphEntry *left = mpRightMost,
1061 *right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1063 for ( sal_uInt16 i = 0; i < pNode->GetNumRows( ); i++ ) {
1064 SmCaretPosGraphEntry* r = left;
1065 for ( sal_uInt16 j = 0; j < pNode->GetNumCols( ); j++ ){
1066 SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
1068 mpRightMost = mpGraph->Add( SmCaretPos( pSubNode, 0 ), r );
1069 if( j != 0 || ( pNode->GetNumRows( ) - 1 ) / 2 == i )
1070 r->SetRight( mpRightMost );
1072 pSubNode->Accept( this );
1074 r = mpRightMost;
1076 mpRightMost->SetRight( right );
1077 if( ( pNode->GetNumRows( ) - 1 ) / 2 == i )
1078 right->SetLeft( mpRightMost );
1081 mpRightMost = right;
1084 /** Build SmCaretPosGraph for SmTextNode
1086 * Lines in an SmTextNode:
1087 * \code
1088 * A B C
1089 * \endcode
1090 * Where A B and C are characters in the text.
1092 * Graph over these, where "left" is before the SmTextNode and "right" is after:
1093 * \dot
1094 * digraph Graph{
1095 * left -> A;
1096 * A -> B
1097 * B -> right;
1098 * };
1099 * \enddot
1100 * Notice that C and right is the same position here.
1102 void SmCaretPosGraphBuildingVisitor::Visit( SmTextNode* pNode )
1104 SAL_WARN_IF( pNode->GetText().isEmpty(), "starmath", "Empty SmTextNode is bad" );
1106 int size = pNode->GetText().getLength();
1107 for( int i = 1; i <= size; i++ ){
1108 SmCaretPosGraphEntry* pRight = mpRightMost;
1109 mpRightMost = mpGraph->Add( SmCaretPos( pNode, i ), pRight );
1110 pRight->SetRight( mpRightMost );
1114 /** Build SmCaretPosGraph for SmBinVerNode
1116 * Lines in an SmBinVerNode:
1117 * \code
1119 * -----
1121 * \endcode
1123 * Graph over these, where "left" is before the SmBinVerNode and "right" is after:
1124 * \dot
1125 * digraph Graph{
1126 * left -> A;
1127 * A -> right;
1128 * B -> right;
1129 * };
1130 * \enddot
1132 void SmCaretPosGraphBuildingVisitor::Visit( SmBinVerNode* pNode )
1134 //None if these children can be NULL, see SmBinVerNode::Arrange
1135 SmNode *pNum = pNode->GetSubNode( 0 ),
1136 *pDenom = pNode->GetSubNode( 2 );
1138 SmCaretPosGraphEntry *left,
1139 *right,
1140 *numLeft,
1141 *denomLeft;
1143 //Set left
1144 left = mpRightMost;
1145 SAL_WARN_IF( !mpRightMost, "starmath", "There must be a position in front of this" );
1147 //Create right
1148 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1150 //Create numLeft
1151 numLeft = mpGraph->Add( SmCaretPos( pNum, 0 ), left );
1152 left->SetRight( numLeft );
1154 //Visit pNum
1155 mpRightMost = numLeft;
1156 pNum->Accept( this );
1157 mpRightMost->SetRight( right );
1158 right->SetLeft( mpRightMost );
1160 //Create denomLeft
1161 denomLeft = mpGraph->Add( SmCaretPos( pDenom, 0 ), left );
1163 //Visit pDenom
1164 mpRightMost = denomLeft;
1165 pDenom->Accept( this );
1166 mpRightMost->SetRight( right );
1168 //Set return parameter
1169 mpRightMost = right;
1172 /** Build SmCaretPosGraph for SmVerticalBraceNode
1174 * Lines in an SmVerticalBraceNode:
1175 * \code
1176 * pScript
1177 * ________
1178 * / \
1179 * pBody
1180 * \endcode
1183 void SmCaretPosGraphBuildingVisitor::Visit( SmVerticalBraceNode* pNode )
1185 SmNode *pBody = pNode->GetSubNode( 0 ),
1186 *pScript = pNode->GetSubNode( 2 );
1187 //None of these children can be NULL
1189 SmCaretPosGraphEntry *left,
1190 *bodyLeft,
1191 *scriptLeft,
1192 *right;
1194 left = mpRightMost;
1196 //Create right
1197 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1199 //Create bodyLeft
1200 bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1201 left->SetRight( bodyLeft );
1202 mpRightMost = bodyLeft;
1203 pBody->Accept( this );
1204 mpRightMost->SetRight( right );
1205 right->SetLeft( mpRightMost );
1207 //Create script
1208 scriptLeft = mpGraph->Add( SmCaretPos( pScript, 0 ), left );
1209 mpRightMost = scriptLeft;
1210 pScript->Accept( this );
1211 mpRightMost->SetRight( right );
1213 //Set return value
1214 mpRightMost = right;
1217 /** Build SmCaretPosGraph for SmBinDiagonalNode
1219 * Lines in an SmBinDiagonalNode:
1220 * \code
1221 * A /
1223 * / B
1224 * \endcode
1225 * Where A and B are lines.
1227 * Used in formulas such as "A wideslash B"
1229 void SmCaretPosGraphBuildingVisitor::Visit( SmBinDiagonalNode* pNode )
1231 SmNode *A = pNode->GetSubNode( 0 ),
1232 *B = pNode->GetSubNode( 1 );
1234 SmCaretPosGraphEntry *left,
1235 *leftA,
1236 *rightA,
1237 *leftB,
1238 *right;
1239 left = mpRightMost;
1241 //Create right
1242 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1244 //Create left A
1245 leftA = mpGraph->Add( SmCaretPos( A, 0 ), left );
1246 left->SetRight( leftA );
1248 //Visit A
1249 mpRightMost = leftA;
1250 A->Accept( this );
1251 rightA = mpRightMost;
1253 //Create left B
1254 leftB = mpGraph->Add( SmCaretPos( B, 0 ), rightA );
1255 rightA->SetRight( leftB );
1257 //Visit B
1258 mpRightMost = leftB;
1259 B->Accept( this );
1260 mpRightMost->SetRight( right );
1261 right->SetLeft( mpRightMost );
1263 //Set return value
1264 mpRightMost = right;
1267 //Straigt forward ( I think )
1268 void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode* pNode )
1270 SmNodeIterator it( pNode );
1271 while( it.Next( ) )
1272 it->Accept( this );
1274 void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode* pNode )
1276 // Unary operator node
1277 SmNodeIterator it( pNode );
1278 while( it.Next( ) )
1279 it->Accept( this );
1283 void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode* pNode )
1285 SmNodeIterator it( pNode );
1286 while( it.Next( ) )
1287 it->Accept( this );
1290 void SmCaretPosGraphBuildingVisitor::Visit( SmFontNode* pNode )
1292 //Has only got one child, should act as an expression if possible
1293 SmNodeIterator it( pNode );
1294 while( it.Next( ) )
1295 it->Accept( this );
1298 /** Build SmCaretPosGraph for SmBracebodyNode
1299 * Acts as an SmExpressionNode
1301 * Below is an example of a formula tree that has multiple children for SmBracebodyNode
1302 * \dot
1303 * digraph {
1304 * labelloc = "t";
1305 * label= "Equation: \"lbrace i mline i in setZ rbrace\"";
1306 * n0 [label="SmTableNode"];
1307 * n0 -> n1 [label="0"];
1308 * n1 [label="SmLineNode"];
1309 * n1 -> n2 [label="0"];
1310 * n2 [label="SmExpressionNode"];
1311 * n2 -> n3 [label="0"];
1312 * n3 [label="SmBraceNode"];
1313 * n3 -> n4 [label="0"];
1314 * n4 [label="SmMathSymbolNode: {"];
1315 * n3 -> n5 [label="1"];
1316 * n5 [label="SmBracebodyNode"];
1317 * n5 -> n6 [label="0"];
1318 * n6 [label="SmExpressionNode"];
1319 * n6 -> n7 [label="0"];
1320 * n7 [label="SmTextNode: i"];
1321 * n5 -> n8 [label="1"];
1322 * n8 [label="SmMathSymbolNode: ∣"];
1323 * n5 -> n9 [label="2"];
1324 * n9 [label="SmExpressionNode"];
1325 * n9 -> n10 [label="0"];
1326 * n10 [label="SmBinHorNode"];
1327 * n10 -> n11 [label="0"];
1328 * n11 [label="SmTextNode: i"];
1329 * n10 -> n12 [label="1"];
1330 * n12 [label="SmMathSymbolNode: ∈"];
1331 * n10 -> n13 [label="2"];
1332 * n13 [label="SmMathSymbolNode: ℤ"];
1333 * n3 -> n14 [label="2"];
1334 * n14 [label="SmMathSymbolNode: }"];
1336 * \enddot
1338 void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode* pNode )
1340 SmNodeIterator it( pNode );
1341 while( it.Next( ) ) {
1342 SmCaretPosGraphEntry* pStart = mpGraph->Add( SmCaretPos( it.Current(), 0), mpRightMost );
1343 mpRightMost->SetRight( pStart );
1344 mpRightMost = pStart;
1345 it->Accept( this );
1349 /** Build SmCaretPosGraph for SmAlignNode
1350 * Acts as an SmExpressionNode, as it only has one child this okay
1352 void SmCaretPosGraphBuildingVisitor::Visit( SmAlignNode* pNode )
1354 SmNodeIterator it( pNode );
1355 while( it.Next( ) )
1356 it->Accept( this );
1359 /** Build SmCaretPosGraph for SmRootNode
1361 * Lines in an SmRootNode:
1362 * \code
1363 * _________
1364 * A/
1365 * \/ B
1367 * \endcode
1368 * A: pExtra ( optional, can be NULL ),
1369 * B: pBody
1371 * Graph over these, where "left" is before the SmRootNode and "right" is after:
1372 * \dot
1373 * digraph Graph{
1374 * left -> B;
1375 * B -> right;
1376 * A -> B;
1378 * \enddot
1380 void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode* pNode )
1382 SmNode *pExtra = pNode->GetSubNode( 0 ), //Argument, NULL for sqrt, and SmTextNode if cubicroot
1383 *pBody = pNode->GetSubNode( 2 ); //Body of the root
1384 SAL_WARN_IF( !pBody, "starmath", "pBody cannot be NULL" );
1386 SmCaretPosGraphEntry *left,
1387 *right,
1388 *bodyLeft,
1389 *bodyRight;
1391 //Get left and save it
1392 SAL_WARN_IF( !mpRightMost, "starmath", "There must be a position in front of this" );
1393 left = mpRightMost;
1395 //Create body left
1396 bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1397 left->SetRight( bodyLeft );
1399 //Create right
1400 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1402 //Visit body
1403 mpRightMost = bodyLeft;
1404 pBody->Accept( this );
1405 bodyRight = mpRightMost;
1406 bodyRight->SetRight( right );
1407 right->SetLeft( bodyRight );
1409 //Visit pExtra
1410 if( pExtra ){
1411 mpRightMost = mpGraph->Add( SmCaretPos( pExtra, 0 ), left );
1412 pExtra->Accept( this );
1413 mpRightMost->SetRight( bodyLeft );
1416 mpRightMost = right;
1420 void SmCaretPosGraphBuildingVisitor::Visit( SmDynIntegralNode* pNode )
1422 //! To be changed: Integrals don't have args.
1423 SmNode *pBody = pNode->Body(); //Body of the root
1424 SAL_WARN_IF( !pBody, "starmath", "pBody cannot be NULL" );
1426 SmCaretPosGraphEntry *left,
1427 *right,
1428 *bodyLeft,
1429 *bodyRight;
1431 //Get left and save it
1432 SAL_WARN_IF( !mpRightMost, "starmath", "There must be a position in front of this" );
1433 left = mpRightMost;
1435 //Create body left
1436 bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1437 left->SetRight( bodyLeft );
1439 //Create right
1440 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1442 //Visit body
1443 mpRightMost = bodyLeft;
1444 pBody->Accept( this );
1445 bodyRight = mpRightMost;
1446 bodyRight->SetRight( right );
1447 right->SetLeft( bodyRight );
1449 mpRightMost = right;
1453 /** Build SmCaretPosGraph for SmPlaceNode
1454 * Consider this a single character.
1456 void SmCaretPosGraphBuildingVisitor::Visit( SmPlaceNode* pNode )
1458 SmCaretPosGraphEntry* right = mpGraph->Add( SmCaretPos( pNode, 1 ), mpRightMost );
1459 mpRightMost->SetRight( right );
1460 mpRightMost = right;
1463 /** SmErrorNode is context dependent metadata, it can't be selected
1465 * @remarks There's no point in deleting, copying and/or moving an instance
1466 * of SmErrorNode as it may not exist in an other context! Thus there are no
1467 * positions to select an SmErrorNode.
1469 void SmCaretPosGraphBuildingVisitor::Visit( SmErrorNode* )
1473 /** Build SmCaretPosGraph for SmBlankNode
1474 * Consider this a single character, as it is only a blank space
1476 void SmCaretPosGraphBuildingVisitor::Visit( SmBlankNode* pNode )
1478 SmCaretPosGraphEntry* right = mpGraph->Add( SmCaretPos( pNode, 1 ), mpRightMost );
1479 mpRightMost->SetRight( right );
1480 mpRightMost = right;
1483 /** Build SmCaretPosGraph for SmBraceNode
1485 * Lines in an SmBraceNode:
1486 * \code
1487 * | |
1488 * | B |
1489 * | |
1490 * \endcode
1491 * B: Body
1493 * Graph over these, where "left" is before the SmBraceNode and "right" is after:
1494 * \dot
1495 * digraph Graph{
1496 * left -> B;
1497 * B -> right;
1499 * \enddot
1501 void SmCaretPosGraphBuildingVisitor::Visit( SmBraceNode* pNode )
1503 SmNode* pBody = pNode->GetSubNode( 1 );
1505 SmCaretPosGraphEntry *left = mpRightMost,
1506 *right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1508 if( pBody->GetType() != NBRACEBODY ) {
1509 mpRightMost = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1510 left->SetRight( mpRightMost );
1511 }else
1512 mpRightMost = left;
1514 pBody->Accept( this );
1515 mpRightMost->SetRight( right );
1516 right->SetLeft( mpRightMost );
1518 mpRightMost = right;
1521 /** Build SmCaretPosGraph for SmAttributNode
1523 * Lines in an SmAttributNode:
1524 * \code
1525 * Attr
1526 * Body
1527 * \endcode
1529 * There's a body and an attribute, the construction is used for "widehat A", where "A" is the body
1530 * and "^" is the attribute ( note GetScaleMode( ) on SmAttributNode tells how the attribute should be
1531 * scaled ).
1533 void SmCaretPosGraphBuildingVisitor::Visit( SmAttributNode* pNode )
1535 SmNode *pAttr = pNode->GetSubNode( 0 ),
1536 *pBody = pNode->GetSubNode( 1 );
1537 //None of the children can be NULL
1539 SmCaretPosGraphEntry *left = mpRightMost,
1540 *attrLeft,
1541 *bodyLeft,
1542 *bodyRight,
1543 *right;
1545 //Creating bodyleft
1546 bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1547 left->SetRight( bodyLeft );
1549 //Creating right
1550 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1552 //Visit the body
1553 mpRightMost = bodyLeft;
1554 pBody->Accept( this );
1555 bodyRight = mpRightMost;
1556 bodyRight->SetRight( right );
1557 right->SetLeft( bodyRight );
1559 //Create attrLeft
1560 attrLeft = mpGraph->Add( SmCaretPos( pAttr, 0 ), left );
1562 //Visit attribute
1563 mpRightMost = attrLeft;
1564 pAttr->Accept( this );
1565 mpRightMost->SetRight( right );
1567 //Set return value
1568 mpRightMost = right;
1571 //Consider these single symboles
1572 void SmCaretPosGraphBuildingVisitor::Visit( SmSpecialNode* pNode )
1574 SmCaretPosGraphEntry* right = mpGraph->Add( SmCaretPos( pNode, 1 ), mpRightMost );
1575 mpRightMost->SetRight( right );
1576 mpRightMost = right;
1578 void SmCaretPosGraphBuildingVisitor::Visit( SmGlyphSpecialNode* pNode )
1580 SmCaretPosGraphEntry* right = mpGraph->Add( SmCaretPos( pNode, 1 ), mpRightMost );
1581 mpRightMost->SetRight( right );
1582 mpRightMost = right;
1584 void SmCaretPosGraphBuildingVisitor::Visit( SmMathSymbolNode* pNode )
1586 SmCaretPosGraphEntry* right = mpGraph->Add( SmCaretPos( pNode, 1 ), mpRightMost );
1587 mpRightMost->SetRight( right );
1588 mpRightMost = right;
1591 void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode* )
1593 //Do nothing
1596 void SmCaretPosGraphBuildingVisitor::Visit( SmDynIntegralSymbolNode* )
1598 //Do nothing
1602 void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode* )
1604 //Do nothing
1606 void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode* )
1608 //Do nothing
1611 // SmCloningVisitor
1613 SmNode* SmCloningVisitor::Clone( SmNode* pNode )
1615 SmNode* pCurrResult = pResult;
1616 pNode->Accept( this );
1617 SmNode* pClone = pResult;
1618 pResult = pCurrResult;
1619 return pClone;
1622 void SmCloningVisitor::CloneNodeAttr( SmNode* pSource, SmNode* pTarget )
1624 pTarget->SetScaleMode( pSource->GetScaleMode( ) );
1625 //Other attributes are set when prepare or arrange is executed
1626 //and may depend on stuff not being cloned here.
1629 void SmCloningVisitor::CloneKids( SmStructureNode* pSource, SmStructureNode* pTarget )
1631 //Cache current result
1632 SmNode* pCurrResult = pResult;
1634 //Create array for holding clones
1635 sal_uInt16 nSize = pSource->GetNumSubNodes( );
1636 SmNodeArray aNodes( nSize );
1638 //Clone children
1639 for( sal_uInt16 i = 0; i < nSize; i++ ){
1640 SmNode* pKid;
1641 if( NULL != ( pKid = pSource->GetSubNode( i ) ) )
1642 pKid->Accept( this );
1643 else
1644 pResult = NULL;
1645 aNodes[i] = pResult;
1648 //Set subnodes of pTarget
1649 pTarget->SetSubNodes( aNodes );
1651 //Restore result as where prior to call
1652 pResult = pCurrResult;
1655 void SmCloningVisitor::Visit( SmTableNode* pNode )
1657 SmTableNode* pClone = new SmTableNode( pNode->GetToken( ) );
1658 CloneNodeAttr( pNode, pClone );
1659 CloneKids( pNode, pClone );
1660 pResult = pClone;
1663 void SmCloningVisitor::Visit( SmBraceNode* pNode )
1665 SmBraceNode* pClone = new SmBraceNode( pNode->GetToken( ) );
1666 CloneNodeAttr( pNode, pClone );
1667 CloneKids( pNode, pClone );
1668 pResult = pClone;
1671 void SmCloningVisitor::Visit( SmBracebodyNode* pNode )
1673 SmBracebodyNode* pClone = new SmBracebodyNode( pNode->GetToken( ) );
1674 CloneNodeAttr( pNode, pClone );
1675 CloneKids( pNode, pClone );
1676 pResult = pClone;
1679 void SmCloningVisitor::Visit( SmOperNode* pNode )
1681 SmOperNode* pClone = new SmOperNode( pNode->GetToken( ) );
1682 CloneNodeAttr( pNode, pClone );
1683 CloneKids( pNode, pClone );
1684 pResult = pClone;
1687 void SmCloningVisitor::Visit( SmAlignNode* pNode )
1689 SmAlignNode* pClone = new SmAlignNode( pNode->GetToken( ) );
1690 CloneNodeAttr( pNode, pClone );
1691 CloneKids( pNode, pClone );
1692 pResult = pClone;
1695 void SmCloningVisitor::Visit( SmAttributNode* pNode )
1697 SmAttributNode* pClone = new SmAttributNode( pNode->GetToken( ) );
1698 CloneNodeAttr( pNode, pClone );
1699 CloneKids( pNode, pClone );
1700 pResult = pClone;
1703 void SmCloningVisitor::Visit( SmFontNode* pNode )
1705 SmFontNode* pClone = new SmFontNode( pNode->GetToken( ) );
1706 pClone->SetSizeParameter( pNode->GetSizeParameter( ), pNode->GetSizeType( ) );
1707 CloneNodeAttr( pNode, pClone );
1708 CloneKids( pNode, pClone );
1709 pResult = pClone;
1712 void SmCloningVisitor::Visit( SmUnHorNode* pNode )
1714 SmUnHorNode* pClone = new SmUnHorNode( pNode->GetToken( ) );
1715 CloneNodeAttr( pNode, pClone );
1716 CloneKids( pNode, pClone );
1717 pResult = pClone;
1720 void SmCloningVisitor::Visit( SmBinHorNode* pNode )
1722 SmBinHorNode* pClone = new SmBinHorNode( pNode->GetToken( ) );
1723 CloneNodeAttr( pNode, pClone );
1724 CloneKids( pNode, pClone );
1725 pResult = pClone;
1728 void SmCloningVisitor::Visit( SmBinVerNode* pNode )
1730 SmBinVerNode* pClone = new SmBinVerNode( pNode->GetToken( ) );
1731 CloneNodeAttr( pNode, pClone );
1732 CloneKids( pNode, pClone );
1733 pResult = pClone;
1736 void SmCloningVisitor::Visit( SmBinDiagonalNode* pNode )
1738 SmBinDiagonalNode *pClone = new SmBinDiagonalNode( pNode->GetToken( ) );
1739 pClone->SetAscending( pNode->IsAscending( ) );
1740 CloneNodeAttr( pNode, pClone );
1741 CloneKids( pNode, pClone );
1742 pResult = pClone;
1745 void SmCloningVisitor::Visit( SmSubSupNode* pNode )
1747 SmSubSupNode *pClone = new SmSubSupNode( pNode->GetToken( ) );
1748 pClone->SetUseLimits( pNode->IsUseLimits( ) );
1749 CloneNodeAttr( pNode, pClone );
1750 CloneKids( pNode, pClone );
1751 pResult = pClone;
1754 void SmCloningVisitor::Visit( SmMatrixNode* pNode )
1756 SmMatrixNode *pClone = new SmMatrixNode( pNode->GetToken( ) );
1757 pClone->SetRowCol( pNode->GetNumRows( ), pNode->GetNumCols( ) );
1758 CloneNodeAttr( pNode, pClone );
1759 CloneKids( pNode, pClone );
1760 pResult = pClone;
1763 void SmCloningVisitor::Visit( SmPlaceNode* pNode )
1765 pResult = new SmPlaceNode( pNode->GetToken( ) );
1766 CloneNodeAttr( pNode, pResult );
1769 void SmCloningVisitor::Visit( SmTextNode* pNode )
1771 SmTextNode* pClone = new SmTextNode( pNode->GetToken( ), pNode->GetFontDesc( ) );
1772 pClone->ChangeText( pNode->GetText( ) );
1773 CloneNodeAttr( pNode, pClone );
1774 pResult = pClone;
1777 void SmCloningVisitor::Visit( SmSpecialNode* pNode )
1779 pResult = new SmSpecialNode( pNode->GetToken( ) );
1780 CloneNodeAttr( pNode, pResult );
1783 void SmCloningVisitor::Visit( SmGlyphSpecialNode* pNode )
1785 pResult = new SmGlyphSpecialNode( pNode->GetToken( ) );
1786 CloneNodeAttr( pNode, pResult );
1789 void SmCloningVisitor::Visit( SmMathSymbolNode* pNode )
1791 pResult = new SmMathSymbolNode( pNode->GetToken( ) );
1792 CloneNodeAttr( pNode, pResult );
1795 void SmCloningVisitor::Visit( SmBlankNode* pNode )
1797 SmBlankNode* pClone = new SmBlankNode( pNode->GetToken( ) );
1798 pClone->SetBlankNum( pNode->GetBlankNum( ) );
1799 pResult = pClone;
1800 CloneNodeAttr( pNode, pResult );
1803 void SmCloningVisitor::Visit( SmErrorNode* pNode )
1805 //PE_NONE is used the information have been discarded and isn't used
1806 pResult = new SmErrorNode( PE_NONE, pNode->GetToken( ) );
1807 CloneNodeAttr( pNode, pResult );
1810 void SmCloningVisitor::Visit( SmLineNode* pNode )
1812 SmLineNode* pClone = new SmLineNode( pNode->GetToken( ) );
1813 CloneNodeAttr( pNode, pClone );
1814 CloneKids( pNode, pClone );
1815 pResult = pClone;
1818 void SmCloningVisitor::Visit( SmExpressionNode* pNode )
1820 SmExpressionNode* pClone = new SmExpressionNode( pNode->GetToken( ) );
1821 CloneNodeAttr( pNode, pClone );
1822 CloneKids( pNode, pClone );
1823 pResult = pClone;
1826 void SmCloningVisitor::Visit( SmPolyLineNode* pNode )
1828 pResult = new SmPolyLineNode( pNode->GetToken( ) );
1829 CloneNodeAttr( pNode, pResult );
1832 void SmCloningVisitor::Visit( SmRootNode* pNode )
1834 SmRootNode* pClone = new SmRootNode( pNode->GetToken( ) );
1835 CloneNodeAttr( pNode, pClone );
1836 CloneKids( pNode, pClone );
1837 pResult = pClone;
1840 void SmCloningVisitor::Visit( SmRootSymbolNode* pNode )
1842 pResult = new SmRootSymbolNode( pNode->GetToken( ) );
1843 CloneNodeAttr( pNode, pResult );
1846 void SmCloningVisitor::Visit( SmDynIntegralNode* pNode )
1848 SmDynIntegralNode* pClone = new SmDynIntegralNode( pNode->GetToken( ) );
1849 CloneNodeAttr( pNode, pClone );
1850 CloneKids( pNode, pClone );
1851 pResult = pClone;
1854 void SmCloningVisitor::Visit( SmDynIntegralSymbolNode* pNode )
1856 pResult = new SmDynIntegralSymbolNode( pNode->GetToken( ) );
1857 CloneNodeAttr( pNode, pResult );
1860 void SmCloningVisitor::Visit( SmRectangleNode* pNode )
1862 pResult = new SmRectangleNode( pNode->GetToken( ) );
1863 CloneNodeAttr( pNode, pResult );
1866 void SmCloningVisitor::Visit( SmVerticalBraceNode* pNode )
1868 SmVerticalBraceNode* pClone = new SmVerticalBraceNode( pNode->GetToken( ) );
1869 CloneNodeAttr( pNode, pClone );
1870 CloneKids( pNode, pClone );
1871 pResult = pClone;
1874 // SmSelectionDrawingVisitor
1876 SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, Point Offset )
1877 : rDev( rDevice ) {
1878 bHasSelectionArea = false;
1880 //Visit everything
1881 SAL_WARN_IF( !pTree, "starmath", "pTree can't be null!" );
1882 if( pTree )
1883 pTree->Accept( this );
1885 //Draw selection if there's any
1886 if( bHasSelectionArea ){
1887 aSelectionArea.Move( Offset.X( ), Offset.Y( ) );
1889 //Save device state
1890 rDev.Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR );
1891 //Change colors
1892 rDev.SetLineColor( );
1893 rDev.SetFillColor( Color( COL_LIGHTGRAY ) );
1895 //Draw rectangle
1896 rDev.DrawRect( aSelectionArea );
1898 //Restore device state
1899 rDev.Pop( );
1903 void SmSelectionDrawingVisitor::ExtendSelectionArea(const Rectangle& rArea)
1905 if ( ! bHasSelectionArea ) {
1906 aSelectionArea = rArea;
1907 bHasSelectionArea = true;
1908 } else
1909 aSelectionArea.Union(rArea);
1912 void SmSelectionDrawingVisitor::DefaultVisit( SmNode* pNode )
1914 if( pNode->IsSelected( ) )
1915 ExtendSelectionArea( pNode->AsRectangle( ) );
1916 VisitChildren( pNode );
1919 void SmSelectionDrawingVisitor::VisitChildren( SmNode* pNode )
1921 SmNodeIterator it( pNode );
1922 while( it.Next( ) )
1923 it->Accept( this );
1926 void SmSelectionDrawingVisitor::Visit( SmTextNode* pNode )
1928 if( pNode->IsSelected( ) ){
1929 rDev.Push( PushFlags::TEXTCOLOR | PushFlags::FONT );
1931 rDev.SetFont( pNode->GetFont( ) );
1932 Point Position = pNode->GetTopLeft( );
1933 long left = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionStart( ) );
1934 long right = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionEnd( ) );
1935 long top = Position.getY( );
1936 long bottom = top + pNode->GetHeight( );
1937 Rectangle rect( left, top, right, bottom );
1939 ExtendSelectionArea( rect );
1941 rDev.Pop( );
1945 // SmNodeToTextVisitor
1947 SmNodeToTextVisitor::SmNodeToTextVisitor( SmNode* pNode, OUString &rText )
1949 pNode->Accept( this );
1950 rText = aCmdText.makeStringAndClear();
1953 void SmNodeToTextVisitor::Visit( SmTableNode* pNode )
1955 if( pNode->GetToken( ).eType == TBINOM ) {
1956 Append( "{ binom" );
1957 LineToText( pNode->GetSubNode( 0 ) );
1958 LineToText( pNode->GetSubNode( 1 ) );
1959 Append("} ");
1960 } else if( pNode->GetToken( ).eType == TSTACK ) {
1961 Append( "stack{ " );
1962 SmNodeIterator it( pNode );
1963 it.Next( );
1964 while( true ) {
1965 LineToText( it.Current( ) );
1966 if( it.Next( ) ) {
1967 Separate( );
1968 Append( "# " );
1969 }else
1970 break;
1972 Separate( );
1973 Append( "}" );
1974 } else { //Assume it's a toplevel table, containing lines
1975 SmNodeIterator it( pNode );
1976 it.Next( );
1977 while( true ) {
1978 Separate( );
1979 it->Accept( this );
1980 if( it.Next( ) ) {
1981 Separate( );
1982 Append( "newline" );
1983 }else
1984 break;
1989 void SmNodeToTextVisitor::Visit( SmBraceNode* pNode )
1991 SmNode *pLeftBrace = pNode->GetSubNode( 0 ),
1992 *pBody = pNode->GetSubNode( 1 ),
1993 *pRightBrace = pNode->GetSubNode( 2 );
1994 //Handle special case where it's absolute function
1995 if( pNode->GetToken( ).eType == TABS ) {
1996 Append( "abs" );
1997 LineToText( pBody );
1998 } else {
1999 if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
2000 Append( "left " );
2001 pLeftBrace->Accept( this );
2002 Separate( );
2003 pBody->Accept( this );
2004 Separate( );
2005 if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
2006 Append( "right " );
2007 pRightBrace->Accept( this );
2011 void SmNodeToTextVisitor::Visit( SmBracebodyNode* pNode )
2013 SmNodeIterator it( pNode );
2014 while( it.Next( ) ){
2015 Separate( );
2016 it->Accept( this );
2020 void SmNodeToTextVisitor::Visit( SmOperNode* pNode )
2022 Append( pNode->GetToken( ).aText );
2023 Separate( );
2024 if( pNode->GetToken( ).eType == TOPER ){
2025 //There's an SmGlyphSpecialNode if eType == TOPER
2026 if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP )
2027 Append( pNode->GetSubNode( 0 )->GetSubNode( 0 )->GetToken( ).aText );
2028 else
2029 Append( pNode->GetSubNode( 0 )->GetToken( ).aText );
2031 if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP ) {
2032 SmSubSupNode *pSubSup = static_cast<SmSubSupNode*>( pNode->GetSubNode( 0 ) );
2033 SmNode* pChild;
2034 if( ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
2035 Separate( );
2036 Append( "lsup { " );
2037 LineToText( pChild );
2038 Append( "} " );
2040 if( ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
2041 Separate( );
2042 Append( "lsub { " );
2043 LineToText( pChild );
2044 Append( "} " );
2046 if( ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
2047 Separate( );
2048 Append( "^ { " );
2049 LineToText( pChild );
2050 Append( "} " );
2052 if( ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
2053 Separate( );
2054 Append( "_ { " );
2055 LineToText( pChild );
2056 Append( "} " );
2058 if( ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {
2059 Separate( );
2060 if (pSubSup->IsUseLimits())
2061 Append( "to { " );
2062 else
2063 Append( "csup { " );
2064 LineToText( pChild );
2065 Append( "} " );
2067 if( ( pChild = pSubSup->GetSubSup( CSUB ) ) ) {
2068 Separate( );
2069 if (pSubSup->IsUseLimits())
2070 Append( "from { " );
2071 else
2072 Append( "csub { " );
2073 LineToText( pChild );
2074 Append( "} " );
2077 LineToText( pNode->GetSubNode( 1 ) );
2080 void SmNodeToTextVisitor::Visit( SmAlignNode* pNode )
2082 Append( pNode->GetToken( ).aText );
2083 LineToText( pNode->GetSubNode( 0 ) );
2086 void SmNodeToTextVisitor::Visit( SmAttributNode* pNode )
2088 Append( pNode->GetToken( ).aText );
2089 LineToText( pNode->GetSubNode( 1 ) );
2092 void SmNodeToTextVisitor::Visit( SmFontNode* pNode )
2094 switch ( pNode->GetToken( ).eType )
2096 case TBOLD:
2097 Append( "bold " );
2098 break;
2099 case TNBOLD:
2100 Append( "nbold " );
2101 break;
2102 case TITALIC:
2103 Append( "italic " );
2104 break;
2105 case TNITALIC:
2106 Append( "nitalic " );
2107 break;
2108 case TPHANTOM:
2109 Append( "phantom " );
2110 break;
2111 case TSIZE:
2113 Append( "size " );
2114 switch ( pNode->GetSizeType( ) )
2116 case FontSizeType::PLUS:
2117 Append( "+" );
2118 break;
2119 case FontSizeType::MINUS:
2120 Append( "-" );
2121 break;
2122 case FontSizeType::MULTIPLY:
2123 Append( "*" );
2124 break;
2125 case FontSizeType::DIVIDE:
2126 Append( "/" );
2127 break;
2128 case FontSizeType::ABSOLUT:
2129 default:
2130 break;
2132 Append( ::rtl::math::doubleToUString(
2133 static_cast<double>( pNode->GetSizeParameter( ) ),
2134 rtl_math_StringFormat_Automatic,
2135 rtl_math_DecimalPlaces_Max, '.', true ) );
2136 Append( " " );
2138 break;
2139 case TBLACK:
2140 Append( "color black " );
2141 break;
2142 case TWHITE:
2143 Append( "color white " );
2144 break;
2145 case TRED:
2146 Append( "color red " );
2147 break;
2148 case TGREEN:
2149 Append( "color green " );
2150 break;
2151 case TBLUE:
2152 Append( "color blue " );
2153 break;
2154 case TCYAN:
2155 Append( "color cyan " );
2156 break;
2157 case TMAGENTA:
2158 Append( "color magenta " );
2159 break;
2160 case TYELLOW:
2161 Append( "color yellow " );
2162 break;
2163 case TSANS:
2164 Append( "font sans " );
2165 break;
2166 case TSERIF:
2167 Append( "font serif " );
2168 break;
2169 case TFIXED:
2170 Append( "font fixed " );
2171 break;
2172 default:
2173 break;
2175 LineToText( pNode->GetSubNode( 1 ) );
2178 void SmNodeToTextVisitor::Visit( SmUnHorNode* pNode )
2180 SmNodeIterator it( pNode, pNode->GetSubNode( 1 )->GetToken( ).eType == TFACT );
2181 while( it.Next( ) ) {
2182 Separate( );
2183 it->Accept( this );
2187 void SmNodeToTextVisitor::Visit( SmBinHorNode* pNode )
2189 SmNode *pLeft = pNode->GetSubNode( 0 ),
2190 *pOper = pNode->GetSubNode( 1 ),
2191 *pRight = pNode->GetSubNode( 2 );
2192 Separate( );
2193 pLeft->Accept( this );
2194 Separate( );
2195 pOper->Accept( this );
2196 Separate( );
2197 pRight->Accept( this );
2198 Separate( );
2201 void SmNodeToTextVisitor::Visit( SmBinVerNode* pNode )
2203 SmNode *pNum = pNode->GetSubNode( 0 ),
2204 *pDenom = pNode->GetSubNode( 2 );
2205 Append( "{ " );
2206 LineToText( pNum );
2207 Append( "over" );
2208 LineToText( pDenom );
2209 Append( "} " );
2212 void SmNodeToTextVisitor::Visit( SmBinDiagonalNode* pNode )
2214 SmNode *pLeftOperand = pNode->GetSubNode( 0 ),
2215 *pRightOperand = pNode->GetSubNode( 1 );
2216 Append( "{ " );
2217 LineToText( pLeftOperand );
2218 Separate( );
2219 Append( "wideslash " );
2220 LineToText( pRightOperand );
2221 Append( "} " );
2224 void SmNodeToTextVisitor::Visit( SmSubSupNode* pNode )
2226 LineToText( pNode->GetBody( ) );
2227 SmNode *pChild;
2228 if( ( pChild = pNode->GetSubSup( LSUP ) ) ) {
2229 Separate( );
2230 Append( "lsup " );
2231 LineToText( pChild );
2233 if( ( pChild = pNode->GetSubSup( LSUB ) ) ) {
2234 Separate( );
2235 Append( "lsub " );
2236 LineToText( pChild );
2238 if( ( pChild = pNode->GetSubSup( RSUP ) ) ) {
2239 Separate( );
2240 Append( "^ " );
2241 LineToText( pChild );
2243 if( ( pChild = pNode->GetSubSup( RSUB ) ) ) {
2244 Separate( );
2245 Append( "_ " );
2246 LineToText( pChild );
2248 if( ( pChild = pNode->GetSubSup( CSUP ) ) ) {
2249 Separate( );
2250 if (pNode->IsUseLimits())
2251 Append( "to " );
2252 else
2253 Append( "csup " );
2254 LineToText( pChild );
2256 if( ( pChild = pNode->GetSubSup( CSUB ) ) ) {
2257 Separate( );
2258 if (pNode->IsUseLimits())
2259 Append( "from " );
2260 else
2261 Append( "csub " );
2262 LineToText( pChild );
2266 void SmNodeToTextVisitor::Visit( SmMatrixNode* pNode )
2268 Append( "matrix{" );
2269 for ( sal_uInt16 i = 0; i < pNode->GetNumRows( ); i++ ) {
2270 for ( sal_uInt16 j = 0; j < pNode->GetNumCols( ); j++ ) {
2271 SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
2272 Separate( );
2273 pSubNode->Accept( this );
2274 Separate( );
2275 if( j != pNode->GetNumCols( ) - 1 )
2276 Append( "#" );
2278 Separate( );
2279 if( i != pNode->GetNumRows( ) - 1 )
2280 Append( "##" );
2282 Append( "} " );
2285 void SmNodeToTextVisitor::Visit( SmPlaceNode* )
2287 Append( "<?>" );
2290 void SmNodeToTextVisitor::Visit( SmTextNode* pNode )
2292 //TODO: This method might need improvements, see SmTextNode::CreateTextFromNode
2293 if( pNode->GetToken( ).eType == TTEXT )
2294 Append( "\"" );
2295 Append( pNode->GetText( ) );
2296 if( pNode->GetToken( ).eType == TTEXT )
2297 Append( "\"" );
2300 void SmNodeToTextVisitor::Visit( SmSpecialNode* pNode )
2302 Append( pNode->GetToken( ).aText );
2305 void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode* pNode )
2307 if( pNode->GetToken( ).eType == TBOPER )
2308 Append( "boper " );
2309 else
2310 Append( "uoper " );
2311 Append( pNode->GetToken( ).aText );
2314 void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
2316 Append( pNode->GetToken( ).aText );
2319 void SmNodeToTextVisitor::Visit( SmBlankNode* pNode )
2321 Append( pNode->GetToken( ).aText );
2324 void SmNodeToTextVisitor::Visit( SmErrorNode* )
2328 void SmNodeToTextVisitor::Visit( SmLineNode* pNode )
2330 SmNodeIterator it( pNode );
2331 while( it.Next( ) ){
2332 Separate( );
2333 it->Accept( this );
2337 void SmNodeToTextVisitor::Visit( SmExpressionNode* pNode )
2339 bool bracketsNeeded = pNode->GetNumSubNodes() != 1 || pNode->GetSubNode(0)->GetType() == NBINHOR;
2340 if (!bracketsNeeded)
2342 const SmNode *pParent = pNode->GetParent();
2343 // nested subsups
2344 bracketsNeeded =
2345 pParent && pParent->GetType() == NSUBSUP &&
2346 pNode->GetNumSubNodes() == 1 &&
2347 pNode->GetSubNode(0)->GetType() == NSUBSUP;
2350 if (bracketsNeeded) {
2351 Append( "{ " );
2353 SmNodeIterator it( pNode );
2354 while( it.Next( ) ) {
2355 it->Accept( this );
2356 Separate( );
2358 if (bracketsNeeded) {
2359 Append( "} " );
2363 void SmNodeToTextVisitor::Visit( SmPolyLineNode* )
2367 void SmNodeToTextVisitor::Visit( SmRootNode* pNode )
2369 SmNode *pExtra = pNode->GetSubNode( 0 ),
2370 *pBody = pNode->GetSubNode( 2 );
2371 if( pExtra ) {
2372 Append( "nroot" );
2373 LineToText( pExtra );
2374 } else
2375 Append( "sqrt" );
2376 LineToText( pBody );
2379 void SmNodeToTextVisitor::Visit( SmRootSymbolNode* )
2383 void SmNodeToTextVisitor::Visit( SmDynIntegralNode* pNode )
2385 SmNode *pBody = pNode->Body();
2386 Append( "intd" );
2387 LineToText( pBody );
2390 void SmNodeToTextVisitor::Visit( SmDynIntegralSymbolNode* )
2394 void SmNodeToTextVisitor::Visit( SmRectangleNode* )
2398 void SmNodeToTextVisitor::Visit( SmVerticalBraceNode* pNode )
2400 SmNode *pBody = pNode->GetSubNode( 0 ),
2401 *pScript = pNode->GetSubNode( 2 );
2402 LineToText( pBody );
2403 Append( pNode->GetToken( ).aText );
2404 LineToText( pScript );
2407 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */