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 <nem...@numbertext.org> AuthorDate: Wed Apr 24 12:30:56 2019 +0200 Commit: László Németh <nem...@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 <nem...@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; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits