[Libreoffice-commits] core.git: Branch 'libreoffice-6-4' - 2 commits - filter/source include/oox oox/source sc/source writerfilter/source

Michael Stahl (via logerrit) logerrit at kemper.freedesktop.org
Tue Jun 9 08:47:00 UTC 2020


 filter/source/msfilter/eschesdo.cxx               |   23 -
 include/oox/token/relationship.hxx                |    1 
 oox/source/token/relationship.inc                 |    1 
 sc/source/filter/excel/excdoc.cxx                 |    7 
 sc/source/filter/excel/xeescher.cxx               |  351 ++++++++++++++++++++--
 sc/source/filter/inc/xcl97rec.hxx                 |    2 
 sc/source/filter/inc/xeescher.hxx                 |   17 +
 sc/source/filter/xcl97/xcl97rec.cxx               |   58 +++
 writerfilter/source/dmapper/DomainMapper_Impl.cxx |   16 -
 9 files changed, 430 insertions(+), 46 deletions(-)

New commits:
commit c9d842ddc54b701eb57cc79032fabcf14391a3a1
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Mon Jun 8 13:05:27 2020 +0200
Commit:     Michael Stahl <michael.stahl at cib.de>
CommitDate: Tue Jun 9 10:40:13 2020 +0200

    tdf#132596 writerfilter: fix paste of RTF with header/footer
    
    The problem is that writerfilter inserts the content of header/footer
    into the body text, but then DomainMapper_Impl::PopPageHeaderFooter()
    calls RemoveLastParagraph() and deletes a body paragraph containing a
    fieldmark, and then in Undo some SwHistoryTextFieldmark can't find it,
    and since ffb26b81e1c7ff1d64959200247bb2edd5a569da this crashes.
    
    This is because of the borked error handling in
    DomainMapper_Impl::PushPageHeaderFooter(); the
    m_xBodyText->createTextCursorByRange() call throws an exception that is
    swallowed, so the m_aTextAppendStack doesn't have an entry containing
    the position in the header.
    
    To fix the error handling, set m_bDiscardHeaderFooter = false only when
    everything was successful.
    
    Also fix the call to be xText->createTextCursorByRange instead
    (this is a regression from 232ad2f2588beff50cb5c1f3b689c581ba317583).
    
    Then it turns out that Undo still crashes, because sw can't Undo
    changes of header/footer content, so just return early unless it's
    a new document.
    
    Change-Id: Ie5aeb45447c5fbd4b3ae15c4cffb9800583a6d1d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95797
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.stahl at cib.de>
    (cherry picked from commit 27151ccf2305eac4192f8c4ceeee267170096a19)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95824
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>

diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 1130007df6f7..76ba72b32aad 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -2212,6 +2212,7 @@ void DomainMapper_Impl::PushPageHeaderFooter(bool bHeader, SectionPropertyMap::P
     const PropertyIds ePropTextLeft = bHeader? PROP_HEADER_TEXT_LEFT: PROP_FOOTER_TEXT_LEFT;
     const PropertyIds ePropText = bHeader? PROP_HEADER_TEXT: PROP_FOOTER_TEXT;
 
+    m_bDiscardHeaderFooter = true;
     m_eInHeaderFooterImport
         = bHeader ? HeaderFooterImportState::header : HeaderFooterImportState::footer;
 
@@ -2225,6 +2226,11 @@ void DomainMapper_Impl::PushPageHeaderFooter(bool bHeader, SectionPropertyMap::P
         // content is not copied from the previous section
         pSectionContext->ClearHeaderFooterLinkToPrevious(bHeader, eType);
 
+        if (!m_bIsNewDoc)
+        {
+            return; // TODO sw cannot Undo insert header/footer without crashing
+        }
+
         uno::Reference< beans::XPropertySet > xPageStyle =
             pSectionContext->GetPageStyle(
                 *this,
@@ -2252,15 +2258,15 @@ void DomainMapper_Impl::PushPageHeaderFooter(bool bHeader, SectionPropertyMap::P
                 xPageStyle->getPropertyValue(getPropertyName(bLeft? ePropTextLeft: ePropText)) >>= xText;
 
                 m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >(xText, uno::UNO_QUERY_THROW),
-                            m_bIsNewDoc? uno::Reference<text::XTextCursor>(): m_xBodyText->createTextCursorByRange(xText->getStart())));
-            }
-            else
-            {
-                m_bDiscardHeaderFooter = true;
+                    m_bIsNewDoc
+                        ? uno::Reference<text::XTextCursor>()
+                        : xText->createTextCursorByRange(xText->getStart())));
+                m_bDiscardHeaderFooter = false; // set only on success!
             }
         }
         catch( const uno::Exception& )
         {
+            DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
         }
     }
 }
commit 577dd32b1c4eb0a4cff574fbabca987cb52b831b
Author:     Serge Krot <Serge.Krot at cib.de>
AuthorDate: Wed May 13 22:52:52 2020 +0200
Commit:     Thorsten Behrens <Thorsten.Behrens at CIB.de>
CommitDate: Tue Jun 9 10:34:32 2020 +0200

    tdf#106181 XLSX export: output form controls
    
    Prepared general algorithm to ouput form controls into XLSX.
    For now only CHECKBOX is supported with a possibility to
    link withem to any worksheet/cell.
    
    Change-Id: Ide8739d81ffb755aeae074c4ebecf24251383e34
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94161
    Tested-by: Jenkins
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    (cherry picked from commit fd238380ae7820f12ac1f7c52d0f7180a93f3ba3)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94835

diff --git a/filter/source/msfilter/eschesdo.cxx b/filter/source/msfilter/eschesdo.cxx
index b145cbef20c8..70212ea7c662 100644
--- a/filter/source/msfilter/eschesdo.cxx
+++ b/filter/source/msfilter/eschesdo.cxx
@@ -417,11 +417,16 @@ sal_uInt32 ImplEESdrWriter::ImplWriteShape( ImplEESdrObject& rObj,
             const Reference< XPropertySet > xPropSet = rObj.mXPropSet;
             const Reference<XPropertySetInfo> xPropInfo = xPropSet.is() ? xPropSet->getPropertySetInfo() : Reference<XPropertySetInfo>();
             // This code is expected to be called only for DOCX format.
-            if (xPropInfo.is() && xPropInfo->hasPropertyByName("AnchorType") && bOOxmlExport)
+            if (xPropInfo.is())
             {
-                text::TextContentAnchorType eAnchorType;
-                xPropSet->getPropertyValue("AnchorType") >>= eAnchorType;
-                bool bInline = eAnchorType == text::TextContentAnchorType_AS_CHARACTER;
+                bool bInline = false;
+                if (xPropInfo->hasPropertyByName("AnchorType"))
+                {
+                    text::TextContentAnchorType eAnchorType;
+                    xPropSet->getPropertyValue("AnchorType") >>= eAnchorType;
+                    bInline = eAnchorType == text::TextContentAnchorType_AS_CHARACTER;
+                }
+
                 mpEscherEx->OpenContainer( ESCHER_SpContainer );
                 if(bInline)
                 {
@@ -828,20 +833,14 @@ void ImplEESdrWriter::ImplWritePage(
 {
     ImplInitPageValues();
 
-    sal_uInt32 nLastPer = 0, nShapes = mXShapes->getCount();
+    const sal_uInt32 nShapes = mXShapes->getCount();
     for( sal_uInt32 n = 0; n < nShapes; ++n )
     {
-        sal_uInt32 nPer = ( 5 * n ) / nShapes;
-        if( nPer != nLastPer )
-        {
-            nLastPer = nPer;
-        }
-
         ImplEESdrObject aObj( *this, *o3tl::doAccess<Reference<XShape>>(
                                     mXShapes->getByIndex( n )) );
         if( aObj.IsValid() )
         {
-            ImplWriteShape( aObj, rSolverContainer );
+            ImplWriteShape( aObj, rSolverContainer, true );
         }
     }
 }
diff --git a/include/oox/token/relationship.hxx b/include/oox/token/relationship.hxx
index ae1580bf2bc5..adc25f4a73b6 100644
--- a/include/oox/token/relationship.hxx
+++ b/include/oox/token/relationship.hxx
@@ -23,6 +23,7 @@ enum class Relationship
     COMMENTS,
     COMMENTAUTHORS,
     CONTROL,
+    CTRLPROP,
     CUSTOMXML,
     CUSTOMXMLPROPS,
     DIAGRAMCOLORS,
diff --git a/oox/source/token/relationship.inc b/oox/source/token/relationship.inc
index 9b163038b169..2b973ded1653 100644
--- a/oox/source/token/relationship.inc
+++ b/oox/source/token/relationship.inc
@@ -3,6 +3,7 @@
 {Relationship::COMMENTS, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"},
 {Relationship::COMMENTAUTHORS, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/commentAuthors"},
 {Relationship::CONTROL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control"},
+{Relationship::CTRLPROP, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp"},
 {Relationship::CUSTOMXML, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml"},
 {Relationship::CUSTOMXMLPROPS, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps"},
 {Relationship::DIAGRAMCOLORS, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/diagramColors"},
diff --git a/sc/source/filter/excel/excdoc.cxx b/sc/source/filter/excel/excdoc.cxx
index 4d9975d034cc..2355f8db4a34 100644
--- a/sc/source/filter/excel/excdoc.cxx
+++ b/sc/source/filter/excel/excdoc.cxx
@@ -687,8 +687,11 @@ void ExcTable::WriteXml( XclExpXmlStream& rStrm )
     rStrm.PushStream( pWorksheet );
 
     pWorksheet->startElement( XML_worksheet,
-            XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)).toUtf8(),
-            FSNS(XML_xmlns, XML_r), rStrm.getNamespaceURL(OOX_NS(officeRel)).toUtf8() );
+        XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)).toUtf8(),
+        FSNS(XML_xmlns, XML_r), rStrm.getNamespaceURL(OOX_NS(officeRel)).toUtf8(),
+        FSNS(XML_xmlns, XML_xdr), "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing", // rStrm.getNamespaceURL(OOX_NS(xm)).toUtf8() -> "http://schemas.microsoft.com/office/excel/2006/main",
+        FSNS(XML_xmlns, XML_x14), rStrm.getNamespaceURL(OOX_NS(xls14Lst)).toUtf8(),
+        FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)).toUtf8());
 
     SetCurrScTab( mnScTab );
     if (mxCellTable)
diff --git a/sc/source/filter/excel/xeescher.cxx b/sc/source/filter/excel/xeescher.cxx
index c49e6a709177..fc634e319549 100644
--- a/sc/source/filter/excel/xeescher.cxx
+++ b/sc/source/filter/excel/xeescher.cxx
@@ -146,7 +146,15 @@ void lcl_WriteAnchorVertex( sax_fastparser::FSHelperPtr const & rComments, const
     rComments->endElement( FSNS( XML_xdr, XML_rowOff ) );
 }
 
-void lcl_GetFromTo( const XclExpRoot& rRoot, const tools::Rectangle &aRect, sal_Int32 nTab, tools::Rectangle &aFrom, tools::Rectangle &aTo )
+long lcl_hmm2output(long value, bool bInEMU)
+{
+    if (bInEMU)
+        return oox::drawingml::convertHmmToEmu(value);
+    else
+        return lcl_hmm2px(value);
+}
+
+void lcl_GetFromTo( const XclExpRoot& rRoot, const tools::Rectangle &aRect, sal_Int32 nTab, tools::Rectangle &aFrom, tools::Rectangle &aTo, bool bInEMU = false )
 {
     sal_Int32 nCol = 0, nRow = 0;
     sal_Int32 nColOff = 0, nRowOff= 0;
@@ -169,8 +177,8 @@ void lcl_GetFromTo( const XclExpRoot& rRoot, const tools::Rectangle &aRect, sal_
             }
             if( r.Left() > aRect.Left() && r.Top() > aRect.Top() )
             {
-                aFrom = tools::Rectangle( nCol-1, lcl_hmm2px( nColOff ),
-                                   nRow-1, lcl_hmm2px( nRowOff ) );
+                aFrom = tools::Rectangle( nCol-1, lcl_hmm2output( nColOff, bInEMU ),
+                                   nRow-1, lcl_hmm2output( nRowOff, bInEMU ) );
                 break;
             }
         }
@@ -192,8 +200,8 @@ void lcl_GetFromTo( const XclExpRoot& rRoot, const tools::Rectangle &aRect, sal_
             }
             if( r.Left() < aRect.Left() && r.Top() > aRect.Top() )
             {
-                aFrom = tools::Rectangle( nCol-1, lcl_hmm2px( nColOff ),
-                                   nRow-1, lcl_hmm2px( nRowOff ) );
+                aFrom = tools::Rectangle( nCol-1, lcl_hmm2output( nColOff, bInEMU ),
+                                   nRow-1, lcl_hmm2output( nRowOff, bInEMU ) );
                 break;
             }
         }
@@ -209,8 +217,8 @@ void lcl_GetFromTo( const XclExpRoot& rRoot, const tools::Rectangle &aRect, sal_
                 nRow++;
             if( r.Right() >= aRect.Right() && r.Bottom() >= aRect.Bottom() )
             {
-                aTo = tools::Rectangle( nCol, lcl_hmm2px( aRect.Right() - r.Left() ),
-                                 nRow, lcl_hmm2px( aRect.Bottom() - r.Top() ));
+                aTo = tools::Rectangle( nCol, lcl_hmm2output( aRect.Right() - r.Left(), bInEMU ),
+                                 nRow, lcl_hmm2output( aRect.Bottom() - r.Top(), bInEMU ));
                 break;
             }
         }
@@ -226,8 +234,8 @@ void lcl_GetFromTo( const XclExpRoot& rRoot, const tools::Rectangle &aRect, sal_
                 nRow++;
             if( r.Right() < aRect.Right() && r.Bottom() >= aRect.Bottom() )
             {
-                aTo = tools::Rectangle( nCol, lcl_hmm2px( r.Left() - aRect.Right() ),
-                                 nRow, lcl_hmm2px( aRect.Bottom() - r.Top() ));
+                aTo = tools::Rectangle( nCol, lcl_hmm2output( r.Left() - aRect.Right(), bInEMU ),
+                                 nRow, lcl_hmm2output( aRect.Bottom() - r.Top(), bInEMU ));
                 break;
             }
         }
@@ -455,6 +463,7 @@ XclExpControlHelper::~XclExpControlHelper()
 void XclExpControlHelper::ConvertSheetLinks( Reference< XShape > const & xShape )
 {
     mxCellLink.reset();
+    mxCellLinkAddress.SetInvalid();
     mxSrcRange.reset();
     mnEntryCount = 0;
 
@@ -475,10 +484,9 @@ void XclExpControlHelper::ConvertSheetLinks( Reference< XShape > const & xShape
             CellAddress aApiAddress;
             if( aBindProp.GetProperty( aApiAddress, SC_UNONAME_BOUNDCELL ) )
             {
-                ScAddress aCellLink;
-                ScUnoConversion::FillScAddress( aCellLink, aApiAddress );
-                if( GetTabInfo().IsExportTab( aCellLink.Tab() ) )
-                    mxCellLink = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, aCellLink );
+                ScUnoConversion::FillScAddress( mxCellLinkAddress, aApiAddress );
+                if( GetTabInfo().IsExportTab( mxCellLinkAddress.Tab() ) )
+                    mxCellLink = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CONTROL, mxCellLinkAddress );
             }
         }
     }
@@ -633,6 +641,7 @@ void XclExpOcxControlObj::WriteSubRecs( XclExpStream& rStrm )
 XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference< XShape > const & xShape , const tools::Rectangle* pChildAnchor ) :
     XclObj( rRoot, EXC_OBJTYPE_UNKNOWN, true ),
     XclMacroHelper( rRoot ),
+    mxShape( xShape ),
     meEventType( EXC_TBX_EVENT_ACTION ),
     mnHeight( 0 ),
     mnState( 0 ),
@@ -646,7 +655,10 @@ XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference<
     mbFlatButton( false ),
     mbFlatBorder( false ),
     mbMultiSel( false ),
-    mbScrollHor( false )
+    mbScrollHor( false ),
+    mbPrint( false ),
+    mbVisible( false ),
+    mnShapeId( 0 )
 {
     namespace FormCompType = css::form::FormComponentType;
     namespace AwtVisualEffect = css::awt::VisualEffect;
@@ -682,7 +694,8 @@ XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference<
 
     // OBJ record flags
     SetLocked( true );
-    SetPrintable( aCtrlProp.GetBoolProperty( "Printable" ) );
+    mbPrint = aCtrlProp.GetBoolProperty( "Printable" );
+    SetPrintable( mbPrint );
     SetAutoFill( false );
     SetAutoLine( false );
 
@@ -690,8 +703,8 @@ XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference<
     mrEscherEx.OpenContainer( ESCHER_SpContainer );
     mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
     EscherPropertyContainer aPropOpt;
-    bool bVisible = aCtrlProp.GetBoolProperty( "EnableVisible" );
-    aPropOpt.AddOpt( ESCHER_Prop_fPrint, bVisible ? 0x00080000 : 0x00080002 ); // visible flag
+    mbVisible = aCtrlProp.GetBoolProperty( "EnableVisible" );
+    aPropOpt.AddOpt( ESCHER_Prop_fPrint, mbVisible ? 0x00080000 : 0x00080002 ); // visible flag
 
     aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01000100 ); // bool field
     aPropOpt.AddOpt( ESCHER_Prop_lTxid, 0 );                        // Text ID
@@ -701,9 +714,8 @@ XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference<
     aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 );     // bool field
 
     // #i51348# name of the control, may overwrite shape name
-    OUString aCtrlName;
-    if( aCtrlProp.GetProperty( aCtrlName, "Name" ) && !aCtrlName.isEmpty() )
-        aPropOpt.AddOpt( ESCHER_Prop_wzName, aCtrlName );
+    if( aCtrlProp.GetProperty( msCtrlName, "Name" ) && !msCtrlName.isEmpty() )
+        aPropOpt.AddOpt( ESCHER_Prop_wzName, msCtrlName );
 
     //Export description as alt text
     if( SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape ) )
@@ -725,8 +737,7 @@ XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference<
     mrEscherEx.UpdateDffFragmentEnd();
 
     // control label
-    OUString aString;
-    if( aCtrlProp.GetProperty( aString, "Label" ) )
+    if( aCtrlProp.GetProperty( msLabel, "Label" ) )
     {
         /*  Be sure to construct the MSODRAWING record containing the
             ClientTextbox atom after the base OBJ's MSODRAWING record data is
@@ -736,7 +747,7 @@ XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference<
         mrEscherEx.UpdateDffFragmentEnd();
 
         sal_uInt16 nXclFont = EXC_FONT_APP;
-        if( !aString.isEmpty() )
+        if( !msLabel.isEmpty() )
         {
             XclFontData aFontData;
             GetFontPropSetHelper().ReadFontProperties( aFontData, aCtrlProp, EXC_FONTPROPSET_CONTROL );
@@ -744,7 +755,7 @@ XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference<
                 nXclFont = GetFontBuffer().Insert( aFontData, EXC_COLOR_CTRLTEXT );
         }
 
-        pTxo.reset( new XclTxo( aString, nXclFont ) );
+        pTxo.reset( new XclTxo( msLabel, nXclFont ) );
         pTxo->SetHorAlign( (mnObjType == EXC_OBJTYPE_BUTTON) ? EXC_OBJ_HOR_CENTER : EXC_OBJ_HOR_LEFT );
         pTxo->SetVerAlign( EXC_OBJ_VER_CENTER );
     }
@@ -881,6 +892,29 @@ XclExpTbxControlObj::XclExpTbxControlObj( XclExpObjectManager& rRoot, Reference<
         break;
     }
 
+    {
+        Reference< XControlModel > xCtrlModel = XclControlHelper::GetControlModel( xShape );
+        if( xCtrlModel.is() )
+        {
+            Reference< XBindableValue > xBindable( xCtrlModel, UNO_QUERY );
+            if( xBindable.is() )
+            {
+                Reference< XServiceInfo > xServInfo( xBindable->getValueBinding(), UNO_QUERY );
+                if( xServInfo.is() && xServInfo->supportsService( SC_SERVICENAME_VALBIND ) )
+                {
+                    ScfPropertySet aBindProp( xServInfo );
+                    CellAddress aApiAddress;
+                    if( aBindProp.GetProperty( aApiAddress, SC_UNONAME_BOUNDCELL ) )
+                    {
+                        ScUnoConversion::FillScAddress( mxCellLinkAddress, aApiAddress );
+                        if( SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape ) )
+                            lcl_GetFromTo( rRoot, pSdrObj->GetLogicRect(), mxCellLinkAddress.Tab(), maAreaFrom, maAreaTo, true );
+                    }
+                }
+            }
+        }
+    }
+
     // spreadsheet links
     ConvertSheetLinks( xShape );
 }
@@ -1052,6 +1086,275 @@ void XclExpTbxControlObj::WriteSbs( XclExpStream& rStrm )
     rStrm.EndRecord();
 }
 
+void XclExpTbxControlObj::setShapeId(sal_Int32 aShapeId)
+{
+    mnShapeId = aShapeId;
+}
+
+// save into xl\drawings\drawing1.xml
+void XclExpTbxControlObj::SaveXml( XclExpXmlStream& rStrm )
+{
+    sax_fastparser::FSHelperPtr& pDrawing = rStrm.GetCurrentStream();
+
+    pDrawing->startElement(FSNS(XML_mc, XML_AlternateContent),
+        FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)).toUtf8());
+    pDrawing->startElement(FSNS(XML_mc, XML_Choice),
+        FSNS(XML_xmlns, XML_a14), rStrm.getNamespaceURL(OOX_NS(a14)).toUtf8(),
+        XML_Requires, "a14");
+
+    pDrawing->startElement(FSNS(XML_xdr, XML_twoCellAnchor), XML_editAs, "oneCell");
+    {
+        pDrawing->startElement(FSNS(XML_xdr, XML_from));
+        lcl_WriteAnchorVertex(pDrawing, maAreaFrom);
+        pDrawing->endElement(FSNS(XML_xdr, XML_from));
+        pDrawing->startElement(FSNS(XML_xdr, XML_to));
+        lcl_WriteAnchorVertex(pDrawing, maAreaTo);
+        pDrawing->endElement(FSNS(XML_xdr, XML_to));
+
+        pDrawing->startElement(FSNS(XML_xdr, XML_sp));
+        {
+            // xdr:nvSpPr
+            pDrawing->startElement(FSNS(XML_xdr, XML_nvSpPr));
+            {
+                pDrawing->singleElement(FSNS(XML_xdr, XML_cNvPr),
+                    XML_id, OString::number(mnShapeId).getStr(),
+                    XML_name, msCtrlName.toUtf8(), // control name
+                    XML_descr, msLabel.toUtf8(), // description as alt text
+                    XML_hidden, mbVisible ? "0" : "1");
+                pDrawing->singleElement(FSNS(XML_xdr, XML_cNvSpPr));
+            }
+            pDrawing->endElement(FSNS(XML_xdr, XML_nvSpPr));
+
+            // xdr:spPr
+            pDrawing->startElement(FSNS(XML_xdr, XML_spPr));
+            {
+                // a:xfrm
+                pDrawing->startElement(FSNS(XML_a, XML_xfrm));
+                {
+                    pDrawing->singleElement(FSNS(XML_a, XML_off),
+                        XML_x, "0",
+                        XML_y, "0");
+                    pDrawing->singleElement(FSNS(XML_a, XML_ext),
+                        XML_cx, "0",
+                        XML_cy, "0");
+                }
+                pDrawing->endElement(FSNS(XML_a, XML_xfrm));
+
+                // a:prstGeom
+                pDrawing->startElement(FSNS(XML_a, XML_prstGeom), XML_prst, "rect");
+                {
+                    pDrawing->singleElement(FSNS(XML_a, XML_avLst));
+                }
+                pDrawing->endElement(FSNS(XML_a, XML_prstGeom));
+            }
+            pDrawing->endElement(FSNS(XML_xdr, XML_spPr));
+
+            // xdr:txBody
+            {
+                pDrawing->startElement(FSNS(XML_xdr, XML_txBody));
+
+#define DEFLRINS 254
+#define DEFTBINS 127
+                sal_Int32 nLeft, nRight, nTop, nBottom;
+                nLeft = nRight = DEFLRINS;
+                nTop = nBottom = DEFTBINS;
+
+                // top inset looks a bit different compared to ppt export
+                // check if something related doesn't work as expected
+                Reference< XPropertySet > rXPropSet(mxShape, UNO_QUERY);
+
+                try
+                {
+                    css::uno::Any mAny;
+
+                    mAny = rXPropSet->getPropertyValue("TextLeftDistance");
+                    if (mAny.hasValue())
+                        mAny >>= nLeft;
+
+                    mAny = rXPropSet->getPropertyValue("TextRightDistance");
+                    if (mAny.hasValue())
+                        mAny >>= nRight;
+
+                    mAny = rXPropSet->getPropertyValue("TextUpperDistance");
+                    if (mAny.hasValue())
+                        mAny >>= nTop;
+
+                    mAny = rXPropSet->getPropertyValue("TextLowerDistance");
+                    if (mAny.hasValue())
+                        mAny >>= nBottom;
+                }
+                catch (...)
+                {
+                }
+
+                // Specifies the inset of the bounding rectangle.
+                // Insets are used just as internal margins for text boxes within shapes.
+                // If this attribute is omitted, then a value of 45720 or 0.05 inches is implied.
+                pDrawing->startElementNS(XML_a, XML_bodyPr,
+                    XML_lIns, (nLeft != DEFLRINS) ? OString::number(oox::drawingml::convertHmmToEmu(nLeft)).getStr() : nullptr,
+                    XML_rIns, (nRight != DEFLRINS) ? OString::number(oox::drawingml::convertHmmToEmu(nRight)).getStr() : nullptr,
+                    XML_tIns, (nTop != DEFTBINS) ? OString::number(oox::drawingml::convertHmmToEmu(nTop)).getStr() : nullptr,
+                    XML_bIns, (nBottom != DEFTBINS) ? OString::number(oox::drawingml::convertHmmToEmu(nBottom)).getStr() : nullptr,
+                    XML_anchor, "ctr");
+
+                {
+                    bool bTextAutoGrowHeight = false;
+
+                    try
+                    {
+                        css::uno::Any mAny;
+
+                        mAny = rXPropSet->getPropertyValue("TextAutoGrowHeight");
+                        if (mAny.hasValue())
+                            mAny >>= bTextAutoGrowHeight;
+                    }
+                    catch (...)
+                    {
+                    }
+
+                    pDrawing->singleElementNS(XML_a, (bTextAutoGrowHeight ? XML_spAutoFit : XML_noAutofit));
+                }
+
+                pDrawing->endElementNS(XML_a, XML_bodyPr);
+
+                {
+                    pDrawing->startElementNS(XML_a, XML_p);
+                    pDrawing->startElementNS(XML_a, XML_r);
+                    pDrawing->startElementNS(XML_a, XML_t);
+                    pDrawing->write(msLabel.toUtf8());
+                    pDrawing->endElementNS(XML_a, XML_t);
+                    pDrawing->endElementNS(XML_a, XML_r);
+                    pDrawing->endElementNS(XML_a, XML_p);
+                }
+
+                pDrawing->endElement(FSNS(XML_xdr, XML_txBody));
+            }
+        }
+        pDrawing->endElement(FSNS(XML_xdr, XML_sp));
+        pDrawing->singleElement(FSNS(XML_xdr, XML_clientData));
+    }
+    pDrawing->endElement(FSNS(XML_xdr, XML_twoCellAnchor));
+    pDrawing->endElement( FSNS( XML_mc, XML_Choice ) );
+    pDrawing->endElement( FSNS( XML_mc, XML_AlternateContent ) );
+}
+
+// output into ctrlProp1.xml
+OUString XclExpTbxControlObj::SaveControlPropertiesXml(XclExpXmlStream& rStrm) const
+{
+    OUString sIdFormControlPr;
+
+    switch (mnObjType)
+    {
+        case EXC_OBJTYPE_CHECKBOX:
+        {
+            const sal_Int32 nDrawing = XclExpObjList::getNewDrawingUniqueId();
+            sax_fastparser::FSHelperPtr pFormControl = rStrm.CreateOutputStream(
+                    XclXmlUtils::GetStreamName( "xl/", "ctrlProps/ctrlProps", nDrawing ),
+                    XclXmlUtils::GetStreamName( "../", "ctrlProps/ctrlProps", nDrawing ),
+                    rStrm.GetCurrentStream()->getOutputStream(),
+                    "application/vnd.ms-excel.controlproperties+xml",
+                    OUStringToOString(oox::getRelationship(Relationship::CTRLPROP), RTL_TEXTENCODING_UTF8).getStr(),
+                    &sIdFormControlPr );
+
+            rStrm.PushStream( pFormControl );
+            // checkbox
+            // <formControlPr
+            //      xmlns="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
+            //      objectType="CheckBox" checked="Checked" lockText="1" noThreeD="1"/>
+            //
+            pFormControl->write("<formControlPr xmlns=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\" objectType=\"CheckBox\"");
+            if (mnState == EXC_OBJ_CHECKBOX_CHECKED)
+                pFormControl->write(" checked=\"Checked\"");
+
+            pFormControl->write(" autoLine=\"false\"");
+
+            if (mbPrint)
+                pFormControl->write(" print=\"true\"");
+            else
+                pFormControl->write(" print=\"false\"");
+
+            if (mxCellLinkAddress.IsValid())
+            {
+                OUString aCellLink = mxCellLinkAddress.Format(ScRefFlags::ADDR_ABS,
+                    &GetDoc(),
+                    ScAddress::Details(::formula::FormulaGrammar::CONV_XL_A1));
+
+                // "Sheet1!$C$5"
+                pFormControl->write(" fmlaLink=\"");
+                if (aCellLink.indexOf('!') < 0)
+                {
+                    pFormControl->write(GetTabInfo().GetScTabName( mxCellLinkAddress.Tab() ).toUtf8());
+                    pFormControl->write("!");
+                }
+                pFormControl->write(aCellLink);
+                pFormControl->write("\"");
+            }
+
+            pFormControl->write(" lockText=\"1\" noThreeD=\"1\"/>");
+            rStrm.PopStream();
+
+            break;
+        }
+    }
+
+    return sIdFormControlPr;
+}
+
+// output into sheet1.xml
+void XclExpTbxControlObj::SaveSheetXml(XclExpXmlStream& rStrm, const OUString& aIdFormControlPr) const
+{
+    switch (mnObjType)
+    {
+        case EXC_OBJTYPE_CHECKBOX:
+        {
+            sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+
+            rWorksheet->startElement(FSNS(XML_mc, XML_AlternateContent),
+                FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)).toUtf8());
+            rWorksheet->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "x14");
+
+            rWorksheet->startElement(
+                XML_control,
+                XML_shapeId, OString::number(mnShapeId).getStr(),
+                FSNS(XML_r, XML_id), aIdFormControlPr.toUtf8(),
+                XML_name, msLabel.toUtf8()); // text to display with checkbox button
+
+            rWorksheet->write("<controlPr defaultSize=\"0\" locked=\"1\" autoFill=\"0\" autoLine=\"0\" autoPict=\"0\"");
+
+            if (mbPrint)
+                rWorksheet->write(" print=\"true\"");
+            else
+                rWorksheet->write(" print=\"false\"");
+
+            if (!msCtrlName.isEmpty())
+            {
+                rWorksheet->write(" altText=\"");
+                rWorksheet->write(msCtrlName.toUtf8()); // alt text
+                rWorksheet->write("\"");
+            }
+
+            rWorksheet->write(">");
+
+            rWorksheet->startElement(XML_anchor, XML_moveWithCells, "true", XML_sizeWithCells, "false");
+            rWorksheet->startElement(XML_from);
+            lcl_WriteAnchorVertex(rWorksheet, maAreaFrom);
+            rWorksheet->endElement(XML_from);
+            rWorksheet->startElement(XML_to);
+            lcl_WriteAnchorVertex(rWorksheet, maAreaTo);
+            rWorksheet->endElement(XML_to);
+            rWorksheet->endElement( XML_anchor );
+
+            rWorksheet->write("</controlPr>");
+
+            rWorksheet->endElement(XML_control);
+            rWorksheet->endElement( FSNS( XML_mc, XML_Choice ) );
+            rWorksheet->endElement( FSNS( XML_mc, XML_AlternateContent ) );
+
+            break;
+        }
+    }
+}
+
 //#endif
 
 XclExpChartObj::XclExpChartObj( XclExpObjectManager& rObjMgr, Reference< XShape > const & xShape, const tools::Rectangle* pChildAnchor, ScDocument* pDoc ) :
diff --git a/sc/source/filter/inc/xcl97rec.hxx b/sc/source/filter/inc/xcl97rec.hxx
index 0999f0ea3dd2..afb381b57060 100644
--- a/sc/source/filter/inc/xcl97rec.hxx
+++ b/sc/source/filter/inc/xcl97rec.hxx
@@ -84,6 +84,8 @@ public:
 
     static void        ResetCounters();
 
+    static sal_Int32    getNewDrawingUniqueId() { return ++mnDrawingMLCount;  }
+
 private:
     static  sal_Int32   mnDrawingMLCount, mnVmlCount;
     SCTAB const         mnScTab;
diff --git a/sc/source/filter/inc/xeescher.hxx b/sc/source/filter/inc/xeescher.hxx
index 62660b8e1b9e..c5b0ac8067bd 100644
--- a/sc/source/filter/inc/xeescher.hxx
+++ b/sc/source/filter/inc/xeescher.hxx
@@ -190,6 +190,8 @@ private:
     XclTokenArrayRef    mxCellLink;     /// Formula for linked cell.
     XclTokenArrayRef    mxSrcRange;     /// Formula for source data range.
     sal_uInt16          mnEntryCount;   /// Number of entries in source range.
+protected:
+    ScAddress mxCellLinkAddress;
 };
 
 class XclMacroHelper : public XclExpControlHelper
@@ -257,6 +259,13 @@ public:
         @return  true = The passed event descriptor was valid, macro name has been found. */
     bool                SetMacroLink( const css::script::ScriptEventDescriptor& rEvent );
 
+    virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
+
+    OUString SaveControlPropertiesXml(XclExpXmlStream& rStrm) const;
+    void SaveSheetXml(XclExpXmlStream& rStrm, const OUString& aIdFormControlPr) const;
+
+    void setShapeId(sal_Int32 aShapeId);
+
 private:
     virtual void        WriteSubRecs( XclExpStream& rStrm ) override;
 
@@ -266,6 +275,7 @@ private:
     void                WriteSbs( XclExpStream& rStrm );
 
 private:
+    const css::uno::Reference< css::drawing::XShape > mxShape;
     ScfInt16Vec         maMultiSel;     /// Indexes of all selected entries in a multi selection.
     XclTbxEventType     meEventType;    /// Type of supported macro event.
     sal_Int32           mnHeight;       /// Height of the control.
@@ -281,6 +291,13 @@ private:
     bool                mbFlatBorder;   /// False = 3D border style; True = Flat border style.
     bool                mbMultiSel;     /// true = Multi selection in listbox.
     bool                mbScrollHor;    /// Scrollbar: true = horizontal.
+    bool                mbPrint;
+    bool                mbVisible;
+    OUString            msCtrlName;
+    OUString            msLabel;
+    sal_Int32           mnShapeId;
+    tools::Rectangle    maAreaFrom;
+    tools::Rectangle    maAreaTo;
 };
 
 //#endif
diff --git a/sc/source/filter/xcl97/xcl97rec.cxx b/sc/source/filter/xcl97/xcl97rec.cxx
index 5597b635ecbd..277f3157afd7 100644
--- a/sc/source/filter/xcl97/xcl97rec.cxx
+++ b/sc/source/filter/xcl97/xcl97rec.cxx
@@ -152,6 +152,17 @@ void XclExpObjList::Save( XclExpStream& rStrm )
 
 namespace {
 
+bool IsFormControlObject( const XclObj *rObj )
+{
+    switch( rObj->GetObjType() )
+    {
+        case EXC_OBJTYPE_CHECKBOX:
+            return true;
+        default:
+            return false;
+    }
+}
+
 bool IsVmlObject( const XclObj *rObj )
 {
     switch( rObj->GetObjType() )
@@ -210,7 +221,7 @@ bool IsValidObject( const XclObj& rObj )
     return true;
 }
 
-void SaveDrawingMLObjects( XclExpObjList& rList, XclExpXmlStream& rStrm, sal_Int32& nDrawingMLCount )
+void SaveDrawingMLObjects( XclExpObjList& rList, XclExpXmlStream& rStrm )
 {
     std::vector<XclObj*> aList;
     aList.reserve(rList.size());
@@ -225,7 +236,7 @@ void SaveDrawingMLObjects( XclExpObjList& rList, XclExpXmlStream& rStrm, sal_Int
     if (aList.empty())
         return;
 
-    sal_Int32 nDrawing = ++nDrawingMLCount;
+    sal_Int32 nDrawing = XclExpObjList::getNewDrawingUniqueId();
     OUString sId;
     sax_fastparser::FSHelperPtr pDrawing = rStrm.CreateOutputStream(
             XclXmlUtils::GetStreamName( "xl/", "drawings/drawing", nDrawing ),
@@ -243,14 +254,54 @@ void SaveDrawingMLObjects( XclExpObjList& rList, XclExpXmlStream& rStrm, sal_Int
             FSNS(XML_xmlns, XML_a),   rStrm.getNamespaceURL(OOX_NS(dml)).toUtf8(),
             FSNS(XML_xmlns, XML_r),   rStrm.getNamespaceURL(OOX_NS(officeRel)).toUtf8() );
 
+    sal_Int32 nShapeId = 1000; // unique id of the shape inside one worksheet (not the whole document)
     for (const auto& rpObj : aList)
+    {
+        // validate shapeId
+        if ( IsFormControlObject( rpObj ) )
+        {
+            XclExpTbxControlObj* pXclExpTbxControlObj = dynamic_cast<XclExpTbxControlObj*>(rpObj);
+            if (pXclExpTbxControlObj)
+            {
+                pXclExpTbxControlObj->setShapeId(++nShapeId);
+            }
+        }
+
         rpObj->SaveXml(rStrm);
+    }
 
     pDrawing->endElement( FSNS( XML_xdr, XML_wsDr ) );
 
     rStrm.PopStream();
 }
 
+void SaveFormControlObjects(XclExpObjList& rList, XclExpXmlStream& rStrm)
+{
+    sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
+
+    rWorksheet->startElement(FSNS(XML_mc, XML_AlternateContent),
+        FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)).toUtf8());
+    rWorksheet->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "x14");
+    rWorksheet->startElement(XML_controls);
+
+    for (const auto& rxObj : rList)
+    {
+        if (IsFormControlObject(rxObj.get()))
+        {
+            XclExpTbxControlObj* pXclExpTbxControlObj = dynamic_cast<XclExpTbxControlObj*>(rxObj.get());
+            if (pXclExpTbxControlObj)
+            {
+                const OUString aIdFormControlPr = pXclExpTbxControlObj->SaveControlPropertiesXml(rStrm);
+                pXclExpTbxControlObj->SaveSheetXml(rStrm, aIdFormControlPr);
+            }
+        }
+    }
+
+    rWorksheet->endElement(XML_controls);
+    rWorksheet->endElement(FSNS(XML_mc, XML_Choice));
+    rWorksheet->endElement(FSNS(XML_mc, XML_AlternateContent));
+}
+
 void SaveVmlObjects( XclExpObjList& rList, XclExpXmlStream& rStrm, sal_Int32& nVmlCount )
 {
     if( GetVmlObjectCount( rList ) == 0 )
@@ -297,7 +348,8 @@ void XclExpObjList::SaveXml( XclExpXmlStream& rStrm )
     if( maObjs.empty())
         return;
 
-    SaveDrawingMLObjects( *this, rStrm, mnDrawingMLCount );
+    SaveDrawingMLObjects( *this, rStrm );
+    SaveFormControlObjects( *this, rStrm );
     SaveVmlObjects( *this, rStrm, mnVmlCount );
 }
 


More information about the Libreoffice-commits mailing list