/**************************************************************
 * 
 * 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_sc.hxx"


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

#if 0
#define _MACRODLG_HXX
#define _BIGINT_HXX
#define _SVCONTNR_HXX
#define BASIC_NODIALOGS
#define _SFXMNUITEM_HXX
#define _SVDXOUT_HXX
#define _SVDATTR_HXX
#define _SFXMNUITEM_HXX
#define _DLGCFG_HXX
#define _SFXMNUMGR_HXX
#define _SFXBASIC_HXX
#define _MODALDLG_HXX
#define _SFX_TEMPLDLG_HXX
#define _SFXSTBMGR_HXX
#define _SFXTBXMGR_HXX
#define _BASE_DLGS_HXX
#define _SFXIMGMGR_HXX
#define _SFXMNUMGR_HXX
#define _SFXSTBITEM_HXX
#define _SFXTBXCTRL_HXX
#define _PASSWD_HXX
//#define _SFXFILEDLG_HXX
//#define _SFXREQUEST_HXX
#define _SFXOBJFACE_HXX

#define _SDR_NOTRANSFORM
#define _SVDXOUT_HXX
#endif
#include <vcl/svapp.hxx>

///////////////////////////////////////////////////////////////////////////
// NODRAW.HXX
// Erweiterte Konstanten, um CLOKs mit SVDRAW.HXX zu vermeiden
// Die u.a. Aenderungen nehmen vorgeschlagene Konstante vorweg
///////////////////////////////////////////////////////////////////////////

#if 0
#define _SDR_NOTRANSFORM		// Transformationen, selten verwendet
#define _SDR_NOTOUCH			// Hit-Tests, selten verwendet

#define	_SDR_NOUNDO				// Undo-Objekte
#define _SDR_NOPAGEOBJ          // SdrPageObj
#define _SDR_NOVIRTOBJ          // SdrVirtObj
#define _SDR_NOGROUPOBJ         // SdrGroupObj
#define _SDR_NOTEXTOBJ          // SdrTextObj
#define _SDR_NOPATHOBJ          // SdrPathObj
#define _SDR_NOEDGEOBJ          // SdrEdgeObj
#define _SDR_NORECTOBJ          // SdrRectObj
#define _SDR_NOCAPTIONOBJ       // SdrCaptionObj
#define _SDR_NOCIRCLEOBJ        // SdrCircleObj
#define _SDR_NOGRAFOBJ          // SdrGrafObj
#define _SDR_NOOLE2OBJ          // SdrOle2Obj
#endif

// Dieses define entfernt die VCControls aus SI.HXX

#define _SI_HXX					// VCControls

////////////////////// Umsetzen der Standard-Defines //////////////////////

//#define _SVDDRAG_HXX		// SdrDragStat
#define _SVDPAGE_HXX        // SdrPage

#ifdef _SDR_NOSURROGATEOBJ
	#undef _SDR_NOSURROGATEOBJ
	#define _SVDSURO_HXX
#endif

#ifdef _SDR_NOPAGEOBJ
	#undef _SDR_NOPAGEOBJ
	#define _SVDOPAGE_HXX
#endif

#ifdef _SDR_NOVIRTOBJ
	#undef _SDR_NOVIRTOBJ
	#define _SVDOVIRT_HXX
#endif

#ifdef _SDR_NOGROUPOBJ
	#undef _SDR_NOGROUPOBJ
	#define _SVDOGRP_HXX
#endif

#ifdef _SDR_NOTEXTOBJ
	#undef _SDR_NOTEXTOBJ
	#define _SVDOTEXT_HXX
#endif

#ifdef _SDR_NOPATHOBJ
	#undef _SDR_NOPATHOBJ
	#define _SVDOPATH_HXX
#endif

#ifdef _SDR_NOEDGEOBJ
	#undef _SDR_NOEDGEOBJ
	#define _SVDOEDGE_HXX
#endif

#ifdef _SDR_NORECTOBJ
	#undef _SDR_NORECTOBJ
	#define _SVDORECT_HXX
#else
	#undef _SDVOTEXT_OBJ
#endif

#ifdef _SDR_NOCAPTIONOBJ
	#undef _SDR_NOCAPTIONOBJ
	#define _SVDCAPT_HXX
#endif

#ifdef _SDR_NOCIRCLEOBJ
	#undef _SDR_NOCIRCLEOBJ
	#define _SVDOCIRC_HXX
#endif

#ifdef _SDR_NOGRAFOBJ
	#undef _SDR_NOGRAFOBJ
	#define _SVDOGRAF_HXX
#else
	#undef _SVDOTEXT_HXX
	#undef _SVDORECT_HXX
#endif

#ifdef _SDR_NOOLE2OBJ
	#undef _SDR_NOOLE2OBJ
	#define _SVDOOLE2_HXX
#else
	#undef _SVDOTEXT_HXX
	#undef _SVDORECT_HXX
#endif

//#ifdef _SDR_NOVIEWS
//	#define _SVDDRAG_HXX
//#endif

////////////////////// Ende der SVDRAW-Modifikationen /////////////////////


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

#include "scitems.hxx"
#include <sfx2/viewfrm.hxx>
#include <sfx2/bindings.hxx>
#include <vcl/help.hxx>
#include <rtl/logfile.hxx>

#include "tabview.hxx"
#include "tabvwsh.hxx"
#include "document.hxx"
#include "gridwin.hxx"
#include "olinewin.hxx"
#include "olinetab.hxx"
#include "tabsplit.hxx"
#include "colrowba.hxx"
#include "tabcont.hxx"
#include "scmod.hxx"
#include "sc.hrc"
#include "viewutil.hxx"
#include "globstr.hrc"
#include "drawview.hxx"
#include "docsh.hxx"
#include "viewuno.hxx"
#include "AccessibilityHints.hxx"
#include "appoptio.hxx"

#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>

#include <string>
#include <algorithm>

#define SPLIT_MARGIN	30
#define SC_ICONSIZE		36

#define SC_SCROLLBAR_MIN	30
#define SC_TABBAR_MIN		6

//	fuer Rad-Maus
#define SC_DELTA_ZOOM	10

using namespace ::com::sun::star;

// STATIC DATA -----------------------------------------------------------


//==================================================================

//	Corner-Button

ScCornerButton::ScCornerButton( Window* pParent, ScViewData* pData, sal_Bool bAdditional ) :
	Window( pParent, WinBits( 0 ) ),
	pViewData( pData ),
	bAdd( bAdditional )
{
	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
	SetBackground( rStyleSettings.GetFaceColor() );
	EnableRTL( sal_False );
}

__EXPORT ScCornerButton::~ScCornerButton()
{
}

void __EXPORT ScCornerButton::Paint( const Rectangle& rRect )
{
	Size aSize = GetOutputSizePixel();
	long nPosX = aSize.Width()-1;
	long nPosY = aSize.Height()-1;

	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();

	Window::Paint(rRect);

	sal_Bool bLayoutRTL = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() );
	long nDarkX = bLayoutRTL ? 0 : nPosX;

    if ( !bAdd && !rStyleSettings.GetHighContrastMode() )
    {
        // match the shaded look of column/row headers

        Color aFace( rStyleSettings.GetFaceColor() );
        Color aWhite( COL_WHITE );
        Color aCenter( aFace );
        aCenter.Merge( aWhite, 0xd0 );          // lighten up a bit
        Color aOuter( aFace );
        aOuter.Merge( aWhite, 0xa0 );           // lighten up more

        long nCenterX = (aSize.Width() / 2) - 1;
        long nCenterY = (aSize.Height() / 2) - 1;

        SetLineColor();
        SetFillColor(aCenter);
        DrawRect( Rectangle( nCenterX, nCenterY, nCenterX, nPosY ) );
        DrawRect( Rectangle( nCenterX, nCenterY, nDarkX, nCenterY ) );
        SetFillColor(aOuter);
        DrawRect( Rectangle( 0, 0, nPosX, nCenterY-1 ) );
        if ( bLayoutRTL )
            DrawRect( Rectangle( nCenterX+1, nCenterY, nPosX, nPosY ) );
        else
            DrawRect( Rectangle( 0, nCenterY, nCenterX-1, nPosY ) );
    }

	//	both buttons have the same look now - only dark right/bottom lines
	SetLineColor( rStyleSettings.GetDarkShadowColor() );
	DrawLine( Point(0,nPosY), Point(nPosX,nPosY) );
	DrawLine( Point(nDarkX,0), Point(nDarkX,nPosY) );
}

void ScCornerButton::StateChanged( StateChangedType nType )
{
	Window::StateChanged( nType );

	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
	SetBackground( rStyleSettings.GetFaceColor() );
	Invalidate();
}

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

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

	const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
	SetBackground( rStyleSettings.GetFaceColor() );
	Invalidate();
}


void __EXPORT ScCornerButton::Resize()
{
	Invalidate();
}

void __EXPORT ScCornerButton::MouseButtonDown( const MouseEvent& rMEvt )
{
	ScModule* pScMod = SC_MOD();
	sal_Bool bDisable = pScMod->IsFormulaMode() || pScMod->IsModalMode();
	if (!bDisable)
	{
		ScTabViewShell* pViewSh = pViewData->GetViewShell();
		pViewSh->SetActive();									// Appear und SetViewFrame
		pViewSh->ActiveGrabFocus();

		sal_Bool bControl = rMEvt.IsMod1();
		pViewSh->SelectAll( bControl );
	}
}

//==================================================================

sal_Bool lcl_HasColOutline( const ScViewData& rViewData )
{
	const ScOutlineTable* pTable = rViewData.GetDocument()->GetOutlineTable(rViewData.GetTabNo());
	if (pTable)
	{
		const ScOutlineArray* pArray = pTable->GetColArray();
		if ( pArray->GetDepth() > 0 )
			return sal_True;
	}
	return sal_False;
}

sal_Bool lcl_HasRowOutline( const ScViewData& rViewData )
{
	const ScOutlineTable* pTable = rViewData.GetDocument()->GetOutlineTable(rViewData.GetTabNo());
	if (pTable)
	{
		const ScOutlineArray* pArray = pTable->GetRowArray();
		if ( pArray->GetDepth() > 0 )
			return sal_True;
	}
	return sal_False;
}

//==================================================================

//	Init und Konstruktoren
//	ScTabView::Init() in tabview5.cxx wegen out of keys


#define TABVIEW_INIT	\
			pSelEngine( NULL ),												\
			aFunctionSet( &aViewData ),										\
			pHdrSelEng( NULL ),												\
			aHdrFunc( &aViewData ),											\
			pDrawView( NULL ),												\
			bDrawSelMode( sal_False ),											\
		    aVScrollTop( pFrameWin, WinBits( WB_VSCROLL | WB_DRAG ) ),		\
		    aVScrollBottom( pFrameWin, WinBits( WB_VSCROLL | WB_DRAG ) ),	\
		    aHScrollLeft( pFrameWin, WinBits( WB_HSCROLL | WB_DRAG ) ),		\
		    aHScrollRight( pFrameWin, WinBits( WB_HSCROLL | WB_DRAG ) ),	\
			aCornerButton( pFrameWin, &aViewData, sal_False ),					\
			aTopButton( pFrameWin, &aViewData, sal_True ),						\
			aScrollBarBox( pFrameWin, WB_SIZEABLE ),						\
			pInputHintWindow( NULL ),										\
			pPageBreakData( NULL ),											\
			pHighlightRanges( NULL ),										\
            pBrushDocument( NULL ),                                         \
            pDrawBrushSet( NULL ),                                          \
            bLockPaintBrush( sal_False ),                                       \
			pTimerWindow( NULL ),											\
			nTipVisible( 0 ),												\
		    bDragging( sal_False ),												\
			bIsBlockMode( sal_False ),											\
			bBlockNeg( sal_False ),												\
			bBlockCols( sal_False ),											\
			bBlockRows( sal_False ),											\
            mfPendingTabBarWidth( -1.0 ),                                   \
			bMinimized( sal_False ),											\
			bInUpdateHeader( sal_False ),										\
			bInActivatePart( sal_False ),										\
			bInZoomUpdate( sal_False ),											\
			bMoveIsShift( sal_False ),											\
            bNewStartIfMarking( sal_False )


ScTabView::ScTabView( Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
			pFrameWin( pParent ),
			aViewData( &rDocSh, pViewShell ),
			TABVIEW_INIT
{
	RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScTabView::ScTabView" );

	Init();
}

//UNUSED2009-05 ScTabView::ScTabView( Window* pParent, const ScTabView& rScTabView, ScTabViewShell* pViewShell ) :
//UNUSED2009-05             pFrameWin( pParent ),
//UNUSED2009-05             aViewData( rScTabView.aViewData ),
//UNUSED2009-05             TABVIEW_INIT
//UNUSED2009-05 {
//UNUSED2009-05     RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScTabView::ScTabView" );
//UNUSED2009-05 
//UNUSED2009-05     aViewData.SetViewShell( pViewShell );
//UNUSED2009-05     Init();
//UNUSED2009-05 
//UNUSED2009-05     UpdateShow();
//UNUSED2009-05     if ( aViewData.GetActivePart() != SC_SPLIT_BOTTOMLEFT )
//UNUSED2009-05         pGridWin[SC_SPLIT_BOTTOMLEFT]->Show();
//UNUSED2009-05 
//UNUSED2009-05     InvalidateSplit();
//UNUSED2009-05 }

void ScTabView::InitScrollBar( ScrollBar& rScrollBar, long nMaxVal )
{
	rScrollBar.SetRange( Range( 0, nMaxVal ) );
	rScrollBar.SetLineSize( 1 );
	rScrollBar.SetPageSize( 1 );				// wird getrennt abgefragt
	rScrollBar.SetVisibleSize( 10 );			// wird bei Resize neu gesetzt

	rScrollBar.SetScrollHdl( LINK(this, ScTabView, ScrollHdl) );
	rScrollBar.SetEndScrollHdl( LINK(this, ScTabView, EndScrollHdl) );
}

//	Scroll-Timer

void ScTabView::SetTimer( ScGridWindow* pWin, const MouseEvent& rMEvt )
{
	pTimerWindow = pWin;
	aTimerMEvt   = rMEvt;
	aScrollTimer.Start();
}

void ScTabView::ResetTimer()
{
	aScrollTimer.Stop();
	pTimerWindow = NULL;
}

IMPL_LINK( ScTabView, TimerHdl, Timer*, EMPTYARG )
{
//	aScrollTimer.Stop();
	if (pTimerWindow)
		pTimerWindow->MouseMove( aTimerMEvt );

	return 0;
}

// --- Resize ---------------------------------------------------------------------

void lcl_SetPosSize( Window& rWindow, const Point& rPos, const Size& rSize,
						long nTotalWidth, sal_Bool bLayoutRTL )
{
	Point aNewPos = rPos;
	if ( bLayoutRTL )
	{
		aNewPos.X() = nTotalWidth - rPos.X() - rSize.Width();
		if ( aNewPos == rWindow.GetPosPixel() && rSize.Width() != rWindow.GetSizePixel().Width() )
		{
			//	Document windows are manually painted right-to-left, so they need to
			//	be repainted if the size changes.
			rWindow.Invalidate();
		}
	}
	rWindow.SetPosSizePixel( aNewPos, rSize );
}

void ScTabView::DoResize( const Point& rOffset, const Size& rSize, sal_Bool bInner )
{
	HideListBox();

	sal_Bool bHasHint = ( pInputHintWindow != NULL );
	if (bHasHint)
		RemoveHintWindow();

	sal_Bool bLayoutRTL = aViewData.GetDocument()->IsLayoutRTL( aViewData.GetTabNo() );
	long nTotalWidth = rSize.Width();
    if ( bLayoutRTL )
        nTotalWidth += 2*rOffset.X();

	sal_Bool bVScroll	 = aViewData.IsVScrollMode();
	sal_Bool bHScroll	 = aViewData.IsHScrollMode();
	sal_Bool bTabControl = aViewData.IsTabMode();
	sal_Bool bHeaders	 = aViewData.IsHeaderMode();
	sal_Bool bOutlMode	 = aViewData.IsOutlineMode();
	sal_Bool bHOutline	 = bOutlMode && lcl_HasColOutline(aViewData);
	sal_Bool bVOutline	 = bOutlMode && lcl_HasRowOutline(aViewData);

	//	Scrollbar-Einstellungen koennen vom Sfx ueberschrieben werden:
	SfxScrollingMode eMode = aViewData.GetViewShell()->GetScrollingMode();
	if ( eMode == SCROLLING_NO )
		bHScroll = bVScroll = sal_False;
	else if ( eMode == SCROLLING_YES || eMode == SCROLLING_AUTO )	//! Auto ???
		bHScroll = bVScroll = sal_True;

	if ( aViewData.GetDocShell()->IsPreview() )
		bHScroll = bVScroll = bTabControl = bHeaders = bOutlMode = bHOutline = bVOutline = sal_False;

	long nBarX = 0;
	long nBarY = 0;
    long nOutlineX = 0;
    long nOutlineY = 0;
	long nOutPosX;
	long nOutPosY;

	long nPosX = rOffset.X();
	long nPosY = rOffset.Y();
	long nSizeX = rSize.Width();
	long nSizeY = rSize.Height();
	long nSize1;

	bMinimized = ( nSizeX<=SC_ICONSIZE || nSizeY<=SC_ICONSIZE );
	if ( bMinimized )
		return;

	long nSplitSizeX = SPLIT_HANDLE_SIZE;
	if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
		nSplitSizeX = 1;
	long nSplitSizeY = SPLIT_HANDLE_SIZE;
	if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
		nSplitSizeY = 1;

	const long nOverlap = 0;	// ScrollBar::GetWindowOverlapPixel();

	aBorderPos = rOffset;
	aFrameSize = rSize;

	if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE )
		if ( aViewData.GetHSplitPos() > nSizeX - SPLIT_MARGIN )
		{
			aViewData.SetHSplitMode( SC_SPLIT_NONE );
			if ( WhichH( aViewData.GetActivePart() ) == SC_SPLIT_RIGHT )
				ActivatePart( SC_SPLIT_BOTTOMLEFT );
			InvalidateSplit();
//			UpdateShow();
		}
	if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
		if ( aViewData.GetVSplitPos() > nSizeY - SPLIT_MARGIN )
		{
			aViewData.SetVSplitMode( SC_SPLIT_NONE );
			if ( WhichV( aViewData.GetActivePart() ) == SC_SPLIT_TOP )
				ActivatePart( SC_SPLIT_BOTTOMLEFT );
			InvalidateSplit();
//			UpdateShow();
		}

	UpdateShow();

	if (bHScroll || bVScroll)		// Scrollbars horizontal oder vertikal
	{
		long nScrollBarSize = pFrameWin->GetSettings().GetStyleSettings().GetScrollBarSize();
		if (bVScroll)
		{
//			nBarX = aVScrollBottom.GetSizePixel().Width();
			nBarX = nScrollBarSize;
			nSizeX -= nBarX - nOverlap;
		}
		if (bHScroll)
		{
//			nBarY = aHScrollLeft.GetSizePixel().Height();
			nBarY = nScrollBarSize;
			nSizeY -= nBarY - nOverlap;
		}

		//	window at the bottom right
		lcl_SetPosSize( aScrollBarBox, Point( nPosX+nSizeX, nPosY+nSizeY ), Size( nBarX, nBarY ),
						nTotalWidth, bLayoutRTL );

		if (bHScroll)								// Scrollbars horizontal
		{
            long nSizeLt = 0;       // left scroll bar
            long nSizeRt = 0;       // right scroll bar
            long nSizeSp = 0;       // splitter

			switch (aViewData.GetHSplitMode())
			{
				case SC_SPLIT_NONE:
					nSizeSp = nSplitSizeX;
					nSizeLt = nSizeX - nSizeSp + nOverlap;			// Ecke ueberdecken
					break;
				case SC_SPLIT_NORMAL:
					nSizeSp = nSplitSizeX;
					nSizeLt = aViewData.GetHSplitPos();
					break;
				case SC_SPLIT_FIX:
					nSizeSp = 0;
					nSizeLt = 0;
					break;
			}
			nSizeRt = nSizeX - nSizeLt - nSizeSp;

			long nTabSize = 0;
			if (bTabControl)
			{
                // pending relative tab bar width from extended document options
                if( mfPendingTabBarWidth >= 0.0 )
                {
                    SetRelTabBarWidth( mfPendingTabBarWidth );
                    mfPendingTabBarWidth = -1.0;
                }

				nTabSize = pTabControl->GetSizePixel().Width()-nOverlap;

				if ( aViewData.GetHSplitMode() != SC_SPLIT_FIX )	// bei linkem Scrollbar
				{
					if (nTabSize > nSizeLt-SC_SCROLLBAR_MIN) nTabSize = nSizeLt-SC_SCROLLBAR_MIN;
					if (nTabSize < SC_TABBAR_MIN) nTabSize = SC_TABBAR_MIN;
					nSizeLt -= nTabSize;
				}
				else												// bei rechtem Scrollbar
				{
					if (nTabSize > nSizeRt-SC_SCROLLBAR_MIN) nTabSize = nSizeRt-SC_SCROLLBAR_MIN;
					if (nTabSize < SC_TABBAR_MIN) nTabSize = SC_TABBAR_MIN;
					nSizeRt -= nTabSize;
				}
			}

			lcl_SetPosSize( *pTabControl, Point(nPosX-nOverlap, nPosY+nSizeY),
												Size(nTabSize+nOverlap, nBarY), nTotalWidth, bLayoutRTL );
            pTabControl->SetSheetLayoutRTL( bLayoutRTL );

			lcl_SetPosSize( aHScrollLeft, Point(nPosX+nTabSize-nOverlap, nPosY+nSizeY),
												Size(nSizeLt+2*nOverlap, nBarY), nTotalWidth, bLayoutRTL );
			lcl_SetPosSize( *pHSplitter, Point( nPosX+nTabSize+nSizeLt, nPosY+nSizeY ),
											Size( nSizeSp, nBarY ), nTotalWidth, bLayoutRTL );
			lcl_SetPosSize( aHScrollRight, Point(nPosX+nTabSize+nSizeLt+nSizeSp-nOverlap,
													nPosY+nSizeY),
											Size(nSizeRt+2*nOverlap, nBarY), nTotalWidth, bLayoutRTL );

			//	SetDragRectPixel is done below
		}

		if (bVScroll)								// Scrollbars vertikal
		{
            long nSizeUp = 0;       // upper scroll bar
            long nSizeSp = 0;       // splitter
			long nSizeDn;			// unterer Scrollbar

			switch (aViewData.GetVSplitMode())
			{
				case SC_SPLIT_NONE:
					nSizeUp = 0;
					nSizeSp = nSplitSizeY;
					break;
				case SC_SPLIT_NORMAL:
					nSizeUp = aViewData.GetVSplitPos();
					nSizeSp = nSplitSizeY;
					break;
				case SC_SPLIT_FIX:
					nSizeUp = 0;
					nSizeSp = 0;
					break;
			}
			nSizeDn = nSizeY - nSizeUp - nSizeSp;

			lcl_SetPosSize( aVScrollTop, Point(nPosX+nSizeX, nPosY-nOverlap),
											Size(nBarX,nSizeUp+2*nOverlap), nTotalWidth, bLayoutRTL );
			lcl_SetPosSize( *pVSplitter, Point( nPosX+nSizeX, nPosY+nSizeUp ),
											Size( nBarX, nSizeSp ), nTotalWidth, bLayoutRTL );
			lcl_SetPosSize( aVScrollBottom, Point(nPosX+nSizeX,
												nPosY+nSizeUp+nSizeSp-nOverlap),
											Size(nBarX, nSizeDn+2*nOverlap), nTotalWidth, bLayoutRTL );

			//	SetDragRectPixel is done below
		}
	}

	//	SetDragRectPixel auch ohne Scrollbars etc., wenn schon gesplittet ist
	if ( bHScroll || aViewData.GetHSplitMode() != SC_SPLIT_NONE )
		pHSplitter->SetDragRectPixel(
			Rectangle( nPosX, nPosY, nPosX+nSizeX, nPosY+nSizeY ), pFrameWin );
	if ( bVScroll || aViewData.GetVSplitMode() != SC_SPLIT_NONE )
		pVSplitter->SetDragRectPixel(
			Rectangle( nPosX, nPosY, nPosX+nSizeX, nPosY+nSizeY ), pFrameWin );

	if (bTabControl && ! bHScroll )
	{
		nBarY = aHScrollLeft.GetSizePixel().Height();
		nBarX = aVScrollBottom.GetSizePixel().Width();

		nSize1 = nSizeX + nOverlap;

		long nTabSize = nSize1;
		if (nTabSize < 0) nTabSize = 0;

		lcl_SetPosSize( *pTabControl, Point(nPosX-nOverlap, nPosY+nSizeY-nBarY),
										Size(nTabSize+nOverlap, nBarY), nTotalWidth, bLayoutRTL );
		nSizeY -= nBarY - nOverlap;
		lcl_SetPosSize( aScrollBarBox, Point( nPosX+nSizeX, nPosY+nSizeY ), Size( nBarX, nBarY ),
										nTotalWidth, bLayoutRTL );

		if( bVScroll )
		{
			Size aVScrSize = aVScrollBottom.GetSizePixel();
			aVScrSize.Height() -= nBarY;
			aVScrollBottom.SetSizePixel( aVScrSize );
		}
	}

	nOutPosX = nPosX;
	nOutPosY = nPosY;

	// Outline-Controls
	if (bVOutline && pRowOutline[SC_SPLIT_BOTTOM])
	{
		nOutlineX = pRowOutline[SC_SPLIT_BOTTOM]->GetDepthSize();
		nSizeX -= nOutlineX;
		nPosX += nOutlineX;
	}
	if (bHOutline && pColOutline[SC_SPLIT_LEFT])
	{
		nOutlineY = pColOutline[SC_SPLIT_LEFT]->GetDepthSize();
		nSizeY -= nOutlineY;
		nPosY += nOutlineY;
	}

	if (bHeaders)								// Spalten/Zeilen-Header
	{
		nBarX = pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width();
		nBarY = pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height();
		nSizeX -= nBarX;
		nSizeY -= nBarY;
		nPosX += nBarX;
		nPosY += nBarY;
	}
	else
		nBarX = nBarY = 0;

		//
		//		Splitter auswerten
		//

	long nLeftSize   = nSizeX;
	long nRightSize  = 0;
	long nTopSize	 = 0;
	long nBottomSize = nSizeY;
	long nSplitPosX  = nPosX;
	long nSplitPosY  = nPosY;

	if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE )
	{
		long nSplitHeight = rSize.Height();
		if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
		{
			//	Fixier-Splitter nicht mit Scrollbar/TabBar ueberlappen lassen
			if ( bHScroll )
				nSplitHeight -= aHScrollLeft.GetSizePixel().Height();
			else if ( bTabControl && pTabControl )
				nSplitHeight -= pTabControl->GetSizePixel().Height();
		}
		nSplitPosX = aViewData.GetHSplitPos();
		lcl_SetPosSize( *pHSplitter,
			Point( nSplitPosX, nOutPosY ), Size( nSplitSizeX, nSplitHeight ), nTotalWidth, bLayoutRTL );
		nLeftSize = nSplitPosX - nPosX;
		nSplitPosX += nSplitSizeX;
		nRightSize = nSizeX - nLeftSize - nSplitSizeX;
	}
	if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
	{
		long nSplitWidth = rSize.Width();
		if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX && bVScroll )
			nSplitWidth -= aVScrollBottom.GetSizePixel().Width();
		nSplitPosY = aViewData.GetVSplitPos();
		lcl_SetPosSize( *pVSplitter,
			Point( nOutPosX, nSplitPosY ), Size( nSplitWidth, nSplitSizeY ), nTotalWidth, bLayoutRTL );
		nTopSize = nSplitPosY - nPosY;
		nSplitPosY += nSplitSizeY;
		nBottomSize = nSizeY - nTopSize - nSplitSizeY;
	}

	//	ShowHide fuer pColOutline / pRowOutline passiert in UpdateShow

	if (bHOutline)								// Outline-Controls
	{
		if (pColOutline[SC_SPLIT_LEFT])
		{
            pColOutline[SC_SPLIT_LEFT]->SetHeaderSize( nBarX );
			lcl_SetPosSize( *pColOutline[SC_SPLIT_LEFT],
					Point(nPosX-nBarX,nOutPosY), Size(nLeftSize+nBarX,nOutlineY), nTotalWidth, bLayoutRTL );
		}
		if (pColOutline[SC_SPLIT_RIGHT])
		{
			pColOutline[SC_SPLIT_RIGHT]->SetHeaderSize( 0 );	// always call to update RTL flag
			lcl_SetPosSize( *pColOutline[SC_SPLIT_RIGHT],
					Point(nSplitPosX,nOutPosY), Size(nRightSize,nOutlineY), nTotalWidth, bLayoutRTL );
		}
	}
	if (bVOutline)
	{
		if (nTopSize)
		{
			if (pRowOutline[SC_SPLIT_TOP] && pRowOutline[SC_SPLIT_BOTTOM])
			{
                pRowOutline[SC_SPLIT_TOP]->SetHeaderSize( nBarY );
				lcl_SetPosSize( *pRowOutline[SC_SPLIT_TOP],
						Point(nOutPosX,nPosY-nBarY), Size(nOutlineX,nTopSize+nBarY), nTotalWidth, bLayoutRTL );
				pRowOutline[SC_SPLIT_BOTTOM]->SetHeaderSize( 0 );
				lcl_SetPosSize( *pRowOutline[SC_SPLIT_BOTTOM],
						Point(nOutPosX,nSplitPosY), Size(nOutlineX,nBottomSize), nTotalWidth, bLayoutRTL );
			}
		}
		else if (pRowOutline[SC_SPLIT_BOTTOM])
		{
            pRowOutline[SC_SPLIT_BOTTOM]->SetHeaderSize( nBarY );
			lcl_SetPosSize( *pRowOutline[SC_SPLIT_BOTTOM],
					Point(nOutPosX,nSplitPosY-nBarY), Size(nOutlineX,nBottomSize+nBarY), nTotalWidth, bLayoutRTL );
		}
	}
	if (bHOutline && bVOutline)
	{
		lcl_SetPosSize( aTopButton, Point(nOutPosX,nOutPosY), Size(nOutlineX,nOutlineY), nTotalWidth, bLayoutRTL );
		aTopButton.Show();
	}
	else
		aTopButton.Hide();

	if (bHeaders)								// Spalten/Zeilen-Header
	{
		lcl_SetPosSize( *pColBar[SC_SPLIT_LEFT],
			Point(nPosX,nPosY-nBarY), Size(nLeftSize,nBarY), nTotalWidth, bLayoutRTL );
		if (pColBar[SC_SPLIT_RIGHT])
			lcl_SetPosSize( *pColBar[SC_SPLIT_RIGHT],
				Point(nSplitPosX,nPosY-nBarY), Size(nRightSize,nBarY), nTotalWidth, bLayoutRTL );

		if (pRowBar[SC_SPLIT_TOP])
			lcl_SetPosSize( *pRowBar[SC_SPLIT_TOP],
				Point(nPosX-nBarX,nPosY), Size(nBarX,nTopSize), nTotalWidth, bLayoutRTL );
		lcl_SetPosSize( *pRowBar[SC_SPLIT_BOTTOM],
			Point(nPosX-nBarX,nSplitPosY), Size(nBarX,nBottomSize), nTotalWidth, bLayoutRTL );

		lcl_SetPosSize( aCornerButton, Point(nPosX-nBarX,nPosY-nBarY), Size(nBarX,nBarY), nTotalWidth, bLayoutRTL );
		aCornerButton.Show();
		pColBar[SC_SPLIT_LEFT]->Show();
		pRowBar[SC_SPLIT_BOTTOM]->Show();
	}
	else
	{
		aCornerButton.Hide();
		pColBar[SC_SPLIT_LEFT]->Hide();			// immer da
		pRowBar[SC_SPLIT_BOTTOM]->Hide();
	}


											// Grid-Windows

	if (bInner)
	{
        long nInnerPosX = bLayoutRTL ? ( nTotalWidth - nPosX - nLeftSize ) : nPosX;
        pGridWin[SC_SPLIT_BOTTOMLEFT]->SetPosPixel( Point(nInnerPosX,nSplitPosY) );
	}
	else
	{
		lcl_SetPosSize( *pGridWin[SC_SPLIT_BOTTOMLEFT],
			Point(nPosX,nSplitPosY), Size(nLeftSize,nBottomSize), nTotalWidth, bLayoutRTL );
		if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE )
			lcl_SetPosSize( *pGridWin[SC_SPLIT_BOTTOMRIGHT],
				Point(nSplitPosX,nSplitPosY), Size(nRightSize,nBottomSize), nTotalWidth, bLayoutRTL );
		if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
			lcl_SetPosSize( *pGridWin[SC_SPLIT_TOPLEFT],
				Point(nPosX,nPosY), Size(nLeftSize,nTopSize), nTotalWidth, bLayoutRTL );
		if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE && aViewData.GetVSplitMode() != SC_SPLIT_NONE )
			lcl_SetPosSize( *pGridWin[SC_SPLIT_TOPRIGHT],
				Point(nSplitPosX,nPosY), Size(nRightSize,nTopSize), nTotalWidth, bLayoutRTL );
	}

				//
				//	Scrollbars updaten
				//

	if (!bInUpdateHeader)
	{
		UpdateScrollBars();		// Scrollbars nicht beim Scrollen neu setzen
		UpdateHeaderWidth();

		InterpretVisible();		// #69343# have everything calculated before painting
	}

	if (bHasHint)
		TestHintWindow();		// neu positionieren

	UpdateVarZoom();	//	update variable zoom types (after resizing GridWindows)

	if (aViewData.GetViewShell()->HasAccessibilityObjects())
		aViewData.GetViewShell()->BroadcastAccessibility(SfxSimpleHint(SC_HINT_ACC_WINDOWRESIZED));
}

void ScTabView::UpdateVarZoom()
{
	//	update variable zoom types

    SvxZoomType eZoomType = GetZoomType();
	if ( eZoomType != SVX_ZOOM_PERCENT && !bInZoomUpdate )
	{
		bInZoomUpdate = sal_True;
		const Fraction& rOldX = GetViewData()->GetZoomX();
		const Fraction& rOldY = GetViewData()->GetZoomY();
		long nOldPercent = ( rOldY.GetNumerator() * 100 ) / rOldY.GetDenominator();
		sal_uInt16 nNewZoom = CalcZoom( eZoomType, (sal_uInt16)nOldPercent );
		Fraction aNew( nNewZoom, 100 );

		if ( aNew != rOldX || aNew != rOldY )
		{
            SetZoom( aNew, aNew, sal_False );   // always separately per sheet
			PaintGrid();
			PaintTop();
			PaintLeft();
			aViewData.GetViewShell()->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM );
            aViewData.GetViewShell()->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
		}
		bInZoomUpdate = sal_False;
	}
}

void ScTabView::UpdateFixPos()
{
	sal_Bool bResize = sal_False;
	if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
		if (aViewData.UpdateFixX())
			bResize = sal_True;
	if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
		if (aViewData.UpdateFixY())
			bResize = sal_True;
	if (bResize)
		RepeatResize(sal_False);
}

void ScTabView::RepeatResize( sal_Bool bUpdateFix )
{
	if ( bUpdateFix )
	{
        ScSplitMode eHSplit = aViewData.GetHSplitMode();
        ScSplitMode eVSplit = aViewData.GetVSplitMode();

        // #i46796# UpdateFixX / UpdateFixY uses GetGridOffset, which requires the
        // outline windows to be available. So UpdateShow has to be called before
        // (also called from DoResize).
        if ( eHSplit == SC_SPLIT_FIX || eVSplit == SC_SPLIT_FIX )
            UpdateShow();

        if ( eHSplit == SC_SPLIT_FIX )
			aViewData.UpdateFixX();
        if ( eVSplit == SC_SPLIT_FIX )
			aViewData.UpdateFixY();
	}

	DoResize( aBorderPos, aFrameSize );

	//!	Border muss neu gesetzt werden ???
}

void ScTabView::GetBorderSize( SvBorder& rBorder, const Size& /* rSize */ )
{
	sal_Bool bScrollBars = aViewData.IsVScrollMode();
	sal_Bool bHeaders	 = aViewData.IsHeaderMode();
	sal_Bool bOutlMode	 = aViewData.IsOutlineMode();
	sal_Bool bHOutline	 = bOutlMode && lcl_HasColOutline(aViewData);
	sal_Bool bVOutline	 = bOutlMode && lcl_HasRowOutline(aViewData);
    sal_Bool bLayoutRTL  = aViewData.GetDocument()->IsLayoutRTL( aViewData.GetTabNo() );

	rBorder = SvBorder();

	if (bScrollBars)							// Scrollbars horizontal oder vertikal
	{
		rBorder.Right()  += aVScrollBottom.GetSizePixel().Width();
		rBorder.Bottom() += aHScrollLeft.GetSizePixel().Height();
	}

	// Outline-Controls
	if (bVOutline && pRowOutline[SC_SPLIT_BOTTOM])
		rBorder.Left() += pRowOutline[SC_SPLIT_BOTTOM]->GetDepthSize();
	if (bHOutline && pColOutline[SC_SPLIT_LEFT])
		rBorder.Top()  += pColOutline[SC_SPLIT_LEFT]->GetDepthSize();

	if (bHeaders)								// Spalten/Zeilen-Header
	{
		rBorder.Left() += pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width();
		rBorder.Top()  += pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height();
	}

    if ( bLayoutRTL )
        ::std::swap( rBorder.Left(), rBorder.Right() );
}

IMPL_LINK( ScTabView, TabBarResize, void*, EMPTYARG )
{
	sal_Bool bHScrollMode = aViewData.IsHScrollMode();

	//	Scrollbar-Einstellungen koennen vom Sfx ueberschrieben werden:
	SfxScrollingMode eMode = aViewData.GetViewShell()->GetScrollingMode();
	if ( eMode == SCROLLING_NO )
		bHScrollMode = sal_False;
	else if ( eMode == SCROLLING_YES || eMode == SCROLLING_AUTO )	//! Auto ???
		bHScrollMode = sal_True;

	if( bHScrollMode )
	{
		const long nOverlap = 0;	// ScrollBar::GetWindowOverlapPixel();
		long nSize = pTabControl->GetSplitSize();

		if (aViewData.GetHSplitMode() != SC_SPLIT_FIX)
		{
            long nMax = pHSplitter->GetPosPixel().X();
            if( pTabControl->IsEffectiveRTL() )
                nMax = pFrameWin->GetSizePixel().Width() - nMax;
            --nMax;
			if (nSize>nMax) nSize = nMax;
		}

		if ( nSize != pTabControl->GetSizePixel().Width() )
		{
			pTabControl->SetSizePixel( Size( nSize+nOverlap,
										pTabControl->GetSizePixel().Height() ) );
			RepeatResize();
		}
	}

	return 0;
}

void ScTabView::SetTabBarWidth( long nNewWidth )
{
	Size aSize = pTabControl->GetSizePixel();

	if ( aSize.Width() != nNewWidth )
	{
		aSize.Width() = nNewWidth;
		pTabControl->SetSizePixel( aSize );
	}
}

void ScTabView::SetRelTabBarWidth( double fRelTabBarWidth )
{
    if( (0.0 <= fRelTabBarWidth) && (fRelTabBarWidth <= 1.0) )
        if( long nFrameWidth = pFrameWin->GetSizePixel().Width() )
            SetTabBarWidth( static_cast< long >( fRelTabBarWidth * nFrameWidth + 0.5 ) );
}

void ScTabView::SetPendingRelTabBarWidth( double fRelTabBarWidth )
{
    mfPendingTabBarWidth = fRelTabBarWidth;
    SetRelTabBarWidth( fRelTabBarWidth );
}

long ScTabView::GetTabBarWidth() const
{
    return pTabControl->GetSizePixel().Width();
}

double ScTabView::GetRelTabBarWidth() const
{
    if( long nFrameWidth = pFrameWin->GetSizePixel().Width() )
        return static_cast< double >( GetTabBarWidth() ) / nFrameWidth;
    return 0.0;
}

double ScTabView::GetPendingRelTabBarWidth() const
{
    return mfPendingTabBarWidth;
}

Window* ScTabView::GetActiveWin()
{
	ScSplitPos ePos = aViewData.GetActivePart();
	DBG_ASSERT(pGridWin[ePos],"kein aktives Fenster");
	return pGridWin[ePos];
}

Window* ScTabView::GetWindowByPos( ScSplitPos ePos )
{
	return pGridWin[ePos];
}

void ScTabView::SetActivePointer( const Pointer& rPointer )
{
	for (sal_uInt16 i=0; i<4; i++)
		if (pGridWin[i])
			pGridWin[i]->SetPointer( rPointer );

/*	ScSplitPos ePos = aViewData.GetActivePart();
	if (pGridWin[ePos])
		pGridWin[ePos]->SetPointer( rPointer );
*/
}

//UNUSED2008-05  void ScTabView::SetActivePointer( const ResId& )
//UNUSED2008-05  {
//UNUSED2008-05      DBG_ERRORFILE( "keine Pointer mit ResId!" );
//UNUSED2008-05  }

void ScTabView::ActiveGrabFocus()
{
	ScSplitPos ePos = aViewData.GetActivePart();
	if (pGridWin[ePos])
		pGridWin[ePos]->GrabFocus();
}

//UNUSED2008-05  void ScTabView::ActiveCaptureMouse()
//UNUSED2008-05  {
//UNUSED2008-05      ScSplitPos ePos = aViewData.GetActivePart();
//UNUSED2008-05      if (pGridWin[ePos])
//UNUSED2008-05          pGridWin[ePos]->CaptureMouse();
//UNUSED2008-05  }
//UNUSED2008-05
//UNUSED2008-05  void ScTabView::ActiveReleaseMouse()
//UNUSED2008-05  {
//UNUSED2008-05      ScSplitPos ePos = aViewData.GetActivePart();
//UNUSED2008-05      if (pGridWin[ePos])
//UNUSED2008-05          pGridWin[ePos]->ReleaseMouse();
//UNUSED2008-05  }
//UNUSED2008-05
//UNUSED2008-05  Point ScTabView::ActivePixelToLogic( const Point& rDevicePoint )
//UNUSED2008-05  {
//UNUSED2008-05      ScSplitPos ePos = aViewData.GetActivePart();
//UNUSED2008-05      if (pGridWin[ePos])
//UNUSED2008-05          return pGridWin[ePos]->PixelToLogic(rDevicePoint);
//UNUSED2008-05      else
//UNUSED2008-05          return Point();
//UNUSED2008-05  }

ScSplitPos ScTabView::FindWindow( Window* pWindow ) const
{
	ScSplitPos eVal = SC_SPLIT_BOTTOMLEFT;		// Default
	for (sal_uInt16 i=0; i<4; i++)
		if ( pGridWin[i] == pWindow )
			eVal = (ScSplitPos) i;

	return eVal;
}

Point ScTabView::GetGridOffset() const
{
	Point aPos;

		// Groessen hier wie in DoResize

	sal_Bool bHeaders	 = aViewData.IsHeaderMode();
	sal_Bool bOutlMode	 = aViewData.IsOutlineMode();
	sal_Bool bHOutline	 = bOutlMode && lcl_HasColOutline(aViewData);
	sal_Bool bVOutline	 = bOutlMode && lcl_HasRowOutline(aViewData);

	// Outline-Controls
	if (bVOutline && pRowOutline[SC_SPLIT_BOTTOM])
		aPos.X() += pRowOutline[SC_SPLIT_BOTTOM]->GetDepthSize();
	if (bHOutline && pColOutline[SC_SPLIT_LEFT])
		aPos.Y() += pColOutline[SC_SPLIT_LEFT]->GetDepthSize();

	if (bHeaders)								// Spalten/Zeilen-Header
	{
		if (pRowBar[SC_SPLIT_BOTTOM])
			aPos.X() += pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width();
		if (pColBar[SC_SPLIT_LEFT])
			aPos.Y() += pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height();
	}

	return aPos;
}

// ---  Scroll-Bars  --------------------------------------------------------

sal_Bool ScTabView::ScrollCommand( const CommandEvent& rCEvt, ScSplitPos ePos )
{
	HideNoteMarker();

	sal_Bool bDone = sal_False;
	const CommandWheelData* pData = rCEvt.GetWheelData();
	if ( pData && pData->GetMode() == COMMAND_WHEEL_ZOOM )
	{
        if ( !aViewData.GetViewShell()->GetViewFrame()->GetFrame().IsInPlace() )
		{
			//	for ole inplace editing, the scale is defined by the visarea and client size
			//	and can't be changed directly

			const Fraction& rOldY = aViewData.GetZoomY();
			long nOld = (long)(( rOldY.GetNumerator() * 100 ) / rOldY.GetDenominator());
			long nNew = nOld;
			if ( pData->GetDelta() < 0 )
				nNew = Max( (long) MINZOOM, (long)( nOld - SC_DELTA_ZOOM ) );
			else
				nNew = Min( (long) MAXZOOM, (long)( nOld + SC_DELTA_ZOOM ) );

			if ( nNew != nOld )
			{
                // scroll wheel doesn't set the AppOptions default

                sal_Bool bSyncZoom = SC_MOD()->GetAppOptions().GetSynchronizeZoom();
                SetZoomType( SVX_ZOOM_PERCENT, bSyncZoom );
				Fraction aFract( nNew, 100 );
                SetZoom( aFract, aFract, bSyncZoom );
				PaintGrid();
				PaintTop();
				PaintLeft();
				aViewData.GetBindings().Invalidate( SID_ATTR_ZOOM );
                aViewData.GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
			}

			bDone = sal_True;
		}
	}
	else
	{
		ScHSplitPos eHPos = WhichH(ePos);
		ScVSplitPos eVPos = WhichV(ePos);
		ScrollBar* pHScroll = ( eHPos == SC_SPLIT_LEFT ) ? &aHScrollLeft : &aHScrollRight;
		ScrollBar* pVScroll = ( eVPos == SC_SPLIT_TOP )  ? &aVScrollTop  : &aVScrollBottom;
		if ( pGridWin[ePos] )
			bDone = pGridWin[ePos]->HandleScrollCommand( rCEvt, pHScroll, pVScroll );
	}
	return bDone;
}

IMPL_LINK( ScTabView, EndScrollHdl, ScrollBar*, pScroll )
{
	sal_Bool bOnlineScroll = sal_True;		//! Optionen

	if ( bDragging )
	{
		if ( bOnlineScroll )				// nur Ranges aktualisieren
			UpdateScrollBars();
		else
		{
			long nScrollMin = 0;		// RangeMin simulieren
			if ( aViewData.GetHSplitMode()==SC_SPLIT_FIX && pScroll == &aHScrollRight )
				nScrollMin = aViewData.GetFixPosX();
			if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == &aVScrollBottom )
				nScrollMin = aViewData.GetFixPosY();

			if ( pScroll == &aHScrollLeft || pScroll == &aHScrollRight )
			{
                sal_Bool bMirror = aViewData.GetDocument()->IsLayoutRTL( aViewData.GetTabNo() ) != Application::GetSettings().GetLayoutRTL();
				ScHSplitPos eWhich = (pScroll == &aHScrollLeft) ? SC_SPLIT_LEFT : SC_SPLIT_RIGHT;
                long nDelta = GetScrollBarPos( *pScroll, bMirror ) + nScrollMin - aViewData.GetPosX(eWhich);
				if (nDelta)	ScrollX( nDelta, eWhich );
			}
			else							// VScroll...
			{
				ScVSplitPos eWhich = (pScroll == &aVScrollTop) ? SC_SPLIT_TOP : SC_SPLIT_BOTTOM;
				long nDelta = GetScrollBarPos( *pScroll, sal_False ) + nScrollMin - aViewData.GetPosY(eWhich);
				if (nDelta) ScrollY( nDelta, eWhich );
			}
		}
		bDragging = sal_False;
	}
	return 0;
}

IMPL_LINK( ScTabView, ScrollHdl, ScrollBar*, pScroll )
{
	sal_Bool bOnlineScroll = sal_True;		//! Optionen

	sal_Bool bHoriz = ( pScroll == &aHScrollLeft || pScroll == &aHScrollRight );
	long nViewPos;
	if ( bHoriz )
		nViewPos = aViewData.GetPosX( (pScroll == &aHScrollLeft) ?
										SC_SPLIT_LEFT : SC_SPLIT_RIGHT );
	else
		nViewPos = aViewData.GetPosY( (pScroll == &aVScrollTop) ?
										SC_SPLIT_TOP : SC_SPLIT_BOTTOM );

    sal_Bool bLayoutRTL = aViewData.GetDocument()->IsLayoutRTL( aViewData.GetTabNo() );
    sal_Bool bMirror = bHoriz && (bLayoutRTL != Application::GetSettings().GetLayoutRTL());

	ScrollType eType = pScroll->GetType();
	if ( eType == SCROLL_DRAG )
	{
		if (!bDragging)
		{
			bDragging = sal_True;
			nPrevDragPos = nViewPos;
		}

		//	Scroll-Position anzeigen
		//	(nur QuickHelp, in der Statuszeile gibt es keinen Eintrag dafuer)

		if (Help::IsQuickHelpEnabled())
		{
            Size aSize = pScroll->GetSizePixel();

            /*  Convert scrollbar mouse position to screen position. If RTL
                mode of scrollbar differs from RTL mode of its parent, then the
                direct call to Window::OutputToNormalizedScreenPixel() will
                give unusable results, because calcualtion of screen position
                is based on parent orientation and expects equal orientation of
                the child position. Need to mirror mouse position before. */
            Point aMousePos = pScroll->GetPointerPosPixel();
            if( pScroll->IsRTLEnabled() != pScroll->GetParent()->IsRTLEnabled() )
                aMousePos.X() = aSize.Width() - aMousePos.X() - 1;
            aMousePos = pScroll->OutputToNormalizedScreenPixel( aMousePos );

            // convert top-left position of scrollbar to screen position
            Point aPos = pScroll->OutputToNormalizedScreenPixel( Point() );

            // get scrollbar scroll position for help text (row number/column name)
			long nScrollMin = 0;		// RangeMin simulieren
			if ( aViewData.GetHSplitMode()==SC_SPLIT_FIX && pScroll == &aHScrollRight )
				nScrollMin = aViewData.GetFixPosX();
			if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == &aVScrollBottom )
				nScrollMin = aViewData.GetFixPosY();
            long nScrollPos = GetScrollBarPos( *pScroll, bMirror ) + nScrollMin;

			String aHelpStr;
			Rectangle aRect;
			sal_uInt16 nAlign;
			if (bHoriz)
			{
				aHelpStr = ScGlobal::GetRscString(STR_COLUMN);
				aHelpStr += ' ';
				aHelpStr += ScColToAlpha((SCCOL) nScrollPos);

				aRect.Left() = aMousePos.X();
				aRect.Top()	 = aPos.Y() - 4;
				nAlign		 = QUICKHELP_BOTTOM|QUICKHELP_CENTER;
			}
			else
			{
				aHelpStr = ScGlobal::GetRscString(STR_ROW);
				aHelpStr += ' ';
				aHelpStr += String::CreateFromInt32(nScrollPos + 1);

                // show quicktext always inside sheet area
                aRect.Left() = bLayoutRTL ? (aPos.X() + aSize.Width() + 8) : (aPos.X() - 8);
				aRect.Top()	 = aMousePos.Y();
                nAlign       = (bLayoutRTL ? QUICKHELP_LEFT : QUICKHELP_RIGHT) | QUICKHELP_VCENTER;
			}
			aRect.Right() 	= aRect.Left();
			aRect.Bottom()	= aRect.Top();

			Help::ShowQuickHelp(pScroll->GetParent(), aRect, aHelpStr, nAlign);
		}
	}

	if ( bOnlineScroll || eType != SCROLL_DRAG )
	{
        if ( bMirror )
		{
			// change scroll type so visible/previous cells calculation below remains the same
			switch ( eType )
			{
				case SCROLL_LINEUP:		eType = SCROLL_LINEDOWN;	break;
				case SCROLL_LINEDOWN:	eType = SCROLL_LINEUP;		break;
				case SCROLL_PAGEUP:		eType = SCROLL_PAGEDOWN;	break;
				case SCROLL_PAGEDOWN:	eType = SCROLL_PAGEUP;		break;
                default:
                {
                    // added to avoid warnings
                }
			}
		}
		long nDelta = pScroll->GetDelta();
		switch ( eType )
		{
			case SCROLL_LINEUP:
				nDelta = -1;
				break;
			case SCROLL_LINEDOWN:
				nDelta = 1;
				break;
			case SCROLL_PAGEUP:
				if ( pScroll == &aHScrollLeft ) nDelta = -(long) aViewData.PrevCellsX( SC_SPLIT_LEFT );
				if ( pScroll == &aHScrollRight ) nDelta = -(long) aViewData.PrevCellsX( SC_SPLIT_RIGHT );
				if ( pScroll == &aVScrollTop ) nDelta = -(long) aViewData.PrevCellsY( SC_SPLIT_TOP );
				if ( pScroll == &aVScrollBottom ) nDelta = -(long) aViewData.PrevCellsY( SC_SPLIT_BOTTOM );
				if (nDelta==0) nDelta=-1;
				break;
			case SCROLL_PAGEDOWN:
				if ( pScroll == &aHScrollLeft ) nDelta = aViewData.VisibleCellsX( SC_SPLIT_LEFT );
				if ( pScroll == &aHScrollRight ) nDelta = aViewData.VisibleCellsX( SC_SPLIT_RIGHT );
				if ( pScroll == &aVScrollTop ) nDelta = aViewData.VisibleCellsY( SC_SPLIT_TOP );
				if ( pScroll == &aVScrollBottom ) nDelta = aViewData.VisibleCellsY( SC_SPLIT_BOTTOM );
				if (nDelta==0) nDelta=1;
				break;
			case SCROLL_DRAG:
				{
					//	nur in die richtige Richtung scrollen, nicht um ausgeblendete
					//	Bereiche herumzittern

					long nScrollMin = 0;		// RangeMin simulieren
					if ( aViewData.GetHSplitMode()==SC_SPLIT_FIX && pScroll == &aHScrollRight )
						nScrollMin = aViewData.GetFixPosX();
					if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == &aVScrollBottom )
						nScrollMin = aViewData.GetFixPosY();

                    long nScrollPos = GetScrollBarPos( *pScroll, bMirror ) + nScrollMin;
					nDelta = nScrollPos - nViewPos;
					if ( nScrollPos > nPrevDragPos )
					{
						if (nDelta<0) nDelta=0;
					}
					else if ( nScrollPos < nPrevDragPos )
					{
						if (nDelta>0) nDelta=0;
					}
					else
						nDelta = 0;
					nPrevDragPos = nScrollPos;
				}
				break;
            default:
            {
                // added to avoid warnings
            }
		}

		if (nDelta)
		{
			sal_Bool bUpdate = ( eType != SCROLL_DRAG );	// bei Drag die Ranges nicht aendern
			if ( bHoriz )
				ScrollX( nDelta, (pScroll == &aHScrollLeft) ? SC_SPLIT_LEFT : SC_SPLIT_RIGHT, bUpdate );
			else
				ScrollY( nDelta, (pScroll == &aVScrollTop) ? SC_SPLIT_TOP : SC_SPLIT_BOTTOM, bUpdate );
		}
	}

	return 0;
}

void ScTabView::ScrollX( long nDeltaX, ScHSplitPos eWhich, sal_Bool bUpdBars )
{
	sal_Bool bHasHint = ( pInputHintWindow != NULL );
	if (bHasHint)
		RemoveHintWindow();

	SCCOL nOldX = aViewData.GetPosX(eWhich);
	SCsCOL nNewX = static_cast<SCsCOL>(nOldX) + static_cast<SCsCOL>(nDeltaX);
	if ( nNewX < 0 )
	{
		nDeltaX -= nNewX;
		nNewX = 0;
	}
	if ( nNewX > MAXCOL )
	{
		nDeltaX -= nNewX - MAXCOL;
		nNewX = MAXCOL;
	}

	SCsCOL nDir = ( nDeltaX > 0 ) ? 1 : -1;
	ScDocument* pDoc = aViewData.GetDocument();
	SCTAB nTab = aViewData.GetTabNo();
    while ( pDoc->ColHidden(nNewX, nTab) &&
			nNewX+nDir >= 0 && nNewX+nDir <= MAXCOL )
        nNewX = sal::static_int_cast<SCsCOL>( nNewX + nDir );

	//	Fixierung

	if (aViewData.GetHSplitMode() == SC_SPLIT_FIX)
	{
		if (eWhich == SC_SPLIT_LEFT)
			nNewX = static_cast<SCsCOL>(nOldX);								// links immer stehenlassen
		else
		{
			SCsCOL nFixX = static_cast<SCsCOL>(aViewData.GetFixPosX());
			if (nNewX < nFixX)
				nNewX = nFixX;
		}
	}
	if (nNewX == static_cast<SCsCOL>(nOldX))
		return;

	HideAllCursors();

	if ( nNewX >= 0 && nNewX <= MAXCOL && nDeltaX )
	{
		SCCOL nTrackX = std::max( nOldX, static_cast<SCCOL>(nNewX) );

			//	Mit VCL wirkt Update() im Moment immer auf alle Fenster, beim Update
			//	nach dem Scrollen des GridWindow's wuerde darum der Col-/RowBar evtl.
			//	mit schon geaenderter Pos. gepainted werden -
			//	darum vorher einmal Update am Col-/RowBar

		if (pColBar[eWhich])
			pColBar[eWhich]->Update();

		long nOldPos = aViewData.GetScrPos( nTrackX, 0, eWhich ).X();
		aViewData.SetPosX( eWhich, static_cast<SCCOL>(nNewX) );
		long nDiff = aViewData.GetScrPos( nTrackX, 0, eWhich ).X() - nOldPos;

		if ( eWhich==SC_SPLIT_LEFT )
		{
			pGridWin[SC_SPLIT_BOTTOMLEFT]->ScrollPixel( nDiff, 0 );
			if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
				pGridWin[SC_SPLIT_TOPLEFT]->ScrollPixel( nDiff, 0 );
		}
		else
		{
			pGridWin[SC_SPLIT_BOTTOMRIGHT]->ScrollPixel( nDiff, 0 );
			if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
				pGridWin[SC_SPLIT_TOPRIGHT]->ScrollPixel( nDiff, 0 );
		}
		if (pColBar[eWhich]) 	 { pColBar[eWhich]->Scroll( nDiff,0 ); pColBar[eWhich]->Update(); }
		if (pColOutline[eWhich]) pColOutline[eWhich]->ScrollPixel( nDiff );
		if (bUpdBars)
			UpdateScrollBars();
	}

	if (nDeltaX==1 || nDeltaX==-1)
		pGridWin[aViewData.GetActivePart()]->Update();

	ShowAllCursors();

	SetNewVisArea();			// MapMode muss schon gesetzt sein

	if (bHasHint)
		TestHintWindow();		// neu positionieren
}

void ScTabView::ScrollY( long nDeltaY, ScVSplitPos eWhich, sal_Bool bUpdBars )
{
	sal_Bool bHasHint = ( pInputHintWindow != NULL );
	if (bHasHint)
		RemoveHintWindow();

	SCROW nOldY = aViewData.GetPosY(eWhich);
	SCsROW nNewY = static_cast<SCsROW>(nOldY) + static_cast<SCsROW>(nDeltaY);
	if ( nNewY < 0 )
	{
		nDeltaY -= nNewY;
		nNewY = 0;
	}
	if ( nNewY > MAXROW )
	{
		nDeltaY -= nNewY - MAXROW;
		nNewY = MAXROW;
	}

	SCsROW nDir = ( nDeltaY > 0 ) ? 1 : -1;
	ScDocument* pDoc = aViewData.GetDocument();
	SCTAB nTab = aViewData.GetTabNo();
    while ( pDoc->RowHidden(nNewY, nTab) &&
			nNewY+nDir >= 0 && nNewY+nDir <= MAXROW )
		nNewY += nDir;

	//	Fixierung

	if (aViewData.GetVSplitMode() == SC_SPLIT_FIX)
	{
		if (eWhich == SC_SPLIT_TOP)
			nNewY = static_cast<SCsROW>(nOldY);								// oben immer stehenlassen
		else
		{
			SCsROW nFixY = static_cast<SCsROW>(aViewData.GetFixPosY());
			if (nNewY < nFixY)
				nNewY = nFixY;
		}
	}
	if (nNewY == static_cast<SCsROW>(nOldY))
		return;

	HideAllCursors();

	if ( nNewY >= 0 && nNewY <= MAXROW && nDeltaY )
	{
		SCROW nTrackY = std::max( nOldY, static_cast<SCROW>(nNewY) );

		//	Zeilenkoepfe anpassen vor dem eigentlichen Scrolling, damit nicht
		//	doppelt gepainted werden muss
		//	PosY darf dann auch noch nicht umgesetzt sein, neuen Wert uebergeben
		SCROW nUNew = static_cast<SCROW>(nNewY);
		UpdateHeaderWidth( &eWhich, &nUNew );				// Zeilenkoepfe anpassen

		if (pRowBar[eWhich])
			pRowBar[eWhich]->Update();

		long nOldPos = aViewData.GetScrPos( 0, nTrackY, eWhich ).Y();
		aViewData.SetPosY( eWhich, static_cast<SCROW>(nNewY) );
		long nDiff = aViewData.GetScrPos( 0, nTrackY, eWhich ).Y() - nOldPos;

		if ( eWhich==SC_SPLIT_TOP )
		{
			pGridWin[SC_SPLIT_TOPLEFT]->ScrollPixel( 0, nDiff );
			if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE )
				pGridWin[SC_SPLIT_TOPRIGHT]->ScrollPixel( 0, nDiff );
		}
		else
		{
			pGridWin[SC_SPLIT_BOTTOMLEFT]->ScrollPixel( 0, nDiff );
			if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE )
				pGridWin[SC_SPLIT_BOTTOMRIGHT]->ScrollPixel( 0, nDiff );
		}
		if (pRowBar[eWhich])	 { pRowBar[eWhich]->Scroll( 0,nDiff ); pRowBar[eWhich]->Update(); }
		if (pRowOutline[eWhich]) pRowOutline[eWhich]->ScrollPixel( nDiff );
		if (bUpdBars)
			UpdateScrollBars();
	}

	if (nDeltaY==1 || nDeltaY==-1)
		pGridWin[aViewData.GetActivePart()]->Update();

	ShowAllCursors();

	SetNewVisArea();			// MapMode muss schon gesetzt sein

	if (bHasHint)
		TestHintWindow();		// neu positionieren
}

void ScTabView::ScrollLines( long nDeltaX, long nDeltaY )
{
	ScSplitPos eWhich = aViewData.GetActivePart();
	if (nDeltaX)
		ScrollX(nDeltaX,WhichH(eWhich));
	if (nDeltaY)
		ScrollY(nDeltaY,WhichV(eWhich));
}

SCROW lcl_LastVisible( ScViewData& rViewData )
{
	//	wenn am Dokumentende viele Zeilen ausgeblendet sind (welcher Trottel macht sowas?),
	//	soll dadurch nicht auf breite Zeilenkoepfe geschaltet werden
	//!	als Member ans Dokument ???

	ScDocument* pDoc = rViewData.GetDocument();
	SCTAB nTab = rViewData.GetTabNo();

	SCROW nVis = MAXROW;
	while ( nVis > 0 && pDoc->GetRowHeight( nVis, nTab ) == 0 )
		--nVis;
	return nVis;
}

void ScTabView::UpdateHeaderWidth( const ScVSplitPos* pWhich, const SCROW* pPosY )
{
	if ( !pRowBar[SC_SPLIT_BOTTOM] || MAXROW < 10000 )
		return;

	SCROW nEndPos = MAXROW;
    if ( !aViewData.GetViewShell()->GetViewFrame()->GetFrame().IsInPlace() )
	{
		//	fuer OLE Inplace immer MAXROW

		if ( pWhich && *pWhich == SC_SPLIT_BOTTOM && pPosY )
			nEndPos = *pPosY;
		else
			nEndPos = aViewData.GetPosY( SC_SPLIT_BOTTOM );
		nEndPos += aViewData.CellsAtY( nEndPos, 1, SC_SPLIT_BOTTOM, SC_SIZE_NONE );	// VisibleCellsY
		if (nEndPos > MAXROW)
			nEndPos = lcl_LastVisible( aViewData );

		if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
		{
			SCROW nTopEnd;
			if ( pWhich && *pWhich == SC_SPLIT_TOP && pPosY )
				nTopEnd = *pPosY;
			else
				nTopEnd = aViewData.GetPosY( SC_SPLIT_TOP );
			nTopEnd += aViewData.CellsAtY( nTopEnd, 1, SC_SPLIT_TOP, SC_SIZE_NONE );// VisibleCellsY
			if (nTopEnd > MAXROW)
				nTopEnd = lcl_LastVisible( aViewData );

			if ( nTopEnd > nEndPos )
				nEndPos = nTopEnd;
		}
	}

	long nSmall = pRowBar[SC_SPLIT_BOTTOM]->GetSmallWidth();
	long nBig   = pRowBar[SC_SPLIT_BOTTOM]->GetBigWidth();
	long nDiff  = nBig - nSmall;

	if (nEndPos>10000)
		nEndPos = 10000;
	else if (nEndPos<1)		// avoid extra step at 0 (when only one row is visible)
		nEndPos = 1;
	long nWidth = nBig - ( 10000 - nEndPos ) * nDiff / 10000;

	if ( nWidth != pRowBar[SC_SPLIT_BOTTOM]->GetWidth() && !bInUpdateHeader )
	{
		bInUpdateHeader = sal_True;

		pRowBar[SC_SPLIT_BOTTOM]->SetWidth( nWidth );
		if (pRowBar[SC_SPLIT_TOP])
			pRowBar[SC_SPLIT_TOP]->SetWidth( nWidth );

		RepeatResize();

		// auf VCL gibt's Update ohne Ende (jedes Update gilt fuer alle Fenster)
		//aCornerButton.Update();		// der bekommt sonst nie ein Update

		bInUpdateHeader = sal_False;
	}
}

inline void ShowHide( Window* pWin, sal_Bool bShow )
{
	DBG_ASSERT(pWin || !bShow, "Fenster ist nicht da");
	if (pWin)
		pWin->Show(bShow);
}

void ScTabView::UpdateShow()
{
	sal_Bool bHScrollMode = aViewData.IsHScrollMode();
	sal_Bool bVScrollMode = aViewData.IsVScrollMode();
	sal_Bool bTabMode	  = aViewData.IsTabMode();
	sal_Bool bOutlMode	  = aViewData.IsOutlineMode();
	sal_Bool bHOutline	  = bOutlMode && lcl_HasColOutline(aViewData);
	sal_Bool bVOutline	  = bOutlMode && lcl_HasRowOutline(aViewData);
	sal_Bool bHeader	  = aViewData.IsHeaderMode();

	sal_Bool bShowH = ( aViewData.GetHSplitMode() != SC_SPLIT_NONE );
	sal_Bool bShowV = ( aViewData.GetVSplitMode() != SC_SPLIT_NONE );

	//	Scrollbar-Einstellungen koennen vom Sfx ueberschrieben werden:
	SfxScrollingMode eMode = aViewData.GetViewShell()->GetScrollingMode();
	if ( eMode == SCROLLING_NO )
		bHScrollMode = bVScrollMode = sal_False;
	else if ( eMode == SCROLLING_YES || eMode == SCROLLING_AUTO )	//! Auto ???
		bHScrollMode = bVScrollMode = sal_True;

	if ( aViewData.GetDocShell()->IsPreview() )
		bHScrollMode = bVScrollMode = bTabMode = bHeader = bOutlMode = bHOutline = bVOutline = sal_False;

		//
		//	Windows anlegen
		//

	if (bShowH && !pGridWin[SC_SPLIT_BOTTOMRIGHT])
	{
		pGridWin[SC_SPLIT_BOTTOMRIGHT] = new ScGridWindow( pFrameWin, &aViewData, SC_SPLIT_BOTTOMRIGHT );
		DoAddWin( pGridWin[SC_SPLIT_BOTTOMRIGHT] );
	}
	if (bShowV && !pGridWin[SC_SPLIT_TOPLEFT])
	{
		pGridWin[SC_SPLIT_TOPLEFT] = new ScGridWindow( pFrameWin, &aViewData, SC_SPLIT_TOPLEFT );
		DoAddWin( pGridWin[SC_SPLIT_TOPLEFT] );
	}
	if (bShowH && bShowV && !pGridWin[SC_SPLIT_TOPRIGHT])
	{
		pGridWin[SC_SPLIT_TOPRIGHT] = new ScGridWindow( pFrameWin, &aViewData, SC_SPLIT_TOPRIGHT );
		DoAddWin( pGridWin[SC_SPLIT_TOPRIGHT] );
	}

	if (bHOutline && !pColOutline[SC_SPLIT_LEFT])
		pColOutline[SC_SPLIT_LEFT] = new ScOutlineWindow( pFrameWin, SC_OUTLINE_HOR, &aViewData, SC_SPLIT_BOTTOMLEFT );
	if (bShowH && bHOutline && !pColOutline[SC_SPLIT_RIGHT])
		pColOutline[SC_SPLIT_RIGHT] = new ScOutlineWindow( pFrameWin, SC_OUTLINE_HOR, &aViewData, SC_SPLIT_BOTTOMRIGHT );

	if (bVOutline && !pRowOutline[SC_SPLIT_BOTTOM])
		pRowOutline[SC_SPLIT_BOTTOM] = new ScOutlineWindow( pFrameWin, SC_OUTLINE_VER, &aViewData, SC_SPLIT_BOTTOMLEFT );
	if (bShowV && bVOutline && !pRowOutline[SC_SPLIT_TOP])
		pRowOutline[SC_SPLIT_TOP] = new ScOutlineWindow( pFrameWin, SC_OUTLINE_VER, &aViewData, SC_SPLIT_TOPLEFT );

	if (bShowH && bHeader && !pColBar[SC_SPLIT_RIGHT])
		pColBar[SC_SPLIT_RIGHT] = new ScColBar( pFrameWin, &aViewData, SC_SPLIT_RIGHT,
												&aHdrFunc, pHdrSelEng );
	if (bShowV && bHeader && !pRowBar[SC_SPLIT_TOP])
		pRowBar[SC_SPLIT_TOP] = new ScRowBar( pFrameWin, &aViewData, SC_SPLIT_TOP,
												&aHdrFunc, pHdrSelEng );

		//
		//	Windows anzeigen
		//

	ShowHide( &aHScrollLeft, bHScrollMode );
	ShowHide( &aHScrollRight, bShowH && bHScrollMode );
	ShowHide( &aVScrollBottom, bVScrollMode );
	ShowHide( &aVScrollTop, bShowV && bVScrollMode );
	ShowHide( &aScrollBarBox, bVScrollMode || bHScrollMode );

	ShowHide( pHSplitter, bHScrollMode || bShowH );			// immer angelegt
	ShowHide( pVSplitter, bVScrollMode || bShowV );
	ShowHide( pTabControl, bTabMode );

													// ab hier dynamisch angelegte

	ShowHide( pGridWin[SC_SPLIT_BOTTOMRIGHT], bShowH );
	ShowHide( pGridWin[SC_SPLIT_TOPLEFT], bShowV );
	ShowHide( pGridWin[SC_SPLIT_TOPRIGHT], bShowH && bShowV );

	ShowHide( pColOutline[SC_SPLIT_LEFT], bHOutline );
	ShowHide( pColOutline[SC_SPLIT_RIGHT], bShowH && bHOutline );

	ShowHide( pRowOutline[SC_SPLIT_BOTTOM], bVOutline );
	ShowHide( pRowOutline[SC_SPLIT_TOP], bShowV && bVOutline );

	ShowHide( pColBar[SC_SPLIT_RIGHT], bShowH && bHeader );
	ShowHide( pRowBar[SC_SPLIT_TOP], bShowV && bHeader );


	//!	neue Gridwindows eintragen
}

// ---  Splitter  --------------------------------------------------------

IMPL_LINK( ScTabView, SplitHdl, Splitter*, pSplitter )
{
	if ( pSplitter == pHSplitter )
		DoHSplit( pHSplitter->GetSplitPosPixel() );
	else
		DoVSplit( pVSplitter->GetSplitPosPixel() );

	if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX || aViewData.GetVSplitMode() == SC_SPLIT_FIX )
		FreezeSplitters( sal_True );

	DoResize( aBorderPos, aFrameSize );

	return 0;
}

void ScTabView::DoHSplit(long nSplitPos)
{
	//	nSplitPos is the real pixel position on the frame window,
	//	mirroring for RTL has to be done here.

	sal_Bool bLayoutRTL = aViewData.GetDocument()->IsLayoutRTL( aViewData.GetTabNo() );
	if ( bLayoutRTL )
		nSplitPos = pFrameWin->GetOutputSizePixel().Width() - nSplitPos - 1;

	long nMinPos;
	long nMaxPos;
	SCCOL nOldDelta;
	SCCOL nNewDelta;

	nMinPos = SPLIT_MARGIN;
	if ( pRowBar[SC_SPLIT_BOTTOM] && pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width() >= nMinPos )
		nMinPos = pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width() + 1;
	nMaxPos = aFrameSize.Width() - SPLIT_MARGIN;

	ScSplitMode aOldMode = aViewData.GetHSplitMode();
	ScSplitMode aNewMode = SC_SPLIT_NORMAL;

	aViewData.SetHSplitPos( nSplitPos );
	if ( nSplitPos < nMinPos || nSplitPos > nMaxPos )
		aNewMode = SC_SPLIT_NONE;

	aViewData.SetHSplitMode( aNewMode );

	if ( aNewMode != aOldMode )
	{
		UpdateShow();		// vor ActivatePart !!

		if ( aNewMode == SC_SPLIT_NONE )
		{
			if (aViewData.GetActivePart() == SC_SPLIT_TOPRIGHT)
				ActivatePart( SC_SPLIT_TOPLEFT );
			if (aViewData.GetActivePart() == SC_SPLIT_BOTTOMRIGHT)
				ActivatePart( SC_SPLIT_BOTTOMLEFT );
		}
		else
		{
			nOldDelta = aViewData.GetPosX( SC_SPLIT_LEFT );
//			aViewData.SetPosX( SC_SPLIT_LEFT, nOldDelta );
			long nLeftWidth = nSplitPos - pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width();
			if ( nLeftWidth < 0 ) nLeftWidth = 0;
			nNewDelta = nOldDelta + aViewData.CellsAtX( nOldDelta, 1, SC_SPLIT_LEFT,
							(sal_uInt16) nLeftWidth );
			if ( nNewDelta > MAXCOL )
				nNewDelta = MAXCOL;
			aViewData.SetPosX( SC_SPLIT_RIGHT, nNewDelta );
			if ( nNewDelta > aViewData.GetCurX() )
				ActivatePart( (WhichV(aViewData.GetActivePart()) == SC_SPLIT_BOTTOM) ?
					SC_SPLIT_BOTTOMLEFT : SC_SPLIT_TOPLEFT );
			else
				ActivatePart( (WhichV(aViewData.GetActivePart()) == SC_SPLIT_BOTTOM) ?
					SC_SPLIT_BOTTOMRIGHT : SC_SPLIT_TOPRIGHT );
		}

		//	#61410# Form-Layer muss den sichtbaren Ausschnitt aller Fenster kennen
		//	dafuer muss hier schon der MapMode stimmen
		for (sal_uInt16 i=0; i<4; i++)
			if (pGridWin[i])
				pGridWin[i]->SetMapMode( pGridWin[i]->GetDrawMapMode() );
		SetNewVisArea();

		PaintGrid();
		PaintTop();

		InvalidateSplit();
	}
}

void ScTabView::DoVSplit(long nSplitPos)
{
	long nMinPos;
	long nMaxPos;
	SCROW nOldDelta;
	SCROW nNewDelta;

	nMinPos = SPLIT_MARGIN;
	if ( pColBar[SC_SPLIT_LEFT] && pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height() >= nMinPos )
		nMinPos = pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height() + 1;
	nMaxPos = aFrameSize.Height() - SPLIT_MARGIN;

	ScSplitMode aOldMode = aViewData.GetVSplitMode();
	ScSplitMode aNewMode = SC_SPLIT_NORMAL;

	aViewData.SetVSplitPos( nSplitPos );
	if ( nSplitPos < nMinPos || nSplitPos > nMaxPos )
		aNewMode = SC_SPLIT_NONE;

	aViewData.SetVSplitMode( aNewMode );

	if ( aNewMode != aOldMode )
	{
		UpdateShow();		// vor ActivatePart !!

		if ( aNewMode == SC_SPLIT_NONE )
		{
			nOldDelta = aViewData.GetPosY( SC_SPLIT_TOP );
			aViewData.SetPosY( SC_SPLIT_BOTTOM, nOldDelta );

			if (aViewData.GetActivePart() == SC_SPLIT_TOPLEFT)
				ActivatePart( SC_SPLIT_BOTTOMLEFT );
			if (aViewData.GetActivePart() == SC_SPLIT_TOPRIGHT)
				ActivatePart( SC_SPLIT_BOTTOMRIGHT );
		}
		else
		{
			if ( aOldMode == SC_SPLIT_NONE )
				nOldDelta = aViewData.GetPosY( SC_SPLIT_BOTTOM );
			else
				nOldDelta = aViewData.GetPosY( SC_SPLIT_TOP );

			aViewData.SetPosY( SC_SPLIT_TOP, nOldDelta );
			long nTopHeight = nSplitPos - pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height();
			if ( nTopHeight < 0 ) nTopHeight = 0;
			nNewDelta = nOldDelta + aViewData.CellsAtY( nOldDelta, 1, SC_SPLIT_TOP,
							(sal_uInt16) nTopHeight );
			if ( nNewDelta > MAXROW )
				nNewDelta = MAXROW;
			aViewData.SetPosY( SC_SPLIT_BOTTOM, nNewDelta );
			if ( nNewDelta > aViewData.GetCurY() )
				ActivatePart( (WhichH(aViewData.GetActivePart()) == SC_SPLIT_LEFT) ?
					SC_SPLIT_TOPLEFT : SC_SPLIT_TOPRIGHT );
			else
				ActivatePart( (WhichH(aViewData.GetActivePart()) == SC_SPLIT_LEFT) ?
					SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT );
		}

		//	#61410# Form-Layer muss den sichtbaren Ausschnitt aller Fenster kennen
		//	dafuer muss hier schon der MapMode stimmen
		for (sal_uInt16 i=0; i<4; i++)
			if (pGridWin[i])
				pGridWin[i]->SetMapMode( pGridWin[i]->GetDrawMapMode() );
		SetNewVisArea();

		PaintGrid();
		PaintLeft();

		InvalidateSplit();
	}
}

Point ScTabView::GetInsertPos()
{
	ScDocument* pDoc = aViewData.GetDocument();
	SCCOL nCol = aViewData.GetCurX();
	SCROW nRow = aViewData.GetCurY();
	SCTAB nTab = aViewData.GetTabNo();
	long nPosX = 0;
	for (SCCOL i=0; i<nCol; i++)
		nPosX += pDoc->GetColWidth(i,nTab);
	nPosX = (long)(nPosX * HMM_PER_TWIPS);
	if ( pDoc->IsNegativePage( nTab ) )
		nPosX = -nPosX;
	long nPosY = (long) pDoc->GetRowHeight( 0, nRow-1, nTab);
	nPosY = (long)(nPosY * HMM_PER_TWIPS);
	return Point(nPosX,nPosY);
}

Point ScTabView::GetChartInsertPos( const Size& rSize, const ScRange& rCellRange )
{
    Point aInsertPos;
    const long nBorder = 100;   // leave 1mm for border
    long nNeededWidth = rSize.Width() + 2 * nBorder;
    long nNeededHeight = rSize.Height() + 2 * nBorder;

    // use the active window, or lower/right if frozen (as in CalcZoom)
    ScSplitPos eUsedPart = aViewData.GetActivePart();
    if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
        eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT;
    if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
        eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT;

    ScGridWindow* pWin = pGridWin[eUsedPart];
    DBG_ASSERT( pWin, "Window not found" );
    if (pWin)
    {
        ActivatePart( eUsedPart );

        //  get the visible rectangle in logic units

        MapMode aDrawMode = pWin->GetDrawMapMode();
        Rectangle aVisible( pWin->PixelToLogic( Rectangle( Point(0,0), pWin->GetOutputSizePixel() ), aDrawMode ) );

        ScDocument* pDoc = aViewData.GetDocument();
        SCTAB nTab = aViewData.GetTabNo();
        sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
        long nLayoutSign = bLayoutRTL ? -1 : 1;

        long nDocX = (long)( (double) pDoc->GetColOffset( MAXCOL + 1, nTab ) * HMM_PER_TWIPS ) * nLayoutSign;
        long nDocY = (long)( (double) pDoc->GetRowOffset( MAXROW + 1, nTab ) * HMM_PER_TWIPS );

        if ( aVisible.Left() * nLayoutSign > nDocX * nLayoutSign )
            aVisible.Left() = nDocX;
        if ( aVisible.Right() * nLayoutSign > nDocX * nLayoutSign )
            aVisible.Right() = nDocX;
        if ( aVisible.Top() > nDocY )
            aVisible.Top() = nDocY;
        if ( aVisible.Bottom() > nDocY )
            aVisible.Bottom() = nDocY;

        //  get the logic position of the selection

        Rectangle aSelection = pDoc->GetMMRect( rCellRange.aStart.Col(), rCellRange.aStart.Row(),
                                                rCellRange.aEnd.Col(), rCellRange.aEnd.Row(), nTab );

        long nLeftSpace = aSelection.Left() - aVisible.Left();
        long nRightSpace = aVisible.Right() - aSelection.Right();
        long nTopSpace = aSelection.Top() - aVisible.Top();
        long nBottomSpace = aVisible.Bottom() - aSelection.Bottom();

        bool bFitLeft = ( nLeftSpace >= nNeededWidth );
        bool bFitRight = ( nRightSpace >= nNeededWidth );

        if ( bFitLeft || bFitRight )
        {
            // first preference: completely left or right of the selection

            // if both fit, prefer left in RTL mode, right otherwise
            bool bPutLeft = bFitLeft && ( bLayoutRTL || !bFitRight );

            if ( bPutLeft )
                aInsertPos.X() = aSelection.Left() - nNeededWidth;
            else
                aInsertPos.X() = aSelection.Right() + 1;

            // align with top of selection (is moved again if it doesn't fit)
            aInsertPos.Y() = std::max( aSelection.Top(), aVisible.Top() );
        }
        else if ( nTopSpace >= nNeededHeight || nBottomSpace >= nNeededHeight )
        {
            // second preference: completely above or below the selection

            if ( nBottomSpace > nNeededHeight )             // bottom is preferred
                aInsertPos.Y() = aSelection.Bottom() + 1;
            else
                aInsertPos.Y() = aSelection.Top() - nNeededHeight;

            // align with (logic) left edge of selection (moved again if it doesn't fit)
            if ( bLayoutRTL )
                aInsertPos.X() = std::min( aSelection.Right(), aVisible.Right() ) - nNeededWidth + 1;
            else
                aInsertPos.X() = std::max( aSelection.Left(), aVisible.Left() );
        }
        else
        {
            // place to the (logic) right of the selection and move so it fits

            if ( bLayoutRTL )
                aInsertPos.X() = aSelection.Left() - nNeededWidth;
            else
                aInsertPos.X() = aSelection.Right() + 1;
            aInsertPos.Y() = std::max( aSelection.Top(), aVisible.Top() );
        }

        // move the position if the object doesn't fit in the screen

        Rectangle aCompareRect( aInsertPos, Size( nNeededWidth, nNeededHeight ) );
        if ( aCompareRect.Right() > aVisible.Right() )
            aInsertPos.X() -= aCompareRect.Right() - aVisible.Right();
        if ( aCompareRect.Bottom() > aVisible.Bottom() )
            aInsertPos.Y() -= aCompareRect.Bottom() - aVisible.Bottom();

        if ( aInsertPos.X() < aVisible.Left() )
            aInsertPos.X() = aVisible.Left();
        if ( aInsertPos.Y() < aVisible.Top() )
            aInsertPos.Y() = aVisible.Top();

        // nNeededWidth / nNeededHeight includes all borders - move aInsertPos to the
        // object position, inside the border

        aInsertPos.X() += nBorder;
        aInsertPos.Y() += nBorder;
    }
    return aInsertPos;
}

Point ScTabView::GetChartDialogPos( const Size& rDialogSize, const Rectangle& rLogicChart )
{
    // rDialogSize must be in pixels, rLogicChart in 1/100 mm. Return value is in pixels.

    Point aRet;

    // use the active window, or lower/right if frozen (as in CalcZoom)
    ScSplitPos eUsedPart = aViewData.GetActivePart();
    if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
        eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT;
    if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
        eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT;

    ScGridWindow* pWin = pGridWin[eUsedPart];
    DBG_ASSERT( pWin, "Window not found" );
    if (pWin)
    {
        MapMode aDrawMode = pWin->GetDrawMapMode();
        Rectangle aObjPixel = pWin->LogicToPixel( rLogicChart, aDrawMode );
        Rectangle aObjAbs( pWin->OutputToAbsoluteScreenPixel( aObjPixel.TopLeft() ),
                           pWin->OutputToAbsoluteScreenPixel( aObjPixel.BottomRight() ) );

        Rectangle aDesktop = pWin->GetDesktopRectPixel();
        Size aSpace = pWin->LogicToPixel( Size( 8, 12 ), MAP_APPFONT );

        ScDocument* pDoc = aViewData.GetDocument();
        SCTAB nTab = aViewData.GetTabNo();
        sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );

        bool bCenterHor = false;

        if ( aDesktop.Bottom() - aObjAbs.Bottom() >= rDialogSize.Height() + aSpace.Height() )
        {
            // first preference: below the chart

            aRet.Y() = aObjAbs.Bottom() + aSpace.Height();
            bCenterHor = true;
        }
        else if ( aObjAbs.Top() - aDesktop.Top() >= rDialogSize.Height() + aSpace.Height() )
        {
            // second preference: above the chart

            aRet.Y() = aObjAbs.Top() - rDialogSize.Height() - aSpace.Height();
            bCenterHor = true;
        }
        else
        {
            bool bFitLeft = ( aObjAbs.Left() - aDesktop.Left() >= rDialogSize.Width() + aSpace.Width() );
            bool bFitRight = ( aDesktop.Right() - aObjAbs.Right() >= rDialogSize.Width() + aSpace.Width() );

            if ( bFitLeft || bFitRight )
            {
                // if both fit, prefer right in RTL mode, left otherwise
                bool bPutRight = bFitRight && ( bLayoutRTL || !bFitLeft );
                if ( bPutRight )
                    aRet.X() = aObjAbs.Right() + aSpace.Width();
                else
                    aRet.X() = aObjAbs.Left() - rDialogSize.Width() - aSpace.Width();

                // center vertically
                aRet.Y() = aObjAbs.Top() + ( aObjAbs.GetHeight() - rDialogSize.Height() ) / 2;
            }
            else
            {
                // doesn't fit on any edge - put at the bottom of the screen
                aRet.Y() = aDesktop.Bottom() - rDialogSize.Height();
                bCenterHor = true;
            }
        }
        if ( bCenterHor )
            aRet.X() = aObjAbs.Left() + ( aObjAbs.GetWidth() - rDialogSize.Width() ) / 2;

        // limit to screen (centering might lead to invalid positions)
        if ( aRet.X() + rDialogSize.Width() - 1 > aDesktop.Right() )
            aRet.X() = aDesktop.Right() - rDialogSize.Width() + 1;
        if ( aRet.X() < aDesktop.Left() )
            aRet.X() = aDesktop.Left();
        if ( aRet.Y() + rDialogSize.Height() - 1 > aDesktop.Bottom() )
            aRet.Y() = aDesktop.Bottom() - rDialogSize.Height() + 1;
        if ( aRet.Y() < aDesktop.Top() )
            aRet.Y() = aDesktop.Top();
    }

    return aRet;
}

void ScTabView::LockModifiers( sal_uInt16 nModifiers )
{
	pSelEngine->LockModifiers( nModifiers );
	pHdrSelEng->LockModifiers( nModifiers );
}

sal_uInt16 ScTabView::GetLockedModifiers() const
{
	return pSelEngine->GetLockedModifiers();
}

Point ScTabView::GetMousePosPixel()
{
	Point aPos;
	ScGridWindow* pWin = (ScGridWindow*)GetActiveWin();

	if ( pWin )
		aPos = pWin->GetMousePosPixel();

	return aPos;
}

sal_Bool lcl_MouseIsOverWin( const Point& rScreenPosPixel, Window* pWin )
{
	if (pWin)
	{
		//	SPLIT_HANDLE_SIZE draufaddieren, damit das Einrasten genau
		//	auf dem Splitter nicht aussetzt

		Point aRel = pWin->NormalizedScreenToOutputPixel( rScreenPosPixel );
		Size aWinSize = pWin->GetOutputSizePixel();
		if ( aRel.X() >= 0 && aRel.X() < aWinSize.Width() + SPLIT_HANDLE_SIZE &&
				aRel.Y() >= 0 && aRel.Y() < aWinSize.Height() + SPLIT_HANDLE_SIZE )
			return sal_True;
	}
	return sal_False;
}

void ScTabView::SnapSplitPos( Point& rScreenPosPixel )
{
	sal_Bool bOverWin = sal_False;
	sal_uInt16 i;
	for (i=0; i<4; i++)
		if (lcl_MouseIsOverWin(rScreenPosPixel,pGridWin[i]))
			bOverWin = sal_True;

	if (!bOverWin)
		return;

	//	#74761# don't snap to cells if the scale will be modified afterwards
    if ( GetZoomType() != SVX_ZOOM_PERCENT )
		return;

	ScSplitPos ePos = SC_SPLIT_BOTTOMLEFT;
	if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
		ePos = SC_SPLIT_TOPLEFT;

	Window* pWin = pGridWin[ePos];
	if (!pWin)
	{
		DBG_ERROR("Window NULL");
		return;
	}

	Point aMouse = pWin->NormalizedScreenToOutputPixel( rScreenPosPixel );
	SCsCOL nPosX;
	SCsROW nPosY;
	//	#52949# bNextIfLarge=FALSE: nicht auf naechste Zelle, wenn ausserhalb des Fensters
	aViewData.GetPosFromPixel( aMouse.X(), aMouse.Y(), ePos, nPosX, nPosY, sal_True, sal_False, sal_False );
	sal_Bool bLeft;
	sal_Bool bTop;
	aViewData.GetMouseQuadrant( aMouse, ePos, nPosX, nPosY, bLeft, bTop );
	if (!bLeft)
		++nPosX;
	if (!bTop)
		++nPosY;
	aMouse = aViewData.GetScrPos( static_cast<SCCOL>(nPosX), static_cast<SCROW>(nPosY), ePos, sal_True );
	rScreenPosPixel = pWin->OutputToNormalizedScreenPixel( aMouse );
}

void ScTabView::FreezeSplitters( sal_Bool bFreeze )
{
	ScSplitMode eOldH = aViewData.GetHSplitMode();
	ScSplitMode eOldV = aViewData.GetVSplitMode();

	ScSplitPos ePos = SC_SPLIT_BOTTOMLEFT;
	if ( eOldV != SC_SPLIT_NONE )
		ePos = SC_SPLIT_TOPLEFT;
	Window* pWin = pGridWin[ePos];

	sal_Bool bLayoutRTL = aViewData.GetDocument()->IsLayoutRTL( aViewData.GetTabNo() );

	if ( bFreeze )
	{
		Point aWinStart = pWin->GetPosPixel();

		Point aSplit;
		SCsCOL nPosX;
		SCsROW nPosY;
		if (eOldH != SC_SPLIT_NONE || eOldV != SC_SPLIT_NONE)
		{
			if (eOldH != SC_SPLIT_NONE)
			{
				long nSplitPos = aViewData.GetHSplitPos();
				if ( bLayoutRTL )
					nSplitPos = pFrameWin->GetOutputSizePixel().Width() - nSplitPos - 1;
				aSplit.X() = nSplitPos - aWinStart.X();
			}
			if (eOldV != SC_SPLIT_NONE)
				aSplit.Y() = aViewData.GetVSplitPos() - aWinStart.Y();

			aViewData.GetPosFromPixel( aSplit.X(), aSplit.Y(), ePos, nPosX, nPosY );
			sal_Bool bLeft;
			sal_Bool bTop;
			aViewData.GetMouseQuadrant( aSplit, ePos, nPosX, nPosY, bLeft, bTop );
			if (!bLeft)
				++nPosX;
			if (!bTop)
				++nPosY;
		}
		else
		{
			nPosX = static_cast<SCsCOL>( aViewData.GetCurX());
			nPosY = static_cast<SCsROW>( aViewData.GetCurY());
		}

		SCCOL nLeftPos = aViewData.GetPosX(SC_SPLIT_LEFT);
		SCROW nTopPos = aViewData.GetPosY(SC_SPLIT_BOTTOM);
		SCCOL nRightPos = static_cast<SCCOL>(nPosX);
		SCROW nBottomPos = static_cast<SCROW>(nPosY);
		if (eOldH != SC_SPLIT_NONE)
			if (aViewData.GetPosX(SC_SPLIT_RIGHT) > nRightPos)
				nRightPos = aViewData.GetPosX(SC_SPLIT_RIGHT);
		if (eOldV != SC_SPLIT_NONE)
		{
			nTopPos = aViewData.GetPosY(SC_SPLIT_TOP);
			if (aViewData.GetPosY(SC_SPLIT_BOTTOM) > nBottomPos)
				nBottomPos = aViewData.GetPosY(SC_SPLIT_BOTTOM);
		}

		aSplit = aViewData.GetScrPos( static_cast<SCCOL>(nPosX), static_cast<SCROW>(nPosY), ePos, sal_True );
		if (nPosX > aViewData.GetPosX(SC_SPLIT_LEFT))		// (aSplit.X() > 0) doesn't work for RTL
		{
			long nSplitPos = aSplit.X() + aWinStart.X();
			if ( bLayoutRTL )
				nSplitPos = pFrameWin->GetOutputSizePixel().Width() - nSplitPos - 1;

			aViewData.SetHSplitMode( SC_SPLIT_FIX );
			aViewData.SetHSplitPos( nSplitPos );
			aViewData.SetFixPosX( nPosX );

			aViewData.SetPosX(SC_SPLIT_LEFT, nLeftPos);
			aViewData.SetPosX(SC_SPLIT_RIGHT, nRightPos);
		}
		else
			aViewData.SetHSplitMode( SC_SPLIT_NONE );
		if (aSplit.Y() > 0)
		{
			aViewData.SetVSplitMode( SC_SPLIT_FIX );
			aViewData.SetVSplitPos( aSplit.Y() + aWinStart.Y() );
			aViewData.SetFixPosY( nPosY );

			aViewData.SetPosY(SC_SPLIT_TOP, nTopPos);
			aViewData.SetPosY(SC_SPLIT_BOTTOM, nBottomPos);
		}
		else
			aViewData.SetVSplitMode( SC_SPLIT_NONE );
	}
	else						// Fixierung aufheben
	{
		if ( eOldH == SC_SPLIT_FIX )
			aViewData.SetHSplitMode( SC_SPLIT_NORMAL );
		if ( eOldV == SC_SPLIT_FIX )
			aViewData.SetVSplitMode( SC_SPLIT_NORMAL );
	}

	//	#61410# Form-Layer muss den sichtbaren Ausschnitt aller Fenster kennen
	//	dafuer muss hier schon der MapMode stimmen
	for (sal_uInt16 i=0; i<4; i++)
		if (pGridWin[i])
			pGridWin[i]->SetMapMode( pGridWin[i]->GetDrawMapMode() );
	SetNewVisArea();

	RepeatResize(sal_False);

	UpdateShow();
	PaintLeft();
	PaintTop();
	PaintGrid();

	//	SC_FOLLOW_NONE: only update active part
	AlignToCursor( aViewData.GetCurX(), aViewData.GetCurY(), SC_FOLLOW_NONE );
	UpdateAutoFillMark();

	InvalidateSplit();
}

void ScTabView::RemoveSplit()
{
	DoHSplit( 0 );
	DoVSplit( 0 );
	RepeatResize();
}

void ScTabView::SplitAtCursor()
{
	ScSplitPos ePos = SC_SPLIT_BOTTOMLEFT;
	if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
		ePos = SC_SPLIT_TOPLEFT;
	Window* pWin = pGridWin[ePos];
	Point aWinStart = pWin->GetPosPixel();

	SCCOL nPosX = aViewData.GetCurX();
	SCROW nPosY = aViewData.GetCurY();
	Point aSplit = aViewData.GetScrPos( nPosX, nPosY, ePos, sal_True );
	if ( nPosX > 0 )
		DoHSplit( aSplit.X() + aWinStart.X() );
	else
		DoHSplit( 0 );
	if ( nPosY > 0 )
		DoVSplit( aSplit.Y() + aWinStart.Y() );
	else
		DoVSplit( 0 );
	RepeatResize();
}

void ScTabView::SplitAtPixel( const Point& rPixel, sal_Bool bHor, sal_Bool bVer )		// fuer API
{
	//	Pixel ist auf die ganze View bezogen, nicht auf das erste GridWin

	if (bHor)
	{
		if ( rPixel.X() > 0 )
			DoHSplit( rPixel.X() );
		else
			DoHSplit( 0 );
	}
	if (bVer)
	{
		if ( rPixel.Y() > 0 )
			DoVSplit( rPixel.Y() );
		else
			DoVSplit( 0 );
	}
	RepeatResize();
}

void ScTabView::InvalidateSplit()
{
	SfxBindings& rBindings = aViewData.GetBindings();
	rBindings.Invalidate( SID_WINDOW_SPLIT );
	rBindings.Invalidate( SID_WINDOW_FIX );

	pHSplitter->SetFixed( aViewData.GetHSplitMode() == SC_SPLIT_FIX );
	pVSplitter->SetFixed( aViewData.GetVSplitMode() == SC_SPLIT_FIX );
}

void ScTabView::SetNewVisArea()
{
	//	#63854# fuer die Controls muss bei VisAreaChanged der Draw-MapMode eingestellt sein
	//	(auch wenn ansonsten der Edit-MapMode gesetzt ist)
	MapMode aOldMode[4];
	MapMode aDrawMode[4];
	sal_uInt16 i;
	for (i=0; i<4; i++)
		if (pGridWin[i])
		{
			aOldMode[i] = pGridWin[i]->GetMapMode();
			aDrawMode[i] = pGridWin[i]->GetDrawMapMode();
			if (aDrawMode[i] != aOldMode[i])
				pGridWin[i]->SetMapMode(aDrawMode[i]);
		}

	Window* pActive = pGridWin[aViewData.GetActivePart()];
	if (pActive)
		aViewData.GetViewShell()->VisAreaChanged(
			pActive->PixelToLogic(Rectangle(Point(),pActive->GetOutputSizePixel())) );
	if (pDrawView)
		pDrawView->VisAreaChanged();	// kein Window uebergeben -> alle Fenster

    UpdateAllOverlays();                // #i79909# with drawing MapMode set

	for (i=0; i<4; i++)
		if (pGridWin[i] && aDrawMode[i] != aOldMode[i])
        {
            pGridWin[i]->flushOverlayManager();     // #i79909# flush overlays before switching to edit MapMode
			pGridWin[i]->SetMapMode(aOldMode[i]);
        }

	SfxViewFrame* pViewFrame = aViewData.GetViewShell()->GetViewFrame();
	if (pViewFrame)
	{
		SfxFrame& rFrame = pViewFrame->GetFrame();
		com::sun::star::uno::Reference<com::sun::star::frame::XController> xController = rFrame.GetController();
		if (xController.is())
		{
			ScTabViewObj* pImp = ScTabViewObj::getImplementation( xController );
			if (pImp)
				pImp->VisAreaChanged();
		}
	}
	if (aViewData.GetViewShell()->HasAccessibilityObjects())
		aViewData.GetViewShell()->BroadcastAccessibility(SfxSimpleHint(SC_HINT_ACC_VISAREACHANGED));
}

sal_Bool ScTabView::HasPageFieldDataAtCursor() const
{
    ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()];
    SCCOL nCol = aViewData.GetCurX();
    SCROW nRow = aViewData.GetCurY();
    if (pWin)
        return pWin->GetDPFieldOrientation( nCol, nRow ) == sheet::DataPilotFieldOrientation_PAGE;

    return sal_False;
}

void ScTabView::StartDataSelect()
{
    ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()];
    SCCOL nCol = aViewData.GetCurX();
    SCROW nRow = aViewData.GetCurY();

    if (!pWin)
        return;

    switch (pWin->GetDPFieldOrientation(nCol, nRow))
    {
        case sheet::DataPilotFieldOrientation_PAGE:
            //  #i36598# If the cursor is on a page field's data cell,
            //  no meaningful input is possible anyway, so this function
            //  can be used to select a page field entry.
            pWin->LaunchPageFieldMenu( nCol, nRow );
        break;
        case sheet::DataPilotFieldOrientation_COLUMN:
        case sheet::DataPilotFieldOrientation_ROW:
            pWin->LaunchDPFieldMenu( nCol, nRow );
        break;
        default:
            pWin->DoAutoFilterMenue( nCol, nRow, sal_True );
    }
}

void ScTabView::EnableRefInput(sal_Bool bFlag)
{
	aHScrollLeft.EnableInput(bFlag);
	aHScrollRight.EnableInput(bFlag);
	aVScrollBottom.EnableInput(bFlag);
	aVScrollTop.EnableInput(bFlag);
	aScrollBarBox.EnableInput(bFlag);

	// ab hier dynamisch angelegte

	if(pTabControl!=NULL) pTabControl->EnableInput(bFlag,sal_True);

	if(pGridWin[SC_SPLIT_BOTTOMLEFT]!=NULL)
		pGridWin[SC_SPLIT_BOTTOMLEFT]->EnableInput(bFlag,sal_False);
	if(pGridWin[SC_SPLIT_BOTTOMRIGHT]!=NULL)
		pGridWin[SC_SPLIT_BOTTOMRIGHT]->EnableInput(bFlag,sal_False);
	if(pGridWin[SC_SPLIT_TOPLEFT]!=NULL)
		pGridWin[SC_SPLIT_TOPLEFT]->EnableInput(bFlag,sal_False);
	if(pGridWin[SC_SPLIT_TOPRIGHT]!=NULL)
		pGridWin[SC_SPLIT_TOPRIGHT]->EnableInput(bFlag,sal_False);
	if(pColBar[SC_SPLIT_RIGHT]!=NULL)
		pColBar[SC_SPLIT_RIGHT]->EnableInput(bFlag,sal_False);
	if(pRowBar[SC_SPLIT_TOP]!=NULL)
		pRowBar[SC_SPLIT_TOP]->EnableInput(bFlag,sal_False);
}



