Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / starmath / source / visitors.cxx
blobfdb1e2103de8fa7fdacb44c507e018732c43a823
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <tools/gen.hxx>
11 #include <vcl/lineinfo.hxx>
12 #include <visitors.hxx>
13 #include "tmpdevice.hxx"
14 #include <cursor.hxx>
15 #include <cassert>
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,
157 SmCaretPos position,
158 Point offset,
159 bool caretVisible )
160 : mrDev( rDevice )
161 , maPos( position )
162 , maOffset( offset )
163 , mbCaretVisible( caretVisible )
165 SAL_WARN_IF( !position.IsValid(), "starmath", "Cannot draw invalid position!" );
166 if( !position.IsValid( ) )
167 return;
169 //Save device state
170 mrDev.Push( PushFlags::FONT | PushFlags::MAPMODE | PushFlags::LINECOLOR | PushFlags::FILLCOLOR | PushFlags::TEXTCOLOR );
172 maPos.pSelectedNode->Accept( this );
173 //Restore device state
174 mrDev.Pop( );
177 void SmCaretDrawingVisitor::Visit( SmTextNode* pNode )
179 long i = maPos.nIndex;
181 mrDev.SetFont( pNode->GetFont( ) );
183 //Find the line
184 SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
186 //Find coordinates
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( );
193 //Set color
194 mrDev.SetLineColor( COL_BLACK );
196 if ( mbCaretVisible ) {
197 //Draw vertical line
198 Point p1( left, top );
199 Point p2( left, top + height );
200 mrDev.DrawLine( p1, p2 );
203 //Underline the line
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 )
211 //Find the line
212 SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
214 //Find coordinates
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( );
221 //Set color
222 mrDev.SetLineColor( COL_BLACK );
224 if ( mbCaretVisible ) {
225 //Draw vertical line
226 Point p1( left, top );
227 Point p2( left, top + height );
228 mrDev.DrawLine( p1, p2 );
231 //Underline the line
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 )
241 //Save device state
242 mpDev->Push( PushFlags::FONT | PushFlags::TEXTCOLOR );
244 long i = maPos.nIndex;
246 mpDev->SetFont( pNode->GetFont( ) );
248 //Find coordinates
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
256 mpDev->Pop( );
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( ) );
270 // SmDrawingVisitor
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( ) )
394 return;
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( ) )
427 return;
429 long nBorderwidth = pNode->GetFont( ).GetBorderWidth( );
431 LineInfo aInfo;
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( ) )
448 return;
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( ) ) ) );
472 aTmp.SetPos( aPos );
474 mrDev.DrawRect( aTmp );
477 void SmDrawingVisitor::DrawTextNode( SmTextNode* pNode )
479 if ( pNode->IsPhantom() || pNode->GetText().isEmpty() || pNode->GetText()[0] == '\0' )
480 return;
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( ) )
505 return;
507 Point rPosition = maPosition;
509 for( auto pChild : *pNode )
511 if(!pChild)
512 continue;
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)
523 , maEndPos(endPos)
524 , mbSelecting(false)
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!");
538 //Visit lines
539 for( auto pChild : *static_cast<SmStructureNode*>(pTree) )
541 if(!pChild)
542 continue;
543 pChild->Accept( this );
544 //If we started a selection in this line and it haven't ended, we do that now!
545 if(mbSelecting) {
546 mbSelecting = false;
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
559 pTree->Accept(this);
562 void SmSetSelectionVisitor::SetSelectedOnAll( SmNode* pSubTree, bool IsSelected ) {
563 pSubTree->SetSelected( IsSelected );
565 if(pSubTree->GetNumSubNodes() == 0)
566 return;
567 //Quick BFS to set all selections
568 for( auto pChild : *static_cast<SmStructureNode*>(pSubTree) )
570 if(!pChild)
571 continue;
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;
588 //Set selected
589 pNode->SetSelected( mbSelecting );
591 //Visit children
592 if(pNode->GetNumSubNodes() > 0)
594 for( auto pChild : *static_cast<SmStructureNode*>(pNode) )
596 if(!pChild)
597 continue;
598 pChild->Accept( this );
599 ChangedState = ( WasSelecting != mbSelecting ) || ChangedState;
603 //If state changed
604 if( 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 );
612 else
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;
647 //Visit children
648 for( auto pChild : *pNode )
650 if(!pChild)
651 continue;
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 ) {
667 long i1 = -1,
668 i2 = -1;
669 if( maStartPos.pSelectedNode == pNode )
670 i1 = maStartPos.nIndex;
671 if( maEndPos.pSelectedNode == pNode )
672 i2 = maEndPos.nIndex;
674 long start, end;
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 ) {
680 start = 0;
681 end = i1;
682 mbSelecting = false;
683 } else if( mbSelecting && i2 != -1 ) {
684 start = 0;
685 end = i2;
686 mbSelecting = false;
687 } else if( !mbSelecting && i1 != -1 ) {
688 start = i1;
689 end = pNode->GetText().getLength();
690 mbSelecting = true;
691 } else if( !mbSelecting && i2 != -1 ) {
692 start = i2;
693 end = pNode->GetText().getLength();
694 mbSelecting = true;
695 } else if( mbSelecting ) {
696 start = 0;
697 end = pNode->GetText().getLength();
698 } else {
699 pNode->SetSelected( false );
700 start = 0;
701 end = 0;
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) )
747 if(!pChild)
748 continue;
749 mpRightMost = mpGraph->Add( SmCaretPos( pChild, 0 ) );
750 pChild->Accept( this );
752 }else
753 pRootNode->Accept(this);
756 SmCaretPosGraphBuildingVisitor::~SmCaretPosGraphBuildingVisitor()
760 void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode* pNode ){
761 for( auto pChild : *pNode )
763 if(!pChild)
764 continue;
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 )
780 if(!pChild)
781 continue;
782 mpRightMost = mpGraph->Add( SmCaretPos( pChild, 0 ), left);
783 if(bIsFirst)
784 left->SetRight(mpRightMost);
785 pChild->Accept( this );
786 mpRightMost->SetRight(right);
787 if(bIsFirst)
788 right->SetLeft(mpRightMost);
789 bIsFirst = false;
791 mpRightMost = right;
794 /** Build SmCaretPosGraph for SmSubSupNode
796 * The child positions in a SubSupNode, where H is the body:
797 * \code
798 * CSUP
800 * LSUP H H RSUP
801 * H H
802 * HHHH
803 * H H
804 * LSUB H H RSUB
806 * CSUB
807 * \endcode
809 * Graph over these, where "left" is before the SmSubSupNode and "right" is after:
810 * \dot
811 * digraph Graph{
812 * left -> H;
813 * H -> right;
814 * LSUP -> H;
815 * LSUB -> H;
816 * CSUP -> right;
817 * CSUB -> right;
818 * RSUP -> right;
819 * RSUB -> right;
820 * };
821 * \enddot
824 void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode* pNode )
826 SmCaretPosGraphEntry *left,
827 *right,
828 *bodyLeft,
829 *bodyRight;
831 assert(mpRightMost);
832 left = mpRightMost;
834 //Create bodyLeft
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??? )
839 //Create right
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 );
849 //If there's an LSUP
850 SmNode* pChild = pNode->GetSubSup( LSUP );
851 if( pChild ){
852 SmCaretPosGraphEntry *cLeft; //Child left
853 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
855 mpRightMost = cLeft;
856 pChild->Accept( this );
858 mpRightMost->SetRight( bodyLeft );
860 //If there's an LSUB
861 pChild = pNode->GetSubSup( LSUB );
862 if( pChild ){
863 SmCaretPosGraphEntry *cLeft; //Child left
864 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
866 mpRightMost = cLeft;
867 pChild->Accept( this );
869 mpRightMost->SetRight( bodyLeft );
871 //If there's an CSUP
872 pChild = pNode->GetSubSup( CSUP );
873 if( pChild ){
874 SmCaretPosGraphEntry *cLeft; //Child left
875 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
877 mpRightMost = cLeft;
878 pChild->Accept( this );
880 mpRightMost->SetRight( right );
882 //If there's an CSUB
883 pChild = pNode->GetSubSup( CSUB );
884 if( pChild ){
885 SmCaretPosGraphEntry *cLeft; //Child left
886 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
888 mpRightMost = cLeft;
889 pChild->Accept( this );
891 mpRightMost->SetRight( right );
893 //If there's an RSUP
894 pChild = pNode->GetSubSup( RSUP );
895 if( pChild ){
896 SmCaretPosGraphEntry *cLeft; //Child left
897 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
899 mpRightMost = cLeft;
900 pChild->Accept( this );
902 mpRightMost->SetRight( right );
904 //If there's an RSUB
905 pChild = pNode->GetSubSup( RSUB );
906 if( pChild ){
907 SmCaretPosGraphEntry *cLeft; //Child left
908 cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
910 mpRightMost = cLeft;
911 pChild->Accept( this );
913 mpRightMost->SetRight( right );
916 //Set return parameters
917 mpRightMost = right;
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:
929 * \code
930 * TO
932 * LSUP H H RSUP BBB BB BBB B B
933 * H H B B B B B B B B
934 * HHHH BBB B B B B B
935 * H H B B B B B B B
936 * LSUB H H RSUB BBB BB BBB B
938 * FROM
939 * \endcode
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:
944 * \dot
945 * digraph Graph{
946 * left -> BODY;
947 * BODY -> right;
948 * LSUP -> BODY;
949 * LSUB -> BODY;
950 * TO -> BODY;
951 * FROM -> BODY;
952 * RSUP -> BODY;
953 * RSUB -> BODY;
954 * };
955 * \enddot
957 void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode* pNode )
959 SmNode *pOper = pNode->GetSubNode( 0 ),
960 *pBody = pNode->GetSubNode( 1 );
962 SmCaretPosGraphEntry *left = mpRightMost,
963 *bodyLeft,
964 *bodyRight,
965 *right;
966 //Create body left
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;
975 //Create right
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;
982 SmNode* pChild;
983 SmCaretPosGraphEntry *childLeft;
984 if( pSubSup ) {
985 pChild = pSubSup->GetSubSup( LSUP );
986 if( pChild ) {
987 //Create position in front of pChild
988 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
989 //Visit pChild
990 mpRightMost = childLeft;
991 pChild->Accept( this );
992 //Set right on mpRightMost from pChild
993 mpRightMost->SetRight( bodyLeft );
996 if( pSubSup ) {
997 pChild = pSubSup->GetSubSup( LSUB );
998 if( pChild ) {
999 //Create position in front of pChild
1000 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1001 //Visit pChild
1002 mpRightMost = childLeft;
1003 pChild->Accept( this );
1004 //Set right on mpRightMost from pChild
1005 mpRightMost->SetRight( bodyLeft );
1008 if( pSubSup ) {
1009 pChild = pSubSup->GetSubSup( CSUP );
1010 if ( pChild ) {//TO
1011 //Create position in front of pChild
1012 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1013 //Visit pChild
1014 mpRightMost = childLeft;
1015 pChild->Accept( this );
1016 //Set right on mpRightMost from pChild
1017 mpRightMost->SetRight( bodyLeft );
1020 if( pSubSup ) {
1021 pChild = pSubSup->GetSubSup( CSUB );
1022 if( pChild ) { //FROM
1023 //Create position in front of pChild
1024 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1025 //Visit pChild
1026 mpRightMost = childLeft;
1027 pChild->Accept( this );
1028 //Set right on mpRightMost from pChild
1029 mpRightMost->SetRight( bodyLeft );
1032 if( pSubSup ) {
1033 pChild = pSubSup->GetSubSup( RSUP );
1034 if ( pChild ) {
1035 //Create position in front of pChild
1036 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1037 //Visit pChild
1038 mpRightMost = childLeft;
1039 pChild->Accept( this );
1040 //Set right on mpRightMost from pChild
1041 mpRightMost->SetRight( bodyLeft );
1044 if( pSubSup ) {
1045 pChild = pSubSup->GetSubSup( RSUB );
1046 if ( pChild ) {
1047 //Create position in front of pChild
1048 childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1049 //Visit pChild
1050 mpRightMost = childLeft;
1051 pChild->Accept( this );
1052 //Set right on mpRightMost from pChild
1053 mpRightMost->SetRight( bodyLeft );
1057 //Return right
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 );
1079 r = mpRightMost;
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:
1092 * \code
1093 * A B C
1094 * \endcode
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:
1098 * \dot
1099 * digraph Graph{
1100 * left -> A;
1101 * A -> B
1102 * B -> right;
1103 * };
1104 * \enddot
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:
1122 * \code
1124 * -----
1126 * \endcode
1128 * Graph over these, where "left" is before the SmBinVerNode and "right" is after:
1129 * \dot
1130 * digraph Graph{
1131 * left -> A;
1132 * A -> right;
1133 * B -> right;
1134 * };
1135 * \enddot
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,
1144 *right,
1145 *numLeft,
1146 *denomLeft;
1148 assert(mpRightMost);
1149 //Set left
1150 left = mpRightMost;
1152 //Create right
1153 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1155 //Create numLeft
1156 numLeft = mpGraph->Add( SmCaretPos( pNum, 0 ), left );
1157 left->SetRight( numLeft );
1159 //Visit pNum
1160 mpRightMost = numLeft;
1161 pNum->Accept( this );
1162 mpRightMost->SetRight( right );
1163 right->SetLeft( mpRightMost );
1165 //Create denomLeft
1166 denomLeft = mpGraph->Add( SmCaretPos( pDenom, 0 ), left );
1168 //Visit pDenom
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:
1180 * \code
1181 * pScript
1182 * ________
1183 * / \
1184 * pBody
1185 * \endcode
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,
1195 *bodyLeft,
1196 *scriptLeft,
1197 *right;
1199 left = mpRightMost;
1201 //Create right
1202 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1204 //Create bodyLeft
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 );
1212 //Create script
1213 scriptLeft = mpGraph->Add( SmCaretPos( pScript, 0 ), left );
1214 mpRightMost = scriptLeft;
1215 pScript->Accept( this );
1216 mpRightMost->SetRight( right );
1218 //Set return value
1219 mpRightMost = right;
1222 /** Build SmCaretPosGraph for SmBinDiagonalNode
1224 * Lines in an SmBinDiagonalNode:
1225 * \code
1226 * A /
1228 * / B
1229 * \endcode
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,
1240 *leftA,
1241 *rightA,
1242 *leftB,
1243 *right;
1244 left = mpRightMost;
1246 //Create right
1247 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1249 //Create left A
1250 leftA = mpGraph->Add( SmCaretPos( A, 0 ), left );
1251 left->SetRight( leftA );
1253 //Visit A
1254 mpRightMost = leftA;
1255 A->Accept( this );
1256 rightA = mpRightMost;
1258 //Create left B
1259 leftB = mpGraph->Add( SmCaretPos( B, 0 ), rightA );
1260 rightA->SetRight( leftB );
1262 //Visit B
1263 mpRightMost = leftB;
1264 B->Accept( this );
1265 mpRightMost->SetRight( right );
1266 right->SetLeft( mpRightMost );
1268 //Set return value
1269 mpRightMost = right;
1272 //Straight forward ( I think )
1273 void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode* pNode )
1275 for( auto pChild : *pNode )
1277 if(!pChild)
1278 continue;
1279 pChild->Accept( this );
1282 void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode* pNode )
1284 // Unary operator node
1285 for( auto pChild : *pNode )
1287 if(!pChild)
1288 continue;
1289 pChild->Accept( this );
1293 void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode* pNode )
1295 for( auto pChild : *pNode )
1297 if(!pChild)
1298 continue;
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 )
1308 if(!pChild)
1309 continue;
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
1318 * \dot
1319 * digraph {
1320 * labelloc = "t";
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: &#124;"]; // 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: &#8712;"]; // Unicode "ELEMENT OF"
1347 * n10 -> n13 [label="2"];
1348 * n13 [label="SmMathSymbolNode: &#8484;"]; // Unicode "DOUBLE-STRUCK CAPITAL Z"
1349 * n3 -> n14 [label="2"];
1350 * n14 [label="SmMathSymbolNode: }"];
1352 * \enddot
1354 void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode* pNode )
1356 for( auto pChild : *pNode )
1358 if(!pChild)
1359 continue;
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 )
1374 if(!pChild)
1375 continue;
1376 pChild->Accept( this );
1380 /** Build SmCaretPosGraph for SmRootNode
1382 * Lines in an SmRootNode:
1383 * \code
1384 * _________
1385 * A/
1386 * \/ B
1388 * \endcode
1389 * A: pExtra ( optional, can be NULL ),
1390 * B: pBody
1392 * Graph over these, where "left" is before the SmRootNode and "right" is after:
1393 * \dot
1394 * digraph Graph{
1395 * left -> B;
1396 * B -> right;
1397 * A -> B;
1399 * \enddot
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
1405 assert(pBody);
1407 SmCaretPosGraphEntry *left,
1408 *right,
1409 *bodyLeft,
1410 *bodyRight;
1412 //Get left and save it
1413 assert(mpRightMost);
1414 left = mpRightMost;
1416 //Create body left
1417 bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1418 left->SetRight( bodyLeft );
1420 //Create right
1421 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1423 //Visit body
1424 mpRightMost = bodyLeft;
1425 pBody->Accept( this );
1426 bodyRight = mpRightMost;
1427 bodyRight->SetRight( right );
1428 right->SetLeft( bodyRight );
1430 //Visit pExtra
1431 if( pExtra ){
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:
1474 * \code
1475 * | |
1476 * | B |
1477 * | |
1478 * \endcode
1479 * B: Body
1481 * Graph over these, where "left" is before the SmBraceNode and "right" is after:
1482 * \dot
1483 * digraph Graph{
1484 * left -> B;
1485 * B -> right;
1487 * \enddot
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 );
1499 }else
1500 mpRightMost = left;
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:
1512 * \code
1513 * Attr
1514 * Body
1515 * \endcode
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
1519 * scaled ).
1521 void SmCaretPosGraphBuildingVisitor::Visit( SmAttributNode* pNode )
1523 SmNode *pAttr = pNode->Attribute(),
1524 *pBody = pNode->Body();
1525 assert(pAttr);
1526 assert(pBody);
1528 SmCaretPosGraphEntry *left = mpRightMost,
1529 *attrLeft,
1530 *bodyLeft,
1531 *bodyRight,
1532 *right;
1534 //Creating bodyleft
1535 bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1536 left->SetRight( bodyLeft );
1538 //Creating right
1539 right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1541 //Visit the body
1542 mpRightMost = bodyLeft;
1543 pBody->Accept( this );
1544 bodyRight = mpRightMost;
1545 bodyRight->SetRight( right );
1546 right->SetLeft( bodyRight );
1548 //Create attrLeft
1549 attrLeft = mpGraph->Add( SmCaretPos( pAttr, 0 ), left );
1551 //Visit attribute
1552 mpRightMost = attrLeft;
1553 pAttr->Accept( this );
1554 mpRightMost->SetRight( right );
1556 //Set return value
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* )
1582 //Do nothing
1585 void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode* )
1587 //Do nothing
1589 void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode* )
1591 //Do nothing
1594 // SmCloningVisitor
1596 SmNode* SmCloningVisitor::Clone( SmNode* pNode )
1598 SmNode* pCurrResult = mpResult;
1599 pNode->Accept( this );
1600 SmNode* pClone = mpResult;
1601 mpResult = pCurrResult;
1602 return pClone;
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 );
1621 //Clone children
1622 for (size_t i = 0; i < nSize; ++i)
1624 SmNode* pKid;
1625 if( nullptr != ( pKid = pSource->GetSubNode( i ) ) )
1626 pKid->Accept( this );
1627 else
1628 mpResult = nullptr;
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 );
1644 mpResult = pClone;
1647 void SmCloningVisitor::Visit( SmBraceNode* pNode )
1649 SmBraceNode* pClone = new SmBraceNode( pNode->GetToken( ) );
1650 CloneNodeAttr( pNode, pClone );
1651 CloneKids( pNode, pClone );
1652 mpResult = pClone;
1655 void SmCloningVisitor::Visit( SmBracebodyNode* pNode )
1657 SmBracebodyNode* pClone = new SmBracebodyNode( pNode->GetToken( ) );
1658 CloneNodeAttr( pNode, pClone );
1659 CloneKids( pNode, pClone );
1660 mpResult = pClone;
1663 void SmCloningVisitor::Visit( SmOperNode* pNode )
1665 SmOperNode* pClone = new SmOperNode( pNode->GetToken( ) );
1666 CloneNodeAttr( pNode, pClone );
1667 CloneKids( pNode, pClone );
1668 mpResult = pClone;
1671 void SmCloningVisitor::Visit( SmAlignNode* pNode )
1673 SmAlignNode* pClone = new SmAlignNode( pNode->GetToken( ) );
1674 CloneNodeAttr( pNode, pClone );
1675 CloneKids( pNode, pClone );
1676 mpResult = pClone;
1679 void SmCloningVisitor::Visit( SmAttributNode* pNode )
1681 SmAttributNode* pClone = new SmAttributNode( pNode->GetToken( ) );
1682 CloneNodeAttr( pNode, pClone );
1683 CloneKids( pNode, pClone );
1684 mpResult = 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 );
1693 mpResult = pClone;
1696 void SmCloningVisitor::Visit( SmUnHorNode* pNode )
1698 SmUnHorNode* pClone = new SmUnHorNode( pNode->GetToken( ) );
1699 CloneNodeAttr( pNode, pClone );
1700 CloneKids( pNode, pClone );
1701 mpResult = pClone;
1704 void SmCloningVisitor::Visit( SmBinHorNode* pNode )
1706 SmBinHorNode* pClone = new SmBinHorNode( pNode->GetToken( ) );
1707 CloneNodeAttr( pNode, pClone );
1708 CloneKids( pNode, pClone );
1709 mpResult = pClone;
1712 void SmCloningVisitor::Visit( SmBinVerNode* pNode )
1714 SmBinVerNode* pClone = new SmBinVerNode( pNode->GetToken( ) );
1715 CloneNodeAttr( pNode, pClone );
1716 CloneKids( pNode, pClone );
1717 mpResult = 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 );
1726 mpResult = 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 );
1735 mpResult = 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 );
1744 mpResult = 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 );
1758 mpResult = 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( ) );
1783 mpResult = pClone;
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 );
1798 mpResult = pClone;
1801 void SmCloningVisitor::Visit( SmExpressionNode* pNode )
1803 SmExpressionNode* pClone = new SmExpressionNode( pNode->GetToken( ) );
1804 CloneNodeAttr( pNode, pClone );
1805 CloneKids( pNode, pClone );
1806 mpResult = 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 );
1820 mpResult = 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 );
1840 mpResult = pClone;
1843 // SmSelectionDrawingVisitor
1845 SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, const Point& rOffset )
1846 : mrDev( rDevice )
1847 , mbHasSelectionArea( false )
1849 //Visit everything
1850 SAL_WARN_IF( !pTree, "starmath", "pTree can't be null!" );
1851 if( pTree )
1852 pTree->Accept( this );
1854 //Draw selection if there's any
1855 if( mbHasSelectionArea ){
1856 maSelectionArea.Move( rOffset.X( ), rOffset.Y( ) );
1858 //Save device state
1859 mrDev.Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR );
1860 //Change colors
1861 mrDev.SetLineColor( );
1862 mrDev.SetFillColor( COL_LIGHTGRAY );
1864 //Draw rectangle
1865 mrDev.DrawRect( maSelectionArea );
1867 //Restore device state
1868 mrDev.Pop( );
1872 void SmSelectionDrawingVisitor::ExtendSelectionArea(const tools::Rectangle& rArea)
1874 if ( ! mbHasSelectionArea ) {
1875 maSelectionArea = rArea;
1876 mbHasSelectionArea = true;
1877 } else
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)
1891 return;
1892 for( auto pChild : *static_cast<SmStructureNode*>(pNode) )
1894 if(!pChild)
1895 continue;
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 );
1915 mrDev.Pop( );
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 ) );
1933 Append("} ");
1934 } else if( pNode->GetToken( ).eType == TSTACK ) {
1935 Append( "stack{ " );
1936 bool bFirst = true;
1937 for( auto pChild : *pNode )
1939 if(!pChild)
1940 continue;
1941 if(bFirst)
1942 bFirst = false;
1943 else
1945 Separate( );
1946 Append( "# " );
1948 LineToText( pChild );
1950 Separate( );
1951 Append( "}" );
1952 } else { //Assume it's a toplevel table, containing lines
1953 bool bFirst = true;
1954 for( auto pChild : *pNode )
1956 if(!pChild)
1957 continue;
1958 if(bFirst)
1959 bFirst = false;
1960 else
1962 Separate( );
1963 Append( "newline" );
1965 Separate( );
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 ) {
1978 Append( "abs" );
1979 LineToText( pBody );
1980 } else {
1981 if( pNode->GetScaleMode( ) == SmScaleMode::Height )
1982 Append( "left " );
1983 pLeftBrace->Accept( this );
1984 Separate( );
1985 pBody->Accept( this );
1986 Separate( );
1987 if( pNode->GetScaleMode( ) == SmScaleMode::Height )
1988 Append( "right " );
1989 pRightBrace->Accept( this );
1993 void SmNodeToTextVisitor::Visit( SmBracebodyNode* pNode )
1995 for( auto pChild : *pNode )
1997 if(!pChild)
1998 continue;
1999 Separate( );
2000 pChild->Accept( this );
2004 void SmNodeToTextVisitor::Visit( SmOperNode* pNode )
2006 Append( pNode->GetToken( ).aText );
2007 Separate( );
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 );
2012 else
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 );
2018 if( pChild ) {
2019 Separate( );
2020 Append( "lsup { " );
2021 LineToText( pChild );
2022 Append( "} " );
2024 pChild = pSubSup->GetSubSup( LSUB );
2025 if( pChild ) {
2026 Separate( );
2027 Append( "lsub { " );
2028 LineToText( pChild );
2029 Append( "} " );
2031 pChild = pSubSup->GetSubSup( RSUP );
2032 if( pChild ) {
2033 Separate( );
2034 Append( "^ { " );
2035 LineToText( pChild );
2036 Append( "} " );
2038 pChild = pSubSup->GetSubSup( RSUB );
2039 if( pChild ) {
2040 Separate( );
2041 Append( "_ { " );
2042 LineToText( pChild );
2043 Append( "} " );
2045 pChild = pSubSup->GetSubSup( CSUP );
2046 if( pChild ) {
2047 Separate( );
2048 if (pSubSup->IsUseLimits())
2049 Append( "to { " );
2050 else
2051 Append( "csup { " );
2052 LineToText( pChild );
2053 Append( "} " );
2055 pChild = pSubSup->GetSubSup( CSUB );
2056 if( pChild ) {
2057 Separate( );
2058 if (pSubSup->IsUseLimits())
2059 Append( "from { " );
2060 else
2061 Append( "csub { " );
2062 LineToText( pChild );
2063 Append( "} " );
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 )
2085 case TBOLD:
2086 Append( "bold " );
2087 break;
2088 case TNBOLD:
2089 Append( "nbold " );
2090 break;
2091 case TITALIC:
2092 Append( "italic " );
2093 break;
2094 case TNITALIC:
2095 Append( "nitalic " );
2096 break;
2097 case TPHANTOM:
2098 Append( "phantom " );
2099 break;
2100 case TSIZE:
2102 Append( "size " );
2103 switch ( pNode->GetSizeType( ) )
2105 case FontSizeType::PLUS:
2106 Append( "+" );
2107 break;
2108 case FontSizeType::MINUS:
2109 Append( "-" );
2110 break;
2111 case FontSizeType::MULTIPLY:
2112 Append( "*" );
2113 break;
2114 case FontSizeType::DIVIDE:
2115 Append( "/" );
2116 break;
2117 case FontSizeType::ABSOLUT:
2118 default:
2119 break;
2121 Append( ::rtl::math::doubleToUString(
2122 static_cast<double>( pNode->GetSizeParameter( ) ),
2123 rtl_math_StringFormat_Automatic,
2124 rtl_math_DecimalPlaces_Max, '.', true ) );
2125 Append( " " );
2127 break;
2128 case TBLACK:
2129 Append( "color black " );
2130 break;
2131 case TWHITE:
2132 Append( "color white " );
2133 break;
2134 case TRED:
2135 Append( "color red " );
2136 break;
2137 case TGREEN:
2138 Append( "color green " );
2139 break;
2140 case TBLUE:
2141 Append( "color blue " );
2142 break;
2143 case TCYAN:
2144 Append( "color cyan " );
2145 break;
2146 case TMAGENTA:
2147 Append( "color magenta " );
2148 break;
2149 case TYELLOW:
2150 Append( "color yellow " );
2151 break;
2152 case TSANS:
2153 Append( "font sans " );
2154 break;
2155 case TSERIF:
2156 Append( "font serif " );
2157 break;
2158 case TFIXED:
2159 Append( "font fixed " );
2160 break;
2161 default:
2162 break;
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 )
2174 auto pChild = *it;
2175 if(!pChild)
2176 continue;
2177 Separate( );
2178 pChild->Accept( this );
2181 else
2183 for( auto pChild : *pNode )
2185 if(!pChild)
2186 continue;
2187 Separate( );
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();
2200 Separate( );
2201 if (bBraceNeeded)
2202 Append( "{ " );
2203 pLeft->Accept( this );
2204 Separate( );
2205 pOper->Accept( this );
2206 Separate( );
2207 pRight->Accept( this );
2208 Separate( );
2209 if (bBraceNeeded)
2210 Append( "} " );
2213 void SmNodeToTextVisitor::Visit( SmBinVerNode* pNode )
2215 SmNode *pNum = pNode->GetSubNode( 0 ),
2216 *pDenom = pNode->GetSubNode( 2 );
2217 Append( "{ " );
2218 LineToText( pNum );
2219 Append( "over" );
2220 LineToText( pDenom );
2221 Append( "} " );
2224 void SmNodeToTextVisitor::Visit( SmBinDiagonalNode* pNode )
2226 SmNode *pLeftOperand = pNode->GetSubNode( 0 ),
2227 *pRightOperand = pNode->GetSubNode( 1 );
2228 Append( "{ " );
2229 LineToText( pLeftOperand );
2230 Separate( );
2231 Append( "wideslash " );
2232 LineToText( pRightOperand );
2233 Append( "} " );
2236 void SmNodeToTextVisitor::Visit( SmSubSupNode* pNode )
2238 LineToText( pNode->GetBody( ) );
2239 SmNode *pChild = pNode->GetSubSup( LSUP );
2240 if( pChild ) {
2241 Separate( );
2242 Append( "lsup " );
2243 LineToText( pChild );
2245 pChild = pNode->GetSubSup( LSUB );
2246 if( pChild ) {
2247 Separate( );
2248 Append( "lsub " );
2249 LineToText( pChild );
2251 pChild = pNode->GetSubSup( RSUP );
2252 if( pChild ) {
2253 Separate( );
2254 Append( "^ " );
2255 LineToText( pChild );
2257 pChild = pNode->GetSubSup( RSUB );
2258 if( pChild ) {
2259 Separate( );
2260 Append( "_ " );
2261 LineToText( pChild );
2263 pChild = pNode->GetSubSup( CSUP );
2264 if( pChild ) {
2265 Separate( );
2266 if (pNode->IsUseLimits())
2267 Append( "to " );
2268 else
2269 Append( "csup " );
2270 LineToText( pChild );
2272 pChild = pNode->GetSubSup( CSUB );
2273 if( pChild ) {
2274 Separate( );
2275 if (pNode->IsUseLimits())
2276 Append( "from " );
2277 else
2278 Append( "csub " );
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 );
2291 Separate( );
2292 pSubNode->Accept( this );
2293 Separate( );
2294 if (j != pNode->GetNumCols() - 1U)
2295 Append( "#" );
2297 Separate( );
2298 if (i != pNode->GetNumRows() - 1U)
2299 Append( "##" );
2301 Append( "} " );
2304 void SmNodeToTextVisitor::Visit( SmPlaceNode* )
2306 Append( "<?>" );
2309 void SmNodeToTextVisitor::Visit( SmTextNode* pNode )
2311 //TODO: This method might need improvements, see SmTextNode::CreateTextFromNode
2312 if( pNode->GetToken( ).eType == TTEXT )
2313 Append( "\"" );
2314 Append( pNode->GetText( ) );
2315 if( pNode->GetToken( ).eType == TTEXT )
2316 Append( "\"" );
2319 void SmNodeToTextVisitor::Visit( SmSpecialNode* pNode )
2321 Append( pNode->GetToken( ).aText );
2324 void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode* pNode )
2326 if( pNode->GetToken( ).eType == TBOPER )
2327 Append( "boper " );
2328 else
2329 Append( "uoper " );
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();
2341 if (nNum <= 0)
2342 return;
2343 sal_uInt16 nWide = nNum / 4;
2344 sal_uInt16 nNarrow = nNum % 4;
2345 for (sal_uInt16 i = 0; i < nWide; i++)
2346 Append( "~" );
2347 for (sal_uInt16 i = 0; i < nNarrow; i++)
2348 Append( "`" );
2349 Append( " " );
2352 void SmNodeToTextVisitor::Visit( SmErrorNode* )
2356 void SmNodeToTextVisitor::Visit( SmLineNode* pNode )
2358 for( auto pChild : *pNode )
2360 if(!pChild)
2361 continue;
2362 Separate( );
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();
2373 // nested subsups
2374 bracketsNeeded =
2375 pParent && pParent->GetType() == SmNodeType::SubSup &&
2376 pNode->GetNumSubNodes() == 1 &&
2377 pNode->GetSubNode(0)->GetType() == SmNodeType::SubSup;
2380 if (bracketsNeeded) {
2381 Append( "{ " );
2383 for( auto pChild : *pNode )
2385 if(!pChild)
2386 continue;
2387 pChild->Accept( this );
2388 Separate( );
2390 if (bracketsNeeded) {
2391 Append( "} " );
2395 void SmNodeToTextVisitor::Visit( SmPolyLineNode* )
2399 void SmNodeToTextVisitor::Visit( SmRootNode* pNode )
2401 SmNode *pExtra = pNode->GetSubNode( 0 ),
2402 *pBody = pNode->GetSubNode( 2 );
2403 if( pExtra ) {
2404 Append( "nroot" );
2405 LineToText( pExtra );
2406 } else
2407 Append( "sqrt" );
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: */