/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

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



// INCLUDE ---------------------------------------------------------------

#include "scitems.hxx"
#include <editeng/eeitem.hxx>


#include <svtools/colorcfg.hxx>
#include <editeng/colritem.hxx>
#include <editeng/editview.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/scripttypeitem.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/printer.hxx>

#include <svx/svdview.hxx>
#include "tabvwsh.hxx"

#include "gridwin.hxx"
#include "viewdata.hxx"
#include "output.hxx"
#include "document.hxx"
#include "attrib.hxx"
#include "patattr.hxx"			// InvertSimple
#include "dbcolect.hxx"
#include "docoptio.hxx"
#include "notemark.hxx"
#include "dbfunc.hxx"			// oder GetPageBreakData an die ViewData
#include "scmod.hxx"
#include "inputhdl.hxx"
#include "rfindlst.hxx"
#include "hiranges.hxx"
#include "pagedata.hxx"
#include "docpool.hxx"
#include "globstr.hrc"
#include "docsh.hxx"			// oder GetSfxInPlaceObject
#include "cbutton.hxx"
#include "invmerge.hxx"
#include "editutil.hxx"
#include "inputopt.hxx"
#include "fillinfo.hxx"
#include "dpcontrol.hxx"
#include "queryparam.hxx"
#include "sc.hrc"
#include <vcl/virdev.hxx>

// #i74769#
#include <svx/sdrpaintwindow.hxx>

//#include "tabvwsh.hxx"			//! Test !!!!

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

void lcl_LimitRect( Rectangle& rRect, const Rectangle& rVisible )
{
	if ( rRect.Top()    < rVisible.Top()-1 )    rRect.Top()    = rVisible.Top()-1;
//	if ( rRect.Left()   < rVisible.Left()-1 )   rRect.Left()   = rVisible.Left()-1;
	if ( rRect.Bottom() > rVisible.Bottom()+1 ) rRect.Bottom() = rVisible.Bottom()+1;
//	if ( rRect.Right()  > rVisible.Right()+1 )  rRect.Right()  = rVisible.Right()+1;

	// #51122# auch wenn das inner-Rectangle nicht sichtbar ist, muss evtl.
	// die Titelzeile gezeichnet werden, darum kein Rueckgabewert mehr.
	// Wenn's weit daneben liegt, wird lcl_DrawOneFrame erst gar nicht gerufen.
}

void lcl_DrawOneFrame( OutputDevice* pDev, const Rectangle& rInnerPixel,
						const String& rTitle, const Color& rColor, sal_Bool bTextBelow,
						double nPPTX, double nPPTY, const Fraction& rZoomY,
						ScDocument* pDoc, ScViewData* pButtonViewData, sal_Bool bLayoutRTL )
{
	//	pButtonViewData wird nur benutzt, um die Button-Groesse zu setzen,
	//	darf ansonsten NULL sein!

	Rectangle aInner = rInnerPixel;
	if ( bLayoutRTL )
	{
		aInner.Left() = rInnerPixel.Right();
		aInner.Right() = rInnerPixel.Left();
	}

	Rectangle aVisible( Point(0,0), pDev->GetOutputSizePixel() );
	lcl_LimitRect( aInner, aVisible );

	Rectangle aOuter = aInner;
	long nHor = (long) ( SC_SCENARIO_HSPACE * nPPTX );
	long nVer = (long) ( SC_SCENARIO_VSPACE * nPPTY );
	aOuter.Left()	-= nHor;
	aOuter.Right()	+= nHor;
	aOuter.Top()	-= nVer;
	aOuter.Bottom()	+= nVer;

	//	use ScPatternAttr::GetFont only for font size
	Font aAttrFont;
	((const ScPatternAttr&)pDoc->GetPool()->GetDefaultItem(ATTR_PATTERN)).
									GetFont(aAttrFont,SC_AUTOCOL_BLACK,pDev,&rZoomY);

	//	everything else from application font
	Font aAppFont = pDev->GetSettings().GetStyleSettings().GetAppFont();
	aAppFont.SetSize( aAttrFont.GetSize() );

	aAppFont.SetAlign( ALIGN_TOP );
	pDev->SetFont( aAppFont );

	Size aTextSize( pDev->GetTextWidth( rTitle ), pDev->GetTextHeight() );

	if ( bTextBelow )
		aOuter.Bottom() += aTextSize.Height();
	else
		aOuter.Top()    -= aTextSize.Height();

	pDev->SetLineColor();
	pDev->SetFillColor( rColor );
	//	links, oben, rechts, unten
	pDev->DrawRect( Rectangle( aOuter.Left(),  aOuter.Top(),    aInner.Left(),  aOuter.Bottom() ) );
	pDev->DrawRect( Rectangle( aOuter.Left(),  aOuter.Top(),    aOuter.Right(), aInner.Top()    ) );
	pDev->DrawRect( Rectangle( aInner.Right(), aOuter.Top(),    aOuter.Right(), aOuter.Bottom() ) );
	pDev->DrawRect( Rectangle( aOuter.Left(),  aInner.Bottom(), aOuter.Right(), aOuter.Bottom() ) );

	long nButtonY = bTextBelow ? aInner.Bottom() : aOuter.Top();

	ScDDComboBoxButton aComboButton((Window*)pDev);
	aComboButton.SetOptSizePixel();
	long nBWidth  = ( aComboButton.GetSizePixel().Width() * rZoomY.GetNumerator() )
						/ rZoomY.GetDenominator();
	long nBHeight = nVer + aTextSize.Height() + 1;
	Size aButSize( nBWidth, nBHeight );
    long nButtonPos = bLayoutRTL ? aOuter.Left() : aOuter.Right()-nBWidth+1;
    aComboButton.Draw( Point(nButtonPos, nButtonY), aButSize, sal_False );
	if (pButtonViewData)
		pButtonViewData->SetScenButSize( aButSize );

	long nTextStart = bLayoutRTL ? aInner.Right() - aTextSize.Width() + 1 : aInner.Left();

	sal_Bool bWasClip = sal_False;
	Region aOldClip;
	sal_Bool bClip = ( aTextSize.Width() > aOuter.Right() - nBWidth - aInner.Left() );
	if ( bClip )
	{
		if (pDev->IsClipRegion())
		{
			bWasClip = sal_True;
			aOldClip = pDev->GetActiveClipRegion();
		}
		long nClipStartX = bLayoutRTL ? aOuter.Left() + nBWidth : aInner.Left();
		long nClipEndX = bLayoutRTL ? aInner.Right() : aOuter.Right() - nBWidth;
		pDev->SetClipRegion( Rectangle( nClipStartX, nButtonY + nVer/2,
								nClipEndX, nButtonY + nVer/2 + aTextSize.Height() ) );
	}

	pDev->DrawText( Point( nTextStart, nButtonY + nVer/2 ), rTitle );

	if ( bClip )
	{
		if ( bWasClip )
			pDev->SetClipRegion(aOldClip);
		else
			pDev->SetClipRegion();
	}

	pDev->SetFillColor();
	pDev->SetLineColor( COL_BLACK );
	pDev->DrawRect( aInner );
	pDev->DrawRect( aOuter );
}

void lcl_DrawScenarioFrames( OutputDevice* pDev, ScViewData* pViewData, ScSplitPos eWhich,
							SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2 )
{
	ScDocument* pDoc = pViewData->GetDocument();
	SCTAB nTab = pViewData->GetTabNo();
	SCTAB nTabCount = pDoc->GetTableCount();
	if ( nTab+1<nTabCount && pDoc->IsScenario(nTab+1) && !pDoc->IsScenario(nTab) )
	{
		if ( nX1 > 0 ) --nX1;
		if ( nY1>=2 ) nY1 -= 2;				// Hack: Titelzeile beruehrt zwei Zellen
		else if ( nY1 > 0 ) --nY1;
		if ( nX2 < MAXCOL ) ++nX2;
		if ( nY2 < MAXROW-1 ) nY2 += 2;		// Hack: Titelzeile beruehrt zwei Zellen
		else if ( nY2 < MAXROW ) ++nY2;
		ScRange aViewRange( nX1,nY1,nTab, nX2,nY2,nTab );

		//!	Ranges an der Table cachen!!!!

		ScMarkData aMarks;
		for (SCTAB i=nTab+1; i<nTabCount && pDoc->IsScenario(i); i++)
			pDoc->MarkScenario( i, nTab, aMarks, sal_False, SC_SCENARIO_SHOWFRAME );
		ScRangeListRef xRanges = new ScRangeList;
		aMarks.FillRangeListWithMarks( xRanges, sal_False );

		sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
		long nLayoutSign = bLayoutRTL ? -1 : 1;

		sal_uInt16 nRangeCount = (sal_uInt16)xRanges->Count();
		for (sal_uInt16 j=0; j<nRangeCount; j++)
		{
			ScRange aRange = *xRanges->GetObject(j);
			//	Szenario-Rahmen immer dann auf zusammengefasste Zellen erweitern, wenn
			//	dadurch keine neuen nicht-ueberdeckten Zellen mit umrandet werden
			pDoc->ExtendTotalMerge( aRange );

			//!	-> Repaint beim Zusammenfassen erweitern !!!

			if ( aRange.Intersects( aViewRange ) )			//! Platz fuer Text/Button?
			{
				Point aStartPos = pViewData->GetScrPos(
									aRange.aStart.Col(), aRange.aStart.Row(), eWhich, sal_True );
				Point aEndPos = pViewData->GetScrPos(
									aRange.aEnd.Col()+1, aRange.aEnd.Row()+1, eWhich, sal_True );
				//	on the grid:
				aStartPos.X() -= nLayoutSign;
				aStartPos.Y() -= 1;
				aEndPos.X() -= nLayoutSign;
				aEndPos.Y() -= 1;

				sal_Bool bTextBelow = ( aRange.aStart.Row() == 0 );

				String aCurrent;
				Color aColor( COL_LIGHTGRAY );
				for (SCTAB nAct=nTab+1; nAct<nTabCount && pDoc->IsScenario(nAct); nAct++)
					if ( pDoc->IsActiveScenario(nAct) && pDoc->HasScenarioRange(nAct,aRange) )
					{
						String aDummyComment;
						sal_uInt16 nDummyFlags;
						pDoc->GetName( nAct, aCurrent );
						pDoc->GetScenarioData( nAct, aDummyComment, aColor, nDummyFlags );
					}

				if (!aCurrent.Len())
					aCurrent = ScGlobal::GetRscString( STR_EMPTYDATA );

				//!	eigener Text "(keins)" statt "(leer)" ???

				lcl_DrawOneFrame( pDev, Rectangle( aStartPos, aEndPos ),
									aCurrent, aColor, bTextBelow,
									pViewData->GetPPTX(), pViewData->GetPPTY(), pViewData->GetZoomY(),
									pDoc, pViewData, bLayoutRTL );
			}
		}
	}
}

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

