[ooo-build-commit] .: 6 commits - patches/dev300

Cédric Bosdonnat cbosdo at kemper.freedesktop.org
Wed Sep 22 12:41:47 PDT 2010


 patches/dev300/apply                   |    8 
 patches/dev300/maths_baseline_fix.diff |  835 +++
 patches/dev300/online_gallery.diff     | 2307 +++++++++
 patches/dev300/sc-single-right.diff    |  603 ++
 patches/dev300/sd_effects_styles.diff  | 3821 +++++++++++++++
 patches/dev300/symbols-20-august.diff  |  238 
 patches/dev300/vEdit-13-August.diff    | 7896 +++++++++++++++++++++++++++++++++
 7 files changed, 15707 insertions(+), 1 deletion(-)

New commits:
commit b0bb9d72d1756b5fde48abba5dee4cc5b95cf277
Author: Cédric Bosdonnat <cedricbosdo at openoffice.org>
Date:   Wed Sep 22 21:40:51 2010 +0200

    Added the GSoc student's patches to their section

diff --git a/patches/dev300/apply b/patches/dev300/apply
index e253e41..73e91ce 100644
--- a/patches/dev300/apply
+++ b/patches/dev300/apply
@@ -2954,9 +2954,15 @@ oox-pptx-import-fix-groups-2.diff, n#619678, rodo
 # soffice process doesn't block ( under linux ) connect
 # to raised office instance instead ( should work for windows too )
 smoketest-officeconnection-fix.diff
-[ GSoC2010 ]
 
+[ GSoC2010 ]
 # Patches from GSoC 2010 students.
+maths_baseline_fix.diff, i#972, spiso
+online_gallery.diff, tijana
+sc-single-right.diff, td123
+sd_effects_styles.diff, pixie
+symbols-20-august.diff, i#11167, jopsen
+vEdit-13-August.diff, jopsen
 
 [ OOXML ]
 oox-pptx-import-fix-placeholder-text-style.diff, n#592906, n#479834, rodo
commit ccc534c27bc51526a291e21797ac337a7a695346
Author: Thomas Dziedzic <tdziedz2 at illinois.edu>
Date:   Wed Sep 22 21:40:32 2010 +0200

    Pushed Thomas' patch AS IS

