Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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 : */
9 :
10 : #include <tools/gen.hxx>
11 : #include <vcl/lineinfo.hxx>
12 : #include "visitors.hxx"
13 : #include "tmpdevice.hxx"
14 : #include "cursor.hxx"
15 :
16 : // SmDefaultingVisitor
17 :
18 2 : void SmDefaultingVisitor::Visit( SmTableNode* pNode )
19 : {
20 2 : DefaultVisit( pNode );
21 2 : }
22 :
23 0 : void SmDefaultingVisitor::Visit( SmBraceNode* pNode )
24 : {
25 0 : DefaultVisit( pNode );
26 0 : }
27 :
28 0 : void SmDefaultingVisitor::Visit( SmBracebodyNode* pNode )
29 : {
30 0 : DefaultVisit( pNode );
31 0 : }
32 :
33 0 : void SmDefaultingVisitor::Visit( SmOperNode* pNode )
34 : {
35 0 : DefaultVisit( pNode );
36 0 : }
37 :
38 0 : void SmDefaultingVisitor::Visit( SmAlignNode* pNode )
39 : {
40 0 : DefaultVisit( pNode );
41 0 : }
42 :
43 0 : void SmDefaultingVisitor::Visit( SmAttributNode* pNode )
44 : {
45 0 : DefaultVisit( pNode );
46 0 : }
47 :
48 0 : void SmDefaultingVisitor::Visit( SmFontNode* pNode )
49 : {
50 0 : DefaultVisit( pNode );
51 0 : }
52 :
53 0 : void SmDefaultingVisitor::Visit( SmUnHorNode* pNode )
54 : {
55 0 : DefaultVisit( pNode );
56 0 : }
57 :
58 0 : void SmDefaultingVisitor::Visit( SmBinHorNode* pNode )
59 : {
60 0 : DefaultVisit( pNode );
61 0 : }
62 :
63 9 : void SmDefaultingVisitor::Visit( SmBinVerNode* pNode )
64 : {
65 9 : DefaultVisit( pNode );
66 9 : }
67 :
68 0 : void SmDefaultingVisitor::Visit( SmBinDiagonalNode* pNode )
69 : {
70 0 : DefaultVisit( pNode );
71 0 : }
72 :
73 6 : void SmDefaultingVisitor::Visit( SmSubSupNode* pNode )
74 : {
75 6 : DefaultVisit( pNode );
76 6 : }
77 :
78 0 : void SmDefaultingVisitor::Visit( SmMatrixNode* pNode )
79 : {
80 0 : DefaultVisit( pNode );
81 0 : }
82 :
83 6 : void SmDefaultingVisitor::Visit( SmPlaceNode* pNode )
84 : {
85 6 : DefaultVisit( pNode );
86 6 : }
87 :
88 0 : void SmDefaultingVisitor::Visit( SmTextNode* pNode )
89 : {
90 0 : DefaultVisit( pNode );
91 0 : }
92 :
93 0 : void SmDefaultingVisitor::Visit( SmSpecialNode* pNode )
94 : {
95 0 : DefaultVisit( pNode );
96 0 : }
97 :
98 0 : void SmDefaultingVisitor::Visit( SmGlyphSpecialNode* pNode )
99 : {
100 0 : DefaultVisit( pNode );
101 0 : }
102 :
103 23 : void SmDefaultingVisitor::Visit( SmMathSymbolNode* pNode )
104 : {
105 23 : DefaultVisit( pNode );
106 23 : }
107 :
108 0 : void SmDefaultingVisitor::Visit( SmBlankNode* pNode )
109 : {
110 0 : DefaultVisit( pNode );
111 0 : }
112 :
113 4 : void SmDefaultingVisitor::Visit( SmErrorNode* pNode )
114 : {
115 4 : DefaultVisit( pNode );
116 4 : }
117 :
118 0 : void SmDefaultingVisitor::Visit( SmLineNode* pNode )
119 : {
120 0 : DefaultVisit( pNode );
121 0 : }
122 :
123 4 : void SmDefaultingVisitor::Visit( SmExpressionNode* pNode )
124 : {
125 4 : DefaultVisit( pNode );
126 4 : }
127 :
128 0 : void SmDefaultingVisitor::Visit( SmPolyLineNode* pNode )
129 : {
130 0 : DefaultVisit( pNode );
131 0 : }
132 :
133 0 : void SmDefaultingVisitor::Visit( SmRootNode* pNode )
134 : {
135 0 : DefaultVisit( pNode );
136 0 : }
137 :
138 0 : void SmDefaultingVisitor::Visit( SmRootSymbolNode* pNode )
139 : {
140 0 : DefaultVisit( pNode );
141 0 : }
142 :
143 0 : void SmDefaultingVisitor::Visit( SmDynIntegralNode* pNode )
144 : {
145 0 : DefaultVisit( pNode );
146 0 : }
147 :
148 0 : void SmDefaultingVisitor::Visit( SmDynIntegralSymbolNode* pNode )
149 : {
150 0 : DefaultVisit( pNode );
151 0 : }
152 :
153 7 : void SmDefaultingVisitor::Visit( SmRectangleNode* pNode )
154 : {
155 7 : DefaultVisit( pNode );
156 7 : }
157 :
158 0 : void SmDefaultingVisitor::Visit( SmVerticalBraceNode* pNode )
159 : {
160 0 : DefaultVisit( pNode );
161 0 : }
162 :
163 : // SmCaretDrawingVisitor
164 :
165 0 : SmCaretDrawingVisitor::SmCaretDrawingVisitor( OutputDevice& rDevice,
166 : SmCaretPos position,
167 : Point offset,
168 : bool caretVisible )
169 0 : : rDev( rDevice )
170 : {
171 0 : pos = position;
172 0 : Offset = offset;
173 0 : isCaretVisible = caretVisible;
174 : SAL_WARN_IF( !position.IsValid(), "starmath", "Cannot draw invalid position!" );
175 0 : if( !position.IsValid( ) )
176 0 : return;
177 :
178 : //Save device state
179 0 : rDev.Push( PushFlags::FONT | PushFlags::MAPMODE | PushFlags::LINECOLOR | PushFlags::FILLCOLOR | PushFlags::TEXTCOLOR );
180 :
181 0 : pos.pSelectedNode->Accept( this );
182 : //Restore device state
183 0 : rDev.Pop( );
184 : }
185 :
186 0 : void SmCaretDrawingVisitor::Visit( SmTextNode* pNode )
187 : {
188 0 : long i = pos.Index;
189 :
190 0 : rDev.SetFont( pNode->GetFont( ) );
191 :
192 : //Find the line
193 0 : SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
194 :
195 : //Find coordinates
196 0 : long left = pNode->GetLeft( ) + rDev.GetTextWidth( pNode->GetText( ), 0, i ) + Offset.X( );
197 0 : long top = pLine->GetTop( ) + Offset.Y( );
198 0 : long height = pLine->GetHeight( );
199 0 : long left_line = pLine->GetLeft( ) + Offset.X( );
200 0 : long right_line = pLine->GetRight( ) + Offset.X( );
201 :
202 : //Set color
203 0 : rDev.SetLineColor( Color( COL_BLACK ) );
204 :
205 0 : if ( isCaretVisible ) {
206 : //Draw vertical line
207 0 : Point p1( left, top );
208 0 : Point p2( left, top + height );
209 0 : rDev.DrawLine( p1, p2 );
210 : }
211 :
212 : //Underline the line
213 0 : Point pLeft( left_line, top + height );
214 0 : Point pRight( right_line, top + height );
215 0 : rDev.DrawLine( pLeft, pRight );
216 0 : }
217 :
218 0 : void SmCaretDrawingVisitor::DefaultVisit( SmNode* pNode )
219 : {
220 0 : rDev.SetLineColor( Color( COL_BLACK ) );
221 :
222 : //Find the line
223 0 : SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
224 :
225 : //Find coordinates
226 0 : long left = pNode->GetLeft( ) + Offset.X( ) + ( pos.Index == 1 ? pNode->GetWidth( ) : 0 );
227 0 : long top = pLine->GetTop( ) + Offset.Y( );
228 0 : long height = pLine->GetHeight( );
229 0 : long left_line = pLine->GetLeft( ) + Offset.X( );
230 0 : long right_line = pLine->GetRight( ) + Offset.X( );
231 :
232 : //Set color
233 0 : rDev.SetLineColor( Color( COL_BLACK ) );
234 :
235 0 : if ( isCaretVisible ) {
236 : //Draw vertical line
237 0 : Point p1( left, top );
238 0 : Point p2( left, top + height );
239 0 : rDev.DrawLine( p1, p2 );
240 : }
241 :
242 : //Underline the line
243 0 : Point pLeft( left_line, top + height );
244 0 : Point pRight( right_line, top + height );
245 0 : rDev.DrawLine( pLeft, pRight );
246 0 : }
247 :
248 : // SmCaretPos2LineVisitor
249 :
250 2 : void SmCaretPos2LineVisitor::Visit( SmTextNode* pNode )
251 : {
252 : //Save device state
253 2 : pDev->Push( PushFlags::FONT | PushFlags::TEXTCOLOR );
254 :
255 2 : long i = pos.Index;
256 :
257 2 : pDev->SetFont( pNode->GetFont( ) );
258 :
259 : //Find coordinates
260 2 : long left = pNode->GetLeft( ) + pDev->GetTextWidth( pNode->GetText( ), 0, i );
261 2 : long top = pNode->GetTop( );
262 2 : long height = pNode->GetHeight( );
263 :
264 2 : line = SmCaretLine( left, top, height );
265 :
266 : //Restore device state
267 2 : pDev->Pop( );
268 2 : }
269 :
270 12 : void SmCaretPos2LineVisitor::DefaultVisit( SmNode* pNode )
271 : {
272 : //Vertical line ( code from SmCaretDrawingVisitor )
273 12 : Point p1 = pNode->GetTopLeft( );
274 12 : if( pos.Index == 1 )
275 6 : p1.Move( pNode->GetWidth( ), 0 );
276 :
277 12 : line = SmCaretLine( p1.X( ), p1.Y( ), pNode->GetHeight( ) );
278 12 : }
279 :
280 :
281 : // SmDrawingVisitor
282 :
283 5097 : void SmDrawingVisitor::Visit( SmTableNode* pNode )
284 : {
285 5097 : DrawChildren( pNode );
286 5097 : }
287 :
288 2482 : void SmDrawingVisitor::Visit( SmBraceNode* pNode )
289 : {
290 2482 : DrawChildren( pNode );
291 2482 : }
292 :
293 2482 : void SmDrawingVisitor::Visit( SmBracebodyNode* pNode )
294 : {
295 2482 : DrawChildren( pNode );
296 2482 : }
297 :
298 906 : void SmDrawingVisitor::Visit( SmOperNode* pNode )
299 : {
300 906 : DrawChildren( pNode );
301 906 : }
302 :
303 0 : void SmDrawingVisitor::Visit( SmAlignNode* pNode )
304 : {
305 0 : DrawChildren( pNode );
306 0 : }
307 :
308 1431 : void SmDrawingVisitor::Visit( SmAttributNode* pNode )
309 : {
310 1431 : DrawChildren( pNode );
311 1431 : }
312 :
313 16 : void SmDrawingVisitor::Visit( SmFontNode* pNode )
314 : {
315 16 : DrawChildren( pNode );
316 16 : }
317 :
318 466 : void SmDrawingVisitor::Visit( SmUnHorNode* pNode )
319 : {
320 466 : DrawChildren( pNode );
321 466 : }
322 :
323 3962 : void SmDrawingVisitor::Visit( SmBinHorNode* pNode )
324 : {
325 3962 : DrawChildren( pNode );
326 3962 : }
327 :
328 1247 : void SmDrawingVisitor::Visit( SmBinVerNode* pNode )
329 : {
330 1247 : DrawChildren( pNode );
331 1247 : }
332 :
333 64 : void SmDrawingVisitor::Visit( SmBinDiagonalNode* pNode )
334 : {
335 64 : DrawChildren( pNode );
336 64 : }
337 :
338 3962 : void SmDrawingVisitor::Visit( SmSubSupNode* pNode )
339 : {
340 3962 : DrawChildren( pNode );
341 3962 : }
342 :
343 102 : void SmDrawingVisitor::Visit( SmMatrixNode* pNode )
344 : {
345 102 : DrawChildren( pNode );
346 102 : }
347 :
348 1566 : void SmDrawingVisitor::Visit( SmPlaceNode* pNode )
349 : {
350 1566 : DrawSpecialNode( pNode );
351 1566 : }
352 :
353 23065 : void SmDrawingVisitor::Visit( SmTextNode* pNode )
354 : {
355 23065 : DrawTextNode( pNode );
356 23065 : }
357 :
358 0 : void SmDrawingVisitor::Visit( SmSpecialNode* pNode )
359 : {
360 0 : DrawSpecialNode( pNode );
361 0 : }
362 :
363 0 : void SmDrawingVisitor::Visit( SmGlyphSpecialNode* pNode )
364 : {
365 0 : DrawSpecialNode( pNode );
366 0 : }
367 :
368 12152 : void SmDrawingVisitor::Visit( SmMathSymbolNode* pNode )
369 : {
370 12152 : DrawSpecialNode( pNode );
371 12152 : }
372 :
373 0 : void SmDrawingVisitor::Visit( SmBlankNode* pNode )
374 : {
375 0 : DrawChildren( pNode );
376 0 : }
377 :
378 136 : void SmDrawingVisitor::Visit( SmErrorNode* pNode )
379 : {
380 136 : DrawSpecialNode( pNode );
381 136 : }
382 :
383 4587 : void SmDrawingVisitor::Visit( SmLineNode* pNode )
384 : {
385 4587 : DrawChildren( pNode );
386 4587 : }
387 :
388 3496 : void SmDrawingVisitor::Visit( SmExpressionNode* pNode )
389 : {
390 3496 : DrawChildren( pNode );
391 3496 : }
392 :
393 442 : void SmDrawingVisitor::Visit( SmRootNode* pNode )
394 : {
395 442 : DrawChildren( pNode );
396 442 : }
397 :
398 0 : void SmDrawingVisitor::Visit(SmDynIntegralNode* pNode)
399 : {
400 0 : DrawChildren( pNode );
401 0 : }
402 :
403 204 : void SmDrawingVisitor::Visit( SmVerticalBraceNode* pNode )
404 : {
405 204 : DrawChildren( pNode );
406 204 : }
407 :
408 442 : void SmDrawingVisitor::Visit( SmRootSymbolNode* pNode )
409 : {
410 442 : if ( pNode->IsPhantom( ) )
411 442 : return;
412 :
413 : // draw root-sign itself
414 442 : DrawSpecialNode( pNode );
415 :
416 442 : SmTmpDevice aTmpDev( ( OutputDevice & ) rDev, true );
417 442 : aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
418 442 : rDev.SetLineColor( );
419 442 : aTmpDev.SetFont( pNode->GetFont( ) );
420 :
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 442 : long nBarHeight = pNode->GetWidth( ) * 7L / 100L;
426 442 : long nBarWidth = pNode->GetBodyWidth( ) + pNode->GetBorderWidth( );
427 442 : Point aBarOffset( pNode->GetWidth( ), +pNode->GetBorderWidth( ) );
428 442 : Point aBarPos( Position + aBarOffset );
429 :
430 442 : 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 442 : Point aDrawPos( rDev.PixelToLogic( rDev.LogicToPixel( aBar.TopLeft( ) ) ) );
436 442 : aBar.SetPos( aDrawPos );
437 :
438 442 : rDev.DrawRect( aBar );
439 : }
440 :
441 0 : void SmDrawingVisitor::Visit( SmDynIntegralSymbolNode* pNode )
442 : {
443 0 : if ( pNode->IsPhantom( ) )
444 0 : return;
445 :
446 : // draw integral-sign itself
447 0 : DrawSpecialNode( pNode );
448 :
449 : //! the rest of this may not be needed at all
450 :
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
455 : }
456 :
457 64 : void SmDrawingVisitor::Visit( SmPolyLineNode* pNode )
458 : {
459 64 : if ( pNode->IsPhantom( ) )
460 64 : return;
461 :
462 64 : long nBorderwidth = pNode->GetFont( ).GetBorderWidth( );
463 :
464 64 : LineInfo aInfo;
465 64 : aInfo.SetWidth( pNode->GetWidth( ) - 2 * nBorderwidth );
466 :
467 128 : Point aOffset ( Point( ) - pNode->GetPolygon( ).GetBoundRect( ).TopLeft( )
468 192 : + Point( nBorderwidth, nBorderwidth ) ),
469 64 : aPos ( Position + aOffset );
470 64 : pNode->GetPolygon( ).Move( aPos.X( ), aPos.Y( ) ); //Works because Polygon wraps a pointer
471 :
472 128 : SmTmpDevice aTmpDev ( ( OutputDevice & ) rDev, false );
473 64 : aTmpDev.SetLineColor( pNode->GetFont( ).GetColor( ) );
474 :
475 128 : rDev.DrawPolyLine( pNode->GetPolygon( ), aInfo );
476 : }
477 :
478 1451 : void SmDrawingVisitor::Visit( SmRectangleNode* pNode )
479 : {
480 1451 : if ( pNode->IsPhantom( ) )
481 1451 : return;
482 :
483 1451 : SmTmpDevice aTmpDev ( ( OutputDevice & ) rDev, false );
484 1451 : aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
485 1451 : rDev.SetLineColor( );
486 1451 : aTmpDev.SetFont( pNode->GetFont( ) );
487 :
488 1451 : sal_uLong nTmpBorderWidth = pNode->GetFont( ).GetBorderWidth( );
489 :
490 : // get rectangle and remove borderspace
491 1451 : Rectangle aTmp ( pNode->AsRectangle( ) + Position - pNode->GetTopLeft( ) );
492 1451 : aTmp.Left( ) += nTmpBorderWidth;
493 1451 : aTmp.Right( ) -= nTmpBorderWidth;
494 1451 : aTmp.Top( ) += nTmpBorderWidth;
495 1451 : aTmp.Bottom( ) -= nTmpBorderWidth;
496 :
497 : SAL_WARN_IF( aTmp.GetHeight() == 0 || aTmp.GetWidth() == 0,
498 : "starmath", "Empty rectangle" );
499 :
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 1451 : Point aPos ( rDev.PixelToLogic( rDev.LogicToPixel( aTmp.TopLeft( ) ) ) );
505 1451 : aTmp.SetPos( aPos );
506 :
507 1451 : rDev.DrawRect( aTmp );
508 : }
509 :
510 37361 : void SmDrawingVisitor::DrawTextNode( SmTextNode* pNode )
511 : {
512 37361 : if ( pNode->IsPhantom() || pNode->GetText().isEmpty() || pNode->GetText()[0] == '\0' )
513 37548 : return;
514 :
515 37174 : SmTmpDevice aTmpDev ( ( OutputDevice & ) rDev, false );
516 37174 : aTmpDev.SetFont( pNode->GetFont( ) );
517 :
518 37174 : Point aPos ( Position );
519 37174 : aPos.Y( ) += pNode->GetBaselineOffset( );
520 : // auf Pixelkoordinaten runden
521 37174 : aPos = rDev.PixelToLogic( rDev.LogicToPixel( aPos ) );
522 :
523 37174 : rDev.DrawStretchText( aPos, pNode->GetWidth( ), pNode->GetText( ) );
524 : }
525 :
526 14296 : void SmDrawingVisitor::DrawSpecialNode( SmSpecialNode* pNode )
527 : {
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 14296 : pNode->GetFont( ).SetAlign( ALIGN_BASELINE );
531 :
532 14296 : DrawTextNode( pNode );
533 14296 : }
534 :
535 30946 : void SmDrawingVisitor::DrawChildren( SmNode* pNode )
536 : {
537 30946 : if ( pNode->IsPhantom( ) )
538 30946 : return;
539 :
540 30946 : Point rPosition = Position;
541 :
542 30946 : SmNodeIterator it( pNode );
543 126519 : while( it.Next( ) )
544 : {
545 64627 : Point aOffset ( it->GetTopLeft( ) - pNode->GetTopLeft( ) );
546 64627 : Position = rPosition + aOffset;
547 64627 : it->Accept( this );
548 : }
549 : }
550 :
551 : // SmSetSelectionVisitor
552 :
553 19 : SmSetSelectionVisitor::SmSetSelectionVisitor( SmCaretPos startPos, SmCaretPos endPos, SmNode* pTree) {
554 19 : StartPos = startPos;
555 19 : EndPos = endPos;
556 19 : IsSelecting = false;
557 :
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 19 : if(pTree->GetType() == NTABLE){
562 : //Change state if StartPos is in front of this node
563 19 : if( StartPos.pSelectedNode == pTree && StartPos.Index == 0 )
564 0 : IsSelecting = !IsSelecting;
565 : //Change state if EndPos is in front of this node
566 19 : if( EndPos.pSelectedNode == pTree && EndPos.Index == 0 )
567 0 : IsSelecting = !IsSelecting;
568 : SAL_WARN_IF(IsSelecting, "starmath", "Caret positions needed to set IsSelecting about, shouldn't be possible!");
569 :
570 : //Visit lines
571 19 : SmNodeIterator it( pTree );
572 57 : while( it.Next( ) ) {
573 19 : it->Accept( this );
574 : //If we started a selection in this line and it haven't ended, we do that now!
575 19 : if(IsSelecting) {
576 0 : IsSelecting = false;
577 0 : 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 0 : StartPos = EndPos = SmCaretPos();
581 : }
582 : }
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 19 : if(pTree->IsSelected())
587 0 : SetSelectedOnAll(pTree, false);
588 : }else //This shouldn't happen, but I don't see any reason to die if it does
589 0 : pTree->Accept(this);
590 19 : }
591 :
592 0 : void SmSetSelectionVisitor::SetSelectedOnAll( SmNode* pSubTree, bool IsSelected ) {
593 0 : pSubTree->SetSelected( IsSelected );
594 :
595 : //Quick BFS to set all selections
596 0 : SmNodeIterator it( pSubTree );
597 0 : while( it.Next( ) )
598 0 : SetSelectedOnAll( it.Current( ), IsSelected );
599 0 : }
600 :
601 49 : void SmSetSelectionVisitor::DefaultVisit( SmNode* pNode ) {
602 : //Change state if StartPos is in front of this node
603 49 : if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
604 0 : IsSelecting = !IsSelecting;
605 : //Change state if EndPos is in front of this node
606 49 : if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
607 0 : IsSelecting = !IsSelecting;
608 :
609 : //Cache current state
610 49 : bool WasSelecting = IsSelecting;
611 49 : bool ChangedState = false;
612 :
613 : //Set selected
614 49 : pNode->SetSelected( IsSelecting );
615 :
616 : //Visit children
617 49 : SmNodeIterator it( pNode );
618 135 : while( it.Next( ) )
619 : {
620 37 : it->Accept( this );
621 37 : ChangedState = ( WasSelecting != IsSelecting ) || ChangedState;
622 : }
623 :
624 : //If state changed
625 49 : if( ChangedState )
626 : {
627 : //Select this node and all of its children
628 : //(Make exception for SmBracebodyNode)
629 0 : if( pNode->GetType() != NBRACEBODY ||
630 0 : !pNode->GetParent() ||
631 0 : pNode->GetParent()->GetType() != NBRACE )
632 0 : SetSelectedOnAll( pNode, true );
633 : else
634 0 : 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.
641 : */
642 : }
643 :
644 : //Change state if StartPos is after this node
645 49 : if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
646 : {
647 0 : IsSelecting = !IsSelecting;
648 : }
649 : //Change state if EndPos is after of this node
650 49 : if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
651 : {
652 1 : IsSelecting = !IsSelecting;
653 : }
654 49 : }
655 :
656 58 : void SmSetSelectionVisitor::VisitCompositionNode( SmNode* pNode ) {
657 : //Change state if StartPos is in front of this node
658 58 : if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
659 16 : IsSelecting = !IsSelecting;
660 : //Change state if EndPos is in front of this node
661 58 : if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
662 17 : IsSelecting = !IsSelecting;
663 :
664 : //Cache current state
665 58 : bool WasSelecting = IsSelecting;
666 :
667 : //Visit children
668 58 : SmNodeIterator it( pNode );
669 209 : while( it.Next( ) )
670 93 : it->Accept( this );
671 :
672 : //Set selected, if everything was selected
673 58 : pNode->SetSelected( WasSelecting && IsSelecting );
674 :
675 : //Change state if StartPos is after this node
676 58 : if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
677 0 : IsSelecting = !IsSelecting;
678 : //Change state if EndPos is after of this node
679 58 : if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
680 0 : IsSelecting = !IsSelecting;
681 58 : }
682 :
683 42 : void SmSetSelectionVisitor::Visit( SmTextNode* pNode ) {
684 42 : long i1 = -1,
685 42 : i2 = -1;
686 42 : if( StartPos.pSelectedNode == pNode )
687 3 : i1 = StartPos.Index;
688 42 : if( EndPos.pSelectedNode == pNode )
689 1 : i2 = EndPos.Index;
690 :
691 : long start, end;
692 42 : pNode->SetSelected( true );
693 42 : if( i1 != -1 && i2 != -1 ) {
694 1 : start = i1 < i2 ? i1 : i2; //MIN
695 1 : end = i1 > i2 ? i1 : i2; //MAX
696 41 : } else if( IsSelecting && i1 != -1 ) {
697 2 : start = 0;
698 2 : end = i1;
699 2 : IsSelecting = false;
700 39 : } else if( IsSelecting && i2 != -1 ) {
701 0 : start = 0;
702 0 : end = i2;
703 0 : IsSelecting = false;
704 39 : } else if( !IsSelecting && i1 != -1 ) {
705 0 : start = i1;
706 0 : end = pNode->GetText().getLength();
707 0 : IsSelecting = true;
708 39 : } else if( !IsSelecting && i2 != -1 ) {
709 0 : start = i2;
710 0 : end = pNode->GetText().getLength();
711 0 : IsSelecting = true;
712 39 : } else if( IsSelecting ) {
713 0 : start = 0;
714 0 : end = pNode->GetText().getLength();
715 : } else {
716 39 : pNode->SetSelected( false );
717 39 : start = 0;
718 39 : end = 0;
719 : }
720 42 : pNode->SetSelected( start != end );
721 42 : pNode->SetSelectionStart( start );
722 42 : pNode->SetSelectionEnd( end );
723 42 : }
724 :
725 35 : void SmSetSelectionVisitor::Visit( SmExpressionNode* pNode ) {
726 35 : VisitCompositionNode( pNode );
727 35 : }
728 :
729 2 : void SmSetSelectionVisitor::Visit( SmLineNode* pNode ) {
730 2 : VisitCompositionNode( pNode );
731 2 : }
732 :
733 0 : void SmSetSelectionVisitor::Visit( SmAlignNode* pNode ) {
734 0 : VisitCompositionNode( pNode );
735 0 : }
736 :
737 12 : void SmSetSelectionVisitor::Visit( SmBinHorNode* pNode ) {
738 12 : VisitCompositionNode( pNode );
739 12 : }
740 :
741 9 : void SmSetSelectionVisitor::Visit( SmUnHorNode* pNode ) {
742 9 : VisitCompositionNode( pNode );
743 9 : }
744 :
745 0 : void SmSetSelectionVisitor::Visit( SmFontNode* pNode ) {
746 0 : VisitCompositionNode( pNode );
747 0 : }
748 :
749 : // SmCaretPosGraphBuildingVisitor
750 :
751 20 : SmCaretPosGraphBuildingVisitor::SmCaretPosGraphBuildingVisitor( SmNode* pRootNode )
752 : : mpRightMost(nullptr)
753 20 : , mpGraph(new SmCaretPosGraph)
754 : {
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 20 : 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 20 : SmNodeIterator it( pRootNode );
763 60 : while( it.Next( ) ){
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
768 : //the visual line.
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 20 : mpRightMost = mpGraph->Add( SmCaretPos( it.Current( ), 0 ) );
774 20 : it->Accept( this );
775 : }
776 : }else
777 0 : pRootNode->Accept(this);
778 20 : }
779 :
780 20 : SmCaretPosGraphBuildingVisitor::~SmCaretPosGraphBuildingVisitor()
781 : {
782 20 : }
783 :
784 4 : void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode* pNode ){
785 4 : SmNodeIterator it( pNode );
786 12 : while( it.Next( ) ){
787 4 : it->Accept( this );
788 : }
789 4 : }
790 :
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.
795 : */
796 3 : void SmCaretPosGraphBuildingVisitor::Visit( SmTableNode* pNode ){
797 3 : SmCaretPosGraphEntry *left = mpRightMost,
798 3 : *right = mpGraph->Add( SmCaretPos( pNode, 1) );
799 3 : bool bIsFirst = true;
800 3 : SmNodeIterator it( pNode );
801 12 : while( it.Next() ){
802 6 : mpRightMost = mpGraph->Add( SmCaretPos( it.Current(), 0 ), left);
803 6 : if(bIsFirst)
804 3 : left->SetRight(mpRightMost);
805 6 : it->Accept( this );
806 6 : mpRightMost->SetRight(right);
807 6 : if(bIsFirst)
808 3 : right->SetLeft(mpRightMost);
809 6 : bIsFirst = false;
810 : }
811 3 : mpRightMost = right;
812 3 : }
813 :
814 : /** Build SmCaretPosGraph for SmSubSupNode
815 : *
816 : * The child positions in a SubSupNode, where H is the body:
817 : * \code
818 : * CSUP
819 : *
820 : * LSUP H H RSUP
821 : * H H
822 : * HHHH
823 : * H H
824 : * LSUB H H RSUB
825 : *
826 : * CSUB
827 : * \endcode
828 : *
829 : * Graph over these, where "left" is before the SmSubSupNode and "right" is after:
830 : * \dot
831 : * digraph Graph{
832 : * left -> H;
833 : * H -> right;
834 : * LSUP -> H;
835 : * LSUB -> H;
836 : * CSUP -> right;
837 : * CSUB -> right;
838 : * RSUP -> right;
839 : * RSUB -> right;
840 : * };
841 : * \enddot
842 : *
843 : */
844 6 : void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode* pNode )
845 : {
846 : SmCaretPosGraphEntry *left,
847 : *right,
848 : *bodyLeft,
849 : *bodyRight;
850 :
851 6 : left = mpRightMost;
852 : SAL_WARN_IF( !mpRightMost, "starmath", "mpRightMost shouldn't be NULL here!" );
853 :
854 : //Create bodyLeft
855 : SAL_WARN_IF( !pNode->GetBody(), "starmath", "SmSubSupNode Doesn't have a body!" );
856 6 : bodyLeft = mpGraph->Add( SmCaretPos( pNode->GetBody( ), 0 ), left );
857 6 : left->SetRight( bodyLeft ); //TODO: Don't make this if LSUP or LSUB are NULL ( not sure??? )
858 :
859 : //Create right
860 6 : right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
861 :
862 : //Visit the body, to get bodyRight
863 6 : mpRightMost = bodyLeft;
864 6 : pNode->GetBody( )->Accept( this );
865 6 : bodyRight = mpRightMost;
866 6 : bodyRight->SetRight( right );
867 6 : right->SetLeft( bodyRight );
868 :
869 : SmNode* pChild;
870 : //If there's an LSUP
871 6 : if( ( pChild = pNode->GetSubSup( LSUP ) ) ){
872 : SmCaretPosGraphEntry *cLeft; //Child left
873 0 : cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
874 :
875 0 : mpRightMost = cLeft;
876 0 : pChild->Accept( this );
877 :
878 0 : mpRightMost->SetRight( bodyLeft );
879 : }
880 : //If there's an LSUB
881 6 : if( ( pChild = pNode->GetSubSup( LSUB ) ) ){
882 : SmCaretPosGraphEntry *cLeft; //Child left
883 0 : cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
884 :
885 0 : mpRightMost = cLeft;
886 0 : pChild->Accept( this );
887 :
888 0 : mpRightMost->SetRight( bodyLeft );
889 : }
890 : //If there's an CSUP
891 6 : if( ( pChild = pNode->GetSubSup( CSUP ) ) ){
892 : SmCaretPosGraphEntry *cLeft; //Child left
893 0 : cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
894 :
895 0 : mpRightMost = cLeft;
896 0 : pChild->Accept( this );
897 :
898 0 : mpRightMost->SetRight( right );
899 : }
900 : //If there's an CSUB
901 6 : if( ( pChild = pNode->GetSubSup( CSUB ) ) ){
902 : SmCaretPosGraphEntry *cLeft; //Child left
903 0 : cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
904 :
905 0 : mpRightMost = cLeft;
906 0 : pChild->Accept( this );
907 :
908 0 : mpRightMost->SetRight( right );
909 : }
910 : //If there's an RSUP
911 6 : if( ( pChild = pNode->GetSubSup( RSUP ) ) ){
912 : SmCaretPosGraphEntry *cLeft; //Child left
913 6 : cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
914 :
915 6 : mpRightMost = cLeft;
916 6 : pChild->Accept( this );
917 :
918 6 : mpRightMost->SetRight( right );
919 : }
920 : //If there's an RSUB
921 6 : if( ( pChild = pNode->GetSubSup( RSUB ) ) ){
922 : SmCaretPosGraphEntry *cLeft; //Child left
923 0 : cLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
924 :
925 0 : mpRightMost = cLeft;
926 0 : pChild->Accept( this );
927 :
928 0 : mpRightMost->SetRight( right );
929 : }
930 :
931 : //Set return parameters
932 6 : mpRightMost = right;
933 6 : }
934 :
935 : /** Build caret position for SmOperNode
936 : *
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.
942 : *
943 : * The child positions in a SmOperNode, where H is symbol, e.g. int, sum or similar:
944 : * \code
945 : * TO
946 : *
947 : * LSUP H H RSUP BBB BB BBB B B
948 : * H H B B B B B B B B
949 : * HHHH BBB B B B B B
950 : * H H B B B B B B B
951 : * LSUB H H RSUB BBB BB BBB B
952 : *
953 : * FROM
954 : * \endcode
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.
957 : *
958 : * Graph over these, where "left" is before the SmOperNode and "right" is after:
959 : * \dot
960 : * digraph Graph{
961 : * left -> BODY;
962 : * BODY -> right;
963 : * LSUP -> BODY;
964 : * LSUB -> BODY;
965 : * TO -> BODY;
966 : * FROM -> BODY;
967 : * RSUP -> BODY;
968 : * RSUB -> BODY;
969 : * };
970 : * \enddot
971 : */
972 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode* pNode )
973 : {
974 0 : SmNode *pOper = pNode->GetSubNode( 0 ),
975 0 : *pBody = pNode->GetSubNode( 1 );
976 :
977 0 : SmCaretPosGraphEntry *left = mpRightMost,
978 : *bodyLeft,
979 : *bodyRight,
980 : *right;
981 : //Create body left
982 0 : bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
983 0 : left->SetRight( bodyLeft );
984 :
985 : //Visit body, get bodyRight
986 0 : mpRightMost = bodyLeft;
987 0 : pBody->Accept( this );
988 0 : bodyRight = mpRightMost;
989 :
990 : //Create right
991 0 : right = mpGraph->Add( SmCaretPos( pNode, 1 ), bodyRight );
992 0 : bodyRight->SetRight( right );
993 :
994 : //Get subsup pNode if any
995 0 : SmSubSupNode* pSubSup = pOper->GetType( ) == NSUBSUP ? static_cast<SmSubSupNode*>(pOper) : NULL;
996 :
997 : SmNode* pChild;
998 : SmCaretPosGraphEntry *childLeft;
999 0 : if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
1000 : //Create position in front of pChild
1001 0 : childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1002 : //Visit pChild
1003 0 : mpRightMost = childLeft;
1004 0 : pChild->Accept( this );
1005 : //Set right on mpRightMost from pChild
1006 0 : mpRightMost->SetRight( bodyLeft );
1007 : }
1008 0 : if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
1009 : //Create position in front of pChild
1010 0 : childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1011 : //Visit pChild
1012 0 : mpRightMost = childLeft;
1013 0 : pChild->Accept( this );
1014 : //Set right on mpRightMost from pChild
1015 0 : mpRightMost->SetRight( bodyLeft );
1016 : }
1017 0 : if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {//TO
1018 : //Create position in front of pChild
1019 0 : childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1020 : //Visit pChild
1021 0 : mpRightMost = childLeft;
1022 0 : pChild->Accept( this );
1023 : //Set right on mpRightMost from pChild
1024 0 : mpRightMost->SetRight( bodyLeft );
1025 : }
1026 0 : if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUB ) ) ) { //FROM
1027 : //Create position in front of pChild
1028 0 : childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1029 : //Visit pChild
1030 0 : mpRightMost = childLeft;
1031 0 : pChild->Accept( this );
1032 : //Set right on mpRightMost from pChild
1033 0 : mpRightMost->SetRight( bodyLeft );
1034 : }
1035 0 : if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
1036 : //Create position in front of pChild
1037 0 : childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1038 : //Visit pChild
1039 0 : mpRightMost = childLeft;
1040 0 : pChild->Accept( this );
1041 : //Set right on mpRightMost from pChild
1042 0 : mpRightMost->SetRight( bodyLeft );
1043 : }
1044 0 : if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
1045 : //Create position in front of pChild
1046 0 : childLeft = mpGraph->Add( SmCaretPos( pChild, 0 ), left );
1047 : //Visit pChild
1048 0 : mpRightMost = childLeft;
1049 0 : pChild->Accept( this );
1050 : //Set right on mpRightMost from pChild
1051 0 : mpRightMost->SetRight( bodyLeft );
1052 : }
1053 :
1054 : //Return right
1055 0 : mpRightMost = right;
1056 0 : }
1057 :
1058 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmMatrixNode* pNode )
1059 : {
1060 0 : SmCaretPosGraphEntry *left = mpRightMost,
1061 0 : *right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1062 :
1063 0 : for ( sal_uInt16 i = 0; i < pNode->GetNumRows( ); i++ ) {
1064 0 : SmCaretPosGraphEntry* r = left;
1065 0 : for ( sal_uInt16 j = 0; j < pNode->GetNumCols( ); j++ ){
1066 0 : SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
1067 :
1068 0 : mpRightMost = mpGraph->Add( SmCaretPos( pSubNode, 0 ), r );
1069 0 : if( j != 0 || ( pNode->GetNumRows( ) - 1 ) / 2 == i )
1070 0 : r->SetRight( mpRightMost );
1071 :
1072 0 : pSubNode->Accept( this );
1073 :
1074 0 : r = mpRightMost;
1075 : }
1076 0 : mpRightMost->SetRight( right );
1077 0 : if( ( pNode->GetNumRows( ) - 1 ) / 2 == i )
1078 0 : right->SetLeft( mpRightMost );
1079 : }
1080 :
1081 0 : mpRightMost = right;
1082 0 : }
1083 :
1084 : /** Build SmCaretPosGraph for SmTextNode
1085 : *
1086 : * Lines in an SmTextNode:
1087 : * \code
1088 : * A B C
1089 : * \endcode
1090 : * Where A B and C are characters in the text.
1091 : *
1092 : * Graph over these, where "left" is before the SmTextNode and "right" is after:
1093 : * \dot
1094 : * digraph Graph{
1095 : * left -> A;
1096 : * A -> B
1097 : * B -> right;
1098 : * };
1099 : * \enddot
1100 : * Notice that C and right is the same position here.
1101 : */
1102 44 : void SmCaretPosGraphBuildingVisitor::Visit( SmTextNode* pNode )
1103 : {
1104 : SAL_WARN_IF( pNode->GetText().isEmpty(), "starmath", "Empty SmTextNode is bad" );
1105 :
1106 44 : int size = pNode->GetText().getLength();
1107 88 : for( int i = 1; i <= size; i++ ){
1108 44 : SmCaretPosGraphEntry* pRight = mpRightMost;
1109 44 : mpRightMost = mpGraph->Add( SmCaretPos( pNode, i ), pRight );
1110 44 : pRight->SetRight( mpRightMost );
1111 : }
1112 44 : }
1113 :
1114 : /** Build SmCaretPosGraph for SmBinVerNode
1115 : *
1116 : * Lines in an SmBinVerNode:
1117 : * \code
1118 : * A
1119 : * -----
1120 : * B
1121 : * \endcode
1122 : *
1123 : * Graph over these, where "left" is before the SmBinVerNode and "right" is after:
1124 : * \dot
1125 : * digraph Graph{
1126 : * left -> A;
1127 : * A -> right;
1128 : * B -> right;
1129 : * };
1130 : * \enddot
1131 : */
1132 7 : void SmCaretPosGraphBuildingVisitor::Visit( SmBinVerNode* pNode )
1133 : {
1134 : //None if these children can be NULL, see SmBinVerNode::Arrange
1135 7 : SmNode *pNum = pNode->GetSubNode( 0 ),
1136 7 : *pDenom = pNode->GetSubNode( 2 );
1137 :
1138 : SmCaretPosGraphEntry *left,
1139 : *right,
1140 : *numLeft,
1141 : *denomLeft;
1142 :
1143 : //Set left
1144 7 : left = mpRightMost;
1145 : SAL_WARN_IF( !mpRightMost, "starmath", "There must be a position in front of this" );
1146 :
1147 : //Create right
1148 7 : right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1149 :
1150 : //Create numLeft
1151 7 : numLeft = mpGraph->Add( SmCaretPos( pNum, 0 ), left );
1152 7 : left->SetRight( numLeft );
1153 :
1154 : //Visit pNum
1155 7 : mpRightMost = numLeft;
1156 7 : pNum->Accept( this );
1157 7 : mpRightMost->SetRight( right );
1158 7 : right->SetLeft( mpRightMost );
1159 :
1160 : //Create denomLeft
1161 7 : denomLeft = mpGraph->Add( SmCaretPos( pDenom, 0 ), left );
1162 :
1163 : //Visit pDenom
1164 7 : mpRightMost = denomLeft;
1165 7 : pDenom->Accept( this );
1166 7 : mpRightMost->SetRight( right );
1167 :
1168 : //Set return parameter
1169 7 : mpRightMost = right;
1170 7 : }
1171 :
1172 : /** Build SmCaretPosGraph for SmVerticalBraceNode
1173 : *
1174 : * Lines in an SmVerticalBraceNode:
1175 : * \code
1176 : * pScript
1177 : * ________
1178 : * / \
1179 : * pBody
1180 : * \endcode
1181 : *
1182 : */
1183 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmVerticalBraceNode* pNode )
1184 : {
1185 0 : SmNode *pBody = pNode->GetSubNode( 0 ),
1186 0 : *pScript = pNode->GetSubNode( 2 );
1187 : //None of these children can be NULL
1188 :
1189 : SmCaretPosGraphEntry *left,
1190 : *bodyLeft,
1191 : *scriptLeft,
1192 : *right;
1193 :
1194 0 : left = mpRightMost;
1195 :
1196 : //Create right
1197 0 : right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1198 :
1199 : //Create bodyLeft
1200 0 : bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1201 0 : left->SetRight( bodyLeft );
1202 0 : mpRightMost = bodyLeft;
1203 0 : pBody->Accept( this );
1204 0 : mpRightMost->SetRight( right );
1205 0 : right->SetLeft( mpRightMost );
1206 :
1207 : //Create script
1208 0 : scriptLeft = mpGraph->Add( SmCaretPos( pScript, 0 ), left );
1209 0 : mpRightMost = scriptLeft;
1210 0 : pScript->Accept( this );
1211 0 : mpRightMost->SetRight( right );
1212 :
1213 : //Set return value
1214 0 : mpRightMost = right;
1215 0 : }
1216 :
1217 : /** Build SmCaretPosGraph for SmBinDiagonalNode
1218 : *
1219 : * Lines in an SmBinDiagonalNode:
1220 : * \code
1221 : * A /
1222 : * /
1223 : * / B
1224 : * \endcode
1225 : * Where A and B are lines.
1226 : *
1227 : * Used in formulas such as "A wideslash B"
1228 : */
1229 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmBinDiagonalNode* pNode )
1230 : {
1231 0 : SmNode *A = pNode->GetSubNode( 0 ),
1232 0 : *B = pNode->GetSubNode( 1 );
1233 :
1234 : SmCaretPosGraphEntry *left,
1235 : *leftA,
1236 : *rightA,
1237 : *leftB,
1238 : *right;
1239 0 : left = mpRightMost;
1240 :
1241 : //Create right
1242 0 : right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1243 :
1244 : //Create left A
1245 0 : leftA = mpGraph->Add( SmCaretPos( A, 0 ), left );
1246 0 : left->SetRight( leftA );
1247 :
1248 : //Visit A
1249 0 : mpRightMost = leftA;
1250 0 : A->Accept( this );
1251 0 : rightA = mpRightMost;
1252 :
1253 : //Create left B
1254 0 : leftB = mpGraph->Add( SmCaretPos( B, 0 ), rightA );
1255 0 : rightA->SetRight( leftB );
1256 :
1257 : //Visit B
1258 0 : mpRightMost = leftB;
1259 0 : B->Accept( this );
1260 0 : mpRightMost->SetRight( right );
1261 0 : right->SetLeft( mpRightMost );
1262 :
1263 : //Set return value
1264 0 : mpRightMost = right;
1265 0 : }
1266 :
1267 : //Straigt forward ( I think )
1268 13 : void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode* pNode )
1269 : {
1270 13 : SmNodeIterator it( pNode );
1271 65 : while( it.Next( ) )
1272 39 : it->Accept( this );
1273 13 : }
1274 9 : void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode* pNode )
1275 : {
1276 : // Unary operator node
1277 9 : SmNodeIterator it( pNode );
1278 36 : while( it.Next( ) )
1279 18 : it->Accept( this );
1280 :
1281 9 : }
1282 :
1283 35 : void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode* pNode )
1284 : {
1285 35 : SmNodeIterator it( pNode );
1286 106 : while( it.Next( ) )
1287 36 : it->Accept( this );
1288 35 : }
1289 :
1290 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmFontNode* pNode )
1291 : {
1292 : //Has only got one child, should act as an expression if possible
1293 0 : SmNodeIterator it( pNode );
1294 0 : while( it.Next( ) )
1295 0 : it->Accept( this );
1296 0 : }
1297 :
1298 : /** Build SmCaretPosGraph for SmBracebodyNode
1299 : * Acts as an SmExpressionNode
1300 : *
1301 : * Below is an example of a formula tree that has multiple children for SmBracebodyNode
1302 : * \dot
1303 : * digraph {
1304 : * labelloc = "t";
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: }"];
1335 : * }
1336 : * \enddot
1337 : */
1338 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode* pNode )
1339 : {
1340 0 : SmNodeIterator it( pNode );
1341 0 : while( it.Next( ) ) {
1342 0 : SmCaretPosGraphEntry* pStart = mpGraph->Add( SmCaretPos( it.Current(), 0), mpRightMost );
1343 0 : mpRightMost->SetRight( pStart );
1344 0 : mpRightMost = pStart;
1345 0 : it->Accept( this );
1346 : }
1347 0 : }
1348 :
1349 : /** Build SmCaretPosGraph for SmAlignNode
1350 : * Acts as an SmExpressionNode, as it only has one child this okay
1351 : */
1352 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmAlignNode* pNode )
1353 : {
1354 0 : SmNodeIterator it( pNode );
1355 0 : while( it.Next( ) )
1356 0 : it->Accept( this );
1357 0 : }
1358 :
1359 : /** Build SmCaretPosGraph for SmRootNode
1360 : *
1361 : * Lines in an SmRootNode:
1362 : * \code
1363 : * _________
1364 : * A/
1365 : * \/ B
1366 : *
1367 : * \endcode
1368 : * A: pExtra ( optional, can be NULL ),
1369 : * B: pBody
1370 : *
1371 : * Graph over these, where "left" is before the SmRootNode and "right" is after:
1372 : * \dot
1373 : * digraph Graph{
1374 : * left -> B;
1375 : * B -> right;
1376 : * A -> B;
1377 : * }
1378 : * \enddot
1379 : */
1380 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode* pNode )
1381 : {
1382 0 : SmNode *pExtra = pNode->GetSubNode( 0 ), //Argument, NULL for sqrt, and SmTextNode if cubicroot
1383 0 : *pBody = pNode->GetSubNode( 2 ); //Body of the root
1384 : SAL_WARN_IF( !pBody, "starmath", "pBody cannot be NULL" );
1385 :
1386 : SmCaretPosGraphEntry *left,
1387 : *right,
1388 : *bodyLeft,
1389 : *bodyRight;
1390 :
1391 : //Get left and save it
1392 : SAL_WARN_IF( !mpRightMost, "starmath", "There must be a position in front of this" );
1393 0 : left = mpRightMost;
1394 :
1395 : //Create body left
1396 0 : bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1397 0 : left->SetRight( bodyLeft );
1398 :
1399 : //Create right
1400 0 : right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1401 :
1402 : //Visit body
1403 0 : mpRightMost = bodyLeft;
1404 0 : pBody->Accept( this );
1405 0 : bodyRight = mpRightMost;
1406 0 : bodyRight->SetRight( right );
1407 0 : right->SetLeft( bodyRight );
1408 :
1409 : //Visit pExtra
1410 0 : if( pExtra ){
1411 0 : mpRightMost = mpGraph->Add( SmCaretPos( pExtra, 0 ), left );
1412 0 : pExtra->Accept( this );
1413 0 : mpRightMost->SetRight( bodyLeft );
1414 : }
1415 :
1416 0 : mpRightMost = right;
1417 0 : }
1418 :
1419 :
1420 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmDynIntegralNode* pNode )
1421 : {
1422 : //! To be changed: Integrals don't have args.
1423 0 : SmNode *pBody = pNode->Body(); //Body of the root
1424 : SAL_WARN_IF( !pBody, "starmath", "pBody cannot be NULL" );
1425 :
1426 : SmCaretPosGraphEntry *left,
1427 : *right,
1428 : *bodyLeft,
1429 : *bodyRight;
1430 :
1431 : //Get left and save it
1432 : SAL_WARN_IF( !mpRightMost, "starmath", "There must be a position in front of this" );
1433 0 : left = mpRightMost;
1434 :
1435 : //Create body left
1436 0 : bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1437 0 : left->SetRight( bodyLeft );
1438 :
1439 : //Create right
1440 0 : right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1441 :
1442 : //Visit body
1443 0 : mpRightMost = bodyLeft;
1444 0 : pBody->Accept( this );
1445 0 : bodyRight = mpRightMost;
1446 0 : bodyRight->SetRight( right );
1447 0 : right->SetLeft( bodyRight );
1448 :
1449 0 : mpRightMost = right;
1450 0 : }
1451 :
1452 :
1453 : /** Build SmCaretPosGraph for SmPlaceNode
1454 : * Consider this a single character.
1455 : */
1456 2 : void SmCaretPosGraphBuildingVisitor::Visit( SmPlaceNode* pNode )
1457 : {
1458 2 : SmCaretPosGraphEntry* right = mpGraph->Add( SmCaretPos( pNode, 1 ), mpRightMost );
1459 2 : mpRightMost->SetRight( right );
1460 2 : mpRightMost = right;
1461 2 : }
1462 :
1463 : /** SmErrorNode is context dependent metadata, it can't be selected
1464 : *
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.
1468 : */
1469 4 : void SmCaretPosGraphBuildingVisitor::Visit( SmErrorNode* )
1470 : {
1471 4 : }
1472 :
1473 : /** Build SmCaretPosGraph for SmBlankNode
1474 : * Consider this a single character, as it is only a blank space
1475 : */
1476 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmBlankNode* pNode )
1477 : {
1478 0 : SmCaretPosGraphEntry* right = mpGraph->Add( SmCaretPos( pNode, 1 ), mpRightMost );
1479 0 : mpRightMost->SetRight( right );
1480 0 : mpRightMost = right;
1481 0 : }
1482 :
1483 : /** Build SmCaretPosGraph for SmBraceNode
1484 : *
1485 : * Lines in an SmBraceNode:
1486 : * \code
1487 : * | |
1488 : * | B |
1489 : * | |
1490 : * \endcode
1491 : * B: Body
1492 : *
1493 : * Graph over these, where "left" is before the SmBraceNode and "right" is after:
1494 : * \dot
1495 : * digraph Graph{
1496 : * left -> B;
1497 : * B -> right;
1498 : * }
1499 : * \enddot
1500 : */
1501 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmBraceNode* pNode )
1502 : {
1503 0 : SmNode* pBody = pNode->GetSubNode( 1 );
1504 :
1505 0 : SmCaretPosGraphEntry *left = mpRightMost,
1506 0 : *right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1507 :
1508 0 : if( pBody->GetType() != NBRACEBODY ) {
1509 0 : mpRightMost = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1510 0 : left->SetRight( mpRightMost );
1511 : }else
1512 0 : mpRightMost = left;
1513 :
1514 0 : pBody->Accept( this );
1515 0 : mpRightMost->SetRight( right );
1516 0 : right->SetLeft( mpRightMost );
1517 :
1518 0 : mpRightMost = right;
1519 0 : }
1520 :
1521 : /** Build SmCaretPosGraph for SmAttributNode
1522 : *
1523 : * Lines in an SmAttributNode:
1524 : * \code
1525 : * Attr
1526 : * Body
1527 : * \endcode
1528 : *
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
1531 : * scaled ).
1532 : */
1533 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmAttributNode* pNode )
1534 : {
1535 0 : SmNode *pAttr = pNode->GetSubNode( 0 ),
1536 0 : *pBody = pNode->GetSubNode( 1 );
1537 : //None of the children can be NULL
1538 :
1539 0 : SmCaretPosGraphEntry *left = mpRightMost,
1540 : *attrLeft,
1541 : *bodyLeft,
1542 : *bodyRight,
1543 : *right;
1544 :
1545 : //Creating bodyleft
1546 0 : bodyLeft = mpGraph->Add( SmCaretPos( pBody, 0 ), left );
1547 0 : left->SetRight( bodyLeft );
1548 :
1549 : //Creating right
1550 0 : right = mpGraph->Add( SmCaretPos( pNode, 1 ) );
1551 :
1552 : //Visit the body
1553 0 : mpRightMost = bodyLeft;
1554 0 : pBody->Accept( this );
1555 0 : bodyRight = mpRightMost;
1556 0 : bodyRight->SetRight( right );
1557 0 : right->SetLeft( bodyRight );
1558 :
1559 : //Create attrLeft
1560 0 : attrLeft = mpGraph->Add( SmCaretPos( pAttr, 0 ), left );
1561 :
1562 : //Visit attribute
1563 0 : mpRightMost = attrLeft;
1564 0 : pAttr->Accept( this );
1565 0 : mpRightMost->SetRight( right );
1566 :
1567 : //Set return value
1568 0 : mpRightMost = right;
1569 0 : }
1570 :
1571 : //Consider these single symboles
1572 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmSpecialNode* pNode )
1573 : {
1574 0 : SmCaretPosGraphEntry* right = mpGraph->Add( SmCaretPos( pNode, 1 ), mpRightMost );
1575 0 : mpRightMost->SetRight( right );
1576 0 : mpRightMost = right;
1577 0 : }
1578 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmGlyphSpecialNode* pNode )
1579 : {
1580 0 : SmCaretPosGraphEntry* right = mpGraph->Add( SmCaretPos( pNode, 1 ), mpRightMost );
1581 0 : mpRightMost->SetRight( right );
1582 0 : mpRightMost = right;
1583 0 : }
1584 22 : void SmCaretPosGraphBuildingVisitor::Visit( SmMathSymbolNode* pNode )
1585 : {
1586 22 : SmCaretPosGraphEntry* right = mpGraph->Add( SmCaretPos( pNode, 1 ), mpRightMost );
1587 22 : mpRightMost->SetRight( right );
1588 22 : mpRightMost = right;
1589 22 : }
1590 :
1591 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode* )
1592 : {
1593 : //Do nothing
1594 0 : }
1595 :
1596 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmDynIntegralSymbolNode* )
1597 : {
1598 : //Do nothing
1599 0 : }
1600 :
1601 :
1602 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode* )
1603 : {
1604 : //Do nothing
1605 0 : }
1606 0 : void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode* )
1607 : {
1608 : //Do nothing
1609 0 : }
1610 :
1611 : // SmCloningVisitor
1612 :
1613 0 : SmNode* SmCloningVisitor::Clone( SmNode* pNode )
1614 : {
1615 0 : SmNode* pCurrResult = pResult;
1616 0 : pNode->Accept( this );
1617 0 : SmNode* pClone = pResult;
1618 0 : pResult = pCurrResult;
1619 0 : return pClone;
1620 : }
1621 :
1622 0 : void SmCloningVisitor::CloneNodeAttr( SmNode* pSource, SmNode* pTarget )
1623 : {
1624 0 : 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.
1627 0 : }
1628 :
1629 0 : void SmCloningVisitor::CloneKids( SmStructureNode* pSource, SmStructureNode* pTarget )
1630 : {
1631 : //Cache current result
1632 0 : SmNode* pCurrResult = pResult;
1633 :
1634 : //Create array for holding clones
1635 0 : sal_uInt16 nSize = pSource->GetNumSubNodes( );
1636 0 : SmNodeArray aNodes( nSize );
1637 :
1638 : //Clone children
1639 0 : for( sal_uInt16 i = 0; i < nSize; i++ ){
1640 : SmNode* pKid;
1641 0 : if( NULL != ( pKid = pSource->GetSubNode( i ) ) )
1642 0 : pKid->Accept( this );
1643 : else
1644 0 : pResult = NULL;
1645 0 : aNodes[i] = pResult;
1646 : }
1647 :
1648 : //Set subnodes of pTarget
1649 0 : pTarget->SetSubNodes( aNodes );
1650 :
1651 : //Restore result as where prior to call
1652 0 : pResult = pCurrResult;
1653 0 : }
1654 :
1655 0 : void SmCloningVisitor::Visit( SmTableNode* pNode )
1656 : {
1657 0 : SmTableNode* pClone = new SmTableNode( pNode->GetToken( ) );
1658 0 : CloneNodeAttr( pNode, pClone );
1659 0 : CloneKids( pNode, pClone );
1660 0 : pResult = pClone;
1661 0 : }
1662 :
1663 0 : void SmCloningVisitor::Visit( SmBraceNode* pNode )
1664 : {
1665 0 : SmBraceNode* pClone = new SmBraceNode( pNode->GetToken( ) );
1666 0 : CloneNodeAttr( pNode, pClone );
1667 0 : CloneKids( pNode, pClone );
1668 0 : pResult = pClone;
1669 0 : }
1670 :
1671 0 : void SmCloningVisitor::Visit( SmBracebodyNode* pNode )
1672 : {
1673 0 : SmBracebodyNode* pClone = new SmBracebodyNode( pNode->GetToken( ) );
1674 0 : CloneNodeAttr( pNode, pClone );
1675 0 : CloneKids( pNode, pClone );
1676 0 : pResult = pClone;
1677 0 : }
1678 :
1679 0 : void SmCloningVisitor::Visit( SmOperNode* pNode )
1680 : {
1681 0 : SmOperNode* pClone = new SmOperNode( pNode->GetToken( ) );
1682 0 : CloneNodeAttr( pNode, pClone );
1683 0 : CloneKids( pNode, pClone );
1684 0 : pResult = pClone;
1685 0 : }
1686 :
1687 0 : void SmCloningVisitor::Visit( SmAlignNode* pNode )
1688 : {
1689 0 : SmAlignNode* pClone = new SmAlignNode( pNode->GetToken( ) );
1690 0 : CloneNodeAttr( pNode, pClone );
1691 0 : CloneKids( pNode, pClone );
1692 0 : pResult = pClone;
1693 0 : }
1694 :
1695 0 : void SmCloningVisitor::Visit( SmAttributNode* pNode )
1696 : {
1697 0 : SmAttributNode* pClone = new SmAttributNode( pNode->GetToken( ) );
1698 0 : CloneNodeAttr( pNode, pClone );
1699 0 : CloneKids( pNode, pClone );
1700 0 : pResult = pClone;
1701 0 : }
1702 :
1703 0 : void SmCloningVisitor::Visit( SmFontNode* pNode )
1704 : {
1705 0 : SmFontNode* pClone = new SmFontNode( pNode->GetToken( ) );
1706 0 : pClone->SetSizeParameter( pNode->GetSizeParameter( ), pNode->GetSizeType( ) );
1707 0 : CloneNodeAttr( pNode, pClone );
1708 0 : CloneKids( pNode, pClone );
1709 0 : pResult = pClone;
1710 0 : }
1711 :
1712 0 : void SmCloningVisitor::Visit( SmUnHorNode* pNode )
1713 : {
1714 0 : SmUnHorNode* pClone = new SmUnHorNode( pNode->GetToken( ) );
1715 0 : CloneNodeAttr( pNode, pClone );
1716 0 : CloneKids( pNode, pClone );
1717 0 : pResult = pClone;
1718 0 : }
1719 :
1720 0 : void SmCloningVisitor::Visit( SmBinHorNode* pNode )
1721 : {
1722 0 : SmBinHorNode* pClone = new SmBinHorNode( pNode->GetToken( ) );
1723 0 : CloneNodeAttr( pNode, pClone );
1724 0 : CloneKids( pNode, pClone );
1725 0 : pResult = pClone;
1726 0 : }
1727 :
1728 0 : void SmCloningVisitor::Visit( SmBinVerNode* pNode )
1729 : {
1730 0 : SmBinVerNode* pClone = new SmBinVerNode( pNode->GetToken( ) );
1731 0 : CloneNodeAttr( pNode, pClone );
1732 0 : CloneKids( pNode, pClone );
1733 0 : pResult = pClone;
1734 0 : }
1735 :
1736 0 : void SmCloningVisitor::Visit( SmBinDiagonalNode* pNode )
1737 : {
1738 0 : SmBinDiagonalNode *pClone = new SmBinDiagonalNode( pNode->GetToken( ) );
1739 0 : pClone->SetAscending( pNode->IsAscending( ) );
1740 0 : CloneNodeAttr( pNode, pClone );
1741 0 : CloneKids( pNode, pClone );
1742 0 : pResult = pClone;
1743 0 : }
1744 :
1745 0 : void SmCloningVisitor::Visit( SmSubSupNode* pNode )
1746 : {
1747 0 : SmSubSupNode *pClone = new SmSubSupNode( pNode->GetToken( ) );
1748 0 : pClone->SetUseLimits( pNode->IsUseLimits( ) );
1749 0 : CloneNodeAttr( pNode, pClone );
1750 0 : CloneKids( pNode, pClone );
1751 0 : pResult = pClone;
1752 0 : }
1753 :
1754 0 : void SmCloningVisitor::Visit( SmMatrixNode* pNode )
1755 : {
1756 0 : SmMatrixNode *pClone = new SmMatrixNode( pNode->GetToken( ) );
1757 0 : pClone->SetRowCol( pNode->GetNumRows( ), pNode->GetNumCols( ) );
1758 0 : CloneNodeAttr( pNode, pClone );
1759 0 : CloneKids( pNode, pClone );
1760 0 : pResult = pClone;
1761 0 : }
1762 :
1763 0 : void SmCloningVisitor::Visit( SmPlaceNode* pNode )
1764 : {
1765 0 : pResult = new SmPlaceNode( pNode->GetToken( ) );
1766 0 : CloneNodeAttr( pNode, pResult );
1767 0 : }
1768 :
1769 0 : void SmCloningVisitor::Visit( SmTextNode* pNode )
1770 : {
1771 0 : SmTextNode* pClone = new SmTextNode( pNode->GetToken( ), pNode->GetFontDesc( ) );
1772 0 : pClone->ChangeText( pNode->GetText( ) );
1773 0 : CloneNodeAttr( pNode, pClone );
1774 0 : pResult = pClone;
1775 0 : }
1776 :
1777 0 : void SmCloningVisitor::Visit( SmSpecialNode* pNode )
1778 : {
1779 0 : pResult = new SmSpecialNode( pNode->GetToken( ) );
1780 0 : CloneNodeAttr( pNode, pResult );
1781 0 : }
1782 :
1783 0 : void SmCloningVisitor::Visit( SmGlyphSpecialNode* pNode )
1784 : {
1785 0 : pResult = new SmGlyphSpecialNode( pNode->GetToken( ) );
1786 0 : CloneNodeAttr( pNode, pResult );
1787 0 : }
1788 :
1789 0 : void SmCloningVisitor::Visit( SmMathSymbolNode* pNode )
1790 : {
1791 0 : pResult = new SmMathSymbolNode( pNode->GetToken( ) );
1792 0 : CloneNodeAttr( pNode, pResult );
1793 0 : }
1794 :
1795 0 : void SmCloningVisitor::Visit( SmBlankNode* pNode )
1796 : {
1797 0 : SmBlankNode* pClone = new SmBlankNode( pNode->GetToken( ) );
1798 0 : pClone->SetBlankNum( pNode->GetBlankNum( ) );
1799 0 : pResult = pClone;
1800 0 : CloneNodeAttr( pNode, pResult );
1801 0 : }
1802 :
1803 0 : void SmCloningVisitor::Visit( SmErrorNode* pNode )
1804 : {
1805 : //PE_NONE is used the information have been discarded and isn't used
1806 0 : pResult = new SmErrorNode( PE_NONE, pNode->GetToken( ) );
1807 0 : CloneNodeAttr( pNode, pResult );
1808 0 : }
1809 :
1810 0 : void SmCloningVisitor::Visit( SmLineNode* pNode )
1811 : {
1812 0 : SmLineNode* pClone = new SmLineNode( pNode->GetToken( ) );
1813 0 : CloneNodeAttr( pNode, pClone );
1814 0 : CloneKids( pNode, pClone );
1815 0 : pResult = pClone;
1816 0 : }
1817 :
1818 0 : void SmCloningVisitor::Visit( SmExpressionNode* pNode )
1819 : {
1820 0 : SmExpressionNode* pClone = new SmExpressionNode( pNode->GetToken( ) );
1821 0 : CloneNodeAttr( pNode, pClone );
1822 0 : CloneKids( pNode, pClone );
1823 0 : pResult = pClone;
1824 0 : }
1825 :
1826 0 : void SmCloningVisitor::Visit( SmPolyLineNode* pNode )
1827 : {
1828 0 : pResult = new SmPolyLineNode( pNode->GetToken( ) );
1829 0 : CloneNodeAttr( pNode, pResult );
1830 0 : }
1831 :
1832 0 : void SmCloningVisitor::Visit( SmRootNode* pNode )
1833 : {
1834 0 : SmRootNode* pClone = new SmRootNode( pNode->GetToken( ) );
1835 0 : CloneNodeAttr( pNode, pClone );
1836 0 : CloneKids( pNode, pClone );
1837 0 : pResult = pClone;
1838 0 : }
1839 :
1840 0 : void SmCloningVisitor::Visit( SmRootSymbolNode* pNode )
1841 : {
1842 0 : pResult = new SmRootSymbolNode( pNode->GetToken( ) );
1843 0 : CloneNodeAttr( pNode, pResult );
1844 0 : }
1845 :
1846 0 : void SmCloningVisitor::Visit( SmDynIntegralNode* pNode )
1847 : {
1848 0 : SmDynIntegralNode* pClone = new SmDynIntegralNode( pNode->GetToken( ) );
1849 0 : CloneNodeAttr( pNode, pClone );
1850 0 : CloneKids( pNode, pClone );
1851 0 : pResult = pClone;
1852 0 : }
1853 :
1854 0 : void SmCloningVisitor::Visit( SmDynIntegralSymbolNode* pNode )
1855 : {
1856 0 : pResult = new SmDynIntegralSymbolNode( pNode->GetToken( ) );
1857 0 : CloneNodeAttr( pNode, pResult );
1858 0 : }
1859 :
1860 0 : void SmCloningVisitor::Visit( SmRectangleNode* pNode )
1861 : {
1862 0 : pResult = new SmRectangleNode( pNode->GetToken( ) );
1863 0 : CloneNodeAttr( pNode, pResult );
1864 0 : }
1865 :
1866 0 : void SmCloningVisitor::Visit( SmVerticalBraceNode* pNode )
1867 : {
1868 0 : SmVerticalBraceNode* pClone = new SmVerticalBraceNode( pNode->GetToken( ) );
1869 0 : CloneNodeAttr( pNode, pClone );
1870 0 : CloneKids( pNode, pClone );
1871 0 : pResult = pClone;
1872 0 : }
1873 :
1874 : // SmSelectionDrawingVisitor
1875 :
1876 0 : SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, Point Offset )
1877 0 : : rDev( rDevice ) {
1878 0 : bHasSelectionArea = false;
1879 :
1880 : //Visit everything
1881 : SAL_WARN_IF( !pTree, "starmath", "pTree can't be null!" );
1882 0 : if( pTree )
1883 0 : pTree->Accept( this );
1884 :
1885 : //Draw selection if there's any
1886 0 : if( bHasSelectionArea ){
1887 0 : aSelectionArea.Move( Offset.X( ), Offset.Y( ) );
1888 :
1889 : //Save device state
1890 0 : rDev.Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR );
1891 : //Change colors
1892 0 : rDev.SetLineColor( );
1893 0 : rDev.SetFillColor( Color( COL_LIGHTGRAY ) );
1894 :
1895 : //Draw rectangle
1896 0 : rDev.DrawRect( aSelectionArea );
1897 :
1898 : //Restore device state
1899 0 : rDev.Pop( );
1900 : }
1901 0 : }
1902 :
1903 0 : void SmSelectionDrawingVisitor::ExtendSelectionArea(const Rectangle& rArea)
1904 : {
1905 0 : if ( ! bHasSelectionArea ) {
1906 0 : aSelectionArea = rArea;
1907 0 : bHasSelectionArea = true;
1908 : } else
1909 0 : aSelectionArea.Union(rArea);
1910 0 : }
1911 :
1912 0 : void SmSelectionDrawingVisitor::DefaultVisit( SmNode* pNode )
1913 : {
1914 0 : if( pNode->IsSelected( ) )
1915 0 : ExtendSelectionArea( pNode->AsRectangle( ) );
1916 0 : VisitChildren( pNode );
1917 0 : }
1918 :
1919 0 : void SmSelectionDrawingVisitor::VisitChildren( SmNode* pNode )
1920 : {
1921 0 : SmNodeIterator it( pNode );
1922 0 : while( it.Next( ) )
1923 0 : it->Accept( this );
1924 0 : }
1925 :
1926 0 : void SmSelectionDrawingVisitor::Visit( SmTextNode* pNode )
1927 : {
1928 0 : if( pNode->IsSelected( ) ){
1929 0 : rDev.Push( PushFlags::TEXTCOLOR | PushFlags::FONT );
1930 :
1931 0 : rDev.SetFont( pNode->GetFont( ) );
1932 0 : Point Position = pNode->GetTopLeft( );
1933 0 : long left = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionStart( ) );
1934 0 : long right = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionEnd( ) );
1935 0 : long top = Position.getY( );
1936 0 : long bottom = top + pNode->GetHeight( );
1937 0 : Rectangle rect( left, top, right, bottom );
1938 :
1939 0 : ExtendSelectionArea( rect );
1940 :
1941 0 : rDev.Pop( );
1942 : }
1943 0 : }
1944 :
1945 : // SmNodeToTextVisitor
1946 :
1947 559 : SmNodeToTextVisitor::SmNodeToTextVisitor( SmNode* pNode, OUString &rText )
1948 : {
1949 559 : pNode->Accept( this );
1950 559 : rText = aCmdText.makeStringAndClear();
1951 559 : }
1952 :
1953 36 : void SmNodeToTextVisitor::Visit( SmTableNode* pNode )
1954 : {
1955 36 : if( pNode->GetToken( ).eType == TBINOM ) {
1956 4 : Append( "{ binom" );
1957 4 : LineToText( pNode->GetSubNode( 0 ) );
1958 4 : LineToText( pNode->GetSubNode( 1 ) );
1959 4 : Append("} ");
1960 32 : } else if( pNode->GetToken( ).eType == TSTACK ) {
1961 16 : Append( "stack{ " );
1962 16 : SmNodeIterator it( pNode );
1963 16 : it.Next( );
1964 : while( true ) {
1965 36 : LineToText( it.Current( ) );
1966 36 : if( it.Next( ) ) {
1967 20 : Separate( );
1968 20 : Append( "# " );
1969 : }else
1970 16 : break;
1971 : }
1972 16 : Separate( );
1973 36 : Append( "}" );
1974 : } else { //Assume it's a toplevel table, containing lines
1975 16 : SmNodeIterator it( pNode );
1976 16 : it.Next( );
1977 : while( true ) {
1978 16 : Separate( );
1979 16 : it->Accept( this );
1980 16 : if( it.Next( ) ) {
1981 0 : Separate( );
1982 0 : Append( "newline" );
1983 : }else
1984 16 : break;
1985 0 : }
1986 : }
1987 36 : }
1988 :
1989 84 : void SmNodeToTextVisitor::Visit( SmBraceNode* pNode )
1990 : {
1991 84 : SmNode *pLeftBrace = pNode->GetSubNode( 0 ),
1992 84 : *pBody = pNode->GetSubNode( 1 ),
1993 84 : *pRightBrace = pNode->GetSubNode( 2 );
1994 : //Handle special case where it's absolute function
1995 84 : if( pNode->GetToken( ).eType == TABS ) {
1996 4 : Append( "abs" );
1997 4 : LineToText( pBody );
1998 : } else {
1999 80 : if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
2000 18 : Append( "left " );
2001 80 : pLeftBrace->Accept( this );
2002 80 : Separate( );
2003 80 : pBody->Accept( this );
2004 80 : Separate( );
2005 80 : if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
2006 18 : Append( "right " );
2007 80 : pRightBrace->Accept( this );
2008 : }
2009 84 : }
2010 :
2011 80 : void SmNodeToTextVisitor::Visit( SmBracebodyNode* pNode )
2012 : {
2013 80 : SmNodeIterator it( pNode );
2014 248 : while( it.Next( ) ){
2015 88 : Separate( );
2016 88 : it->Accept( this );
2017 : }
2018 80 : }
2019 :
2020 27 : void SmNodeToTextVisitor::Visit( SmOperNode* pNode )
2021 : {
2022 27 : Append( pNode->GetToken( ).aText );
2023 27 : Separate( );
2024 27 : if( pNode->GetToken( ).eType == TOPER ){
2025 : //There's an SmGlyphSpecialNode if eType == TOPER
2026 0 : if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP )
2027 0 : Append( pNode->GetSubNode( 0 )->GetSubNode( 0 )->GetToken( ).aText );
2028 : else
2029 0 : Append( pNode->GetSubNode( 0 )->GetToken( ).aText );
2030 : }
2031 27 : if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP ) {
2032 7 : SmSubSupNode *pSubSup = static_cast<SmSubSupNode*>( pNode->GetSubNode( 0 ) );
2033 : SmNode* pChild;
2034 7 : if( ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
2035 0 : Separate( );
2036 0 : Append( "lsup { " );
2037 0 : LineToText( pChild );
2038 0 : Append( "} " );
2039 : }
2040 7 : if( ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
2041 0 : Separate( );
2042 0 : Append( "lsub { " );
2043 0 : LineToText( pChild );
2044 0 : Append( "} " );
2045 : }
2046 7 : if( ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
2047 0 : Separate( );
2048 0 : Append( "^ { " );
2049 0 : LineToText( pChild );
2050 0 : Append( "} " );
2051 : }
2052 7 : if( ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
2053 0 : Separate( );
2054 0 : Append( "_ { " );
2055 0 : LineToText( pChild );
2056 0 : Append( "} " );
2057 : }
2058 7 : if( ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {
2059 5 : Separate( );
2060 5 : if (pSubSup->IsUseLimits())
2061 4 : Append( "to { " );
2062 : else
2063 1 : Append( "csup { " );
2064 5 : LineToText( pChild );
2065 5 : Append( "} " );
2066 : }
2067 7 : if( ( pChild = pSubSup->GetSubSup( CSUB ) ) ) {
2068 7 : Separate( );
2069 7 : if (pSubSup->IsUseLimits())
2070 6 : Append( "from { " );
2071 : else
2072 1 : Append( "csub { " );
2073 7 : LineToText( pChild );
2074 7 : Append( "} " );
2075 : }
2076 : }
2077 27 : LineToText( pNode->GetSubNode( 1 ) );
2078 27 : }
2079 :
2080 14 : void SmNodeToTextVisitor::Visit( SmAlignNode* pNode )
2081 : {
2082 14 : Append( pNode->GetToken( ).aText );
2083 14 : LineToText( pNode->GetSubNode( 0 ) );
2084 14 : }
2085 :
2086 36 : void SmNodeToTextVisitor::Visit( SmAttributNode* pNode )
2087 : {
2088 36 : Append( pNode->GetToken( ).aText );
2089 36 : LineToText( pNode->GetSubNode( 1 ) );
2090 36 : }
2091 :
2092 34 : void SmNodeToTextVisitor::Visit( SmFontNode* pNode )
2093 : {
2094 34 : switch ( pNode->GetToken( ).eType )
2095 : {
2096 : case TBOLD:
2097 2 : Append( "bold " );
2098 2 : break;
2099 : case TNBOLD:
2100 0 : Append( "nbold " );
2101 0 : break;
2102 : case TITALIC:
2103 2 : Append( "italic " );
2104 2 : break;
2105 : case TNITALIC:
2106 2 : Append( "nitalic " );
2107 2 : break;
2108 : case TPHANTOM:
2109 4 : Append( "phantom " );
2110 4 : break;
2111 : case TSIZE:
2112 : {
2113 2 : Append( "size " );
2114 2 : switch ( pNode->GetSizeType( ) )
2115 : {
2116 : case FontSizeType::PLUS:
2117 0 : Append( "+" );
2118 0 : break;
2119 : case FontSizeType::MINUS:
2120 0 : Append( "-" );
2121 0 : break;
2122 : case FontSizeType::MULTIPLY:
2123 0 : Append( "*" );
2124 0 : break;
2125 : case FontSizeType::DIVIDE:
2126 0 : Append( "/" );
2127 0 : break;
2128 : case FontSizeType::ABSOLUT:
2129 : default:
2130 2 : break;
2131 : }
2132 : Append( ::rtl::math::doubleToUString(
2133 2 : static_cast<double>( pNode->GetSizeParameter( ) ),
2134 : rtl_math_StringFormat_Automatic,
2135 2 : rtl_math_DecimalPlaces_Max, '.', true ) );
2136 2 : Append( " " );
2137 : }
2138 2 : break;
2139 : case TBLACK:
2140 0 : Append( "color black " );
2141 0 : break;
2142 : case TWHITE:
2143 2 : Append( "color white " );
2144 2 : break;
2145 : case TRED:
2146 2 : Append( "color red " );
2147 2 : break;
2148 : case TGREEN:
2149 6 : Append( "color green " );
2150 6 : break;
2151 : case TBLUE:
2152 2 : Append( "color blue " );
2153 2 : break;
2154 : case TCYAN:
2155 2 : Append( "color cyan " );
2156 2 : break;
2157 : case TMAGENTA:
2158 0 : Append( "color magenta " );
2159 0 : break;
2160 : case TYELLOW:
2161 2 : Append( "color yellow " );
2162 2 : break;
2163 : case TSANS:
2164 2 : Append( "font sans " );
2165 2 : break;
2166 : case TSERIF:
2167 2 : Append( "font serif " );
2168 2 : break;
2169 : case TFIXED:
2170 2 : Append( "font fixed " );
2171 2 : break;
2172 : default:
2173 0 : break;
2174 : }
2175 34 : LineToText( pNode->GetSubNode( 1 ) );
2176 34 : }
2177 :
2178 38 : void SmNodeToTextVisitor::Visit( SmUnHorNode* pNode )
2179 : {
2180 38 : SmNodeIterator it( pNode, pNode->GetSubNode( 1 )->GetToken( ).eType == TFACT );
2181 152 : while( it.Next( ) ) {
2182 76 : Separate( );
2183 76 : it->Accept( this );
2184 : }
2185 38 : }
2186 :
2187 116 : void SmNodeToTextVisitor::Visit( SmBinHorNode* pNode )
2188 : {
2189 116 : SmNode *pLeft = pNode->GetSubNode( 0 ),
2190 116 : *pOper = pNode->GetSubNode( 1 ),
2191 116 : *pRight = pNode->GetSubNode( 2 );
2192 116 : Separate( );
2193 116 : pLeft->Accept( this );
2194 116 : Separate( );
2195 116 : pOper->Accept( this );
2196 116 : Separate( );
2197 116 : pRight->Accept( this );
2198 116 : Separate( );
2199 116 : }
2200 :
2201 26 : void SmNodeToTextVisitor::Visit( SmBinVerNode* pNode )
2202 : {
2203 26 : SmNode *pNum = pNode->GetSubNode( 0 ),
2204 26 : *pDenom = pNode->GetSubNode( 2 );
2205 26 : Append( "{ " );
2206 26 : LineToText( pNum );
2207 26 : Append( "over" );
2208 26 : LineToText( pDenom );
2209 26 : Append( "} " );
2210 26 : }
2211 :
2212 0 : void SmNodeToTextVisitor::Visit( SmBinDiagonalNode* pNode )
2213 : {
2214 0 : SmNode *pLeftOperand = pNode->GetSubNode( 0 ),
2215 0 : *pRightOperand = pNode->GetSubNode( 1 );
2216 0 : Append( "{ " );
2217 0 : LineToText( pLeftOperand );
2218 0 : Separate( );
2219 0 : Append( "wideslash " );
2220 0 : LineToText( pRightOperand );
2221 0 : Append( "} " );
2222 0 : }
2223 :
2224 34 : void SmNodeToTextVisitor::Visit( SmSubSupNode* pNode )
2225 : {
2226 34 : LineToText( pNode->GetBody( ) );
2227 : SmNode *pChild;
2228 34 : if( ( pChild = pNode->GetSubSup( LSUP ) ) ) {
2229 2 : Separate( );
2230 2 : Append( "lsup " );
2231 2 : LineToText( pChild );
2232 : }
2233 34 : if( ( pChild = pNode->GetSubSup( LSUB ) ) ) {
2234 2 : Separate( );
2235 2 : Append( "lsub " );
2236 2 : LineToText( pChild );
2237 : }
2238 34 : if( ( pChild = pNode->GetSubSup( RSUP ) ) ) {
2239 16 : Separate( );
2240 16 : Append( "^ " );
2241 16 : LineToText( pChild );
2242 : }
2243 34 : if( ( pChild = pNode->GetSubSup( RSUB ) ) ) {
2244 10 : Separate( );
2245 10 : Append( "_ " );
2246 10 : LineToText( pChild );
2247 : }
2248 34 : if( ( pChild = pNode->GetSubSup( CSUP ) ) ) {
2249 2 : Separate( );
2250 2 : if (pNode->IsUseLimits())
2251 0 : Append( "to " );
2252 : else
2253 2 : Append( "csup " );
2254 2 : LineToText( pChild );
2255 : }
2256 34 : if( ( pChild = pNode->GetSubSup( CSUB ) ) ) {
2257 2 : Separate( );
2258 2 : if (pNode->IsUseLimits())
2259 0 : Append( "from " );
2260 : else
2261 2 : Append( "csub " );
2262 2 : LineToText( pChild );
2263 : }
2264 34 : }
2265 :
2266 4 : void SmNodeToTextVisitor::Visit( SmMatrixNode* pNode )
2267 : {
2268 4 : Append( "matrix{" );
2269 12 : for ( sal_uInt16 i = 0; i < pNode->GetNumRows( ); i++ ) {
2270 28 : for ( sal_uInt16 j = 0; j < pNode->GetNumCols( ); j++ ) {
2271 20 : SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
2272 20 : Separate( );
2273 20 : pSubNode->Accept( this );
2274 20 : Separate( );
2275 20 : if( j != pNode->GetNumCols( ) - 1 )
2276 12 : Append( "#" );
2277 : }
2278 8 : Separate( );
2279 8 : if( i != pNode->GetNumRows( ) - 1 )
2280 4 : Append( "##" );
2281 : }
2282 4 : Append( "} " );
2283 4 : }
2284 :
2285 2 : void SmNodeToTextVisitor::Visit( SmPlaceNode* )
2286 : {
2287 2 : Append( "<?>" );
2288 2 : }
2289 :
2290 680 : void SmNodeToTextVisitor::Visit( SmTextNode* pNode )
2291 : {
2292 : //TODO: This method might need improvements, see SmTextNode::CreateTextFromNode
2293 680 : if( pNode->GetToken( ).eType == TTEXT )
2294 6 : Append( "\"" );
2295 680 : Append( pNode->GetText( ) );
2296 680 : if( pNode->GetToken( ).eType == TTEXT )
2297 6 : Append( "\"" );
2298 680 : }
2299 :
2300 131 : void SmNodeToTextVisitor::Visit( SmSpecialNode* pNode )
2301 : {
2302 131 : Append( pNode->GetToken( ).aText );
2303 131 : }
2304 :
2305 0 : void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode* pNode )
2306 : {
2307 0 : if( pNode->GetToken( ).eType == TBOPER )
2308 0 : Append( "boper " );
2309 : else
2310 0 : Append( "uoper " );
2311 0 : Append( pNode->GetToken( ).aText );
2312 0 : }
2313 :
2314 380 : void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
2315 : {
2316 380 : Append( pNode->GetToken( ).aText );
2317 380 : }
2318 :
2319 4 : void SmNodeToTextVisitor::Visit( SmBlankNode* pNode )
2320 : {
2321 4 : Append( pNode->GetToken( ).aText );
2322 4 : }
2323 :
2324 4 : void SmNodeToTextVisitor::Visit( SmErrorNode* )
2325 : {
2326 4 : }
2327 :
2328 0 : void SmNodeToTextVisitor::Visit( SmLineNode* pNode )
2329 : {
2330 0 : SmNodeIterator it( pNode );
2331 0 : while( it.Next( ) ){
2332 0 : Separate( );
2333 0 : it->Accept( this );
2334 : }
2335 0 : }
2336 :
2337 112 : void SmNodeToTextVisitor::Visit( SmExpressionNode* pNode )
2338 : {
2339 112 : bool bracketsNeeded = pNode->GetNumSubNodes() != 1 || pNode->GetSubNode(0)->GetType() == NBINHOR;
2340 112 : if (!bracketsNeeded)
2341 : {
2342 22 : const SmNode *pParent = pNode->GetParent();
2343 : // nested subsups
2344 : bracketsNeeded =
2345 23 : pParent && pParent->GetType() == NSUBSUP &&
2346 24 : pNode->GetNumSubNodes() == 1 &&
2347 23 : pNode->GetSubNode(0)->GetType() == NSUBSUP;
2348 : }
2349 :
2350 112 : if (bracketsNeeded) {
2351 90 : Append( "{ " );
2352 : }
2353 112 : SmNodeIterator it( pNode );
2354 422 : while( it.Next( ) ) {
2355 198 : it->Accept( this );
2356 198 : Separate( );
2357 : }
2358 112 : if (bracketsNeeded) {
2359 90 : Append( "} " );
2360 : }
2361 112 : }
2362 :
2363 0 : void SmNodeToTextVisitor::Visit( SmPolyLineNode* )
2364 : {
2365 0 : }
2366 :
2367 4 : void SmNodeToTextVisitor::Visit( SmRootNode* pNode )
2368 : {
2369 4 : SmNode *pExtra = pNode->GetSubNode( 0 ),
2370 4 : *pBody = pNode->GetSubNode( 2 );
2371 4 : if( pExtra ) {
2372 2 : Append( "nroot" );
2373 2 : LineToText( pExtra );
2374 : } else
2375 2 : Append( "sqrt" );
2376 4 : LineToText( pBody );
2377 4 : }
2378 :
2379 0 : void SmNodeToTextVisitor::Visit( SmRootSymbolNode* )
2380 : {
2381 0 : }
2382 :
2383 0 : void SmNodeToTextVisitor::Visit( SmDynIntegralNode* pNode )
2384 : {
2385 0 : SmNode *pBody = pNode->Body();
2386 0 : Append( "intd" );
2387 0 : LineToText( pBody );
2388 0 : }
2389 :
2390 0 : void SmNodeToTextVisitor::Visit( SmDynIntegralSymbolNode* )
2391 : {
2392 0 : }
2393 :
2394 0 : void SmNodeToTextVisitor::Visit( SmRectangleNode* )
2395 : {
2396 0 : }
2397 :
2398 4 : void SmNodeToTextVisitor::Visit( SmVerticalBraceNode* pNode )
2399 : {
2400 4 : SmNode *pBody = pNode->GetSubNode( 0 ),
2401 4 : *pScript = pNode->GetSubNode( 2 );
2402 4 : LineToText( pBody );
2403 4 : Append( pNode->GetToken( ).aText );
2404 4 : LineToText( pScript );
2405 46 : }
2406 :
2407 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|