diff options
author | László Németh <nemeth@numbertext.org> | 2018-01-31 16:35:05 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2018-02-02 09:06:42 +0100 |
commit | 1037e3759bf178b52d16c12a811717f94ab9950a (patch) | |
tree | a16ef8d43b9de36691e903e634e6ce64256b55cd /sw/source/core | |
parent | 41759e1e892f37c0a51b8ee8cf9422a42230f0c9 (diff) |
tdf#115319 references with Hungarian articles
Add new alternative reference formats, stored by
the proposed text:reference-language attribute.
This is an implementation of the ODF improvement draft
published in the bug report.
Note: choose Hungarian locale setting to show the
new "Article a/az + Page" etc. reference formats
in dialog window "Fields".
Change-Id: I210d4b9a3e821fb4e45e24643bad9c70b867c89d
Reviewed-on: https://gerrit.libreoffice.org/48944
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Diffstat (limited to 'sw/source/core')
-rw-r--r-- | sw/source/core/fields/reffld.cxx | 173 | ||||
-rw-r--r-- | sw/source/core/unocore/unofield.cxx | 1 | ||||
-rw-r--r-- | sw/source/core/unocore/unomap.cxx | 1 |
3 files changed, 173 insertions, 2 deletions
diff --git a/sw/source/core/fields/reffld.cxx b/sw/source/core/fields/reffld.cxx index c0749e131509..cf7eafe65497 100644 --- a/sw/source/core/fields/reffld.cxx +++ b/sw/source/core/fields/reffld.cxx @@ -20,6 +20,7 @@ #include <com/sun/star/text/ReferenceFieldPart.hpp> #include <com/sun/star/text/ReferenceFieldSource.hpp> #include <unotools/localedatawrapper.hxx> +#include <unotools/charclass.hxx> #include <comphelper/processfactory.hxx> #include <comphelper/string.hxx> #include <editeng/unolingu.hxx> @@ -196,12 +197,151 @@ bool IsFrameBehind( const SwTextNode& rMyNd, sal_Int32 nMySttPos, return bRefIsLower; } +// tdf#115319 create alternative reference formats, if the user asked for it +// (ReferenceFieldLanguage attribute of the reference field is not empty), and +// language of the text and ReferenceFieldLanguage are the same. +// Right now only HUNGARIAN seems to need this (as in the related issue, +// the reversed caption order in autocaption, solved by #i61007#) +static void lcl_formatReferenceLanguage( OUString& rRefText, + bool bClosingParenthesis, LanguageType eLang, + const OUString& rReferenceLanguage) +{ + if (eLang != LANGUAGE_HUNGARIAN || (rReferenceLanguage != "hu" && rReferenceLanguage != "Hu")) + return; + + // Add Hungarian definitive article (a/az) before references, + // similar to \aref, \apageref etc. of LaTeX Babel package. + // + // for example: + // + // "az 1. oldalon" ("on page 1"), but + // "a 2. oldalon" ("on page 2") + // "a fentebbi", "az alábbi" (above/below) + // "a Lorem", "az Ipsum" + // + // Support following numberings of EU publications: + // + // 1., 1a., a), (1), (1a), iii., III., IA. + // + // (http://publications.europa.eu/code/hu/hu-120700.htm, + // http://publications.europa.eu/code/hu/hu-4100600.htm) + + LanguageTag aLanguageTag(eLang); + CharClass aCharClass( aLanguageTag ); + sal_Int32 nLen = rRefText.getLength(); + sal_Int32 i; + // substring of rRefText starting with letter or number + OUString sNumbering; + // is article "az"? + bool bArticleAz = false; + // is numbering a number? + bool bNum = false; + + // search first member of the numbering (numbers or letters) + for (i=0; i<nLen && (sNumbering.isEmpty() || + ((bNum && aCharClass.isDigit(rRefText, i)) || + (!bNum && aCharClass.isLetter(rRefText, i)))); ++i) + { + // start of numbering within the field text + if (sNumbering.isEmpty() && aCharClass.isLetterNumeric(rRefText, i)) { + sNumbering = rRefText.copy(i); + bNum = aCharClass.isDigit(rRefText, i); + } + } + + // length of numbering + nLen = i - (rRefText.getLength() - sNumbering.getLength()); + + if (bNum) + { + // az 1, 1000, 1000000, 1000000000... + // az 5, 50, 500... + if ((sNumbering.startsWith("1") && (nLen == 1 || nLen == 4 || nLen == 7 || nLen == 10)) || + sNumbering.startsWith("5")) + bArticleAz = true; + } + else if (nLen == 1 && sNumbering[0] < 128) + { + // ASCII 1-letter numbering + // az a), e), f) ... x) + // az i., v. (but, a x.) + static OUString sLettersStartingWithVowels = "aefilmnorsuxyAEFILMNORSUXY"; + if (sLettersStartingWithVowels.indexOf(sNumbering[0]) != -1) + { + // x), X) are letters, but x. and X. etc. are Roman numbers + if (bClosingParenthesis || + (sNumbering[0] != 'x' && sNumbering[0] != 'X')) + bArticleAz = true; + } else if ((sNumbering[0] == 'v' || sNumbering[0] == 'V') && !bClosingParenthesis) + // v), V) are letters, but v. and V. are Roman numbers + bArticleAz = true; + } + else + { + static const sal_Unicode sVowelsWithDiacritic[] = { + 0x00E1, 0x00C1, 0x00E9, 0x00C9, 0x00ED, 0x00CD, + 0x00F3, 0x00D3, 0x00F6, 0x00D6, 0x0151, 0x0150, + 0x00FA, 0x00DA, 0x00FC, 0x00DC, 0x0171, 0x0170, 0 }; + static OUString sVowels = "aAeEoOuU" + OUString(sVowelsWithDiacritic); + + // handle more than 1-letter long Roman numbers and + // their possible combinations with letters: + // az IA, a IIB, a IIIC., az Ia, a IIb., a iiic), az LVIII. szonett + bool bRomanNumber = false; + if (nLen > 1 && (nLen + 1 >= sNumbering.getLength() || sNumbering[nLen] == '.')) + { + sal_Unicode last = sNumbering[nLen - 1]; + OUString sNumberingTrim; + if ((last >= 'A' && last < 'I') || (last >= 'a' && last < 'i')) + sNumberingTrim = sNumbering.copy(0, nLen - 1); + else + sNumberingTrim = sNumbering.copy(0, nLen); + bRomanNumber = + sNumberingTrim.replaceAll("i", "").replaceAll("v", "").replaceAll("x", "").replaceAll("l", "").replaceAll("c", "").isEmpty() || + sNumberingTrim.replaceAll("I", "").replaceAll("V", "").replaceAll("X", "").replaceAll("L", "").replaceAll("C", "").isEmpty(); + } + + if ( + // Roman number and a letter optionally + ( bRomanNumber && ( + (sNumbering[0] == 'i' && sNumbering[1] != 'i' && sNumbering[1] != 'v' && sNumbering[1] != 'x') || + (sNumbering[0] == 'I' && sNumbering[1] != 'I' && sNumbering[1] != 'V' && sNumbering[1] != 'X') || + (sNumbering[0] == 'v' && sNumbering[1] != 'i') || + (sNumbering[0] == 'V' && sNumbering[1] != 'I') || + (sNumbering[0] == 'l' && sNumbering[1] != 'x') || + (sNumbering[0] == 'L' && sNumbering[1] != 'X')) ) || + // a word starting with vowel (not Roman number) + ( !bRomanNumber && sVowels.indexOf(sNumbering[0]) != -1)) + { + bArticleAz = true; + } + } + // not a title text starting already with a definitive article + if ( !sNumbering.startsWith("A ") && !sNumbering.startsWith("Az ") && + !sNumbering.startsWith("a ") && !sNumbering.startsWith("az ") ) + { + // lowercase, if rReferenceLanguage == "hu", not "Hu" + OUString sArticle; + + if ( rReferenceLanguage == "hu" ) + sArticle = "a"; + else + sArticle = "A"; + + if (bArticleAz) + sArticle += "z"; + + rRefText = sArticle + " " + rRefText; + } +} + /// get references SwGetRefField::SwGetRefField( SwGetRefFieldType* pFieldType, - const OUString& rSetRef, sal_uInt16 nSubTyp, + const OUString& rSetRef, const OUString& rSetReferenceLanguage, sal_uInt16 nSubTyp, sal_uInt16 nSequenceNo, sal_uLong nFormat ) : SwField( pFieldType, nFormat ), sSetRefName( rSetRef ), + sSetReferenceLanguage( rSetReferenceLanguage ), nSubType( nSubTyp ), nSeqNo( nSequenceNo ) { @@ -380,6 +520,8 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr ) if( nSeqNo == pFootnoteIdx->GetSeqRefNo() ) { sText = pFootnoteIdx->GetFootnote().GetViewNumStr( *pDoc ); + if (!sSetReferenceLanguage.isEmpty()) + lcl_formatReferenceLanguage(sText, false, GetLanguage(), sSetReferenceLanguage); break; } } @@ -413,6 +555,8 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr ) } } sText = aBuf.makeStringAndClear(); + if (!sSetReferenceLanguage.isEmpty()) + lcl_formatReferenceLanguage(sText, false, GetLanguage(), sSetReferenceLanguage); } } } @@ -436,6 +580,9 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr ) sText = pPage->GetPageDesc()->GetNumType().GetNumStr( nPageNo ); else sText = OUString::number(nPageNo); + + if (!sSetReferenceLanguage.isEmpty()) + lcl_formatReferenceLanguage(sText, false, GetLanguage(), sSetReferenceLanguage); } } break; @@ -451,6 +598,10 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr ) aField.SetLevel( MAXLEVEL - 1 ); aField.ChangeExpansion( pFrame, pTextNd, true ); sText = aField.GetNumber(); + + if (!sSetReferenceLanguage.isEmpty()) + lcl_formatReferenceLanguage(sText, false, GetLanguage(), sSetReferenceLanguage); + } } break; @@ -478,6 +629,9 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr ) *pTextNd, nNumStart ) ? aLocaleData.getAboveWord() : aLocaleData.getBelowWord(); + + if (!sSetReferenceLanguage.isEmpty()) + lcl_formatReferenceLanguage(sText, false, GetLanguage(), sSetReferenceLanguage); } break; // #i81002# @@ -485,10 +639,19 @@ void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr ) case REF_NUMBER_NO_CONTEXT: case REF_NUMBER_FULL_CONTEXT: { + // for differentiation of Roman numbers and letters in Hungarian article handling + bool bClosingParenthesis = false; + if ( pFieldTextAttr && pFieldTextAttr->GetpTextNode() ) { sText = MakeRefNumStr( pFieldTextAttr->GetTextNode(), *pTextNd, GetFormat() ); + if ( !sText.isEmpty() && !sSetReferenceLanguage.isEmpty() ) + bClosingParenthesis = pTextNd->GetNumRule()->MakeNumString( *(pTextNd->GetNum()), true).endsWith(")"); } + + if (!sSetReferenceLanguage.isEmpty()) + lcl_formatReferenceLanguage(sText, bClosingParenthesis, GetLanguage(), sSetReferenceLanguage); + } break; @@ -575,7 +738,7 @@ OUString SwGetRefField::MakeRefNumStr( const SwTextNode& rTextNodeOfField, SwField* SwGetRefField::Copy() const { SwGetRefField* pField = new SwGetRefField( static_cast<SwGetRefFieldType*>(GetTyp()), - sSetRefName, nSubType, + sSetRefName, sSetReferenceLanguage, nSubType, nSeqNo, GetFormat() ); pField->sText = sText; return pField; @@ -660,6 +823,9 @@ bool SwGetRefField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const case FIELD_PROP_PAR3: rAny <<= Expand(); break; + case FIELD_PROP_PAR4: + rAny <<= sSetReferenceLanguage; + break; case FIELD_PROP_SHORT1: rAny <<= static_cast<sal_Int16>(nSeqNo); break; @@ -732,6 +898,9 @@ bool SwGetRefField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId ) SetExpand( sTmpStr ); } break; + case FIELD_PROP_PAR4: + rAny >>= sSetReferenceLanguage; + break; case FIELD_PROP_SHORT1: { sal_Int16 nSetSeq = 0; diff --git a/sw/source/core/unocore/unofield.cxx b/sw/source/core/unocore/unofield.cxx index 5e45a339d1a6..db1cc9b3e378 100644 --- a/sw/source/core/unocore/unofield.cxx +++ b/sw/source/core/unocore/unofield.cxx @@ -1469,6 +1469,7 @@ void SAL_CALL SwXTextField::attach( SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef); pField = new SwGetRefField(static_cast<SwGetRefFieldType*>(pFieldType), m_pImpl->m_pProps->sPar1, + m_pImpl->m_pProps->sPar4, 0, 0, 0); diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx index 51eeee194701..c17964931264 100644 --- a/sw/source/core/unocore/unomap.cxx +++ b/sw/source/core/unocore/unomap.cxx @@ -878,6 +878,7 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s {OUString(UNO_NAME_REFERENCE_FIELD_SOURCE),FIELD_PROP_USHORT2, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, {OUString(UNO_NAME_SEQUENCE_NUMBER), FIELD_PROP_SHORT1, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0}, {OUString(UNO_NAME_SOURCE_NAME), FIELD_PROP_PAR1, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, + {OUString(UNO_NAME_REFERENCE_FIELD_LANGUAGE), FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0}, COMMON_FLDTYP_PROPERTIES { OUString(), 0, css::uno::Type(), 0, 0 } }; |