[Libreoffice-commits] core.git: Branch 'distro/collabora/co-2021' - sc/qa sc/source

Miklos Vajna (via logerrit) logerrit at kemper.freedesktop.org
Thu Jul 8 06:39:13 UTC 2021


 sc/qa/unit/data/xlsx/checkbox-form-control.xlsx |binary
 sc/qa/unit/subsequent_export-test.cxx           |   20 ++++
 sc/source/filter/excel/xeescher.cxx             |   99 +++++++++++++++++++++++-
 sc/source/filter/inc/xeescher.hxx               |    3 
 sc/source/filter/xcl97/xcl97rec.cxx             |   12 ++
 5 files changed, 132 insertions(+), 2 deletions(-)

New commits:
commit c9a07fa73742a10b072300e7120be3ef8427d8e7
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed Jun 30 16:22:42 2021 +0200
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Thu Jul 8 08:38:36 2021 +0200

    XLSX export: improve handling of checkbox (form controls)
    
    This builds on top of commit fd238380ae7820f12ac1f7c52d0f7180a93f3ba3
    (tdf#106181 XLSX export: output form controls, 2020-05-13) and adds the
    missing VML version which seems to be mandated by Excel 2019.
    
    It is not perfect (e.g. there is still an unwanted border around the
    checkbox), but the checkbox has a correct position and its label is
    readable, while it was just lost previously.
    
    (cherry picked from commit 94678a7b9c6b7e577c15adacc885e03551bcf17b)
    
    Conflicts:
            sc/qa/unit/subsequent_export-test2.cxx
    
    Change-Id: I08198d068a0eb85061d138719cfc60d73c46398e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118488
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>

diff --git a/sc/qa/unit/data/xlsx/checkbox-form-control.xlsx b/sc/qa/unit/data/xlsx/checkbox-form-control.xlsx
new file mode 100644
index 000000000000..ad761a573aae
Binary files /dev/null and b/sc/qa/unit/data/xlsx/checkbox-form-control.xlsx differ
diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx
index 77068268bff8..4baebf766459 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -281,6 +281,7 @@ public:
     void testTdf84874();
     void testTdf136721_paper_size();
     void testTdf139258_rotated_image();
+    void testCheckboxFormControlXlsxExport();
 
     CPPUNIT_TEST_SUITE(ScExportTest);
     CPPUNIT_TEST(test);
@@ -460,6 +461,7 @@ public:
     CPPUNIT_TEST(testTdf84874);
     CPPUNIT_TEST(testTdf136721_paper_size);
     CPPUNIT_TEST(testTdf139258_rotated_image);
+    CPPUNIT_TEST(testCheckboxFormControlXlsxExport);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -5849,6 +5851,24 @@ void ScExportTest::testTdf139258_rotated_image()
     assertXPathContent(pDrawing, "/xdr:wsDr/xdr:twoCellAnchor/xdr:to/xdr:row", "25");
 }
 
+void ScExportTest::testCheckboxFormControlXlsxExport()
+{
+    // Given a document that has a checkbox form control:
+    ScDocShellRef xShell = loadDoc(u"checkbox-form-control.", FORMAT_XLSX);
+    CPPUNIT_ASSERT(xShell.is());
+
+    // When exporting to XLSX:
+    std::shared_ptr<utl::TempFile> pXPathFile
+        = ScBootstrapFixture::exportTo(&(*xShell), FORMAT_XLSX);
+
+    // Then make sure its VML markup is written and it has a correct position + size:
+    xmlDocUniquePtr pDoc
+        = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/drawings/vmlDrawing1.vml");
+    // Without the fix in place, this test would have failed as there was no such stream.
+    CPPUNIT_ASSERT(pDoc);
+    assertXPathContent(pDoc, "/xml/v:shape/xx:ClientData/xx:Anchor", "1, 22, 3, 3, 3, 30, 6, 1");
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/filter/excel/xeescher.cxx b/sc/source/filter/excel/xeescher.cxx
index 7a7514aa7061..19fb63465a48 100644
--- a/sc/source/filter/excel/xeescher.cxx
+++ b/sc/source/filter/excel/xeescher.cxx
@@ -70,6 +70,8 @@
 #include <oox/export/chartexport.hxx>
 #include <oox/export/utils.hxx>
 #include <oox/token/namespaces.hxx>
+#include <oox/export/vmlexport.hxx>
+#include <sax/fastattribs.hxx>
 #include <memory>
 
 using namespace com::sun::star;
@@ -659,7 +661,8 @@ XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference<
     mbScrollHor( false ),
     mbPrint( false ),
     mbVisible( false ),
-    mnShapeId( 0 )
+    mnShapeId( 0 ),
+    mrRoot(rRoot)
 {
     namespace FormCompType = css::form::FormComponentType;
     namespace AwtVisualEffect = css::awt::VisualEffect;
@@ -1092,6 +1095,100 @@ void XclExpTbxControlObj::setShapeId(sal_Int32 aShapeId)
     mnShapeId = aShapeId;
 }
 
+namespace
+{
+/// Handles the VML export of form controls (e.g. checkboxes).
+class VmlFormControlExporter : public oox::vml::VMLExport
+{
+    sal_uInt16 m_nObjType;
+    tools::Rectangle m_aAreaFrom;
+    tools::Rectangle m_aAreaTo;
+    OUString m_aLabel;
+
+public:
+    VmlFormControlExporter(const sax_fastparser::FSHelperPtr& p, sal_uInt16 nObjType,
+                           const tools::Rectangle& rAreaFrom, const tools::Rectangle& rAreaTo,
+                           const OUString& rLabel);
+
+protected:
+    using VMLExport::StartShape;
+    sal_Int32 StartShape() override;
+    using VMLExport::EndShape;
+    void EndShape(sal_Int32 nShapeElement) override;
+};
+
+VmlFormControlExporter::VmlFormControlExporter(const sax_fastparser::FSHelperPtr& p,
+                                               sal_uInt16 nObjType,
+                                               const tools::Rectangle& rAreaFrom,
+                                               const tools::Rectangle& rAreaTo,
+                                               const OUString& rLabel)
+    : VMLExport(p)
+    , m_nObjType(nObjType)
+    , m_aAreaFrom(rAreaFrom)
+    , m_aAreaTo(rAreaTo)
+    , m_aLabel(rLabel)
+{
+}
+
+sal_Int32 VmlFormControlExporter::StartShape()
+{
+    // Host control.
+    AddShapeAttribute(XML_type, "#_x0000_t201");
+    return VMLExport::StartShape();
+}
+
+void VmlFormControlExporter::EndShape(sal_Int32 nShapeElement)
+{
+    sax_fastparser::FSHelperPtr pVmlDrawing = GetFS();
+
+    pVmlDrawing->startElement(FSNS(XML_v, XML_textbox));
+    pVmlDrawing->startElement(XML_div);
+    pVmlDrawing->write(m_aLabel);
+    pVmlDrawing->endElement(XML_div);
+    pVmlDrawing->endElement(FSNS(XML_v, XML_textbox));
+
+    OString aObjectType;
+    switch (m_nObjType)
+    {
+        case EXC_OBJTYPE_CHECKBOX:
+            aObjectType = "Checkbox";
+            break;
+    }
+    pVmlDrawing->startElement(FSNS(XML_x, XML_ClientData), XML_ObjectType, aObjectType);
+    OString aAnchor = OString::number(m_aAreaFrom.Left());
+    aAnchor += ", " + OString::number(m_aAreaFrom.Top());
+    aAnchor += ", " + OString::number(m_aAreaFrom.Right());
+    aAnchor += ", " + OString::number(m_aAreaFrom.Bottom());
+    aAnchor += ", " + OString::number(m_aAreaTo.Left());
+    aAnchor += ", " + OString::number(m_aAreaTo.Top());
+    aAnchor += ", " + OString::number(m_aAreaTo.Right());
+    aAnchor += ", " + OString::number(m_aAreaTo.Bottom());
+    XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_Anchor), aAnchor);
+
+    // XclExpOcxControlObj::WriteSubRecs() has the same fixed value.
+    XclXmlUtils::WriteElement(pVmlDrawing, FSNS(XML_x, XML_TextVAlign), "Center");
+
+    pVmlDrawing->endElement(FSNS(XML_x, XML_ClientData));
+    VMLExport::EndShape(nShapeElement);
+}
+
+}
+
+/// Save into xl/drawings/vmlDrawing1.vml.
+void XclExpTbxControlObj::SaveVml(XclExpXmlStream& rStrm)
+{
+    SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mxShape);
+    tools::Rectangle aAreaFrom;
+    tools::Rectangle aAreaTo;
+    // Unlike XclExpTbxControlObj::SaveXml(), this is not calculated in EMUs.
+    lcl_GetFromTo(mrRoot, pObj->GetLogicRect(), GetTab(), aAreaFrom, aAreaTo);
+    VmlFormControlExporter aFormControlExporter(rStrm.GetCurrentStream(), GetObjType(), aAreaFrom,
+                                                aAreaTo, msLabel);
+    aFormControlExporter.AddSdrObject(*pObj, /*eHOri=*/-1,
+                                      /*eVOri=*/-1, /*eHRel=*/-1, /*eVRel=*/-1,
+                                      /*pWrapAttrList=*/nullptr, /*bOOxmlExport=*/true);
+}
+
 // save into xl\drawings\drawing1.xml
 void XclExpTbxControlObj::SaveXml( XclExpXmlStream& rStrm )
 {
diff --git a/sc/source/filter/inc/xeescher.hxx b/sc/source/filter/inc/xeescher.hxx
index 1a08b6db9886..b37117521093 100644
--- a/sc/source/filter/inc/xeescher.hxx
+++ b/sc/source/filter/inc/xeescher.hxx
@@ -259,6 +259,8 @@ public:
 
     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
 
+    void SaveVml(XclExpXmlStream& rStrm);
+
     OUString SaveControlPropertiesXml(XclExpXmlStream& rStrm) const;
     void SaveSheetXml(XclExpXmlStream& rStrm, const OUString& aIdFormControlPr) const;
 
@@ -296,6 +298,7 @@ private:
     sal_Int32           mnShapeId;
     tools::Rectangle    maAreaFrom;
     tools::Rectangle    maAreaTo;
+    XclExpObjectManager& mrRoot;
 };
 
 //#endif
diff --git a/sc/source/filter/xcl97/xcl97rec.cxx b/sc/source/filter/xcl97/xcl97rec.cxx
index 571376205724..d786f09c040c 100644
--- a/sc/source/filter/xcl97/xcl97rec.cxx
+++ b/sc/source/filter/xcl97/xcl97rec.cxx
@@ -181,7 +181,7 @@ bool IsVmlObject( const XclObj *rObj )
 sal_Int32 GetVmlObjectCount( XclExpObjList& rList )
 {
     return static_cast<sal_Int32>(std::count_if(rList.begin(), rList.end(),
-        [](const std::unique_ptr<XclObj>& rxObj) { return IsVmlObject( rxObj.get() ); }));
+        [](const std::unique_ptr<XclObj>& rxObj) { return IsVmlObject( rxObj.get() ) || IsFormControlObject( rxObj.get() ); }));
 }
 
 bool IsValidObject( const XclObj& rObj )
@@ -336,6 +336,7 @@ void SaveVmlObjects( XclExpObjList& rList, XclExpXmlStream& rStrm, sal_Int32& nV
     rStrm.GetCurrentStream()->singleElement(XML_legacyDrawing, FSNS(XML_r, XML_id), sId.toUtf8());
 
     rStrm.PushStream( pVmlDrawing );
+    pVmlDrawing->write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
     pVmlDrawing->startElement( XML_xml,
             FSNS(XML_xmlns, XML_v),   rStrm.getNamespaceURL(OOX_NS(vml)).toUtf8(),
             FSNS(XML_xmlns, XML_o),   rStrm.getNamespaceURL(OOX_NS(vmlOffice)).toUtf8(),
@@ -344,6 +345,15 @@ void SaveVmlObjects( XclExpObjList& rList, XclExpXmlStream& rStrm, sal_Int32& nV
 
     for ( const auto& rxObj : rList )
     {
+        if (IsFormControlObject(rxObj.get()))
+        {
+            auto pFormControlObject = dynamic_cast<XclExpTbxControlObj*>(rxObj.get());
+            if (pFormControlObject)
+            {
+                pFormControlObject->SaveVml(rStrm);
+            }
+        }
+
         if( !IsVmlObject( rxObj.get() ) )
             continue;
         rxObj->SaveXml( rStrm );


More information about the Libreoffice-commits mailing list