/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_starmath.hxx"


#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/accessibility/AccessibleEventObject.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/XAccessible.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/frame/XDesktop.hpp>
#include <com/sun/star/frame/XFramesSupplier.hpp>
#include <com/sun/star/container/XChild.hpp>

#include <comphelper/processfactory.hxx>
#include <comphelper/storagehelper.hxx>
#include <rtl/logfile.hxx>
#include <sfx2/app.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/docinsert.hxx>
#include <sfx2/filedlghelper.hxx>
#include <sfx2/msg.hxx>
#include <sfx2/objface.hxx>
#include <sfx2/printer.hxx>
#include <sfx2/request.hxx>
#include <svl/eitem.hxx>
#include <svl/intitem.hxx>
#include <svl/itemset.hxx>
#include <svl/poolitem.hxx>
#include <svl/ptitem.hxx>
#include <svl/stritem.hxx>
#include <svtools/transfer.hxx>
#include <svl/undo.hxx>
#include <svl/whiter.hxx>
#include <svx/dialogs.hrc>
#include <editeng/editeng.hxx>
#include <svx/svxdlg.hxx>
#include <svx/zoomitem.hxx>
#include <vcl/decoview.hxx>
#include <vcl/menu.hxx>
#include <vcl/msgbox.hxx>
#include <vcl/wrkwin.hxx>
#include <unotools/streamwrap.hxx>

#include "unomodel.hxx"
#include "view.hxx"
#include "config.hxx"
#include "dialog.hxx"
#include "document.hxx"
#include "starmath.hrc"
#include "toolbox.hxx"
#include "mathmlimport.hxx"


#define MINWIDTH		200
#define MINHEIGHT		200
#define MINSPLIT		40
#define SPLITTERWIDTH	2

#define MINZOOM 25
#define MAXZOOM 800

#define SmViewShell
#include "smslots.hxx"

using namespace com::sun::star;
using namespace com::sun::star::accessibility;
using namespace com::sun::star::uno;

using ::rtl::OUString;

//////////////////////////////////////////////////////////////////////

SmGraphicWindow::SmGraphicWindow(SmViewShell* pShell):
	ScrollableWindow(&pShell->GetViewFrame()->GetWindow(), 0),
    pAccessible(0),
	pViewShell(pShell),
	nZoom(100),
	bIsCursorVisible(sal_False)
{
	// docking windows are usually hidden (often already done in the
	// resource) and will be shown by the sfx framework.
	Hide();

	const Fraction aFraction (1,1);
	SetMapMode( MapMode(MAP_100TH_MM, Point(), aFraction, aFraction));

    ApplyColorConfigValues( SM_MOD()->GetColorConfig() );

    SetTotalSize();

	SetHelpId(HID_SMA_WIN_DOCUMENT);
	SetUniqueId(HID_SMA_WIN_DOCUMENT);
}

SmGraphicWindow::~SmGraphicWindow()
{
    if (pAccessible)
        pAccessible->ClearWin();    // make Accessible defunctional
    // Note: memory for pAccessible will be freed when the reference
    // xAccessible is released.
}

void SmGraphicWindow::StateChanged( StateChangedType eType )
{
	if ( eType == STATE_CHANGE_INITSHOW )
		Show();
	ScrollableWindow::StateChanged( eType );
}


void SmGraphicWindow::ApplyColorConfigValues( const svtools::ColorConfig &rColorCfg )
{
    // Note: SetTextColor not necessary since the nodes that
    // get painted have the color information.
#if OSL_DEBUG_LEVEL > 1
//   ColorData nVal = rColorCfg.GetColorValue(svtools::DOCCOLOR).nColor;
#endif
    SetBackground( Color( (ColorData) rColorCfg.GetColorValue(svtools::DOCCOLOR).nColor ) );
    Invalidate();
}


void SmGraphicWindow::DataChanged( const DataChangedEvent& rEvt )
{
    ApplyColorConfigValues( SM_MOD()->GetColorConfig() );

    ScrollableWindow::DataChanged( rEvt );
}


void SmGraphicWindow::MouseButtonDown(const MouseEvent& rMEvt)
{
	ScrollableWindow::MouseButtonDown(rMEvt);

	//
	// set formula-cursor and selection of edit window according to the
	// position clicked at
	//
	DBG_ASSERT(rMEvt.GetClicks() > 0, "Sm : 0 clicks");
	if ( rMEvt.IsLeft() && pViewShell->GetEditWindow() )
	{
		const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree();
		//! kann NULL sein! ZB wenn bereits beim laden des Dokuments (bevor der
		//! Parser angeworfen wurde) ins Fenster geklickt wird.
		if (!pTree)
			return;

		// get click position relativ to formula
		Point  aPos (PixelToLogic(rMEvt.GetPosPixel())
					 - GetFormulaDrawPos());

		// if it was clicked inside the formula then get the appropriate node
		const SmNode *pNode = 0;
		if (pTree->OrientedDist(aPos) <= 0)
			pNode = pTree->FindRectClosestTo(aPos);

		if (pNode)
		{	SmEditWindow  *pEdit = pViewShell->GetEditWindow();
			const SmToken  aToken (pNode->GetToken());

#ifdef notnow
			// include introducing symbols of special char and text
			// (ie '%' and '"')
			sal_uInt16  nExtra = (aToken.eType == TSPECIAL  ||  aToken.eType == TTEXT) ? 1 : 0;

			// set selection to the beginning of the token
			ESelection  aSel (aToken.nRow - 1, aToken.nCol - 1 - nExtra);

			if (rMEvt.GetClicks() != 1)
			{	// select whole token
				// for text include terminating symbol (ie '"')
				aSel.nEndPos += aToken.aText.Len() + nExtra
								+ (aToken.eType == TTEXT ? 1 : 0);
			}
#endif
			// set selection to the beginning of the token
            ESelection  aSel (aToken.nRow - 1, aToken.nCol - 1);

			if (rMEvt.GetClicks() != 1 || aToken.eType == TPLACE)
                aSel.nEndPos = aSel.nEndPos + sal::static_int_cast< sal_uInt16 >(aToken.aText.Len());

			pEdit->SetSelection(aSel);
			SetCursor(pNode);

			// allow for immediate editing and
			//! implicitly synchronize the cursor position mark in this window
			pEdit->GrabFocus();
		}
	}
}

void SmGraphicWindow::GetFocus()
{
/*
    if (xAccessible.is())
    {
        uno::Any aOldValue, aNewValue;
        // aOldValue remains empty
        aNewValue <<= AccessibleStateType::FOCUSED;
        pAccessible->LaunchEvent( AccessibleEventId::STATE_CHANGED,
                aOldValue, aNewValue );
    }
*/
}

void SmGraphicWindow::LoseFocus()
{
    ScrollableWindow::LoseFocus();
    if (xAccessible.is())
    {
        uno::Any aOldValue, aNewValue;
        aOldValue <<= AccessibleStateType::FOCUSED;
        // aNewValue remains empty
        pAccessible->LaunchEvent( AccessibleEventId::STATE_CHANGED,
                aOldValue, aNewValue );
    }
}

void SmGraphicWindow::ShowCursor(sal_Bool bShow)
	// shows or hides the formula-cursor depending on 'bShow' is sal_True or not
{
	sal_Bool  bInvert = bShow != IsCursorVisible();

	if (bInvert)
		InvertTracking(aCursorRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW);

	SetIsCursorVisible(bShow);
}


void SmGraphicWindow::SetCursor(const SmNode *pNode)
{
	const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree();

	// get appropriate rectangle
	Point aOffset (pNode->GetTopLeft() - pTree->GetTopLeft()),
		  aTLPos  (GetFormulaDrawPos() + aOffset);
	aTLPos.X() -= pNode->GetItalicLeftSpace();
	Size  aSize   (pNode->GetItalicSize());
	Point aBRPos  (aTLPos.X() + aSize.Width(), aTLPos.Y() + aSize.Height());

	SetCursor(Rectangle(aTLPos, aSize));
}

void SmGraphicWindow::SetCursor(const Rectangle &rRect)
	// sets cursor to new position (rectangle) 'rRect'.
	// The old cursor will be removed, and the new one will be shown if
	// that is activated in the ConfigItem
{
    SmModule *pp = SM_MOD();

	if (IsCursorVisible())
		ShowCursor(sal_False);		// clean up remainings of old cursor
	aCursorRect = rRect;
	if (pp->GetConfig()->IsShowFormulaCursor())
		ShowCursor(sal_True);		// draw new cursor
}

const SmNode * SmGraphicWindow::SetCursorPos(sal_uInt16 nRow, sal_uInt16 nCol)
	// looks for a VISIBLE node in the formula tree with it's token at
	// (or around) the position 'nRow', 'nCol' in the edit window
	// (row and column numbering starts with 1 there!).
	// If there is such a node the formula-cursor is set to cover that nodes
	// rectangle. If not the formula-cursor will be hidden.
	// In any case the search result is being returned.
{
	// find visible node with token at nRow, nCol
	const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree(),
				 *pNode = 0;
	if (pTree)
		pNode = pTree->FindTokenAt(nRow, nCol);

	if (pNode)
		SetCursor(pNode);
	else
		ShowCursor(sal_False);

	return pNode;
}


void SmGraphicWindow::Paint(const Rectangle&)
{
	DBG_ASSERT(pViewShell, "Sm : NULL pointer");

	SmDocShell &rDoc = *pViewShell->GetDoc();
	Point aPoint;

	rDoc.Draw(*this, aPoint);	//! modifies aPoint to be the topleft
								//! corner of the formula
	SetFormulaDrawPos(aPoint);

	SetIsCursorVisible(sal_False);	// (old) cursor must be drawn again

	const SmEditWindow *pEdit = pViewShell->GetEditWindow();
	if (pEdit)
	{	// get new position for formula-cursor (for possible altered formula)
		sal_uInt16	nRow, nCol;
		SmGetLeftSelectionPart(pEdit->GetSelection(), nRow, nCol);
		nRow++;
		nCol++;
		const SmNode *pFound = SetCursorPos(nRow, nCol);

        SmModule  *pp = SM_MOD();
		if (pFound && pp->GetConfig()->IsShowFormulaCursor())
			ShowCursor(sal_True);
	}
}


void SmGraphicWindow::SetTotalSize ()
{
	SmDocShell &rDoc = *pViewShell->GetDoc();
	const Size aTmp( PixelToLogic( LogicToPixel( rDoc.GetSize() )));
	if ( aTmp != ScrollableWindow::GetTotalSize() )
		ScrollableWindow::SetTotalSize( aTmp );
}


void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt)
{
    if (! (GetView() && GetView()->KeyInput(rKEvt)) )
		ScrollableWindow::KeyInput(rKEvt);
}


void SmGraphicWindow::Command(const CommandEvent& rCEvt)
{
	sal_Bool bCallBase = sal_True;
    if ( !pViewShell->GetViewFrame()->GetFrame().IsInPlace() )
	{
		switch ( rCEvt.GetCommand() )
		{
			case COMMAND_CONTEXTMENU:
			{
				GetParent()->ToTop();
                SmResId aResId( RID_VIEWMENU );
                PopupMenu* pPopupMenu = new PopupMenu(aResId);
				pPopupMenu->SetSelectHdl(LINK(this, SmGraphicWindow, MenuSelectHdl));
                Point aPos(5, 5);
                if (rCEvt.IsMouseEvent())
                    aPos = rCEvt.GetMousePosPixel();
                DBG_ASSERT( pViewShell, "view shell missing" );

                // added for replaceability of context menus #96085, #93782
                pViewShell->GetViewFrame()->GetBindings().GetDispatcher()
                        ->ExecutePopup( aResId, this, &aPos );
                //pPopupMenu->Execute( this, aPos );

				delete pPopupMenu;
				bCallBase = sal_False;
			}
			break;

			case COMMAND_WHEEL:
			{
				const CommandWheelData* pWData = rCEvt.GetWheelData();
				if  ( pWData && COMMAND_WHEEL_ZOOM == pWData->GetMode() )
				{
                    sal_uInt16 nTmpZoom = GetZoom();
					if( 0L > pWData->GetDelta() )
                        nTmpZoom -= 10;
					else
                        nTmpZoom += 10;
                    SetZoom( nTmpZoom );
					bCallBase = sal_False;
				}
			}
			break;
		}
	}
	if ( bCallBase )
		ScrollableWindow::Command (rCEvt);
}


IMPL_LINK_INLINE_START( SmGraphicWindow, MenuSelectHdl, Menu *, pMenu )
{
    SmViewShell *pViewSh = GetView();
	if (pViewSh)
		pViewSh->GetViewFrame()->GetDispatcher()->Execute( pMenu->GetCurItemId() );
	return 0;
}
IMPL_LINK_INLINE_END( SmGraphicWindow, MenuSelectHdl, Menu *, pMenu )


void SmGraphicWindow::SetZoom(sal_uInt16 Factor)
{
	nZoom = Min(Max((sal_uInt16) Factor, (sal_uInt16) MINZOOM), (sal_uInt16) MAXZOOM);
	Fraction   aFraction (nZoom, 100);
	SetMapMode( MapMode(MAP_100TH_MM, Point(), aFraction, aFraction) );
	SetTotalSize();
    SmViewShell *pViewSh = GetView();
	if (pViewSh)
		pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_ATTR_ZOOM);
	Invalidate();
}


void SmGraphicWindow::ZoomToFitInWindow()
{
	SmDocShell &rDoc = *pViewShell->GetDoc();

	// set defined mapmode before calling 'LogicToPixel' below
	SetMapMode(MapMode(MAP_100TH_MM));

	Size	   aSize (LogicToPixel(rDoc.GetSize()));
	Size	   aWindowSize (GetSizePixel());

	if (aSize.Width() > 0  &&  aSize.Height() > 0)
    {
        long nVal = Min ((85 * aWindowSize.Width())  / aSize.Width(),
                      (85 * aWindowSize.Height()) / aSize.Height());
        SetZoom ( sal::static_int_cast< sal_uInt16 >(nVal) );
    }
}

uno::Reference< XAccessible > SmGraphicWindow::CreateAccessible()
{
    if (!pAccessible)
    {
        pAccessible = new SmGraphicAccessible( this );
        xAccessible = pAccessible;
    }
    return xAccessible;
}

/**************************************************************************/


SmGraphicController::SmGraphicController(SmGraphicWindow &rSmGraphic,
                        sal_uInt16          nId_,
						SfxBindings 	&rBindings) :
    SfxControllerItem(nId_, rBindings),
    rGraphic(rSmGraphic)
{
}


void SmGraphicController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
{
	rGraphic.SetTotalSize();
	rGraphic.Invalidate();
	SfxControllerItem::StateChanged (nSID, eState, pState);
}


/**************************************************************************/


SmEditController::SmEditController(SmEditWindow &rSmEdit,
                     sal_uInt16       nId_,
					 SfxBindings  &rBindings) :
    SfxControllerItem(nId_, rBindings),
    rEdit(rSmEdit)
{
}


#if OSL_DEBUG_LEVEL > 1
SmEditController::~SmEditController()
{
}
#endif


void SmEditController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
{
	const SfxStringItem *pItem = PTR_CAST(SfxStringItem, pState);

	if ((pItem != NULL) && (rEdit.GetText() != pItem->GetValue()))
		rEdit.SetText(pItem->GetValue());
	SfxControllerItem::StateChanged (nSID, eState, pState);
}


/**************************************************************************/

SmCmdBoxWindow::SmCmdBoxWindow(SfxBindings *pBindings_, SfxChildWindow *pChildWindow,
							   Window *pParent) :
    SfxDockingWindow(pBindings_, pChildWindow, pParent, SmResId(RID_CMDBOXWINDOW)),
    aEdit       (*this),
    aController (aEdit, SID_TEXT, *pBindings_),
    bExiting    (sal_False)
{
	Hide ();

    aInitialFocusTimer.SetTimeoutHdl(LINK(this, SmCmdBoxWindow, InitialFocusTimerHdl));
    aInitialFocusTimer.SetTimeout(100);
}


SmCmdBoxWindow::~SmCmdBoxWindow ()
{
    aInitialFocusTimer.Stop();
    bExiting = sal_True;
}


SmViewShell * SmCmdBoxWindow::GetView()
{
    SfxViewShell *pView = GetBindings().GetDispatcher()->GetFrame()->GetViewShell();
    return PTR_CAST(SmViewShell, pView);
}

void SmCmdBoxWindow::Resize()
{
	Rectangle aRect = Rectangle(Point(0, 0), GetOutputSizePixel());

	if (! IsFloatingMode())
	{
		switch (GetAlignment())
		{
			case SFX_ALIGN_TOP:		aRect.Bottom()--;	break;
			case SFX_ALIGN_BOTTOM:	aRect.Top()++;		break;
			case SFX_ALIGN_LEFT:	aRect.Right()--;	break;
			case SFX_ALIGN_RIGHT:	aRect.Left()++;		break;
            default:
                break;
		}
	}

	DecorationView aView(this);
	aRect.Left() += 8; aRect.Top()	 += 8;
	aRect.Right()-= 8; aRect.Bottom()-= 8;
	aRect = aView.DrawFrame( aRect, FRAME_DRAW_DOUBLEIN );

	aEdit.SetPosSizePixel(aRect.TopLeft(), aRect.GetSize());
	SfxDockingWindow::Resize();
	Invalidate();
}


void SmCmdBoxWindow::Paint(const Rectangle& /*rRect*/)
{
	Rectangle aRect = Rectangle(Point(0, 0), GetOutputSizePixel());
	DecorationView aView(this);

	if (! IsFloatingMode())
	{
		Point aFrom, aTo;
		switch (GetAlignment())
		{
			case SFX_ALIGN_TOP:
				aFrom = aRect.BottomLeft(); aTo = aRect.BottomRight();
				aRect.Bottom()--;
				break;

			case SFX_ALIGN_BOTTOM:
				aFrom = aRect.TopLeft(); aTo = aRect.TopRight();
				aRect.Top()++;
				break;

			case SFX_ALIGN_LEFT:
				aFrom = aRect.TopRight(); aTo = aRect.BottomRight();
				aRect.Right()--;
				break;

			case SFX_ALIGN_RIGHT:
				aFrom = aRect.TopLeft(); aTo = aRect.BottomLeft();
				aRect.Left()++;
				break;

            default:
                break;
		}
		DrawLine( aFrom, aTo );
		aView.DrawFrame(aRect, FRAME_DRAW_OUT);
	}
	aRect.Left() += 8; aRect.Top()	 += 8;
	aRect.Right()-= 8; aRect.Bottom()-= 8;
	aRect = aView.DrawFrame( aRect, FRAME_DRAW_DOUBLEIN );
}


Size SmCmdBoxWindow::CalcDockingSize(SfxChildAlignment eAlign)
{
	switch (eAlign)
	{
		case SFX_ALIGN_LEFT:
		case SFX_ALIGN_RIGHT:
			return Size();
        default:
            break;
	}
	return SfxDockingWindow::CalcDockingSize(eAlign);
}


SfxChildAlignment SmCmdBoxWindow::CheckAlignment(SfxChildAlignment eActual,
											 SfxChildAlignment eWish)
{
	switch (eWish)
	{
		case SFX_ALIGN_TOP:
		case SFX_ALIGN_BOTTOM:
		case SFX_ALIGN_NOALIGNMENT:
			return eWish;
        default:
            break;
	}

	return eActual;
}


void SmCmdBoxWindow::StateChanged( StateChangedType nStateChange )
{
	if (STATE_CHANGE_INITSHOW == nStateChange)
    {
        Resize();   // #98848# avoid SmEditWindow not being painted correctly

        // set initial position of window in floating mode
        if (sal_True == IsFloatingMode())
            AdjustPosition();   //! don't change pos in docking-mode !

//        // make sure the formula can be edited right away
//        aEdit.GrabFocus();

        // grab focus as above does not work...
		// Thus we implement a timer based solution to get the initial
        // focus in the Edit window.
		aInitialFocusTimer.Start();
    }

    SfxDockingWindow::StateChanged( nStateChange );
}


IMPL_LINK( SmCmdBoxWindow, InitialFocusTimerHdl, Timer *, EMPTYARG /*pTimer*/ )
{
    // We want to have the focus in the edit window once Math has been opened
    // to allow for immediate typing.
    // Problem: There is no proper way to do this
    // Thus: this timer based soultion has been implemented (see GrabFocus below)
    //
    // Follow-up problem (#i114910): grabing the focus may bust the help system since 
    // it relies on getting the current frame which conflicts with grabbing the focus.
    // Thus aside from the 'GrabFocus' call everything else is to get the
    // help reliably working despite using 'GrabFocus'.

    try
    {
        uno::Reference< frame::XDesktop > xDesktop;
        uno::Reference< lang::XMultiServiceFactory > xSMGR( comphelper::getProcessServiceFactory() );
        if (xSMGR.is())
        {
            xDesktop = uno::Reference< frame::XDesktop >(
                xSMGR->createInstance( rtl::OUString::createFromAscii( "com.sun.star.frame.Desktop" )), uno::UNO_QUERY_THROW );
        }

        aEdit.GrabFocus();

        if (xDesktop.is())
        {
            bool bInPlace = GetView()->GetViewFrame()->GetFrame().IsInPlace();
            uno::Reference< frame::XFrame > xFrame( GetBindings().GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface());
            if ( bInPlace )
            {
                uno::Reference< container::XChild > xModel( GetView()->GetDoc()->GetModel(), uno::UNO_QUERY_THROW );
                uno::Reference< frame::XModel > xParent( xModel->getParent(), uno::UNO_QUERY_THROW );
                uno::Reference< frame::XController > xParentCtrler( xParent->getCurrentController() );
                uno::Reference< frame::XFramesSupplier > xParentFrame( xParentCtrler->getFrame(), uno::UNO_QUERY_THROW );
                xParentFrame->setActiveFrame( xFrame );
            }
            else
            {
                uno::Reference< frame::XFramesSupplier > xFramesSupplier( xDesktop, uno::UNO_QUERY );
                xFramesSupplier->setActiveFrame( xFrame );
            }
        }
    }
    catch (uno::Exception &)
    {
        DBG_ASSERT( 0, "failed to properly set initial focus to edit window" );
    }
    return 0;
}


void SmCmdBoxWindow::AdjustPosition()
{
	Point aPt;
	const Rectangle aRect( aPt, GetParent()->GetOutputSizePixel() );
	Point aTopLeft( Point( aRect.Left(),
						   aRect.Bottom() - GetSizePixel().Height() ) );
	Point aPos( GetParent()->OutputToScreenPixel( aTopLeft ) );
	if (aPos.X() < 0)
		aPos.X() = 0;
	if (aPos.Y() < 0)
		aPos.Y() = 0;
	SetPosPixel( aPos );
}


void SmCmdBoxWindow::ToggleFloatingMode()
{
	SfxDockingWindow::ToggleFloatingMode();

	if (GetFloatingWindow())
		GetFloatingWindow()->SetMinOutputSizePixel(Size (200, 50));
}


void SmCmdBoxWindow::GetFocus()
{
    if (!bExiting)
        aEdit.GrabFocus();
}

/**************************************************************************/


SFX_IMPL_DOCKINGWINDOW(SmCmdBoxWrapper, SID_CMDBOXWINDOW);

SmCmdBoxWrapper::SmCmdBoxWrapper(Window *pParentWindow, sal_uInt16 nId,
								 SfxBindings *pBindings,
								 SfxChildWinInfo *pInfo) :
	SfxChildWindow(pParentWindow, nId)
{
	pWindow = new SmCmdBoxWindow(pBindings, this, pParentWindow);

    // make window docked to the bottom initially (after first start)
    eChildAlignment = SFX_ALIGN_BOTTOM;
    ((SfxDockingWindow *)pWindow)->Initialize(pInfo);
}


#if OSL_DEBUG_LEVEL > 1
SmCmdBoxWrapper::~SmCmdBoxWrapper()
{
}
#endif


/**************************************************************************/

struct SmViewShell_Impl
{
    sfx2::DocumentInserter* pDocInserter;
    SfxRequest*             pRequest;

    SmViewShell_Impl() :
          pDocInserter( NULL )
        , pRequest( NULL )
    {}

    ~SmViewShell_Impl()
    {
        delete pDocInserter;
        delete pRequest;
    }
};

TYPEINIT1( SmViewShell, SfxViewShell );

SFX_IMPL_INTERFACE(SmViewShell, SfxViewShell, SmResId(0))
{
	SFX_OBJECTBAR_REGISTRATION( SFX_OBJECTBAR_TOOLS | SFX_VISIBILITY_STANDARD |
								SFX_VISIBILITY_FULLSCREEN | SFX_VISIBILITY_SERVER,
								SmResId(RID_MATH_TOOLBOX ));

	SFX_CHILDWINDOW_REGISTRATION(SID_TASKPANE);
	SFX_CHILDWINDOW_REGISTRATION(SmToolBoxWrapper::GetChildWindowId());
	SFX_CHILDWINDOW_REGISTRATION(SmCmdBoxWrapper::GetChildWindowId());
}


SFX_IMPL_NAMED_VIEWFACTORY(SmViewShell, "Default")
{
	SFX_VIEW_REGISTRATION(SmDocShell);
}


Size SmViewShell::GetOptimalSizePixel() const
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::GetOptimalSizePixel" );

	return aGraphic.LogicToPixel( ((SmViewShell*)this)->GetDoc()->GetSize() );
}


void SmViewShell::AdjustPosSizePixel(const Point &rPos, const Size &rSize)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::AdjustPosSizePixel" );

	aGraphic.SetPosSizePixel(rPos, rSize);
}


void SmViewShell::InnerResizePixel(const Point &rOfs, const Size &rSize)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::InnerResizePixel" );

    Size aObjSize = GetObjectShell()->GetVisArea().GetSize();
    if ( aObjSize.Width() > 0 && aObjSize.Height() > 0 )
    {
        Size aProvidedSize = GetWindow()->PixelToLogic( rSize, MAP_100TH_MM );
        SfxViewShell::SetZoomFactor( Fraction( aProvidedSize.Width(), aObjSize.Width() ),
                        Fraction( aProvidedSize.Height(), aObjSize.Height() ) );
    }

    SetBorderPixel( SvBorder() );
    GetGraphicWindow().SetPosSizePixel(rOfs, rSize);
	GetGraphicWindow().SetTotalSize();
}


void SmViewShell::OuterResizePixel(const Point &rOfs, const Size &rSize)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::OuterResizePixel" );

    SmGraphicWindow &rWin = GetGraphicWindow();
    rWin.SetPosSizePixel(rOfs, rSize);
    if (GetDoc()->IsPreview())
        rWin.ZoomToFitInWindow();
    rWin.Update();
}


void SmViewShell::QueryObjAreaPixel( Rectangle& rRect ) const
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::QueryObjAreaPixel" );

	rRect.SetSize( GetGraphicWindow().GetSizePixel() );
}


void SmViewShell::SetZoomFactor( const Fraction &rX, const Fraction &rY )
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::SetZoomFactor" );

	const Fraction &rFrac = rX < rY ? rX : rY;
	GetGraphicWindow().SetZoom( (sal_uInt16) long(rFrac * Fraction( 100, 1 )) );

	//Um Rundungsfehler zu minimieren lassen wir von der Basisklasse ggf.
	//auch die krummen Werte einstellen
	SfxViewShell::SetZoomFactor( rX, rY );
}


Size SmViewShell::GetTextLineSize(OutputDevice& rDevice, const String& rLine)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::GetTextLineSize" );

	String aText;
	Size   aSize(rDevice.GetTextWidth(rLine), rDevice.GetTextHeight());
	sal_uInt16 nTabs = rLine.GetTokenCount('\t');

	if (nTabs > 0)
	{
		long TabPos = rDevice.GetTextWidth('n') * 8;

		aSize.Width() = 0;

		for (sal_uInt16 i = 0; i < nTabs; i++)
		{
			if (i > 0)
				aSize.Width() = ((aSize.Width() / TabPos) + 1) * TabPos;

			aText = rLine.GetToken(i, '\t');
			aText.EraseLeadingChars('\t');
			aText.EraseTrailingChars('\t');
			aSize.Width() += rDevice.GetTextWidth(aText);
		}
	}

	return aSize;
}


Size SmViewShell::GetTextSize(OutputDevice& rDevice, const String& rText, long MaxWidth)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::GetTextSize" );

	Size	aSize;
	String	aLine;
	Size	TextSize;
	String	aText;
	sal_uInt16	nLines = rText.GetTokenCount('\n');

	for (sal_uInt16 i = 0; i < nLines; i++)
	{
		aLine = rText.GetToken(i, '\n');
		aLine.EraseAllChars('\r');
		aLine.EraseLeadingChars('\n');
		aLine.EraseTrailingChars('\n');

		aSize = GetTextLineSize(rDevice, aLine);

		if (aSize.Width() > MaxWidth)
		{
			do
			{
				xub_StrLen m	= aLine.Len();
				xub_StrLen nLen = m;

				for (xub_StrLen n = 0; n < nLen; n++)
				{
					sal_Unicode cLineChar = aLine.GetChar(n);
					if ((cLineChar == ' ') || (cLineChar == '\t'))
					{
						aText = aLine.Copy(0, n);
						if (GetTextLineSize(rDevice, aText).Width() < MaxWidth)
							m = n;
						else
							break;
					}
				}

				aText = aLine.Copy(0, m);
				aLine.Erase(0, m);
				aSize = GetTextLineSize(rDevice, aText);
				TextSize.Height() += aSize.Height();
				TextSize.Width() = Max(TextSize.Width(), Min(aSize.Width(), MaxWidth));

				aLine.EraseLeadingChars(' ');
				aLine.EraseLeadingChars('\t');
				aLine.EraseLeadingChars(' ');
			}
			while (aLine.Len() > 0);
		}
		else
		{
			TextSize.Height() += aSize.Height();
			TextSize.Width() = Max(TextSize.Width(), aSize.Width());
		}
	}

	return TextSize;
}


void SmViewShell::DrawTextLine(OutputDevice& rDevice, const Point& rPosition, const String& rLine)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::DrawTextLine" );

	String	aText;
	Point	aPoint (rPosition);
	sal_uInt16	nTabs = rLine.GetTokenCount('\t');

	if (nTabs > 0)
	{
		long TabPos = rDevice.GetTextWidth('n') * 8;

		for (sal_uInt16 i = 0; i < nTabs; i++)
		{
			if (i > 0)
				aPoint.X() = ((aPoint.X() / TabPos) + 1) * TabPos;

			aText = rLine.GetToken(i, '\t');
			aText.EraseLeadingChars('\t');
			aText.EraseTrailingChars('\t');
			rDevice.DrawText(aPoint, aText);
			aPoint.X() += rDevice.GetTextWidth(aText);
		}
	}
	else
		rDevice.DrawText(aPoint, rLine);
}


void SmViewShell::DrawText(OutputDevice& rDevice, const Point& rPosition, const String& rText, sal_uInt16 MaxWidth)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::DrawText" );

	sal_uInt16	nLines = rText.GetTokenCount('\n');
	Point	aPoint (rPosition);
	Size	aSize;
	String	aLine;
	String	aText;

	for (sal_uInt16 i = 0; i < nLines; i++)
	{
		aLine = rText.GetToken(i, '\n');
		aLine.EraseAllChars('\r');
		aLine.EraseLeadingChars('\n');
		aLine.EraseTrailingChars('\n');
		aSize = GetTextLineSize(rDevice, aLine);
		if (aSize.Width() > MaxWidth)
		{
			do
			{
				xub_StrLen m	= aLine.Len();
				xub_StrLen nLen = m;

				for (xub_StrLen n = 0; n < nLen; n++)
				{
					sal_Unicode cLineChar = aLine.GetChar(n);
					if ((cLineChar == ' ') || (cLineChar == '\t'))
					{
						aText = aLine.Copy(0, n);
						if (GetTextLineSize(rDevice, aText).Width() < MaxWidth)
							m = n;
						else
							break;
					}
				}
				aText = aLine.Copy(0, m);
				aLine.Erase(0, m);

				DrawTextLine(rDevice, aPoint, aText);
				aPoint.Y() += aSize.Height();

				aLine.EraseLeadingChars(' ');
				aLine.EraseLeadingChars('\t');
				aLine.EraseLeadingChars(' ');
			}
			while (GetTextLineSize(rDevice, aLine).Width() > MaxWidth);

			// print the remaining text
			if (aLine.Len() > 0)
			{
				DrawTextLine(rDevice, aPoint, aLine);
				aPoint.Y() += aSize.Height();
			}
		}
		else
		{
			DrawTextLine(rDevice, aPoint, aLine);
			aPoint.Y() += aSize.Height();
		}
	}
}

void SmViewShell::Impl_Print(
        OutputDevice &rOutDev, 
        const SmPrintUIOptions &rPrintUIOptions,
        Rectangle aOutRect, Point aZeroPoint )
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::Impl_Print" );

    const bool bIsPrintTitle = rPrintUIOptions.getBoolValue( PRTUIOPT_TITLE_ROW, sal_True );
    const bool bIsPrintFrame = rPrintUIOptions.getBoolValue( PRTUIOPT_BORDER, sal_True );
    const bool bIsPrintFormulaText = rPrintUIOptions.getBoolValue( PRTUIOPT_FORMULA_TEXT, sal_True );
    SmPrintSize ePrintSize( static_cast< SmPrintSize >( rPrintUIOptions.getIntValue( PRTUIOPT_PRINT_FORMAT, PRINT_SIZE_NORMAL ) ));
    const sal_uInt16 nZoomFactor = static_cast< sal_uInt16 >(rPrintUIOptions.getIntValue( PRTUIOPT_PRINT_SCALE, 100 ));
// IsIgnoreSpacesRight is a parser option! Thus it does not get evaluated here anymore (too late).
//    const bool bNoRightSpaces = rPrintUIOptions.getBoolValue( PRTUIOPT_NO_RIGHT_SPACE, sal_True );

    rOutDev.Push();
    rOutDev.SetLineColor( Color(COL_BLACK) );

	// output text on top
    if (bIsPrintTitle)
	{
		Size aSize600 (0, 600);
		Size aSize650 (0, 650);
		Font aFont(FAMILY_DONTKNOW, aSize600);

		aFont.SetAlign(ALIGN_TOP);
		aFont.SetWeight(WEIGHT_BOLD);
		aFont.SetSize(aSize650);
        aFont.SetColor( Color(COL_BLACK) );
        rOutDev.SetFont(aFont);

        Size aTitleSize (GetTextSize(rOutDev, GetDoc()->GetTitle(), aOutRect.GetWidth() - 200));

		aFont.SetWeight(WEIGHT_NORMAL);
		aFont.SetSize(aSize600);
        rOutDev.SetFont(aFont);

        Size aDescSize (GetTextSize(rOutDev, GetDoc()->GetComment(), aOutRect.GetWidth() - 200));

        if (bIsPrintFrame)
            rOutDev.DrawRect(Rectangle(aOutRect.TopLeft(),
                               Size(aOutRect.GetWidth(), 100 + aTitleSize.Height() + 200 + aDescSize.Height() + 100)));
        aOutRect.Top() += 200;

		// output title
		aFont.SetWeight(WEIGHT_BOLD);
		aFont.SetSize(aSize650);
        rOutDev.SetFont(aFont);
        Point aPoint(aOutRect.Left() + (aOutRect.GetWidth() - aTitleSize.Width())  / 2,
                     aOutRect.Top());
        DrawText(rOutDev, aPoint, GetDoc()->GetTitle(),
                 sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200));
        aOutRect.Top() += aTitleSize.Height() + 200;

		// output description
		aFont.SetWeight(WEIGHT_NORMAL);
		aFont.SetSize(aSize600);
        rOutDev.SetFont(aFont);
        aPoint.X() = aOutRect.Left() + (aOutRect.GetWidth()  - aDescSize.Width())  / 2;
        aPoint.Y() = aOutRect.Top();
        DrawText(rOutDev, aPoint, GetDoc()->GetComment(),
                 sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200));
        aOutRect.Top() += aDescSize.Height() + 300;
	}

	// output text on bottom
    if (bIsPrintFormulaText)
	{
        Font aFont(FAMILY_DONTKNOW, Size(0, 600));
		aFont.SetAlign(ALIGN_TOP);
        aFont.SetColor( Color(COL_BLACK) );

		// get size
        rOutDev.SetFont(aFont);

        Size aSize (GetTextSize(rOutDev, GetDoc()->GetText(), aOutRect.GetWidth() - 200));

        aOutRect.Bottom() -= aSize.Height() + 600;

        if (bIsPrintFrame)
            rOutDev.DrawRect(Rectangle(aOutRect.BottomLeft(),
                               Size(aOutRect.GetWidth(), 200 + aSize.Height() + 200)));

        Point aPoint (aOutRect.Left() + (aOutRect.GetWidth()  - aSize.Width())  / 2,
                      aOutRect.Bottom() + 300);
        DrawText(rOutDev, aPoint, GetDoc()->GetText(),
                 sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200));
        aOutRect.Bottom() -= 200;
	}

    if (bIsPrintFrame)
        rOutDev.DrawRect(aOutRect);

    aOutRect.Top()    += 100;
    aOutRect.Left()   += 100;
    aOutRect.Bottom() -= 100;
    aOutRect.Right()  -= 100;

	Size aSize (GetDoc()->GetSize());

	MapMode    OutputMapMode;
    // PDF export should always use PRINT_SIZE_NORMAL ...
    if (!rPrintUIOptions.getBoolValue( "IsPrinter", sal_False ) )
        ePrintSize = PRINT_SIZE_NORMAL;
    switch (ePrintSize)
	{
		case PRINT_SIZE_NORMAL:
			OutputMapMode = MapMode(MAP_100TH_MM);
			break;

		case PRINT_SIZE_SCALED:
			if ((aSize.Width() > 0) && (aSize.Height() > 0))
			{
                Size     OutputSize (rOutDev.LogicToPixel(Size(aOutRect.GetWidth(),
                                                            aOutRect.GetHeight()), MapMode(MAP_100TH_MM)));
                Size     GraphicSize (rOutDev.LogicToPixel(aSize, MapMode(MAP_100TH_MM)));
				sal_uInt16	 nZ = (sal_uInt16) Min((long)Fraction(OutputSize.Width()  * 100L, GraphicSize.Width()),
											  (long)Fraction(OutputSize.Height() * 100L, GraphicSize.Height()));
				Fraction aFraction ((sal_uInt16) Max ((sal_uInt16) MINZOOM, Min((sal_uInt16) MAXZOOM, (sal_uInt16) (nZ - 10))), (sal_uInt16) 100);

                OutputMapMode = MapMode(MAP_100TH_MM, aZeroPoint, aFraction, aFraction);
			}
			else
				OutputMapMode = MapMode(MAP_100TH_MM);
			break;

		case PRINT_SIZE_ZOOMED:
		{
            Fraction aFraction( nZoomFactor, 100 );

            OutputMapMode = MapMode(MAP_100TH_MM, aZeroPoint, aFraction, aFraction);
			break;
		}
	}

    aSize = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aSize, OutputMapMode),
								   MapMode(MAP_100TH_MM));

    Point aPos (aOutRect.Left() + (aOutRect.GetWidth()  - aSize.Width())  / 2,
                aOutRect.Top()  + (aOutRect.GetHeight() - aSize.Height()) / 2);

    aPos     = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aPos, MapMode(MAP_100TH_MM)),
										  OutputMapMode);
    aOutRect   = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aOutRect, MapMode(MAP_100TH_MM)),
										  OutputMapMode);

    rOutDev.SetMapMode(OutputMapMode);
    rOutDev.SetClipRegion(Region(aOutRect));
    GetDoc()->Draw(rOutDev, aPos);
    rOutDev.SetClipRegion();

    rOutDev.Pop();
}

sal_uInt16 SmViewShell::Print(SfxProgress & /*rProgress*/, sal_Bool /*bIsAPI*/)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::Print" );
    DBG_ASSERT( 0, "SmViewShell::Print: no longer used with new UI print dialog. Should be removed!!" );
	return 0;
}


SfxPrinter* SmViewShell::GetPrinter(sal_Bool bCreate)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::GetPrinter" );

	SmDocShell *pDoc = GetDoc();
	if ( pDoc->HasPrinter() || bCreate )
		return pDoc->GetPrinter();
	return 0;
}


sal_uInt16 SmViewShell::SetPrinter(SfxPrinter *pNewPrinter, sal_uInt16 nDiffFlags, bool )
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::SetPrinter" );
    SfxPrinter *pOld = GetDoc()->GetPrinter();
    if ( pOld && pOld->IsPrinting() )
        return SFX_PRINTERROR_BUSY;

	if ((nDiffFlags & SFX_PRINTER_PRINTER) == SFX_PRINTER_PRINTER)
		GetDoc()->SetPrinter( pNewPrinter );

	if ((nDiffFlags & SFX_PRINTER_OPTIONS) == SFX_PRINTER_OPTIONS)
	{
        SmModule *pp = SM_MOD();
		pp->GetConfig()->ItemSetToConfig(pNewPrinter->GetOptions());
	}
	return 0;
}


SfxTabPage* SmViewShell::CreatePrintOptionsPage(Window *pParent,
												const SfxItemSet &rOptions)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::CreatePrintOptionsPage" );

	return SmPrintOptionsTabPage::Create(pParent, rOptions);
}


SmEditWindow *SmViewShell::GetEditWindow()
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::GetEditWindow" );

	SmCmdBoxWrapper *pWrapper = (SmCmdBoxWrapper *) GetViewFrame()->
			GetChildWindow( SmCmdBoxWrapper::GetChildWindowId() );

	if (pWrapper != NULL)
	{
		SmEditWindow *pEditWin	= pWrapper->GetEditWindow();
		DBG_ASSERT( pEditWin, "SmEditWindow missing" );
		return pEditWin;
	}

	return NULL;
}


void SmViewShell::SetStatusText(const String& Text)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::SetStatusText" );

	StatusText = Text;
	GetViewFrame()->GetBindings().Invalidate(SID_TEXTSTATUS);
}


void SmViewShell::ShowError( const SmErrorDesc *pErrorDesc )
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::ShowError" );

	DBG_ASSERT(GetDoc(), "Sm : Document missing");
	if (pErrorDesc || 0 != (pErrorDesc = GetDoc()->GetParser().GetError(0)) )
	{
		SetStatusText( pErrorDesc->Text );
		GetEditWindow()->MarkError( Point( pErrorDesc->pNode->GetColumn(),
										   pErrorDesc->pNode->GetRow()));
	}
}


void SmViewShell::NextError()
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::NextError" );

	DBG_ASSERT(GetDoc(), "Sm : Document missing");
	const SmErrorDesc   *pErrorDesc = GetDoc()->GetParser().NextError();

	if (pErrorDesc)
		ShowError( pErrorDesc );
}


void SmViewShell::PrevError()
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::PrevError" );

	DBG_ASSERT(GetDoc(), "Sm : Document missing");
	const SmErrorDesc   *pErrorDesc = GetDoc()->GetParser().PrevError();

	if (pErrorDesc)
		ShowError( pErrorDesc );
}


sal_Bool SmViewShell::Insert( SfxMedium& rMedium )
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::Insert" );

    SmDocShell *pDoc = GetDoc();
    String aText( pDoc->GetText() );
    String aTemp = aText;
    sal_Bool bRet = sal_False, bChkOldVersion = sal_True;

    uno::Reference < embed::XStorage > xStorage = rMedium.GetStorage();
    uno::Reference< container::XNameAccess > xNameAccess( xStorage, uno::UNO_QUERY );
    if ( xNameAccess.is() && xNameAccess->getElementNames().getLength() )
    {
        if ( xNameAccess->hasByName( C2S( "content.xml" ) ) || xNameAccess->hasByName( C2S( "Content.xml" ) ))
        {
            bChkOldVersion = sal_False;
            // is this a fabulous math package ?
            Reference<com::sun::star::frame::XModel> xModel(pDoc->GetModel());
            SmXMLImportWrapper aEquation(xModel);    //!! modifies the result of pDoc->GetText() !!
            bRet = 0 == aEquation.Import(rMedium);
        }
    }

    if( bRet )
    {
		aText = pDoc->GetText();
        SmEditWindow *pEditWin = GetEditWindow();
        if (pEditWin)
            pEditWin->InsertText( aText );
        else
        {
            DBG_ERROR( "EditWindow missing" );
            aTemp += aText;
            aText  = aTemp;
        }

        pDoc->Parse();
        pDoc->SetModified(sal_True);

        SfxBindings &rBnd = GetViewFrame()->GetBindings();
        rBnd.Invalidate(SID_GAPHIC_SM);
        rBnd.Invalidate(SID_TEXT);
    }
    return bRet;
}


sal_Bool SmViewShell::InsertFrom(SfxMedium &rMedium)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::InsertFrom" );

    sal_Bool        bSuccess = sal_False;
    SmDocShell *pDoc = GetDoc();
    SvStream   *pStream = rMedium.GetInStream();
    String      aText( pDoc->GetText() );
    String      aTemp = aText;

    if (pStream)
    {
        const String& rFltName = rMedium.GetFilter()->GetFilterName();
        if ( rFltName.EqualsAscii(MATHML_XML) )
        {
            Reference<com::sun::star::frame::XModel> xModel( pDoc->GetModel() );
            SmXMLImportWrapper aEquation(xModel);    //!! modifies the result of pDoc->GetText() !!
            bSuccess = 0 == aEquation.Import(rMedium);
        }
        else
        {
            //bSuccess = ImportSM20File( pStream );
        }
    }

    if( bSuccess )
    {
		aText = pDoc->GetText();
        SmEditWindow *pEditWin = GetEditWindow();
        if (pEditWin)
            pEditWin->InsertText( aText );
        else
        {
            DBG_ERROR( "EditWindow missing" );
            aTemp += aText;
            aText  = aTemp;
        }

        pDoc->Parse();
        pDoc->SetModified(sal_True);

        SfxBindings &rBnd = GetViewFrame()->GetBindings();
        rBnd.Invalidate(SID_GAPHIC_SM);
        rBnd.Invalidate(SID_TEXT);
    }

    return bSuccess;
}


void SmViewShell::Execute(SfxRequest& rReq)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::Execute" );

	SmEditWindow *pWin = GetEditWindow();

	switch (rReq.GetSlot())
	{
		case SID_FORMULACURSOR:
		{
            SmModule *pp = SM_MOD();

			const SfxItemSet  *pArgs = rReq.GetArgs();
			const SfxPoolItem *pItem;

			sal_Bool  bVal;
			if ( pArgs &&
				 SFX_ITEM_SET == pArgs->GetItemState( SID_FORMULACURSOR, sal_False, &pItem))
				bVal = ((SfxBoolItem *) pItem)->GetValue();
			else
				bVal = !pp->GetConfig()->IsShowFormulaCursor();

			pp->GetConfig()->SetShowFormulaCursor(bVal);
			GetGraphicWindow().ShowCursor(bVal);
			break;
		}
		case SID_DRAW:
			if (pWin)
			{
				GetDoc()->SetText( pWin->GetText() );
				SetStatusText(String());
				ShowError( 0 );
                GetDoc()->Repaint();
			}
			break;

		case SID_ADJUST:
        case SID_FITINWINDOW:
			aGraphic.ZoomToFitInWindow();
			break;

		case SID_VIEW050:
			aGraphic.SetZoom(50);
			break;

		case SID_VIEW100:
			aGraphic.SetZoom(100);
			break;

		case SID_VIEW200:
			aGraphic.SetZoom(200);
			break;

		case SID_ZOOMIN:
			aGraphic.SetZoom(aGraphic.GetZoom() + 25);
			break;

		case SID_ZOOMOUT:
			DBG_ASSERT(aGraphic.GetZoom() >= 25, "Sm: falsches sal_uInt16 Argument");
			aGraphic.SetZoom(aGraphic.GetZoom() - 25);
			break;

        case SID_COPYOBJECT:
        {
            //TODO/LATER: does not work because of UNO Tunneling - will be fixed later
            Reference< datatransfer::XTransferable > xTrans( GetDoc()->GetModel(), uno::UNO_QUERY );
            if( xTrans.is() )
            {
                Reference< lang::XUnoTunnel> xTnnl( xTrans, uno::UNO_QUERY);
                if( xTnnl.is() )
                {
                    TransferableHelper* pTrans = reinterpret_cast< TransferableHelper * >(
                            sal::static_int_cast< sal_uIntPtr >(
                            xTnnl->getSomething( TransferableHelper::getUnoTunnelId() )));
                    if( pTrans )
                        pTrans->CopyToClipboard( this ? GetEditWindow() : 0 );
                }
            }
        }
        break;

        case SID_PASTEOBJECT:
        {
            TransferableDataHelper aData( TransferableDataHelper::CreateFromSystemClipboard(this ? GetEditWindow(): 0) );
            uno::Reference < io::XInputStream > xStrm;
            SotFormatStringId nId;
            if( aData.GetTransferable().is() &&
                ( aData.HasFormat( nId = SOT_FORMATSTR_ID_EMBEDDED_OBJ ) ||
                  (aData.HasFormat( SOT_FORMATSTR_ID_OBJECTDESCRIPTOR ) &&
                   aData.HasFormat( nId = SOT_FORMATSTR_ID_EMBED_SOURCE ))) &&
                aData.GetInputStream( nId, xStrm ) && xStrm.is() )
            {
                try
                {
                    uno::Reference < embed::XStorage > xStorage =
                            ::comphelper::OStorageHelper::GetStorageFromInputStream( xStrm, ::comphelper::getProcessServiceFactory() );
                    uno::Reference < beans::XPropertySet > xProps( xStorage, uno::UNO_QUERY );
                    SfxMedium aMedium( xStorage, String() );
                    Insert( aMedium );
                    GetDoc()->UpdateText();
                }
                catch (uno::Exception &)
                {
                    DBG_ERROR( "SmViewShell::Execute (SID_PASTEOBJECT): failed to get storage from input stream" );
                }
            }
        }
        break;


		case SID_CUT:
			if (pWin)
				pWin->Cut();
			break;

		case SID_COPY:
			if (pWin)
			{
				if (pWin->IsAllSelected())
				{
                    GetViewFrame()->GetDispatcher()->Execute(
								SID_COPYOBJECT, SFX_CALLMODE_STANDARD,
								new SfxVoidItem(SID_COPYOBJECT), 0L);
				}
				else
					pWin->Copy();
			}
			break;

		case SID_PASTE:
			{
				sal_Bool bCallExec = 0 == pWin;
				if( !bCallExec )
				{
					TransferableDataHelper aDataHelper(
						TransferableDataHelper::CreateFromSystemClipboard(
													GetEditWindow()) );

					if( aDataHelper.GetTransferable().is() &&
						aDataHelper.HasFormat( FORMAT_STRING ))
						pWin->Paste();
					else
						bCallExec = sal_True;
				}
				if( bCallExec )
				{
                    GetViewFrame()->GetDispatcher()->Execute(
							SID_PASTEOBJECT, SFX_CALLMODE_STANDARD,
							new SfxVoidItem(SID_PASTEOBJECT), 0L);
				}
			}
			break;

		case SID_DELETE:
			if (pWin)
				pWin->Delete();
			break;

		case SID_SELECT:
			if (pWin)
				pWin->SelectAll();
			break;

		case SID_INSERTCOMMAND:
		{
			const SfxInt16Item& rItem =
				(const SfxInt16Item&)rReq.GetArgs()->Get(SID_INSERTCOMMAND);

			if (pWin)
				pWin->InsertCommand(rItem.GetValue());
			break;
		}

		case SID_INSERTTEXT:
		{
			const SfxStringItem& rItem =
				    (const SfxStringItem&)rReq.GetArgs()->Get(SID_INSERTTEXT);
			if (pWin)
				pWin->InsertText(rItem.GetValue());
			break;
		}

        case SID_IMPORT_FORMULA:
        {
            delete pImpl->pRequest;
            pImpl->pRequest = new SfxRequest( rReq );
            delete pImpl->pDocInserter;
            pImpl->pDocInserter =
                new ::sfx2::DocumentInserter( 0, GetDoc()->GetFactory().GetFactoryName(), 0 );
            pImpl->pDocInserter->StartExecuteModal( LINK( this, SmViewShell, DialogClosedHdl ) );
            break;
        }

        case SID_IMPORT_MATHML_CLIPBOARD:
        {
            TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard(GetEditWindow()) );
            uno::Reference < io::XInputStream > xStrm;
            SotFormatStringId nId = SOT_FORMAT_SYSTEM_START; //dummy initialize to avoid warning
            if  ( aDataHelper.GetTransferable().is() )
            {
                if ( aDataHelper.HasFormat( nId = SOT_FORMATSTR_ID_MATHML ) )
                {
                    if ( aDataHelper.GetInputStream( nId, xStrm ) && xStrm.is() )
                    {
                        SfxMedium* pClipboardMedium = new SfxMedium();
                        pClipboardMedium->GetItemSet(); //generate initial itemset, not sure if necessary
                        const SfxFilter* pMathFilter = SfxFilter::GetFilterByName( String::CreateFromAscii(MATHML_XML) );
                        pClipboardMedium->SetFilter(pMathFilter);
                        pClipboardMedium->setStreamToLoadFrom( xStrm, sal_True /*bIsReadOnly*/ );
                        InsertFrom(*pClipboardMedium);
                        GetDoc()->UpdateText();
                        delete pClipboardMedium;
                    }
                }
                else
                {
                    if ( aDataHelper.HasFormat( nId = FORMAT_STRING) )
                    {
                        // In case of FORMAT_STRING no stream exists, need to generate one
                        ::rtl::OUString aString;
                        if (aDataHelper.GetString( nId, aString))
                        {
                            SfxMedium* pClipboardMedium = new SfxMedium();
                            pClipboardMedium->GetItemSet(); //generates initial itemset, not sure if necessary
                            const SfxFilter* pMathFilter = SfxFilter::GetFilterByName( String::CreateFromAscii(MATHML_XML) );
                            pClipboardMedium->SetFilter(pMathFilter);

                            SvMemoryStream * pStrm;
                            // The text to be imported might asserts encoding like 'encoding="utf-8"' but FORMAT_STRING is UTF-16.
                            // Force encoding to UTF-16, if encoding exists.
                            bool bForceUTF16 = false;
                            sal_Int32 nPosL = aString.indexOf( OUString::createFromAscii("encoding=\""));
                            sal_Int32 nPosU = -1;
                            if ( nPosL >= 0 && nPosL +10 < aString.getLength() )
                            {
                                nPosL += 10;
                                nPosU = aString.indexOf( '"',nPosL);
                                if (nPosU > nPosL)
                                {
                                    bForceUTF16 = true;
                                }
                            }
                            if ( bForceUTF16 )
                            {
                                OUString aNewString = aString.replaceAt( nPosL,nPosU-nPosL,OUString::createFromAscii("UTF-16"));
                                pStrm = new SvMemoryStream( (void*)aNewString.getStr(), aNewString.getLength() * sizeof(sal_Unicode), STREAM_READ);
                            }
                            else
                            {
                                pStrm = new SvMemoryStream( (void*)aString.getStr(), aString.getLength() * sizeof(sal_Unicode), STREAM_READ);
                            }
                            com::sun::star::uno::Reference<com::sun::star::io::XInputStream> xStrm( new ::utl::OInputStreamWrapper( *pStrm ) );
                            pClipboardMedium->setStreamToLoadFrom( xStrm, sal_True /*bIsReadOnly*/ );
                            InsertFrom(*pClipboardMedium);
                            GetDoc()->UpdateText();
                            delete pClipboardMedium;
                            delete pStrm;
                        }
                    }
                }
            }
            break;
        }

        case SID_NEXTERR:
			NextError();
			if (pWin)
				pWin->GrabFocus();
			break;

		case SID_PREVERR:
			PrevError();
			if (pWin)
				pWin->GrabFocus();
			break;

		case SID_NEXTMARK:
			if (pWin)
			{
				pWin->SelNextMark();
				pWin->GrabFocus();
			}
			break;

		case SID_PREVMARK:
			if (pWin)
			{
				pWin->SelPrevMark();
				pWin->GrabFocus();
			}
			break;

		case SID_TEXTSTATUS:
		{
			if (rReq.GetArgs() != NULL)
			{
				const SfxStringItem& rItem =
					(const SfxStringItem&)rReq.GetArgs()->Get(SID_TEXTSTATUS);

				SetStatusText(rItem.GetValue());
			}

			break;
		}

		case SID_GETEDITTEXT:
			if (pWin)
				if (pWin->GetText ().Len ()) GetDoc()->SetText( pWin->GetText() );
			break;

		case SID_ATTR_ZOOM:
		{
            if ( !GetViewFrame()->GetFrame().IsInPlace() )
			{
				//CHINA001 SvxZoomDialog *pDlg = 0;
				AbstractSvxZoomDialog *pDlg = 0;
				const SfxItemSet *pSet = rReq.GetArgs();
				if ( !pSet )
				{
					SfxItemSet aSet( GetDoc()->GetPool(), SID_ATTR_ZOOM, SID_ATTR_ZOOM);
					aSet.Put( SvxZoomItem( SVX_ZOOM_PERCENT, aGraphic.GetZoom()));
					//CHINA001 pDlg = new SvxZoomDialog( &GetViewFrame()->GetWindow(), aSet);
					SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
					if(pFact)
					{
						pDlg = pFact->CreateSvxZoomDialog(&GetViewFrame()->GetWindow(), aSet);
						DBG_ASSERT(pDlg, "Dialogdiet fail!");//CHINA001
					}
					pDlg->SetLimits( MINZOOM, MAXZOOM );
					if( pDlg->Execute() != RET_CANCEL )
						pSet = pDlg->GetOutputItemSet();
				}
				if ( pSet )
				{
					const SvxZoomItem &rZoom = (const SvxZoomItem &)pSet->Get(SID_ATTR_ZOOM);
					switch( rZoom.GetType() )
					{
						case SVX_ZOOM_PERCENT:
                            aGraphic.SetZoom((sal_uInt16)rZoom.GetValue ());
							break;

						case SVX_ZOOM_OPTIMAL:
							aGraphic.ZoomToFitInWindow();
							break;

						case SVX_ZOOM_PAGEWIDTH:
						case SVX_ZOOM_WHOLEPAGE:
						{
							const MapMode aMap( MAP_100TH_MM );
							SfxPrinter *pPrinter = GetPrinter( sal_True );
							Point aPoint;
							Rectangle  OutputRect(aPoint, pPrinter->GetOutputSize());
							Size	   OutputSize(pPrinter->LogicToPixel(Size(OutputRect.GetWidth(),
																			  OutputRect.GetHeight()), aMap));
							Size	   GraphicSize(pPrinter->LogicToPixel(GetDoc()->GetSize(), aMap));
							sal_uInt16	   nZ = (sal_uInt16) Min((long)Fraction(OutputSize.Width()	* 100L, GraphicSize.Width()),
														 (long)Fraction(OutputSize.Height() * 100L, GraphicSize.Height()));
							aGraphic.SetZoom (nZ);
							break;
						}
                        default:
                            break;
					}
				}
				delete pDlg;
			}
		}
		break;

        case SID_TOOLBOX:
        {
            GetViewFrame()->ToggleChildWindow( SmToolBoxWrapper::GetChildWindowId() );
        }
        break;

        case SID_SYMBOLS_CATALOGUE:
        {

            // get device used to retrieve the FontList
            SmDocShell *pDoc = GetDoc();
            OutputDevice *pDev = pDoc->GetPrinter();
            if (!pDev || pDev->GetDevFontCount() == 0)
                pDev = &SM_MOD()->GetDefaultVirtualDev();
            DBG_ASSERT (pDev, "device for font list missing" );

            SmModule *pp = SM_MOD();
            SmSymbolDialog( NULL, pDev, pp->GetSymbolManager(), *this ).Execute();
        }
        break;
	}
	rReq.Done();
}


void SmViewShell::GetState(SfxItemSet &rSet)
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::GetState" );

	SfxWhichIter aIter(rSet);

    SmEditWindow *pEditWin = GetEditWindow();
	for (sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich())
	{
		switch (nWh)
		{
		case SID_CUT:
		case SID_COPY:
		case SID_DELETE:
            if (! pEditWin || ! pEditWin->IsSelected())
				rSet.DisableItem(nWh);
			break;

		case SID_PASTE:
            if( !xClipEvtLstnr.is()  &&  pEditWin)
			{
				TransferableDataHelper aDataHelper(
						TransferableDataHelper::CreateFromSystemClipboard(
                                                        pEditWin) );

				bPasteState = aDataHelper.GetTransferable().is() &&
				 ( aDataHelper.HasFormat( FORMAT_STRING ) ||
				   aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBEDDED_OBJ ) ||
				   (aDataHelper.HasFormat( SOT_FORMATSTR_ID_OBJECTDESCRIPTOR )
				 	 && aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE )));
			}
			if( !bPasteState )
				rSet.DisableItem( nWh );
			break;

		case SID_ATTR_ZOOM:
			rSet.Put(SvxZoomItem( SVX_ZOOM_PERCENT, aGraphic.GetZoom()));
			/* no break here */
		case SID_VIEW050:
		case SID_VIEW100:
		case SID_VIEW200:
		case SID_ADJUST:
		case SID_ZOOMIN:
		case SID_ZOOMOUT:
		case SID_FITINWINDOW:
            if ( GetViewFrame()->GetFrame().IsInPlace() )
				rSet.DisableItem( nWh );
			break;

		case SID_NEXTERR:
		case SID_PREVERR:
		case SID_NEXTMARK:
		case SID_PREVMARK:
		case SID_DRAW:
		case SID_SELECT:
            if (! pEditWin || pEditWin->IsEmpty())
				rSet.DisableItem(nWh);
			break;

		case SID_TEXTSTATUS:
			{
				rSet.Put(SfxStringItem(nWh, StatusText));
			}
			break;

		case SID_FORMULACURSOR:
			{
                SmModule *pp = SM_MOD();
				rSet.Put(SfxBoolItem(nWh, pp->GetConfig()->IsShowFormulaCursor()));
			}
			break;

        case SID_TOOLBOX:
            {
                sal_Bool bState = sal_False;
                SfxChildWindow *pChildWnd = GetViewFrame()->
                        GetChildWindow( SmToolBoxWrapper::GetChildWindowId() );
                if (pChildWnd  &&  pChildWnd->GetWindow()->IsVisible())
                    bState = sal_True;
                rSet.Put(SfxBoolItem(SID_TOOLBOX, bState));
            }
            break;

        }
	}
}


SmViewShell::SmViewShell(SfxViewFrame *pFrame_, SfxViewShell *):
    SfxViewShell(pFrame_, SFX_VIEW_HAS_PRINTOPTIONS | SFX_VIEW_CAN_PRINT),
	aGraphic(this),
    aGraphicController(aGraphic, SID_GAPHIC_SM, pFrame_->GetBindings()),
    pImpl( new SmViewShell_Impl )
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::SmViewShell" );

//    pViewFrame = &pFrame_->GetWindow();

	SetStatusText(String());
	SetWindow(&aGraphic);
	SfxShell::SetName(C2S("SmView"));
	SfxShell::SetUndoManager( &GetDoc()->GetEditEngine().GetUndoManager() );
	SetHelpId( HID_SMA_VIEWSHELL_DOCUMENT );
}


SmViewShell::~SmViewShell()
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::~SmViewShell" );

    //!! this view shell is not active anymore !!
    // Thus 'SmGetActiveView' will give a 0 pointer.
    // Thus we need to supply this view as argument
    SmEditWindow *pEditWin = GetEditWindow();
    if (pEditWin)
        pEditWin->DeleteEditView( *this );
    delete pImpl;
}

void SmViewShell::Deactivate( sal_Bool bIsMDIActivate )
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::Deactivate" );

	SmEditWindow *pEdit = GetEditWindow();
	if ( pEdit )
		pEdit->Flush();

	SfxViewShell::Deactivate( bIsMDIActivate );
}


void SmViewShell::Activate( sal_Bool bIsMDIActivate )
{
    RTL_LOGFILE_CONTEXT( aLog, "starmath: SmViewShell::Activate" );

	SfxViewShell::Activate( bIsMDIActivate );

	SmEditWindow *pEdit = GetEditWindow();
	if ( pEdit )
	{
        //! Since there is no way to be informed if a "drag and drop"
        //! event has taken place, we call SetText here in order to
        //! syncronize the GraphicWindow display with the text in the
        //! EditEngine.
        SmDocShell *pDoc = GetDoc();
        pDoc->SetText( pDoc->GetEditEngine().GetText( LINEEND_LF ) );

		if ( bIsMDIActivate )
			pEdit->GrabFocus();
	}
}

//------------------------------------------------------------------

IMPL_LINK( SmViewShell, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg )
{
    DBG_ASSERT( _pFileDlg, "SmViewShell::DialogClosedHdl(): no file dialog" );
    DBG_ASSERT( pImpl->pDocInserter, "ScDocShell::DialogClosedHdl(): no document inserter" );

    if ( ERRCODE_NONE == _pFileDlg->GetError() )
    {
        //sal_uInt16 nSlot = pImpl->pRequest->GetSlot();
        SfxMedium* pMedium = pImpl->pDocInserter->CreateMedium();

        if ( pMedium != NULL )
        {
            if ( pMedium->IsStorage() )
                Insert( *pMedium );
            else
                InsertFrom( *pMedium );
            delete pMedium;

            SmDocShell* pDoc = GetDoc();
            pDoc->UpdateText();
            pDoc->ArrangeFormula();
            pDoc->Repaint();
            // adjust window, repaint, increment ModifyCount,...
            GetViewFrame()->GetBindings().Invalidate(SID_GAPHIC_SM);
        }
    }

    pImpl->pRequest->SetReturnValue( SfxBoolItem( pImpl->pRequest->GetSlot(), sal_True ) );
    pImpl->pRequest->Done();
    return 0;
}

void SmViewShell::Notify( SfxBroadcaster& , const SfxHint& rHint )
{
	if ( rHint.IsA(TYPE(SfxSimpleHint)) )
    {
        switch( ( (SfxSimpleHint&) rHint ).GetId() )
        {
            case SFX_HINT_MODECHANGED:
            case SFX_HINT_DOCCHANGED:
				GetViewFrame()->GetBindings().InvalidateAll(sal_False);
				break;
			default:
				break;
		}
	}
}

