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 <tools/gen.hxx>
11 #include <vcl/lineinfo.hxx>
12 #include <visitors.hxx>
13 #include "tmpdevice.hxx"
17 // SmDefaultingVisitor
19 void SmDefaultingVisitor::Visit( SmTableNode
* pNode
)
21 DefaultVisit( pNode
);
24 void SmDefaultingVisitor::Visit( SmBraceNode
* pNode
)
26 DefaultVisit( pNode
);
29 void SmDefaultingVisitor::Visit( SmBracebodyNode
* pNode
)
31 DefaultVisit( pNode
);
34 void SmDefaultingVisitor::Visit( SmOperNode
* pNode
)
36 DefaultVisit( pNode
);
39 void SmDefaultingVisitor::Visit( SmAlignNode
* pNode
)
41 DefaultVisit( pNode
);
44 void SmDefaultingVisitor::Visit( SmAttributNode
* pNode
)
46 DefaultVisit( pNode
);
49 void SmDefaultingVisitor::Visit( SmFontNode
* pNode
)
51 DefaultVisit( pNode
);
54 void SmDefaultingVisitor::Visit( SmUnHorNode
* pNode
)
56 DefaultVisit( pNode
);
59 void SmDefaultingVisitor::Visit( SmBinHorNode
* pNode
)
61 DefaultVisit( pNode
);
64 void SmDefaultingVisitor::Visit( SmBinVerNode
* pNode
)
66 DefaultVisit( pNode
);
69 void SmDefaultingVisitor::Visit( SmBinDiagonalNode
* pNode
)
71 DefaultVisit( pNode
);
74 void SmDefaultingVisitor::Visit( SmSubSupNode
* pNode
)
76 DefaultVisit( pNode
);
79 void SmDefaultingVisitor::Visit( SmMatrixNode
* pNode
)
81 DefaultVisit( pNode
);
84 void SmDefaultingVisitor::Visit( SmPlaceNode
* pNode
)
86 DefaultVisit( pNode
);
89 void SmDefaultingVisitor::Visit( SmTextNode
* pNode
)
91 DefaultVisit( pNode
);
94 void SmDefaultingVisitor::Visit( SmSpecialNode
* pNode
)
96 DefaultVisit( pNode
);
99 void SmDefaultingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
101 DefaultVisit( pNode
);
104 void SmDefaultingVisitor::Visit( SmMathSymbolNode
* pNode
)
106 DefaultVisit( pNode
);
109 void SmDefaultingVisitor::Visit( SmBlankNode
* pNode
)
111 DefaultVisit( pNode
);
114 void SmDefaultingVisitor::Visit( SmErrorNode
* pNode
)
116 DefaultVisit( pNode
);
119 void SmDefaultingVisitor::Visit( SmLineNode
* pNode
)
121 DefaultVisit( pNode
);
124 void SmDefaultingVisitor::Visit( SmExpressionNode
* pNode
)
126 DefaultVisit( pNode
);
129 void SmDefaultingVisitor::Visit( SmPolyLineNode
* pNode
)
131 DefaultVisit( pNode
);
134 void SmDefaultingVisitor::Visit( SmRootNode
* pNode
)
136 DefaultVisit( pNode
);
139 void SmDefaultingVisitor::Visit( SmRootSymbolNode
* pNode
)
141 DefaultVisit( pNode
);
144 void SmDefaultingVisitor::Visit( SmRectangleNode
* pNode
)
146 DefaultVisit( pNode
);
149 void SmDefaultingVisitor::Visit( SmVerticalBraceNode
* pNode
)
151 DefaultVisit( pNode
);
154 // SmCaretDrawingVisitor
156 SmCaretDrawingVisitor::SmCaretDrawingVisitor( OutputDevice
& rDevice
,
163 , mbCaretVisible( caretVisible
)
165 SAL_WARN_IF( !position
.IsValid(), "starmath", "Cannot draw invalid position!" );
166 if( !position
.IsValid( ) )
170 mrDev
.Push( PushFlags::FONT
| PushFlags::MAPMODE
| PushFlags::LINECOLOR
| PushFlags::FILLCOLOR
| PushFlags::TEXTCOLOR
);
172 maPos
.pSelectedNode
->Accept( this );
173 //Restore device state
177 void SmCaretDrawingVisitor::Visit( SmTextNode
* pNode
)
179 long i
= maPos
.nIndex
;
181 mrDev
.SetFont( pNode
->GetFont( ) );
184 SmNode
* pLine
= SmCursor::FindTopMostNodeInLine( pNode
);
187 long left
= pNode
->GetLeft( ) + mrDev
.GetTextWidth( pNode
->GetText( ), 0, i
) + maOffset
.X( );
188 long top
= pLine
->GetTop( ) + maOffset
.Y( );
189 long height
= pLine
->GetHeight( );
190 long left_line
= pLine
->GetLeft( ) + maOffset
.X( );
191 long right_line
= pLine
->GetRight( ) + maOffset
.X( );
194 mrDev
.SetLineColor( COL_BLACK
);
196 if ( mbCaretVisible
) {
198 Point
p1( left
, top
);
199 Point
p2( left
, top
+ height
);
200 mrDev
.DrawLine( p1
, p2
);
204 Point
aLeft( left_line
, top
+ height
);
205 Point
aRight( right_line
, top
+ height
);
206 mrDev
.DrawLine( aLeft
, aRight
);
209 void SmCaretDrawingVisitor::DefaultVisit( SmNode
* pNode
)
212 SmNode
* pLine
= SmCursor::FindTopMostNodeInLine( pNode
);
215 long left
= pNode
->GetLeft( ) + maOffset
.X( ) + ( maPos
.nIndex
== 1 ? pNode
->GetWidth( ) : 0 );
216 long top
= pLine
->GetTop( ) + maOffset
.Y( );
217 long height
= pLine
->GetHeight( );
218 long left_line
= pLine
->GetLeft( ) + maOffset
.X( );
219 long right_line
= pLine
->GetRight( ) + maOffset
.X( );
222 mrDev
.SetLineColor( COL_BLACK
);
224 if ( mbCaretVisible
) {
226 Point
p1( left
, top
);
227 Point
p2( left
, top
+ height
);
228 mrDev
.DrawLine( p1
, p2
);
232 Point
aLeft( left_line
, top
+ height
);
233 Point
aRight( right_line
, top
+ height
);
234 mrDev
.DrawLine( aLeft
, aRight
);
237 // SmCaretPos2LineVisitor
239 void SmCaretPos2LineVisitor::Visit( SmTextNode
* pNode
)
242 mpDev
->Push( PushFlags::FONT
| PushFlags::TEXTCOLOR
);
244 long i
= maPos
.nIndex
;
246 mpDev
->SetFont( pNode
->GetFont( ) );
249 long left
= pNode
->GetLeft( ) + mpDev
->GetTextWidth( pNode
->GetText( ), 0, i
);
250 long top
= pNode
->GetTop( );
251 long height
= pNode
->GetHeight( );
253 maLine
= SmCaretLine( left
, top
, height
);
255 //Restore device state
259 void SmCaretPos2LineVisitor::DefaultVisit( SmNode
* pNode
)
261 //Vertical line ( code from SmCaretDrawingVisitor )
262 Point p1
= pNode
->GetTopLeft( );
263 if( maPos
.nIndex
== 1 )
264 p1
.Move( pNode
->GetWidth( ), 0 );
266 maLine
= SmCaretLine( p1
.X( ), p1
.Y( ), pNode
->GetHeight( ) );
272 void SmDrawingVisitor::Visit( SmTableNode
* pNode
)
274 DrawChildren( pNode
);
277 void SmDrawingVisitor::Visit( SmBraceNode
* pNode
)
279 DrawChildren( pNode
);
282 void SmDrawingVisitor::Visit( SmBracebodyNode
* pNode
)
284 DrawChildren( pNode
);
287 void SmDrawingVisitor::Visit( SmOperNode
* pNode
)
289 DrawChildren( pNode
);
292 void SmDrawingVisitor::Visit( SmAlignNode
* pNode
)
294 DrawChildren( pNode
);
297 void SmDrawingVisitor::Visit( SmAttributNode
* pNode
)
299 DrawChildren( pNode
);
302 void SmDrawingVisitor::Visit( SmFontNode
* pNode
)
304 DrawChildren( pNode
);
307 void SmDrawingVisitor::Visit( SmUnHorNode
* pNode
)
309 DrawChildren( pNode
);
312 void SmDrawingVisitor::Visit( SmBinHorNode
* pNode
)
314 DrawChildren( pNode
);
317 void SmDrawingVisitor::Visit( SmBinVerNode
* pNode
)
319 DrawChildren( pNode
);
322 void SmDrawingVisitor::Visit( SmBinDiagonalNode
* pNode
)
324 DrawChildren( pNode
);
327 void SmDrawingVisitor::Visit( SmSubSupNode
* pNode
)
329 DrawChildren( pNode
);
332 void SmDrawingVisitor::Visit( SmMatrixNode
* pNode
)
334 DrawChildren( pNode
);
337 void SmDrawingVisitor::Visit( SmPlaceNode
* pNode
)
339 DrawSpecialNode( pNode
);
342 void SmDrawingVisitor::Visit( SmTextNode
* pNode
)
344 DrawTextNode( pNode
);
347 void SmDrawingVisitor::Visit( SmSpecialNode
* pNode
)
349 DrawSpecialNode( pNode
);
352 void SmDrawingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
354 DrawSpecialNode( pNode
);
357 void SmDrawingVisitor::Visit( SmMathSymbolNode
* pNode
)
359 DrawSpecialNode( pNode
);
362 void SmDrawingVisitor::Visit( SmBlankNode
* )
366 void SmDrawingVisitor::Visit( SmErrorNode
* pNode
)
368 DrawSpecialNode( pNode
);
371 void SmDrawingVisitor::Visit( SmLineNode
* pNode
)
373 DrawChildren( pNode
);
376 void SmDrawingVisitor::Visit( SmExpressionNode
* pNode
)
378 DrawChildren( pNode
);
381 void SmDrawingVisitor::Visit( SmRootNode
* pNode
)
383 DrawChildren( pNode
);
386 void SmDrawingVisitor::Visit( SmVerticalBraceNode
* pNode
)
388 DrawChildren( pNode
);
391 void SmDrawingVisitor::Visit( SmRootSymbolNode
* pNode
)
393 if ( pNode
->IsPhantom( ) )
396 // draw root-sign itself
397 DrawSpecialNode( pNode
);
399 SmTmpDevice
aTmpDev( mrDev
, true );
400 aTmpDev
.SetFillColor( pNode
->GetFont( ).GetColor( ) );
401 mrDev
.SetLineColor( );
402 aTmpDev
.SetFont( pNode
->GetFont( ) );
404 // since the width is always unscaled it corresponds to the _original_
405 // _unscaled_ font height to be used, we use that to calculate the
406 // bar height. Thus it is independent of the arguments height.
407 // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
408 long nBarHeight
= pNode
->GetWidth( ) * 7L / 100L;
409 long nBarWidth
= pNode
->GetBodyWidth( ) + pNode
->GetBorderWidth( );
410 Point
aBarOffset( pNode
->GetWidth( ), +pNode
->GetBorderWidth( ) );
411 Point
aBarPos( maPosition
+ aBarOffset
);
413 tools::Rectangle
aBar( aBarPos
, Size( nBarWidth
, nBarHeight
) );
414 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
415 //! increasing zoomfactor.
416 // This is done by shifting its output-position to a point that
417 // corresponds exactly to a pixel on the output device.
418 Point
aDrawPos( mrDev
.PixelToLogic( mrDev
.LogicToPixel( aBar
.TopLeft( ) ) ) );
419 aBar
.SetPos( aDrawPos
);
421 mrDev
.DrawRect( aBar
);
424 void SmDrawingVisitor::Visit( SmPolyLineNode
* pNode
)
426 if ( pNode
->IsPhantom( ) )
429 long nBorderwidth
= pNode
->GetFont( ).GetBorderWidth( );
432 aInfo
.SetWidth( pNode
->GetWidth( ) - 2 * nBorderwidth
);
434 Point
aOffset ( Point( ) - pNode
->GetPolygon( ).GetBoundRect( ).TopLeft( )
435 + Point( nBorderwidth
, nBorderwidth
) ),
436 aPos ( maPosition
+ aOffset
);
437 pNode
->GetPolygon( ).Move( aPos
.X( ), aPos
.Y( ) ); //Works because Polygon wraps a pointer
439 SmTmpDevice
aTmpDev ( mrDev
, false );
440 aTmpDev
.SetLineColor( pNode
->GetFont( ).GetColor( ) );
442 mrDev
.DrawPolyLine( pNode
->GetPolygon( ), aInfo
);
445 void SmDrawingVisitor::Visit( SmRectangleNode
* pNode
)
447 if ( pNode
->IsPhantom( ) )
450 SmTmpDevice
aTmpDev ( mrDev
, false );
451 aTmpDev
.SetFillColor( pNode
->GetFont( ).GetColor( ) );
452 mrDev
.SetLineColor( );
453 aTmpDev
.SetFont( pNode
->GetFont( ) );
455 sal_uLong nTmpBorderWidth
= pNode
->GetFont( ).GetBorderWidth( );
457 // get rectangle and remove borderspace
458 tools::Rectangle
aTmp ( pNode
->AsRectangle( ) + maPosition
- pNode
->GetTopLeft( ) );
459 aTmp
.AdjustLeft(nTmpBorderWidth
);
460 aTmp
.AdjustRight( -sal_Int32(nTmpBorderWidth
) );
461 aTmp
.AdjustTop(nTmpBorderWidth
);
462 aTmp
.AdjustBottom( -sal_Int32(nTmpBorderWidth
) );
464 SAL_WARN_IF( aTmp
.GetHeight() == 0 || aTmp
.GetWidth() == 0,
465 "starmath", "Empty rectangle" );
467 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
468 //! increasing zoomfactor.
469 // This is done by shifting its output-position to a point that
470 // corresponds exactly to a pixel on the output device.
471 Point
aPos ( mrDev
.PixelToLogic( mrDev
.LogicToPixel( aTmp
.TopLeft( ) ) ) );
474 mrDev
.DrawRect( aTmp
);
477 void SmDrawingVisitor::DrawTextNode( SmTextNode
* pNode
)
479 if ( pNode
->IsPhantom() || pNode
->GetText().isEmpty() || pNode
->GetText()[0] == '\0' )
482 SmTmpDevice
aTmpDev ( mrDev
, false );
483 aTmpDev
.SetFont( pNode
->GetFont( ) );
485 Point
aPos ( maPosition
);
486 aPos
.AdjustY(pNode
->GetBaselineOffset( ) );
487 // round to pixel coordinate
488 aPos
= mrDev
.PixelToLogic( mrDev
.LogicToPixel( aPos
) );
490 mrDev
.DrawStretchText( aPos
, pNode
->GetWidth( ), pNode
->GetText( ) );
493 void SmDrawingVisitor::DrawSpecialNode( SmSpecialNode
* pNode
)
495 //! since this chars might come from any font, that we may not have
496 //! set to ALIGN_BASELINE yet, we do it now.
497 pNode
->GetFont( ).SetAlignment( ALIGN_BASELINE
);
499 DrawTextNode( pNode
);
502 void SmDrawingVisitor::DrawChildren( SmStructureNode
* pNode
)
504 if ( pNode
->IsPhantom( ) )
507 Point rPosition
= maPosition
;
509 for( auto pChild
: *pNode
)
513 Point
aOffset ( pChild
->GetTopLeft( ) - pNode
->GetTopLeft( ) );
514 maPosition
= rPosition
+ aOffset
;
515 pChild
->Accept( this );
519 // SmSetSelectionVisitor
521 SmSetSelectionVisitor::SmSetSelectionVisitor( SmCaretPos startPos
, SmCaretPos endPos
, SmNode
* pTree
)
522 : maStartPos(startPos
)
526 //Assume that pTree is a SmTableNode
527 SAL_WARN_IF(pTree
->GetType() != SmNodeType::Table
, "starmath", "pTree should be a SmTableNode!");
528 //Visit root node, this is special as this node cannot be selected, but its children can!
529 if(pTree
->GetType() == SmNodeType::Table
){
530 //Change state if maStartPos is in front of this node
531 if( maStartPos
.pSelectedNode
== pTree
&& maStartPos
.nIndex
== 0 )
532 mbSelecting
= !mbSelecting
;
533 //Change state if maEndPos is in front of this node
534 if( maEndPos
.pSelectedNode
== pTree
&& maEndPos
.nIndex
== 0 )
535 mbSelecting
= !mbSelecting
;
536 SAL_WARN_IF(mbSelecting
, "starmath", "Caret positions needed to set mbSelecting about, shouldn't be possible!");
539 for( auto pChild
: *static_cast<SmStructureNode
*>(pTree
) )
543 pChild
->Accept( this );
544 //If we started a selection in this line and it haven't ended, we do that now!
547 SetSelectedOnAll(pChild
);
548 //Set maStartPos and maEndPos to invalid positions, this ensures that an unused
549 //start or end (because we forced end above), doesn't start a new selection.
550 maStartPos
= maEndPos
= SmCaretPos();
553 //Check if pTree isn't selected
554 SAL_WARN_IF(pTree
->IsSelected(), "starmath", "pTree should never be selected!");
555 //Discard the selection if there's a bug (it's better than crashing)
556 if(pTree
->IsSelected())
557 SetSelectedOnAll(pTree
, false);
558 }else //This shouldn't happen, but I don't see any reason to die if it does
562 void SmSetSelectionVisitor::SetSelectedOnAll( SmNode
* pSubTree
, bool IsSelected
) {
563 pSubTree
->SetSelected( IsSelected
);
565 if(pSubTree
->GetNumSubNodes() == 0)
567 //Quick BFS to set all selections
568 for( auto pChild
: *static_cast<SmStructureNode
*>(pSubTree
) )
572 SetSelectedOnAll( pChild
, IsSelected
);
576 void SmSetSelectionVisitor::DefaultVisit( SmNode
* pNode
) {
577 //Change state if maStartPos is in front of this node
578 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 0 )
579 mbSelecting
= !mbSelecting
;
580 //Change state if maEndPos is in front of this node
581 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 0 )
582 mbSelecting
= !mbSelecting
;
584 //Cache current state
585 bool WasSelecting
= mbSelecting
;
586 bool ChangedState
= false;
589 pNode
->SetSelected( mbSelecting
);
592 if(pNode
->GetNumSubNodes() > 0)
594 for( auto pChild
: *static_cast<SmStructureNode
*>(pNode
) )
598 pChild
->Accept( this );
599 ChangedState
= ( WasSelecting
!= mbSelecting
) || ChangedState
;
606 //Select this node and all of its children
607 //(Make exception for SmBracebodyNode)
608 if( pNode
->GetType() != SmNodeType::Bracebody
||
609 !pNode
->GetParent() ||
610 pNode
->GetParent()->GetType() != SmNodeType::Brace
)
611 SetSelectedOnAll( pNode
);
613 SetSelectedOnAll( pNode
->GetParent() );
614 /* If the equation is: sqrt{2 + 4} + 5
615 * And the selection is: sqrt{2 + [4} +] 5
616 * Where [ denotes maStartPos and ] denotes maEndPos
617 * Then the sqrt node should be selected, so that the
618 * effective selection is: [sqrt{2 + 4} +] 5
619 * The same is the case if we swap maStartPos and maEndPos.
623 //Change state if maStartPos is after this node
624 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 1 )
626 mbSelecting
= !mbSelecting
;
628 //Change state if maEndPos is after of this node
629 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 1 )
631 mbSelecting
= !mbSelecting
;
635 void SmSetSelectionVisitor::VisitCompositionNode( SmStructureNode
* pNode
)
637 //Change state if maStartPos is in front of this node
638 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 0 )
639 mbSelecting
= !mbSelecting
;
640 //Change state if maEndPos is in front of this node
641 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 0 )
642 mbSelecting
= !mbSelecting
;
644 //Cache current state
645 bool WasSelecting
= mbSelecting
;
648 for( auto pChild
: *pNode
)
652 pChild
->Accept( this );
655 //Set selected, if everything was selected
656 pNode
->SetSelected( WasSelecting
&& mbSelecting
);
658 //Change state if maStartPos is after this node
659 if( maStartPos
.pSelectedNode
== pNode
&& maStartPos
.nIndex
== 1 )
660 mbSelecting
= !mbSelecting
;
661 //Change state if maEndPos is after of this node
662 if( maEndPos
.pSelectedNode
== pNode
&& maEndPos
.nIndex
== 1 )
663 mbSelecting
= !mbSelecting
;
666 void SmSetSelectionVisitor::Visit( SmTextNode
* pNode
) {
669 if( maStartPos
.pSelectedNode
== pNode
)
670 i1
= maStartPos
.nIndex
;
671 if( maEndPos
.pSelectedNode
== pNode
)
672 i2
= maEndPos
.nIndex
;
675 pNode
->SetSelected(true);
676 if( i1
!= -1 && i2
!= -1 ) {
677 start
= std::min(i1
, i2
);
678 end
= std::max(i1
, i2
);
679 } else if( mbSelecting
&& i1
!= -1 ) {
683 } else if( mbSelecting
&& i2
!= -1 ) {
687 } else if( !mbSelecting
&& i1
!= -1 ) {
689 end
= pNode
->GetText().getLength();
691 } else if( !mbSelecting
&& i2
!= -1 ) {
693 end
= pNode
->GetText().getLength();
695 } else if( mbSelecting
) {
697 end
= pNode
->GetText().getLength();
699 pNode
->SetSelected( false );
703 pNode
->SetSelected( start
!= end
);
704 pNode
->SetSelectionStart( start
);
705 pNode
->SetSelectionEnd( end
);
708 void SmSetSelectionVisitor::Visit( SmExpressionNode
* pNode
) {
709 VisitCompositionNode( pNode
);
712 void SmSetSelectionVisitor::Visit( SmLineNode
* pNode
) {
713 VisitCompositionNode( pNode
);
716 void SmSetSelectionVisitor::Visit( SmAlignNode
* pNode
) {
717 VisitCompositionNode( pNode
);
720 void SmSetSelectionVisitor::Visit( SmBinHorNode
* pNode
) {
721 VisitCompositionNode( pNode
);
724 void SmSetSelectionVisitor::Visit( SmUnHorNode
* pNode
) {
725 VisitCompositionNode( pNode
);
728 void SmSetSelectionVisitor::Visit( SmFontNode
* pNode
) {
729 VisitCompositionNode( pNode
);
732 // SmCaretPosGraphBuildingVisitor
734 SmCaretPosGraphBuildingVisitor::SmCaretPosGraphBuildingVisitor( SmNode
* pRootNode
)
735 : mpRightMost(nullptr)
736 , mpGraph(new SmCaretPosGraph
)
738 //pRootNode should always be a table
739 SAL_WARN_IF( pRootNode
->GetType( ) != SmNodeType::Table
, "starmath", "pRootNode must be a table node");
740 //Handle the special case where SmNodeType::Table is used a rootnode
741 if( pRootNode
->GetType( ) == SmNodeType::Table
){
742 //Children are SmLineNodes
743 //Or so I thought... Apparently, the children can be instances of SmExpression
744 //especially if there's a error in the formula... So he we go, a simple work around.
745 for( auto pChild
: *static_cast<SmStructureNode
*>(pRootNode
) )
749 mpRightMost
= mpGraph
->Add( SmCaretPos( pChild
, 0 ) );
750 pChild
->Accept( this );
753 pRootNode
->Accept(this);
756 SmCaretPosGraphBuildingVisitor::~SmCaretPosGraphBuildingVisitor()
760 void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode
* pNode
){
761 for( auto pChild
: *pNode
)
765 pChild
->Accept( this );
769 /** Build SmCaretPosGraph for SmTableNode
770 * This method covers cases where SmTableNode is used in a binom or stack,
771 * the special case where it is used as root node for the entire formula is
772 * handled in the constructor.
774 void SmCaretPosGraphBuildingVisitor::Visit( SmTableNode
* pNode
){
775 SmCaretPosGraphEntry
*left
= mpRightMost
,
776 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1) );
777 bool bIsFirst
= true;
778 for( auto pChild
: *pNode
)
782 mpRightMost
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
784 left
->SetRight(mpRightMost
);
785 pChild
->Accept( this );
786 mpRightMost
->SetRight(right
);
788 right
->SetLeft(mpRightMost
);
794 /** Build SmCaretPosGraph for SmSubSupNode
796 * The child positions in a SubSupNode, where H is the body:
809 * Graph over these, where "left" is before the SmSubSupNode and "right" is after:
824 void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode
* pNode
)
826 SmCaretPosGraphEntry
*left
,
835 SAL_WARN_IF( !pNode
->GetBody(), "starmath", "SmSubSupNode Doesn't have a body!" );
836 bodyLeft
= mpGraph
->Add( SmCaretPos( pNode
->GetBody( ), 0 ), left
);
837 left
->SetRight( bodyLeft
); //TODO: Don't make this if LSUP or LSUB are NULL ( not sure??? )
840 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
842 //Visit the body, to get bodyRight
843 mpRightMost
= bodyLeft
;
844 pNode
->GetBody( )->Accept( this );
845 bodyRight
= mpRightMost
;
846 bodyRight
->SetRight( right
);
847 right
->SetLeft( bodyRight
);
850 SmNode
* pChild
= pNode
->GetSubSup( LSUP
);
852 SmCaretPosGraphEntry
*cLeft
; //Child left
853 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
856 pChild
->Accept( this );
858 mpRightMost
->SetRight( bodyLeft
);
861 pChild
= pNode
->GetSubSup( LSUB
);
863 SmCaretPosGraphEntry
*cLeft
; //Child left
864 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
867 pChild
->Accept( this );
869 mpRightMost
->SetRight( bodyLeft
);
872 pChild
= pNode
->GetSubSup( CSUP
);
874 SmCaretPosGraphEntry
*cLeft
; //Child left
875 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
878 pChild
->Accept( this );
880 mpRightMost
->SetRight( right
);
883 pChild
= pNode
->GetSubSup( CSUB
);
885 SmCaretPosGraphEntry
*cLeft
; //Child left
886 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
889 pChild
->Accept( this );
891 mpRightMost
->SetRight( right
);
894 pChild
= pNode
->GetSubSup( RSUP
);
896 SmCaretPosGraphEntry
*cLeft
; //Child left
897 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), bodyRight
);
900 pChild
->Accept( this );
902 mpRightMost
->SetRight( right
);
905 pChild
= pNode
->GetSubSup( RSUB
);
907 SmCaretPosGraphEntry
*cLeft
; //Child left
908 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), bodyRight
);
911 pChild
->Accept( this );
913 mpRightMost
->SetRight( right
);
916 //Set return parameters
920 /** Build caret position for SmOperNode
922 * If first child is an SmSubSupNode we will ignore its
923 * body, as this body is a SmMathSymbol, for SUM, INT or similar
924 * that shouldn't be subject to modification.
925 * If first child is not a SmSubSupNode, ignore it completely
926 * as it is a SmMathSymbol.
928 * The child positions in a SmOperNode, where H is symbol, e.g. int, sum or similar:
932 * LSUP H H RSUP BBB BB BBB B B
933 * H H B B B B B B B B
936 * LSUB H H RSUB BBB BB BBB B
940 * Notice, CSUP, etc. are actually grandchildren, but inorder to ignore H, these are visited
941 * from here. If they are present, that is if pOper is an instance of SmSubSupNode.
943 * Graph over these, where "left" is before the SmOperNode and "right" is after:
957 void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode
* pNode
)
959 SmNode
*pOper
= pNode
->GetSubNode( 0 ),
960 *pBody
= pNode
->GetSubNode( 1 );
962 SmCaretPosGraphEntry
*left
= mpRightMost
,
967 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
968 left
->SetRight( bodyLeft
);
970 //Visit body, get bodyRight
971 mpRightMost
= bodyLeft
;
972 pBody
->Accept( this );
973 bodyRight
= mpRightMost
;
976 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), bodyRight
);
977 bodyRight
->SetRight( right
);
979 //Get subsup pNode if any
980 SmSubSupNode
* pSubSup
= pOper
->GetType( ) == SmNodeType::SubSup
? static_cast<SmSubSupNode
*>(pOper
) : nullptr;
983 SmCaretPosGraphEntry
*childLeft
;
985 pChild
= pSubSup
->GetSubSup( LSUP
);
987 //Create position in front of pChild
988 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
990 mpRightMost
= childLeft
;
991 pChild
->Accept( this );
992 //Set right on mpRightMost from pChild
993 mpRightMost
->SetRight( bodyLeft
);
997 pChild
= pSubSup
->GetSubSup( LSUB
);
999 //Create position in front of pChild
1000 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
);
1009 pChild
= pSubSup
->GetSubSup( CSUP
);
1011 //Create position in front of pChild
1012 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1014 mpRightMost
= childLeft
;
1015 pChild
->Accept( this );
1016 //Set right on mpRightMost from pChild
1017 mpRightMost
->SetRight( bodyLeft
);
1021 pChild
= pSubSup
->GetSubSup( CSUB
);
1022 if( pChild
) { //FROM
1023 //Create position in front of pChild
1024 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1026 mpRightMost
= childLeft
;
1027 pChild
->Accept( this );
1028 //Set right on mpRightMost from pChild
1029 mpRightMost
->SetRight( bodyLeft
);
1033 pChild
= pSubSup
->GetSubSup( RSUP
);
1035 //Create position in front of pChild
1036 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1038 mpRightMost
= childLeft
;
1039 pChild
->Accept( this );
1040 //Set right on mpRightMost from pChild
1041 mpRightMost
->SetRight( bodyLeft
);
1045 pChild
= pSubSup
->GetSubSup( RSUB
);
1047 //Create position in front of pChild
1048 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1050 mpRightMost
= childLeft
;
1051 pChild
->Accept( this );
1052 //Set right on mpRightMost from pChild
1053 mpRightMost
->SetRight( bodyLeft
);
1058 mpRightMost
= right
;
1061 void SmCaretPosGraphBuildingVisitor::Visit( SmMatrixNode
* pNode
)
1063 SmCaretPosGraphEntry
*left
= mpRightMost
,
1064 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1066 for (size_t i
= 0; i
< pNode
->GetNumRows(); ++i
)
1068 SmCaretPosGraphEntry
* r
= left
;
1069 for (size_t j
= 0; j
< pNode
->GetNumCols(); ++j
)
1071 SmNode
* pSubNode
= pNode
->GetSubNode( i
* pNode
->GetNumCols( ) + j
);
1073 mpRightMost
= mpGraph
->Add( SmCaretPos( pSubNode
, 0 ), r
);
1074 if( j
!= 0 || ( pNode
->GetNumRows() - 1U ) / 2 == i
)
1075 r
->SetRight( mpRightMost
);
1077 pSubNode
->Accept( this );
1081 mpRightMost
->SetRight( right
);
1082 if( ( pNode
->GetNumRows() - 1U ) / 2 == i
)
1083 right
->SetLeft( mpRightMost
);
1086 mpRightMost
= right
;
1089 /** Build SmCaretPosGraph for SmTextNode
1091 * Lines in an SmTextNode:
1095 * Where A B and C are characters in the text.
1097 * Graph over these, where "left" is before the SmTextNode and "right" is after:
1105 * Notice that C and right is the same position here.
1107 void SmCaretPosGraphBuildingVisitor::Visit( SmTextNode
* pNode
)
1109 SAL_WARN_IF( pNode
->GetText().isEmpty(), "starmath", "Empty SmTextNode is bad" );
1111 int size
= pNode
->GetText().getLength();
1112 for( int i
= 1; i
<= size
; i
++ ){
1113 SmCaretPosGraphEntry
* pRight
= mpRightMost
;
1114 mpRightMost
= mpGraph
->Add( SmCaretPos( pNode
, i
), pRight
);
1115 pRight
->SetRight( mpRightMost
);
1119 /** Build SmCaretPosGraph for SmBinVerNode
1121 * Lines in an SmBinVerNode:
1128 * Graph over these, where "left" is before the SmBinVerNode and "right" is after:
1137 void SmCaretPosGraphBuildingVisitor::Visit( SmBinVerNode
* pNode
)
1139 //None if these children can be NULL, see SmBinVerNode::Arrange
1140 SmNode
*pNum
= pNode
->GetSubNode( 0 ),
1141 *pDenom
= pNode
->GetSubNode( 2 );
1143 SmCaretPosGraphEntry
*left
,
1148 assert(mpRightMost
);
1153 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1156 numLeft
= mpGraph
->Add( SmCaretPos( pNum
, 0 ), left
);
1157 left
->SetRight( numLeft
);
1160 mpRightMost
= numLeft
;
1161 pNum
->Accept( this );
1162 mpRightMost
->SetRight( right
);
1163 right
->SetLeft( mpRightMost
);
1166 denomLeft
= mpGraph
->Add( SmCaretPos( pDenom
, 0 ), left
);
1169 mpRightMost
= denomLeft
;
1170 pDenom
->Accept( this );
1171 mpRightMost
->SetRight( right
);
1173 //Set return parameter
1174 mpRightMost
= right
;
1177 /** Build SmCaretPosGraph for SmVerticalBraceNode
1179 * Lines in an SmVerticalBraceNode:
1188 void SmCaretPosGraphBuildingVisitor::Visit( SmVerticalBraceNode
* pNode
)
1190 SmNode
*pBody
= pNode
->Body(),
1191 *pScript
= pNode
->Script();
1192 //None of these children can be NULL
1194 SmCaretPosGraphEntry
*left
,
1202 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1205 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1206 left
->SetRight( bodyLeft
);
1207 mpRightMost
= bodyLeft
;
1208 pBody
->Accept( this );
1209 mpRightMost
->SetRight( right
);
1210 right
->SetLeft( mpRightMost
);
1213 scriptLeft
= mpGraph
->Add( SmCaretPos( pScript
, 0 ), left
);
1214 mpRightMost
= scriptLeft
;
1215 pScript
->Accept( this );
1216 mpRightMost
->SetRight( right
);
1219 mpRightMost
= right
;
1222 /** Build SmCaretPosGraph for SmBinDiagonalNode
1224 * Lines in an SmBinDiagonalNode:
1230 * Where A and B are lines.
1232 * Used in formulas such as "A wideslash B"
1234 void SmCaretPosGraphBuildingVisitor::Visit( SmBinDiagonalNode
* pNode
)
1236 SmNode
*A
= pNode
->GetSubNode( 0 ),
1237 *B
= pNode
->GetSubNode( 1 );
1239 SmCaretPosGraphEntry
*left
,
1247 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1250 leftA
= mpGraph
->Add( SmCaretPos( A
, 0 ), left
);
1251 left
->SetRight( leftA
);
1254 mpRightMost
= leftA
;
1256 rightA
= mpRightMost
;
1259 leftB
= mpGraph
->Add( SmCaretPos( B
, 0 ), rightA
);
1260 rightA
->SetRight( leftB
);
1263 mpRightMost
= leftB
;
1265 mpRightMost
->SetRight( right
);
1266 right
->SetLeft( mpRightMost
);
1269 mpRightMost
= right
;
1272 //Straight forward ( I think )
1273 void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode
* pNode
)
1275 for( auto pChild
: *pNode
)
1279 pChild
->Accept( this );
1282 void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode
* pNode
)
1284 // Unary operator node
1285 for( auto pChild
: *pNode
)
1289 pChild
->Accept( this );
1293 void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode
* pNode
)
1295 for( auto pChild
: *pNode
)
1299 pChild
->Accept( this );
1303 void SmCaretPosGraphBuildingVisitor::Visit( SmFontNode
* pNode
)
1305 //Has only got one child, should act as an expression if possible
1306 for( auto pChild
: *pNode
)
1310 pChild
->Accept( this );
1314 /** Build SmCaretPosGraph for SmBracebodyNode
1315 * Acts as an SmExpressionNode
1317 * Below is an example of a formula tree that has multiple children for SmBracebodyNode
1321 * label= "Equation: \"lbrace i mline i in setZ rbrace\"";
1322 * n0 [label="SmTableNode"];
1323 * n0 -> n1 [label="0"];
1324 * n1 [label="SmLineNode"];
1325 * n1 -> n2 [label="0"];
1326 * n2 [label="SmExpressionNode"];
1327 * n2 -> n3 [label="0"];
1328 * n3 [label="SmBraceNode"];
1329 * n3 -> n4 [label="0"];
1330 * n4 [label="SmMathSymbolNode: {"];
1331 * n3 -> n5 [label="1"];
1332 * n5 [label="SmBracebodyNode"];
1333 * n5 -> n6 [label="0"];
1334 * n6 [label="SmExpressionNode"];
1335 * n6 -> n7 [label="0"];
1336 * n7 [label="SmTextNode: i"];
1337 * n5 -> n8 [label="1"];
1338 * n8 [label="SmMathSymbolNode: |"]; // Unicode "VERTICAL LINE"
1339 * n5 -> n9 [label="2"];
1340 * n9 [label="SmExpressionNode"];
1341 * n9 -> n10 [label="0"];
1342 * n10 [label="SmBinHorNode"];
1343 * n10 -> n11 [label="0"];
1344 * n11 [label="SmTextNode: i"];
1345 * n10 -> n12 [label="1"];
1346 * n12 [label="SmMathSymbolNode: ∈"]; // Unicode "ELEMENT OF"
1347 * n10 -> n13 [label="2"];
1348 * n13 [label="SmMathSymbolNode: ℤ"]; // Unicode "DOUBLE-STRUCK CAPITAL Z"
1349 * n3 -> n14 [label="2"];
1350 * n14 [label="SmMathSymbolNode: }"];
1354 void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode
* pNode
)
1356 for( auto pChild
: *pNode
)
1360 SmCaretPosGraphEntry
* pStart
= mpGraph
->Add( SmCaretPos( pChild
, 0), mpRightMost
);
1361 mpRightMost
->SetRight( pStart
);
1362 mpRightMost
= pStart
;
1363 pChild
->Accept( this );
1367 /** Build SmCaretPosGraph for SmAlignNode
1368 * Acts as an SmExpressionNode, as it only has one child this okay
1370 void SmCaretPosGraphBuildingVisitor::Visit( SmAlignNode
* pNode
)
1372 for( auto pChild
: *pNode
)
1376 pChild
->Accept( this );
1380 /** Build SmCaretPosGraph for SmRootNode
1382 * Lines in an SmRootNode:
1389 * A: pExtra ( optional, can be NULL ),
1392 * Graph over these, where "left" is before the SmRootNode and "right" is after:
1401 void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode
* pNode
)
1403 SmNode
*pExtra
= pNode
->GetSubNode( 0 ), //Argument, NULL for sqrt, and SmTextNode if cubicroot
1404 *pBody
= pNode
->GetSubNode( 2 ); //Body of the root
1407 SmCaretPosGraphEntry
*left
,
1412 //Get left and save it
1413 assert(mpRightMost
);
1417 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1418 left
->SetRight( bodyLeft
);
1421 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1424 mpRightMost
= bodyLeft
;
1425 pBody
->Accept( this );
1426 bodyRight
= mpRightMost
;
1427 bodyRight
->SetRight( right
);
1428 right
->SetLeft( bodyRight
);
1432 mpRightMost
= mpGraph
->Add( SmCaretPos( pExtra
, 0 ), left
);
1433 pExtra
->Accept( this );
1434 mpRightMost
->SetRight( bodyLeft
);
1437 mpRightMost
= right
;
1441 /** Build SmCaretPosGraph for SmPlaceNode
1442 * Consider this a single character.
1444 void SmCaretPosGraphBuildingVisitor::Visit( SmPlaceNode
* pNode
)
1446 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1447 mpRightMost
->SetRight( right
);
1448 mpRightMost
= right
;
1451 /** SmErrorNode is context dependent metadata, it can't be selected
1453 * @remarks There's no point in deleting, copying and/or moving an instance
1454 * of SmErrorNode as it may not exist in an other context! Thus there are no
1455 * positions to select an SmErrorNode.
1457 void SmCaretPosGraphBuildingVisitor::Visit( SmErrorNode
* )
1461 /** Build SmCaretPosGraph for SmBlankNode
1462 * Consider this a single character, as it is only a blank space
1464 void SmCaretPosGraphBuildingVisitor::Visit( SmBlankNode
* pNode
)
1466 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1467 mpRightMost
->SetRight( right
);
1468 mpRightMost
= right
;
1471 /** Build SmCaretPosGraph for SmBraceNode
1473 * Lines in an SmBraceNode:
1481 * Graph over these, where "left" is before the SmBraceNode and "right" is after:
1489 void SmCaretPosGraphBuildingVisitor::Visit( SmBraceNode
* pNode
)
1491 SmNode
* pBody
= pNode
->Body();
1493 SmCaretPosGraphEntry
*left
= mpRightMost
,
1494 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1496 if( pBody
->GetType() != SmNodeType::Bracebody
) {
1497 mpRightMost
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1498 left
->SetRight( mpRightMost
);
1502 pBody
->Accept( this );
1503 mpRightMost
->SetRight( right
);
1504 right
->SetLeft( mpRightMost
);
1506 mpRightMost
= right
;
1509 /** Build SmCaretPosGraph for SmAttributNode
1511 * Lines in an SmAttributNode:
1517 * There's a body and an attribute, the construction is used for "widehat A", where "A" is the body
1518 * and "^" is the attribute ( note GetScaleMode( ) on SmAttributNode tells how the attribute should be
1521 void SmCaretPosGraphBuildingVisitor::Visit( SmAttributNode
* pNode
)
1523 SmNode
*pAttr
= pNode
->Attribute(),
1524 *pBody
= pNode
->Body();
1528 SmCaretPosGraphEntry
*left
= mpRightMost
,
1535 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1536 left
->SetRight( bodyLeft
);
1539 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1542 mpRightMost
= bodyLeft
;
1543 pBody
->Accept( this );
1544 bodyRight
= mpRightMost
;
1545 bodyRight
->SetRight( right
);
1546 right
->SetLeft( bodyRight
);
1549 attrLeft
= mpGraph
->Add( SmCaretPos( pAttr
, 0 ), left
);
1552 mpRightMost
= attrLeft
;
1553 pAttr
->Accept( this );
1554 mpRightMost
->SetRight( right
);
1557 mpRightMost
= right
;
1560 //Consider these single symbols
1561 void SmCaretPosGraphBuildingVisitor::Visit( SmSpecialNode
* pNode
)
1563 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1564 mpRightMost
->SetRight( right
);
1565 mpRightMost
= right
;
1567 void SmCaretPosGraphBuildingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
1569 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1570 mpRightMost
->SetRight( right
);
1571 mpRightMost
= right
;
1573 void SmCaretPosGraphBuildingVisitor::Visit( SmMathSymbolNode
* pNode
)
1575 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1576 mpRightMost
->SetRight( right
);
1577 mpRightMost
= right
;
1580 void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode
* )
1585 void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode
* )
1589 void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode
* )
1596 SmNode
* SmCloningVisitor::Clone( SmNode
* pNode
)
1598 SmNode
* pCurrResult
= mpResult
;
1599 pNode
->Accept( this );
1600 SmNode
* pClone
= mpResult
;
1601 mpResult
= pCurrResult
;
1605 void SmCloningVisitor::CloneNodeAttr( SmNode
const * pSource
, SmNode
* pTarget
)
1607 pTarget
->SetScaleMode( pSource
->GetScaleMode( ) );
1608 //Other attributes are set when prepare or arrange is executed
1609 //and may depend on stuff not being cloned here.
1612 void SmCloningVisitor::CloneKids( SmStructureNode
* pSource
, SmStructureNode
* pTarget
)
1614 //Cache current result
1615 SmNode
* pCurrResult
= mpResult
;
1617 //Create array for holding clones
1618 size_t nSize
= pSource
->GetNumSubNodes( );
1619 SmNodeArray
aNodes( nSize
);
1622 for (size_t i
= 0; i
< nSize
; ++i
)
1625 if( nullptr != ( pKid
= pSource
->GetSubNode( i
) ) )
1626 pKid
->Accept( this );
1629 aNodes
[i
] = mpResult
;
1632 //Set subnodes of pTarget
1633 pTarget
->SetSubNodes( std::move(aNodes
) );
1635 //Restore result as where prior to call
1636 mpResult
= pCurrResult
;
1639 void SmCloningVisitor::Visit( SmTableNode
* pNode
)
1641 SmTableNode
* pClone
= new SmTableNode( pNode
->GetToken( ) );
1642 CloneNodeAttr( pNode
, pClone
);
1643 CloneKids( pNode
, pClone
);
1647 void SmCloningVisitor::Visit( SmBraceNode
* pNode
)
1649 SmBraceNode
* pClone
= new SmBraceNode( pNode
->GetToken( ) );
1650 CloneNodeAttr( pNode
, pClone
);
1651 CloneKids( pNode
, pClone
);
1655 void SmCloningVisitor::Visit( SmBracebodyNode
* pNode
)
1657 SmBracebodyNode
* pClone
= new SmBracebodyNode( pNode
->GetToken( ) );
1658 CloneNodeAttr( pNode
, pClone
);
1659 CloneKids( pNode
, pClone
);
1663 void SmCloningVisitor::Visit( SmOperNode
* pNode
)
1665 SmOperNode
* pClone
= new SmOperNode( pNode
->GetToken( ) );
1666 CloneNodeAttr( pNode
, pClone
);
1667 CloneKids( pNode
, pClone
);
1671 void SmCloningVisitor::Visit( SmAlignNode
* pNode
)
1673 SmAlignNode
* pClone
= new SmAlignNode( pNode
->GetToken( ) );
1674 CloneNodeAttr( pNode
, pClone
);
1675 CloneKids( pNode
, pClone
);
1679 void SmCloningVisitor::Visit( SmAttributNode
* pNode
)
1681 SmAttributNode
* pClone
= new SmAttributNode( pNode
->GetToken( ) );
1682 CloneNodeAttr( pNode
, pClone
);
1683 CloneKids( pNode
, pClone
);
1687 void SmCloningVisitor::Visit( SmFontNode
* pNode
)
1689 SmFontNode
* pClone
= new SmFontNode( pNode
->GetToken( ) );
1690 pClone
->SetSizeParameter( pNode
->GetSizeParameter( ), pNode
->GetSizeType( ) );
1691 CloneNodeAttr( pNode
, pClone
);
1692 CloneKids( pNode
, pClone
);
1696 void SmCloningVisitor::Visit( SmUnHorNode
* pNode
)
1698 SmUnHorNode
* pClone
= new SmUnHorNode( pNode
->GetToken( ) );
1699 CloneNodeAttr( pNode
, pClone
);
1700 CloneKids( pNode
, pClone
);
1704 void SmCloningVisitor::Visit( SmBinHorNode
* pNode
)
1706 SmBinHorNode
* pClone
= new SmBinHorNode( pNode
->GetToken( ) );
1707 CloneNodeAttr( pNode
, pClone
);
1708 CloneKids( pNode
, pClone
);
1712 void SmCloningVisitor::Visit( SmBinVerNode
* pNode
)
1714 SmBinVerNode
* pClone
= new SmBinVerNode( pNode
->GetToken( ) );
1715 CloneNodeAttr( pNode
, pClone
);
1716 CloneKids( pNode
, pClone
);
1720 void SmCloningVisitor::Visit( SmBinDiagonalNode
* pNode
)
1722 SmBinDiagonalNode
*pClone
= new SmBinDiagonalNode( pNode
->GetToken( ) );
1723 pClone
->SetAscending( pNode
->IsAscending( ) );
1724 CloneNodeAttr( pNode
, pClone
);
1725 CloneKids( pNode
, pClone
);
1729 void SmCloningVisitor::Visit( SmSubSupNode
* pNode
)
1731 SmSubSupNode
*pClone
= new SmSubSupNode( pNode
->GetToken( ) );
1732 pClone
->SetUseLimits( pNode
->IsUseLimits( ) );
1733 CloneNodeAttr( pNode
, pClone
);
1734 CloneKids( pNode
, pClone
);
1738 void SmCloningVisitor::Visit( SmMatrixNode
* pNode
)
1740 SmMatrixNode
*pClone
= new SmMatrixNode( pNode
->GetToken( ) );
1741 pClone
->SetRowCol( pNode
->GetNumRows( ), pNode
->GetNumCols( ) );
1742 CloneNodeAttr( pNode
, pClone
);
1743 CloneKids( pNode
, pClone
);
1747 void SmCloningVisitor::Visit( SmPlaceNode
* pNode
)
1749 mpResult
= new SmPlaceNode( pNode
->GetToken( ) );
1750 CloneNodeAttr( pNode
, mpResult
);
1753 void SmCloningVisitor::Visit( SmTextNode
* pNode
)
1755 SmTextNode
* pClone
= new SmTextNode( pNode
->GetToken( ), pNode
->GetFontDesc( ) );
1756 pClone
->ChangeText( pNode
->GetText( ) );
1757 CloneNodeAttr( pNode
, pClone
);
1761 void SmCloningVisitor::Visit( SmSpecialNode
* pNode
)
1763 mpResult
= new SmSpecialNode( pNode
->GetToken( ) );
1764 CloneNodeAttr( pNode
, mpResult
);
1767 void SmCloningVisitor::Visit( SmGlyphSpecialNode
* pNode
)
1769 mpResult
= new SmGlyphSpecialNode( pNode
->GetToken( ) );
1770 CloneNodeAttr( pNode
, mpResult
);
1773 void SmCloningVisitor::Visit( SmMathSymbolNode
* pNode
)
1775 mpResult
= new SmMathSymbolNode( pNode
->GetToken( ) );
1776 CloneNodeAttr( pNode
, mpResult
);
1779 void SmCloningVisitor::Visit( SmBlankNode
* pNode
)
1781 SmBlankNode
* pClone
= new SmBlankNode( pNode
->GetToken( ) );
1782 pClone
->SetBlankNum( pNode
->GetBlankNum( ) );
1784 CloneNodeAttr( pNode
, mpResult
);
1787 void SmCloningVisitor::Visit( SmErrorNode
* pNode
)
1789 mpResult
= new SmErrorNode( pNode
->GetToken( ) );
1790 CloneNodeAttr( pNode
, mpResult
);
1793 void SmCloningVisitor::Visit( SmLineNode
* pNode
)
1795 SmLineNode
* pClone
= new SmLineNode( pNode
->GetToken( ) );
1796 CloneNodeAttr( pNode
, pClone
);
1797 CloneKids( pNode
, pClone
);
1801 void SmCloningVisitor::Visit( SmExpressionNode
* pNode
)
1803 SmExpressionNode
* pClone
= new SmExpressionNode( pNode
->GetToken( ) );
1804 CloneNodeAttr( pNode
, pClone
);
1805 CloneKids( pNode
, pClone
);
1809 void SmCloningVisitor::Visit( SmPolyLineNode
* pNode
)
1811 mpResult
= new SmPolyLineNode( pNode
->GetToken( ) );
1812 CloneNodeAttr( pNode
, mpResult
);
1815 void SmCloningVisitor::Visit( SmRootNode
* pNode
)
1817 SmRootNode
* pClone
= new SmRootNode( pNode
->GetToken( ) );
1818 CloneNodeAttr( pNode
, pClone
);
1819 CloneKids( pNode
, pClone
);
1823 void SmCloningVisitor::Visit( SmRootSymbolNode
* pNode
)
1825 mpResult
= new SmRootSymbolNode( pNode
->GetToken( ) );
1826 CloneNodeAttr( pNode
, mpResult
);
1829 void SmCloningVisitor::Visit( SmRectangleNode
* pNode
)
1831 mpResult
= new SmRectangleNode( pNode
->GetToken( ) );
1832 CloneNodeAttr( pNode
, mpResult
);
1835 void SmCloningVisitor::Visit( SmVerticalBraceNode
* pNode
)
1837 SmVerticalBraceNode
* pClone
= new SmVerticalBraceNode( pNode
->GetToken( ) );
1838 CloneNodeAttr( pNode
, pClone
);
1839 CloneKids( pNode
, pClone
);
1843 // SmSelectionDrawingVisitor
1845 SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice
& rDevice
, SmNode
* pTree
, const Point
& rOffset
)
1847 , mbHasSelectionArea( false )
1850 SAL_WARN_IF( !pTree
, "starmath", "pTree can't be null!" );
1852 pTree
->Accept( this );
1854 //Draw selection if there's any
1855 if( mbHasSelectionArea
){
1856 maSelectionArea
.Move( rOffset
.X( ), rOffset
.Y( ) );
1859 mrDev
.Push( PushFlags::LINECOLOR
| PushFlags::FILLCOLOR
);
1861 mrDev
.SetLineColor( );
1862 mrDev
.SetFillColor( COL_LIGHTGRAY
);
1865 mrDev
.DrawRect( maSelectionArea
);
1867 //Restore device state
1872 void SmSelectionDrawingVisitor::ExtendSelectionArea(const tools::Rectangle
& rArea
)
1874 if ( ! mbHasSelectionArea
) {
1875 maSelectionArea
= rArea
;
1876 mbHasSelectionArea
= true;
1878 maSelectionArea
.Union(rArea
);
1881 void SmSelectionDrawingVisitor::DefaultVisit( SmNode
* pNode
)
1883 if( pNode
->IsSelected( ) )
1884 ExtendSelectionArea( pNode
->AsRectangle( ) );
1885 VisitChildren( pNode
);
1888 void SmSelectionDrawingVisitor::VisitChildren( SmNode
* pNode
)
1890 if(pNode
->GetNumSubNodes() == 0)
1892 for( auto pChild
: *static_cast<SmStructureNode
*>(pNode
) )
1896 pChild
->Accept( this );
1900 void SmSelectionDrawingVisitor::Visit( SmTextNode
* pNode
)
1902 if( pNode
->IsSelected( ) ){
1903 mrDev
.Push( PushFlags::TEXTCOLOR
| PushFlags::FONT
);
1905 mrDev
.SetFont( pNode
->GetFont( ) );
1906 Point Position
= pNode
->GetTopLeft( );
1907 long left
= Position
.getX( ) + mrDev
.GetTextWidth( pNode
->GetText( ), 0, pNode
->GetSelectionStart( ) );
1908 long right
= Position
.getX( ) + mrDev
.GetTextWidth( pNode
->GetText( ), 0, pNode
->GetSelectionEnd( ) );
1909 long top
= Position
.getY( );
1910 long bottom
= top
+ pNode
->GetHeight( );
1911 tools::Rectangle
rect( left
, top
, right
, bottom
);
1913 ExtendSelectionArea( rect
);
1919 // SmNodeToTextVisitor
1921 SmNodeToTextVisitor::SmNodeToTextVisitor( SmNode
* pNode
, OUString
&rText
)
1923 pNode
->Accept( this );
1924 rText
= maCmdText
.makeStringAndClear();
1927 void SmNodeToTextVisitor::Visit( SmTableNode
* pNode
)
1929 if( pNode
->GetToken( ).eType
== TBINOM
) {
1930 Append( "{ binom" );
1931 LineToText( pNode
->GetSubNode( 0 ) );
1932 LineToText( pNode
->GetSubNode( 1 ) );
1934 } else if( pNode
->GetToken( ).eType
== TSTACK
) {
1935 Append( "stack{ " );
1937 for( auto pChild
: *pNode
)
1948 LineToText( pChild
);
1952 } else { //Assume it's a toplevel table, containing lines
1954 for( auto pChild
: *pNode
)
1963 Append( "newline" );
1966 pChild
->Accept( this );
1971 void SmNodeToTextVisitor::Visit( SmBraceNode
* pNode
)
1973 SmNode
*pLeftBrace
= pNode
->OpeningBrace(),
1974 *pBody
= pNode
->Body(),
1975 *pRightBrace
= pNode
->ClosingBrace();
1976 //Handle special case where it's absolute function
1977 if( pNode
->GetToken( ).eType
== TABS
) {
1979 LineToText( pBody
);
1981 if( pNode
->GetScaleMode( ) == SmScaleMode::Height
)
1983 pLeftBrace
->Accept( this );
1985 pBody
->Accept( this );
1987 if( pNode
->GetScaleMode( ) == SmScaleMode::Height
)
1989 pRightBrace
->Accept( this );
1993 void SmNodeToTextVisitor::Visit( SmBracebodyNode
* pNode
)
1995 for( auto pChild
: *pNode
)
2000 pChild
->Accept( this );
2004 void SmNodeToTextVisitor::Visit( SmOperNode
* pNode
)
2006 Append( pNode
->GetToken( ).aText
);
2008 if( pNode
->GetToken( ).eType
== TOPER
){
2009 //There's an SmGlyphSpecialNode if eType == TOPER
2010 if( pNode
->GetSubNode( 0 )->GetType( ) == SmNodeType::SubSup
)
2011 Append( pNode
->GetSubNode( 0 )->GetSubNode( 0 )->GetToken( ).aText
);
2013 Append( pNode
->GetSubNode( 0 )->GetToken( ).aText
);
2015 if( pNode
->GetSubNode( 0 )->GetType( ) == SmNodeType::SubSup
) {
2016 SmSubSupNode
*pSubSup
= static_cast<SmSubSupNode
*>( pNode
->GetSubNode( 0 ) );
2017 SmNode
* pChild
= pSubSup
->GetSubSup( LSUP
);
2020 Append( "lsup { " );
2021 LineToText( pChild
);
2024 pChild
= pSubSup
->GetSubSup( LSUB
);
2027 Append( "lsub { " );
2028 LineToText( pChild
);
2031 pChild
= pSubSup
->GetSubSup( RSUP
);
2035 LineToText( pChild
);
2038 pChild
= pSubSup
->GetSubSup( RSUB
);
2042 LineToText( pChild
);
2045 pChild
= pSubSup
->GetSubSup( CSUP
);
2048 if (pSubSup
->IsUseLimits())
2051 Append( "csup { " );
2052 LineToText( pChild
);
2055 pChild
= pSubSup
->GetSubSup( CSUB
);
2058 if (pSubSup
->IsUseLimits())
2059 Append( "from { " );
2061 Append( "csub { " );
2062 LineToText( pChild
);
2066 LineToText( pNode
->GetSubNode( 1 ) );
2069 void SmNodeToTextVisitor::Visit( SmAlignNode
* pNode
)
2071 Append( pNode
->GetToken( ).aText
);
2072 LineToText( pNode
->GetSubNode( 0 ) );
2075 void SmNodeToTextVisitor::Visit( SmAttributNode
* pNode
)
2077 Append( pNode
->GetToken( ).aText
);
2078 LineToText( pNode
->Body() );
2081 void SmNodeToTextVisitor::Visit( SmFontNode
* pNode
)
2083 switch ( pNode
->GetToken( ).eType
)
2092 Append( "italic " );
2095 Append( "nitalic " );
2098 Append( "phantom " );
2103 switch ( pNode
->GetSizeType( ) )
2105 case FontSizeType::PLUS
:
2108 case FontSizeType::MINUS
:
2111 case FontSizeType::MULTIPLY
:
2114 case FontSizeType::DIVIDE
:
2117 case FontSizeType::ABSOLUT
:
2121 Append( ::rtl::math::doubleToUString(
2122 static_cast<double>( pNode
->GetSizeParameter( ) ),
2123 rtl_math_StringFormat_Automatic
,
2124 rtl_math_DecimalPlaces_Max
, '.', true ) );
2129 Append( "color black " );
2132 Append( "color white " );
2135 Append( "color red " );
2138 Append( "color green " );
2141 Append( "color blue " );
2144 Append( "color cyan " );
2147 Append( "color magenta " );
2150 Append( "color yellow " );
2153 Append( "font sans " );
2156 Append( "font serif " );
2159 Append( "font fixed " );
2164 LineToText( pNode
->GetSubNode( 1 ) );
2167 void SmNodeToTextVisitor::Visit( SmUnHorNode
* pNode
)
2169 if(pNode
->GetSubNode( 1 )->GetToken( ).eType
== TFACT
)
2171 // visit children in the reverse order
2172 for( auto it
= pNode
->rbegin(); it
!= pNode
->rend(); ++it
)
2178 pChild
->Accept( this );
2183 for( auto pChild
: *pNode
)
2188 pChild
->Accept( this );
2193 void SmNodeToTextVisitor::Visit( SmBinHorNode
* pNode
)
2195 const SmNode
*pParent
= pNode
->GetParent();
2196 bool bBraceNeeded
= pParent
&& pParent
->GetType() == SmNodeType::Font
;
2197 SmNode
*pLeft
= pNode
->LeftOperand(),
2198 *pOper
= pNode
->Symbol(),
2199 *pRight
= pNode
->RightOperand();
2203 pLeft
->Accept( this );
2205 pOper
->Accept( this );
2207 pRight
->Accept( this );
2213 void SmNodeToTextVisitor::Visit( SmBinVerNode
* pNode
)
2215 SmNode
*pNum
= pNode
->GetSubNode( 0 ),
2216 *pDenom
= pNode
->GetSubNode( 2 );
2220 LineToText( pDenom
);
2224 void SmNodeToTextVisitor::Visit( SmBinDiagonalNode
* pNode
)
2226 SmNode
*pLeftOperand
= pNode
->GetSubNode( 0 ),
2227 *pRightOperand
= pNode
->GetSubNode( 1 );
2229 LineToText( pLeftOperand
);
2231 Append( "wideslash " );
2232 LineToText( pRightOperand
);
2236 void SmNodeToTextVisitor::Visit( SmSubSupNode
* pNode
)
2238 LineToText( pNode
->GetBody( ) );
2239 SmNode
*pChild
= pNode
->GetSubSup( LSUP
);
2243 LineToText( pChild
);
2245 pChild
= pNode
->GetSubSup( LSUB
);
2249 LineToText( pChild
);
2251 pChild
= pNode
->GetSubSup( RSUP
);
2255 LineToText( pChild
);
2257 pChild
= pNode
->GetSubSup( RSUB
);
2261 LineToText( pChild
);
2263 pChild
= pNode
->GetSubSup( CSUP
);
2266 if (pNode
->IsUseLimits())
2270 LineToText( pChild
);
2272 pChild
= pNode
->GetSubSup( CSUB
);
2275 if (pNode
->IsUseLimits())
2279 LineToText( pChild
);
2283 void SmNodeToTextVisitor::Visit( SmMatrixNode
* pNode
)
2285 Append( "matrix{" );
2286 for (size_t i
= 0; i
< pNode
->GetNumRows(); ++i
)
2288 for (size_t j
= 0; j
< pNode
->GetNumCols( ); ++j
)
2290 SmNode
* pSubNode
= pNode
->GetSubNode( i
* pNode
->GetNumCols( ) + j
);
2292 pSubNode
->Accept( this );
2294 if (j
!= pNode
->GetNumCols() - 1U)
2298 if (i
!= pNode
->GetNumRows() - 1U)
2304 void SmNodeToTextVisitor::Visit( SmPlaceNode
* )
2309 void SmNodeToTextVisitor::Visit( SmTextNode
* pNode
)
2311 //TODO: This method might need improvements, see SmTextNode::CreateTextFromNode
2312 if( pNode
->GetToken( ).eType
== TTEXT
)
2314 Append( pNode
->GetText( ) );
2315 if( pNode
->GetToken( ).eType
== TTEXT
)
2319 void SmNodeToTextVisitor::Visit( SmSpecialNode
* pNode
)
2321 Append( pNode
->GetToken( ).aText
);
2324 void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode
* pNode
)
2326 if( pNode
->GetToken( ).eType
== TBOPER
)
2330 Append( pNode
->GetToken( ).aText
);
2333 void SmNodeToTextVisitor::Visit( SmMathSymbolNode
* pNode
)
2335 Append( pNode
->GetToken( ).aText
);
2338 void SmNodeToTextVisitor::Visit( SmBlankNode
* pNode
)
2340 sal_uInt16 nNum
= pNode
->GetBlankNum();
2343 sal_uInt16 nWide
= nNum
/ 4;
2344 sal_uInt16 nNarrow
= nNum
% 4;
2345 for (sal_uInt16 i
= 0; i
< nWide
; i
++)
2347 for (sal_uInt16 i
= 0; i
< nNarrow
; i
++)
2352 void SmNodeToTextVisitor::Visit( SmErrorNode
* )
2356 void SmNodeToTextVisitor::Visit( SmLineNode
* pNode
)
2358 for( auto pChild
: *pNode
)
2363 pChild
->Accept( this );
2367 void SmNodeToTextVisitor::Visit( SmExpressionNode
* pNode
)
2369 bool bracketsNeeded
= pNode
->GetNumSubNodes() != 1 || pNode
->GetSubNode(0)->GetType() == SmNodeType::BinHor
;
2370 if (!bracketsNeeded
)
2372 const SmNode
*pParent
= pNode
->GetParent();
2375 pParent
&& pParent
->GetType() == SmNodeType::SubSup
&&
2376 pNode
->GetNumSubNodes() == 1 &&
2377 pNode
->GetSubNode(0)->GetType() == SmNodeType::SubSup
;
2380 if (bracketsNeeded
) {
2383 for( auto pChild
: *pNode
)
2387 pChild
->Accept( this );
2390 if (bracketsNeeded
) {
2395 void SmNodeToTextVisitor::Visit( SmPolyLineNode
* )
2399 void SmNodeToTextVisitor::Visit( SmRootNode
* pNode
)
2401 SmNode
*pExtra
= pNode
->GetSubNode( 0 ),
2402 *pBody
= pNode
->GetSubNode( 2 );
2405 LineToText( pExtra
);
2408 LineToText( pBody
);
2411 void SmNodeToTextVisitor::Visit( SmRootSymbolNode
* )
2415 void SmNodeToTextVisitor::Visit( SmRectangleNode
* )
2419 void SmNodeToTextVisitor::Visit( SmVerticalBraceNode
* pNode
)
2421 SmNode
*pBody
= pNode
->Body(),
2422 *pScript
= pNode
->Script();
2423 LineToText( pBody
);
2424 Append( pNode
->GetToken( ).aText
);
2425 LineToText( pScript
);
2428 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */