diff options
author | Tamás Zolnai <tamas.zolnai@collabora.com> | 2017-08-23 17:46:30 +0200 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2017-08-25 15:31:15 +0200 |
commit | 9b40796fd3e8f724d69a343e0444220b69a6d6ab (patch) | |
tree | 777eeff0e42ce26e6011cf01c014dcba144f29cc | |
parent | 8170245a9d9b9aeff913e0b3477fc2a9d508af80 (diff) |
tdf#50097: DOCX: export form controls as MSO ActiveX controls
* 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
Signed-off-by: Tamás Zolnai <tamas.zolnai@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/41256
Tested-by: Jenkins <ci@libreoffice.org>
(cherry picked from commit c0cc02e2934aeb12dda44818955e5964496c186a)
Change-Id: I38bb2b2ffd2676c5459b61ec2549c31348bab41c
This test intended to be an export test
Change-Id: Ib233bd603185efdb85ed30f3d00c28512d57a0ac
Reviewed-on: https://gerrit.libreoffice.org/41355
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Tamás Zolnai <tamas.zolnai@collabora.com>
(cherry picked from commit a7e8c5304b740cb4e03e25b7217ce6071c29c09b)
Fix two issues in ActiveX DOCX import / export code
* Inline anchored VML shape had wrong vertical position
** In MSO inline shapes are positioned to the top of the baseline
* During export all shape ids were the same (shape_0)
** VML shapes used to be exported only as fallback,
I guess that's why it did not cause any issue before.
** Override the shapeid generator with a new one, which
actually generates unique shapeids.
Reviewed-on: https://gerrit.libreoffice.org/41319
Reviewed-by: Tamás Zolnai <tamas.zolnai@collabora.com>
Tested-by: Tamás Zolnai <tamas.zolnai@collabora.com>
(cherry picked from commit 2d1fe7fb67ec1ff1b96912c0945d17d54aecb12e)
Change-Id: I752f39d092d0b61d91824141655dae662dbeafbc
DOCX: Fix an other test case of ActiveX control export
When LO control is anchored to the end of the run, it
is exported into a new run.
Reviewed-on: https://gerrit.libreoffice.org/41472
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Tamás Zolnai <tamas.zolnai@collabora.com>
(cherry picked from commit b129421764ae78a1422812169fce8eb4914a6b22)
Change-Id: I9269fd1b34924780aad61c452d1e2094dc8e4aad
Reviewed-on: https://gerrit.libreoffice.org/41484
Reviewed-by: Andras Timar <andras.timar@collabora.com>
Tested-by: Andras Timar <andras.timar@collabora.com>
31 files changed, 545 insertions, 355 deletions
diff --git a/filter/source/msfilter/eschesdo.cxx b/filter/source/msfilter/eschesdo.cxx index 5b9028d0db03..ba28dbfa48d5 100644 --- a/filter/source/msfilter/eschesdo.cxx +++ b/filter/source/msfilter/eschesdo.cxx @@ -39,6 +39,7 @@ #include <com/sun/star/drawing/TextAdjust.hpp> #include <com/sun/star/drawing/LineDash.hpp> #include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> #include <com/sun/star/drawing/CircleKind.hpp> #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/task/XStatusIndicator.hpp> @@ -423,7 +424,24 @@ sal_uInt32 ImplEESdrWriter::ImplWriteShape( ImplEESdrObject& rObj, } else if ( rObj.GetType() == "drawing.Control" ) { - break; + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + bool bInline = false; + const Reference< XPropertySet > xPropSet(rObj.mXPropSet, UNO_QUERY); + if(xPropSet.is()) + { + text::TextContentAnchorType eAnchorType; + xPropSet->getPropertyValue("AnchorType") >>= eAnchorType; + bInline = eAnchorType == text::TextContentAnchorType_AS_CHARACTER; + } + + if(bInline) + { + ADD_SHAPE( ESCHER_ShpInst_PictureFrame, SHAPEFLAG_HAVESPT | SHAPEFLAG_HAVEANCHOR ); + } + else + { + ADD_SHAPE( ESCHER_ShpInst_HostControl, SHAPEFLAG_HAVESPT | SHAPEFLAG_HAVEANCHOR ); + } } else if ( rObj.GetType() == "drawing.Connector" ) { diff --git a/include/filter/msfilter/escherex.hxx b/include/filter/msfilter/escherex.hxx index 746bb2a6d5e0..7948716a67fc 100644 --- a/include/filter/msfilter/escherex.hxx +++ b/include/filter/msfilter/escherex.hxx @@ -1048,7 +1048,8 @@ public: /** Creates and returns a new shape identifier, updates the internal shape counters and registers the identifier in the DGG cluster table. */ - inline sal_uInt32 GenerateShapeId() { return mxGlobal->GenerateShapeId( mnCurrentDg, mbEscherSpgr ); } + virtual sal_uInt32 GenerateShapeId() { return mxGlobal->GenerateShapeId( mnCurrentDg, mbEscherSpgr ); } + /** Returns the graphic provider from the global object that has been passed to the constructor. diff --git a/include/oox/export/vmlexport.hxx b/include/oox/export/vmlexport.hxx index e9971e0c685a..6ef32469e2af 100644 --- a/include/oox/export/vmlexport.hxx +++ b/include/oox/export/vmlexport.hxx @@ -82,6 +82,7 @@ class OOX_DLLPUBLIC VMLExport : public EscherEx /// Anchoring. sal_Int16 m_eHOri, m_eVOri, m_eHRel, m_eVRel; + bool m_bInline; // css::text::TextContentAnchorType_AS_CHARACTER /// Parent position. const Point* m_pNdTopLeft; @@ -101,11 +102,31 @@ class OOX_DLLPUBLIC VMLExport : public EscherEx /// Remember style, the most important shape attribute ;-) OStringBuffer *m_pShapeStyle; + /// Remember the generated shape id. + OString m_sShapeId; + /// Remember which shape types we had already written. bool *m_pShapeTypeWritten; + /// It seems useless to write out an XML_ID attribute next to XML_id which defines the actual shape id + bool m_bSkipwzName; + + /// Use '#' mark for type attribute (check Type Attribute of VML shape in OOXML documentation) + bool m_bUseHashMarkForType; + + /** There is a shapeid generation mechanism in EscherEx, but it does not seem to work + * so override the existing behavior to get actually unique ids. + */ + bool m_bOverrideShapeIdGeneration; + + /// Prefix for overriden shape id generation (used if m_bOverrideShapeIdGeneration is true) + OString m_sShapeIDPrefix; + + /// Counter for generating shape ids (used if m_bOverrideShapeIdGeneration is true) + sal_uInt64 m_nShapeIDCounter; + public: - VMLExport( ::sax_fastparser::FSHelperPtr const & pSerializer, VMLTextExport* pTextExport = nullptr ); + VMLExport( ::sax_fastparser::FSHelperPtr const & pSerializer, VMLTextExport* pTextExport = nullptr); virtual ~VMLExport() override; const ::sax_fastparser::FSHelperPtr& @@ -116,11 +137,16 @@ public: /// Export the sdr object as VML. /// /// Call this when you need to export the object as VML. - void AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri = -1, + OString AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri = -1, sal_Int16 eVOri = -1, sal_Int16 eHRel = -1, sal_Int16 eVRel = -1, const Point* pNdTopLeft = nullptr, const bool bOOxmlExport = false ); + OString AddInlineSdrObject( const SdrObject& rObj, const bool bOOxmlExport = false ); virtual void AddSdrObjectVMLObject( const SdrObject& rObj) override; static bool IsWaterMarkShape(const OUString& rStr); + + void SetSkipwzName(bool bSkipwzName) { m_bSkipwzName = bSkipwzName; } + void SetHashMarkForType(bool bUseHashMarkForType) { m_bUseHashMarkForType = bUseHashMarkForType; } + void OverrideShapeIDGen(bool bOverrideShapeIdGeneration, const OString sShapeIDPrefix = OString()); protected: /// Add an attribute to the generated <v:shape/> element. /// @@ -131,6 +157,9 @@ protected: using EscherEx::StartShape; using EscherEx::EndShape; + /// Override shape ID generation when m_bOverrideShapeIdGeneration is set to true + virtual sal_uInt32 GenerateShapeId() override; + /// Start the shape for which we just collected the information. /// /// Returns the element's tag number, -1 means we wrote nothing. @@ -154,7 +183,7 @@ private: private: /// Create an OString representing the id from a numerical id. - static OString ShapeIdString( sal_uInt32 nId ); + OString ShapeIdString( sal_uInt32 nId ); /// Add flip X and\or flip Y void AddFlipXY( ); diff --git a/include/oox/ole/olehelper.hxx b/include/oox/ole/olehelper.hxx index 4e2a2d8e62fc..dbbf1a110d1a 100644 --- a/include/oox/ole/olehelper.hxx +++ b/include/oox/ole/olehelper.hxx @@ -29,6 +29,7 @@ #include <rtl/ustring.hxx> #include <sal/types.h> #include <tools/ref.hxx> +#include <memory> namespace com { namespace sun { namespace star { namespace awt { class XControlModel; } @@ -52,6 +53,8 @@ namespace oox { namespace ole { + class ControlModelBase; + class EmbeddedControl; #define OLE_GUID_STDFONT "{0BE35203-8F91-11CE-9DE3-00AA004BB851}" @@ -134,6 +137,38 @@ namespace OleHelper bool bWithGuid ); } +class OOX_DLLPUBLIC OleFormCtrlExportHelper final +{ + std::unique_ptr<::oox::ole::EmbeddedControl> mpControl; + ::oox::ole::ControlModelBase* mpModel; + ::oox::GraphicHelper maGrfHelper; + css::uno::Reference< css::frame::XModel > mxDocModel; + css::uno::Reference< css::awt::XControlModel > mxControlModel; + + OUString maName; + OUString maTypeName; + OUString maFullName; + OUString maGUID; +public: + OleFormCtrlExportHelper( const css::uno::Reference< css::uno::XComponentContext >& rxCtx, const css::uno::Reference< css::frame::XModel >& xDocModel, const css::uno::Reference< css::awt::XControlModel >& xModel ); + ~OleFormCtrlExportHelper(); + + OUString getGUID() + { + OUString sResult; + if ( maGUID.getLength() > 2 ) + sResult = maGUID.copy(1, maGUID.getLength() - 2 ); + return sResult; + } + const OUString& getFullName() { return maFullName; } + const OUString& getTypeName() { return maTypeName; } + const OUString& getName() { return maName; } + bool isValid() { return mpModel != nullptr; } + void exportName( const css::uno::Reference< css::io::XOutputStream >& rxOut ); + void exportCompObj( const css::uno::Reference< css::io::XOutputStream >& rxOut ); + void exportControl( const css::uno::Reference< css::io::XOutputStream >& rxOut, const css::awt::Size& rSize, bool bAutoClose = false ); +}; + // ideally it would be great to get rid of SvxMSConvertOCXControls // however msfilter/source/msfilter/svdfppt.cxx still uses // SvxMSConvertOCXControls as a base class, unfortunately oox depends on diff --git a/oox/source/export/preset-definitions-to-shape-types.pl b/oox/source/export/preset-definitions-to-shape-types.pl index 2fe929705746..b41dd58953e8 100644 --- a/oox/source/export/preset-definitions-to-shape-types.pl +++ b/oox/source/export/preset-definitions-to-shape-types.pl @@ -287,7 +287,7 @@ my %shapes_ids = ( 198 => 'actionButtonDocument', 199 => 'actionButtonSound', 200 => 'actionButtonMovie', - 201 => 'hostControl', # should not be used + 201 => 'hostControl', 202 => 'textBox' ); # An error occurred, we have to ignore this shape diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx index 33c112e0c287..cf6e5d6234f2 100644 --- a/oox/source/export/vmlexport.cxx +++ b/oox/source/export/vmlexport.cxx @@ -59,6 +59,7 @@ VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr const & pSerializer, VMLText , m_eVOri( 0 ) , m_eHRel( 0 ) , m_eVRel( 0 ) + , m_bInline( false ) , m_pNdTopLeft( nullptr ) , m_pSdrObject( nullptr ) , m_pShapeAttrList( nullptr ) @@ -66,6 +67,10 @@ VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr const & pSerializer, VMLText , m_nShapeFlags(0) , m_pShapeStyle( new OStringBuffer( 200 ) ) , m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT ] ) + , m_bSkipwzName( false ) + , m_bUseHashMarkForType( false ) + , m_bOverrideShapeIdGeneration( false ) + , m_nShapeIDCounter( 0 ) { mnGroupLevel = 1; memset( m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof( bool ) ); @@ -188,19 +193,21 @@ void VMLExport::AddShape( sal_uInt32 nShapeType, sal_uInt32 nShapeFlags, sal_uIn { m_nShapeType = nShapeType; m_nShapeFlags = nShapeFlags; + + m_sShapeId = ShapeIdString( nShapeId ); // If shape is a watermark object - should keep the original shape's name // because Microsoft detects if it is a watermark by the actual name if (!IsWaterMarkShape(m_pSdrObject->GetName())) { // Not a watermark object - m_pShapeAttrList->add( XML_id, ShapeIdString( nShapeId ) ); + m_pShapeAttrList->add( XML_id, m_sShapeId ); } else { // A watermark object - store the optional shape ID m_pShapeAttrList->add( XML_id, OUStringToOString(m_pSdrObject->GetName(), RTL_TEXTENCODING_UTF8) ); // also ('o:spid') - m_pShapeAttrList->addNS( XML_o, XML_spid, ShapeIdString( nShapeId ) ); + m_pShapeAttrList->addNS( XML_o, XML_spid, m_sShapeId ); } } @@ -214,6 +221,18 @@ bool VMLExport::IsWaterMarkShape(const OUString& rStr) return false; } +void VMLExport::OverrideShapeIDGen(bool bOverrideShapeIdGen, const OString sShapeIDPrefix) +{ + m_bOverrideShapeIdGeneration = bOverrideShapeIdGen; + if(bOverrideShapeIdGen) + { + assert(!sShapeIDPrefix.isEmpty()); + m_sShapeIDPrefix = sShapeIDPrefix; + } + else + m_sShapeIDPrefix.clear(); +} + static void impl_AddArrowHead( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue ) { if ( !pAttrList ) @@ -859,7 +878,7 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect aStream.Seek(0); OUString idStr = SvxMSDffManager::MSDFFReadZString(aStream, it->nPropSize, true); aStream.Seek(0); - if (!IsWaterMarkShape(m_pSdrObject->GetName())) + if (!IsWaterMarkShape(m_pSdrObject->GetName()) && !m_bSkipwzName) m_pShapeAttrList->add(XML_ID, OUStringToOString(idStr, RTL_TEXTENCODING_UTF8).getStr()); bAlreadyWritten[ESCHER_Prop_wzName] = true; @@ -890,7 +909,10 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect OString VMLExport::ShapeIdString( sal_uInt32 nId ) { - return OStringBuffer( 20 ).append( "shape_" ).append( sal_Int64( nId ) ).makeStringAndClear(); + if(m_bOverrideShapeIdGeneration) + return OStringBuffer( 20 ).append( m_sShapeIDPrefix ).append( sal_Int64( nId ) ).makeStringAndClear(); + else + return OStringBuffer( 20 ).append( "shape_" ).append( sal_Int64( nId ) ).makeStringAndClear(); } void VMLExport::AddFlipXY( ) @@ -949,12 +971,18 @@ void VMLExport::AddRectangleDimensions( OStringBuffer& rBuffer, const Rectangle& if ( !rBuffer.isEmpty() ) rBuffer.append( ";" ); - if (rbAbsolutePos) + if (rbAbsolutePos && !m_bInline) { rBuffer.append( "position:absolute;" ); } - if ( mnGroupLevel == 1 ) + if(m_bInline) + { + rBuffer.append( "width:" ).append( double( rRectangle.Right() - rRectangle.Left() ) / 20 ) + .append( "pt;height:" ).append( double( rRectangle.Bottom() - rRectangle.Top() ) / 20 ) + .append( "pt" ); + } + else if ( mnGroupLevel == 1 ) { rBuffer.append( "margin-left:" ).append( double( rRectangle.Left() ) / 20 ) .append( "pt;margin-top:" ).append( double( rRectangle.Top() ) / 20 ) @@ -1025,6 +1053,14 @@ OUString lcl_getAnchorIdFromGrabBag(const SdrObject* pSdrObject) return aResult; } +sal_uInt32 VMLExport::GenerateShapeId() +{ + if(!m_bOverrideShapeIdGeneration) + return EscherEx::GenerateShapeId(); + else + return m_nShapeIDCounter++; +} + sal_Int32 VMLExport::StartShape() { if ( m_nShapeType == ESCHER_ShpInst_Nil ) @@ -1041,6 +1077,62 @@ sal_Int32 VMLExport::StartShape() case ESCHER_ShpInst_Ellipse: nShapeElement = XML_oval; break; case ESCHER_ShpInst_Arc: nShapeElement = XML_arc; break; case ESCHER_ShpInst_Line: nShapeElement = XML_line; break; + case ESCHER_ShpInst_HostControl: + { + // We don't have a shape definition for host control in presetShapeDefinitions.xml + // So use a definition copied from DOCX file created with MSO + bReferToShapeType = true; + nShapeElement = XML_shape; + if ( !m_pShapeTypeWritten[ m_nShapeType ] ) + { + OStringBuffer sShapeType; + sShapeType.append("<v:shapetype id=\"shapetype_").append(OString::number(m_nShapeType)). + append("\" coordsize=\"21600,21600\" o:spt=\"").append(OString::number(m_nShapeType)). + append("\" path=\"m,l,21600l21600,21600l21600,xe\">\n"). + append("<v:stroke joinstyle=\"miter\"/>\n" + "<v:path shadowok=\"f\" o:extrusionok=\"f\" strokeok=\"f\" fillok=\"f\" o:connecttype=\"rect\"/>\n" + "<o:lock v:ext=\"edit\" shapetype=\"t\"/>\n" + "</v:shapetype>"); + m_pSerializer->write(sShapeType.makeStringAndClear().getStr()); + m_pShapeTypeWritten[ m_nShapeType ] = true; + } + break; + } + case ESCHER_ShpInst_PictureFrame: + { + // We don't have a shape definition for picture frame in presetShapeDefinitions.xml + // So use a definition copied from DOCX file created with MSO + bReferToShapeType = true; + nShapeElement = XML_shape; + if ( !m_pShapeTypeWritten[ m_nShapeType ] ) + { + OStringBuffer sShapeType; + sShapeType.append("<v:shapetype id=\"shapetype_").append(OString::number(m_nShapeType)). + append("\" coordsize=\"21600,21600\" o:spt=\"").append(OString::number(m_nShapeType)). + append("\" o:preferrelative=\"t\" path=\"m@4@5l@4@11@9@11@9@5xe\" filled=\"f\" stroked=\"f\">\n"). + append("<v:stroke joinstyle=\"miter\"/>\n" + "<v:formulas>\n" + "<v:f eqn=\"if lineDrawn pixelLineWidth 0\"/>\n" + "<v:f eqn=\"sum @0 1 0\"/>\n" + "<v:f eqn=\"sum 0 0 @1\"/>\n" + "<v:f eqn=\"prod @2 1 2\"/>\n" + "<v:f eqn=\"prod @3 21600 pixelWidth\"/>\n" + "<v:f eqn=\"prod @3 21600 pixelHeight\"/>\n" + "<v:f eqn=\"sum @0 0 1\"/>\n" + "<v:f eqn=\"prod @6 1 2\"/>\n" + "<v:f eqn=\"prod @7 21600 pixelWidth\"/>\n" + "<v:f eqn=\"sum @8 21600 0\"/>\n" + "<v:f eqn=\"prod @7 21600 pixelHeight\"/>\n" + "<v:f eqn=\"sum @10 21600 0\"/>\n" + "</v:formulas>\n" + "<v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\"/>\n" + "<o:lock v:ext=\"edit\" aspectratio=\"t\"/>\n" + "</v:shapetype>"); + m_pSerializer->write(sShapeType.makeStringAndClear().getStr()); + m_pShapeTypeWritten[ m_nShapeType ] = true; + } + break; + } default: if ( m_nShapeType < ESCHER_ShpInst_COUNT ) { @@ -1147,7 +1239,10 @@ sal_Int32 VMLExport::StartShape() if ( nShapeElement >= 0 && !m_pShapeAttrList->hasAttribute( XML_type ) && bReferToShapeType ) { - m_pShapeAttrList->add( XML_type, OStringBuffer( 20 ) + OStringBuffer sTypeBuffer( 20 ); + if (m_bUseHashMarkForType) + sTypeBuffer.append("#"); + m_pShapeAttrList->add( XML_type, sTypeBuffer .append( "shapetype_" ).append( sal_Int32( m_nShapeType ) ) .makeStringAndClear() ); } @@ -1220,7 +1315,7 @@ void VMLExport::EndShape( sal_Int32 nShapeElement ) } } -void VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 eVOri, sal_Int16 eHRel, sal_Int16 eVRel, const Point* pNdTopLeft, const bool bOOxmlExport ) +OString VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 eVOri, sal_Int16 eHRel, sal_Int16 eVRel, const Point* pNdTopLeft, const bool bOOxmlExport ) { m_pSdrObject = &rObj; m_eHOri = eHOri; @@ -1228,7 +1323,21 @@ void VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 m_eHRel = eHRel; m_eVRel = eVRel; m_pNdTopLeft = pNdTopLeft; + m_bInline = false; + EscherEx::AddSdrObject(rObj, bOOxmlExport); + return m_sShapeId; +} + +OString VMLExport::AddInlineSdrObject( const SdrObject& rObj, const bool bOOxmlExport ) +{ + m_pSdrObject = &rObj; + m_eHOri = -1; + m_eVOri = -1; + m_eHRel = -1; + m_eVRel = -1; + m_bInline = true; EscherEx::AddSdrObject(rObj, bOOxmlExport); + return m_sShapeId; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/ole/olehelper.cxx b/oox/source/ole/olehelper.cxx index bb1ed9ce4f67..d78a3ac8e8eb 100644 --- a/oox/source/ole/olehelper.cxx +++ b/oox/source/ole/olehelper.cxx @@ -330,35 +330,7 @@ Reference< css::frame::XFrame > lcl_getFrame( const Reference< css::frame::XMod return xFrame; } -class OleFormCtrlExportHelper final -{ - ::oox::ole::EmbeddedControl maControl; - ::oox::ole::ControlModelBase* mpModel; - ::oox::GraphicHelper maGrfHelper; - Reference< XModel > mxDocModel; - Reference< XControlModel > mxControlModel; - - OUString maName; - OUString maTypeName; - OUString maFullName; - OUString maGUID; -public: - OleFormCtrlExportHelper( const Reference< XComponentContext >& rxCtx, const Reference< XModel >& xDocModel, const Reference< XControlModel >& xModel ); - OUString getGUID() - { - OUString sResult; - if ( maGUID.getLength() > 2 ) - sResult = maGUID.copy(1, maGUID.getLength() - 2 ); - return sResult; - } - const OUString& getFullName() { return maFullName; } - const OUString& getTypeName() { return maTypeName; } - bool isValid() { return mpModel != nullptr; } - void exportName( const Reference< XOutputStream >& rxOut ); - void exportCompObj( const Reference< XOutputStream >& rxOut ); - void exportControl( const Reference< XOutputStream >& rxOut, const css::awt::Size& rSize ); -}; -OleFormCtrlExportHelper::OleFormCtrlExportHelper( const Reference< XComponentContext >& rxCtx, const Reference< XModel >& rxDocModel, const Reference< XControlModel >& xCntrlModel ) : maControl( "Unknown" ), mpModel( nullptr ), maGrfHelper( rxCtx, lcl_getFrame( rxDocModel ), StorageRef() ), mxDocModel( rxDocModel ), mxControlModel( xCntrlModel ) +OleFormCtrlExportHelper::OleFormCtrlExportHelper( const Reference< XComponentContext >& rxCtx, const Reference< XModel >& rxDocModel, const Reference< XControlModel >& xCntrlModel ) : mpControl(nullptr), mpModel( nullptr ), maGrfHelper( rxCtx, lcl_getFrame( rxDocModel ), StorageRef() ), mxDocModel( rxDocModel ), mxControlModel( xCntrlModel ) { // try to get the guid Reference< css::beans::XPropertySet > xProps( xCntrlModel, UNO_QUERY ); @@ -405,14 +377,18 @@ OleFormCtrlExportHelper::OleFormCtrlExportHelper( const Reference< XComponentCo aPropSet.getProperty(maName, PROP_Name ); maTypeName = OUString::createFromAscii( it->second.sName ); maFullName = "Microsoft Forms 2.0 " + maTypeName; - maControl = EmbeddedControl( maName ); + mpControl.reset(new EmbeddedControl( maName )); maGUID = OUString::createFromAscii( it->second.sGUID ); - mpModel = maControl.createModelFromGuid( maGUID ); + mpModel = mpControl->createModelFromGuid( maGUID ); } } } } +OleFormCtrlExportHelper::~OleFormCtrlExportHelper() +{ +} + void OleFormCtrlExportHelper::exportName( const Reference< XOutputStream >& rxOut ) { oox::BinaryXOutputStream aOut( rxOut, false ); @@ -427,13 +403,14 @@ void OleFormCtrlExportHelper::exportCompObj( const Reference< XOutputStream >& r mpModel->exportCompObj( aOut ); } -void OleFormCtrlExportHelper::exportControl( const Reference< XOutputStream >& rxOut, const Size& rSize ) +void OleFormCtrlExportHelper::exportControl( const Reference< XOutputStream >& rxOut, const Size& rSize, bool bAutoClose ) { - oox::BinaryXOutputStream aOut( rxOut, false ); + oox::BinaryXOutputStream aOut( rxOut, bAutoClose ); if ( mpModel ) { ::oox::ole::ControlConverter aConv( mxDocModel, maGrfHelper ); - maControl.convertFromProperties( mxControlModel, aConv ); + if(mpControl) + mpControl->convertFromProperties( mxControlModel, aConv ); mpModel->maSize.first = rSize.Width; mpModel->maSize.second = rSize.Height; mpModel->exportBinaryModel( aOut ); diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt index 6d4fcb8a47f5..99ff379230be 100644 --- a/oox/source/token/tokens.txt +++ b/oox/source/token/tokens.txt @@ -745,6 +745,7 @@ avLst average avg avgSubtotal +ax axId axPos axis @@ -5808,6 +5809,7 @@ xmlPr xmlns xpath xrange +xsc xscale xsi xy diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx index 9f9903a04e88..814835fae503 100644 --- a/oox/source/vml/vmlshape.cxx +++ b/oox/source/vml/vmlshape.cxx @@ -623,6 +623,8 @@ void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, else // static (is the default) means anchored inline { rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER); + // Use top orientation, this one seems similar to what MSO uses as inline + rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::TOP)); } lcl_setSurround( rPropSet, rTypeModel, rGraphicHelper ); } diff --git a/sw/qa/extras/ooxmlexport/data/activex.docx b/sw/qa/extras/ooxmlexport/data/activex.docx Binary files differdeleted file mode 100644 index eb546d9795ef..000000000000 --- a/sw/qa/extras/ooxmlexport/data/activex.docx +++ /dev/null diff --git a/sw/qa/extras/ooxmlimport/data/activex_checkbox.docx b/sw/qa/extras/ooxmlexport/data/activex_checkbox.docx Binary files differindex d7415ef5a5c6..d7415ef5a5c6 100755 --- a/sw/qa/extras/ooxmlimport/data/activex_checkbox.docx +++ b/sw/qa/extras/ooxmlexport/data/activex_checkbox.docx diff --git a/sw/qa/extras/ooxmlexport/data/activex_control_align.odt b/sw/qa/extras/ooxmlexport/data/activex_control_align.odt Binary files differnew file mode 100755 index 000000000000..b9944c7e5abe --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/activex_control_align.odt diff --git a/sw/qa/extras/ooxmlexport/data/activex_control_at_run_end.odt b/sw/qa/extras/ooxmlexport/data/activex_control_at_run_end.odt Binary files differnew file mode 100755 index 000000000000..9008cb90a530 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/activex_control_at_run_end.odt diff --git a/sw/qa/extras/ooxmlexport/data/activexbin.docx b/sw/qa/extras/ooxmlexport/data/activexbin.docx Binary files differdeleted file mode 100644 index ecf4599ed0e9..000000000000 --- a/sw/qa/extras/ooxmlexport/data/activexbin.docx +++ /dev/null diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx index db99b277daf4..9902cb127141 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx @@ -15,7 +15,6 @@ #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/drawing/LineJoint.hpp> #include <com/sun/star/drawing/LineStyle.hpp> -#include <com/sun/star/drawing/XControlShape.hpp> #include <com/sun/star/awt/Gradient.hpp> #include <com/sun/star/style/TabStop.hpp> #include <com/sun/star/view/XViewSettingsSupplier.hpp> diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx index 6844e3ead9fc..151b1cc65c53 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx @@ -15,7 +15,6 @@ #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/drawing/LineJoint.hpp> #include <com/sun/star/drawing/LineStyle.hpp> -#include <com/sun/star/drawing/XControlShape.hpp> #include <com/sun/star/awt/Gradient.hpp> #include <com/sun/star/style/TabStop.hpp> #include <com/sun/star/view/XViewSettingsSupplier.hpp> @@ -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<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); - uno::Reference<beans::XPropertySet> xTextDocumentPropertySet(xTextDocument, uno::UNO_QUERY); - uno::Sequence<beans::PropertyValue> 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<xml::dom::XDocument> aActiveXDom; - uno::Sequence<uno::Reference<xml::dom::XDocument> > 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<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); - uno::Reference<beans::XPropertySet> xTextDocumentPropertySet(xTextDocument, uno::UNO_QUERY); - uno::Sequence<beans::PropertyValue> 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<io::XInputStream> aActiveXBin; - uno::Sequence<uno::Reference<io::XInputStream> > 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 8e6714e7bfff..0796a20f2502 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx @@ -15,7 +15,6 @@ #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/drawing/LineJoint.hpp> #include <com/sun/star/drawing/LineStyle.hpp> -#include <com/sun/star/drawing/XControlShape.hpp> #include <com/sun/star/awt/Gradient.hpp> #include <com/sun/star/style/TabStop.hpp> #include <com/sun/star/view/XViewSettingsSupplier.hpp> 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 <swmodeltestbase.hxx> -#if !defined(_WIN32) + #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp> #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp> @@ -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 e7f24005cd92..1b9d9b82fee8 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx @@ -9,7 +9,7 @@ #include <swmodeltestbase.hxx> -#if !defined(_WIN32) + #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp> #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp> @@ -123,7 +123,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"); } @@ -1120,6 +1120,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"); @@ -1127,9 +1128,8 @@ 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 +} CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx index ccba14821d76..0a0ea9f3804e 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx @@ -10,7 +10,6 @@ #include <swmodeltestbase.hxx> #include <com/sun/star/beans/XPropertySet.hpp> -#include <com/sun/star/drawing/XControlShape.hpp> #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp> #include <com/sun/star/text/XPageCursor.hpp> #include <com/sun/star/text/XTextColumns.hpp> @@ -21,9 +20,12 @@ #include <com/sun/star/graphic/XGraphic.hpp> #include <com/sun/star/text/HoriOrientation.hpp> #include <com/sun/star/text/RelOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> #include <com/sun/star/view/XViewSettingsSupplier.hpp> #include <com/sun/star/style/LineSpacing.hpp> #include <com/sun/star/style/LineSpacingMode.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> #include <sfx2/docfile.hxx> #include <sfx2/docfilt.hxx> @@ -402,6 +404,129 @@ DECLARE_OOXMLEXPORT_TEST(testWatermark, "watermark-shapetype.docx") CPPUNIT_ASSERT_EQUAL(xPropertySet1->getPropertyValue("TextAutoGrowHeight"), xPropertySet2->getPropertyValue("TextAutoGrowHeight")); } +DECLARE_OOXMLEXPORT_TEST( testActiveXCheckbox, "activex_checkbox.docx" ) +{ + uno::Reference<drawing::XControlShape> xControlShape( getShape(1), uno::UNO_QUERY ); + CPPUNIT_ASSERT( xControlShape.is() ); + + // Check control type + uno::Reference<beans::XPropertySet> xPropertySet( xControlShape->getControl(), uno::UNO_QUERY ); + uno::Reference<lang::XServiceInfo> 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<OUString>(xPropertySet, "Label") ); + + // Check background color (highlight system color) + CPPUNIT_ASSERT_EQUAL( sal_Int32( 0x316AC5 ), getProperty<sal_Int32>(xPropertySet, "BackgroundColor") ); + + // Check Text color (active border system color) + if(!mbExported) // Bug: text color is not exported + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xD4D0C8), getProperty<sal_Int32>(xPropertySet, "TextColor")); + + // Check state of the checkbox + CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty<sal_Int16>(xPropertySet, "State")); + + // Check anchor type + uno::Reference<beans::XPropertySet> xPropertySet2(xControlShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER,getProperty<text::TextContentAnchorType>(xPropertySet2,"AnchorType")); +} + +DECLARE_OOXMLEXPORT_TEST(testActiveXControlAlign, "activex_control_align.odt") +{ + // First check box aligned as a floating object + uno::Reference<drawing::XControlShape> xControlShape(getShape(1), uno::UNO_QUERY); + CPPUNIT_ASSERT(xControlShape.is()); + + // Check whether we have the right control + uno::Reference<beans::XPropertySet> xPropertySet(xControlShape->getControl(), uno::UNO_QUERY); + uno::Reference<lang::XServiceInfo> xServiceInfo(xPropertySet, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(true, bool(xServiceInfo->supportsService( "com.sun.star.form.component.CheckBox"))); + CPPUNIT_ASSERT_EQUAL(OUString("Floating Check Box"), getProperty<OUString>(xPropertySet, "Label")); + + // Check anchor type + uno::Reference<beans::XPropertySet> xPropertySet2(xControlShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER,getProperty<text::TextContentAnchorType>(xPropertySet2,"AnchorType")); + + // Also check positin and size + uno::Reference<drawing::XShape> xShape(xControlShape, uno::UNO_QUERY); + CPPUNIT_ASSERT(xShape.is()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(4470), xShape->getSize().Width); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1427), xShape->getSize().Height); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5126), xShape->getPosition().X); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2341), xShape->getPosition().Y); + + // Second check box aligned inline / as character + xControlShape.set(getShape(2), uno::UNO_QUERY); + + // Check whether we have the right control + xPropertySet.set(xControlShape->getControl(), uno::UNO_QUERY); + xServiceInfo.set(xPropertySet, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(true, bool(xServiceInfo->supportsService("com.sun.star.form.component.CheckBox"))); + CPPUNIT_ASSERT_EQUAL(OUString("Inline Check Box"), getProperty<OUString>(xPropertySet, "Label")); + + // Check anchor type + xPropertySet2.set(xControlShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AS_CHARACTER,getProperty<text::TextContentAnchorType>(xPropertySet2,"AnchorType")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(text::VertOrientation::TOP),getProperty<sal_Int32>(xPropertySet2,"VertOrient")); + + // Also check positin and size + xShape.set(xControlShape, uno::UNO_QUERY); + CPPUNIT_ASSERT(xShape.is()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(4410), xShape->getSize().Width); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1083), xShape->getSize().Height); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xShape->getPosition().X); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1085), xShape->getPosition().Y); + + // Also check the specific OOXML elements + xmlDocPtr pXmlDoc = parseExport(); + CPPUNIT_ASSERT(pXmlDoc); + // For inline controls use w:object as parent element and pictureFrame shapetype + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/w:object", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/w:object/v:shapetype", "spt", "75"); + // For floating controls use w:pict as parent element and hostControl shapetype + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r[1]/w:pict", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r[1]/w:pict/v:shapetype", "spt", "201"); + + // Have different shape ids + CPPUNIT_ASSERT(getXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/w:object/v:shape", "id") != + getXPath(pXmlDoc, "/w:document/w:body/w:p/w:r[1]/w:pict/v:shape", "id")); +} + +DECLARE_OOXMLEXPORT_TEST(testActiveXControlAtRunEnd, "activex_control_at_run_end.odt") +{ + // Two issues were here: + // 1) second shape was not export (it is anchored to the end of the run) + // 2) inline property was inherited to the second shape by mistake + + // First checkbox is the inlined one + uno::Reference<drawing::XControlShape> xControlShape(getShape(1), uno::UNO_QUERY); + CPPUNIT_ASSERT(xControlShape.is()); + + // Check whether we have the right control + uno::Reference<beans::XPropertySet> xPropertySet(xControlShape->getControl(), uno::UNO_QUERY); + uno::Reference<lang::XServiceInfo> xServiceInfo(xPropertySet, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(true, bool(xServiceInfo->supportsService( "com.sun.star.form.component.CheckBox"))); + CPPUNIT_ASSERT_EQUAL(OUString("Inline Checkbox"), getProperty<OUString>(xPropertySet, "Label")); + + // Check anchor type + uno::Reference<beans::XPropertySet> xPropertySet2(xControlShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AS_CHARACTER,getProperty<text::TextContentAnchorType>(xPropertySet2,"AnchorType")); + + // Second check box anchored to character + xControlShape.set(getShape(2), uno::UNO_QUERY); + + // Check whether we have the right control + xPropertySet.set(xControlShape->getControl(), uno::UNO_QUERY); + xServiceInfo.set(xPropertySet, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(true, bool(xServiceInfo->supportsService("com.sun.star.form.component.CheckBox"))); + CPPUNIT_ASSERT_EQUAL(OUString("Floating Checkbox"), getProperty<OUString>(xPropertySet, "Label")); + + // Check anchor type + xPropertySet2.set(xControlShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER,getProperty<text::TextContentAnchorType>(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 fa5f9dfc19b1..5fca6c4a6597 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx @@ -15,7 +15,6 @@ #include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/drawing/LineJoint.hpp> #include <com/sun/star/drawing/LineStyle.hpp> -#include <com/sun/star/drawing/XControlShape.hpp> #include <com/sun/star/awt/Gradient.hpp> #include <com/sun/star/style/TabStop.hpp> #include <com/sun/star/view/XViewSettingsSupplier.hpp> diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx index 4eb2512a4bf8..a45d1c8469e3 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx @@ -60,7 +60,6 @@ #include <unotools/streamwrap.hxx> #include <comphelper/propertysequence.hxx> #include <com/sun/star/drawing/HomogenMatrix3.hpp> -#include <com/sun/star/drawing/XControlShape.hpp> #include <com/sun/star/awt/CharSet.hpp> #include <com/sun/star/text/TextContentAnchorType.hpp> #include <test/mtfxmldump.hxx> @@ -87,7 +86,6 @@ public: } }; -#if !defined _WIN32 class FailTest : public Test { public: @@ -121,7 +119,7 @@ public: finish(); } }; -#endif + DECLARE_OOXMLIMPORT_TEST(testImageHyperlink, "image-hyperlink.docx") { @@ -129,8 +127,6 @@ DECLARE_OOXMLIMPORT_TEST(testImageHyperlink, "image-hyperlink.docx") CPPUNIT_ASSERT_EQUAL(OUString("http://www.libreoffice.org/"), URL); } -#if !defined(_WIN32) - DECLARE_SW_IMPORT_TEST(testMathMalformedXml, "math-malformed_xml.docx", nullptr, FailTest) { CPPUNIT_ASSERT(!mxComponent.is()); @@ -443,6 +439,7 @@ DECLARE_OOXMLIMPORT_TEST(testN775899, "n775899.docx") DECLARE_OOXMLIMPORT_TEST(testN777345, "n777345.docx") { #if !defined(MACOSX) +#if !defined(_WIN32) // The problem was that v:imagedata inside v:rect was ignored. uno::Reference<document::XEmbeddedObjectSupplier2> xSupplier(getShape(1), uno::UNO_QUERY); uno::Reference<graphic::XGraphic> xGraphic = xSupplier->getReplacementGraphic(); @@ -451,6 +448,7 @@ DECLARE_OOXMLIMPORT_TEST(testN777345, "n777345.docx") // the checksum of a white/transparent placeholder rectangle. CPPUNIT_ASSERT_EQUAL(BitmapChecksum(SAL_CONST_UINT64(18203404956065762943)), aGraphic.GetChecksum()); #endif +#endif } DECLARE_OOXMLIMPORT_TEST(testN778140, "n778140.docx") @@ -605,7 +603,7 @@ DECLARE_OOXMLIMPORT_TEST(testGroupshapeChildRotation, "groupshape-child-rotation uno::Reference<drawing::XShapes> xGroupShape(getShape(1), uno::UNO_QUERY); uno::Reference<drawing::XShape> xShape(xGroupShape->getByIndex(0), uno::UNO_QUERY); CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xShape->getPosition().X); - CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xShape->getPosition().Y); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-5741), xShape->getPosition().Y); #if ! TEST_FONTS_MISSING xShape.set(xGroupShape->getByIndex(4), uno::UNO_QUERY); @@ -1109,8 +1107,6 @@ DECLARE_OOXMLIMPORT_TEST(testTdf49073, "tdf49073.docx") CPPUNIT_ASSERT_EQUAL(sal_Int16(text::RubyAdjust_RIGHT) ,getProperty<sal_Int16>(getParagraph(6)->getStart(),"RubyAdjust")); } -#endif - DECLARE_OOXMLIMPORT_TEST(testTdf85232, "tdf85232.docx") { uno::Reference<drawing::XShapes> xShapes(getShapeByName("Group 219"), uno::UNO_QUERY); @@ -1591,33 +1587,6 @@ DECLARE_OOXMLIMPORT_TEST(testTdf111550, "tdf111550.docx") getCell(innerTable, "A1", "[outer:A2]\n[inner:A1]"); } -DECLARE_OOXMLIMPORT_TEST( testActiveXCheckbox, "activex_checkbox.docx" ) -{ - uno::Reference<drawing::XControlShape> xControlShape( getShape(1), uno::UNO_QUERY ); - CPPUNIT_ASSERT( xControlShape.is() ); - - // Check control type - uno::Reference<beans::XPropertySet> xPropertySet( xControlShape->getControl(), uno::UNO_QUERY ); - uno::Reference<lang::XServiceInfo> 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<OUString>(xPropertySet, "Label") ); - - // Check background color (highlight system color) - CPPUNIT_ASSERT_EQUAL( sal_Int32( 0x316AC5 ), getProperty<sal_Int32>(xPropertySet, "BackgroundColor") ); - - // Check Text color (active border system color) - CPPUNIT_ASSERT_EQUAL(sal_Int32(0xD4D0C8), getProperty<sal_Int32>(xPropertySet, "TextColor")); - - // Check state of the checkbox - CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty<sal_Int16>(xPropertySet, "State")); - - // Check anchor type - uno::Reference<beans::XPropertySet> xPropertySet2(xControlShape, uno::UNO_QUERY); - CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER,getProperty<text::TextContentAnchorType>(xPropertySet2,"AnchorType")); -} - // tests should only be added to ooxmlIMPORT *if* they fail round-tripping in ooxmlEXPORT CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index d6d0f5dd2a7c..dc99177ceef9 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -46,6 +46,8 @@ #include <oox/export/utils.hxx> #include <oox/mathml/export.hxx> #include <oox/drawingml/drawingmltypes.hxx> +#include <oox/export/vmlexport.hxx> +#include <oox/ole/olehelper.hxx> #include <editeng/autokernitem.hxx> #include <editeng/unoprnms.hxx> @@ -128,6 +130,7 @@ #include <com/sun/star/text/GraphicCrop.hpp> #include <com/sun/star/drawing/LineStyle.hpp> #include <com/sun/star/embed/EmbedStates.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> #include <algorithm> @@ -1309,6 +1312,8 @@ void DocxAttributeOutput::EndRun() WritePostponedFormControl(*it); m_aPostponedFormControls.clear(); + WritePostponedActiveXControl(false); + WritePendingPlaceholder(); m_pRedlineData = nullptr; @@ -2044,6 +2049,8 @@ void DocxAttributeOutput::EndRunProperties( const SwRedlineData* pRedlineData ) WritePostponedOLE(); + WritePostponedActiveXControl(true); + // 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); @@ -4735,6 +4742,115 @@ void DocxAttributeOutput::WritePostponedFormControl(const SdrObject* pObject) } } +void DocxAttributeOutput::WritePostponedActiveXControl(bool bInsideRun) +{ + for( std::vector<PostponedDrawing>::const_iterator it = m_aPostponedActiveXControls.begin(); + it != m_aPostponedActiveXControls.end(); ++it ) + { + WriteActiveXControl(it->object, *(it->frame), *(it->point), bInsideRun); + } + m_aPostponedActiveXControls.clear(); +} + +void DocxAttributeOutput::WriteActiveXControl(const SdrObject* pObject, const SwFrameFormat& rFrameFormat,const Point& rNdTopLeft, bool bInsideRun) +{ + SdrUnoObj *pFormObj = const_cast<SdrUnoObj*>(dynamic_cast< const SdrUnoObj*>(pObject)); + if (!pFormObj) + return; + + uno::Reference<awt::XControlModel> xControlModel = pFormObj->GetUnoControlModel(); + if (!xControlModel.is()) + return; + + const bool bAnchoredInline = rFrameFormat.GetAnchor().GetAnchorId() == static_cast<RndStdIds>(css::text::TextContentAnchorType_AS_CHARACTER); + + if(!bInsideRun) + { + m_pSerializer->startElementNS(XML_w, XML_r, FSEND); + } + + // 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<drawing::XShape> xShape(const_cast<SdrObject*>(pObject)->getUnoShape(), uno::UNO_QUERY); + std::pair<OString,OString> sRelIdAndName = m_rExport.WriteActiveXObject(xShape, xControlModel); + + // VML shape definition + m_rExport.VMLExporter().SetSkipwzName(true); + m_rExport.VMLExporter().SetHashMarkForType(true); + m_rExport.VMLExporter().OverrideShapeIDGen(true, "control_shape_"); + 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); + } + // Restore default values + m_rExport.VMLExporter().SetSkipwzName(false); + m_rExport.VMLExporter().SetHashMarkForType(false); + m_rExport.VMLExporter().OverrideShapeIDGen(false); + + // 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); + + if(!bInsideRun) + { + m_pSerializer->endElementNS(XML_w, XML_r); + } +} + +bool DocxAttributeOutput::ExportAsActiveXControl(const SdrObject* pObject) const +{ + SdrUnoObj *pFormObj = const_cast<SdrUnoObj*>(dynamic_cast< const SdrUnoObj*>(pObject)); + if (!pFormObj) + return false; + + uno::Reference<awt::XControlModel> 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<lang::XServiceInfo> 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( const SdrObject*, SwOLENode& rNode, const Size& rSize, const SwFlyFrameFormat* pFlyFrameFormat ) { if( !m_pPostponedOLEs ) @@ -5037,7 +5153,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 7c5149be2ff8..11046dcfa514 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -417,6 +417,9 @@ private: bool PostponeOLE( const SdrObject* pSdrObj, 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 bInsideRun); + 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(bool bInsideRun); void WritePostponedDiagram(); void WritePostponedChart(); void WritePostponedOLE(); @@ -875,6 +879,7 @@ private: const SdrObject* m_postponedChart; Size m_postponedChartSize; std::vector<const SdrObject*> m_aPostponedFormControls; + std::vector<PostponedDrawing> m_aPostponedActiveXControls; const SwField* pendingPlaceholder; /// Maps postit fields to ID's, used in commentRangeStart/End, commentReference and comment.xml. std::vector< std::pair<const SwPostItField*, sal_Int32> > m_postitFields; diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index 0e3cfd280f22..8cb24b34fe18 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -31,6 +31,7 @@ #include <com/sun/star/xml/dom/XDocument.hpp> #include <com/sun/star/xml/sax/XSAXSerializable.hpp> #include <com/sun/star/xml/sax/Writer.hpp> +#include <com/sun/star/awt/XControlModel.hpp> #include <oox/token/tokens.hxx> #include <oox/export/drawingml.hxx> @@ -38,6 +39,9 @@ #include <oox/export/chartexport.hxx> #include <oox/export/shapes.hxx> #include <oox/helper/propertyset.hxx> +#include <oox/helper/binaryoutputstream.hxx> +#include <oox/ole/olestorage.hxx> +#include <oox/ole/olehelper.hxx> #include <map> #include <algorithm> @@ -417,6 +421,54 @@ OString DocxExport::WriteOLEObject(SwOLEObj& rObject, OUString & io_rProgID) return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 ); } +std::pair<OString, OString> DocxExport::WriteActiveXObject(const uno::Reference<drawing::XShape>& rxShape, + const uno::Reference<awt::XControlModel>& rxControlModel) +{ + ++m_nActiveXControls; + + // Write out ActiveX binary + const OUString sBinaryFileName = "word/activeX/activeX" + OUString::number(m_nActiveXControls) + ".bin"; + + OString sGUID; + OString sName; + uno::Reference<io::XStream> 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<io::XOutputStream> 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>(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(), + "http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary", + sBinaryFileName.copy(sBinaryFileName.lastIndexOf("/") + 1) ); + + pActiveXFS->singleElementNS(XML_ax, XML_ocx, + FSNS(XML_xmlns, XML_ax), "http://schemas.microsoft.com/office/2006/activeX", + FSNS(XML_xmlns, XML_r), "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + 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(), + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control", + sXMLFileName.copy(sBinaryFileName.indexOf("/") + 1)), + RTL_TEXTENCODING_UTF8); + + return std::pair<OString, OString>(sXMLId, sName); +} + void DocxExport::OutputDML(uno::Reference<drawing::XShape>& xShape) { uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW); @@ -460,8 +512,6 @@ void DocxExport::ExportDocument_Impl() WriteCustomXml(); - WriteActiveX(); - WriteEmbeddings(); WriteVBA(); @@ -1161,100 +1211,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<uno::Reference<xml::dom::XDocument> > activeXDomlist; - uno::Sequence<uno::Reference<io::XInputStream> > 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<xml::dom::XDocument> activeXDom = activeXDomlist[j]; - uno::Reference<io::XInputStream> activeXBin = activeXBinList[j]; - - if ( activeXDom.is() ) - { - m_pFilter->addRelation( m_pDocumentFS->getOutputStream(), - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/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 catched!"); - } - - 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" ) , - "http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary", - "activeX"+OUString::number((j+1))+".bin" ); - - } - } -} - void DocxExport::WriteVBA() { uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY); @@ -1518,6 +1474,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 3623c5718eeb..ed71fc6504b9 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 >& xModel, sal_Int32 nCount, ::sax_fastparser::FSHelperPtr const & m_pSerializer ); OString WriteOLEObject(SwOLEObj& rObject, OUString & io_rProgID); + std::pair<OString,OString> WriteActiveXObject(const uno::Reference<css::drawing::XShape>& rxShape, + const uno::Reference<awt::XControlModel>& rxControlModel); /// Writes the shape using drawingML syntax. void OutputDML( css::uno::Reference< css::drawing::XShape >& xShape ); diff --git a/writerfilter/inc/ooxml/OOXMLDocument.hxx b/writerfilter/inc/ooxml/OOXMLDocument.hxx index 1b33336c8996..123c26f8b301 100644 --- a/writerfilter/inc/ooxml/OOXMLDocument.hxx +++ b/writerfilter/inc/ooxml/OOXMLDocument.hxx @@ -75,7 +75,7 @@ class OOXMLStream { public: enum StreamType_t { UNKNOWN, DOCUMENT, STYLES, WEBSETTINGS, FONTTABLE, NUMBERING, - FOOTNOTES, ENDNOTES, COMMENTS, THEME, CUSTOMXML, CUSTOMXMLPROPS, ACTIVEX, ACTIVEXBIN, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT, FOOTER, HEADER, SIGNATURE, VBADATA }; + FOOTNOTES, ENDNOTES, COMMENTS, THEME, CUSTOMXML, CUSTOMXMLPROPS, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT, FOOTER, HEADER, SIGNATURE, VBADATA }; typedef std::shared_ptr<OOXMLStream> Pointer_t; virtual ~OOXMLStream() {} @@ -226,8 +226,6 @@ public: virtual css::uno::Sequence<css::uno::Sequence< css::uno::Any> > getGlossaryDomList() = 0; virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomList( ) = 0; virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomPropsList( ) = 0; - virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getActiveXDomList( ) = 0; - virtual css::uno::Sequence<css::uno::Reference<css::io::XInputStream> > getActiveXBinList() = 0; virtual css::uno::Sequence<css::beans::PropertyValue > getEmbeddingsList() = 0; }; diff --git a/writerfilter/source/filter/WriterFilter.cxx b/writerfilter/source/filter/WriterFilter.cxx index 4a1ce7762e3c..206640bda607 100644 --- a/writerfilter/source/filter/WriterFilter.cxx +++ b/writerfilter/source/filter/WriterFilter.cxx @@ -225,10 +225,6 @@ sal_Bool WriterFilter::filter(const uno::Sequence< beans::PropertyValue >& aDesc aGrabBagProperties["OOXCustomXml"] = uno::makeAny(pDocument->getCustomXmlDomList()); aGrabBagProperties["OOXCustomXmlProps"] = uno::makeAny(pDocument->getCustomXmlDomPropsList()); - // Adding the saved ActiveX DOM - aGrabBagProperties["OOXActiveX"] = uno::makeAny(pDocument->getActiveXDomList()); - aGrabBagProperties["OOXActiveXBin"] = uno::makeAny(pDocument->getActiveXBinList()); - // Adding the saved Glossary Documnet DOM to the document's grab bag aGrabBagProperties["OOXGlossary"] = uno::makeAny(pDocument->getGlossaryDocDom()); aGrabBagProperties["OOXGlossaryDom"] = uno::makeAny(pDocument->getGlossaryDomList()); diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx index d313078f22a6..0f0e11bd7fb7 100644 --- a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx +++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx @@ -167,10 +167,6 @@ uno::Reference<xml::dom::XDocument> OOXMLDocumentImpl::importSubStream(OOXMLStre { importSubStreamRelations(pStream, OOXMLStream::CUSTOMXMLPROPS); } - if(OOXMLStream::ACTIVEX == nType) - { - importSubStreamRelations(pStream, OOXMLStream::ACTIVEXBIN); - } if(OOXMLStream::CHARTS == nType) { importSubStreamRelations(pStream, OOXMLStream::EMBEDDINGS); @@ -221,14 +217,8 @@ void OOXMLDocumentImpl::importSubStreamRelations(const OOXMLStream::Pointer_t& p mxCustomXmlProsDom = xRelation; } } - else if(OOXMLStream::ACTIVEXBIN == nType) - { - // imporing activex.bin files for activex.xml from activeX folder. - mxActiveXBin = xcpInputStream; - } else if(OOXMLStream::EMBEDDINGS == nType) { - // imporing activex.bin files for activex.xml from activeX folder. mxEmbeddings = xcpInputStream; } else if(OOXMLStream::CHARTS == nType) @@ -493,8 +483,6 @@ void OOXMLDocumentImpl::resolve(Stream & rStream) // Custom xml's are handled as part of grab bag. resolveCustomXmlStream(rStream); - resolveActiveXStream(rStream); - resolveFastSubStream(rStream, OOXMLStream::FONTTABLE); resolveFastSubStream(rStream, OOXMLStream::STYLES); resolveFastSubStream(rStream, OOXMLStream::NUMBERING); @@ -804,63 +792,6 @@ void OOXMLDocumentImpl::resolveEmbeddingsStream(const OOXMLStream::Pointer_t& pS mxEmbeddingsList = comphelper::containerToSequence(aEmbeddings); } -void OOXMLDocumentImpl::resolveActiveXStream(Stream & rStream) -{ - // Resolving all ActiveX[n].xml files from ActiveX folder. - uno::Reference<embed::XRelationshipAccess> xRelationshipAccess; - xRelationshipAccess.set((dynamic_cast<OOXMLStreamImpl&>(*mpStream.get())).accessDocumentStream(), uno::UNO_QUERY); - if (xRelationshipAccess.is()) - { - static const char sCustomType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control"; - static const char sCustomTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/control"; - OUString sTarget("Target"); - bool bFound = false; - sal_Int32 counter = 0; - uno::Sequence< uno::Sequence< beans::StringPair > > aSeqs = xRelationshipAccess->getAllRelationships(); - uno::Sequence<uno::Reference<xml::dom::XDocument> > xActiveXDomListTemp(aSeqs.getLength()); - uno::Sequence<uno::Reference<io::XInputStream> > xActiveXBinListTemp(aSeqs.getLength()); - for (sal_Int32 j = 0; j < aSeqs.getLength(); j++) - { - uno::Sequence< beans::StringPair > aSeq = aSeqs[j]; - for (sal_Int32 i = 0; i < aSeq.getLength(); i++) - { - beans::StringPair aPair = aSeq[i]; - // Need to resolve only ActiveX files from document relationships. - // Skipping other files. - if (aPair.Second == sCustomType || - aPair.Second == sCustomTypeStrict) - bFound = true; - else if(aPair.First == sTarget && bFound) - { - // Adding value to extern variable customTarget. It will be used in ooxmlstreamimpl - // to ensure ActiveX.xml target is visited in lcl_getTarget. - customTarget = aPair.Second; - } - } - if(bFound) - { - uno::Reference<xml::dom::XDocument> activeXTemp = importSubStream(OOXMLStream::ACTIVEX); - // This will add all ActiveX[n].xml to grabbag list. - if(activeXTemp.is()) - { - xActiveXDomListTemp[counter] = activeXTemp; - if(mxActiveXBin.is()) - { - xActiveXBinListTemp[counter] = mxActiveXBin; - } - counter++; - resolveFastSubStream(rStream, OOXMLStream::ACTIVEX); - } - bFound = false; - } - } - xActiveXDomListTemp.realloc(counter); - xActiveXBinListTemp.realloc(counter); - mxActiveXDomList = xActiveXDomListTemp; - mxActiveXBinList = xActiveXBinListTemp; - } -} - uno::Reference<xml::dom::XDocument> OOXMLDocumentImpl::getGlossaryDocDom( ) { return mxGlossaryDocDom; @@ -928,16 +859,6 @@ uno::Sequence<uno::Reference<xml::dom::XDocument> > OOXMLDocumentImpl::getCustom return mxCustomXmlDomPropsList; } -uno::Sequence<uno::Reference<xml::dom::XDocument> > OOXMLDocumentImpl::getActiveXDomList( ) -{ - return mxActiveXDomList; -} - -uno::Sequence<uno::Reference<io::XInputStream> > OOXMLDocumentImpl::getActiveXBinList( ) -{ - return mxActiveXBinList; -} - uno::Sequence<beans::PropertyValue > OOXMLDocumentImpl::getEmbeddingsList( ) { return mxEmbeddingsList; diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx index 43bdeb651d78..5c9bd0b1bff5 100644 --- a/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx +++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx @@ -48,9 +48,6 @@ class OOXMLDocumentImpl : public OOXMLDocument css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > mxCustomXmlDomList; css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > mxCustomXmlDomPropsList; css::uno::Reference<css::xml::dom::XDocument> mxCustomXmlProsDom; - css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > mxActiveXDomList; - css::uno::Sequence<css::uno::Reference<css::io::XInputStream> > mxActiveXBinList; - css::uno::Reference<css::io::XInputStream> mxActiveXBin; css::uno::Reference<css::io::XInputStream> mxEmbeddings; css::uno::Sequence < css::beans::PropertyValue > mxEmbeddingsList; bool mbIsSubstream; @@ -88,7 +85,6 @@ protected: const sal_Int32 nNoteId); void resolveCustomXmlStream(Stream & rStream); - void resolveActiveXStream(Stream & rStream); void resolveGlossaryStream(Stream & rStream); void resolveEmbeddingsStream(const OOXMLStream::Pointer_t& pStream); public: @@ -131,8 +127,6 @@ public: virtual css::uno::Reference<css::xml::dom::XDocument> getThemeDom() override; virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomList() override; virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomPropsList() override; - virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getActiveXDomList() override; - virtual css::uno::Sequence<css::uno::Reference<css::io::XInputStream> > getActiveXBinList() override; virtual css::uno::Reference<css::xml::dom::XDocument> getGlossaryDocDom() override; virtual css::uno::Sequence<css::uno::Sequence< css::uno::Any> > getGlossaryDomList() override; virtual css::uno::Sequence<css::beans::PropertyValue > getEmbeddingsList() override; diff --git a/writerfilter/source/ooxml/OOXMLStreamImpl.cxx b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx index fe26b58cbe93..3d3a6a0b268e 100644 --- a/writerfilter/source/ooxml/OOXMLStreamImpl.cxx +++ b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx @@ -141,8 +141,6 @@ bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAcc static const char sThemeType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"; static const char sCustomType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml"; static const char sCustomPropsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps"; - static const char sActiveXType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control"; - static const char sActiveXBinType[] = "http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary"; static const char sGlossaryType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument"; static const char sWebSettings[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings"; static const char sSettingsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings"; @@ -163,7 +161,6 @@ bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAcc static const char sThemeTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/theme"; static const char sCustomTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/customXml"; static const char sCustomPropsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/customXmlProps"; - static const char sActiveXTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/control"; static const char sGlossaryTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/glossaryDocument"; static const char sWebSettingsStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings"; static const char sSettingsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/settings"; @@ -228,14 +225,6 @@ bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAcc sStreamType = sCustomPropsType; sStreamTypeStrict = sCustomPropsTypeStrict; break; - case ACTIVEX: - sStreamType = sActiveXType; - sStreamTypeStrict = sActiveXTypeStrict; - break; - case ACTIVEXBIN: - sStreamType = sActiveXBinType; - sStreamTypeStrict = sActiveXBinType; - break; case SETTINGS: sStreamType = sSettingsType; sStreamTypeStrict = sSettingsTypeStrict; @@ -302,8 +291,8 @@ bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAcc bFound = true; else if (rPair.First == sTarget) { - // checking item[n].xml or activex[n].xml is not visited already. - if(customTarget != rPair.Second && (sStreamType == sCustomType || sStreamType == sActiveXType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType)) + // checking item[n].xml is not visited already. + if(customTarget != rPair.Second && (sStreamType == sCustomType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType)) { bFound = false; } |