[Libreoffice-commits] core.git: sw/qa sw/source writerfilter/source

László Németh (via logerrit) logerrit at kemper.freedesktop.org
Fri Apr 26 06:29:16 UTC 2019


 sw/qa/extras/ooxmlexport/data/tdf67207.docx       |binary
 sw/qa/extras/ooxmlexport/ooxmlexport11.cxx        |   32 ++++++++++++++++++++++
 sw/source/filter/ww8/docxexport.cxx               |   23 +++++++++++++++
 writerfilter/source/dmapper/DomainMapper_Impl.cxx |   28 +++++++++++++++++--
 writerfilter/source/dmapper/PropertyIds.cxx       |    4 ++
 writerfilter/source/dmapper/PropertyIds.hxx       |    4 ++
 writerfilter/source/dmapper/SettingsTable.cxx     |   29 +++++++++++++++++++
 writerfilter/source/dmapper/SettingsTable.hxx     |    2 +
 8 files changed, 120 insertions(+), 2 deletions(-)

New commits:
commit 071c3309260aeae22f464d26bfa56a747f6a02cb
Author:     László Németh <nemeth at numbertext.org>
AuthorDate: Wed Apr 24 12:30:56 2019 +0200
Commit:     László Németh <nemeth at numbertext.org>
CommitDate: Fri Apr 26 08:28:11 2019 +0200

    tdf#67207 DOCX mail merge: fix export/import of database fields
    
    to support the registered databases (containing ODS, XLSX
    sheet or ODT text table data sources).
    
    Now database fields don't lose their database connection,
    and File->Print can merge mails after DOCX export/import, if
    the LO instance has got a registered database with the same
    name and table, as in saved in w:settings/w:mailMerge/w:query
    element of the DOCX document in the form of
    
    SELECT * FROM [databaseName].dbo.[tableName]$
    
    query.
    
    Notes:
    
    – This fix supports only single table usage.
    
    – The exported DOCX document is editable in MSO, too,
      without losing the database connection in LO later.
    
    Change-Id: I97826b7ee7defd0243dbaffa0325c5b11dd2c0d1
    Reviewed-on: https://gerrit.libreoffice.org/71228
    Tested-by: Jenkins
    Reviewed-by: László Németh <nemeth at numbertext.org>

diff --git a/sw/qa/extras/ooxmlexport/data/tdf67207.docx b/sw/qa/extras/ooxmlexport/data/tdf67207.docx
new file mode 100644
index 000000000000..b0604c266394
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf67207.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
index 1e2bd17db9a7..7d9b392f635b 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
@@ -988,6 +988,38 @@ DECLARE_OOXMLIMPORT_TEST(testTdf123054, "tdf123054.docx")
                          getProperty<OUString>(getParagraph(20), "ParaStyleName"));
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf67207_MERGEFIELD_DATABASE, "tdf67207.docx")
+{
+    // database fields use the database "database" and its table "Sheet1"
+    uno::Reference<beans::XPropertySet> xTextField = getProperty< uno::Reference<beans::XPropertySet> >(getRun(getParagraph(2), 2), "TextField");
+    CPPUNIT_ASSERT(xTextField.is());
+    uno::Reference<lang::XServiceInfo> xServiceInfo(xTextField, uno::UNO_QUERY_THROW);
+    uno::Reference<text::XDependentTextField> xDependent(xTextField, uno::UNO_QUERY_THROW);
+
+    CPPUNIT_ASSERT(xServiceInfo->supportsService("com.sun.star.text.TextField.Database"));
+    OUString sValue;
+    xTextField->getPropertyValue("Content") >>= sValue;
+    CPPUNIT_ASSERT_EQUAL(OUString::fromUtf8("<c1>"), sValue);
+
+    uno::Reference<beans::XPropertySet> xFiledMaster = xDependent->getTextFieldMaster();
+    uno::Reference<lang::XServiceInfo> xFiledMasterServiceInfo(xFiledMaster, uno::UNO_QUERY_THROW);
+
+    CPPUNIT_ASSERT(xFiledMasterServiceInfo->supportsService("com.sun.star.text.fieldmaster.Database"));
+
+    // Defined properties: DataBaseName, Name, DataTableName, DataColumnName, DependentTextFields, DataCommandType, InstanceName, DataBaseURL
+    CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("DataBaseName") >>= sValue);
+    CPPUNIT_ASSERT_EQUAL(OUString("database"), sValue);
+    sal_Int32 nCommandType;
+    CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("DataCommandType") >>= nCommandType);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nCommandType); // css::sdb::CommandType::TABLE
+    CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("DataTableName") >>= sValue);
+    CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), sValue);
+    CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("DataColumnName") >>= sValue);
+    CPPUNIT_ASSERT_EQUAL(OUString("c1"), sValue);
+    CPPUNIT_ASSERT(xFiledMaster->getPropertyValue("InstanceName") >>= sValue);
+    CPPUNIT_ASSERT_EQUAL(OUString("com.sun.star.text.fieldmaster.DataBase.database.Sheet1.c1"), sValue);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index 501f632ff3f2..3b9e677e7219 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -33,6 +33,7 @@
 #include <com/sun/star/xml/sax/XSAXSerializable.hpp>
 #include <com/sun/star/xml/sax/Writer.hpp>
 #include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
 
 #include <oox/token/namespaces.hxx>
 #include <oox/token/tokens.hxx>
@@ -63,6 +64,7 @@
 #include <section.hxx>
 #include <ftninfo.hxx>
 #include <pagedesc.hxx>
+#include <swdbdata.hxx>
 
 #include <editeng/unoprnms.hxx>
 #include <editeng/editobj.hxx>
@@ -979,6 +981,27 @@ void DocxExport::WriteSettings()
         pFS->endElementNS( XML_w, XML_compat );
     }
 
+    // export current mail merge database and table names
+    SwDBData aData = m_pDoc->GetDBData();
+    if ( !aData.sDataSource.isEmpty() && aData.nCommandType == css::sdb::CommandType::TABLE && !aData.sCommand.isEmpty() )
+    {
+        OUStringBuffer aDataSource;
+        aDataSource.append("SELECT * FROM ");
+        aDataSource.append(aData.sDataSource); // current database
+        aDataSource.append(".dbo."); // default database owner
+        aDataSource.append(aData.sCommand); // sheet name
+        aDataSource.append("$"); // sheet identifier
+        const OUString sDataSource = aDataSource.makeStringAndClear();
+        pFS->startElementNS( XML_w, XML_mailMerge );
+        pFS->singleElementNS(XML_w, XML_mainDocumentType,
+            FSNS( XML_w, XML_val ), "formLetters" );
+        pFS->singleElementNS(XML_w, XML_dataType,
+            FSNS( XML_w, XML_val ), "textFile" );
+        pFS->singleElementNS( XML_w, XML_query,
+            FSNS( XML_w, XML_val ), OUStringToOString( sDataSource, RTL_TEXTENCODING_UTF8 ).getStr() );
+        pFS->endElementNS( XML_w, XML_mailMerge );
+    }
+
     // Automatic hyphenation: it's a global setting in Word, it's a paragraph setting in Writer.
     // Use the setting from the default style.
     SwTextFormatColl* pColl = m_pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD, /*bRegardLanguage=*/false);
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 6f49eecf348e..961a88872bff 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -3080,8 +3080,15 @@ uno::Reference<beans::XPropertySet> DomainMapper_Impl::FindOrCreateFieldMaster(c
     uno::Reference< beans::XPropertySet > xMaster;
     OUString sFieldMasterService( OUString::createFromAscii(pFieldMasterService) );
     OUStringBuffer aFieldMasterName;
+    OUString sDatabaseDataSourceName = GetSettingsTable()->GetCurrentDatabaseDataSource();
+    bool bIsMergeField = sFieldMasterService.endsWith("Database");
     aFieldMasterName.appendAscii( pFieldMasterService );
     aFieldMasterName.append('.');
+    if ( bIsMergeField && !sDatabaseDataSourceName.isEmpty() )
+    {
+        aFieldMasterName.append(sDatabaseDataSourceName);
+        aFieldMasterName.append('.');
+    }
     aFieldMasterName.append(rFieldMasterName);
     OUString sFieldMasterName = aFieldMasterName.makeStringAndClear();
     if(xFieldMasterAccess->hasByName(sFieldMasterName))
@@ -3093,10 +3100,27 @@ uno::Reference<beans::XPropertySet> DomainMapper_Impl::FindOrCreateFieldMaster(c
     {
         //create the master
         xMaster.set( m_xTextFactory->createInstance(sFieldMasterService), uno::UNO_QUERY_THROW);
-        //set the master's name
-        xMaster->setPropertyValue(
+        if ( !bIsMergeField || sDatabaseDataSourceName.isEmpty() )
+        {
+            //set the master's name
+            xMaster->setPropertyValue(
                     getPropertyName(PROP_NAME),
                     uno::makeAny(rFieldMasterName));
+        } else {
+           // set database data, based on the "databasename.tablename" of sDatabaseDataSourceName
+           xMaster->setPropertyValue(
+                    getPropertyName(PROP_DATABASE_NAME),
+                    uno::makeAny(sDatabaseDataSourceName.copy(0, sDatabaseDataSourceName.indexOf('.'))));
+           xMaster->setPropertyValue(
+                    getPropertyName(PROP_COMMAND_TYPE),
+                    uno::makeAny(sal_Int32(0)));
+           xMaster->setPropertyValue(
+                    getPropertyName(PROP_DATATABLE_NAME),
+                    uno::makeAny(sDatabaseDataSourceName.copy(sDatabaseDataSourceName.indexOf('.') + 1)));
+           xMaster->setPropertyValue(
+                    getPropertyName(PROP_DATACOLUMN_NAME),
+                    uno::makeAny(rFieldMasterName));
+        }
     }
     return xMaster;
 }
diff --git a/writerfilter/source/dmapper/PropertyIds.cxx b/writerfilter/source/dmapper/PropertyIds.cxx
index e51062541d47..28b9092e96e2 100644
--- a/writerfilter/source/dmapper/PropertyIds.cxx
+++ b/writerfilter/source/dmapper/PropertyIds.cxx
@@ -350,6 +350,10 @@ OUString getPropertyName( PropertyIds eId )
         case PROP_RUBY_ADJUST: sName = "RubyAdjust"; break;
         case PROP_RUBY_POSITION: sName = "RubyPosition"; break;
         case PROP_LAYOUT_IN_CELL: sName = "IsLayoutInCell"; break;
+        case PROP_DATABASE_NAME: sName = "DataBaseName"; break;
+        case PROP_COMMAND_TYPE: sName = "DataCommandType"; break;
+        case PROP_DATATABLE_NAME: sName = "DataTableName"; break;
+        case PROP_DATACOLUMN_NAME: sName = "DataColumnName"; break;
     }
     assert(sName.getLength()>0);
     return sName;
diff --git a/writerfilter/source/dmapper/PropertyIds.hxx b/writerfilter/source/dmapper/PropertyIds.hxx
index 331a978d0d42..eed9dd62bb30 100644
--- a/writerfilter/source/dmapper/PropertyIds.hxx
+++ b/writerfilter/source/dmapper/PropertyIds.hxx
@@ -348,6 +348,10 @@ enum PropertyIds
         ,PROP_RUBY_ADJUST
         ,PROP_RUBY_POSITION
         ,PROP_LAYOUT_IN_CELL
+        ,PROP_DATABASE_NAME
+        ,PROP_COMMAND_TYPE
+        ,PROP_DATATABLE_NAME
+        ,PROP_DATACOLUMN_NAME
     };
 
 //Returns the UNO string equivalent to eId.
diff --git a/writerfilter/source/dmapper/SettingsTable.cxx b/writerfilter/source/dmapper/SettingsTable.cxx
index beae5a4942bd..76601e49eae2 100644
--- a/writerfilter/source/dmapper/SettingsTable.cxx
+++ b/writerfilter/source/dmapper/SettingsTable.cxx
@@ -256,6 +256,7 @@ struct SettingsTable_Impl
 
     std::vector<beans::PropertyValue> m_aCompatSettings;
     uno::Sequence<beans::PropertyValue> m_pCurrentCompatSetting;
+    OUString            m_sCurrentDatabaseDataSource;
 
     DocumentProtection_Impl m_DocumentProtection;
 
@@ -460,6 +461,29 @@ void SettingsTable::lcl_sprm(Sprm& rSprm)
     case NS_ooxml::LN_CT_Settings_mirrorMargins:
         m_pImpl->m_bMirrorMargin = nIntValue;
         break;
+    case NS_ooxml::LN_CT_Settings_mailMerge:
+    {
+        writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+        if (pProperties.get())
+            pProperties->resolve(*this);
+    }
+    break;
+    case NS_ooxml::LN_CT_MailMerge_query:
+    {
+        // try to get the "database.table" name from the query saved previously
+        OUString sVal = pValue->getString();
+        if ( sVal.endsWith("$") && sVal.indexOf(".dbo.") > 0 )
+        {
+            sal_Int32 nSpace = sVal.lastIndexOf(' ');
+            sal_Int32 nDbo = sVal.lastIndexOf(".dbo.");
+            if ( nSpace > 0 && nSpace < nDbo - 1 )
+            {
+                m_pImpl->m_sCurrentDatabaseDataSource = sVal.copy(nSpace + 1, nDbo - nSpace - 1) +
+                            sVal.copy(nDbo + 4, sVal.getLength() - nDbo - 5);
+            }
+        }
+    }
+    break;
     case NS_ooxml::LN_CT_Compat_compatSetting:
     {
         writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
@@ -595,6 +619,11 @@ css::uno::Sequence<css::beans::PropertyValue> SettingsTable::GetDocumentProtecti
     return m_pImpl->m_DocumentProtection.toSequence();
 }
 
+OUString SettingsTable::GetCurrentDatabaseDataSource() const
+{
+    return m_pImpl->m_sCurrentDatabaseDataSource;
+}
+
 static bool lcl_isDefault(const uno::Reference<beans::XPropertyState>& xPropertyState, const OUString& rPropertyName)
 {
     return xPropertyState->getPropertyState(rPropertyName) == beans::PropertyState_DEFAULT_VALUE;
diff --git a/writerfilter/source/dmapper/SettingsTable.hxx b/writerfilter/source/dmapper/SettingsTable.hxx
index 7d539336f78e..8e7136989b47 100644
--- a/writerfilter/source/dmapper/SettingsTable.hxx
+++ b/writerfilter/source/dmapper/SettingsTable.hxx
@@ -88,6 +88,8 @@ class SettingsTable : public LoggedProperties, public LoggedTable
 
     sal_Int32 GetWordCompatibilityMode() const;
 
+    OUString GetCurrentDatabaseDataSource() const;
+
  private:
     // Properties
     virtual void lcl_attribute(Id Name, Value & val) override;


More information about the Libreoffice-commits mailing list