summaryrefslogtreecommitdiff
path: root/starmath/source/visitors.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'starmath/source/visitors.cxx')
-rw-r--r--starmath/source/visitors.cxx2541
1 files changed, 2541 insertions, 0 deletions
diff --git a/starmath/source/visitors.cxx b/starmath/source/visitors.cxx
new file mode 100644
index 000000000000..78e5adcbeddf
--- /dev/null
+++ b/starmath/source/visitors.cxx
@@ -0,0 +1,2541 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is
+ * Jonas Finnemann Jensen <jopsen@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C) 2010 the
+ * Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Jonas Finnemann Jensen <jopsen@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+#include "visitors.hxx"
+#include "cursor.hxx"
+
+///////////////////////////////////// SmVisitorTest /////////////////////////////////////
+
+void SmVisitorTest::Visit( SmTableNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NTABLE, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmBraceNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NBRACE, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmBracebodyNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NBRACEBODY, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmOperNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NOPER, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmAlignNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NALIGN, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmAttributNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NATTRIBUT, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmFontNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NFONT, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmUnHorNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NUNHOR, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmBinHorNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NBINHOR, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmBinVerNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NBINVER, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmBinDiagonalNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NBINDIAGONAL, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmSubSupNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NSUBSUP, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmMatrixNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NMATRIX, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmPlaceNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NPLACE, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmTextNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NTEXT, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmSpecialNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NSPECIAL, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmGlyphSpecialNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NGLYPH_SPECIAL, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmMathSymbolNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NMATH, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmBlankNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NBLANK, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmErrorNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NERROR, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmLineNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NLINE, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmExpressionNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NEXPRESSION, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmPolyLineNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NPOLYLINE, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmRootNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NROOT, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmRootSymbolNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NROOTSYMBOL, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmRectangleNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NRECTANGLE, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::Visit( SmVerticalBraceNode* pNode )
+{
+ OSL_ENSURE( pNode->GetType( ) == NVERTICAL_BRACE, "the visitor-patterns isn't implemented correctly" );
+ VisitChildren( pNode );
+}
+
+void SmVisitorTest::VisitChildren( SmNode* pNode )
+{
+ SmNodeIterator it( pNode );
+ while( it.Next( ) )
+ it->Accept( this );
+}
+
+/////////////////////////////// SmDefaultingVisitor ////////////////////////////////
+
+void SmDefaultingVisitor::Visit( SmTableNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmBraceNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmBracebodyNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmOperNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmAlignNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmAttributNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmFontNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmUnHorNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmBinHorNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmBinVerNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmBinDiagonalNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmSubSupNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmMatrixNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmPlaceNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmTextNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmSpecialNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmGlyphSpecialNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmMathSymbolNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmBlankNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmErrorNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmLineNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmExpressionNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmPolyLineNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmRootNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmRootSymbolNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmRectangleNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+void SmDefaultingVisitor::Visit( SmVerticalBraceNode* pNode )
+{
+ DefaultVisit( pNode );
+}
+
+/////////////////////////////// SmCaretDrawingVisitor ////////////////////////////////
+
+SmCaretDrawingVisitor::SmCaretDrawingVisitor( OutputDevice& rDevice,
+ SmCaretPos position,
+ Point offset,
+ bool caretVisible )
+ : rDev( rDevice )
+{
+ pos = position;
+ Offset = offset;
+ isCaretVisible = caretVisible;
+ OSL_ENSURE( position.IsValid( ), "Cannot draw invalid position!" );
+ if( !position.IsValid( ) )
+ return;
+
+ //Save device state
+ rDev.Push( PUSH_FONT | PUSH_MAPMODE | PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR );
+
+ pos.pSelectedNode->Accept( this );
+ //Restore device state
+ rDev.Pop( );
+}
+
+void SmCaretDrawingVisitor::Visit( SmTextNode* pNode )
+{
+ long i = pos.Index;
+
+ rDev.SetFont( pNode->GetFont( ) );
+
+ //Find the line
+ SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
+
+ //Find coordinates
+ long left = pNode->GetLeft( ) + rDev.GetTextWidth( pNode->GetText( ), 0, i ) + Offset.X( );
+ long top = pLine->GetTop( ) + Offset.Y( );
+ long height = pLine->GetHeight( );
+ long left_line = pLine->GetLeft( ) + Offset.X( );
+ long right_line = pLine->GetRight( ) + Offset.X( );
+
+ //Set color
+ rDev.SetLineColor( Color( COL_BLACK ) );
+
+ if ( isCaretVisible ) {
+ //Draw vertical line
+ Point p1( left, top );
+ Point p2( left, top + height );
+ rDev.DrawLine( p1, p2 );
+ }
+
+ //Underline the line
+ Point pLeft( left_line, top + height );
+ Point pRight( right_line, top + height );
+ rDev.DrawLine( pLeft, pRight );
+}
+
+void SmCaretDrawingVisitor::DefaultVisit( SmNode* pNode )
+{
+ rDev.SetLineColor( Color( COL_BLACK ) );
+
+ //Find the line
+ SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
+
+ //Find coordinates
+ long left = pNode->GetLeft( ) + Offset.X( ) + ( pos.Index == 1 ? pNode->GetWidth( ) : 0 );
+ long top = pLine->GetTop( ) + Offset.Y( );
+ long height = pLine->GetHeight( );
+ long left_line = pLine->GetLeft( ) + Offset.X( );
+ long right_line = pLine->GetRight( ) + Offset.X( );
+
+ //Set color
+ rDev.SetLineColor( Color( COL_BLACK ) );
+
+ if ( isCaretVisible ) {
+ //Draw vertical line
+ Point p1( left, top );
+ Point p2( left, top + height );
+ rDev.DrawLine( p1, p2 );
+ }
+
+ //Underline the line
+ Point pLeft( left_line, top + height );
+ Point pRight( right_line, top + height );
+ rDev.DrawLine( pLeft, pRight );
+}
+
+/////////////////////////////// SmCaretPos2LineVisitor ////////////////////////////////
+
+void SmCaretPos2LineVisitor::Visit( SmTextNode* pNode )
+{
+ //Save device state
+ pDev->Push( PUSH_FONT | PUSH_TEXTCOLOR );
+
+ long i = pos.Index;
+
+ pDev->SetFont( pNode->GetFont( ) );
+
+ //Find coordinates
+ long left = pNode->GetLeft( ) + pDev->GetTextWidth( pNode->GetText( ), 0, i );
+ long top = pNode->GetTop( );
+ long height = pNode->GetHeight( );
+
+ line = SmCaretLine( left, top, height );
+
+ //Restore device state
+ pDev->Pop( );
+}
+
+void SmCaretPos2LineVisitor::DefaultVisit( SmNode* pNode )
+{
+ //Vertical line ( code from SmCaretDrawingVisitor )
+ Point p1 = pNode->GetTopLeft( );
+ if( pos.Index == 1 )
+ p1.Move( pNode->GetWidth( ), 0 );
+
+ line = SmCaretLine( p1.X( ), p1.Y( ), pNode->GetHeight( ) );
+}
+
+/////////////////////////////// Nasty temporary device!!! ////////////////////////////////
+
+#include <tools/gen.hxx>
+#include <tools/fract.hxx>
+#include <rtl/math.hxx>
+#include <tools/color.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/lineinfo.hxx>
+#include <vcl/outdev.hxx>
+#include <sfx2/module.hxx>
+#include "symbol.hxx"
+#include "smmod.hxx"
+
+class SmTmpDevice2
+{
+ OutputDevice &rOutDev;
+
+ // disallow use of copy-constructor and assignment-operator
+ SmTmpDevice2( const SmTmpDevice2 &rTmpDev );
+ SmTmpDevice2 & operator = ( const SmTmpDevice2 &rTmpDev );
+
+ Color Impl_GetColor( const Color& rColor );
+
+public:
+ SmTmpDevice2( OutputDevice &rTheDev, bool bUseMap100th_mm );
+ ~SmTmpDevice2( ) { rOutDev.Pop( ); }
+
+ void SetFont( const Font &rNewFont );
+
+ void SetLineColor( const Color& rColor ) { rOutDev.SetLineColor( Impl_GetColor( rColor ) ); }
+ void SetFillColor( const Color& rColor ) { rOutDev.SetFillColor( Impl_GetColor( rColor ) ); }
+ void SetTextColor( const Color& rColor ) { rOutDev.SetTextColor( Impl_GetColor( rColor ) ); }
+
+ operator OutputDevice & ( ) { return rOutDev; }
+};
+
+SmTmpDevice2::SmTmpDevice2( OutputDevice &rTheDev, bool bUseMap100th_mm ) :
+ rOutDev( rTheDev )
+{
+ rOutDev.Push( PUSH_FONT | PUSH_MAPMODE |
+ PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR );
+ if ( bUseMap100th_mm && MAP_100TH_MM != rOutDev.GetMapMode( ).GetMapUnit( ) )
+ {
+ OSL_FAIL( "incorrect MapMode?" );
+ rOutDev.SetMapMode( MAP_100TH_MM ); //format for 100% always
+ }
+}
+
+Color SmTmpDevice2::Impl_GetColor( const Color& rColor )
+{
+ ColorData nNewCol = rColor.GetColor( );
+ if ( COL_AUTO == nNewCol )
+ {
+ if ( OUTDEV_PRINTER == rOutDev.GetOutDevType( ) )
+ nNewCol = COL_BLACK;
+ else
+ {
+ Color aBgCol( rOutDev.GetBackground( ).GetColor( ) );
+ if ( OUTDEV_WINDOW == rOutDev.GetOutDevType( ) )
+ aBgCol = ( ( Window & ) rOutDev ).GetDisplayBackground( ).GetColor( );
+
+ nNewCol = SM_MOD( )->GetColorConfig( ).GetColorValue( svtools::FONTCOLOR ).nColor;
+
+ Color aTmpColor( nNewCol );
+ if ( aBgCol.IsDark( ) && aTmpColor.IsDark( ) )
+ nNewCol = COL_WHITE;
+ else if ( aBgCol.IsBright( ) && aTmpColor.IsBright( ) )
+ nNewCol = COL_BLACK;
+ }
+ }
+ return Color( nNewCol );
+}
+
+void SmTmpDevice2::SetFont( const Font &rNewFont )
+{
+ rOutDev.SetFont( rNewFont );
+ rOutDev.SetTextColor( Impl_GetColor( rNewFont.GetColor( ) ) );
+}
+
+/////////////////////////////// SmDrawingVisitor ////////////////////////////////
+
+void SmDrawingVisitor::Visit( SmTableNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmBraceNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmBracebodyNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmOperNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmAlignNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmAttributNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmFontNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmUnHorNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmBinHorNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmBinVerNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmBinDiagonalNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmSubSupNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmMatrixNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmPlaceNode* pNode )
+{
+ DrawSpecialNode( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmTextNode* pNode )
+{
+ DrawTextNode( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmSpecialNode* pNode )
+{
+ DrawSpecialNode( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmGlyphSpecialNode* pNode )
+{
+ DrawSpecialNode( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmMathSymbolNode* pNode )
+{
+ DrawSpecialNode( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmBlankNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmErrorNode* pNode )
+{
+ DrawSpecialNode( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmLineNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmExpressionNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmRootNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmVerticalBraceNode* pNode )
+{
+ DrawChildren( pNode );
+}
+
+void SmDrawingVisitor::Visit( SmRootSymbolNode* pNode )
+{
+ if ( pNode->IsPhantom( ) )
+ return;
+
+ // draw root-sign itself
+ DrawSpecialNode( pNode );
+
+ SmTmpDevice2 aTmpDev( ( OutputDevice & ) rDev, true );
+ aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
+ rDev.SetLineColor( );
+ aTmpDev.SetFont( pNode->GetFont( ) );
+
+ // since the width is always unscaled it corresponds ot the _original_
+ // _unscaled_ font height to be used, we use that to calculate the
+ // bar height. Thus it is independent of the arguments height.
+ // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
+ long nBarHeight = pNode->GetWidth( ) * 7L / 100L;
+ long nBarWidth = pNode->GetBodyWidth( ) + pNode->GetBorderWidth( );
+ Point aBarOffset( pNode->GetWidth( ), +pNode->GetBorderWidth( ) );
+ Point aBarPos( Position + aBarOffset );
+
+ Rectangle aBar( aBarPos, Size( nBarWidth, nBarHeight ) );
+ //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
+ //! increasing zoomfactor.
+ // This is done by shifting it's output-position to a point that
+ // corresponds exactly to a pixel on the output device.
+ Point aDrawPos( rDev.PixelToLogic( rDev.LogicToPixel( aBar.TopLeft( ) ) ) );
+ aBar.SetPos( aDrawPos );
+
+ rDev.DrawRect( aBar );
+}
+
+void SmDrawingVisitor::Visit( SmPolyLineNode* pNode )
+{
+ if ( pNode->IsPhantom( ) )
+ return;
+
+ long nBorderwidth = pNode->GetFont( ).GetBorderWidth( );
+
+ LineInfo aInfo;
+ aInfo.SetWidth( pNode->GetWidth( ) - 2 * nBorderwidth );
+
+ Point aOffset ( Point( ) - pNode->GetPolygon( ).GetBoundRect( ).TopLeft( )
+ + Point( nBorderwidth, nBorderwidth ) ),
+ aPos ( Position + aOffset );
+ pNode->GetPolygon( ).Move( aPos.X( ), aPos.Y( ) ); //Works because Polygon wraps a pointer
+
+ SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, false );
+ aTmpDev.SetLineColor( pNode->GetFont( ).GetColor( ) );
+
+ rDev.DrawPolyLine( pNode->GetPolygon( ), aInfo );
+}
+
+void SmDrawingVisitor::Visit( SmRectangleNode* pNode )
+{
+ if ( pNode->IsPhantom( ) )
+ return;
+
+ SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, false );
+ aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
+ rDev.SetLineColor( );
+ aTmpDev.SetFont( pNode->GetFont( ) );
+
+ sal_uLong nTmpBorderWidth = pNode->GetFont( ).GetBorderWidth( );
+
+ // get rectangle and remove borderspace
+ Rectangle aTmp ( pNode->AsRectangle( ) + Position - pNode->GetTopLeft( ) );
+ aTmp.Left( ) += nTmpBorderWidth;
+ aTmp.Right( ) -= nTmpBorderWidth;
+ aTmp.Top( ) += nTmpBorderWidth;
+ aTmp.Bottom( ) -= nTmpBorderWidth;
+
+ DBG_ASSERT( aTmp.GetHeight( ) > 0 && aTmp.GetWidth( ) > 0,
+ "Sm: leeres Rechteck" );
+
+ //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
+ //! increasing zoomfactor.
+ // This is done by shifting it's output-position to a point that
+ // corresponds exactly to a pixel on the output device.
+ Point aPos ( rDev.PixelToLogic( rDev.LogicToPixel( aTmp.TopLeft( ) ) ) );
+ aTmp.SetPos( aPos );
+
+ rDev.DrawRect( aTmp );
+}
+
+void SmDrawingVisitor::DrawTextNode( SmTextNode* pNode )
+{
+ if ( pNode->IsPhantom( ) || pNode->GetText( ).Len( ) == 0 || pNode->GetText( ).GetChar( 0 ) == xub_Unicode( '\0' ) )
+ return;
+
+ SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, false );
+ aTmpDev.SetFont( pNode->GetFont( ) );
+
+ Point aPos ( Position );
+ aPos.Y( ) += pNode->GetBaselineOffset( );
+ // auf Pixelkoordinaten runden
+ aPos = rDev.PixelToLogic( rDev.LogicToPixel( aPos ) );
+
+ rDev.DrawStretchText( aPos, pNode->GetWidth( ), pNode->GetText( ) );
+}
+
+void SmDrawingVisitor::DrawSpecialNode( SmSpecialNode* pNode )
+{
+ //! since this chars might come from any font, that we may not have
+ //! set to ALIGN_BASELINE yet, we do it now.
+ pNode->GetFont( ).SetAlign( ALIGN_BASELINE );
+
+ DrawTextNode( pNode );
+}
+
+void SmDrawingVisitor::DrawChildren( SmNode* pNode )
+{
+ if ( pNode->IsPhantom( ) )
+ return;
+
+ Point rPosition = Position;
+
+ SmNodeIterator it( pNode );
+ while( it.Next( ) )
+ {
+ Point aOffset ( it->GetTopLeft( ) - pNode->GetTopLeft( ) );
+ Position = rPosition + aOffset;
+ it->Accept( this );
+ }
+}
+
+/////////////////////////////// SmSetSelectionVisitor ////////////////////////////////
+
+SmSetSelectionVisitor::SmSetSelectionVisitor( SmCaretPos startPos, SmCaretPos endPos, SmNode* pTree) {
+ StartPos = startPos;
+ EndPos = endPos;
+ IsSelecting = false;
+
+ //Assume that pTree is a SmTableNode
+ OSL_ENSURE(pTree->GetType() == NTABLE, "pTree should be a SmTableNode!");
+ //Visit root node, this is special as this node cannot be selected, but it's children can!
+ if(pTree->GetType() == NTABLE){
+ //Change state if StartPos is infront of this node
+ if( StartPos.pSelectedNode == pTree && StartPos.Index == 0 )
+ IsSelecting = !IsSelecting;
+ //Change state if EndPos is infront of this node
+ if( EndPos.pSelectedNode == pTree && EndPos.Index == 0 )
+ IsSelecting = !IsSelecting;
+ OSL_ENSURE(!IsSelecting, "Caret positions needed to set IsSelecting about, shouldn't be possible!");
+
+ //Visit lines
+ SmNodeIterator it( pTree );
+ while( it.Next( ) ) {
+ it->Accept( this );
+ //If we started a selection in this line and it haven't ended, we do that now!
+ if(IsSelecting) {
+ IsSelecting = false;
+ SetSelectedOnAll(it.Current(), true);
+ //Set StartPos and EndPos to invalid positions, this ensures that an unused
+ //start or end (because we forced end above), doesn't start a new selection.
+ StartPos = EndPos = SmCaretPos();
+ }
+ }
+ //Check if pTree isn't selected
+ OSL_ENSURE(!pTree->IsSelected(), "pTree should never be selected!");
+ //Discard the selection if there's a bug (it's better than crashing)
+ if(pTree->IsSelected())
+ SetSelectedOnAll(pTree, false);
+ }else //This shouldn't happen, but I don't see any reason to die if it does
+ pTree->Accept(this);
+}
+
+void SmSetSelectionVisitor::SetSelectedOnAll( SmNode* pSubTree, bool IsSelected ) {
+ pSubTree->SetSelected( IsSelected );
+
+ //Quick BFS to set all selections
+ SmNodeIterator it( pSubTree );
+ while( it.Next( ) )
+ SetSelectedOnAll( it.Current( ), IsSelected );
+}
+
+void SmSetSelectionVisitor::DefaultVisit( SmNode* pNode ) {
+ //Change state if StartPos is infront of this node
+ if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
+ IsSelecting = !IsSelecting;
+ //Change state if EndPos is infront of this node
+ if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
+ IsSelecting = !IsSelecting;
+
+ //Cache current state
+ bool WasSelecting = IsSelecting;
+ bool ChangedState = false;
+
+ //Set selected
+ pNode->SetSelected( IsSelecting );
+
+ //Visit children
+ SmNodeIterator it( pNode );
+ while( it.Next( ) )
+ {
+ it->Accept( this );
+ ChangedState = ( WasSelecting != IsSelecting ) || ChangedState;
+ }
+
+ //If state changed
+ if( ChangedState )
+ {
+ //Select this node and all of it's children
+ //(Make exception for SmBracebodyNode)
+ if( pNode->GetType() != NBRACEBODY ||
+ !pNode->GetParent() ||
+ pNode->GetParent()->GetType() != NBRACE )
+ SetSelectedOnAll( pNode, true );
+ else
+ SetSelectedOnAll( pNode->GetParent(), true );
+ /* If the equation is: sqrt{2 + 4} + 5
+ * And the selection is: sqrt{2 + [4} +] 5
+ * Where [ denotes StartPos and ] denotes EndPos
+ * Then the sqrt node should be selected, so that the
+ * effective selection is: [sqrt{2 + 4} +] 5
+ * The same is the case if we swap StartPos and EndPos.
+ */
+ }
+
+ //Change state if StartPos is after this node
+ if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
+ {
+ IsSelecting = !IsSelecting;
+ }
+ //Change state if EndPos is after of this node
+ if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
+ {
+ IsSelecting = !IsSelecting;
+ }
+}
+
+void SmSetSelectionVisitor::VisitCompositionNode( SmNode* pNode ) {
+ //Change state if StartPos is infront of this node
+ if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
+ IsSelecting = !IsSelecting;
+ //Change state if EndPos is infront of this node
+ if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
+ IsSelecting = !IsSelecting;
+
+ //Cache current state
+ bool WasSelecting = IsSelecting;
+
+ //Visit children
+ SmNodeIterator it( pNode );
+ while( it.Next( ) )
+ it->Accept( this );
+
+ //Set selected, if everything was selected
+ pNode->SetSelected( WasSelecting && IsSelecting );
+
+ //Change state if StartPos is after this node
+ if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
+ IsSelecting = !IsSelecting;
+ //Change state if EndPos is after of this node
+ if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
+ IsSelecting = !IsSelecting;
+}
+
+void SmSetSelectionVisitor::Visit( SmTextNode* pNode ) {
+ long i1 = -1,
+ i2 = -1;
+ if( StartPos.pSelectedNode == pNode )
+ i1 = StartPos.Index;
+ if( EndPos.pSelectedNode == pNode )
+ i2 = EndPos.Index;
+
+ long start, end;
+ pNode->SetSelected( true );
+ if( i1 != -1 && i2 != -1 ) {
+ start = i1 < i2 ? i1 : i2; //MIN
+ end = i1 > i2 ? i1 : i2; //MAX
+ } else if( IsSelecting && i1 != -1 ) {
+ start = 0;
+ end = i1;
+ IsSelecting = false;
+ } else if( IsSelecting && i2 != -1 ) {
+ start = 0;
+ end = i2;
+ IsSelecting = false;
+ } else if( !IsSelecting && i1 != -1 ) {
+ start = i1;
+ end = pNode->GetText( ).Len( );
+ IsSelecting = true;
+ } else if( !IsSelecting && i2 != -1 ) {
+ start = i2;
+ end = pNode->GetText( ).Len( );
+ IsSelecting = true;
+ } else if( IsSelecting ) {
+ start = 0;
+ end = pNode->GetText( ).Len( );
+ } else {
+ pNode->SetSelected( false );
+ start = 0;
+ end = 0;
+ }
+ pNode->SetSelected( start != end );
+ pNode->SetSelectionStart( start );
+ pNode->SetSelectionEnd( end );
+}
+
+void SmSetSelectionVisitor::Visit( SmExpressionNode* pNode ) {
+ VisitCompositionNode( pNode );
+}
+
+void SmSetSelectionVisitor::Visit( SmLineNode* pNode ) {
+ VisitCompositionNode( pNode );
+}
+
+void SmSetSelectionVisitor::Visit( SmAlignNode* pNode ) {
+ VisitCompositionNode( pNode );
+}
+
+void SmSetSelectionVisitor::Visit( SmBinHorNode* pNode ) {
+ VisitCompositionNode( pNode );
+}
+
+void SmSetSelectionVisitor::Visit( SmUnHorNode* pNode ) {
+ VisitCompositionNode( pNode );
+}
+
+void SmSetSelectionVisitor::Visit( SmFontNode* pNode ) {
+ VisitCompositionNode( pNode );
+}
+
+/////////////////////////////// SmCaretPosGraphBuildingVisitor ////////////////////////////////
+
+SmCaretPosGraphBuildingVisitor::SmCaretPosGraphBuildingVisitor( SmNode* pRootNode ) {
+ pRightMost = NULL;
+ pGraph = new SmCaretPosGraph( );
+ //pRootNode should always be a table
+ OSL_ENSURE( pRootNode->GetType( ) == NTABLE, "pRootNode must be a table node");
+ //Handle the special case where NTABLE is used a rootnode
+ if( pRootNode->GetType( ) == NTABLE ){
+ //Children are SmLineNodes
+ //Or so I thought... Aparently, the children can be instances of SmExpression
+ //especially if there's a error in the formula... So he we go, a simple work around.
+ SmNodeIterator it( pRootNode );
+ while( it.Next( ) ){
+ //There's a special invariant between this method and the Visit( SmLineNode* )
+ //Usually pRightMost may not be NULL, to avoid this pRightMost should here be
+ //set to a new SmCaretPos infront of it.Current( ), however, if it.Current( ) is
+ //an instance of SmLineNode we let SmLineNode create this position infront of
+ //the visual line.
+ //The argument for doing this is that we now don't have to worry about SmLineNode
+ //being a visual line composition node. Thus, no need for yet another special case
+ //in SmCursor::IsLineCompositionNode and everywhere this method is used.
+ //if( it->GetType( ) != NLINE )
+ pRightMost = pGraph->Add( SmCaretPos( it.Current( ), 0 ) );
+ it->Accept( this );
+ }
+ }else
+ pRootNode->Accept(this);
+}
+
+void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode* pNode ){
+ SmNodeIterator it( pNode );
+ while( it.Next( ) ){
+ it->Accept( this );
+ }
+}
+
+/** Build SmCaretPosGraph for SmTableNode
+ * This method covers cases where SmTableNode is used in a binom or stack,
+ * the special case where it is used as root node for the entire formula is
+ * handled in the constructor.
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmTableNode* pNode ){
+ SmCaretPosGraphEntry *left = pRightMost,
+ *right = pGraph->Add( SmCaretPos( pNode, 1) );
+ bool bIsFirst = true;
+ SmNodeIterator it( pNode );
+ while( it.Next() ){
+ pRightMost = pGraph->Add( SmCaretPos( it.Current(), 0 ), left);
+ if(bIsFirst)
+ left->SetRight(pRightMost);
+ it->Accept( this );
+ pRightMost->SetRight(right);
+ if(bIsFirst)
+ right->SetLeft(pRightMost);
+ bIsFirst = false;
+ }
+ pRightMost = right;
+}
+
+/** Build SmCaretPosGraph for SmSubSupNode
+ *
+ * The child positions in a SubSupNode, where H is the body:
+ * \code
+ * CSUP
+ *
+ * LSUP H H RSUP
+ * H H
+ * HHHH
+ * H H
+ * LSUB H H RSUB
+ *
+ * CSUB
+ * \endcode
+ *
+ * Graph over these, where "left" is before the SmSubSupNode and "right" is after:
+ * \dot
+ * digraph Graph{
+ * left -> H;
+ * H -> right;
+ * LSUP -> H;
+ * LSUB -> H;
+ * CSUP -> right;
+ * CSUB -> right;
+ * RSUP -> right;
+ * RSUB -> right;
+ * };
+ * \enddot
+ *
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode* pNode )
+{
+ SmCaretPosGraphEntry *left,
+ *right,
+ *bodyLeft,
+ *bodyRight;
+
+ left = pRightMost;
+ OSL_ENSURE( pRightMost, "pRightMost shouldn't be NULL here!" );
+
+ //Create bodyLeft
+ OSL_ENSURE( pNode->GetBody( ), "SmSubSupNode Doesn't have a body!" );
+ bodyLeft = pGraph->Add( SmCaretPos( pNode->GetBody( ), 0 ), left );
+ left->SetRight( bodyLeft ); //TODO: Don't make this if LSUP or LSUB are NULL ( not sure??? )
+
+ //Create right
+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
+
+ //Visit the body, to get bodyRight
+ pRightMost = bodyLeft;
+ pNode->GetBody( )->Accept( this );
+ bodyRight = pRightMost;
+ bodyRight->SetRight( right );
+ right->SetLeft( bodyRight );
+
+ SmNode* pChild;
+ //If there's an LSUP
+ if( ( pChild = pNode->GetSubSup( LSUP ) ) ){
+ SmCaretPosGraphEntry *cLeft; //Child left
+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
+
+ pRightMost = cLeft;
+ pChild->Accept( this );
+
+ pRightMost->SetRight( bodyLeft );
+ }
+ //If there's an LSUB
+ if( ( pChild = pNode->GetSubSup( LSUB ) ) ){
+ SmCaretPosGraphEntry *cLeft; //Child left
+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
+
+ pRightMost = cLeft;
+ pChild->Accept( this );
+
+ pRightMost->SetRight( bodyLeft );
+ }
+ //If there's an CSUP
+ if( ( pChild = pNode->GetSubSup( CSUP ) ) ){
+ SmCaretPosGraphEntry *cLeft; //Child left
+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
+
+ pRightMost = cLeft;
+ pChild->Accept( this );
+
+ pRightMost->SetRight( right );
+ }
+ //If there's an CSUB
+ if( ( pChild = pNode->GetSubSup( CSUB ) ) ){
+ SmCaretPosGraphEntry *cLeft; //Child left
+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
+
+ pRightMost = cLeft;
+ pChild->Accept( this );
+
+ pRightMost->SetRight( right );
+ }
+ //If there's an RSUP
+ if( ( pChild = pNode->GetSubSup( RSUP ) ) ){
+ SmCaretPosGraphEntry *cLeft; //Child left
+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
+
+ pRightMost = cLeft;
+ pChild->Accept( this );
+
+ pRightMost->SetRight( right );
+ }
+ //If there's an RSUB
+ if( ( pChild = pNode->GetSubSup( RSUB ) ) ){
+ SmCaretPosGraphEntry *cLeft; //Child left
+ cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
+
+ pRightMost = cLeft;
+ pChild->Accept( this );
+
+ pRightMost->SetRight( right );
+ }
+
+ //Set return parameters
+ pRightMost = right;
+}
+
+/** Build caret position for SmOperNode
+ *
+ * If first child is an SmSubSupNode we will ignore it's
+ * body, as this body is a SmMathSymbol, for SUM, INT or similar
+ * that shouldn't be subject to modification.
+ * If first child is not a SmSubSupNode, ignore it completely
+ * as it is a SmMathSymbol.
+ *
+ * The child positions in a SmOperNode, where H is symbol, e.g. int, sum or similar:
+ * \code
+ * TO
+ *
+ * LSUP H H RSUP BBB BB BBB B B
+ * H H B B B B B B B B
+ * HHHH BBB B B B B B
+ * H H B B B B B B B
+ * LSUB H H RSUB BBB BB BBB B
+ *
+ * FROM
+ * \endcode
+ * Notice, CSUP, etc. are actually granchildren, but inorder to ignore H, these are visited
+ * from here. If they are present, that is if pOper is an instance of SmSubSupNode.
+ *
+ * Graph over these, where "left" is before the SmOperNode and "right" is after:
+ * \dot
+ * digraph Graph{
+ * left -> BODY;
+ * BODY -> right;
+ * LSUP -> BODY;
+ * LSUB -> BODY;
+ * TO -> BODY;
+ * FROM -> BODY;
+ * RSUP -> BODY;
+ * RSUB -> BODY;
+ * };
+ * \enddot
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode* pNode )
+{
+ SmNode *pOper = pNode->GetSubNode( 0 ),
+ *pBody = pNode->GetSubNode( 1 );
+
+ SmCaretPosGraphEntry *left = pRightMost,
+ *bodyLeft,
+ *bodyRight,
+ *right;
+ //Create body left
+ bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
+ left->SetRight( bodyLeft );
+
+ //Visit body, get bodyRight
+ pRightMost = bodyLeft;
+ pBody->Accept( this );
+ bodyRight = pRightMost;
+
+ //Create right
+ right = pGraph->Add( SmCaretPos( pNode, 1 ), bodyRight );
+ bodyRight->SetRight( right );
+
+ //Get subsup pNode if any
+ SmSubSupNode* pSubSup = pOper->GetType( ) == NSUBSUP ? ( SmSubSupNode* )pOper : NULL;
+
+ SmNode* pChild;
+ SmCaretPosGraphEntry *childLeft;
+ if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
+ //Create position infront of pChild
+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
+ //Visit pChild
+ pRightMost = childLeft;
+ pChild->Accept( this );
+ //Set right on pRightMost from pChild
+ pRightMost->SetRight( bodyLeft );
+ }
+ if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
+ //Create position infront of pChild
+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
+ //Visit pChild
+ pRightMost = childLeft;
+ pChild->Accept( this );
+ //Set right on pRightMost from pChild
+ pRightMost->SetRight( bodyLeft );
+ }
+ if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {//TO
+ //Create position infront of pChild
+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
+ //Visit pChild
+ pRightMost = childLeft;
+ pChild->Accept( this );
+ //Set right on pRightMost from pChild
+ pRightMost->SetRight( bodyLeft );
+ }
+ if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUB ) ) ) { //FROM
+ //Create position infront of pChild
+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
+ //Visit pChild
+ pRightMost = childLeft;
+ pChild->Accept( this );
+ //Set right on pRightMost from pChild
+ pRightMost->SetRight( bodyLeft );
+ }
+ if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
+ //Create position infront of pChild
+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
+ //Visit pChild
+ pRightMost = childLeft;
+ pChild->Accept( this );
+ //Set right on pRightMost from pChild
+ pRightMost->SetRight( bodyLeft );
+ }
+ if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
+ //Create position infront of pChild
+ childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
+ //Visit pChild
+ pRightMost = childLeft;
+ pChild->Accept( this );
+ //Set right on pRightMost from pChild
+ pRightMost->SetRight( bodyLeft );
+ }
+
+ //Return right
+ pRightMost = right;
+}
+
+void SmCaretPosGraphBuildingVisitor::Visit( SmMatrixNode* pNode )
+{
+ SmCaretPosGraphEntry *left = pRightMost,
+ *right = pGraph->Add( SmCaretPos( pNode, 1 ) );
+
+ for ( sal_uInt16 i = 0; i < pNode->GetNumRows( ); i++ ) {
+ SmCaretPosGraphEntry* r = left;
+ for ( sal_uInt16 j = 0; j < pNode->GetNumCols( ); j++ ){
+ SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
+
+ pRightMost = pGraph->Add( SmCaretPos( pSubNode, 0 ), r );
+ if( j != 0 || ( pNode->GetNumRows( ) - 1 ) / 2 == i )
+ r->SetRight( pRightMost );
+
+ pSubNode->Accept( this );
+
+ r = pRightMost;
+ }
+ pRightMost->SetRight( right );
+ if( ( pNode->GetNumRows( ) - 1 ) / 2 == i )
+ right->SetLeft( pRightMost );
+ }
+
+ pRightMost = right;
+}
+
+/** Build SmCaretPosGraph for SmTextNode
+ *
+ * Lines in an SmTextNode:
+ * \code
+ * A B C
+ * \endcode
+ * Where A B and C are characters in the text.
+ *
+ * Graph over these, where "left" is before the SmTextNode and "right" is after:
+ * \dot
+ * digraph Graph{
+ * left -> A;
+ * A -> B
+ * B -> right;
+ * };
+ * \enddot
+ * Notice that C and right is the same position here.
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmTextNode* pNode )
+{
+ OSL_ENSURE( pNode->GetText( ).Len( ) > 0, "Empty SmTextNode is bad" );
+
+ int size = pNode->GetText( ).Len( );
+ for( int i = 1; i <= size; i++ ){
+ SmCaretPosGraphEntry* pRight = pRightMost;
+ pRightMost = pGraph->Add( SmCaretPos( pNode, i ), pRight );
+ pRight->SetRight( pRightMost );
+ }
+}
+
+/** Build SmCaretPosGraph for SmBinVerNode
+ *
+ * Lines in an SmBinVerNode:
+ * \code
+ * A
+ * -----
+ * B
+ * \endcode
+ *
+ * Graph over these, where "left" is before the SmBinVerNode and "right" is after:
+ * \dot
+ * digraph Graph{
+ * left -> A;
+ * A -> right;
+ * B -> right;
+ * };
+ * \enddot
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmBinVerNode* pNode )
+{
+ //None if these children can be NULL, see SmBinVerNode::Arrange
+ SmNode *pNum = pNode->GetSubNode( 0 ),
+ *pDenom = pNode->GetSubNode( 2 );
+
+ SmCaretPosGraphEntry *left,
+ *right,
+ *numLeft,
+ *denomLeft;
+
+ //Set left
+ left = pRightMost;
+ OSL_ENSURE( pRightMost, "There must be a position infront of this" );
+
+ //Create right
+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
+
+ //Create numLeft
+ numLeft = pGraph->Add( SmCaretPos( pNum, 0 ), left );
+ left->SetRight( numLeft );
+
+ //Visit pNum
+ pRightMost = numLeft;
+ pNum->Accept( this );
+ pRightMost->SetRight( right );
+ right->SetLeft( pRightMost );
+
+ //Create denomLeft
+ denomLeft = pGraph->Add( SmCaretPos( pDenom, 0 ), left );
+
+ //Visit pDenom
+ pRightMost = denomLeft;
+ pDenom->Accept( this );
+ pRightMost->SetRight( right );
+
+ //Set return parameter
+ pRightMost = right;
+}
+
+/** Build SmCaretPosGraph for SmVerticalBraceNode
+ *
+ * Lines in an SmVerticalBraceNode:
+ * \code
+ * pScript
+ * ________
+ * / \
+ * pBody
+ * \endcode
+ *
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmVerticalBraceNode* pNode )
+{
+ SmNode *pBody = pNode->GetSubNode( 0 ),
+ *pScript = pNode->GetSubNode( 2 );
+ //None of these children can be NULL
+
+ SmCaretPosGraphEntry *left,
+ *bodyLeft,
+ *scriptLeft,
+ *right;
+
+ left = pRightMost;
+
+ //Create right
+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
+
+ //Create bodyLeft
+ bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
+ left->SetRight( bodyLeft );
+ pRightMost = bodyLeft;
+ pBody->Accept( this );
+ pRightMost->SetRight( right );
+ right->SetLeft( pRightMost );
+
+ //Create script
+ scriptLeft = pGraph->Add( SmCaretPos( pScript, 0 ), left );
+ pRightMost = scriptLeft;
+ pScript->Accept( this );
+ pRightMost->SetRight( right );
+
+ //Set return value
+ pRightMost = right;
+}
+
+/** Build SmCaretPosGraph for SmBinDiagonalNode
+ *
+ * Lines in an SmBinDiagonalNode:
+ * \code
+ * A /
+ * /
+ * / B
+ * \endcode
+ * Where A and B are lines.
+ *
+ * Used in formulas such as "A wideslash B"
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmBinDiagonalNode* pNode )
+{
+ SmNode *A = pNode->GetSubNode( 0 ),
+ *B = pNode->GetSubNode( 1 );
+
+ SmCaretPosGraphEntry *left,
+ *leftA,
+ *rightA,
+ *leftB,
+ *right;
+ left = pRightMost;
+
+ //Create right
+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
+
+ //Create left A
+ leftA = pGraph->Add( SmCaretPos( A, 0 ), left );
+ left->SetRight( leftA );
+
+ //Visit A
+ pRightMost = leftA;
+ A->Accept( this );
+ rightA = pRightMost;
+
+ //Create left B
+ leftB = pGraph->Add( SmCaretPos( B, 0 ), rightA );
+ rightA->SetRight( leftB );
+
+ //Visit B
+ pRightMost = leftB;
+ B->Accept( this );
+ pRightMost->SetRight( right );
+ right->SetLeft( pRightMost );
+
+ //Set return value
+ pRightMost = right;
+}
+
+//Straigt forward ( I think )
+void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode* pNode )
+{
+ SmNodeIterator it( pNode );
+ while( it.Next( ) )
+ it->Accept( this );
+}
+void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode* pNode )
+{
+ // Unary operator node
+ SmNodeIterator it( pNode );
+ while( it.Next( ) )
+ it->Accept( this );
+
+}
+
+void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode* pNode )
+{
+ SmNodeIterator it( pNode );
+ while( it.Next( ) )
+ it->Accept( this );
+}
+
+void SmCaretPosGraphBuildingVisitor::Visit( SmFontNode* pNode )
+{
+ //Has only got one child, should act as an expression if possible
+ SmNodeIterator it( pNode );
+ while( it.Next( ) )
+ it->Accept( this );
+}
+
+/** Build SmCaretPosGraph for SmBracebodyNode
+ * Acts as an SmExpressionNode
+ *
+ * Below is an example of a formula tree that has multiple children for SmBracebodyNode
+ * \dot
+ * digraph {
+ * labelloc = "t";
+ * label= "Equation: \"lbrace i mline i in setZ rbrace\"";
+ * n0 [label="SmTableNode"];
+ * n0 -> n1 [label="0"];
+ * n1 [label="SmLineNode"];
+ * n1 -> n2 [label="0"];
+ * n2 [label="SmExpressionNode"];
+ * n2 -> n3 [label="0"];
+ * n3 [label="SmBraceNode"];
+ * n3 -> n4 [label="0"];
+ * n4 [label="SmMathSymbolNode: {"];
+ * n3 -> n5 [label="1"];
+ * n5 [label="SmBracebodyNode"];
+ * n5 -> n6 [label="0"];
+ * n6 [label="SmExpressionNode"];
+ * n6 -> n7 [label="0"];
+ * n7 [label="SmTextNode: i"];
+ * n5 -> n8 [label="1"];
+ * n8 [label="SmMathSymbolNode: ∣"];
+ * n5 -> n9 [label="2"];
+ * n9 [label="SmExpressionNode"];
+ * n9 -> n10 [label="0"];
+ * n10 [label="SmBinHorNode"];
+ * n10 -> n11 [label="0"];
+ * n11 [label="SmTextNode: i"];
+ * n10 -> n12 [label="1"];
+ * n12 [label="SmMathSymbolNode: ∈"];
+ * n10 -> n13 [label="2"];
+ * n13 [label="SmMathSymbolNode: ℤ"];
+ * n3 -> n14 [label="2"];
+ * n14 [label="SmMathSymbolNode: }"];
+ * }
+ * \enddot
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode* pNode )
+{
+ SmNodeIterator it( pNode );
+ while( it.Next( ) ) {
+ SmCaretPosGraphEntry* pStart = pGraph->Add( SmCaretPos( it.Current(), 0), pRightMost );
+ pRightMost->SetRight( pStart );
+ pRightMost = pStart;
+ it->Accept( this );
+ }
+}
+
+/** Build SmCaretPosGraph for SmAlignNode
+ * Acts as an SmExpressionNode, as it only has one child this okay
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmAlignNode* pNode )
+{
+ SmNodeIterator it( pNode );
+ while( it.Next( ) )
+ it->Accept( this );
+}
+
+/** Build SmCaretPosGraph for SmRootNode
+ *
+ * Lines in an SmRootNode:
+ * \code
+ * _________
+ * A/
+ * \/ B
+ *
+ * \endcode
+ * A: pExtra ( optional, can be NULL ),
+ * B: pBody
+ *
+ * Graph over these, where "left" is before the SmRootNode and "right" is after:
+ * \dot
+ * digraph Graph{
+ * left -> B;
+ * B -> right;
+ * A -> B;
+ * }
+ * \enddot
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode* pNode )
+{
+ SmNode *pExtra = pNode->GetSubNode( 0 ), //Argument, NULL for sqrt, and SmTextNode if cubicroot
+ *pBody = pNode->GetSubNode( 2 ); //Body of the root
+ OSL_ENSURE( pBody, "pBody cannot be NULL" );
+
+ SmCaretPosGraphEntry *left,
+ *right,
+ *bodyLeft,
+ *bodyRight;
+
+ //Get left and save it
+ OSL_ENSURE( pRightMost, "There must be a position infront of this" );
+ left = pRightMost;
+
+ //Create body left
+ bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
+ left->SetRight( bodyLeft );
+
+ //Create right
+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
+
+ //Visit body
+ pRightMost = bodyLeft;
+ pBody->Accept( this );
+ bodyRight = pRightMost;
+ bodyRight->SetRight( right );
+ right->SetLeft( bodyRight );
+
+ //Visit pExtra
+ if( pExtra ){
+ pRightMost = pGraph->Add( SmCaretPos( pExtra, 0 ), left );
+ pExtra->Accept( this );
+ pRightMost->SetRight( bodyLeft );
+ }
+
+ pRightMost = right;
+}
+
+/** Build SmCaretPosGraph for SmPlaceNode
+ * Consider this a single character.
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmPlaceNode* pNode )
+{
+ SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
+ pRightMost->SetRight( right );
+ pRightMost = right;
+}
+
+/** SmErrorNode is context dependent metadata, it can't be selected
+ *
+ * @remarks There's no point in deleting, copying and/or moving an instance
+ * of SmErrorNode as it may not exist in an other context! Thus there are no
+ * positions to select an SmErrorNode.
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmErrorNode* )
+{
+}
+
+/** Build SmCaretPosGraph for SmBlankNode
+ * Consider this a single character, as it is only a blank space
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmBlankNode* pNode )
+{
+ SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
+ pRightMost->SetRight( right );
+ pRightMost = right;
+}
+
+/** Build SmCaretPosGraph for SmBraceNode
+ *
+ * Lines in an SmBraceNode:
+ * \code
+ * | |
+ * | B |
+ * | |
+ * \endcode
+ * B: Body
+ *
+ * Graph over these, where "left" is before the SmBraceNode and "right" is after:
+ * \dot
+ * digraph Graph{
+ * left -> B;
+ * B -> right;
+ * }
+ * \enddot
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmBraceNode* pNode )
+{
+ SmNode* pBody = pNode->GetSubNode( 1 );
+
+ SmCaretPosGraphEntry *left = pRightMost,
+ *right = pGraph->Add( SmCaretPos( pNode, 1 ) );
+
+ if( pBody->GetType() != NBRACEBODY ) {
+ pRightMost = pGraph->Add( SmCaretPos( pBody, 0 ), left );
+ left->SetRight( pRightMost );
+ }else
+ pRightMost = left;
+
+ pBody->Accept( this );
+ pRightMost->SetRight( right );
+ right->SetLeft( pRightMost );
+
+ pRightMost = right;
+}
+
+/** Build SmCaretPosGraph for SmAttributNode
+ *
+ * Lines in an SmAttributNode:
+ * \code
+ * Attr
+ * Body
+ * \endcode
+ *
+ * There's a body and an attribute, the construction is used for "widehat A", where "A" is the body
+ * and "^" is the attribute ( note GetScaleMode( ) on SmAttributNode tells how the attribute should be
+ * scaled ).
+ */
+void SmCaretPosGraphBuildingVisitor::Visit( SmAttributNode* pNode )
+{
+ SmNode *pAttr = pNode->GetSubNode( 0 ),
+ *pBody = pNode->GetSubNode( 1 );
+ //None of the children can be NULL
+
+ SmCaretPosGraphEntry *left = pRightMost,
+ *attrLeft,
+ *bodyLeft,
+ *bodyRight,
+ *right;
+
+ //Creating bodyleft
+ bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
+ left->SetRight( bodyLeft );
+
+ //Creating right
+ right = pGraph->Add( SmCaretPos( pNode, 1 ) );
+
+ //Visit the body
+ pRightMost = bodyLeft;
+ pBody->Accept( this );
+ bodyRight = pRightMost;
+ bodyRight->SetRight( right );
+ right->SetLeft( bodyRight );
+
+ //Create attrLeft
+ attrLeft = pGraph->Add( SmCaretPos( pAttr, 0 ), left );
+
+ //Visit attribute
+ pRightMost = attrLeft;
+ pAttr->Accept( this );
+ pRightMost->SetRight( right );
+
+ //Set return value
+ pRightMost = right;
+}
+
+//Consider these single symboles
+void SmCaretPosGraphBuildingVisitor::Visit( SmSpecialNode* pNode )
+{
+ SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
+ pRightMost->SetRight( right );
+ pRightMost = right;
+}
+void SmCaretPosGraphBuildingVisitor::Visit( SmGlyphSpecialNode* pNode )
+{
+ SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
+ pRightMost->SetRight( right );
+ pRightMost = right;
+}
+void SmCaretPosGraphBuildingVisitor::Visit( SmMathSymbolNode* pNode )
+{
+ SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
+ pRightMost->SetRight( right );
+ pRightMost = right;
+}
+
+void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode* )
+{
+ //Do nothing
+}
+void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode* )
+{
+ //Do nothing
+}
+void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode* )
+{
+ //Do nothing
+}
+
+/////////////////////////////// SmCloningVisitor ///////////////////////////////
+
+SmNode* SmCloningVisitor::Clone( SmNode* pNode )
+{
+ SmNode* pCurrResult = pResult;
+ pNode->Accept( this );
+ SmNode* pClone = pResult;
+ pResult = pCurrResult;
+ return pClone;
+}
+
+void SmCloningVisitor::CloneNodeAttr( SmNode* pSource, SmNode* pTarget )
+{
+ pTarget->SetScaleMode( pSource->GetScaleMode( ) );
+ //Other attributes are set when prepare or arrange is executed
+ //and may depend on stuff not being cloned here.
+}
+
+void SmCloningVisitor::CloneKids( SmStructureNode* pSource, SmStructureNode* pTarget )
+{
+ //Cache current result
+ SmNode* pCurrResult = pResult;
+
+ //Create array for holding clones
+ sal_uInt16 nSize = pSource->GetNumSubNodes( );
+ SmNodeArray aNodes( nSize );
+
+ //Clone children
+ SmNode* pKid;
+ for( sal_uInt16 i = 0; i < nSize; i++ ){
+ if( NULL != ( pKid = pSource->GetSubNode( i ) ) )
+ pKid->Accept( this );
+ else
+ pResult = NULL;
+ aNodes[i] = pResult;
+ }
+
+ //Set subnodes of pTarget
+ pTarget->SetSubNodes( aNodes );
+
+ //Restore result as where prior to call
+ pResult = pCurrResult;
+}
+
+void SmCloningVisitor::Visit( SmTableNode* pNode )
+{
+ SmTableNode* pClone = new SmTableNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmBraceNode* pNode )
+{
+ SmBraceNode* pClone = new SmBraceNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmBracebodyNode* pNode )
+{
+ SmBracebodyNode* pClone = new SmBracebodyNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmOperNode* pNode )
+{
+ SmOperNode* pClone = new SmOperNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmAlignNode* pNode )
+{
+ SmAlignNode* pClone = new SmAlignNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmAttributNode* pNode )
+{
+ SmAttributNode* pClone = new SmAttributNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmFontNode* pNode )
+{
+ SmFontNode* pClone = new SmFontNode( pNode->GetToken( ) );
+ pClone->SetSizeParameter( pNode->GetSizeParameter( ), pNode->GetSizeType( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmUnHorNode* pNode )
+{
+ SmUnHorNode* pClone = new SmUnHorNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmBinHorNode* pNode )
+{
+ SmBinHorNode* pClone = new SmBinHorNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmBinVerNode* pNode )
+{
+ SmBinVerNode* pClone = new SmBinVerNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmBinDiagonalNode* pNode )
+{
+ SmBinDiagonalNode *pClone = new SmBinDiagonalNode( pNode->GetToken( ) );
+ pClone->SetAscending( pNode->IsAscending( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmSubSupNode* pNode )
+{
+ SmSubSupNode *pClone = new SmSubSupNode( pNode->GetToken( ) );
+ pClone->SetUseLimits( pNode->IsUseLimits( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmMatrixNode* pNode )
+{
+ SmMatrixNode *pClone = new SmMatrixNode( pNode->GetToken( ) );
+ pClone->SetRowCol( pNode->GetNumRows( ), pNode->GetNumCols( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmPlaceNode* pNode )
+{
+ pResult = new SmPlaceNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pResult );
+}
+
+void SmCloningVisitor::Visit( SmTextNode* pNode )
+{
+ SmTextNode* pClone = new SmTextNode( pNode->GetToken( ), pNode->GetFontDesc( ) );
+ pClone->ChangeText( pNode->GetText( ) );
+ CloneNodeAttr( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmSpecialNode* pNode )
+{
+ pResult = new SmSpecialNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pResult );
+}
+
+void SmCloningVisitor::Visit( SmGlyphSpecialNode* pNode )
+{
+ pResult = new SmGlyphSpecialNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pResult );
+}
+
+void SmCloningVisitor::Visit( SmMathSymbolNode* pNode )
+{
+ pResult = new SmMathSymbolNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pResult );
+}
+
+void SmCloningVisitor::Visit( SmBlankNode* pNode )
+{
+ SmBlankNode* pClone = new SmBlankNode( pNode->GetToken( ) );
+ pClone->SetBlankNum( pNode->GetBlankNum( ) );
+ pResult = pClone;
+ CloneNodeAttr( pNode, pResult );
+}
+
+void SmCloningVisitor::Visit( SmErrorNode* pNode )
+{
+ //PE_NONE is used the information have been discarded and isn't used
+ pResult = new SmErrorNode( PE_NONE, pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pResult );
+}
+
+void SmCloningVisitor::Visit( SmLineNode* pNode )
+{
+ SmLineNode* pClone = new SmLineNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmExpressionNode* pNode )
+{
+ SmExpressionNode* pClone = new SmExpressionNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmPolyLineNode* pNode )
+{
+ pResult = new SmPolyLineNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pResult );
+}
+
+void SmCloningVisitor::Visit( SmRootNode* pNode )
+{
+ SmRootNode* pClone = new SmRootNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+void SmCloningVisitor::Visit( SmRootSymbolNode* pNode )
+{
+ pResult = new SmRootSymbolNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pResult );
+}
+
+void SmCloningVisitor::Visit( SmRectangleNode* pNode )
+{
+ pResult = new SmRectangleNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pResult );
+}
+
+void SmCloningVisitor::Visit( SmVerticalBraceNode* pNode )
+{
+ SmVerticalBraceNode* pClone = new SmVerticalBraceNode( pNode->GetToken( ) );
+ CloneNodeAttr( pNode, pClone );
+ CloneKids( pNode, pClone );
+ pResult = pClone;
+}
+
+/////////////////////////////// SmSelectionDrawingVisitor ///////////////////////////////
+
+SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, Point Offset )
+ : rDev( rDevice ) {
+ bHasSelectionArea = false;
+
+ //Visit everything
+ OSL_ENSURE( pTree, "pTree can't be null!" );
+ if( pTree )
+ pTree->Accept( this );
+
+ //Draw selection if there's any
+ if( bHasSelectionArea ){
+ aSelectionArea.Move( Offset.X( ), Offset.Y( ) );
+
+ //Save device state
+ rDev.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
+ //Change colors
+ rDev.SetLineColor( );
+ rDev.SetFillColor( Color( COL_LIGHTGRAY ) );
+
+ //Draw rectangle
+ rDev.DrawRect( aSelectionArea );
+
+ //Restore device state
+ rDev.Pop( );
+ }
+}
+
+void SmSelectionDrawingVisitor::ExtendSelectionArea( Rectangle aArea )
+{
+ if ( ! bHasSelectionArea ) {
+ aSelectionArea = aArea;
+ bHasSelectionArea = true;
+ } else
+ aSelectionArea.Union( aArea );
+}
+
+void SmSelectionDrawingVisitor::DefaultVisit( SmNode* pNode )
+{
+ if( pNode->IsSelected( ) )
+ ExtendSelectionArea( pNode->AsRectangle( ) );
+ VisitChildren( pNode );
+}
+
+void SmSelectionDrawingVisitor::VisitChildren( SmNode* pNode )
+{
+ SmNodeIterator it( pNode );
+ while( it.Next( ) )
+ it->Accept( this );
+}
+
+void SmSelectionDrawingVisitor::Visit( SmTextNode* pNode )
+{
+ if( pNode->IsSelected( ) ){
+ rDev.Push( PUSH_TEXTCOLOR | PUSH_FONT );
+
+ rDev.SetFont( pNode->GetFont( ) );
+ Point Position = pNode->GetTopLeft( );
+ long left = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionStart( ) );
+ long right = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionEnd( ) );
+ long top = Position.getY( );
+ long bottom = top + pNode->GetHeight( );
+ Rectangle rect( left, top, right, bottom );
+
+ ExtendSelectionArea( rect );
+
+ rDev.Pop( );
+ }
+}
+
+/////////////////////////////// SmNodeToTextVisitor ///////////////////////////////
+
+void SmNodeToTextVisitor::Visit( SmTableNode* pNode )
+{
+ if( pNode->GetToken( ).eType == TBINOM ) {
+ Append( "{ binom" );
+ LineToText( pNode->GetSubNode( 0 ) );
+ LineToText( pNode->GetSubNode( 1 ) );
+ Append("} ");
+ } else if( pNode->GetToken( ).eType == TSTACK ) {
+ Append( "stack{ " );
+ SmNodeIterator it( pNode );
+ it.Next( );
+ while( true ) {
+ LineToText( it.Current( ) );
+ if( it.Next( ) ) {
+ Separate( );
+ Append( "# " );
+ }else
+ break;
+ }
+ Separate( );
+ Append( "}" );
+ } else { //Assume it's a toplevel table, containing lines
+ SmNodeIterator it( pNode );
+ it.Next( );
+ while( true ) {
+ Separate( );
+ it->Accept( this );
+ if( it.Next( ) ) {
+ Separate( );
+ Append( "newline" );
+ }else
+ break;
+ }
+ }
+}
+
+void SmNodeToTextVisitor::Visit( SmBraceNode* pNode )
+{
+ SmNode *pLeftBrace = pNode->GetSubNode( 0 ),
+ *pBody = pNode->GetSubNode( 1 ),
+ *pRightBrace = pNode->GetSubNode( 2 );
+ //Handle special case where it's absolute function
+ if( pNode->GetToken( ).eType == TABS ) {
+ Append( "abs" );
+ LineToText( pBody );
+ } else {
+ if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
+ Append( "left " );
+ pLeftBrace->Accept( this );
+ Separate( );
+ pBody->Accept( this );
+ Separate( );
+ if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
+ Append( "right " );
+ pRightBrace->Accept( this );
+ }
+}
+
+void SmNodeToTextVisitor::Visit( SmBracebodyNode* pNode )
+{
+ SmNodeIterator it( pNode );
+ while( it.Next( ) ){
+ Separate( );
+ it->Accept( this );
+ }
+}
+
+void SmNodeToTextVisitor::Visit( SmOperNode* pNode )
+{
+ Append( pNode->GetToken( ).aText );
+ Separate( );
+ if( pNode->GetToken( ).eType == TOPER ){
+ //There's an SmGlyphSpecialNode if eType == TOPER
+ if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP )
+ Append( pNode->GetSubNode( 0 )->GetSubNode( 0 )->GetToken( ).aText );
+ else
+ Append( pNode->GetSubNode( 0 )->GetToken( ).aText );
+ }
+ if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP ) {
+ SmSubSupNode *pSubSup = ( SmSubSupNode* )pNode->GetSubNode( 0 );
+ SmNode* pChild;
+ if( ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
+ Separate( );
+ Append( "lsup { " );
+ LineToText( pChild );
+ Append( "} " );
+ }
+ if( ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
+ Separate( );
+ Append( "lsub { " );
+ LineToText( pChild );
+ Append( "} " );
+ }
+ if( ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
+ Separate( );
+ Append( "rsup { " );
+ LineToText( pChild );
+ Append( "} " );
+ }
+ if( ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
+ Separate( );
+ Append( "rsub { " );
+ LineToText( pChild );
+ Append( "} " );
+ }
+ if( ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {
+ Separate( );
+ Append( "csup { " );
+ LineToText( pChild );
+ Append( "} " );
+ }
+ if( ( pChild = pSubSup->GetSubSup( CSUB ) ) ) {
+ Separate( );
+ Append( "csub { " );
+ LineToText( pChild );
+ Append( "} " );
+ }
+ }
+ LineToText( pNode->GetSubNode( 1 ) );
+}
+
+void SmNodeToTextVisitor::Visit( SmAlignNode* pNode )
+{
+ Append( pNode->GetToken( ).aText );
+ LineToText( pNode->GetSubNode( 0 ) );
+}
+
+void SmNodeToTextVisitor::Visit( SmAttributNode* pNode )
+{
+ Append( pNode->GetToken( ).aText );
+ LineToText( pNode->GetSubNode( 1 ) );
+}
+
+void SmNodeToTextVisitor::Visit( SmFontNode* pNode )
+{
+ switch ( pNode->GetToken( ).eType )
+ {
+ case TBOLD:
+ Append( "bold " );
+ break;
+ case TNBOLD:
+ Append( "nbold " );
+ break;
+ case TITALIC:
+ Append( "italic " );
+ break;
+ case TNITALIC:
+ Append( "nitalic " );
+ break;
+ case TPHANTOM:
+ Append( "phantom " );
+ break;
+ case TSIZE:
+ {
+ Append( "size " );
+ switch ( pNode->GetSizeType( ) )
+ {
+ case FNTSIZ_PLUS:
+ Append( "+" );
+ break;
+ case FNTSIZ_MINUS:
+ Append( "-" );
+ break;
+ case FNTSIZ_MULTIPLY:
+ Append( "*" );
+ break;
+ case FNTSIZ_DIVIDE:
+ Append( "/" );
+ break;
+ case FNTSIZ_ABSOLUT:
+ default:
+ break;
+ }
+ Append( String( ::rtl::math::doubleToUString(
+ static_cast<double>( pNode->GetSizeParameter( ) ),
+ rtl_math_StringFormat_Automatic,
+ rtl_math_DecimalPlaces_Max, '.', sal_True ) ) );
+ Append( " " );
+ }
+ break;
+ case TBLACK:
+ Append( "color black " );
+ break;
+ case TWHITE:
+ Append( "color white " );
+ break;
+ case TRED:
+ Append( "color red " );
+ break;
+ case TGREEN:
+ Append( "color green " );
+ break;
+ case TBLUE:
+ Append( "color blue " );
+ break;
+ case TCYAN:
+ Append( "color cyan " );
+ break;
+ case TMAGENTA:
+ Append( "color magenta " );
+ break;
+ case TYELLOW:
+ Append( "color yellow " );
+ break;
+ case TSANS:
+ Append( "font sans " );
+ break;
+ case TSERIF:
+ Append( "font serif " );
+ break;
+ case TFIXED:
+ Append( "font fixed " );
+ break;
+ default:
+ break;
+ }
+ LineToText( pNode->GetSubNode( 1 ) );
+}
+
+void SmNodeToTextVisitor::Visit( SmUnHorNode* pNode )
+{
+ SmNodeIterator it( pNode, pNode->GetSubNode( 1 )->GetToken( ).eType == TFACT );
+ while( it.Next( ) ) {
+ Separate( );
+ it->Accept( this );
+ }
+}
+
+void SmNodeToTextVisitor::Visit( SmBinHorNode* pNode )
+{
+ SmNode *pLeft = pNode->GetSubNode( 0 ),
+ *pOper = pNode->GetSubNode( 1 ),
+ *pRight = pNode->GetSubNode( 2 );
+ Separate( );
+ pLeft->Accept( this );
+ Separate( );
+ pOper->Accept( this );
+ Separate( );
+ pRight->Accept( this );
+ Separate( );
+}
+
+void SmNodeToTextVisitor::Visit( SmBinVerNode* pNode )
+{
+ SmNode *pNum = pNode->GetSubNode( 0 ),
+ *pDenom = pNode->GetSubNode( 2 );
+ Append( "{ " );
+ LineToText( pNum );
+ Append( "over" );
+ LineToText( pDenom );
+ Append( "} " );
+}
+
+void SmNodeToTextVisitor::Visit( SmBinDiagonalNode* pNode )
+{
+ SmNode *pLeftOperand = pNode->GetSubNode( 0 ),
+ *pRightOperand = pNode->GetSubNode( 1 );
+ Append( "{ " );
+ LineToText( pLeftOperand );
+ Separate( );
+ Append( "wideslash " );
+ LineToText( pRightOperand );
+ Append( "} " );
+}
+
+void SmNodeToTextVisitor::Visit( SmSubSupNode* pNode )
+{
+ LineToText( pNode->GetBody( ) );
+ SmNode *pChild;
+ if( ( pChild = pNode->GetSubSup( LSUP ) ) ) {
+ Separate( );
+ Append( "lsup " );
+ LineToText( pChild );
+ }
+ if( ( pChild = pNode->GetSubSup( LSUB ) ) ) {
+ Separate( );
+ Append( "lsub " );
+ LineToText( pChild );
+ }
+ if( ( pChild = pNode->GetSubSup( RSUP ) ) ) {
+ Separate( );
+ Append( "rsup " );
+ LineToText( pChild );
+ }
+ if( ( pChild = pNode->GetSubSup( RSUB ) ) ) {
+ Separate( );
+ Append( "rsub " );
+ LineToText( pChild );
+ }
+ if( ( pChild = pNode->GetSubSup( CSUP ) ) ) {
+ Separate( );
+ Append( "csup " );
+ LineToText( pChild );
+ }
+ if( ( pChild = pNode->GetSubSup( CSUB ) ) ) {
+ Separate( );
+ Append( "csub " );
+ LineToText( pChild );
+ }
+}
+
+void SmNodeToTextVisitor::Visit( SmMatrixNode* pNode )
+{
+ Append( "matrix{" );
+ for ( sal_uInt16 i = 0; i < pNode->GetNumRows( ); i++ ) {
+ for ( sal_uInt16 j = 0; j < pNode->GetNumCols( ); j++ ) {
+ SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
+ Separate( );
+ pSubNode->Accept( this );
+ Separate( );
+ if( j != pNode->GetNumCols( ) - 1 )
+ Append( "#" );
+ }
+ Separate( );
+ if( i != pNode->GetNumRows( ) - 1 )
+ Append( "##" );
+ }
+ Append( "} " );
+}
+
+void SmNodeToTextVisitor::Visit( SmPlaceNode* )
+{
+ Append( "<?>" );
+}
+
+void SmNodeToTextVisitor::Visit( SmTextNode* pNode )
+{
+ //TODO: This method might need improvements, see SmTextNode::CreateTextFromNode
+ if( pNode->GetToken( ).eType == TTEXT )
+ Append( "\"" );
+ Append( pNode->GetText( ) );
+ if( pNode->GetToken( ).eType == TTEXT )
+ Append( "\"" );
+}
+
+void SmNodeToTextVisitor::Visit( SmSpecialNode* pNode )
+{
+ Append( pNode->GetToken( ).aText );
+}
+
+void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode* pNode )
+{
+ if( pNode->GetToken( ).eType == TBOPER )
+ Append( "boper " );
+ else
+ Append( "uoper " );
+ Append( pNode->GetToken( ).aText );
+}
+
+void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
+{
+ Append( pNode->GetToken( ).aText );
+}
+
+void SmNodeToTextVisitor::Visit( SmBlankNode* pNode )
+{
+ Append( pNode->GetToken( ).aText );
+}
+
+void SmNodeToTextVisitor::Visit( SmErrorNode* )
+{
+}
+
+void SmNodeToTextVisitor::Visit( SmLineNode* pNode )
+{
+ SmNodeIterator it( pNode );
+ while( it.Next( ) ){
+ Separate( );
+ it->Accept( this );
+ }
+}
+
+void SmNodeToTextVisitor::Visit( SmExpressionNode* pNode )
+{
+ bool bracketsNeeded = pNode->GetNumSubNodes() != 1 || pNode->GetSubNode(0)->GetType() == NBINHOR;
+ if (bracketsNeeded) {
+ Append( "{ " );
+ }
+ SmNodeIterator it( pNode );
+ while( it.Next( ) ) {
+ it->Accept( this );
+ Separate( );
+ }
+ if (bracketsNeeded) {
+ Append( "} " );
+ }
+}
+
+void SmNodeToTextVisitor::Visit( SmPolyLineNode* )
+{
+}
+
+void SmNodeToTextVisitor::Visit( SmRootNode* pNode )
+{
+ SmNode *pExtra = pNode->GetSubNode( 0 ),
+ *pBody = pNode->GetSubNode( 2 );
+ if( pExtra ) {
+ Append( "nroot" );
+ LineToText( pExtra );
+ } else
+ Append( "sqrt" );
+ LineToText( pBody );
+}
+
+void SmNodeToTextVisitor::Visit( SmRootSymbolNode* )
+{
+}
+
+void SmNodeToTextVisitor::Visit( SmRectangleNode* )
+{
+}
+
+void SmNodeToTextVisitor::Visit( SmVerticalBraceNode* pNode )
+{
+ SmNode *pBody = pNode->GetSubNode( 0 ),
+ *pScript = pNode->GetSubNode( 2 );
+ LineToText( pBody );
+ Append( pNode->GetToken( ).aText );
+ LineToText( pScript );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */