summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@gmail.com>2013-01-18 14:36:33 -0500
committerKohei Yoshida <kohei.yoshida@gmail.com>2013-01-18 14:41:42 -0500
commitc55d52262ea1d5f869a9528fd051ee19e687f1cc (patch)
treea6e1006b20330584d62dd611ddd9580fb4a28e37
parentc881b1b50e3be023efd4dfdebddd002545ed71b3 (diff)
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. Change-Id: I3675f76baed19b48cec403964c19df00725a044b
-rw-r--r--sc/inc/column.hxx1
-rw-r--r--sc/inc/document.hxx10
-rw-r--r--sc/inc/table.hxx1
-rw-r--r--sc/qa/unit/ucalc.cxx31
-rw-r--r--sc/source/core/data/column.cxx105
-rw-r--r--sc/source/core/data/document.cxx15
-rw-r--r--sc/source/core/data/table2.cxx13
-rw-r--r--sc/source/ui/view/drawvie4.cxx178
8 files changed, 349 insertions, 5 deletions
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 96df4d99403f..f4370a98356a 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -168,6 +168,7 @@ public:
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 7573a80c0b24..3874916a4793 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1029,6 +1029,16 @@ public:
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 fa03a7f1e292..30eb97abb66d 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -351,6 +351,7 @@ public:
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 9e116c3aeb60..6a2ac0fbfcfe 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -117,7 +117,7 @@ public:
void testRangeList();
void testInput();
void testCellFunctions();
-
+ void testCopyToDocument();
/**
* Make sure the SHEETS function gets properly updated during sheet
* insertion and removal.
@@ -268,6 +268,7 @@ public:
CPPUNIT_TEST(testRangeList);
CPPUNIT_TEST(testInput);
CPPUNIT_TEST(testCellFunctions);
+ CPPUNIT_TEST(testCopyToDocument);
CPPUNIT_TEST(testSheetsFunc);
CPPUNIT_TEST(testVolatileFunc);
CPPUNIT_TEST(testFormulaDepTracking);
@@ -1153,6 +1154,34 @@ void Test::testCellFunctions()
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 aefe0437e923..8520dc3953fa 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -1191,6 +1191,111 @@ void ScColumn::CopyToClip(SCROW nRow1, SCROW nRow2, ScColumn& rColumn, bool bKee
}
}
+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;
+ }
+};
+
+}
+
+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));
+ 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 a3e5cfa6286e..d2ff1eecafee 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1956,6 +1956,21 @@ void ScDocument::CopyToClip(const ScClipParam& rClipParam,
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 6087841ce86d..2d909c020fb8 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -653,6 +653,19 @@ void ScTable::CopyToClip(const ScRangeList& rRanges, ScTable* pTable,
}
}
+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 c49820b937ed..a6289d0b9aa7 100644
--- a/sc/source/ui/view/drawvie4.cxx
+++ b/sc/source/ui/view/drawvie4.cxx
@@ -42,6 +42,8 @@
#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;
@@ -137,14 +139,183 @@ sal_Bool ScDrawView::BeginDrag( Window* pWindow, const Point& rStartPos )
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 ) );
+ 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);
@@ -152,7 +323,6 @@ void ScDrawView::DoCopy()
// 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();