[PATCH] Change in core[libreoffice-4-0]: fdo#58988, fdo#58562: Populate draw clip document with data ...
Kohei Yoshida (via Code Review)
gerrit at gerrit.libreoffice.org
Fri Jan 18 13:01:50 PST 2013
Hi,
I have submitted a patch for review:
https://gerrit.libreoffice.org/1757
To pull it, you can do:
git pull ssh://gerrit.libreoffice.org:29418/core refs/changes/57/1757/1
fdo#58988, fdo#58562: Populate draw clip document with data for charts.
Without populating the clip document, copying a chart (or charts) into
clipboard makes the charts lose all their referenced data, which causes
the pasted chart to appear empty.
Conflicts:
sc/source/ui/view/drawvie4.cxx
Change-Id: I0e7ce7cfbcdb3c9f120c6f0c72c58ab320901e6b
---
M sc/inc/column.hxx
M sc/inc/document.hxx
M sc/inc/table.hxx
M sc/qa/unit/ucalc.cxx
M sc/source/core/data/column.cxx
M sc/source/core/data/document.cxx
M sc/source/core/data/table2.cxx
M sc/source/ui/view/drawvie4.cxx
8 files changed, 362 insertions(+), 6 deletions(-)
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 7abce09..3e927c8 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -168,6 +168,7 @@
void DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, sal_uInt16 nDelFlag );
void DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag );
void CopyToClip(SCROW nRow1, SCROW nRow2, ScColumn& rColumn, bool bKeepScenarioFlags) const;
+ void CopyStaticToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol);
void CopyFromClip(SCROW nRow1, SCROW nRow2, long nDy,
sal_uInt16 nInsFlag, bool bAsLink, bool bSkipAttrForEmpty, ScColumn& rColumn);
void StartListeningInArea( SCROW nRow1, SCROW nRow2 );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 76df284..c7c09d8 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1027,6 +1027,16 @@
const ScMarkData* pMarks = NULL, bool bAllTabs = false, bool bKeepScenarioFlags = false,
bool bIncludeObjects = false, bool bCloneNoteCaptions = true, bool bUseRangeForVBA = false );
+ /**
+ * Copy only raw cell values to another document. Formula cells are
+ * converted to raw cells. No formatting info are copied.
+ *
+ * @param rSrcRange source range in the source document
+ * @param nDestTab table in the clip document to copy to.
+ * @param pDestDoc document to copy to
+ */
+ void CopyStaticToDocument(const ScRange& rSrcRange, SCTAB nDestTab, ScDocument* pDestDoc);
+
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,
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 512dee2..26d5a69 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -350,6 +350,7 @@
bool bKeepScenarioFlags, bool bCloneNoteCaptions);
void CopyToClip(const ScRangeList& rRanges, ScTable* pTable,
bool bKeepScenarioFlags, bool bCloneNoteCaptions);
+ void CopyStaticToDocument(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pDestTab);
void CopyFromClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCsCOL nDx, SCsROW nDy,
sal_uInt16 nInsFlag, bool bAsLink, bool bSkipAttrForEmpty, ScTable* pTable);
void StartListeningInArea( SCCOL nCol1, SCROW nRow1,
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 14d0da1..11ca7fe 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -117,7 +117,7 @@
void testRangeList();
void testInput();
void testCellFunctions();
-
+ void testCopyToDocument();
/**
* Make sure the SHEETS function gets properly updated during sheet
* insertion and removal.
@@ -263,6 +263,7 @@
CPPUNIT_TEST(testRangeList);
CPPUNIT_TEST(testInput);
CPPUNIT_TEST(testCellFunctions);
+ CPPUNIT_TEST(testCopyToDocument);
CPPUNIT_TEST(testSheetsFunc);
CPPUNIT_TEST(testVolatileFunc);
CPPUNIT_TEST(testFormulaDepTracking);
@@ -1146,6 +1147,34 @@
m_pDoc->DeleteTab(0);
}
+void Test::testCopyToDocument()
+{
+ CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "src"));
+
+ m_pDoc->SetString(0, 0, 0, "Header");
+ m_pDoc->SetString(0, 1, 0, "1");
+ m_pDoc->SetString(0, 2, 0, "2");
+ m_pDoc->SetString(0, 3, 0, "3");
+ m_pDoc->SetString(0, 4, 0, "=4/2");
+ m_pDoc->CalcAll();
+
+ // Copy statically to another document.
+
+ ScDocument aDestDoc(SCDOCMODE_DOCUMENT);
+ aDestDoc.InsertTab(0, "src");
+ m_pDoc->CopyStaticToDocument(ScRange(0,1,0,0,3,0), 0, &aDestDoc); // Copy A2:A4
+ m_pDoc->CopyStaticToDocument(ScAddress(0,0,0), 0, &aDestDoc); // Copy A1
+ m_pDoc->CopyStaticToDocument(ScRange(0,4,0,0,7,0), 0, &aDestDoc); // Copy A5:A8
+
+ CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,0,0), aDestDoc.GetString(0,0,0));
+ CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,1,0), aDestDoc.GetString(0,1,0));
+ CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,2,0), aDestDoc.GetString(0,2,0));
+ CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,3,0), aDestDoc.GetString(0,3,0));
+ CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,4,0), aDestDoc.GetString(0,4,0));
+
+ m_pDoc->DeleteTab(0);
+}
+
void Test::testSheetsFunc()
{
rtl::OUString aTabName1("test1");
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index d40e359..462abe7 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -1205,6 +1205,120 @@
}
}
+namespace {
+
+class FindInRows : std::unary_function<ColEntry, bool>
+{
+ SCROW mnRow1;
+ SCROW mnRow2;
+public:
+ FindInRows(SCROW nRow1, SCROW nRow2) : mnRow1(nRow1), mnRow2(nRow2) {}
+ bool operator() (const ColEntry& rEntry)
+ {
+ return mnRow1 <= rEntry.nRow && rEntry.nRow <= mnRow2;
+ }
+};
+
+class FindAboveRow : std::unary_function<ColEntry, bool>
+{
+ SCROW mnRow;
+public:
+ FindAboveRow(SCROW nRow) : mnRow(nRow) {}
+ bool operator() (const ColEntry& rEntry)
+ {
+ return mnRow < rEntry.nRow;
+ }
+};
+
+struct DeleteCell : std::unary_function<ColEntry, void>
+{
+ void operator() (ColEntry& rEntry)
+ {
+ rEntry.pCell->Delete();
+ }
+};
+
+}
+
+void ScColumn::CopyStaticToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol)
+{
+ if (nRow1 > nRow2)
+ return;
+
+ // First, clear the destination column for the row range specified.
+ std::vector<ColEntry>::iterator it, itEnd;
+
+ it = std::find_if(rDestCol.maItems.begin(), rDestCol.maItems.end(), FindInRows(nRow1, nRow2));
+ if (it != rDestCol.maItems.end())
+ {
+ itEnd = std::find_if(it, rDestCol.maItems.end(), FindAboveRow(nRow2));
+ std::for_each(it, itEnd, DeleteCell());
+ rDestCol.maItems.erase(it, itEnd);
+ }
+
+ // Determine the range of cells in the original column that need to be copied.
+ it = std::find_if(maItems.begin(), maItems.end(), FindInRows(nRow1, nRow2));
+ if (it != maItems.end())
+ itEnd = std::find_if(it, maItems.end(), FindAboveRow(nRow2));
+
+ // Clone and staticize all cells that need to be copied.
+ std::vector<ColEntry> aCopied;
+ aCopied.reserve(std::distance(it, itEnd));
+ for (; it != itEnd; ++it)
+ {
+ ColEntry aEntry;
+ aEntry.nRow = it->nRow;
+ switch (it->pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ {
+ const ScValueCell& rCell = static_cast<const ScValueCell&>(*it->pCell);
+ aEntry.pCell = new ScValueCell(rCell.GetValue());
+ aCopied.push_back(aEntry);
+ }
+ break;
+ case CELLTYPE_STRING:
+ {
+ const ScStringCell& rCell = static_cast<const ScStringCell&>(*it->pCell);
+ aEntry.pCell = new ScStringCell(rCell.GetString());
+ aCopied.push_back(aEntry);
+ }
+ break;
+ case CELLTYPE_EDIT:
+ {
+ // Convert to a simple string cell.
+ const ScEditCell& rCell = static_cast<const ScEditCell&>(*it->pCell);
+ aEntry.pCell = new ScStringCell(rCell.GetString());
+ aCopied.push_back(aEntry);
+ }
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell& rCell = static_cast<ScFormulaCell&>(*it->pCell);
+ if (rCell.GetDirty() && pDocument->GetAutoCalc())
+ rCell.Interpret();
+
+ if (rCell.GetErrorCode())
+ // Skip cells with error.
+ break;
+
+ if (rCell.IsValue())
+ aEntry.pCell = new ScValueCell(rCell.GetValue());
+ else
+ aEntry.pCell = new ScStringCell(rCell.GetString());
+ aCopied.push_back(aEntry);
+ }
+ break;
+ default:
+ ; // ignore the rest.
+ }
+ }
+
+ // Insert the cells into destination column. At this point the
+ // destination column shouldn't have any cells within the specified range.
+ it = std::find_if(rDestCol.maItems.begin(), rDestCol.maItems.end(), FindAboveRow(nRow2));
+ rDestCol.maItems.insert(it, aCopied.begin(), aCopied.end());
+}
void ScColumn::CopyToColumn(
SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, bool bMarked, ScColumn& rColumn,
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 65e904f..95018d7 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1956,6 +1956,21 @@
pClipDoc->ExtendMerge(aClipRange, true);
}
+void ScDocument::CopyStaticToDocument(const ScRange& rSrcRange, SCTAB nDestTab, ScDocument* pDestDoc)
+{
+ if (!pDestDoc)
+ return;
+
+ ScTable* pSrcTab = rSrcRange.aStart.Tab() < static_cast<SCTAB>(maTabs.size()) ? maTabs[rSrcRange.aStart.Tab()] : NULL;
+ ScTable* pDestTab = nDestTab < static_cast<SCTAB>(pDestDoc->maTabs.size()) ? pDestDoc->maTabs[nDestTab] : NULL;
+
+ if (!pSrcTab || !pDestTab)
+ return;
+
+ pSrcTab->CopyStaticToDocument(
+ rSrcRange.aStart.Col(), rSrcRange.aStart.Row(), rSrcRange.aEnd.Col(), rSrcRange.aEnd.Row(), pDestTab);
+}
+
void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
SCCOL nCol2, SCROW nRow2,
SCTAB nTab, ScDocument* pClipDoc)
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 073f726..fe439bb 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -653,6 +653,19 @@
}
}
+void ScTable::CopyStaticToDocument(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pDestTab)
+{
+ if (nCol1 > nCol2)
+ return;
+
+ for (SCCOL i = nCol1; i <= nCol2; ++i)
+ {
+ ScColumn& rSrcCol = aCol[i];
+ ScColumn& rDestCol = pDestTab->aCol[i];
+ rSrcCol.CopyStaticToDocument(nRow1, nRow2, rDestCol);
+ }
+}
+
void ScTable::CopyConditionalFormat( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
SCsCOL nDx, SCsROW nDy, ScTable* pTable)
{
diff --git a/sc/source/ui/view/drawvie4.cxx b/sc/source/ui/view/drawvie4.cxx
index 5283781..651aea2 100644
--- a/sc/source/ui/view/drawvie4.cxx
+++ b/sc/source/ui/view/drawvie4.cxx
@@ -42,6 +42,11 @@
#include "globstr.hrc"
#include "chartarr.hxx"
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XComponentSupplier.hpp>
+
using namespace com::sun::star;
// STATIC DATA -----------------------------------------------------------
@@ -144,22 +149,190 @@
return bReturn;
}
+namespace {
+
+void getRangeFromOle2Object(const SdrOle2Obj& rObj, std::vector<OUString>& rRangeRep)
+{
+ if (!rObj.IsChart())
+ // not a chart object.
+ return;
+
+ uno::Reference<embed::XEmbeddedObject> xObj = rObj.GetObjRef();
+ if (!xObj.is())
+ return;
+
+ uno::Reference<embed::XComponentSupplier> xCompSupp(xObj, uno::UNO_QUERY);
+ if (!xCompSupp.is())
+ return;
+
+ uno::Reference<chart2::XChartDocument> xChartDoc(xCompSupp->getComponent(), uno::UNO_QUERY);
+ if (!xChartDoc.is())
+ return;
+
+ uno::Reference<chart2::data::XDataSource> xDataSource(xChartDoc, uno::UNO_QUERY);
+ if (!xDataSource.is())
+ return;
+
+ // Get all data sources used in this chart.
+ uno::Sequence<uno::Reference<chart2::data::XLabeledDataSequence> > xSeqs = xDataSource->getDataSequences();
+ for (sal_Int32 i = 0, n = xSeqs.getLength(); i < n; ++i)
+ {
+ uno::Reference<chart2::data::XLabeledDataSequence> xLS = xSeqs[i];
+ uno::Reference<chart2::data::XDataSequence> xSeq = xLS->getValues();
+ if (xSeq.is())
+ {
+ OUString aRep = xSeq->getSourceRangeRepresentation();
+ rRangeRep.push_back(aRep);
+ }
+ xSeq = xLS->getLabel();
+ if (xSeq.is())
+ {
+ OUString aRep = xSeq->getSourceRangeRepresentation();
+ rRangeRep.push_back(aRep);
+ }
+ }
+}
+
+/**
+ * Get all cell ranges that are referenced by the selected chart objects.
+ */
+void getChartSourceRanges(ScDocument* pDoc, const SdrMarkList& rObjs, std::vector<ScRange>& rRanges)
+{
+ std::vector<OUString> aRangeReps;
+ for (size_t i = 0, n = rObjs.GetMarkCount(); i < n; ++i)
+ {
+ const SdrMark* pMark = rObjs.GetMark(i);
+ if (!pMark)
+ continue;
+
+ const SdrObject* pObj = pMark->GetMarkedSdrObj();
+ if (!pObj)
+ continue;
+
+ switch (pObj->GetObjIdentifier())
+ {
+ case OBJ_OLE2:
+ getRangeFromOle2Object(static_cast<const SdrOle2Obj&>(*pObj), aRangeReps);
+ break;
+ case OBJ_GRUP:
+ {
+ SdrObjListIter aIter(*pObj, IM_DEEPNOGROUPS);
+ for (SdrObject* pSubObj = aIter.Next(); pSubObj; pSubObj = aIter.Next())
+ {
+ if (pSubObj->GetObjIdentifier() != OBJ_OLE2)
+ continue;
+
+ getRangeFromOle2Object(static_cast<const SdrOle2Obj&>(*pSubObj), aRangeReps);
+ }
+
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ // Compile all range representation strings into ranges.
+ std::vector<OUString>::const_iterator it = aRangeReps.begin(), itEnd = aRangeReps.end();
+ for (; it != itEnd; ++it)
+ {
+ ScRange aRange;
+ ScAddress aAddr;
+ if (aRange.Parse(*it, pDoc, pDoc->GetAddressConvention()) & SCA_VALID)
+ rRanges.push_back(aRange);
+ else if (aAddr.Parse(*it, pDoc, pDoc->GetAddressConvention()) & SCA_VALID)
+ rRanges.push_back(aAddr);
+ }
+}
+
+class InsertTabIndex : std::unary_function<ScRange, void>
+{
+ std::vector<SCTAB>& mrTabs;
+public:
+ InsertTabIndex(std::vector<SCTAB>& rTabs) : mrTabs(rTabs) {}
+ void operator() (const ScRange& rRange)
+ {
+ mrTabs.push_back(rRange.aStart.Tab());
+ }
+};
+
+class CopyRangeData : std::unary_function<ScRange, void>
+{
+ ScDocument* mpSrc;
+ ScDocument* mpDest;
+public:
+ CopyRangeData(ScDocument* pSrc, ScDocument* pDest) : mpSrc(pSrc), mpDest(pDest) {}
+
+ void operator() (const ScRange& rRange)
+ {
+ OUString aTabName;
+ mpSrc->GetName(rRange.aStart.Tab(), aTabName);
+
+ SCTAB nTab;
+ if (!mpDest->GetTable(aTabName, nTab))
+ // Sheet by this name doesn't exist.
+ return;
+
+ mpSrc->CopyStaticToDocument(rRange, nTab, mpDest);
+ }
+};
+
+void copyChartRefDataToClipDoc(ScDocument* pSrcDoc, ScDocument* pClipDoc, const std::vector<ScRange>& rRanges)
+{
+ // Get a list of referenced table indices.
+ std::vector<SCTAB> aTabs;
+ std::for_each(rRanges.begin(), rRanges.end(), InsertTabIndex(aTabs));
+ std::sort(aTabs.begin(), aTabs.end());
+ aTabs.erase(std::unique(aTabs.begin(), aTabs.end()), aTabs.end());
+
+ // Get table names.
+ if (aTabs.empty())
+ return;
+
+ // Create sheets only for referenced source sheets.
+ OUString aName;
+ std::vector<SCTAB>::const_iterator it = aTabs.begin(), itEnd = aTabs.end();
+ if (!pSrcDoc->GetName(*it, aName))
+ return;
+
+ pClipDoc->SetTabNameOnLoad(0, aName); // document initially has one sheet.
+
+ for (++it; it != itEnd; ++it)
+ {
+ if (!pSrcDoc->GetName(*it, aName))
+ return;
+
+ pClipDoc->AppendTabOnLoad(aName);
+ }
+
+ std::for_each(rRanges.begin(), rRanges.end(), CopyRangeData(pSrcDoc, pClipDoc));
+}
+
+}
+
void ScDrawView::DoCopy()
{
- sal_Bool bAnyOle, bOneOle;
const SdrMarkList& rMarkList = GetMarkedObjectList();
- CheckOle( rMarkList, bAnyOle, bOneOle );
+ std::vector<ScRange> aRanges;
+ getChartSourceRanges(pDoc, rMarkList, aRanges);
// update ScGlobal::pDrawClipDocShellRef
- ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
- SdrModel* pModel = GetAllMarkedModel();
+ ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc(!aRanges.empty()) );
+ if (ScGlobal::pDrawClipDocShellRef)
+ {
+ // Copy data referenced by the chart objects to the draw clip
+ // document. We need to do this before GetMarkedObjModel() below.
+ ScDocShellRef xDocSh = *ScGlobal::pDrawClipDocShellRef;
+ ScDocument* pClipDoc = xDocSh->GetDocument();
+ copyChartRefDataToClipDoc(pDoc, pClipDoc, aRanges);
+ }
+ SdrModel* pModel = GetMarkedObjModel();
ScDrawLayer::SetGlobalDrawPersist(NULL);
// Charts now always copy their data in addition to the source reference, so
// there's no need to call SchDLL::Update for the charts in the clipboard doc.
// Update with the data (including NumberFormatter) from the live document would
// also store the NumberFormatter in the clipboard chart (#88749#)
- // lcl_RefreshChartData( pModel, pViewData->GetDocument() );
ScDocShell* pDocSh = pViewData->GetDocShell();
--
To view, visit https://gerrit.libreoffice.org/1757
To unsubscribe, visit https://gerrit.libreoffice.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0e7ce7cfbcdb3c9f120c6f0c72c58ab320901e6b
Gerrit-PatchSet: 1
Gerrit-Project: core
Gerrit-Branch: libreoffice-4-0
Gerrit-Owner: Kohei Yoshida <kohei.yoshida at gmail.com>
More information about the LibreOffice
mailing list