editeng/qa/unit/core-test.cxx | 47 +++++++++++++++++++++++++++++++++ editeng/source/editeng/ContentNode.cxx | 3 +- editeng/source/items/flditem.cxx | 27 +++++++++++++++--- sc/inc/editutil.hxx | 5 +++ sc/source/core/tool/editutil.cxx | 19 ++++++++++++- sc/source/ui/view/prevwsh.cxx | 7 ---- sc/source/ui/view/printfun.cxx | 7 ---- sc/source/ui/view/tabvwsh4.cxx | 8 +---- sw/source/core/fields/docufld.cxx | 23 ++++++++++++---- 9 files changed, 116 insertions(+), 30 deletions(-)
New commits: commit 52d8e57447f93a47cfeaea35ee1346ba95699904 Author: Michael Meeks <[email protected]> AuthorDate: Tue Feb 10 21:22:31 2026 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Sat Feb 28 17:03:42 2026 +0100 editeng: don't preserve escapement attribute on paragraph break. This fixes a particuarly annoying habit of a trailing superscript ordinal suffix getting dragged into the next bullet and causing the unwary user weird small fonts, and non-aligned bullets. Nail only the most obvious case, leaving multi-line superscript in-place, and ignoring other attributes. Include unit test. Change-Id: I9ba5009ed17377e5c2f24c9edb74c3a1c1393cd4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199203 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200676 Reviewed-by: Caolán McNamara <[email protected]> diff --git a/editeng/qa/unit/core-test.cxx b/editeng/qa/unit/core-test.cxx index c68727f575af..7ce9de7c1f2a 100644 --- a/editeng/qa/unit/core-test.cxx +++ b/editeng/qa/unit/core-test.cxx @@ -30,6 +30,7 @@ #include <editeng/editobj.hxx> #include <editeng/flditem.hxx> #include <editeng/udlnitem.hxx> +#include <editeng/escapementitem.hxx> #include <svl/srchitem.hxx> #include <svl/voiditem.hxx> #include <editeng/fontitem.hxx> @@ -134,6 +135,7 @@ public: void testTdf154248MultilineFieldWrapping(); void testTdf151748StaleKashidaArray(); void testTdf162803StaleKashidaArray(); + void testEscapementNotPreservedOnParaBreak(); DECL_STATIC_LINK(Test, CalcFieldValueHdl, EditFieldInfo*, void); @@ -168,6 +170,7 @@ public: CPPUNIT_TEST(testTdf154248MultilineFieldWrapping); CPPUNIT_TEST(testTdf151748StaleKashidaArray); CPPUNIT_TEST(testTdf162803StaleKashidaArray); + CPPUNIT_TEST(testEscapementNotPreservedOnParaBreak); CPPUNIT_TEST_SUITE_END(); private: @@ -2372,6 +2375,50 @@ void Test::testTdf162803StaleKashidaArray() } } +void Test::testEscapementNotPreservedOnParaBreak() +{ + EditEngine aEditEngine(mpItemPool.get()); + EditDoc& rDoc = aEditEngine.GetEditDoc(); + + OUString aParaText = u"item 1st"_ustr; + aEditEngine.SetText(aParaText); + CPPUNIT_ASSERT_EQUAL(aParaText, rDoc.GetParaAsString(0)); + + { + std::unique_ptr<SfxItemSet> pSet(new SfxItemSet(aEditEngine.GetEmptyItemSet())); + SvxEscapementItem aSuperscript(SvxEscapement::Superscript, EE_CHAR_ESCAPEMENT); + pSet->Put(aSuperscript); + aEditEngine.QuickSetAttribs(*pSet, ESelection(0, 6, 0, 8)); + } + + { + std::unique_ptr<SfxItemSet> pSet(new SfxItemSet(aEditEngine.GetEmptyItemSet())); + SvxWeightItem aBold(WEIGHT_BOLD, EE_CHAR_WEIGHT); + pSet->Put(aBold); + aEditEngine.QuickSetAttribs(*pSet, ESelection(0, 6, 0, 8)); + } + + // new para break at the end of the text (cf. pressing enter) + ContentNode* pNode = rDoc.GetObject(0); + CPPUNIT_ASSERT(pNode); + EditPaM aEndPaM(pNode, pNode->Len()); + rDoc.InsertParaBreak(aEndPaM, true /* bKeepEndingAttribs */); + + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), rDoc.Count()); + CPPUNIT_ASSERT_EQUAL(aParaText, rDoc.GetParaAsString(0)); + CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(1)); + + // Check new para's character attributes + pNode = rDoc.GetObject(1); + CPPUNIT_ASSERT(pNode); + + const EditCharAttrib* pBoldAttr = pNode->GetCharAttribs().FindEmptyAttrib(EE_CHAR_WEIGHT, 0); + CPPUNIT_ASSERT_MESSAGE("Bold attribute should be carried over.", pBoldAttr != nullptr); + + const EditCharAttrib* pEscAttr = pNode->GetCharAttribs().FindEmptyAttrib(EE_CHAR_ESCAPEMENT, 0); + CPPUNIT_ASSERT_MESSAGE("Escapement attribute should NOT be included.", !pEscAttr); +} + CPPUNIT_TEST_SUITE_REGISTRATION(Test); } diff --git a/editeng/source/editeng/ContentNode.cxx b/editeng/source/editeng/ContentNode.cxx index 56c2659c7025..1904e55cb1aa 100644 --- a/editeng/source/editeng/ContentNode.cxx +++ b/editeng/source/editeng/ContentNode.cxx @@ -302,7 +302,8 @@ void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, else if ( pAttrib->GetEnd() == nCut ) { // must be copied as an empty attributes. - if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !maCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) ) + if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !maCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) + && pAttrib->GetItem()->Which() != EE_CHAR_ESCAPEMENT ) { EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, 0 ); assert(pNewAttrib); commit eef50420cbed14c979ff4d35bc07c94dfb6149f6 Author: Caolán McNamara <[email protected]> AuthorDate: Fri Jan 30 10:43:23 2026 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Sat Feb 28 17:03:35 2026 +0100 Use Documents/filename in jailed mode as file path field results The path is useless in jailed kit mode, so present a field result that the document is in some (translated) "Documents" toplevel directory when LibreOfficeKit::isActive() so it's stable between runs and retains some structural hint to distinguish between the various field modes. Change-Id: Ia8040924396207583e1a12b989d8862962371fc9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198420 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200675 Reviewed-by: Caolán McNamara <[email protected]> diff --git a/editeng/source/items/flditem.cxx b/editeng/source/items/flditem.cxx index 70a54653b090..96f1952bd8da 100644 --- a/editeng/source/items/flditem.cxx +++ b/editeng/source/items/flditem.cxx @@ -24,11 +24,15 @@ #include <svl/zforlist.hxx> #include <tools/urlobj.hxx> +#include <comphelper/lok.hxx> #include <editeng/flditem.hxx> #include <editeng/CustomPropertyField.hxx> #include <editeng/measfld.hxx> #include <editeng/unonames.hxx> +#include <sfx2/sfxresid.hxx> +#include <sfx2/strings.hrc> + #include <tools/debug.hxx> #include <libxml/xmlwriter.h> @@ -735,17 +739,30 @@ OUString SvxExtFileField::GetFormatted() const } else if( INetProtocol::File == aURLObj.GetProtocol() ) { + // Note: The path is useless in jailed kit mode, so present a view that + // the document is in a Documents toplevel directory for LibreOfficeKit::isActive() switch( eFormat ) { case SvxFileFormat::PathFull: - aString = aURLObj.getFSysPath(FSysStyle::Detect); + if (comphelper::LibreOfficeKit::isActive()) + { + aString = "/" + SfxResId(STR_GID_DOCUMENT) + "/" + + aURLObj.getName(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous); + } + else + aString = aURLObj.getFSysPath(FSysStyle::Detect); break; case SvxFileFormat::PathOnly: - aURLObj.removeSegment(INetURLObject::LAST_SEGMENT, false); - // #101742# Leave trailing slash at the pathname - aURLObj.setFinalSlash(); - aString = aURLObj.getFSysPath(FSysStyle::Detect); + if (comphelper::LibreOfficeKit::isActive()) + aString = "/" + SfxResId(STR_GID_DOCUMENT); + else + { + aURLObj.removeSegment(INetURLObject::LAST_SEGMENT, false); + // #101742# Leave trailing slash at the pathname + aURLObj.setFinalSlash(); + aString = aURLObj.getFSysPath(FSysStyle::Detect); + } break; case SvxFileFormat::NameOnly: diff --git a/sc/inc/editutil.hxx b/sc/inc/editutil.hxx index b580a811d4da..ae105b72e599 100644 --- a/sc/inc/editutil.hxx +++ b/sc/inc/editutil.hxx @@ -29,6 +29,7 @@ #include <tools/fract.hxx> #include <vcl/outdev.hxx> +class INetURLObject; class ScDocument; class ScPatternAttr; class ScEditEngineDefaulter; @@ -209,6 +210,10 @@ struct ScHeaderFieldData SvxNumType eNumType; ScHeaderFieldData(); + + // Set aLongDocName and aShortDocName from rURLObj, + // falling back back to aTitle, + void SetDocNames(const INetURLObject& rURLObj); }; // for headers/footers with fields diff --git a/sc/source/core/tool/editutil.cxx b/sc/source/core/tool/editutil.cxx index 89a4622f8f41..6176ed8765cc 100644 --- a/sc/source/core/tool/editutil.cxx +++ b/sc/source/core/tool/editutil.cxx @@ -18,6 +18,7 @@ */ #include <scitems.hxx> +#include <comphelper/lok.hxx> #include <comphelper/processfactory.hxx> #include <editeng/eeitem.hxx> @@ -32,7 +33,8 @@ #include <svl/numformat.hxx> #include <svl/inethist.hxx> #include <sfx2/objsh.hxx> -#include <comphelper/lok.hxx> +#include <sfx2/sfxresid.hxx> +#include <sfx2/strings.hrc> #include <osl/diagnose.h> #include <com/sun/star/text/textfield/Type.hpp> @@ -880,6 +882,21 @@ OUString ScHeaderEditEngine::CalcFieldValue( const SvxFieldItem& rField, return aRet; } +void ScHeaderFieldData::SetDocNames(const INetURLObject& rURLObj) +{ + aLongDocName = rURLObj.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous); + if (!aLongDocName.isEmpty()) + { + aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous); + // The path is useless in jailed kit mode, so present a view that the + // document is in a Documents toplevel directory for LibreOfficeKit::isActive() + if (comphelper::LibreOfficeKit::isActive()) + aLongDocName = "/" + SfxResId(STR_GID_DOCUMENT) + "/" + aShortDocName; + } + else + aShortDocName = aLongDocName = aTitle; +} + // field data ScFieldEditEngine::ScFieldEditEngine( diff --git a/sc/source/ui/view/prevwsh.cxx b/sc/source/ui/view/prevwsh.cxx index f633c5ebb364..715c17be7c0d 100644 --- a/sc/source/ui/view/prevwsh.cxx +++ b/sc/source/ui/view/prevwsh.cxx @@ -876,12 +876,7 @@ void ScPreviewShell::FillFieldData( ScHeaderFieldData& rData ) else rData.aTitle = pDocShell->GetTitle(); - const INetURLObject& rURLObj = pDocShell->GetMedium()->GetURLObject(); - rData.aLongDocName = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ); - if ( !rData.aLongDocName.isEmpty() ) - rData.aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous); - else - rData.aShortDocName = rData.aLongDocName = rData.aTitle; + rData.SetDocNames(pDocShell->GetMedium()->GetURLObject()); rData.nPageNo = pPreview->GetPageNo() + 1; bool bAllTested = pPreview->AllTested(); diff --git a/sc/source/ui/view/printfun.cxx b/sc/source/ui/view/printfun.cxx index a390c0be38c2..26ffd086531b 100644 --- a/sc/source/ui/view/printfun.cxx +++ b/sc/source/ui/view/printfun.cxx @@ -1100,12 +1100,7 @@ void ScPrintFunc::InitParam( const ScPrintOptions* pOptions ) else aFieldData.aTitle = rDocShell.GetTitle(); - const INetURLObject& rURLObj = rDocShell.GetMedium()->GetURLObject(); - aFieldData.aLongDocName = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ); - if ( !aFieldData.aLongDocName.isEmpty() ) - aFieldData.aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous); - else - aFieldData.aShortDocName = aFieldData.aLongDocName = aFieldData.aTitle; + aFieldData.SetDocNames(rDocShell.GetMedium()->GetURLObject()); // Printer settings (Orientation, Paper) at DoPrint } diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx index d2a3d04e7133..aa3e3406cf8f 100644 --- a/sc/source/ui/view/tabvwsh4.cxx +++ b/sc/source/ui/view/tabvwsh4.cxx @@ -2330,12 +2330,8 @@ void ScTabViewShell::FillFieldData( ScHeaderFieldData& rData ) else rData.aTitle = pDocShell->GetTitle(); - const INetURLObject& rURLObj = pDocShell->GetMedium()->GetURLObject(); - rData.aLongDocName = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ); - if ( !rData.aLongDocName.isEmpty() ) - rData.aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous); - else - rData.aShortDocName = rData.aLongDocName = rData.aTitle; + rData.SetDocNames(pDocShell->GetMedium()->GetURLObject()); + rData.nPageNo = 1; rData.nTotalPages = 99; diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx index c2639ce82234..1b5b7c068033 100644 --- a/sw/source/core/fields/docufld.cxx +++ b/sw/source/core/fields/docufld.cxx @@ -37,6 +37,7 @@ #include <o3tl/any.hxx> #include <o3tl/string_view.hxx> #include <unotools/localedatawrapper.hxx> +#include <comphelper/lok.hxx> #include <comphelper/processfactory.hxx> #include <comphelper/string.hxx> #include <tools/urlobj.hxx> @@ -55,6 +56,8 @@ #include <swmodule.hxx> #include <sfx2/docfile.hxx> #include <sfx2/doctempl.hxx> +#include <sfx2/sfxresid.hxx> +#include <sfx2/strings.hrc> #include <fmtfld.hxx> #include <txtfld.hxx> #include <charfmt.hxx> @@ -436,9 +439,14 @@ OUString SwFileNameFieldType::Expand(SwFileNameFormat nFormat) const if( pDShell && pDShell->HasName() ) { const INetURLObject& rURLObj = pDShell->GetMedium()->GetURLObject(); + // Note: The path is useless in jailed kit mode, so present a view that + // the document is in a Documents toplevel directory for LibreOfficeKit::isActive() switch( nFormat & ~SwFileNameFormat::Fixed ) { case SwFileNameFormat::Path: + if (comphelper::LibreOfficeKit::isActive()) + aRet = "/" + SfxResId(STR_GID_DOCUMENT); + else { if( INetProtocol::File == rURLObj.GetProtocol() ) { @@ -470,12 +478,17 @@ OUString SwFileNameFieldType::Expand(SwFileNameFormat nFormat) const break; default: - if( INetProtocol::File == rURLObj.GetProtocol() ) - aRet = rURLObj.GetFull(); + if (comphelper::LibreOfficeKit::isActive()) + aRet = "/" + SfxResId(STR_GID_DOCUMENT) + "/" + rURLObj.GetLastName(INetURLObject::DecodeMechanism::WithCharset); else - aRet = URIHelper::removePassword( - rURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), - INetURLObject::EncodeMechanism::WasEncoded, URL_DECODE ); + { + if( INetProtocol::File == rURLObj.GetProtocol() ) + aRet = rURLObj.GetFull(); + else + aRet = URIHelper::removePassword( + rURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), + INetURLObject::EncodeMechanism::WasEncoded, URL_DECODE ); + } } } return aRet;
