ooo-build r15429 - trunk/patches/test



Author: kyoshida
Date: Sat Feb 28 06:43:07 2009
New Revision: 15429
URL: http://svn.gnome.org/viewvc/ooo-build?rev=15429&view=rev

Log:
on-going work to support multi-range copy and paste in Calc.


Added:
   trunk/patches/test/calc-multi-range-copy-paste.diff

Added: trunk/patches/test/calc-multi-range-copy-paste.diff
==============================================================================
--- (empty file)
+++ trunk/patches/test/calc-multi-range-copy-paste.diff	Sat Feb 28 06:43:07 2009
@@ -0,0 +1,1306 @@
+diff --git sc/inc/clipparam.hxx sc/inc/clipparam.hxx
+new file mode 100644
+index 0000000..79d45f9
+--- /dev/null
++++ sc/inc/clipparam.hxx
+@@ -0,0 +1,70 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: document.hxx,v $
++ * $Revision: 1.115.36.9 $
++ *
++ * 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.
++ *
++ ************************************************************************/
++
++#ifndef SC_CLIPPARAM_HXX
++#define SC_CLIPPARAM_HXX
++
++#include "rangelst.hxx"
++
++struct ScClipParam
++{
++    enum Direction { Unspecified, Column, Row };
++
++    ScRangeList maRanges;
++    Direction   meDirection;
++    bool        mbCutMode;
++
++    ScClipParam();
++    explicit ScClipParam(const ScClipParam& r);
++
++    bool isMultiRange() const;
++
++    /** 
++     * Get the column size of a pasted range.  Note that when the range is
++     * non-contiguous, we first compress all individual ranges into a single 
++     * range, and the size of that compressed range is returned.
++     */
++    SCCOL getPasteColSize();
++
++    /** 
++     * Same as the above method, but returns the row size of the compressed 
++     * range. 
++     */
++    SCROW getPasteRowSize();
++
++    /** 
++     * Return a single range that encompasses all individual ranges.
++     */
++    ScRange getWholeRange();
++
++    void transpose();
++};
++
++#endif
+diff --git sc/inc/document.hxx sc/inc/document.hxx
+index d8ce3a5..b7664bc 100644
+--- sc/inc/document.hxx
++++ sc/inc/document.hxx
+@@ -138,6 +138,7 @@ class ScAutoNameCache;
+ class ScTemporaryChartLock;
+ class ScLookupCache;
+ struct ScLookupCacheMapImpl;
++struct ScClipParam;
+ 
+ namespace com { namespace sun { namespace star {
+     namespace lang {
+@@ -289,6 +290,7 @@ private:
+ 	ScFieldEditEngine*	pCacheFieldEditEngine;
+ 
+     ::std::auto_ptr<ScDocProtection> pDocProtection;
++    ::std::auto_ptr<ScClipParam>     mpClipParam;
+ 
+     ::std::auto_ptr<ScExternalRefManager> pExternalRefMgr;
+ 	String              aDocName;                       // opt: Dokumentname
+@@ -311,7 +313,6 @@ private:
+ 
+     sal_uInt32          nRangeOverflowType;             // used in (xml) loading for overflow warnings
+ 
+-	ScRange				aClipRange;
+ 	ScRange				aEmbedRange;
+ 	ScAddress			aCurTextWidthCalcPos;
+ 	ScAddress			aOnlineSpellPos;				// within whole document
+@@ -363,7 +364,6 @@ private:
+ 	BOOL				bForcedFormulaPending;
+ 	BOOL				bCalculatingFormulaTree;
+ 	BOOL				bIsClip;
+-	BOOL				bCutMode;
+ 	BOOL				bIsUndo;
+ 	BOOL				bIsVisible;						// set from view ctor
+ 
+@@ -971,6 +971,9 @@ public:
+                                 BOOL bKeepScenarioFlags = FALSE,
+                                 BOOL bIncludeObjects = FALSE,
+                                 BOOL bCloneNoteCaptions = TRUE);
++    void            CopyToClip(const ScClipParam& rClipParam, ScDocument* pClipDoc, 
++                               const ScMarkData* pMarks = NULL, bool bKeepScenarioFlags = false,
++                               bool bIncludeObjects = false, bool bCloneNoteCaptions = true);
+ 	void			CopyTabToClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ 								SCTAB nTab, ScDocument* pClipDoc = NULL);
+ 	void 			CopyBlockFromClip( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+@@ -998,6 +1001,12 @@ public:
+ 									BOOL bSkipAttrForEmpty = FALSE,
+                                     const ScRangeList * pDestRanges = NULL );
+ 
++    void            CopyMultiRangeFromClip(const ScAddress& rDestPos, const ScMarkData& rMark, 
++                                           sal_uInt16 nInsFlag, ScDocument* pClipDoc, 
++                                           bool bResetCut = true, bool bAsLink = false,
++                                           bool bIncludeFiltered = true,
++                                           bool bSkipAttrForEmpty = false);
++
+ 	void			GetClipArea(SCCOL& nClipX, SCROW& nClipY, BOOL bIncludeFiltered);
+ 	void			GetClipStart(SCCOL& nClipX, SCROW& nClipY);
+ 
+@@ -1007,6 +1016,9 @@ public:
+ 
+ 	SC_DLLPUBLIC void			TransposeClip( ScDocument* pTransClip, USHORT nFlags, BOOL bAsLink );
+ 
++    ScClipParam&    GetClipParam();
++    void            SetClipParam(const ScClipParam& rParam);
++
+ 	void			MixDocument( const ScRange& rRange, USHORT nFunction, BOOL bSkipEmpty,
+ 									ScDocument* pSrcDoc );
+ 
+diff --git sc/inc/table.hxx sc/inc/table.hxx
+index 74b743f..e8865ed 100644
+--- sc/inc/table.hxx
++++ sc/inc/table.hxx
+@@ -297,6 +297,8 @@ public:
+ 	void		DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, USHORT nDelFlag);
+ 	void		CopyToClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pTable,
+                             BOOL bKeepScenarioFlags, BOOL bCloneNoteCaptions);
++    void        CopyToClip(const ScRangeList& rRanges, ScTable* pTable, 
++                           bool bKeepScenarioFlags, bool bCloneNoteCaptions);
+ 	void		CopyFromClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCsCOL nDx, SCsROW nDy,
+ 								USHORT nInsFlag, BOOL bAsLink, BOOL bSkipAttrForEmpty, ScTable* pTable);
+ 	void		StartListeningInArea( SCCOL nCol1, SCROW nRow1,
+diff --git sc/source/core/data/clipparam.cxx sc/source/core/data/clipparam.cxx
+new file mode 100644
+index 0000000..77ea4ee
+--- /dev/null
++++ sc/source/core/data/clipparam.cxx
+@@ -0,0 +1,235 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: document.cxx,v $
++ * $Revision: 1.90.36.8 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_sc.hxx"
++
++// INCLUDE ---------------------------------------------------------------
++
++#include "clipparam.hxx"
++
++ScClipParam::ScClipParam() :
++    meDirection(Unspecified),
++    mbCutMode(false)
++{
++}
++
++ScClipParam::ScClipParam(const ScClipParam& r) :
++    maRanges(r.maRanges),
++    meDirection(r.meDirection),
++    mbCutMode(r.mbCutMode)
++{
++}
++
++bool ScClipParam::isMultiRange() const
++{
++    return maRanges.Count() > 1;
++}
++
++static SCCOLROW lcl_getRealColSize(ScClipParam::Direction eDir, ScRangeList& rRanges)
++{
++    if (!rRanges.Count())
++        return 0;
++
++    switch (eDir)
++    {
++        case ScClipParam::Column:
++        {
++            SCCOLROW nColSize = 0;
++            for (ScRangePtr p = rRanges.First(); p; p = rRanges.Next())
++                nColSize += p->aEnd.Col() - p->aStart.Col() + 1;
++            return nColSize;
++        }
++        break;
++        case ScClipParam::Row:
++        {
++            // We assume that all ranges have identical column size.
++            const ScRange& rRange = *rRanges.First();
++            return rRange.aEnd.Col() - rRange.aStart.Col() + 1;
++        }
++        break;
++        case ScClipParam::Unspecified:
++        default:
++            ;
++    }
++    return 0;
++}
++
++static SCCOLROW lcl_getRealRowSize(ScClipParam::Direction eDir, ScRangeList& rRanges)
++{
++    if (!rRanges.Count())
++        return 0;
++
++    switch (eDir)
++    {
++        case ScClipParam::Column:
++        {
++            // We assume that all ranges have identical row size.
++            const ScRange& rRange = *rRanges.First();
++            return rRange.aEnd.Row() - rRange.aStart.Row() + 1;
++        }
++        break;
++        case ScClipParam::Row:
++        {
++            SCCOLROW nRowSize = 0;
++            for (ScRangePtr p = rRanges.First(); p; p = rRanges.Next())
++                nRowSize += p->aEnd.Row() - p->aStart.Row() + 1;
++            return nRowSize;
++        }
++        break;
++        case ScClipParam::Unspecified:
++        default:
++            ;
++    }
++    return 0;
++}
++
++SCCOL ScClipParam::getPasteColSize()
++{
++    if (!maRanges.Count())
++        return 0;
++
++    switch (meDirection)
++    {
++        case ScClipParam::Column:
++        {
++            SCCOL nColSize = 0;
++            for (ScRangePtr p = maRanges.First(); p; p = maRanges.Next())
++                nColSize += p->aEnd.Col() - p->aStart.Col() + 1;
++            return nColSize;
++        }
++        break;
++        case ScClipParam::Row:
++        {
++            // We assume that all ranges have identical column size.
++            const ScRange& rRange = *maRanges.First();
++            return rRange.aEnd.Col() - rRange.aStart.Col() + 1;
++        }
++        break;
++        case ScClipParam::Unspecified:
++        default:
++            ;
++    }
++    return 0;
++}
++
++SCROW ScClipParam::getPasteRowSize()
++{
++    if (!maRanges.Count())
++        return 0;
++
++    switch (meDirection)
++    {
++        case ScClipParam::Column:
++        {
++            // We assume that all ranges have identical row size.
++            const ScRange& rRange = *maRanges.First();
++            return rRange.aEnd.Row() - rRange.aStart.Row() + 1;
++        }
++        break;
++        case ScClipParam::Row:
++        {
++            SCROW nRowSize = 0;
++            for (ScRangePtr p = maRanges.First(); p; p = maRanges.Next())
++                nRowSize += p->aEnd.Row() - p->aStart.Row() + 1;
++            return nRowSize;
++        }
++        break;
++        case ScClipParam::Unspecified:
++        default:
++            ;
++    }
++    return 0;
++}
++
++ScRange ScClipParam::getWholeRange()
++{
++    ScRange aWhole;
++    bool bFirst = true;
++    for (ScRange* p = maRanges.First(); p; p = maRanges.Next())
++    {
++        if (bFirst)
++        {    
++            aWhole = *p;
++            bFirst = false;
++            continue;
++        }
++
++        if (aWhole.aStart.Col() > p->aStart.Col())
++            aWhole.aStart.SetCol(p->aStart.Col());
++
++        if (aWhole.aStart.Row() > p->aStart.Row())
++            aWhole.aStart.SetRow(p->aStart.Row());
++
++        if (aWhole.aEnd.Col() < p->aEnd.Col())
++            aWhole.aEnd.SetCol(p->aEnd.Col());
++
++        if (aWhole.aEnd.Row() > p->aEnd.Row())
++            aWhole.aEnd.SetRow(p->aEnd.Row());
++    }
++    return aWhole;
++}
++
++void ScClipParam::transpose()
++{
++    switch (meDirection)
++    {
++        case ScClipParam::Column: 
++            meDirection = ScClipParam::Row;
++        break;
++        case ScClipParam::Row:
++            meDirection = ScClipParam::Column;
++        break;
++    }
++
++    ScRangeList aNewRanges;
++    if (maRanges.Count())
++    {
++        ScRange* p = maRanges.First();
++        SCCOL nColOrigin = p->aStart.Col();
++        SCROW nRowOrigin = p->aStart.Row();
++        for (; p; p = maRanges.Next())
++        {
++            SCCOL nColDelta = p->aStart.Col() - nColOrigin;
++            SCROW nRowDelta = p->aStart.Row() - nRowOrigin;
++            SCCOL nCol1 = 0;
++            SCCOL nCol2 = static_cast<SCCOL>(p->aEnd.Row() - p->aStart.Row());
++            SCROW nRow1 = 0;
++            SCROW nRow2 = static_cast<SCROW>(p->aEnd.Col() - p->aStart.Col());
++            nCol1 += static_cast<SCCOL>(nRowDelta);
++            nCol2 += static_cast<SCCOL>(nRowDelta);
++            nRow1 += static_cast<SCROW>(nColDelta);
++            nRow2 += static_cast<SCROW>(nColDelta);
++            ScRange aNew(nCol1, nRow1, p->aStart.Tab(), nCol2, nRow2, p->aStart.Tab());
++            aNewRanges.Append(aNew);
++        }
++    }
++    maRanges = aNewRanges;
++}
+diff --git sc/source/core/data/column.cxx sc/source/core/data/column.cxx
+index c396a27..93b33a1 100644
+--- sc/source/core/data/column.cxx
++++ sc/source/core/data/column.cxx
+@@ -1260,6 +1260,7 @@ void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
+ 
+ void ScColumn::CopyToClip(SCROW nRow1, SCROW nRow2, ScColumn& rColumn, BOOL bKeepScenarioFlags, BOOL bCloneNoteCaptions)
+ {
++    fprintf(stdout, "ScColumn::CopyToClip:   col = %ld\n", nCol);
+ 	pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
+ 							bKeepScenarioFlags ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
+ 
+diff --git sc/source/core/data/documen2.cxx sc/source/core/data/documen2.cxx
+index 9bf31a2..7dfa529 100644
+--- sc/source/core/data/documen2.cxx
++++ sc/source/core/data/documen2.cxx
+@@ -95,6 +95,7 @@
+ #include "lookupcache.hxx"
+ #include "externalrefmgr.hxx"
+ #include "tabprotection.hxx"
++#include "clipparam.hxx"
+ #include <com/sun/star/document/XVbaEventsHelper.hpp>
+ 
+ // pImpl because including lookupcache.hxx in document.hxx isn't wanted, and
+@@ -154,6 +155,7 @@ ScDocument::ScDocument( ScDocumentMode	eMode,
+ 		pScriptTypeData( NULL ),
+         pCacheFieldEditEngine( NULL ),
+         pDocProtection( NULL ),
++        mpClipParam( NULL ),
+         pExternalRefMgr( NULL ),
+ 		pViewOptions( NULL ),
+ 		pDocOptions( NULL ),
+@@ -182,7 +184,6 @@ ScDocument::ScDocument( ScDocumentMode	eMode,
+ 		bForcedFormulaPending( FALSE ),
+ 		bCalculatingFormulaTree( FALSE ),
+ 		bIsClip( eMode == SCDOCMODE_CLIP ),
+-		bCutMode( FALSE ),
+ 		bIsUndo( eMode == SCDOCMODE_UNDO ),
+ 		bIsVisible( FALSE ),
+ 		bIsEmbedded( FALSE ),
+diff --git sc/source/core/data/documen3.cxx sc/source/core/data/documen3.cxx
+index 071674b..f04b1b8 100644
+--- sc/source/core/data/documen3.cxx
++++ sc/source/core/data/documen3.cxx
+@@ -80,6 +80,7 @@
+ #include "listenercalls.hxx"
+ #include "svtools/PasswordHelper.hxx"
+ #include "tabprotection.hxx"
++#include "clipparam.hxx"
+ 
+ #include <memory>
+ 
+@@ -868,7 +869,7 @@ void ScDocument::UpdateReference( UpdateRefMode eUpdateRefMode,
+ 		{
+ 			ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
+ 			if (pClipDoc)
+-				pClipDoc->bCutMode = FALSE;
++				pClipDoc->GetClipParam().mbCutMode = false;
+ 		}
+ 	}
+ }
+@@ -878,7 +879,10 @@ void ScDocument::UpdateTranspose( const ScAddress& rDestPos, ScDocument* pClipDo
+ {
+ 	DBG_ASSERT(pClipDoc->bIsClip, "UpdateTranspose: kein Clip");
+ 
+-	ScRange aSource = pClipDoc->aClipRange;			// Tab wird noch angepasst
++	ScRange aSource;
++    ScClipParam& rClipParam = GetClipParam();
++    if (rClipParam.maRanges.Count())
++        aSource = *rClipParam.maRanges.First();
+ 	ScAddress aDest = rDestPos;
+ 
+ 	SCTAB nClipTab = 0;
+diff --git sc/source/core/data/document.cxx sc/source/core/data/document.cxx
+index 6a97fb5..1364b09 100644
+--- sc/source/core/data/document.cxx
++++ sc/source/core/data/document.cxx
+@@ -94,6 +94,7 @@
+ #include "postit.hxx"
+ #include "externalrefmgr.hxx"
+ #include "tabprotection.hxx"
++#include "clipparam.hxx"
+ 
+ namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
+ 
+@@ -1258,7 +1259,7 @@ void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, BOOL bColInfo, BOOL bRowI
+ void ScDocument::SetCutMode( BOOL bVal )
+ {
+ 	if (bIsClip)
+-		bCutMode = bVal;
++        GetClipParam().mbCutMode = bVal;
+ 	else
+ 	{
+ 		DBG_ERROR("SetCutMode without bIsClip");
+@@ -1269,7 +1270,7 @@ void ScDocument::SetCutMode( BOOL bVal )
+ BOOL ScDocument::IsCutMode()
+ {
+ 	if (bIsClip)
+-		return bCutMode;
++		return GetClipParam().mbCutMode;
+ 	else
+ 	{
+ 		DBG_ERROR("IsCutMode ohne bIsClip");
+@@ -1400,9 +1401,11 @@ void ScDocument::CopyToClip(SCCOL nCol1, SCROW nRow1,
+ 			pClipDoc = SC_MOD()->GetClipDoc();
+ 		}
+ 
++        ScClipParam& rClipParam = pClipDoc->GetClipParam();
++        rClipParam.maRanges.RemoveAll();
++        rClipParam.maRanges.Append(ScRange( nCol1,nRow1,0, nCol2,nRow2,0 ));
+ 		pClipDoc->aDocName = aDocName;
+-		pClipDoc->aClipRange = ScRange( nCol1,nRow1,0, nCol2,nRow2,0 );
+-		pClipDoc->ResetClip( this, pMarks );
++        pClipDoc->ResetClip( this, pMarks );
+ 		USHORT i;
+         SCTAB j;
+ 
+@@ -1441,10 +1444,64 @@ void ScDocument::CopyToClip(SCCOL nCol1, SCROW nRow1,
+ 					}
+ 				}
+ 
+-		pClipDoc->bCutMode = bCut;
++		pClipDoc->GetClipParam().mbCutMode = bCut;
+ 	}
+ }
+ 
++void ScDocument::CopyToClip(const ScClipParam& rClipParam, 
++                            ScDocument* pClipDoc, const ScMarkData* pMarks,
++                            bool bKeepScenarioFlags, bool bIncludeObjects, bool bCloneNoteCaptions)
++{
++    if (bIsClip)
++        return;
++
++    if (!pClipDoc)
++    {
++        DBG_ERROR("CopyToClip: no ClipDoc");
++        pClipDoc = SC_MOD()->GetClipDoc();
++    }
++
++#if 0
++    USHORT i;
++    SCTAB j;
++
++    std::set<USHORT> aUsedNames;        // indexes of named ranges that are used in the copied cells
++    for (j = 0; j <= MAXTAB; j++)
++        if (pTab[j] && pClipDoc->pTab[j])
++            if ( bAllTabs || !pMarks || pMarks->GetTableSelect(j) )
++                pTab[j]->FindRangeNamesInUse( nCol1, nRow1, nCol2, nRow2, aUsedNames );
++
++    pClipDoc->pRangeName->FreeAll();
++    for (i = 0; i < pRangeName->GetCount(); i++)		//! DB-Bereiche Pivot-Bereiche auch !!!
++    {
++        USHORT nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
++        bool bInUse = ( aUsedNames.find(nIndex) != aUsedNames.end() );
++        if (bInUse)
++        {
++            ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
++            if (!pClipDoc->pRangeName->Insert(pData))
++                delete pData;
++            else
++                pData->SetIndex(nIndex);
++        }
++    }
++#endif
++
++    pClipDoc->aDocName = aDocName;
++    pClipDoc->SetClipParam(rClipParam);
++    pClipDoc->ResetClip(this, pMarks);
++
++    for (SCTAB i = 0; i <= MAXTAB; ++i)
++    {
++        if (!pTab[i] || !pClipDoc->pTab[i])
++            continue;
++
++        if (pMarks && !pMarks->GetTableSelect(i))
++            continue;
++
++        pTab[i]->CopyToClip(rClipParam.maRanges, pClipDoc->pTab[i], bKeepScenarioFlags, bCloneNoteCaptions);
++    }
++}
+ 
+ void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
+ 								SCCOL nCol2, SCROW nRow2,
+@@ -1460,14 +1517,16 @@ void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
+ 			pClipDoc = SC_MOD()->GetClipDoc();
+ 		}
+ 
++        ScClipParam& rClipParam = pClipDoc->GetClipParam();
+ 		pClipDoc->aDocName = aDocName;
+-		pClipDoc->aClipRange = ScRange( nCol1,nRow1,0, nCol2,nRow2,0 );
++        rClipParam.maRanges.RemoveAll();
++        rClipParam.maRanges.Append(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
+ 		pClipDoc->ResetClip( this, nTab );
+ 
+ 		if (pTab[nTab] && pClipDoc->pTab[nTab])
+             pTab[nTab]->CopyToClip(nCol1, nRow1, nCol2, nRow2, pClipDoc->pTab[nTab], FALSE, TRUE);
+ 
+-		pClipDoc->bCutMode = FALSE;
++		pClipDoc->GetClipParam().mbCutMode = false;
+ 	}
+ }
+ 
+@@ -1497,6 +1556,7 @@ void ScDocument::TransposeClip( ScDocument* pTransClip, USHORT nFlags, BOOL bAsL
+ 
+ 		//	Daten
+ 
++    ScRange aClipRange = GetClipParam().getWholeRange();
+ 	if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
+ 	{
+ 		for (SCTAB i=0; i<=MAXTAB; i++)
+@@ -1525,10 +1585,8 @@ void ScDocument::TransposeClip( ScDocument* pTransClip, USHORT nFlags, BOOL bAsL
+ 				}
+ 			}
+ 
+-		pTransClip->aClipRange = ScRange( 0, 0, aClipRange.aStart.Tab(),
+-                static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
+-                static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()),
+-									aClipRange.aEnd.Tab() );
++        pTransClip->SetClipParam(GetClipParam());
++        pTransClip->GetClipParam().transpose();
+ 	}
+ 	else
+ 	{
+@@ -1537,9 +1595,21 @@ void ScDocument::TransposeClip( ScDocument* pTransClip, USHORT nFlags, BOOL bAsL
+ 
+ 		//	Dies passiert erst beim Einfuegen...
+ 
+-	bCutMode = FALSE;
++	GetClipParam().mbCutMode = false;
+ }
+ 
++ScClipParam& ScDocument::GetClipParam()
++{
++    if (!mpClipParam.get())
++        mpClipParam.reset(new ScClipParam);
++
++    return *mpClipParam;
++}
++
++void ScDocument::SetClipParam(const ScClipParam& rParam)
++{
++    mpClipParam.reset(new ScClipParam(rParam));
++}
+ 
+ BOOL ScDocument::IsClipboardSource() const
+ {
+@@ -1639,7 +1709,7 @@ void ScDocument::CopyBlockFromClip( SCCOL nCol1, SCROW nRow1,
+                         && ppClipTab[nClipTab + nFollow + 1] )
+                     ++nFollow;
+ 
+-                if ( pCBFCP->pClipDoc->bCutMode )
++                if ( pCBFCP->pClipDoc->GetClipParam().mbCutMode )
+                 {
+                     BOOL bOldInserting = IsInsertingFromOtherDoc();
+                     SetInsertingFromOtherDoc( TRUE);
+@@ -1681,7 +1751,9 @@ void ScDocument::CopyNonFilteredFromClip( SCCOL nCol1, SCROW nRow1,
+         pCBFCP->pClipDoc->GetRowFlagsArray( nFlagTab);
+ 
+ 	SCROW nSourceRow = rClipStartRow;
+-	SCROW nSourceEnd = pCBFCP->pClipDoc->aClipRange.aEnd.Row();
++	SCROW nSourceEnd = 0;
++    if (pCBFCP->pClipDoc->GetClipParam().maRanges.Count())
++        nSourceEnd = pCBFCP->pClipDoc->GetClipParam().maRanges.First()->aEnd.Row();
+ 	SCROW nDestRow = nRow1;
+ 
+ 	while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
+@@ -1795,17 +1867,22 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
+ 
+             SCCOL nXw = 0;
+             SCROW nYw = 0;
++            ScRange aClipRange;
++            fprintf(stdout, "ScDocument::CopyFromClip:   clip range count = %d\n", 
++                    pClipDoc->GetClipParam().maRanges.Count());
++            if (pClipDoc->GetClipParam().maRanges.Count())
++                aClipRange = *pClipDoc->GetClipParam().maRanges.First();
+             for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)    // find largest merge overlap
+                 if (pClipDoc->pTab[nTab])                   // all sheets of the clipboard content
+                 {
+-                    SCCOL nThisEndX = pClipDoc->aClipRange.aEnd.Col();
+-                    SCROW nThisEndY = pClipDoc->aClipRange.aEnd.Row();
+-                    pClipDoc->ExtendMerge( pClipDoc->aClipRange.aStart.Col(),
+-                                            pClipDoc->aClipRange.aStart.Row(),
++                    SCCOL nThisEndX = aClipRange.aEnd.Col();
++                    SCROW nThisEndY = aClipRange.aEnd.Row();
++                    pClipDoc->ExtendMerge( aClipRange.aStart.Col(),
++                                            aClipRange.aStart.Row(),
+                                             nThisEndX, nThisEndY, nTab );
+                     // only extra value from ExtendMerge
+-                    nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - pClipDoc->aClipRange.aEnd.Col() );
+-                    nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - pClipDoc->aClipRange.aEnd.Row() );
++                    nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - aClipRange.aEnd.Col() );
++                    nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - aClipRange.aEnd.Row() );
+                     if ( nThisEndX > nXw )
+                         nXw = nThisEndX;
+                     if ( nThisEndY > nYw )
+@@ -1864,10 +1941,10 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
+ 			if (bDoDouble)
+ 				ScColumn::bDoubleAlloc = TRUE;
+ 
+-            SCCOL nClipStartCol = pClipDoc->aClipRange.aStart.Col();
+-            SCROW nClipStartRow = pClipDoc->aClipRange.aStart.Row();
++            SCCOL nClipStartCol = aClipRange.aStart.Col();
++            SCROW nClipStartRow = aClipRange.aStart.Row();
+             // WaE: commented because unused:   SCCOL nClipEndCol = pClipDoc->aClipRange.aEnd.Col();
+-            SCROW nClipEndRow = pClipDoc->aClipRange.aEnd.Row();
++            SCROW nClipEndRow = aClipRange.aEnd.Row();
+             for (ULONG nRange = 0; nRange < pDestRanges->Count(); ++nRange)
+             {
+                 const ScRange* pRange = pDestRanges->GetObject( nRange);
+@@ -1918,7 +1995,7 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
+                         nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
+                     } while (nC1 <= nCol2);
+                     if (nClipStartRow > nClipEndRow)
+-                        nClipStartRow = pClipDoc->aClipRange.aStart.Row();
++                        nClipStartRow = aClipRange.aStart.Row();
+                     nC1 = nCol1;
+                     nC2 = nC1 + nXw;
+                     if (nC2 > nCol2)
+@@ -1991,19 +2068,80 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
+ 			// nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
+ 			BroadcastFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
+ 			if (bResetCut)
+-				pClipDoc->bCutMode = FALSE;
++				pClipDoc->GetClipParam().mbCutMode = false;
+ 			SetAutoCalc( bOldAutoCalc );
+ 		}
+ 	}
+ }
+ 
++void ScDocument::CopyMultiRangeFromClip(
++    const ScAddress& rDestPos, const ScMarkData& rMark, sal_uInt16 nInsFlag, ScDocument* pClipDoc,
++    bool bResetCut, bool bAsLink, bool bIncludeFiltered, bool bSkipAttrForEmpty)
++{
++    fprintf(stdout, "ScDocument::CopyMultiRangeFromClip:   skip empty (%d)\n", bSkipAttrForEmpty);
++
++    if (bIsClip)
++        return;
++
++    if (!pClipDoc->bIsClip || !pClipDoc->GetTableCount())
++        // There is nothing in the clip doc to copy.
++        return;
++
++    SCCOL nCol1 = rDestPos.Col();
++    SCROW nRow1 = rDestPos.Row();
++    ScClipParam& rClipParam = pClipDoc->GetClipParam();
++
++    ScCopyBlockFromClipParams aCBFCP;
++    aCBFCP.pRefUndoDoc = NULL;
++    aCBFCP.pClipDoc = pClipDoc;
++    aCBFCP.nInsFlag = nInsFlag;
++    aCBFCP.bAsLink	= bAsLink;
++    aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
++    aCBFCP.nTabStart = MAXTAB;
++    aCBFCP.nTabEnd = 0;
++
++    SCCOL nCols = rClipParam.getPasteColSize();
++    SCROW nRows = rClipParam.getPasteRowSize();
++    for (SCTAB j = 0; j <= MAXTAB; ++j)
++    {    
++        if (pTab[j] && rMark.GetTableSelect(j))
++        {
++            if ( j < aCBFCP.nTabStart )
++                aCBFCP.nTabStart = j;
++            aCBFCP.nTabEnd = j;
++        }
++    }
++
++    if (!bSkipAttrForEmpty)
++    {
++        sal_uInt16 nDelFlag = IDF_CONTENTS;
++        DeleteArea(nCol1, nRow1, nCol1+nCols-1, nRow1+nRows-1, rMark, nDelFlag);
++    }
++
++    for (ScRange* p = rClipParam.maRanges.First(); p; p = rClipParam.maRanges.Next())
++    {
++        SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
++        SCsROW nDy = static_cast<SCsROW>(nRow1 - p->aStart.Row());
++        SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
++        SCROW nRow2 = nRow1 + p->aEnd.Row() - p->aStart.Row();
++    
++        CopyBlockFromClip(nCol1, nRow1, nCol2, nRow2, rMark, nDx, nDy, &aCBFCP);
++
++        if (rClipParam.meDirection == ScClipParam::Column)
++            nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
++        if (rClipParam.meDirection == ScClipParam::Row)
++            nRow1 += p->aEnd.Row() - p->aStart.Row() + 1;
++    }
++}
+ 
+ void ScDocument::SetClipArea( const ScRange& rArea, BOOL bCut )
+ {
+ 	if (bIsClip)
+ 	{
+-		aClipRange = rArea;
+-		bCutMode = bCut;
++        ScClipParam& rClipParam = GetClipParam();
++        rClipParam.maRanges.RemoveAll();
++        rClipParam.maRanges.Append(rArea);
++		rClipParam.mbCutMode = bCut;
+ 	}
+ 	else
+ 	{
+@@ -2014,34 +2152,54 @@ void ScDocument::SetClipArea( const ScRange& rArea, BOOL bCut )
+ 
+ void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, BOOL bIncludeFiltered)
+ {
+-	if (bIsClip)
+-	{
+-		nClipX = aClipRange.aEnd.Col() - aClipRange.aStart.Col();
+-
+-		if ( bIncludeFiltered )
+-			nClipY = aClipRange.aEnd.Row() - aClipRange.aStart.Row();
+-		else
+-		{
+-			//	count non-filtered rows
+-			//	count on first used table in clipboard
+-			SCTAB nCountTab = 0;
+-			while ( nCountTab < MAXTAB && !pTab[nCountTab] )
+-				++nCountTab;
+-
+-            SCROW nResult = GetRowFlagsArray( nCountTab).CountForCondition(
+-                    aClipRange.aStart.Row(), aClipRange.aEnd.Row(),
+-                    CR_FILTERED, 0);
+-
+-			if ( nResult > 0 )
+-				nClipY = nResult - 1;
+-			else
+-				nClipY = 0;					// always return at least 1 row
+-		}
+-	}
+-	else
+-	{
++    if (!bIsClip)
++    {    
+ 		DBG_ERROR("GetClipArea: kein Clip");
+-	}
++        return;
++    }
++
++    ScRangeList& rClipRanges = GetClipParam().maRanges;
++    if (!rClipRanges.Count())
++        // No clip range.  Bail out.
++        return;
++
++    ScRangePtr p = rClipRanges.First();
++    SCCOL nStartCol = p->aStart.Col();
++    SCCOL nEndCol   = p->aEnd.Col();
++    SCROW nStartRow = p->aStart.Row();
++    SCROW nEndRow   = p->aEnd.Row();
++    for (p = rClipRanges.Next(); p; p = rClipRanges.Next())
++    {
++        if (p->aStart.Col() < nStartCol)
++            nStartCol = p->aStart.Col();
++        if (p->aStart.Row() < nStartRow)
++            nStartRow = p->aStart.Row();
++        if (p->aEnd.Col() > nEndCol)
++            nEndCol = p->aEnd.Col();
++        if (p->aEnd.Row() < nEndRow)
++            nEndRow = p->aEnd.Row();
++    }
++
++    nClipX = nEndCol - nStartCol;
++
++    if ( bIncludeFiltered )
++        nClipY = nEndRow - nStartRow;
++    else
++    {
++        //	count non-filtered rows
++        //	count on first used table in clipboard
++        SCTAB nCountTab = 0;
++        while ( nCountTab < MAXTAB && !pTab[nCountTab] )
++            ++nCountTab;
++
++        SCROW nResult = GetRowFlagsArray( nCountTab).CountForCondition(
++                nStartRow, nEndRow, CR_FILTERED, 0);
++
++        if ( nResult > 0 )
++            nClipY = nResult - 1;
++        else
++            nClipY = 0;					// always return at least 1 row
++    }
+ }
+ 
+ 
+@@ -2049,8 +2207,12 @@ void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
+ {
+ 	if (bIsClip)
+ 	{
+-		nClipX = aClipRange.aStart.Col();
+-		nClipY = aClipRange.aStart.Row();
++        ScRangeList& rClipRanges = GetClipParam().maRanges;
++        if (rClipRanges.Count())
++        {
++            nClipX = rClipRanges.First()->aStart.Col();
++            nClipY = rClipRanges.First()->aStart.Row();
++        }
+ 	}
+ 	else
+ 	{
+@@ -2066,8 +2228,12 @@ BOOL ScDocument::HasClipFilteredRows()
+ 	while ( nCountTab < MAXTAB && !pTab[nCountTab] )
+ 		++nCountTab;
+ 
+-    return GetRowFlagsArray( nCountTab).HasCondition( aClipRange.aStart.Row(),
+-            aClipRange.aEnd.Row(), CR_FILTERED, CR_FILTERED);
++    ScRangeList& rClipRanges = GetClipParam().maRanges;
++    if (!rClipRanges.Count())
++        return false;
++
++    return GetRowFlagsArray( nCountTab).HasCondition( rClipRanges.First()->aStart.Row(),
++            rClipRanges.First()->aEnd.Row(), CR_FILTERED, CR_FILTERED);
+ }
+ 
+ 
+diff --git sc/source/core/data/makefile.mk sc/source/core/data/makefile.mk
+index bd0ded7..2abd0d8 100644
+--- sc/source/core/data/makefile.mk
++++ sc/source/core/data/makefile.mk
+@@ -56,6 +56,7 @@ SLOFILES =  \
+ 	$(SLO)$/bcaslot.obj \
+ 	$(SLO)$/cell.obj \
+ 	$(SLO)$/cell2.obj \
++        $(SLO)$/clipparam.obj \
+ 	$(SLO)$/column.obj \
+ 	$(SLO)$/column2.obj \
+ 	$(SLO)$/column3.obj \
+diff --git sc/source/core/data/table2.cxx sc/source/core/data/table2.cxx
+index 2f92042..b92cbf8 100644
+--- sc/source/core/data/table2.cxx
++++ sc/source/core/data/table2.cxx
+@@ -367,6 +367,16 @@ void ScTable::CopyToClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ 	}
+ }
+ 
++void ScTable::CopyToClip(const ScRangeList& rRanges, ScTable* pTable, 
++                         bool bKeepScenarioFlags, bool bCloneNoteCaptions)
++{
++    ScRangeList aRanges(rRanges);
++    for (ScRangePtr p = aRanges.First(); p; p = aRanges.Next())
++    {
++        CopyToClip(p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), 
++                   pTable, bKeepScenarioFlags, bCloneNoteCaptions);
++    }
++}
+ 
+ void ScTable::CopyFromClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ 							SCsCOL nDx, SCsROW nDy, USHORT nInsFlag,
+diff --git sc/source/ui/inc/viewfunc.hxx sc/source/ui/inc/viewfunc.hxx
+index 051a705..243628c 100644
+--- sc/source/ui/inc/viewfunc.hxx
++++ sc/source/ui/inc/viewfunc.hxx
+@@ -359,6 +359,10 @@ private:
+ 	void			PasteRTF( SCCOL nCol, SCROW nStartRow,
+ 								const ::com::sun::star::uno::Reference<
+ 										::com::sun::star::datatransfer::XTransferable >& rxTransferable );
++    bool            PasteMultiRangesFromClip( sal_uInt16 nFlags, ScDocument* pClipDoc, sal_uInt16 nFunction,
++                                              bool bSkipEmpty, bool bTranspos, bool bAsLink,
++                                              InsCellCmd eMoveMode, sal_uInt16 nUndoExtraFlags );
++
+ 	USHORT			GetOptimalColWidth( SCCOL nCol, SCTAB nTab, BOOL bFormula );
+ 
+ 	void			StartFormatArea();
+diff --git sc/source/ui/view/tabvwsh4.cxx sc/source/ui/view/tabvwsh4.cxx
+index 551ce8a..3d49c52 100644
+--- sc/source/ui/view/tabvwsh4.cxx
++++ sc/source/ui/view/tabvwsh4.cxx
+@@ -1513,7 +1513,7 @@ BOOL ScTabViewShell::TabKeyInput(const KeyEvent& rKEvt)
+ 		//	#51889# Spezialfall: Copy/Cut bei Mehrfachselektion -> Fehlermeldung
+ 		//	(Slot ist disabled, SfxViewShell::KeyInput wuerde also kommentarlos verschluckt)
+ 		KeyFuncType eFunc = aCode.GetFunction();
+-		if ( eFunc == KEYFUNC_COPY || eFunc == KEYFUNC_CUT )
++		if ( eFunc == KEYFUNC_CUT )
+ 		{
+ 			ScRange aDummy;
+ 			ScMarkType eMarkType = GetViewData()->GetSimpleArea( aDummy );
+diff --git sc/source/ui/view/viewfun3.cxx sc/source/ui/view/viewfun3.cxx
+index a675074..7d66f71 100644
+--- sc/source/ui/view/viewfun3.cxx
++++ sc/source/ui/view/viewfun3.cxx
+@@ -210,6 +210,7 @@
+ #include "drwtrans.hxx"
+ #include "docuno.hxx"
+ #include "undodat.hxx"   // Amelia Wang
++#include "clipparam.hxx"
+ 
+ using namespace com::sun::star;
+ 
+@@ -310,10 +311,10 @@ BOOL ScViewFunc::CopyToClip( ScDocument* pClipDoc, BOOL bCut, BOOL bApi, BOOL bI
+ 
+ 	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 )
+ 	{
+-		ScDocument* pDoc = GetViewData()->GetDocument();
+-		ScMarkData& rMark = GetViewData()->GetMarkData();
+ 		if ( !pDoc->HasSelectedBlockMatrixFragment(
+ 						aRange.aStart.Col(), aRange.aStart.Row(),
+ 						aRange.aEnd.Col(),   aRange.aEnd.Row(),
+@@ -380,10 +381,131 @@ BOOL ScViewFunc::CopyToClip( ScDocument* pClipDoc, BOOL bCut, BOOL bApi, BOOL bI
+ 				ErrorMessage(STR_MATRIXFRAGMENTERR);
+ 		}
+ 	}
++    else if (eMarkType == SC_MARK_MULTI)
++    {
++        bool bSuccess = false;
++        fprintf(stdout, "ScViewFunc::CopyToClip:   multi selection.\n");
++        ScClipParam aClipParam;
++        aClipParam.mbCutMode = false;
++        rMark.FillRangeListWithMarks(&aClipParam.maRanges, false);
++        String aStr;
++        aClipParam.maRanges.Format(aStr, SCR_ABS_3D, pDoc);
++        fprintf(stdout, "ScViewFunc::CopyToClip:   ranges = '%s'\n", 
++                rtl::OUStringToOString(aStr, RTL_TEXTENCODING_UTF8).getStr());
++
++        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;
++            ScRangePtr p = aClipParam.maRanges.First();
++            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 (p = aClipParam.maRanges.Next(); p; p = aClipParam.maRanges.Next())
++            {
++                if (pDoc->HasSelectedBlockMatrixFragment(
++                    p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), rMark))
++                {    
++                    bValidRanges = false;
++                    break;
++                }
++
++                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, false);
++
++            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);
++        if (!bApi)
++            ErrorMessage(STR_NOMULTISELECT);
+ 	}
+ 
+ 	return bDone;
+@@ -755,6 +877,11 @@ BOOL ScViewFunc::PasteFromClip( USHORT nFlags, ScDocument* pClipDoc,
+ 		return FALSE;
+ 	}
+ 
++    ScClipParam& rClipParam = pClipDoc->GetClipParam();
++    if (rClipParam.isMultiRange())
++        return PasteMultiRangesFromClip(nFlags, pClipDoc, nFunction, bSkipEmpty, bTranspose, bAsLink, 
++                                        eMoveMode, nUndoExtraFlags);
++
+ 	//	fuer Undo etc. immer alle oder keine Inhalte sichern
+ 	USHORT nContFlags = IDF_NONE;
+ 	if (nFlags & IDF_CONTENTS)
+diff --git sc/source/ui/view/viewfun4.cxx sc/source/ui/view/viewfun4.cxx
+index d3bf9ec..14bc277 100644
+--- sc/source/ui/view/viewfun4.cxx
++++ sc/source/ui/view/viewfun4.cxx
+@@ -81,6 +81,7 @@
+ #include "impex.hxx"
+ #include "editutil.hxx"
+ #include "editable.hxx"
++#include "clipparam.hxx"
+ 
+ using namespace com::sun::star;
+ 
+@@ -188,6 +189,148 @@ void ScViewFunc::PasteRTF( SCCOL nStartCol, SCROW nStartRow,
+ 	}
+ }
+ 
++namespace {
++
++class CursorSwitcher
++{
++public:
++    CursorSwitcher(ScViewFunc* pViewFunc) :
++        mpViewFunc(pViewFunc)
++    {
++        mpViewFunc->HideCursor();
++    }
++
++    ~CursorSwitcher()
++    {
++        mpViewFunc->ShowCursor();
++    }
++private:
++    ScViewFunc* mpViewFunc;
++};
++
++}
++
++bool ScViewFunc::PasteMultiRangesFromClip(
++    sal_uInt16 nFlags, ScDocument* pClipDoc, sal_uInt16 nFunction,
++    bool bSkipEmpty, bool bTranspose, bool bAsLink, InsCellCmd eMoveMode, sal_uInt16 nUndoExtraFlags)
++{
++    StackPrinter __stack_printer__("ScViewFunc::PasteMultiRangesFromClip");
++    ScClipParam& rClipParam = pClipDoc->GetClipParam();
++    switch (rClipParam.meDirection)
++    {
++        case ScClipParam::Column:
++            fprintf(stdout, "ScViewFunc::PasteMultiRangesFromClip:   column direction\n");
++        break;
++        case ScClipParam::Row:
++            fprintf(stdout, "ScViewFunc::PasteMultiRangesFromClip:   row direction\n");
++        break;
++        default:
++            fprintf(stdout, "ScViewFunc::PasteMultiRangesFromClip:   other\n");
++    }
++
++    String aStr;
++    rClipParam.maRanges.Format(aStr, SCR_ABS_3D, pClipDoc);
++    fprintf(stdout, "ScViewFunc::PasteMultiRangesFromClip:   ranges = '%s'\n", 
++            rtl::OUStringToOString(aStr, RTL_TEXTENCODING_UTF8).getStr());
++
++    fprintf(stdout, "ScViewFunc::PasteMultiRangesFromClip:   skip empty? (%d)\n", bSkipEmpty);
++
++    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;
++
++    ScViewData& rViewData = *GetViewData();
++    ScDocument* pDoc = rViewData.GetDocument();
++    ScDocShell* pDocSh = rViewData.GetDocShell();
++    ScMarkData aMark(rViewData.GetMarkData());
++    const ScAddress& rCurPos = rViewData.GetCurPos();
++    SCCOL nColSize = rClipParam.getPasteColSize();
++    SCROW nRowSize = rClipParam.getPasteRowSize();
++
++    // 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;
++
++    if (bTranspose)
++    {
++        if (nRowSize > 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);
++    }
++
++    // 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);
++    aMark.SetMarkArea(aMarkedRange);
++
++    ::std::auto_ptr<ScDocument> pUndoDoc;
++    if (pDoc->IsUndoEnabled())
++    {
++        pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
++        pUndoDoc->InitUndoSelected(pDoc, aMark, false, false);
++        pDoc->CopyToDocument(aMarkedRange, IDF_ALL, 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);
++        }
++    }
++
++    CursorSwitcher aCursorSwitch(this);
++    MarkRange(aMarkedRange);
++    pDoc->CopyMultiRangeFromClip(rCurPos, aMark, nContFlags, pClipDoc, 
++                                 true, bAsLink, false, bSkipEmpty);
++
++    if (pMixDoc.get())          
++        pDoc->MixDocument(aMarkedRange, nFunction, bSkipEmpty, pMixDoc.get());
++
++    pDocSh->PostPaint(rCurPos.Col(), rCurPos.Row(), rCurPos.Tab(), 
++                      rCurPos.Col()+nColSize-1, rCurPos.Row()+nRowSize-1, rCurPos.Tab(), 
++                      PAINT_GRID);
++
++    if (pDoc->IsUndoEnabled())
++    {
++        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, IDF_ALL, NULL, NULL, NULL, NULL, false);
++        pDocSh->GetUndoManager()->AddUndoAction(pUndo, false);
++    }
++    return true;
++}
++
+ //	Thesaurus - Undo ok
+ void ScViewFunc::DoThesaurus( BOOL bRecord )
+ {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]