From c0cc02e2934aeb12dda44818955e5964496c186a Mon Sep 17 00:00:00 2001 From: Tamás Zolnai Date: Thu, 17 Aug 2017 21:47:22 +0200 Subject: tdf#50097: DOCX: export form controls as MSO ActiveX controls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use the same structure for export what MSO uses ** Position and size information are exported as VML shape properties ** Different handling of inline and floating controls (pict or object) ** Do some changes on VML shape export to match how MSO exports these controls ** Write out activeX.xml and activeX.bin to store control properties ** Use persistStorage storage type defined in activeX.xml * Drop grabbaging of activex.XML and activeX.bin * Cleanup control related test code Change-Id: I38bb2b2ffd2676c5459b61ec2549c31348bab41c Signed-off-by: Tamás Zolnai Reviewed-on: https://gerrit.libreoffice.org/41256 Tested-by: Jenkins --- sw/qa/extras/ooxmlexport/data/activex.docx | Bin 40422 -> 0 bytes .../extras/ooxmlexport/data/activex_checkbox.docx | Bin 0 -> 13851 bytes sw/qa/extras/ooxmlexport/data/activexbin.docx | Bin 41606 -> 0 bytes sw/qa/extras/ooxmlexport/ooxmlexport2.cxx | 1 - sw/qa/extras/ooxmlexport/ooxmlexport3.cxx | 57 -------- sw/qa/extras/ooxmlexport/ooxmlexport5.cxx | 1 - sw/qa/extras/ooxmlexport/ooxmlexport6.cxx | 8 +- sw/qa/extras/ooxmlexport/ooxmlexport7.cxx | 8 +- sw/qa/extras/ooxmlexport/ooxmlexport9.cxx | 29 +++- sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx | 1 - .../extras/ooxmlimport/data/activex_checkbox.docx | Bin 13851 -> 0 bytes sw/qa/extras/ooxmlimport/ooxmlimport.cxx | 28 ---- sw/source/filter/ww8/docxattributeoutput.cxx | 104 +++++++++++++- sw/source/filter/ww8/docxattributeoutput.hxx | 5 + sw/source/filter/ww8/docxexport.cxx | 149 ++++++++------------- sw/source/filter/ww8/docxexport.hxx | 6 + 16 files changed, 203 insertions(+), 194 deletions(-) delete mode 100644 sw/qa/extras/ooxmlexport/data/activex.docx create mode 100755 sw/qa/extras/ooxmlexport/data/activex_checkbox.docx delete mode 100644 sw/qa/extras/ooxmlexport/data/activexbin.docx delete mode 100755 sw/qa/extras/ooxmlimport/data/activex_checkbox.docx (limited to 'sw') diff --git a/sw/qa/extras/ooxmlexport/data/activex.docx b/sw/qa/extras/ooxmlexport/data/activex.docx deleted file mode 100644 index eb546d9795ef..000000000000 Binary files a/sw/qa/extras/ooxmlexport/data/activex.docx and /dev/null differ diff --git a/sw/qa/extras/ooxmlexport/data/activex_checkbox.docx b/sw/qa/extras/ooxmlexport/data/activex_checkbox.docx new file mode 100755 index 000000000000..d7415ef5a5c6 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/activex_checkbox.docx differ diff --git a/sw/qa/extras/ooxmlexport/data/activexbin.docx b/sw/qa/extras/ooxmlexport/data/activexbin.docx deleted file mode 100644 index ecf4599ed0e9..000000000000 Binary files a/sw/qa/extras/ooxmlexport/data/activexbin.docx and /dev/null differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx index 72062211959d..b5e63cf65a86 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx index 85b1b8fef611..0303237aece2 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -537,62 +536,6 @@ DECLARE_OOXMLEXPORT_TEST(testCustomXmlGrabBag, "customxml.docx") CPPUNIT_ASSERT(CustomXml); // Grab Bag has all the expected elements } -DECLARE_OOXMLEXPORT_TEST(testActiveXGrabBag, "activex.docx") -{ - // The problem was that activeX.xml files were missing from docx file after saving file. - // This test case tests whether activex files grabbagged properly in correct object. - - uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); - uno::Reference xTextDocumentPropertySet(xTextDocument, uno::UNO_QUERY); - uno::Sequence aGrabBag(0); - xTextDocumentPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag; - CPPUNIT_ASSERT(aGrabBag.hasElements()); // Grab Bag not empty - bool bActiveX = false; - for(int i = 0; i < aGrabBag.getLength(); ++i) - { - if (aGrabBag[i].Name == "OOXActiveX") - { - bActiveX = true; - uno::Reference aActiveXDom; - uno::Sequence > aActiveXDomList; - CPPUNIT_ASSERT(aGrabBag[i].Value >>= aActiveXDomList); // PropertyValue of proper type - sal_Int32 length = aActiveXDomList.getLength(); - CPPUNIT_ASSERT_EQUAL(sal_Int32(5), length); - aActiveXDom = aActiveXDomList[0]; - CPPUNIT_ASSERT(aActiveXDom.get()); // Reference not empty - } - } - CPPUNIT_ASSERT(bActiveX); // Grab Bag has all the expected elements -} - -DECLARE_OOXMLEXPORT_TEST(testActiveXBinGrabBag, "activexbin.docx") -{ - // The problem was that activeX.bin files were missing from docx file after saving file. - // This test case tests whether activex bin files grabbagged properly in correct object. - - uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); - uno::Reference xTextDocumentPropertySet(xTextDocument, uno::UNO_QUERY); - uno::Sequence aGrabBag(0); - xTextDocumentPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag; - CPPUNIT_ASSERT(aGrabBag.hasElements()); // Grab Bag not empty - bool bActiveX = false; - for(int i = 0; i < aGrabBag.getLength(); ++i) - { - if (aGrabBag[i].Name == "OOXActiveXBin") - { - bActiveX = true; - uno::Reference aActiveXBin; - uno::Sequence > aActiveXBinList; - CPPUNIT_ASSERT(aGrabBag[i].Value >>= aActiveXBinList); // PropertyValue of proper type - sal_Int32 length = aActiveXBinList.getLength(); - CPPUNIT_ASSERT_EQUAL(sal_Int32(5), length); - aActiveXBin = aActiveXBinList[0]; - CPPUNIT_ASSERT(aActiveXBin.get()); // Reference not empty - } - } - CPPUNIT_ASSERT(bActiveX); // Grab Bag has all the expected elements -} - DECLARE_OOXMLEXPORT_TEST(testFdo69644, "fdo69644.docx") { // The problem was that the exporter exported the table definition diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx index a690c4519ea7..96868a3b6f66 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx index 2891b3ff162f..a5a28a21d9b7 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx @@ -9,7 +9,7 @@ #include -#if !defined(_WIN32) + #include #include @@ -455,7 +455,7 @@ DECLARE_OOXMLEXPORT_TEST(testVMLData, "TestVMLData.docx") xmlDocPtr pXmlDoc = parseExport("word/header2.xml"); if (!pXmlDoc) return; - CPPUNIT_ASSERT(getXPath(pXmlDoc, "/w:hdr/w:p/w:r/mc:AlternateContent/mc:Fallback/w:pict/v:rect", "stroked").match("f")); + CPPUNIT_ASSERT(getXPath(pXmlDoc, "/w:hdr/w:p/w:r/mc:AlternateContent/mc:Fallback/w:pict/v:shape", "stroked").match("f")); } DECLARE_OOXMLEXPORT_TEST(testImageData, "image_data.docx") @@ -465,7 +465,7 @@ DECLARE_OOXMLEXPORT_TEST(testImageData, "image_data.docx") xmlDocPtr pXmlDoc = parseExport("word/header2.xml"); if (!pXmlDoc) return; - CPPUNIT_ASSERT(getXPath(pXmlDoc, "/w:hdr/w:p/w:r/mc:AlternateContent/mc:Fallback/w:pict/v:rect/v:imagedata", "detectmouseclick").match("t")); + CPPUNIT_ASSERT(getXPath(pXmlDoc, "/w:hdr/w:p/w:r/mc:AlternateContent/mc:Fallback/w:pict/v:shape/v:imagedata", "detectmouseclick").match("t")); } DECLARE_OOXMLEXPORT_TEST(testFdo70838, "fdo70838.docx") @@ -929,8 +929,6 @@ DECLARE_OOXMLEXPORT_TEST(testSyncedRelativePercent, "tdf93676-1.odt") assertXPath(pXmlDoc, "//wp14:pctHeight", 0); } -#endif - CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx index d564e8031b26..8607ff84fca5 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx @@ -9,7 +9,6 @@ #include -#if !defined(_WIN32) #include #include @@ -125,7 +124,7 @@ DECLARE_OOXMLEXPORT_TEST(testPictureWatermark, "pictureWatermark.docx") return; // Check the watermark ID - assertXPath(pXmlHeader1, "/w:hdr[1]/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Fallback[1]/w:pict[1]/v:rect[1]","id","WordPictureWatermark11962361"); + assertXPath(pXmlHeader1, "/w:hdr[1]/w:p[1]/w:r[1]/mc:AlternateContent[1]/mc:Fallback[1]/w:pict[1]/v:shape[1]","id","WordPictureWatermark11962361"); } @@ -1127,6 +1126,8 @@ DECLARE_OOXMLEXPORT_TEST(testTDF93675, "no-numlevel-but-indented.odt") assertXPath(pXmlDoc, "//w:ind", "start", "1418"); } + + DECLARE_OOXMLEXPORT_TEST(testFlipAndRotateCustomShape, "flip_and_rotate.odt") { xmlDocPtr pXmlDoc = parseExport("word/document.xml"); @@ -1141,6 +1142,7 @@ DECLARE_OOXMLEXPORT_TEST(testFlipAndRotateCustomShape, "flip_and_rotate.odt") #ifndef MACOSX /* Retina-related rounding rountrip error * hard to smooth out due to the use of string compare * instead of number */ +#if !defined(_WIN32) assertXPath(pXmlDoc, "//a:custGeom/a:pathLst/a:path/a:lnTo[1]/a:pt", "x", "2351"); assertXPath(pXmlDoc, "//a:custGeom/a:pathLst/a:path/a:lnTo[1]/a:pt", "y", "3171"); assertXPath(pXmlDoc, "//a:custGeom/a:pathLst/a:path/a:lnTo[2]/a:pt", "x", "1695"); @@ -1148,9 +1150,9 @@ DECLARE_OOXMLEXPORT_TEST(testFlipAndRotateCustomShape, "flip_and_rotate.odt") assertXPath(pXmlDoc, "//a:custGeom/a:pathLst/a:path/a:lnTo[3]/a:pt", "x", "1695"); assertXPath(pXmlDoc, "//a:custGeom/a:pathLst/a:path/a:lnTo[3]/a:pt", "y", "1701"); #endif +#endif } -#endif CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx index caecccfa0681..afdd942eade4 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -27,6 +26,7 @@ #include #include #include +#include #include #include @@ -818,6 +818,33 @@ DECLARE_OOXMLEXPORT_TEST(testTdf105095, "tdf105095.docx") CPPUNIT_ASSERT(xTextRange->getString().endsWith("\tfootnote")); } +DECLARE_OOXMLIMPORT_TEST( testActiveXCheckbox, "activex_checkbox.docx" ) +{ + uno::Reference xControlShape( getShape(1), uno::UNO_QUERY ); + CPPUNIT_ASSERT( xControlShape.is() ); + + // Check control type + uno::Reference xPropertySet( xControlShape->getControl(), uno::UNO_QUERY ); + uno::Reference xServiceInfo( xPropertySet, uno::UNO_QUERY ); + CPPUNIT_ASSERT_EQUAL( true, bool( xServiceInfo->supportsService( "com.sun.star.form.component.CheckBox" ) ) ); + + // Check custom label + CPPUNIT_ASSERT_EQUAL( OUString( "Custom Caption" ), getProperty(xPropertySet, "Label") ); + + // Check background color (highlight system color) + CPPUNIT_ASSERT_EQUAL( sal_Int32( 0x316AC5 ), getProperty(xPropertySet, "BackgroundColor") ); + + // Check Text color (active border system color) + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xD4D0C8), getProperty(xPropertySet, "TextColor")); + + // Check state of the checkbox + CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty(xPropertySet, "State")); + + // Check anchor type + uno::Reference xPropertySet2(xControlShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER,getProperty(xPropertySet2,"AnchorType")); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx index c3b2af4bc065..7e5373e60241 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/sw/qa/extras/ooxmlimport/data/activex_checkbox.docx b/sw/qa/extras/ooxmlimport/data/activex_checkbox.docx deleted file mode 100755 index d7415ef5a5c6..000000000000 Binary files a/sw/qa/extras/ooxmlimport/data/activex_checkbox.docx and /dev/null differ diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx index 2c2da5e9e7f3..e44d41f26d03 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx @@ -61,7 +61,6 @@ #include #include #include -#include #include #include @@ -1464,33 +1463,6 @@ DECLARE_OOXMLIMPORT_TEST(testGroupShapeFontName, "groupshape-fontname.docx") CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty(getRun(getParagraphOfText(1, xText), 1), "CharFontNameAsian")); } -DECLARE_OOXMLIMPORT_TEST( testActiveXCheckbox, "activex_checkbox.docx" ) -{ - uno::Reference xControlShape( getShape(1), uno::UNO_QUERY ); - CPPUNIT_ASSERT( xControlShape.is() ); - - // Check control type - uno::Reference xPropertySet( xControlShape->getControl(), uno::UNO_QUERY ); - uno::Reference xServiceInfo( xPropertySet, uno::UNO_QUERY ); - CPPUNIT_ASSERT_EQUAL( true, bool( xServiceInfo->supportsService( "com.sun.star.form.component.CheckBox" ) ) ); - - // Check custom label - CPPUNIT_ASSERT_EQUAL( OUString( "Custom Caption" ), getProperty(xPropertySet, "Label") ); - - // Check background color (highlight system color) - CPPUNIT_ASSERT_EQUAL( sal_Int32( 0x316AC5 ), getProperty(xPropertySet, "BackgroundColor") ); - - // Check Text color (active border system color) - CPPUNIT_ASSERT_EQUAL(sal_Int32(0xD4D0C8), getProperty(xPropertySet, "TextColor")); - - // Check state of the checkbox - CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty(xPropertySet, "State")); - - // Check anchor type - uno::Reference xPropertySet2(xControlShape, uno::UNO_QUERY); - CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER,getProperty(xPropertySet2,"AnchorType")); -} - DECLARE_OOXMLIMPORT_TEST(testTdf111550, "tdf111550.docx") { // The test document has following ill-formed structure: diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 93cd4daba349..3c8bddef0cbf 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include #include @@ -2043,6 +2045,8 @@ void DocxAttributeOutput::EndRunProperties( const SwRedlineData* pRedlineData ) WritePostponedOLE(); + WritePostponedActiveXControl(); + // merge the properties _before_ the run text (strictly speaking, just // after the start of the run) m_pSerializer->mergeTopMarks(Tag_StartRunProperties, sax_fastparser::MergeMarks::PREPEND); @@ -4781,6 +4785,101 @@ void DocxAttributeOutput::WritePostponedFormControl(const SdrObject* pObject) } } +void DocxAttributeOutput::WritePostponedActiveXControl() +{ + for( std::vector::const_iterator it = m_aPostponedActiveXControls.begin(); + it != m_aPostponedActiveXControls.end(); ++it ) + { + WriteActiveXControl(it->object, *(it->frame), *(it->point)); + } + m_aPostponedActiveXControls.clear(); +} + + +void DocxAttributeOutput::WriteActiveXControl(const SdrObject* pObject, const SwFrameFormat& rFrameFormat,const Point& rNdTopLeft) +{ + SdrUnoObj *pFormObj = const_cast(dynamic_cast< const SdrUnoObj*>(pObject)); + if (!pFormObj) + return; + + uno::Reference xControlModel = pFormObj->GetUnoControlModel(); + if (!xControlModel.is()) + return; + + const bool bAnchoredInline = rFrameFormat.GetAnchor().GetAnchorId() == static_cast(css::text::TextContentAnchorType_AS_CHARACTER); + + // w:pict for floating embedded control and w:object for inline embedded control + if(bAnchoredInline) + m_pSerializer->startElementNS(XML_w, XML_object, FSEND); + else + m_pSerializer->startElementNS(XML_w, XML_pict, FSEND); + + // write ActiveX fragment and ActiveX binary + uno::Reference xShape(const_cast(pObject)->getUnoShape(), uno::UNO_QUERY); + std::pair sRelIdAndName = m_rExport.WriteActiveXObject(xShape, xControlModel); + + // VML shape definition + m_rExport.VMLExporter().SetSkipwzName(); + m_rExport.VMLExporter().SetHashMarkForType(); + OString sShapeId; + if(bAnchoredInline) + { + sShapeId = m_rExport.VMLExporter().AddInlineSdrObject(*pObject, true); + } + else + { + const SwFormatHoriOrient& rHoriOri = rFrameFormat.GetHoriOrient(); + const SwFormatVertOrient& rVertOri = rFrameFormat.GetVertOrient(); + sShapeId = m_rExport.VMLExporter().AddSdrObject(*pObject, + rHoriOri.GetHoriOrient(), rVertOri.GetVertOrient(), + rHoriOri.GetRelationOrient(), + rVertOri.GetRelationOrient(), &rNdTopLeft, true); + } + + // control + m_pSerializer->singleElementNS(XML_w, XML_control, + FSNS(XML_r, XML_id), sRelIdAndName.first.getStr(), + FSNS(XML_w, XML_name), sRelIdAndName.second.getStr(), + FSNS(XML_w, XML_shapeid), sShapeId.getStr(), + FSEND); + + if(bAnchoredInline) + m_pSerializer->endElementNS(XML_w, XML_object); + else + m_pSerializer->endElementNS(XML_w, XML_pict); +} + +bool DocxAttributeOutput::ExportAsActiveXControl(const SdrObject* pObject) const +{ + SdrUnoObj *pFormObj = const_cast(dynamic_cast< const SdrUnoObj*>(pObject)); + if (!pFormObj) + return false; + + uno::Reference xControlModel = pFormObj->GetUnoControlModel(); + if (!xControlModel.is()) + return false; + + uno::Reference< css::frame::XModel > xModel( m_rExport.m_pDoc->GetDocShell() ? m_rExport.m_pDoc->GetDocShell()->GetModel() : nullptr ); + if (!xModel.is()) + return false; + + uno::Reference xInfo(xControlModel, uno::UNO_QUERY); + if (!xInfo.is()) + return false; + + // See WritePostponedFormControl + // By now date field and combobox is handled on a different way, so let's not interfere with the other method. + if(xInfo->supportsService("com.sun.star.form.component.DateField") || + xInfo->supportsService("com.sun.star.form.component.ComboBox")) + return false; + + oox::ole::OleFormCtrlExportHelper exportHelper(comphelper::getProcessComponentContext(), xModel, xControlModel); + if(!exportHelper.isValid()) + return false; + + return true; +} + bool DocxAttributeOutput::PostponeOLE( SwOLENode& rNode, const Size& rSize, const SwFlyFrameFormat* pFlyFrameFormat ) { if( !m_pPostponedOLEs ) @@ -5066,7 +5165,10 @@ void DocxAttributeOutput::OutputFlyFrame_Impl( const ww8::Frame &rFrame, const P case ww8::Frame::eFormControl: { const SdrObject* pObject = rFrame.GetFrameFormat().FindRealSdrObject(); - m_aPostponedFormControls.push_back(pObject); + if(ExportAsActiveXControl(pObject)) + m_aPostponedActiveXControls.push_back(PostponedDrawing(pObject, &(rFrame.GetFrameFormat()), &rNdTopLeft)); + else + m_aPostponedFormControls.push_back(pObject); m_bPostponedProcessingFly = true ; } break; diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 8daa50aea34a..54d67559b35e 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -417,6 +417,9 @@ private: bool PostponeOLE( SwOLENode& rNode, const Size& rSize, const SwFlyFrameFormat* pFlyFrameFormat ); void WriteOLE( SwOLENode& rNode, const Size& rSize, const SwFlyFrameFormat* rFlyFrameFormat ); + void WriteActiveXControl(const SdrObject* pObject, const SwFrameFormat& rFrameFormat, const Point& rNdTopLeft); + bool ExportAsActiveXControl(const SdrObject* pObject) const; + /// checks whether the current component is a diagram static bool IsDiagram (const SdrObject* sdrObject); @@ -697,6 +700,7 @@ private: void WritePostponedGraphic(); void WritePostponedMath(const SwOLENode* pObject); void WritePostponedFormControl(const SdrObject* pObject); + void WritePostponedActiveXControl(); void WritePostponedDiagram(); void WritePostponedChart(); void WritePostponedOLE(); @@ -873,6 +877,7 @@ private: const SdrObject* m_postponedChart; Size m_postponedChartSize; std::vector m_aPostponedFormControls; + std::vector m_aPostponedActiveXControls; const SwField* pendingPlaceholder; /// Maps postit fields to ID's, used in commentRangeStart/End, commentReference and comment.xml. std::vector< std::pair > m_postitFields; diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index 87de4e11b242..c3df2b0cf18f 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,9 @@ #include #include #include +#include +#include +#include #include #include @@ -419,6 +423,54 @@ OString DocxExport::WriteOLEObject(SwOLEObj& rObject, OUString & io_rProgID) return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 ); } +std::pair DocxExport::WriteActiveXObject(const uno::Reference& rxShape, + const uno::Reference& rxControlModel) +{ + ++m_nActiveXControls; + + // Write out ActiveX binary + const OUString sBinaryFileName = "word/activeX/activeX" + OUString::number(m_nActiveXControls) + ".bin"; + + OString sGUID; + OString sName; + uno::Reference xOutStorage(m_pFilter->openFragmentStream(sBinaryFileName, "application/vnd.ms-office.activeX"), uno::UNO_QUERY); + if(xOutStorage.is()) + { + oox::ole::OleStorage aOleStorage(m_pFilter->getComponentContext(), xOutStorage, false); + uno::Reference xOutputStream(aOleStorage.openOutputStream("contents"), uno::UNO_SET_THROW); + uno::Reference< css::frame::XModel > xModel( m_pDoc->GetDocShell() ? m_pDoc->GetDocShell()->GetModel() : nullptr ); + oox::ole::OleFormCtrlExportHelper exportHelper(comphelper::getProcessComponentContext(), xModel, rxControlModel); + if ( !exportHelper.isValid() ) + return std::make_pair(OString(), OString()); + sGUID = OUStringToOString(exportHelper.getGUID(), RTL_TEXTENCODING_UTF8); + sName = OUStringToOString(exportHelper.getName(), RTL_TEXTENCODING_UTF8); + exportHelper.exportControl(xOutputStream, rxShape->getSize(), true); + aOleStorage.commit(); + } + + // Write out ActiveX fragment + const OUString sXMLFileName = "word/activeX/activeX" + OUString::number( m_nActiveXControls ) + ".xml"; + ::sax_fastparser::FSHelperPtr pActiveXFS = m_pFilter->openFragmentStreamWithSerializer(sXMLFileName, "application/vnd.ms-office.activeX+xml" ); + + const OUString sBinaryId = m_pFilter->addRelation( pActiveXFS->getOutputStream(), + oox::getRelationship(Relationship::ACTIVEXCONTROLBINARY), + sBinaryFileName.copy(sBinaryFileName.lastIndexOf("/") + 1) ); + + pActiveXFS->singleElementNS(XML_ax, XML_ocx, + FSNS(XML_xmlns, XML_ax), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(ax)), RTL_TEXTENCODING_UTF8).getStr(), + FSNS(XML_xmlns, XML_r), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(), + FSNS(XML_ax, XML_classid), OString("{" + sGUID + "}").getStr(), + FSNS(XML_ax, XML_persistence), "persistStorage", + FSNS(XML_r, XML_id), OUStringToOString(sBinaryId, RTL_TEXTENCODING_UTF8).getStr(), FSEND); + + OString sXMLId = OUStringToOString(m_pFilter->addRelation(m_pDocumentFS->getOutputStream(), + oox::getRelationship(Relationship::CONTROL), + sXMLFileName.copy(sBinaryFileName.indexOf("/") + 1)), + RTL_TEXTENCODING_UTF8); + + return std::pair(sXMLId, sName); +} + void DocxExport::OutputDML(uno::Reference const & xShape) { uno::Reference xServiceInfo(xShape, uno::UNO_QUERY_THROW); @@ -462,8 +514,6 @@ void DocxExport::ExportDocument_Impl() WriteCustomXml(); - WriteActiveX(); - WriteEmbeddings(); WriteVBA(); @@ -1171,100 +1221,6 @@ void DocxExport::WriteCustomXml() } } -void DocxExport::WriteActiveX() -{ - uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW ); - - uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); - OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG; - if ( !xPropSetInfo->hasPropertyByName( aName ) ) - return; - - uno::Sequence > activeXDomlist; - uno::Sequence > activeXBinList; - uno::Sequence< beans::PropertyValue > propList; - xPropSet->getPropertyValue( aName ) >>= propList; - for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp ) - { - OUString propName = propList[nProp].Name; - if ( propName == "OOXActiveX" ) - { - propList[nProp].Value >>= activeXDomlist; - break; - } - } - - for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp ) - { - OUString propName = propList[nProp].Name; - if ( propName == "OOXActiveXBin" ) - { - propList[nProp].Value >>= activeXBinList; - break; - } - } - - for (sal_Int32 j = 0; j < activeXDomlist.getLength(); j++) - { - uno::Reference activeXDom = activeXDomlist[j]; - uno::Reference activeXBin = activeXBinList[j]; - - if ( activeXDom.is() ) - { - m_pFilter->addRelation( m_pDocumentFS->getOutputStream(), - oox::getRelationship(Relationship::CONTROL), - "activeX/activeX"+OUString::number((j+1))+".xml" ); - - uno::Reference< xml::sax::XSAXSerializable > serializer( activeXDom, uno::UNO_QUERY ); - uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() ); - writer->setOutputStream( GetFilter().openFragmentStream( "word/activeX/activeX"+OUString::number((j+1))+".xml", - "application/vnd.ms-office.activeX+xml" ) ); - serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ), - uno::Sequence< beans::StringPair >() ); - } - - if ( activeXBin.is() ) - { - uno::Reference< io::XOutputStream > xOutStream = GetFilter().openFragmentStream("word/activeX/activeX"+OUString::number((j+1))+".bin", - "application/vnd.ms-office.activeX"); - - try - { - sal_Int32 nBufferSize = 512; - uno::Sequence< sal_Int8 > aDataBuffer(nBufferSize); - sal_Int32 nRead; - do - { - nRead = activeXBin->readBytes( aDataBuffer, nBufferSize ); - if( nRead ) - { - if( nRead < nBufferSize ) - { - nBufferSize = nRead; - aDataBuffer.realloc(nRead); - } - xOutStream->writeBytes( aDataBuffer ); - } - } - while( nRead ); - xOutStream->flush(); - } - catch(const uno::Exception&) - { - SAL_WARN("sw.ww8", "WriteActiveX() ::Failed to copy Inputstream to outputstream exception caught!"); - } - - xOutStream->closeOutput(); - // Adding itemprops's relationship entry to item.xml.rels file - m_pFilter->addRelation( GetFilter().openFragmentStream( "/word/activeX/activeX"+OUString::number((j+1))+".xml", - "application/vnd.ms-office.activeX+xml" ) , - oox::getRelationship(Relationship::ACTIVEXCONTROLBINARY), - "activeX"+OUString::number((j+1))+".bin" ); - - } - } -} - void DocxExport::WriteVBA() { uno::Reference xStorageBasedDocument(m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY); @@ -1528,6 +1484,7 @@ DocxExport::DocxExport( DocxExportFilter *pFilter, SwDoc *pDocument, SwPaM *pCur m_nHeaders( 0 ), m_nFooters( 0 ), m_nOLEObjects( 0 ), + m_nActiveXControls( 0 ), m_nHeadersFootersInSection(0), m_pVMLExport( nullptr ), m_pSdrExport( nullptr ), diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx index 915f50122bfc..73f690a66198 100644 --- a/sw/source/filter/ww8/docxexport.hxx +++ b/sw/source/filter/ww8/docxexport.hxx @@ -49,6 +49,7 @@ namespace oox { namespace com { namespace sun { namespace star { namespace frame { class XModel; } namespace drawing { class XShape; } + namespace awt { class XControlModel; } } } } /// Data to be written in the document settings part of the document @@ -91,6 +92,9 @@ class DocxExport : public MSWordExportBase /// OLE objects counter. sal_Int32 m_nOLEObjects; + /// ActiveX controls counter + sal_Int32 m_nActiveXControls; + ///Footer and Header counter in Section properties sal_Int32 m_nHeadersFootersInSection; @@ -174,6 +178,8 @@ public: /// Returns the relationd id OString OutputChart( css::uno::Reference< css::frame::XModel > const & xModel, sal_Int32 nCount, ::sax_fastparser::FSHelperPtr const & m_pSerializer ); OString WriteOLEObject(SwOLEObj& rObject, OUString & io_rProgID); + std::pair WriteActiveXObject(const uno::Reference& rxShape, + const uno::Reference& rxControlModel); /// Writes the shape using drawingML syntax. void OutputDML( css::uno::Reference< css::drawing::XShape > const & xShape ); -- cgit