ooo-build r15429 - trunk/patches/test
- From: kyoshida svn gnome org
- To: svn-commits-list gnome org
- Subject: ooo-build r15429 - trunk/patches/test
- Date: Sat, 28 Feb 2009 06:43:07 +0000 (UTC)
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]