summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2022-03-19 12:52:21 +0900
committerTomaž Vajngerl <quikee@gmail.com>2022-04-12 01:23:55 +0200
commit7edd5f552c76bbe05c196cfdcdc5f94292a38a30 (patch)
tree5335cd6f576b7905032df8044ee5d6c3bfd24daa /sc
parentff13e71e72271736116632662b63f8f8dd3de54a (diff)
sc: add support for copy/cut and paste of Sparklines
Currently cut,copy and paste will copy the Sparkline and create a new SparklineGroup for each cell in the new cell range. This probably need to be adjusted so the SparklineGroup is shared. Change-Id: I6f86bb026753b2b4b5bfa46aca4ca9794721f311 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132473 Tested-by: Tomaž Vajngerl <quikee@gmail.com> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com> (cherry picked from commit b8cf500ed8ac7bd01a351e2815ce8251e506d79c) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132828 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Diffstat (limited to 'sc')
-rw-r--r--sc/inc/SparklineGroup.hxx31
-rw-r--r--sc/inc/clipcontext.hxx7
-rw-r--r--sc/inc/column.hxx11
-rw-r--r--sc/inc/mtvcellfunc.hxx8
-rw-r--r--sc/qa/unit/SparklineTest.cxx110
-rw-r--r--sc/source/core/data/clipcontext.cxx21
-rw-r--r--sc/source/core/data/column.cxx1
-rw-r--r--sc/source/core/data/column2.cxx69
-rw-r--r--sc/source/core/data/column3.cxx14
-rw-r--r--sc/source/core/data/column4.cxx50
-rw-r--r--sc/source/core/data/document10.cxx3
-rw-r--r--sc/source/ui/inc/cliputil.hxx6
12 files changed, 318 insertions, 13 deletions
diff --git a/sc/inc/SparklineGroup.hxx b/sc/inc/SparklineGroup.hxx
index 0d3935492d04..9f00985e9f61 100644
--- a/sc/inc/SparklineGroup.hxx
+++ b/sc/inc/SparklineGroup.hxx
@@ -105,7 +105,36 @@ public:
{
}
- SparklineGroup(const SparklineGroup&) = delete;
+ SparklineGroup(SparklineGroup const& pOtherSparkline)
+ : m_aColorSeries(pOtherSparkline.m_aColorSeries)
+ , m_aColorNegative(pOtherSparkline.m_aColorNegative)
+ , m_aColorAxis(pOtherSparkline.m_aColorAxis)
+ , m_aColorMarkers(pOtherSparkline.m_aColorMarkers)
+ , m_aColorFirst(pOtherSparkline.m_aColorFirst)
+ , m_aColorLast(pOtherSparkline.m_aColorLast)
+ , m_aColorHigh(pOtherSparkline.m_aColorHigh)
+ , m_aColorLow(pOtherSparkline.m_aColorLow)
+ , m_eMinAxisType(pOtherSparkline.m_eMinAxisType)
+ , m_eMaxAxisType(pOtherSparkline.m_eMaxAxisType)
+ , m_fLineWeight(pOtherSparkline.m_fLineWeight)
+ , m_eType(pOtherSparkline.m_eType)
+ , m_bDateAxis(pOtherSparkline.m_bDateAxis)
+ , m_eDisplayEmptyCellsAs(pOtherSparkline.m_eDisplayEmptyCellsAs)
+ , m_bMarkers(pOtherSparkline.m_bMarkers)
+ , m_bHigh(pOtherSparkline.m_bHigh)
+ , m_bLow(pOtherSparkline.m_bLow)
+ , m_bFirst(pOtherSparkline.m_bFirst)
+ , m_bLast(pOtherSparkline.m_bLast)
+ , m_bNegative(pOtherSparkline.m_bNegative)
+ , m_bDisplayXAxis(pOtherSparkline.m_bDisplayXAxis)
+ , m_bDisplayHidden(pOtherSparkline.m_bDisplayHidden)
+ , m_bRightToLeft(pOtherSparkline.m_bRightToLeft)
+ , m_aManualMax(pOtherSparkline.m_aManualMax)
+ , m_aManualMin(pOtherSparkline.m_aManualMin)
+ , m_sUID(pOtherSparkline.m_sUID)
+ {
+ }
+
SparklineGroup& operator=(const SparklineGroup&) = delete;
};
diff --git a/sc/inc/clipcontext.hxx b/sc/inc/clipcontext.hxx
index 32e2dd97767a..b09e1be78761 100644
--- a/sc/inc/clipcontext.hxx
+++ b/sc/inc/clipcontext.hxx
@@ -12,6 +12,7 @@
#include "address.hxx"
#include "cellvalue.hxx"
#include "celltextattr.hxx"
+#include "Sparkline.hxx"
#include <memory>
#include <vector>
@@ -60,11 +61,11 @@ class SC_DLLPUBLIC CopyFromClipContext final : public ClipContextBase
std::vector<sc::CellTextAttr> maSingleCellAttrs;
std::vector<const ScPatternAttr*> maSinglePatterns;
std::vector<const ScPostIt*> maSingleNotes;
+ std::vector<std::shared_ptr<sc::Sparkline>> maSingleSparkline;
ScConditionalFormatList* mpCondFormatList;
bool mbAsLink:1;
bool mbSkipEmptyCells:1;
- bool mbCloneNotes:1;
bool mbTableProtected:1;
public:
@@ -119,6 +120,9 @@ public:
const ScPostIt* getSingleCellNote( size_t nColOffset ) const;
void setSingleCellNote( size_t nColOffset, const ScPostIt* pNote );
+ std::shared_ptr<sc::Sparkline> const& getSingleSparkline(size_t nColOffset) const;
+ void setSingleSparkline(size_t nColOffset, std::shared_ptr<sc::Sparkline> const& pSparkline);
+
void setCondFormatList( ScConditionalFormatList* pCondFormatList );
ScConditionalFormatList* getCondFormatList();
@@ -135,6 +139,7 @@ public:
*/
bool isSkipEmptyCells() const;
bool isCloneNotes() const;
+ bool isCloneSparklines() const;
bool isDateCell( const ScColumn& rCol, SCROW nRow ) const;
};
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 6e2039a27456..962e6cc1f2ea 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -222,6 +222,9 @@ friend class sc::CellStoreEvent;
SCROW nRow, SCTAB nTab, const OUString& rString, formula::FormulaGrammar::AddressConvention eConv,
const ScSetStringParam* pParam );
+ void duplicateSparkline(sc::CopyFromClipContext& rContext, sc::ColumnBlockPosition* pBlockPos,
+ size_t nColOffset, size_t nDestSize, ScAddress aDestPosition);
+
public:
/** Broadcast mode for SetDirty(SCROW,SCROW,BroadcastMode). */
@@ -247,6 +250,8 @@ public:
const sc::CellTextAttrStoreType& GetCellAttrStore() const { return maCellTextAttrs; }
sc::CellNoteStoreType& GetCellNoteStore() { return maCellNotes; }
const sc::CellNoteStoreType& GetCellNoteStore() const { return maCellNotes; }
+ sc::SparklineStoreType& GetSparklineStore() { return maSparklines; }
+ const sc::SparklineStoreType& GetSparklineStore() const { return maSparklines; }
ScRefCellValue GetCellValue( SCROW nRow ) const;
ScRefCellValue GetCellValue( sc::ColumnBlockPosition& rBlockPos, SCROW nRow );
@@ -660,6 +665,10 @@ public:
void CreateSparklineCell(SCROW nRow, std::shared_ptr<sc::Sparkline> const& pSparkline);
void DeleteSparklineCells(sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2);
bool DeleteSparkline(SCROW nRow);
+ bool IsSparklinesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const;
+ void CopyCellSparklinesToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, SCROW nRowOffsetDest) const;
+ void DuplicateSparklines(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol,
+ sc::ColumnBlockPosition& rDestBlockPos, SCROW nRowOffsetDest = 0) const;
// cell notes
ScPostIt* GetCellNote( SCROW nRow );
@@ -688,7 +697,7 @@ public:
SCROW nRowOffsetDest = 0) const;
void DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol,
- sc::ColumnBlockPosition& maDestBlockPos, bool bCloneCaption, SCROW nRowOffsetDest=0 ) const;
+ sc::ColumnBlockPosition& rDestBlockPos, bool bCloneCaption, SCROW nRowOffsetDest = 0) const;
void UpdateNoteCaptions( SCROW nRow1, SCROW nRow2 );
diff --git a/sc/inc/mtvcellfunc.hxx b/sc/inc/mtvcellfunc.hxx
index a2a708d5f8fc..89e41fb915fd 100644
--- a/sc/inc/mtvcellfunc.hxx
+++ b/sc/inc/mtvcellfunc.hxx
@@ -178,6 +178,14 @@ ProcessBroadcaster(
BroadcasterStoreType, broadcaster_block, FuncElem, FuncElseNoOp<size_t> >(it, rStore, nRow1, nRow2, rFuncElem, aElse);
}
+template<typename Functor>
+typename SparklineStoreType::const_iterator
+ParseSparkline(const SparklineStoreType::const_iterator& itPos, const SparklineStoreType& rStore, SCROW nStart, SCROW nEnd, Functor& rFunctor)
+{
+ FuncElseNoOp<size_t> aElse;
+ return ParseElements1<SparklineStoreType, sparkline_block, Functor, FuncElseNoOp<size_t> >(itPos, rStore, nStart, nEnd, rFunctor, aElse);
+}
+
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/SparklineTest.cxx b/sc/qa/unit/SparklineTest.cxx
index 2a2dfde71b5b..167c4e4d9e3d 100644
--- a/sc/qa/unit/SparklineTest.cxx
+++ b/sc/qa/unit/SparklineTest.cxx
@@ -9,6 +9,8 @@
#include "helper/qahelper.hxx"
#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <cliputil.hxx>
#include <Sparkline.hxx>
#include <SparklineGroup.hxx>
@@ -46,10 +48,14 @@ public:
void testAddSparkline();
void testDeleteSprkline();
+ void testCopyPasteSparkline();
+ void testCutPasteSparkline();
CPPUNIT_TEST_SUITE(SparklineTest);
CPPUNIT_TEST(testAddSparkline);
CPPUNIT_TEST(testDeleteSprkline);
+ CPPUNIT_TEST(testCopyPasteSparkline);
+ CPPUNIT_TEST(testCutPasteSparkline);
CPPUNIT_TEST_SUITE_END();
};
@@ -118,6 +124,110 @@ void SparklineTest::testDeleteSprkline()
xDocSh->DoClose();
}
+void SparklineTest::testCopyPasteSparkline()
+{
+ ScDocShellRef xDocSh = loadEmptyDocument();
+ CPPUNIT_ASSERT(xDocSh);
+
+ ScDocument& rDocument = xDocSh->GetDocument();
+ ScTabViewShell* pViewShell = xDocSh->GetBestViewShell(false);
+ CPPUNIT_ASSERT(pViewShell);
+
+ auto* pCreatedSparkline = createTestSparkline(rDocument);
+ CPPUNIT_ASSERT(pCreatedSparkline);
+
+ ScRange aSourceRange(0, 6, 0, 0, 6, 0);
+ auto pSparkline = rDocument.GetSparkline(aSourceRange.aStart);
+
+ CPPUNIT_ASSERT(pSparkline);
+ CPPUNIT_ASSERT_EQUAL(SCCOL(0), pSparkline->getColumn());
+ CPPUNIT_ASSERT_EQUAL(SCROW(6), pSparkline->getRow());
+
+ // CopyToClip / CopyFromClip with a aClipDoc
+ {
+ ScDocument aClipDoc(SCDOCMODE_CLIP);
+ copyToClip(&rDocument, aSourceRange, &aClipDoc);
+
+ auto pClipSparkline = aClipDoc.GetSparkline(aSourceRange.aStart);
+ CPPUNIT_ASSERT(pClipSparkline);
+
+ ScRange aPasteRange(0, 7, 0, 0, 7, 0);
+
+ ScMarkData aMark(rDocument.GetSheetLimits());
+ aMark.SetMarkArea(aPasteRange);
+ rDocument.CopyFromClip(aPasteRange, aMark, InsertDeleteFlags::ALL, nullptr, &aClipDoc);
+
+ auto pSparklineCopy = rDocument.GetSparkline(aPasteRange.aStart);
+ CPPUNIT_ASSERT(pSparklineCopy);
+
+ CPPUNIT_ASSERT_EQUAL(SCCOL(0), pSparklineCopy->getColumn());
+ CPPUNIT_ASSERT_EQUAL(SCROW(7), pSparklineCopy->getRow());
+ }
+
+ // Copy / Paste with a ClipDoc
+ {
+ pViewShell->GetViewData().GetMarkData().SetMarkArea(aSourceRange);
+
+ // Copy
+ ScDocument aClipDoc(SCDOCMODE_CLIP);
+ pViewShell->GetViewData().GetView()->CopyToClip(&aClipDoc, false, false, false, false);
+
+ // Paste
+ ScRange aPasteRange(0, 8, 0, 0, 8, 0);
+
+ pViewShell->GetViewData().GetMarkData().SetMarkArea(aPasteRange);
+ pViewShell->GetViewData().GetView()->PasteFromClip(InsertDeleteFlags::ALL, &aClipDoc);
+
+ auto pSparklineCopy = rDocument.GetSparkline(aPasteRange.aStart);
+ CPPUNIT_ASSERT(pSparklineCopy);
+
+ CPPUNIT_ASSERT_EQUAL(SCCOL(0), pSparklineCopy->getColumn());
+ CPPUNIT_ASSERT_EQUAL(SCROW(8), pSparklineCopy->getRow());
+ }
+
+ xDocSh->DoClose();
+}
+
+void SparklineTest::testCutPasteSparkline()
+{
+ ScDocShellRef xDocSh = loadEmptyDocument();
+ CPPUNIT_ASSERT(xDocSh);
+
+ ScDocument& rDocument = xDocSh->GetDocument();
+ ScTabViewShell* pViewShell = xDocSh->GetBestViewShell(false);
+ CPPUNIT_ASSERT(pViewShell);
+
+ auto* pCreatedSparkline = createTestSparkline(rDocument);
+ CPPUNIT_ASSERT(pCreatedSparkline);
+
+ ScRange aSourceRange(0, 6, 0, 0, 6, 0);
+ auto pSparkline = rDocument.GetSparkline(aSourceRange.aStart);
+
+ CPPUNIT_ASSERT(pSparkline);
+ CPPUNIT_ASSERT_EQUAL(SCCOL(0), pSparkline->getColumn());
+ CPPUNIT_ASSERT_EQUAL(SCROW(6), pSparkline->getRow());
+
+ // Mark source range
+ pViewShell->GetViewData().GetMarkData().SetMarkArea(aSourceRange);
+
+ // Cut
+ pViewShell->GetViewData().GetView()->CopyToClip(nullptr, true /*bCut*/, false, false, true);
+
+ // Paste
+ ScRange aPasteRange(0, 7, 0, 0, 7, 0);
+ pViewShell->GetViewData().GetMarkData().SetMarkArea(aPasteRange);
+ ScClipUtil::PasteFromClipboard(pViewShell->GetViewData(), pViewShell, false);
+
+ // Check
+ auto pSparklineCopy = rDocument.GetSparkline(aPasteRange.aStart);
+ CPPUNIT_ASSERT(pSparklineCopy);
+
+ CPPUNIT_ASSERT_EQUAL(SCCOL(0), pSparklineCopy->getColumn());
+ CPPUNIT_ASSERT_EQUAL(SCROW(7), pSparklineCopy->getRow());
+
+ xDocSh->DoClose();
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SparklineTest);
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx
index 02e2bcc86652..70f2319a185f 100644
--- a/sc/source/core/data/clipcontext.cxx
+++ b/sc/source/core/data/clipcontext.cxx
@@ -46,7 +46,6 @@ CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc,
mnInsertFlag(nInsertFlag), mnDeleteFlag(InsertDeleteFlags::NONE),
mpCondFormatList(nullptr),
mbAsLink(bAsLink), mbSkipEmptyCells(bSkipEmptyCells),
- mbCloneNotes (mnInsertFlag & (InsertDeleteFlags::NOTE|InsertDeleteFlags::ADDNOTES)),
mbTableProtected(false)
{
}
@@ -120,6 +119,7 @@ void CopyFromClipContext::setSingleCellColumnSize( size_t nSize )
maSingleCellAttrs.resize(nSize);
maSinglePatterns.resize(nSize, nullptr);
maSingleNotes.resize(nSize, nullptr);
+ maSingleSparkline.resize(nSize);
}
ScCellValue& CopyFromClipContext::getSingleCell( size_t nColOffset )
@@ -300,6 +300,18 @@ void CopyFromClipContext::setSingleCellNote( size_t nColOffset, const ScPostIt*
maSingleNotes[nColOffset] = pNote;
}
+std::shared_ptr<sc::Sparkline> const& CopyFromClipContext::getSingleSparkline(size_t nColOffset) const
+{
+ assert(nColOffset < maSingleSparkline.size());
+ return maSingleSparkline[nColOffset];
+}
+
+void CopyFromClipContext::setSingleSparkline(size_t nColOffset, std::shared_ptr<sc::Sparkline> const& pSparkline)
+{
+ assert(nColOffset < maSingleSparkline.size());
+ maSingleSparkline[nColOffset] = pSparkline;
+}
+
void CopyFromClipContext::setCondFormatList( ScConditionalFormatList* pCondFormatList )
{
mpCondFormatList = pCondFormatList;
@@ -332,7 +344,12 @@ bool CopyFromClipContext::isSkipEmptyCells() const
bool CopyFromClipContext::isCloneNotes() const
{
- return mbCloneNotes;
+ return bool(mnInsertFlag & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES));
+}
+
+bool CopyFromClipContext::isCloneSparklines() const
+{
+ return bool(mnInsertFlag & InsertDeleteFlags::SPARKLINES);
}
bool CopyFromClipContext::isDateCell( const ScColumn& rCol, SCROW nRow ) const
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index da2763064c31..94c83f002dfe 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -918,6 +918,7 @@ public:
setDefaultAttrsToDest(nTopRow, nDataSize);
mrSrcCol.DuplicateNotes(nTopRow, nDataSize, mrDestCol, maDestPos, false);
+ mrSrcCol.DuplicateSparklines(nTopRow, nDataSize, mrDestCol, maDestPos);
}
};
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 5a6d4c435e68..fc262bc78627 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -42,6 +42,7 @@
#include <rowheightcontext.hxx>
#include <tokenstringcontext.hxx>
#include <sortparam.hxx>
+#include <SparklineGroup.hxx>
#include <editeng/eeitem.hxx>
#include <o3tl/safeint.hxx>
@@ -1996,6 +1997,74 @@ bool ScColumn::DeleteSparkline(SCROW nRow)
return true;
}
+bool ScColumn::IsSparklinesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
+{
+ std::pair<sc::SparklineStoreType::const_iterator,size_t> aPos = maSparklines.position(nStartRow);
+ sc::SparklineStoreType::const_iterator it = aPos.first;
+ if (it == maSparklines.end())
+ return false;
+
+ if (it->type != sc::element_type_empty)
+ return false;
+
+ // start position of next block which is not empty.
+ SCROW nNextRow = nStartRow + it->size - aPos.second;
+ return nEndRow < nNextRow;
+}
+
+namespace
+{
+
+class CopySparklinesHandler
+{
+ ScColumn& mrDestColumn;
+ sc::SparklineStoreType& mrDestSparkline;
+ sc::SparklineStoreType::iterator miDestPosition;
+ SCROW mnDestOffset;
+
+public:
+ CopySparklinesHandler(ScColumn& rDestColumn, SCROW nDestOffset)
+ : mrDestColumn(rDestColumn)
+ , mrDestSparkline(mrDestColumn.GetSparklineStore())
+ , miDestPosition(mrDestSparkline.begin())
+ , mnDestOffset(nDestOffset)
+ {}
+
+ void operator() (size_t nRow, const sc::SparklineCell* pCell)
+ {
+ SCROW nDestRow = nRow + mnDestOffset;
+
+ auto const& pSparkline = pCell->getSparkline();
+ auto const& pGroup = pCell->getSparklineGroup();
+
+ auto pNewSparklineGroup = std::make_shared<sc::SparklineGroup>(*pGroup); // Copy the group
+ auto pNewSparkline = std::make_shared<sc::Sparkline>(mrDestColumn.GetCol(), nDestRow, pNewSparklineGroup);
+
+ pNewSparkline->setInputRange(pSparkline->getInputRange());
+
+ miDestPosition = mrDestSparkline.set(miDestPosition, nDestRow, new sc::SparklineCell(pNewSparkline));
+ }
+};
+
+}
+
+void ScColumn::CopyCellSparklinesToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, SCROW nRowOffsetDest) const
+{
+ if (IsSparklinesEmptyBlock(nRow1, nRow2))
+ // The column has no cell sparklines to copy between specified rows.
+ return;
+
+ CopySparklinesHandler aFunctor(rDestCol, nRowOffsetDest);
+ sc::ParseSparkline(maSparklines.begin(), maSparklines, nRow1, nRow2, aFunctor);
+}
+
+void ScColumn::DuplicateSparklines(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol,
+ sc::ColumnBlockPosition& rDestBlockPos, SCROW nRowOffsetDest) const
+{
+ CopyCellSparklinesToDocument(nStartRow, nStartRow + nDataSize - 1, rDestCol, nRowOffsetDest);
+ rDestBlockPos.miSparklinePos = rDestCol.maSparklines.begin();
+}
+
// Notes
ScPostIt* ScColumn::GetCellNote(SCROW nRow)
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 798ac2579ce3..966a182cbf7c 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1120,6 +1120,11 @@ class CopyCellsFromClipHandler
mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestBlockPos, bCloneCaption, mnRowOffset);
}
+ void duplicateSparklines(SCROW nStartRow, size_t nDataSize)
+ {
+ mrSrcCol.DuplicateSparklines(nStartRow, nDataSize, mrDestCol, maDestBlockPos, mnRowOffset);
+ }
+
public:
CopyCellsFromClipHandler(sc::CopyFromClipContext& rCxt, ScColumn& rSrcCol, ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, tools::Long nRowOffset, svl::SharedStringPool* pSharedStringPool) :
mrCxt(rCxt),
@@ -1159,6 +1164,7 @@ public:
{
SCROW nSrcRow1 = node.position + nOffset;
bool bCopyCellNotes = mrCxt.isCloneNotes();
+ bool bCopySparklines = mrCxt.isCloneSparklines();
InsertDeleteFlags nFlags = mrCxt.getInsertFlag();
@@ -1169,6 +1175,10 @@ public:
bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
}
+ if (bCopySparklines) // If there is a sparkline is it empty?
+ {
+ duplicateSparklines(nSrcRow1, nDataSize);
+ }
return;
}
@@ -1359,6 +1369,10 @@ public:
bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
}
+ if (bCopySparklines)
+ {
+ duplicateSparklines(nSrcRow1, nDataSize);
+ }
}
};
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index c2fc0e54d33e..c2dc4a63085b 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -31,6 +31,8 @@
#include <recursionhelper.hxx>
#include <docsh.hxx>
+#include <SparklineGroup.hxx>
+
#include <o3tl/safeint.hxx>
#include <svl/sharedstringpool.hxx>
#include <sal/log.hxx>
@@ -116,6 +118,9 @@ void ScColumn::DeleteBeforeCopyFromClip(
if (nDelFlag & InsertDeleteFlags::NOTE)
DeleteCellNotes(*pBlockPos, aRange.mnRow1, aRange.mnRow2, false);
+ if (nDelFlag & InsertDeleteFlags::SPARKLINES)
+ DeleteSparklineCells(*pBlockPos, aRange.mnRow1, aRange.mnRow2);
+
if (nDelFlag & InsertDeleteFlags::EDITATTR)
RemoveEditAttribs(*pBlockPos, aRange.mnRow1, aRange.mnRow2);
@@ -204,6 +209,9 @@ void ScColumn::DeleteBeforeCopyFromClip(
if (nDelFlag & InsertDeleteFlags::NOTE)
DeleteCellNotes(*pBlockPos, nRow1, nRow2, false);
+ if (nDelFlag & InsertDeleteFlags::SPARKLINES)
+ DeleteSparklineCells(*pBlockPos, nRow1, nRow2);
+
if (nDelFlag & InsertDeleteFlags::EDITATTR)
RemoveEditAttribs(*pBlockPos, nRow1, nRow2);
@@ -321,6 +329,11 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
}
}
+ ScAddress aDestPosition(nCol, nRow1, nTab);
+
+ duplicateSparkline(rCxt, pBlockPos, nColOffset, nDestSize, aDestPosition);
+
+ // Notes
const ScPostIt* pNote = rCxt.getSingleCellNote(nColOffset);
if (!(pNote && (nFlags & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)) != InsertDeleteFlags::NONE))
return;
@@ -330,13 +343,12 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
ScDocument* pClipDoc = rCxt.getClipDoc();
const ScAddress aSrcPos = pClipDoc->GetClipParam().getWholeRange().aStart;
std::vector<ScPostIt*> aNotes;
- ScAddress aDestPos(nCol, nRow1, nTab);
aNotes.reserve(nDestSize);
for (size_t i = 0; i < nDestSize; ++i)
{
bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
- aNotes.push_back(pNote->Clone(aSrcPos, rDocument, aDestPos, bCloneCaption).release());
- aDestPos.IncRow();
+ aNotes.push_back(pNote->Clone(aSrcPos, rDocument, aDestPosition, bCloneCaption).release());
+ aDestPosition.IncRow();
}
pBlockPos->miCellNotePos =
@@ -344,11 +356,37 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
pBlockPos->miCellNotePos, nRow1, aNotes.begin(), aNotes.end());
// Notify our LOK clients.
- aDestPos.SetRow(nRow1);
+ aDestPosition.SetRow(nRow1);
for (size_t i = 0; i < nDestSize; ++i)
{
- ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Add, &rDocument, aDestPos, aNotes[i]);
- aDestPos.IncRow();
+ ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Add, &rDocument, aDestPosition, aNotes[i]);
+ aDestPosition.IncRow();
+ }
+}
+
+void ScColumn::duplicateSparkline(sc::CopyFromClipContext& rContext, sc::ColumnBlockPosition* pBlockPos,
+ size_t nColOffset, size_t nDestSize, ScAddress aDestPosition)
+{
+ if ((rContext.getInsertFlag() & InsertDeleteFlags::SPARKLINES) == InsertDeleteFlags::NONE)
+ return;
+
+ auto pSparkline = rContext.getSingleSparkline(nColOffset);
+ if (pSparkline)
+ {
+ auto const& pSparklineGroup = pSparkline->getSparklineGroup();
+
+ std::vector<sc::SparklineCell*> aSparklines(nDestSize, nullptr);
+ ScAddress aCurrentPosition = aDestPosition;
+ for (size_t i = 0; i < nDestSize; ++i)
+ {
+ auto pNewSparklineGroup = std::make_shared<sc::SparklineGroup>(*pSparklineGroup);
+ auto pNewSparkline = std::make_shared<sc::Sparkline>(aCurrentPosition.Col(), aCurrentPosition.Row(), pNewSparklineGroup);
+ pNewSparkline->setInputRange(pSparkline->getInputRange());
+ aSparklines[i] = new sc::SparklineCell(pNewSparkline);
+ aCurrentPosition.IncRow();
+ }
+
+ pBlockPos->miSparklinePos = maSparklines.set(pBlockPos->miSparklinePos, aDestPosition.Row(), aSparklines.begin(), aSparklines.end());
}
}
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index ada5aff2d625..2ceeb4954fd5 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -125,6 +125,9 @@ bool ScDocument::CopyOneCellFromClip(
if ((rCxt.getInsertFlag() & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)) != InsertDeleteFlags::NONE)
rCxt.setSingleCellNote(nColOffset, pClipDoc->GetNote(aSrcPos));
+ if ((rCxt.getInsertFlag() & InsertDeleteFlags::SPARKLINES) != InsertDeleteFlags::NONE)
+ rCxt.setSingleSparkline(nColOffset, pClipDoc->GetSparkline(aSrcPos));
+
ScColumn* pSrcCol = pSrcTab->FetchColumn(aSrcPos.Col());
assert(pSrcCol);
// Determine the script type of the copied single cell.
diff --git a/sc/source/ui/inc/cliputil.hxx b/sc/source/ui/inc/cliputil.hxx
index 022b3586d241..dc0ee5b9b8d4 100644
--- a/sc/source/ui/inc/cliputil.hxx
+++ b/sc/source/ui/inc/cliputil.hxx
@@ -10,6 +10,7 @@
#pragma once
#include <types.hxx>
+#include <scdllapi.h>
class ScViewData;
class ScTabViewShell;
@@ -19,9 +20,10 @@ class ScRangeList;
namespace ScClipUtil
{
- void PasteFromClipboard( ScViewData& rViewData, ScTabViewShell* pTabViewShell, bool bShowDialog );
- bool CheckDestRanges(
+SC_DLLPUBLIC void PasteFromClipboard( ScViewData& rViewData, ScTabViewShell* pTabViewShell, bool bShowDialog );
+
+bool CheckDestRanges(
const ScDocument& rDoc, SCCOL nSrcCols, SCROW nSrcRows, const ScMarkData& rMark,
const ScRangeList& rDest);
}