1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #include <rtl/math.hxx>
11 #include <sal/log.hxx>
12 #include <tools/gen.hxx>
13 #include <vcl/lineinfo.hxx>
14 #include <visitors.hxx>
15 #include "tmpdevice.hxx"
18 #include "mathtype.hxx"
19 #include <starmathdatabase.hxx>
21 // SmDefaultingVisitor
23 void SmDefaultingVisitor::Visit( SmTableNode
* pNode
)
25 DefaultVisit( pNode
);
28 void SmDefaultingVisitor::Visit( SmBraceNode
* pNode
)
30 DefaultVisit( pNode
);
33 void SmDefaultingVisitor::Visit( SmBracebodyNode
* pNode
)
35 DefaultVisit( pNode
);
38 void SmDefaultingVisitor::Visit( SmOperNode
* pNode
)
40 DefaultVisit( pNode
);
43 void SmDefaultingVisitor::Visit( SmAlignNode
* pNode
)
45 DefaultVisit( pNode
);
48 void SmDefaultingVisitor::Visit( SmAttributNode
* pNode
)
50 DefaultVisit( pNode
);
53 void SmDefaultingVisitor::Visit( SmFontNode
* pNode
)
55 DefaultVisit( pNode
);
58 void SmDefaultingVisitor::Visit( SmUnHorNode
* pNode
)
60 DefaultVisit( pNode
);
63 void SmDefaultingVisitor::Visit( SmBinHorNode
* pNode
)
65 DefaultVisit( pNode
);
68 void SmDefaultingVisitor::Visit( SmBinVerNode
* pNode
)
70 DefaultVisit( pNode
);
73 void SmDefaultingVisitor::Visit( SmBinDiagonalNode
* pNode
)
75 DefaultVisit( pNode
);
78 void SmDefaultingVisitor::Visit( SmSubSupNode
* pNode
)
80 DefaultVisit( pNode
);
83 void SmDefaultingVisitor::Visit( SmMatrixNode
* pNode
)
85 DefaultVisit( pNode
);
88 void SmDefaultingVisitor::Visit( SmPlaceNode
* pNode
)
90 DefaultVisit( pNode
);
93 void SmDefaultingVisitor::Visit( SmTextNode
* pNode
)
95 DefaultVisit( pNode
);
98 void SmDefaultingVisitor::Visit( SmSpecialNode
* pNode
)
100 DefaultVisit( pNode
);
103 void SmDefaultingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
105 DefaultVisit( pNode
);
108 void SmDefaultingVisitor::Visit( SmMathSymbolNode
* pNode
)
110 DefaultVisit( pNode
);
113 void SmDefaultingVisitor::Visit( SmBlankNode
* pNode
)
115 DefaultVisit( pNode
);
118 void SmDefaultingVisitor::Visit( SmErrorNode
* pNode
)
120 DefaultVisit( pNode
);
123 void SmDefaultingVisitor::Visit( SmLineNode
* pNode
)
125 DefaultVisit( pNode
);
128 void SmDefaultingVisitor::Visit( SmExpressionNode
* pNode
)
130 DefaultVisit( pNode
);
133 void SmDefaultingVisitor::Visit( SmPolyLineNode
* pNode
)
135 DefaultVisit( pNode
);
138 void SmDefaultingVisitor::Visit( SmRootNode
* pNode
)
140 DefaultVisit( pNode
);
143 void SmDefaultingVisitor::Visit( SmRootSymbolNode
* pNode
)
145 DefaultVisit( pNode
);
148 void SmDefaultingVisitor::Visit( SmRectangleNode
* pNode
)
150 DefaultVisit( pNode
);
153 void SmDefaultingVisitor::Visit( SmVerticalBraceNode
* pNode
)
155 DefaultVisit( pNode
);
158 // SmCaretDrawingVisitor
160 SmCaretDrawingVisitor::SmCaretDrawingVisitor( OutputDevice
& rDevice
,
167 , mbCaretVisible( caretVisible
)
169 SAL_WARN_IF( !position
.IsValid(), "starmath", "Cannot draw invalid position!" );
170 if( !position
.IsValid( ) )
174 mrDev
.Push( PushFlags::FONT
| PushFlags::MAPMODE
| PushFlags::LINECOLOR
| PushFlags::FILLCOLOR
| PushFlags::TEXTCOLOR
);
176 maPos
.pSelectedNode
->Accept( this );
177 //Restore device state
181 void SmCaretDrawingVisitor::Visit( SmTextNode
* pNode
)
183 tools::Long i
= maPos
.nIndex
;
185 mrDev
.SetFont( pNode
->GetFont( ) );
188 SmNode
* pLine
= SmCursor::FindTopMostNodeInLine( pNode
);
191 tools::Long left
= pNode
->GetLeft( ) + mrDev
.GetTextWidth( pNode
->GetText( ), 0, i
) + maOffset
.X( );
192 tools::Long top
= pLine
->GetTop( ) + maOffset
.Y( );
193 tools::Long height
= pLine
->GetHeight( );
194 tools::Long left_line
= pLine
->GetLeft( ) + maOffset
.X( );
195 tools::Long right_line
= pLine
->GetRight( ) + maOffset
.X( );
198 mrDev
.SetLineColor( COL_BLACK
);
200 if ( mbCaretVisible
) {
202 Point
p1( left
, top
);
203 Point
p2( left
, top
+ height
);
204 mrDev
.DrawLine( p1
, p2
);
208 Point
aLeft( left_line
, top
+ height
);
209 Point
aRight( right_line
, top
+ height
);
210 mrDev
.DrawLine( aLeft
, aRight
);
213 void SmCaretDrawingVisitor::DefaultVisit( SmNode
* pNode
)
216 SmNode
* pLine
= SmCursor::FindTopMostNodeInLine( pNode
);
219 tools::Long left
= pNode
->GetLeft( ) + maOffset
.X( ) + ( maPos
.nIndex
== 1 ? pNode
->GetWidth( ) : 0 );
220 tools::Long top
= pLine
->GetTop( ) + maOffset
.Y( );
221 tools::Long height
= pLine
->GetHeight( );
222 tools::Long left_line
= pLine
->GetLeft( ) + maOffset
.X( );
223 tools::Long right_line
= pLine
->GetRight( ) + maOffset
.X( );
226 mrDev
.SetLineColor( COL_BLACK
);
228 if ( mbCaretVisible
) {
230 Point
p1( left
, top
);
231 Point
p2( left
, top
+ height
);
232 mrDev
.DrawLine( p1
, p2
);
236 Point
aLeft( left_line
, top
+ height
);
237 Point
aRight( right_line
, top
+ height
);
238 mrDev
.DrawLine( aLeft
, aRight
);
241 // SmCaretPos2LineVisitor
243 void SmCaretPos2LineVisitor::Visit( SmTextNode
* pNode
)
246 mpDev
->Push( PushFlags::FONT
| PushFlags::TEXTCOLOR
);
248 tools::Long i
= maPos
.nIndex
;
250 mpDev
->SetFont( pNode
->GetFont( ) );
253 tools::Long left
= pNode
->GetLeft( ) + mpDev
->GetTextWidth( pNode
->GetText( ), 0, i
);
254 tools::Long top
= pNode
->GetTop( );
255 tools::Long height
= pNode
->GetHeight( );
257 maLine
= SmCaretLine( left
, top
, height
);
259 //Restore device state
263 void SmCaretPos2LineVisitor::DefaultVisit( SmNode
* pNode
)
265 //Vertical line ( code from SmCaretDrawingVisitor )
266 Point p1
= pNode
->GetTopLeft( );
267 if( maPos
.nIndex
== 1 )
268 p1
.Move( pNode
->GetWidth( ), 0 );
270 maLine
= SmCaretLine( p1
.X( ), p1
.Y( ), pNode
->GetHeight( ) );
276 void SmDrawingVisitor::Visit( SmTableNode
* pNode
)
278 DrawChildren( pNode
);
281 void SmDrawingVisitor::Visit( SmBraceNode
* pNode
)
283 DrawChildren( pNode
);
286 void SmDrawingVisitor::Visit( SmBracebodyNode
* pNode
)
288 DrawChildren( pNode
);
291 void SmDrawingVisitor::Visit( SmOperNode
* pNode
)
293 DrawChildren( pNode
);
296 void SmDrawingVisitor::Visit( SmAlignNode
* pNode
)
298 DrawChildren( pNode
);
301 void SmDrawingVisitor::Visit( SmAttributNode
* pNode
)
303 DrawChildren( pNode
);
306 void SmDrawingVisitor::Visit( SmFontNode
* pNode
)
308 DrawChildren( pNode
);
311 void SmDrawingVisitor::Visit( SmUnHorNode
* pNode
)
313 DrawChildren( pNode
);
316 void SmDrawingVisitor::Visit( SmBinHorNode
* pNode
)
318 DrawChildren( pNode
);
321 void SmDrawingVisitor::Visit( SmBinVerNode
* pNode
)
323 DrawChildren( pNode
);
326 void SmDrawingVisitor::Visit( SmBinDiagonalNode
* pNode
)
328 DrawChildren( pNode
);
331 void SmDrawingVisitor::Visit( SmSubSupNode
* pNode
)
333 DrawChildren( pNode
);
336 void SmDrawingVisitor::Visit( SmMatrixNode
* pNode
)
338 DrawChildren( pNode
);
341 void SmDrawingVisitor::Visit( SmPlaceNode
* pNode
)
343 DrawSpecialNode( pNode
);
346 void SmDrawingVisitor::Visit( SmTextNode
* pNode
)
348 DrawTextNode( pNode
);
351 void SmDrawingVisitor::Visit( SmSpecialNode
* pNode
)
353 DrawSpecialNode( pNode
);
356 void SmDrawingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
358 DrawSpecialNode( pNode
);
361 void SmDrawingVisitor::Visit( SmMathSymbolNode
* pNode
)
363 DrawSpecialNode( pNode
);
366 void SmDrawingVisitor::Visit( SmBlankNode
* )
370 void SmDrawingVisitor::Visit( SmErrorNode
* pNode
)
372 DrawSpecialNode( pNode
);
375 void SmDrawingVisitor::Visit( SmLineNode
* pNode
)
377 DrawChildren( pNode
);
380 void SmDrawingVisitor::Visit( SmExpressionNode
* pNode
)
382 DrawChildren( pNode
);
385 void SmDrawingVisitor::Visit( SmRootNode
* pNode
)
387 DrawChildren( pNode
);
390 void SmDrawingVisitor::Visit( SmVerticalBraceNode
* pNode
)
392 DrawChildren( pNode
);
395 void SmDrawingVisitor::Visit( SmRootSymbolNode
* pNode
)
397 if ( pNode
->IsPhantom( ) )
400 // draw root-sign itself
401 DrawSpecialNode( pNode
);
403 SmTmpDevice
aTmpDev( mrDev
, true );
404 aTmpDev
.SetFillColor( pNode
->GetFont( ).GetColor( ) );
405 mrDev
.SetLineColor( );
406 aTmpDev
.SetFont( pNode
->GetFont( ) );
408 // since the width is always unscaled it corresponds to the _original_
409 // _unscaled_ font height to be used, we use that to calculate the
410 // bar height. Thus it is independent of the arguments height.
411 // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
412 tools::Long nBarHeight
= pNode
->GetWidth( ) * 7 / 100;
413 tools::Long nBarWidth
= pNode
->GetBodyWidth( ) + pNode
->GetBorderWidth( );
414 Point
aBarOffset( pNode
->GetWidth( ), +pNode
->GetBorderWidth( ) );
415 Point
aBarPos( maPosition
+ aBarOffset
);
417 tools::Rectangle
aBar( aBarPos
, Size( nBarWidth
, nBarHeight
) );
418 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
419 //! increasing zoomfactor.
420 // This is done by shifting its output-position to a point that
421 // corresponds exactly to a pixel on the output device.
422 Point
aDrawPos( mrDev
.PixelToLogic( mrDev
.LogicToPixel( aBar
.TopLeft( ) ) ) );
423 aBar
.SetPos( aDrawPos
);
425 mrDev
.DrawRect( aBar
);
428 void SmDrawingVisitor::Visit( SmPolyLineNode
* pNode
)
430 if ( pNode
->IsPhantom( ) )
433 tools::Long nBorderwidth
= pNode
->GetFont( ).GetBorderWidth( );
436 aInfo
.SetWidth( pNode
->GetWidth( ) - 2 * nBorderwidth
);
438 Point
aOffset ( Point( ) - pNode
->GetPolygon( ).GetBoundRect( ).TopLeft( )
439 + Point( nBorderwidth
, nBorderwidth
) ),
440 aPos ( maPosition
+ aOffset
);
441 pNode
->GetPolygon( ).Move( aPos
.X( ), aPos
.Y( ) ); //Works because Polygon wraps a pointer
443 SmTmpDevice
aTmpDev ( mrDev
, false );
444 aTmpDev
.SetLineColor( pNode
->GetFont( ).GetColor( ) );
446 mrDev
.DrawPolyLine( pNode
->GetPolygon( ), aInfo
);
449 void SmDrawingVisitor::Visit( SmRectangleNode
* pNode
)
451 if ( pNode
->IsPhantom( ) )
454 SmTmpDevice
aTmpDev ( mrDev
, false );
455 aTmpDev
.SetFillColor( pNode
->GetFont( ).GetColor( ) );
456 mrDev
.SetLineColor( );
457 aTmpDev
.SetFont( pNode
->GetFont( ) );
459 sal_uLong nTmpBorderWidth
= pNode
->GetFont( ).GetBorderWidth( );
461 // get rectangle and remove borderspace
462 tools::Rectangle
aTmp ( pNode
->AsRectangle( ) + maPosition
- pNode
->GetTopLeft( ) );
463 aTmp
.AdjustLeft(nTmpBorderWidth
);
464 aTmp
.AdjustRight( -sal_Int32(nTmpBorderWidth
) );
465 aTmp
.AdjustTop(nTmpBorderWidth
);
466 aTmp
.AdjustBottom( -sal_Int32(nTmpBorderWidth
) );
468 SAL_WARN_IF( aTmp
.IsEmpty(), "starmath", "Empty rectangle" );
470 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
471 //! increasing zoomfactor.
472 // This is done by shifting its output-position to a point that
473 // corresponds exactly to a pixel on the output device.
474 Point
aPos ( mrDev
.PixelToLogic( mrDev
.LogicToPixel( aTmp
.TopLeft( ) ) ) );
477 mrDev
.DrawRect( aTmp
);
480 void SmDrawingVisitor::DrawTextNode( SmTextNode
* pNode
)
482 if ( pNode
->IsPhantom() || pNode
->GetText().isEmpty() || pNode
->GetText()[0] == '\0' )
485 SmTmpDevice
aTmpDev ( mrDev
, false );
486 aTmpDev
.SetFont( pNode
->GetFont( ) );
488 Point
aPos ( maPosition
);
489 aPos
.AdjustY(pNode
->GetBaselineOffset( ) );
490 // round to pixel coordinate
491 aPos
= mrDev
.PixelToLogic( mrDev
.LogicToPixel( aPos
) );
493 mrDev
.DrawStretchText( aPos
, pNode
->GetWidth( ), pNode
->GetText( ) );
496 void SmDrawingVisitor::DrawSpecialNode( SmSpecialNode
* pNode
)
498 //! since this chars might come from any font, that we may not have
499 //! set to ALIGN_BASELINE yet, we do it now.
500 pNode
->GetFont( ).SetAlignment( ALIGN_BASELINE
);
502 DrawTextNode( pNode
);
505 void SmDrawingVisitor::DrawChildren( SmStructureNode
* pNode
)
507 if ( pNode
->IsPhantom( ) )
510 Point rPosition
= maPosition
;
512 for( auto pChild
: *pNode
)
516 Point
aOffset ( pChild
->GetTopLeft( ) - pNode
->GetTopLeft( ) );
517 maPosition
= rPosition
+ aOffset
;
518 pChild
->Accept( this );
522 // SmSetSelectionVisitor
524 SmSetSelectionVisitor::SmSetSelectionVisitor( SmCaretPos startPos
, SmCaretPos endPos
, SmNode
* pTree
)
525 : maStartPos(startPos
)
529 //Assume that pTree is a SmTableNode
530 SAL_WARN_IF(pTree
->GetType() != SmNodeType::Table
, "starmath", "pTree should be a SmTableNode!");
531 //Visit root node, this is special as this node cannot be selected, but its children can!
532 if(pTree
->GetType() == SmNodeType::Table
){
533 //Change state if maStartPos is in front of this node
534 if( maStartPos
.pSelectedNode
== pTree
&& maStartPos
.nIndex
== 0 )
535 mbSelecting
= !mbSelecting
;
536 //Change state if maEndPos is in front of this node
537 if( maEndPos
.pSelectedNode
== pTree
&& maEndPos
.nIndex
== 0 )
538 mbSelecting
= !mbSelecting
;
539 SAL_WARN_IF(mbSelecting
, "starmath", "Caret positions needed to set mbSelecting about, shouldn't be possible!");
542 for( auto pChild
: *static_cast<SmStructureNode
*>(pTree
) )
546 pChild
->Accept( this );
547 //If we started a selection in this line and it haven't ended, we do that now!
550 SetSelectedOnAll(pChild
);
551 //Set maStartPos and maEndPos to invalid positions, this ensures that an unused
552 //start or end (because we forced end above), doesn't start a new selection.
553 maStartPos
= maEndPos
= SmCaretPos();
556 //Check if pTree isn't selected
557 SAL_WARN_IF(pTree
->IsSelected(), "starmath", "pTree should never be selected!");
558 //Discard the selection if there's a bug (it's better than crashing)
559 if(pTree
->IsSelected())
560 SetSelectedOnAll(pTree
, false);
561 }else //This shouldn't happen, but I don't see any reason to die if it does
565 void SmSetSelectionVisitor::SetSelectedOnAll( SmNode
* pSubTree
, bool IsSelected
) {
566 pSubTree
->SetSelected( IsSelected
);
568 if(pSubTree
->GetNumSubNodes() == 0)
570 //Quick BFS to set all selections
571 for( auto pChild
: *static_cast<SmStructureNode
*>(pSubTree
) )
575 SetSelectedOnAll( pChild
, IsSelected
);
579 void SmSetSelectionVisitor::DefaultVisit( SmNode
* pNode
) {
580 //Change state if maStartPos is in front of this node
581 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 0 )
582 mbSelecting
= !mbSelecting
;
583 //Change state if maEndPos is in front of this node
584 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 0 )
585 mbSelecting
= !mbSelecting
;
587 //Cache current state
588 bool WasSelecting
= mbSelecting
;
589 bool ChangedState
= false;
592 pNode
->SetSelected( mbSelecting
);
595 if(pNode
->GetNumSubNodes() > 0)
597 for( auto pChild
: *static_cast<SmStructureNode
*>(pNode
) )
601 pChild
->Accept( this );
602 ChangedState
= ( WasSelecting
!= mbSelecting
) || ChangedState
;
609 //Select this node and all of its children
610 //(Make exception for SmBracebodyNode)
611 if( pNode
->GetType() != SmNodeType::Bracebody
||
612 !pNode
->GetParent() ||
613 pNode
->GetParent()->GetType() != SmNodeType::Brace
)
614 SetSelectedOnAll( pNode
);
616 SetSelectedOnAll( pNode
->GetParent() );
617 /* If the equation is: sqrt{2 + 4} + 5
618 * And the selection is: sqrt{2 + [4} +] 5
619 * Where [ denotes maStartPos and ] denotes maEndPos
620 * Then the sqrt node should be selected, so that the
621 * effective selection is: [sqrt{2 + 4} +] 5
622 * The same is the case if we swap maStartPos and maEndPos.
626 //Change state if maStartPos is after this node
627 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 1 )
629 mbSelecting
= !mbSelecting
;
631 //Change state if maEndPos is after of this node
632 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 1 )
634 mbSelecting
= !mbSelecting
;
638 void SmSetSelectionVisitor::VisitCompositionNode( SmStructureNode
* pNode
)
640 //Change state if maStartPos is in front of this node
641 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 0 )
642 mbSelecting
= !mbSelecting
;
643 //Change state if maEndPos is in front of this node
644 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 0 )
645 mbSelecting
= !mbSelecting
;
647 //Cache current state
648 bool WasSelecting
= mbSelecting
;
651 for( auto pChild
: *pNode
)
655 pChild
->Accept( this );
658 //Set selected, if everything was selected
659 pNode
->SetSelected( WasSelecting
&& mbSelecting
);
661 //Change state if maStartPos is after this node
662 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 1 )
663 mbSelecting
= !mbSelecting
;
664 //Change state if maEndPos is after of this node
665 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 1 )
666 mbSelecting
= !mbSelecting
;
669 void SmSetSelectionVisitor::Visit( SmTextNode
* pNode
) {
672 if( maStartPos
.pSelectedNode
== pNode
)
673 i1
= maStartPos
.nIndex
;
674 if( maEndPos
.pSelectedNode
== pNode
)
675 i2
= maEndPos
.nIndex
;
677 tools::Long start
, end
;
678 pNode
->SetSelected(true);
679 if( i1
!= -1 && i2
!= -1 ) {
680 start
= std::min(i1
, i2
);
681 end
= std::max(i1
, i2
);
682 } else if( mbSelecting
&& i1
!= -1 ) {
686 } else if( mbSelecting
&& i2
!= -1 ) {
690 } else if( !mbSelecting
&& i1
!= -1 ) {
692 end
= pNode
->GetText().getLength();
694 } else if( !mbSelecting
&& i2
!= -1 ) {
696 end
= pNode
->GetText().getLength();
698 } else if( mbSelecting
) {
700 end
= pNode
->GetText().getLength();
702 pNode
->SetSelected( false );
706 pNode
->SetSelected( start
!= end
);
707 pNode
->SetSelectionStart( start
);
708 pNode
->SetSelectionEnd( end
);
711 void SmSetSelectionVisitor::Visit( SmExpressionNode
* pNode
) {
712 VisitCompositionNode( pNode
);
715 void SmSetSelectionVisitor::Visit( SmLineNode
* pNode
) {
716 VisitCompositionNode( pNode
);
719 void SmSetSelectionVisitor::Visit( SmAlignNode
* pNode
) {
720 VisitCompositionNode( pNode
);
723 void SmSetSelectionVisitor::Visit( SmBinHorNode
* pNode
) {
724 VisitCompositionNode( pNode
);
727 void SmSetSelectionVisitor::Visit( SmUnHorNode
* pNode
) {
728 VisitCompositionNode( pNode
);
731 void SmSetSelectionVisitor::Visit( SmFontNode
* pNode
) {
732 VisitCompositionNode( pNode
);
735 // SmCaretPosGraphBuildingVisitor
737 SmCaretPosGraphBuildingVisitor::SmCaretPosGraphBuildingVisitor( SmNode
* pRootNode
)
738 : mpRightMost(nullptr)
739 , mpGraph(new SmCaretPosGraph
)
741 //pRootNode should always be a table
742 SAL_WARN_IF( pRootNode
->GetType( ) != SmNodeType::Table
, "starmath", "pRootNode must be a table node");
743 //Handle the special case where SmNodeType::Table is used a rootnode
744 if( pRootNode
->GetType( ) == SmNodeType::Table
){
745 //Children are SmLineNodes
746 //Or so I thought... Apparently, the children can be instances of SmExpression
747 //especially if there's an error in the formula... So here we go, a simple work around.
748 for( auto pChild
: *static_cast<SmStructureNode
*>(pRootNode
) )
752 mpRightMost
= mpGraph
->Add( SmCaretPos( pChild
, 0 ) );
753 pChild
->Accept( this );
756 pRootNode
->Accept(this);
759 SmCaretPosGraphBuildingVisitor::~SmCaretPosGraphBuildingVisitor()
763 void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode
* pNode
){
764 for( auto pChild
: *pNode
)
768 pChild
->Accept( this );
772 /** Build SmCaretPosGraph for SmTableNode
773 * This method covers cases where SmTableNode is used in a binom or stack,
774 * the special case where it is used as root node for the entire formula is
775 * handled in the constructor.
777 void SmCaretPosGraphBuildingVisitor::Visit( SmTableNode
* pNode
){
778 SmCaretPosGraphEntry
*left
= mpRightMost
,
779 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1) );
780 bool bIsFirst
= true;
781 for( auto pChild
: *pNode
)
785 mpRightMost
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
787 left
->SetRight(mpRightMost
);
788 pChild
->Accept( this );
789 mpRightMost
->SetRight(right
);
791 right
->SetLeft(mpRightMost
);
797 /** Build SmCaretPosGraph for SmSubSupNode
799 * The child positions in a SubSupNode, where H is the body:
812 * Graph over these, where "left" is before the SmSubSupNode and "right" is after:
827 void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode
* pNode
)
829 SmCaretPosGraphEntry
*left
,
838 SAL_WARN_IF( !pNode
->GetBody(), "starmath", "SmSubSupNode Doesn't have a body!" );
839 bodyLeft
= mpGraph
->Add( SmCaretPos( pNode
->GetBody( ), 0 ), left
);
840 left
->SetRight( bodyLeft
); //TODO: Don't make this if LSUP or LSUB are NULL ( not sure??? )
843 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
845 //Visit the body, to get bodyRight
846 mpRightMost
= bodyLeft
;
847 pNode
->GetBody( )->Accept( this );
848 bodyRight
= mpRightMost
;
849 bodyRight
->SetRight( right
);
850 right
->SetLeft( bodyRight
);
853 SmNode
* pChild
= pNode
->GetSubSup( LSUP
);
855 SmCaretPosGraphEntry
*cLeft
; //Child left
856 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
859 pChild
->Accept( this );
861 mpRightMost
->SetRight( bodyLeft
);
864 pChild
= pNode
->GetSubSup( LSUB
);
866 SmCaretPosGraphEntry
*cLeft
; //Child left
867 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
870 pChild
->Accept( this );
872 mpRightMost
->SetRight( bodyLeft
);
875 pChild
= pNode
->GetSubSup( CSUP
);
877 SmCaretPosGraphEntry
*cLeft
; //Child left
878 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
881 pChild
->Accept( this );
883 mpRightMost
->SetRight( right
);
886 pChild
= pNode
->GetSubSup( CSUB
);
888 SmCaretPosGraphEntry
*cLeft
; //Child left
889 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
892 pChild
->Accept( this );
894 mpRightMost
->SetRight( right
);
897 pChild
= pNode
->GetSubSup( RSUP
);
899 SmCaretPosGraphEntry
*cLeft
; //Child left
900 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), bodyRight
);
903 pChild
->Accept( this );
905 mpRightMost
->SetRight( right
);
908 pChild
= pNode
->GetSubSup( RSUB
);
910 SmCaretPosGraphEntry
*cLeft
; //Child left
911 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), bodyRight
);
914 pChild
->Accept( this );
916 mpRightMost
->SetRight( right
);
919 //Set return parameters
923 /** Build caret position for SmOperNode
925 * If first child is an SmSubSupNode we will ignore its
926 * body, as this body is a SmMathSymbol, for SUM, INT or similar
927 * that shouldn't be subject to modification.
928 * If first child is not a SmSubSupNode, ignore it completely
929 * as it is a SmMathSymbol.
931 * The child positions in a SmOperNode, where H is symbol, e.g. int, sum or similar:
935 * LSUP H H RSUP BBB BB BBB B B
936 * H H B B B B B B B B
939 * LSUB H H RSUB BBB BB BBB B
943 * Notice, CSUP, etc. are actually grandchildren, but inorder to ignore H, these are visited
944 * from here. If they are present, that is if pOper is an instance of SmSubSupNode.
946 * Graph over these, where "left" is before the SmOperNode and "right" is after:
960 void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode
* pNode
)
962 SmNode
*pOper
= pNode
->GetSubNode( 0 ),
963 *pBody
= pNode
->GetSubNode( 1 );
965 SmCaretPosGraphEntry
*left
= mpRightMost
,
970 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
971 left
->SetRight( bodyLeft
);
973 //Visit body, get bodyRight
974 mpRightMost
= bodyLeft
;
975 pBody
->Accept( this );
976 bodyRight
= mpRightMost
;
979 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), bodyRight
);
980 bodyRight
->SetRight( right
);
982 //Get subsup pNode if any
983 SmSubSupNode
* pSubSup
= pOper
->GetType( ) == SmNodeType::SubSup
? static_cast<SmSubSupNode
*>(pOper
) : nullptr;
986 SmNode
* pChild
= pSubSup
->GetSubSup( LSUP
);
988 //Create position in front of pChild
989 SmCaretPosGraphEntry
*childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
991 mpRightMost
= childLeft
;
992 pChild
->Accept( this );
993 //Set right on mpRightMost from pChild
994 mpRightMost
->SetRight( bodyLeft
);
997 pChild
= pSubSup
->GetSubSup( LSUB
);
999 //Create position in front of pChild
1000 SmCaretPosGraphEntry
*childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1002 mpRightMost
= childLeft
;
1003 pChild
->Accept( this );
1004 //Set right on mpRightMost from pChild
1005 mpRightMost
->SetRight( bodyLeft
);
1008 pChild
= pSubSup
->GetSubSup( CSUP
);
1010 //Create position in front of pChild
1011 SmCaretPosGraphEntry
*childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1013 mpRightMost
= childLeft
;
1014 pChild
->Accept( this );
1015 //Set right on mpRightMost from pChild
1016 mpRightMost
->SetRight( bodyLeft
);
1019 pChild
= pSubSup
->GetSubSup( CSUB
);
1020 if( pChild
) { //FROM
1021 //Create position in front of pChild
1022 SmCaretPosGraphEntry
*childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1024 mpRightMost
= childLeft
;
1025 pChild
->Accept( this );
1026 //Set right on mpRightMost from pChild
1027 mpRightMost
->SetRight( bodyLeft
);
1030 pChild
= pSubSup
->GetSubSup( RSUP
);
1032 //Create position in front of pChild
1033 SmCaretPosGraphEntry
*childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1035 mpRightMost
= childLeft
;
1036 pChild
->Accept( this );
1037 //Set right on mpRightMost from pChild
1038 mpRightMost
->SetRight( bodyLeft
);
1041 pChild
= pSubSup
->GetSubSup( RSUB
);
1043 //Create position in front of pChild
1044 SmCaretPosGraphEntry
*childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1046 mpRightMost
= childLeft
;
1047 pChild
->Accept( this );
1048 //Set right on mpRightMost from pChild
1049 mpRightMost
->SetRight( bodyLeft
);
1054 mpRightMost
= right
;
1057 void SmCaretPosGraphBuildingVisitor::Visit( SmMatrixNode
* pNode
)
1059 SmCaretPosGraphEntry
*left
= mpRightMost
,
1060 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1062 for (size_t i
= 0; i
< pNode
->GetNumRows(); ++i
)
1064 SmCaretPosGraphEntry
* r
= left
;
1065 for (size_t j
= 0; j
< pNode
->GetNumCols(); ++j
)
1067 SmNode
* pSubNode
= pNode
->GetSubNode( i
* pNode
->GetNumCols( ) + j
);
1069 mpRightMost
= mpGraph
->Add( SmCaretPos( pSubNode
, 0 ), r
);
1070 if( j
!= 0 || ( pNode
->GetNumRows() - 1U ) / 2 == i
)
1071 r
->SetRight( mpRightMost
);
1073 pSubNode
->Accept( this );
1077 mpRightMost
->SetRight( right
);
1078 if( ( pNode
->GetNumRows() - 1U ) / 2 == i
)
1079 right
->SetLeft( mpRightMost
);
1082 mpRightMost
= right
;
1085 /** Build SmCaretPosGraph for SmTextNode
1087 * Lines in an SmTextNode:
1091 * Where A B and C are characters in the text.
1093 * Graph over these, where "left" is before the SmTextNode and "right" is after:
1101 * Notice that C and right is the same position here.
1103 void SmCaretPosGraphBuildingVisitor::Visit( SmTextNode
* pNode
)
1105 SAL_WARN_IF( pNode
->GetText().isEmpty(), "starmath", "Empty SmTextNode is bad" );
1107 int size
= pNode
->GetText().getLength();
1108 for( int i
= 1; i
<= size
; i
++ ){
1109 SmCaretPosGraphEntry
* pRight
= mpRightMost
;
1110 mpRightMost
= mpGraph
->Add( SmCaretPos( pNode
, i
), pRight
);
1111 pRight
->SetRight( mpRightMost
);
1115 /** Build SmCaretPosGraph for SmBinVerNode
1117 * Lines in an SmBinVerNode:
1124 * Graph over these, where "left" is before the SmBinVerNode and "right" is after:
1133 void SmCaretPosGraphBuildingVisitor::Visit( SmBinVerNode
* pNode
)
1135 //None if these children can be NULL, see SmBinVerNode::Arrange
1136 SmNode
*pNum
= pNode
->GetSubNode( 0 ),
1137 *pDenom
= pNode
->GetSubNode( 2 );
1139 SmCaretPosGraphEntry
*left
,
1144 assert(mpRightMost
);
1149 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1152 numLeft
= mpGraph
->Add( SmCaretPos( pNum
, 0 ), left
);
1153 left
->SetRight( numLeft
);
1156 mpRightMost
= numLeft
;
1157 pNum
->Accept( this );
1158 mpRightMost
->SetRight( right
);
1159 right
->SetLeft( mpRightMost
);
1162 denomLeft
= mpGraph
->Add( SmCaretPos( pDenom
, 0 ), left
);
1165 mpRightMost
= denomLeft
;
1166 pDenom
->Accept( this );
1167 mpRightMost
->SetRight( right
);
1169 //Set return parameter
1170 mpRightMost
= right
;
1173 /** Build SmCaretPosGraph for SmVerticalBraceNode
1175 * Lines in an SmVerticalBraceNode:
1184 void SmCaretPosGraphBuildingVisitor::Visit( SmVerticalBraceNode
* pNode
)
1186 SmNode
*pBody
= pNode
->Body(),
1187 *pScript
= pNode
->Script();
1188 //None of these children can be NULL
1190 SmCaretPosGraphEntry
*left
,
1198 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1201 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1202 left
->SetRight( bodyLeft
);
1203 mpRightMost
= bodyLeft
;
1204 pBody
->Accept( this );
1205 mpRightMost
->SetRight( right
);
1206 right
->SetLeft( mpRightMost
);
1209 scriptLeft
= mpGraph
->Add( SmCaretPos( pScript
, 0 ), left
);
1210 mpRightMost
= scriptLeft
;
1211 pScript
->Accept( this );
1212 mpRightMost
->SetRight( right
);
1215 mpRightMost
= right
;
1218 /** Build SmCaretPosGraph for SmBinDiagonalNode
1220 * Lines in an SmBinDiagonalNode:
1226 * Where A and B are lines.
1228 * Used in formulas such as "A wideslash B"
1230 void SmCaretPosGraphBuildingVisitor::Visit( SmBinDiagonalNode
* pNode
)
1232 SmNode
*A
= pNode
->GetSubNode( 0 ),
1233 *B
= pNode
->GetSubNode( 1 );
1235 SmCaretPosGraphEntry
*left
,
1243 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1246 leftA
= mpGraph
->Add( SmCaretPos( A
, 0 ), left
);
1247 left
->SetRight( leftA
);
1250 mpRightMost
= leftA
;
1252 rightA
= mpRightMost
;
1255 leftB
= mpGraph
->Add( SmCaretPos( B
, 0 ), rightA
);
1256 rightA
->SetRight( leftB
);
1259 mpRightMost
= leftB
;
1261 mpRightMost
->SetRight( right
);
1262 right
->SetLeft( mpRightMost
);
1265 mpRightMost
= right
;
1268 //Straight forward ( I think )
1269 void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode
* pNode
)
1271 for( auto pChild
: *pNode
)
1275 pChild
->Accept( this );
1278 void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode
* pNode
)
1280 // Unary operator node
1281 for( auto pChild
: *pNode
)
1285 pChild
->Accept( this );
1289 void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode
* pNode
)
1291 for( auto pChild
: *pNode
)
1295 pChild
->Accept( this );
1299 void SmCaretPosGraphBuildingVisitor::Visit( SmFontNode
* pNode
)
1301 //Has only got one child, should act as an expression if possible
1302 for( auto pChild
: *pNode
)
1306 pChild
->Accept( this );
1310 /** Build SmCaretPosGraph for SmBracebodyNode
1311 * Acts as an SmExpressionNode
1313 * Below is an example of a formula tree that has multiple children for SmBracebodyNode
1317 * label= "Equation: \"lbrace i mline i in setZ rbrace\"";
1318 * n0 [label="SmTableNode"];
1319 * n0 -> n1 [label="0"];
1320 * n1 [label="SmLineNode"];
1321 * n1 -> n2 [label="0"];
1322 * n2 [label="SmExpressionNode"];
1323 * n2 -> n3 [label="0"];
1324 * n3 [label="SmBraceNode"];
1325 * n3 -> n4 [label="0"];
1326 * n4 [label="SmMathSymbolNode: {"];
1327 * n3 -> n5 [label="1"];
1328 * n5 [label="SmBracebodyNode"];
1329 * n5 -> n6 [label="0"];
1330 * n6 [label="SmExpressionNode"];
1331 * n6 -> n7 [label="0"];
1332 * n7 [label="SmTextNode: i"];
1333 * n5 -> n8 [label="1"];
1334 * n8 [label="SmMathSymbolNode: |"]; // Unicode "VERTICAL LINE"
1335 * n5 -> n9 [label="2"];
1336 * n9 [label="SmExpressionNode"];
1337 * n9 -> n10 [label="0"];
1338 * n10 [label="SmBinHorNode"];
1339 * n10 -> n11 [label="0"];
1340 * n11 [label="SmTextNode: i"];
1341 * n10 -> n12 [label="1"];
1342 * n12 [label="SmMathSymbolNode: ∈"]; // Unicode "ELEMENT OF"
1343 * n10 -> n13 [label="2"];
1344 * n13 [label="SmMathSymbolNode: ℤ"]; // Unicode "DOUBLE-STRUCK CAPITAL Z"
1345 * n3 -> n14 [label="2"];
1346 * n14 [label="SmMathSymbolNode: }"];
1350 void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode
* pNode
)
1352 for( auto pChild
: *pNode
)
1356 SmCaretPosGraphEntry
* pStart
= mpGraph
->Add( SmCaretPos( pChild
, 0), mpRightMost
);
1357 mpRightMost
->SetRight( pStart
);
1358 mpRightMost
= pStart
;
1359 pChild
->Accept( this );
1363 /** Build SmCaretPosGraph for SmAlignNode
1364 * Acts as an SmExpressionNode, as it only has one child this okay
1366 void SmCaretPosGraphBuildingVisitor::Visit( SmAlignNode
* pNode
)
1368 for( auto pChild
: *pNode
)
1372 pChild
->Accept( this );
1376 /** Build SmCaretPosGraph for SmRootNode
1378 * Lines in an SmRootNode:
1385 * A: pExtra ( optional, can be NULL ),
1388 * Graph over these, where "left" is before the SmRootNode and "right" is after:
1397 void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode
* pNode
)
1399 SmNode
*pExtra
= pNode
->GetSubNode( 0 ), //Argument, NULL for sqrt, and SmTextNode if cubicroot
1400 *pBody
= pNode
->GetSubNode( 2 ); //Body of the root
1403 SmCaretPosGraphEntry
*left
,
1408 //Get left and save it
1409 assert(mpRightMost
);
1413 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1414 left
->SetRight( bodyLeft
);
1417 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1420 mpRightMost
= bodyLeft
;
1421 pBody
->Accept( this );
1422 bodyRight
= mpRightMost
;
1423 bodyRight
->SetRight( right
);
1424 right
->SetLeft( bodyRight
);
1428 mpRightMost
= mpGraph
->Add( SmCaretPos( pExtra
, 0 ), left
);
1429 pExtra
->Accept( this );
1430 mpRightMost
->SetRight( bodyLeft
);
1433 mpRightMost
= right
;
1437 /** Build SmCaretPosGraph for SmPlaceNode
1438 * Consider this a single character.
1440 void SmCaretPosGraphBuildingVisitor::Visit( SmPlaceNode
* pNode
)
1442 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1443 mpRightMost
->SetRight( right
);
1444 mpRightMost
= right
;
1447 /** SmErrorNode is context dependent metadata, it can't be selected
1449 * @remarks There's no point in deleting, copying and/or moving an instance
1450 * of SmErrorNode as it may not exist in another context! Thus there are no
1451 * positions to select an SmErrorNode.
1453 void SmCaretPosGraphBuildingVisitor::Visit( SmErrorNode
* )
1457 /** Build SmCaretPosGraph for SmBlankNode
1458 * Consider this a single character, as it is only a blank space
1460 void SmCaretPosGraphBuildingVisitor::Visit( SmBlankNode
* pNode
)
1462 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1463 mpRightMost
->SetRight( right
);
1464 mpRightMost
= right
;
1467 /** Build SmCaretPosGraph for SmBraceNode
1469 * Lines in an SmBraceNode:
1477 * Graph over these, where "left" is before the SmBraceNode and "right" is after:
1485 void SmCaretPosGraphBuildingVisitor::Visit( SmBraceNode
* pNode
)
1487 SmNode
* pBody
= pNode
->Body();
1489 SmCaretPosGraphEntry
*left
= mpRightMost
,
1490 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1492 if( pBody
->GetType() != SmNodeType::Bracebody
) {
1493 mpRightMost
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1494 left
->SetRight( mpRightMost
);
1498 pBody
->Accept( this );
1499 mpRightMost
->SetRight( right
);
1500 right
->SetLeft( mpRightMost
);
1502 mpRightMost
= right
;
1505 /** Build SmCaretPosGraph for SmAttributNode
1507 * Lines in an SmAttributNode:
1513 * There's a body and an attribute, the construction is used for "widehat A", where "A" is the body
1514 * and "^" is the attribute ( note GetScaleMode( ) on SmAttributNode tells how the attribute should be
1517 void SmCaretPosGraphBuildingVisitor::Visit( SmAttributNode
* pNode
)
1519 SmNode
*pAttr
= pNode
->Attribute(),
1520 *pBody
= pNode
->Body();
1524 SmCaretPosGraphEntry
*left
= mpRightMost
,
1531 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1532 left
->SetRight( bodyLeft
);
1535 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1538 mpRightMost
= bodyLeft
;
1539 pBody
->Accept( this );
1540 bodyRight
= mpRightMost
;
1541 bodyRight
->SetRight( right
);
1542 right
->SetLeft( bodyRight
);
1545 attrLeft
= mpGraph
->Add( SmCaretPos( pAttr
, 0 ), left
);
1548 mpRightMost
= attrLeft
;
1549 pAttr
->Accept( this );
1550 mpRightMost
->SetRight( right
);
1553 mpRightMost
= right
;
1556 //Consider these single symbols
1557 void SmCaretPosGraphBuildingVisitor::Visit( SmSpecialNode
* pNode
)
1559 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1560 mpRightMost
->SetRight( right
);
1561 mpRightMost
= right
;
1563 void SmCaretPosGraphBuildingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
1565 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1566 mpRightMost
->SetRight( right
);
1567 mpRightMost
= right
;
1569 void SmCaretPosGraphBuildingVisitor::Visit( SmMathSymbolNode
* pNode
)
1571 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1572 mpRightMost
->SetRight( right
);
1573 mpRightMost
= right
;
1576 void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode
* )
1581 void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode
* )
1585 void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode
* )
1592 SmNode
* SmCloningVisitor::Clone( SmNode
* pNode
)
1594 SmNode
* pCurrResult
= mpResult
;
1595 pNode
->Accept( this );
1596 SmNode
* pClone
= mpResult
;
1597 mpResult
= pCurrResult
;
1601 void SmCloningVisitor::CloneNodeAttr( SmNode
const * pSource
, SmNode
* pTarget
)
1603 pTarget
->SetScaleMode( pSource
->GetScaleMode( ) );
1604 //Other attributes are set when prepare or arrange is executed
1605 //and may depend on stuff not being cloned here.
1608 void SmCloningVisitor::CloneKids( SmStructureNode
* pSource
, SmStructureNode
* pTarget
)
1610 //Cache current result
1611 SmNode
* pCurrResult
= mpResult
;
1613 //Create array for holding clones
1614 size_t nSize
= pSource
->GetNumSubNodes( );
1615 SmNodeArray
aNodes( nSize
);
1618 for (size_t i
= 0; i
< nSize
; ++i
)
1621 if( nullptr != ( pKid
= pSource
->GetSubNode( i
) ) )
1622 pKid
->Accept( this );
1625 aNodes
[i
] = mpResult
;
1628 //Set subnodes of pTarget
1629 pTarget
->SetSubNodes( std::move(aNodes
) );
1631 //Restore result as where prior to call
1632 mpResult
= pCurrResult
;
1635 void SmCloningVisitor::Visit( SmTableNode
* pNode
)
1637 SmTableNode
* pClone
= new SmTableNode( pNode
->GetToken( ) );
1638 CloneNodeAttr( pNode
, pClone
);
1639 CloneKids( pNode
, pClone
);
1643 void SmCloningVisitor::Visit( SmBraceNode
* pNode
)
1645 SmBraceNode
* pClone
= new SmBraceNode( pNode
->GetToken( ) );
1646 CloneNodeAttr( pNode
, pClone
);
1647 CloneKids( pNode
, pClone
);
1651 void SmCloningVisitor::Visit( SmBracebodyNode
* pNode
)
1653 SmBracebodyNode
* pClone
= new SmBracebodyNode( pNode
->GetToken( ) );
1654 CloneNodeAttr( pNode
, pClone
);
1655 CloneKids( pNode
, pClone
);
1659 void SmCloningVisitor::Visit( SmOperNode
* pNode
)
1661 SmOperNode
* pClone
= new SmOperNode( pNode
->GetToken( ) );
1662 CloneNodeAttr( pNode
, pClone
);
1663 CloneKids( pNode
, pClone
);
1667 void SmCloningVisitor::Visit( SmAlignNode
* pNode
)
1669 SmAlignNode
* pClone
= new SmAlignNode( pNode
->GetToken( ) );
1670 CloneNodeAttr( pNode
, pClone
);
1671 CloneKids( pNode
, pClone
);
1675 void SmCloningVisitor::Visit( SmAttributNode
* pNode
)
1677 SmAttributNode
* pClone
= new SmAttributNode( pNode
->GetToken( ) );
1678 CloneNodeAttr( pNode
, pClone
);
1679 CloneKids( pNode
, pClone
);
1683 void SmCloningVisitor::Visit( SmFontNode
* pNode
)
1685 SmFontNode
* pClone
= new SmFontNode( pNode
->GetToken( ) );
1686 pClone
->SetSizeParameter( pNode
->GetSizeParameter( ), pNode
->GetSizeType( ) );
1687 CloneNodeAttr( pNode
, pClone
);
1688 CloneKids( pNode
, pClone
);
1692 void SmCloningVisitor::Visit( SmUnHorNode
* pNode
)
1694 SmUnHorNode
* pClone
= new SmUnHorNode( pNode
->GetToken( ) );
1695 CloneNodeAttr( pNode
, pClone
);
1696 CloneKids( pNode
, pClone
);
1700 void SmCloningVisitor::Visit( SmBinHorNode
* pNode
)
1702 SmBinHorNode
* pClone
= new SmBinHorNode( pNode
->GetToken( ) );
1703 CloneNodeAttr( pNode
, pClone
);
1704 CloneKids( pNode
, pClone
);
1708 void SmCloningVisitor::Visit( SmBinVerNode
* pNode
)
1710 SmBinVerNode
* pClone
= new SmBinVerNode( pNode
->GetToken( ) );
1711 CloneNodeAttr( pNode
, pClone
);
1712 CloneKids( pNode
, pClone
);
1716 void SmCloningVisitor::Visit( SmBinDiagonalNode
* pNode
)
1718 SmBinDiagonalNode
*pClone
= new SmBinDiagonalNode( pNode
->GetToken( ) );
1719 pClone
->SetAscending( pNode
->IsAscending( ) );
1720 CloneNodeAttr( pNode
, pClone
);
1721 CloneKids( pNode
, pClone
);
1725 void SmCloningVisitor::Visit( SmSubSupNode
* pNode
)
1727 SmSubSupNode
*pClone
= new SmSubSupNode( pNode
->GetToken( ) );
1728 pClone
->SetUseLimits( pNode
->IsUseLimits( ) );
1729 CloneNodeAttr( pNode
, pClone
);
1730 CloneKids( pNode
, pClone
);
1734 void SmCloningVisitor::Visit( SmMatrixNode
* pNode
)
1736 SmMatrixNode
*pClone
= new SmMatrixNode( pNode
->GetToken( ) );
1737 pClone
->SetRowCol( pNode
->GetNumRows( ), pNode
->GetNumCols( ) );
1738 CloneNodeAttr( pNode
, pClone
);
1739 CloneKids( pNode
, pClone
);
1743 void SmCloningVisitor::Visit( SmPlaceNode
* pNode
)
1745 mpResult
= new SmPlaceNode( pNode
->GetToken( ) );
1746 CloneNodeAttr( pNode
, mpResult
);
1749 void SmCloningVisitor::Visit( SmTextNode
* pNode
)
1751 SmTextNode
* pClone
= new SmTextNode( pNode
->GetToken( ), pNode
->GetFontDesc( ) );
1752 pClone
->ChangeText( pNode
->GetText( ) );
1753 CloneNodeAttr( pNode
, pClone
);
1757 void SmCloningVisitor::Visit( SmSpecialNode
* pNode
)
1759 mpResult
= new SmSpecialNode( pNode
->GetToken( ) );
1760 CloneNodeAttr( pNode
, mpResult
);
1763 void SmCloningVisitor::Visit( SmGlyphSpecialNode
* pNode
)
1765 mpResult
= new SmGlyphSpecialNode( pNode
->GetToken( ) );
1766 CloneNodeAttr( pNode
, mpResult
);
1769 void SmCloningVisitor::Visit( SmMathSymbolNode
* pNode
)
1771 mpResult
= new SmMathSymbolNode( pNode
->GetToken( ) );
1772 CloneNodeAttr( pNode
, mpResult
);
1775 void SmCloningVisitor::Visit( SmBlankNode
* pNode
)
1777 SmBlankNode
* pClone
= new SmBlankNode( pNode
->GetToken( ) );
1778 pClone
->SetBlankNum( pNode
->GetBlankNum( ) );
1780 CloneNodeAttr( pNode
, mpResult
);
1783 void SmCloningVisitor::Visit( SmErrorNode
* pNode
)
1785 mpResult
= new SmErrorNode( pNode
->GetToken( ) );
1786 CloneNodeAttr( pNode
, mpResult
);
1789 void SmCloningVisitor::Visit( SmLineNode
* pNode
)
1791 SmLineNode
* pClone
= new SmLineNode( pNode
->GetToken( ) );
1792 CloneNodeAttr( pNode
, pClone
);
1793 CloneKids( pNode
, pClone
);
1797 void SmCloningVisitor::Visit( SmExpressionNode
* pNode
)
1799 SmExpressionNode
* pClone
= new SmExpressionNode( pNode
->GetToken( ) );
1800 CloneNodeAttr( pNode
, pClone
);
1801 CloneKids( pNode
, pClone
);
1805 void SmCloningVisitor::Visit( SmPolyLineNode
* pNode
)
1807 mpResult
= new SmPolyLineNode( pNode
->GetToken( ) );
1808 CloneNodeAttr( pNode
, mpResult
);
1811 void SmCloningVisitor::Visit( SmRootNode
* pNode
)
1813 SmRootNode
* pClone
= new SmRootNode( pNode
->GetToken( ) );
1814 CloneNodeAttr( pNode
, pClone
);
1815 CloneKids( pNode
, pClone
);
1819 void SmCloningVisitor::Visit( SmRootSymbolNode
* pNode
)
1821 mpResult
= new SmRootSymbolNode( pNode
->GetToken( ) );
1822 CloneNodeAttr( pNode
, mpResult
);
1825 void SmCloningVisitor::Visit( SmRectangleNode
* pNode
)
1827 mpResult
= new SmRectangleNode( pNode
->GetToken( ) );
1828 CloneNodeAttr( pNode
, mpResult
);
1831 void SmCloningVisitor::Visit( SmVerticalBraceNode
* pNode
)
1833 SmVerticalBraceNode
* pClone
= new SmVerticalBraceNode( pNode
->GetToken( ) );
1834 CloneNodeAttr( pNode
, pClone
);
1835 CloneKids( pNode
, pClone
);
1839 // SmSelectionDrawingVisitor
1841 SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice
& rDevice
, SmNode
* pTree
, const Point
& rOffset
)
1843 , mbHasSelectionArea( false )
1846 SAL_WARN_IF( !pTree
, "starmath", "pTree can't be null!" );
1848 pTree
->Accept( this );
1850 //Draw selection if there's any
1851 if( !mbHasSelectionArea
) return;
1853 maSelectionArea
.Move( rOffset
.X( ), rOffset
.Y( ) );
1856 mrDev
.Push( PushFlags::LINECOLOR
| PushFlags::FILLCOLOR
);
1858 mrDev
.SetLineColor( );
1859 mrDev
.SetFillColor( COL_LIGHTGRAY
);
1862 mrDev
.DrawRect( maSelectionArea
);
1864 //Restore device state
1868 void SmSelectionDrawingVisitor::ExtendSelectionArea(const tools::Rectangle
& rArea
)
1870 if ( ! mbHasSelectionArea
) {
1871 maSelectionArea
= rArea
;
1872 mbHasSelectionArea
= true;
1874 maSelectionArea
.Union(rArea
);
1877 void SmSelectionDrawingVisitor::DefaultVisit( SmNode
* pNode
)
1879 if( pNode
->IsSelected( ) )
1880 ExtendSelectionArea( pNode
->AsRectangle( ) );
1881 VisitChildren( pNode
);
1884 void SmSelectionDrawingVisitor::VisitChildren( SmNode
* pNode
)
1886 if(pNode
->GetNumSubNodes() == 0)
1888 for( auto pChild
: *static_cast<SmStructureNode
*>(pNode
) )
1892 pChild
->Accept( this );
1896 void SmSelectionDrawingVisitor::Visit( SmTextNode
* pNode
)
1898 if( !pNode
->IsSelected())
1901 mrDev
.Push( PushFlags::TEXTCOLOR
| PushFlags::FONT
);
1903 mrDev
.SetFont( pNode
->GetFont( ) );
1904 Point Position
= pNode
->GetTopLeft( );
1905 tools::Long left
= Position
.getX( ) + mrDev
.GetTextWidth( pNode
->GetText( ), 0, pNode
->GetSelectionStart( ) );
1906 tools::Long right
= Position
.getX( ) + mrDev
.GetTextWidth( pNode
->GetText( ), 0, pNode
->GetSelectionEnd( ) );
1907 tools::Long top
= Position
.getY( );
1908 tools::Long bottom
= top
+ pNode
->GetHeight( );
1909 tools::Rectangle
rect( left
, top
, right
, bottom
);
1911 ExtendSelectionArea( rect
);
1916 // SmNodeToTextVisitor
1918 SmNodeToTextVisitor::SmNodeToTextVisitor( SmNode
* pNode
, OUString
&rText
)
1920 pNode
->Accept( this );
1921 maCmdText
.stripEnd(' ');
1922 rText
= maCmdText
.makeStringAndClear();
1925 void SmNodeToTextVisitor::Visit( SmTableNode
* pNode
)
1927 if( pNode
->GetToken( ).eType
== TBINOM
) {
1928 Append( "{ binom" );
1929 LineToText( pNode
->GetSubNode( 0 ) );
1930 LineToText( pNode
->GetSubNode( 1 ) );
1932 } else if( pNode
->GetToken( ).eType
== TSTACK
) {
1933 Append( "stack{ " );
1935 for( auto pChild
: *pNode
)
1946 LineToText( pChild
);
1950 } else { //Assume it's a toplevel table, containing lines
1952 for( auto pChild
: *pNode
)
1961 Append( "newline" );
1964 pChild
->Accept( this );
1969 void SmNodeToTextVisitor::Visit( SmBraceNode
* pNode
)
1971 if ( pNode
->GetToken().eType
== TEVALUATE
)
1973 SmNode
*pBody
= pNode
->Body();
1974 Append( "evaluate { " );
1975 pBody
->Accept( this );
1979 SmNode
*pLeftBrace
= pNode
->OpeningBrace(),
1980 *pBody
= pNode
->Body(),
1981 *pRightBrace
= pNode
->ClosingBrace();
1982 //Handle special case where it's absolute function
1983 if( pNode
->GetToken( ).eType
== TABS
) {
1985 LineToText( pBody
);
1987 if( pNode
->GetScaleMode( ) == SmScaleMode::Height
)
1989 pLeftBrace
->Accept( this );
1991 pBody
->Accept( this );
1993 if( pNode
->GetScaleMode( ) == SmScaleMode::Height
)
1995 pRightBrace
->Accept( this );
2000 void SmNodeToTextVisitor::Visit( SmBracebodyNode
* pNode
)
2002 for( auto pChild
: *pNode
)
2007 pChild
->Accept( this );
2011 void SmNodeToTextVisitor::Visit( SmOperNode
* pNode
)
2013 Append( pNode
->GetToken( ).aText
);
2015 if( pNode
->GetToken( ).eType
== TOPER
){
2016 //There's an SmGlyphSpecialNode if eType == TOPER
2017 if( pNode
->GetSubNode( 0 )->GetType( ) == SmNodeType::SubSup
)
2018 Append( pNode
->GetSubNode( 0 )->GetSubNode( 0 )->GetToken( ).aText
);
2020 Append( pNode
->GetSubNode( 0 )->GetToken( ).aText
);
2022 if( pNode
->GetSubNode( 0 )->GetType( ) == SmNodeType::SubSup
) {
2023 SmSubSupNode
*pSubSup
= static_cast<SmSubSupNode
*>( pNode
->GetSubNode( 0 ) );
2024 SmNode
* pChild
= pSubSup
->GetSubSup( LSUP
);
2027 Append( "lsup { " );
2028 LineToText( pChild
);
2031 pChild
= pSubSup
->GetSubSup( LSUB
);
2034 Append( "lsub { " );
2035 LineToText( pChild
);
2038 pChild
= pSubSup
->GetSubSup( RSUP
);
2042 LineToText( pChild
);
2045 pChild
= pSubSup
->GetSubSup( RSUB
);
2049 LineToText( pChild
);
2052 pChild
= pSubSup
->GetSubSup( CSUP
);
2055 if (pSubSup
->IsUseLimits())
2058 Append( "csup { " );
2059 LineToText( pChild
);
2062 pChild
= pSubSup
->GetSubSup( CSUB
);
2065 if (pSubSup
->IsUseLimits())
2066 Append( "from { " );
2068 Append( "csub { " );
2069 LineToText( pChild
);
2073 LineToText( pNode
->GetSubNode( 1 ) );
2076 void SmNodeToTextVisitor::Visit( SmAlignNode
* pNode
)
2078 Append( pNode
->GetToken( ).aText
);
2079 LineToText( pNode
->GetSubNode( 0 ) );
2082 void SmNodeToTextVisitor::Visit( SmAttributNode
* pNode
)
2084 Append( pNode
->GetToken( ).aText
);
2085 LineToText( pNode
->Body() );
2088 void SmNodeToTextVisitor::Visit( SmFontNode
* pNode
)
2091 sal_uInt8 nr
, ng
, nb
;
2092 std::unique_ptr
<SmColorTokenTableEntry
> aSmColorTokenTableEntry
;
2093 switch ( pNode
->GetToken( ).eType
)
2102 Append( "italic " );
2105 Append( "nitalic " );
2108 Append( "phantom " );
2113 switch ( pNode
->GetSizeType( ) )
2115 case FontSizeType::PLUS
:
2118 case FontSizeType::MINUS
:
2121 case FontSizeType::MULTIPLY
:
2124 case FontSizeType::DIVIDE
:
2127 case FontSizeType::ABSOLUT
:
2131 Append( ::rtl::math::doubleToUString(
2132 static_cast<double>( pNode
->GetSizeParameter( ) ),
2133 rtl_math_StringFormat_Automatic
,
2134 rtl_math_DecimalPlaces_Max
, '.', true ) );
2139 case TDVIPSNAMESCOL
:
2140 Append( "color dvip " );
2141 nc
= pNode
->GetToken().aText
.toUInt32(16);
2142 aSmColorTokenTableEntry
= starmathdatabase::Identify_Color_Parser( nc
);
2143 Append( aSmColorTokenTableEntry
->pIdent
);
2149 nc
= pNode
->GetToken().aText
.toUInt32(16);
2150 aSmColorTokenTableEntry
= starmathdatabase::Identify_Color_Parser( nc
);
2151 Append( aSmColorTokenTableEntry
->pIdent
);
2154 nc
= pNode
->GetToken().aText
.toUInt32(16);
2155 aSmColorTokenTableEntry
= starmathdatabase::Identify_Color_Parser( nc
);
2156 Append( "color rgb " );
2162 Append(OUString::number(nr
));
2164 Append(OUString::number(ng
));
2166 Append(OUString::number(nb
));
2170 nc
= pNode
->GetToken().aText
.toUInt32(16);
2171 aSmColorTokenTableEntry
= starmathdatabase::Identify_Color_Parser( nc
);
2172 Append( "color rgba " );
2173 nc
= pNode
->GetToken().aText
.toUInt32(16);
2180 Append(OUString::number(nr
));
2182 Append(OUString::number(ng
));
2184 Append(OUString::number(nb
));
2186 Append(OUString::number(nc
));
2190 nc
= pNode
->GetToken().aText
.toUInt32(16);
2191 aSmColorTokenTableEntry
= starmathdatabase::Identify_Color_Parser( nc
);
2192 Append( "color hex " );
2193 nc
= pNode
->GetToken().aText
.toUInt32(16);
2194 Append(OUString::number(nc
,16));
2198 Append( "font sans " );
2201 Append( "font serif " );
2204 Append( "font fixed " );
2209 LineToText( pNode
->GetSubNode( 1 ) );
2212 void SmNodeToTextVisitor::Visit( SmUnHorNode
* pNode
)
2214 if(pNode
->GetSubNode( 1 )->GetToken( ).eType
== TFACT
)
2216 // visit children in the reverse order
2217 for( auto it
= pNode
->rbegin(); it
!= pNode
->rend(); ++it
)
2223 pChild
->Accept( this );
2228 for( auto pChild
: *pNode
)
2233 pChild
->Accept( this );
2238 void SmNodeToTextVisitor::Visit( SmBinHorNode
* pNode
)
2240 const SmNode
*pParent
= pNode
->GetParent();
2241 bool bBraceNeeded
= pParent
&& pParent
->GetType() == SmNodeType::Font
;
2242 SmNode
*pLeft
= pNode
->LeftOperand(),
2243 *pOper
= pNode
->Symbol(),
2244 *pRight
= pNode
->RightOperand();
2248 pLeft
->Accept( this );
2250 pOper
->Accept( this );
2252 pRight
->Accept( this );
2258 void SmNodeToTextVisitor::Visit( SmBinVerNode
* pNode
)
2260 if( pNode
->GetToken().eType
== TOVER
){
2261 SmNode
*pNum
= pNode
->GetSubNode( 0 ),
2262 *pDenom
= pNode
->GetSubNode( 2 );
2266 LineToText( pDenom
);
2269 SmNode
*pNum
= pNode
->GetSubNode( 0 ),
2270 *pDenom
= pNode
->GetSubNode( 2 );
2274 LineToText( pDenom
);
2279 void SmNodeToTextVisitor::Visit( SmBinDiagonalNode
* pNode
)
2281 SmNode
*pLeftOperand
= pNode
->GetSubNode( 0 ),
2282 *pRightOperand
= pNode
->GetSubNode( 1 );
2284 LineToText( pLeftOperand
);
2286 Append( "wideslash " );
2287 LineToText( pRightOperand
);
2291 void SmNodeToTextVisitor::Visit( SmSubSupNode
* pNode
)
2293 if( pNode
->GetToken().eType
== TEVALUATE
)
2295 Append("evaluate { ");
2296 pNode
->GetSubNode( 0 )->GetSubNode( 1 )->Accept(this);
2298 SmNode
* pChild
= pNode
->GetSubSup( RSUP
);
2302 LineToText( pChild
);
2305 pChild
= pNode
->GetSubSup( RSUB
);
2308 Append( "from { " );
2309 LineToText( pChild
);
2315 LineToText( pNode
->GetBody( ) );
2316 SmNode
*pChild
= pNode
->GetSubSup( LSUP
);
2320 LineToText( pChild
);
2322 pChild
= pNode
->GetSubSup( LSUB
);
2326 LineToText( pChild
);
2328 pChild
= pNode
->GetSubSup( RSUP
);
2332 LineToText( pChild
);
2334 pChild
= pNode
->GetSubSup( RSUB
);
2338 LineToText( pChild
);
2340 pChild
= pNode
->GetSubSup( CSUP
);
2343 if (pNode
->IsUseLimits())
2347 LineToText( pChild
);
2349 pChild
= pNode
->GetSubSup( CSUB
);
2352 if (pNode
->IsUseLimits())
2356 LineToText( pChild
);
2361 void SmNodeToTextVisitor::Visit( SmMatrixNode
* pNode
)
2363 Append( "matrix{" );
2364 for (size_t i
= 0; i
< pNode
->GetNumRows(); ++i
)
2366 for (size_t j
= 0; j
< pNode
->GetNumCols( ); ++j
)
2368 SmNode
* pSubNode
= pNode
->GetSubNode( i
* pNode
->GetNumCols( ) + j
);
2371 pSubNode
->Accept( this );
2373 if (j
!= pNode
->GetNumCols() - 1U)
2377 if (i
!= pNode
->GetNumRows() - 1U)
2383 void SmNodeToTextVisitor::Visit( SmPlaceNode
* )
2388 void SmNodeToTextVisitor::Visit( SmTextNode
* pNode
)
2390 SmTokenType type
= pNode
->GetToken( ).eType
;
2394 Append( pNode
->GetToken().aText
);
2398 Append( pNode
->GetToken().aText
);
2401 Append( pNode
->GetToken().aText
);
2405 Append( pNode
->GetToken().aText
);
2409 Append( pNode
->GetToken().aText
);
2412 Append( pNode
->GetToken().aText
);
2417 void SmNodeToTextVisitor::Visit( SmSpecialNode
* pNode
)
2419 SmTokenType type
= pNode
->GetToken().eType
;
2428 Append( pNode
->GetToken().aText
);
2433 void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode
* pNode
)
2435 if( pNode
->GetToken( ).eType
== TBOPER
)
2439 Append( pNode
->GetToken( ).aText
);
2442 //TODO to improve this it is required to improve mathmlimport.
2443 void SmNodeToTextVisitor::Visit( SmMathSymbolNode
* pNode
)
2445 if ( ( pNode
->GetToken().nGroup
& TG::LBrace
)
2446 || ( pNode
->GetToken().nGroup
& TG::RBrace
)
2447 || ( pNode
->GetToken().nGroup
& TG::Sum
)
2448 || ( pNode
->GetToken().nGroup
& TG::Product
)
2449 || ( pNode
->GetToken().nGroup
& TG::Relation
)
2450 || ( pNode
->GetToken().nGroup
& TG::UnOper
)
2451 || ( pNode
->GetToken().nGroup
& TG::Oper
)
2453 Append( pNode
->GetToken().aText
);
2456 sal_Unicode cChar
= pNode
->GetToken().cMathChar
;
2475 if( pNode
->GetToken().eType
== TTOWARD
) Append("toward");
2476 else Append("rightarrow");
2479 Append("leftarrow");
2485 Append("downarrow");
2488 Append("lambdabar");
2548 Append("notexists");
2556 case MS_BACKEPSILON
:
2557 Append("backepsilon");
2565 case 0x22b2: // NORMAL SUBGROUP OF
2566 Append(OUStringChar(cChar
));
2568 case 0x22b3: // CONTAINS AS NORMAL SUBGROUP
2569 Append(OUStringChar(cChar
));
2593 Append("widetilde");
2598 case 0xeb01: //no space
2599 case 0xeb08: //normal space
2601 case 0xef04: //tiny space
2602 case 0xef05: //tiny space
2603 case 0xeb02: //small space
2604 case 0xeb04: //medium space
2607 case 0xeb05: //large space
2614 Append(OUStringChar(cChar
));
2619 void SmNodeToTextVisitor::Visit( SmBlankNode
* pNode
)
2621 sal_uInt16 nNum
= pNode
->GetBlankNum();
2624 sal_uInt16 nWide
= nNum
/ 4;
2625 sal_uInt16 nNarrow
= nNum
% 4;
2626 for (sal_uInt16 i
= 0; i
< nWide
; i
++)
2628 for (sal_uInt16 i
= 0; i
< nNarrow
; i
++)
2633 void SmNodeToTextVisitor::Visit( SmErrorNode
* )
2637 void SmNodeToTextVisitor::Visit( SmLineNode
* pNode
)
2639 for( auto pChild
: *pNode
)
2644 pChild
->Accept( this );
2648 void SmNodeToTextVisitor::Visit( SmExpressionNode
* pNode
)
2650 bool bracketsNeeded
= pNode
->GetNumSubNodes() != 1 || pNode
->GetSubNode(0)->GetType() == SmNodeType::BinHor
;
2651 if (!bracketsNeeded
)
2653 const SmNode
*pParent
= pNode
->GetParent();
2656 pParent
&& pParent
->GetType() == SmNodeType::SubSup
&&
2657 pNode
->GetNumSubNodes() == 1 &&
2658 pNode
->GetSubNode(0)->GetType() == SmNodeType::SubSup
;
2661 if (bracketsNeeded
) {
2664 for( auto pChild
: *pNode
)
2668 pChild
->Accept( this );
2671 if (bracketsNeeded
) {
2676 void SmNodeToTextVisitor::Visit( SmPolyLineNode
* )
2680 void SmNodeToTextVisitor::Visit( SmRootNode
* pNode
)
2682 SmNode
*pExtra
= pNode
->GetSubNode( 0 ),
2683 *pBody
= pNode
->GetSubNode( 2 );
2686 LineToText( pExtra
);
2689 LineToText( pBody
);
2692 void SmNodeToTextVisitor::Visit( SmRootSymbolNode
* )
2696 void SmNodeToTextVisitor::Visit( SmRectangleNode
* )
2700 void SmNodeToTextVisitor::Visit( SmVerticalBraceNode
* pNode
)
2702 SmNode
*pBody
= pNode
->Body(),
2703 *pScript
= pNode
->Script();
2704 LineToText( pBody
);
2705 Append( pNode
->GetToken( ).aText
);
2706 LineToText( pScript
);
2709 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */