sw/qa/extras/mailmerge/data/grabbagtest.docx |binary sw/qa/extras/mailmerge/data/onecell.xlsx |binary sw/qa/extras/mailmerge/mailmerge.cxx | 92 +++++++++++++++++++++++---- sw/source/core/doc/docnew.cxx | 9 ++ sw/source/ui/dbui/mmresultdialogs.cxx | 8 ++ writerfilter/source/dmapper/DomainMapper.cxx | 2 6 files changed, 98 insertions(+), 13 deletions(-)
New commits: commit 123d3a9301c90925c23cfb4806d7b0be01b975d6 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri May 20 20:56:56 2022 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Mon May 23 10:54:16 2022 +0200 sw: copy grab bags in mail merge Otherwise formatting may get lost when the result is stored as DOCX. Change-Id: I62cbeb1fc9f120dd9c424daf5dc0471686715537 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134694 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sw/qa/extras/mailmerge/data/grabbagtest.docx b/sw/qa/extras/mailmerge/data/grabbagtest.docx new file mode 100644 index 000000000000..4b40f1fb4e94 Binary files /dev/null and b/sw/qa/extras/mailmerge/data/grabbagtest.docx differ diff --git a/sw/qa/extras/mailmerge/data/onecell.xlsx b/sw/qa/extras/mailmerge/data/onecell.xlsx new file mode 100644 index 000000000000..972f6b3c5fc5 Binary files /dev/null and b/sw/qa/extras/mailmerge/data/onecell.xlsx differ diff --git a/sw/qa/extras/mailmerge/mailmerge.cxx b/sw/qa/extras/mailmerge/mailmerge.cxx index 53678a1caf94..c5b0a6cb16b8 100644 --- a/sw/qa/extras/mailmerge/mailmerge.cxx +++ b/sw/qa/extras/mailmerge/mailmerge.cxx @@ -16,7 +16,9 @@ #include <com/sun/star/text/MailMergeType.hpp> #include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/table/TableBorder.hpp> #include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/text/XTextTable.hpp> #include <com/sun/star/sdbc/XRowSet.hpp> #include <com/sun/star/sdbcx/XRowLocate.hpp> #include <com/sun/star/task/XJob.hpp> @@ -76,7 +78,7 @@ public: * calling executeMailMerge() after modifying the job arguments. */ void executeMailMergeTest( const char* filename, const char* datasource, const char* tablename, - bool file, int selection, const char* column ) + char const*const filter, int selection, const char* column ) { maMMtestFilename = filename; header(); @@ -88,7 +90,7 @@ public: const OUString aURI( m_directories.getURLFromSrc(mpTestDocumentPath) + OUString::createFromAscii(datasource) ); const OUString aPrefix = column ? OUString::createFromAscii( column ) : "LOMM_"; const OUString aDBName = registerDBsource( aURI, aWorkDir ); - initMailMergeJobAndArgs( filename, tablename, aDBName, aPrefix, aWorkDir, file, selection, column != nullptr ); + initMailMergeJobAndArgs( filename, tablename, aDBName, aPrefix, aWorkDir, filter, selection, column != nullptr ); verify(); finish(); @@ -137,7 +139,8 @@ public: } void initMailMergeJobAndArgs( const char* filename, const char* tablename, const OUString &aDBName, - const OUString &aPrefix, const OUString &aWorkDir, bool file, int nDataSets, + const OUString &aPrefix, const OUString &aWorkDir, + char const*const filter, int nDataSets, const bool bPrefixIsColumn ) { uno::Reference< task::XJob > xJob( getMultiServiceFactory()->createInstance( "com.sun.star.text.MailMerge" ), uno::UNO_QUERY_THROW ); @@ -145,13 +148,16 @@ public: mMMargs.reserve( 15 ); - mMMargs.emplace_back( UNO_NAME_OUTPUT_TYPE, uno::Any( file ? text::MailMergeType::FILE : text::MailMergeType::SHELL ) ); + mMMargs.emplace_back( UNO_NAME_OUTPUT_TYPE, uno::Any( filter ? text::MailMergeType::FILE : text::MailMergeType::SHELL ) ); mMMargs.emplace_back( UNO_NAME_DOCUMENT_URL, uno::Any( ( OUString( m_directories.getURLFromSrc(mpTestDocumentPath) + OUString::createFromAscii(filename)) ) ) ); mMMargs.emplace_back( UNO_NAME_DATA_SOURCE_NAME, uno::Any( aDBName ) ); mMMargs.emplace_back( UNO_NAME_OUTPUT_URL, uno::Any( aWorkDir ) ); - if (file) + if (filter) + { mMMargs.emplace_back( UNO_NAME_FILE_NAME_PREFIX, uno::Any( aPrefix ) ); + mMMargs.emplace_back(UNO_NAME_SAVE_FILTER, uno::Any(OUString::createFromAscii(filter))); + } if (bPrefixIsColumn) mMMargs.emplace_back( UNO_NAME_FILE_NAME_FROM_COLUMN, uno::Any( true ) ); @@ -255,7 +261,7 @@ public: /** Loads number-th document from mail merge. Requires file output from mail merge. */ - void loadMailMergeDocument( int number ) + void loadMailMergeDocument(int number, char const*const ext = ".odt") { OUString name; if (!msMailMergeOutputPrefix.isEmpty()) @@ -267,7 +273,7 @@ public: aURLObj.SetSmartURL( msMailMergeDocumentURL ); name = aURLObj.GetBase(); } - name += OUString::number( number ) + ".odt"; + name += OUString::number(number) + OStringToOUString(std::string_view(ext, strlen(ext)), RTL_TEXTENCODING_ASCII_US); loadMailMergeDocument( name ); } @@ -297,7 +303,7 @@ protected: const char* maMMtestFilename; }; -#define DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, file, BaseClass, selection, column) \ +#define DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, filter, BaseClass, selection, column) \ class TestName : public BaseClass { \ protected: \ virtual OUString getTestName() override { return #TestName; } \ @@ -307,7 +313,7 @@ protected: CPPUNIT_TEST_SUITE_END(); \ \ void MailMerge() { \ - executeMailMergeTest(filename, datasource, tablename, file, selection, column); \ + executeMailMergeTest(filename, datasource, tablename, filter, selection, column); \ } \ void verify() override; \ }; \ @@ -316,17 +322,17 @@ protected: // Will generate the resulting document in mxMMDocument. #define DECLARE_SHELL_MAILMERGE_TEST(TestName, filename, datasource, tablename) \ - DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, false, MMTest, 0, nullptr) + DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, nullptr, MMTest, 0, nullptr) // Will generate documents as files, use loadMailMergeDocument(). #define DECLARE_FILE_MAILMERGE_TEST(TestName, filename, datasource, tablename) \ - DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, true, MMTest, 0, nullptr) + DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, "writer8", MMTest, 0, nullptr) #define DECLARE_SHELL_MAILMERGE_TEST_SELECTION(TestName, filename, datasource, tablename, selection) \ - DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, false, MMTest, selection, nullptr) + DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, nullptr, MMTest, selection, nullptr) #define DECLARE_FILE_MAILMERGE_TEST_COLUMN(TestName, filename, datasource, tablename, column) \ - DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, true, MMTest, 0, column) + DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, "writer8", MMTest, 0, column) int MMTest::documentStartPageNumber( int document ) const { // See documentStartPageNumber() . @@ -1291,5 +1297,65 @@ DECLARE_SHELL_MAILMERGE_TEST(testTdf128148, "tdf128148.odt", "4_v01.ods", "Tabel } } +namespace com::sun::star::table { + +static std::ostream& operator<<(std::ostream& rStream, table::BorderLine const& rLine) +{ + rStream << "BorderLine(" << rLine.Color << "," << rLine.InnerLineWidth << "," << rLine.OuterLineWidth << "," << rLine.LineDistance << ")"; + return rStream; +} + +static std::ostream& operator<<(std::ostream& rStream, table::TableBorder const& rBorder) +{ + rStream << "TableBorder(\n " + << rBorder.TopLine << "," << static_cast<bool>(rBorder.IsTopLineValid) << ",\n " + << rBorder.BottomLine << "," << static_cast<bool>(rBorder.IsBottomLineValid) << ",\n " + << rBorder.LeftLine << "," << static_cast<bool>(rBorder.IsLeftLineValid) << ",\n " + << rBorder.RightLine << "," << static_cast<bool>(rBorder.IsRightLineValid) << ",\n " + << rBorder.HorizontalLine << "," << static_cast<bool>(rBorder.IsHorizontalLineValid) << ",\n " + << rBorder.VerticalLine << "," << static_cast<bool>(rBorder.IsVerticalLineValid) << ",\n " + << rBorder.Distance << "," << static_cast<bool>(rBorder.IsDistanceValid) << ")"; + return rStream; +} + +} + +DECLARE_MAILMERGE_TEST(testGrabBag, "grabbagtest.docx", "onecell.xlsx", "Sheet1", "MS Word 2007 XML", MMTest, 0, nullptr) +{ + executeMailMerge(true); + + loadMailMergeDocument(0, ".docx"); + + SwXTextDocument *const pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + CPPUNIT_ASSERT(pTextDoc); + + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pTextDoc->GetDocShell()->GetWrtShell()->GetPhyPageNum()); + + // check grabbag + uno::Reference<beans::XPropertySet> const xModel( + mxComponent, uno::UNO_QUERY_THROW); + uno::Sequence<beans::PropertyValue> aInteropGrabBag; + pTextDoc->getPropertyValue("InteropGrabBag") >>= aInteropGrabBag; + CPPUNIT_ASSERT_EQUAL(sal_Int32(13), aInteropGrabBag.getLength()); + + // check table border - comes from table style "Tabellenraster" + uno::Reference<text::XTextTable> const xTable(getParagraphOrTable(1, pTextDoc->getText()), uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertySet> const xTableProps(xTable, uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(table::TableBorder( + table::BorderLine(util::Color(0), 0, 18, 0), true, + table::BorderLine(util::Color(0), 0, 18, 0), true, + table::BorderLine(util::Color(0), 0, 18, 0), true, + table::BorderLine(util::Color(0), 0, 18, 0), true, + table::BorderLine(util::Color(0), 0, 18, 0), true, + table::BorderLine(util::Color(0), 0, 0, 0), true, + sal_Int16(191), true), + getProperty<table::TableBorder>(xTableProps, "TableBorder")); + + // check font is Arial - comes from theme (wrong result was "" - nothing) + uno::Reference<text::XText> const xCell(xTable->getCellByName("A1"), uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertySet> const xParaA1(getParagraphOrTable(1, xCell->getText()), uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT_EQUAL(OUString("Arial"), getProperty<OUString>(xParaA1, "CharFontName")); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx index 72182b7435d0..72798b019e15 100644 --- a/sw/source/core/doc/docnew.cxx +++ b/sw/source/core/doc/docnew.cxx @@ -28,6 +28,7 @@ #include <doc.hxx> #include <proofreadingiterator.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/text/XFlatParagraphIteratorProvider.hpp> #include <com/sun/star/linguistic2/XProofreadingIterator.hpp> #include <com/sun/star/i18n/ScriptType.hpp> @@ -906,6 +907,14 @@ SfxObjectShell* SwDoc::CreateCopy( bool bCallInitNew, bool bEmpty ) const xRet->ReplaceStyles(*this); + uno::Reference<beans::XPropertySet> const xThisSet( + GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertySet> const xRetSet( + pRetShell->GetBaseModel(), uno::UNO_QUERY_THROW); + uno::Sequence<beans::PropertyValue> aInteropGrabBag; + xThisSet->getPropertyValue("InteropGrabBag") >>= aInteropGrabBag; + xRetSet->setPropertyValue("InteropGrabBag", uno::Any(aInteropGrabBag)); + if( !bEmpty ) { #ifdef DBG_UTIL diff --git a/sw/source/ui/dbui/mmresultdialogs.cxx b/sw/source/ui/dbui/mmresultdialogs.cxx index b2db4782bd6c..9ff6315eefb0 100644 --- a/sw/source/ui/dbui/mmresultdialogs.cxx +++ b/sw/source/ui/dbui/mmresultdialogs.cxx @@ -682,6 +682,14 @@ IMPL_LINK_NOARG(SwMMResultSaveDialog, SaveOutputHdl_Impl, weld::Button&, void) pTempView->GetDocShell()->GetDoc()->ReplaceDefaults( *pTargetView->GetDocShell()->GetDoc()); pTempView->GetDocShell()->GetDoc()->ReplaceDocumentProperties( *pTargetView->GetDocShell()->GetDoc(), true ); + uno::Reference<beans::XPropertySet> const xThisSet( + pTargetView->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertySet> const xRetSet( + pTempView->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW); + uno::Sequence<beans::PropertyValue> aInteropGrabBag; + xThisSet->getPropertyValue("InteropGrabBag") >>= aInteropGrabBag; + xRetSet->setPropertyValue("InteropGrabBag", uno::Any(aInteropGrabBag)); + pTargetView->GetWrtShell().PastePages( pTempView->GetWrtShell(), documentStartPageNumber(xConfigItem.get(), nDoc, false), documentEndPageNumber(xConfigItem.get(), nDoc, false)); diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index 0b070b23ea85..cefb05fd5292 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -378,6 +378,8 @@ void DomainMapper::lcl_attribute(Id nName, Value & val) m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "asciiTheme", ThemeTable::getStringForTheme(nIntValue)); if (m_pImpl->GetTopContext()) { + // note: overwrite Fonts_ascii with Fonts_asciiTheme *even if* + // theme font is empty - this is apparently what Word 2013 does uno::Any aPropValue( m_pImpl->GetThemeTable()->getFontNameForTheme( nIntValue ) ); m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME, aPropValue ); m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_FONT_NAME_ASCII, aPropValue, true, CHAR_GRAB_BAG );