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"
16 // SmDefaultingVisitor
18 void SmDefaultingVisitor::Visit( SmTableNode
* pNode
)
20 DefaultVisit( pNode
);
23 void SmDefaultingVisitor::Visit( SmBraceNode
* pNode
)
25 DefaultVisit( pNode
);
28 void SmDefaultingVisitor::Visit( SmBracebodyNode
* pNode
)
30 DefaultVisit( pNode
);
33 void SmDefaultingVisitor::Visit( SmOperNode
* pNode
)
35 DefaultVisit( pNode
);
38 void SmDefaultingVisitor::Visit( SmAlignNode
* pNode
)
40 DefaultVisit( pNode
);
43 void SmDefaultingVisitor::Visit( SmAttributNode
* pNode
)
45 DefaultVisit( pNode
);
48 void SmDefaultingVisitor::Visit( SmFontNode
* pNode
)
50 DefaultVisit( pNode
);
53 void SmDefaultingVisitor::Visit( SmUnHorNode
* pNode
)
55 DefaultVisit( pNode
);
58 void SmDefaultingVisitor::Visit( SmBinHorNode
* pNode
)
60 DefaultVisit( pNode
);
63 void SmDefaultingVisitor::Visit( SmBinVerNode
* pNode
)
65 DefaultVisit( pNode
);
68 void SmDefaultingVisitor::Visit( SmBinDiagonalNode
* pNode
)
70 DefaultVisit( pNode
);
73 void SmDefaultingVisitor::Visit( SmSubSupNode
* pNode
)
75 DefaultVisit( pNode
);
78 void SmDefaultingVisitor::Visit( SmMatrixNode
* pNode
)
80 DefaultVisit( pNode
);
83 void SmDefaultingVisitor::Visit( SmPlaceNode
* pNode
)
85 DefaultVisit( pNode
);
88 void SmDefaultingVisitor::Visit( SmTextNode
* pNode
)
90 DefaultVisit( pNode
);
93 void SmDefaultingVisitor::Visit( SmSpecialNode
* pNode
)
95 DefaultVisit( pNode
);
98 void SmDefaultingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
100 DefaultVisit( pNode
);
103 void SmDefaultingVisitor::Visit( SmMathSymbolNode
* pNode
)
105 DefaultVisit( pNode
);
108 void SmDefaultingVisitor::Visit( SmBlankNode
* pNode
)
110 DefaultVisit( pNode
);
113 void SmDefaultingVisitor::Visit( SmErrorNode
* pNode
)
115 DefaultVisit( pNode
);
118 void SmDefaultingVisitor::Visit( SmLineNode
* pNode
)
120 DefaultVisit( pNode
);
123 void SmDefaultingVisitor::Visit( SmExpressionNode
* pNode
)
125 DefaultVisit( pNode
);
128 void SmDefaultingVisitor::Visit( SmPolyLineNode
* pNode
)
130 DefaultVisit( pNode
);
133 void SmDefaultingVisitor::Visit( SmRootNode
* pNode
)
135 DefaultVisit( pNode
);
138 void SmDefaultingVisitor::Visit( SmRootSymbolNode
* pNode
)
140 DefaultVisit( pNode
);
143 void SmDefaultingVisitor::Visit( SmDynIntegralNode
* pNode
)
145 DefaultVisit( pNode
);
148 void SmDefaultingVisitor::Visit( SmDynIntegralSymbolNode
* pNode
)
150 DefaultVisit( pNode
);
153 void SmDefaultingVisitor::Visit( SmRectangleNode
* pNode
)
155 DefaultVisit( pNode
);
158 void SmDefaultingVisitor::Visit( SmVerticalBraceNode
* pNode
)
160 DefaultVisit( pNode
);
163 // SmCaretDrawingVisitor
165 SmCaretDrawingVisitor::SmCaretDrawingVisitor( OutputDevice
& rDevice
,
173 isCaretVisible
= caretVisible
;
174 SAL_WARN_IF( !position
.IsValid(), "starmath", "Cannot draw invalid position!" );
175 if( !position
.IsValid( ) )
179 rDev
.Push( PushFlags::FONT
| PushFlags::MAPMODE
| PushFlags::LINECOLOR
| PushFlags::FILLCOLOR
| PushFlags::TEXTCOLOR
);
181 pos
.pSelectedNode
->Accept( this );
182 //Restore device state
186 void SmCaretDrawingVisitor::Visit( SmTextNode
* pNode
)
190 rDev
.SetFont( pNode
->GetFont( ) );
193 SmNode
* pLine
= SmCursor::FindTopMostNodeInLine( pNode
);
196 long left
= pNode
->GetLeft( ) + rDev
.GetTextWidth( pNode
->GetText( ), 0, i
) + Offset
.X( );
197 long top
= pLine
->GetTop( ) + Offset
.Y( );
198 long height
= pLine
->GetHeight( );
199 long left_line
= pLine
->GetLeft( ) + Offset
.X( );
200 long right_line
= pLine
->GetRight( ) + Offset
.X( );
203 rDev
.SetLineColor( Color( COL_BLACK
) );
205 if ( isCaretVisible
) {
207 Point
p1( left
, top
);
208 Point
p2( left
, top
+ height
);
209 rDev
.DrawLine( p1
, p2
);
213 Point
pLeft( left_line
, top
+ height
);
214 Point
pRight( right_line
, top
+ height
);
215 rDev
.DrawLine( pLeft
, pRight
);
218 void SmCaretDrawingVisitor::DefaultVisit( SmNode
* pNode
)
220 rDev
.SetLineColor( Color( COL_BLACK
) );
223 SmNode
* pLine
= SmCursor::FindTopMostNodeInLine( pNode
);
226 long left
= pNode
->GetLeft( ) + Offset
.X( ) + ( pos
.Index
== 1 ? pNode
->GetWidth( ) : 0 );
227 long top
= pLine
->GetTop( ) + Offset
.Y( );
228 long height
= pLine
->GetHeight( );
229 long left_line
= pLine
->GetLeft( ) + Offset
.X( );
230 long right_line
= pLine
->GetRight( ) + Offset
.X( );
233 rDev
.SetLineColor( Color( COL_BLACK
) );
235 if ( isCaretVisible
) {
237 Point
p1( left
, top
);
238 Point
p2( left
, top
+ height
);
239 rDev
.DrawLine( p1
, p2
);
243 Point
pLeft( left_line
, top
+ height
);
244 Point
pRight( right_line
, top
+ height
);
245 rDev
.DrawLine( pLeft
, pRight
);
248 // SmCaretPos2LineVisitor
250 void SmCaretPos2LineVisitor::Visit( SmTextNode
* pNode
)
253 pDev
->Push( PushFlags::FONT
| PushFlags::TEXTCOLOR
);
257 pDev
->SetFont( pNode
->GetFont( ) );
260 long left
= pNode
->GetLeft( ) + pDev
->GetTextWidth( pNode
->GetText( ), 0, i
);
261 long top
= pNode
->GetTop( );
262 long height
= pNode
->GetHeight( );
264 line
= SmCaretLine( left
, top
, height
);
266 //Restore device state
270 void SmCaretPos2LineVisitor::DefaultVisit( SmNode
* pNode
)
272 //Vertical line ( code from SmCaretDrawingVisitor )
273 Point p1
= pNode
->GetTopLeft( );
275 p1
.Move( pNode
->GetWidth( ), 0 );
277 line
= SmCaretLine( p1
.X( ), p1
.Y( ), pNode
->GetHeight( ) );
283 void SmDrawingVisitor::Visit( SmTableNode
* pNode
)
285 DrawChildren( pNode
);
288 void SmDrawingVisitor::Visit( SmBraceNode
* pNode
)
290 DrawChildren( pNode
);
293 void SmDrawingVisitor::Visit( SmBracebodyNode
* pNode
)
295 DrawChildren( pNode
);
298 void SmDrawingVisitor::Visit( SmOperNode
* pNode
)
300 DrawChildren( pNode
);
303 void SmDrawingVisitor::Visit( SmAlignNode
* pNode
)
305 DrawChildren( pNode
);
308 void SmDrawingVisitor::Visit( SmAttributNode
* pNode
)
310 DrawChildren( pNode
);
313 void SmDrawingVisitor::Visit( SmFontNode
* pNode
)
315 DrawChildren( pNode
);
318 void SmDrawingVisitor::Visit( SmUnHorNode
* pNode
)
320 DrawChildren( pNode
);
323 void SmDrawingVisitor::Visit( SmBinHorNode
* pNode
)
325 DrawChildren( pNode
);
328 void SmDrawingVisitor::Visit( SmBinVerNode
* pNode
)
330 DrawChildren( pNode
);
333 void SmDrawingVisitor::Visit( SmBinDiagonalNode
* pNode
)
335 DrawChildren( pNode
);
338 void SmDrawingVisitor::Visit( SmSubSupNode
* pNode
)
340 DrawChildren( pNode
);
343 void SmDrawingVisitor::Visit( SmMatrixNode
* pNode
)
345 DrawChildren( pNode
);
348 void SmDrawingVisitor::Visit( SmPlaceNode
* pNode
)
350 DrawSpecialNode( pNode
);
353 void SmDrawingVisitor::Visit( SmTextNode
* pNode
)
355 DrawTextNode( pNode
);
358 void SmDrawingVisitor::Visit( SmSpecialNode
* pNode
)
360 DrawSpecialNode( pNode
);
363 void SmDrawingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
365 DrawSpecialNode( pNode
);
368 void SmDrawingVisitor::Visit( SmMathSymbolNode
* pNode
)
370 DrawSpecialNode( pNode
);
373 void SmDrawingVisitor::Visit( SmBlankNode
* pNode
)
375 DrawChildren( pNode
);
378 void SmDrawingVisitor::Visit( SmErrorNode
* pNode
)
380 DrawSpecialNode( pNode
);
383 void SmDrawingVisitor::Visit( SmLineNode
* pNode
)
385 DrawChildren( pNode
);
388 void SmDrawingVisitor::Visit( SmExpressionNode
* pNode
)
390 DrawChildren( pNode
);
393 void SmDrawingVisitor::Visit( SmRootNode
* pNode
)
395 DrawChildren( pNode
);
398 void SmDrawingVisitor::Visit(SmDynIntegralNode
* pNode
)
400 DrawChildren( pNode
);
403 void SmDrawingVisitor::Visit( SmVerticalBraceNode
* pNode
)
405 DrawChildren( pNode
);
408 void SmDrawingVisitor::Visit( SmRootSymbolNode
* pNode
)
410 if ( pNode
->IsPhantom( ) )
413 // draw root-sign itself
414 DrawSpecialNode( pNode
);
416 SmTmpDevice
aTmpDev( ( OutputDevice
& ) rDev
, true );
417 aTmpDev
.SetFillColor( pNode
->GetFont( ).GetColor( ) );
418 rDev
.SetLineColor( );
419 aTmpDev
.SetFont( pNode
->GetFont( ) );
421 // since the width is always unscaled it corresponds ot the _original_
422 // _unscaled_ font height to be used, we use that to calculate the
423 // bar height. Thus it is independent of the arguments height.
424 // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
425 long nBarHeight
= pNode
->GetWidth( ) * 7L / 100L;
426 long nBarWidth
= pNode
->GetBodyWidth( ) + pNode
->GetBorderWidth( );
427 Point
aBarOffset( pNode
->GetWidth( ), +pNode
->GetBorderWidth( ) );
428 Point
aBarPos( Position
+ aBarOffset
);
430 Rectangle
aBar( aBarPos
, Size( nBarWidth
, nBarHeight
) );
431 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
432 //! increasing zoomfactor.
433 // This is done by shifting its output-position to a point that
434 // corresponds exactly to a pixel on the output device.
435 Point
aDrawPos( rDev
.PixelToLogic( rDev
.LogicToPixel( aBar
.TopLeft( ) ) ) );
436 aBar
.SetPos( aDrawPos
);
438 rDev
.DrawRect( aBar
);
441 void SmDrawingVisitor::Visit( SmDynIntegralSymbolNode
* pNode
)
443 if ( pNode
->IsPhantom( ) )
446 // draw integral-sign itself
447 DrawSpecialNode( pNode
);
449 //! the rest of this may not be needed at all
451 // this should be something like:
452 // instead of just drawing the node, take some information about the body.
453 // This is also how SmRootSymbol does it (probably by means of SmRootNode)
454 // NEXT: Check out SmRootNode
457 void SmDrawingVisitor::Visit( SmPolyLineNode
* pNode
)
459 if ( pNode
->IsPhantom( ) )
462 long nBorderwidth
= pNode
->GetFont( ).GetBorderWidth( );
465 aInfo
.SetWidth( pNode
->GetWidth( ) - 2 * nBorderwidth
);
467 Point
aOffset ( Point( ) - pNode
->GetPolygon( ).GetBoundRect( ).TopLeft( )
468 + Point( nBorderwidth
, nBorderwidth
) ),
469 aPos ( Position
+ aOffset
);
470 pNode
->GetPolygon( ).Move( aPos
.X( ), aPos
.Y( ) ); //Works because Polygon wraps a pointer
472 SmTmpDevice
aTmpDev ( ( OutputDevice
& ) rDev
, false );
473 aTmpDev
.SetLineColor( pNode
->GetFont( ).GetColor( ) );
475 rDev
.DrawPolyLine( pNode
->GetPolygon( ), aInfo
);
478 void SmDrawingVisitor::Visit( SmRectangleNode
* pNode
)
480 if ( pNode
->IsPhantom( ) )
483 SmTmpDevice
aTmpDev ( ( OutputDevice
& ) rDev
, false );
484 aTmpDev
.SetFillColor( pNode
->GetFont( ).GetColor( ) );
485 rDev
.SetLineColor( );
486 aTmpDev
.SetFont( pNode
->GetFont( ) );
488 sal_uLong nTmpBorderWidth
= pNode
->GetFont( ).GetBorderWidth( );
490 // get rectangle and remove borderspace
491 Rectangle
aTmp ( pNode
->AsRectangle( ) + Position
- pNode
->GetTopLeft( ) );
492 aTmp
.Left( ) += nTmpBorderWidth
;
493 aTmp
.Right( ) -= nTmpBorderWidth
;
494 aTmp
.Top( ) += nTmpBorderWidth
;
495 aTmp
.Bottom( ) -= nTmpBorderWidth
;
497 SAL_WARN_IF( aTmp
.GetHeight() == 0 || aTmp
.GetWidth() == 0,
498 "starmath", "Empty rectangle" );
500 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
501 //! increasing zoomfactor.
502 // This is done by shifting its output-position to a point that
503 // corresponds exactly to a pixel on the output device.
504 Point
aPos ( rDev
.PixelToLogic( rDev
.LogicToPixel( aTmp
.TopLeft( ) ) ) );
507 rDev
.DrawRect( aTmp
);
510 void SmDrawingVisitor::DrawTextNode( SmTextNode
* pNode
)
512 if ( pNode
->IsPhantom() || pNode
->GetText().isEmpty() || pNode
->GetText()[0] == '\0' )
515 SmTmpDevice
aTmpDev ( ( OutputDevice
& ) rDev
, false );
516 aTmpDev
.SetFont( pNode
->GetFont( ) );
518 Point
aPos ( Position
);
519 aPos
.Y( ) += pNode
->GetBaselineOffset( );
520 // auf Pixelkoordinaten runden
521 aPos
= rDev
.PixelToLogic( rDev
.LogicToPixel( aPos
) );
523 rDev
.DrawStretchText( aPos
, pNode
->GetWidth( ), pNode
->GetText( ) );
526 void SmDrawingVisitor::DrawSpecialNode( SmSpecialNode
* pNode
)
528 //! since this chars might come from any font, that we may not have
529 //! set to ALIGN_BASELINE yet, we do it now.
530 pNode
->GetFont( ).SetAlign( ALIGN_BASELINE
);
532 DrawTextNode( pNode
);
535 void SmDrawingVisitor::DrawChildren( SmNode
* pNode
)
537 if ( pNode
->IsPhantom( ) )
540 Point rPosition
= Position
;
542 SmNodeIterator
it( pNode
);
545 Point
aOffset ( it
->GetTopLeft( ) - pNode
->GetTopLeft( ) );
546 Position
= rPosition
+ aOffset
;
551 // SmSetSelectionVisitor
553 SmSetSelectionVisitor::SmSetSelectionVisitor( SmCaretPos startPos
, SmCaretPos endPos
, SmNode
* pTree
) {
558 //Assume that pTree is a SmTableNode
559 SAL_WARN_IF(pTree
->GetType() != NTABLE
, "starmath", "pTree should be a SmTableNode!");
560 //Visit root node, this is special as this node cannot be selected, but its children can!
561 if(pTree
->GetType() == NTABLE
){
562 //Change state if StartPos is in front of this node
563 if( StartPos
.pSelectedNode
== pTree
&& StartPos
.Index
== 0 )
564 IsSelecting
= !IsSelecting
;
565 //Change state if EndPos is in front of this node
566 if( EndPos
.pSelectedNode
== pTree
&& EndPos
.Index
== 0 )
567 IsSelecting
= !IsSelecting
;
568 SAL_WARN_IF(IsSelecting
, "starmath", "Caret positions needed to set IsSelecting about, shouldn't be possible!");
571 SmNodeIterator
it( pTree
);
572 while( it
.Next( ) ) {
574 //If we started a selection in this line and it haven't ended, we do that now!
577 SetSelectedOnAll(it
.Current(), true);
578 //Set StartPos and EndPos to invalid positions, this ensures that an unused
579 //start or end (because we forced end above), doesn't start a new selection.
580 StartPos
= EndPos
= SmCaretPos();
583 //Check if pTree isn't selected
584 SAL_WARN_IF(pTree
->IsSelected(), "starmath", "pTree should never be selected!");
585 //Discard the selection if there's a bug (it's better than crashing)
586 if(pTree
->IsSelected())
587 SetSelectedOnAll(pTree
, false);
588 }else //This shouldn't happen, but I don't see any reason to die if it does
592 void SmSetSelectionVisitor::SetSelectedOnAll( SmNode
* pSubTree
, bool IsSelected
) {
593 pSubTree
->SetSelected( IsSelected
);
595 //Quick BFS to set all selections
596 SmNodeIterator
it( pSubTree
);
598 SetSelectedOnAll( it
.Current( ), IsSelected
);
601 void SmSetSelectionVisitor::DefaultVisit( SmNode
* pNode
) {
602 //Change state if StartPos is in front of this node
603 if( StartPos
.pSelectedNode
== pNode
&& StartPos
.Index
== 0 )
604 IsSelecting
= !IsSelecting
;
605 //Change state if EndPos is in front of this node
606 if( EndPos
.pSelectedNode
== pNode
&& EndPos
.Index
== 0 )
607 IsSelecting
= !IsSelecting
;
609 //Cache current state
610 bool WasSelecting
= IsSelecting
;
611 bool ChangedState
= false;
614 pNode
->SetSelected( IsSelecting
);
617 SmNodeIterator
it( pNode
);
621 ChangedState
= ( WasSelecting
!= IsSelecting
) || ChangedState
;
627 //Select this node and all of its children
628 //(Make exception for SmBracebodyNode)
629 if( pNode
->GetType() != NBRACEBODY
||
630 !pNode
->GetParent() ||
631 pNode
->GetParent()->GetType() != NBRACE
)
632 SetSelectedOnAll( pNode
, true );
634 SetSelectedOnAll( pNode
->GetParent(), true );
635 /* If the equation is: sqrt{2 + 4} + 5
636 * And the selection is: sqrt{2 + [4} +] 5
637 * Where [ denotes StartPos and ] denotes EndPos
638 * Then the sqrt node should be selected, so that the
639 * effective selection is: [sqrt{2 + 4} +] 5
640 * The same is the case if we swap StartPos and EndPos.
644 //Change state if StartPos is after this node
645 if( StartPos
.pSelectedNode
== pNode
&& StartPos
.Index
== 1 )
647 IsSelecting
= !IsSelecting
;
649 //Change state if EndPos is after of this node
650 if( EndPos
.pSelectedNode
== pNode
&& EndPos
.Index
== 1 )
652 IsSelecting
= !IsSelecting
;
656 void SmSetSelectionVisitor::VisitCompositionNode( SmNode
* pNode
) {
657 //Change state if StartPos is in front of this node
658 if( StartPos
.pSelectedNode
== pNode
&& StartPos
.Index
== 0 )
659 IsSelecting
= !IsSelecting
;
660 //Change state if EndPos is in front of this node
661 if( EndPos
.pSelectedNode
== pNode
&& EndPos
.Index
== 0 )
662 IsSelecting
= !IsSelecting
;
664 //Cache current state
665 bool WasSelecting
= IsSelecting
;
668 SmNodeIterator
it( pNode
);
672 //Set selected, if everything was selected
673 pNode
->SetSelected( WasSelecting
&& IsSelecting
);
675 //Change state if StartPos is after this node
676 if( StartPos
.pSelectedNode
== pNode
&& StartPos
.Index
== 1 )
677 IsSelecting
= !IsSelecting
;
678 //Change state if EndPos is after of this node
679 if( EndPos
.pSelectedNode
== pNode
&& EndPos
.Index
== 1 )
680 IsSelecting
= !IsSelecting
;
683 void SmSetSelectionVisitor::Visit( SmTextNode
* pNode
) {
686 if( StartPos
.pSelectedNode
== pNode
)
688 if( EndPos
.pSelectedNode
== pNode
)
692 pNode
->SetSelected( true );
693 if( i1
!= -1 && i2
!= -1 ) {
694 start
= i1
< i2
? i1
: i2
; //MIN
695 end
= i1
> i2
? i1
: i2
; //MAX
696 } else if( IsSelecting
&& i1
!= -1 ) {
700 } else if( IsSelecting
&& i2
!= -1 ) {
704 } else if( !IsSelecting
&& i1
!= -1 ) {
706 end
= pNode
->GetText().getLength();
708 } else if( !IsSelecting
&& i2
!= -1 ) {
710 end
= pNode
->GetText().getLength();
712 } else if( IsSelecting
) {
714 end
= pNode
->GetText().getLength();
716 pNode
->SetSelected( false );
720 pNode
->SetSelected( start
!= end
);
721 pNode
->SetSelectionStart( start
);
722 pNode
->SetSelectionEnd( end
);
725 void SmSetSelectionVisitor::Visit( SmExpressionNode
* pNode
) {
726 VisitCompositionNode( pNode
);
729 void SmSetSelectionVisitor::Visit( SmLineNode
* pNode
) {
730 VisitCompositionNode( pNode
);
733 void SmSetSelectionVisitor::Visit( SmAlignNode
* pNode
) {
734 VisitCompositionNode( pNode
);
737 void SmSetSelectionVisitor::Visit( SmBinHorNode
* pNode
) {
738 VisitCompositionNode( pNode
);
741 void SmSetSelectionVisitor::Visit( SmUnHorNode
* pNode
) {
742 VisitCompositionNode( pNode
);
745 void SmSetSelectionVisitor::Visit( SmFontNode
* pNode
) {
746 VisitCompositionNode( pNode
);
749 // SmCaretPosGraphBuildingVisitor
751 SmCaretPosGraphBuildingVisitor::SmCaretPosGraphBuildingVisitor( SmNode
* pRootNode
)
752 : mpRightMost(nullptr)
753 , mpGraph(new SmCaretPosGraph
)
755 //pRootNode should always be a table
756 SAL_WARN_IF( pRootNode
->GetType( ) != NTABLE
, "starmath", "pRootNode must be a table node");
757 //Handle the special case where NTABLE is used a rootnode
758 if( pRootNode
->GetType( ) == NTABLE
){
759 //Children are SmLineNodes
760 //Or so I thought... Aparently, the children can be instances of SmExpression
761 //especially if there's a error in the formula... So he we go, a simple work around.
762 SmNodeIterator
it( pRootNode
);
764 //There's a special invariant between this method and the Visit( SmLineNode* )
765 //Usually mpRightMost may not be NULL, to avoid this mpRightMost should here be
766 //set to a new SmCaretPos in front of it.Current( ), however, if it.Current( ) is
767 //an instance of SmLineNode we let SmLineNode create this position in front of
769 //The argument for doing this is that we now don't have to worry about SmLineNode
770 //being a visual line composition node. Thus, no need for yet another special case
771 //in SmCursor::IsLineCompositionNode and everywhere this method is used.
772 //if( it->GetType( ) != NLINE )
773 mpRightMost
= mpGraph
->Add( SmCaretPos( it
.Current( ), 0 ) );
777 pRootNode
->Accept(this);
780 SmCaretPosGraphBuildingVisitor::~SmCaretPosGraphBuildingVisitor()
784 void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode
* pNode
){
785 SmNodeIterator
it( pNode
);
791 /** Build SmCaretPosGraph for SmTableNode
792 * This method covers cases where SmTableNode is used in a binom or stack,
793 * the special case where it is used as root node for the entire formula is
794 * handled in the constructor.
796 void SmCaretPosGraphBuildingVisitor::Visit( SmTableNode
* pNode
){
797 SmCaretPosGraphEntry
*left
= mpRightMost
,
798 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1) );
799 bool bIsFirst
= true;
800 SmNodeIterator
it( pNode
);
802 mpRightMost
= mpGraph
->Add( SmCaretPos( it
.Current(), 0 ), left
);
804 left
->SetRight(mpRightMost
);
806 mpRightMost
->SetRight(right
);
808 right
->SetLeft(mpRightMost
);
814 /** Build SmCaretPosGraph for SmSubSupNode
816 * The child positions in a SubSupNode, where H is the body:
829 * Graph over these, where "left" is before the SmSubSupNode and "right" is after:
844 void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode
* pNode
)
846 SmCaretPosGraphEntry
*left
,
852 SAL_WARN_IF( !mpRightMost
, "starmath", "mpRightMost shouldn't be NULL here!" );
855 SAL_WARN_IF( !pNode
->GetBody(), "starmath", "SmSubSupNode Doesn't have a body!" );
856 bodyLeft
= mpGraph
->Add( SmCaretPos( pNode
->GetBody( ), 0 ), left
);
857 left
->SetRight( bodyLeft
); //TODO: Don't make this if LSUP or LSUB are NULL ( not sure??? )
860 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
862 //Visit the body, to get bodyRight
863 mpRightMost
= bodyLeft
;
864 pNode
->GetBody( )->Accept( this );
865 bodyRight
= mpRightMost
;
866 bodyRight
->SetRight( right
);
867 right
->SetLeft( bodyRight
);
871 if( ( pChild
= pNode
->GetSubSup( LSUP
) ) ){
872 SmCaretPosGraphEntry
*cLeft
; //Child left
873 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
876 pChild
->Accept( this );
878 mpRightMost
->SetRight( bodyLeft
);
881 if( ( pChild
= pNode
->GetSubSup( LSUB
) ) ){
882 SmCaretPosGraphEntry
*cLeft
; //Child left
883 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
886 pChild
->Accept( this );
888 mpRightMost
->SetRight( bodyLeft
);
891 if( ( pChild
= pNode
->GetSubSup( CSUP
) ) ){
892 SmCaretPosGraphEntry
*cLeft
; //Child left
893 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
896 pChild
->Accept( this );
898 mpRightMost
->SetRight( right
);
901 if( ( pChild
= pNode
->GetSubSup( CSUB
) ) ){
902 SmCaretPosGraphEntry
*cLeft
; //Child left
903 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
906 pChild
->Accept( this );
908 mpRightMost
->SetRight( right
);
911 if( ( pChild
= pNode
->GetSubSup( RSUP
) ) ){
912 SmCaretPosGraphEntry
*cLeft
; //Child left
913 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), bodyRight
);
916 pChild
->Accept( this );
918 mpRightMost
->SetRight( right
);
921 if( ( pChild
= pNode
->GetSubSup( RSUB
) ) ){
922 SmCaretPosGraphEntry
*cLeft
; //Child left
923 cLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), bodyRight
);
926 pChild
->Accept( this );
928 mpRightMost
->SetRight( right
);
931 //Set return parameters
935 /** Build caret position for SmOperNode
937 * If first child is an SmSubSupNode we will ignore its
938 * body, as this body is a SmMathSymbol, for SUM, INT or similar
939 * that shouldn't be subject to modification.
940 * If first child is not a SmSubSupNode, ignore it completely
941 * as it is a SmMathSymbol.
943 * The child positions in a SmOperNode, where H is symbol, e.g. int, sum or similar:
947 * LSUP H H RSUP BBB BB BBB B B
948 * H H B B B B B B B B
951 * LSUB H H RSUB BBB BB BBB B
955 * Notice, CSUP, etc. are actually granchildren, but inorder to ignore H, these are visited
956 * from here. If they are present, that is if pOper is an instance of SmSubSupNode.
958 * Graph over these, where "left" is before the SmOperNode and "right" is after:
972 void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode
* pNode
)
974 SmNode
*pOper
= pNode
->GetSubNode( 0 ),
975 *pBody
= pNode
->GetSubNode( 1 );
977 SmCaretPosGraphEntry
*left
= mpRightMost
,
982 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
983 left
->SetRight( bodyLeft
);
985 //Visit body, get bodyRight
986 mpRightMost
= bodyLeft
;
987 pBody
->Accept( this );
988 bodyRight
= mpRightMost
;
991 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), bodyRight
);
992 bodyRight
->SetRight( right
);
994 //Get subsup pNode if any
995 SmSubSupNode
* pSubSup
= pOper
->GetType( ) == NSUBSUP
? static_cast<SmSubSupNode
*>(pOper
) : NULL
;
998 SmCaretPosGraphEntry
*childLeft
;
999 if( pSubSup
&& ( pChild
= pSubSup
->GetSubSup( LSUP
) ) ) {
1000 //Create position in front of pChild
1001 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1003 mpRightMost
= childLeft
;
1004 pChild
->Accept( this );
1005 //Set right on mpRightMost from pChild
1006 mpRightMost
->SetRight( bodyLeft
);
1008 if( pSubSup
&& ( pChild
= pSubSup
->GetSubSup( LSUB
) ) ) {
1009 //Create position in front of pChild
1010 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1012 mpRightMost
= childLeft
;
1013 pChild
->Accept( this );
1014 //Set right on mpRightMost from pChild
1015 mpRightMost
->SetRight( bodyLeft
);
1017 if( pSubSup
&& ( pChild
= pSubSup
->GetSubSup( CSUP
) ) ) {//TO
1018 //Create position in front of pChild
1019 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1021 mpRightMost
= childLeft
;
1022 pChild
->Accept( this );
1023 //Set right on mpRightMost from pChild
1024 mpRightMost
->SetRight( bodyLeft
);
1026 if( pSubSup
&& ( pChild
= pSubSup
->GetSubSup( CSUB
) ) ) { //FROM
1027 //Create position in front of pChild
1028 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1030 mpRightMost
= childLeft
;
1031 pChild
->Accept( this );
1032 //Set right on mpRightMost from pChild
1033 mpRightMost
->SetRight( bodyLeft
);
1035 if( pSubSup
&& ( pChild
= pSubSup
->GetSubSup( RSUP
) ) ) {
1036 //Create position in front of pChild
1037 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1039 mpRightMost
= childLeft
;
1040 pChild
->Accept( this );
1041 //Set right on mpRightMost from pChild
1042 mpRightMost
->SetRight( bodyLeft
);
1044 if( pSubSup
&& ( pChild
= pSubSup
->GetSubSup( RSUB
) ) ) {
1045 //Create position in front of pChild
1046 childLeft
= mpGraph
->Add( SmCaretPos( pChild
, 0 ), left
);
1048 mpRightMost
= childLeft
;
1049 pChild
->Accept( this );
1050 //Set right on mpRightMost from pChild
1051 mpRightMost
->SetRight( bodyLeft
);
1055 mpRightMost
= right
;
1058 void SmCaretPosGraphBuildingVisitor::Visit( SmMatrixNode
* pNode
)
1060 SmCaretPosGraphEntry
*left
= mpRightMost
,
1061 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1063 for ( sal_uInt16 i
= 0; i
< pNode
->GetNumRows( ); i
++ ) {
1064 SmCaretPosGraphEntry
* r
= left
;
1065 for ( sal_uInt16 j
= 0; j
< pNode
->GetNumCols( ); j
++ ){
1066 SmNode
* pSubNode
= pNode
->GetSubNode( i
* pNode
->GetNumCols( ) + j
);
1068 mpRightMost
= mpGraph
->Add( SmCaretPos( pSubNode
, 0 ), r
);
1069 if( j
!= 0 || ( pNode
->GetNumRows( ) - 1 ) / 2 == i
)
1070 r
->SetRight( mpRightMost
);
1072 pSubNode
->Accept( this );
1076 mpRightMost
->SetRight( right
);
1077 if( ( pNode
->GetNumRows( ) - 1 ) / 2 == i
)
1078 right
->SetLeft( mpRightMost
);
1081 mpRightMost
= right
;
1084 /** Build SmCaretPosGraph for SmTextNode
1086 * Lines in an SmTextNode:
1090 * Where A B and C are characters in the text.
1092 * Graph over these, where "left" is before the SmTextNode and "right" is after:
1100 * Notice that C and right is the same position here.
1102 void SmCaretPosGraphBuildingVisitor::Visit( SmTextNode
* pNode
)
1104 SAL_WARN_IF( pNode
->GetText().isEmpty(), "starmath", "Empty SmTextNode is bad" );
1106 int size
= pNode
->GetText().getLength();
1107 for( int i
= 1; i
<= size
; i
++ ){
1108 SmCaretPosGraphEntry
* pRight
= mpRightMost
;
1109 mpRightMost
= mpGraph
->Add( SmCaretPos( pNode
, i
), pRight
);
1110 pRight
->SetRight( mpRightMost
);
1114 /** Build SmCaretPosGraph for SmBinVerNode
1116 * Lines in an SmBinVerNode:
1123 * Graph over these, where "left" is before the SmBinVerNode and "right" is after:
1132 void SmCaretPosGraphBuildingVisitor::Visit( SmBinVerNode
* pNode
)
1134 //None if these children can be NULL, see SmBinVerNode::Arrange
1135 SmNode
*pNum
= pNode
->GetSubNode( 0 ),
1136 *pDenom
= pNode
->GetSubNode( 2 );
1138 SmCaretPosGraphEntry
*left
,
1145 SAL_WARN_IF( !mpRightMost
, "starmath", "There must be a position in front of this" );
1148 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1151 numLeft
= mpGraph
->Add( SmCaretPos( pNum
, 0 ), left
);
1152 left
->SetRight( numLeft
);
1155 mpRightMost
= numLeft
;
1156 pNum
->Accept( this );
1157 mpRightMost
->SetRight( right
);
1158 right
->SetLeft( mpRightMost
);
1161 denomLeft
= mpGraph
->Add( SmCaretPos( pDenom
, 0 ), left
);
1164 mpRightMost
= denomLeft
;
1165 pDenom
->Accept( this );
1166 mpRightMost
->SetRight( right
);
1168 //Set return parameter
1169 mpRightMost
= right
;
1172 /** Build SmCaretPosGraph for SmVerticalBraceNode
1174 * Lines in an SmVerticalBraceNode:
1183 void SmCaretPosGraphBuildingVisitor::Visit( SmVerticalBraceNode
* pNode
)
1185 SmNode
*pBody
= pNode
->GetSubNode( 0 ),
1186 *pScript
= pNode
->GetSubNode( 2 );
1187 //None of these children can be NULL
1189 SmCaretPosGraphEntry
*left
,
1197 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1200 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1201 left
->SetRight( bodyLeft
);
1202 mpRightMost
= bodyLeft
;
1203 pBody
->Accept( this );
1204 mpRightMost
->SetRight( right
);
1205 right
->SetLeft( mpRightMost
);
1208 scriptLeft
= mpGraph
->Add( SmCaretPos( pScript
, 0 ), left
);
1209 mpRightMost
= scriptLeft
;
1210 pScript
->Accept( this );
1211 mpRightMost
->SetRight( right
);
1214 mpRightMost
= right
;
1217 /** Build SmCaretPosGraph for SmBinDiagonalNode
1219 * Lines in an SmBinDiagonalNode:
1225 * Where A and B are lines.
1227 * Used in formulas such as "A wideslash B"
1229 void SmCaretPosGraphBuildingVisitor::Visit( SmBinDiagonalNode
* pNode
)
1231 SmNode
*A
= pNode
->GetSubNode( 0 ),
1232 *B
= pNode
->GetSubNode( 1 );
1234 SmCaretPosGraphEntry
*left
,
1242 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1245 leftA
= mpGraph
->Add( SmCaretPos( A
, 0 ), left
);
1246 left
->SetRight( leftA
);
1249 mpRightMost
= leftA
;
1251 rightA
= mpRightMost
;
1254 leftB
= mpGraph
->Add( SmCaretPos( B
, 0 ), rightA
);
1255 rightA
->SetRight( leftB
);
1258 mpRightMost
= leftB
;
1260 mpRightMost
->SetRight( right
);
1261 right
->SetLeft( mpRightMost
);
1264 mpRightMost
= right
;
1267 //Straigt forward ( I think )
1268 void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode
* pNode
)
1270 SmNodeIterator
it( pNode
);
1274 void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode
* pNode
)
1276 // Unary operator node
1277 SmNodeIterator
it( pNode
);
1283 void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode
* pNode
)
1285 SmNodeIterator
it( pNode
);
1290 void SmCaretPosGraphBuildingVisitor::Visit( SmFontNode
* pNode
)
1292 //Has only got one child, should act as an expression if possible
1293 SmNodeIterator
it( pNode
);
1298 /** Build SmCaretPosGraph for SmBracebodyNode
1299 * Acts as an SmExpressionNode
1301 * Below is an example of a formula tree that has multiple children for SmBracebodyNode
1305 * label= "Equation: \"lbrace i mline i in setZ rbrace\"";
1306 * n0 [label="SmTableNode"];
1307 * n0 -> n1 [label="0"];
1308 * n1 [label="SmLineNode"];
1309 * n1 -> n2 [label="0"];
1310 * n2 [label="SmExpressionNode"];
1311 * n2 -> n3 [label="0"];
1312 * n3 [label="SmBraceNode"];
1313 * n3 -> n4 [label="0"];
1314 * n4 [label="SmMathSymbolNode: {"];
1315 * n3 -> n5 [label="1"];
1316 * n5 [label="SmBracebodyNode"];
1317 * n5 -> n6 [label="0"];
1318 * n6 [label="SmExpressionNode"];
1319 * n6 -> n7 [label="0"];
1320 * n7 [label="SmTextNode: i"];
1321 * n5 -> n8 [label="1"];
1322 * n8 [label="SmMathSymbolNode: ∣"];
1323 * n5 -> n9 [label="2"];
1324 * n9 [label="SmExpressionNode"];
1325 * n9 -> n10 [label="0"];
1326 * n10 [label="SmBinHorNode"];
1327 * n10 -> n11 [label="0"];
1328 * n11 [label="SmTextNode: i"];
1329 * n10 -> n12 [label="1"];
1330 * n12 [label="SmMathSymbolNode: ∈"];
1331 * n10 -> n13 [label="2"];
1332 * n13 [label="SmMathSymbolNode: ℤ"];
1333 * n3 -> n14 [label="2"];
1334 * n14 [label="SmMathSymbolNode: }"];
1338 void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode
* pNode
)
1340 SmNodeIterator
it( pNode
);
1341 while( it
.Next( ) ) {
1342 SmCaretPosGraphEntry
* pStart
= mpGraph
->Add( SmCaretPos( it
.Current(), 0), mpRightMost
);
1343 mpRightMost
->SetRight( pStart
);
1344 mpRightMost
= pStart
;
1349 /** Build SmCaretPosGraph for SmAlignNode
1350 * Acts as an SmExpressionNode, as it only has one child this okay
1352 void SmCaretPosGraphBuildingVisitor::Visit( SmAlignNode
* pNode
)
1354 SmNodeIterator
it( pNode
);
1359 /** Build SmCaretPosGraph for SmRootNode
1361 * Lines in an SmRootNode:
1368 * A: pExtra ( optional, can be NULL ),
1371 * Graph over these, where "left" is before the SmRootNode and "right" is after:
1380 void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode
* pNode
)
1382 SmNode
*pExtra
= pNode
->GetSubNode( 0 ), //Argument, NULL for sqrt, and SmTextNode if cubicroot
1383 *pBody
= pNode
->GetSubNode( 2 ); //Body of the root
1384 SAL_WARN_IF( !pBody
, "starmath", "pBody cannot be NULL" );
1386 SmCaretPosGraphEntry
*left
,
1391 //Get left and save it
1392 SAL_WARN_IF( !mpRightMost
, "starmath", "There must be a position in front of this" );
1396 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1397 left
->SetRight( bodyLeft
);
1400 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1403 mpRightMost
= bodyLeft
;
1404 pBody
->Accept( this );
1405 bodyRight
= mpRightMost
;
1406 bodyRight
->SetRight( right
);
1407 right
->SetLeft( bodyRight
);
1411 mpRightMost
= mpGraph
->Add( SmCaretPos( pExtra
, 0 ), left
);
1412 pExtra
->Accept( this );
1413 mpRightMost
->SetRight( bodyLeft
);
1416 mpRightMost
= right
;
1420 void SmCaretPosGraphBuildingVisitor::Visit( SmDynIntegralNode
* pNode
)
1422 //! To be changed: Integrals don't have args.
1423 SmNode
*pBody
= pNode
->Body(); //Body of the root
1424 SAL_WARN_IF( !pBody
, "starmath", "pBody cannot be NULL" );
1426 SmCaretPosGraphEntry
*left
,
1431 //Get left and save it
1432 SAL_WARN_IF( !mpRightMost
, "starmath", "There must be a position in front of this" );
1436 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1437 left
->SetRight( bodyLeft
);
1440 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1443 mpRightMost
= bodyLeft
;
1444 pBody
->Accept( this );
1445 bodyRight
= mpRightMost
;
1446 bodyRight
->SetRight( right
);
1447 right
->SetLeft( bodyRight
);
1449 mpRightMost
= right
;
1453 /** Build SmCaretPosGraph for SmPlaceNode
1454 * Consider this a single character.
1456 void SmCaretPosGraphBuildingVisitor::Visit( SmPlaceNode
* pNode
)
1458 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1459 mpRightMost
->SetRight( right
);
1460 mpRightMost
= right
;
1463 /** SmErrorNode is context dependent metadata, it can't be selected
1465 * @remarks There's no point in deleting, copying and/or moving an instance
1466 * of SmErrorNode as it may not exist in an other context! Thus there are no
1467 * positions to select an SmErrorNode.
1469 void SmCaretPosGraphBuildingVisitor::Visit( SmErrorNode
* )
1473 /** Build SmCaretPosGraph for SmBlankNode
1474 * Consider this a single character, as it is only a blank space
1476 void SmCaretPosGraphBuildingVisitor::Visit( SmBlankNode
* pNode
)
1478 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1479 mpRightMost
->SetRight( right
);
1480 mpRightMost
= right
;
1483 /** Build SmCaretPosGraph for SmBraceNode
1485 * Lines in an SmBraceNode:
1493 * Graph over these, where "left" is before the SmBraceNode and "right" is after:
1501 void SmCaretPosGraphBuildingVisitor::Visit( SmBraceNode
* pNode
)
1503 SmNode
* pBody
= pNode
->GetSubNode( 1 );
1505 SmCaretPosGraphEntry
*left
= mpRightMost
,
1506 *right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1508 if( pBody
->GetType() != NBRACEBODY
) {
1509 mpRightMost
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1510 left
->SetRight( mpRightMost
);
1514 pBody
->Accept( this );
1515 mpRightMost
->SetRight( right
);
1516 right
->SetLeft( mpRightMost
);
1518 mpRightMost
= right
;
1521 /** Build SmCaretPosGraph for SmAttributNode
1523 * Lines in an SmAttributNode:
1529 * There's a body and an attribute, the construction is used for "widehat A", where "A" is the body
1530 * and "^" is the attribute ( note GetScaleMode( ) on SmAttributNode tells how the attribute should be
1533 void SmCaretPosGraphBuildingVisitor::Visit( SmAttributNode
* pNode
)
1535 SmNode
*pAttr
= pNode
->GetSubNode( 0 ),
1536 *pBody
= pNode
->GetSubNode( 1 );
1537 //None of the children can be NULL
1539 SmCaretPosGraphEntry
*left
= mpRightMost
,
1546 bodyLeft
= mpGraph
->Add( SmCaretPos( pBody
, 0 ), left
);
1547 left
->SetRight( bodyLeft
);
1550 right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ) );
1553 mpRightMost
= bodyLeft
;
1554 pBody
->Accept( this );
1555 bodyRight
= mpRightMost
;
1556 bodyRight
->SetRight( right
);
1557 right
->SetLeft( bodyRight
);
1560 attrLeft
= mpGraph
->Add( SmCaretPos( pAttr
, 0 ), left
);
1563 mpRightMost
= attrLeft
;
1564 pAttr
->Accept( this );
1565 mpRightMost
->SetRight( right
);
1568 mpRightMost
= right
;
1571 //Consider these single symboles
1572 void SmCaretPosGraphBuildingVisitor::Visit( SmSpecialNode
* pNode
)
1574 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1575 mpRightMost
->SetRight( right
);
1576 mpRightMost
= right
;
1578 void SmCaretPosGraphBuildingVisitor::Visit( SmGlyphSpecialNode
* pNode
)
1580 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1581 mpRightMost
->SetRight( right
);
1582 mpRightMost
= right
;
1584 void SmCaretPosGraphBuildingVisitor::Visit( SmMathSymbolNode
* pNode
)
1586 SmCaretPosGraphEntry
* right
= mpGraph
->Add( SmCaretPos( pNode
, 1 ), mpRightMost
);
1587 mpRightMost
->SetRight( right
);
1588 mpRightMost
= right
;
1591 void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode
* )
1596 void SmCaretPosGraphBuildingVisitor::Visit( SmDynIntegralSymbolNode
* )
1602 void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode
* )
1606 void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode
* )
1613 SmNode
* SmCloningVisitor::Clone( SmNode
* pNode
)
1615 SmNode
* pCurrResult
= pResult
;
1616 pNode
->Accept( this );
1617 SmNode
* pClone
= pResult
;
1618 pResult
= pCurrResult
;
1622 void SmCloningVisitor::CloneNodeAttr( SmNode
* pSource
, SmNode
* pTarget
)
1624 pTarget
->SetScaleMode( pSource
->GetScaleMode( ) );
1625 //Other attributes are set when prepare or arrange is executed
1626 //and may depend on stuff not being cloned here.
1629 void SmCloningVisitor::CloneKids( SmStructureNode
* pSource
, SmStructureNode
* pTarget
)
1631 //Cache current result
1632 SmNode
* pCurrResult
= pResult
;
1634 //Create array for holding clones
1635 sal_uInt16 nSize
= pSource
->GetNumSubNodes( );
1636 SmNodeArray
aNodes( nSize
);
1639 for( sal_uInt16 i
= 0; i
< nSize
; i
++ ){
1641 if( NULL
!= ( pKid
= pSource
->GetSubNode( i
) ) )
1642 pKid
->Accept( this );
1645 aNodes
[i
] = pResult
;
1648 //Set subnodes of pTarget
1649 pTarget
->SetSubNodes( aNodes
);
1651 //Restore result as where prior to call
1652 pResult
= pCurrResult
;
1655 void SmCloningVisitor::Visit( SmTableNode
* pNode
)
1657 SmTableNode
* pClone
= new SmTableNode( pNode
->GetToken( ) );
1658 CloneNodeAttr( pNode
, pClone
);
1659 CloneKids( pNode
, pClone
);
1663 void SmCloningVisitor::Visit( SmBraceNode
* pNode
)
1665 SmBraceNode
* pClone
= new SmBraceNode( pNode
->GetToken( ) );
1666 CloneNodeAttr( pNode
, pClone
);
1667 CloneKids( pNode
, pClone
);
1671 void SmCloningVisitor::Visit( SmBracebodyNode
* pNode
)
1673 SmBracebodyNode
* pClone
= new SmBracebodyNode( pNode
->GetToken( ) );
1674 CloneNodeAttr( pNode
, pClone
);
1675 CloneKids( pNode
, pClone
);
1679 void SmCloningVisitor::Visit( SmOperNode
* pNode
)
1681 SmOperNode
* pClone
= new SmOperNode( pNode
->GetToken( ) );
1682 CloneNodeAttr( pNode
, pClone
);
1683 CloneKids( pNode
, pClone
);
1687 void SmCloningVisitor::Visit( SmAlignNode
* pNode
)
1689 SmAlignNode
* pClone
= new SmAlignNode( pNode
->GetToken( ) );
1690 CloneNodeAttr( pNode
, pClone
);
1691 CloneKids( pNode
, pClone
);
1695 void SmCloningVisitor::Visit( SmAttributNode
* pNode
)
1697 SmAttributNode
* pClone
= new SmAttributNode( pNode
->GetToken( ) );
1698 CloneNodeAttr( pNode
, pClone
);
1699 CloneKids( pNode
, pClone
);
1703 void SmCloningVisitor::Visit( SmFontNode
* pNode
)
1705 SmFontNode
* pClone
= new SmFontNode( pNode
->GetToken( ) );
1706 pClone
->SetSizeParameter( pNode
->GetSizeParameter( ), pNode
->GetSizeType( ) );
1707 CloneNodeAttr( pNode
, pClone
);
1708 CloneKids( pNode
, pClone
);
1712 void SmCloningVisitor::Visit( SmUnHorNode
* pNode
)
1714 SmUnHorNode
* pClone
= new SmUnHorNode( pNode
->GetToken( ) );
1715 CloneNodeAttr( pNode
, pClone
);
1716 CloneKids( pNode
, pClone
);
1720 void SmCloningVisitor::Visit( SmBinHorNode
* pNode
)
1722 SmBinHorNode
* pClone
= new SmBinHorNode( pNode
->GetToken( ) );
1723 CloneNodeAttr( pNode
, pClone
);
1724 CloneKids( pNode
, pClone
);
1728 void SmCloningVisitor::Visit( SmBinVerNode
* pNode
)
1730 SmBinVerNode
* pClone
= new SmBinVerNode( pNode
->GetToken( ) );
1731 CloneNodeAttr( pNode
, pClone
);
1732 CloneKids( pNode
, pClone
);
1736 void SmCloningVisitor::Visit( SmBinDiagonalNode
* pNode
)
1738 SmBinDiagonalNode
*pClone
= new SmBinDiagonalNode( pNode
->GetToken( ) );
1739 pClone
->SetAscending( pNode
->IsAscending( ) );
1740 CloneNodeAttr( pNode
, pClone
);
1741 CloneKids( pNode
, pClone
);
1745 void SmCloningVisitor::Visit( SmSubSupNode
* pNode
)
1747 SmSubSupNode
*pClone
= new SmSubSupNode( pNode
->GetToken( ) );
1748 pClone
->SetUseLimits( pNode
->IsUseLimits( ) );
1749 CloneNodeAttr( pNode
, pClone
);
1750 CloneKids( pNode
, pClone
);
1754 void SmCloningVisitor::Visit( SmMatrixNode
* pNode
)
1756 SmMatrixNode
*pClone
= new SmMatrixNode( pNode
->GetToken( ) );
1757 pClone
->SetRowCol( pNode
->GetNumRows( ), pNode
->GetNumCols( ) );
1758 CloneNodeAttr( pNode
, pClone
);
1759 CloneKids( pNode
, pClone
);
1763 void SmCloningVisitor::Visit( SmPlaceNode
* pNode
)
1765 pResult
= new SmPlaceNode( pNode
->GetToken( ) );
1766 CloneNodeAttr( pNode
, pResult
);
1769 void SmCloningVisitor::Visit( SmTextNode
* pNode
)
1771 SmTextNode
* pClone
= new SmTextNode( pNode
->GetToken( ), pNode
->GetFontDesc( ) );
1772 pClone
->ChangeText( pNode
->GetText( ) );
1773 CloneNodeAttr( pNode
, pClone
);
1777 void SmCloningVisitor::Visit( SmSpecialNode
* pNode
)
1779 pResult
= new SmSpecialNode( pNode
->GetToken( ) );
1780 CloneNodeAttr( pNode
, pResult
);
1783 void SmCloningVisitor::Visit( SmGlyphSpecialNode
* pNode
)
1785 pResult
= new SmGlyphSpecialNode( pNode
->GetToken( ) );
1786 CloneNodeAttr( pNode
, pResult
);
1789 void SmCloningVisitor::Visit( SmMathSymbolNode
* pNode
)
1791 pResult
= new SmMathSymbolNode( pNode
->GetToken( ) );
1792 CloneNodeAttr( pNode
, pResult
);
1795 void SmCloningVisitor::Visit( SmBlankNode
* pNode
)
1797 SmBlankNode
* pClone
= new SmBlankNode( pNode
->GetToken( ) );
1798 pClone
->SetBlankNum( pNode
->GetBlankNum( ) );
1800 CloneNodeAttr( pNode
, pResult
);
1803 void SmCloningVisitor::Visit( SmErrorNode
* pNode
)
1805 //PE_NONE is used the information have been discarded and isn't used
1806 pResult
= new SmErrorNode( PE_NONE
, pNode
->GetToken( ) );
1807 CloneNodeAttr( pNode
, pResult
);
1810 void SmCloningVisitor::Visit( SmLineNode
* pNode
)
1812 SmLineNode
* pClone
= new SmLineNode( pNode
->GetToken( ) );
1813 CloneNodeAttr( pNode
, pClone
);
1814 CloneKids( pNode
, pClone
);
1818 void SmCloningVisitor::Visit( SmExpressionNode
* pNode
)
1820 SmExpressionNode
* pClone
= new SmExpressionNode( pNode
->GetToken( ) );
1821 CloneNodeAttr( pNode
, pClone
);
1822 CloneKids( pNode
, pClone
);
1826 void SmCloningVisitor::Visit( SmPolyLineNode
* pNode
)
1828 pResult
= new SmPolyLineNode( pNode
->GetToken( ) );
1829 CloneNodeAttr( pNode
, pResult
);
1832 void SmCloningVisitor::Visit( SmRootNode
* pNode
)
1834 SmRootNode
* pClone
= new SmRootNode( pNode
->GetToken( ) );
1835 CloneNodeAttr( pNode
, pClone
);
1836 CloneKids( pNode
, pClone
);
1840 void SmCloningVisitor::Visit( SmRootSymbolNode
* pNode
)
1842 pResult
= new SmRootSymbolNode( pNode
->GetToken( ) );
1843 CloneNodeAttr( pNode
, pResult
);
1846 void SmCloningVisitor::Visit( SmDynIntegralNode
* pNode
)
1848 SmDynIntegralNode
* pClone
= new SmDynIntegralNode( pNode
->GetToken( ) );
1849 CloneNodeAttr( pNode
, pClone
);
1850 CloneKids( pNode
, pClone
);
1854 void SmCloningVisitor::Visit( SmDynIntegralSymbolNode
* pNode
)
1856 pResult
= new SmDynIntegralSymbolNode( pNode
->GetToken( ) );
1857 CloneNodeAttr( pNode
, pResult
);
1860 void SmCloningVisitor::Visit( SmRectangleNode
* pNode
)
1862 pResult
= new SmRectangleNode( pNode
->GetToken( ) );
1863 CloneNodeAttr( pNode
, pResult
);
1866 void SmCloningVisitor::Visit( SmVerticalBraceNode
* pNode
)
1868 SmVerticalBraceNode
* pClone
= new SmVerticalBraceNode( pNode
->GetToken( ) );
1869 CloneNodeAttr( pNode
, pClone
);
1870 CloneKids( pNode
, pClone
);
1874 // SmSelectionDrawingVisitor
1876 SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice
& rDevice
, SmNode
* pTree
, Point Offset
)
1878 bHasSelectionArea
= false;
1881 SAL_WARN_IF( !pTree
, "starmath", "pTree can't be null!" );
1883 pTree
->Accept( this );
1885 //Draw selection if there's any
1886 if( bHasSelectionArea
){
1887 aSelectionArea
.Move( Offset
.X( ), Offset
.Y( ) );
1890 rDev
.Push( PushFlags::LINECOLOR
| PushFlags::FILLCOLOR
);
1892 rDev
.SetLineColor( );
1893 rDev
.SetFillColor( Color( COL_LIGHTGRAY
) );
1896 rDev
.DrawRect( aSelectionArea
);
1898 //Restore device state
1903 void SmSelectionDrawingVisitor::ExtendSelectionArea(const Rectangle
& rArea
)
1905 if ( ! bHasSelectionArea
) {
1906 aSelectionArea
= rArea
;
1907 bHasSelectionArea
= true;
1909 aSelectionArea
.Union(rArea
);
1912 void SmSelectionDrawingVisitor::DefaultVisit( SmNode
* pNode
)
1914 if( pNode
->IsSelected( ) )
1915 ExtendSelectionArea( pNode
->AsRectangle( ) );
1916 VisitChildren( pNode
);
1919 void SmSelectionDrawingVisitor::VisitChildren( SmNode
* pNode
)
1921 SmNodeIterator
it( pNode
);
1926 void SmSelectionDrawingVisitor::Visit( SmTextNode
* pNode
)
1928 if( pNode
->IsSelected( ) ){
1929 rDev
.Push( PushFlags::TEXTCOLOR
| PushFlags::FONT
);
1931 rDev
.SetFont( pNode
->GetFont( ) );
1932 Point Position
= pNode
->GetTopLeft( );
1933 long left
= Position
.getX( ) + rDev
.GetTextWidth( pNode
->GetText( ), 0, pNode
->GetSelectionStart( ) );
1934 long right
= Position
.getX( ) + rDev
.GetTextWidth( pNode
->GetText( ), 0, pNode
->GetSelectionEnd( ) );
1935 long top
= Position
.getY( );
1936 long bottom
= top
+ pNode
->GetHeight( );
1937 Rectangle
rect( left
, top
, right
, bottom
);
1939 ExtendSelectionArea( rect
);
1945 // SmNodeToTextVisitor
1947 SmNodeToTextVisitor::SmNodeToTextVisitor( SmNode
* pNode
, OUString
&rText
)
1949 pNode
->Accept( this );
1950 rText
= aCmdText
.makeStringAndClear();
1953 void SmNodeToTextVisitor::Visit( SmTableNode
* pNode
)
1955 if( pNode
->GetToken( ).eType
== TBINOM
) {
1956 Append( "{ binom" );
1957 LineToText( pNode
->GetSubNode( 0 ) );
1958 LineToText( pNode
->GetSubNode( 1 ) );
1960 } else if( pNode
->GetToken( ).eType
== TSTACK
) {
1961 Append( "stack{ " );
1962 SmNodeIterator
it( pNode
);
1965 LineToText( it
.Current( ) );
1974 } else { //Assume it's a toplevel table, containing lines
1975 SmNodeIterator
it( pNode
);
1982 Append( "newline" );
1989 void SmNodeToTextVisitor::Visit( SmBraceNode
* pNode
)
1991 SmNode
*pLeftBrace
= pNode
->GetSubNode( 0 ),
1992 *pBody
= pNode
->GetSubNode( 1 ),
1993 *pRightBrace
= pNode
->GetSubNode( 2 );
1994 //Handle special case where it's absolute function
1995 if( pNode
->GetToken( ).eType
== TABS
) {
1997 LineToText( pBody
);
1999 if( pNode
->GetScaleMode( ) == SCALE_HEIGHT
)
2001 pLeftBrace
->Accept( this );
2003 pBody
->Accept( this );
2005 if( pNode
->GetScaleMode( ) == SCALE_HEIGHT
)
2007 pRightBrace
->Accept( this );
2011 void SmNodeToTextVisitor::Visit( SmBracebodyNode
* pNode
)
2013 SmNodeIterator
it( pNode
);
2014 while( it
.Next( ) ){
2020 void SmNodeToTextVisitor::Visit( SmOperNode
* pNode
)
2022 Append( pNode
->GetToken( ).aText
);
2024 if( pNode
->GetToken( ).eType
== TOPER
){
2025 //There's an SmGlyphSpecialNode if eType == TOPER
2026 if( pNode
->GetSubNode( 0 )->GetType( ) == NSUBSUP
)
2027 Append( pNode
->GetSubNode( 0 )->GetSubNode( 0 )->GetToken( ).aText
);
2029 Append( pNode
->GetSubNode( 0 )->GetToken( ).aText
);
2031 if( pNode
->GetSubNode( 0 )->GetType( ) == NSUBSUP
) {
2032 SmSubSupNode
*pSubSup
= static_cast<SmSubSupNode
*>( pNode
->GetSubNode( 0 ) );
2034 if( ( pChild
= pSubSup
->GetSubSup( LSUP
) ) ) {
2036 Append( "lsup { " );
2037 LineToText( pChild
);
2040 if( ( pChild
= pSubSup
->GetSubSup( LSUB
) ) ) {
2042 Append( "lsub { " );
2043 LineToText( pChild
);
2046 if( ( pChild
= pSubSup
->GetSubSup( RSUP
) ) ) {
2049 LineToText( pChild
);
2052 if( ( pChild
= pSubSup
->GetSubSup( RSUB
) ) ) {
2055 LineToText( pChild
);
2058 if( ( pChild
= pSubSup
->GetSubSup( CSUP
) ) ) {
2060 if (pSubSup
->IsUseLimits())
2063 Append( "csup { " );
2064 LineToText( pChild
);
2067 if( ( pChild
= pSubSup
->GetSubSup( CSUB
) ) ) {
2069 if (pSubSup
->IsUseLimits())
2070 Append( "from { " );
2072 Append( "csub { " );
2073 LineToText( pChild
);
2077 LineToText( pNode
->GetSubNode( 1 ) );
2080 void SmNodeToTextVisitor::Visit( SmAlignNode
* pNode
)
2082 Append( pNode
->GetToken( ).aText
);
2083 LineToText( pNode
->GetSubNode( 0 ) );
2086 void SmNodeToTextVisitor::Visit( SmAttributNode
* pNode
)
2088 Append( pNode
->GetToken( ).aText
);
2089 LineToText( pNode
->GetSubNode( 1 ) );
2092 void SmNodeToTextVisitor::Visit( SmFontNode
* pNode
)
2094 switch ( pNode
->GetToken( ).eType
)
2103 Append( "italic " );
2106 Append( "nitalic " );
2109 Append( "phantom " );
2114 switch ( pNode
->GetSizeType( ) )
2116 case FontSizeType::PLUS
:
2119 case FontSizeType::MINUS
:
2122 case FontSizeType::MULTIPLY
:
2125 case FontSizeType::DIVIDE
:
2128 case FontSizeType::ABSOLUT
:
2132 Append( ::rtl::math::doubleToUString(
2133 static_cast<double>( pNode
->GetSizeParameter( ) ),
2134 rtl_math_StringFormat_Automatic
,
2135 rtl_math_DecimalPlaces_Max
, '.', true ) );
2140 Append( "color black " );
2143 Append( "color white " );
2146 Append( "color red " );
2149 Append( "color green " );
2152 Append( "color blue " );
2155 Append( "color cyan " );
2158 Append( "color magenta " );
2161 Append( "color yellow " );
2164 Append( "font sans " );
2167 Append( "font serif " );
2170 Append( "font fixed " );
2175 LineToText( pNode
->GetSubNode( 1 ) );
2178 void SmNodeToTextVisitor::Visit( SmUnHorNode
* pNode
)
2180 SmNodeIterator
it( pNode
, pNode
->GetSubNode( 1 )->GetToken( ).eType
== TFACT
);
2181 while( it
.Next( ) ) {
2187 void SmNodeToTextVisitor::Visit( SmBinHorNode
* pNode
)
2189 SmNode
*pLeft
= pNode
->GetSubNode( 0 ),
2190 *pOper
= pNode
->GetSubNode( 1 ),
2191 *pRight
= pNode
->GetSubNode( 2 );
2193 pLeft
->Accept( this );
2195 pOper
->Accept( this );
2197 pRight
->Accept( this );
2201 void SmNodeToTextVisitor::Visit( SmBinVerNode
* pNode
)
2203 SmNode
*pNum
= pNode
->GetSubNode( 0 ),
2204 *pDenom
= pNode
->GetSubNode( 2 );
2208 LineToText( pDenom
);
2212 void SmNodeToTextVisitor::Visit( SmBinDiagonalNode
* pNode
)
2214 SmNode
*pLeftOperand
= pNode
->GetSubNode( 0 ),
2215 *pRightOperand
= pNode
->GetSubNode( 1 );
2217 LineToText( pLeftOperand
);
2219 Append( "wideslash " );
2220 LineToText( pRightOperand
);
2224 void SmNodeToTextVisitor::Visit( SmSubSupNode
* pNode
)
2226 LineToText( pNode
->GetBody( ) );
2228 if( ( pChild
= pNode
->GetSubSup( LSUP
) ) ) {
2231 LineToText( pChild
);
2233 if( ( pChild
= pNode
->GetSubSup( LSUB
) ) ) {
2236 LineToText( pChild
);
2238 if( ( pChild
= pNode
->GetSubSup( RSUP
) ) ) {
2241 LineToText( pChild
);
2243 if( ( pChild
= pNode
->GetSubSup( RSUB
) ) ) {
2246 LineToText( pChild
);
2248 if( ( pChild
= pNode
->GetSubSup( CSUP
) ) ) {
2250 if (pNode
->IsUseLimits())
2254 LineToText( pChild
);
2256 if( ( pChild
= pNode
->GetSubSup( CSUB
) ) ) {
2258 if (pNode
->IsUseLimits())
2262 LineToText( pChild
);
2266 void SmNodeToTextVisitor::Visit( SmMatrixNode
* pNode
)
2268 Append( "matrix{" );
2269 for ( sal_uInt16 i
= 0; i
< pNode
->GetNumRows( ); i
++ ) {
2270 for ( sal_uInt16 j
= 0; j
< pNode
->GetNumCols( ); j
++ ) {
2271 SmNode
* pSubNode
= pNode
->GetSubNode( i
* pNode
->GetNumCols( ) + j
);
2273 pSubNode
->Accept( this );
2275 if( j
!= pNode
->GetNumCols( ) - 1 )
2279 if( i
!= pNode
->GetNumRows( ) - 1 )
2285 void SmNodeToTextVisitor::Visit( SmPlaceNode
* )
2290 void SmNodeToTextVisitor::Visit( SmTextNode
* pNode
)
2292 //TODO: This method might need improvements, see SmTextNode::CreateTextFromNode
2293 if( pNode
->GetToken( ).eType
== TTEXT
)
2295 Append( pNode
->GetText( ) );
2296 if( pNode
->GetToken( ).eType
== TTEXT
)
2300 void SmNodeToTextVisitor::Visit( SmSpecialNode
* pNode
)
2302 Append( pNode
->GetToken( ).aText
);
2305 void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode
* pNode
)
2307 if( pNode
->GetToken( ).eType
== TBOPER
)
2311 Append( pNode
->GetToken( ).aText
);
2314 void SmNodeToTextVisitor::Visit( SmMathSymbolNode
* pNode
)
2316 Append( pNode
->GetToken( ).aText
);
2319 void SmNodeToTextVisitor::Visit( SmBlankNode
* pNode
)
2321 Append( pNode
->GetToken( ).aText
);
2324 void SmNodeToTextVisitor::Visit( SmErrorNode
* )
2328 void SmNodeToTextVisitor::Visit( SmLineNode
* pNode
)
2330 SmNodeIterator
it( pNode
);
2331 while( it
.Next( ) ){
2337 void SmNodeToTextVisitor::Visit( SmExpressionNode
* pNode
)
2339 bool bracketsNeeded
= pNode
->GetNumSubNodes() != 1 || pNode
->GetSubNode(0)->GetType() == NBINHOR
;
2340 if (!bracketsNeeded
)
2342 const SmNode
*pParent
= pNode
->GetParent();
2345 pParent
&& pParent
->GetType() == NSUBSUP
&&
2346 pNode
->GetNumSubNodes() == 1 &&
2347 pNode
->GetSubNode(0)->GetType() == NSUBSUP
;
2350 if (bracketsNeeded
) {
2353 SmNodeIterator
it( pNode
);
2354 while( it
.Next( ) ) {
2358 if (bracketsNeeded
) {
2363 void SmNodeToTextVisitor::Visit( SmPolyLineNode
* )
2367 void SmNodeToTextVisitor::Visit( SmRootNode
* pNode
)
2369 SmNode
*pExtra
= pNode
->GetSubNode( 0 ),
2370 *pBody
= pNode
->GetSubNode( 2 );
2373 LineToText( pExtra
);
2376 LineToText( pBody
);
2379 void SmNodeToTextVisitor::Visit( SmRootSymbolNode
* )
2383 void SmNodeToTextVisitor::Visit( SmDynIntegralNode
* pNode
)
2385 SmNode
*pBody
= pNode
->Body();
2387 LineToText( pBody
);
2390 void SmNodeToTextVisitor::Visit( SmDynIntegralSymbolNode
* )
2394 void SmNodeToTextVisitor::Visit( SmRectangleNode
* )
2398 void SmNodeToTextVisitor::Visit( SmVerticalBraceNode
* pNode
)
2400 SmNode
*pBody
= pNode
->GetSubNode( 0 ),
2401 *pScript
= pNode
->GetSubNode( 2 );
2402 LineToText( pBody
);
2403 Append( pNode
->GetToken( ).aText
);
2404 LineToText( pScript
);
2407 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */