sc/inc/SparklineGroup.hxx | 31 +++++++- sc/inc/clipcontext.hxx | 7 + sc/inc/column.hxx | 11 ++ sc/inc/document.hxx | 2 sc/inc/mtvcellfunc.hxx | 8 ++ sc/inc/table.hxx | 2 sc/qa/unit/SparklineImportExportTest.cxx | 12 +-- sc/qa/unit/SparklineTest.cxx | 120 +++++++++++++++++++++++++++++-- sc/source/core/data/clipcontext.cxx | 21 ++++- sc/source/core/data/column.cxx | 1 sc/source/core/data/column2.cxx | 69 +++++++++++++++++ sc/source/core/data/column3.cxx | 14 +++ sc/source/core/data/column4.cxx | 50 +++++++++++- sc/source/core/data/document.cxx | 4 - sc/source/core/data/document10.cxx | 3 sc/source/core/data/table2.cxx | 11 +- sc/source/ui/inc/cliputil.hxx | 6 + sc/source/ui/view/cellsh.cxx | 4 - sc/source/ui/view/output.cxx | 4 - 19 files changed, 341 insertions(+), 39 deletions(-)
New commits: commit 7edd5f552c76bbe05c196cfdcdc5f94292a38a30 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Sat Mar 19 12:52:21 2022 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Tue Apr 12 01:23:55 2022 +0200 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 <qui...@gmail.com> Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit b8cf500ed8ac7bd01a351e2815ce8251e506d79c) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132828 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> 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); } commit ff13e71e72271736116632662b63f8f8dd3de54a Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Sat Mar 19 10:56:27 2022 +0900 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Tue Apr 12 01:23:41 2022 +0200 sc: change GetSparkline to return a shared_ptr instead of raw ptr Change-Id: If3d7b3ad4b96eb7d3b126ee8b130f8d5e684cd3c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132472 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit 413f144e84629fe8f3bae5d984b40228fdeec5c1) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132795 Tested-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 02e8a8b26e4d..a79584f3e7a6 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -1241,7 +1241,7 @@ public: sc::MultiDataCellState HasMultipleDataCells( const ScRange& rRange ) const; /** Spaklines */ - SC_DLLPUBLIC sc::Sparkline* GetSparkline(ScAddress const & rPosition); + SC_DLLPUBLIC std::shared_ptr<sc::Sparkline> GetSparkline(ScAddress const & rPosition); SC_DLLPUBLIC sc::Sparkline* CreateSparkline(ScAddress const & rPosition, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup); SC_DLLPUBLIC sc::SparklineList* GetSparklineList(SCTAB nTab); SC_DLLPUBLIC bool DeleteSparkline(ScAddress const& rPosition); diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 4ae72c22418a..3fde00a7b414 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -475,7 +475,7 @@ public: // Sparklines - sc::Sparkline* GetSparkline(SCCOL nCol, SCROW nRow); + std::shared_ptr<sc::Sparkline> GetSparkline(SCCOL nCol, SCROW nRow); sc::Sparkline* CreateSparkline(SCCOL nCol, SCROW nRow, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup); bool DeleteSparkline(SCCOL nCol, SCROW nRow); diff --git a/sc/qa/unit/SparklineImportExportTest.cxx b/sc/qa/unit/SparklineImportExportTest.cxx index fe15d783b58e..25af95c8770e 100644 --- a/sc/qa/unit/SparklineImportExportTest.cxx +++ b/sc/qa/unit/SparklineImportExportTest.cxx @@ -57,7 +57,7 @@ void checkSparklines(ScDocument& rDocument) { // Sparkline at Sheet1:A2 { - sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 1, 0)); // A2 + auto pSparkline = rDocument.GetSparkline(ScAddress(0, 1, 0)); // A2 CPPUNIT_ASSERT(pSparkline); auto pSparklineGroup = pSparkline->getSparklineGroup(); CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, pSparklineGroup->m_eType); @@ -90,7 +90,7 @@ void checkSparklines(ScDocument& rDocument) } // Sparkline at Sheet1:A3 { - sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 2, 0)); // A3 + auto pSparkline = rDocument.GetSparkline(ScAddress(0, 2, 0)); // A3 CPPUNIT_ASSERT(pSparkline); auto pSparklineGroup = pSparkline->getSparklineGroup(); CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, pSparklineGroup->m_eType); @@ -123,28 +123,28 @@ void checkSparklines(ScDocument& rDocument) } // Sparkline at Sheet2:B1 { - sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 0, 1)); //B1 + auto pSparkline = rDocument.GetSparkline(ScAddress(1, 0, 1)); //B1 CPPUNIT_ASSERT(pSparkline); auto pSparklineGroup = pSparkline->getSparklineGroup(); CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Column, pSparklineGroup->m_eType); } // Sparkline at Sheet2:B2 { - sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 1)); //B2 + auto pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 1)); //B2 CPPUNIT_ASSERT(pSparkline); auto pSparklineGroup = pSparkline->getSparklineGroup(); CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, pSparklineGroup->m_eType); } // Sparkline at Sheet2:B2 { - sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 1)); //B2 + auto pSparkline = rDocument.GetSparkline(ScAddress(1, 1, 1)); //B2 CPPUNIT_ASSERT(pSparkline); auto pSparklineGroup = pSparkline->getSparklineGroup(); CPPUNIT_ASSERT_EQUAL(sc::SparklineType::Line, pSparklineGroup->m_eType); } // Sparkline doesn't exists at A4 { - sc::Sparkline* pSparkline = rDocument.GetSparkline(ScAddress(0, 3, 0)); //A4 + auto pSparkline = rDocument.GetSparkline(ScAddress(0, 3, 0)); //A4 CPPUNIT_ASSERT(!pSparkline); } } diff --git a/sc/qa/unit/SparklineTest.cxx b/sc/qa/unit/SparklineTest.cxx index 74f40579d99f..2a2dfde71b5b 100644 --- a/sc/qa/unit/SparklineTest.cxx +++ b/sc/qa/unit/SparklineTest.cxx @@ -82,13 +82,13 @@ void SparklineTest::testAddSparkline() ScDocument& rDocument = xDocSh->GetDocument(); - sc::Sparkline* pSparkline = createTestSparkline(rDocument); + auto pSparkline = createTestSparkline(rDocument); CPPUNIT_ASSERT(pSparkline); - sc::Sparkline* pGetSparkline = rDocument.GetSparkline(ScAddress(0, 6, 0)); + auto pGetSparkline = rDocument.GetSparkline(ScAddress(0, 6, 0)); CPPUNIT_ASSERT(pGetSparkline); - CPPUNIT_ASSERT_EQUAL(pGetSparkline, pSparkline); + CPPUNIT_ASSERT_EQUAL(pGetSparkline.get(), pSparkline); sc::SparklineList* pList = rDocument.GetSparklineList(0); CPPUNIT_ASSERT(pList); @@ -107,12 +107,12 @@ void SparklineTest::testDeleteSprkline() ScDocument& rDocument = xDocSh->GetDocument(); - sc::Sparkline* pSparkline = createTestSparkline(rDocument); + auto pSparkline = createTestSparkline(rDocument); CPPUNIT_ASSERT(pSparkline); clearRange(&rDocument, ScRange(0, 6, 0, 0, 6, 0)); - sc::Sparkline* pGetSparkline = rDocument.GetSparkline(ScAddress(0, 6, 0)); + auto pGetSparkline = rDocument.GetSparkline(ScAddress(0, 6, 0)); CPPUNIT_ASSERT(!pGetSparkline); xDocSh->DoClose(); diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index db13642e060d..5f4e6c466c07 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -6557,7 +6557,7 @@ bool ScDocument::IsInVBAMode() const } // Sparklines -sc::Sparkline* ScDocument::GetSparkline(ScAddress const& rPosition) +std::shared_ptr<sc::Sparkline> ScDocument::GetSparkline(ScAddress const& rPosition) { SCTAB nTab = rPosition.Tab(); @@ -6565,7 +6565,7 @@ sc::Sparkline* ScDocument::GetSparkline(ScAddress const& rPosition) { return maTabs[nTab]->GetSparkline(rPosition.Col(), rPosition.Row()); } - return nullptr; + return std::shared_ptr<sc::Sparkline>(); } sc::Sparkline* ScDocument::CreateSparkline(ScAddress const& rPosition, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup) diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index fc7689ebe4a4..3f12b3cd3579 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -1811,19 +1811,16 @@ ScFormulaCell* ScTable::GetFormulaCell( SCCOL nCol, SCROW nRow ) // Sparklines -sc::Sparkline* ScTable::GetSparkline(SCCOL nCol, SCROW nRow) +std::shared_ptr<sc::Sparkline> ScTable::GetSparkline(SCCOL nCol, SCROW nRow) { if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount()) - return nullptr; + return std::shared_ptr<sc::Sparkline>(); sc::SparklineCell* pSparklineCell = aCol[nCol].GetSparklineCell(nRow); if (!pSparklineCell) - return nullptr; + return std::shared_ptr<sc::Sparkline>(); - std::shared_ptr<sc::Sparkline> pSparkline(pSparklineCell->getSparkline()); - assert(pSparkline); - - return pSparkline.get(); + return pSparklineCell->getSparkline(); } sc::Sparkline* ScTable::CreateSparkline(SCCOL nCol, SCROW nRow, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup) diff --git a/sc/source/ui/view/cellsh.cxx b/sc/source/ui/view/cellsh.cxx index 72e4b3c74e1d..f1df448a1288 100644 --- a/sc/source/ui/view/cellsh.cxx +++ b/sc/source/ui/view/cellsh.cxx @@ -110,8 +110,8 @@ bool canShowDeleteSparkline(ScDocument& rDocument, ScRange const& rRange) { for (SCROW nY = rRange.aStart.Row(); nY <= rRange.aEnd.Row(); nY++) { - auto* pSparkline = rDocument.GetSparkline(ScAddress(nX, nY, nTab)); - if (pSparkline == nullptr) + auto pSparkline = rDocument.GetSparkline(ScAddress(nX, nY, nTab)); + if (!pSparkline) { return false; } diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx index 29073a3aac81..1e6a6c018f29 100644 --- a/sc/source/ui/view/output.cxx +++ b/sc/source/ui/view/output.cxx @@ -2466,7 +2466,7 @@ void drawColumn(vcl::RenderContext& rRenderContext, tools::Rectangle const & rRe } } -void drawSparkline(sc::Sparkline* pSparkline, vcl::RenderContext& rRenderContext, ScDocument* pDocument, +void drawSparkline(std::shared_ptr<sc::Sparkline> const& pSparkline, vcl::RenderContext& rRenderContext, ScDocument* pDocument, tools::Rectangle const & rRectangle) { auto const & rRangeList = pSparkline->getInputRange(); @@ -2566,7 +2566,7 @@ void ScOutputData::DrawSparklines(vcl::RenderContext& rRenderContext) mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab ); } - sc::Sparkline* pSparkline = nullptr; + std::shared_ptr<sc::Sparkline> pSparkline; ScAddress aCurrentAddress(nX, pRowInfo[nArrY].nRowNo, nTab); if (!mpDoc->ColHidden(nX, nTab) && (pSparkline = mpDoc->GetSparkline(aCurrentAddress))