tdf#88214 sw: text formatting: adapt empty line at end of para to Word

For an empty line at the end of an empty paragraph, Writer already uses
any existing text attribute in the paragraph, see for example
testEmptyTrailingSpans.

For an empty line at the end of a non-empty paragraph, Writer text
formatting uses only paragraph attributes, ignoring any text attributes,
whereas the UI will display the attributes from the text attributes
(such as font height) if you move the cursor there.

Word uses text attributes also in this case, so adapt the inconsistent
Writer behaviour: text formatting now uses text attributes too.

Apparently this can be achieved by calling SeekAndChgBefore() instead of
SeekAndChg().

Add another compat flag "ApplyTextAttrToEmptyLineAtEndOfParagraph" to
preserve the formatting of existing ODF documents.

Adapt test document fdo74110.docx, it has a line break with "Angsana
New" font.

Change-Id: I0863d3077e419404194b47110e4ad2bdda3d11c4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165887
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
This commit is contained in:
Michael Stahl 2024-04-08 15:26:00 +02:00
parent b523a72fd0
commit 2b47fae7e3
11 changed files with 98 additions and 3 deletions

View File

@ -98,6 +98,7 @@ enum class DocumentSettingId
ALLOW_TEXT_AFTER_FLOATING_TABLE_BREAK,
// tdf#119908 new paragraph justification
JUSTIFY_LINES_WITH_SHRINKING,
APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH,
// COMPATIBILITY FLAGS END
BROWSE_MODE,
HTML_MODE,

View File

@ -0,0 +1,27 @@
{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch0\stshfloch31506\stshfhich31506\stshfbi31506\deflang3079\deflangfe3079\themelang3079\themelangfe0\themelangcs0
{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2Times New Roman{\*\falt Arial};}
}
{\*\defchp \f0\fs22\lang3079\langfe1033\langfenp1033 }
{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1
\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }
\noqfpromote
{\stylesheet
{\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0
\f0\fs23\lang3079\langfe1033\cgrid\langnp3079\langfenp1033 \snext0 \sqformat \spriority0 Normal;}
{\s15\ql \li0\ri0\widctlpar\tqc\tx4536\tqr\tx9072\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \f0\fs23\lang3079\langfe1033\cgrid\langnp3079\langfenp1033
\sbasedon0 \snext15 \slink16 \sunhideused header;}
{\*\cs16 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \sbasedon10 \slink15 \slocked Kopfzeile Zchn;}
}
\paperw11906\paperh16838\margl1417\margr1417\margt1417\margb1134\gutter0\ltrsect
\deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0
\showxmlerrors1\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1417\dgvorigin1417\dghshow1\dgvshow1
\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct
\asianbrkrule\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0
{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0
\ltrpar \pard\plain \ltrpar\s15\qc \li0\ri0\widctlpar
\tqc\tx4536\tqr\tx9072\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \f0\fs23\lang3079\langfe1033\cgrid\langnp3079\langfenp1033 {\rtlch\fcs1 \af0\afs16 \ltrch\fcs0
\fs16 \line \line \line
\par \line
\par }
}

View File

