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 <starmathdatabase.hxx>
20 // SmDefaultingVisitor
22 void SmDefaultingVisitor::Visit( SmTableNode
* pNode
)
24 DefaultVisit( pNode
);
27 void SmDefaultingVisitor::Visit( SmBraceNode
* pNode
)
29 DefaultVisit( pNode
);
32 void SmDefaultingVisitor::Visit( SmBracebodyNode
* pNode
)
34 DefaultVisit( pNode
);
37 void SmDefaultingVisitor::Visit( SmOperNode
* pNode
)
39 DefaultVisit( pNode
);
42 void SmDefaultingVisitor::Visit( SmAlignNode
* pNode
)
44 DefaultVisit( pNode
);
47 void SmDefaultingVisitor::Visit( SmAttributeNode
* pNode
)
49 DefaultVisit( pNode
);
52 void SmDefaultingVisitor::Visit( SmFontNode
* pNode
)
54 DefaultVisit( pNode
);
57 void SmDefaultingVisitor::Visit( SmUnHorNode
* pNode
)
59 DefaultVisit( pNode
);
62 void SmDefaultingVisitor::Visit( SmBinHorNode
* pNode
)
64 DefaultVisit( pNode
);
67 void SmDefaultingVisitor::Visit( SmBinVerNode
* pNode
)
69 DefaultVisit( pNode
);
72 void SmDefaultingVisitor::Visit( SmBinDiagonalNode
* pNode
)
74 DefaultVisit( pNode
);
77 void SmDefaultingVisitor::Visit( SmSubSupNode
* pNode
)
79 DefaultVisit( pNode
);
82 void SmDefaultingVisitor::Visit( SmMatrixNode
* pNode
)
84 DefaultVisit( pNode
);
87 void SmDefaultingVisitor::Visit( SmPlaceNode
* pNode
)
89 DefaultVisit( pNode
);
92 void SmDefaultingVisitor::Visit( SmTextNode
* pNode
)
94 DefaultVisit( pNode
);
97 void SmDefaultingVisitor::Visit( SmSpecialNode
* pNode
)
99 DefaultVisit( pNode
);
102 void SmDefaultingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
104 DefaultVisit( pNode
);
107 void SmDefaultingVisitor::Visit( SmMathSymbolNode
* pNode
)
109 DefaultVisit( pNode
);
112 void SmDefaultingVisitor::Visit( SmBlankNode
* pNode
)
114 DefaultVisit( pNode
);
117 void SmDefaultingVisitor::Visit( SmErrorNode
* pNode
)
119 DefaultVisit( pNode
);
122 void SmDefaultingVisitor::Visit( SmLineNode
* pNode
)
124 DefaultVisit( pNode
);
127 void SmDefaultingVisitor::Visit( SmExpressionNode
* pNode
)
129 DefaultVisit( pNode
);
132 void SmDefaultingVisitor::Visit( SmPolyLineNode
* pNode
)
134 DefaultVisit( pNode
);
137 void SmDefaultingVisitor::Visit( SmRootNode
* pNode
)
139 DefaultVisit( pNode
);
142 void SmDefaultingVisitor::Visit( SmRootSymbolNode
* pNode
)
144 DefaultVisit( pNode
);
147 void SmDefaultingVisitor::Visit( SmRectangleNode
* pNode
)
149 DefaultVisit( pNode
);
152 void SmDefaultingVisitor::Visit( SmVerticalBraceNode
* pNode
)
154 DefaultVisit( pNode
);
157 // SmCaretLinesVisitor
159 SmCaretLinesVisitor::SmCaretLinesVisitor(OutputDevice
& rDevice
, SmCaretPos position
, Point offset
)
166 void SmCaretLinesVisitor::DoIt()
168 SAL_WARN_IF(!maPos
.IsValid(), "starmath", "Cannot draw invalid position!");
169 if (!maPos
.IsValid())
173 mrDev
.Push( vcl::PushFlags::FONT
| vcl::PushFlags::MAPMODE
| vcl::PushFlags::LINECOLOR
| vcl::PushFlags::FILLCOLOR
| vcl::PushFlags::TEXTCOLOR
);
175 maPos
.pSelectedNode
->Accept( this );
176 //Restore device state
180 void SmCaretLinesVisitor::Visit( SmTextNode
* pNode
)
182 tools::Long i
= maPos
.nIndex
;
184 mrDev
.SetFont( pNode
->GetFont( ) );
187 SmNode
* pLine
= SmCursor::FindTopMostNodeInLine( pNode
);
190 tools::Long left
= pNode
->GetLeft( ) + mrDev
.GetTextWidth( pNode
->GetText( ), 0, i
) + maOffset
.X( );
191 tools::Long top
= pLine
->GetTop( ) + maOffset
.Y( );
192 tools::Long height
= pLine
->GetHeight( );
193 tools::Long left_line
= pLine
->GetLeft( ) + maOffset
.X( );
194 tools::Long right_line
= pLine
->GetRight( ) + maOffset
.X( );
197 ProcessCaretLine({ left
, top
}, { left
, top
+ height
});
200 ProcessUnderline({ left_line
, top
+ height
}, { right_line
, top
+ height
});
203 void SmCaretLinesVisitor::DefaultVisit( SmNode
* pNode
)
206 SmNode
* pLine
= SmCursor::FindTopMostNodeInLine( pNode
);
209 tools::Long left
= pNode
->GetLeft( ) + maOffset
.X( ) + ( maPos
.nIndex
== 1 ? pNode
->GetWidth( ) : 0 );
210 tools::Long top
= pLine
->GetTop( ) + maOffset
.Y( );
211 tools::Long height
= pLine
->GetHeight( );
212 tools::Long left_line
= pLine
->GetLeft( ) + maOffset
.X( );
213 tools::Long right_line
= pLine
->GetRight( ) + maOffset
.X( );
216 ProcessCaretLine({ left
, top
}, { left
, top
+ height
});
219 ProcessUnderline({ left_line
, top
+ height
}, { right_line
, top
+ height
});
222 // SmCaretRectanglesVisitor
224 SmCaretRectanglesVisitor::SmCaretRectanglesVisitor(OutputDevice
& rDevice
, SmCaretPos position
)
225 : SmCaretLinesVisitor(rDevice
, position
, {})
230 void SmCaretRectanglesVisitor::ProcessCaretLine(Point from
, Point to
) { maCaret
= { from
, to
}; }
231 void SmCaretRectanglesVisitor::ProcessUnderline(Point
/*from*/, Point
/*to*/) {} // No underline
233 // SmCaretDrawingVisitor
235 SmCaretDrawingVisitor::SmCaretDrawingVisitor( OutputDevice
& rDevice
,
239 : SmCaretLinesVisitor(rDevice
, position
, offset
)
240 , mbCaretVisible( caretVisible
)
245 void SmCaretDrawingVisitor::ProcessCaretLine(Point from
, Point to
)
247 if ( mbCaretVisible
) {
249 getDev().SetLineColor(COL_BLACK
);
251 getDev().DrawLine(from
, to
);
255 void SmCaretDrawingVisitor::ProcessUnderline(Point from
, Point to
)
258 getDev().SetLineColor(COL_BLACK
);
260 getDev().DrawLine(from
, to
);
263 // SmCaretPos2LineVisitor
265 void SmCaretPos2LineVisitor::Visit( SmTextNode
* pNode
)
268 mpDev
->Push( vcl::PushFlags::FONT
| vcl::PushFlags::TEXTCOLOR
);
270 tools::Long i
= maPos
.nIndex
;
272 mpDev
->SetFont( pNode
->GetFont( ) );
275 tools::Long left
= pNode
->GetLeft( ) + mpDev
->GetTextWidth( pNode
->GetText( ), 0, i
);
276 tools::Long top
= pNode
->GetTop( );
277 tools::Long height
= pNode
->GetHeight( );
279 maLine
= SmCaretLine( left
, top
, height
);
281 //Restore device state
285 void SmCaretPos2LineVisitor::DefaultVisit( SmNode
* pNode
)
287 //Vertical line ( code from SmCaretDrawingVisitor )
288 Point p1
= pNode
->GetTopLeft( );
289 if( maPos
.nIndex
== 1 )
290 p1
.Move( pNode
->GetWidth( ), 0 );
292 maLine
= SmCaretLine( p1
.X( ), p1
.Y( ), pNode
->GetHeight( ) );
298 void SmDrawingVisitor::Visit( SmTableNode
* pNode
)
300 DrawChildren( pNode
);
303 void SmDrawingVisitor::Visit( SmBraceNode
* pNode
)
305 DrawChildren( pNode
);
308 void SmDrawingVisitor::Visit( SmBracebodyNode
* pNode
)
310 DrawChildren( pNode
);
313 void SmDrawingVisitor::Visit( SmOperNode
* pNode
)
315 DrawChildren( pNode
);
318 void SmDrawingVisitor::Visit( SmAlignNode
* pNode
)
320 DrawChildren( pNode
);
323 void SmDrawingVisitor::Visit( SmAttributeNode
* pNode
)
325 DrawChildren( pNode
);
328 void SmDrawingVisitor::Visit( SmFontNode
* pNode
)
330 DrawChildren( pNode
);
333 void SmDrawingVisitor::Visit( SmUnHorNode
* pNode
)
335 DrawChildren( pNode
);
338 void SmDrawingVisitor::Visit( SmBinHorNode
* pNode
)
340 DrawChildren( pNode
);
343 void SmDrawingVisitor::Visit( SmBinVerNode
* pNode
)
345 DrawChildren( pNode
);
348 void SmDrawingVisitor::Visit( SmBinDiagonalNode
* pNode
)
350 DrawChildren( pNode
);
353 void SmDrawingVisitor::Visit( SmSubSupNode
* pNode
)
355 DrawChildren( pNode
);
358 void SmDrawingVisitor::Visit( SmMatrixNode
* pNode
)
360 DrawChildren( pNode
);
363 void SmDrawingVisitor::Visit( SmPlaceNode
* pNode
)
365 DrawSpecialNode( pNode
);
368 void SmDrawingVisitor::Visit( SmTextNode
* pNode
)
370 DrawTextNode( pNode
);
373 void SmDrawingVisitor::Visit( SmSpecialNode
* pNode
)
375 DrawSpecialNode( pNode
);
378 void SmDrawingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
380 DrawSpecialNode( pNode
);
383 void SmDrawingVisitor::Visit( SmMathSymbolNode
* pNode
)
385 DrawSpecialNode( pNode
);
388 void SmDrawingVisitor::Visit( SmBlankNode
* )
392 void SmDrawingVisitor::Visit( SmErrorNode
* pNode
)
394 DrawSpecialNode( pNode
);
397 void SmDrawingVisitor::Visit( SmLineNode
* pNode
)
399 DrawChildren( pNode
);
402 void SmDrawingVisitor::Visit( SmExpressionNode
* pNode
)
404 DrawChildren( pNode
);
407 void SmDrawingVisitor::Visit( SmRootNode
* pNode
)
409 DrawChildren( pNode
);
412 void SmDrawingVisitor::Visit( SmVerticalBraceNode
* pNode
)
414 DrawChildren( pNode
);
417 void SmDrawingVisitor::Visit( SmRootSymbolNode
* pNode
)
419 if ( pNode
->IsPhantom( ) )
422 // draw root-sign itself
423 DrawSpecialNode( pNode
);
425 SmTmpDevice
aTmpDev( mrDev
, true );
426 aTmpDev
.SetFillColor( pNode
->GetFont( ).GetColor( ) );
427 mrDev
.SetLineColor( );
428 aTmpDev
.SetFont( pNode
->GetFont( ) );
430 // since the width is always unscaled it corresponds to the _original_
431 // _unscaled_ font height to be used, we use that to calculate the
432 // bar height. Thus it is independent of the arguments height.
433 // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
434 tools::Long nBarHeight
= pNode
->GetWidth( ) * 7 / 100;
435 tools::Long nBarWidth
= pNode
->GetBodyWidth( ) + pNode
->GetBorderWidth( );
436 Point
aBarOffset( pNode
->GetWidth( ), +pNode
->GetBorderWidth( ) );
437 Point
aBarPos( maPosition
+ aBarOffset
);
439 tools::Rectangle
aBar( aBarPos
, Size( nBarWidth
, nBarHeight
) );
440 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
441 //! increasing zoomfactor.
442 // This is done by shifting its output-position to a point that
443 // corresponds exactly to a pixel on the output device.
444 Point
aDrawPos( mrDev
.PixelToLogic( mrDev
.LogicToPixel( aBar
.TopLeft( ) ) ) );
445 aBar
.SetPos( aDrawPos
);
447 mrDev
.DrawRect( aBar
);
450 void SmDrawingVisitor::Visit( SmPolyLineNode
* pNode
)
452 if ( pNode
->IsPhantom( ) )
455 tools::Long nBorderwidth
= pNode
->GetFont( ).GetBorderWidth( );
458 aInfo
.SetWidth( pNode
->GetWidth( ) - 2 * nBorderwidth
);
460 Point
aOffset ( Point( ) - pNode
->GetPolygon( ).GetBoundRect( ).TopLeft( )
461 + Point( nBorderwidth
, nBorderwidth
) ),
462 aPos ( maPosition
+ aOffset
);
463 pNode
->GetPolygon( ).Move( aPos
.X( ), aPos
.Y( ) ); //Works because Polygon wraps a pointer
465 SmTmpDevice
aTmpDev ( mrDev
, false );
466 aTmpDev
.SetLineColor( pNode
->GetFont( ).GetColor( ) );
468 mrDev
.DrawPolyLine( pNode
->GetPolygon( ), aInfo
);
471 void SmDrawingVisitor::Visit( SmRectangleNode
* pNode
)
473 if ( pNode
->IsPhantom( ) )
476 SmTmpDevice
aTmpDev ( mrDev
, false );
477 aTmpDev
.SetFillColor( pNode
->GetFont( ).GetColor( ) );
478 mrDev
.SetLineColor( );
479 aTmpDev
.SetFont( pNode
->GetFont( ) );
481 sal_uLong nTmpBorderWidth
= pNode
->GetFont( ).GetBorderWidth( );
483 // get rectangle and remove borderspace
484 tools::Rectangle
aTmp ( pNode
->AsRectangle( ) + maPosition
- pNode
->GetTopLeft( ) );
485 aTmp
.AdjustLeft(nTmpBorderWidth
);
486 aTmp
.AdjustRight( -sal_Int32(nTmpBorderWidth
) );
487 aTmp
.AdjustTop(nTmpBorderWidth
);
488 aTmp
.AdjustBottom( -sal_Int32(nTmpBorderWidth
) );
490 SAL_WARN_IF( aTmp
.IsEmpty(), "starmath", "Empty rectangle" );
492 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
493 //! increasing zoomfactor.
494 // This is done by shifting its output-position to a point that
495 // corresponds exactly to a pixel on the output device.
496 Point
aPos ( mrDev
.PixelToLogic( mrDev
.LogicToPixel( aTmp
.TopLeft( ) ) ) );
499 mrDev
.DrawRect( aTmp
);
502 void SmDrawingVisitor::DrawTextNode( SmTextNode
* pNode
)
504 if ( pNode
->IsPhantom() || pNode
->GetText().isEmpty() || pNode
->GetText()[0] == '\0' )
507 SmTmpDevice
aTmpDev ( mrDev
, false );
508 aTmpDev
.SetFont( pNode
->GetFont( ) );
510 Point
aPos ( maPosition
);
511 aPos
.AdjustY(pNode
->GetBaselineOffset( ) );
512 // round to pixel coordinate
513 aPos
= mrDev
.PixelToLogic( mrDev
.LogicToPixel( aPos
) );
515 mrDev
.DrawStretchText( aPos
, pNode
->GetWidth( ), pNode
->GetText( ) );
518 void SmDrawingVisitor::DrawSpecialNode( SmSpecialNode
* pNode
)
520 //! since this chars might come from any font, that we may not have
521 //! set to ALIGN_BASELINE yet, we do it now.
522 pNode
->GetFont( ).SetAlignment( ALIGN_BASELINE
);
524 DrawTextNode( pNode
);
527 void SmDrawingVisitor::DrawChildren( SmStructureNode
* pNode
)
529 if ( pNode
->IsPhantom( ) )
532 Point rPosition
= maPosition
;
534 for( auto pChild
: *pNode
)
538 Point
aOffset ( pChild
->GetTopLeft( ) - pNode
->GetTopLeft( ) );
539 maPosition
= rPosition
+ aOffset
;
540 pChild
->Accept( this );
544 // SmSetSelectionVisitor
546 SmSetSelectionVisitor::SmSetSelectionVisitor( SmCaretPos startPos
, SmCaretPos endPos
, SmNode
* pTree
)
547 : maStartPos(startPos
)
551 //Assume that pTree is a SmTableNode
552 SAL_WARN_IF(pTree
->GetType() != SmNodeType::Table
, "starmath", "pTree should be a SmTableNode!");
553 //Visit root node, this is special as this node cannot be selected, but its children can!
554 if(pTree
->GetType() == SmNodeType::Table
){
555 //Change state if maStartPos is in front of this node
556 if( maStartPos
.pSelectedNode
== pTree
&& maStartPos
.nIndex
== 0 )
557 mbSelecting
= !mbSelecting
;
558 //Change state if maEndPos is in front of this node
559 if( maEndPos
.pSelectedNode
== pTree
&& maEndPos
.nIndex
== 0 )
560 mbSelecting
= !mbSelecting
;
561 SAL_WARN_IF(mbSelecting
, "starmath", "Caret positions needed to set mbSelecting about, shouldn't be possible!");
564 for( auto pChild
: *static_cast<SmStructureNode
*>(pTree
) )
568 pChild
->Accept( this );
569 //If we started a selection in this line and it haven't ended, we do that now!
572 SetSelectedOnAll(pChild
);
573 //Set maStartPos and maEndPos to invalid positions, this ensures that an unused
574 //start or end (because we forced end above), doesn't start a new selection.
575 maStartPos
= maEndPos
= SmCaretPos();
578 //Check if pTree isn't selected
579 SAL_WARN_IF(pTree
->IsSelected(), "starmath", "pTree should never be selected!");
580 //Discard the selection if there's a bug (it's better than crashing)
581 if(pTree
->IsSelected())
582 SetSelectedOnAll(pTree
, false);
583 }else //This shouldn't happen, but I don't see any reason to die if it does
587 void SmSetSelectionVisitor::SetSelectedOnAll( SmNode
* pSubTree
, bool IsSelected
) {
588 pSubTree
->SetSelected( IsSelected
);
590 if(pSubTree
->GetNumSubNodes() == 0)
592 //Quick BFS to set all selections
593 for( auto pChild
: *static_cast<SmStructureNode
*>(pSubTree
) )
597 SetSelectedOnAll( pChild
, IsSelected
);
601 void SmSetSelectionVisitor::DefaultVisit( SmNode
* pNode
) {
602 //Change state if maStartPos is in front of this node
603 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 0 )
604 mbSelecting
= !mbSelecting
;
605 //Change state if maEndPos is in front of this node
606 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 0 )
607 mbSelecting
= !mbSelecting
;
609 //Cache current state
610 bool WasSelecting
= mbSelecting
;
611 bool ChangedState
= false;
614 pNode
->SetSelected( mbSelecting
);
617 if(pNode
->GetNumSubNodes() > 0)
619 for( auto pChild
: *static_cast<SmStructureNode
*>(pNode
) )
623 pChild
->Accept( this );
624 ChangedState
= ( WasSelecting
!= mbSelecting
) || ChangedState
;
631 //Select this node and all of its children
632 //(Make exception for SmBracebodyNode)
633 if( pNode
->GetType() != SmNodeType::Bracebody
||
634 !pNode
->GetParent() ||
635 pNode
->GetParent()->GetType() != SmNodeType::Brace
)
636 SetSelectedOnAll( pNode
);
638 SetSelectedOnAll( pNode
->GetParent() );
639 /* If the equation is: sqrt{2 + 4} + 5
640 * And the selection is: sqrt{2 + [4} +] 5
641 * Where [ denotes maStartPos and ] denotes maEndPos
642 * Then the sqrt node should be selected, so that the
643 * effective selection is: [sqrt{2 + 4} +] 5
644 * The same is the case if we swap maStartPos and maEndPos.
648 //Change state if maStartPos is after this node
649 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 1 )
651 mbSelecting
= !mbSelecting
;
653 //Change state if maEndPos is after of this node
654 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 1 )
656 mbSelecting
= !mbSelecting
;
660 void SmSetSelectionVisitor::VisitCompositionNode( SmStructureNode
* pNode
)
662 //Change state if maStartPos is in front of this node
663 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 0 )
664 mbSelecting
= !mbSelecting
;
665 //Change state if maEndPos is in front of this node
666 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 0 )
667 mbSelecting
= !mbSelecting
;
669 //Cache current state
670 bool WasSelecting
= mbSelecting
;
673 for( auto pChild
: *pNode
)
677 pChild
->Accept( this );
680 //Set selected, if everything was selected
681 pNode
->SetSelected( WasSelecting
&& mbSelecting
);
683 //Change state if maStartPos is after this node
684 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 1 )
685 mbSelecting
= !mbSelecting
;
686 //Change state if maEndPos is after of this node
687 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 1 )
688 mbSelecting
= !mbSelecting
;
691 void SmSetSelectionVisitor::Visit( SmTextNode
* pNode
) {
694 if( maStartPos
.pSelectedNode
== pNode
)
695 i1
= maStartPos
.nIndex
;
696 if( maEndPos
.pSelectedNode
== pNode
)
697 i2
= maEndPos
.nIndex
;
699 tools::Long start
, end
;
700 pNode
->SetSelected(true);
701 if( i1
!= -1 && i2
!= -1 ) {
702 start
= std::min(i1
, i2
);
703 end
= std::max(i1
, i2
);
704 } else if( mbSelecting
&& i1
!= -1 ) {
708 } else if( mbSelecting
&& i2
!= -1 ) {
712 } else if( !mbSelecting
&& i1
!= -1 ) {
714 end
= pNode
->GetText().getLength();
716 } else if( !mbSelecting
&& i2
!= -1 ) {
718 end
= pNode
->GetText().getLength();
720 } else if( mbSelecting
) {
722 end
= pNode
->GetText().getLength();
724 pNode
->SetSelected( false );
728 pNode
->SetSelected( start
!= end
);
729 pNode
->SetSelectionStart( start
);
730 pNode
->SetSelectionEnd( end
);
733 void SmSetSelectionVisitor::Visit( SmExpressionNode
* pNode
) {
734 VisitCompositionNode( pNode
);
737 void SmSetSelectionVisitor::Visit( SmLineNode
* pNode
) {
738 VisitCompositionNode( pNode
);
741 void SmSetSelectionVisitor::Visit( SmAlignNode
* pNode
) {
742 VisitCompositionNode( pNode
);
745 void SmSetSelectionVisitor::Visit( SmBinHorNode
* pNode
) {
746 VisitCompositionNode( pNode
);
749 void SmSetSelectionVisitor::Visit( SmUnHorNode
* pNode
) {
750 VisitCompositionNode( pNode
);
753 void SmSetSelectionVisitor::Visit( SmFontNode
* pNode
) {
754 VisitCompositionNode( pNode
);
757 // SmCaretPosGraphBuildingVisitor
759 SmCaretPosGraphBuildingVisitor::SmCaretPosGraphBuildingVisitor( SmNode
* pRootNode
)
760 : mpRightMost(nullptr)
761 , mpGraph(new SmCaretPosGraph
)
763 //pRootNode should always be a table
764 SAL_WARN_IF( pRootNode
->GetType( ) != SmNodeType::Table
, "starmath", "pRootNode must be a table node");
765 //Handle the special case where SmNodeType::Table is used a rootnode
766 if( pRootNode
->GetType( ) == SmNodeType::Table
){
767 //Children are SmLineNodes
768 //Or so I thought... Apparently, the children can be instances of SmExpression
769 //especially if there's an error in the formula... So here we go, a simple work around.
770 for( auto pChild
: *static_cast<SmStructureNode
*>(pRootNode
) )
774 mpRightMost
= mpGraph
->Add( SmCaretPos( pChild
, 0 ) );
775 pChild
->Accept( this );
778 pRootNode
->Accept(this);
781 SmCaretPosGraphBuildingVisitor::~SmCaretPosGraphBuildingVisitor()
785 void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode
* pNode
){
786 for( auto pChild
: *pNode
)
790 pChild
->Accept( this );
794 /** Build SmCaretPosGraph for SmTableNode
795 * This method covers cases where SmTableNode is used in a binom or stack,
796 * the special case where it is used as root node for the entire formula is
797 * handled in the constructor.
799 void SmCaretPosGraphBuildingVisitor::Visit( SmTableNode
* pNode
){
800 SmCaretPosGraphEntry
*left
= mpRightMost
,
801 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1) );
802 bool bIsFirst
= true;
803 for( auto pChild
: *pNode
)
807 mpRightMost
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
809 left
->SetRight(mpRightMost
);
810 pChild
->Accept( this );
811 mpRightMost
->SetRight(right
);
813 right
->SetLeft(mpRightMost
);
819 /** Build SmCaretPosGraph for SmSubSupNode
821 * The child positions in a SubSupNode, where H is the body:
834 * Graph over these, where "left" is before the SmSubSupNode and "right" is after:
849 void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode
* pNode
)
851 SmCaretPosGraphEntry
*left
,
860 SAL_WARN_IF( !pNode
->GetBody(), "starmath", "SmSubSupNode Doesn't have a body!" );
861 bodyLeft
= mpGraph
->Add( SmCaretPos( pNode
->GetBody( ), 0 ), left
);
862 left
->SetRight( bodyLeft
); //TODO: Don't make this if LSUP or LSUB are NULL ( not sure??? )
865 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
867 //Visit the body, to get bodyRight
868 mpRightMost
= bodyLeft
;
869 pNode
->GetBody( )->Accept( this );
870 bodyRight
= mpRightMost
;
871 bodyRight
->SetRight( right
);
872 right
->SetLeft( bodyRight
);
875 SmNode
* pChild
= pNode
->GetSubSup( LSUP
);
877 SmCaretPosGraphEntry
*cLeft
; //Child left
878 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
881 pChild
->Accept( this );
883 mpRightMost
->SetRight( bodyLeft
);
886 pChild
= pNode
->GetSubSup( LSUB
);
888 SmCaretPosGraphEntry
*cLeft
; //Child left
889 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
892 pChild
->Accept( this );
894 mpRightMost
->SetRight( bodyLeft
);
897 pChild
= pNode
->GetSubSup( CSUP
);
899 SmCaretPosGraphEntry
*cLeft
; //Child left
900 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
903 pChild
->Accept( this );
905 mpRightMost
->SetRight( right
);
908 pChild
= pNode
->GetSubSup( CSUB
);
910 SmCaretPosGraphEntry
*cLeft
; //Child left
911 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
914 pChild
->Accept( this );
916 mpRightMost
->SetRight( right
);
919 pChild
= pNode
->GetSubSup( RSUP
);
921 SmCaretPosGraphEntry
*cLeft
; //Child left
922 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), bodyRight
);
925 pChild
->Accept( this );
927 mpRightMost
->SetRight( right
);
930 pChild
= pNode
->GetSubSup( RSUB
);
932 SmCaretPosGraphEntry
*cLeft
; //Child left
933 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), bodyRight
);
936 pChild
->Accept( this );
938 mpRightMost
->SetRight( right
);
941 //Set return parameters
945 /** Build caret position for SmOperNode
947 * If first child is an SmSubSupNode we will ignore its
948 * body, as this body is a SmMathSymbol, for SUM, INT or similar
949 * that shouldn't be subject to modification.
950 * If first child is not a SmSubSupNode, ignore it completely
951 * as it is a SmMathSymbol.
953 * The child positions in a SmOperNode, where H is symbol, e.g. int, sum or similar:
957 * LSUP H H RSUP BBB BB BBB B B
958 * H H B B B B B B B B
961 * LSUB H H RSUB BBB BB BBB B
965 * Notice, CSUP, etc. are actually grandchildren, but inorder to ignore H, these are visited
966 * from here. If they are present, that is if pOper is an instance of SmSubSupNode.
968 * Graph over these, where "left" is before the SmOperNode and "right" is after:
982 void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode
* pNode
)
984 SmNode
*pOper
= pNode
->GetSubNode( 0 ),
985 *pBody
= pNode
->GetSubNode( 1 );
987 SmCaretPosGraphEntry
*left
= mpRightMost
,
992 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
993 left
->SetRight( bodyLeft
);
995 //Visit body, get bodyRight
996 mpRightMost
= bodyLeft
;
997 pBody
->Accept( this );
998 bodyRight
= mpRightMost
;
1001 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), bodyRight
);
1002 bodyRight
->SetRight( right
);
1004 //Get subsup pNode if any
1005 SmSubSupNode
* pSubSup
= pOper
->GetType( ) == SmNodeType::SubSup
? static_cast<SmSubSupNode
*>(pOper
) : nullptr;
1008 SmNode
* pChild
= pSubSup
->GetSubSup( LSUP
);
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( LSUB
);
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( CSUP
);
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( CSUB
);
1042 if( pChild
) { //FROM
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
);
1052 pChild
= pSubSup
->GetSubSup( RSUP
);
1054 //Create position in front of pChild
1055 SmCaretPosGraphEntry
*childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1057 mpRightMost
= childLeft
;
1058 pChild
->Accept( this );
1059 //Set right on mpRightMost from pChild
1060 mpRightMost
->SetRight( bodyLeft
);
1063 pChild
= pSubSup
->GetSubSup( RSUB
);
1065 //Create position in front of pChild
1066 SmCaretPosGraphEntry
*childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1068 mpRightMost
= childLeft
;
1069 pChild
->Accept( this );
1070 //Set right on mpRightMost from pChild
1071 mpRightMost
->SetRight( bodyLeft
);
1076 mpRightMost
= right
;
1079 void SmCaretPosGraphBuildingVisitor::Visit( SmMatrixNode
* pNode
)
1081 SmCaretPosGraphEntry
*left
= mpRightMost
,
1082 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1084 for (size_t i
= 0; i
< pNode
->GetNumRows(); ++i
)
1086 SmCaretPosGraphEntry
* r
= left
;
1087 for (size_t j
= 0; j
< pNode
->GetNumCols(); ++j
)
1089 SmNode
* pSubNode
= pNode
->GetSubNode( i
* pNode
->GetNumCols( ) + j
);
1091 mpRightMost
= mpGraph
->Add( SmCaretPos( pSubNode
, 0 ), r
);
1092 if( j
!= 0 || ( pNode
->GetNumRows() - 1U ) / 2 == i
)
1093 r
->SetRight( mpRightMost
);
1095 pSubNode
->Accept( this );
1099 mpRightMost
->SetRight( right
);
1100 if( ( pNode
->GetNumRows() - 1U ) / 2 == i
)
1101 right
->SetLeft( mpRightMost
);
1104 mpRightMost
= right
;
1107 /** Build SmCaretPosGraph for SmTextNode
1109 * Lines in an SmTextNode:
1113 * Where A B and C are characters in the text.
1115 * Graph over these, where "left" is before the SmTextNode and "right" is after:
1123 * Notice that C and right is the same position here.
1125 void SmCaretPosGraphBuildingVisitor::Visit( SmTextNode
* pNode
)
1127 SAL_WARN_IF( pNode
->GetText().isEmpty(), "starmath", "Empty SmTextNode is bad" );
1129 int size
= pNode
->GetText().getLength();
1130 for( int i
= 1; i
<= size
; i
++ ){
1131 SmCaretPosGraphEntry
* pRight
= mpRightMost
;
1132 mpRightMost
= mpGraph
->Add( SmCaretPos( pNode
, i
), pRight
);
1133 pRight
->SetRight( mpRightMost
);
1137 /** Build SmCaretPosGraph for SmBinVerNode
1139 * Lines in an SmBinVerNode:
1146 * Graph over these, where "left" is before the SmBinVerNode and "right" is after:
1155 void SmCaretPosGraphBuildingVisitor::Visit( SmBinVerNode
* pNode
)
1157 //None if these children can be NULL, see SmBinVerNode::Arrange
1158 SmNode
*pNum
= pNode
->GetSubNode( 0 ),
1159 *pDenom
= pNode
->GetSubNode( 2 );
1161 SmCaretPosGraphEntry
*left
,
1166 assert(mpRightMost
);
1171 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1174 numLeft
= mpGraph
->Add( SmCaretPos( pNum
, 0 ), left
);
1175 left
->SetRight( numLeft
);
1178 mpRightMost
= numLeft
;
1179 pNum
->Accept( this );
1180 mpRightMost
->SetRight( right
);
1181 right
->SetLeft( mpRightMost
);
1184 denomLeft
= mpGraph
->Add( SmCaretPos( pDenom
, 0 ), left
);
1187 mpRightMost
= denomLeft
;
1188 pDenom
->Accept( this );
1189 mpRightMost
->SetRight( right
);
1191 //Set return parameter
1192 mpRightMost
= right
;
1195 /** Build SmCaretPosGraph for SmVerticalBraceNode
1197 * Lines in an SmVerticalBraceNode:
1206 void SmCaretPosGraphBuildingVisitor::Visit( SmVerticalBraceNode
* pNode
)
1208 SmNode
*pBody
= pNode
->Body(),
1209 *pScript
= pNode
->Script();
1210 //None of these children can be NULL
1212 SmCaretPosGraphEntry
*left
,
1220 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1223 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1224 left
->SetRight( bodyLeft
);
1225 mpRightMost
= bodyLeft
;
1226 pBody
->Accept( this );
1227 mpRightMost
->SetRight( right
);
1228 right
->SetLeft( mpRightMost
);
1231 scriptLeft
= mpGraph
->Add( SmCaretPos( pScript
, 0 ), left
);
1232 mpRightMost
= scriptLeft
;
1233 pScript
->Accept( this );
1234 mpRightMost
->SetRight( right
);
1237 mpRightMost
= right
;
1240 /** Build SmCaretPosGraph for SmBinDiagonalNode
1242 * Lines in an SmBinDiagonalNode:
1248 * Where A and B are lines.
1250 * Used in formulas such as "A wideslash B"
1252 void SmCaretPosGraphBuildingVisitor::Visit( SmBinDiagonalNode
* pNode
)
1254 SmNode
*A
= pNode
->GetSubNode( 0 ),
1255 *B
= pNode
->GetSubNode( 1 );
1257 SmCaretPosGraphEntry
*left
,
1265 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1268 leftA
= mpGraph
->Add( SmCaretPos( A
, 0 ), left
);
1269 left
->SetRight( leftA
);
1272 mpRightMost
= leftA
;
1274 rightA
= mpRightMost
;
1277 leftB
= mpGraph
->Add( SmCaretPos( B
, 0 ), rightA
);
1278 rightA
->SetRight( leftB
);
1281 mpRightMost
= leftB
;
1283 mpRightMost
->SetRight( right
);
1284 right
->SetLeft( mpRightMost
);
1287 mpRightMost
= right
;
1290 //Straight forward ( I think )
1291 void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode
* pNode
)
1293 for( auto pChild
: *pNode
)
1297 pChild
->Accept( this );
1300 void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode
* pNode
)
1302 // Unary operator node
1303 for( auto pChild
: *pNode
)
1307 pChild
->Accept( this );
1311 void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode
* pNode
)
1313 for( auto pChild
: *pNode
)
1317 pChild
->Accept( this );
1321 void SmCaretPosGraphBuildingVisitor::Visit( SmFontNode
* pNode
)
1323 //Has only got one child, should act as an expression if possible
1324 for( auto pChild
: *pNode
)
1328 pChild
->Accept( this );
1332 /** Build SmCaretPosGraph for SmBracebodyNode
1333 * Acts as an SmExpressionNode
1335 * Below is an example of a formula tree that has multiple children for SmBracebodyNode
1339 * label= "Equation: \"lbrace i mline i in setZ rbrace\"";
1340 * n0 [label="SmTableNode"];
1341 * n0 -> n1 [label="0"];
1342 * n1 [label="SmLineNode"];
1343 * n1 -> n2 [label="0"];
1344 * n2 [label="SmExpressionNode"];
1345 * n2 -> n3 [label="0"];
1346 * n3 [label="SmBraceNode"];
1347 * n3 -> n4 [label="0"];
1348 * n4 [label="SmMathSymbolNode: {"];
1349 * n3 -> n5 [label="1"];
1350 * n5 [label="SmBracebodyNode"];
1351 * n5 -> n6 [label="0"];
1352 * n6 [label="SmExpressionNode"];
1353 * n6 -> n7 [label="0"];
1354 * n7 [label="SmTextNode: i"];
1355 * n5 -> n8 [label="1"];
1356 * n8 [label="SmMathSymbolNode: |"]; // Unicode "VERTICAL LINE"
1357 * n5 -> n9 [label="2"];
1358 * n9 [label="SmExpressionNode"];
1359 * n9 -> n10 [label="0"];
1360 * n10 [label="SmBinHorNode"];
1361 * n10 -> n11 [label="0"];
1362 * n11 [label="SmTextNode: i"];
1363 * n10 -> n12 [label="1"];
1364 * n12 [label="SmMathSymbolNode: ∈"]; // Unicode "ELEMENT OF"
1365 * n10 -> n13 [label="2"];
1366 * n13 [label="SmMathSymbolNode: ℤ"]; // Unicode "DOUBLE-STRUCK CAPITAL Z"
1367 * n3 -> n14 [label="2"];
1368 * n14 [label="SmMathSymbolNode: }"];
1372 void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode
* pNode
)
1374 for( auto pChild
: *pNode
)
1378 SmCaretPosGraphEntry
* pStart
= mpGraph
->Add( SmCaretPos( pChild
, 0), mpRightMost
);
1379 mpRightMost
->SetRight( pStart
);
1380 mpRightMost
= pStart
;
1381 pChild
->Accept( this );
1385 /** Build SmCaretPosGraph for SmAlignNode
1386 * Acts as an SmExpressionNode, as it only has one child this okay
1388 void SmCaretPosGraphBuildingVisitor::Visit( SmAlignNode
* pNode
)
1390 for( auto pChild
: *pNode
)
1394 pChild
->Accept( this );
1398 /** Build SmCaretPosGraph for SmRootNode
1400 * Lines in an SmRootNode:
1407 * A: pExtra ( optional, can be NULL ),
1410 * Graph over these, where "left" is before the SmRootNode and "right" is after:
1419 void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode
* pNode
)
1421 SmNode
*pExtra
= pNode
->GetSubNode( 0 ), //Argument, NULL for sqrt, and SmTextNode if cubicroot
1422 *pBody
= pNode
->GetSubNode( 2 ); //Body of the root
1425 SmCaretPosGraphEntry
*left
,
1430 //Get left and save it
1431 assert(mpRightMost
);
1435 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1436 left
->SetRight( bodyLeft
);
1439 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1442 mpRightMost
= bodyLeft
;
1443 pBody
->Accept( this );
1444 bodyRight
= mpRightMost
;
1445 bodyRight
->SetRight( right
);
1446 right
->SetLeft( bodyRight
);
1450 mpRightMost
= mpGraph
->Add( SmCaretPos( pExtra
, 0 ), left
);
1451 pExtra
->Accept( this );
1452 mpRightMost
->SetRight( bodyLeft
);
1455 mpRightMost
= right
;
1459 /** Build SmCaretPosGraph for SmPlaceNode
1460 * Consider this a single character.
1462 void SmCaretPosGraphBuildingVisitor::Visit( SmPlaceNode
* pNode
)
1464 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1465 mpRightMost
->SetRight( right
);
1466 mpRightMost
= right
;
1469 /** SmErrorNode is context dependent metadata, it can't be selected
1471 * @remarks There's no point in deleting, copying and/or moving an instance
1472 * of SmErrorNode as it may not exist in another context! Thus there are no
1473 * positions to select an SmErrorNode.
1475 void SmCaretPosGraphBuildingVisitor::Visit( SmErrorNode
* )
1479 /** Build SmCaretPosGraph for SmBlankNode
1480 * Consider this a single character, as it is only a blank space
1482 void SmCaretPosGraphBuildingVisitor::Visit( SmBlankNode
* pNode
)
1484 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1485 mpRightMost
->SetRight( right
);
1486 mpRightMost
= right
;
1489 /** Build SmCaretPosGraph for SmBraceNode
1491 * Lines in an SmBraceNode:
1499 * Graph over these, where "left" is before the SmBraceNode and "right" is after:
1507 void SmCaretPosGraphBuildingVisitor::Visit( SmBraceNode
* pNode
)
1509 SmNode
* pBody
= pNode
->Body();
1511 SmCaretPosGraphEntry
*left
= mpRightMost
,
1512 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1514 if( pBody
->GetType() != SmNodeType::Bracebody
) {
1515 mpRightMost
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1516 left
->SetRight( mpRightMost
);
1520 pBody
->Accept( this );
1521 mpRightMost
->SetRight( right
);
1522 right
->SetLeft( mpRightMost
);
1524 mpRightMost
= right
;
1527 /** Build SmCaretPosGraph for SmAttributeNode
1529 * Lines in an SmAttributeNode:
1535 * There's a body and an attribute, the construction is used for "widehat A", where "A" is the body
1536 * and "^" is the attribute ( note GetScaleMode( ) on SmAttributeNode tells how the attribute should be
1539 void SmCaretPosGraphBuildingVisitor::Visit( SmAttributeNode
* pNode
)
1541 SmNode
*pAttr
= pNode
->Attribute(),
1542 *pBody
= pNode
->Body();
1546 SmCaretPosGraphEntry
*left
= mpRightMost
,
1553 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1554 left
->SetRight( bodyLeft
);
1557 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1560 mpRightMost
= bodyLeft
;
1561 pBody
->Accept( this );
1562 bodyRight
= mpRightMost
;
1563 bodyRight
->SetRight( right
);
1564 right
->SetLeft( bodyRight
);
1567 attrLeft
= mpGraph
->Add( SmCaretPos( pAttr
, 0 ), left
);
1570 mpRightMost
= attrLeft
;
1571 pAttr
->Accept( this );
1572 mpRightMost
->SetRight( right
);
1575 mpRightMost
= right
;
1578 //Consider these single symbols
1579 void SmCaretPosGraphBuildingVisitor::Visit( SmSpecialNode
* pNode
)
1581 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1582 mpRightMost
->SetRight( right
);
1583 mpRightMost
= right
;
1585 void SmCaretPosGraphBuildingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
1587 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1588 mpRightMost
->SetRight( right
);
1589 mpRightMost
= right
;
1591 void SmCaretPosGraphBuildingVisitor::Visit( SmMathSymbolNode
* pNode
)
1593 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1594 mpRightMost
->SetRight( right
);
1595 mpRightMost
= right
;
1598 void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode
* )
1603 void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode
* )
1607 void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode
* )
1614 SmNode
* SmCloningVisitor::Clone( SmNode
* pNode
)
1616 SmNode
* pCurrResult
= mpResult
;
1617 pNode
->Accept( this );
1618 SmNode
* pClone
= mpResult
;
1619 mpResult
= pCurrResult
;
1623 void SmCloningVisitor::CloneNodeAttr( SmNode
const * pSource
, SmNode
* pTarget
)
1625 pTarget
->SetScaleMode( pSource
->GetScaleMode( ) );
1626 //Other attributes are set when prepare or arrange is executed
1627 //and may depend on stuff not being cloned here.
1630 void SmCloningVisitor::CloneKids( SmStructureNode
* pSource
, SmStructureNode
* pTarget
)
1632 //Cache current result
1633 SmNode
* pCurrResult
= mpResult
;
1635 //Create array for holding clones
1636 size_t nSize
= pSource
->GetNumSubNodes( );
1637 SmNodeArray
aNodes( nSize
);
1640 for (size_t i
= 0; i
< nSize
; ++i
)
1643 if( nullptr != ( pKid
= pSource
->GetSubNode( i
) ) )
1644 pKid
->Accept( this );
1647 aNodes
[i
] = mpResult
;
1650 //Set subnodes of pTarget
1651 pTarget
->SetSubNodes( std::move(aNodes
) );
1653 //Restore result as where prior to call
1654 mpResult
= pCurrResult
;
1657 void SmCloningVisitor::Visit( SmTableNode
* pNode
)
1659 SmTableNode
* pClone
= new SmTableNode( pNode
->GetToken( ) );
1660 pClone
->SetSelection( pNode
->GetSelection() );
1661 CloneNodeAttr( pNode
, pClone
);
1662 CloneKids( pNode
, pClone
);
1666 void SmCloningVisitor::Visit( SmBraceNode
* pNode
)
1668 SmBraceNode
* pClone
= new SmBraceNode( pNode
->GetToken( ) );
1669 pClone
->SetSelection( pNode
->GetSelection() );
1670 CloneNodeAttr( pNode
, pClone
);
1671 CloneKids( pNode
, pClone
);
1675 void SmCloningVisitor::Visit( SmBracebodyNode
* pNode
)
1677 SmBracebodyNode
* pClone
= new SmBracebodyNode( pNode
->GetToken( ) );
1678 pClone
->SetSelection( pNode
->GetSelection() );
1679 CloneNodeAttr( pNode
, pClone
);
1680 CloneKids( pNode
, pClone
);
1684 void SmCloningVisitor::Visit( SmOperNode
* pNode
)
1686 SmOperNode
* pClone
= new SmOperNode( pNode
->GetToken( ) );
1687 pClone
->SetSelection( pNode
->GetSelection() );
1688 CloneNodeAttr( pNode
, pClone
);
1689 CloneKids( pNode
, pClone
);
1693 void SmCloningVisitor::Visit( SmAlignNode
* pNode
)
1695 SmAlignNode
* pClone
= new SmAlignNode( pNode
->GetToken( ) );
1696 pClone
->SetSelection( pNode
->GetSelection() );
1697 CloneNodeAttr( pNode
, pClone
);
1698 CloneKids( pNode
, pClone
);
1702 void SmCloningVisitor::Visit( SmAttributeNode
* pNode
)
1704 SmAttributeNode
* pClone
= new SmAttributeNode( pNode
->GetToken( ) );
1705 pClone
->SetSelection( pNode
->GetSelection() );
1706 CloneNodeAttr( pNode
, pClone
);
1707 CloneKids( pNode
, pClone
);
1711 void SmCloningVisitor::Visit( SmFontNode
* pNode
)
1713 SmFontNode
* pClone
= new SmFontNode( pNode
->GetToken( ) );
1714 pClone
->SetSelection( pNode
->GetSelection() );
1715 pClone
->SetSizeParameter( pNode
->GetSizeParameter( ), pNode
->GetSizeType( ) );
1716 CloneNodeAttr( pNode
, pClone
);
1717 CloneKids( pNode
, pClone
);
1721 void SmCloningVisitor::Visit( SmUnHorNode
* pNode
)
1723 SmUnHorNode
* pClone
= new SmUnHorNode( pNode
->GetToken( ) );
1724 pClone
->SetSelection( pNode
->GetSelection() );
1725 CloneNodeAttr( pNode
, pClone
);
1726 CloneKids( pNode
, pClone
);
1730 void SmCloningVisitor::Visit( SmBinHorNode
* pNode
)
1732 SmBinHorNode
* pClone
= new SmBinHorNode( pNode
->GetToken( ) );
1733 pClone
->SetSelection( pNode
->GetSelection() );
1734 CloneNodeAttr( pNode
, pClone
);
1735 CloneKids( pNode
, pClone
);
1739 void SmCloningVisitor::Visit( SmBinVerNode
* pNode
)
1741 SmBinVerNode
* pClone
= new SmBinVerNode( pNode
->GetToken( ) );
1742 pClone
->SetSelection( pNode
->GetSelection() );
1743 CloneNodeAttr( pNode
, pClone
);
1744 CloneKids( pNode
, pClone
);
1748 void SmCloningVisitor::Visit( SmBinDiagonalNode
* pNode
)
1750 SmBinDiagonalNode
*pClone
= new SmBinDiagonalNode( pNode
->GetToken( ) );
1751 pClone
->SetSelection( pNode
->GetSelection() );
1752 pClone
->SetAscending( pNode
->IsAscending( ) );
1753 CloneNodeAttr( pNode
, pClone
);
1754 CloneKids( pNode
, pClone
);
1758 void SmCloningVisitor::Visit( SmSubSupNode
* pNode
)
1760 SmSubSupNode
*pClone
= new SmSubSupNode( pNode
->GetToken( ) );
1761 pClone
->SetSelection( pNode
->GetSelection() );
1762 pClone
->SetUseLimits( pNode
->IsUseLimits( ) );
1763 CloneNodeAttr( pNode
, pClone
);
1764 CloneKids( pNode
, pClone
);
1768 void SmCloningVisitor::Visit( SmMatrixNode
* pNode
)
1770 SmMatrixNode
*pClone
= new SmMatrixNode( pNode
->GetToken( ) );
1771 pClone
->SetSelection( pNode
->GetSelection() );
1772 pClone
->SetRowCol( pNode
->GetNumRows( ), pNode
->GetNumCols( ) );
1773 CloneNodeAttr( pNode
, pClone
);
1774 CloneKids( pNode
, pClone
);
1778 void SmCloningVisitor::Visit( SmPlaceNode
* pNode
)
1780 mpResult
= new SmPlaceNode( pNode
->GetToken( ) );
1781 mpResult
->SetSelection( pNode
->GetSelection() );
1782 CloneNodeAttr( pNode
, mpResult
);
1785 void SmCloningVisitor::Visit( SmTextNode
* pNode
)
1787 SmTextNode
* pClone
= new SmTextNode( pNode
->GetToken( ), pNode
->GetFontDesc( ) );
1788 pClone
->SetSelection( pNode
->GetSelection() );
1789 pClone
->ChangeText( pNode
->GetText( ) );
1790 CloneNodeAttr( pNode
, pClone
);
1794 void SmCloningVisitor::Visit( SmSpecialNode
* pNode
)
1796 mpResult
= new SmSpecialNode( pNode
->GetToken( ) );
1797 mpResult
->SetSelection( pNode
->GetSelection() );
1798 CloneNodeAttr( pNode
, mpResult
);
1801 void SmCloningVisitor::Visit( SmGlyphSpecialNode
* pNode
)
1803 mpResult
= new SmGlyphSpecialNode( pNode
->GetToken( ) );
1804 mpResult
->SetSelection( pNode
->GetSelection() );
1805 CloneNodeAttr( pNode
, mpResult
);
1808 void SmCloningVisitor::Visit( SmMathSymbolNode
* pNode
)
1810 mpResult
= new SmMathSymbolNode( pNode
->GetToken( ) );
1811 mpResult
->SetSelection( pNode
->GetSelection() );
1812 CloneNodeAttr( pNode
, mpResult
);
1815 void SmCloningVisitor::Visit( SmBlankNode
* pNode
)
1817 SmBlankNode
* pClone
= new SmBlankNode( pNode
->GetToken( ) );
1818 pClone
->SetSelection( pNode
->GetSelection() );
1819 pClone
->SetBlankNum( pNode
->GetBlankNum( ) );
1821 CloneNodeAttr( pNode
, mpResult
);
1824 void SmCloningVisitor::Visit( SmErrorNode
* pNode
)
1826 mpResult
= new SmErrorNode( pNode
->GetToken( ) );
1827 mpResult
->SetSelection( pNode
->GetSelection() );
1828 CloneNodeAttr( pNode
, mpResult
);
1831 void SmCloningVisitor::Visit( SmLineNode
* pNode
)
1833 SmLineNode
* pClone
= new SmLineNode( pNode
->GetToken( ) );
1834 pClone
->SetSelection( pNode
->GetSelection() );
1835 CloneNodeAttr( pNode
, pClone
);
1836 CloneKids( pNode
, pClone
);
1840 void SmCloningVisitor::Visit( SmExpressionNode
* pNode
)
1842 SmExpressionNode
* pClone
= new SmExpressionNode( pNode
->GetToken( ) );
1843 pClone
->SetSelection( pNode
->GetSelection() );
1844 CloneNodeAttr( pNode
, pClone
);
1845 CloneKids( pNode
, pClone
);
1849 void SmCloningVisitor::Visit( SmPolyLineNode
* pNode
)
1851 mpResult
= new SmPolyLineNode( pNode
->GetToken( ) );
1852 mpResult
->SetSelection( pNode
->GetSelection() );
1853 CloneNodeAttr( pNode
, mpResult
);
1856 void SmCloningVisitor::Visit( SmRootNode
* pNode
)
1858 SmRootNode
* pClone
= new SmRootNode( pNode
->GetToken( ) );
1859 pClone
->SetSelection( pNode
->GetSelection() );
1860 CloneNodeAttr( pNode
, pClone
);
1861 CloneKids( pNode
, pClone
);
1865 void SmCloningVisitor::Visit( SmRootSymbolNode
* pNode
)
1867 mpResult
= new SmRootSymbolNode( pNode
->GetToken( ) );
1868 mpResult
->SetSelection( pNode
->GetSelection() );
1869 CloneNodeAttr( pNode
, mpResult
);
1872 void SmCloningVisitor::Visit( SmRectangleNode
* pNode
)
1874 mpResult
= new SmRectangleNode( pNode
->GetToken( ) );
1875 mpResult
->SetSelection( pNode
->GetSelection() );
1876 CloneNodeAttr( pNode
, mpResult
);
1879 void SmCloningVisitor::Visit( SmVerticalBraceNode
* pNode
)
1881 SmVerticalBraceNode
* pClone
= new SmVerticalBraceNode( pNode
->GetToken( ) );
1882 pClone
->SetSelection( pNode
->GetSelection() );
1883 CloneNodeAttr( pNode
, pClone
);
1884 CloneKids( pNode
, pClone
);
1888 // SmSelectionDrawingVisitor
1890 SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice
& rDevice
, SmNode
* pTree
, const Point
& rOffset
)
1891 : SmSelectionRectanglesVisitor( rDevice
, pTree
)
1893 //Draw selection if there's any
1894 if(GetSelection().IsEmpty()) return;
1896 tools::Rectangle aSelectionArea
= GetSelection() + rOffset
;
1899 rDevice
.Push( vcl::PushFlags::LINECOLOR
| vcl::PushFlags::FILLCOLOR
);
1901 rDevice
.SetLineColor( );
1902 rDevice
.SetFillColor( COL_LIGHTGRAY
);
1905 rDevice
.DrawRect( aSelectionArea
);
1907 //Restore device state
1911 // SmSelectionRectanglesVisitor
1913 SmSelectionRectanglesVisitor::SmSelectionRectanglesVisitor(OutputDevice
& rDevice
, SmNode
* pTree
)
1917 SAL_WARN_IF(!pTree
, "starmath", "pTree can't be null!");
1919 pTree
->Accept(this);
1922 void SmSelectionRectanglesVisitor::DefaultVisit( SmNode
* pNode
)
1924 if( pNode
->IsSelected( ) )
1925 ExtendSelectionArea( pNode
->AsRectangle( ) );
1926 VisitChildren( pNode
);
1929 void SmSelectionRectanglesVisitor::VisitChildren( SmNode
* pNode
)
1931 if(pNode
->GetNumSubNodes() == 0)
1933 for( auto pChild
: *static_cast<SmStructureNode
*>(pNode
) )
1937 pChild
->Accept( this );
1941 void SmSelectionRectanglesVisitor::Visit( SmTextNode
* pNode
)
1943 if( !pNode
->IsSelected())
1946 mrDev
.Push( vcl::PushFlags::TEXTCOLOR
| vcl::PushFlags::FONT
);
1948 mrDev
.SetFont( pNode
->GetFont( ) );
1949 Point Position
= pNode
->GetTopLeft( );
1950 tools::Long left
= Position
.getX( ) + mrDev
.GetTextWidth( pNode
->GetText( ), 0, pNode
->GetSelectionStart( ) );
1951 tools::Long right
= Position
.getX( ) + mrDev
.GetTextWidth( pNode
->GetText( ), 0, pNode
->GetSelectionEnd( ) );
1952 tools::Long top
= Position
.getY( );
1953 tools::Long bottom
= top
+ pNode
->GetHeight( );
1954 tools::Rectangle
rect( left
, top
, right
, bottom
);
1956 ExtendSelectionArea( rect
);
1961 // SmNodeToTextVisitor
1963 SmNodeToTextVisitor::SmNodeToTextVisitor( SmNode
* pNode
, OUString
&rText
)
1965 pNode
->Accept( this );
1966 maCmdText
.stripEnd(' ');
1967 rText
= maCmdText
.makeStringAndClear();
1970 void SmNodeToTextVisitor::Visit( SmTableNode
* pNode
)
1972 if( pNode
->GetToken( ).eType
== TBINOM
) {
1974 LineToText( pNode
->GetSubNode( 0 ) );
1975 LineToText( pNode
->GetSubNode( 1 ) );
1977 } else if( pNode
->GetToken( ).eType
== TSTACK
) {
1980 for( auto pChild
: *pNode
)
1991 LineToText( pChild
);
1995 } else { //Assume it's a toplevel table, containing lines
1997 for( auto pChild
: *pNode
)
2009 pChild
->Accept( this );
2014 void SmNodeToTextVisitor::Visit( SmBraceNode
* pNode
)
2016 if ( pNode
->GetToken().eType
== TEVALUATE
)
2018 SmNode
*pBody
= pNode
->Body();
2019 Append(u
"evaluate { ");
2020 pBody
->Accept( this );
2024 SmNode
*pLeftBrace
= pNode
->OpeningBrace(),
2025 *pBody
= pNode
->Body(),
2026 *pRightBrace
= pNode
->ClosingBrace();
2027 //Handle special case where it's absolute function
2028 if( pNode
->GetToken( ).eType
== TABS
) {
2030 LineToText( pBody
);
2032 if( pNode
->GetScaleMode( ) == SmScaleMode::Height
)
2034 pLeftBrace
->Accept( this );
2036 pBody
->Accept( this );
2038 if( pNode
->GetScaleMode( ) == SmScaleMode::Height
)
2040 pRightBrace
->Accept( this );
2045 void SmNodeToTextVisitor::Visit( SmBracebodyNode
* pNode
)
2047 for( auto pChild
: *pNode
)
2052 pChild
->Accept( this );
2056 void SmNodeToTextVisitor::Visit( SmOperNode
* pNode
)
2058 Append( pNode
->GetToken( ).aText
);
2060 if( pNode
->GetToken( ).eType
== TOPER
){
2061 //There's an SmGlyphSpecialNode if eType == TOPER
2062 if( pNode
->GetSubNode( 0 )->GetType( ) == SmNodeType::SubSup
)
2063 Append( pNode
->GetSubNode( 0 )->GetSubNode( 0 )->GetToken( ).aText
);
2065 Append( pNode
->GetSubNode( 0 )->GetToken( ).aText
);
2067 if( pNode
->GetSubNode( 0 )->GetType( ) == SmNodeType::SubSup
) {
2068 SmSubSupNode
*pSubSup
= static_cast<SmSubSupNode
*>( pNode
->GetSubNode( 0 ) );
2069 SmNode
* pChild
= pSubSup
->GetSubSup( LSUP
);
2073 LineToText( pChild
);
2076 pChild
= pSubSup
->GetSubSup( LSUB
);
2080 LineToText( pChild
);
2083 pChild
= pSubSup
->GetSubSup( RSUP
);
2087 LineToText( pChild
);
2090 pChild
= pSubSup
->GetSubSup( RSUB
);
2094 LineToText( pChild
);
2097 pChild
= pSubSup
->GetSubSup( CSUP
);
2100 if (pSubSup
->IsUseLimits())
2104 LineToText( pChild
);
2107 pChild
= pSubSup
->GetSubSup( CSUB
);
2110 if (pSubSup
->IsUseLimits())
2114 LineToText( pChild
);
2118 LineToText( pNode
->GetSubNode( 1 ) );
2121 void SmNodeToTextVisitor::Visit( SmAlignNode
* pNode
)
2123 Append( pNode
->GetToken( ).aText
);
2124 LineToText( pNode
->GetSubNode( 0 ) );
2127 void SmNodeToTextVisitor::Visit( SmAttributeNode
* pNode
)
2129 Append( pNode
->GetToken( ).aText
);
2130 LineToText( pNode
->Body() );
2133 void SmNodeToTextVisitor::Visit( SmFontNode
* pNode
)
2136 sal_uInt8 nr
, ng
, nb
;
2137 switch ( pNode
->GetToken( ).eType
)
2149 Append(u
"nitalic ");
2152 Append(u
"phantom ");
2157 switch ( pNode
->GetSizeType( ) )
2159 case FontSizeType::PLUS
:
2162 case FontSizeType::MINUS
:
2165 case FontSizeType::MULTIPLY
:
2168 case FontSizeType::DIVIDE
:
2171 case FontSizeType::ABSOLUT
:
2175 Append( ::rtl::math::doubleToUString(
2176 static_cast<double>( pNode
->GetSizeParameter( ) ),
2177 rtl_math_StringFormat_Automatic
,
2178 rtl_math_DecimalPlaces_Max
, '.', true ) );
2183 case TDVIPSNAMESCOL
:
2184 Append(u
"color dvip ");
2185 nc
= pNode
->GetToken().cMathChar
.toUInt32(16);
2186 Append( starmathdatabase::Identify_Color_Parser( nc
).aIdent
);
2192 nc
= pNode
->GetToken().cMathChar
.toUInt32(16);
2193 Append( starmathdatabase::Identify_Color_Parser( nc
).aIdent
);
2196 nc
= pNode
->GetToken().cMathChar
.toUInt32(16);
2197 Append(u
"color rgb ");
2203 Append(OUString::number(nr
));
2205 Append(OUString::number(ng
));
2207 Append(OUString::number(nb
));
2211 Append(u
"color rgba ");
2212 nc
= pNode
->GetToken().cMathChar
.toUInt32(16);
2219 Append(OUString::number(nr
));
2221 Append(OUString::number(ng
));
2223 Append(OUString::number(nb
));
2225 Append(OUString::number(nc
));
2229 Append(u
"color hex ");
2230 nc
= pNode
->GetToken().cMathChar
.toUInt32(16);
2231 Append(OUString::number(nc
,16));
2235 Append(u
"font sans ");
2238 Append(u
"font serif ");
2241 Append(u
"font fixed ");
2246 LineToText( pNode
->GetSubNode( 1 ) );
2249 void SmNodeToTextVisitor::Visit( SmUnHorNode
* pNode
)
2251 if(pNode
->GetSubNode( 1 )->GetToken( ).eType
== TFACT
)
2253 // visit children in the reverse order
2254 for( auto it
= pNode
->rbegin(); it
!= pNode
->rend(); ++it
)
2260 pChild
->Accept( this );
2265 for( auto pChild
: *pNode
)
2270 pChild
->Accept( this );
2275 void SmNodeToTextVisitor::Visit( SmBinHorNode
* pNode
)
2277 const SmNode
*pParent
= pNode
->GetParent();
2278 bool bBraceNeeded
= pParent
&& pParent
->GetType() == SmNodeType::Font
;
2279 SmNode
*pLeft
= pNode
->LeftOperand(),
2280 *pOper
= pNode
->Symbol(),
2281 *pRight
= pNode
->RightOperand();
2285 pLeft
->Accept( this );
2287 pOper
->Accept( this );
2289 pRight
->Accept( this );
2295 void SmNodeToTextVisitor::Visit( SmBinVerNode
* pNode
)
2297 if( pNode
->GetToken().eType
== TOVER
){
2298 SmNode
*pNum
= pNode
->GetSubNode( 0 ),
2299 *pDenom
= pNode
->GetSubNode( 2 );
2303 LineToText( pDenom
);
2306 SmNode
*pNum
= pNode
->GetSubNode( 0 ),
2307 *pDenom
= pNode
->GetSubNode( 2 );
2311 LineToText( pDenom
);
2316 void SmNodeToTextVisitor::Visit( SmBinDiagonalNode
* pNode
)
2318 SmNode
*pLeftOperand
= pNode
->GetSubNode( 0 ),
2319 *pRightOperand
= pNode
->GetSubNode( 1 );
2321 LineToText( pLeftOperand
);
2323 Append(u
"wideslash ");
2324 LineToText( pRightOperand
);
2328 void SmNodeToTextVisitor::Visit( SmSubSupNode
* pNode
)
2330 if( pNode
->GetToken().eType
== TEVALUATE
)
2332 Append(u
"evaluate { ");
2333 pNode
->GetSubNode( 0 )->GetSubNode( 1 )->Accept(this);
2335 SmNode
* pChild
= pNode
->GetSubSup( RSUP
);
2339 LineToText( pChild
);
2342 pChild
= pNode
->GetSubSup( RSUB
);
2346 LineToText( pChild
);
2352 LineToText( pNode
->GetBody( ) );
2353 SmNode
*pChild
= pNode
->GetSubSup( LSUP
);
2357 LineToText( pChild
);
2359 pChild
= pNode
->GetSubSup( LSUB
);
2363 LineToText( pChild
);
2365 pChild
= pNode
->GetSubSup( RSUP
);
2369 LineToText( pChild
);
2371 pChild
= pNode
->GetSubSup( RSUB
);
2375 LineToText( pChild
);
2377 pChild
= pNode
->GetSubSup( CSUP
);
2380 if (pNode
->IsUseLimits())
2384 LineToText( pChild
);
2386 pChild
= pNode
->GetSubSup( CSUB
);
2389 if (pNode
->IsUseLimits())
2393 LineToText( pChild
);
2398 void SmNodeToTextVisitor::Visit( SmMatrixNode
* pNode
)
2401 for (size_t i
= 0; i
< pNode
->GetNumRows(); ++i
)
2403 for (size_t j
= 0; j
< pNode
->GetNumCols( ); ++j
)
2405 SmNode
* pSubNode
= pNode
->GetSubNode( i
* pNode
->GetNumCols( ) + j
);
2408 pSubNode
->Accept( this );
2410 if (j
!= pNode
->GetNumCols() - 1U)
2414 if (i
!= pNode
->GetNumRows() - 1U)
2420 void SmNodeToTextVisitor::Visit( SmPlaceNode
* )
2425 void SmNodeToTextVisitor::Visit( SmTextNode
* pNode
)
2427 SmTokenType type
= pNode
->GetToken( ).eType
;
2431 Append( pNode
->GetToken().aText
);
2435 Append( pNode
->GetToken().aText
);
2438 Append( pNode
->GetToken().aText
);
2442 Append( pNode
->GetToken().aText
);
2446 Append( pNode
->GetToken().aText
);
2449 Append( pNode
->GetToken().aText
);
2454 void SmNodeToTextVisitor::Visit( SmSpecialNode
* pNode
)
2456 SmTokenType type
= pNode
->GetToken().eType
;
2459 Append(u
"lim sup ");
2462 Append(u
"lim inf ");
2465 Append( pNode
->GetToken().aText
);
2470 void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode
* pNode
)
2472 if( pNode
->GetToken( ).eType
== TBOPER
)
2476 Append( pNode
->GetToken( ).aText
);
2479 //TODO to improve this it is required to improve mathmlimport.
2480 void SmNodeToTextVisitor::Visit( SmMathSymbolNode
* pNode
)
2482 if ( ( pNode
->GetToken().nGroup
& TG::LBrace
)
2483 || ( pNode
->GetToken().nGroup
& TG::RBrace
)
2484 || ( pNode
->GetToken().nGroup
& TG::Sum
)
2485 || ( pNode
->GetToken().nGroup
& TG::Product
)
2486 || ( pNode
->GetToken().nGroup
& TG::Relation
)
2487 || ( pNode
->GetToken().nGroup
& TG::UnOper
)
2488 || ( pNode
->GetToken().nGroup
& TG::Oper
)
2490 Append( pNode
->GetToken().aText
);
2493 sal_Unicode cChar
= pNode
->GetToken().cMathChar
[0];
2512 if( pNode
->GetToken().eType
== TTOWARD
) Append(u
"toward");
2513 else Append(u
"rightarrow");
2516 Append(u
"leftarrow");
2522 Append(u
"downarrow");
2525 Append(u
"lambdabar");
2573 Append(u
"dlrarrow");
2585 Append(u
"notexists");
2588 Append(u
"emptyset");
2593 case MS_BACKEPSILON
:
2594 Append(u
"backepsilon");
2600 Append(u
"infinity");
2602 case 0x22b2: // NORMAL SUBGROUP OF
2603 Append(OUStringChar(cChar
));
2605 case 0x22b3: // CONTAINS AS NORMAL SUBGROUP
2606 Append(OUStringChar(cChar
));
2612 Append(u
"dotsvert");
2615 Append(u
"dotsaxis");
2621 Append(u
"dotsdown");
2630 Append(u
"widetilde");
2635 case 0xeb01: //no space
2636 case 0xeb08: //normal space
2638 case 0xef04: //tiny space
2639 case 0xef05: //tiny space
2640 case 0xeb02: //small space
2641 case 0xeb04: //medium space
2644 case 0xeb05: //large space
2651 Append(OUStringChar(cChar
));
2656 void SmNodeToTextVisitor::Visit( SmBlankNode
* pNode
)
2658 sal_uInt16 nNum
= pNode
->GetBlankNum();
2661 sal_uInt16 nWide
= nNum
/ 4;
2662 sal_uInt16 nNarrow
= nNum
% 4;
2663 for (sal_uInt16 i
= 0; i
< nWide
; i
++)
2665 for (sal_uInt16 i
= 0; i
< nNarrow
; i
++)
2670 void SmNodeToTextVisitor::Visit( SmErrorNode
* )
2674 void SmNodeToTextVisitor::Visit( SmLineNode
* pNode
)
2676 for( auto pChild
: *pNode
)
2681 pChild
->Accept( this );
2685 void SmNodeToTextVisitor::Visit( SmExpressionNode
* pNode
)
2687 bool bracketsNeeded
= pNode
->GetNumSubNodes() != 1 || pNode
->GetSubNode(0)->GetType() == SmNodeType::BinHor
;
2688 if (!bracketsNeeded
)
2690 const SmNode
*pParent
= pNode
->GetParent();
2693 pParent
&& pParent
->GetType() == SmNodeType::SubSup
&&
2694 pNode
->GetNumSubNodes() == 1 &&
2695 pNode
->GetSubNode(0)->GetType() == SmNodeType::SubSup
;
2698 if (bracketsNeeded
) {
2701 for( auto pChild
: *pNode
)
2705 pChild
->Accept( this );
2708 if (bracketsNeeded
) {
2713 void SmNodeToTextVisitor::Visit( SmPolyLineNode
* )
2717 void SmNodeToTextVisitor::Visit( SmRootNode
* pNode
)
2719 SmNode
*pExtra
= pNode
->GetSubNode( 0 ),
2720 *pBody
= pNode
->GetSubNode( 2 );
2723 LineToText( pExtra
);
2726 LineToText( pBody
);
2729 void SmNodeToTextVisitor::Visit( SmRootSymbolNode
* )
2733 void SmNodeToTextVisitor::Visit( SmRectangleNode
* )
2737 void SmNodeToTextVisitor::Visit( SmVerticalBraceNode
* pNode
)
2739 SmNode
*pBody
= pNode
->Body(),
2740 *pScript
= pNode
->Script();
2741 LineToText( pBody
);
2742 Append( pNode
->GetToken( ).aText
);
2743 LineToText( pScript
);
2746 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */