Date: prev next · Thread: first prev next last
2013 Archives by date, by thread · List index


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@gmail.com>


Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.