void lcl_DrawHighlight( ScOutputData& rOutputData, ScViewData* pViewData,
						ScHighlightRanges& rHighlightRanges )
{
	SCTAB nTab = pViewData->GetTabNo();
	sal_uLong nCount = rHighlightRanges.Count();
	for (sal_uLong i=0; i<nCount; i++)
	{
		ScHighlightEntry* pEntry = rHighlightRanges.GetObject( i );
		if (pEntry)
		{
			ScRange aRange = pEntry->aRef;
			if ( nTab >= aRange.aStart.Tab() && nTab <= aRange.aEnd.Tab() )
			{
				rOutputData.DrawRefMark(
									aRange.aStart.Col(), aRange.aStart.Row(),
									aRange.aEnd.Col(), aRange.aEnd.Row(),
									pEntry->aColor, sal_False );
			}
		}
	}
}

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

void ScGridWindow::DoInvertRect( const Rectangle& rPixel )
{
//	Invert( PixelToLogic(rPixel) );

	if ( rPixel == aInvertRect )
		aInvertRect = Rectangle();		// aufheben
	else
	{
		DBG_ASSERT( aInvertRect.IsEmpty(), "DoInvertRect nicht paarig" );

		aInvertRect = rPixel;			// neues Rechteck merken
	}

    UpdateHeaderOverlay();      // uses aInvertRect
}

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

void __EXPORT ScGridWindow::PrePaint()
{
	// forward PrePaint to DrawingLayer
	ScTabViewShell* pTabViewShell = pViewData->GetViewShell();

	if(pTabViewShell)
	{
		SdrView* pDrawView = pTabViewShell->GetSdrView();

		if(pDrawView)
		{
            pDrawView->PrePaint();
        }
    }
}

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

void __EXPORT ScGridWindow::Paint( const Rectangle& rRect )
{
    //TODO/LATER: how to get environment? Do we need that?!
    /*
	ScDocShell* pDocSh = pViewData->GetDocShell();
	SvInPlaceEnvironment* pEnv = pDocSh->GetIPEnv();
	if (pEnv && pEnv->GetRectsChangedLockCount())
	{
		Invalidate(rRect);
		return;
    }*/

	ScDocument* pDoc = pViewData->GetDocument();
	if ( pDoc->IsInInterpreter() )
	{
		//	via Reschedule, interpretierende Zellen nicht nochmal anstossen
		//	hier kein Invalidate, sonst kommt z.B. eine Error-Box nie an die Reihe
		//	(Bug 36381). Durch bNeedsRepaint wird spaeter alles nochmal gemalt.

		if ( bNeedsRepaint )
		{
			//!	Rechtecke zusammenfassen?
			aRepaintPixel = Rectangle();			// mehrfach -> alles painten
		}
		else
		{
			bNeedsRepaint = sal_True;
			aRepaintPixel = LogicToPixel(rRect);	// nur betroffenen Bereich
		}
		return;
	}

    // #i117893# If GetSizePixel needs to call the resize handler, the resulting nested Paint call
    // (possibly for a larger rectangle) has to be allowed. Call GetSizePixel before setting bIsInPaint.
    GetSizePixel();

	if (bIsInPaint)
		return;

	bIsInPaint = sal_True;

	Rectangle aPixRect = LogicToPixel( rRect );

	SCCOL nX1 = pViewData->GetPosX(eHWhich);
	SCROW nY1 = pViewData->GetPosY(eVWhich);

	SCTAB nTab = pViewData->GetTabNo();

	double nPPTX = pViewData->GetPPTX();
	double nPPTY = pViewData->GetPPTY();

	Rectangle aMirroredPixel = aPixRect;
	if ( pDoc->IsLayoutRTL( nTab ) )
	{
		//	mirror and swap
		long nWidth = GetSizePixel().Width();
		aMirroredPixel.Left()  = nWidth - 1 - aPixRect.Right();
		aMirroredPixel.Right() = nWidth - 1 - aPixRect.Left();
	}

	long nScrX = ScViewData::ToPixel( pDoc->GetColWidth( nX1, nTab ), nPPTX );
	while ( nScrX <= aMirroredPixel.Left() && nX1 < MAXCOL )
	{
		++nX1;
		nScrX += ScViewData::ToPixel( pDoc->GetColWidth( nX1, nTab ), nPPTX );
	}
	SCCOL nX2 = nX1;
	while ( nScrX <= aMirroredPixel.Right() && nX2 < MAXCOL )
	{
		++nX2;
		nScrX += ScViewData::ToPixel( pDoc->GetColWidth( nX2, nTab ), nPPTX );
	}

	long nScrY = 0;
    ScViewData::AddPixelsWhile( nScrY, aPixRect.Top(), nY1, MAXROW, nPPTY, pDoc, nTab);
	SCROW nY2 = nY1;
    if (nScrY <= aPixRect.Bottom() && nY2 < MAXROW)
    {
        ++nY2;
        ScViewData::AddPixelsWhile( nScrY, aPixRect.Bottom(), nY2, MAXROW, nPPTY, pDoc, nTab);
    }

	Draw( nX1,nY1,nX2,nY2, SC_UPDATE_MARKS );			// nicht weiterzeichnen

	bIsInPaint = sal_False;
}

//
// 	Draw  ----------------------------------------------------------------
//

void ScGridWindow::Draw( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, ScUpdateMode eMode )
{
	ScModule* pScMod = SC_MOD();
	sal_Bool bTextWysiwyg = pScMod->GetInputOptions().GetTextWysiwyg();
	sal_Bool bGridFirst = sal_True;		//! entscheiden!!!

	if (pViewData->IsMinimized())
		return;

	PutInOrder( nX1, nX2 );
	PutInOrder( nY1, nY2 );

	DBG_ASSERT( ValidCol(nX2) && ValidRow(nY2), "GridWin Draw Bereich zu gross" );

	SCCOL nPosX = pViewData->GetPosX( eHWhich );
	SCROW nPosY = pViewData->GetPosY( eVWhich );
	if (nX2 < nPosX || nY2 < nPosY)
		return;											// unsichtbar
	if (nX1 < nPosX) nX1 = nPosX;
	if (nY1 < nPosY) nY1 = nPosY;

	SCCOL nXRight = nPosX + pViewData->VisibleCellsX(eHWhich);
	if (nXRight > MAXCOL) nXRight = MAXCOL;
	SCROW nYBottom = nPosY + pViewData->VisibleCellsY(eVWhich);
	if (nYBottom > MAXROW) nYBottom = MAXROW;

    // Store the current visible range.
    maVisibleRange.mnCol1 = nPosX;
    maVisibleRange.mnCol2 = nXRight;
    maVisibleRange.mnRow1 = nPosY;
    maVisibleRange.mnRow2 = nYBottom;

	if (nX1 > nXRight || nY1 > nYBottom)
		return;											// unsichtbar
	if (nX2 > nXRight) nX2 = nXRight;
	if (nY2 > nYBottom) nY2 = nYBottom;

	if ( eMode != SC_UPDATE_MARKS )
		if (nX2 < nXRight)
			nX2 = nXRight;								// zum Weiterzeichnen

		//	ab hier kein return mehr

	++nPaintCount;					// merken, dass gemalt wird (wichtig beim Invertieren)

	ScDocShell* pDocSh = pViewData->GetDocShell();
	ScDocument* pDoc = pDocSh->GetDocument();
	SCTAB nTab = pViewData->GetTabNo();

	pDoc->ExtendHidden( nX1, nY1, nX2, nY2, nTab );

	Point aScrPos = pViewData->GetScrPos( nX1, nY1, eWhich );
	long nMirrorWidth = GetSizePixel().Width();
	sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
	long nLayoutSign = bLayoutRTL ? -1 : 1;
	if ( bLayoutRTL )
	{
		long nEndPixel = pViewData->GetScrPos( nX2+1, nPosY, eWhich ).X();
		nMirrorWidth = aScrPos.X() - nEndPixel;
		aScrPos.X() = nEndPixel + 1;
	}

	long nScrX = aScrPos.X();
	long nScrY = aScrPos.Y();

	SCCOL nCurX = pViewData->GetCurX();
	SCROW nCurY = pViewData->GetCurY();
	SCCOL nCurEndX = nCurX;
	SCROW nCurEndY = nCurY;
	pDoc->ExtendMerge( nCurX, nCurY, nCurEndX, nCurEndY, nTab );
	sal_Bool bCurVis = nCursorHideCount==0 &&
					( nCurEndX+1 >= nX1 && nCurX <= nX2+1 && nCurEndY+1 >= nY1 && nCurY <= nY2+1 );

	//	AutoFill-Anfasser
	if ( !bCurVis && nCursorHideCount==0 && bAutoMarkVisible && aAutoMarkPos.Tab() == nTab &&
			( aAutoMarkPos.Col() != nCurX || aAutoMarkPos.Row() != nCurY ) )
	{
		SCCOL nHdlX = aAutoMarkPos.Col();
		SCROW nHdlY = aAutoMarkPos.Row();
		pDoc->ExtendMerge( nHdlX, nHdlY, nHdlX, nHdlY, nTab );
		bCurVis = ( nHdlX+1 >= nX1 && nHdlX <= nX2 && nHdlY+1 >= nY1 && nHdlY <= nY2 );
		//	links und oben ist nicht betroffen

		//!	AutoFill-Anfasser alleine (ohne Cursor) zeichnen ???
	}

	double nPPTX = pViewData->GetPPTX();
	double nPPTY = pViewData->GetPPTY();

	const ScViewOptions& rOpts = pViewData->GetOptions();
	sal_Bool bFormulaMode = rOpts.GetOption( VOPT_FORMULAS );
	sal_Bool bMarkClipped = rOpts.GetOption( VOPT_CLIPMARKS );

		// Datenblock

    ScTableInfo aTabInfo;
    pDoc->FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab,
										nPPTX, nPPTY, sal_False, bFormulaMode,
										&pViewData->GetMarkData() );

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

	Fraction aZoomX = pViewData->GetZoomX();
	Fraction aZoomY = pViewData->GetZoomY();
    ScOutputData aOutputData( this, OUTTYPE_WINDOW, aTabInfo, pDoc, nTab,
								nScrX, nScrY, nX1, nY1, nX2, nY2, nPPTX, nPPTY,
								&aZoomX, &aZoomY );

	aOutputData.SetMirrorWidth( nMirrorWidth );			// needed for RTL

    std::auto_ptr< VirtualDevice > xFmtVirtDev;
    sal_Bool bLogicText = bTextWysiwyg;                     // call DrawStrings in logic MapMode?

	if ( bTextWysiwyg )
	{
		//	use printer for text formatting

		OutputDevice* pFmtDev = pDoc->GetPrinter();
		pFmtDev->SetMapMode( pViewData->GetLogicMode(eWhich) );
		aOutputData.SetFmtDevice( pFmtDev );
	}
    else if ( aZoomX != aZoomY && pViewData->IsOle() )
    {
        //  #i45033# For OLE inplace editing with different zoom factors,
        //  use a virtual device with 1/100th mm as text formatting reference

        xFmtVirtDev.reset( new VirtualDevice );
        xFmtVirtDev->SetMapMode( MAP_100TH_MM );
        aOutputData.SetFmtDevice( xFmtVirtDev.get() );

        bLogicText = sal_True;                      // use logic MapMode
    }

    const svtools::ColorConfig& rColorCfg = pScMod->GetColorConfig();
    Color aGridColor( rColorCfg.GetColorValue( svtools::CALCGRID, sal_False ).nColor );
	if ( aGridColor.GetColor() == COL_TRANSPARENT )
	{
		//	use view options' grid color only if color config has "automatic" color
		aGridColor = rOpts.GetGridColor();
	}

	aOutputData.SetSyntaxMode		( pViewData->IsSyntaxMode() );
	aOutputData.SetGridColor		( aGridColor );
	aOutputData.SetShowNullValues	( rOpts.GetOption( VOPT_NULLVALS ) );
	aOutputData.SetShowFormulas		( bFormulaMode );
    aOutputData.SetShowSpellErrors  ( pDoc->GetDocOptions().IsAutoSpell() );
	aOutputData.SetMarkClipped		( bMarkClipped );

	aOutputData.SetUseStyleColor( sal_True );		// always set in table view

	aOutputData.SetEditObject( GetEditObject() );
	aOutputData.SetViewShell( pViewData->GetViewShell() );

	sal_Bool bGrid = rOpts.GetOption( VOPT_GRID );
	sal_Bool bPage = rOpts.GetOption( VOPT_PAGEBREAKS );

	if ( eMode == SC_UPDATE_CHANGED )
	{
		aOutputData.FindChanged();
		aOutputData.SetSingleGrid(sal_True);
	}

	sal_Bool bPageMode = pViewData->IsPagebreakMode();
	if (bPageMode)										// nach FindChanged
	{
		// SetPagebreakMode initialisiert auch bPrinted Flags
		aOutputData.SetPagebreakMode( pViewData->GetView()->GetPageBreakData() );
	}

	EditView*	pEditView = NULL;
	sal_Bool		bEditMode = pViewData->HasEditView(eWhich);
	if ( bEditMode && pViewData->GetRefTabNo() == nTab )
	{
		SCCOL nEditCol;
		SCROW nEditRow;
		pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow );
		SCCOL nEditEndCol = pViewData->GetEditEndCol();
		SCROW nEditEndRow = pViewData->GetEditEndRow();

		if ( nEditEndCol >= nX1 && nEditCol <= nX2 && nEditEndRow >= nY1 && nEditRow <= nY2 )
			aOutputData.SetEditCell( nEditCol, nEditRow );
		else
			bEditMode = sal_False;

		//	nur Edit-Area zu zeichnen?
		//!	dann muss trotzdem noch der Rand / das Gitter gemalt werden!

//		if ( nEditCol <= nX1 && nEditEndCol >= nX2 && nEditRow <= nY1 && nEditEndRow >= nY2 )
//			bOnlyEdit = sal_True;
	}

	// define drawing layer map mode and paint rectangle
	const MapMode aDrawMode = GetDrawMapMode();
	Rectangle aDrawingRectLogic;

	{
		// get drawing pixel rect
		Rectangle aDrawingRectPixel(Point(nScrX, nScrY), Size(aOutputData.GetScrW(), aOutputData.GetScrH()));

		// correct for border (left/right)
		if(MAXCOL == nX2)
		{
			if(bLayoutRTL)
			{
				aDrawingRectPixel.Left() = 0L;
			}
			else
			{
				aDrawingRectPixel.Right() = GetOutputSizePixel().getWidth();
			}
		}

		// correct for border (bottom)
		if(MAXROW == nY2)
		{
			aDrawingRectPixel.Bottom() = GetOutputSizePixel().getHeight();
		}

		// get logic positions
		aDrawingRectLogic = PixelToLogic(aDrawingRectPixel, aDrawMode);
	}

// not necessary with overlay
//	if (bCurVis)
//		HideCursor();

    OutputDevice* pContentDev = this;       // device for document content, used by overlay manager
	SdrPaintWindow* pTargetPaintWindow = 0;	// #i74769# work with SdrPaintWindow directly

	{
		// init redraw
		ScTabViewShell* pTabViewShell = pViewData->GetViewShell();

		if(pTabViewShell)
		{
			MapMode aCurrentMapMode(pContentDev->GetMapMode());
			pContentDev->SetMapMode(aDrawMode);
			SdrView* pDrawView = pTabViewShell->GetSdrView();

			if(pDrawView)
			{
				// #i74769# Use new BeginDrawLayers() interface
				Region aDrawingRegion(aDrawingRectLogic);
				pTargetPaintWindow = pDrawView->BeginDrawLayers(this, aDrawingRegion);
				OSL_ENSURE(pTargetPaintWindow, "BeginDrawLayers: Got no SdrPaintWindow (!)");

				// #i74769# get target device from SdrPaintWindow, this may be the prerender
				// device now, too.
				pContentDev = &(pTargetPaintWindow->GetTargetOutputDevice());
                aOutputData.SetContentDevice( pContentDev );
			}

			pContentDev->SetMapMode(aCurrentMapMode);
		}
	}

	//	Rand (Wiese) (Pixel)
	if ( nX2==MAXCOL || nY2==MAXROW )
	{
		// save MapMode and set to pixel
		MapMode aCurrentMapMode(pContentDev->GetMapMode());
		pContentDev->SetMapMode(MAP_PIXEL);

		Rectangle aPixRect = Rectangle( Point(), GetOutputSizePixel() );
        pContentDev->SetFillColor( rColorCfg.GetColorValue(svtools::APPBACKGROUND).nColor );
		pContentDev->SetLineColor();
		if ( nX2==MAXCOL )
		{
			Rectangle aDrawRect( aPixRect );
			if ( bLayoutRTL )
				aDrawRect.Right() = nScrX - 1;
			else
				aDrawRect.Left() = nScrX + aOutputData.GetScrW();
			if (aDrawRect.Right() >= aDrawRect.Left())
				pContentDev->DrawRect( aDrawRect );
		}
		if ( nY2==MAXROW )
		{
			Rectangle aDrawRect( aPixRect );
			aDrawRect.Top() = nScrY + aOutputData.GetScrH();
			if ( nX2==MAXCOL )
			{
				// no double painting of the corner
				if ( bLayoutRTL )
					aDrawRect.Left() = nScrX;
				else
					aDrawRect.Right() = nScrX + aOutputData.GetScrW() - 1;
			}
			if (aDrawRect.Bottom() >= aDrawRect.Top())
				pContentDev->DrawRect( aDrawRect );
		}

		// restore MapMode
		pContentDev->SetMapMode(aCurrentMapMode);
	}

	if ( pDoc->HasBackgroundDraw( nTab, aDrawingRectLogic ) )
	{
		pContentDev->SetMapMode(MAP_PIXEL);
		aOutputData.DrawClear();

			// Drawing Hintergrund

		pContentDev->SetMapMode(aDrawMode);
		DrawRedraw( aOutputData, eMode, SC_LAYER_BACK );
	}
	else
		aOutputData.SetSolidBackground(sal_True);

	pContentDev->SetMapMode(MAP_PIXEL);
	aOutputData.DrawBackground();
	if ( bGridFirst && ( bGrid || bPage ) )
		aOutputData.DrawGrid( bGrid, bPage );
	if ( bPageMode )
	{
		// #87655# DrawPagePreview draws complete lines/page numbers, must always be clipped
		if ( aOutputData.SetChangedClip() )
		{
            DrawPagePreview(nX1,nY1,nX2,nY2, pContentDev);
			pContentDev->SetClipRegion();
		}
	}
	aOutputData.DrawShadow();
	aOutputData.DrawFrame();
	if ( !bLogicText )
		aOutputData.DrawStrings(sal_False);		// in pixel MapMode

    // edit cells and printer-metrics text must be before the buttons
    // (DataPilot buttons contain labels in UI font)

    pContentDev->SetMapMode(pViewData->GetLogicMode(eWhich));
    if ( bLogicText )
        aOutputData.DrawStrings(sal_True);      // in logic MapMode if bTextWysiwyg is set
    aOutputData.DrawEdit(sal_True);
    pContentDev->SetMapMode(MAP_PIXEL);

		// Autofilter- und Pivot-Buttons

    DrawButtons( nX1, nY1, nX2, nY2, aTabInfo, pContentDev );          // Pixel

		// Notiz-Anzeiger

	if ( rOpts.GetOption( VOPT_NOTES ) )
		aOutputData.DrawNoteMarks();

	if ( !bGridFirst && ( bGrid || bPage ) )
	{
		aOutputData.DrawGrid( bGrid, bPage );
	}
	aOutputData.DrawClipMarks();

	//	Szenario / ChangeTracking muss auf jeden Fall nach DrawGrid sein, auch bei !bGridFirst

	//!	Test, ob ChangeTrack-Anzeige aktiv ist
	//!	Szenario-Rahmen per View-Optionen abschaltbar?

	SCTAB nTabCount = pDoc->GetTableCount();
	ScHighlightRanges* pHigh = pViewData->GetView()->GetHighlightRanges();
	sal_Bool bHasScenario = ( nTab+1<nTabCount && pDoc->IsScenario(nTab+1) && !pDoc->IsScenario(nTab) );
	sal_Bool bHasChange = ( pDoc->GetChangeTrack() != NULL );

	if ( bHasChange || bHasScenario || pHigh != NULL )
	{

		//! SetChangedClip() mit DrawMarks() zusammenfassen?? (anderer MapMode!)

		sal_Bool bAny = sal_True;
		if (eMode == SC_UPDATE_CHANGED)
			bAny = aOutputData.SetChangedClip();
		if (bAny)
		{
			if ( bHasChange )
				aOutputData.DrawChangeTrack();

			if ( bHasScenario )
				lcl_DrawScenarioFrames( pContentDev, pViewData, eWhich, nX1,nY1,nX2,nY2 );

			if ( pHigh )
				lcl_DrawHighlight( aOutputData, pViewData, *pHigh );

			if (eMode == SC_UPDATE_CHANGED)
				pContentDev->SetClipRegion();
		}
	}

		// Drawing Vordergrund

	pContentDev->SetMapMode(aDrawMode);

	DrawRedraw( aOutputData, eMode, SC_LAYER_FRONT );
	DrawRedraw( aOutputData, eMode, SC_LAYER_INTERN );
    DrawSdrGrid( aDrawingRectLogic, pContentDev );

	if (!bIsInScroll)								// Drawing Markierungen
	{
		if(eMode == SC_UPDATE_CHANGED && aOutputData.SetChangedClip())
		{
			pContentDev->SetClipRegion();
		}

		//sal_Bool bDraw = sal_True;
		//if (eMode == SC_UPDATE_CHANGED)
		//	bDraw = NeedDrawMarks() && aOutputData.SetChangedClip();
		//if (bDraw)
		//{
		//	DrawMarks();
		//	if (eMode == SC_UPDATE_CHANGED)
		//		pContentDev->SetClipRegion();
		//}
	}

	pContentDev->SetMapMode(MAP_PIXEL);

#ifdef OLD_SELECTION_PAINT
	if (pViewData->IsActive())
		aOutputData.DrawMark( this );
#endif

	if ( pViewData->IsRefMode() && nTab >= pViewData->GetRefStartZ() && nTab <= pViewData->GetRefEndZ() )
	{
        // The AutoFill shrink area has an own overlay now
#if 0
		//	Schraffur beim Loeschen per AutoFill
		if ( pViewData->GetRefType() == SC_REFTYPE_FILL )
		{
			ScRange aRange;
			if ( pViewData->GetDelMark( aRange ) )
			{
				if ( aRange.aStart.Col() < nX1 ) aRange.aStart.SetCol(nX1);
				if ( aRange.aEnd.Col() > nX2 )	 aRange.aEnd.SetCol(nX2);
				if ( aRange.aStart.Row() < nY1 ) aRange.aStart.SetRow(nY1);
				if ( aRange.aEnd.Row() > nY2 )	 aRange.aEnd.SetRow(nY2);
				if ( aRange.aStart.Col() <= aRange.aEnd.Col() &&
					 aRange.aStart.Row() <= aRange.aEnd.Row() )
				{
					Point aStart = pViewData->GetScrPos( aRange.aStart.Col(),
														 aRange.aStart.Row(), eWhich );
					Point aEnd = pViewData->GetScrPos( aRange.aEnd.Col()+1,
													   aRange.aEnd.Row()+1, eWhich );
					aEnd.X() -= 1;
					aEnd.Y() -= 1;

					//	Markierung aufheben - roter Rahmen bleibt stehen
					Rectangle aRect( aStart,aEnd );
					Invert( aRect, INVERT_HIGHLIGHT );

					//!	Delete-Bereich extra kennzeichnen?!?!?
				}
			}
		}
#endif

        Color aRefColor( rColorCfg.GetColorValue(svtools::CALCREFERENCE).nColor );
		aOutputData.DrawRefMark( pViewData->GetRefStartX(), pViewData->GetRefStartY(),
								 pViewData->GetRefEndX(), pViewData->GetRefEndY(),
								 aRefColor, sal_False );
	}

		//	Range-Finder

	ScInputHandler* pHdl = pScMod->GetInputHdl( pViewData->GetViewShell() );
	if (pHdl)
	{
		ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
		if ( pRangeFinder && !pRangeFinder->IsHidden() &&
				pRangeFinder->GetDocName() == pDocSh->GetTitle() )
		{
			sal_uInt16 nCount = (sal_uInt16)pRangeFinder->Count();
			for (sal_uInt16 i=0; i<nCount; i++)
			{
				ScRangeFindData* pData = pRangeFinder->GetObject(i);
				if (pData)
				{
					ScRange aRef = pData->aRef;
					aRef.Justify();
					if ( aRef.aStart.Tab() >= nTab && aRef.aEnd.Tab() <= nTab )
						aOutputData.DrawRefMark( aRef.aStart.Col(), aRef.aStart.Row(),
												aRef.aEnd.Col(), aRef.aEnd.Row(),
												Color( ScRangeFindList::GetColorName( i ) ),
												sal_True );
				}
			}
		}
	}

	{
		// end redraw
		ScTabViewShell* pTabViewShell = pViewData->GetViewShell();

		if(pTabViewShell)
		{
			MapMode aCurrentMapMode(pContentDev->GetMapMode());
			pContentDev->SetMapMode(aDrawMode);
			SdrView* pDrawView = pTabViewShell->GetSdrView();

			if(pDrawView)
			{
				// #i74769# work with SdrPaintWindow directly
				pDrawView->EndDrawLayers(*pTargetPaintWindow, true);
			}

			pContentDev->SetMapMode(aCurrentMapMode);
		}
	}

	//	InPlace Edit-View
	// moved after EndDrawLayers() to get it outside the overlay buffer and
	// on top of everything
	if ( bEditMode && (pViewData->GetRefTabNo() == pViewData->GetTabNo()) )
	{
        //! use pContentDev for EditView?
        SetMapMode(MAP_PIXEL);
		SCCOL nCol1 = pViewData->GetEditStartCol();
		SCROW nRow1 = pViewData->GetEditStartRow();
		SCCOL nCol2 = pViewData->GetEditEndCol();
		SCROW nRow2 = pViewData->GetEditEndRow();
		SetLineColor();
		SetFillColor( pEditView->GetBackgroundColor() );
		Point aStart = pViewData->GetScrPos( nCol1, nRow1, eWhich );
		Point aEnd = pViewData->GetScrPos( nCol2+1, nRow2+1, eWhich );
		aEnd.X() -= 2 * nLayoutSign;		// don't overwrite grid
		aEnd.Y() -= 2;
		DrawRect( Rectangle( aStart,aEnd ) );

		SetMapMode(pViewData->GetLogicMode());
		pEditView->Paint( PixelToLogic( Rectangle( Point( nScrX, nScrY ),
							Size( aOutputData.GetScrW(), aOutputData.GetScrH() ) ) ) );
		SetMapMode(MAP_PIXEL);
	}

	if (pViewData->HasEditView(eWhich))
	{
		// flush OverlayManager before changing the MapMode
		flushOverlayManager();

		// set MapMode for text edit
		SetMapMode(pViewData->GetLogicMode());
	}
	else
		SetMapMode(aDrawMode);

	if ( pNoteMarker )
		pNoteMarker->Draw();		// ueber den Cursor, im Drawing-MapMode

	//DrawStartTimer();				// fuer bunte Handles ohne System-Clipping

	//
	//	Wenn waehrend des Paint etwas invertiert wurde (Selektion geaendert aus Basic-Macro),
	//	ist das jetzt durcheinandergekommen und es muss neu gemalt werden
	//

	DBG_ASSERT(nPaintCount, "nPaintCount falsch");
	--nPaintCount;
	if (!nPaintCount)
		CheckNeedsRepaint();
}

void ScGridWindow::CheckNeedsRepaint()
{
	//	called at the end of painting, and from timer after background text width calculation

	if (bNeedsRepaint)
	{
		bNeedsRepaint = sal_False;
		if (aRepaintPixel.IsEmpty())
			Invalidate();
		else
			Invalidate(PixelToLogic(aRepaintPixel));
		aRepaintPixel = Rectangle();

        // selection function in status bar might also be invalid
        SfxBindings& rBindings = pViewData->GetBindings();
        rBindings.Invalidate( SID_STATUS_SUM );
        rBindings.Invalidate( SID_ATTR_SIZE );
        rBindings.Invalidate( SID_TABLE_CELL );
	}
}

void ScGridWindow::DrawPagePreview( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, OutputDevice* pContentDev )
{
	ScPageBreakData* pPageData = pViewData->GetView()->GetPageBreakData();
	if (pPageData)
	{
		ScDocument* pDoc = pViewData->GetDocument();
		SCTAB nTab = pViewData->GetTabNo();
		Size aWinSize = GetOutputSizePixel();
        const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
        Color aManual( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKMANUAL).nColor );
        Color aAutomatic( rColorCfg.GetColorValue(svtools::CALCPAGEBREAK).nColor );

		String aPageText = ScGlobal::GetRscString( STR_PAGE );
		if ( nPageScript == 0 )
		{
			//	get script type of translated "Page" string only once
			nPageScript = pDoc->GetStringScriptType( aPageText );
			if (nPageScript == 0)
				nPageScript = ScGlobal::GetDefaultScriptType();
		}
		aPageText += ' ';

		Font aFont;
		ScEditEngineDefaulter* pEditEng = NULL;
		const ScPatternAttr& rDefPattern = ((const ScPatternAttr&)pDoc->GetPool()->GetDefaultItem(ATTR_PATTERN));
		if ( nPageScript == SCRIPTTYPE_LATIN )
		{
			//	use single font and call DrawText directly
			rDefPattern.GetFont( aFont, SC_AUTOCOL_BLACK );
			aFont.SetColor( Color( COL_LIGHTGRAY ) );
			//	font size is set as needed
		}
		else
		{
			//	use EditEngine to draw mixed-script string
			pEditEng = new ScEditEngineDefaulter( EditEngine::CreatePool(), sal_True );
			pEditEng->SetRefMapMode( pContentDev->GetMapMode() );
			SfxItemSet* pEditDefaults = new SfxItemSet( pEditEng->GetEmptyItemSet() );
			rDefPattern.FillEditItemSet( pEditDefaults );
			pEditDefaults->Put( SvxColorItem( Color( COL_LIGHTGRAY ), EE_CHAR_COLOR ) );
			pEditEng->SetDefaults( pEditDefaults );
		}

        sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
		for (sal_uInt16 nPos=0; nPos<nCount; nPos++)
		{
			ScPrintRangeData& rData = pPageData->GetData(nPos);
			ScRange aRange = rData.GetPrintRange();
			if ( aRange.aStart.Col() <= nX2+1  && aRange.aEnd.Col()+1 >= nX1 &&
				 aRange.aStart.Row() <= nY2+1 && aRange.aEnd.Row()+1 >= nY1 )
			{
				//	3 Pixel Rahmen um den Druckbereich
				//	(mittlerer Pixel auf den Gitterlinien)

				pContentDev->SetLineColor();
				if (rData.IsAutomatic())
					pContentDev->SetFillColor( aAutomatic );
				else
					pContentDev->SetFillColor( aManual );

				Point aStart = pViewData->GetScrPos(
									aRange.aStart.Col(), aRange.aStart.Row(), eWhich, sal_True );
				Point aEnd = pViewData->GetScrPos(
									aRange.aEnd.Col() + 1, aRange.aEnd.Row() + 1, eWhich, sal_True );
				aStart.X() -= 2;
				aStart.Y() -= 2;

				//	Ueberlaeufe verhindern:
				if ( aStart.X() < -10 )	aStart.X() = -10;
				if ( aStart.Y() < -10 )	aStart.Y() = -10;
				if ( aEnd.X() > aWinSize.Width() + 10 )
					aEnd.X() = aWinSize.Width() + 10;
				if ( aEnd.Y() > aWinSize.Height() + 10 )
					aEnd.Y() = aWinSize.Height() + 10;

				pContentDev->DrawRect( Rectangle( aStart, Point(aEnd.X(),aStart.Y()+2) ) );
				pContentDev->DrawRect( Rectangle( aStart, Point(aStart.X()+2,aEnd.Y()) ) );
				pContentDev->DrawRect( Rectangle( Point(aStart.X(),aEnd.Y()-2), aEnd ) );
				pContentDev->DrawRect( Rectangle( Point(aEnd.X()-2,aStart.Y()), aEnd ) );

				//	Seitenumbrueche
				//!	anders darstellen (gestrichelt ????)

				size_t nColBreaks = rData.GetPagesX();
				const SCCOL* pColEnd = rData.GetPageEndX();
				size_t nColPos;
				for (nColPos=0; nColPos+1<nColBreaks; nColPos++)
				{
					SCCOL nBreak = pColEnd[nColPos]+1;
					if ( nBreak >= nX1 && nBreak <= nX2+1 )
					{
						//! hidden suchen
                        if (pDoc->HasColBreak(nBreak, nTab) & BREAK_MANUAL)
							pContentDev->SetFillColor( aManual );
						else
							pContentDev->SetFillColor( aAutomatic );
						Point aBreak = pViewData->GetScrPos(
										nBreak, aRange.aStart.Row(), eWhich, sal_True );
						pContentDev->DrawRect( Rectangle( aBreak.X()-1, aStart.Y(), aBreak.X(), aEnd.Y() ) );
					}
				}

				size_t nRowBreaks = rData.GetPagesY();
				const SCROW* pRowEnd = rData.GetPageEndY();
				size_t nRowPos;
				for (nRowPos=0; nRowPos+1<nRowBreaks; nRowPos++)
				{
					SCROW nBreak = pRowEnd[nRowPos]+1;
					if ( nBreak >= nY1 && nBreak <= nY2+1 )
					{
						//! hidden suchen
                        if (pDoc->HasRowBreak(nBreak, nTab) & BREAK_MANUAL)
							pContentDev->SetFillColor( aManual );
						else
							pContentDev->SetFillColor( aAutomatic );
						Point aBreak = pViewData->GetScrPos(
										aRange.aStart.Col(), nBreak, eWhich, sal_True );
						pContentDev->DrawRect( Rectangle( aStart.X(), aBreak.Y()-1, aEnd.X(), aBreak.Y() ) );
					}
				}

				//	Seitenzahlen

				SCROW nPrStartY = aRange.aStart.Row();
				for (nRowPos=0; nRowPos<nRowBreaks; nRowPos++)
				{
					SCROW nPrEndY = pRowEnd[nRowPos];
					if ( nPrEndY >= nY1 && nPrStartY <= nY2 )
					{
						SCCOL nPrStartX = aRange.aStart.Col();
						for (nColPos=0; nColPos<nColBreaks; nColPos++)
						{
							SCCOL nPrEndX = pColEnd[nColPos];
							if ( nPrEndX >= nX1 && nPrStartX <= nX2 )
							{
								Point aPageStart = pViewData->GetScrPos(
														nPrStartX, nPrStartY, eWhich, sal_True );
								Point aPageEnd = pViewData->GetScrPos(
														nPrEndX+1,nPrEndY+1, eWhich, sal_True );

								long nPageNo = rData.GetFirstPage();
								if ( rData.IsTopDown() )
									nPageNo += ((long)nColPos)*nRowBreaks+nRowPos;
								else
									nPageNo += ((long)nRowPos)*nColBreaks+nColPos;
								String aPageStr = aPageText;
								aPageStr += String::CreateFromInt32(nPageNo);

								if ( pEditEng )
								{
									//	find right font size with EditEngine
									long nHeight = 100;
									pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
									pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
									pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
									pEditEng->SetText( aPageStr );
									Size aSize100( pEditEng->CalcTextWidth(), pEditEng->GetTextHeight() );

									//	40% of width or 60% of height
									long nSizeX = 40 * ( aPageEnd.X() - aPageStart.X() ) / aSize100.Width();
									long nSizeY = 60 * ( aPageEnd.Y() - aPageStart.Y() ) / aSize100.Height();
									nHeight = Min(nSizeX,nSizeY);
									pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
									pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
									pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );

									//	centered output with EditEngine
									Size aTextSize( pEditEng->CalcTextWidth(), pEditEng->GetTextHeight() );
									Point aPos( (aPageStart.X()+aPageEnd.X()-aTextSize.Width())/2,
												(aPageStart.Y()+aPageEnd.Y()-aTextSize.Height())/2 );
									pEditEng->Draw( pContentDev, aPos );
								}
								else
								{
									//	find right font size for DrawText
									aFont.SetSize( Size( 0,100 ) );
									pContentDev->SetFont( aFont );
									Size aSize100( pContentDev->GetTextWidth( aPageStr ), pContentDev->GetTextHeight() );

									//	40% of width or 60% of height
									long nSizeX = 40 * ( aPageEnd.X() - aPageStart.X() ) / aSize100.Width();
									long nSizeY = 60 * ( aPageEnd.Y() - aPageStart.Y() ) / aSize100.Height();
									aFont.SetSize( Size( 0,Min(nSizeX,nSizeY) ) );
									pContentDev->SetFont( aFont );

									//	centered output with DrawText
									Size aTextSize( pContentDev->GetTextWidth( aPageStr ), pContentDev->GetTextHeight() );
									Point aPos( (aPageStart.X()+aPageEnd.X()-aTextSize.Width())/2,
												(aPageStart.Y()+aPageEnd.Y()-aTextSize.Height())/2 );
									pContentDev->DrawText( aPos, aPageStr );
								}
							}
							nPrStartX = nPrEndX + 1;
						}
					}
					nPrStartY = nPrEndY + 1;
				}
			}
		}

		delete pEditEng;
	}
}

void ScGridWindow::DrawButtons( SCCOL nX1, SCROW /*nY1*/, SCCOL nX2, SCROW /*nY2*/, ScTableInfo& rTabInfo, OutputDevice* pContentDev )
{
    aComboButton.SetOutputDevice( pContentDev );

    ScDocument* pDoc = pViewData->GetDocument();
    ScDPFieldButton aCellBtn(pContentDev, &GetSettings().GetStyleSettings(), &pViewData->GetZoomX(), &pViewData->GetZoomY(), pDoc);

	SCCOL nCol;
	SCROW nRow;
	SCSIZE nArrY;
	SCSIZE nQuery;
	SCTAB			nTab = pViewData->GetTabNo();
	ScDBData*		pDBData = NULL;
	ScQueryParam*	pQueryParam = NULL;

    RowInfo*        pRowInfo = rTabInfo.mpRowInfo;
    sal_uInt16          nArrCount = rTabInfo.mnArrCount;

	sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );

	Point aOldPos  = aComboButton.GetPosPixel();	// Zustand fuer MouseDown/Up
	Size  aOldSize = aComboButton.GetSizePixel();   // merken

	for (nArrY=1; nArrY+1<nArrCount; nArrY++)
	{
		if ( pRowInfo[nArrY].bAutoFilter && pRowInfo[nArrY].bChanged )
		{
			RowInfo* pThisRowInfo = &pRowInfo[nArrY];

			nRow = pThisRowInfo->nRowNo;


			for (nCol=nX1; nCol<=nX2; nCol++)
			{
				CellInfo* pInfo = &pThisRowInfo->pCellInfo[nCol+1];
				if ( pInfo->bAutoFilter && !pInfo->bHOverlapped && !pInfo->bVOverlapped )
				{
					if (!pQueryParam)
						pQueryParam = new ScQueryParam;

					sal_Bool bNewData = sal_True;
					if (pDBData)
					{
						SCCOL nStartCol;
						SCROW nStartRow;
						SCCOL nEndCol;
						SCROW nEndRow;
						SCTAB nAreaTab;
						pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
						if ( nCol >= nStartCol && nCol <= nEndCol &&
							 nRow >= nStartRow && nRow <= nEndRow )
							bNewData = sal_False;
					}
					if (bNewData)
					{
						pDBData = pDoc->GetDBAtCursor( nCol, nRow, nTab );
						if (pDBData)
							pDBData->GetQueryParam( *pQueryParam );
						else
						{
							// can also be part of DataPilot table
							// DBG_ERROR("Auto-Filter-Button ohne DBData");
						}
					}

					//	pQueryParam kann nur MAXQUERY Eintraege enthalten

					sal_Bool bSimpleQuery = sal_True;
					sal_Bool bColumnFound = sal_False;
					if (!pQueryParam->bInplace)
						bSimpleQuery = sal_False;
					for (nQuery=0; nQuery<MAXQUERY && bSimpleQuery; nQuery++)
						if (pQueryParam->GetEntry(nQuery).bDoQuery)
						{
							//	hier nicht auf EQUAL beschraenken
							//	(auch bei ">1" soll der Spaltenkopf blau werden)

							if (pQueryParam->GetEntry(nQuery).nField == nCol)
								bColumnFound = sal_True;
							if (nQuery > 0)
								if (pQueryParam->GetEntry(nQuery).eConnect != SC_AND)
									bSimpleQuery = sal_False;
						}

                    bool bArrowState = bSimpleQuery && bColumnFound;
					long	nSizeX;
					long	nSizeY;
					pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
					Point aScrPos = pViewData->GetScrPos( nCol, nRow, eWhich );

                    aCellBtn.setBoundingBox(aScrPos, Size(nSizeX-1, nSizeY-1), bLayoutRTL);
                    aCellBtn.setPopupLeft(bLayoutRTL);   // #i114944# AutoFilter button is left-aligned in RTL
                    aCellBtn.setDrawBaseButton(false);
                    aCellBtn.setDrawPopupButton(true);
                    aCellBtn.setHasHiddenMember(bArrowState);
                    aCellBtn.draw();
				}
			}
		}

		if ( pRowInfo[nArrY].bPushButton && pRowInfo[nArrY].bChanged )
		{
			RowInfo* pThisRowInfo = &pRowInfo[nArrY];
			nRow = pThisRowInfo->nRowNo;
			for (nCol=nX1; nCol<=nX2; nCol++)
			{
				CellInfo* pInfo = &pThisRowInfo->pCellInfo[nCol+1];
				if ( pInfo->bPushButton && !pInfo->bHOverlapped && !pInfo->bVOverlapped )
				{
					Point aScrPos = pViewData->GetScrPos( nCol, nRow, eWhich );
					long nSizeX;
					long nSizeY;
					pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
					long nPosX = aScrPos.X();
					long nPosY = aScrPos.Y();
					// bLayoutRTL is handled in setBoundingBox

                    String aStr;
                    pDoc->GetString(nCol, nRow, nTab, aStr);
                    aCellBtn.setText(aStr);
                    aCellBtn.setBoundingBox(Point(nPosX, nPosY), Size(nSizeX-1, nSizeY-1), bLayoutRTL);
                    aCellBtn.setPopupLeft(false);   // DataPilot popup is always right-aligned for now
                    aCellBtn.setDrawBaseButton(true);
                    aCellBtn.setDrawPopupButton(pInfo->bPopupButton);
                    aCellBtn.setHasHiddenMember(pInfo->bFilterActive);
                    aCellBtn.draw();
				}
			}
		}

        if ( bListValButton && pRowInfo[nArrY].nRowNo == aListValPos.Row() && pRowInfo[nArrY].bChanged )
        {
            Rectangle aRect = GetListValButtonRect( aListValPos );
            aComboButton.SetPosPixel( aRect.TopLeft() );
            aComboButton.SetSizePixel( aRect.GetSize() );
            pContentDev->SetClipRegion( aRect );
            aComboButton.Draw( sal_False, sal_False );
            pContentDev->SetClipRegion();           // always called from Draw() without clip region
            aComboButton.SetPosPixel( aOldPos );    // restore old state
            aComboButton.SetSizePixel( aOldSize );  // for MouseUp/Down (AutoFilter)
        }
	}

	delete pQueryParam;
    aComboButton.SetOutputDevice( this );
}

Rectangle ScGridWindow::GetListValButtonRect( const ScAddress& rButtonPos )
{
    ScDocument* pDoc = pViewData->GetDocument();
    SCTAB nTab = pViewData->GetTabNo();
    sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
    long nLayoutSign = bLayoutRTL ? -1 : 1;

    ScDDComboBoxButton aButton( this );             // for optimal size
    Size aBtnSize = aButton.GetSizePixel();

    SCCOL nCol = rButtonPos.Col();
    SCROW nRow = rButtonPos.Row();

    long nCellSizeX;    // width of this cell, including merged
    long nDummy;
    pViewData->GetMergeSizePixel( nCol, nRow, nCellSizeX, nDummy );

    // for height, only the cell's row is used, excluding merged cells
    long nCellSizeY = ScViewData::ToPixel( pDoc->GetRowHeight( nRow, nTab ), pViewData->GetPPTY() );
    long nAvailable = nCellSizeX;

    //  left edge of next cell if there is a non-hidden next column
    SCCOL nNextCol = nCol + 1;
    const ScMergeAttr* pMerge = static_cast<const ScMergeAttr*>(pDoc->GetAttr( nCol,nRow,nTab, ATTR_MERGE ));
    if ( pMerge->GetColMerge() > 1 )
        nNextCol = nCol + pMerge->GetColMerge();    // next cell after the merged area
    while ( nNextCol <= MAXCOL && pDoc->ColHidden(nNextCol, nTab) )
        ++nNextCol;
    sal_Bool bNextCell = ( nNextCol <= MAXCOL );
    if ( bNextCell )
        nAvailable = ScViewData::ToPixel( pDoc->GetColWidth( nNextCol, nTab ), pViewData->GetPPTX() );

    if ( nAvailable < aBtnSize.Width() )
        aBtnSize.Width() = nAvailable;
    if ( nCellSizeY < aBtnSize.Height() )
        aBtnSize.Height() = nCellSizeY;

    Point aPos = pViewData->GetScrPos( nCol, nRow, eWhich, sal_True );
    aPos.X() += nCellSizeX * nLayoutSign;               // start of next cell
    if (!bNextCell)
        aPos.X() -= aBtnSize.Width() * nLayoutSign;     // right edge of cell if next cell not available
    aPos.Y() += nCellSizeY - aBtnSize.Height();
    // X remains at the left edge

    if ( bLayoutRTL )
        aPos.X() -= aBtnSize.Width()-1;     // align right edge of button with cell border

    return Rectangle( aPos, aBtnSize );
}

sal_Bool ScGridWindow::IsAutoFilterActive( SCCOL nCol, SCROW nRow, SCTAB nTab )
{
	ScDocument*		pDoc	= pViewData->GetDocument();
	ScDBData*		pDBData = pDoc->GetDBAtCursor( nCol, nRow, nTab );
	ScQueryParam	aQueryParam;

	if ( pDBData )
		pDBData->GetQueryParam( aQueryParam );
	else
	{
		DBG_ERROR("Auto-Filter-Button ohne DBData");
	}

	sal_Bool	bSimpleQuery = sal_True;
	sal_Bool	bColumnFound = sal_False;
	SCSIZE	nQuery;

	if ( !aQueryParam.bInplace )
		bSimpleQuery = sal_False;

	//	aQueryParam kann nur MAXQUERY Eintraege enthalten

	for ( nQuery=0; nQuery<MAXQUERY && bSimpleQuery; nQuery++ )
		if ( aQueryParam.GetEntry(nQuery).bDoQuery )
		{
			if (aQueryParam.GetEntry(nQuery).nField == nCol)
				bColumnFound = sal_True;

			if (nQuery > 0)
				if (aQueryParam.GetEntry(nQuery).eConnect != SC_AND)
					bSimpleQuery = sal_False;
		}

	return ( bSimpleQuery && bColumnFound );
}

void ScGridWindow::DrawComboButton( const Point&	rCellPos,
									long			nCellSizeX,
									long			nCellSizeY,
                                    sal_Bool            bArrowState,
									sal_Bool			bBtnIn )
{
	Point	aScrPos	 = rCellPos;
	Size	aBtnSize = aComboButton.GetSizePixel();

	if ( nCellSizeX < aBtnSize.Width() || nCellSizeY < aBtnSize.Height() )
	{
		if ( nCellSizeX < aBtnSize.Width() )
			aBtnSize.Width() = nCellSizeX;

		if ( nCellSizeY < aBtnSize.Height() )
			aBtnSize.Height() = nCellSizeY;

		aComboButton.SetSizePixel( aBtnSize );
	}

	sal_Bool bLayoutRTL = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() );

	if ( bLayoutRTL )
		aScrPos.X() -= nCellSizeX - 1;
	else
		aScrPos.X() += nCellSizeX - aBtnSize.Width();
	aScrPos.Y() += nCellSizeY - aBtnSize.Height();

	aComboButton.SetPosPixel( aScrPos );

	HideCursor();
    aComboButton.Draw( bArrowState, bBtnIn );
	ShowCursor();
}

void ScGridWindow::InvertSimple( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
									sal_Bool bTestMerge, sal_Bool bRepeat )
{
	//!	if INVERT_HIGHLIGHT swaps foreground and background (like on Mac),
	//!	use INVERT_HIGHLIGHT only for cells that have no background color set
	//!	(here and in ScOutputData::DrawMark)

	PutInOrder( nX1, nX2 );
	PutInOrder( nY1, nY2 );

	ScMarkData& rMark = pViewData->GetMarkData();
	ScDocument* pDoc = pViewData->GetDocument();
	SCTAB nTab = pViewData->GetTabNo();

	sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
	long nLayoutSign = bLayoutRTL ? -1 : 1;

	SCCOL nTestX2 = nX2;
	SCROW nTestY2 = nY2;
	if (bTestMerge)
		pDoc->ExtendMerge( nX1,nY1, nTestX2,nTestY2, nTab );

	SCCOL nPosX = pViewData->GetPosX( eHWhich );
	SCROW nPosY = pViewData->GetPosY( eVWhich );
	if (nTestX2 < nPosX || nTestY2 < nPosY)
		return;											// unsichtbar
	SCCOL nRealX1 = nX1;
	if (nX1 < nPosX)
		nX1 = nPosX;
	if (nY1 < nPosY)
		nY1 = nPosY;

	SCCOL nXRight = nPosX + pViewData->VisibleCellsX(eHWhich);
	if (nXRight > MAXCOL) nXRight = MAXCOL;
	SCROW nYBottom = nPosY + pViewData->VisibleCellsY(eVWhich);
	if (nYBottom > MAXROW) nYBottom = MAXROW;

	if (nX1 > nXRight || nY1 > nYBottom)
		return;											// unsichtbar
	if (nX2 > nXRight) nX2 = nXRight;
	if (nY2 > nYBottom) nY2 = nYBottom;

	MapMode aOld = GetMapMode(); SetMapMode(MAP_PIXEL);		// erst nach den return's !!!

	double nPPTX = pViewData->GetPPTX();
	double nPPTY = pViewData->GetPPTY();

	ScInvertMerger aInvert( this );

	Point aScrPos = pViewData->GetScrPos( nX1, nY1, eWhich );
	long nScrY = aScrPos.Y();
	sal_Bool bWasHidden = sal_False;
	for (SCROW nY=nY1; nY<=nY2; nY++)
	{
		sal_Bool bFirstRow = ( nY == nPosY );						// first visible row?
		sal_Bool bDoHidden = sal_False;									// versteckte nachholen ?
		sal_uInt16 nHeightTwips = pDoc->GetRowHeight( nY,nTab );
		sal_Bool bDoRow = ( nHeightTwips != 0 );
		if (bDoRow)
		{
			if (bTestMerge)
				if (bWasHidden)					// auf versteckte zusammengefasste testen
				{
//					--nY;						// nY geaendert -> vorherige zeichnen
					bDoHidden = sal_True;
					bDoRow = sal_True;
				}

			bWasHidden = sal_False;
		}
		else
		{
			bWasHidden = sal_True;
			if (bTestMerge)
				if (nY==nY2)
					bDoRow = sal_True;				// letzte Zeile aus Block
		}

		if ( bDoRow )
		{
			SCCOL nLoopEndX = nX2;
			if (nX2 < nX1)						// Rest von zusammengefasst
			{
				SCCOL nStartX = nX1;
				while ( ((const ScMergeFlagAttr*)pDoc->
							GetAttr(nStartX,nY,nTab,ATTR_MERGE_FLAG))->IsHorOverlapped() )
					--nStartX;
				if (nStartX <= nX2)
					nLoopEndX = nX1;
			}

			long nEndY = nScrY + ScViewData::ToPixel( nHeightTwips, nPPTY ) - 1;
			long nScrX = aScrPos.X();
			for (SCCOL nX=nX1; nX<=nLoopEndX; nX++)
			{
				long nWidth = ScViewData::ToPixel( pDoc->GetColWidth( nX,nTab ), nPPTX );
				if ( nWidth > 0 )
				{
					long nEndX = nScrX + ( nWidth - 1 ) * nLayoutSign;
					if (bTestMerge)
					{
						SCROW nThisY = nY;
						const ScPatternAttr* pPattern = pDoc->GetPattern( nX, nY, nTab );
						const ScMergeFlagAttr* pMergeFlag = (const ScMergeFlagAttr*) &pPattern->
																		GetItem(ATTR_MERGE_FLAG);
						if ( pMergeFlag->IsVerOverlapped() && ( bDoHidden || bFirstRow ) )
						{
							while ( pMergeFlag->IsVerOverlapped() && nThisY > 0 &&
                                    (pDoc->RowHidden(nThisY-1, nTab) || bFirstRow) )
							{
								--nThisY;
								pPattern = pDoc->GetPattern( nX, nThisY, nTab );
								pMergeFlag = (const ScMergeFlagAttr*) &pPattern->GetItem(ATTR_MERGE_FLAG);
							}
						}

						// nur Rest von zusammengefasster zu sehen ?
						SCCOL nThisX = nX;
						if ( pMergeFlag->IsHorOverlapped() && nX == nPosX && nX > nRealX1 )
						{
							while ( pMergeFlag->IsHorOverlapped() )
							{
								--nThisX;
								pPattern = pDoc->GetPattern( nThisX, nThisY, nTab );
								pMergeFlag = (const ScMergeFlagAttr*) &pPattern->GetItem(ATTR_MERGE_FLAG);
							}
						}

						if ( rMark.IsCellMarked( nThisX, nThisY, sal_True ) == bRepeat )
						{
							if ( !pMergeFlag->IsOverlapped() )
							{
								ScMergeAttr* pMerge = (ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
								if (pMerge->GetColMerge() > 0 || pMerge->GetRowMerge() > 0)
								{
									Point aEndPos = pViewData->GetScrPos(
											nThisX + pMerge->GetColMerge(),
											nThisY + pMerge->GetRowMerge(), eWhich );
									if ( aEndPos.X() * nLayoutSign > nScrX * nLayoutSign && aEndPos.Y() > nScrY )
									{
										aInvert.AddRect( Rectangle( nScrX,nScrY,
													aEndPos.X()-nLayoutSign,aEndPos.Y()-1 ) );
									}
								}
								else if ( nEndX * nLayoutSign >= nScrX * nLayoutSign && nEndY >= nScrY )
								{
									aInvert.AddRect( Rectangle( nScrX,nScrY,nEndX,nEndY ) );
								}
							}
						}
					}
					else		// !bTestMerge
					{
						if ( rMark.IsCellMarked( nX, nY, sal_True ) == bRepeat &&
												nEndX * nLayoutSign >= nScrX * nLayoutSign && nEndY >= nScrY )
						{
							aInvert.AddRect( Rectangle( nScrX,nScrY,nEndX,nEndY ) );
						}
					}

					nScrX = nEndX + nLayoutSign;
				}
			}
			nScrY = nEndY + 1;
		}
	}

	aInvert.Flush();		// before restoring MapMode

	SetMapMode(aOld);

	CheckInverted();
}

void ScGridWindow::GetSelectionRects( ::std::vector< Rectangle >& rPixelRects )
{
    // transformed from ScGridWindow::InvertSimple

//  ScMarkData& rMark = pViewData->GetMarkData();
    ScMarkData aMultiMark( pViewData->GetMarkData() );
    aMultiMark.SetMarking( sal_False );
    aMultiMark.MarkToMulti();

	ScDocument* pDoc = pViewData->GetDocument();
	SCTAB nTab = pViewData->GetTabNo();

	sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
	long nLayoutSign = bLayoutRTL ? -1 : 1;

    if ( !aMultiMark.IsMultiMarked() )
        return;

    ScRange aMultiRange;
    aMultiMark.GetMultiMarkArea( aMultiRange );
    SCCOL nX1 = aMultiRange.aStart.Col();
    SCROW nY1 = aMultiRange.aStart.Row();
    SCCOL nX2 = aMultiRange.aEnd.Col();
    SCROW nY2 = aMultiRange.aEnd.Row();

	PutInOrder( nX1, nX2 );
	PutInOrder( nY1, nY2 );

    sal_Bool bTestMerge = sal_True;
    sal_Bool bRepeat = sal_True;

	SCCOL nTestX2 = nX2;
	SCROW nTestY2 = nY2;
	if (bTestMerge)
		pDoc->ExtendMerge( nX1,nY1, nTestX2,nTestY2, nTab );

	SCCOL nPosX = pViewData->GetPosX( eHWhich );
	SCROW nPosY = pViewData->GetPosY( eVWhich );
	if (nTestX2 < nPosX || nTestY2 < nPosY)
		return;											// unsichtbar
	SCCOL nRealX1 = nX1;
	if (nX1 < nPosX)
		nX1 = nPosX;
	if (nY1 < nPosY)
		nY1 = nPosY;

	SCCOL nXRight = nPosX + pViewData->VisibleCellsX(eHWhich);
	if (nXRight > MAXCOL) nXRight = MAXCOL;
	SCROW nYBottom = nPosY + pViewData->VisibleCellsY(eVWhich);
	if (nYBottom > MAXROW) nYBottom = MAXROW;

	if (nX1 > nXRight || nY1 > nYBottom)
		return;											// unsichtbar
	if (nX2 > nXRight) nX2 = nXRight;
	if (nY2 > nYBottom) nY2 = nYBottom;

//	MapMode aOld = GetMapMode(); SetMapMode(MAP_PIXEL);		// erst nach den return's !!!

	double nPPTX = pViewData->GetPPTX();
	double nPPTY = pViewData->GetPPTY();

    ScInvertMerger aInvert( &rPixelRects );

	Point aScrPos = pViewData->GetScrPos( nX1, nY1, eWhich );
	long nScrY = aScrPos.Y();
	sal_Bool bWasHidden = sal_False;
	for (SCROW nY=nY1; nY<=nY2; nY++)
	{
		sal_Bool bFirstRow = ( nY == nPosY );						// first visible row?
		sal_Bool bDoHidden = sal_False;									// versteckte nachholen ?
		sal_uInt16 nHeightTwips = pDoc->GetRowHeight( nY,nTab );
		sal_Bool bDoRow = ( nHeightTwips != 0 );
		if (bDoRow)
		{
			if (bTestMerge)
				if (bWasHidden)					// auf versteckte zusammengefasste testen
				{
					bDoHidden = sal_True;
					bDoRow = sal_True;
				}

			bWasHidden = sal_False;
		}
		else
		{
			bWasHidden = sal_True;
			if (bTestMerge)
				if (nY==nY2)
					bDoRow = sal_True;				// letzte Zeile aus Block
		}

		if ( bDoRow )
		{
			SCCOL nLoopEndX = nX2;
			if (nX2 < nX1)						// Rest von zusammengefasst
			{
				SCCOL nStartX = nX1;
				while ( ((const ScMergeFlagAttr*)pDoc->
							GetAttr(nStartX,nY,nTab,ATTR_MERGE_FLAG))->IsHorOverlapped() )
					--nStartX;
				if (nStartX <= nX2)
					nLoopEndX = nX1;
			}

			long nEndY = nScrY + ScViewData::ToPixel( nHeightTwips, nPPTY ) - 1;
			long nScrX = aScrPos.X();
			for (SCCOL nX=nX1; nX<=nLoopEndX; nX++)
			{
				long nWidth = ScViewData::ToPixel( pDoc->GetColWidth( nX,nTab ), nPPTX );
				if ( nWidth > 0 )
				{
					long nEndX = nScrX + ( nWidth - 1 ) * nLayoutSign;
					if (bTestMerge)
					{
						SCROW nThisY = nY;
						const ScPatternAttr* pPattern = pDoc->GetPattern( nX, nY, nTab );
						const ScMergeFlagAttr* pMergeFlag = (const ScMergeFlagAttr*) &pPattern->
																		GetItem(ATTR_MERGE_FLAG);
						if ( pMergeFlag->IsVerOverlapped() && ( bDoHidden || bFirstRow ) )
						{
							while ( pMergeFlag->IsVerOverlapped() && nThisY > 0 &&
                                    (pDoc->RowHidden(nThisY-1, nTab) || bFirstRow) )
							{
								--nThisY;
								pPattern = pDoc->GetPattern( nX, nThisY, nTab );
								pMergeFlag = (const ScMergeFlagAttr*) &pPattern->GetItem(ATTR_MERGE_FLAG);
							}
						}

						// nur Rest von zusammengefasster zu sehen ?
						SCCOL nThisX = nX;
						if ( pMergeFlag->IsHorOverlapped() && nX == nPosX && nX > nRealX1 )
						{
							while ( pMergeFlag->IsHorOverlapped() )
							{
								--nThisX;
								pPattern = pDoc->GetPattern( nThisX, nThisY, nTab );
								pMergeFlag = (const ScMergeFlagAttr*) &pPattern->GetItem(ATTR_MERGE_FLAG);
							}
						}

						if ( aMultiMark.IsCellMarked( nThisX, nThisY, sal_True ) == bRepeat )
						{
							if ( !pMergeFlag->IsOverlapped() )
							{
								ScMergeAttr* pMerge = (ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
								if (pMerge->GetColMerge() > 0 || pMerge->GetRowMerge() > 0)
								{
									Point aEndPos = pViewData->GetScrPos(
											nThisX + pMerge->GetColMerge(),
											nThisY + pMerge->GetRowMerge(), eWhich );
									if ( aEndPos.X() * nLayoutSign > nScrX * nLayoutSign && aEndPos.Y() > nScrY )
									{
										aInvert.AddRect( Rectangle( nScrX,nScrY,
													aEndPos.X()-nLayoutSign,aEndPos.Y()-1 ) );
									}
								}
								else if ( nEndX * nLayoutSign >= nScrX * nLayoutSign && nEndY >= nScrY )
								{
									aInvert.AddRect( Rectangle( nScrX,nScrY,nEndX,nEndY ) );
								}
							}
						}
					}
					else		// !bTestMerge
					{
						if ( aMultiMark.IsCellMarked( nX, nY, sal_True ) == bRepeat &&
												nEndX * nLayoutSign >= nScrX * nLayoutSign && nEndY >= nScrY )
						{
							aInvert.AddRect( Rectangle( nScrX,nScrY,nEndX,nEndY ) );
						}
					}

					nScrX = nEndX + nLayoutSign;
				}
			}
			nScrY = nEndY + 1;
		}
	}

//	aInvert.Flush();		// before restoring MapMode
}

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

//UNUSED2008-05  void ScGridWindow::DrawDragRect( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2 )
//UNUSED2008-05  {
//UNUSED2008-05      if ( nX2 < pViewData->GetPosX(eHWhich) || nY2 < pViewData->GetPosY(eVWhich) )
//UNUSED2008-05          return;
//UNUSED2008-05  
//UNUSED2008-05      Update();           // wegen XOR
//UNUSED2008-05  
//UNUSED2008-05      MapMode aOld = GetMapMode(); SetMapMode(MAP_PIXEL);
//UNUSED2008-05  
//UNUSED2008-05      SCTAB nTab = pViewData->GetTabNo();
//UNUSED2008-05  
//UNUSED2008-05      SCCOL nPosX = pViewData->GetPosX(WhichH(eWhich));
//UNUSED2008-05      SCROW nPosY = pViewData->GetPosY(WhichV(eWhich));
//UNUSED2008-05      if (nX1 < nPosX) nX1 = nPosX;
//UNUSED2008-05      if (nX2 < nPosX) nX2 = nPosX;
//UNUSED2008-05      if (nY1 < nPosY) nY1 = nPosY;
//UNUSED2008-05      if (nY2 < nPosY) nY2 = nPosY;
//UNUSED2008-05  
//UNUSED2008-05      Point aScrPos( pViewData->GetScrPos( nX1, nY1, eWhich ) );
//UNUSED2008-05  
//UNUSED2008-05      long nSizeXPix=0;
//UNUSED2008-05      long nSizeYPix=0;
//UNUSED2008-05      ScDocument* pDoc = pViewData->GetDocument();
//UNUSED2008-05      double nPPTX = pViewData->GetPPTX();
//UNUSED2008-05      double nPPTY = pViewData->GetPPTY();
//UNUSED2008-05      SCCOLROW i;
//UNUSED2008-05  
//UNUSED2008-05      sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
//UNUSED2008-05      long nLayoutSign = bLayoutRTL ? -1 : 1;
//UNUSED2008-05  
//UNUSED2008-05      if (ValidCol(nX2) && nX2>=nX1)
//UNUSED2008-05          for (i=nX1; i<=nX2; i++)
//UNUSED2008-05              nSizeXPix += ScViewData::ToPixel( pDoc->GetColWidth( static_cast<SCCOL>(i), nTab ), nPPTX );
//UNUSED2008-05      else
//UNUSED2008-05      {
//UNUSED2008-05          aScrPos.X() -= nLayoutSign;
//UNUSED2008-05          nSizeXPix   += 2;
//UNUSED2008-05      }
//UNUSED2008-05  
//UNUSED2008-05      if (ValidRow(nY2) && nY2>=nY1)
//UNUSED2008-05          for (i=nY1; i<=nY2; i++)
//UNUSED2008-05              nSizeYPix += ScViewData::ToPixel( pDoc->GetRowHeight( i, nTab ), nPPTY );
//UNUSED2008-05      else
//UNUSED2008-05      {
//UNUSED2008-05          aScrPos.Y() -= 1;
//UNUSED2008-05          nSizeYPix   += 2;
//UNUSED2008-05      }
//UNUSED2008-05  
//UNUSED2008-05      aScrPos.X() -= 2 * nLayoutSign;
//UNUSED2008-05      aScrPos.Y() -= 2;
//UNUSED2008-05  //	Rectangle aRect( aScrPos, Size( nSizeXPix + 3, nSizeYPix + 3 ) );
//UNUSED2008-05      Rectangle aRect( aScrPos.X(), aScrPos.Y(),
//UNUSED2008-05                       aScrPos.X() + ( nSizeXPix + 2 ) * nLayoutSign, aScrPos.Y() + nSizeYPix + 2 );
//UNUSED2008-05      if ( bLayoutRTL )
//UNUSED2008-05      {
//UNUSED2008-05          aRect.Left() = aRect.Right();   // end position is left
//UNUSED2008-05          aRect.Right() = aScrPos.X();
//UNUSED2008-05      }
//UNUSED2008-05  
//UNUSED2008-05      Invert(Rectangle( aRect.Left(), aRect.Top(), aRect.Left()+2, aRect.Bottom() ));
//UNUSED2008-05      Invert(Rectangle( aRect.Right()-2, aRect.Top(), aRect.Right(), aRect.Bottom() ));
//UNUSED2008-05      Invert(Rectangle( aRect.Left()+3, aRect.Top(), aRect.Right()-3, aRect.Top()+2 ));
//UNUSED2008-05      Invert(Rectangle( aRect.Left()+3, aRect.Bottom()-2, aRect.Right()-3, aRect.Bottom() ));
//UNUSED2008-05  
//UNUSED2008-05      SetMapMode(aOld);
//UNUSED2008-05  }

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

void ScGridWindow::DrawCursor()
{
// #114409#
//	SCTAB nTab = pViewData->GetTabNo();
//	SCCOL nX = pViewData->GetCurX();
//	SCROW nY = pViewData->GetCurY();
//
//	//	in verdeckten Zellen nicht zeichnen
//
//	ScDocument* pDoc = pViewData->GetDocument();
//	const ScPatternAttr* pPattern = pDoc->GetPattern(nX,nY,nTab);
//	const ScMergeFlagAttr& rMerge = (const ScMergeFlagAttr&) pPattern->GetItem(ATTR_MERGE_FLAG);
//	if (rMerge.IsOverlapped())
//		return;
//
//	//	links/oben ausserhalb des Bildschirms ?
//
//	sal_Bool bVis = ( nX>=pViewData->GetPosX(eHWhich) && nY>=pViewData->GetPosY(eVWhich) );
//	if (!bVis)
//	{
//		SCCOL nEndX = nX;
//		SCROW nEndY = nY;
//		ScDocument* pDoc = pViewData->GetDocument();
//		const ScMergeAttr& rMerge = (const ScMergeAttr&) pPattern->GetItem(ATTR_MERGE);
//		if (rMerge.GetColMerge() > 1)
//			nEndX += rMerge.GetColMerge()-1;
//		if (rMerge.GetRowMerge() > 1)
//			nEndY += rMerge.GetRowMerge()-1;
//		bVis = ( nEndX>=pViewData->GetPosX(eHWhich) && nEndY>=pViewData->GetPosY(eVWhich) );
//	}
//
//	if ( bVis )
//	{
//		//	hier kein Update, da aus Paint gerufen und laut Zaehler Cursor schon da
//		//	wenn Update noetig, dann bei Hide/Showcursor vor dem Hoch-/Runterzaehlen
//
//		MapMode aOld = GetMapMode(); SetMapMode(MAP_PIXEL);
//
//		Point aScrPos = pViewData->GetScrPos( nX, nY, eWhich, sal_True );
//		sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
//
//		//	completely right of/below the screen?
//		//	(test with logical start position in aScrPos)
//		sal_Bool bMaybeVisible;
//		if ( bLayoutRTL )
//			bMaybeVisible = ( aScrPos.X() >= -2 && aScrPos.Y() >= -2 );
//		else
//		{
//			Size aOutSize = GetOutputSizePixel();
//			bMaybeVisible = ( aScrPos.X() <= aOutSize.Width() + 2 && aScrPos.Y() <= aOutSize.Height() + 2 );
//		}
//		if ( bMaybeVisible )
//		{
//			long nSizeXPix;
//			long nSizeYPix;
//			pViewData->GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix );
//
//			if ( bLayoutRTL )
//				aScrPos.X() -= nSizeXPix - 2;		// move instead of mirroring
//
//			sal_Bool bFix = ( pViewData->GetHSplitMode() == SC_SPLIT_FIX ||
//							pViewData->GetVSplitMode() == SC_SPLIT_FIX );
//			if ( pViewData->GetActivePart()==eWhich || bFix )
//			{
//				//	old UNX version with two Invert calls causes flicker.
//				//	if optimization is needed, a new flag should be added
//				//	to InvertTracking
//
//				aScrPos.X() -= 2;
//				aScrPos.Y() -= 2;
//				Rectangle aRect( aScrPos, Size( nSizeXPix + 3, nSizeYPix + 3 ) );
//
//				Invert(Rectangle( aRect.Left(), aRect.Top(), aRect.Left()+2, aRect.Bottom() ));
//				Invert(Rectangle( aRect.Right()-2, aRect.Top(), aRect.Right(), aRect.Bottom() ));
//				Invert(Rectangle( aRect.Left()+3, aRect.Top(), aRect.Right()-3, aRect.Top()+2 ));
//				Invert(Rectangle( aRect.Left()+3, aRect.Bottom()-2, aRect.Right()-3, aRect.Bottom() ));
//			}
//			else
//			{
//				Rectangle aRect( aScrPos, Size( nSizeXPix - 1, nSizeYPix - 1 ) );
//				Invert( aRect );
//			}
//		}
//
//		SetMapMode(aOld);
//	}
}

	//	AutoFill-Anfasser:

void ScGridWindow::DrawAutoFillMark()
{
// #114409#
//	if ( bAutoMarkVisible && aAutoMarkPos.Tab() == pViewData->GetTabNo() )
//	{
//		SCCOL nX = aAutoMarkPos.Col();
//		SCROW nY = aAutoMarkPos.Row();
//		SCTAB nTab = pViewData->GetTabNo();
//		ScDocument* pDoc = pViewData->GetDocument();
//		sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
//
//		Point aFillPos = pViewData->GetScrPos( nX, nY, eWhich, sal_True );
//		long nSizeXPix;
//		long nSizeYPix;
//		pViewData->GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix );
//		if ( bLayoutRTL )
//			aFillPos.X() -= nSizeXPix + 3;
//		else
//			aFillPos.X() += nSizeXPix - 2;
//
//		aFillPos.Y() += nSizeYPix;
//		aFillPos.Y() -= 2;
//		Rectangle aFillRect( aFillPos, Size(6,6) );
//		//	Anfasser von Zeichenobjekten sind 7*7
//
//		MapMode aOld = GetMapMode(); SetMapMode(MAP_PIXEL);
//		Invert( aFillRect );
//		SetMapMode(aOld);
//	}
}

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

void ScGridWindow::DataChanged( const DataChangedEvent& rDCEvt )
{
	Window::DataChanged(rDCEvt);

	if ( (rDCEvt.GetType() == DATACHANGED_PRINTER) ||
		 (rDCEvt.GetType() == DATACHANGED_DISPLAY) ||
		 (rDCEvt.GetType() == DATACHANGED_FONTS) ||
		 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
		 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
		  (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
	{
		if ( rDCEvt.GetType() == DATACHANGED_FONTS && eWhich == pViewData->GetActivePart() )
			pViewData->GetDocShell()->UpdateFontList();

		if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
			 (rDCEvt.GetFlags() & SETTINGS_STYLE) )
		{
			if ( eWhich == pViewData->GetActivePart() )		// only once for the view
			{
				ScTabView* pView = pViewData->GetView();

				//	update scale in case the UI ScreenZoom has changed
				ScGlobal::UpdatePPT(this);
				pView->RecalcPPT();

				//	RepeatResize in case scroll bar sizes have changed
				pView->RepeatResize();
                pView->UpdateAllOverlays();

				//	invalidate cell attribs in input handler, in case the
				//	EditEngine BackgroundColor has to be changed
				if ( pViewData->IsActive() )
				{
					ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
					if (pHdl)
						pHdl->ForgetLastPattern();
				}
			}
		}

		Invalidate();
	}
}




