Improve HIDE_NON_NUMERICAL compatibility with Word

The previous implementation of REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL had
some major incompatibilites with Word. In particular, it stripped
letters even if they were included in the "numbering" system.

This commit fixes a lot of the flaws in the previous implementation, so
it's now a lot closer to Word.

Change-Id: Ifaa67fbc2d53b0d4fb85e7305b2dbdf78cf0a1ad
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158451
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
This commit is contained in:
Skyler Grey
2023-10-30 20:10:27 +01:00
committed by Caolán McNamara
parent 15972993ff
commit 2ddd1378fc
7 changed files with 152 additions and 72 deletions
+3 -1
View File
@@ -169,11 +169,13 @@ public:
OUString MakeNumString( const SwNumberTree::tNumberVector & rNumVector,
const bool bInclStrings = true,
const unsigned int _nRestrictToThisLevel = MAXLEVEL,
const bool bHideNonNumerical = false,
Extremities* pExtremities = nullptr,
LanguageType nLang = LANGUAGE_SYSTEM) const;
OUString MakeRefNumString( const SwNodeNum& rNodeNum,
const bool bInclSuperiorNumLabels,
const int nRestrictInclToThisLevel ) const;
const int nRestrictInclToThisLevel,
const bool bHideNonNumerical ) const;
OUString MakeParagraphStyleListString() const;
/** @return list of associated text nodes */
-5
View File
@@ -117,11 +117,6 @@ private:
virtual OUString ExpandImpl(SwRootFrame const* pLayout) const override;
virtual std::unique_ptr<SwField> Copy() const override;
/// Strip out text that is not either a number or a delimiter. Used in STYLEREF for when you
/// have chapters labelled "Chapter X.Y" and want to just keep the "X.Y". Distinct from
/// GetExpandedTextOfReferencedTextNode so you can run it after any other processing
void StylerefStripNonnumerical(OUString& rText) const;
public:
SwGetRefField( SwGetRefFieldType*, OUString aSetRef, OUString aReferenceLanguage,
sal_uInt16 nSubType, sal_uInt16 nSeqNo, sal_uInt16 nFlags, sal_uLong nFormat );
+106 -15
View File
@@ -648,9 +648,51 @@ OUString SwNumRule::MakeNumString( const SwNodeNum& rNum, bool bInclStrings ) co
return OUString();
}
namespace {
/// Strip out text that is not a delimiter. Used in STYLEREF for when you
/// have chapters labelled "Chapter X.Y" and want to just keep the "X.Y"
/// Only used on the prefix/infix/suffix, so the numbers are not modified
void StripNonDelimiter(OUString& rText)
{
std::vector<sal_Unicode> charactersToKeep;
for (int i = 0; i < rText.getLength(); i++) {
auto character = rText[i];
// tdf#86790# for Word compatibility: I haven't found any better way to determine whether a
// character is a delimiter than testing in Word and listing them out. Furthermore, I haven't
// found a list so I can't be certain this is the complete set- if there's a compatibility issue
// with this in the future, here's the first place to look...
if (
character == '.'
|| character == ','
|| character == ':'
|| character == ';'
|| character == '-'
|| character == '('
|| character == ')'
|| character == '['
|| character == ']'
|| character == '{'
|| character == '}'
|| character == '/'
|| character == '\\'
|| character == '|'
)
charactersToKeep.push_back(character);
}
if (charactersToKeep.size())
rText = OUString(charactersToKeep.data(), charactersToKeep.size());
else
rText = OUString();
}
}
OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVector,
const bool bInclStrings,
const unsigned int _nRestrictToThisLevel,
const bool bHideNonNumerical,
SwNumRule::Extremities* pExtremities,
LanguageType nLang ) const
{
@@ -672,12 +714,27 @@ OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVecto
if (rMyNFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE)
{
if (!rMyNFormat.HasListFormat())
return bInclStrings ? rMyNFormat.GetPrefix() + rMyNFormat.GetSuffix() : OUString();
if (!rMyNFormat.HasListFormat()) {
OUString sRet = bInclStrings ? rMyNFormat.GetPrefix() + rMyNFormat.GetSuffix() : OUString();
StripNonDelimiter(sRet);
return sRet;
}
// If numbering is disabled for this level we should emit just prefix/suffix
// Remove everything between first %1% and last %n% (including markers)
OUString sLevelFormat = rMyNFormat.GetListFormat(bInclStrings);
OUString sLevelFormat = rMyNFormat.GetListFormat(bInclStrings && !bHideNonNumerical);
if (bInclStrings && bHideNonNumerical) {
// If hiding non numerical text, we need to strip the prefix and suffix properly, so let's add them manually
OUString sPrefix = rMyNFormat.GetPrefix();
OUString sSuffix = rMyNFormat.GetSuffix();
StripNonDelimiter(sPrefix);
StripNonDelimiter(sSuffix);
sLevelFormat = sPrefix + sLevelFormat + sSuffix;
}
sal_Int32 nFirstPosition = sLevelFormat.indexOf("%");
sal_Int32 nLastPosition = sLevelFormat.lastIndexOf("%");
if (nFirstPosition >= 0 && nLastPosition >= nFirstPosition)
@@ -689,7 +746,17 @@ OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVecto
if (rMyNFormat.HasListFormat())
{
OUString sLevelFormat = rMyNFormat.GetListFormat(bInclStrings);
OUString sLevelFormat = rMyNFormat.GetListFormat(bInclStrings && !bHideNonNumerical);
if (bInclStrings && bHideNonNumerical) {
OUString sPrefix = rMyNFormat.GetPrefix();
OUString sSuffix = rMyNFormat.GetSuffix();
StripNonDelimiter(sPrefix);
StripNonDelimiter(sSuffix);
sLevelFormat = sPrefix + sLevelFormat + sSuffix;
}
// In this case we are ignoring GetIncludeUpperLevels: we put all
// level numbers requested by level format
@@ -697,28 +764,46 @@ OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVecto
{
OUString sReplacement;
const SwNumFormat& rNFormat = Get(i);
OUString sFind("%" + OUString::number(i + 1) + "%");
sal_Int32 nPosition = sLevelFormat.indexOf(sFind);
if (rNFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE)
{
// Numbering disabled - replacement is empty
// And we should skip all level string content until next level marker:
// so %1%.%2%.%3% with second level as NONE will result 1.1, not 1..1
OUString sFind("%" + OUString::number(i + 1) + "%");
sal_Int32 nPositionToken = sLevelFormat.indexOf(sFind);
sal_Int32 nPositionNextToken = sLevelFormat.indexOf('%', nPositionToken + sFind.getLength());
if (nPositionToken >= 0 && nPositionNextToken >= nPositionToken)
sal_Int32 nPositionNext = sLevelFormat.indexOf('%', nPosition + sFind.getLength());
if (nPosition >= 0 && nPositionNext >= nPosition)
{
sLevelFormat = sLevelFormat.replaceAt(nPositionToken, nPositionNextToken - nPositionToken, u"");
sLevelFormat = sLevelFormat.replaceAt(nPosition, nPositionNext - nPosition, u"");
}
continue;
}
else if (rNumVector[i])
sReplacement = Get(i).GetNumStr(rNumVector[i], aLocale, rMyNFormat.GetIsLegal());
else
sReplacement = "0"; // all 0 level are a 0
OUString sFind("%" + OUString::number(i + 1) + "%");
sal_Int32 nPosition = sLevelFormat.indexOf(sFind);
if (nPosition >= 0)
{
if (bHideNonNumerical)
{
sal_Int32 nPositionNext = sLevelFormat.indexOf('%', nPosition + sFind.getLength());
if (nPositionNext >= nPosition) {
sal_Int32 nReplaceStart = nPosition + sFind.getLength();
sal_Int32 nReplaceCount = nPositionNext - nReplaceStart;
OUString sSeparator = sLevelFormat.copy(nReplaceStart, nReplaceCount);
StripNonDelimiter(sSeparator);
sLevelFormat = sLevelFormat.replaceAt(nReplaceStart, nReplaceCount, sSeparator);
}
}
sLevelFormat = sLevelFormat.replaceAt(nPosition, sFind.getLength(), sReplacement);
}
}
aStr = sLevelFormat;
@@ -769,8 +854,13 @@ OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVecto
SVX_NUM_CHAR_SPECIAL != rMyNFormat.GetNumberingType() &&
SVX_NUM_BITMAP != rMyNFormat.GetNumberingType())
{
const OUString& sPrefix = rMyNFormat.GetPrefix();
const OUString& sSuffix = rMyNFormat.GetSuffix();
OUString sPrefix = rMyNFormat.GetPrefix();
OUString sSuffix = rMyNFormat.GetSuffix();
if (bHideNonNumerical) {
StripNonDelimiter(sPrefix);
StripNonDelimiter(sSuffix);
}
aStr.insert(0, sPrefix);
aStr.append(sSuffix);
@@ -787,7 +877,8 @@ OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVecto
OUString SwNumRule::MakeRefNumString( const SwNodeNum& rNodeNum,
const bool bInclSuperiorNumLabels,
const int nRestrictInclToThisLevel ) const
const int nRestrictInclToThisLevel,
const bool bHideNonNumerical ) const
{
OUString aRefNumStr;
@@ -822,7 +913,7 @@ OUString SwNumRule::MakeRefNumString( const SwNodeNum& rNodeNum,
Extremities aExtremities;
OUString aPrevStr = MakeNumString( pWorkingNodeNum->GetNumberVector(),
true, MAXLEVEL,
&aExtremities);
bHideNonNumerical, &aExtremities);
sal_Int32 nStrip = 0;
while ( nStrip < aExtremities.nPrefixChars )
{
+12 -32
View File
@@ -75,7 +75,9 @@ using namespace ::com::sun::star::lang;
static std::pair<OUString, bool> MakeRefNumStr(SwRootFrame const* pLayout,
const SwTextNode& rTextNodeOfField,
const SwTextNode& rTextNodeOfReferencedItem,
sal_uInt32 nRefNumFormat);
sal_uInt16 nSubType,
sal_uInt32 nRefNumFormat,
sal_uInt16 nFlags);
static void lcl_GetLayTree( const SwFrame* pFrame, std::vector<const SwFrame*>& rArr )
{
@@ -425,30 +427,6 @@ static OUString lcl_formatStringByCombiningCharacter(std::u16string_view sText,
return sRet.makeStringAndClear();
}
void SwGetRefField::StylerefStripNonnumerical(OUString& rText) const
{
// for STYLEREF, hide text that is neither a delimiter nor a number if that flag is set
if ( m_nSubType != REF_STYLE || (GetFlags() & REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL) != REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL )
return;
std::vector<sal_Unicode> charactersToKeep;
for (int i = 0; i < rText.getLength(); i++) {
auto character = rText[i];
if (
(character >= '(' && character <= '@') || // includes 0-9 and most of the punctuation we want
(character >= '[' && character <= '_') // includes the rest of the punctuation we want
)
charactersToKeep.push_back(character);
}
if (charactersToKeep.size())
rText = OUString(charactersToKeep.data(), charactersToKeep.size());
else
rText = OUString();
}
// #i85090#
OUString SwGetRefField::GetExpandedTextOfReferencedTextNode(
SwRootFrame const& rLayout, SwTextNode* pTextNode, SwFrame* pFrame) const
@@ -468,8 +446,6 @@ OUString SwGetRefField::GetExpandedTextOfReferencedTextNode(
sRet = lcl_formatStringByCombiningCharacter( sRet, cStrikethrough );
}
StylerefStripNonnumerical(sRet);
return sRet;
}
@@ -798,7 +774,7 @@ void SwGetRefField::UpdateField(const SwTextField* pFieldTextAttr, SwFrame* pFra
if ( pFieldTextAttr && pFieldTextAttr->GetpTextNode() )
{
auto result =
MakeRefNumStr(pLayout, pFieldTextAttr->GetTextNode(), *pTextNd, GetFormat());
MakeRefNumStr(pLayout, pFieldTextAttr->GetTextNode(), *pTextNd, m_nSubType, GetFormat(), GetFlags());
rText = result.first;
// for differentiation of Roman numbers and letters in Hungarian article handling
bool bClosingParenthesis = result.second;
@@ -808,22 +784,25 @@ void SwGetRefField::UpdateField(const SwTextField* pFieldTextAttr, SwFrame* pFra
}
}
}
break;
default:
OSL_FAIL("<SwGetRefField::UpdateField(..)> - unknown format type");
}
StylerefStripNonnumerical(rText);
}
// #i81002#
static std::pair<OUString, bool> MakeRefNumStr(
SwRootFrame const*const pLayout,
const SwTextNode& i_rTextNodeOfField,
const SwTextNode& i_rTextNodeOfReferencedItem,
const sal_uInt32 nRefNumFormat)
const sal_uInt16 nSubType,
const sal_uInt32 nRefNumFormat,
const sal_uInt16 nFlags)
{
bool bHideNonNumerical = (nSubType == REF_STYLE) && ((nFlags & REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL) == REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL);
SwTextNode const& rTextNodeOfField(pLayout
? *sw::GetParaPropsNode(*pLayout, i_rTextNodeOfField)
: i_rTextNodeOfField);
@@ -897,7 +876,8 @@ static std::pair<OUString, bool> MakeRefNumStr(
rTextNodeOfReferencedItem.GetNumRule()->MakeRefNumString(
*(rTextNodeOfReferencedItem.GetNum(pLayout)),
bInclSuperiorNumLabels,
nRestrictInclToThisLevel ),
nRestrictInclToThisLevel,
bHideNonNumerical ),
rTextNodeOfReferencedItem.GetNumRule()->MakeNumString(
*(rTextNodeOfReferencedItem.GetNum(pLayout)),
true).endsWith(")") );
+1
View File
@@ -3267,6 +3267,7 @@ OUString SwTextNode::GetNumString( const bool _bInclPrefixAndSuffixStrings,
return pRule->MakeNumString( GetNum(pLayout, eRedline)->GetNumberVector(),
_bInclPrefixAndSuffixStrings,
_nRestrictToThisLevel,
false,
nullptr,
GetLang(0));
}
+29 -19
View File
@@ -46,6 +46,25 @@ static sal_uInt16 nFieldDlgFormatSel = 0;
#define USER_DATA_VERSION_1 "1"
#define USER_DATA_VERSION USER_DATA_VERSION_1
namespace {
enum FMT_REF_IDX
{
FMT_REF_PAGE_IDX = 0,
FMT_REF_CHAPTER_IDX = 1,
FMT_REF_TEXT_IDX = 2,
FMT_REF_UPDOWN_IDX = 3,
FMT_REF_PAGE_PGDSC_IDX = 4,
FMT_REF_ONLYNUMBER_IDX = 5,
FMT_REF_ONLYCAPTION_IDX = 6,
FMT_REF_ONLYSEQNO_IDX = 7,
FMT_REF_NUMBER_IDX = 8,
FMT_REF_NUMBER_NO_CONTEXT_IDX = 9,
FMT_REF_NUMBER_FULL_CONTEXT_IDX = 10
};
}
SwFieldRefPage::SwFieldRefPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *const pCoreSet )
: SwFieldPage(pPage, pController, "modules/swriter/ui/fldrefpage.ui", "FieldRefPage", pCoreSet)
, mpSavedSelectedTextNode(nullptr)
@@ -98,6 +117,7 @@ SwFieldRefPage::SwFieldRefPage(weld::Container* pPage, weld::DialogController* p
m_xSelectionLB->connect_changed(LINK(this, SwFieldRefPage, SubTypeListBoxHdl));
m_xSelectionLB->connect_row_activated(LINK(this, SwFieldRefPage, TreeViewInsertHdl));
m_xFormatLB->connect_row_activated(LINK(this, SwFieldRefPage, TreeViewInsertHdl));
m_xFormatLB->connect_changed(LINK(this, SwFieldRefPage, FormatHdl));
// #i83479#
m_xSelectionToolTipLB->connect_changed( LINK(this, SwFieldRefPage, SubTypeTreeListBoxHdl) );
@@ -455,10 +475,19 @@ IMPL_LINK_NOARG(SwFieldRefPage, SubTypeListBoxHdl, weld::TreeView&, void)
SubTypeHdl();
}
IMPL_LINK_NOARG(SwFieldRefPage, FormatHdl, weld::TreeView&, void)
{
SubTypeHdl();
}
void SwFieldRefPage::SubTypeHdl()
{
sal_uInt16 nTypeId = m_xTypeLB->get_id(GetTypeSel()).toUInt32();
sal_uInt16 nFormat = m_xFormatLB->get_selected_id().toUInt32();
m_xStylerefHideNonNumericalCB->set_visible(nFormat == FMT_REF_NUMBER_IDX
|| nFormat == FMT_REF_NUMBER_NO_CONTEXT_IDX
|| nFormat == FMT_REF_NUMBER_FULL_CONTEXT_IDX);
m_xStylerefFlags->set_visible(nTypeId == REFFLDFLAG_STYLE);
switch(nTypeId)
@@ -800,25 +829,6 @@ bool SwFieldRefPage::MatchSubstring( const OUString& rListString, const OUString
return aListString.indexOf(aSubstr) >= 0;
}
namespace {
enum FMT_REF_IDX
{
FMT_REF_PAGE_IDX = 0,
FMT_REF_CHAPTER_IDX = 1,
FMT_REF_TEXT_IDX = 2,
FMT_REF_UPDOWN_IDX = 3,
FMT_REF_PAGE_PGDSC_IDX = 4,
FMT_REF_ONLYNUMBER_IDX = 5,
FMT_REF_ONLYCAPTION_IDX = 6,
FMT_REF_ONLYSEQNO_IDX = 7,
FMT_REF_NUMBER_IDX = 8,
FMT_REF_NUMBER_NO_CONTEXT_IDX = 9,
FMT_REF_NUMBER_FULL_CONTEXT_IDX = 10
};
}
const TranslateId FMT_REF_ARY[] =
{
FMT_REF_PAGE,
+1
View File
@@ -66,6 +66,7 @@ class SwFieldRefPage : public SwFieldPage
DECL_LINK(SubTypeTreeListBoxHdl, weld::TreeView&, void);
DECL_LINK(ModifyHdl, weld::Entry&, void);
DECL_LINK(ModifyHdl_Impl, weld::Entry&, void);
DECL_LINK(FormatHdl, weld::TreeView&, void);
void SubTypeHdl();