[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