From db04be037b611e296ef9f2542322c52ed82d7a2b Mon Sep 17 00:00:00 2001 From: Mike Kaganski Date: Fri, 18 May 2018 18:48:38 +0300 Subject: tdf#35798: Hide empty Database fields' paragraphs (+ compat option) With this change, Database fields that expand to empty values behave as if they are "Hidden Paragraph" fields. A compatibility option to enable this behaviour is added. The option is enabled by default, and for any non-native documents (for compatibility with other office suites). For existing (F)ODT documents, the option is disabled for those documents that don't have this setting set, to keep the layout of legacy documents. Change-Id: Ic5e8cb15a3a7d1a765a984eef4b0d97666df7dfd Reviewed-on: https://gerrit.libreoffice.org/54552 Tested-by: Jenkins Reviewed-by: Mike Kaganski --- sw/CppunitTest_sw_mailmerge.mk | 4 + sw/inc/IDocumentSettingAccess.hxx | 1 + sw/inc/doc.hxx | 3 + sw/inc/ndhints.hxx | 26 +++-- sw/inc/ndtxt.hxx | 12 +- sw/inc/viewsh.hxx | 2 + sw/qa/extras/mailmerge/data/5-with-blanks.ods | Bin 0 -> 9193 bytes sw/qa/extras/mailmerge/data/tdf35798-legacy.fodt | 37 ++++++ sw/qa/extras/mailmerge/data/tdf35798-legacy.odt | Bin 0 -> 9557 bytes sw/qa/extras/mailmerge/data/tdf35798-new.fodt | 38 ++++++ sw/qa/extras/mailmerge/data/tdf35798-new.odt | Bin 0 -> 9556 bytes sw/qa/extras/mailmerge/mailmerge.cxx | 140 +++++++++++++++++++++++ sw/source/core/doc/DocumentSettingManager.cxx | 8 ++ sw/source/core/doc/doc.cxx | 128 +++++++++++++-------- sw/source/core/doc/doctxm.cxx | 4 +- sw/source/core/inc/DocumentSettingManager.hxx | 1 + sw/source/core/text/txtfrm.cxx | 9 +- sw/source/core/txtnode/atrfld.cxx | 26 +++-- sw/source/core/txtnode/ndtxt.cxx | 2 +- sw/source/core/txtnode/thints.cxx | 65 ++++++----- sw/source/core/view/viewsh.cxx | 20 ++++ sw/source/filter/xml/xmlimp.cxx | 26 +++++ sw/source/ui/config/optcomp.cxx | 16 ++- sw/source/uibase/app/docshini.cxx | 22 ++-- sw/source/uibase/uno/SwXDocumentSettings.cxx | 18 +++ sw/uiconfig/swriter/ui/optcompatpage.ui | 1 + 26 files changed, 489 insertions(+), 120 deletions(-) create mode 100644 sw/qa/extras/mailmerge/data/5-with-blanks.ods create mode 100644 sw/qa/extras/mailmerge/data/tdf35798-legacy.fodt create mode 100644 sw/qa/extras/mailmerge/data/tdf35798-legacy.odt create mode 100644 sw/qa/extras/mailmerge/data/tdf35798-new.fodt create mode 100644 sw/qa/extras/mailmerge/data/tdf35798-new.odt (limited to 'sw') diff --git a/sw/CppunitTest_sw_mailmerge.mk b/sw/CppunitTest_sw_mailmerge.mk index 925c639e8b25..766be12acbb2 100644 --- a/sw/CppunitTest_sw_mailmerge.mk +++ b/sw/CppunitTest_sw_mailmerge.mk @@ -45,7 +45,10 @@ $(eval $(call gb_CppunitTest_use_components,sw_mailmerge, \ dbaccess/util/dba \ embeddedobj/util/embobj \ filter/source/config/cache/filterconfig1 \ + filter/source/odfflatxml/odfflatxml \ filter/source/storagefilterdetect/storagefd \ + filter/source/xmlfilteradaptor/xmlfa \ + filter/source/xmlfilterdetect/xmlfd \ forms/util/frm \ framework/util/fwk \ i18npool/util/i18npool \ @@ -79,6 +82,7 @@ $(eval $(call gb_CppunitTest_use_components,sw_mailmerge, \ ) \ ) \ xmloff/util/xo \ + xmlscript/util/xmlscript \ )) $(eval $(call gb_CppunitTest_use_configuration,sw_mailmerge)) diff --git a/sw/inc/IDocumentSettingAccess.hxx b/sw/inc/IDocumentSettingAccess.hxx index e3ac10797b89..a66f2367c22f 100644 --- a/sw/inc/IDocumentSettingAccess.hxx +++ b/sw/inc/IDocumentSettingAccess.hxx @@ -83,6 +83,7 @@ enum class DocumentSettingId SUBTRACT_FLYS, // tdf#112443 disable off-page content positioning DISABLE_OFF_PAGE_POSITIONING, + EMPTY_DB_FIELD_HIDES_PARA, // COMPATIBILITY FLAGS END BROWSE_MODE, HTML_MODE, diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index d588428b8890..ab3acf7d9070 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -466,6 +466,9 @@ public: ::sw::DocumentFieldsManager & GetDocumentFieldsManager(); + bool FieldCanHidePara(SwFieldIds eFieldId) const; + bool FieldHidesPara(const SwField& rField) const; + // IDocumentContentOperations IDocumentContentOperations const & getIDocumentContentOperations() const; IDocumentContentOperations & getIDocumentContentOperations(); diff --git a/sw/inc/ndhints.hxx b/sw/inc/ndhints.hxx index 77aebc67d2be..0d66f9c3ead2 100644 --- a/sw/inc/ndhints.hxx +++ b/sw/inc/ndhints.hxx @@ -77,6 +77,8 @@ class SwpHtEnd : public o3tl::sorted_vector(this)->CalcHiddenParaField(); + CalcHiddenParaField(); } - return m_bHasHiddenParaField; + return m_bHiddenByParaField; } void InsertNesting(SwTextAttrNesting & rNewHint); @@ -144,7 +148,7 @@ private: #endif public: - SwpHints(); + SwpHints(const SwTextNode& rParent); size_t Count() const { return m_HintsByStart.size(); } bool Contains( const SwTextAttr *pHt ) const; @@ -179,8 +183,8 @@ public: bool HasFootnote() const { return m_bFootnote; } bool IsInSplitNode() const { return m_bInSplitNode; } - /// calc current value of m_bHasHiddenParaField, returns true iff changed - bool CalcHiddenParaField(); + // calc current value of m_bHiddenByParaField, returns true iff changed + bool CalcHiddenParaField() const; // changes mutable state DECL_FIXEDMEMPOOL_NEWDEL(SwpHints) }; diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index 50cc3a75172f..894f8c078635 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -21,6 +21,7 @@ #include +#include "doc.hxx" #include "swdllapi.h" #include "node.hxx" #include "hintids.hxx" @@ -701,8 +702,13 @@ public: { if (m_pSwpHints) m_pSwpHints->SetCalcHiddenParaField(); } /// is the paragraph visible? - bool HasHiddenParaField() const - { return m_pSwpHints && m_pSwpHints->HasHiddenParaField(); } + bool IsHiddenByParaField() const + { return m_pSwpHints && m_pSwpHints->IsHiddenByParaField(); } + + bool FieldCanHidePara(SwFieldIds eFieldId) const + { return GetDoc()->FieldCanHidePara(eFieldId); } + bool FieldHidesPara(const SwField& rField) const + { return GetDoc()->FieldHidesPara(rField); } /// Hidden Paragraph Field: @@ -811,7 +817,7 @@ inline SwpHints& SwTextNode::GetOrCreateSwpHints() { if ( !m_pSwpHints ) { - m_pSwpHints.reset(new SwpHints); + m_pSwpHints.reset(new SwpHints(*this)); } return *m_pSwpHints; } diff --git a/sw/inc/viewsh.hxx b/sw/inc/viewsh.hxx index 30f5911da9bd..832f4f9dd878 100644 --- a/sw/inc/viewsh.hxx +++ b/sw/inc/viewsh.hxx @@ -410,6 +410,8 @@ public: void SetSubtractFlysAnchoredAtFlys(bool bSubtractFlysAnchoredAtFlys); + void SetEmptyDbFieldHidesPara(bool bEmptyDbFieldHidesPara); + // DOCUMENT COMPATIBILITY FLAGS END // Calls Idle-formatter of Layout. diff --git a/sw/qa/extras/mailmerge/data/5-with-blanks.ods b/sw/qa/extras/mailmerge/data/5-with-blanks.ods new file mode 100644 index 000000000000..722f74830688 Binary files /dev/null and b/sw/qa/extras/mailmerge/data/5-with-blanks.ods differ diff --git a/sw/qa/extras/mailmerge/data/tdf35798-legacy.fodt b/sw/qa/extras/mailmerge/data/tdf35798-legacy.fodt new file mode 100644 index 000000000000..c6dd8661e869 --- /dev/null +++ b/sw/qa/extras/mailmerge/data/tdf35798-legacy.fodt @@ -0,0 +1,37 @@ + + + + 2014-10-22T13:27:38.6731542792018-05-19T13:45:25.911000000PT6M54S4LibreOfficeDev/6.1.0.0.alpha1$Windows_X86_64 LibreOffice_project/dd1ab570d5791145c10a4e8f28b048ec8f70edb0 + + + 5-with-blanks + names + 0 + + + + + + + + + + + + + + + + + + Heading + Title: <Title> + First Name: <First Name> + Last Name: <Last Name> + Title: <Title>First Name: <First Name> + First Name: <First Name>Last Name: <Last Name> + Title: <Title>First Name: <First Name>Last Name: <Last Name> + Trailing text + + + \ No newline at end of file diff --git a/sw/qa/extras/mailmerge/data/tdf35798-legacy.odt b/sw/qa/extras/mailmerge/data/tdf35798-legacy.odt new file mode 100644 index 000000000000..fe37e5e962fd Binary files /dev/null and b/sw/qa/extras/mailmerge/data/tdf35798-legacy.odt differ diff --git a/sw/qa/extras/mailmerge/data/tdf35798-new.fodt b/sw/qa/extras/mailmerge/data/tdf35798-new.fodt new file mode 100644 index 000000000000..8de149cab75a --- /dev/null +++ b/sw/qa/extras/mailmerge/data/tdf35798-new.fodt @@ -0,0 +1,38 @@ + + + + 2014-10-22T13:27:38.6731542792018-05-19T13:45:25.911000000PT6M54S4LibreOfficeDev/6.1.0.0.alpha1$Windows_X86_64 LibreOffice_project/dd1ab570d5791145c10a4e8f28b048ec8f70edb0 + + + 5-with-blanks + names + 0 + true + + + + + + + + + + + + + + + + + + Heading + Title: <Title> + First Name: <First Name> + Last Name: <Last Name> + Title: <Title>First Name: <First Name> + First Name: <First Name>Last Name: <Last Name> + Title: <Title>First Name: <First Name>Last Name: <Last Name> + Trailing text + + + \ No newline at end of file diff --git a/sw/qa/extras/mailmerge/data/tdf35798-new.odt b/sw/qa/extras/mailmerge/data/tdf35798-new.odt new file mode 100644 index 000000000000..84323b96e658 Binary files /dev/null and b/sw/qa/extras/mailmerge/data/tdf35798-new.odt differ diff --git a/sw/qa/extras/mailmerge/mailmerge.cxx b/sw/qa/extras/mailmerge/mailmerge.cxx index d961216fb8a8..ca1f3ec47b0e 100644 --- a/sw/qa/extras/mailmerge/mailmerge.cxx +++ b/sw/qa/extras/mailmerge/mailmerge.cxx @@ -677,5 +677,145 @@ DECLARE_FILE_MAILMERGE_TEST(testTdf102010, "empty.odt", "10-testing-addresses.od loadMailMergeDocument( 1 ); } +namespace +{ +constexpr char const* const EmptyValuesLegacyData[][8] + = { { "Heading", "Title: ", "First Name: firstname1", "Last Name: lastname1", + "Title: First Name: firstname1", "First Name: firstname1 Last Name: lastname1", + "Title: First Name: firstname1 Last Name: lastname1", "Trailing text" }, + { "Heading", "Title: title2", "First Name: ", "Last Name: lastname2", + "Title: title2 First Name: ", "First Name: Last Name: lastname2", + "Title: title2 First Name: Last Name: lastname2", "Trailing text" }, + { "Heading", "Title: title3", "First Name: firstname3", "Last Name: ", + "Title: title3 First Name: firstname3", "First Name: firstname3 Last Name: ", + "Title: title3 First Name: firstname3 Last Name: ", "Trailing text" }, + { "Heading", "Title: ", "First Name: ", "Last Name: lastname4", + "Title: First Name: ", "First Name: Last Name: lastname4", + "Title: First Name: Last Name: lastname4", "Trailing text" }, + { "Heading", "Title: title5", "First Name: ", "Last Name: ", "Title: title5 First Name: ", + "First Name: Last Name: ", "Title: title5 First Name: Last Name: ", "Trailing text" } }; +constexpr char const* const EmptyValuesNewData[][8] + = { { "Heading", "First Name: firstname1", "Last Name: lastname1", + "Title: First Name: firstname1", "First Name: firstname1 Last Name: lastname1", + "Title: First Name: firstname1 Last Name: lastname1", "Trailing text" }, + { "Heading", "Title: title2", "Last Name: lastname2", + "Title: title2 First Name: ", "First Name: Last Name: lastname2", + "Title: title2 First Name: Last Name: lastname2", "Trailing text" }, + { "Heading", "Title: title3", "First Name: firstname3", + "Title: title3 First Name: firstname3", "First Name: firstname3 Last Name: ", + "Title: title3 First Name: firstname3 Last Name: ", "Trailing text" }, + { "Heading", "Last Name: lastname4", "First Name: Last Name: lastname4", + "Title: First Name: Last Name: lastname4", "Trailing text" }, + { "Heading", "Title: title5", "Title: title5 First Name: ", + "Title: title5 First Name: Last Name: ", "Trailing text" } }; +} + +// The following four tests (testEmptyValuesLegacyODT, testEmptyValuesNewODT, (testEmptyValuesLegacyFODT, testEmptyValuesNewFODT) +// check that for native documents without "EmptyDbFieldHidesPara" compatibility option, all paragraphs are exported visible, +// while for documents with the option enabled, the paragraphs with all Database fields having empty values are hidden. + +DECLARE_FILE_MAILMERGE_TEST(testEmptyValuesLegacyODT, "tdf35798-legacy.odt", "5-with-blanks.ods", + "names") +{ + executeMailMerge(); + for (int doc = 0; doc < 5; ++doc) + { + loadMailMergeDocument(doc); + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT(pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + pDoc->RemoveInvisibleContent(); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + for (int i = 0; i < 8; ++i) + { + auto xPara = getParagraph(i+1); + SAL_WARN("sw.qa", "Testing doc " + OUString::number(doc) + " paragraph " + + OUString::number(i + 1)); + CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(EmptyValuesLegacyData[doc][i]), + xPara->getString()); + } + CPPUNIT_ASSERT_EQUAL(8, getParagraphs()); + } +} + +DECLARE_FILE_MAILMERGE_TEST(testEmptyValuesNewODT, "tdf35798-new.odt", "5-with-blanks.ods", + "names") +{ + executeMailMerge(); + for (int doc = 0; doc < 5; ++doc) + { + loadMailMergeDocument(doc); + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT(pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + pDoc->RemoveInvisibleContent(); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + int i; + for (i = 0; i < 8; ++i) + { + const char* pExpected = EmptyValuesNewData[doc][i]; + if (!pExpected) + break; + auto xPara = getParagraph(i + 1); + SAL_WARN("sw.qa", "Testing doc " + OUString::number(doc) + " paragraph " + + OUString::number(i + 1)); + CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(pExpected), + xPara->getString()); + } + CPPUNIT_ASSERT_EQUAL(i, getParagraphs()); + } +} + +DECLARE_FILE_MAILMERGE_TEST(testEmptyValuesLegacyFODT, "tdf35798-legacy.fodt", "5-with-blanks.ods", + "names") +{ + executeMailMerge(); + for (int doc = 0; doc < 5; ++doc) + { + loadMailMergeDocument(doc); + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT(pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + pDoc->RemoveInvisibleContent(); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + for (int i = 0; i < 8; ++i) + { + auto xPara = getParagraph(i + 1); + SAL_WARN("sw.qa", "Testing doc " + OUString::number(doc) + " paragraph " + + OUString::number(i + 1)); + CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(EmptyValuesLegacyData[doc][i]), + xPara->getString()); + } + CPPUNIT_ASSERT_EQUAL(8, getParagraphs()); + } +} + +DECLARE_FILE_MAILMERGE_TEST(testEmptyValuesNewFODT, "tdf35798-new.fodt", "5-with-blanks.ods", + "names") +{ + executeMailMerge(); + for (int doc = 0; doc < 5; ++doc) + { + loadMailMergeDocument(doc); + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT(pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + pDoc->RemoveInvisibleContent(); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + int i; + for (i = 0; i < 8; ++i) + { + const char* pExpected = EmptyValuesNewData[doc][i]; + if (!pExpected) + break; + auto xPara = getParagraph(i + 1); + SAL_WARN("sw.qa", "Testing doc " + OUString::number(doc) + " paragraph " + + OUString::number(i + 1)); + CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(pExpected), xPara->getString()); + } + CPPUNIT_ASSERT_EQUAL(i, getParagraphs()); + } +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/doc/DocumentSettingManager.cxx b/sw/source/core/doc/DocumentSettingManager.cxx index 77de92017537..c900a985dee2 100644 --- a/sw/source/core/doc/DocumentSettingManager.cxx +++ b/sw/source/core/doc/DocumentSettingManager.cxx @@ -114,6 +114,8 @@ sw::DocumentSettingManager::DocumentSettingManager(SwDoc &rDoc) mbProtectForm = aOptions.GetDefault( SvtCompatibilityEntry::Index::ProtectForm ); mbMsWordCompTrailingBlanks = aOptions.GetDefault( SvtCompatibilityEntry::Index::MsWordTrailingBlanks ); mbSubtractFlys = aOptions.GetDefault( SvtCompatibilityEntry::Index::SubtractFlysAnchoredAtFlys ); + mbEmptyDbFieldHidesPara + = aOptions.GetDefault(SvtCompatibilityEntry::Index::EmptyDbFieldHidesPara); } else { @@ -131,6 +133,7 @@ sw::DocumentSettingManager::DocumentSettingManager(SwDoc &rDoc) mbProtectForm = false; mbMsWordCompTrailingBlanks = false; mbSubtractFlys = false; + mbEmptyDbFieldHidesPara = true; } // COMPATIBILITY FLAGS END @@ -204,6 +207,7 @@ bool sw::DocumentSettingManager::get(/*[in]*/ DocumentSettingId id) const case DocumentSettingId::EMBED_SYSTEM_FONTS: return mEmbedSystemFonts; case DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING: return mApplyParagraphMarkFormatToNumbering; case DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING: return mbDisableOffPagePositioning; + case DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA: return mbEmptyDbFieldHidesPara; default: OSL_FAIL("Invalid setting id"); } @@ -421,6 +425,9 @@ void sw::DocumentSettingManager::set(/*[in]*/ DocumentSettingId id, /*[in]*/ boo case DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING: mbDisableOffPagePositioning = value; break; + case DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA: + mbEmptyDbFieldHidesPara = value; + break; default: OSL_FAIL("Invalid setting id"); } @@ -562,6 +569,7 @@ void sw::DocumentSettingManager::ReplaceCompatibilityOptions(const DocumentSetti mbTabRelativeToIndent = rSource.mbTabRelativeToIndent; mbTabAtLeftIndentForParagraphsInList = rSource.mbTabAtLeftIndentForParagraphsInList; mbMsWordCompTrailingBlanks = rSource.mbMsWordCompTrailingBlanks; + mbEmptyDbFieldHidesPara = rSource.mbEmptyDbFieldHidesPara; } sal_uInt32 sw::DocumentSettingManager::Getn32DummyCompatibilityOptions1() const diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx index 9f4a08b7bd42..5fbd8f84271d 100644 --- a/sw/source/core/doc/doc.cxx +++ b/sw/source/core/doc/doc.cxx @@ -1318,6 +1318,73 @@ void SwDoc::Summary( SwDoc* pExtDoc, sal_uInt8 nLevel, sal_uInt8 nPara, bool bIm } } +namespace +{ +void RemoveOrDeleteContents(SwTextNode* pTextNd, IDocumentContentOperations& xOperations) +{ + SwPaM aPam(*pTextNd, 0, *pTextNd, pTextNd->GetText().getLength()); + + // Remove hidden paragraph or delete contents: + // Delete contents if + // 1. removing the paragraph would result in an empty section or + // 2. if the paragraph is the last paragraph in the section and + // there is no paragraph in front of the paragraph: + if ((2 == pTextNd->EndOfSectionIndex() - pTextNd->StartOfSectionIndex()) + || (1 == pTextNd->EndOfSectionIndex() - pTextNd->GetIndex() + && !pTextNd->GetNodes()[pTextNd->GetIndex() - 1]->GetTextNode())) + { + xOperations.DeleteRange(aPam); + } + else + { + aPam.DeleteMark(); + xOperations.DelFullPara(aPam); + } +} +// Returns if the data was actually modified +bool HandleHidingField(SwFormatField& rFormatField, const SwNodes& rNodes, + IDocumentContentOperations& xOperations) +{ + SwTextNode* pTextNd; + if (rFormatField.GetTextField() + && nullptr != (pTextNd = rFormatField.GetTextField()->GetpTextNode()) + && pTextNd->GetpSwpHints() && pTextNd->IsHiddenByParaField() + && &pTextNd->GetNodes() == &rNodes) + { + RemoveOrDeleteContents(pTextNd, xOperations); + return true; + } + return false; +} +} + +bool SwDoc::FieldCanHidePara(SwFieldIds eFieldId) const +{ + switch (eFieldId) + { + case SwFieldIds::HiddenPara: + return true; + case SwFieldIds::Database: + return GetDocumentSettingManager().get( + DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA); + default: + return false; + } +} + +bool SwDoc::FieldHidesPara(const SwField& rField) const +{ + switch (rField.GetTyp()->Which()) + { + case SwFieldIds::HiddenPara: + return static_cast(rField).IsHidden(); + case SwFieldIds::Database: + return FieldCanHidePara(SwFieldIds::Database) && rField.ExpandField(true).isEmpty(); + default: + return false; + } +} + /// Remove the invisible content from the document e.g. hidden areas, hidden paragraphs bool SwDoc::RemoveInvisibleContent() { @@ -1325,35 +1392,22 @@ bool SwDoc::RemoveInvisibleContent() GetIDocumentUndoRedo().StartUndo( SwUndoId::UI_DELETE_INVISIBLECNTNT, nullptr ); { - SwTextNode* pTextNd; - SwIterator aIter( *getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::HiddenPara ) ); - for( SwFormatField* pFormatField = aIter.First(); pFormatField; pFormatField = aIter.Next() ) + // Removing some nodes for one SwFieldIds::Database type might remove the type from + // document's field types, invalidating iterators. So, we need to create own list of + // matching types prior to processing them. + std::vector aHidingFieldTypes; + for (const auto* pType : *getIDocumentFieldsAccess().GetFieldTypes()) { - if( pFormatField->GetTextField() && - nullptr != ( pTextNd = pFormatField->GetTextField()->GetpTextNode() ) && - pTextNd->GetpSwpHints() && pTextNd->HasHiddenParaField() && - &pTextNd->GetNodes() == &GetNodes() ) - { - bRet = true; - SwPaM aPam(*pTextNd, 0, *pTextNd, pTextNd->GetText().getLength()); - - // Remove hidden paragraph or delete contents: - // Delete contents if - // 1. removing the paragraph would result in an empty section or - // 2. if the paragraph is the last paragraph in the section and - // there is no paragraph in front of the paragraph: - if ( ( 2 == pTextNd->EndOfSectionIndex() - pTextNd->StartOfSectionIndex() ) || - ( 1 == pTextNd->EndOfSectionIndex() - pTextNd->GetIndex() && - !GetNodes()[ pTextNd->GetIndex() - 1 ]->GetTextNode() ) ) - { - getIDocumentContentOperations().DeleteRange( aPam ); - } - else - { - aPam.DeleteMark(); - getIDocumentContentOperations().DelFullPara( aPam ); - } - } + if (FieldCanHidePara(pType->Which())) + aHidingFieldTypes.push_back(pType); + } + for (const auto* pType : aHidingFieldTypes) + { + SwIterator aIter(*pType); + for (SwFormatField* pFormatField = aIter.First(); pFormatField; + pFormatField = aIter.Next()) + bRet |= HandleHidingField(*pFormatField, GetNodes(), + getIDocumentContentOperations()); } } @@ -1369,23 +1423,7 @@ bool SwDoc::RemoveInvisibleContent() { bRemoved = true; bRet = true; - - // Remove hidden paragraph or delete contents: - // Delete contents if - // 1. removing the paragraph would result in an empty section or - // 2. if the paragraph is the last paragraph in the section and - // there is no paragraph in front of the paragraph: - if ( ( 2 == pTextNd->EndOfSectionIndex() - pTextNd->StartOfSectionIndex() ) || - ( 1 == pTextNd->EndOfSectionIndex() - pTextNd->GetIndex() && - !GetNodes()[ pTextNd->GetIndex() - 1 ]->GetTextNode() ) ) - { - getIDocumentContentOperations().DeleteRange( aPam ); - } - else - { - aPam.DeleteMark(); - getIDocumentContentOperations().DelFullPara( aPam ); - } + RemoveOrDeleteContents(pTextNd, getIDocumentContentOperations()); } else if ( pTextNd->HasHiddenCharAttribute( false ) ) { diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx index 34cdce1fee6c..4d7741fdb402 100644 --- a/sw/source/core/doc/doctxm.cxx +++ b/sw/source/core/doc/doctxm.cxx @@ -1152,7 +1152,7 @@ void SwTOXBaseSection::UpdateMarks( const SwTOXInternational& rIntl, pTOXSrc->GetText().getLength() && pTOXSrc->HasWriterListeners() && pTOXSrc->getLayoutFrame( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() ) && (!IsFromChapter() || ::lcl_FindChapterNode( *pTOXSrc ) == pOwnChapterNode ) && - !pTOXSrc->HasHiddenParaField() && + !pTOXSrc->IsHiddenByParaField() && !SwScriptInfo::IsInHiddenRange( *pTOXSrc, pTextMark->GetStart() ) ) { SwTOXSortTabBase* pBase = nullptr; @@ -1205,7 +1205,7 @@ void SwTOXBaseSection::UpdateOutline( const SwTextNode* pOwnChapterNode ) if( pTextNd && pTextNd->Len() && pTextNd->HasWriterListeners() && sal_uInt16( pTextNd->GetAttrOutlineLevel()) <= GetLevel() && pTextNd->getLayoutFrame( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() ) && - !pTextNd->HasHiddenParaField() && + !pTextNd->IsHiddenByParaField() && !pTextNd->HasHiddenCharAttribute( true ) && ( !IsFromChapter() || ::lcl_FindChapterNode( *pTextNd ) == pOwnChapterNode )) diff --git a/sw/source/core/inc/DocumentSettingManager.hxx b/sw/source/core/inc/DocumentSettingManager.hxx index 5f762d099ca8..1cf9a9d9fea9 100644 --- a/sw/source/core/inc/DocumentSettingManager.hxx +++ b/sw/source/core/inc/DocumentSettingManager.hxx @@ -155,6 +155,7 @@ class DocumentSettingManager : bool mbLastBrowseMode : 1; bool mbDisableOffPagePositioning; // tdf#112443 + bool mbEmptyDbFieldHidesPara; public: diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx index c1e953725fc8..227f802e6135 100644 --- a/sw/source/core/text/txtfrm.cxx +++ b/sw/source/core/text/txtfrm.cxx @@ -459,12 +459,11 @@ bool SwTextFrame::IsHiddenNow() const return true; } - const bool bHiddenCharsHidePara = GetTextNode()->HasHiddenCharAttribute( true ); - const bool bHiddenParaField = GetTextNode()->HasHiddenParaField(); - const SwViewShell* pVsh = getRootFrame()->GetCurrShell(); - - if ( pVsh && ( bHiddenCharsHidePara || bHiddenParaField ) ) + if ( const SwViewShell* pVsh = getRootFrame()->GetCurrShell() ) { + const bool bHiddenCharsHidePara = GetTextNode()->HasHiddenCharAttribute(true); + const bool bHiddenParaField = GetTextNode()->IsHiddenByParaField(); + if ( ( bHiddenParaField && ( !pVsh->GetViewOptions()->IsShowHiddenPara() && diff --git a/sw/source/core/txtnode/atrfld.cxx b/sw/source/core/txtnode/atrfld.cxx index 36c39618074a..8ebffec8b24c 100644 --- a/sw/source/core/txtnode/atrfld.cxx +++ b/sw/source/core/txtnode/atrfld.cxx @@ -380,18 +380,26 @@ void SwTextField::ExpandTextField(const bool bForceNotify) const const SwField* pField = GetFormatField().GetField(); const OUString aNewExpand( pField->ExpandField(m_pTextNode->GetDoc()->IsClipBoard()) ); + const SwFieldIds nWhich = pField->GetTyp()->Which(); + const bool bSameExpandSimpleNotification + = SwFieldIds::Chapter != nWhich && SwFieldIds::PageNumber != nWhich + && SwFieldIds::RefPageGet != nWhich + // Page count fields to not use aExpand during formatting, + // therefore an invalidation of the text frame has to be triggered even if aNewExpand == aExpand: + && (SwFieldIds::DocStat != nWhich + || DS_PAGE != static_cast(pField)->GetSubType()) + && (SwFieldIds::GetExp != nWhich + || static_cast(pField)->IsInBodyText()); + + bool bHiddenParaChanged = false; + if (aNewExpand != m_aExpand || bSameExpandSimpleNotification) + bHiddenParaChanged = m_pTextNode->CalcHiddenParaField(); + if (aNewExpand == m_aExpand) { - const SwFieldIds nWhich = pField->GetTyp()->Which(); - if ( SwFieldIds::Chapter != nWhich - && SwFieldIds::PageNumber != nWhich - && SwFieldIds::RefPageGet != nWhich - // Page count fields to not use aExpand during formatting, - // therefore an invalidation of the text frame has to be triggered even if aNewExpand == aExpand: - && ( SwFieldIds::DocStat != nWhich || DS_PAGE != static_cast(pField)->GetSubType() ) - && ( SwFieldIds::GetExp != nWhich || static_cast(pField)->IsInBodyText() ) ) + if ( bSameExpandSimpleNotification ) { - if( m_pTextNode->CalcHiddenParaField() ) + if( bHiddenParaChanged ) { m_pTextNode->ModifyNotification( nullptr, nullptr ); } diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index 389e2320c613..98ababf17492 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -4111,7 +4111,7 @@ void SwTextNode::CalcHiddenCharFlags() const // #i12836# enhanced pdf export bool SwTextNode::IsHidden() const { - if ( HasHiddenParaField() || HasHiddenCharAttribute( true ) ) + if ( IsHiddenByParaField() || HasHiddenCharAttribute( true ) ) return true; const SwSectionNode* pSectNd = FindSectionNode(); diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx index 2db0657c3fe1..32bb7841f9cd 100644 --- a/sw/source/core/txtnode/thints.cxx +++ b/sw/source/core/txtnode/thints.cxx @@ -19,6 +19,7 @@ #include +#include #include #include #include @@ -89,11 +90,12 @@ using namespace ::com::sun::star::i18n; -SwpHints::SwpHints() - : m_pHistory(nullptr) +SwpHints::SwpHints(const SwTextNode& rParent) + : m_rParent(rParent) + , m_pHistory(nullptr) , m_bInSplitNode(false) , m_bCalcHiddenParaField(false) - , m_bHasHiddenParaField(false) + , m_bHiddenByParaField(false) , m_bFootnote(false) , m_bDDEFields(false) { @@ -1144,19 +1146,21 @@ void SwTextNode::DestroyAttr( SwTextAttr* pAttr ) if( !pDoc->IsInDtor() ) { SwTextField *const pTextField(static_txtattr_cast(pAttr)); - const SwField* pField = pAttr->GetFormatField().GetField(); + SwFieldType* pFieldType = pAttr->GetFormatField().GetField()->GetTyp(); //JP 06-08-95: DDE-fields are an exception - assert(SwFieldIds::Dde == pField->GetTyp()->Which() || + assert(SwFieldIds::Dde == pFieldType->Which() || this == pTextField->GetpTextNode()); // certain fields must update the SwDoc's calculation flags - switch( pField->GetTyp()->Which() ) + + // Certain fields (like HiddenParaField) must trigger recalculation of visible flag + if (FieldCanHidePara(pFieldType->Which())) + SetCalcHiddenParaField(); + + switch( pFieldType->Which() ) { case SwFieldIds::HiddenPara: - // HiddenParaField must trigger recalculation of visible flag - SetCalcHiddenParaField(); - SAL_FALLTHROUGH; case SwFieldIds::DbSetNumber: case SwFieldIds::GetExp: case SwFieldIds::Database: @@ -1169,7 +1173,7 @@ void SwTextNode::DestroyAttr( SwTextAttr* pAttr ) break; case SwFieldIds::Dde: if (GetNodes().IsDocNodes() && pTextField->GetpTextNode()) - static_cast(pField->GetTyp())->DecRefCnt(); + static_cast(pFieldType)->DecRefCnt(); break; case SwFieldIds::Postit: { @@ -1460,8 +1464,8 @@ bool SwTextNode::InsertHint( SwTextAttr * const pAttr, const SetAttrMode nMode ) case RES_TXTATR_FIELD: { - // trigger notification for HiddenParaFields - if( SwFieldIds::HiddenPara == pAttr->GetFormatField().GetField()->GetTyp()->Which() ) + // trigger notification for relevant fields, like HiddenParaFields + if (FieldCanHidePara(pAttr->GetFormatField().GetField()->GetTyp()->Which())) { bHiddenPara = true; } @@ -2581,38 +2585,32 @@ void SwpHints::CalcFlags() } } -bool SwpHints::CalcHiddenParaField() +bool SwpHints::CalcHiddenParaField() const { m_bCalcHiddenParaField = false; - bool bOldHasHiddenParaField = m_bHasHiddenParaField; - bool bNewHasHiddenParaField = false; + const bool bOldHiddenByParaField = m_bHiddenByParaField; + bool bNewHiddenByParaField = false; const size_t nSize = Count(); - const SwTextAttr *pTextHt; + const SwTextAttr* pTextHt; - for( size_t nPos = 0; nPos < nSize; ++nPos ) + for (size_t nPos = 0; nPos < nSize; ++nPos) { pTextHt = Get(nPos); const sal_uInt16 nWhich = pTextHt->Which(); - if( RES_TXTATR_FIELD == nWhich ) + if (RES_TXTATR_FIELD == nWhich) { const SwFormatField& rField = pTextHt->GetFormatField(); - if( SwFieldIds::HiddenPara == rField.GetField()->GetTyp()->Which() ) + if (m_rParent.FieldCanHidePara(rField.GetField()->GetTyp()->Which()) + && !(bNewHiddenByParaField = m_rParent.FieldHidesPara(*rField.GetField()))) { - if( !static_cast(rField.GetField())->IsHidden() ) - { - SetHiddenParaField(false); - return bOldHasHiddenParaField != bNewHasHiddenParaField; - } - else - { - bNewHasHiddenParaField = true; - } + // If there's at least one field telling not to hide, so be it + break; } } } - SetHiddenParaField( bNewHasHiddenParaField ); - return bOldHasHiddenParaField != bNewHasHiddenParaField; + SetHiddenByParaField(bNewHiddenByParaField); + return bOldHiddenByParaField != bNewHiddenByParaField; } void SwpHints::NoteInHistory( SwTextAttr *pAttr, const bool bNew ) @@ -3280,7 +3278,8 @@ void SwpHints::DeleteAtPos( const size_t nPos ) if( pHint->Which() == RES_TXTATR_FIELD ) { SwTextField *const pTextField(static_txtattr_cast(pHint)); - const SwFieldType* pFieldTyp = pTextField->GetFormatField().GetField()->GetTyp(); + const SwField* pField = pTextField->GetFormatField().GetField(); + const SwFieldType* pFieldTyp = pField->GetTyp(); if( SwFieldIds::Dde == pFieldTyp->Which() ) { const SwTextNode* pNd = pTextField->GetpTextNode(); @@ -3288,8 +3287,8 @@ void SwpHints::DeleteAtPos( const size_t nPos ) const_cast(static_cast(pFieldTyp))->DecRefCnt(); pTextField->ChgTextNode(nullptr); } - else if ( m_bHasHiddenParaField && - SwFieldIds::HiddenPara == pFieldTyp->Which() ) + else if (m_bHiddenByParaField + && m_rParent.FieldCanHidePara(pField->GetTyp()->Which())) { m_bCalcHiddenParaField = true; } diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx index 609afdfa7170..76435e704cd9 100644 --- a/sw/source/core/view/viewsh.cxx +++ b/sw/source/core/view/viewsh.cxx @@ -924,6 +924,26 @@ void SwViewShell::SetSubtractFlysAnchoredAtFlys(bool bSubtractFlysAnchoredAtFlys rIDSA.set(DocumentSettingId::SUBTRACT_FLYS, bSubtractFlysAnchoredAtFlys); } +void SwViewShell::SetEmptyDbFieldHidesPara(bool bEmptyDbFieldHidesPara) +{ + IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess(); + if (rIDSA.get(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA) != bEmptyDbFieldHidesPara) + { + SwWait aWait(*GetDoc()->GetDocShell(), true); + rIDSA.set(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA, bEmptyDbFieldHidesPara); + StartAction(); + GetDoc()->getIDocumentState().SetModified(); + for (auto* pFieldType : *GetDoc()->getIDocumentFieldsAccess().GetFieldTypes()) + { + if (pFieldType->Which() == SwFieldIds::Database) + { + pFieldType->ModifyNotification(nullptr, nullptr); + } + } + EndAction(); + } +} + void SwViewShell::Reformat() { SwWait aWait( *GetDoc()->GetDocShell(), true ); diff --git a/sw/source/filter/xml/xmlimp.cxx b/sw/source/filter/xml/xmlimp.cxx index c7e33d926357..e88f90e2c621 100644 --- a/sw/source/filter/xml/xmlimp.cxx +++ b/sw/source/filter/xml/xmlimp.cxx @@ -588,6 +588,32 @@ void SwXMLImport::startDocument() m_bOrganizerMode = true; } } + + // default document properties + const OUString sDefSettings("DefaultDocumentSettings"); + if (xPropertySetInfo->hasPropertyByName(sDefSettings)) + { + aAny = xImportInfo->getPropertyValue(sDefSettings); + Sequence aProps; + if (aAny >>= aProps) + { + Reference xFac(GetModel(), UNO_QUERY); + Reference xProps( + xFac->createInstance("com.sun.star.document.Settings"), UNO_QUERY); + Reference xInfo(xProps->getPropertySetInfo()); + + if (xProps.is() && xInfo.is()) + { + for (const auto& rProp : aProps) + { + if (xInfo->hasPropertyByName(rProp.Name)) + { + xProps->setPropertyValue(rProp.Name, rProp.Value); + } + } + } + } + } } // There only is a text cursor by now if we are in insert mode. In any diff --git a/sw/source/ui/config/optcomp.cxx b/sw/source/ui/config/optcomp.cxx index 0a7a423f484b..c7ef44e4ff39 100644 --- a/sw/source/ui/config/optcomp.cxx +++ b/sw/source/ui/config/optcomp.cxx @@ -113,7 +113,8 @@ sal_uLong convertBools2Ulong_Impl bool _bExpandWordSpace, bool _bProtectForm, bool _bMsWordCompTrailingBlanks, - bool bSubtractFlysAnchoredAtFlys + bool bSubtractFlysAnchoredAtFlys, + bool bEmptyDbFieldHidesPara ) { sal_uLong nRet = 0; @@ -160,6 +161,9 @@ sal_uLong convertBools2Ulong_Impl nSetBit = nSetBit << 1; if (bSubtractFlysAnchoredAtFlys) nRet |= nSetBit; + nSetBit = nSetBit << 1; + if (bEmptyDbFieldHidesPara) + nRet |= nSetBit; return nRet; } @@ -244,7 +248,8 @@ void SwCompatibilityOptPage::InitControls( const SfxItemSet& rSet ) aEntry.getValue( SvtCompatibilityEntry::Index::ExpandWordSpace ), aEntry.getValue( SvtCompatibilityEntry::Index::ProtectForm ), aEntry.getValue( SvtCompatibilityEntry::Index::MsWordTrailingBlanks ), - aEntry.getValue( SvtCompatibilityEntry::Index::SubtractFlysAnchoredAtFlys ) ); + aEntry.getValue( SvtCompatibilityEntry::Index::SubtractFlysAnchoredAtFlys ), + aEntry.getValue( SvtCompatibilityEntry::Index::EmptyDbFieldHidesPara ) ); m_pFormattingLB->SetEntryData( nPos, reinterpret_cast(static_cast(nOptions)) ); } @@ -317,7 +322,8 @@ sal_uLong SwCompatibilityOptPage::GetDocumentOptions() const !rIDocumentSettingAccess.get( DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK ), rIDocumentSettingAccess.get( DocumentSettingId::PROTECT_FORM ), rIDocumentSettingAccess.get( DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS ), - rIDocumentSettingAccess.get( DocumentSettingId::SUBTRACT_FLYS ) ); + rIDocumentSettingAccess.get( DocumentSettingId::SUBTRACT_FLYS ), + rIDocumentSettingAccess.get( DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA ) ); } return nRet; } @@ -409,6 +415,10 @@ bool SwCompatibilityOptPage::FillItemSet( SfxItemSet* ) m_pWrtShell->SetSubtractFlysAnchoredAtFlys(bChecked); break; + case SvtCompatibilityEntry::Index::EmptyDbFieldHidesPara: + m_pWrtShell->SetEmptyDbFieldHidesPara(bChecked); + break; + default: break; } diff --git a/sw/source/uibase/app/docshini.cxx b/sw/source/uibase/app/docshini.cxx index 1435276ff9cd..cb9241609f77 100644 --- a/sw/source/uibase/app/docshini.cxx +++ b/sw/source/uibase/app/docshini.cxx @@ -88,6 +88,7 @@ #include #include #include +#include #include @@ -483,14 +484,6 @@ bool SwDocShell::Load( SfxMedium& rMedium ) { bool bRet = false; - // If this is an ODF file being loaded, then by default, use legacy processing - // for tdf#99729 (if required, it will be overridden in *::ReadUserDataSequence()) - if (IsOwnStorageFormat(rMedium)) - { - if (m_xDoc.get() && m_xDoc->getIDocumentDrawModelAccess().GetDrawModel()) - m_xDoc->getIDocumentDrawModelAccess().GetDrawModel()->SetAnchoredTextOverflowLegacy(true); - } - if (SfxObjectShell::Load(rMedium)) { comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = getEmbeddedObjectContainer(); @@ -502,6 +495,19 @@ bool SwDocShell::Load( SfxMedium& rMedium ) AddLink(); // set Link and update Data!! + // Define some settings for legacy ODF files that have different default values now + // (if required, they will be overridden later when settings will be read) + if (IsOwnStorageFormat(rMedium)) + { + // legacy processing for tdf#99729 + if (m_xDoc->getIDocumentDrawModelAccess().GetDrawModel()) + m_xDoc->getIDocumentDrawModelAccess().GetDrawModel()->SetAnchoredTextOverflowLegacy( + true); + // legacy behaviour (not hiding paragraph) for Database (MailMerge) fields + m_xDoc->GetDocumentSettingManager().set(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA, + false); + } + // Loading // for MD OSL_ENSURE( !m_xBasePool.is(), "who hasn't destroyed their Pool?" ); diff --git a/sw/source/uibase/uno/SwXDocumentSettings.cxx b/sw/source/uibase/uno/SwXDocumentSettings.cxx index f665bfefc0b0..281bee24a542 100644 --- a/sw/source/uibase/uno/SwXDocumentSettings.cxx +++ b/sw/source/uibase/uno/SwXDocumentSettings.cxx @@ -136,6 +136,7 @@ enum SwDocumentSettingsPropertyHandles HANDLE_PROP_LINE_SPACING_SHRINKS_FIRST_LINE, HANDLE_SUBTRACT_FLYS, HANDLE_DISABLE_OFF_PAGE_POSITIONING, + HANDLE_EMPTY_DB_FIELD_HIDES_PARA, }; static MasterPropertySetInfo * lcl_createSettingsInfo() @@ -214,6 +215,7 @@ static MasterPropertySetInfo * lcl_createSettingsInfo() { OUString("PropLineSpacingShrinksFirstLine"), HANDLE_PROP_LINE_SPACING_SHRINKS_FIRST_LINE, cppu::UnoType::get(), 0}, { OUString("SubtractFlysAnchoredAtFlys"), HANDLE_SUBTRACT_FLYS, cppu::UnoType::get(), 0}, { OUString("DisableOffPagePositioning"), HANDLE_DISABLE_OFF_PAGE_POSITIONING, cppu::UnoType::get(), 0}, + { OUString("EmptyDbFieldHidesPara"), HANDLE_EMPTY_DB_FIELD_HIDES_PARA, cppu::UnoType::get(), 0 }, /* * As OS said, we don't have a view when we need to set this, so I have to * find another solution before adding them to this property set - MTG @@ -878,6 +880,16 @@ void SwXDocumentSettings::_setSingleValue( const comphelper::PropertyInfo & rInf } } break; + case HANDLE_EMPTY_DB_FIELD_HIDES_PARA: + { + bool bTmp; + if (rValue >>= bTmp) + { + mpDoc->getIDocumentSettingAccess().set(DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA, + bTmp); + } + } + break; default: throw UnknownPropertyException(); } @@ -1304,6 +1316,12 @@ void SwXDocumentSettings::_getSingleValue( const comphelper::PropertyInfo & rInf rValue <<= mpDoc->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING); } break; + case HANDLE_EMPTY_DB_FIELD_HIDES_PARA: + { + rValue <<= mpDoc->getIDocumentSettingAccess().get( + DocumentSettingId::EMPTY_DB_FIELD_HIDES_PARA); + } + break; default: throw UnknownPropertyException(); } diff --git a/sw/uiconfig/swriter/ui/optcompatpage.ui b/sw/uiconfig/swriter/ui/optcompatpage.ui index 93478630ca3b..40b7c3ed8add 100644 --- a/sw/uiconfig/swriter/ui/optcompatpage.ui +++ b/sw/uiconfig/swriter/ui/optcompatpage.ui @@ -67,6 +67,7 @@ Protect form MS Word-compatible trailing blanks Tolerate white lines of PDF page backgrounds for compatibility with old documents + A database field (e.g., MailMerge) with empty value hides its paragraph <User settings> -- cgit v1.2.3