1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/text/ReferenceFieldPart.hpp>
21 #include <com/sun/star/text/ReferenceFieldSource.hpp>
22 #include <o3tl/unreachable.hxx>
23 #include <unotools/localedatawrapper.hxx>
24 #include <unotools/charclass.hxx>
26 #include <IDocumentFieldsAccess.hxx>
27 #include <IDocumentLayoutAccess.hxx>
28 #include <IDocumentMarkAccess.hxx>
31 #include <pagefrm.hxx>
32 #include <rootfrm.hxx>
33 #include <modeltoviewhelper.hxx>
37 #include <fmtrfmrk.hxx>
38 #include <txtrfmrk.hxx>
46 #include <pagedesc.hxx>
48 #include <crossrefbookmark.hxx>
51 #include <unofldmid.h>
52 #include <SwStyleNameMapper.hxx>
53 #include <shellres.hxx>
54 #include <poolfmt.hxx>
55 #include <strings.hrc>
56 #include <numrule.hxx>
57 #include <SwNodeNum.hxx>
64 #include <string_view>
68 using namespace ::com::sun::star
;
69 using namespace ::com::sun::star::text
;
70 using namespace ::com::sun::star::lang
;
72 static std::pair
<OUString
, bool> MakeRefNumStr(SwRootFrame
const* pLayout
,
73 const SwTextNode
& rTextNodeOfField
,
74 const SwTextNode
& rTextNodeOfReferencedItem
,
75 sal_uInt32 nRefNumFormat
);
77 static void lcl_GetLayTree( const SwFrame
* pFrame
, std::vector
<const SwFrame
*>& rArr
)
81 if( pFrame
->IsBodyFrame() ) // unspectacular
82 pFrame
= pFrame
->GetUpper();
85 rArr
.push_back( pFrame
);
87 // this is the last page
88 if( pFrame
->IsPageFrame() )
91 if( pFrame
->IsFlyFrame() )
92 pFrame
= static_cast<const SwFlyFrame
*>(pFrame
)->GetAnchorFrame();
94 pFrame
= pFrame
->GetUpper();
99 bool IsFrameBehind( const SwTextNode
& rMyNd
, sal_Int32 nMySttPos
,
100 const SwTextNode
& rBehindNd
, sal_Int32 nSttPos
)
102 const SwTextFrame
* pMyFrame
= static_cast<SwTextFrame
*>(rMyNd
.getLayoutFrame(
103 rMyNd
.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr));
104 const SwTextFrame
* pFrame
= static_cast<SwTextFrame
*>(rBehindNd
.getLayoutFrame(
105 rBehindNd
.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr));
107 if( !pFrame
|| !pMyFrame
)
110 TextFrameIndex
const nMySttPosIndex(pMyFrame
->MapModelToView(&rMyNd
, nMySttPos
));
111 TextFrameIndex
const nSttPosIndex(pFrame
->MapModelToView(&rBehindNd
, nSttPos
));
112 while (pFrame
&& !pFrame
->IsInside(nSttPosIndex
))
113 pFrame
= pFrame
->GetFollow();
114 while (pMyFrame
&& !pMyFrame
->IsInside(nMySttPosIndex
))
115 pMyFrame
= pMyFrame
->GetFollow();
117 if( !pFrame
|| !pMyFrame
|| pFrame
== pMyFrame
)
120 std::vector
<const SwFrame
*> aRefArr
, aArr
;
121 ::lcl_GetLayTree( pFrame
, aRefArr
);
122 ::lcl_GetLayTree( pMyFrame
, aArr
);
124 size_t nRefCnt
= aRefArr
.size() - 1, nCnt
= aArr
.size() - 1;
128 // Loop as long as a frame does not equal?
129 while( nRefCnt
&& nCnt
&& aRefArr
[ nRefCnt
] == aArr
[ nCnt
] )
131 const SwFrame
* pTmpFrame
= aArr
[ nCnt
];
132 bVert
= pTmpFrame
->IsVertical();
133 bR2L
= pTmpFrame
->IsRightToLeft();
138 // If a counter overflows?
139 if( aRefArr
[ nRefCnt
] == aArr
[ nCnt
] )
147 const SwFrame
* pRefFrame
= aRefArr
[ nRefCnt
];
148 const SwFrame
* pFieldFrame
= aArr
[ nCnt
];
150 // different frames, check their Y-/X-position
151 bool bRefIsLower
= false;
152 if( ( SwFrameType::Column
| SwFrameType::Cell
) & pFieldFrame
->GetType() ||
153 ( SwFrameType::Column
| SwFrameType::Cell
) & pRefFrame
->GetType() )
155 if( pFieldFrame
->GetType() == pRefFrame
->GetType() )
157 // here, the X-pos is more important
161 bRefIsLower
= pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() ||
162 ( pRefFrame
->getFrameArea().Top() == pFieldFrame
->getFrameArea().Top() &&
163 pRefFrame
->getFrameArea().Left() < pFieldFrame
->getFrameArea().Left() );
165 bRefIsLower
= pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() ||
166 ( pRefFrame
->getFrameArea().Top() == pFieldFrame
->getFrameArea().Top() &&
167 pRefFrame
->getFrameArea().Left() > pFieldFrame
->getFrameArea().Left() );
170 bRefIsLower
= pRefFrame
->getFrameArea().Left() > pFieldFrame
->getFrameArea().Left() ||
171 ( pRefFrame
->getFrameArea().Left() == pFieldFrame
->getFrameArea().Left() &&
172 pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() );
174 bRefIsLower
= pRefFrame
->getFrameArea().Left() < pFieldFrame
->getFrameArea().Left() ||
175 ( pRefFrame
->getFrameArea().Left() == pFieldFrame
->getFrameArea().Left() &&
176 pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() );
179 else if( ( SwFrameType::Column
| SwFrameType::Cell
) & pFieldFrame
->GetType() )
180 pFieldFrame
= aArr
[ nCnt
- 1 ];
182 pRefFrame
= aRefArr
[ nRefCnt
- 1 ];
185 if( pRefFrame
) // misuse as flag
190 bRefIsLower
= pRefFrame
->getFrameArea().Left() < pFieldFrame
->getFrameArea().Left() ||
191 ( pRefFrame
->getFrameArea().Left() == pFieldFrame
->getFrameArea().Left() &&
192 pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() );
194 bRefIsLower
= pRefFrame
->getFrameArea().Left() > pFieldFrame
->getFrameArea().Left() ||
195 ( pRefFrame
->getFrameArea().Left() == pFieldFrame
->getFrameArea().Left() &&
196 pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() );
199 bRefIsLower
= pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() ||
200 ( pRefFrame
->getFrameArea().Top() == pFieldFrame
->getFrameArea().Top() &&
201 pRefFrame
->getFrameArea().Left() > pFieldFrame
->getFrameArea().Left() );
203 bRefIsLower
= pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() ||
204 ( pRefFrame
->getFrameArea().Top() == pFieldFrame
->getFrameArea().Top() &&
205 pRefFrame
->getFrameArea().Left() < pFieldFrame
->getFrameArea().Left() );
210 // tdf#115319 create alternative reference formats, if the user asked for it
211 // (ReferenceFieldLanguage attribute of the reference field is not empty), and
212 // language of the text and ReferenceFieldLanguage are the same.
213 // Right now only HUNGARIAN seems to need this (as in the related issue,
214 // the reversed caption order in autocaption, solved by #i61007#)
215 static void lcl_formatReferenceLanguage( OUString
& rRefText
,
216 bool bClosingParenthesis
, LanguageType eLang
,
217 const OUString
& rReferenceLanguage
)
219 if (eLang
!= LANGUAGE_HUNGARIAN
|| (rReferenceLanguage
!= "hu" && rReferenceLanguage
!= "Hu"))
222 // Add Hungarian definitive article (a/az) before references,
223 // similar to \aref, \apageref etc. of LaTeX Babel package.
227 // "az 1. oldalon" ("on page 1"), but
228 // "a 2. oldalon" ("on page 2")
229 // "a fentebbi", "az alábbi" (above/below)
230 // "a Lorem", "az Ipsum"
232 // Support following numberings of EU publications:
234 // 1., 1a., a), (1), (1a), iii., III., IA.
236 // (http://publications.europa.eu/code/hu/hu-120700.htm,
237 // http://publications.europa.eu/code/hu/hu-4100600.htm)
239 LanguageTag
aLanguageTag(eLang
);
240 CharClass
aCharClass( aLanguageTag
);
241 sal_Int32 nLen
= rRefText
.getLength();
243 // substring of rRefText starting with letter or number
246 bool bArticleAz
= false;
247 // is numbering a number?
250 // search first member of the numbering (numbers or letters)
251 for (i
=0; i
<nLen
&& (sNumbering
.isEmpty() ||
252 ((bNum
&& aCharClass
.isDigit(rRefText
, i
)) ||
253 (!bNum
&& aCharClass
.isLetter(rRefText
, i
)))); ++i
)
255 // start of numbering within the field text
256 if (sNumbering
.isEmpty() && aCharClass
.isLetterNumeric(rRefText
, i
)) {
257 sNumbering
= rRefText
.copy(i
);
258 bNum
= aCharClass
.isDigit(rRefText
, i
);
262 // length of numbering
263 nLen
= i
- (rRefText
.getLength() - sNumbering
.getLength());
267 // az 1, 1000, 1000000, 1000000000...
269 if ((sNumbering
.startsWith("1") && (nLen
== 1 || nLen
== 4 || nLen
== 7 || nLen
== 10)) ||
270 sNumbering
.startsWith("5"))
273 else if (nLen
== 1 && sNumbering
[0] < 128)
275 // ASCII 1-letter numbering
276 // az a), e), f) ... x)
277 // az i., v. (but, a x.)
278 static const std::u16string_view sLettersStartingWithVowels
= u
"aefilmnorsuxyAEFILMNORSUXY";
279 if (sLettersStartingWithVowels
.find(sNumbering
[0]) != std::u16string_view::npos
)
281 // x), X) are letters, but x. and X. etc. are Roman numbers
282 if (bClosingParenthesis
||
283 (sNumbering
[0] != 'x' && sNumbering
[0] != 'X'))
285 } else if ((sNumbering
[0] == 'v' || sNumbering
[0] == 'V') && !bClosingParenthesis
)
286 // v), V) are letters, but v. and V. are Roman numbers
291 static const sal_Unicode sVowelsWithDiacritic
[] = {
292 0x00E1, 0x00C1, 0x00E9, 0x00C9, 0x00ED, 0x00CD,
293 0x00F3, 0x00D3, 0x00F6, 0x00D6, 0x0151, 0x0150,
294 0x00FA, 0x00DA, 0x00FC, 0x00DC, 0x0171, 0x0170, 0 };
295 static OUString sVowels
= OUStringLiteral(u
"aAeEiIoOuU") + sVowelsWithDiacritic
;
297 // handle more than 1-letter long Roman numbers and
298 // their possible combinations with letters:
299 // az IA, a IIB, a IIIC., az Ia, a IIb., a iiic), az LVIII. szonett
300 bool bRomanNumber
= false;
301 if (nLen
> 1 && (nLen
+ 1 >= sNumbering
.getLength() || sNumbering
[nLen
] == '.'))
303 sal_Unicode last
= sNumbering
[nLen
- 1];
304 OUString sNumberingTrim
;
305 if ((last
>= 'A' && last
< 'I') || (last
>= 'a' && last
< 'i'))
306 sNumberingTrim
= sNumbering
.copy(0, nLen
- 1);
308 sNumberingTrim
= sNumbering
.copy(0, nLen
);
310 sNumberingTrim
.replaceAll("i", "").replaceAll("v", "").replaceAll("x", "").replaceAll("l", "").replaceAll("c", "").isEmpty() ||
311 sNumberingTrim
.replaceAll("I", "").replaceAll("V", "").replaceAll("X", "").replaceAll("L", "").replaceAll("C", "").isEmpty();
315 // Roman number and a letter optionally
317 (sNumbering
[0] == 'i' && sNumbering
[1] != 'i' && sNumbering
[1] != 'v' && sNumbering
[1] != 'x') ||
318 (sNumbering
[0] == 'I' && sNumbering
[1] != 'I' && sNumbering
[1] != 'V' && sNumbering
[1] != 'X') ||
319 (sNumbering
[0] == 'v' && sNumbering
[1] != 'i') ||
320 (sNumbering
[0] == 'V' && sNumbering
[1] != 'I') ||
321 (sNumbering
[0] == 'l' && sNumbering
[1] != 'x') ||
322 (sNumbering
[0] == 'L' && sNumbering
[1] != 'X')) ) ||
323 // a word starting with vowel (not Roman number)
324 ( !bRomanNumber
&& sVowels
.indexOf(sNumbering
[0]) != -1))
329 // not a title text starting already with a definitive article
330 if ( sNumbering
.startsWith("A ") || sNumbering
.startsWith("Az ") ||
331 sNumbering
.startsWith("a ") || sNumbering
.startsWith("az ") )
334 // lowercase, if rReferenceLanguage == "hu", not "Hu"
337 if ( rReferenceLanguage
== "hu" )
345 rRefText
= sArticle
+ " " + rRefText
;
349 SwGetRefField::SwGetRefField( SwGetRefFieldType
* pFieldType
,
350 const OUString
& rSetRef
, const OUString
& rSetReferenceLanguage
, sal_uInt16 nSubTyp
,
351 sal_uInt16 nSequenceNo
, sal_uLong nFormat
)
352 : SwField( pFieldType
, nFormat
),
353 m_sSetRefName( rSetRef
),
354 m_sSetReferenceLanguage( rSetReferenceLanguage
),
355 m_nSubType( nSubTyp
),
356 m_nSeqNo( nSequenceNo
)
360 SwGetRefField::~SwGetRefField()
364 OUString
SwGetRefField::GetDescription() const
366 return SwResId(STR_REFERENCE
);
369 sal_uInt16
SwGetRefField::GetSubType() const
374 void SwGetRefField::SetSubType( sal_uInt16 n
)
380 bool SwGetRefField::IsRefToHeadingCrossRefBookmark() const
382 return GetSubType() == REF_BOOKMARK
&&
383 ::sw::mark::CrossRefHeadingBookmark::IsLegalName(m_sSetRefName
);
386 bool SwGetRefField::IsRefToNumItemCrossRefBookmark() const
388 return GetSubType() == REF_BOOKMARK
&&
389 ::sw::mark::CrossRefNumItemBookmark::IsLegalName(m_sSetRefName
);
392 const SwTextNode
* SwGetRefField::GetReferencedTextNode() const
394 SwGetRefFieldType
*pTyp
= dynamic_cast<SwGetRefFieldType
*>(GetTyp());
397 sal_Int32 nDummy
= -1;
398 return SwGetRefFieldType::FindAnchor( &pTyp
->GetDoc(), m_sSetRefName
, m_nSubType
, m_nSeqNo
, &nDummy
);
402 OUString
SwGetRefField::GetExpandedTextOfReferencedTextNode(
403 SwRootFrame
const& rLayout
) const
405 const SwTextNode
* pReferencedTextNode( GetReferencedTextNode() );
406 return pReferencedTextNode
407 ? sw::GetExpandTextMerged(&rLayout
, *pReferencedTextNode
, true, false, ExpandMode(0))
411 void SwGetRefField::SetExpand( const OUString
& rStr
)
414 m_sTextRLHidden
= rStr
;
417 OUString
SwGetRefField::ExpandImpl(SwRootFrame
const*const pLayout
) const
419 return pLayout
&& pLayout
->IsHideRedlines() ? m_sTextRLHidden
: m_sText
;
422 OUString
SwGetRefField::GetFieldName() const
424 const OUString aName
= GetTyp()->GetName();
425 if ( !aName
.isEmpty() || !m_sSetRefName
.isEmpty() )
427 return aName
+ " " + m_sSetRefName
;
429 return ExpandImpl(nullptr);
433 static void FilterText(OUString
& rText
, LanguageType
const eLang
,
434 OUString
const& rSetReferenceLanguage
)
436 // remove all special characters (replace them with blanks)
440 rText
= rText
.replaceAll(u
"\u00ad", "");
441 OUStringBuffer
aBuf(rText
);
442 const sal_Int32 l
= aBuf
.getLength();
443 for (sal_Int32 i
= 0; i
< l
; ++i
)
449 else if (aBuf
[i
] == 0x2011)
454 rText
= aBuf
.makeStringAndClear();
455 if (!rSetReferenceLanguage
.isEmpty())
457 lcl_formatReferenceLanguage(rText
, false, eLang
, rSetReferenceLanguage
);
461 // #i81002# - parameter <pFieldTextAttr> added
462 void SwGetRefField::UpdateField( const SwTextField
* pFieldTextAttr
)
465 m_sTextRLHidden
.clear();
467 SwDoc
& rDoc
= static_cast<SwGetRefFieldType
*>(GetTyp())->GetDoc();
468 // finding the reference target (the number)
469 sal_Int32 nNumStart
= -1;
470 sal_Int32 nNumEnd
= -1;
471 SwTextNode
* pTextNd
= SwGetRefFieldType::FindAnchor(
472 &rDoc
, m_sSetRefName
, m_nSubType
, m_nSeqNo
, &nNumStart
, &nNumEnd
477 m_sText
= SwViewShell::GetShellRes()->aGetRefField_RefItemNotFound
;
478 m_sTextRLHidden
= m_sText
;
482 SwRootFrame
const* pLayout(nullptr);
483 SwRootFrame
const* pLayoutRLHidden(nullptr);
484 for (SwRootFrame
const*const pLay
: rDoc
.GetAllLayouts())
486 if (pLay
->IsHideRedlines())
488 pLayoutRLHidden
= pLay
;
496 // where is the category name (e.g. "Illustration")?
497 const OUString aText
= pTextNd
->GetText();
498 const sal_Int32 nCatStart
= aText
.indexOf(m_sSetRefName
);
499 const bool bHasCat
= nCatStart
>=0;
500 const sal_Int32 nCatEnd
= bHasCat
? nCatStart
+ m_sSetRefName
.getLength() : -1;
502 // length of the referenced text
503 const sal_Int32 nLen
= aText
.getLength();
506 switch( GetFormat() )
510 case REF_ONLYCAPTION
:
513 // needed part of Text
519 case REF_SEQUENCEFLD
:
521 switch( GetFormat() )
523 // "Category and Number"
526 nStart
= std::min(nNumStart
, nCatStart
);
527 nEnd
= std::max(nNumEnd
, nCatEnd
);
535 case REF_ONLYCAPTION
: {
536 // next alphanumeric character after category+number
537 if (const SwTextAttr
* const pTextAttr
=
538 pTextNd
->GetTextAttrForCharAt(nNumStart
, RES_TXTATR_FIELD
)
540 // start searching from nFrom
541 const sal_Int32 nFrom
= bHasCat
542 ? std::max(nNumStart
+ 1, nCatEnd
)
544 nStart
= SwGetExpField::GetReferenceTextPos( pTextAttr
->GetFormatField(), rDoc
, nFrom
);
546 nStart
= bHasCat
? std::max(nNumEnd
, nCatEnd
) : nNumEnd
;
555 nEnd
= std::min(nStart
+ 1, nLen
);
558 // "Reference" (whole Text)
571 // text is spread across multiple nodes - get whole text or only until end of node?
572 nEnd
= nNumEnd
<0 ? nLen
: nNumEnd
;
582 // get number or numString
583 for( size_t i
= 0; i
< rDoc
.GetFootnoteIdxs().size(); ++i
)
585 SwTextFootnote
* const pFootnoteIdx
= rDoc
.GetFootnoteIdxs()[i
];
586 if( m_nSeqNo
== pFootnoteIdx
->GetSeqRefNo() )
588 m_sText
= pFootnoteIdx
->GetFootnote().GetViewNumStr(rDoc
, nullptr);
589 m_sTextRLHidden
= pFootnoteIdx
->GetFootnote().GetViewNumStr(rDoc
, pLayoutRLHidden
);
590 if (!m_sSetReferenceLanguage
.isEmpty())
592 lcl_formatReferenceLanguage(m_sText
, false, GetLanguage(), m_sSetReferenceLanguage
);
593 lcl_formatReferenceLanguage(m_sTextRLHidden
, false, GetLanguage(), m_sSetReferenceLanguage
);
609 if( nStart
!= nEnd
) // a section?
611 m_sText
= pTextNd
->GetExpandText(pLayout
, nStart
, nEnd
- nStart
, false, false, false, ExpandMode(0));
612 if (m_nSubType
== REF_OUTLINE
613 || (m_nSubType
== REF_SEQUENCEFLD
&& REF_CONTENT
== GetFormat()))
615 m_sTextRLHidden
= sw::GetExpandTextMerged(
616 pLayoutRLHidden
, *pTextNd
, false, false, ExpandMode(0));
620 m_sTextRLHidden
= pTextNd
->GetExpandText(pLayoutRLHidden
,
621 nStart
, nEnd
- nStart
, false, false, false, ExpandMode::HideDeletions
);
623 FilterText(m_sText
, GetLanguage(), m_sSetReferenceLanguage
);
624 FilterText(m_sTextRLHidden
, GetLanguage(), m_sSetReferenceLanguage
);
630 case REF_PAGE_PGDESC
:
633 [this, pTextNd
, nNumStart
](OUString
& rText
, SwRootFrame
const*const pLay
)
635 SwTextFrame
const* pFrame
= static_cast<SwTextFrame
*>(pTextNd
->getLayoutFrame(pLay
, nullptr, nullptr));
636 SwTextFrame
const*const pSave
= pFrame
;
639 TextFrameIndex
const nNumStartIndex(pFrame
->MapModelToView(pTextNd
, nNumStart
));
640 while (pFrame
&& !pFrame
->IsInside(nNumStartIndex
))
641 pFrame
= pFrame
->GetFollow();
644 if( pFrame
|| nullptr != ( pFrame
= pSave
))
646 sal_uInt16 nPageNo
= pFrame
->GetVirtPageNum();
647 const SwPageFrame
*pPage
;
648 if( REF_PAGE_PGDESC
== GetFormat() &&
649 nullptr != ( pPage
= pFrame
->FindPageFrame() ) &&
650 pPage
->GetPageDesc() )
652 rText
= pPage
->GetPageDesc()->GetNumType().GetNumStr(nPageNo
);
656 rText
= OUString::number(nPageNo
);
659 if (!m_sSetReferenceLanguage
.isEmpty())
660 lcl_formatReferenceLanguage(rText
, false, GetLanguage(), m_sSetReferenceLanguage
);
663 // sw_redlinehide: currently only one of these layouts will exist,
664 // so the getLayoutFrame will use the same frame in both cases
665 func(m_sText
, pLayout
);
666 func(m_sTextRLHidden
, pLayoutRLHidden
);
673 [this, pTextNd
](OUString
& rText
, SwRootFrame
const*const pLay
)
675 // a bit tricky: search any frame
676 SwFrame
const*const pFrame
= pTextNd
->getLayoutFrame(pLay
);
679 SwChapterFieldType aFieldTyp
;
680 SwChapterField
aField( &aFieldTyp
, 0 );
681 aField
.SetLevel( MAXLEVEL
- 1 );
682 aField
.ChangeExpansion( *pFrame
, pTextNd
, true );
683 rText
= aField
.GetNumber(pLay
);
685 if (!m_sSetReferenceLanguage
.isEmpty())
686 lcl_formatReferenceLanguage(rText
, false, GetLanguage(), m_sSetReferenceLanguage
);
689 func(m_sText
, pLayout
);
690 func(m_sTextRLHidden
, pLayoutRLHidden
);
697 // simplified: use parameter <pFieldTextAttr>
698 if( !pFieldTextAttr
|| !pFieldTextAttr
->GetpTextNode() )
701 LanguageTag
aLanguageTag( GetLanguage());
702 LocaleDataWrapper
aLocaleData( aLanguageTag
);
704 // first a "short" test - in case both are in the same node
705 if( pFieldTextAttr
->GetpTextNode() == pTextNd
)
707 m_sText
= nNumStart
< pFieldTextAttr
->GetStart()
708 ? aLocaleData
.getAboveWord()
709 : aLocaleData
.getBelowWord();
710 m_sTextRLHidden
= m_sText
;
714 m_sText
= ::IsFrameBehind( *pFieldTextAttr
->GetpTextNode(), pFieldTextAttr
->GetStart(),
715 *pTextNd
, nNumStart
)
716 ? aLocaleData
.getAboveWord()
717 : aLocaleData
.getBelowWord();
719 if (!m_sSetReferenceLanguage
.isEmpty())
720 lcl_formatReferenceLanguage(m_sText
, false, GetLanguage(), m_sSetReferenceLanguage
);
722 m_sTextRLHidden
= m_sText
;
727 case REF_NUMBER_NO_CONTEXT
:
728 case REF_NUMBER_FULL_CONTEXT
:
730 if ( pFieldTextAttr
&& pFieldTextAttr
->GetpTextNode() )
733 MakeRefNumStr(pLayout
, pFieldTextAttr
->GetTextNode(), *pTextNd
, GetFormat());
734 m_sText
= result
.first
;
735 // for differentiation of Roman numbers and letters in Hungarian article handling
736 bool bClosingParenthesis
= result
.second
;
737 if (!m_sSetReferenceLanguage
.isEmpty())
739 lcl_formatReferenceLanguage(m_sText
, bClosingParenthesis
, GetLanguage(), m_sSetReferenceLanguage
);
742 MakeRefNumStr(pLayoutRLHidden
, pFieldTextAttr
->GetTextNode(), *pTextNd
, GetFormat());
743 m_sTextRLHidden
= result
.first
;
744 bClosingParenthesis
= result
.second
;
745 if (!m_sSetReferenceLanguage
.isEmpty())
747 lcl_formatReferenceLanguage(m_sTextRLHidden
, bClosingParenthesis
, GetLanguage(), m_sSetReferenceLanguage
);
754 OSL_FAIL("<SwGetRefField::UpdateField(..)> - unknown format type");
759 static std::pair
<OUString
, bool> MakeRefNumStr(
760 SwRootFrame
const*const pLayout
,
761 const SwTextNode
& i_rTextNodeOfField
,
762 const SwTextNode
& i_rTextNodeOfReferencedItem
,
763 const sal_uInt32 nRefNumFormat
)
765 SwTextNode
const& rTextNodeOfField(pLayout
766 ? *sw::GetParaPropsNode(*pLayout
, i_rTextNodeOfField
)
767 : i_rTextNodeOfField
);
768 SwTextNode
const& rTextNodeOfReferencedItem(pLayout
769 ? *sw::GetParaPropsNode(*pLayout
, i_rTextNodeOfReferencedItem
)
770 : i_rTextNodeOfReferencedItem
);
771 if ( rTextNodeOfReferencedItem
.HasNumber() &&
772 rTextNodeOfReferencedItem
.IsCountedInList() )
774 OSL_ENSURE( rTextNodeOfReferencedItem
.GetNum(pLayout
),
775 "<SwGetRefField::MakeRefNumStr(..)> - referenced paragraph has number, but no <SwNodeNum> instance!" );
777 // Determine, up to which level the superior list labels have to be
778 // included - default is to include all superior list labels.
779 int nRestrictInclToThisLevel( 0 );
780 // Determine for format REF_NUMBER the level, up to which the superior
781 // list labels have to be restricted, if the text node of the reference
782 // field and the text node of the referenced item are in the same
784 if ( nRefNumFormat
== REF_NUMBER
&&
785 rTextNodeOfField
.FindFlyStartNode()
786 == rTextNodeOfReferencedItem
.FindFlyStartNode() &&
787 rTextNodeOfField
.FindFootnoteStartNode()
788 == rTextNodeOfReferencedItem
.FindFootnoteStartNode() &&
789 rTextNodeOfField
.FindHeaderStartNode()
790 == rTextNodeOfReferencedItem
.FindHeaderStartNode() &&
791 rTextNodeOfField
.FindFooterStartNode()
792 == rTextNodeOfReferencedItem
.FindFooterStartNode() )
794 const SwNodeNum
* pNodeNumForTextNodeOfField( nullptr );
795 if ( rTextNodeOfField
.HasNumber() &&
796 rTextNodeOfField
.GetNumRule() == rTextNodeOfReferencedItem
.GetNumRule() )
798 pNodeNumForTextNodeOfField
= rTextNodeOfField
.GetNum(pLayout
);
802 pNodeNumForTextNodeOfField
=
803 rTextNodeOfReferencedItem
.GetNum(pLayout
)->GetPrecedingNodeNumOf(rTextNodeOfField
);
805 if ( pNodeNumForTextNodeOfField
)
807 const SwNumberTree::tNumberVector rFieldNumVec
=
808 pNodeNumForTextNodeOfField
->GetNumberVector();
809 const SwNumberTree::tNumberVector rRefItemNumVec
=
810 rTextNodeOfReferencedItem
.GetNum()->GetNumberVector();
811 std::size_t nLevel( 0 );
812 while ( nLevel
< rFieldNumVec
.size() && nLevel
< rRefItemNumVec
.size() )
814 if ( rRefItemNumVec
[nLevel
] == rFieldNumVec
[nLevel
] )
816 nRestrictInclToThisLevel
= nLevel
+ 1;
827 // Determine, if superior list labels have to be included
828 const bool bInclSuperiorNumLabels(
829 ( nRestrictInclToThisLevel
< rTextNodeOfReferencedItem
.GetActualListLevel() &&
830 ( nRefNumFormat
== REF_NUMBER
|| nRefNumFormat
== REF_NUMBER_FULL_CONTEXT
) ) );
832 OSL_ENSURE( rTextNodeOfReferencedItem
.GetNumRule(),
833 "<SwGetRefField::MakeRefNumStr(..)> - referenced numbered paragraph has no numbering rule set!" );
834 return std::make_pair(
835 rTextNodeOfReferencedItem
.GetNumRule()->MakeRefNumString(
836 *(rTextNodeOfReferencedItem
.GetNum(pLayout
)),
837 bInclSuperiorNumLabels
,
838 nRestrictInclToThisLevel
),
839 rTextNodeOfReferencedItem
.GetNumRule()->MakeNumString(
840 *(rTextNodeOfReferencedItem
.GetNum(pLayout
)),
841 true).endsWith(")") );
844 return std::make_pair(OUString(), false);
847 std::unique_ptr
<SwField
> SwGetRefField::Copy() const
849 std::unique_ptr
<SwGetRefField
> pField( new SwGetRefField( static_cast<SwGetRefFieldType
*>(GetTyp()),
850 m_sSetRefName
, m_sSetReferenceLanguage
, m_nSubType
,
851 m_nSeqNo
, GetFormat() ) );
852 pField
->m_sText
= m_sText
;
853 pField
->m_sTextRLHidden
= m_sTextRLHidden
;
854 return std::unique_ptr
<SwField
>(pField
.release());
857 /// get reference name
858 OUString
SwGetRefField::GetPar1() const
860 return m_sSetRefName
;
863 /// set reference name
864 void SwGetRefField::SetPar1( const OUString
& rName
)
866 m_sSetRefName
= rName
;
869 OUString
SwGetRefField::GetPar2() const
871 return ExpandImpl(nullptr);
874 bool SwGetRefField::QueryValue( uno::Any
& rAny
, sal_uInt16 nWhichId
) const
878 case FIELD_PROP_USHORT1
:
883 case REF_PAGE
: nPart
= ReferenceFieldPart::PAGE
; break;
884 case REF_CHAPTER
: nPart
= ReferenceFieldPart::CHAPTER
; break;
885 case REF_CONTENT
: nPart
= ReferenceFieldPart::TEXT
; break;
886 case REF_UPDOWN
: nPart
= ReferenceFieldPart::UP_DOWN
; break;
887 case REF_PAGE_PGDESC
: nPart
= ReferenceFieldPart::PAGE_DESC
; break;
888 case REF_ONLYNUMBER
: nPart
= ReferenceFieldPart::CATEGORY_AND_NUMBER
; break;
889 case REF_ONLYCAPTION
: nPart
= ReferenceFieldPart::ONLY_CAPTION
; break;
890 case REF_ONLYSEQNO
: nPart
= ReferenceFieldPart::ONLY_SEQUENCE_NUMBER
; break;
892 case REF_NUMBER
: nPart
= ReferenceFieldPart::NUMBER
; break;
893 case REF_NUMBER_NO_CONTEXT
: nPart
= ReferenceFieldPart::NUMBER_NO_CONTEXT
; break;
894 case REF_NUMBER_FULL_CONTEXT
: nPart
= ReferenceFieldPart::NUMBER_FULL_CONTEXT
; break;
899 case FIELD_PROP_USHORT2
:
901 sal_Int16 nSource
= 0;
904 case REF_SETREFATTR
: nSource
= ReferenceFieldSource::REFERENCE_MARK
; break;
905 case REF_SEQUENCEFLD
: nSource
= ReferenceFieldSource::SEQUENCE_FIELD
; break;
906 case REF_BOOKMARK
: nSource
= ReferenceFieldSource::BOOKMARK
; break;
907 case REF_OUTLINE
: OSL_FAIL("not implemented"); break;
908 case REF_FOOTNOTE
: nSource
= ReferenceFieldSource::FOOTNOTE
; break;
909 case REF_ENDNOTE
: nSource
= ReferenceFieldSource::ENDNOTE
; break;
914 case FIELD_PROP_PAR1
:
916 OUString
sTmp(GetPar1());
917 if(REF_SEQUENCEFLD
== m_nSubType
)
919 sal_uInt16 nPoolId
= SwStyleNameMapper::GetPoolIdFromUIName( sTmp
, SwGetPoolIdFromName::TxtColl
);
922 case RES_POOLCOLL_LABEL_ABB
:
923 case RES_POOLCOLL_LABEL_TABLE
:
924 case RES_POOLCOLL_LABEL_FRAME
:
925 case RES_POOLCOLL_LABEL_DRAWING
:
926 case RES_POOLCOLL_LABEL_FIGURE
:
927 SwStyleNameMapper::FillProgName(nPoolId
, sTmp
) ;
934 case FIELD_PROP_PAR3
:
935 rAny
<<= ExpandImpl(nullptr);
937 case FIELD_PROP_PAR4
:
938 rAny
<<= m_sSetReferenceLanguage
;
940 case FIELD_PROP_SHORT1
:
941 rAny
<<= static_cast<sal_Int16
>(m_nSeqNo
);
949 bool SwGetRefField::PutValue( const uno::Any
& rAny
, sal_uInt16 nWhichId
)
953 case FIELD_PROP_USHORT1
:
959 case ReferenceFieldPart::PAGE
: nPart
= REF_PAGE
; break;
960 case ReferenceFieldPart::CHAPTER
: nPart
= REF_CHAPTER
; break;
961 case ReferenceFieldPart::TEXT
: nPart
= REF_CONTENT
; break;
962 case ReferenceFieldPart::UP_DOWN
: nPart
= REF_UPDOWN
; break;
963 case ReferenceFieldPart::PAGE_DESC
: nPart
= REF_PAGE_PGDESC
; break;
964 case ReferenceFieldPart::CATEGORY_AND_NUMBER
: nPart
= REF_ONLYNUMBER
; break;
965 case ReferenceFieldPart::ONLY_CAPTION
: nPart
= REF_ONLYCAPTION
; break;
966 case ReferenceFieldPart::ONLY_SEQUENCE_NUMBER
: nPart
= REF_ONLYSEQNO
; break;
968 case ReferenceFieldPart::NUMBER
: nPart
= REF_NUMBER
; break;
969 case ReferenceFieldPart::NUMBER_NO_CONTEXT
: nPart
= REF_NUMBER_NO_CONTEXT
; break;
970 case ReferenceFieldPart::NUMBER_FULL_CONTEXT
: nPart
= REF_NUMBER_FULL_CONTEXT
; break;
971 default: return false;
976 case FIELD_PROP_USHORT2
:
978 sal_Int16 nSource
= 0;
982 case ReferenceFieldSource::REFERENCE_MARK
: m_nSubType
= REF_SETREFATTR
; break;
983 case ReferenceFieldSource::SEQUENCE_FIELD
:
985 if(REF_SEQUENCEFLD
== m_nSubType
)
987 m_nSubType
= REF_SEQUENCEFLD
;
988 ConvertProgrammaticToUIName();
991 case ReferenceFieldSource::BOOKMARK
: m_nSubType
= REF_BOOKMARK
; break;
992 case ReferenceFieldSource::FOOTNOTE
: m_nSubType
= REF_FOOTNOTE
; break;
993 case ReferenceFieldSource::ENDNOTE
: m_nSubType
= REF_ENDNOTE
; break;
997 case FIELD_PROP_PAR1
:
1002 ConvertProgrammaticToUIName();
1005 case FIELD_PROP_PAR3
:
1009 SetExpand( sTmpStr
);
1012 case FIELD_PROP_PAR4
:
1013 rAny
>>= m_sSetReferenceLanguage
;
1015 case FIELD_PROP_SHORT1
:
1017 sal_Int16 nSetSeq
= 0;
1029 void SwGetRefField::ConvertProgrammaticToUIName()
1031 if(!(GetTyp() && REF_SEQUENCEFLD
== m_nSubType
))
1034 SwDoc
& rDoc
= static_cast<SwGetRefFieldType
*>(GetTyp())->GetDoc();
1035 const OUString rPar1
= GetPar1();
1036 // don't convert when the name points to an existing field type
1037 if (rDoc
.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp
, rPar1
, false))
1040 sal_uInt16 nPoolId
= SwStyleNameMapper::GetPoolIdFromProgName( rPar1
, SwGetPoolIdFromName::TxtColl
);
1041 const char* pResId
= nullptr;
1044 case RES_POOLCOLL_LABEL_ABB
:
1045 pResId
= STR_POOLCOLL_LABEL_ABB
;
1047 case RES_POOLCOLL_LABEL_TABLE
:
1048 pResId
= STR_POOLCOLL_LABEL_TABLE
;
1050 case RES_POOLCOLL_LABEL_FRAME
:
1051 pResId
= STR_POOLCOLL_LABEL_FRAME
;
1053 case RES_POOLCOLL_LABEL_DRAWING
:
1054 pResId
= STR_POOLCOLL_LABEL_DRAWING
;
1056 case RES_POOLCOLL_LABEL_FIGURE
:
1057 pResId
= STR_POOLCOLL_LABEL_FIGURE
;
1061 SetPar1(SwResId(pResId
));
1064 SwGetRefFieldType::SwGetRefFieldType( SwDoc
& rDc
)
1065 : SwFieldType( SwFieldIds::GetRef
), m_rDoc( rDc
)
1068 std::unique_ptr
<SwFieldType
> SwGetRefFieldType::Copy() const
1070 return std::make_unique
<SwGetRefFieldType
>( m_rDoc
);
1073 void SwGetRefFieldType::UpdateGetReferences()
1075 std::vector
<SwFormatField
*> vFields
;
1076 GatherFields(vFields
, false);
1077 for(auto pFormatField
: vFields
)
1079 // update only the GetRef fields
1080 //JP 3.4.2001: Task 71231 - we need the correct language
1081 SwGetRefField
* pGRef
= static_cast<SwGetRefField
*>(pFormatField
->GetField());
1082 const SwTextField
* pTField
;
1083 if(!pGRef
->GetLanguage() &&
1084 nullptr != (pTField
= pFormatField
->GetTextField()) &&
1085 pTField
->GetpTextNode())
1087 pGRef
->SetLanguage(pTField
->GetpTextNode()->GetLang(pTField
->GetStart()));
1091 pGRef
->UpdateField(pFormatField
->GetTextField());
1093 NotifyClients(nullptr, nullptr);
1096 void SwGetRefFieldType::SwClientNotify(const SwModify
&, const SfxHint
& rHint
)
1098 auto pLegacy
= dynamic_cast<const sw::LegacyModifyHint
*>(&rHint
);
1101 if(!pLegacy
->m_pNew
&& !pLegacy
->m_pOld
)
1102 // update to all GetReference fields
1103 // hopefully, this codepath is soon dead code, and
1104 // UpdateGetReferences gets only called directly
1105 UpdateGetReferences();
1107 // forward to text fields, they "expand" the text
1108 NotifyClients(pLegacy
->m_pOld
, pLegacy
->m_pNew
);
1113 bool IsMarkHintHidden(SwRootFrame
const& rLayout
,
1114 SwTextNode
const& rNode
, SwTextAttrEnd
const& rHint
)
1116 if (!rLayout
.HasMergedParas())
1120 SwTextFrame
const*const pFrame(static_cast<SwTextFrame
const*>(
1121 rNode
.getLayoutFrame(&rLayout
)));
1126 sal_Int32
const*const pEnd(rHint
.GetEnd());
1129 return pFrame
->MapModelToView(&rNode
, rHint
.GetStart())
1130 == pFrame
->MapModelToView(&rNode
, *pEnd
);
1134 assert(rHint
.HasDummyChar());
1135 return pFrame
->MapModelToView(&rNode
, rHint
.GetStart())
1136 == pFrame
->MapModelToView(&rNode
, rHint
.GetStart() + 1);
1142 SwTextNode
* SwGetRefFieldType::FindAnchor( SwDoc
* pDoc
, const OUString
& rRefMark
,
1143 sal_uInt16 nSubType
, sal_uInt16 nSeqNo
,
1144 sal_Int32
* pStt
, sal_Int32
* pEnd
,
1145 SwRootFrame
const*const pLayout
)
1147 OSL_ENSURE( pStt
, "Why did no one check the StartPos?" );
1149 IDocumentRedlineAccess
& rIDRA(pDoc
->getIDocumentRedlineAccess());
1150 SwTextNode
* pTextNd
= nullptr;
1153 case REF_SETREFATTR
:
1155 const SwFormatRefMark
*pRef
= pDoc
->GetRefMark( rRefMark
);
1156 SwTextRefMark
const*const pRefMark(pRef
? pRef
->GetTextRefMark() : nullptr);
1157 if (pRefMark
&& (!pLayout
|| !sw::IsMarkHintHidden(*pLayout
,
1158 pRefMark
->GetTextNode(), *pRefMark
)))
1160 pTextNd
= const_cast<SwTextNode
*>(&pRef
->GetTextRefMark()->GetTextNode());
1161 *pStt
= pRef
->GetTextRefMark()->GetStart();
1163 *pEnd
= pRef
->GetTextRefMark()->GetAnyEnd();
1168 case REF_SEQUENCEFLD
:
1170 SwFieldType
* pFieldType
= pDoc
->getIDocumentFieldsAccess().GetFieldType( SwFieldIds::SetExp
, rRefMark
, false );
1171 if( pFieldType
&& pFieldType
->HasWriterListeners() &&
1172 nsSwGetSetExpType::GSE_SEQ
& static_cast<SwSetExpFieldType
*>(pFieldType
)->GetType() )
1174 std::vector
<SwFormatField
*> vFields
;
1175 pFieldType
->GatherFields(vFields
, false);
1176 for(auto pFormatField
: vFields
)
1178 SwTextField
*const pTextField(pFormatField
->GetTextField());
1179 if (pTextField
&& nSeqNo
==
1180 static_cast<SwSetExpField
*>(pFormatField
->GetField())->GetSeqNumber()
1181 && (!pLayout
|| !pLayout
->IsHideRedlines()
1182 || !sw::IsFieldDeletedInModel(rIDRA
, *pTextField
)))
1184 pTextNd
= pTextField
->GetpTextNode();
1185 *pStt
= pTextField
->GetStart();
1187 *pEnd
= (*pStt
) + 1;
1197 IDocumentMarkAccess::const_iterator_t ppMark
= pDoc
->getIDocumentMarkAccess()->findMark(rRefMark
);
1198 if (ppMark
!= pDoc
->getIDocumentMarkAccess()->getAllMarksEnd()
1199 && (!pLayout
|| !pLayout
->IsHideRedlines()
1200 || !sw::IsMarkHidden(*pLayout
, **ppMark
)))
1202 const ::sw::mark::IMark
* pBkmk
= *ppMark
;
1203 const SwPosition
* pPos
= &pBkmk
->GetMarkStart();
1205 pTextNd
= pPos
->nNode
.GetNode().GetTextNode();
1206 *pStt
= pPos
->nContent
.GetIndex();
1209 if(!pBkmk
->IsExpanded())
1213 if(dynamic_cast< ::sw::mark::CrossRefBookmark
const *>(pBkmk
))
1215 OSL_ENSURE( pTextNd
,
1216 "<SwGetRefFieldType::FindAnchor(..)> - node marked by cross-reference bookmark isn't a text node --> crash" );
1217 *pEnd
= pTextNd
->Len();
1220 else if(pBkmk
->GetOtherMarkPos().nNode
== pBkmk
->GetMarkPos().nNode
)
1221 *pEnd
= pBkmk
->GetMarkEnd().nContent
.GetIndex();
1235 for( auto pFootnoteIdx
: pDoc
->GetFootnoteIdxs() )
1236 if( nSeqNo
== pFootnoteIdx
->GetSeqRefNo() )
1238 if (pLayout
&& pLayout
->IsHideRedlines()
1239 && sw::IsFootnoteDeleted(rIDRA
, *pFootnoteIdx
))
1243 // otherwise: the position at the start of the footnote
1244 // will be mapped to something visible at least...
1245 SwNodeIndex
* pIdx
= pFootnoteIdx
->GetStartNode();
1248 SwNodeIndex
aIdx( *pIdx
, 1 );
1249 pTextNd
= aIdx
.GetNode().GetTextNode();
1250 if( nullptr == pTextNd
)
1251 pTextNd
= static_cast<SwTextNode
*>(pDoc
->GetNodes().GoNext( &aIdx
));
1271 std::set
<sal_uInt16
> aIds
;
1272 std::set
<sal_uInt16
> aDstIds
;
1273 std::map
<sal_uInt16
, sal_uInt16
> sequencedIds
; /// ID numbers sorted by sequence number.
1276 void Init(SwDoc
& rDoc
, SwDoc
& rDestDoc
, bool bField
);
1277 static void GetNoteIdsFromDoc( SwDoc
& rDoc
, std::set
<sal_uInt16
> &rIds
);
1278 void GetFieldIdsFromDoc( SwDoc
& rDoc
, std::set
<sal_uInt16
> &rIds
);
1279 void AddId( sal_uInt16 id
, sal_uInt16 seqNum
);
1280 static sal_uInt16
GetFirstUnusedId( std::set
<sal_uInt16
> &rIds
);
1283 explicit RefIdsMap( const OUString
& rName
) : aName( rName
), bInit( false ) {}
1285 void Check( SwDoc
& rDoc
, SwDoc
& rDestDoc
, SwGetRefField
& rField
, bool bField
);
1287 const OUString
& GetName() const { return aName
; }
1292 /// Get a sorted list of the field IDs from a document.
1293 /// @param[in] rDoc The document to search.
1294 /// @param[in,out] rIds The list of IDs found in the document.
1295 void RefIdsMap::GetFieldIdsFromDoc( SwDoc
& rDoc
, std::set
<sal_uInt16
> &rIds
)
1297 SwFieldType
*const pType
= rDoc
.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp
, aName
, false);
1300 std::vector
<SwFormatField
*> vFields
;
1301 pType
->GatherFields(vFields
);
1302 for(const auto pF
: vFields
)
1303 rIds
.insert(static_cast<SwSetExpField
const*>(pF
->GetField())->GetSeqNumber());
1306 /// Get a sorted list of the footnote/endnote IDs from a document.
1307 /// @param[in] rDoc The document to search.
1308 /// @param[in,out] rIds The list of IDs found in the document.
1309 void RefIdsMap::GetNoteIdsFromDoc( SwDoc
& rDoc
, std::set
<sal_uInt16
> &rIds
)
1311 for( auto n
= rDoc
.GetFootnoteIdxs().size(); n
; )
1312 rIds
.insert( rDoc
.GetFootnoteIdxs()[ --n
]->GetSeqRefNo() );
1315 /// Initialise the aIds and aDestIds collections from the source documents.
1316 /// @param[in] rDoc The source document.
1317 /// @param[in] rDestDoc The destination document.
1318 /// @param[in] bField True if we're interested in all fields, false for footnotes.
1319 void RefIdsMap::Init( SwDoc
& rDoc
, SwDoc
& rDestDoc
, bool bField
)
1326 GetFieldIdsFromDoc( rDestDoc
, aIds
);
1327 GetFieldIdsFromDoc( rDoc
, aDstIds
);
1329 // Map all the new src fields to the next available unused id
1330 for (const auto& rId
: aDstIds
)
1331 AddId( GetFirstUnusedId(aIds
), rId
);
1333 // Change the Sequence number of all SetExp fields in the source document
1334 SwFieldType
* pType
= rDoc
.getIDocumentFieldsAccess().GetFieldType( SwFieldIds::SetExp
, aName
, false );
1337 std::vector
<SwFormatField
*> vFields
;
1338 pType
->GatherFields(vFields
, false);
1339 for(auto pF
: vFields
)
1341 if(!pF
->GetTextField())
1343 SwSetExpField
*const pSetExp(static_cast<SwSetExpField
*>(pF
->GetField()));
1344 sal_uInt16
const n
= pSetExp
->GetSeqNumber();
1345 pSetExp
->SetSeqNumber(sequencedIds
[n
]);
1351 GetNoteIdsFromDoc( rDestDoc
, aIds
);
1352 GetNoteIdsFromDoc( rDoc
, aDstIds
);
1354 for (const auto& rId
: aDstIds
)
1355 AddId( GetFirstUnusedId(aIds
), rId
);
1357 // Change the footnotes/endnotes in the source doc to the new ID
1358 for ( const auto pFootnoteIdx
: rDoc
.GetFootnoteIdxs() )
1360 sal_uInt16
const n
= pFootnoteIdx
->GetSeqRefNo();
1361 pFootnoteIdx
->SetSeqNo(sequencedIds
[n
]);
1367 /// Get the lowest number unused in the passed set.
1368 /// @param[in] rIds The set of used ID numbers.
1369 /// @returns The lowest number unused by the passed set
1370 sal_uInt16
RefIdsMap::GetFirstUnusedId( std::set
<sal_uInt16
> &rIds
)
1374 for( const auto& rId
: rIds
)
1385 /// Add a new ID and sequence number to the "occupied" collection.
1386 /// @param[in] id The ID number.
1387 /// @param[in] seqNum The sequence number.
1388 void RefIdsMap::AddId( sal_uInt16 id
, sal_uInt16 seqNum
)
1391 sequencedIds
[ seqNum
] = id
;
1394 void RefIdsMap::Check( SwDoc
& rDoc
, SwDoc
& rDestDoc
, SwGetRefField
& rField
,
1397 Init( rDoc
, rDestDoc
, bField
);
1399 sal_uInt16
const nSeqNo
= rField
.GetSeqNo();
1401 // check if it needs to be remapped
1402 // if sequencedIds doesn't contain the number, it means there is no
1403 // SetExp field / footnote in the source document: do not modify
1404 // the number, which works well for copy from/paste to same document
1405 // (and if it is not the same document, there's no "correct" result anyway)
1406 if (sequencedIds
.count(nSeqNo
))
1408 rField
.SetSeqNo( sequencedIds
[nSeqNo
] );
1412 /// 1. if _both_ SetExp + GetExp / Footnote + GetExp field are copied,
1413 /// ensure that both get a new unused matching number
1414 /// 2. if only SetExp / Footnote is copied, it gets a new unused number
1415 /// 3. if only GetExp field is copied, for the case of copy from / paste to
1416 /// same document it's desirable to keep the same number;
1417 /// for other cases of copy/paste or master documents it's not obvious
1418 /// what is most desirable since it's going to be wrong anyway
1419 void SwGetRefFieldType::MergeWithOtherDoc( SwDoc
& rDestDoc
)
1421 if (&rDestDoc
== &m_rDoc
)
1424 if (rDestDoc
.IsClipBoard())
1426 // when copying _to_ clipboard, expectation is that no fields exist
1427 // so no re-mapping is required to avoid collisions
1428 assert(!rDestDoc
.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef
)->HasWriterListeners());
1429 return; // don't modify the fields in the source doc
1432 // then there are RefFields in the DescDox - so all RefFields in the SourceDoc
1433 // need to be converted to have unique IDs for both documents
1434 RefIdsMap aFntMap
{ OUString() };
1435 std::vector
<std::unique_ptr
<RefIdsMap
>> aFieldMap
;
1437 std::vector
<SwFormatField
*> vFields
;
1438 GatherFields(vFields
);
1439 for(auto pField
: vFields
)
1441 SwGetRefField
& rRefField
= *static_cast<SwGetRefField
*>(pField
->GetField());
1442 switch( rRefField
.GetSubType() )
1444 case REF_SEQUENCEFLD
:
1446 RefIdsMap
* pMap
= nullptr;
1447 for( auto n
= aFieldMap
.size(); n
; )
1449 if (aFieldMap
[ --n
]->GetName() == rRefField
.GetSetRefName())
1451 pMap
= aFieldMap
[ n
].get();
1457 pMap
= new RefIdsMap( rRefField
.GetSetRefName() );
1458 aFieldMap
.push_back(std::unique_ptr
<RefIdsMap
>(pMap
));
1461 pMap
->Check(m_rDoc
, rDestDoc
, rRefField
, true);
1467 aFntMap
.Check(m_rDoc
, rDestDoc
, rRefField
, false);
1473 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */