tdf#99969: make sure to copy the chart source ranges to clipboard
... even when they are outside of the copied cell range. Otherwise,
it is impossible to transfer the missing data when switching to
own data on paste.
The copy of the missing ranges avoids copying cell attributes, for
performance reasons, but also to avoid overwriting the attributes
of already copied cells. Otherwise, ScDrawLayer::CopyToClip would
need the bKeepScenarioFlags, or the CopyToClipContext used in the
caller ScDocument::CopyToClip, for consistent copy; or a method to
avoid overwriting already copied cells (this change simply copies
all chart ranges, withiut checking if they were copied already).
Change-Id: Id02e0c20517e7e8a17bb0a31d1b230196cda1a58
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164294
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/sc/inc/clipcontext.hxx b/sc/inc/clipcontext.hxx
index a6c989a..8c3bc17 100644
--- a/sc/inc/clipcontext.hxx
+++ b/sc/inc/clipcontext.hxx
@@ -161,12 +161,15 @@ public:
class CopyToClipContext final : public ClipContextBase
{
bool mbKeepScenarioFlags:1;
bool mbCopyChartRanges : 1 = false; // Copying ranges not included in selection:
// only copy data, not cell attributes
public:
CopyToClipContext(ScDocument& rDoc, bool bKeepScenarioFlags);
CopyToClipContext(ScDocument& rDoc, bool bKeepScenarioFlags, bool bCopyChartRanges = false);
virtual ~CopyToClipContext() override;
bool isKeepScenarioFlags() const;
bool isCopyChartRanges() const { return mbCopyChartRanges; }
};
class CopyToDocContext final : public ClipContextBase
diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx
index 4e6b925..fc6f136 100644
--- a/sc/source/core/data/clipcontext.cxx
+++ b/sc/source/core/data/clipcontext.cxx
@@ -403,8 +403,8 @@ bool CopyFromClipContext::isDateCell( const ScColumn& rCol, SCROW nRow ) const
}
CopyToClipContext::CopyToClipContext(
ScDocument& rDoc, bool bKeepScenarioFlags) :
ClipContextBase(rDoc), mbKeepScenarioFlags(bKeepScenarioFlags) {}
ScDocument& rDoc, bool bKeepScenarioFlags, bool bCopyChartRanges) :
ClipContextBase(rDoc), mbKeepScenarioFlags(bKeepScenarioFlags), mbCopyChartRanges(bCopyChartRanges) {}
CopyToClipContext::~CopyToClipContext() {}
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 22d8cec..34524e4 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -879,14 +879,16 @@ public:
void ScColumn::CopyToClip(
sc::CopyToClipContext& rCxt, SCROW nRow1, SCROW nRow2, ScColumn& rColumn ) const
{
pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
rCxt.isKeepScenarioFlags() ? (ScMF::All & ~ScMF::Scenario) : ScMF::All );
if (!rCxt.isCopyChartRanges()) // No need to copy attributes for chart ranges
pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
rCxt.isKeepScenarioFlags() ? (ScMF::All & ~ScMF::Scenario) : ScMF::All );
{
CopyToClipHandler aFunc(GetDoc(), *this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol));
sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
}
if (!rCxt.isCopyChartRanges()) // No need to copy attributes for chart ranges
{
CopyTextAttrToClipHandler aFunc(rColumn.maCellTextAttrs);
sc::ParseBlock(maCellTextAttrs.begin(), maCellTextAttrs, aFunc, nRow1, nRow2);
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 7ad5a3e..c5f3f50 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2223,6 +2223,7 @@ void ScDocument::CopyToClip(const ScClipParam& rClipParam,
sc::CopyToClipContext aCxt(*pClipDoc, bKeepScenarioFlags);
CopyRangeNamesToClip(pClipDoc, aClipRange, pMarks);
// 1. Copy selected cells
for (SCTAB i = 0; i < nEndTab; ++i)
{
if (!maTabs[i] || i >= pClipDoc->GetTableCount() || !pClipDoc->maTabs[i])
@@ -2232,12 +2233,17 @@ void ScDocument::CopyToClip(const ScClipParam& rClipParam,
continue;
maTabs[i]->CopyToClip(aCxt, rClipParam.maRanges, pClipDoc->maTabs[i].get());
}
if (mpDrawLayer && bIncludeObjects)
// 2. Copy drawing objects in the selection. Do in after the first "copy cells" pass, because
// the embedded objects (charts) coud reference cells from tabs not (yet) copied; doing it now
// allows to know what is already copied, to not owerwrite attributes of already copied data.
if (mpDrawLayer && bIncludeObjects)
{
for (SCTAB i = 0; i < nEndTab; ++i)
{
// also copy drawing objects
tools::Rectangle aObjRect = GetMMRect(
aClipRange.aStart.Col(), aClipRange.aStart.Row(), aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
tools::Rectangle aObjRect = GetMMRect(aClipRange.aStart.Col(), aClipRange.aStart.Row(),
aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i);
mpDrawLayer->CopyToClip(pClipDoc, i, aObjRect);
}
}
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index e404d6af..b9b2279 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -88,6 +88,7 @@
#include <docpool.hxx>
#include <detfunc.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <clipcontext.hxx>
#include <clipparam.hxx>
#include <memory>
@@ -1834,6 +1835,34 @@ void ScDrawLayer::CopyToClip( ScDocument* pClipDoc, SCTAB nTab, const tools::Rec
pDestPage->InsertObject(pNewObject.get());
// Store the chart's source data to the clipboad document, even when it's out of the
// copied range. It will be ignored when pasted to the same document; when pasted to
// another document, ScDocument::mpClipParam will provide the actually copied ranges,
// and the data copied here will be used to break connection and switch to own data
// in ScDrawLayer::CopyFromClip.
if (xOldChart && !xOldChart->hasInternalDataProvider())
{
sc::CopyToClipContext aCxt(*pClipDoc, false, true);
OUString aChartName = static_cast<SdrOle2Obj*>(pOldObject)->GetPersistName();
std::vector<ScRangeList> aRangesVector;
pDoc->GetChartRanges(aChartName, aRangesVector, *pDoc);
for (const ScRangeList& ranges : aRangesVector)
{
for (const ScRange& r : ranges)
{
for (SCTAB i = r.aStart.Tab(); i <= r.aEnd.Tab(); ++i)
{
ScTable* pTab = pDoc->FetchTable(i);
ScTable* pClipTab = pClipDoc->FetchTable(i);
if (!pTab || !pClipTab)
continue;
pTab->CopyToClip(aCxt, r.aStart.Col(), r.aStart.Row(), r.aEnd.Col(),
r.aEnd.Row(), pClipTab);
}
}
}
}
// no undo needed in clipboard document
// charts are not updated
}