@ -88,6 +88,24 @@ CPPUNIT_TEST_FIXTURE(Test, testFloattableLegacyWrapEmptyParagraph)
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs2.size());
}
CPPUNIT_TEST_FIXTURE(Test, testApplyTextAttrToEmptyLineAtEndOfParagraph)
{
createSwDoc("A011-charheight.rtf");
calcLayout();
SwDoc* pDoc = getSwDoc();
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
SwContentFrame* pLastPara = pPage->FindLastBodyContent();
// wrong was 449 (11.5pt)
CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(368), pLastPara->getFrameArea().Height());
SwContentFrame* pFirstPara = pPage->FindFirstBodyContent();
// wrong was 817 (11.5pt)
CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(736), pFirstPara->getFrameArea().Height());
}
CPPUNIT_TEST_FIXTURE(Test, testFlyMinimalWrap)
{
// Given a document with a first page that has a shape and a table in it (not floating table),

View File

@ -249,6 +249,8 @@ bool sw::DocumentSettingManager::get(/*[in]*/ DocumentSettingId id) const
case DocumentSettingId::AUTO_FIRST_LINE_INDENT_DISREGARD_LINE_SPACE:
return mbAutoFirstLineIndentDisregardLineSpace;
case DocumentSettingId::HYPHENATE_URLS: return mbHyphenateURLs;
case DocumentSettingId::APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH:
return mbApplyTextAttrToEmptyLineAtEndOfParagraph;
case DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES:
return mbDoNotBreakWrappedTables;
case DocumentSettingId::ALLOW_TEXT_AFTER_FLOATING_TABLE_BREAK:
@ -443,6 +445,10 @@ void sw::DocumentSettingManager::set(/*[in]*/ DocumentSettingId id, /*[in]*/ boo
mbHyphenateURLs = value;
break;
case DocumentSettingId::APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH:
mbApplyTextAttrToEmptyLineAtEndOfParagraph = value;
break;
case DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES:
mbDoNotBreakWrappedTables = value;
break;
@ -1091,6 +1097,11 @@ void sw::DocumentSettingManager::dumpAsXml(xmlTextWriterPtr pWriter) const
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"),
BAD_CAST(OString::number(mnImagePreferredDPI).getStr()));
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("mbApplyTextAttrToEmptyLineAtEndOfParagraph"));
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"),
BAD_CAST(OString::boolean(mbApplyTextAttrToEmptyLineAtEndOfParagraph).getStr()));
(void)xmlTextWriterEndElement(pWriter);
(void)xmlTextWriterEndElement(pWriter);
(void)xmlTextWriterEndElement(pWriter);

View File

@ -178,6 +178,7 @@ class DocumentSettingManager final :
bool mbDoNotBreakWrappedTables = false;
bool mbAllowTextAfterFloatingTableBreak = false;
bool mbJustifyLinesWithShrinking = false;
bool mbApplyTextAttrToEmptyLineAtEndOfParagraph = true;
// If this is on as_char flys wrapping will be handled the same like in Word
bool mbNoNumberingShowFollowBy;
bool mbDropCapPunctuation; // tdf#150200, tdf#150438

View File

@ -852,6 +852,7 @@ void SwTextFormatter::CalcAscent( SwTextFormatInfo &rInf, SwLinePortion *pPor )
// In empty lines the attributes are switched on via SeekStart
const bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
if ( pPor->IsQuoVadisPortion() )
bChg = SeekStartAndChg( rInf, true );
else
@ -860,10 +861,16 @@ void SwTextFormatter::CalcAscent( SwTextFormatInfo &rInf, SwLinePortion *pPor )
{
if( !rInf.GetText().isEmpty() )
{
if ( pPor->GetLen() || !rInf.GetIdx()
|| ( m_pCurr != pLast && !pLast->IsFlyPortion() )
|| !m_pCurr->IsRest() ) // instead of !rInf.GetRest()
if ((rInf.GetIdx() != TextFrameIndex(rInf.GetText().getLength())
|| rInf.GetRest() // field continued - not empty
|| !GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
DocumentSettingId::APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH))
&& (pPor->GetLen() || !rInf.GetIdx()
|| (m_pCurr != pLast && !pLast->IsFlyPortion())
|| !m_pCurr->IsRest())) // instead of !rInf.GetRest()
{
bChg = SeekAndChg( rInf );
}
else
bChg = SeekAndChgBefore( rInf );
}

View File

@ -1945,6 +1945,7 @@ void SwWW8ImplReader::ImportDop()
m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE, true);
m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
// rely on default for HYPHENATE_URLS=false
// rely on default for APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH=true
IDocumentSettingAccess& rIDSA = m_rDoc.getIDocumentSettingAccess();
if (m_xWDop->fDontBreakWrappedTables)

View File

@ -1298,6 +1298,7 @@ void SwXMLImport::SetConfigurationSettings(const Sequence < PropertyValue > & aC
bool bCollapseEmptyCellPara = false;
bool bAutoFirstLineIndentDisregardLineSpace = false;
bool bHyphenateURLs = false;
bool bApplyTextAttrToEmptyLineAtEndOfParagraph = false;
bool bDoNotBreakWrappedTables = false;
bool bAllowTextAfterFloatingTableBreak = false;
bool bDropCapPunctuation = false;
@ -1398,6 +1399,10 @@ void SwXMLImport::SetConfigurationSettings(const Sequence < PropertyValue > & aC
{
bHyphenateURLs = true;
}
else if (rValue.Name == "ApplyTextAttrToEmptyLineAtEndOfParagraph")
{
bApplyTextAttrToEmptyLineAtEndOfParagraph = true;
}
else if (rValue.Name == "DoNotBreakWrappedTables")
{
rValue.Value >>= bDoNotBreakWrappedTables;
@ -1575,6 +1580,11 @@ void SwXMLImport::SetConfigurationSettings(const Sequence < PropertyValue > & aC
xProps->setPropertyValue("HyphenateURLs", Any(true));
}
if (!bApplyTextAttrToEmptyLineAtEndOfParagraph)
{
xProps->setPropertyValue("ApplyTextAttrToEmptyLineAtEndOfParagraph", Any(false));
}
if (bDoNotBreakWrappedTables)
{
xProps->setPropertyValue("DoNotBreakWrappedTables", Any(true));

View File

@ -159,6 +159,7 @@ enum SwDocumentSettingsPropertyHandles
HANDLE_NO_NUMBERING_SHOW_FOLLOWBY,
HANDLE_DROP_CAP_PUNCTUATION,
HANDLE_USE_VARIABLE_WIDTH_NBSP,
HANDLE_APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH,
};
}
@ -264,6 +265,7 @@ static rtl::Reference<MasterPropertySetInfo> lcl_createSettingsInfo()
{ OUString("NoNumberingShowFollowBy"), HANDLE_NO_NUMBERING_SHOW_FOLLOWBY, cppu::UnoType<bool>::get(), 0 },
{ OUString("DropCapPunctuation"), HANDLE_DROP_CAP_PUNCTUATION, cppu::UnoType<bool>::get(), 0 },
{ OUString("UseVariableWidthNBSP"), HANDLE_USE_VARIABLE_WIDTH_NBSP, cppu::UnoType<bool>::get(), 0 },
{ OUString("ApplyTextAttrToEmptyLineAtEndOfParagraph"), HANDLE_APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH, cppu::UnoType<bool>::get(), 0 },
/*
* As OS said, we don't have a view when we need to set this, so I have to
@ -1074,6 +1076,16 @@ void SwXDocumentSettings::_setSingleValue( const comphelper::PropertyInfo & rInf
}
}
break;
case HANDLE_APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH:
{
bool bTmp;
if (rValue >>= bTmp)
{
mpDoc->getIDocumentSettingAccess().set(
DocumentSettingId::APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH, bTmp);
}
}
break;
case HANDLE_DO_NOT_BREAK_WRAPPED_TABLES:
{
bool bTmp;
@ -1656,6 +1668,12 @@ void SwXDocumentSettings::_getSingleValue( const comphelper::PropertyInfo & rInf
DocumentSettingId::HYPHENATE_URLS);
}
break;
case HANDLE_APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH:
{
rValue <<= mpDoc->getIDocumentSettingAccess().get(
DocumentSettingId::APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH);
}
break;
case HANDLE_DO_NOT_BREAK_WRAPPED_TABLES:
{
rValue <<= mpDoc->getIDocumentSettingAccess().get(

View File

@ -330,6 +330,7 @@ void WriterFilter::setTargetDocument(const uno::Reference<lang::XComponent>& xDo
xSettings->setPropertyValue("DisableOffPagePositioning", uno::Any(true));
xSettings->setPropertyValue("DropCapPunctuation", uno::Any(true));
// rely on default for HyphenateURLs=false
// rely on default for APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH=true
}
void WriterFilter::setSourceDocument(const uno::Reference<lang::XComponent>& xDoc)