bump product version to 4.1.6.2
[LibreOffice.git] / starmath / source / visitors.cxx
blobfc0ffc80cc7a6b6277663b341524411c2c8895a3
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 */
9 #include "visitors.hxx"
10 #include "cursor.hxx"
12 ///////////////////////////////////// SmVisitorTest /////////////////////////////////////
14 void SmVisitorTest::Visit( SmTableNode* pNode )
16 OSL_ENSURE( pNode->GetType( ) == NTABLE, "the visitor-patterns isn't implemented correctly" );
17 VisitChildren( pNode );
20 void SmVisitorTest::Visit( SmBraceNode* pNode )
22 OSL_ENSURE( pNode->GetType( ) == NBRACE, "the visitor-patterns isn't implemented correctly" );
23 VisitChildren( pNode );
26 void SmVisitorTest::Visit( SmBracebodyNode* pNode )
28 OSL_ENSURE( pNode->GetType( ) == NBRACEBODY, "the visitor-patterns isn't implemented correctly" );
29 VisitChildren( pNode );
32 void SmVisitorTest::Visit( SmOperNode* pNode )
34 OSL_ENSURE( pNode->GetType( ) == NOPER, "the visitor-patterns isn't implemented correctly" );
35 VisitChildren( pNode );
38 void SmVisitorTest::Visit( SmAlignNode* pNode )
40 OSL_ENSURE( pNode->GetType( ) == NALIGN, "the visitor-patterns isn't implemented correctly" );
41 VisitChildren( pNode );
44 void SmVisitorTest::Visit( SmAttributNode* pNode )
46 OSL_ENSURE( pNode->GetType( ) == NATTRIBUT, "the visitor-patterns isn't implemented correctly" );
47 VisitChildren( pNode );
50 void SmVisitorTest::Visit( SmFontNode* pNode )
52 OSL_ENSURE( pNode->GetType( ) == NFONT, "the visitor-patterns isn't implemented correctly" );
53 VisitChildren( pNode );
56 void SmVisitorTest::Visit( SmUnHorNode* pNode )
58 OSL_ENSURE( pNode->GetType( ) == NUNHOR, "the visitor-patterns isn't implemented correctly" );
59 VisitChildren( pNode );
62 void SmVisitorTest::Visit( SmBinHorNode* pNode )
64 OSL_ENSURE( pNode->GetType( ) == NBINHOR, "the visitor-patterns isn't implemented correctly" );
65 VisitChildren( pNode );
68 void SmVisitorTest::Visit( SmBinVerNode* pNode )
70 OSL_ENSURE( pNode->GetType( ) == NBINVER, "the visitor-patterns isn't implemented correctly" );
71 VisitChildren( pNode );
74 void SmVisitorTest::Visit( SmBinDiagonalNode* pNode )
76 OSL_ENSURE( pNode->GetType( ) == NBINDIAGONAL, "the visitor-patterns isn't implemented correctly" );
77 VisitChildren( pNode );
80 void SmVisitorTest::Visit( SmSubSupNode* pNode )
82 OSL_ENSURE( pNode->GetType( ) == NSUBSUP, "the visitor-patterns isn't implemented correctly" );
83 VisitChildren( pNode );
86 void SmVisitorTest::Visit( SmMatrixNode* pNode )
88 OSL_ENSURE( pNode->GetType( ) == NMATRIX, "the visitor-patterns isn't implemented correctly" );
89 VisitChildren( pNode );
92 void SmVisitorTest::Visit( SmPlaceNode* pNode )
94 OSL_ENSURE( pNode->GetType( ) == NPLACE, "the visitor-patterns isn't implemented correctly" );
95 VisitChildren( pNode );
98 void SmVisitorTest::Visit( SmTextNode* pNode )
100 OSL_ENSURE( pNode->GetType( ) == NTEXT, "the visitor-patterns isn't implemented correctly" );
101 VisitChildren( pNode );
104 void SmVisitorTest::Visit( SmSpecialNode* pNode )
106 OSL_ENSURE( pNode->GetType( ) == NSPECIAL, "the visitor-patterns isn't implemented correctly" );
107 VisitChildren( pNode );
110 void SmVisitorTest::Visit( SmGlyphSpecialNode* pNode )
112 OSL_ENSURE( pNode->GetType( ) == NGLYPH_SPECIAL, "the visitor-patterns isn't implemented correctly" );
113 VisitChildren( pNode );
116 void SmVisitorTest::Visit( SmMathSymbolNode* pNode )
118 OSL_ENSURE( pNode->GetType( ) == NMATH, "the visitor-patterns isn't implemented correctly" );
119 VisitChildren( pNode );
122 void SmVisitorTest::Visit( SmBlankNode* pNode )
124 OSL_ENSURE( pNode->GetType( ) == NBLANK, "the visitor-patterns isn't implemented correctly" );
125 VisitChildren( pNode );
128 void SmVisitorTest::Visit( SmErrorNode* pNode )
130 OSL_ENSURE( pNode->GetType( ) == NERROR, "the visitor-patterns isn't implemented correctly" );
131 VisitChildren( pNode );
134 void SmVisitorTest::Visit( SmLineNode* pNode )
136 OSL_ENSURE( pNode->GetType( ) == NLINE, "the visitor-patterns isn't implemented correctly" );
137 VisitChildren( pNode );
140 void SmVisitorTest::Visit( SmExpressionNode* pNode )
142 OSL_ENSURE( pNode->GetType( ) == NEXPRESSION, "the visitor-patterns isn't implemented correctly" );
143 VisitChildren( pNode );
146 void SmVisitorTest::Visit( SmPolyLineNode* pNode )
148 OSL_ENSURE( pNode->GetType( ) == NPOLYLINE, "the visitor-patterns isn't implemented correctly" );
149 VisitChildren( pNode );
152 void SmVisitorTest::Visit( SmRootNode* pNode )
154 OSL_ENSURE( pNode->GetType( ) == NROOT, "the visitor-patterns isn't implemented correctly" );
155 VisitChildren( pNode );
158 void SmVisitorTest::Visit( SmRootSymbolNode* pNode )
160 OSL_ENSURE( pNode->GetType( ) == NROOTSYMBOL, "the visitor-patterns isn't implemented correctly" );
161 VisitChildren( pNode );
164 void SmVisitorTest::Visit( SmRectangleNode* pNode )
166 OSL_ENSURE( pNode->GetType( ) == NRECTANGLE, "the visitor-patterns isn't implemented correctly" );
167 VisitChildren( pNode );
170 void SmVisitorTest::Visit( SmVerticalBraceNode* pNode )
172 OSL_ENSURE( pNode->GetType( ) == NVERTICAL_BRACE, "the visitor-patterns isn't implemented correctly" );
173 VisitChildren( pNode );
176 void SmVisitorTest::VisitChildren( SmNode* pNode )
178 SmNodeIterator it( pNode );
179 while( it.Next( ) )
180 it->Accept( this );
183 /////////////////////////////// SmDefaultingVisitor ////////////////////////////////
185 void SmDefaultingVisitor::Visit( SmTableNode* pNode )
187 DefaultVisit( pNode );
190 void SmDefaultingVisitor::Visit( SmBraceNode* pNode )
192 DefaultVisit( pNode );
195 void SmDefaultingVisitor::Visit( SmBracebodyNode* pNode )
197 DefaultVisit( pNode );
200 void SmDefaultingVisitor::Visit( SmOperNode* pNode )
202 DefaultVisit( pNode );
205 void SmDefaultingVisitor::Visit( SmAlignNode* pNode )
207 DefaultVisit( pNode );
210 void SmDefaultingVisitor::Visit( SmAttributNode* pNode )
212 DefaultVisit( pNode );
215 void SmDefaultingVisitor::Visit( SmFontNode* pNode )
217 DefaultVisit( pNode );
220 void SmDefaultingVisitor::Visit( SmUnHorNode* pNode )
222 DefaultVisit( pNode );
225 void SmDefaultingVisitor::Visit( SmBinHorNode* pNode )
227 DefaultVisit( pNode );
230 void SmDefaultingVisitor::Visit( SmBinVerNode* pNode )
232 DefaultVisit( pNode );
235 void SmDefaultingVisitor::Visit( SmBinDiagonalNode* pNode )
237 DefaultVisit( pNode );
240 void SmDefaultingVisitor::Visit( SmSubSupNode* pNode )
242 DefaultVisit( pNode );
245 void SmDefaultingVisitor::Visit( SmMatrixNode* pNode )
247 DefaultVisit( pNode );
250 void SmDefaultingVisitor::Visit( SmPlaceNode* pNode )
252 DefaultVisit( pNode );
255 void SmDefaultingVisitor::Visit( SmTextNode* pNode )
257 DefaultVisit( pNode );
260 void SmDefaultingVisitor::Visit( SmSpecialNode* pNode )
262 DefaultVisit( pNode );
265 void SmDefaultingVisitor::Visit( SmGlyphSpecialNode* pNode )
267 DefaultVisit( pNode );
270 void SmDefaultingVisitor::Visit( SmMathSymbolNode* pNode )
272 DefaultVisit( pNode );
275 void SmDefaultingVisitor::Visit( SmBlankNode* pNode )
277 DefaultVisit( pNode );
280 void SmDefaultingVisitor::Visit( SmErrorNode* pNode )
282 DefaultVisit( pNode );
285 void SmDefaultingVisitor::Visit( SmLineNode* pNode )
287 DefaultVisit( pNode );
290 void SmDefaultingVisitor::Visit( SmExpressionNode* pNode )
292 DefaultVisit( pNode );
295 void SmDefaultingVisitor::Visit( SmPolyLineNode* pNode )
297 DefaultVisit( pNode );
300 void SmDefaultingVisitor::Visit( SmRootNode* pNode )
302 DefaultVisit( pNode );
305 void SmDefaultingVisitor::Visit( SmRootSymbolNode* pNode )
307 DefaultVisit( pNode );
310 void SmDefaultingVisitor::Visit( SmRectangleNode* pNode )
312 DefaultVisit( pNode );
315 void SmDefaultingVisitor::Visit( SmVerticalBraceNode* pNode )
317 DefaultVisit( pNode );
320 /////////////////////////////// SmCaretDrawingVisitor ////////////////////////////////
322 SmCaretDrawingVisitor::SmCaretDrawingVisitor( OutputDevice& rDevice,
323 SmCaretPos position,
324 Point offset,
325 bool caretVisible )
326 : rDev( rDevice )
328 pos = position;
329 Offset = offset;
330 isCaretVisible = caretVisible;
331 OSL_ENSURE( position.IsValid( ), "Cannot draw invalid position!" );
332 if( !position.IsValid( ) )
333 return;
335 //Save device state
336 rDev.Push( PUSH_FONT | PUSH_MAPMODE | PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR );
338 pos.pSelectedNode->Accept( this );
339 //Restore device state
340 rDev.Pop( );
343 void SmCaretDrawingVisitor::Visit( SmTextNode* pNode )
345 long i = pos.Index;
347 rDev.SetFont( pNode->GetFont( ) );
349 //Find the line
350 SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
352 //Find coordinates
353 long left = pNode->GetLeft( ) + rDev.GetTextWidth( pNode->GetText( ), 0, i ) + Offset.X( );
354 long top = pLine->GetTop( ) + Offset.Y( );
355 long height = pLine->GetHeight( );
356 long left_line = pLine->GetLeft( ) + Offset.X( );
357 long right_line = pLine->GetRight( ) + Offset.X( );
359 //Set color
360 rDev.SetLineColor( Color( COL_BLACK ) );
362 if ( isCaretVisible ) {
363 //Draw vertical line
364 Point p1( left, top );
365 Point p2( left, top + height );
366 rDev.DrawLine( p1, p2 );
369 //Underline the line
370 Point pLeft( left_line, top + height );
371 Point pRight( right_line, top + height );
372 rDev.DrawLine( pLeft, pRight );
375 void SmCaretDrawingVisitor::DefaultVisit( SmNode* pNode )
377 rDev.SetLineColor( Color( COL_BLACK ) );
379 //Find the line
380 SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
382 //Find coordinates
383 long left = pNode->GetLeft( ) + Offset.X( ) + ( pos.Index == 1 ? pNode->GetWidth( ) : 0 );
384 long top = pLine->GetTop( ) + Offset.Y( );
385 long height = pLine->GetHeight( );
386 long left_line = pLine->GetLeft( ) + Offset.X( );
387 long right_line = pLine->GetRight( ) + Offset.X( );
389 //Set color
390 rDev.SetLineColor( Color( COL_BLACK ) );
392 if ( isCaretVisible ) {
393 //Draw vertical line
394 Point p1( left, top );
395 Point p2( left, top + height );
396 rDev.DrawLine( p1, p2 );
399 //Underline the line
400 Point pLeft( left_line, top + height );
401 Point pRight( right_line, top + height );
402 rDev.DrawLine( pLeft, pRight );
405 /////////////////////////////// SmCaretPos2LineVisitor ////////////////////////////////
407 void SmCaretPos2LineVisitor::Visit( SmTextNode* pNode )
409 //Save device state
410 pDev->Push( PUSH_FONT | PUSH_TEXTCOLOR );
412 long i = pos.Index;
414 pDev->SetFont( pNode->GetFont( ) );
416 //Find coordinates
417 long left = pNode->GetLeft( ) + pDev->GetTextWidth( pNode->GetText( ), 0, i );
418 long top = pNode->GetTop( );
419 long height = pNode->GetHeight( );
421 line = SmCaretLine( left, top, height );
423 //Restore device state
424 pDev->Pop( );
427 void SmCaretPos2LineVisitor::DefaultVisit( SmNode* pNode )
429 //Vertical line ( code from SmCaretDrawingVisitor )
430 Point p1 = pNode->GetTopLeft( );
431 if( pos.Index == 1 )
432 p1.Move( pNode->GetWidth( ), 0 );
434 line = SmCaretLine( p1.X( ), p1.Y( ), pNode->GetHeight( ) );
437 /////////////////////////////// Nasty temporary device!!! ////////////////////////////////
439 #include <tools/gen.hxx>
440 #include <tools/fract.hxx>
441 #include <rtl/math.hxx>
442 #include <tools/color.hxx>
443 #include <vcl/metric.hxx>
444 #include <vcl/lineinfo.hxx>
445 #include <vcl/outdev.hxx>
446 #include <sfx2/module.hxx>
447 #include "symbol.hxx"
448 #include "smmod.hxx"
450 class SmTmpDevice2
452 OutputDevice &rOutDev;
454 // disallow use of copy-constructor and assignment-operator
455 SmTmpDevice2( const SmTmpDevice2 &rTmpDev );
456 SmTmpDevice2 & operator = ( const SmTmpDevice2 &rTmpDev );
458 Color Impl_GetColor( const Color& rColor );
460 public:
461 SmTmpDevice2( OutputDevice &rTheDev, bool bUseMap100th_mm );
462 ~SmTmpDevice2( ) { rOutDev.Pop( ); }
464 void SetFont( const Font &rNewFont );
466 void SetLineColor( const Color& rColor ) { rOutDev.SetLineColor( Impl_GetColor( rColor ) ); }
467 void SetFillColor( const Color& rColor ) { rOutDev.SetFillColor( Impl_GetColor( rColor ) ); }
468 void SetTextColor( const Color& rColor ) { rOutDev.SetTextColor( Impl_GetColor( rColor ) ); }
470 operator OutputDevice & ( ) const { return rOutDev; }
473 SmTmpDevice2::SmTmpDevice2( OutputDevice &rTheDev, bool bUseMap100th_mm ) :
474 rOutDev( rTheDev )
476 rOutDev.Push( PUSH_FONT | PUSH_MAPMODE |
477 PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR );
478 if ( bUseMap100th_mm && MAP_100TH_MM != rOutDev.GetMapMode( ).GetMapUnit( ) )
480 OSL_FAIL( "incorrect MapMode?" );
481 rOutDev.SetMapMode( MAP_100TH_MM ); //format for 100% always
485 Color SmTmpDevice2::Impl_GetColor( const Color& rColor )
487 ColorData nNewCol = rColor.GetColor( );
488 if ( COL_AUTO == nNewCol )
490 if ( OUTDEV_PRINTER == rOutDev.GetOutDevType( ) )
491 nNewCol = COL_BLACK;
492 else
494 Color aBgCol( rOutDev.GetBackground( ).GetColor( ) );
495 if ( OUTDEV_WINDOW == rOutDev.GetOutDevType( ) )
496 aBgCol = ( ( Window & ) rOutDev ).GetDisplayBackground( ).GetColor( );
498 nNewCol = SM_MOD( )->GetColorConfig( ).GetColorValue( svtools::FONTCOLOR ).nColor;
500 Color aTmpColor( nNewCol );
501 if ( aBgCol.IsDark( ) && aTmpColor.IsDark( ) )
502 nNewCol = COL_WHITE;
503 else if ( aBgCol.IsBright( ) && aTmpColor.IsBright( ) )
504 nNewCol = COL_BLACK;
507 return Color( nNewCol );
510 void SmTmpDevice2::SetFont( const Font &rNewFont )
512 rOutDev.SetFont( rNewFont );
513 rOutDev.SetTextColor( Impl_GetColor( rNewFont.GetColor( ) ) );
516 /////////////////////////////// SmDrawingVisitor ////////////////////////////////
518 void SmDrawingVisitor::Visit( SmTableNode* pNode )
520 DrawChildren( pNode );
523 void SmDrawingVisitor::Visit( SmBraceNode* pNode )
525 DrawChildren( pNode );
528 void SmDrawingVisitor::Visit( SmBracebodyNode* pNode )
530 DrawChildren( pNode );
533 void SmDrawingVisitor::Visit( SmOperNode* pNode )
535 DrawChildren( pNode );
538 void SmDrawingVisitor::Visit( SmAlignNode* pNode )
540 DrawChildren( pNode );
543 void SmDrawingVisitor::Visit( SmAttributNode* pNode )
545 DrawChildren( pNode );
548 void SmDrawingVisitor::Visit( SmFontNode* pNode )
550 DrawChildren( pNode );
553 void SmDrawingVisitor::Visit( SmUnHorNode* pNode )
555 DrawChildren( pNode );
558 void SmDrawingVisitor::Visit( SmBinHorNode* pNode )
560 DrawChildren( pNode );
563 void SmDrawingVisitor::Visit( SmBinVerNode* pNode )
565 DrawChildren( pNode );
568 void SmDrawingVisitor::Visit( SmBinDiagonalNode* pNode )
570 DrawChildren( pNode );
573 void SmDrawingVisitor::Visit( SmSubSupNode* pNode )
575 DrawChildren( pNode );
578 void SmDrawingVisitor::Visit( SmMatrixNode* pNode )
580 DrawChildren( pNode );
583 void SmDrawingVisitor::Visit( SmPlaceNode* pNode )
585 DrawSpecialNode( pNode );
588 void SmDrawingVisitor::Visit( SmTextNode* pNode )
590 DrawTextNode( pNode );
593 void SmDrawingVisitor::Visit( SmSpecialNode* pNode )
595 DrawSpecialNode( pNode );
598 void SmDrawingVisitor::Visit( SmGlyphSpecialNode* pNode )
600 DrawSpecialNode( pNode );
603 void SmDrawingVisitor::Visit( SmMathSymbolNode* pNode )
605 DrawSpecialNode( pNode );
608 void SmDrawingVisitor::Visit( SmBlankNode* pNode )
610 DrawChildren( pNode );
613 void SmDrawingVisitor::Visit( SmErrorNode* pNode )
615 DrawSpecialNode( pNode );
618 void SmDrawingVisitor::Visit( SmLineNode* pNode )
620 DrawChildren( pNode );
623 void SmDrawingVisitor::Visit( SmExpressionNode* pNode )
625 DrawChildren( pNode );
628 void SmDrawingVisitor::Visit( SmRootNode* pNode )
630 DrawChildren( pNode );
633 void SmDrawingVisitor::Visit( SmVerticalBraceNode* pNode )
635 DrawChildren( pNode );
638 void SmDrawingVisitor::Visit( SmRootSymbolNode* pNode )
640 if ( pNode->IsPhantom( ) )
641 return;
643 // draw root-sign itself
644 DrawSpecialNode( pNode );
646 SmTmpDevice2 aTmpDev( ( OutputDevice & ) rDev, true );
647 aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
648 rDev.SetLineColor( );
649 aTmpDev.SetFont( pNode->GetFont( ) );
651 // since the width is always unscaled it corresponds ot the _original_
652 // _unscaled_ font height to be used, we use that to calculate the
653 // bar height. Thus it is independent of the arguments height.
654 // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
655 long nBarHeight = pNode->GetWidth( ) * 7L / 100L;
656 long nBarWidth = pNode->GetBodyWidth( ) + pNode->GetBorderWidth( );
657 Point aBarOffset( pNode->GetWidth( ), +pNode->GetBorderWidth( ) );
658 Point aBarPos( Position + aBarOffset );
660 Rectangle aBar( aBarPos, Size( nBarWidth, nBarHeight ) );
661 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
662 //! increasing zoomfactor.
663 // This is done by shifting its output-position to a point that
664 // corresponds exactly to a pixel on the output device.
665 Point aDrawPos( rDev.PixelToLogic( rDev.LogicToPixel( aBar.TopLeft( ) ) ) );
666 aBar.SetPos( aDrawPos );
668 rDev.DrawRect( aBar );
671 void SmDrawingVisitor::Visit( SmPolyLineNode* pNode )
673 if ( pNode->IsPhantom( ) )
674 return;
676 long nBorderwidth = pNode->GetFont( ).GetBorderWidth( );
678 LineInfo aInfo;
679 aInfo.SetWidth( pNode->GetWidth( ) - 2 * nBorderwidth );
681 Point aOffset ( Point( ) - pNode->GetPolygon( ).GetBoundRect( ).TopLeft( )
682 + Point( nBorderwidth, nBorderwidth ) ),
683 aPos ( Position + aOffset );
684 pNode->GetPolygon( ).Move( aPos.X( ), aPos.Y( ) ); //Works because Polygon wraps a pointer
686 SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, false );
687 aTmpDev.SetLineColor( pNode->GetFont( ).GetColor( ) );
689 rDev.DrawPolyLine( pNode->GetPolygon( ), aInfo );
692 void SmDrawingVisitor::Visit( SmRectangleNode* pNode )
694 if ( pNode->IsPhantom( ) )
695 return;
697 SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, false );
698 aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
699 rDev.SetLineColor( );
700 aTmpDev.SetFont( pNode->GetFont( ) );
702 sal_uLong nTmpBorderWidth = pNode->GetFont( ).GetBorderWidth( );
704 // get rectangle and remove borderspace
705 Rectangle aTmp ( pNode->AsRectangle( ) + Position - pNode->GetTopLeft( ) );
706 aTmp.Left( ) += nTmpBorderWidth;
707 aTmp.Right( ) -= nTmpBorderWidth;
708 aTmp.Top( ) += nTmpBorderWidth;
709 aTmp.Bottom( ) -= nTmpBorderWidth;
711 OSL_ENSURE( aTmp.GetHeight( ) > 0 && aTmp.GetWidth( ) > 0,
712 "Sm: leeres Rechteck" );
714 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
715 //! increasing zoomfactor.
716 // This is done by shifting its output-position to a point that
717 // corresponds exactly to a pixel on the output device.
718 Point aPos ( rDev.PixelToLogic( rDev.LogicToPixel( aTmp.TopLeft( ) ) ) );
719 aTmp.SetPos( aPos );
721 rDev.DrawRect( aTmp );
724 void SmDrawingVisitor::DrawTextNode( SmTextNode* pNode )
726 if ( pNode->IsPhantom() || pNode->GetText().isEmpty() || pNode->GetText()[0] == '\0' )
727 return;
729 SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, false );
730 aTmpDev.SetFont( pNode->GetFont( ) );
732 Point aPos ( Position );
733 aPos.Y( ) += pNode->GetBaselineOffset( );
734 // auf Pixelkoordinaten runden
735 aPos = rDev.PixelToLogic( rDev.LogicToPixel( aPos ) );
737 rDev.DrawStretchText( aPos, pNode->GetWidth( ), pNode->GetText( ) );
740 void SmDrawingVisitor::DrawSpecialNode( SmSpecialNode* pNode )
742 //! since this chars might come from any font, that we may not have
743 //! set to ALIGN_BASELINE yet, we do it now.
744 pNode->GetFont( ).SetAlign( ALIGN_BASELINE );
746 DrawTextNode( pNode );
749 void SmDrawingVisitor::DrawChildren( SmNode* pNode )
751 if ( pNode->IsPhantom( ) )
752 return;
754 Point rPosition = Position;
756 SmNodeIterator it( pNode );
757 while( it.Next( ) )
759 Point aOffset ( it->GetTopLeft( ) - pNode->GetTopLeft( ) );
760 Position = rPosition + aOffset;
761 it->Accept( this );
765 /////////////////////////////// SmSetSelectionVisitor ////////////////////////////////
767 SmSetSelectionVisitor::SmSetSelectionVisitor( SmCaretPos startPos, SmCaretPos endPos, SmNode* pTree) {
768 StartPos = startPos;
769 EndPos = endPos;
770 IsSelecting = false;
772 //Assume that pTree is a SmTableNode
773 OSL_ENSURE(pTree->GetType() == NTABLE, "pTree should be a SmTableNode!");
774 //Visit root node, this is special as this node cannot be selected, but its children can!
775 if(pTree->GetType() == NTABLE){
776 //Change state if StartPos is in front of this node
777 if( StartPos.pSelectedNode == pTree && StartPos.Index == 0 )
778 IsSelecting = !IsSelecting;
779 //Change state if EndPos is in front of this node
780 if( EndPos.pSelectedNode == pTree && EndPos.Index == 0 )
781 IsSelecting = !IsSelecting;
782 OSL_ENSURE(!IsSelecting, "Caret positions needed to set IsSelecting about, shouldn't be possible!");
784 //Visit lines
785 SmNodeIterator it( pTree );
786 while( it.Next( ) ) {
787 it->Accept( this );
788 //If we started a selection in this line and it haven't ended, we do that now!
789 if(IsSelecting) {
790 IsSelecting = false;
791 SetSelectedOnAll(it.Current(), true);
792 //Set StartPos and EndPos to invalid positions, this ensures that an unused
793 //start or end (because we forced end above), doesn't start a new selection.
794 StartPos = EndPos = SmCaretPos();
797 //Check if pTree isn't selected
798 OSL_ENSURE(!pTree->IsSelected(), "pTree should never be selected!");
799 //Discard the selection if there's a bug (it's better than crashing)
800 if(pTree->IsSelected())
801 SetSelectedOnAll(pTree, false);
802 }else //This shouldn't happen, but I don't see any reason to die if it does
803 pTree->Accept(this);
806 void SmSetSelectionVisitor::SetSelectedOnAll( SmNode* pSubTree, bool IsSelected ) {
807 pSubTree->SetSelected( IsSelected );
809 //Quick BFS to set all selections
810 SmNodeIterator it( pSubTree );
811 while( it.Next( ) )
812 SetSelectedOnAll( it.Current( ), IsSelected );
815 void SmSetSelectionVisitor::DefaultVisit( SmNode* pNode ) {
816 //Change state if StartPos is in front of this node
817 if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
818 IsSelecting = !IsSelecting;
819 //Change state if EndPos is in front of this node
820 if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
821 IsSelecting = !IsSelecting;
823 //Cache current state
824 bool WasSelecting = IsSelecting;
825 bool ChangedState = false;
827 //Set selected
828 pNode->SetSelected( IsSelecting );
830 //Visit children
831 SmNodeIterator it( pNode );
832 while( it.Next( ) )
834 it->Accept( this );
835 ChangedState = ( WasSelecting != IsSelecting ) || ChangedState;
838 //If state changed
839 if( ChangedState )
841 //Select this node and all of its children
842 //(Make exception for SmBracebodyNode)
843 if( pNode->GetType() != NBRACEBODY ||
844 !pNode->GetParent() ||
845 pNode->GetParent()->GetType() != NBRACE )
846 SetSelectedOnAll( pNode, true );
847 else
848 SetSelectedOnAll( pNode->GetParent(), true );
849 /* If the equation is: sqrt{2 + 4} + 5
850 * And the selection is: sqrt{2 + [4} +] 5
851 * Where [ denotes StartPos and ] denotes EndPos
852 * Then the sqrt node should be selected, so that the
853 * effective selection is: [sqrt{2 + 4} +] 5
854 * The same is the case if we swap StartPos and EndPos.
858 //Change state if StartPos is after this node
859 if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
861 IsSelecting = !IsSelecting;
863 //Change state if EndPos is after of this node
864 if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
866 IsSelecting = !IsSelecting;
870 void SmSetSelectionVisitor::VisitCompositionNode( SmNode* pNode ) {
871 //Change state if StartPos is in front of this node
872 if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
873 IsSelecting = !IsSelecting;
874 //Change state if EndPos is in front of this node
875 if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
876 IsSelecting = !IsSelecting;
878 //Cache current state
879 bool WasSelecting = IsSelecting;
881 //Visit children
882 SmNodeIterator it( pNode );
883 while( it.Next( ) )
884 it->Accept( this );
886 //Set selected, if everything was selected
887 pNode->SetSelected( WasSelecting && IsSelecting );
889 //Change state if StartPos is after this node
890 if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
891 IsSelecting = !IsSelecting;
892 //Change state if EndPos is after of this node
893 if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
894 IsSelecting = !IsSelecting;
897 void SmSetSelectionVisitor::Visit( SmTextNode* pNode ) {
898 long i1 = -1,
899 i2 = -1;
900 if( StartPos.pSelectedNode == pNode )
901 i1 = StartPos.Index;
902 if( EndPos.pSelectedNode == pNode )
903 i2 = EndPos.Index;
905 long start, end;
906 pNode->SetSelected( true );
907 if( i1 != -1 && i2 != -1 ) {
908 start = i1 < i2 ? i1 : i2; //MIN
909 end = i1 > i2 ? i1 : i2; //MAX
910 } else if( IsSelecting && i1 != -1 ) {
911 start = 0;
912 end = i1;
913 IsSelecting = false;
914 } else if( IsSelecting && i2 != -1 ) {
915 start = 0;
916 end = i2;
917 IsSelecting = false;
918 } else if( !IsSelecting && i1 != -1 ) {
919 start = i1;
920 end = pNode->GetText().getLength();
921 IsSelecting = true;
922 } else if( !IsSelecting && i2 != -1 ) {
923 start = i2;
924 end = pNode->GetText().getLength();
925 IsSelecting = true;
926 } else if( IsSelecting ) {
927 start = 0;
928 end = pNode->GetText().getLength();
929 } else {
930 pNode->SetSelected( false );
931 start = 0;
932 end = 0;
934 pNode->SetSelected( start != end );
935 pNode->SetSelectionStart( start );
936 pNode->SetSelectionEnd( end );
939 void SmSetSelectionVisitor::Visit( SmExpressionNode* pNode ) {
940 VisitCompositionNode( pNode );
943 void SmSetSelectionVisitor::Visit( SmLineNode* pNode ) {
944 VisitCompositionNode( pNode );
947 void SmSetSelectionVisitor::Visit( SmAlignNode* pNode ) {
948 VisitCompositionNode( pNode );
951 void SmSetSelectionVisitor::Visit( SmBinHorNode* pNode ) {
952 VisitCompositionNode( pNode );
955 void SmSetSelectionVisitor::Visit( SmUnHorNode* pNode ) {
956 VisitCompositionNode( pNode );
959 void SmSetSelectionVisitor::Visit( SmFontNode* pNode ) {
960 VisitCompositionNode( pNode );
963 /////////////////////////////// SmCaretPosGraphBuildingVisitor ////////////////////////////////
965 SmCaretPosGraphBuildingVisitor::SmCaretPosGraphBuildingVisitor( SmNode* pRootNode ) {
966 pRightMost = NULL;
967 pGraph = new SmCaretPosGraph( );
968 //pRootNode should always be a table
969 OSL_ENSURE( pRootNode->GetType( ) == NTABLE, "pRootNode must be a table node");
970 //Handle the special case where NTABLE is used a rootnode
971 if( pRootNode->GetType( ) == NTABLE ){
972 //Children are SmLineNodes
973 //Or so I thought... Aparently, the children can be instances of SmExpression
974 //especially if there's a error in the formula... So he we go, a simple work around.
975 SmNodeIterator it( pRootNode );
976 while( it.Next( ) ){
977 //There's a special invariant between this method and the Visit( SmLineNode* )
978 //Usually pRightMost may not be NULL, to avoid this pRightMost should here be
979 //set to a new SmCaretPos in front of it.Current( ), however, if it.Current( ) is
980 //an instance of SmLineNode we let SmLineNode create this position in front of
981 //the visual line.
982 //The argument for doing this is that we now don't have to worry about SmLineNode
983 //being a visual line composition node. Thus, no need for yet another special case
984 //in SmCursor::IsLineCompositionNode and everywhere this method is used.
985 //if( it->GetType( ) != NLINE )
986 pRightMost = pGraph->Add( SmCaretPos( it.Current( ), 0 ) );
987 it->Accept( this );
989 }else
990 pRootNode->Accept(this);
993 void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode* pNode ){
994 SmNodeIterator it( pNode );
995 while( it.Next( ) ){
996 it->Accept( this );
1000 /** Build SmCaretPosGraph for SmTableNode
1001 * This method covers cases where SmTableNode is used in a binom or stack,
1002 * the special case where it is used as root node for the entire formula is
1003 * handled in the constructor.
1005 void SmCaretPosGraphBuildingVisitor::Visit( SmTableNode* pNode ){
1006 SmCaretPosGraphEntry *left = pRightMost,
1007 *right = pGraph->Add( SmCaretPos( pNode, 1) );
1008 bool bIsFirst = true;
1009 SmNodeIterator it( pNode );
1010 while( it.Next() ){
1011 pRightMost = pGraph->Add( SmCaretPos( it.Current(), 0 ), left);
1012 if(bIsFirst)
1013 left->SetRight(pRightMost);
1014 it->Accept( this );
1015 pRightMost->SetRight(right);
1016 if(bIsFirst)
1017 right->SetLeft(pRightMost);
1018 bIsFirst = false;
1020 pRightMost = right;
1023 /** Build SmCaretPosGraph for SmSubSupNode
1025 * The child positions in a SubSupNode, where H is the body:
1026 * \code
1027 * CSUP
1029 * LSUP H H RSUP
1030 * H H
1031 * HHHH
1032 * H H
1033 * LSUB H H RSUB
1035 * CSUB
1036 * \endcode
1038 * Graph over these, where "left" is before the SmSubSupNode and "right" is after:
1039 * \dot
1040 * digraph Graph{
1041 * left -> H;
1042 * H -> right;
1043 * LSUP -> H;
1044 * LSUB -> H;
1045 * CSUP -> right;
1046 * CSUB -> right;
1047 * RSUP -> right;
1048 * RSUB -> right;
1049 * };
1050 * \enddot
1053 void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode* pNode )
1055 SmCaretPosGraphEntry *left,
1056 *right,
1057 *bodyLeft,
1058 *bodyRight;
1060 left = pRightMost;
1061 OSL_ENSURE( pRightMost, "pRightMost shouldn't be NULL here!" );
1063 //Create bodyLeft
1064 OSL_ENSURE( pNode->GetBody( ), "SmSubSupNode Doesn't have a body!" );
1065 bodyLeft = pGraph->Add( SmCaretPos( pNode->GetBody( ), 0 ), left );
1066 left->SetRight( bodyLeft ); //TODO: Don't make this if LSUP or LSUB are NULL ( not sure??? )
1068 //Create right
1069 right = pGraph->Add( SmCaretPos( pNode, 1 ) );
1071 //Visit the body, to get bodyRight
1072 pRightMost = bodyLeft;
1073 pNode->GetBody( )->Accept( this );
1074 bodyRight = pRightMost;
1075 bodyRight->SetRight( right );
1076 right->SetLeft( bodyRight );
1078 SmNode* pChild;
1079 //If there's an LSUP
1080 if( ( pChild = pNode->GetSubSup( LSUP ) ) ){
1081 SmCaretPosGraphEntry *cLeft; //Child left
1082 cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
1084 pRightMost = cLeft;
1085 pChild->Accept( this );
1087 pRightMost->SetRight( bodyLeft );
1089 //If there's an LSUB
1090 if( ( pChild = pNode->GetSubSup( LSUB ) ) ){
1091 SmCaretPosGraphEntry *cLeft; //Child left
1092 cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
1094 pRightMost = cLeft;
1095 pChild->Accept( this );
1097 pRightMost->SetRight( bodyLeft );
1099 //If there's an CSUP
1100 if( ( pChild = pNode->GetSubSup( CSUP ) ) ){
1101 SmCaretPosGraphEntry *cLeft; //Child left
1102 cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
1104 pRightMost = cLeft;
1105 pChild->Accept( this );
1107 pRightMost->SetRight( right );
1109 //If there's an CSUB
1110 if( ( pChild = pNode->GetSubSup( CSUB ) ) ){
1111 SmCaretPosGraphEntry *cLeft; //Child left
1112 cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
1114 pRightMost = cLeft;
1115 pChild->Accept( this );
1117 pRightMost->SetRight( right );
1119 //If there's an RSUP
1120 if( ( pChild = pNode->GetSubSup( RSUP ) ) ){
1121 SmCaretPosGraphEntry *cLeft; //Child left
1122 cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
1124 pRightMost = cLeft;
1125 pChild->Accept( this );
1127 pRightMost->SetRight( right );
1129 //If there's an RSUB
1130 if( ( pChild = pNode->GetSubSup( RSUB ) ) ){
1131 SmCaretPosGraphEntry *cLeft; //Child left
1132 cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
1134 pRightMost = cLeft;
1135 pChild->Accept( this );
1137 pRightMost->SetRight( right );
1140 //Set return parameters
1141 pRightMost = right;
1144 /** Build caret position for SmOperNode
1146 * If first child is an SmSubSupNode we will ignore its
1147 * body, as this body is a SmMathSymbol, for SUM, INT or similar
1148 * that shouldn't be subject to modification.
1149 * If first child is not a SmSubSupNode, ignore it completely
1150 * as it is a SmMathSymbol.
1152 * The child positions in a SmOperNode, where H is symbol, e.g. int, sum or similar:
1153 * \code
1154 * TO
1156 * LSUP H H RSUP BBB BB BBB B B
1157 * H H B B B B B B B B
1158 * HHHH BBB B B B B B
1159 * H H B B B B B B B
1160 * LSUB H H RSUB BBB BB BBB B
1162 * FROM
1163 * \endcode
1164 * Notice, CSUP, etc. are actually granchildren, but inorder to ignore H, these are visited
1165 * from here. If they are present, that is if pOper is an instance of SmSubSupNode.
1167 * Graph over these, where "left" is before the SmOperNode and "right" is after:
1168 * \dot
1169 * digraph Graph{
1170 * left -> BODY;
1171 * BODY -> right;
1172 * LSUP -> BODY;
1173 * LSUB -> BODY;
1174 * TO -> BODY;
1175 * FROM -> BODY;
1176 * RSUP -> BODY;
1177 * RSUB -> BODY;
1178 * };
1179 * \enddot
1181 void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode* pNode )
1183 SmNode *pOper = pNode->GetSubNode( 0 ),
1184 *pBody = pNode->GetSubNode( 1 );
1186 SmCaretPosGraphEntry *left = pRightMost,
1187 *bodyLeft,
1188 *bodyRight,
1189 *right;
1190 //Create body left
1191 bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
1192 left->SetRight( bodyLeft );
1194 //Visit body, get bodyRight
1195 pRightMost = bodyLeft;
1196 pBody->Accept( this );
1197 bodyRight = pRightMost;
1199 //Create right
1200 right = pGraph->Add( SmCaretPos( pNode, 1 ), bodyRight );
1201 bodyRight->SetRight( right );
1203 //Get subsup pNode if any
1204 SmSubSupNode* pSubSup = pOper->GetType( ) == NSUBSUP ? ( SmSubSupNode* )pOper : NULL;
1206 SmNode* pChild;
1207 SmCaretPosGraphEntry *childLeft;
1208 if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
1209 //Create position in front of pChild
1210 childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
1211 //Visit pChild
1212 pRightMost = childLeft;
1213 pChild->Accept( this );
1214 //Set right on pRightMost from pChild
1215 pRightMost->SetRight( bodyLeft );
1217 if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
1218 //Create position in front of pChild
1219 childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
1220 //Visit pChild
1221 pRightMost = childLeft;
1222 pChild->Accept( this );
1223 //Set right on pRightMost from pChild
1224 pRightMost->SetRight( bodyLeft );
1226 if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {//TO
1227 //Create position in front of pChild
1228 childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
1229 //Visit pChild
1230 pRightMost = childLeft;
1231 pChild->Accept( this );
1232 //Set right on pRightMost from pChild
1233 pRightMost->SetRight( bodyLeft );
1235 if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUB ) ) ) { //FROM
1236 //Create position in front of pChild
1237 childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
1238 //Visit pChild
1239 pRightMost = childLeft;
1240 pChild->Accept( this );
1241 //Set right on pRightMost from pChild
1242 pRightMost->SetRight( bodyLeft );
1244 if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
1245 //Create position in front of pChild
1246 childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
1247 //Visit pChild
1248 pRightMost = childLeft;
1249 pChild->Accept( this );
1250 //Set right on pRightMost from pChild
1251 pRightMost->SetRight( bodyLeft );
1253 if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
1254 //Create position in front of pChild
1255 childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
1256 //Visit pChild
1257 pRightMost = childLeft;
1258 pChild->Accept( this );
1259 //Set right on pRightMost from pChild
1260 pRightMost->SetRight( bodyLeft );
1263 //Return right
1264 pRightMost = right;
1267 void SmCaretPosGraphBuildingVisitor::Visit( SmMatrixNode* pNode )
1269 SmCaretPosGraphEntry *left = pRightMost,
1270 *right = pGraph->Add( SmCaretPos( pNode, 1 ) );
1272 for ( sal_uInt16 i = 0; i < pNode->GetNumRows( ); i++ ) {
1273 SmCaretPosGraphEntry* r = left;
1274 for ( sal_uInt16 j = 0; j < pNode->GetNumCols( ); j++ ){
1275 SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
1277 pRightMost = pGraph->Add( SmCaretPos( pSubNode, 0 ), r );
1278 if( j != 0 || ( pNode->GetNumRows( ) - 1 ) / 2 == i )
1279 r->SetRight( pRightMost );
1281 pSubNode->Accept( this );
1283 r = pRightMost;
1285 pRightMost->SetRight( right );
1286 if( ( pNode->GetNumRows( ) - 1 ) / 2 == i )
1287 right->SetLeft( pRightMost );
1290 pRightMost = right;
1293 /** Build SmCaretPosGraph for SmTextNode
1295 * Lines in an SmTextNode:
1296 * \code
1297 * A B C
1298 * \endcode
1299 * Where A B and C are characters in the text.
1301 * Graph over these, where "left" is before the SmTextNode and "right" is after:
1302 * \dot
1303 * digraph Graph{
1304 * left -> A;
1305 * A -> B
1306 * B -> right;
1307 * };
1308 * \enddot
1309 * Notice that C and right is the same position here.
1311 void SmCaretPosGraphBuildingVisitor::Visit( SmTextNode* pNode )
1313 OSL_ENSURE( !pNode->GetText().isEmpty(), "Empty SmTextNode is bad" );
1315 int size = pNode->GetText().getLength();
1316 for( int i = 1; i <= size; i++ ){
1317 SmCaretPosGraphEntry* pRight = pRightMost;
1318 pRightMost = pGraph->Add( SmCaretPos( pNode, i ), pRight );
1319 pRight->SetRight( pRightMost );
1323 /** Build SmCaretPosGraph for SmBinVerNode
1325 * Lines in an SmBinVerNode:
1326 * \code
1328 * -----
1330 * \endcode
1332 * Graph over these, where "left" is before the SmBinVerNode and "right" is after:
1333 * \dot
1334 * digraph Graph{
1335 * left -> A;
1336 * A -> right;
1337 * B -> right;
1338 * };
1339 * \enddot
1341 void SmCaretPosGraphBuildingVisitor::Visit( SmBinVerNode* pNode )
1343 //None if these children can be NULL, see SmBinVerNode::Arrange
1344 SmNode *pNum = pNode->GetSubNode( 0 ),
1345 *pDenom = pNode->GetSubNode( 2 );
1347 SmCaretPosGraphEntry *left,
1348 *right,
1349 *numLeft,
1350 *denomLeft;
1352 //Set left
1353 left = pRightMost;
1354 OSL_ENSURE( pRightMost, "There must be a position in front of this" );
1356 //Create right
1357 right = pGraph->Add( SmCaretPos( pNode, 1 ) );
1359 //Create numLeft
1360 numLeft = pGraph->Add( SmCaretPos( pNum, 0 ), left );
1361 left->SetRight( numLeft );
1363 //Visit pNum
1364 pRightMost = numLeft;
1365 pNum->Accept( this );
1366 pRightMost->SetRight( right );
1367 right->SetLeft( pRightMost );
1369 //Create denomLeft
1370 denomLeft = pGraph->Add( SmCaretPos( pDenom, 0 ), left );
1372 //Visit pDenom
1373 pRightMost = denomLeft;
1374 pDenom->Accept( this );
1375 pRightMost->SetRight( right );
1377 //Set return parameter
1378 pRightMost = right;
1381 /** Build SmCaretPosGraph for SmVerticalBraceNode
1383 * Lines in an SmVerticalBraceNode:
1384 * \code
1385 * pScript
1386 * ________
1387 * / \
1388 * pBody
1389 * \endcode
1392 void SmCaretPosGraphBuildingVisitor::Visit( SmVerticalBraceNode* pNode )
1394 SmNode *pBody = pNode->GetSubNode( 0 ),
1395 *pScript = pNode->GetSubNode( 2 );
1396 //None of these children can be NULL
1398 SmCaretPosGraphEntry *left,
1399 *bodyLeft,
1400 *scriptLeft,
1401 *right;
1403 left = pRightMost;
1405 //Create right
1406 right = pGraph->Add( SmCaretPos( pNode, 1 ) );
1408 //Create bodyLeft
1409 bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
1410 left->SetRight( bodyLeft );
1411 pRightMost = bodyLeft;
1412 pBody->Accept( this );
1413 pRightMost->SetRight( right );
1414 right->SetLeft( pRightMost );
1416 //Create script
1417 scriptLeft = pGraph->Add( SmCaretPos( pScript, 0 ), left );
1418 pRightMost = scriptLeft;
1419 pScript->Accept( this );
1420 pRightMost->SetRight( right );
1422 //Set return value
1423 pRightMost = right;
1426 /** Build SmCaretPosGraph for SmBinDiagonalNode
1428 * Lines in an SmBinDiagonalNode:
1429 * \code
1430 * A /
1432 * / B
1433 * \endcode
1434 * Where A and B are lines.
1436 * Used in formulas such as "A wideslash B"
1438 void SmCaretPosGraphBuildingVisitor::Visit( SmBinDiagonalNode* pNode )
1440 SmNode *A = pNode->GetSubNode( 0 ),
1441 *B = pNode->GetSubNode( 1 );
1443 SmCaretPosGraphEntry *left,
1444 *leftA,
1445 *rightA,
1446 *leftB,
1447 *right;
1448 left = pRightMost;
1450 //Create right
1451 right = pGraph->Add( SmCaretPos( pNode, 1 ) );
1453 //Create left A
1454 leftA = pGraph->Add( SmCaretPos( A, 0 ), left );
1455 left->SetRight( leftA );
1457 //Visit A
1458 pRightMost = leftA;
1459 A->Accept( this );
1460 rightA = pRightMost;
1462 //Create left B
1463 leftB = pGraph->Add( SmCaretPos( B, 0 ), rightA );
1464 rightA->SetRight( leftB );
1466 //Visit B
1467 pRightMost = leftB;
1468 B->Accept( this );
1469 pRightMost->SetRight( right );
1470 right->SetLeft( pRightMost );
1472 //Set return value
1473 pRightMost = right;
1476 //Straigt forward ( I think )
1477 void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode* pNode )
1479 SmNodeIterator it( pNode );
1480 while( it.Next( ) )
1481 it->Accept( this );
1483 void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode* pNode )
1485 // Unary operator node
1486 SmNodeIterator it( pNode );
1487 while( it.Next( ) )
1488 it->Accept( this );
1492 void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode* pNode )
1494 SmNodeIterator it( pNode );
1495 while( it.Next( ) )
1496 it->Accept( this );
1499 void SmCaretPosGraphBuildingVisitor::Visit( SmFontNode* pNode )
1501 //Has only got one child, should act as an expression if possible
1502 SmNodeIterator it( pNode );
1503 while( it.Next( ) )
1504 it->Accept( this );
1507 /** Build SmCaretPosGraph for SmBracebodyNode
1508 * Acts as an SmExpressionNode
1510 * Below is an example of a formula tree that has multiple children for SmBracebodyNode
1511 * \dot
1512 * digraph {
1513 * labelloc = "t";
1514 * label= "Equation: \"lbrace i mline i in setZ rbrace\"";
1515 * n0 [label="SmTableNode"];
1516 * n0 -> n1 [label="0"];
1517 * n1 [label="SmLineNode"];
1518 * n1 -> n2 [label="0"];
1519 * n2 [label="SmExpressionNode"];
1520 * n2 -> n3 [label="0"];
1521 * n3 [label="SmBraceNode"];
1522 * n3 -> n4 [label="0"];
1523 * n4 [label="SmMathSymbolNode: {"];
1524 * n3 -> n5 [label="1"];
1525 * n5 [label="SmBracebodyNode"];
1526 * n5 -> n6 [label="0"];
1527 * n6 [label="SmExpressionNode"];
1528 * n6 -> n7 [label="0"];
1529 * n7 [label="SmTextNode: i"];
1530 * n5 -> n8 [label="1"];
1531 * n8 [label="SmMathSymbolNode: ∣"];
1532 * n5 -> n9 [label="2"];
1533 * n9 [label="SmExpressionNode"];
1534 * n9 -> n10 [label="0"];
1535 * n10 [label="SmBinHorNode"];
1536 * n10 -> n11 [label="0"];
1537 * n11 [label="SmTextNode: i"];
1538 * n10 -> n12 [label="1"];
1539 * n12 [label="SmMathSymbolNode: ∈"];
1540 * n10 -> n13 [label="2"];
1541 * n13 [label="SmMathSymbolNode: ℤ"];
1542 * n3 -> n14 [label="2"];
1543 * n14 [label="SmMathSymbolNode: }"];
1545 * \enddot
1547 void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode* pNode )
1549 SmNodeIterator it( pNode );
1550 while( it.Next( ) ) {
1551 SmCaretPosGraphEntry* pStart = pGraph->Add( SmCaretPos( it.Current(), 0), pRightMost );
1552 pRightMost->SetRight( pStart );
1553 pRightMost = pStart;
1554 it->Accept( this );
1558 /** Build SmCaretPosGraph for SmAlignNode
1559 * Acts as an SmExpressionNode, as it only has one child this okay
1561 void SmCaretPosGraphBuildingVisitor::Visit( SmAlignNode* pNode )
1563 SmNodeIterator it( pNode );
1564 while( it.Next( ) )
1565 it->Accept( this );
1568 /** Build SmCaretPosGraph for SmRootNode
1570 * Lines in an SmRootNode:
1571 * \code
1572 * _________
1573 * A/
1574 * \/ B
1576 * \endcode
1577 * A: pExtra ( optional, can be NULL ),
1578 * B: pBody
1580 * Graph over these, where "left" is before the SmRootNode and "right" is after:
1581 * \dot
1582 * digraph Graph{
1583 * left -> B;
1584 * B -> right;
1585 * A -> B;
1587 * \enddot
1589 void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode* pNode )
1591 SmNode *pExtra = pNode->GetSubNode( 0 ), //Argument, NULL for sqrt, and SmTextNode if cubicroot
1592 *pBody = pNode->GetSubNode( 2 ); //Body of the root
1593 OSL_ENSURE( pBody, "pBody cannot be NULL" );
1595 SmCaretPosGraphEntry *left,
1596 *right,
1597 *bodyLeft,
1598 *bodyRight;
1600 //Get left and save it
1601 OSL_ENSURE( pRightMost, "There must be a position in front of this" );
1602 left = pRightMost;
1604 //Create body left
1605 bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
1606 left->SetRight( bodyLeft );
1608 //Create right
1609 right = pGraph->Add( SmCaretPos( pNode, 1 ) );
1611 //Visit body
1612 pRightMost = bodyLeft;
1613 pBody->Accept( this );
1614 bodyRight = pRightMost;
1615 bodyRight->SetRight( right );
1616 right->SetLeft( bodyRight );
1618 //Visit pExtra
1619 if( pExtra ){
1620 pRightMost = pGraph->Add( SmCaretPos( pExtra, 0 ), left );
1621 pExtra->Accept( this );
1622 pRightMost->SetRight( bodyLeft );
1625 pRightMost = right;
1628 /** Build SmCaretPosGraph for SmPlaceNode
1629 * Consider this a single character.
1631 void SmCaretPosGraphBuildingVisitor::Visit( SmPlaceNode* pNode )
1633 SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
1634 pRightMost->SetRight( right );
1635 pRightMost = right;
1638 /** SmErrorNode is context dependent metadata, it can't be selected
1640 * @remarks There's no point in deleting, copying and/or moving an instance
1641 * of SmErrorNode as it may not exist in an other context! Thus there are no
1642 * positions to select an SmErrorNode.
1644 void SmCaretPosGraphBuildingVisitor::Visit( SmErrorNode* )
1648 /** Build SmCaretPosGraph for SmBlankNode
1649 * Consider this a single character, as it is only a blank space
1651 void SmCaretPosGraphBuildingVisitor::Visit( SmBlankNode* pNode )
1653 SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
1654 pRightMost->SetRight( right );
1655 pRightMost = right;
1658 /** Build SmCaretPosGraph for SmBraceNode
1660 * Lines in an SmBraceNode:
1661 * \code
1662 * | |
1663 * | B |
1664 * | |
1665 * \endcode
1666 * B: Body
1668 * Graph over these, where "left" is before the SmBraceNode and "right" is after:
1669 * \dot
1670 * digraph Graph{
1671 * left -> B;
1672 * B -> right;
1674 * \enddot
1676 void SmCaretPosGraphBuildingVisitor::Visit( SmBraceNode* pNode )
1678 SmNode* pBody = pNode->GetSubNode( 1 );
1680 SmCaretPosGraphEntry *left = pRightMost,
1681 *right = pGraph->Add( SmCaretPos( pNode, 1 ) );
1683 if( pBody->GetType() != NBRACEBODY ) {
1684 pRightMost = pGraph->Add( SmCaretPos( pBody, 0 ), left );
1685 left->SetRight( pRightMost );
1686 }else
1687 pRightMost = left;
1689 pBody->Accept( this );
1690 pRightMost->SetRight( right );
1691 right->SetLeft( pRightMost );
1693 pRightMost = right;
1696 /** Build SmCaretPosGraph for SmAttributNode
1698 * Lines in an SmAttributNode:
1699 * \code
1700 * Attr
1701 * Body
1702 * \endcode
1704 * There's a body and an attribute, the construction is used for "widehat A", where "A" is the body
1705 * and "^" is the attribute ( note GetScaleMode( ) on SmAttributNode tells how the attribute should be
1706 * scaled ).
1708 void SmCaretPosGraphBuildingVisitor::Visit( SmAttributNode* pNode )
1710 SmNode *pAttr = pNode->GetSubNode( 0 ),
1711 *pBody = pNode->GetSubNode( 1 );
1712 //None of the children can be NULL
1714 SmCaretPosGraphEntry *left = pRightMost,
1715 *attrLeft,
1716 *bodyLeft,
1717 *bodyRight,
1718 *right;
1720 //Creating bodyleft
1721 bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
1722 left->SetRight( bodyLeft );
1724 //Creating right
1725 right = pGraph->Add( SmCaretPos( pNode, 1 ) );
1727 //Visit the body
1728 pRightMost = bodyLeft;
1729 pBody->Accept( this );
1730 bodyRight = pRightMost;
1731 bodyRight->SetRight( right );
1732 right->SetLeft( bodyRight );
1734 //Create attrLeft
1735 attrLeft = pGraph->Add( SmCaretPos( pAttr, 0 ), left );
1737 //Visit attribute
1738 pRightMost = attrLeft;
1739 pAttr->Accept( this );
1740 pRightMost->SetRight( right );
1742 //Set return value
1743 pRightMost = right;
1746 //Consider these single symboles
1747 void SmCaretPosGraphBuildingVisitor::Visit( SmSpecialNode* pNode )
1749 SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
1750 pRightMost->SetRight( right );
1751 pRightMost = right;
1753 void SmCaretPosGraphBuildingVisitor::Visit( SmGlyphSpecialNode* pNode )
1755 SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
1756 pRightMost->SetRight( right );
1757 pRightMost = right;
1759 void SmCaretPosGraphBuildingVisitor::Visit( SmMathSymbolNode* pNode )
1761 SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
1762 pRightMost->SetRight( right );
1763 pRightMost = right;
1766 void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode* )
1768 //Do nothing
1770 void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode* )
1772 //Do nothing
1774 void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode* )
1776 //Do nothing
1779 /////////////////////////////// SmCloningVisitor ///////////////////////////////
1781 SmNode* SmCloningVisitor::Clone( SmNode* pNode )
1783 SmNode* pCurrResult = pResult;
1784 pNode->Accept( this );
1785 SmNode* pClone = pResult;
1786 pResult = pCurrResult;
1787 return pClone;
1790 void SmCloningVisitor::CloneNodeAttr( SmNode* pSource, SmNode* pTarget )
1792 pTarget->SetScaleMode( pSource->GetScaleMode( ) );
1793 //Other attributes are set when prepare or arrange is executed
1794 //and may depend on stuff not being cloned here.
1797 void SmCloningVisitor::CloneKids( SmStructureNode* pSource, SmStructureNode* pTarget )
1799 //Cache current result
1800 SmNode* pCurrResult = pResult;
1802 //Create array for holding clones
1803 sal_uInt16 nSize = pSource->GetNumSubNodes( );
1804 SmNodeArray aNodes( nSize );
1806 //Clone children
1807 SmNode* pKid;
1808 for( sal_uInt16 i = 0; i < nSize; i++ ){
1809 if( NULL != ( pKid = pSource->GetSubNode( i ) ) )
1810 pKid->Accept( this );
1811 else
1812 pResult = NULL;
1813 aNodes[i] = pResult;
1816 //Set subnodes of pTarget
1817 pTarget->SetSubNodes( aNodes );
1819 //Restore result as where prior to call
1820 pResult = pCurrResult;
1823 void SmCloningVisitor::Visit( SmTableNode* pNode )
1825 SmTableNode* pClone = new SmTableNode( pNode->GetToken( ) );
1826 CloneNodeAttr( pNode, pClone );
1827 CloneKids( pNode, pClone );
1828 pResult = pClone;
1831 void SmCloningVisitor::Visit( SmBraceNode* pNode )
1833 SmBraceNode* pClone = new SmBraceNode( pNode->GetToken( ) );
1834 CloneNodeAttr( pNode, pClone );
1835 CloneKids( pNode, pClone );
1836 pResult = pClone;
1839 void SmCloningVisitor::Visit( SmBracebodyNode* pNode )
1841 SmBracebodyNode* pClone = new SmBracebodyNode( pNode->GetToken( ) );
1842 CloneNodeAttr( pNode, pClone );
1843 CloneKids( pNode, pClone );
1844 pResult = pClone;
1847 void SmCloningVisitor::Visit( SmOperNode* pNode )
1849 SmOperNode* pClone = new SmOperNode( pNode->GetToken( ) );
1850 CloneNodeAttr( pNode, pClone );
1851 CloneKids( pNode, pClone );
1852 pResult = pClone;
1855 void SmCloningVisitor::Visit( SmAlignNode* pNode )
1857 SmAlignNode* pClone = new SmAlignNode( pNode->GetToken( ) );
1858 CloneNodeAttr( pNode, pClone );
1859 CloneKids( pNode, pClone );
1860 pResult = pClone;
1863 void SmCloningVisitor::Visit( SmAttributNode* pNode )
1865 SmAttributNode* pClone = new SmAttributNode( pNode->GetToken( ) );
1866 CloneNodeAttr( pNode, pClone );
1867 CloneKids( pNode, pClone );
1868 pResult = pClone;
1871 void SmCloningVisitor::Visit( SmFontNode* pNode )
1873 SmFontNode* pClone = new SmFontNode( pNode->GetToken( ) );
1874 pClone->SetSizeParameter( pNode->GetSizeParameter( ), pNode->GetSizeType( ) );
1875 CloneNodeAttr( pNode, pClone );
1876 CloneKids( pNode, pClone );
1877 pResult = pClone;
1880 void SmCloningVisitor::Visit( SmUnHorNode* pNode )
1882 SmUnHorNode* pClone = new SmUnHorNode( pNode->GetToken( ) );
1883 CloneNodeAttr( pNode, pClone );
1884 CloneKids( pNode, pClone );
1885 pResult = pClone;
1888 void SmCloningVisitor::Visit( SmBinHorNode* pNode )
1890 SmBinHorNode* pClone = new SmBinHorNode( pNode->GetToken( ) );
1891 CloneNodeAttr( pNode, pClone );
1892 CloneKids( pNode, pClone );
1893 pResult = pClone;
1896 void SmCloningVisitor::Visit( SmBinVerNode* pNode )
1898 SmBinVerNode* pClone = new SmBinVerNode( pNode->GetToken( ) );
1899 CloneNodeAttr( pNode, pClone );
1900 CloneKids( pNode, pClone );
1901 pResult = pClone;
1904 void SmCloningVisitor::Visit( SmBinDiagonalNode* pNode )
1906 SmBinDiagonalNode *pClone = new SmBinDiagonalNode( pNode->GetToken( ) );
1907 pClone->SetAscending( pNode->IsAscending( ) );
1908 CloneNodeAttr( pNode, pClone );
1909 CloneKids( pNode, pClone );
1910 pResult = pClone;
1913 void SmCloningVisitor::Visit( SmSubSupNode* pNode )
1915 SmSubSupNode *pClone = new SmSubSupNode( pNode->GetToken( ) );
1916 pClone->SetUseLimits( pNode->IsUseLimits( ) );
1917 CloneNodeAttr( pNode, pClone );
1918 CloneKids( pNode, pClone );
1919 pResult = pClone;
1922 void SmCloningVisitor::Visit( SmMatrixNode* pNode )
1924 SmMatrixNode *pClone = new SmMatrixNode( pNode->GetToken( ) );
1925 pClone->SetRowCol( pNode->GetNumRows( ), pNode->GetNumCols( ) );
1926 CloneNodeAttr( pNode, pClone );
1927 CloneKids( pNode, pClone );
1928 pResult = pClone;
1931 void SmCloningVisitor::Visit( SmPlaceNode* pNode )
1933 pResult = new SmPlaceNode( pNode->GetToken( ) );
1934 CloneNodeAttr( pNode, pResult );
1937 void SmCloningVisitor::Visit( SmTextNode* pNode )
1939 SmTextNode* pClone = new SmTextNode( pNode->GetToken( ), pNode->GetFontDesc( ) );
1940 pClone->ChangeText( pNode->GetText( ) );
1941 CloneNodeAttr( pNode, pClone );
1942 pResult = pClone;
1945 void SmCloningVisitor::Visit( SmSpecialNode* pNode )
1947 pResult = new SmSpecialNode( pNode->GetToken( ) );
1948 CloneNodeAttr( pNode, pResult );
1951 void SmCloningVisitor::Visit( SmGlyphSpecialNode* pNode )
1953 pResult = new SmGlyphSpecialNode( pNode->GetToken( ) );
1954 CloneNodeAttr( pNode, pResult );
1957 void SmCloningVisitor::Visit( SmMathSymbolNode* pNode )
1959 pResult = new SmMathSymbolNode( pNode->GetToken( ) );
1960 CloneNodeAttr( pNode, pResult );
1963 void SmCloningVisitor::Visit( SmBlankNode* pNode )
1965 SmBlankNode* pClone = new SmBlankNode( pNode->GetToken( ) );
1966 pClone->SetBlankNum( pNode->GetBlankNum( ) );
1967 pResult = pClone;
1968 CloneNodeAttr( pNode, pResult );
1971 void SmCloningVisitor::Visit( SmErrorNode* pNode )
1973 //PE_NONE is used the information have been discarded and isn't used
1974 pResult = new SmErrorNode( PE_NONE, pNode->GetToken( ) );
1975 CloneNodeAttr( pNode, pResult );
1978 void SmCloningVisitor::Visit( SmLineNode* pNode )
1980 SmLineNode* pClone = new SmLineNode( pNode->GetToken( ) );
1981 CloneNodeAttr( pNode, pClone );
1982 CloneKids( pNode, pClone );
1983 pResult = pClone;
1986 void SmCloningVisitor::Visit( SmExpressionNode* pNode )
1988 SmExpressionNode* pClone = new SmExpressionNode( pNode->GetToken( ) );
1989 CloneNodeAttr( pNode, pClone );
1990 CloneKids( pNode, pClone );
1991 pResult = pClone;
1994 void SmCloningVisitor::Visit( SmPolyLineNode* pNode )
1996 pResult = new SmPolyLineNode( pNode->GetToken( ) );
1997 CloneNodeAttr( pNode, pResult );
2000 void SmCloningVisitor::Visit( SmRootNode* pNode )
2002 SmRootNode* pClone = new SmRootNode( pNode->GetToken( ) );
2003 CloneNodeAttr( pNode, pClone );
2004 CloneKids( pNode, pClone );
2005 pResult = pClone;
2008 void SmCloningVisitor::Visit( SmRootSymbolNode* pNode )
2010 pResult = new SmRootSymbolNode( pNode->GetToken( ) );
2011 CloneNodeAttr( pNode, pResult );
2014 void SmCloningVisitor::Visit( SmRectangleNode* pNode )
2016 pResult = new SmRectangleNode( pNode->GetToken( ) );
2017 CloneNodeAttr( pNode, pResult );
2020 void SmCloningVisitor::Visit( SmVerticalBraceNode* pNode )
2022 SmVerticalBraceNode* pClone = new SmVerticalBraceNode( pNode->GetToken( ) );
2023 CloneNodeAttr( pNode, pClone );
2024 CloneKids( pNode, pClone );
2025 pResult = pClone;
2028 /////////////////////////////// SmSelectionDrawingVisitor ///////////////////////////////
2030 SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, Point Offset )
2031 : rDev( rDevice ) {
2032 bHasSelectionArea = false;
2034 //Visit everything
2035 OSL_ENSURE( pTree, "pTree can't be null!" );
2036 if( pTree )
2037 pTree->Accept( this );
2039 //Draw selection if there's any
2040 if( bHasSelectionArea ){
2041 aSelectionArea.Move( Offset.X( ), Offset.Y( ) );
2043 //Save device state
2044 rDev.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
2045 //Change colors
2046 rDev.SetLineColor( );
2047 rDev.SetFillColor( Color( COL_LIGHTGRAY ) );
2049 //Draw rectangle
2050 rDev.DrawRect( aSelectionArea );
2052 //Restore device state
2053 rDev.Pop( );
2057 void SmSelectionDrawingVisitor::ExtendSelectionArea( Rectangle aArea )
2059 if ( ! bHasSelectionArea ) {
2060 aSelectionArea = aArea;
2061 bHasSelectionArea = true;
2062 } else
2063 aSelectionArea.Union( aArea );
2066 void SmSelectionDrawingVisitor::DefaultVisit( SmNode* pNode )
2068 if( pNode->IsSelected( ) )
2069 ExtendSelectionArea( pNode->AsRectangle( ) );
2070 VisitChildren( pNode );
2073 void SmSelectionDrawingVisitor::VisitChildren( SmNode* pNode )
2075 SmNodeIterator it( pNode );
2076 while( it.Next( ) )
2077 it->Accept( this );
2080 void SmSelectionDrawingVisitor::Visit( SmTextNode* pNode )
2082 if( pNode->IsSelected( ) ){
2083 rDev.Push( PUSH_TEXTCOLOR | PUSH_FONT );
2085 rDev.SetFont( pNode->GetFont( ) );
2086 Point Position = pNode->GetTopLeft( );
2087 long left = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionStart( ) );
2088 long right = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionEnd( ) );
2089 long top = Position.getY( );
2090 long bottom = top + pNode->GetHeight( );
2091 Rectangle rect( left, top, right, bottom );
2093 ExtendSelectionArea( rect );
2095 rDev.Pop( );
2099 /////////////////////////////// SmNodeToTextVisitor ///////////////////////////////
2101 SmNodeToTextVisitor::SmNodeToTextVisitor( SmNode* pNode, OUString &rText )
2103 pNode->Accept( this );
2104 rText = aCmdText.makeStringAndClear();
2107 void SmNodeToTextVisitor::Visit( SmTableNode* pNode )
2109 if( pNode->GetToken( ).eType == TBINOM ) {
2110 Append( "{ binom" );
2111 LineToText( pNode->GetSubNode( 0 ) );
2112 LineToText( pNode->GetSubNode( 1 ) );
2113 Append("} ");
2114 } else if( pNode->GetToken( ).eType == TSTACK ) {
2115 Append( "stack{ " );
2116 SmNodeIterator it( pNode );
2117 it.Next( );
2118 while( true ) {
2119 LineToText( it.Current( ) );
2120 if( it.Next( ) ) {
2121 Separate( );
2122 Append( "# " );
2123 }else
2124 break;
2126 Separate( );
2127 Append( "}" );
2128 } else { //Assume it's a toplevel table, containing lines
2129 SmNodeIterator it( pNode );
2130 it.Next( );
2131 while( true ) {
2132 Separate( );
2133 it->Accept( this );
2134 if( it.Next( ) ) {
2135 Separate( );
2136 Append( "newline" );
2137 }else
2138 break;
2143 void SmNodeToTextVisitor::Visit( SmBraceNode* pNode )
2145 SmNode *pLeftBrace = pNode->GetSubNode( 0 ),
2146 *pBody = pNode->GetSubNode( 1 ),
2147 *pRightBrace = pNode->GetSubNode( 2 );
2148 //Handle special case where it's absolute function
2149 if( pNode->GetToken( ).eType == TABS ) {
2150 Append( "abs" );
2151 LineToText( pBody );
2152 } else {
2153 if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
2154 Append( "left " );
2155 pLeftBrace->Accept( this );
2156 Separate( );
2157 pBody->Accept( this );
2158 Separate( );
2159 if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
2160 Append( "right " );
2161 pRightBrace->Accept( this );
2165 void SmNodeToTextVisitor::Visit( SmBracebodyNode* pNode )
2167 SmNodeIterator it( pNode );
2168 while( it.Next( ) ){
2169 Separate( );
2170 it->Accept( this );
2174 void SmNodeToTextVisitor::Visit( SmOperNode* pNode )
2176 Append( pNode->GetToken( ).aText );
2177 Separate( );
2178 if( pNode->GetToken( ).eType == TOPER ){
2179 //There's an SmGlyphSpecialNode if eType == TOPER
2180 if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP )
2181 Append( pNode->GetSubNode( 0 )->GetSubNode( 0 )->GetToken( ).aText );
2182 else
2183 Append( pNode->GetSubNode( 0 )->GetToken( ).aText );
2185 if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP ) {
2186 SmSubSupNode *pSubSup = ( SmSubSupNode* )pNode->GetSubNode( 0 );
2187 SmNode* pChild;
2188 if( ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
2189 Separate( );
2190 Append( "lsup { " );
2191 LineToText( pChild );
2192 Append( "} " );
2194 if( ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
2195 Separate( );
2196 Append( "lsub { " );
2197 LineToText( pChild );
2198 Append( "} " );
2200 if( ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
2201 Separate( );
2202 Append( "^ { " );
2203 LineToText( pChild );
2204 Append( "} " );
2206 if( ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
2207 Separate( );
2208 Append( "_ { " );
2209 LineToText( pChild );
2210 Append( "} " );
2212 if( ( pChild = pSubSup->GetSubSup( CSUB ) ) ) {
2213 Separate( );
2214 if (pSubSup->IsUseLimits())
2215 Append( "from { " );
2216 else
2217 Append( "csub { " );
2218 LineToText( pChild );
2219 Append( "} " );
2221 if( ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {
2222 Separate( );
2223 if (pSubSup->IsUseLimits())
2224 Append( "to { " );
2225 else
2226 Append( "csup { " );
2227 LineToText( pChild );
2228 Append( "} " );
2231 LineToText( pNode->GetSubNode( 1 ) );
2234 void SmNodeToTextVisitor::Visit( SmAlignNode* pNode )
2236 Append( pNode->GetToken( ).aText );
2237 LineToText( pNode->GetSubNode( 0 ) );
2240 void SmNodeToTextVisitor::Visit( SmAttributNode* pNode )
2242 Append( pNode->GetToken( ).aText );
2243 LineToText( pNode->GetSubNode( 1 ) );
2246 void SmNodeToTextVisitor::Visit( SmFontNode* pNode )
2248 switch ( pNode->GetToken( ).eType )
2250 case TBOLD:
2251 Append( "bold " );
2252 break;
2253 case TNBOLD:
2254 Append( "nbold " );
2255 break;
2256 case TITALIC:
2257 Append( "italic " );
2258 break;
2259 case TNITALIC:
2260 Append( "nitalic " );
2261 break;
2262 case TPHANTOM:
2263 Append( "phantom " );
2264 break;
2265 case TSIZE:
2267 Append( "size " );
2268 switch ( pNode->GetSizeType( ) )
2270 case FNTSIZ_PLUS:
2271 Append( "+" );
2272 break;
2273 case FNTSIZ_MINUS:
2274 Append( "-" );
2275 break;
2276 case FNTSIZ_MULTIPLY:
2277 Append( "*" );
2278 break;
2279 case FNTSIZ_DIVIDE:
2280 Append( "/" );
2281 break;
2282 case FNTSIZ_ABSOLUT:
2283 default:
2284 break;
2286 Append( ::rtl::math::doubleToUString(
2287 static_cast<double>( pNode->GetSizeParameter( ) ),
2288 rtl_math_StringFormat_Automatic,
2289 rtl_math_DecimalPlaces_Max, '.', sal_True ) );
2290 Append( " " );
2292 break;
2293 case TBLACK:
2294 Append( "color black " );
2295 break;
2296 case TWHITE:
2297 Append( "color white " );
2298 break;
2299 case TRED:
2300 Append( "color red " );
2301 break;
2302 case TGREEN:
2303 Append( "color green " );
2304 break;
2305 case TBLUE:
2306 Append( "color blue " );
2307 break;
2308 case TCYAN:
2309 Append( "color cyan " );
2310 break;
2311 case TMAGENTA:
2312 Append( "color magenta " );
2313 break;
2314 case TYELLOW:
2315 Append( "color yellow " );
2316 break;
2317 case TSANS:
2318 Append( "font sans " );
2319 break;
2320 case TSERIF:
2321 Append( "font serif " );
2322 break;
2323 case TFIXED:
2324 Append( "font fixed " );
2325 break;
2326 default:
2327 break;
2329 LineToText( pNode->GetSubNode( 1 ) );
2332 void SmNodeToTextVisitor::Visit( SmUnHorNode* pNode )
2334 SmNodeIterator it( pNode, pNode->GetSubNode( 1 )->GetToken( ).eType == TFACT );
2335 while( it.Next( ) ) {
2336 Separate( );
2337 it->Accept( this );
2341 void SmNodeToTextVisitor::Visit( SmBinHorNode* pNode )
2343 SmNode *pLeft = pNode->GetSubNode( 0 ),
2344 *pOper = pNode->GetSubNode( 1 ),
2345 *pRight = pNode->GetSubNode( 2 );
2346 Separate( );
2347 pLeft->Accept( this );
2348 Separate( );
2349 pOper->Accept( this );
2350 Separate( );
2351 pRight->Accept( this );
2352 Separate( );
2355 void SmNodeToTextVisitor::Visit( SmBinVerNode* pNode )
2357 SmNode *pNum = pNode->GetSubNode( 0 ),
2358 *pDenom = pNode->GetSubNode( 2 );
2359 Append( "{ " );
2360 LineToText( pNum );
2361 Append( "over" );
2362 LineToText( pDenom );
2363 Append( "} " );
2366 void SmNodeToTextVisitor::Visit( SmBinDiagonalNode* pNode )
2368 SmNode *pLeftOperand = pNode->GetSubNode( 0 ),
2369 *pRightOperand = pNode->GetSubNode( 1 );
2370 Append( "{ " );
2371 LineToText( pLeftOperand );
2372 Separate( );
2373 Append( "wideslash " );
2374 LineToText( pRightOperand );
2375 Append( "} " );
2378 void SmNodeToTextVisitor::Visit( SmSubSupNode* pNode )
2380 LineToText( pNode->GetBody( ) );
2381 SmNode *pChild;
2382 if( ( pChild = pNode->GetSubSup( LSUP ) ) ) {
2383 Separate( );
2384 Append( "lsup " );
2385 LineToText( pChild );
2387 if( ( pChild = pNode->GetSubSup( LSUB ) ) ) {
2388 Separate( );
2389 Append( "lsub " );
2390 LineToText( pChild );
2392 if( ( pChild = pNode->GetSubSup( RSUP ) ) ) {
2393 Separate( );
2394 Append( "^ " );
2395 LineToText( pChild );
2397 if( ( pChild = pNode->GetSubSup( RSUB ) ) ) {
2398 Separate( );
2399 Append( "_ " );
2400 LineToText( pChild );
2402 if( ( pChild = pNode->GetSubSup( CSUB ) ) ) {
2403 Separate( );
2404 if (pNode->IsUseLimits())
2405 Append( "from " );
2406 else
2407 Append( "csub " );
2408 LineToText( pChild );
2410 if( ( pChild = pNode->GetSubSup( CSUP ) ) ) {
2411 Separate( );
2412 if (pNode->IsUseLimits())
2413 Append( "to " );
2414 else
2415 Append( "csup " );
2416 LineToText( pChild );
2420 void SmNodeToTextVisitor::Visit( SmMatrixNode* pNode )
2422 Append( "matrix{" );
2423 for ( sal_uInt16 i = 0; i < pNode->GetNumRows( ); i++ ) {
2424 for ( sal_uInt16 j = 0; j < pNode->GetNumCols( ); j++ ) {
2425 SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
2426 Separate( );
2427 pSubNode->Accept( this );
2428 Separate( );
2429 if( j != pNode->GetNumCols( ) - 1 )
2430 Append( "#" );
2432 Separate( );
2433 if( i != pNode->GetNumRows( ) - 1 )
2434 Append( "##" );
2436 Append( "} " );
2439 void SmNodeToTextVisitor::Visit( SmPlaceNode* )
2441 Append( "<?>" );
2444 void SmNodeToTextVisitor::Visit( SmTextNode* pNode )
2446 //TODO: This method might need improvements, see SmTextNode::CreateTextFromNode
2447 if( pNode->GetToken( ).eType == TTEXT )
2448 Append( "\"" );
2449 Append( pNode->GetText( ) );
2450 if( pNode->GetToken( ).eType == TTEXT )
2451 Append( "\"" );
2454 void SmNodeToTextVisitor::Visit( SmSpecialNode* pNode )
2456 Append( pNode->GetToken( ).aText );
2459 void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode* pNode )
2461 if( pNode->GetToken( ).eType == TBOPER )
2462 Append( "boper " );
2463 else
2464 Append( "uoper " );
2465 Append( pNode->GetToken( ).aText );
2468 void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
2470 Append( pNode->GetToken( ).aText );
2473 void SmNodeToTextVisitor::Visit( SmBlankNode* pNode )
2475 Append( pNode->GetToken( ).aText );
2478 void SmNodeToTextVisitor::Visit( SmErrorNode* )
2482 void SmNodeToTextVisitor::Visit( SmLineNode* pNode )
2484 SmNodeIterator it( pNode );
2485 while( it.Next( ) ){
2486 Separate( );
2487 it->Accept( this );
2491 void SmNodeToTextVisitor::Visit( SmExpressionNode* pNode )
2493 bool bracketsNeeded = pNode->GetNumSubNodes() != 1 || pNode->GetSubNode(0)->GetType() == NBINHOR;
2494 if (!bracketsNeeded)
2496 const SmNode *pParent = pNode->GetParent();
2497 // nested subsups
2498 bracketsNeeded =
2499 pParent && pParent->GetType() == NSUBSUP &&
2500 pNode->GetNumSubNodes() == 1 &&
2501 pNode->GetSubNode(0)->GetType() == NSUBSUP;
2504 if (bracketsNeeded) {
2505 Append( "{ " );
2507 SmNodeIterator it( pNode );
2508 while( it.Next( ) ) {
2509 it->Accept( this );
2510 Separate( );
2512 if (bracketsNeeded) {
2513 Append( "} " );
2517 void SmNodeToTextVisitor::Visit( SmPolyLineNode* )
2521 void SmNodeToTextVisitor::Visit( SmRootNode* pNode )
2523 SmNode *pExtra = pNode->GetSubNode( 0 ),
2524 *pBody = pNode->GetSubNode( 2 );
2525 if( pExtra ) {
2526 Append( "nroot" );
2527 LineToText( pExtra );
2528 } else
2529 Append( "sqrt" );
2530 LineToText( pBody );
2533 void SmNodeToTextVisitor::Visit( SmRootSymbolNode* )
2537 void SmNodeToTextVisitor::Visit( SmRectangleNode* )
2541 void SmNodeToTextVisitor::Visit( SmVerticalBraceNode* pNode )
2543 SmNode *pBody = pNode->GetSubNode( 0 ),
2544 *pScript = pNode->GetSubNode( 2 );
2545 LineToText( pBody );
2546 Append( pNode->GetToken( ).aText );
2547 LineToText( pScript );
2550 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */