/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * 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"



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

#define _SV_NOXSOUND

#define _BASE_DLGS_HXX
#define _BIGINT_HXX
#define _CACHESTR_HXX
#define _CONFIG_HXX
#define _CURSOR_HXX
#define _CTRLTOOL_HXX
#define _DLGCFG_HXX
#define _DYNARR_HXX
#define _EXTATTR_HXX
#define _FILDLG_HXX
#define _FONTDLG_HXX
#define _FRM3D_HXX
#define _INTRO_HXX
#define _ISETBWR_HXX
#define _NO_SVRTF_PARSER_HXX
#define _MACRODLG_HXX
#define _MODALDLG_HXX
#define _MOREBUTTON_HXX
#define _OUTLINER_HXX
#define _PVRWIN_HXX
#define _RULER_HXX
#define _SCRWIN_HXX
#define _SETBRW_HXX
#define _STDCTRL_HXX
#define _STDMENU_HXX
#define _TABBAR_HXX
#define _TREELIST_HXX
#define _VALUESET_HXX
#define _VCATTR_HXX
#define _VCBRW_HXX
#define _VCTRLS_HXX
#define _VCSBX_HXX
#define _VCONT_HXX
#define _VDRWOBJ_HXX

#define _PASSWD_HXX

#define _SFX_DOCFILE_HXX
#define _SFX_DOCINF_HXX
#define _SFX_DOCSH_HXX
#define _SFX_PRNMON_HXX
#define _SFX_RESMGR_HXX
#define _SFX_TEMPLDLG_HXX
#define _SFXBASIC_HXX
#define _SFXCTRLITEM
#define _SFXDLGCFG_HXX
#define _SFXFILEDLG_HXX
#define _SFXIPFRM_HXX
#define _SFX_MACRO_HXX
#define _SFXMNUITEM_HXX
#define _SFXMNUMGR_HXX
#define _SFXMULTISEL_HXX
#define _SFXMSGDESCR_HXX
#define _SFXMSGPOOL_HXX
#define _SFX_MINFITEM_HXX
#define _SFXOBJFACE_HXX
#define _SFXOBJFAC_HXX
#define _SFX_SAVEOPT_HXX
#define _SFXSTBITEM_HXX
#define _SFXSTBMGR_HXX
#define _SFXTBXCTRL_HXX
#define _SFXTBXMGR_HXX

#define _SI_HXX

#define _SVBOXITM_HXX
#define _SVCONTNR_HXX	  //

#define _SDR_NOTRANSFORM

#define _SVDRAG_HXX
#define _SVINCVW_HXX
#define _SVRTV_HXX
#define _SVTABBX_HXX
#define _SVTREEBOX_HXX
#define _SVTREELIST_HXX

#define _SVX_DAILDLL_HXX
#define _SVX_HYPHEN_HXX
#define _SVX_IMPGRF_HXX
#define _SVX_LAYCTRL_HXX
#define _SVX_OPTITEMS_HXX
#define _SVX_OPTGERL_HXX
#define _SVX_OPTSAVE_HXX
#define _SVX_OPTSPELL_HXX
#define _SVX_OPTPATH_HXX
#define _SVX_OPTLINGU_HXX
#define _SVX_RULER_HXX
#define _SVX_RULRITEM_HXX
#define _SVX_SELCTRL_HXX
#define _SVX_SPLWRAP_HXX
#define _SVX_SPLDLG_HXX
#define _SVX_STDDLG_HXX
#define _SVX_THESDLG_HXX

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

#include "scitems.hxx"
#include <svx/dbexch.hrc>
#include <svx/svdetc.hxx>
#include <svx/svditer.hxx>
#include <svx/svdoole2.hxx>
#include <svx/svdpage.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/docfile.hxx>
#include <svl/stritem.hxx>
#include <svl/ptitem.hxx>
#include <svl/urlbmk.hxx>
#include <sot/clsids.hxx>
#include <sot/formats.hxx>
#include <vcl/graph.hxx>
#include <vcl/virdev.hxx>
#include <vcl/msgbox.hxx>
#include <tools/urlobj.hxx>
#include <sot/exchange.hxx>
#include <memory>

#include "attrib.hxx"
#include "patattr.hxx"
#include "dociter.hxx"
#include "viewfunc.hxx"
#include "tabvwsh.hxx"
#include "docsh.hxx"
#include "docfunc.hxx"
#include "undoblk.hxx"
#include "refundo.hxx"
#include "globstr.hrc"
#include "global.hxx"
#include "transobj.hxx"
#include "drwtrans.hxx"
#include "rangenam.hxx"
#include "dbcolect.hxx"
#include "impex.hxx"			// Sylk-ID fuer CB
#include "chgtrack.hxx"
#include "waitoff.hxx"
#include "scmod.hxx"
#include "sc.hrc"
#include "inputopt.hxx"
#include "warnbox.hxx"
#include "drwlayer.hxx"
#include "editable.hxx"
#include "transobj.hxx"
#include "drwtrans.hxx"
#include "docuno.hxx"
#include "clipparam.hxx"
#include "undodat.hxx"
#include "drawview.hxx"

using namespace com::sun::star;

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


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

//	GlobalName der Writer-DocShell kommt jetzt aus comphelper/classids.hxx

//----------------------------------------------------------------------------
//		C U T

void ScViewFunc::CutToClip( ScDocument* pClipDoc, sal_Bool bIncludeObjects )
{
    UpdateInputLine();

    ScEditableTester aTester( this );
    if (!aTester.IsEditable())					// selection editable?
    {
        ErrorMessage( aTester.GetMessageId() );
        return;
    }

    ScRange aRange;								// zu loeschender Bereich
    if ( GetViewData()->GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
    {
        ScDocument* pDoc = GetViewData()->GetDocument();
        ScDocShell* pDocSh = GetViewData()->GetDocShell();
        ScMarkData& rMark = GetViewData()->GetMarkData();
        const sal_Bool bRecord(pDoc->IsUndoEnabled());					// Undo/Redo

        ScDocShellModificator aModificator( *pDocSh );

        if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )			// mark the range if not marked yet
        {
            DoneBlockMode();
            InitOwnBlockMode();
            rMark.SetMarkArea( aRange );
            MarkDataChanged();
        }

        CopyToClip( pClipDoc, sal_True, false, bIncludeObjects );			// Ab ins Clipboard

        ScAddress aOldEnd( aRange.aEnd );		// Zusammengefasste Zellen im Bereich?
        pDoc->ExtendMerge( aRange, sal_True );

        ScDocument* pUndoDoc = NULL;
        if ( bRecord )
        {
            pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
            pUndoDoc->InitUndoSelected( pDoc, rMark );
            // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
            ScRange aCopyRange = aRange;
            aCopyRange.aStart.SetTab(0);
            aCopyRange.aEnd.SetTab(pDoc->GetTableCount()-1);
            pDoc->CopyToDocument( aCopyRange, (IDF_ALL & ~IDF_OBJECTS) | IDF_NOCAPTIONS, false, pUndoDoc );
            pDoc->BeginDrawUndo();
        }

        sal_uInt16 nExtFlags = 0;
        pDocSh->UpdatePaintExt( nExtFlags, aRange );

        HideCursor();							// Cursor aendert sich !

        rMark.MarkToMulti();
        pDoc->DeleteSelection( IDF_ALL, rMark );
        if ( bIncludeObjects )
            pDoc->DeleteObjectsInSelection( rMark );
        rMark.MarkToSimple();

        if ( !AdjustRowHeight( aRange.aStart.Row(), aRange.aEnd.Row() ) )
            pDocSh->PostPaint( aRange, PAINT_GRID, nExtFlags );

        if ( bRecord )							// erst jetzt ist Draw-Undo verfuegbar
            pDocSh->GetUndoManager()->AddUndoAction(
                new ScUndoCut( pDocSh, aRange, aOldEnd, rMark, pUndoDoc ) );

        aModificator.SetDocumentModified();
        ShowCursor();							// Cursor aendert sich !
        pDocSh->UpdateOle(GetViewData());

        CellContentChanged();
    }
    else
        ErrorMessage( STR_NOMULTISELECT );
}


//----------------------------------------------------------------------------
//		C O P Y

sal_Bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, sal_Bool bCut, sal_Bool bApi, sal_Bool bIncludeObjects, sal_Bool bStopEdit )
{
    sal_Bool bDone = false;
    if ( bStopEdit )
        UpdateInputLine();

    ScRange aRange;
    ScMarkType eMarkType = GetViewData()->GetSimpleArea( aRange );
    ScDocument* pDoc = GetViewData()->GetDocument();
    ScMarkData& rMark = GetViewData()->GetMarkData();
    if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
    {
        if ( !pDoc->HasSelectedBlockMatrixFragment(
                        aRange.aStart.Col(), aRange.aStart.Row(),
                        aRange.aEnd.Col(),   aRange.aEnd.Row(),
                        rMark ) )
        {
            sal_Bool bSysClip = false;
            if ( !pClipDoc )									// no clip doc specified
            {
                pClipDoc = new ScDocument( SCDOCMODE_CLIP );	// create one (deleted by ScTransferObj)
                bSysClip = sal_True;								// and copy into system
            }

            if ( !bCut )
            {
                ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
                if ( pChangeTrack )
                    pChangeTrack->ResetLastCut();	// kein CutMode mehr
            }

            if ( bSysClip && bIncludeObjects )
            {
                sal_Bool bAnyOle = pDoc->HasOLEObjectsInArea( aRange, &rMark );
                // update ScGlobal::pDrawClipDocShellRef
                ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
            }

            ScClipParam aClipParam(aRange, bCut);
            aClipParam.setSourceDocID( pDoc->GetDocumentID() );
            pDoc->CopyToClip(aClipParam, pClipDoc, &rMark, false, false, bIncludeObjects);

            if ( pDoc && pClipDoc )
            {
                ScDrawLayer* pDrawLayer = pClipDoc->GetDrawLayer();
                if ( pDrawLayer )
                {
                    ScClipParam& rClipParam = pClipDoc->GetClipParam();
                    ScRangeListVector& rRangesVector = rClipParam.maProtectedChartRangesVector;
                    SCTAB nTabCount = pClipDoc->GetTableCount();
                    for ( SCTAB nTab = 0; nTab < nTabCount; ++nTab )
                    {
                        SdrPage* pPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
                        if ( pPage )
                        {
                            ScChartHelper::FillProtectedChartRangesVector( rRangesVector, pDoc, pPage );
                        }
                    }
                }
            }

            if (bSysClip)
            {
                ScDrawLayer::SetGlobalDrawPersist(NULL);

                ScGlobal::SetClipDocName( pDoc->GetDocumentShell()->GetTitle( SFX_TITLE_FULLNAME ) );
            }
            pClipDoc->ExtendMerge( aRange, sal_True );

            if (bSysClip)
            {
                ScDocShell* pDocSh = GetViewData()->GetDocShell();
                TransferableObjectDescriptor aObjDesc;
                pDocSh->FillTransferableObjectDescriptor( aObjDesc );
                aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
                // maSize is set in ScTransferObj ctor

                ScTransferObj* pTransferObj = new ScTransferObj( pClipDoc, aObjDesc );
                uno::Reference<datatransfer::XTransferable> xTransferable( pTransferObj );

                if ( ScGlobal::pDrawClipDocShellRef )
                {
                    SfxObjectShellRef aPersistRef( &(*ScGlobal::pDrawClipDocShellRef) );
                    pTransferObj->SetDrawPersist( aPersistRef );	// keep persist for ole objects alive
                }

                pTransferObj->CopyToClipboard( GetActiveWin() );	// system clipboard
                SC_MOD()->SetClipObject( pTransferObj, NULL );		// internal clipboard
            }

            bDone = sal_True;
        }
        else
        {
            if (!bApi)
                ErrorMessage(STR_MATRIXFRAGMENTERR);
        }
    }
    else if (eMarkType == SC_MARK_MULTI)
    {
        bool bSuccess = false;
        ScClipParam aClipParam;
        aClipParam.mbCutMode = false;
        rMark.MarkToSimple();
        rMark.FillRangeListWithMarks(&aClipParam.maRanges, false);

        do
        {
            if (bCut)
                // We con't support cutting of multi-selections.
                break;

            if (pClipDoc)
                // TODO: What's this for?
                break;

            ::std::auto_ptr<ScDocument> pDocClip(new ScDocument(SCDOCMODE_CLIP));

            // Check for geometrical feasibility of the ranges.
            bool bValidRanges = true;
            ScRange* p = aClipParam.maRanges.front();
            SCCOL nPrevColDelta = 0;
            SCROW nPrevRowDelta = 0;
            SCCOL nPrevCol = p->aStart.Col();
            SCROW nPrevRow = p->aStart.Row();
            SCCOL nPrevColSize = p->aEnd.Col() - p->aStart.Col() + 1;
            SCROW nPrevRowSize = p->aEnd.Row() - p->aStart.Row() + 1;
            for ( size_t i = 1; i < aClipParam.maRanges.size(); ++i )
            {
                p = aClipParam.maRanges[i];
                if (pDoc->HasSelectedBlockMatrixFragment(
                    p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), rMark))
                {
                    if (!bApi)
                        ErrorMessage(STR_MATRIXFRAGMENTERR);
                    return false;
                }

                SCCOL nColDelta = p->aStart.Col() - nPrevCol;
                SCROW nRowDelta = p->aStart.Row() - nPrevRow;

                if ((nColDelta && nRowDelta) || (nPrevColDelta && nRowDelta) || (nPrevRowDelta && nColDelta))
                {
                    bValidRanges = false;
                    break;
                }

                if (aClipParam.meDirection == ScClipParam::Unspecified)
                {
                    if (nColDelta)
                        aClipParam.meDirection = ScClipParam::Column;
                    if (nRowDelta)
                        aClipParam.meDirection = ScClipParam::Row;
                }

                SCCOL nColSize = p->aEnd.Col() - p->aStart.Col() + 1;
                SCROW nRowSize = p->aEnd.Row() - p->aStart.Row() + 1;

                if (aClipParam.meDirection == ScClipParam::Column && nRowSize != nPrevRowSize)
                {
                    // column-oriented ranges must have identical row size.
                    bValidRanges = false;
                    break;
                }
                if (aClipParam.meDirection == ScClipParam::Row && nColSize != nPrevColSize)
                {
                    // likewise, row-oriented ranges must have identical
                    // column size.
                    bValidRanges = false;
                    break;
                }

                nPrevCol = p->aStart.Col();
                nPrevRow = p->aStart.Row();
                nPrevColDelta = nColDelta;
                nPrevRowDelta = nRowDelta;
                nPrevColSize  = nColSize;
                nPrevRowSize  = nRowSize;
            }
            if (!bValidRanges)
                break;

            pDoc->CopyToClip(aClipParam, pDocClip.get(), &rMark, false, false, bIncludeObjects);

            ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
            if ( pChangeTrack )
                pChangeTrack->ResetLastCut();	// kein CutMode mehr

            {
                ScDocShell* pDocSh = GetViewData()->GetDocShell();
                TransferableObjectDescriptor aObjDesc;
                pDocSh->FillTransferableObjectDescriptor( aObjDesc );
                aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
                // maSize is set in ScTransferObj ctor

                ScTransferObj* pTransferObj = new ScTransferObj( pDocClip.release(), aObjDesc );
                uno::Reference<datatransfer::XTransferable> xTransferable( pTransferObj );

                if ( ScGlobal::pDrawClipDocShellRef )
                {
                    SfxObjectShellRef aPersistRef( &(*ScGlobal::pDrawClipDocShellRef) );
                    pTransferObj->SetDrawPersist( aPersistRef );	// keep persist for ole objects alive
                }

                pTransferObj->CopyToClipboard( GetActiveWin() );	// system clipboard
                SC_MOD()->SetClipObject( pTransferObj, NULL );		// internal clipboard
            }

            bSuccess = true;
        }
        while (false);

        if (!bSuccess && !bApi)
            ErrorMessage(STR_NOMULTISELECT);

        bDone = bSuccess;
    }
    else
    {
        if (!bApi)
            ErrorMessage(STR_NOMULTISELECT);
    }

    return bDone;
}

// Copy the content of the Range into clipboard. Adding this method for VBA API: Range.Copy().
sal_Bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, const ScRange& rRange, sal_Bool bCut, sal_Bool bApi, sal_Bool bIncludeObjects, sal_Bool bStopEdit )
{
    sal_Bool bDone = false;
    if ( bStopEdit )
        UpdateInputLine();

    ScRange aRange = rRange;
    ScDocument* pDoc = GetViewData()->GetDocument();
    if ( pDoc && !pDoc->HasSelectedBlockMatrixFragment( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() ) )
    {
        sal_Bool bSysClip = false;
        if ( !pClipDoc )
        {
            // Create one (deleted by ScTransferObj).
            pClipDoc = new ScDocument( SCDOCMODE_CLIP );
            bSysClip = true;
        }
        if ( !bCut )
        {
            ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
            if ( pChangeTrack )
                pChangeTrack->ResetLastCut();
        }

        if ( bSysClip && bIncludeObjects )
        {
            sal_Bool bAnyOle = pDoc->HasOLEObjectsInArea( aRange );
            // Update ScGlobal::pDrawClipDocShellRef.
            ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
        }

        ScClipParam aClipParam( aRange, bCut );
        pDoc->CopyToClip4VBA( aClipParam, pClipDoc, false, bIncludeObjects );
        if ( bSysClip )
        {
            ScDrawLayer::SetGlobalDrawPersist(NULL);
            ScGlobal::SetClipDocName( pDoc->GetDocumentShell()->GetTitle( SFX_TITLE_FULLNAME ) );
        }
        pClipDoc->ExtendMerge( aRange, true );

        if ( bSysClip )
        {
            ScDocShell* pDocSh = GetViewData()->GetDocShell();
            TransferableObjectDescriptor aObjDesc;
            pDocSh->FillTransferableObjectDescriptor( aObjDesc );
            aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();

            ScTransferObj* pTransferObj = new ScTransferObj( pClipDoc, aObjDesc );
            uno::Reference<datatransfer::XTransferable> xTransferable( pTransferObj );
            if ( ScGlobal::pDrawClipDocShellRef )
            {
                SfxObjectShellRef aPersistRef( &(*ScGlobal::pDrawClipDocShellRef) );
                pTransferObj->SetDrawPersist( aPersistRef );
            }
            pTransferObj->CopyToClipboard( GetActiveWin() );
            SC_MOD()->SetClipObject( pTransferObj, NULL );
        }

        bDone = true;
    }
    else
    {
        if ( !bApi )
            ErrorMessage(STR_MATRIXFRAGMENTERR);
    }

    return bDone;
}

ScTransferObj* ScViewFunc::CopyToTransferable()
{
    ScRange aRange;
    if ( GetViewData()->GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
    {
        ScDocument* pDoc = GetViewData()->GetDocument();
        ScMarkData& rMark = GetViewData()->GetMarkData();
        if ( !pDoc->HasSelectedBlockMatrixFragment(
                        aRange.aStart.Col(), aRange.aStart.Row(),
                        aRange.aEnd.Col(),   aRange.aEnd.Row(),
                        rMark ) )
        {
            ScDocument *pClipDoc = new ScDocument( SCDOCMODE_CLIP );    // create one (deleted by ScTransferObj)

            sal_Bool bAnyOle = pDoc->HasOLEObjectsInArea( aRange, &rMark );
            ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );

            ScClipParam aClipParam(aRange, false);
            pDoc->CopyToClip(aClipParam, pClipDoc, &rMark, false, false, true);

            ScDrawLayer::SetGlobalDrawPersist(NULL);
            pClipDoc->ExtendMerge( aRange, sal_True );

            ScDocShell* pDocSh = GetViewData()->GetDocShell();
            TransferableObjectDescriptor aObjDesc;
            pDocSh->FillTransferableObjectDescriptor( aObjDesc );
            aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
            ScTransferObj* pTransferObj = new ScTransferObj( pClipDoc, aObjDesc );
            return pTransferObj;
        }
    }

    return NULL;
}

//----------------------------------------------------------------------------
//		P A S T E

void ScViewFunc::PasteDraw()
{
    ScViewData* pViewData = GetViewData();
    SCCOL nPosX = pViewData->GetCurX();
    SCROW nPosY = pViewData->GetCurY();
    Window* pWin = GetActiveWin();
    Point aPos = pWin->PixelToLogic( pViewData->GetScrPos( nPosX, nPosY,
                                     pViewData->GetActivePart() ) );
    ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard( pWin );
    if (pDrawClip)
        PasteDraw( aPos, pDrawClip->GetModel(), false,
            pDrawClip->GetSourceDocID() == pViewData->GetDocument()->GetDocumentID() );
}

void ScViewFunc::PasteFromSystem()
{
    UpdateInputLine();

    Window* pWin = GetActiveWin();
    ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard( pWin );
    ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard( pWin );

    if (pOwnClip)
    {
        // keep a reference in case the clipboard is changed during PasteFromClip
        uno::Reference<datatransfer::XTransferable> aOwnClipRef( pOwnClip );
        PasteFromClip( IDF_ALL, pOwnClip->GetDocument(),
                        PASTE_NOFUNC, false, false, false, INS_NONE, IDF_NONE,
                        sal_True );		// allow warning dialog
    }
    else if (pDrawClip)
        PasteDraw();
    else
    {
        TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );

        {
            sal_uLong nBiff8 = SotExchange::RegisterFormatName(
                    String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Biff8")));
            sal_uLong nBiff5 = SotExchange::RegisterFormatName(
                    String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Biff5")));

                //	als erstes SvDraw-Model, dann Grafik
                //	(Grafik darf nur bei einzelner Grafik drinstehen)

            if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_DRAWING ))
            {
                // special case for tables from drawing
                if( aDataHelper.HasFormat( SOT_FORMAT_RTF ) )
                {
                    PasteFromSystem( FORMAT_RTF );
                }
                else
                {
                    PasteFromSystem( SOT_FORMATSTR_ID_DRAWING );
                }
            }
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_SVXB ))
                PasteFromSystem( SOT_FORMATSTR_ID_SVXB );
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE ))
            {
                //	If it's a Writer object, insert RTF instead of OLE

                //	Else, if the class id is all-zero, and SYLK is available,
                //	it probably is spreadsheet cells that have been put
                //	on the clipboard by OOo, so use the SYLK. (fdo#31077)

                sal_Bool bDoRtf = false;
                TransferableObjectDescriptor aObjDesc;
                if( aDataHelper.GetTransferableObjectDescriptor( SOT_FORMATSTR_ID_OBJECTDESCRIPTOR, aObjDesc ) )
                {
                    bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
                                 aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
                               && aDataHelper.HasFormat( SOT_FORMAT_RTF ) );
                }
                if ( bDoRtf )
                    PasteFromSystem( FORMAT_RTF );
                else if ( aObjDesc.maClassName == SvGlobalName( 0,0,0,0,0,0,0,0,0,0,0 )
                          && aDataHelper.HasFormat( SOT_FORMATSTR_ID_SYLK ))
                    PasteFromSystem( SOT_FORMATSTR_ID_SYLK );
                else
                    PasteFromSystem( SOT_FORMATSTR_ID_EMBED_SOURCE );
            }
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE ))
                PasteFromSystem( SOT_FORMATSTR_ID_LINK_SOURCE );
            // the following format can not affect scenario from #89579#
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE ))
                PasteFromSystem( SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE );
            // FORMAT_PRIVATE no longer here (can't work if pOwnClip is NULL)
            else if (aDataHelper.HasFormat(nBiff8))      // before xxx_OLE formats
                PasteFromSystem(nBiff8);
            else if (aDataHelper.HasFormat(nBiff5))
                PasteFromSystem(nBiff5);
            else if (aDataHelper.HasFormat(FORMAT_RTF))
                PasteFromSystem(FORMAT_RTF);
            else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_HTML))
                PasteFromSystem(SOT_FORMATSTR_ID_HTML);
            else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_HTML_SIMPLE))
                PasteFromSystem(SOT_FORMATSTR_ID_HTML_SIMPLE);
            else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_SYLK))
                PasteFromSystem(SOT_FORMATSTR_ID_SYLK);
            else if (aDataHelper.HasFormat(FORMAT_STRING))
                PasteFromSystem(FORMAT_STRING);
            else if (aDataHelper.HasFormat(FORMAT_GDIMETAFILE))
                PasteFromSystem(FORMAT_GDIMETAFILE);
            else if (aDataHelper.HasFormat(FORMAT_BITMAP))
                PasteFromSystem(FORMAT_BITMAP);
            // xxx_OLE formats come last, like in SotExchange tables
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE_OLE ))
                PasteFromSystem( SOT_FORMATSTR_ID_EMBED_SOURCE_OLE );
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE_OLE ))
                PasteFromSystem( SOT_FORMATSTR_ID_LINK_SOURCE_OLE );
        }
    }
    //	keine Fehlermeldung, weil SID_PASTE in der idl das FastCall-Flag hat,
    //	also auch gerufen wird, wenn nichts im Clipboard steht (#42531#)
}

void ScViewFunc::PasteFromTransferable( const uno::Reference<datatransfer::XTransferable>& rxTransferable )
{
    ScTransferObj *pOwnClip=0;
    ScDrawTransferObj *pDrawClip=0;
    uno::Reference<lang::XUnoTunnel> xTunnel( rxTransferable, uno::UNO_QUERY );
    if ( xTunnel.is() )
    {
        sal_Int64 nHandle = xTunnel->getSomething( ScTransferObj::getUnoTunnelId() );
        if ( nHandle )
            pOwnClip = (ScTransferObj*) (sal_IntPtr) nHandle;
        else
        {
            nHandle = xTunnel->getSomething( ScDrawTransferObj::getUnoTunnelId() );
            if ( nHandle )
                pDrawClip = (ScDrawTransferObj*) (sal_IntPtr) nHandle;
        }
    }

    if (pOwnClip)
    {
        PasteFromClip( IDF_ALL, pOwnClip->GetDocument(),
                        PASTE_NOFUNC, false, false, false, INS_NONE, IDF_NONE,
                        sal_True );		// allow warning dialog
    }
    else if (pDrawClip)
    {
        ScViewData* pViewData = GetViewData();
        SCCOL nPosX = pViewData->GetCurX();
        SCROW nPosY = pViewData->GetCurY();
        Window* pWin = GetActiveWin();
        Point aPos = pWin->PixelToLogic( pViewData->GetScrPos( nPosX, nPosY, pViewData->GetActivePart() ) );
        PasteDraw( aPos, pDrawClip->GetModel(), false, pDrawClip->GetSourceDocID() == pViewData->GetDocument()->GetDocumentID() );
    }
    else
    {
            TransferableDataHelper aDataHelper( rxTransferable );
        {
            sal_uLong nBiff8 = SotExchange::RegisterFormatName(
                    String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Biff8")));
            sal_uLong nBiff5 = SotExchange::RegisterFormatName(
                    String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Biff5")));
            sal_uLong nFormatId = 0;
                //	als erstes SvDraw-Model, dann Grafik
                //	(Grafik darf nur bei einzelner Grafik drinstehen)

            if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_DRAWING ))
                nFormatId = SOT_FORMATSTR_ID_DRAWING;
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_SVXB ))
                nFormatId = SOT_FORMATSTR_ID_SVXB;
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE ))
            {
                //	If it's a Writer object, insert RTF instead of OLE
                sal_Bool bDoRtf = false;
                TransferableObjectDescriptor aObjDesc;
                if( aDataHelper.GetTransferableObjectDescriptor( SOT_FORMATSTR_ID_OBJECTDESCRIPTOR, aObjDesc ) )
                {
                    bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
                                 aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
                               && aDataHelper.HasFormat( SOT_FORMAT_RTF ) );
                }
                if ( bDoRtf )
                    nFormatId = FORMAT_RTF;
                else
                    nFormatId = SOT_FORMATSTR_ID_EMBED_SOURCE;
            }
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE ))
                nFormatId = SOT_FORMATSTR_ID_LINK_SOURCE;
            // the following format can not affect scenario from #89579#
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE ))
                nFormatId = SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE;
            // FORMAT_PRIVATE no longer here (can't work if pOwnClip is NULL)
            else if (aDataHelper.HasFormat(nBiff8))      // before xxx_OLE formats
                nFormatId = nBiff8;
            else if (aDataHelper.HasFormat(nBiff5))
                nFormatId = nBiff5;
            else if (aDataHelper.HasFormat(FORMAT_RTF))
                nFormatId = FORMAT_RTF;
            else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_HTML))
                nFormatId = SOT_FORMATSTR_ID_HTML;
            else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_HTML_SIMPLE))
                nFormatId = SOT_FORMATSTR_ID_HTML_SIMPLE;
            else if (aDataHelper.HasFormat(SOT_FORMATSTR_ID_SYLK))
                nFormatId = SOT_FORMATSTR_ID_SYLK;
            else if (aDataHelper.HasFormat(FORMAT_STRING))
                nFormatId = FORMAT_STRING;
            else if (aDataHelper.HasFormat(FORMAT_GDIMETAFILE))
                nFormatId = FORMAT_GDIMETAFILE;
            else if (aDataHelper.HasFormat(FORMAT_BITMAP))
                nFormatId = FORMAT_BITMAP;
            // xxx_OLE formats come last, like in SotExchange tables
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE_OLE ))
                nFormatId = SOT_FORMATSTR_ID_EMBED_SOURCE_OLE;
            else if (aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE_OLE ))
                nFormatId = SOT_FORMATSTR_ID_LINK_SOURCE_OLE;
            else
                return;

            PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
                GetViewData()->GetCurX(), GetViewData()->GetCurY(),
                NULL, false, false );
        }
    }
}

sal_Bool ScViewFunc::PasteFromSystem( sal_uLong nFormatId, sal_Bool bApi )
{
    UpdateInputLine();

    sal_Bool bRet = sal_True;
    Window* pWin = GetActiveWin();
    ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard( pWin );
    if ( nFormatId == 0 && pOwnClip )
    {
        // keep a reference in case the clipboard is changed during PasteFromClip
        uno::Reference<datatransfer::XTransferable> aOwnClipRef( pOwnClip );
        PasteFromClip( IDF_ALL, pOwnClip->GetDocument(),
                        PASTE_NOFUNC, false, false, false, INS_NONE, IDF_NONE,
                        !bApi );		// allow warning dialog
    }
    else
    {
        TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
        if ( !aDataHelper.GetTransferable().is() )
            return false;

        bRet = PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
                                GetViewData()->GetCurX(), GetViewData()->GetCurY(),
                                NULL, false, !bApi );		// allow warning dialog

        if ( !bRet && !bApi )
            ErrorMessage(STR_PASTE_ERROR);
    }
    return bRet;
}


//----------------------------------------------------------------------------
//		P A S T E

sal_Bool ScViewFunc::PasteOnDrawObject( const uno::Reference<datatransfer::XTransferable>& rxTransferable,
                                    SdrObject* pHitObj, sal_Bool bLink )
{
    sal_Bool bRet = false;
    if ( bLink )
    {
        TransferableDataHelper aDataHelper( rxTransferable );
        if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_SVXB ) )
        {
            SotStorageStreamRef xStm;
            if( aDataHelper.GetSotStorageStream( SOT_FORMATSTR_ID_SVXB, xStm ) )
            {
                Graphic aGraphic;
                *xStm >> aGraphic;
                bRet = ApplyGraphicToObject( pHitObj, aGraphic );
            }
        }
        else if ( aDataHelper.HasFormat( SOT_FORMAT_GDIMETAFILE ) )
        {
            GDIMetaFile aMtf;
            if( aDataHelper.GetGDIMetaFile( FORMAT_GDIMETAFILE, aMtf ) )
                bRet = ApplyGraphicToObject( pHitObj, Graphic(aMtf) );
        }
        else if ( aDataHelper.HasFormat( SOT_FORMAT_BITMAP ) )
        {
            Bitmap aBmp;
            if( aDataHelper.GetBitmap( FORMAT_BITMAP, aBmp ) )
                bRet = ApplyGraphicToObject( pHitObj, Graphic(aBmp) );
        }
    }
    else
    {
        //	ham' wa noch nich
    }
    return bRet;
}

sal_Bool lcl_SelHasAttrib( ScDocument* pDoc, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                        const ScMarkData& rTabSelection, sal_uInt16 nMask )
{
    SCTAB nTabCount = pDoc->GetTableCount();
    for (SCTAB nTab=0; nTab<nTabCount; nTab++)
        if ( rTabSelection.GetTableSelect(nTab) && pDoc->HasAttrib( nCol1, nRow1, nTab, nCol2, nRow2, nTab, nMask ) )
            return sal_True;
    return false;
}

//
//		Einfuegen auf Tabelle:
//

//	internes Paste

namespace {

class CursorSwitcher
{
public:
    CursorSwitcher(ScViewFunc* pViewFunc) :
        mpViewFunc(pViewFunc)
    {
        mpViewFunc->HideCursor();
    }

    ~CursorSwitcher()
    {
        mpViewFunc->ShowCursor();
    }
private:
    ScViewFunc* mpViewFunc;
};

bool lcl_checkDestRangeForOverwrite(const ScRange& rDestRange, const ScDocument* pDoc, const ScMarkData& rMark, Window* pParentWnd)
{
    bool bIsEmpty = true;
    SCTAB nTabCount = pDoc->GetTableCount();
    for (SCTAB nTab=0; nTab < nTabCount && bIsEmpty; ++nTab)
    {
        if (!rMark.GetTableSelect(nTab))
            continue;

        bIsEmpty = pDoc->IsBlockEmpty(nTab, rDestRange.aStart.Col(), rDestRange.aStart.Row(),
                                      rDestRange.aEnd.Col(), rDestRange.aEnd.Row());
    }

    if (!bIsEmpty)
    {
        ScReplaceWarnBox aBox(pParentWnd);
        if (aBox.Execute() != RET_YES)
        {
            //	changing the configuration is within the ScReplaceWarnBox
            return false;
        }
    }
    return true;
}

}

sal_Bool ScViewFunc::PasteFromClip( sal_uInt16 nFlags, ScDocument* pClipDoc,
                                    sal_uInt16 nFunction, sal_Bool bSkipEmpty,
                                    sal_Bool bTranspose, sal_Bool bAsLink,
                                    InsCellCmd eMoveMode, sal_uInt16 nUndoExtraFlags,
                                    sal_Bool bAllowDialogs )
{
    if (!pClipDoc)
    {
        OSL_FAIL("PasteFromClip: pClipDoc=0 not allowed");
        return false;
    }

    //	fuer Undo etc. immer alle oder keine Inhalte sichern
    sal_uInt16 nContFlags = IDF_NONE;
    if (nFlags & IDF_CONTENTS)
        nContFlags |= IDF_CONTENTS;
    if (nFlags & IDF_ATTRIB)
        nContFlags |= IDF_ATTRIB;
    // evtl. Attribute ins Undo ohne sie vom Clip ins Doc zu kopieren
    sal_uInt16 nUndoFlags = nContFlags;
    if (nUndoExtraFlags & IDF_ATTRIB)
        nUndoFlags |= IDF_ATTRIB;
    // do not copy note captions into undo document
    nUndoFlags |= IDF_NOCAPTIONS;

    ScClipParam& rClipParam = pClipDoc->GetClipParam();
    if (rClipParam.isMultiRange())
        return PasteMultiRangesFromClip(
            nFlags, pClipDoc, nFunction, bSkipEmpty, bTranspose, bAsLink, bAllowDialogs,
            eMoveMode, nContFlags, nUndoFlags);

    sal_Bool bCutMode = pClipDoc->IsCutMode();		// if transposing, take from original clipdoc
    sal_Bool bIncludeFiltered = bCutMode;

    // paste drawing: also if IDF_NOTE is set (to create drawing layer for note captions)
    sal_Bool bPasteDraw = ( pClipDoc->GetDrawLayer() && ( nFlags & (IDF_OBJECTS|IDF_NOTE) ) );

    ScDocShellRef aTransShellRef;	// for objects in xTransClip - must remain valid as long as xTransClip
    ScDocument* pOrigClipDoc = NULL;
    ::std::auto_ptr< ScDocument > xTransClip;
    if ( bTranspose )
    {
        SCCOL nX;
        SCROW nY;
        // include filtered rows until TransposeClip can skip them
        bIncludeFiltered = sal_True;
        pClipDoc->GetClipArea( nX, nY, sal_True );
        if ( nY > static_cast<sal_Int32>(MAXCOL) )						// zuviele Zeilen zum Transponieren
        {
            ErrorMessage(STR_PASTE_FULL);
            return false;
        }
        pOrigClipDoc = pClipDoc;		// fuer Referenzen

        if ( bPasteDraw )
        {
            aTransShellRef = new ScDocShell;		// DocShell needs a Ref immediately
            aTransShellRef->DoInitNew(NULL);
        }
        ScDrawLayer::SetGlobalDrawPersist(aTransShellRef);

        xTransClip.reset( new ScDocument( SCDOCMODE_CLIP ));
        pClipDoc->TransposeClip( xTransClip.get(), nFlags, bAsLink );
        pClipDoc = xTransClip.get();

        ScDrawLayer::SetGlobalDrawPersist(NULL);
    }

    SCCOL nStartCol;
    SCROW nStartRow;
    SCTAB nStartTab;
    SCCOL nEndCol;
    SCROW nEndRow;
    SCTAB nEndTab;
    SCCOL nClipSizeX;
    SCROW nClipSizeY;
    pClipDoc->GetClipArea( nClipSizeX, nClipSizeY, sal_True );		// size in clipboard doc

    //	size in target doc: include filtered rows only if CutMode is set
    SCCOL nDestSizeX;
    SCROW nDestSizeY;
    pClipDoc->GetClipArea( nDestSizeX, nDestSizeY, bIncludeFiltered );

    ScDocument* pDoc = GetViewData()->GetDocument();
    ScDocShell* pDocSh = GetViewData()->GetDocShell();
    ScMarkData& rMark = GetViewData()->GetMarkData();
    ::svl::IUndoManager* pUndoMgr = pDocSh->GetUndoManager();
    const sal_Bool bRecord(pDoc->IsUndoEnabled());

    ScDocShellModificator aModificator( *pDocSh );

    ScRange aMarkRange;
    ScMarkData aFilteredMark( rMark);   // local copy for all modifications
    ScMarkType eMarkType = GetViewData()->GetSimpleArea( aMarkRange, aFilteredMark);
    bool bMarkIsFiltered = (eMarkType == SC_MARK_SIMPLE_FILTERED);
    bool bNoPaste = ((eMarkType != SC_MARK_SIMPLE && !bMarkIsFiltered) ||
            (bMarkIsFiltered && (eMoveMode != INS_NONE || bAsLink)));

    if (!bNoPaste)
    {
        if (!rMark.IsMarked())
        {
            // Create a selection with clipboard row count and check that for
            // filtered.
            nStartCol = GetViewData()->GetCurX();
            nStartRow = GetViewData()->GetCurY();
            nStartTab = GetViewData()->GetTabNo();
            nEndCol = nStartCol + nDestSizeX;
            nEndRow = nStartRow + nDestSizeY;
            nEndTab = nStartTab;
            aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
            if (ScViewUtil::HasFiltered( aMarkRange, pDoc))
            {
                bMarkIsFiltered = true;
                // Fit to clipboard's row count unfiltered rows. If there is no
                // fit assume that pasting is not possible. Note that nDestSizeY is
                // size-1 (difference).
                if (!ScViewUtil::FitToUnfilteredRows( aMarkRange, pDoc, nDestSizeY+1))
                    bNoPaste = true;
            }
            aFilteredMark.SetMarkArea( aMarkRange);
        }
        else
        {
            // Expand the marked area when the destination area is larger than the
            // current selection, to get the undo do the right thing. (i#106711)
            ScRange aRange;
            aFilteredMark.GetMarkArea( aRange );
            if( (aRange.aEnd.Col() - aRange.aStart.Col()) < nDestSizeX )
            {
                aRange.aEnd.SetCol(aRange.aStart.Col() + nDestSizeX);
                aFilteredMark.SetMarkArea(aRange);
            }
        }
    }

    if (bNoPaste)
    {
        ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
        return false;
    }

    SCROW nUnfilteredRows = aMarkRange.aEnd.Row() - aMarkRange.aStart.Row() + 1;
    ScRangeList aRangeList;
    if (bMarkIsFiltered)
    {
        ScViewUtil::UnmarkFiltered( aFilteredMark, pDoc);
        aFilteredMark.FillRangeListWithMarks( &aRangeList, false);
        nUnfilteredRows = 0;
        size_t ListSize = aRangeList.size();
        for ( size_t i = 0; i < ListSize; ++i )
        {
            ScRange* p = aRangeList[i];
            nUnfilteredRows += p->aEnd.Row() - p->aStart.Row() + 1;
        }
#if 0
        /* This isn't needed but could be a desired restriction. */
        // For filtered, destination rows have to be an exact multiple of
        // source rows. Note that nDestSizeY is size-1 (difference), so
        // nDestSizeY==0 fits always.
        if ((nUnfilteredRows % (nDestSizeY+1)) != 0)
        {
            /* FIXME: this should be a more descriptive error message then. */
            ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
            return false;
        }
#endif
    }

    // Also for a filtered selection the area is used, for undo et al.
    if ( aFilteredMark.IsMarked() || bMarkIsFiltered )
    {
        aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
        SCCOL nBlockAddX = nEndCol-nStartCol;
        SCROW nBlockAddY = nEndRow-nStartRow;

        //	Nachfrage, wenn die Selektion groesser als 1 Zeile/Spalte, aber kleiner
        //	als das Clipboard ist (dann wird ueber die Selektion hinaus eingefuegt)

        //	ClipSize is not size, but difference
        if ( ( nBlockAddX != 0 && nBlockAddX < nDestSizeX ) ||
             ( nBlockAddY != 0 && nBlockAddY < nDestSizeY ) ||
             ( bMarkIsFiltered && nUnfilteredRows < nDestSizeY+1 ) )
        {
            ScWaitCursorOff aWaitOff( GetFrameWin() );
            String aMessage = ScGlobal::GetRscString( STR_PASTE_BIGGER );
            QueryBox aBox( GetViewData()->GetDialogParent(),
                            WinBits(WB_YES_NO | WB_DEF_NO), aMessage );
            if ( aBox.Execute() != RET_YES )
            {
                return false;
            }
        }

        if (nBlockAddX <= nDestSizeX)
            nEndCol = nStartCol + nDestSizeX;

        if (nBlockAddY <= nDestSizeY)
        {
            nEndRow = nStartRow + nDestSizeY;
            if (bMarkIsFiltered || nEndRow > aMarkRange.aEnd.Row())
            {
                // Same as above if nothing was marked: re-fit selection to
                // unfiltered rows. Extending the selection actually may
                // introduce filtered rows where there weren't any before, so
                // we also need to test for that.
                aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
                if (bMarkIsFiltered || ScViewUtil::HasFiltered( aMarkRange, pDoc))
                {
                    bMarkIsFiltered = true;
                    // Worst case: all rows up to the end of the sheet are filtered.
                    if (!ScViewUtil::FitToUnfilteredRows( aMarkRange, pDoc, nDestSizeY+1))
                    {
                        ErrorMessage(STR_PASTE_FULL);
                        return false;
                    }
                }
                aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
                aFilteredMark.SetMarkArea( aMarkRange);
                if (bMarkIsFiltered)
                {
                    ScViewUtil::UnmarkFiltered( aFilteredMark, pDoc);
                    aFilteredMark.FillRangeListWithMarks( &aRangeList, sal_True);
                }
            }
        }
    }
    else
    {
        nStartCol = GetViewData()->GetCurX();
        nStartRow = GetViewData()->GetCurY();
        nStartTab = GetViewData()->GetTabNo();
        nEndCol = nStartCol + nDestSizeX;
        nEndRow = nStartRow + nDestSizeY;
        nEndTab = nStartTab;
    }

    bool bOffLimits = !ValidCol(nEndCol) || !ValidRow(nEndRow);

    //	Zielbereich, wie er angezeigt wird:
    ScRange aUserRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab );

    //	Sollen Zellen eingefuegt werden?
    //	(zu grosse nEndCol/nEndRow werden weiter unten erkannt)
    sal_Bool bInsertCells = ( eMoveMode != INS_NONE && !bOffLimits );
    if ( bInsertCells )
    {
        //	Instead of EnterListAction, the paste undo action is merged into the
        //	insert action, so Repeat can insert the right cells

        MarkRange( aUserRange );			// wird vor CopyFromClip sowieso gesetzt

        // CutMode is reset on insertion of cols/rows but needed again on cell move
        sal_Bool bCut = pClipDoc->IsCutMode();
        if (!InsertCells( eMoveMode, bRecord, true ))	// is inserting possible?
        {
            return false;
            //	#i21036# EnterListAction isn't used, and InsertCells doesn't insert
            //	its undo action on failure, so no undo handling is needed here
        }
        if ( bCut )
            pClipDoc->SetCutMode( bCut );
    }
    else if (!bOffLimits)
    {
        sal_Bool bAskIfNotEmpty = bAllowDialogs &&
                                ( nFlags & IDF_CONTENTS ) &&
                                nFunction == PASTE_NOFUNC &&
                                SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
        if ( bAskIfNotEmpty )
        {
            if (!lcl_checkDestRangeForOverwrite(aUserRange, pDoc, aFilteredMark, GetViewData()->GetDialogParent()))
                return false;
        }
    }

    SCCOL nClipStartX; 						// Clipboard-Bereich erweitern
    SCROW nClipStartY;
    pClipDoc->GetClipStart( nClipStartX, nClipStartY );
    SCCOL nUndoEndCol = nClipStartX + nClipSizeX;
    SCROW nUndoEndRow = nClipStartY + nClipSizeY;	// end of source area in clipboard document
    sal_Bool bClipOver = false;
    // #i68690# ExtendMerge for the clip doc must be called with the clipboard's sheet numbers.
    // The same end column/row can be used for all calls because the clip doc doesn't contain
    // content outside the clip area.
    for (SCTAB nClipTab=0; nClipTab<=MAXTAB; nClipTab++)
        if ( pClipDoc->HasTable(nClipTab) )
            if ( pClipDoc->ExtendMerge( nClipStartX,nClipStartY, nUndoEndCol,nUndoEndRow, nClipTab, false ) )
                bClipOver = sal_True;
    nUndoEndCol -= nClipStartX + nClipSizeX;
    nUndoEndRow -= nClipStartY + nClipSizeY;		// now contains only the difference added by ExtendMerge
    nUndoEndCol = sal::static_int_cast<SCCOL>( nUndoEndCol + nEndCol );
    nUndoEndRow = sal::static_int_cast<SCROW>( nUndoEndRow + nEndRow ); // destination area, expanded for merged cells

    if (nUndoEndCol>MAXCOL || nUndoEndRow>MAXROW)
    {
        ErrorMessage(STR_PASTE_FULL);
        return false;
    }

    pDoc->ExtendMergeSel( nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark, false );

        //	Test auf Zellschutz

    ScEditableTester aTester( pDoc, nStartTab, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow );
    if (!aTester.IsEditable())
    {
        ErrorMessage(aTester.GetMessageId());
        return false;
    }

        //! Test auf Ueberlappung
        //! nur wirkliche Schnittmenge testen !!!!!!!

    ScDocFunc& rDocFunc = pDocSh->GetDocFunc();
    if ( bRecord )
    {
        String aUndo = ScGlobal::GetRscString( pClipDoc->IsCutMode() ? STR_UNDO_MOVE : STR_UNDO_COPY );
        pUndoMgr->EnterListAction( aUndo, aUndo );
    }

    if (bClipOver)
        if (lcl_SelHasAttrib( pDoc, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark, HASATTR_OVERLAPPED ))
        {       // "Cell merge not possible if cells already merged"
            ScDocAttrIterator aIter( pDoc, nStartTab, nStartCol, nStartRow, nUndoEndCol, nUndoEndRow );
            const ScPatternAttr* pPattern = NULL;
            const ScMergeAttr* pMergeFlag = NULL;
            const ScMergeFlagAttr* pMergeFlagAttr = NULL;
            SCCOL nCol = -1;
            SCROW nRow1 = -1;
            SCROW nRow2 = -1;
            while ( ( pPattern = aIter.GetNext( nCol, nRow1, nRow2 ) ) != NULL )
            {
                pMergeFlag = (const ScMergeAttr*) &pPattern->GetItem(ATTR_MERGE);
                pMergeFlagAttr = (const ScMergeFlagAttr*) &pPattern->GetItem(ATTR_MERGE_FLAG);
                if( ( pMergeFlag && pMergeFlag->IsMerged() ) || ( pMergeFlagAttr && pMergeFlagAttr->IsOverlapped() ) )
                {
                    ScRange aRange(nCol, nRow1, nStartTab);
                    pDoc->ExtendOverlapped(aRange);
                    pDoc->ExtendMerge(aRange, sal_True, sal_True);
                    rDocFunc.UnmergeCells(aRange, bRecord, sal_True);
                }
            }
        }

    if ( !bCutMode )
    {
        ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
        if ( pChangeTrack )
            pChangeTrack->ResetLastCut();	// kein CutMode mehr
    }

    sal_Bool bColInfo = ( nStartRow==0 && nEndRow==MAXROW );
    sal_Bool bRowInfo = ( nStartCol==0 && nEndCol==MAXCOL );

    ScDocument* pUndoDoc	= NULL;
    ScDocument* pRefUndoDoc = NULL;
    ScDocument* pRedoDoc	= NULL;
    ScRefUndoData* pUndoData = NULL;

    if ( bRecord )
    {
        pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
        pUndoDoc->InitUndoSelected( pDoc, aFilteredMark, bColInfo, bRowInfo );

        // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
        SCTAB nTabCount = pDoc->GetTableCount();
        pDoc->CopyToDocument( nStartCol, nStartRow, 0, nUndoEndCol, nUndoEndRow, nTabCount-1,
                                nUndoFlags, false, pUndoDoc );

        if ( bCutMode )
        {
            pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO );
            pRefUndoDoc->InitUndo( pDoc, 0, nTabCount-1, false, false );

            pUndoData = new ScRefUndoData( pDoc );
        }
    }

    sal_uInt16 nExtFlags = 0;
    pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
                                       nEndCol,   nEndRow,   nEndTab );		// content before the change

    if (GetViewData()->IsActive())
    {
        DoneBlockMode();
        InitOwnBlockMode();
    }
    rMark.SetMarkArea( aUserRange );
    MarkDataChanged();

    HideCursor();							// Cursor aendert sich !

        //
        //	Aus Clipboard kopieren,
        //	wenn gerechnet werden soll, Originaldaten merken
        //

    ScDocument* pMixDoc = NULL;
    if ( bSkipEmpty || nFunction )
    {
        if ( nFlags & IDF_CONTENTS )
        {
            pMixDoc = new ScDocument( SCDOCMODE_UNDO );
            pMixDoc->InitUndo( pDoc, nStartTab, nEndTab );
            pDoc->CopyToDocument( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
                                    IDF_CONTENTS, false, pMixDoc );
        }
    }

    /*  Make draw layer and start drawing undo.
        - Needed before AdjustBlockHeight to track moved drawing objects.
        - Needed before pDoc->CopyFromClip to track inserted note caption objects.
     */
    if ( bPasteDraw )
        pDocSh->MakeDrawLayer();
    if ( bRecord )
        pDoc->BeginDrawUndo();

    sal_uInt16 nNoObjFlags = nFlags & ~IDF_OBJECTS;
    if (!bAsLink)
    {
        //	copy normally (original range)
        pDoc->CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags,
                pRefUndoDoc, pClipDoc, sal_True, false, bIncludeFiltered,
                bSkipEmpty, (bMarkIsFiltered ? &aRangeList : NULL) );

        // bei Transpose Referenzen per Hand anpassen
        if ( bTranspose && bCutMode && (nFlags & IDF_CONTENTS) )
            pDoc->UpdateTranspose( aUserRange.aStart, pOrigClipDoc, aFilteredMark, pRefUndoDoc );
    }
    else if (!bTranspose)
    {
        //	copy with bAsLink=TRUE
        pDoc->CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags, pRefUndoDoc, pClipDoc,
                                sal_True, sal_True, bIncludeFiltered, bSkipEmpty );
    }
    else
    {
        //	alle Inhalte kopieren (im TransClipDoc stehen nur Formeln)
        pDoc->CopyFromClip( aUserRange, aFilteredMark, nContFlags, pRefUndoDoc, pClipDoc );
    }

    // skipped rows and merged cells don't mix
    if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
        rDocFunc.UnmergeCells( aUserRange, false, sal_True );

    pDoc->ExtendMergeSel( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, sal_True );    // Refresh
                                                                                    // und Bereich neu

    if ( pMixDoc )				// Rechenfunktionen mit Original-Daten auszufuehren ?
    {
        pDoc->MixDocument( aUserRange, nFunction, bSkipEmpty, pMixDoc );
    }
    delete pMixDoc;

    AdjustBlockHeight();			// update row heights before pasting objects

    ::std::vector< ::rtl::OUString > aExcludedChartNames;
    SdrPage* pPage = NULL;

    if ( nFlags & IDF_OBJECTS )
    {
        ScDrawView* pScDrawView = GetScDrawView();
        SdrModel* pModel = ( pScDrawView ? pScDrawView->GetModel() : NULL );
        pPage = ( pModel ? pModel->GetPage( static_cast< sal_uInt16 >( nStartTab ) ) : NULL );
        if ( pPage )
        {
            ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
        }

        //	Paste the drawing objects after the row heights have been updated.

        pDoc->CopyFromClip( aUserRange, aFilteredMark, IDF_OBJECTS, pRefUndoDoc, pClipDoc,
                                sal_True, false, bIncludeFiltered );
    }


    pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
                                       nEndCol,   nEndRow,   nEndTab );		// content after the change


        //	ggf. Autofilter-Koepfe loeschen
    if (bCutMode)
        if (pDoc->RefreshAutoFilter( nClipStartX,nClipStartY, nClipStartX+nClipSizeX,
                                        nClipStartY+nClipSizeY, nStartTab ))
            pDocSh->PostPaint( nClipStartX,nClipStartY,nStartTab,
                                nClipStartX+nClipSizeX,nClipStartY,nStartTab,
                                PAINT_GRID );

    ShowCursor();							// Cursor aendert sich !

    //! 	Block-Bereich bei RefUndoDoc weglassen !!!

    if ( bRecord )
    {
        // Redo-Daten werden erst beim ersten Undo kopiert
        // ohne RefUndoDoc muss das Redo-Doc noch nicht angelegt werden

        if (pRefUndoDoc)
        {
            pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
            pRedoDoc->InitUndo( pDoc, nStartTab, nEndTab, bColInfo, bRowInfo );

            //		angepasste Referenzen ins Redo-Doc

            SCTAB nTabCount = pDoc->GetTableCount();
            pRedoDoc->AddUndoTab( 0, nTabCount-1 );
            pDoc->CopyUpdated( pRefUndoDoc, pRedoDoc );

            //		alte Referenzen ins Undo-Doc

            //! Tabellen selektieren ?
            pUndoDoc->AddUndoTab( 0, nTabCount-1 );
            pRefUndoDoc->DeleteArea( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, IDF_ALL );
            pRefUndoDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1,
                                            IDF_FORMULA, false, pUndoDoc );
            delete pRefUndoDoc;
        }

        //	DeleteUnchanged for pUndoData is in ScUndoPaste ctor,
        //	UndoData for redo is made during first undo

        ScUndoPasteOptions aOptions;			// store options for repeat
        aOptions.nFunction  = nFunction;
        aOptions.bSkipEmpty = bSkipEmpty;
        aOptions.bTranspose = bTranspose;
        aOptions.bAsLink    = bAsLink;
        aOptions.eMoveMode  = eMoveMode;

        SfxUndoAction* pUndo = new ScUndoPaste( pDocSh,
                                nStartCol, nStartRow, nStartTab,
                                nUndoEndCol, nUndoEndRow, nEndTab, aFilteredMark,
                                pUndoDoc, pRedoDoc, nFlags | nUndoFlags,
                                pUndoData, NULL, NULL, NULL,
                                false, &aOptions );		// sal_False = Redo data not yet copied

        if ( bInsertCells )
        {
            //	Merge the paste undo action into the insert action.
            //	Use ScUndoWrapper so the ScUndoPaste pointer can be stored in the insert action.

            pUndoMgr->AddUndoAction( new ScUndoWrapper( pUndo ), sal_True );
        }
        else
            pUndoMgr->AddUndoAction( pUndo );
        pUndoMgr->LeaveListAction();
    }

    sal_uInt16 nPaint = PAINT_GRID;
    if (bColInfo)
    {
        nPaint |= PAINT_TOP;
        nUndoEndCol = MAXCOL;				// nur zum Zeichnen !
    }
    if (bRowInfo)
    {
        nPaint |= PAINT_LEFT;
        nUndoEndRow = MAXROW;				// nur zum Zeichnen !
    }
    pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
                        nUndoEndCol, nUndoEndRow, nEndTab, nPaint, nExtFlags );
    // AdjustBlockHeight has already been called above

    aModificator.SetDocumentModified();
    PostPasteFromClip(aUserRange, rMark);

    if ( nFlags & IDF_OBJECTS )
    {
        ScModelObj* pModelObj = ( pDocSh ? ScModelObj::getImplementation( pDocSh->GetModel() ) : NULL );
        if ( pDoc && pPage && pModelObj )
        {
            bool bSameDoc = ( rClipParam.getSourceDocID() == pDoc->GetDocumentID() );
            const ScRangeListVector& rProtectedChartRangesVector( rClipParam.maProtectedChartRangesVector );
            ScChartHelper::CreateProtectedChartListenersAndNotify( pDoc, pPage, pModelObj, nStartTab,
                rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
        }
    }

    return sal_True;
}

bool ScViewFunc::PasteMultiRangesFromClip(
    sal_uInt16 nFlags, ScDocument* pClipDoc, sal_uInt16 nFunction,
    bool bSkipEmpty, bool bTranspose, bool bAsLink, bool bAllowDialogs,
    InsCellCmd eMoveMode, sal_uInt16 /*nContFlags*/, sal_uInt16 nUndoFlags)
{
    ScViewData& rViewData = *GetViewData();
    ScDocument* pDoc = rViewData.GetDocument();
    ScDocShell* pDocSh = rViewData.GetDocShell();
    ScMarkData aMark(rViewData.GetMarkData());
    const ScAddress& rCurPos = rViewData.GetCurPos();
    ScClipParam& rClipParam = pClipDoc->GetClipParam();
    SCCOL nColSize = rClipParam.getPasteColSize();
    SCROW nRowSize = rClipParam.getPasteRowSize();

    if (bTranspose)
    {
        if (static_cast<SCROW>(rCurPos.Col()) + nRowSize-1 > static_cast<SCROW>(MAXCOL))
        {
            ErrorMessage(STR_PASTE_FULL);
            return false;
        }

        ::std::auto_ptr<ScDocument> pTransClip(new ScDocument(SCDOCMODE_CLIP));
        pClipDoc->TransposeClip(pTransClip.get(), nFlags, bAsLink);
        pClipDoc = pTransClip.release();
        SCCOL nTempColSize = nColSize;
        nColSize = static_cast<SCCOL>(nRowSize);
        nRowSize = static_cast<SCROW>(nTempColSize);
    }

    if (!ValidCol(rCurPos.Col()+nColSize-1) || !ValidRow(rCurPos.Row()+nRowSize-1))
    {
        ErrorMessage(STR_PASTE_FULL);
        return false;
    }

    // Determine the first and last selected sheet numbers.
    SCTAB nTab1 = aMark.GetFirstSelected();
    SCTAB nTab2 = nTab1;
    for (SCTAB i = nTab1+1; i <= MAXTAB; ++i)
        if (aMark.GetTableSelect(i))
            nTab2 = i;

    ScDocShellModificator aModificator(*pDocSh);

    // For multi-selection paste, we don't support cell duplication for larger
    // destination range.  In case the destination is marked, we reset it to
    // the clip size.
    ScRange aMarkedRange(rCurPos.Col(), rCurPos.Row(), nTab1,
                         rCurPos.Col()+nColSize-1, rCurPos.Row()+nRowSize-1, nTab2);

    // Extend the marked range to account for filtered rows in the destination
    // area.
    if (ScViewUtil::HasFiltered(aMarkedRange, pDoc))
    {
        if (!ScViewUtil::FitToUnfilteredRows(aMarkedRange, pDoc, nRowSize))
            return false;
    }

    bool bAskIfNotEmpty =
        bAllowDialogs && (nFlags & IDF_CONTENTS) &&
        nFunction == PASTE_NOFUNC && SC_MOD()->GetInputOptions().GetReplaceCellsWarn();

    if (bAskIfNotEmpty)
    {
        if (!lcl_checkDestRangeForOverwrite(aMarkedRange, pDoc, aMark, rViewData.GetDialogParent()))
            return false;
    }

    aMark.SetMarkArea(aMarkedRange);
    MarkRange(aMarkedRange);

    bool bInsertCells = (eMoveMode != INS_NONE);
    if (bInsertCells)
    {
        if (!InsertCells(eMoveMode, pDoc->IsUndoEnabled(), true))
            return false;
    }

    ::std::auto_ptr<ScDocument> pUndoDoc;
    if (pDoc->IsUndoEnabled())
    {
        pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
        pUndoDoc->InitUndoSelected(pDoc, aMark, false, false);
        pDoc->CopyToDocument(aMarkedRange, nUndoFlags, false, pUndoDoc.get(), &aMark, true);
    }

    ::std::auto_ptr<ScDocument> pMixDoc;
    if ( bSkipEmpty || nFunction )
    {
        if ( nFlags & IDF_CONTENTS )
        {
            pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
            pMixDoc->InitUndoSelected(pDoc, aMark, false, false);
            pDoc->CopyToDocument(aMarkedRange, IDF_CONTENTS, false, pMixDoc.get(), &aMark, true);
        }
    }

    /*  Make draw layer and start drawing undo.
        - Needed before AdjustBlockHeight to track moved drawing objects.
        - Needed before pDoc->CopyFromClip to track inserted note caption objects.
     */
    if (nFlags & IDF_OBJECTS)
        pDocSh->MakeDrawLayer();
    if (pDoc->IsUndoEnabled())
        pDoc->BeginDrawUndo();

    CursorSwitcher aCursorSwitch(this);
    sal_uInt16 nNoObjFlags = nFlags & ~IDF_OBJECTS;
    pDoc->CopyMultiRangeFromClip(rCurPos, aMark, nNoObjFlags, pClipDoc,
                                 true, bAsLink, false, bSkipEmpty);

    if (pMixDoc.get())
        pDoc->MixDocument(aMarkedRange, nFunction, bSkipEmpty, pMixDoc.get());

    AdjustBlockHeight();            // update row heights before pasting objects

    if (nFlags & IDF_OBJECTS)
    {
        //  Paste the drawing objects after the row heights have been updated.
        pDoc->CopyMultiRangeFromClip(rCurPos, aMark, IDF_OBJECTS, pClipDoc,
                                     true, false, false, true);
    }

    pDocSh->PostPaint(
        aMarkedRange.aStart.Col(), aMarkedRange.aStart.Row(), nTab1,
        aMarkedRange.aEnd.Col(), aMarkedRange.aEnd.Row(), nTab1, PAINT_GRID);

    if (pDoc->IsUndoEnabled())
    {
        ::svl::IUndoManager* pUndoMgr = pDocSh->GetUndoManager();
        String aUndo = ScGlobal::GetRscString(
            pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
        pUndoMgr->EnterListAction(aUndo, aUndo);

        ScUndoPasteOptions aOptions;            // store options for repeat
        aOptions.nFunction  = nFunction;
        aOptions.bSkipEmpty = bSkipEmpty;
        aOptions.bTranspose = bTranspose;
        aOptions.bAsLink    = bAsLink;
        aOptions.eMoveMode  = eMoveMode;

        ScUndoPaste* pUndo = new ScUndoPaste(pDocSh,
            aMarkedRange.aStart.Col(),
            aMarkedRange.aStart.Row(),
            aMarkedRange.aStart.Tab(),
            aMarkedRange.aEnd.Col(),
            aMarkedRange.aEnd.Row(),
            aMarkedRange.aEnd.Tab(),
            aMark, pUndoDoc.release(), NULL, nFlags|nUndoFlags, NULL, NULL, NULL, NULL, false, &aOptions);

        if (bInsertCells)
            pUndoMgr->AddUndoAction(new ScUndoWrapper(pUndo), true);
        else
            pUndoMgr->AddUndoAction(pUndo, false);

        pUndoMgr->LeaveListAction();
    }
    aModificator.SetDocumentModified();
    PostPasteFromClip(aMarkedRange, aMark);
    return true;
}

void ScViewFunc::PostPasteFromClip(const ScRange& rPasteRange, const ScMarkData& rMark)
{
    ScViewData* pViewData = GetViewData();
    ScDocShell* pDocSh = pViewData->GetDocShell();
    ScDocument* pDoc = pViewData->GetDocument();
    pDocSh->UpdateOle(pViewData);

    SelectionChanged();

    // #i97876# Spreadsheet data changes are not notified
    ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
    if ( pModelObj && pModelObj->HasChangesListeners() )
    {
        ScRangeList aChangeRanges;
        SCTAB nTabCount = pDoc->GetTableCount();
        for ( SCTAB i = 0; i < nTabCount; ++i )
        {
            if ( rMark.GetTableSelect( i ) )
            {
                ScRange aChangeRange(rPasteRange);
                aChangeRange.aStart.SetTab( i );
                aChangeRange.aEnd.SetTab( i );
                aChangeRanges.Append( aChangeRange );
            }
        }
        pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "cell-change" ) ), aChangeRanges );
    }
}


//----------------------------------------------------------------------------
//		D R A G   A N D   D R O P
//
//	innerhalb des Dokuments

sal_Bool ScViewFunc::MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
                                sal_Bool bCut, sal_Bool bRecord, sal_Bool bPaint, sal_Bool bApi )
{
    ScDocShell* pDocSh = GetViewData()->GetDocShell();
    HideAllCursors();		// wegen zusammengefassten

    sal_Bool bSuccess = sal_True;
    SCTAB nDestTab = rDestPos.Tab();
    const ScMarkData& rMark = GetViewData()->GetMarkData();
    if ( rSource.aStart.Tab() == nDestTab && rSource.aEnd.Tab() == nDestTab && rMark.GetSelectCount() > 1 )
    {
        //	moving within one table and several tables selected -> apply to all selected tables

        if ( bRecord )
        {
            String aUndo = ScGlobal::GetRscString( bCut ? STR_UNDO_MOVE : STR_UNDO_COPY );
            pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
        }

        //	collect ranges of consecutive selected tables

        ScRange aLocalSource = rSource;
        ScAddress aLocalDest = rDestPos;
        SCTAB nTabCount = pDocSh->GetDocument()->GetTableCount();
        SCTAB nStartTab = 0;
        while ( nStartTab < nTabCount && bSuccess )
        {
            while ( nStartTab < nTabCount && !rMark.GetTableSelect(nStartTab) )
                ++nStartTab;
            if ( nStartTab < nTabCount )
            {
                SCTAB nEndTab = nStartTab;
                while ( nEndTab+1 < nTabCount && rMark.GetTableSelect(nEndTab+1) )
                    ++nEndTab;

                aLocalSource.aStart.SetTab( nStartTab );
                aLocalSource.aEnd.SetTab( nEndTab );
                aLocalDest.SetTab( nStartTab );

                bSuccess = pDocSh->GetDocFunc().MoveBlock(
                                aLocalSource, aLocalDest, bCut, bRecord, bPaint, bApi );

                nStartTab = nEndTab + 1;
            }
        }

        if ( bRecord )
            pDocSh->GetUndoManager()->LeaveListAction();
    }
    else
    {
        //	move the block as specified
        bSuccess = pDocSh->GetDocFunc().MoveBlock(
                                rSource, rDestPos, bCut, bRecord, bPaint, bApi );
    }

    ShowAllCursors();
    if (bSuccess)
    {
        //	Zielbereich markieren
        ScAddress aDestEnd(
                    rDestPos.Col() + rSource.aEnd.Col() - rSource.aStart.Col(),
                    rDestPos.Row() + rSource.aEnd.Row() - rSource.aStart.Row(),
                    nDestTab );

        sal_Bool bIncludeFiltered = bCut;
        if ( !bIncludeFiltered )
        {
            // find number of non-filtered rows
            SCROW nPastedCount = pDocSh->GetDocument()->CountNonFilteredRows(
                rSource.aStart.Row(), rSource.aEnd.Row(), rSource.aStart.Tab());

            if ( nPastedCount == 0 )
                nPastedCount = 1;
            aDestEnd.SetRow( rDestPos.Row() + nPastedCount - 1 );
        }

        MarkRange( ScRange( rDestPos, aDestEnd ), false );			//! sal_False ???

        pDocSh->UpdateOle(GetViewData());
        SelectionChanged();
    }
    return bSuccess;
}

//	Link innerhalb des Dokuments

sal_Bool ScViewFunc::LinkBlock( const ScRange& rSource, const ScAddress& rDestPos, sal_Bool bApi )
{
    //	Test auf Ueberlappung

    if ( rSource.aStart.Tab() == rDestPos.Tab() )
    {
        SCCOL nDestEndCol = rDestPos.Col() + ( rSource.aEnd.Col() - rSource.aStart.Col() );
        SCROW nDestEndRow = rDestPos.Row() + ( rSource.aEnd.Row() - rSource.aStart.Row() );

        if ( rSource.aStart.Col() <= nDestEndCol && rDestPos.Col() <= rSource.aEnd.Col() &&
             rSource.aStart.Row() <= nDestEndRow && rDestPos.Row() <= rSource.aEnd.Row() )
        {
            if (!bApi)
                ErrorMessage( STR_ERR_LINKOVERLAP );
            return false;
        }
    }

    //	Ausfuehren per Paste

    ScDocument* pDoc = GetViewData()->GetDocument();
    ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP );
    pDoc->CopyTabToClip( rSource.aStart.Col(), rSource.aStart.Row(),
                            rSource.aEnd.Col(), rSource.aEnd.Row(),
                            rSource.aStart.Tab(), pClipDoc );

    //	Zielbereich markieren (Cursor setzen, keine Markierung)

    if ( GetViewData()->GetTabNo() != rDestPos.Tab() )
        SetTabNo( rDestPos.Tab() );

    MoveCursorAbs( rDestPos.Col(), rDestPos.Row(), SC_FOLLOW_NONE, false, false );

    //	Paste

    PasteFromClip( IDF_ALL, pClipDoc, PASTE_NOFUNC, false, false, sal_True );		// als Link

    delete pClipDoc;

    return sal_True;
}

void ScViewFunc::DataFormPutData( SCROW nCurrentRow ,
                                  SCROW nStartRow , SCCOL nStartCol ,
                                  SCROW nEndRow , SCCOL nEndCol ,
                                  Edit** pEdits ,
                                  sal_uInt16 aColLength )
{
    ScDocument* pDoc = GetViewData()->GetDocument();
    ScDocShell* pDocSh = GetViewData()->GetDocShell();
    ScMarkData& rMark = GetViewData()->GetMarkData();
    ScDocShellModificator aModificator( *pDocSh );
    ::svl::IUndoManager* pUndoMgr = pDocSh->GetUndoManager();
    if ( pDoc )
    {
        const sal_Bool bRecord( pDoc->IsUndoEnabled());
        ScDocument* pUndoDoc = NULL;
        ScDocument* pRedoDoc = NULL;
        ScRefUndoData* pUndoData = NULL;
        SCTAB nTab = GetViewData()->GetTabNo();
        SCTAB nStartTab = nTab;
        SCTAB nEndTab = nTab;

        {
                ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack();
                if ( pChangeTrack )
                        pChangeTrack->ResetLastCut();   // kein CutMode mehr
        }
        ScRange aUserRange( nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab );
        sal_Bool bColInfo = ( nStartRow==0 && nEndRow==MAXROW );
        sal_Bool bRowInfo = ( nStartCol==0 && nEndCol==MAXCOL );
        SCCOL nUndoEndCol = nStartCol+aColLength-1;
        SCROW nUndoEndRow = nCurrentRow;
        sal_uInt16 nUndoFlags = IDF_NONE;

        if ( bRecord )
        {
            pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
            pUndoDoc->InitUndoSelected( pDoc , rMark , bColInfo , bRowInfo );
            pDoc->CopyToDocument( aUserRange , 1 , false , pUndoDoc );
        }
        sal_uInt16 nExtFlags = 0;
        pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab , nEndCol, nEndRow, nEndTab ); // content before the change
        pDoc->BeginDrawUndo();

        for(sal_uInt16 i = 0; i < aColLength; i++)
        {
            if (pEdits[i])
            {
                String  aFieldName=pEdits[i]->GetText();
                pDoc->SetString( nStartCol + i, nCurrentRow, nTab, aFieldName );
            }
        }
        pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab );  // content after the change
        SfxUndoAction* pUndo = new ScUndoDataForm( pDocSh,
                                                                nStartCol, nCurrentRow, nStartTab,
                                                                nUndoEndCol, nUndoEndRow, nEndTab, rMark,
                                                                pUndoDoc, pRedoDoc, nUndoFlags,
                                                                pUndoData, NULL, NULL, NULL,
                                                                false );           // FALSE = Redo data not yet copied
        pUndoMgr->AddUndoAction( new ScUndoWrapper( pUndo ), true );

        sal_uInt16 nPaint = PAINT_GRID;
        if (bColInfo)
        {
                nPaint |= PAINT_TOP;
                nUndoEndCol = MAXCOL;                           // nur zum Zeichnen !
        }
        if (bRowInfo)
        {
                nPaint |= PAINT_LEFT;
                nUndoEndRow = MAXROW;                           // nur zum Zeichnen !
        }

        pDocSh->PostPaint( nStartCol, nCurrentRow, nStartTab,
                                                nUndoEndCol, nUndoEndRow, nEndTab, nPaint, nExtFlags );
        pDocSh->UpdateOle(GetViewData());
    }
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