diff --git a/patches/dev300/sc-single-right.diff b/patches/dev300/sc-single-right.diff
new file mode 100644
index 0000000..51f54e4
--- /dev/null
+++ b/patches/dev300/sc-single-right.diff
@@ -0,0 +1,603 @@
+--- sc/source/ui/view/gridwin.cxx.orig2	2010-08-10 11:27:53.922000033 -0500
++++ sc/source/ui/view/gridwin.cxx	2010-08-15 22:09:59.868000093 -0500
+@@ -123,6 +123,8 @@
+ #include "cellsh.hxx"
+ #include "overlayobject.hxx"
+ 
++#include "popmenu.hxx"
++
+ #include "drawview.hxx"
+ #include <svx/sdrpagewindow.hxx>
+ #include <svx/sdr/overlay/overlaymanager.hxx>
+@@ -449,7 +451,8 @@
+             nPaintCount( 0 ),
+             bNeedsRepaint( FALSE ),
+             bAutoMarkVisible( FALSE ),
+-            bListValButton( FALSE )
++            bListValButton( FALSE ),
++            bMoveSingle( false )
+ {
+     switch(eWhich)
+     {
+@@ -1512,6 +1515,29 @@
+ 
+     aCurMousePos = rMEvt.GetPosPixel();
+ 
++    std::vector<Rectangle> aPixelRects;
++    GetSelectionRects( aPixelRects );
++
++    // is there a better way to test if the selected rectangle is only 1 cell
++    BOOL test;
++    std::vector<Rectangle>::iterator it = aPixelRects.begin();
++    if( aPixelRects.size() )
++        test = it->Top() == it->Bottom() && it->Left() == it->Right();
++
++    ScRange aRange;
++    ScMarkType eMarkType = pViewData->GetSimpleArea( aRange );
++
++    if( bMoveSingle && /*rMEvt.IsLeft() &&*/ ( ( eMarkType != SC_MARK_MULTI && test ) || !pViewData->GetMarkData().IsMarked() ) )
++    {
++        //bMoveSingle = false;
++
++        SCCOL nCol = pViewData->GetCurX();
++        SCROW nRow = pViewData->GetCurY();
++        SCTAB nTab = pViewData->GetTabNo();
++
++        pViewData->GetView()->MarkCursor( nCol, nRow, nTab );
++    }
++
+     //	Filter-Popup beendet sich mit eigenem Mausklick, nicht erst beim Klick
+     //	in das GridWindow, darum ist die folgende Abfrage nicht mehr noetig:
+ #if 0
+@@ -1783,7 +1809,7 @@
+             //		Gridwin - SelectionEngine
+             //
+ 
+-    if ( rMEvt.IsLeft() )
++    if ( rMEvt.IsLeft() || ( rMEvt.IsRight() && bMoveSingle ) )
+     {
+         ScViewSelectionEngine* pSelEng = pViewData->GetView()->GetSelEngine();
+         pSelEng->SetWindow(this);
+@@ -2257,6 +2283,8 @@
+ 
+ void __EXPORT ScGridWindow::MouseMove( const MouseEvent& rMEvt )
+ {
++    bMoveSingle = false;
++
+     aCurMousePos = rMEvt.GetPosPixel();
+ 
+     if ( rMEvt.IsLeaveWindow() && pNoteMarker && !pNoteMarker->IsByKeyboard() )
+@@ -2446,14 +2474,48 @@
+         {
+             BOOL bAlt = rMEvt.IsMod2();
+ 
++            //ScMarkData& rMark = pViewData->GetMarkData();
++            //EditView* pEditView = pViewData->GetEditView( eWhich );
++            //Cursor* pCur = pEditView->GetCursor();
++            //SCTAB nTab = pViewData->GetTabNo();
++            SCCOL nX = pViewData->GetCurX();
++            SCROW nY = pViewData->GetCurY();
++            Point aScrPos = pViewData->GetScrPos( nX, nY, eWhich, TRUE );
++
++            long nSizeXPix;
++            long nSizeYPix;
++
++            // get dimensions of cursor
++            pViewData->GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix );
++
++
++            BOOL bLeft   = ((aCurMousePos.X() >= aScrPos.X() && aCurMousePos.X() <= aScrPos.X() + 1) && aCurMousePos.Y() >= aScrPos.Y() && aCurMousePos.Y() <= aScrPos.Y() + nSizeYPix );
++            BOOL bTop    = ((aCurMousePos.Y() >= aScrPos.Y() && aCurMousePos.Y() <= aScrPos.Y() + 1) && aCurMousePos.X() >= aScrPos.X() && aCurMousePos.X() <= aScrPos.X() + nSizeXPix );
++            // bottom and right borders actually count as the next cells that's why we do == instead of by range
++            // need to fix checking if click is on border but changes to a different cell or is this desireable?
++            BOOL bBottom = ((aCurMousePos.Y() == aScrPos.Y() + nSizeYPix - 1) &&
++                             aCurMousePos.X() >= aScrPos.X() && aCurMousePos.X() <= aScrPos.X() + nSizeXPix );
++            BOOL bRight  = ((aCurMousePos.X() == aScrPos.X() + nSizeXPix - 1) &&
++                             aCurMousePos.Y() >= aScrPos.Y() && aCurMousePos.Y() <= aScrPos.Y() + nSizeYPix );
++            //BOOL bBottom = ((aCurMousePos.Y() >= aScrPos.Y() + nSizeYPix - 1 && aCurMousePos.Y() <= aScrPos.Y() + nSizeYPix + 1) &&
++            //                 aCurMousePos.X() >= aScrPos.X() && aCurMousePos.X() <= aScrPos.X() + nSizeXPix );
++            //BOOL bRight  = ((aCurMousePos.X() >= aScrPos.X() + nSizeXPix - 1 && aCurMousePos.X() <= aScrPos.X() + nSizeXPix + 1) &&
++            //                 aCurMousePos.Y() >= aScrPos.Y() && aCurMousePos.Y() <= aScrPos.Y() + nSizeYPix );
++
+             if (bEditMode)									// Edit-Mode muss zuerst kommen!
+                 SetPointer( Pointer( POINTER_ARROW ) );
+-            else if ( !bAlt && !nButtonDown &&
+-                        GetEditUrl(rMEvt.GetPosPixel()) )
++            else if ( !bAlt && !nButtonDown && GetEditUrl(rMEvt.GetPosPixel()) )
+                 SetPointer( Pointer( POINTER_REFHAND ) );
++            else if ( ( bLeft || bTop || bBottom || bRight ) )
++            {
++                SetPointer( Pointer( POINTER_MOVE ) );
++                bMoveSingle = TRUE;
++                return;
++            }
+             else if ( DrawMouseMove(rMEvt) )				// setzt Pointer um
+                 return;
+         }
++
+     }
+ 
+     if ( pViewData->GetView()->GetSelEngine()->SelMouseMove( rMEvt ) )
+@@ -2765,6 +2827,12 @@
+ 
+     if ( nCmd == COMMAND_CONTEXTMENU && !SC_MOD()->GetIsWaterCan() )
+     {
++        // don't display context menu when we are over the cursor border, to implement right click dragging
++        if (bMoveSingle)
++        {
++            return;
++        }
++
+         if (pViewData->IsAnyFillMode())
+         {
+             pViewData->GetView()->StopRefMode();
+@@ -3832,11 +3900,11 @@
+     const ScDragData& rData = pScMod->GetDragData();
+ 
+     return DropTransferObj( rData.pCellTransfer, nDragStartX, nDragStartY,
+-                                PixelToLogic(rEvt.maPosPixel), rEvt.mnAction );
++                                PixelToLogic(rEvt.maPosPixel), rEvt.maPosPixel, rEvt.mnAction );
+ }
+ 
+ sal_Int8 ScGridWindow::DropTransferObj( ScTransferObj* pTransObj, SCCOL nDestPosX, SCROW nDestPosY,
+-                                        const Point& rLogicPos, sal_Int8 nDndAction )
++                                        const Point& rLogicPos, const Point& rMousePos, sal_Int8 nDndAction )
+ {
+     if ( !pTransObj )
+         return 0;
+@@ -3859,6 +3927,8 @@
+         bIsMove = ( nDndAction & DND_ACTION_MOVE && !bIsNavi );
+     }
+ 
++    bool bIsRight = ( nDndAction == DND_ACTION_RIGHT && !bIsNavi );
++
+     BOOL bIsLink = ( nDndAction == DND_ACTION_LINK );
+ 
+     ScRange aSource = pTransObj->GetRange();
+@@ -3949,6 +4019,7 @@
+                 {
+                     // call with bApi = TRUE to avoid error messages in drop handler
+                     bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, TRUE /*bRecord*/, TRUE /*bApi*/, TRUE /*bPartOfPaste*/ );
++
+                     if ( bDone )
+                     {
+                         if ( nThisTab == nSourceTab )
+@@ -3976,6 +4047,195 @@
+                         // call with bApi = TRUE to avoid error messages in drop handler
+                         bDone = pView->LinkBlock( aSource, aDest.aStart, TRUE /*bApi*/ );
+                     }
++                    else if ( bIsRight )
++                    {
++                        ScPopupMenu maPopup(ScResId( RID_POPUP_RIGHTDRAGDROP ));
++
++                        // GetMousePosPixel() returns the position from the start of the drag.. need to fix this, workaround segfaults :S
++                        //EditView* pEditView = pViewData->GetEditView( eWhich );
++                        //Cursor* pCur = pEditView->GetCursor();
++                        sal_uInt16 nItemId = maPopup.Execute( this, rMousePos);//Point(nDestPosX * pCur->GetWidth(), nDestPosY * pCur->GetHeight() )); //GetMousePosPixel()); //Point(nDestPosX, nDestPosY));
++
++                        //maPopup.Execute(pViewData->GetView()->GetWindowByPos( eWhich ), Point(0,0));/*rLogicPos);*/
++
++                        // follow excel's format for now
++                        switch ( nItemId )
++                        {
++                        case RID_RIGHTDRAGDROP_MOVE:
++                            // Move Here
++                            bIsMove = TRUE;
++                            bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove, TRUE /*bRecord*/, TRUE /*bPaint*/, TRUE /*bApi*/ );
++                            break;
++
++                        case RID_RIGHTDRAGDROP_COPY:
++                            // Copy Here
++                            bIsMove = FALSE;
++                            bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove, TRUE /*bRecord*/, TRUE /*bPaint*/, TRUE /*bApi*/ );
++                            break;
++
++                        case RID_RIGHTDRAGDROP_COPYVALUES:
++                            // Copy Here as Values Only
++                            break;
++
++                        case RID_RIGHTDRAGDROP_COPYFORMATS:
++                            // Copy Here as Formats Only
++                            break;
++
++                        case RID_RIGHTDRAGDROP_LINK:
++                            // Link Here
++                            bIsLink = TRUE;
++                            bDone = pView->LinkBlock( aSource, aDest.aStart, TRUE /*bApi*/ );
++                            break;
++
++                        case RID_RIGHTDRAGDROP_HYPERLINK:
++                            // Create Hyperlink Here
++                            break;
++
++                        case RID_RIGHTDRAGDROP_SHIFTDOWNC:
++                            // Shift Down and Copy
++                            meDragInsertMode = INS_CELLSDOWN;
++                            aUndo = ScGlobal::GetRscString( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY );
++                            pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
++
++                            bDone = TRUE;
++                            bIsMove = FALSE;
++                            if ( meDragInsertMode != INS_NONE )
++                            {
++                                // call with bApi = TRUE to avoid error messages in drop handler
++                                bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, TRUE /*bRecord*/, TRUE /*bApi*/, TRUE /*bPartOfPaste*/ );
++                                if ( bDone )
++                                {
++                                    if ( nThisTab == nSourceTab )
++                                    {
++                                        if ( meDragInsertMode == INS_CELLSDOWN &&
++                                             nDestPosX == aSource.aStart.Col() && nDestPosY < aSource.aStart.Row() )
++                                        {
++                                            bDone = aSource.Move( 0, nSizeY, 0, pSourceDoc );
++                                        }
++                                        else if ( meDragInsertMode == INS_CELLSRIGHT &&
++                                                  nDestPosY == aSource.aStart.Row() && nDestPosX < aSource.aStart.Col() )
++                                        {
++                                            bDone = aSource.Move( nSizeX, 0, 0, pSourceDoc );
++                                        }
++                                    }
++                                    pDocSh->UpdateOle( pViewData );
++                                    pView->CellContentChanged();
++                                }
++                            }
++                            bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove, TRUE /*bRecord*/, TRUE /*bPaint*/, TRUE /*bApi*/ );
++                            break;
++
++                        case RID_RIGHTDRAGDROP_SHIFTRIGHTC:
++                            // Shift Right and Copy
++                            meDragInsertMode = INS_CELLSRIGHT;
++                            aUndo = ScGlobal::GetRscString( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY );
++                            pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
++
++                            bDone = TRUE;
++                            bIsMove = FALSE;
++                            if ( meDragInsertMode != INS_NONE )
++                            {
++                                // call with bApi = TRUE to avoid error messages in drop handler
++                                bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, TRUE /*bRecord*/, TRUE /*bApi*/, TRUE /*bPartOfPaste*/ );
++                                if ( bDone )
++                                {
++                                    if ( nThisTab == nSourceTab )
++                                    {
++                                        if ( meDragInsertMode == INS_CELLSDOWN &&
++                                             nDestPosX == aSource.aStart.Col() && nDestPosY < aSource.aStart.Row() )
++                                        {
++                                            bDone = aSource.Move( 0, nSizeY, 0, pSourceDoc );
++                                        }
++                                        else if ( meDragInsertMode == INS_CELLSRIGHT &&
++                                                  nDestPosY == aSource.aStart.Row() && nDestPosX < aSource.aStart.Col() )
++                                        {
++                                            bDone = aSource.Move( nSizeX, 0, 0, pSourceDoc );
++                                        }
++                                    }
++                                    pDocSh->UpdateOle( pViewData );
++                                    pView->CellContentChanged();
++                                }
++                            }
++                            bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove, TRUE /*bRecord*/, TRUE /*bPaint*/, TRUE /*bApi*/ );
++                            break;
++
++                        case RID_RIGHTDRAGDROP_SHIFTDOWNM:
++                            // Shift Down and Move
++                            meDragInsertMode = INS_CELLSDOWN;
++                            aUndo = ScGlobal::GetRscString( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY );
++                            pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
++
++                            bDone = TRUE;
++                            bIsMove = TRUE;
++                            if ( meDragInsertMode != INS_NONE )
++                            {
++                                // call with bApi = TRUE to avoid error messages in drop handler
++                                bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, TRUE /*bRecord*/, TRUE /*bApi*/, TRUE /*bPartOfPaste*/ );
++                                if ( bDone )
++                                {
++                                    if ( nThisTab == nSourceTab )
++                                    {
++                                        if ( meDragInsertMode == INS_CELLSDOWN &&
++                                             nDestPosX == aSource.aStart.Col() && nDestPosY < aSource.aStart.Row() )
++                                        {
++                                            bDone = aSource.Move( 0, nSizeY, 0, pSourceDoc );
++                                        }
++                                        else if ( meDragInsertMode == INS_CELLSRIGHT &&
++                                                  nDestPosY == aSource.aStart.Row() && nDestPosX < aSource.aStart.Col() )
++                                        {
++                                            bDone = aSource.Move( nSizeX, 0, 0, pSourceDoc );
++                                        }
++                                    }
++                                    pDocSh->UpdateOle( pViewData );
++                                    pView->CellContentChanged();
++                                }
++                            }
++                            bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove, TRUE /*bRecord*/, TRUE /*bPaint*/, TRUE /*bApi*/ );
++                            break;
++
++                        case RID_RIGHTDRAGDROP_SHIFTRIGHTM:
++                            // Shift Right and Move
++                            meDragInsertMode = INS_CELLSRIGHT;
++                            aUndo = ScGlobal::GetRscString( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY );
++                            pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
++
++                            bDone = TRUE;
++                            bIsMove = TRUE;
++                            if ( meDragInsertMode != INS_NONE )
++                            {
++                                // call with bApi = TRUE to avoid error messages in drop handler
++                                bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, TRUE /*bRecord*/, TRUE /*bApi*/, TRUE /*bPartOfPaste*/ );
++                                if ( bDone )
++                                {
++                                    if ( nThisTab == nSourceTab )
++                                    {
++                                        if ( meDragInsertMode == INS_CELLSDOWN &&
++                                             nDestPosX == aSource.aStart.Col() && nDestPosY < aSource.aStart.Row() )
++                                        {
++                                            bDone = aSource.Move( 0, nSizeY, 0, pSourceDoc );
++                                        }
++                                        else if ( meDragInsertMode == INS_CELLSRIGHT &&
++                                                  nDestPosY == aSource.aStart.Row() && nDestPosX < aSource.aStart.Col() )
++                                        {
++                                            bDone = aSource.Move( nSizeX, 0, 0, pSourceDoc );
++                                        }
++                                    }
++                                    pDocSh->UpdateOle( pViewData );
++                                    pView->CellContentChanged();
++                                }
++                            }
++                            bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove, TRUE /*bRecord*/, TRUE /*bPaint*/, TRUE /*bApi*/ );
++                            break;
++
++                        case 0:
++                            // nothing selected
++                        case RID_RIGHTDRAGDROP_CANCEL:
++                            // Cancel
++                        default:
++                            // Need to return DND_ACTION_NONE to prevent moving the shaded area if nothing is to be done.
++                            return DND_ACTION_NONE;
++                        }
++                    }
+                     else
+                     {
+                         // call with bApi = TRUE to avoid error messages in drop handler
+@@ -4317,7 +4577,7 @@
+         {
+             // keep a reference to the data in case the selection is changed during paste
+             uno::Reference<datatransfer::XTransferable> xRef( pCellTransfer );
+-            DropTransferObj( pCellTransfer, nPosX, nPosY, aLogicPos, DND_ACTION_COPY );
++            DropTransferObj( pCellTransfer, nPosX, nPosY, aLogicPos, rPosPixel, DND_ACTION_COPY );
+         }
+         else
+         {
+--- sc/source/ui/inc/gridwin.hxx.orig2	2010-08-16 21:54:09.998000096 -0500
++++ sc/source/ui/inc/gridwin.hxx	2010-08-16 21:54:18.584000098 -0500
+@@ -116,6 +116,8 @@
+ 
+     ::boost::shared_ptr<Rectangle> mpAutoFillRect;
+ 
++    bool                    bMoveSingle;
++
+     /** 
+      * Stores current visible column and row ranges, used to avoid expensive 
+      * operations on objects that are outside visible area. 
+--- sc/inc/sc.hrc.orig2	2010-08-14 09:16:59.107000093 -0500
++++ sc/inc/sc.hrc	2010-08-14 09:31:40.135000093 -0500
+@@ -1643,6 +1643,21 @@
+ 
+ #define SC_DIALOGS_END                  (SC_DIALOGS_START + 155)
+ 
++// Popup for right dragging.
++#define RID_POPUP_RIGHTDRAGDROP			(SC_DIALOGS_START + 156)
++#define RID_RIGHTDRAGDROP_MOVE			(SC_DIALOGS_START + 157)
++#define RID_RIGHTDRAGDROP_COPY			(SC_DIALOGS_START + 158)
++#define RID_RIGHTDRAGDROP_COPYVALUES	(SC_DIALOGS_START + 159)
++#define RID_RIGHTDRAGDROP_COPYFORMATS	(SC_DIALOGS_START + 160)
++#define RID_RIGHTDRAGDROP_LINK			(SC_DIALOGS_START + 161)
++#define RID_RIGHTDRAGDROP_HYPERLINK		(SC_DIALOGS_START + 162)
++#define RID_RIGHTDRAGDROP_SHIFTDOWNC	(SC_DIALOGS_START + 163)
++#define RID_RIGHTDRAGDROP_SHIFTRIGHTC	(SC_DIALOGS_START + 164)
++#define RID_RIGHTDRAGDROP_SHIFTDOWNM	(SC_DIALOGS_START + 165)
++#define RID_RIGHTDRAGDROP_SHIFTRIGHTM	(SC_DIALOGS_START + 166)
++#define RID_RIGHTDRAGDROP_CANCEL		(SC_DIALOGS_START + 167)
++
++
+ #ifndef STD_MASKCOLOR
+ #define STD_MASKCOLOR Color { Red = 0xFF00; Green = 0x0000; Blue = 0xFF00; }
+ #endif
+--- sc/source/ui/navipi/navipi.src.orig2	2010-08-14 09:36:21.672000092 -0500
++++ sc/source/ui/navipi/navipi.src	2010-08-15 17:25:02.982000089 -0500
+@@ -370,45 +370,70 @@
+         };
+     };
+ };
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
++Menu RID_POPUP_RIGHTDRAGDROP
++{
++    ItemList =
++    {
++        MenuItem
++        {
++            Identifier = RID_RIGHTDRAGDROP_MOVE ;
++            Text [ en-US ] = "Move Here" ;
++        };
++        MenuItem
++        {
++            Identifier = RID_RIGHTDRAGDROP_COPY ;
++            Text [ en-US ] = "Copy Here" ;
++        };
++        //MenuItem
++        //{
++        //    Identifier = RID_RIGHTDRAGDROP_COPYVALUES ;
++        //    Text [ en-US ] = "Copy Here as Values Only" ;
++        //};
++        //MenuItem
++        //{
++        //    Identifier = RID_RIGHTDRAGDROP_COPYFORMATS ;
++        //    Text [ en-US ] = "Copy Here as Formats Only" ;
++        //};
++        MenuItem
++        {
++            Identifier = RID_RIGHTDRAGDROP_LINK ;
++            Text [ en-US ] = "Link Here" ;
++        };
++        //MenuItem
++        //{
++        //    Identifier = RID_RIGHTDRAGDROP_HYPERLINK ;
++        //    Text [ en-US ] = "Create Hyperlink Here" ;
++        //};
++        //////////////////////////////////////////////////
++        MenuItem { Separator = TRUE ; };
++        //////////////////////////////////////////////////
++        MenuItem
++        {
++            Identifier = RID_RIGHTDRAGDROP_SHIFTDOWNC ;
++            Text [ en-US ] = "Shift Down and Copy" ;
++        };
++        MenuItem
++        {
++            Identifier = RID_RIGHTDRAGDROP_SHIFTRIGHTC ;
++            Text [ en-US ] = "Shift Right and Copy" ;
++        };
++        MenuItem
++        {
++            Identifier = RID_RIGHTDRAGDROP_SHIFTDOWNM ;
++            Text [ en-US ] = "Shift Down and Move" ;
++        };
++        MenuItem
++        {
++            Identifier = RID_RIGHTDRAGDROP_SHIFTRIGHTM ;
++            Text [ en-US ] = "Shift Right and Move" ;
++        };
++        //////////////////////////////////////////////////
++        MenuItem { Separator = TRUE ; };
++        //////////////////////////////////////////////////
++        MenuItem
++        {
++            Identifier = RID_RIGHTDRAGDROP_CANCEL ;
++            Text [ en-US ] = "Cancel" ;
++        };
++    };
++};
+--- vcl/source/window/seleng.cxx.orig2	2010-08-10 11:35:56.392000035 -0500
++++ vcl/source/window/seleng.cxx	2010-08-14 08:20:22.702000092 -0500
+@@ -202,7 +202,7 @@
+ BOOL SelectionEngine::SelMouseButtonDown( const MouseEvent& rMEvt )
+ {
+     nFlags &= (~SELENG_CMDEVT);
+-    if ( !pFunctionSet || !pWin || rMEvt.GetClicks() > 1 || rMEvt.IsRight() )
++    if ( !pFunctionSet || !pWin || rMEvt.GetClicks() > 1)
+         return FALSE;
+ 
+     USHORT nModifier = rMEvt.GetModifier() | nLockedMods;
+--- vcl/source/window/winproc.cxx.orig2	2010-08-12 20:54:52.205000092 -0500
++++ vcl/source/window/winproc.cxx	2010-08-13 23:26:41.251000089 -0500
+@@ -546,8 +546,8 @@
+             // den Status der Maustasten, damit man mit Mod1 z.B. sofort
+             // in den Kopiermodus gehen kann.
+             const MouseSettings& rMSettings = pMouseDownWin->GetSettings().GetMouseSettings();
+-            if ( (nCode & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) ==
+-                 (rMSettings.GetStartDragCode() & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) )
++            if ( ( (nCode & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) ==
++                 (rMSettings.GetStartDragCode() & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) ) || ( nCode & MOUSE_RIGHT ) )
+             {
+                 if ( !pMouseDownWin->ImplGetFrameData()->mbStartDragCalled )
+                 {
+@@ -697,8 +697,8 @@
+                 pChild->ImplGetFrameData()->mnFirstMouseX      = nMouseX;
+                 pChild->ImplGetFrameData()->mnFirstMouseY      = nMouseY;
+                 pChild->ImplGetFrameData()->mnFirstMouseCode   = nCode;
+-                pChild->ImplGetFrameData()->mbStartDragCalled  = !((nCode & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) ==
+-                                                            (rMSettings.GetStartDragCode() & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)));
++                pChild->ImplGetFrameData()->mbStartDragCalled  = !( ((nCode & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) ==
++                                                            (rMSettings.GetStartDragCode() & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE))) || ( nCode & MOUSE_RIGHT ) );
+             }
+             pChild->ImplGetFrameData()->mnMouseDownTime = nMsgTime;
+         }
+--- vcl/unx/source/dtrans/X11_selection.cxx.orig2	2010-08-13 21:04:01.229000093 -0500
++++ vcl/unx/source/dtrans/X11_selection.cxx	2010-08-14 08:22:34.206000092 -0500
+@@ -2763,9 +2763,10 @@
+                 sendDropPosition( true, rMessage.xkey.time );
+         }
+     }
+-    else if(
++    else if((
+             ( rMessage.type == ButtonPress || rMessage.type == ButtonRelease ) &&
+-            rMessage.xbutton.button == m_nDragButton )
++            rMessage.xbutton.button == m_nDragButton ) ||
++            ( rMessage.xbutton.button == Button3 ) )
+     {
+         bool bCancel = true;
+         if( m_aDropWindow != None )
+@@ -2783,7 +2784,7 @@
+                     dtde.Context		= new DropTargetDropContext( m_aCurrentDropWindow, m_nDropTimestamp, *this );
+                     dtde.LocationX		= x;
+                     dtde.LocationY		= y;
+-                    dtde.DropAction		= m_nUserDragAction;
++                    dtde.DropAction		= ( rMessage.xbutton.button == Button3 ) ? DNDConstants::ACTION_RIGHT : m_nUserDragAction;
+                     dtde.SourceActions	= m_nSourceActions;
+                     dtde.Transferable	= m_xDragSourceTransferable;
+                     m_bDropSent					= true;
+--- svtools/inc/svtools/transfer.hxx.orig2	2010-08-14 00:03:15.653000092 -0500
++++ svtools/inc/svtools/transfer.hxx	2010-08-14 01:10:08.078000092 -0500
+@@ -73,6 +73,7 @@
+ #define DND_ACTION_MOVE		::com::sun::star::datatransfer::dnd::DNDConstants::ACTION_MOVE
+ #define DND_ACTION_COPYMOVE ::com::sun::star::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE
+ #define DND_ACTION_LINK		::com::sun::star::datatransfer::dnd::DNDConstants::ACTION_LINK
++#define DND_ACTION_RIGHT    ::com::sun::star::datatransfer::dnd::DNDConstants::ACTION_RIGHT
+ 
+ #define DND_POINTER_NONE	0
+ #define DND_IMAGE_NONE		0
+--- offapi/com/sun/star/datatransfer/dnd/DNDConstants.idl.orig2	2010-08-14 01:09:16.240000096 -0500
++++ offapi/com/sun/star/datatransfer/dnd/DNDConstants.idl	2010-08-14 01:09:23.002000093 -0500
+@@ -76,6 +76,12 @@
+     const byte ACTION_REFERENCE = 0x04;
+     
+     //=============================================================================
++    /** Action for right click dragging.
++    */
++
++    const byte ACTION_RIGHT = 0x08;
++
++    //=============================================================================
+     /** Action default.
+     */
+ 
commit d6b73c9d63b02142b9d48d9fed1573912ee3705e
Author: Jonas Jensen <jopsen at gmail.com>
Date:   Wed Sep 22 21:39:23 2010 +0200

    Pushed Jonas' patches AS IS

diff --git a/patches/dev300/symbols-20-august.diff b/patches/dev300/symbols-20-august.diff
new file mode 100644
index 0000000..6d91994
--- /dev/null
+++ b/patches/dev300/symbols-20-august.diff
@@ -0,0 +1,238 @@
+diff --git extras/source/truetype/symbol/OpenSymbol.sfd extras/source/truetype/symbol/OpenSymbol.sfd
+index e04c03f..d6ecc95 100644
+--- extras/source/truetype/symbol/OpenSymbol.sfd
++++ extras/source/truetype/symbol/OpenSymbol.sfd
+@@ -13,13 +13,14 @@ Descent: 410
+ LayerCount: 2
+ Layer: 0 1 "Back"  1
+ Layer: 1 1 "Fore"  0
++NeedsXUIDChange: 1
+ XUID: [1021 161 2043615882 15846768]
+ FSType: 8
+ OS2Version: 0
+ OS2_WeightWidthSlopeOnly: 0
+ OS2_UseTypoMetrics: 1
+ CreationTime: 1144938807
+-ModificationTime: 1238168413
++ModificationTime: 1281980608
+ PfmFamily: 81
+ TTFWeight: 400
+ TTFWidth: 5
+@@ -591,8 +592,8 @@ NameList: Adobe Glyph List
+ DisplaySize: -24
+ AntiAlias: 1
+ FitToEm: 1
+-WinInfo: 0 45 18
+-BeginChars: 65539 912
++WinInfo: 135 45 18
++BeginChars: 65539 914
+ 
+ StartChar: .notdef
+ Encoding: 65536 -1 0
+@@ -100162,5 +100163,88 @@ SplineSet
+ EndSplineSet
+ Validated: 1
+ EndChar
++
++StartChar: uni27FC
++Encoding: 10236 10236 912
++Width: 2048
++VWidth: 0
++Flags: W
++LayerCount: 2
++Fore
++SplineSet
++120.605 893.365 m 0,0,1
++ 130.745 894.649 130.745 894.649 139.122 886.971 c 128,-1,2
++ 147.499 879.293 147.499 879.293 147.099 869.08 c 2,3,-1
++ 147.099 657.135 l 1,4,-1
++ 1753.62 657.135 l 1,5,6
++ 1721.36 678.613 1721.36 678.613 1692.21 706.222 c 128,-1,7
++ 1663.06 733.83 1663.06 733.83 1644.5 757.892 c 128,-1,8
++ 1625.94 781.953 1625.94 781.953 1611.99 802.947 c 128,-1,9
++ 1598.04 823.94 1598.04 823.94 1591.94 836.207 c 2,10,-1
++ 1585.83 848.475 l 1,11,12
++ 1580.32 857.07 1580.32 857.07 1583.64 867.92 c 128,-1,13
++ 1586.96 878.77 1586.96 878.77 1596.33 882.81 c 128,-1,14
++ 1605.71 886.85 1605.71 886.85 1615.88 881.814 c 128,-1,15
++ 1626.05 876.778 1626.05 876.778 1628.51 866.872 c 1,16,17
++ 1631.31 860.546 1631.31 860.546 1636.84 849.729 c 128,-1,18
++ 1642.37 838.911 1642.37 838.911 1662.49 809.124 c 128,-1,19
++ 1682.61 779.338 1682.61 779.338 1706.09 753.681 c 128,-1,20
++ 1729.56 728.024 1729.56 728.024 1768.64 699.899 c 128,-1,21
++ 1807.71 671.774 1807.71 671.774 1850.76 656.4 c 1,22,23
++ 1865.45 654.098 1865.45 654.098 1865.48 633.585 c 0,24,25
++ 1865.49 624.275 1865.49 624.275 1861.81 618.755 c 128,-1,26
++ 1858.13 613.236 1858.13 613.236 1854.45 612.371 c 2,27,-1
++ 1850.76 611.507 l 1,28,29
++ 1807.71 596.133 1807.71 596.133 1768.99 568.798 c 128,-1,30
++ 1730.26 541.464 1730.26 541.464 1705.74 513.434 c 128,-1,31
++ 1681.21 485.405 1681.21 485.405 1662.84 459.572 c 128,-1,32
++ 1644.47 433.739 1644.47 433.739 1636.49 417.386 c 2,33,-1
++ 1628.51 401.033 l 1,34,35
++ 1626.05 391.127 1626.05 391.127 1615.88 386.09 c 128,-1,36
++ 1605.71 381.053 1605.71 381.053 1596.33 385.093 c 128,-1,37
++ 1586.96 389.134 1586.96 389.134 1583.64 399.985 c 128,-1,38
++ 1580.32 410.837 1580.32 410.837 1585.83 419.432 c 0,39,40
++ 1587.95 424.066 1587.95 424.066 1592.14 432.201 c 128,-1,41
++ 1596.33 440.337 1596.33 440.337 1611.48 464.117 c 128,-1,42
++ 1626.63 487.897 1626.63 487.897 1644.23 510.113 c 128,-1,43
++ 1661.82 532.328 1661.82 532.328 1690.99 560.441 c 128,-1,44
++ 1720.15 588.555 1720.15 588.555 1752.15 610.037 c 1,45,-1
++ 147.099 610.037 l 1,46,-1
++ 147.099 398.091 l 2,47,48
++ 147.231 388.76 147.231 388.76 140.056 381.483 c 128,-1,49
++ 132.882 374.206 132.882 374.206 123.55 374.206 c 128,-1,50
++ 114.217 374.206 114.217 374.206 107.042 381.483 c 128,-1,51
++ 99.8674 388.76 99.8674 388.76 100 398.091 c 2,52,-1
++ 100 629.171 l 2,53,54
++ 99.1577 633.586 99.1577 633.586 100 638.002 c 2,55,-1
++ 100 869.082 l 2,56,57
++ 99.6602 877.819 99.6602 877.819 105.795 885.049 c 128,-1,58
++ 111.93 892.279 111.93 892.279 120.605 893.365 c 0,0,1
++EndSplineSet
++EndChar
++
++StartChar: uni2312
++Encoding: 8978 8978 913
++Width: 760
++VWidth: 0
++Flags: W
++LayerCount: 2
++Fore
++SplineSet
++30.002 1123.25 m 1,0,1
++ 30.002 1218.06 30.002 1218.06 76.9414 1298.72 c 128,-1,2
++ 123.88 1379.38 123.88 1379.38 204.536 1426.31 c 128,-1,3
++ 285.192 1473.25 285.192 1473.25 380.001 1473.25 c 128,-1,4
++ 474.809 1473.25 474.809 1473.25 555.465 1426.31 c 128,-1,5
++ 636.121 1379.38 636.121 1379.38 683.061 1298.72 c 128,-1,6
++ 730 1218.06 730 1218.06 730 1123.25 c 1,7,-1
++ 643.486 1123.25 l 1,8,9
++ 643.486 1232.78 643.486 1232.78 566.506 1309.76 c 128,-1,10
++ 489.525 1386.74 489.525 1386.74 380.001 1386.74 c 128,-1,11
++ 270.477 1386.74 270.477 1386.74 193.496 1309.76 c 128,-1,12
++ 116.515 1232.78 116.515 1232.78 116.515 1123.25 c 1,13,-1
++ 30.002 1123.25 l 1,0,1
++EndSplineSet
++EndChar
+ EndChars
+ EndSplineFont
+diff --git extras/source/truetype/symbol/opens___.ttf extras/source/truetype/symbol/opens___.ttf
+index b4f169f..b7fb394 100644
+Binary files extras/source/truetype/symbol/opens___.ttf and extras/source/truetype/symbol/opens___.ttf differ
+diff --git officecfg/registry/data/org/openoffice/Office/Math.xcu officecfg/registry/data/org/openoffice/Office/Math.xcu
+index cf11e57..b185902 100644
+--- officecfg/registry/data/org/openoffice/Office/Math.xcu
++++ officecfg/registry/data/org/openoffice/Office/Math.xcu
+@@ -994,5 +994,19 @@
+         <value>Id1</value>
+       </prop>
+     </node>
++    <node oor:name="mapsto" oor:op="replace">
++      <prop oor:name="Char">
++        <value>10236</value>
++      </prop>
++      <prop oor:name="Set">
++        <value>Special</value>
++      </prop>
++      <prop oor:name="Predefined">
++        <value>true</value>
++      </prop>
++      <prop oor:name="FontFormatId">
++        <value>Id1</value>
++      </prop>
++    </node>
+   </node>
+ </oor:component-data>
+diff --git starmath/inc/parse.hxx starmath/inc/parse.hxx
+index 0211d97..b462abb 100644
+--- starmath/inc/parse.hxx
++++ starmath/inc/parse.hxx
+@@ -106,7 +106,7 @@ enum SmTokenType
+     TLEFTARROW,		TRIGHTARROW,	TUPARROW,		TDOWNARROW,		TDIVIDES,
+     TNDIBVIDES,		TSETN,			TSETZ,			TSETQ,			TSETR,
+     TSETC,			TWIDEVEC,		TWIDETILDE,		TWIDEHAT,		TWIDESLASH,
+-    TWIDEBACKSLASH, TLDBRACKET,		TRDBRACKET,
++    TWIDEBACKSLASH, TLDBRACKET,		TRDBRACKET,     TBOW,
+     TUNKNOWN,		TDEBUG
+ };
+ 
+diff --git starmath/inc/types.hxx starmath/inc/types.hxx
+index b8cb4d0..4596877 100644
+--- starmath/inc/types.hxx
++++ starmath/inc/types.hxx
+@@ -165,6 +165,7 @@ enum MathSymbol
+     MS_FORALL       = (sal_Unicode) 0x2200,
+ 
+     MS_HAT          = (sal_Unicode) 0xE091,
++    MS_BOW          = (sal_Unicode) 0x2312,
+     MS_CHECK        = (sal_Unicode) 0xE092,
+     MS_BREVE        = (sal_Unicode) 0xE093,
+     MS_ACUTE        = (sal_Unicode) 0xE094,
+diff --git starmath/source/parse.cxx starmath/source/parse.cxx
+index aab3502..3fc2912 100644
+--- starmath/source/parse.cxx
++++ starmath/source/parse.cxx
+@@ -202,7 +202,7 @@ static const SmTokenTableEntry aTokenTable[] =
+     { "infinity" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
+     { "infty" , TINFINITY, MS_INFINITY, TGSTANDALONE, 5},
+     { "int", TINT, MS_INT, TGOPER, 5},
+-    { "intersection", TINTERSECT, MS_INTERSECT, TGPRODUCT, 0},
++    { "intersection", TINTERSECT, MS_INTERSECT, TGPRODUCT | TGOPER, 0},
+     { "ital", TITALIC, '\0', TGFONTATTR, 5},
+     { "italic", TITALIC, '\0', TGFONTATTR, 5},
+     { "lambdabar" , TLAMBDABAR, MS_LAMBDABAR, TGSTANDALONE, 5},
+@@ -312,13 +312,14 @@ static const SmTokenTableEntry aTokenTable[] =
+     { "transr", TTRANSR, MS_TRANSR, TGRELATION, 0},
+     { "underbrace", TUNDERBRACE, MS_UNDERBRACE, TGPRODUCT, 5},
+     { "underline", TUNDERLINE, '\0', TGATTRIBUT, 5},
+-    { "union", TUNION, MS_UNION, TGSUM, 0},
++    { "union", TUNION, MS_UNION, TGSUM | TGOPER, 0},
+     { "uoper", TUOPER, '\0', TGUNOPER, 5},
+     { "uparrow" , TUPARROW, MS_UPARROW, TGSTANDALONE, 5},
+     { "vec", TVEC, MS_VEC, TGATTRIBUT, 5},
+     { "white", TWHITE, '\0', TGCOLOR, 0},
+     { "widebslash", TWIDEBACKSLASH, MS_BACKSLASH, TGPRODUCT, 0 },
+     { "widehat", TWIDEHAT, MS_HAT, TGATTRIBUT, 5},
++    { "bow", TBOW, MS_BOW, TGATTRIBUT, 5},
+     { "widetilde", TWIDETILDE, MS_TILDE, TGATTRIBUT, 5},
+     { "wideslash", TWIDESLASH, MS_SLASH, TGPRODUCT, 0 },
+     { "widevec", TWIDEVEC, MS_VEC, TGATTRIBUT, 5},
+@@ -1624,6 +1625,8 @@ void SmParser::Oper()
+ 
+     switch (eType)
+     {
++        case TINTERSECT:
++        case TUNION :
+         case TSUM :
+         case TPROD :
+         case TCOPROD :
+@@ -1781,6 +1784,7 @@ void SmParser::Attribut()
+ 
+         case TWIDEVEC :
+         case TWIDEHAT :
++        case TBOW :
+         case TWIDETILDE :
+             pAttr = new SmMathSymbolNode(CurToken);
+             eScaleMode = SCALE_WIDTH;
+diff --git starmath/source/symbol.src starmath/source/symbol.src
+index c4cab66..ed0fb9b 100644
+--- starmath/source/symbol.src
++++ starmath/source/symbol.src
+@@ -268,6 +268,7 @@ Resource RID_LOCALIZED_NAMES
+             < "perthousand" ; > ;
+             < "and" ; > ;
+             < "or" ; > ;
++            < "mapsto" ; > ;
+         };
+     };
+     StringArray RID_UI_SYMBOL_NAMES
+@@ -340,6 +341,7 @@ Resource RID_LOCALIZED_NAMES
+         < "perthousand" ; > ;
+         < "and" ; > ;
+         < "or" ; > ;
++        < "mapsto" ; > ;
+     };
+     };
+ };
diff --git a/patches/dev300/vEdit-13-August.diff b/patches/dev300/vEdit-13-August.diff
new file mode 100644
index 0000000..117a757
--- /dev/null
+++ b/patches/dev300/vEdit-13-August.diff
@@ -0,0 +1,7896 @@
+diff --git starmath/inc/caret.hxx starmath/inc/caret.hxx
+new file mode 100644
+index 0000000..b1ff954
+--- /dev/null
++++ starmath/inc/caret.hxx
+@@ -0,0 +1,445 @@
++#ifndef CARET_H
++#define CARET_H
++
++#include "node.hxx"
++
++/** Representation of caret position with an equantion */
++struct SmCaretPos{
++    SmCaretPos(SmNode* selectedNode = NULL, int iIndex = 0) {
++        pSelectedNode = selectedNode;
++        Index = iIndex;
++    }
++    /** Selected node */
++    SmNode* pSelectedNode;
++    /** Index within the selected node
++     *
++     * 0: Position infront of a node
++     * 1: Position after a node or after first char in SmTextNode
++     * n: Position after n char in SmTextNode
++     *
++     * Notice how there's special cases for SmTextNode.
++     */
++    //TODO: Special cases for SmBlankNode is needed
++    //TODO: Consider forgetting about the todo above... As it's really unpleasent.
++    int Index;
++    /** True, if this is a valid caret position */
++    bool IsValid() { return pSelectedNode != NULL; }
++    bool operator!=(SmCaretPos pos) const {
++        return pos.pSelectedNode != pSelectedNode || Index != pos.Index;
++    }
++    bool operator==(SmCaretPos pos) const {
++        return pos.pSelectedNode == pSelectedNode && Index == pos.Index;
++    }
++    /** Get the caret position after pNode, regardless of pNode
++     *
++     * Gets the caret position following pNode, this is SmCaretPos(pNode, 1).
++     * Unless pNode is an instance of SmTextNode, then the index is the text length.
++     */
++    static SmCaretPos GetPosAfter(SmNode* pNode) {
++        if(pNode && pNode->GetType() == NTEXT)
++            return SmCaretPos(pNode, ((SmTextNode*)pNode)->GetText().Len());
++        return SmCaretPos(pNode, 1);
++    }
++};
++
++/** A line that represents a caret */
++class SmCaretLine{
++public:
++    SmCaretLine(long left = 0, long top = 0, long height = 0) {
++        _top = top;
++        _left = left;
++        _height = height;
++    }
++    long GetTop() const {return _top;}
++    long GetLeft() const {return _left;}
++    long GetHeight() const {return _height;}
++    long SquaredDistanceX(SmCaretLine line) const{
++        return (GetLeft() - line.GetLeft()) * (GetLeft() - line.GetLeft());
++    }
++    long SquaredDistanceX(Point pos) const{
++        return (GetLeft() - pos.X()) * (GetLeft() - pos.X());
++    }
++    long SquaredDistanceY(SmCaretLine line) const{
++        long d = GetTop() - line.GetTop();
++        if(d < 0)
++            d = (d * -1) - GetHeight();
++        else
++            d = d - line.GetHeight();
++        if(d < 0)
++            return 0;
++        return d * d;
++    }
++    long SquaredDistanceY(Point pos) const{
++        long d = GetTop() - pos.Y();
++        if(d < 0)
++            d = (d * -1) - GetHeight();
++        if(d < 0)
++            return 0;
++        return d * d;
++    }
++private:
++    long _top;
++    long _left;
++    long _height;
++};
++
++/////////////////////////////// SmCaretPosGraph////////////////////////////////
++
++/** An entry in SmCaretPosGraph */
++struct SmCaretPosGraphEntry{
++    SmCaretPosGraphEntry(SmCaretPos pos = SmCaretPos(),
++                       SmCaretPosGraphEntry* left = NULL,
++                       SmCaretPosGraphEntry* right = NULL){
++        CaretPos = pos;
++        Left = left;
++        Right = right;
++    }
++    /** Caret position */
++    SmCaretPos CaretPos;
++    /** Entry to the left visually */
++    SmCaretPosGraphEntry* Left;
++    /** Entry to the right visually */
++    SmCaretPosGraphEntry* Right;
++    void SetRight(SmCaretPosGraphEntry* right){
++        Right = right;
++    }
++    void SetLeft(SmCaretPosGraphEntry* left){
++        Left = left;
++    }
++};
++
++/** Define SmCaretPosGraph to be less than one page 4096 */
++#define SmCaretPosGraphSize   255
++
++class SmCaretPosGraph;
++
++/** Iterator for SmCaretPosGraph */
++class SmCaretPosGraphIterator{
++public:
++    SmCaretPosGraphIterator(SmCaretPosGraph* graph){
++        pGraph = graph;
++        nOffset = 0;
++        pEntry = NULL;
++    }
++    /** Get the next entry, NULL if none */
++    SmCaretPosGraphEntry* Next();
++    /** Get the current entry, NULL if none */
++    SmCaretPosGraphEntry* Current(){
++        return pEntry;
++    }
++    /** Get the current entry, NULL if none */
++    SmCaretPosGraphEntry* operator->(){
++        return pEntry;
++    }
++private:
++    /** Next entry to return */
++    int nOffset;
++    /** Current graph */
++    SmCaretPosGraph* pGraph;
++    /** Current entry */
++    SmCaretPosGraphEntry* pEntry;
++};
++
++
++/** A graph over all caret positions
++ * @remarks Graphs can only grow, entries cannot be removed!
++ */
++class SmCaretPosGraph{
++public:
++    SmCaretPosGraph(){
++        pNext = NULL;
++        nOffset = 0;
++    }
++    ~SmCaretPosGraph();
++    SmCaretPosGraphEntry* Add(SmCaretPosGraphEntry entry);
++    SmCaretPosGraphEntry* Add(SmCaretPos pos,
++                            SmCaretPosGraphEntry* left = NULL,
++                            SmCaretPosGraphEntry* right = NULL){
++        j_assert(pos.Index >= 0, "Index shouldn't be -1!");
++        return Add(SmCaretPosGraphEntry(pos, left, right));
++    }
++    /** Get an iterator for this graph */
++    SmCaretPosGraphIterator GetIterator(){
++        return SmCaretPosGraphIterator(this);
++    }
++    friend class SmCaretPosGraphIterator;
++private:
++    /** Next graph, to be used when this graph is full */
++    SmCaretPosGraph* pNext;
++    /** Next free entry in graph */
++    int nOffset;
++    /** Entries in this graph segment */
++    SmCaretPosGraphEntry Graph[SmCaretPosGraphSize];
++};
++
++/** \page visual_formula_editing Visual Formula Editing
++ * A visual formula editor allows users to easily edit formulas without having to learn and 
++ * use complicated commands. A visual formula editor is a WYSIWYG editor. For OpenOffice Math
++ * this essentially means that you can click on the formula image, to get a caret, which you
++ * can move with arrow keys, and use to modify the formula by entering text, clicking buttons
++ * or using shortcuts.
++ * 
++ * \subsection formula_trees Formula Trees
++ * A formula in OpenOffice Math is a tree of nodes, take for instance the formula 
++ * "A + {B cdot C} over D", it looks like this 
++ * \f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$. The tree for this formula 
++ * looks like this:
++ * 
++ * \dot 
++ * digraph {
++ * labelloc = "t";
++ * label= "Equation: \"A  + {B  cdot C} over D\"";
++ * size = "9,9";
++ * n0 [label="SmTableNode (1)"];
++ * n0 -> n1 [label="0"];
++ * n1 [label="SmLineNode (2)"];
++ * n1 -> n2 [label="0"];
++ * n2 [label="SmExpressionNode (3)"];
++ * n2 -> n3 [label="0"];
++ * n3 [label="SmBinHorNode (4)"];
++ * n3 -> n4 [label="0"];
++ * n4 [label="SmTextNode: A (5)"];
++ * n3 -> n5 [label="1"];
++ * n5 [label="SmMathSymbolNode:  (6)"];
++ * n3 -> n6 [label="2"];
++ * n6 [label="SmBinVerNode (7)"];
++ * n6 -> n7 [label="0"];
++ * n7 [label="SmExpressionNode (8)"];
++ * n7 -> n8 [label="0"];
++ * n8 [label="SmBinHorNode (9)"];
++ * n8 -> n9 [label="0"];
++ * n9 [label="SmTextNode: B (10)"];
++ * n8 -> n10 [label="1"];
++ * n10 [label="SmMathSymbolNode: â‹… (11)"];
++ * n8 -> n11 [label="2"];
++ * n11 [label="SmTextNode: C (12)"];
++ * n6 -> n12 [label="1"];
++ * n12 [label="SmRectangleNode (13)"];
++ * n6 -> n13 [label="2"];
++ * n13 [label="SmTextNode: D (14)"];
++ * }
++ * \enddot
++ * 
++ * The vertices are nodes, their label says what kind of node and the number in parentheses is
++ *  the identifier of the node (In practices a pointer is used instead of the id). The direction
++ *  of the edges tells which node is parent and which is child. The label of the edges are the
++ *  child node index number, given to SmNode::GetSubNode() of the parent to get the child node.
++ * 
++ *
++ * \subsection visual_lines Visual Lines
++ * 
++ * Inorder to do caret movement in visual lines, we need a definition of caret position and 
++ * visual line. In a tree such as the above there are three visual lines. There's the outer most
++ * line, with entries such as 
++ * \f$\mbox{A}\f$, \f$ + \f$ and \f$ \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$. Then there's
++ *  the numerator line of the fraction it has entries \f$ \mbox{B} \f$, \f$ \cdot \f$ and \f$ \mbox{C} \f$.
++ *  And last by not least there's the denominator line of the fraction it's only entry is \f$ \mbox{D} \f$.
++ * 
++ * For visual editing it should be possible to place a caret on both sides of any line entry, 
++ * consider a line entry a character or construction that in a line is treated as a character.
++ *  Imagine the caret is placed to the right of the plus sign (id: 6), now if user presses 
++ * backspace this should delete the plus sign (id: 6), and if the user presses delete this 
++ * should delete the entire fraction (id: 7). This is because the caret is in the outer most 
++ * line where the fraction is considered a line entry.
++ * 
++ * However, inorder to prevent users from accidentally deleting large subtrees, just because 
++ * they logically placed there caret a in the wrong line, require that complex constructions 
++ * such as a fraction is selected before it is deleted. Thus in this case it wouldn't be 
++ * deleted, but only selected and then deleted if the user hit delete again. Anyway, this is 
++ * slightly off topic for now.
++ * 
++ * Important about visual lines is that they don't always have an SmExpressionNode as root 
++ * and the entries in a visual line is all the nodes of a subtree ordered left to right that
++ *  isn't either an SmExpressionNode, SmBinHorNode or SmUnHorNode.
++ * 
++ * 
++ * \subsection caret_positions Caret Positions
++ *
++ * A caret position in OpenOffice Math is representated by an instance of SmCaretPos. 
++ * That is a caret position is a node and an index related to this node. For most nodes the 
++ * index 0, means caret is infront of this node, the index 1 means caret is after this node.
++ * For SmTextNode the index is the caret position after the specified number of characters, 
++ * imagine an SmTextNode with the number 1337. The index 3 in such SmTextNode would mean a 
++ * caret placed right before 7, e.g. "133|7".
++ * 
++ * For SmExpressionNode, SmBinHorNode and SmUnHorNode the only legal index is 0, which means
++ *  infront of the node. Actually the index 0 may only because for the first caret position 
++ * in a visual line. From the example above, consider the following subtree that constitutes 
++ * a visual line:
++ * 
++ * \dot 
++ * digraph {
++ * labelloc = "t";
++ * label= "Subtree that constitutes a visual line";
++ * size = "7,5";
++ * n7 [label="SmExpressionNode (8)"];
++ * n7 -> n8 [label="0"];
++ * n8 [label="SmBinHorNode (9)"];
++ * n8 -> n9 [label="0"];
++ * n9 [label="SmTextNode: B (10)"];
++ * n8 -> n10 [label="1"];
++ * n10 [label="SmMathSymbolNode: â‹… (11)"];
++ * n8 -> n11 [label="2"];
++ * n11 [label="SmTextNode: C (12)"];
++ * }
++ * \enddot
++ * Here the caret positions are:
++ * 
++ * <TABLE>
++ * <TR><TD><B>Caret position:</B></TD><TD><B>Example:</B></TD>
++ * </TR><TR>
++ *     <TD>{id: 8, index: 0}</TD>
++ *     <TD>\f$ \mid \mbox{C} \cdot \mbox{C} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 10, index: 1}</TD>
++ *     <TD>\f$ \mbox{C} \mid \cdot \mbox{C} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 11, index: 1}</TD>
++ *     <TD>\f$ \mbox{C} \cdot \mid \mbox{C} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 12, index: 1}</TD>
++ *     <TD>\f$ \mbox{C} \cdot \mbox{C} \mid \f$</TD>
++ * </TR><TR>
++ * </TABLE>
++ *
++ * Where \f$ \mid \f$ is used to denote caret position.
++ * 
++ * With these exceptions included in the definition the id and index: {id: 11, index: 0} does
++ * \b not constitute a caret position in the given context. Note the method 
++ * SmCaretPos::IsValid() does not check if this invariant holds true, but code in SmCaret, 
++ * SmSetSelectionVisitor and other places depends on this invariant to hold.
++ * 
++ *
++ * \subsection caret_movement Caret Movement
++ * 
++ * As the placement of caret positions depends very much on the context within which a node 
++ * appears it is not trivial to find all caret positions and determine which follows which. 
++ * In OpenOffice Math this is done by the SmCaretPosGraphBuildingVisitor. This visitor builds 
++ * graph (an instnce of SmCaretPosGraph) over the caret positions. For details on how this 
++ * graph is build, and how new methods should be implemented see SmCaretPosGraphBuildingVisitor.
++ * 
++ * The result of the SmCaretPosGraphBuildingVisitor is a graph over the caret positions in a 
++ * formula, representated by an instance of SmCaretPosGraph. Each entry (instances of SmCaretPosGraphEntry)
++ * has a pointer to the entry to the left and right of itself. This way we can easily find 
++ * the caret position to a right or left of a given caret position. Note each caret position 
++ * only appears once in this graph.
++ * 
++ * When searching for a caret position after a left click on the formula this map is also used.
++ * We simply iterate over all entries, uses the SmCaretPos2LineVisitor to find a line for each
++ * caret position. Then the distance from the click to the line is computed and we choose the
++ * caret position closest to the click.
++ * 
++ * For up and down movement, we also iterator over all caret positions and use SmCaretPos2LineVisitor
++ * to find a line for each caret position. Then we compute the distance from the current
++ * caret position to every other caret position and chooses the one closest that is either
++ * above or below the current caret position, depending on wether we're doing up or down movement.
++ * 
++ * This result of this approach to caret movement is that we have logically predictable 
++ * movement for left and right, whilst leftclick, up and down movement depends on the sizes 
++ * and placement of all node and may be less logically predictable. This solution also means
++ * that we only have one complex visitor generating the graph, imagine the nightmare if we 
++ * had a visitor for movement in each direction.
++ * 
++ * Making up and down movement independent of node sizes and placement wouldn't necessarily
++ * be a good thing either. Consider the formula \f$ \frac{1+2+3+4+5}{6} \f$, if the caret is
++ * placed as displayed here: \f$ \frac{1+2+3+4+5}{6 \mid} \f$, up movement should move to right 
++ * after "3": \f$ \frac{1+2+3|+4+5}{6} \f$. However, such a move depends on the sizes and placement
++ * of all nodes in the fraction.
++ * 
++ *
++ * \subsubsection caretpos_graph_example Example of Caret Position Graph
++ * 
++ * If we consider the formula 
++ * \f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$ from \ref formula_trees. 
++ * It has the following caret positions:
++ * 
++ * <TABLE>
++ * <TR>
++ *     <TD><B>Caret position:</B></TD>
++ *     <TD><B>Example:</B></TD>
++ * </TR><TR>
++ *     <TD>{id: 3, index: 0}</TD>
++ *     <TD>\f$ \mid\mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 5, index: 1}</TD>
++ *     <TD>\f$ \mbox{A}\mid + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 6, index: 1}</TD>
++ *     <TD>\f$ \mbox{A} + \mid \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 8, index: 0}</TD>
++ *     <TD>\f$ \mbox{A} + \frac{ \mid \mbox{B} \cdot \mbox{C}}{\mbox{D}} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 10, index: 1}</TD>
++ *     <TD>\f$ \mbox{A} + \frac{\mbox{B} \mid \cdot \mbox{C}}{\mbox{D}} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 11, index: 1}</TD>
++ *     <TD>\f$ \mbox{A} + \frac{\mbox{B} \cdot \mid \mbox{C}}{\mbox{D}} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 12, index: 1}</TD>
++ *     <TD>\f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C} \mid}{\mbox{D}} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 14, index: 0}</TD>
++ *     <TD>\f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mid \mbox{D}} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 14, index: 1}</TD>
++ *     <TD>\f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D} \mid} \f$</TD>
++ * </TR><TR>
++ *     <TD>{id: 7, index: 1}</TD>
++ *     <TD>\f$ \mbox{A} + \frac{\mbox{B} \cdot \mbox{C}}{\mbox{D}} \mid \f$</TD>
++ * </TR>
++ * </TABLE>
++ * 
++ * Below is a directed graph over the caret postions and how you can move between them.
++ * \dot
++ * digraph {
++ *     labelloc = "t";
++ *     label= "Caret Position Graph";
++ *     size = "4,6";
++ *     p0 [label = "{id: 3, index: 0}"];
++ *     p0 -> p1 [fontsize = 10.0, label = "right"];
++ *     p1 [label = "{id: 5, index: 1}"];
++ *     p1 -> p0 [fontsize = 10.0, label = "left"];
++ *     p1 -> p2 [fontsize = 10.0, label = "right"];
++ *     p2 [label = "{id: 6, index: 1}"];
++ *     p2 -> p1 [fontsize = 10.0, label = "left"];
++ *     p2 -> p3 [fontsize = 10.0, label = "right"];
++ *     p3 [label = "{id: 8, index: 0}"];
++ *     p3 -> p2 [fontsize = 10.0, label = "left"];
++ *     p3 -> p4 [fontsize = 10.0, label = "right"];
++ *     p4 [label = "{id: 10, index: 1}"];
++ *     p4 -> p3 [fontsize = 10.0, label = "left"];
++ *     p4 -> p5 [fontsize = 10.0, label = "right"];
++ *     p5 [label = "{id: 11, index: 1}"];
++ *     p5 -> p4 [fontsize = 10.0, label = "left"];
++ *     p5 -> p6 [fontsize = 10.0, label = "right"];
++ *     p6 [label = "{id: 12, index: 1}"];
++ *     p6 -> p5 [fontsize = 10.0, label = "left"];
++ *     p6 -> p9 [fontsize = 10.0, label = "right"];
++ *     p7 [label = "{id: 14, index: 0}"];
++ *     p7 -> p2 [fontsize = 10.0, label = "left"];
++ *     p7 -> p8 [fontsize = 10.0, label = "right"];
++ *     p8 [label = "{id: 14, index: 1}"];
++ *     p8 -> p7 [fontsize = 10.0, label = "left"];
++ *     p8 -> p9 [fontsize = 10.0, label = "right"];
++ *     p9 [label = "{id: 7, index: 1}"];
++ *     p9 -> p6 [fontsize = 10.0, label = "left"];
++ * }
++ * \enddot
++ */ 
++
++/* TODO: Write documentation about the following keywords:
++ * 
++ * Visual Selections:
++ *  - Show images
++ *  - Talk about how the visitor does this
++ * 
++ * Modifying a Visual Line:
++ *  - Find top most non-compo of the line (e.g. The subtree that constitutes a line)
++ *  - Make the line into a list
++ *  - Edit the list, add/remove/modify nodes
++ *  - Parse the list back into a subtree
++ *  - Insert the new subtree where the old was taken
++ */
++
++#endif /* CARET_H */
+diff --git starmath/inc/cursor.hxx starmath/inc/cursor.hxx
+new file mode 100644
+index 0000000..ff865a8
+--- /dev/null
++++ starmath/inc/cursor.hxx
+@@ -0,0 +1,404 @@
++#ifndef SMCURSOR_H
++#define SMCURSOR_H
++
++#include "node.hxx"
++#include "caret.hxx"
++
++/** Factor to multiple the squared horizontical distance with
++ * Used for Up and Down movement.
++ */
++#define HORIZONTICAL_DISTANCE_FACTOR        10
++
++/** Enum of direction for movement */
++enum SmMovementDirection{
++    MoveUp,
++    MoveDown,
++    MoveLeft,
++    MoveRight
++};
++
++/** Enum of elements that can inserted into a formula */
++enum SmFormulaElement{
++    BlankElement,
++    FactorialElement,
++    PlusElement,
++    MinusElement,
++    CDotElement,
++    EqualElement,
++    LessThanElement,
++    GreaterThanElement
++};
++
++/** Bracket types that can be inserted */
++enum SmBracketType {
++    /** None brackets, left command "none" */
++    NoneBrackets,
++    /** Round brackets, left command "(" */
++    RoundBrackets,
++    /**Square brackets, left command "[" */
++    SquareBrackets,
++    /** Double square brackets, left command "ldbracket" */
++    DoubleSquareBrackets,
++    /** Line brackets, left command "lline" */
++    LineBrackets,
++    /** Double line brackets, left command "ldline" */
++    DoubleLineBrackets,
++    /** Curly brackets, left command "lbrace" */
++    CurlyBrackets,
++    /** Angle brackets, left command "langle" */
++    AngleBrackets,
++    /** Ceiling brackets, left command "lceil" */
++    CeilBrackets,
++    /** Floor brackets, left command "lfloor" */
++    FloorBrackets
++};
++
++/** A list of nodes */
++typedef std::list<SmNode*> SmNodeList;
++
++class SmDocShell;
++
++/** Formula cursor
++ *
++ * This class is used to represent a cursor in a formula, which can be used to manipulate
++ * an formula programmatically.
++ * @remarks This class is a very intimite friend of SmDocShell.
++ */
++class SmCursor{
++public:
++    SmCursor(SmNode* tree, SmDocShell* pShell){
++        //Initialize members
++        pTree           = tree;
++        anchor          = NULL;
++        position        = NULL;
++        pGraph          = NULL;
++        pDocShell       = pShell;
++        pClipboard      = NULL;
++        nEditSections   = 0;
++        //Build graph
++        BuildGraph();
++    }
++
++    ~SmCursor(){
++        SetClipboard();
++        if(pGraph)
++            delete pGraph;
++        pGraph = NULL;
++    }
++    
++    /** Gets the anchor */
++    SmCaretPos GetAnchor(){ return anchor->CaretPos; }
++    
++    /** Get position */
++    SmCaretPos GetPosition() { return position->CaretPos; }
++    
++    /** True, if the cursor has a selection */
++    bool HasSelection() { return anchor != position; }
++    
++    /** Move the position of this cursor */
++    void Move(OutputDevice* pDev, SmMovementDirection direction, bool bMoveAnchor = true);
++    
++    /** Move to the caret position closet to a given point */
++    void MoveTo(OutputDevice* pDev, Point pos, bool bMoveAnchor = true);
++
++    /** Delete the current selection or do nothing */
++    void Delete();
++
++    /** Insert text at the current position */
++    void InsertText(XubString aString);
++
++    /** Insert an element into the formula */
++    void InsertElement(SmFormulaElement element);
++
++    /** Insert a command specified in commands.src*/
++    void InsertCommand(USHORT nCommand);
++
++    /** Insert command text translated into line entries at position 
++     *
++     * Note: This method uses the parser to translate a command text into a
++     * tree, then it copies line entries from this tree into the current tree.
++     * Will not work for commands such as newline or ##, if position is in a matrix.
++     * This will work for stuff like "A intersection B". But stuff spaning multiple lines
++     * or dependent on the context which position is placed in will not work!
++     */
++    void InsertCommandText(String aCommandText);
++
++    /** Insert a special node created from aString
++     *
++     * Used for handling insert request from the "catalog" dialog.
++     * The provided string should be formatet as the desired command: %phi
++     * Note: this method ONLY supports commands defined in Math.xcu
++     *
++     * For more complex expressions use InsertCommandText, this method doesn't
++     * use SmParser, this means that it's faster, but not as strong.
++     */
++    void InsertSpecial(XubString aString);
++
++    /** Create sub-/super script
++     *
++     * If there's a selection, it will be move into the appropriate sub-/super scription
++     * of the node infront of it. If there's no node infront of position (or the selection),
++     * a sub-/super scription of a new SmPlaceNode will be made.
++     *
++     * If there's is an existing subscription of the node, the caret will be moved into it,
++     * and any selection will replace it.
++     */
++    void InsertSubSup(SmSubSup eSubSup);
++
++    /** Create a limit on an SmOperNode
++     *
++     * This this method only work if the caret is inside an SmOperNode, or to the right of one.
++     * Notice also that this method ignores any selection made.
++     *
++     * @param bMoveCaret If true that caret will be moved into the limit.
++     *
++     * @returns True, if the caret was in a context where this operation was possible.
++     */
++    BOOL InsertLimit(SmSubSup eSubSup, BOOL bMoveCaret = TRUE);
++
++    /** Insert a new row or newline
++     *
++     * Inserts a new row if position is in an matrix or stack command.
++     * Otherwise a newline is inserted if we're in a toplevel line.
++     *
++     * @returns True, if a new row/line could be inserted.
++     *
++     * @remarks If the caret is placed in a subline of a command that doesn't support
++     *          this operator the method returns FALSE, and doesn't do anything.
++     */
++    BOOL InsertRow();
++
++    /** Insert a fraction, use selection as numerator */
++    void InsertFraction();
++
++    /** Create brackets around current selection, or new SmPlaceNode */
++    void InsertBrackets(SmBracketType eBracketType);
++
++    /** Copy the current selection */
++    void Copy();
++    /** Cut the current selection */
++    void Cut(){
++        Copy();
++        Delete();
++    }
++    /** Paste the clipboard */
++    void Paste();
++
++    /** Returns true if more than one node is selected 
++     *
++     * This method is used for implementing backspace and delete.
++     * If one of these causes a complex selection, e.g. a node with
++     * subnodes or similar, this should not be deleted imidiately.
++     */
++    bool HasComplexSelection();
++
++    /** Finds the topmost node in a visual line
++     *
++     * If MoveUpIfSelected is true, this will move up to the parent line
++     * if the parent of the current line is selected.
++     */
++    static SmNode* FindTopMostNodeInLine(SmNode* pSNode, bool MoveUpIfSelected = false);
++
++    /** Draw the caret */
++    void Draw(OutputDevice& pDev, Point Offset);
++
++private:
++    friend class SmDocShell;
++
++    SmCaretPosGraphEntry    *anchor,
++                            *position;
++    /** Formula tree */
++    SmNode* pTree;
++    /** Owner of the formula tree */
++    SmDocShell* pDocShell;
++    /** Graph over caret position in the current tree */
++    SmCaretPosGraph* pGraph;
++    /** Clipboard holder */
++    SmNodeList* pClipboard;
++
++    /** Returns a node that is selected, if any could be found */
++    SmNode* FindSelectedNode(SmNode* pNode);
++
++    /** Is this one of the nodes used to compose a line
++     *
++     * These are SmExpression, SmBinHorNode, SmUnHorNode etc.
++     */
++    static bool IsLineCompositionNode(SmNode* pNode);
++
++    /** Count number of selected nodes, excluding line composition nodes
++     *
++     * Note this function doesn't count line composition nodes and it
++     * does count all subnodes as well as the owner nodes.
++     *
++     * Used by SmCursor::HasComplexSelection()
++     */
++    int CountSelectedNodes(SmNode* pNode);
++
++    /** Convert a visual line to a list
++     *
++     * Note this method will delete all the nodes that will no longer be needed.
++     * that includes pLine!
++     * This method also deletes SmErrorNode's as they're just meta info in the line.
++     */
++    static SmNodeList* LineToList(SmStructureNode* pLine, SmNodeList* pList = new SmNodeList());
++
++    /** Clone a visual line to a list 
++     *
++     * Doesn't clone SmErrorNode's these are ignored, as they are context dependent metadata.
++     */
++    static SmNodeList* CloneLineToList(SmStructureNode* pLine, 
++                                       bool bOnlyIfSelected = false, 
++                                       SmNodeList* pList = new SmNodeList());
++
++    /** Build pGraph over caret positions */
++    void BuildGraph();
++
++    /** Insert new nodes in the tree after position */
++    void InsertNodes(SmNodeList* pNewNodes);
++
++    /** tries to set position to a specific SmCaretPos
++     *
++     * @returns false on failure to find the position in pGraph.
++     */
++    bool SetCaretPosition(SmCaretPos pos, bool moveAnchor = false);
++
++    /** Set selected on nodes of the tree */
++    void AnnotateSelection();
++
++    /** Set the clipboard, and release current clipboard 
++     *
++     * Call this method with NULL to reset the clipboard
++     * @remarks: This method takes ownership of pList.
++     */
++    void SetClipboard(SmNodeList* pList = NULL);
++
++    /** Clone list of nodes (creates a deep clone) */
++    static SmNodeList* CloneList(SmNodeList* pList);
++
++    /** Find an iterator pointing to the node in pLineList following aCaretPos
++     *
++     * If aCaretPos::pSelectedNode cannot be found it is assumed that it's infront of pLineList,
++     * thus not an element in pLineList. In this case this method returns an iterator to the
++     * first element in pLineList.
++     *
++     * If the current position is inside an SmTextNode, this node will be split in two, for this
++     * reason you should beaware that iterators to elements in pLineList may be invalidated, and
++     * that you should call PatchLineList() with this iterator if no action is taken.
++     */
++    static SmNodeList::iterator FindPositionInLineList(SmNodeList* pLineList, SmCaretPos aCaretPos);
++
++    /** Patch a line list after modification, merge SmTextNode, remove SmPlaceNode etc.
++     *
++     * @param pLineList The line list to patch
++     * @param aIter     Iterator pointing to the element that needs to be patched with it's previous.
++     *
++     * When the list is patched text nodes before and after aIter will be merged.
++     * If there's an, in the context, inappropriate SmPlaceNode before or after aIter it will also be
++     * removed.
++     *
++     * @returns A caret position equivalent to one selecting the node before aIter, the method returns
++     *          an invalid SmCaretPos to indicate placement infront of the line.
++     */
++     static SmCaretPos PatchLineList(SmNodeList* pLineList, SmNodeList::iterator aIter);
++
++    /** Take selected nodes from a list
++     *
++     * Puts the selected nodes into pSelectedNodes, or if pSelectedNodes is NULL deletes
++     * the selected nodes.
++     * Note: If there's a selection inside an SmTextNode this node will be split, and it
++     * will not be merged when the selection have been taken. Use PatchLineList on the
++     * iterator returns to fix this.
++     *
++     * @returns An iterator pointing to the element following the selection taken.
++     */
++    static SmNodeList::iterator TakeSelectedNodesFromList(SmNodeList *pLineList,
++                                                         SmNodeList *pSelectedNodes = NULL);
++
++    /** Create an instance of SmMathSymbolNode usable for brackets */
++    static SmNode *CreateBracket(SmBracketType eBracketType, BOOL bIsLeft);
++
++    /** The number of times BeginEdit have been called
++     * Used to allow nesting of BeginEdit() and EndEdit() sections
++     */
++    int nEditSections;
++    /** Holds data for BeginEdit() and EndEdit() */
++    BOOL bIsEnabledSetModifiedSmDocShell;
++    /** Begin section where the tree will be modified */
++    void BeginEdit();
++    /** End section where the tree will be modified */
++    void EndEdit();
++    /** Request the formula is repainted */
++    void RequestRepaint();
++};
++
++/** Minimalistic recursive decent SmNodeList parser
++ *
++ * This parser is used to take a list of nodes that constitues a line
++ * and parse them to a tree of SmBinHorNode, SmUnHorNode and SmExpression.
++ *
++ * Please note, this will not handle all kinds of nodes, only nodes that
++ * constitues and entry in a line.
++ *
++ * Below is an EBNF representation of the grammar used for this parser:
++ * \code
++ * Expression   -> Relation*
++ * Relation     -> Sum [(=|<|>|...) Sum]*
++ * Sum          -> Product [(+|-) Product]*
++ * Product      -> Factor [(*|/) Factor]*
++ * Factor       -> [+|-|-+|...]* Factor | Postfix
++ * Postfix      -> node [!]*
++ * \endcode
++ */
++class SmNodeListParser{
++public:
++    /** Create an instance of SmNodeListParser */
++    SmNodeListParser(){
++        pList = NULL;
++    }
++    /** Parse a list of nodes to an expression 
++     *
++     * If bDeleteErrorNodes is true, old error nodes will be deleted.
++     */
++    SmNode* Parse(SmNodeList* list, bool bDeleteErrorNodes = true);
++    /** True, if the token is an operator */
++    static BOOL IsOperator(const SmToken &token);
++    /** True, if the token is a relation operator */
++    static BOOL IsRelationOperator(const SmToken &token);
++    /** True, if the token is a sum operator */
++    static BOOL IsSumOperator(const SmToken &token);
++    /** True, if the token is a product operator */
++    static BOOL IsProductOperator(const SmToken &token);
++    /** True, if the token is a unary operator */
++    static BOOL IsUnaryOperator(const SmToken &token);
++    /** True, if the token is a postfix operator */
++    static BOOL IsPostfixOperator(const SmToken &token);
++private:
++    SmNodeList* pList;
++    /** Get the current terminal */
++    SmNode* Terminal(){
++        if(pList->size() > 0)
++            return pList->front();
++        return NULL;
++    }
++    /** Move to next terminal */
++    SmNode* Next(){
++        pList->pop_front();
++        return Terminal();
++    }
++    /** Take the current terminal */
++    SmNode* Take(){
++        SmNode* pRetVal = Terminal();
++        Next();
++        return pRetVal;
++    }
++    SmNode* Expression();
++    SmNode* Relation();
++    SmNode* Sum();
++    SmNode* Product();
++    SmNode* Factor();
++    SmNode* Postfix();
++    SmNode* Error();
++};
++
++
++#endif /* SMCURSOR_H */
+diff --git starmath/inc/document.hxx starmath/inc/document.hxx
+index 364eff2..1e7cd62 100644
+--- starmath/inc/document.hxx
++++ starmath/inc/document.hxx
+@@ -47,6 +47,7 @@ class SmNode;
+ class SfxMenuBarManager;
+ class SfxPrinter;
+ class Printer;
++class SmCursor;
+ 
+ #define HINT_DATACHANGED	1004
+ 
+@@ -105,6 +106,7 @@ class SmDocShell : public SfxObjectShell, public SfxListener
+ {
+     friend class SmPrinterAccess;
+     friend class SmModel;
++    friend class SmCursor;
+ 
+     String				aText;
+     SmFormat   			aFormat;
+@@ -122,6 +124,7 @@ class SmDocShell : public SfxObjectShell, public SfxListener
+                         nBottomBorder;
+     USHORT				nModifyCount;
+     BOOL				bIsFormulaArranged;
++    SmCursor           *pCursor;
+ 
+ 
+ 
+@@ -157,10 +160,15 @@ class SmDocShell : public SfxObjectShell, public SfxListener
+     OutputDevice*       GetRefDev();
+ 
+     BOOL				IsFormulaArranged() const { return bIsFormulaArranged; }
+-    void				SetFormulaArranged(BOOL bVal) { bIsFormulaArranged = bVal; }
++    void		        SetFormulaArranged(BOOL bVal) { bIsFormulaArranged = bVal; }
+ 
+     virtual BOOL		ConvertFrom(SfxMedium &rMedium);
+ 
++    /** Called whenever the formula is changed
++     * Deletes the current cursor
++     */
++    void                InvalidateCursor();
++
+ public:
+     TYPEINFO();
+     SFX_DECL_INTERFACE(SFX_INTERFACE_SMA_START+1)
+@@ -204,7 +212,7 @@ public:
+     EditEngine & 	GetEditEngine();
+     SfxItemPool &	GetEditEngineItemPool();
+ 
+-    void		Draw(OutputDevice &rDev, Point &rPosition);
++    void		DrawFormula(OutputDevice &rDev, Point &rPosition, BOOL bDrawSelection = FALSE);
+     Size		GetSize();
+ 
+     void        Repaint();
+@@ -218,6 +226,15 @@ public:
+ 
+     virtual void SetVisArea (const Rectangle & rVisArea);
+     virtual void SetModified(BOOL bModified);
++
++    /** Get a cursor for modifying this document 
++     * @remarks Don't store this reference, a new cursor may be made...
++     */
++    SmCursor&   GetCursor();
++    /** True, if cursor have previously been requested and thus
++     * has some sort of position.
++     */
++    BOOL        HasCursor() { return pCursor != NULL; }
+ };
+ 
+ 
+diff --git starmath/inc/edit.hxx starmath/inc/edit.hxx
+index 595564f..56bafab 100644
+--- starmath/inc/edit.hxx
++++ starmath/inc/edit.hxx
+@@ -68,15 +68,13 @@ class SmEditWindow : public Window, public DropTargetHelper
+     ScrollBar	   *pHScrollBar,
+                    *pVScrollBar;
+     ScrollBarBox   *pScrollBox;
+-    Timer			aModifyTimer,
+-                    aCursorMoveTimer;
++    Timer			aModifyTimer;
+     ESelection		aOldSelection;
+ 
+     virtual void KeyInput(const KeyEvent& rKEvt);
+     virtual void Command(const CommandEvent& rCEvt);
+     DECL_LINK(MenuSelectHdl, Menu *);
+     DECL_LINK(ModifyTimerHdl, Timer *);
+-    DECL_LINK(CursorMoveTimerHdl, Timer *);
+ 
+     virtual void DataChanged( const DataChangedEvent& );
+     virtual void Resize();
+diff --git starmath/inc/node.hxx starmath/inc/node.hxx
+index dabb503..7a19b6a 100644
+--- starmath/inc/node.hxx
++++ starmath/inc/node.hxx
+@@ -31,6 +31,24 @@
+ 
+ 
+ #include <vector>
++#include <fstream>
++#include <iostream>
++#include <stdio.h>
++
++//My special assert macro
++//TODO: replace this with DBG_ASSERT when this patch moves to production, can be done using search/replace
++#define j_assert(cond, msg)     do{                                                             \
++                                    if(!(cond))                                                 \
++                                    {                                                           \
++                                        std::cerr<<"Failed assertion: "<<msg<<", at line ";     \
++                                        char* f = (char*)__FILE__;                              \
++                                        f += strlen(f);                                         \
++                                        do f--; while(*f != '/');                               \
++                                        do f--; while(*f != '/');                               \
++                                        do f--; while(*f != '/');                               \
++                                        fprintf(stderr, "%d in %s\n", __LINE__, f + 1);         \
++                                    }                                                           \
++                                } while(false)
+ 
+ #include "parse.hxx"
+ #include "types.hxx"
+@@ -41,6 +59,7 @@
+ #define ATTR_BOLD		0x0001
+ #define ATTR_ITALIC		0x0002
+ 
++
+ #define FNTSIZ_ABSOLUT	1
+ #define FNTSIZ_PLUS 	2
+ #define FNTSIZ_MINUS	3
+@@ -59,6 +78,7 @@
+ 
+ extern SmFormat	*pActiveFormat;
+ 
++class SmVisitor;
+ class SmDocShell;
+ class SmNode;
+ class SmStructureNode;
+@@ -97,6 +117,8 @@ class SmNode : public SmRect
+                     nAttributes;
+     BOOL			bIsPhantom,
+                     bIsDebug;
++                    
++    BOOL            bIsSelected;
+ protected:
+     SmNode(SmNodeType eNodeType, const SmToken &rNodeToken);
+ 
+@@ -160,7 +182,6 @@ public:
+ #ifdef SM_RECT_DEBUG
+     using   SmRect::Draw;
+ #endif
+-    virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
+ 
+     virtual void    GetAccessibleText( String &rText ) const;
+     sal_Int32       GetAccessibleIndex() const { return nAccIndex; }
+@@ -180,12 +201,126 @@ public:
+ 
+     const SmNode *	FindTokenAt(USHORT nRow, USHORT nCol) const;
+     const SmNode *	FindRectClosestTo(const Point &rPoint) const;
+-};
++    
++    /** Accept a visitor
++     * Calls the method for this class on the visitor
++     */
++    virtual void Accept(SmVisitor* pVisitor);
++    
++    /** True if this node is selected */
++    BOOL IsSelected() const {return bIsSelected;}
++    void SetSelected(BOOL Selected = true) {bIsSelected = Selected;}
++    
++    /** The tree as dot graph for graphviz, usable for debugging 
++     * Convert the output to a image using $ dot graph.gv -Tpng > graph.png
++     */
++    inline void DumpAsDot(std::ostream &out, String* label = NULL) const{
++        int id = 0;
++        DumpAsDot(out, label, -1, id, -1);
++    }
+ 
++    /** Get the parent node of this node */
++    SmStructureNode* GetParent(){ return aParentNode; }
++    /** Set the parent node */
++    void SetParent(SmStructureNode* parent){
++        aParentNode = parent;
++    }
++
++    /** Get the index of a child node
++     *
++     * Returns -1, if pSubNode isn't a subnode of this.
++     */
++    int IndexOfSubNode(SmNode* pSubNode){
++        USHORT nSize = GetNumSubNodes();
++        for(USHORT i = 0; i < nSize; i++)
++            if(pSubNode == GetSubNode(i))
++                return i;
++        return -1;
++    }
++    /** Set the token for this node */
++    void SetToken(SmToken& token){
++        aNodeToken = token;
++    }
++protected:
++    /** Sets parent on children of this node */
++    void ClaimPaternity(){
++        SmNode* pNode;
++        USHORT	nSize = GetNumSubNodes();
++        for (USHORT i = 0;	i < nSize;	i++)
++            if (NULL != (pNode = GetSubNode(i)))
++                pNode->SetParent((SmStructureNode*)this); //Cast is valid if we have children
++    }
++private:
++    SmStructureNode* aParentNode;
++    void DumpAsDot(std::ostream &out, String* label, int number, int& id, int parent) const;
++};
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
++/** A simple auxiliary iterator class for SmNode
++ *
++ * Example of iteration over children of pMyNode:
++ * \code
++ *  //Node to iterate over:
++ *  SmNode* pMyNode = 0;// A pointer from somewhere
++ *  //The iterator:
++ *  SmNodeIterator it(pMyNode);
++ *  //The iteration:
++ *  while(it.Next()) {
++ *      it->SetSelected(true);
++ *  }
++ * \endcode
++ */
++class SmNodeIterator{
++public:
++    SmNodeIterator(SmNode* node, bool bReverse = false){
++        pNode = node;
++        nSize = pNode->GetNumSubNodes();
++        nIndex = 0;
++        pChildNode = NULL;
++        bIsReverse = bReverse;
++    }
++    /** Get the subnode or NULL if none */
++    SmNode* Next(){
++        while(!bIsReverse && nIndex < nSize){
++            if(NULL != (pChildNode = pNode->GetSubNode(nIndex++)))
++                return pChildNode;
++        }
++        while(bIsReverse && nSize > 0){
++            if(NULL != (pChildNode = pNode->GetSubNode((nSize--)-1)))
++                return pChildNode;
++        }
++        pChildNode = NULL;
++        return NULL;
++    }
++    /** Get the current child node, NULL if none */
++    SmNode* Current(){
++        return pChildNode;
++    }
++    /** Get the current child node, NULL if none */
++    SmNode* operator->(){
++        return pChildNode;
++    }
++private:
++    /** Current child */
++    SmNode* pChildNode;
++    /** Node whos children we're iterating over */
++    SmNode* pNode;
++    /** Size of the node */
++    USHORT nSize;
++    /** Current index in the node */
++    USHORT nIndex;
++    /** Move reverse */
++    bool bIsReverse;
++};
++
++////////////////////////////////////////////////////////////////////////////////
+ 
++/** Abstract baseclass for all composite node
++ *
++ * Subclasses of this class can have subnodes. Nodes that doesn't derivate from
++ * this class does not have subnodes.
++ */
+ class SmStructureNode : public SmNode
+ {
+     SmNodeArray  aSubNodes;
+@@ -212,12 +347,29 @@ public:
+     virtual SmStructureNode & operator = ( const SmStructureNode &rNode );
+ 
+     virtual void  GetAccessibleText( String &rText ) const;
++
++    void SetSubNode(USHORT nIndex, SmNode* pNode){
++        int size = aSubNodes.size();
++        if(size <= nIndex){
++            //Resize subnodes array
++            aSubNodes.resize(nIndex + 1);
++            //Set new slots to NULL
++            for(int i = size; i < nIndex+1; i++)
++                aSubNodes[i] = NULL;
++        }
++        aSubNodes[nIndex] = pNode;
++        ClaimPaternity();
++    }
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Abstract base class for all visible node
++ *
++ * Nodes that doesn't derivate from this class doesn't draw anything, but their
++ * children.
++ */
+ class SmVisibleNode : public SmNode
+ {
+ protected:
+@@ -252,7 +404,10 @@ public:
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Draws a rectangle
++ *
++ * Used for drawing the line in the OVER and OVERSTRIKE commands.
++ */
+ class SmRectangleNode : public SmGraphicNode
+ {
+     Size  aToSize;
+@@ -270,15 +425,19 @@ public:
+ #ifdef SM_RECT_DEBUG
+     using   SmRect::Draw;
+ #endif
+-    virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
++
+     
+     void CreateTextFromNode(String &rText);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Polygon line node
++ *
++ * Used to draw the slash of the WIDESLASH command by SmBinDiagonalNode.
++ */
+ class SmPolyLineNode : public SmGraphicNode
+ {
+     Polygon		aPoly;
+@@ -289,6 +448,8 @@ public:
+     SmPolyLineNode(const SmToken &rNodeToken);
+ 
+     long		 GetWidth() const { return nWidth; }
++    Size         GetToSize() const { return aToSize; }
++    Polygon     &GetPolygon() { return aPoly; }
+ 
+     virtual void AdaptToX(const OutputDevice &rDev, ULONG nWidth);
+     virtual void AdaptToY(const OutputDevice &rDev, ULONG nHeight);
+@@ -298,17 +459,29 @@ public:
+ #ifdef SM_RECT_DEBUG
+     using   SmRect::Draw;
+ #endif
+-    virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
++
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Text node 
++ * 
++ * @remarks This class also serves as baseclass for all nodes that contains text.
++ */
+ class SmTextNode : public SmVisibleNode
+ {
+     XubString   aText;
+     USHORT      nFontDesc;
++    /** Index within text where the selection starts
++     * @remarks Only valid if SmNode::IsSelected() is true
++     */
++    xub_StrLen  nSelectionStart;
++    /** Index within text where the selection ends
++     * @remarks Only valid if SmNode::IsSelected() is true
++     */
++    xub_StrLen  nSelectionEnd;
+ 
+ protected:
+     SmTextNode(SmNodeType eNodeType, const SmToken &rNodeToken, USHORT nFontDescP)
+@@ -328,6 +501,25 @@ public:
+     USHORT				GetFontDesc() const { return nFontDesc; }
+     void				SetText(const XubString &rText) { aText = rText; }
+     const XubString &	GetText() const { return aText; }
++    /** Change the text of this node, including the underlying token */
++    void                ChangeText(const XubString &rText) {
++        aText = rText;
++        SmToken token = GetToken();
++        token.aText = rText;
++        SetToken(token);
++    } 
++    /** Index within GetText() where the selection starts
++     * @remarks Only valid of SmNode::IsSelected() is true
++     */
++    xub_StrLen          GetSelectionStart() const {return nSelectionStart;}
++    /** Index within GetText() where the selection end
++     * @remarks Only valid of SmNode::IsSelected() is true
++     */
++    xub_StrLen          GetSelectionEnd() const {return nSelectionEnd;}
++    /** Set the index within GetText() where the selection starts */
++    void                SetSelectionStart(xub_StrLen index) {nSelectionStart = index;}
++    /** Set the index within GetText() where the selection end */
++    void                SetSelectionEnd(xub_StrLen index) {nSelectionEnd = index;}
+ 
+     virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
+@@ -336,15 +528,22 @@ public:
+ #ifdef SM_RECT_DEBUG
+     using   SmRect::Draw;
+ #endif
+-    virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
++
+ 
+     virtual void  GetAccessibleText( String &rText ) const;
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Special node for user defined characters
++ *
++ * Node used for pre- and user-defined characters from:
++ * officecfg/registry/data/org/openoffice/Office/Math.xcu
++ *
++ * This is just single characters, I think.
++ */
+ class SmSpecialNode : public SmTextNode
+ {
+ protected:
+@@ -363,13 +562,22 @@ public:
+ #ifdef SM_RECT_DEBUG
+     using   SmRect::Draw;
+ #endif
+-    virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
++
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Glyph node for custom operators
++ *
++ * This node is used with commands: oper, uoper and boper.
++ * E.g. in "A boper op B", "op" will be an instance of SmGlyphSpecialNode.
++ * "boper" simply inteprets "op", the following token, as an binary operator.
++ * The command "uoper" interprets the following token as unary operator.
++ * For these commands an instance of SmGlyphSpecialNode is used for the
++ * operator token, following the command.
++ */
+ class SmGlyphSpecialNode : public SmSpecialNode
+ {
+ public:
+@@ -378,12 +586,16 @@ public:
+     {}
+ 
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Math symbol node
++ *
++ * Use for math symbols such as plus, minus and integrale in the INT command.
++ */
+ class SmMathSymbolNode : public SmSpecialNode
+ {
+ protected:
+@@ -404,12 +616,18 @@ public:
+     virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
+     void CreateTextFromNode(String &rText);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Root symbol node
++ *
++ * Root symbol node used by SmRootNode to create the root symbol, infront of 
++ * the line with the line above. I don't think this node should be used for
++ * anything else.
++ */
+ class SmRootSymbolNode : public SmMathSymbolNode
+ {
+     ULONG  nBodyWidth;  // width of body (argument) of root sign
+@@ -419,19 +637,26 @@ public:
+     :   SmMathSymbolNode(NROOTSYMBOL, rNodeToken)
+     {}
+ 
++    ULONG GetBodyWidth() const {return nBodyWidth;};
+     virtual void AdaptToX(const OutputDevice &rDev, ULONG nWidth);
+     virtual void AdaptToY(const OutputDevice &rDev, ULONG nHeight);
+ 
+ #ifdef SM_RECT_DEBUG
+     using   SmRect::Draw;
+ #endif
+-    virtual void Draw(OutputDevice &rDev, const Point &rPosition) const;
++
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Place node
++ *
++ * Used to create the <?> command, that denotes place where something can be
++ * written.
++ * It is drawn as a square with a shadow.
++ */
+ class SmPlaceNode : public SmMathSymbolNode
+ {
+ public:
+@@ -439,15 +664,21 @@ public:
+     :	SmMathSymbolNode(NPLACE, rNodeToken)
+     {
+     }
++    SmPlaceNode() : SmMathSymbolNode(NPLACE, SmToken(TPLACE, MS_PLACE, "<?>")) {};
+ 
+     virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Error node, for parsing errors
++ *
++ * This node is used for parsing errors and draws an questionmark turned upside
++ * down (inverted question mark).
++ */
+ class SmErrorNode : public SmMathSymbolNode
+ {
+ public:
+@@ -459,12 +690,19 @@ public:
+ 
+     virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Table node
++ *
++ * This is the root node for the formula tree. This node is also used for the
++ * STACK and BINOM commands. When used for root node, its
++ * children are instances of SmLineNode, and in some obscure cases the a child
++ * can be an instance of SmExpressionNode, mainly when errors occur. 
++ */
+ class SmTableNode : public SmStructureNode
+ {
+ public:
+@@ -476,12 +714,17 @@ public:
+     virtual SmNode * GetLeftMost();
+ 
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** A line
++ *
++ * Used as child of SmTableNode when the SmTableNode is the root node of the
++ * formula tree. 
++ */
+ class SmLineNode : public SmStructureNode
+ {
+ protected:
+@@ -496,12 +739,18 @@ public:
+ 
+     virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell);
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Expression node
++ *
++ * Used whenever you have an expression such as "A OVER {B + C}", here there is
++ * an expression node that allows "B + C" to be the denominator of the
++ * SmBinVerNode, that the OVER command creates.
++ */
+ class SmExpressionNode : public SmLineNode
+ {
+ public:
+@@ -511,12 +760,16 @@ public:
+ 
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
+     void CreateTextFromNode(String &rText);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Unary horizontical node
++ *
++ * The same as SmBinHorNode except this is for unary operators.
++ */
+ class SmUnHorNode : public SmStructureNode
+ {
+ public:
+@@ -527,12 +780,23 @@ public:
+     }
+ 
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Root node
++ *
++ * Used for create square roots and other roots, example:
++ * \f$ \sqrt[\mbox{[Argument]}]{\mbox{[Body]}} \f$.
++ *
++ * Children:<BR>
++ * 0: Argument (optional)<BR>
++ * 1: Symbol (instance of SmRootSymbolNode)<BR>
++ * 2: Body<BR>
++ * Where argument is optinal and may be NULL.
++ */
+ class SmRootNode : public SmStructureNode
+ {
+ protected:
+@@ -549,12 +813,23 @@ public:
+ 
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
+     void CreateTextFromNode(String &rText);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Binary horizontial node
++ *
++ * This node is used for binary operators. In a formula such as "A + B".
++ *
++ * Children:<BR>
++ * 0: Left operand<BR>
++ * 1: Binary operator<BR>
++ * 2: Right operand<BR>
++ *
++ * None of the children may be NULL.
++ */
+ class SmBinHorNode : public SmStructureNode
+ {
+ public:
+@@ -565,12 +840,24 @@ public:
+     }
+ 
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Binary horizontical node
++ *
++ * This node is used for creating the OVER command, consider the formula:
++ * "numerator OVER denominator", which looks like
++ * \f$ \frac{\mbox{numerator}}{\mbox{denominator}} \f$
++ *
++ * Children:<BR>
++ * 0: Numerator<BR>
++ * 1: Line (instance of SmRectangleNode)<BR>
++ * 2: Denominator<BR>
++ * None of the children may be NULL.
++ */
+ class SmBinVerNode : public SmStructureNode
+ {
+ public:
+@@ -585,12 +872,22 @@ public:
+ 
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
+     void CreateTextFromNode(String &rText);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Binary diagonal node
++ *
++ * Used for implementing the WIDESLASH command, example: "A WIDESLASH B".
++ *
++ * Children:<BR>
++ * 0: Left operand<BR>
++ * 1: right operand<BR>
++ * 2: Line (instance of SmPolyLineNode).<BR>
++ * None of the children may be NULL.
++ */
+ class SmBinDiagonalNode : public SmStructureNode
+ {
+     BOOL	bAscending;
+@@ -605,35 +902,53 @@ public:
+     void 	SetAscending(BOOL bVal)  { bAscending = bVal; }
+ 
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+ 
+-// enums used to index sub-/supscripts in the 'aSubNodes' array
+-// in 'SmSubSupNode'
+-// See graphic for positions at char:
+-//
+-//		CSUP
+-//
+-// LSUP H  H RSUP
+-//		H  H
+-//		HHHH
+-//		H  H
+-// LSUB H  H RSUB
+-//
+-//		CSUB
+-//
++/** Enum used to index sub-/supscripts in the 'aSubNodes' array
++ * in 'SmSubSupNode'
++ *
++ * See graphic for positions at char:
++ *
++ * \code
++ *		CSUP
++ *
++ * LSUP H  H RSUP
++ *		H  H
++ *		HHHH
++ *		H  H
++ * LSUB H  H RSUB
++ *
++ *		CSUB
++ * \endcode
++ */
+ enum SmSubSup
+ {	CSUB, CSUP, RSUB, RSUP, LSUB, LSUP
+ };
+ 
+-// numbers of entries in the above enum (that is: the number of possible
+-// sub-/supscripts)
++/** numbers of entries in the above enum (that is: the number of possible
++ * sub-/supscripts)
++ */
+ #define SUBSUP_NUM_ENTRIES 6
+ 
+-
++/** Super- and subscript node
++ *
++ * Used for creating super- and subscripts for commands such as:
++ * "^", "_", "lsup", "lsub", "csup" and "csub".
++ * Example: "A^2" which looks like: \f$ A^2 \f$
++ *
++ * This node is also used for creating limits on SmOperNode, when
++ * "FROM" and "TO" commands are used with "INT", "SUM" or similar.
++ *
++ * Children of this node can be enumerated using the SmSubSup enum.
++ * Please note that children may be NULL, except for the body.
++ * It is recommended that you access children using GetBody() and
++ * GetSubSup().
++ */
+ class SmSubSupNode : public SmStructureNode
+ {
+     BOOL  bUseLimits;
+@@ -646,7 +961,9 @@ public:
+         bUseLimits = FALSE;
+     }
+ 
++    /** Get body (Not NULL) */
+     SmNode *	   GetBody()	{ return GetSubNode(0); }
++    /** Get body (Not NULL) */
+     const SmNode * GetBody() const
+     {
+         return ((SmSubSupNode *) this)->GetBody();
+@@ -655,17 +972,39 @@ public:
+     void  SetUseLimits(BOOL bVal) { bUseLimits = bVal; }
+     BOOL  IsUseLimits() const { return bUseLimits; };
+ 
++    /** Get super- or subscript
++     * @remarks this method may return NULL.
++     */
+     SmNode * GetSubSup(SmSubSup eSubSup) { return GetSubNode( sal::static_int_cast< USHORT >(1 + eSubSup) ); };
+ 
++    /** Set the body */
++    void SetBody(SmNode* pBody) { SetSubNode(0, pBody); }
++    void SetSubSup(SmSubSup eSubSup, SmNode* pScript) { SetSubNode( 1 + eSubSup, pScript); }
++
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
+     void CreateTextFromNode(String &rText);
++    void Accept(SmVisitor* pVisitor);
+ 
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Node for brace construction
++ *
++ * Used for "lbrace [body] rbrace" and similar constructions.
++ * Should look like \f$ \{\mbox{[body]}\} \f$
++ *
++ * Children:<BR>
++ * 0: Opening brace<BR>
++ * 1: Body (usually SmBracebodyNode)<BR>
++ * 2: Closing brace<BR>
++ * None of the children can be NULL.
++ *
++ * Note that child 1 (Body) is usually SmBracebodyNode, I don't know if it can
++ * be an SmExpressionNode, haven't seen the case. But didn't quite read parser.cxx
++ * enought to exclude this possibility.
++ */
+ class SmBraceNode : public SmStructureNode
+ {
+ public:
+@@ -677,12 +1016,21 @@ public:
+ 
+     virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat);
+     void CreateTextFromNode(String &rText);
++    void Accept(SmVisitor* pVisitor);
+ };
+ 
+ 
+ ////////////////////////////////////////////////////////////////////////////////
+ 
+-
++/** Body of an SmBraceNode
++ * 
++ * This usually only has one child an SmExpressionNode, however, it can also
++ * have other children.
++ * Consider the formula "lbrace [body1] mline [body2] rbrace", looks like:
++ * \f$ \{\mbox{[body1] | [body2]}\} \f$.
++ * In this case SmBracebodyNode will have three children, "[body1]", "|" and
++ * [body2].
++ */
+ class SmBracebodyNode : public SmStructureNode
+ {
+     long  nBodyHeight;
+@@ -692,6 +1040,7 @@ public:
+ 
+     virtual void	Arrange(const OutputDevice &rDev, const SmFormat &rFormat);

... etc. - the rest is truncated


More information about the ooo-build-commit mailing list