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>
52 #include <unofldmid.h>
53 #include <SwStyleNameMapper.hxx>
54 #include <shellres.hxx>
55 #include <poolfmt.hxx>
56 #include <strings.hrc>
57 #include <numrule.hxx>
58 #include <SwNodeNum.hxx>
65 #include <string_view>
69 using namespace ::com::sun::star
;
70 using namespace ::com::sun::star::text
;
71 using namespace ::com::sun::star::lang
;
73 static std::pair
<OUString
, bool> MakeRefNumStr(SwRootFrame
const* pLayout
,
74 const SwTextNode
& rTextNodeOfField
,
75 const SwTextNode
& rTextNodeOfReferencedItem
,
76 sal_uInt32 nRefNumFormat
);
78 static void lcl_GetLayTree( const SwFrame
* pFrame
, std::vector
<const SwFrame
*>& rArr
)
82 if( pFrame
->IsBodyFrame() ) // unspectacular
83 pFrame
= pFrame
->GetUpper();
86 rArr
.push_back( pFrame
);
88 // this is the last page
89 if( pFrame
->IsPageFrame() )
92 if( pFrame
->IsFlyFrame() )
93 pFrame
= static_cast<const SwFlyFrame
*>(pFrame
)->GetAnchorFrame();
95 pFrame
= pFrame
->GetUpper();
100 bool IsFrameBehind( const SwTextNode
& rMyNd
, sal_Int32 nMySttPos
,
101 const SwTextNode
& rBehindNd
, sal_Int32 nSttPos
)
103 const SwTextFrame
* pMyFrame
= static_cast<SwTextFrame
*>(rMyNd
.getLayoutFrame(
104 rMyNd
.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr));
105 const SwTextFrame
* pFrame
= static_cast<SwTextFrame
*>(rBehindNd
.getLayoutFrame(
106 rBehindNd
.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr));
108 if( !pFrame
|| !pMyFrame
)
111 TextFrameIndex
const nMySttPosIndex(pMyFrame
->MapModelToView(&rMyNd
, nMySttPos
));
112 TextFrameIndex
const nSttPosIndex(pFrame
->MapModelToView(&rBehindNd
, nSttPos
));
113 while (pFrame
&& !pFrame
->IsInside(nSttPosIndex
))
114 pFrame
= pFrame
->GetFollow();
115 while (pMyFrame
&& !pMyFrame
->IsInside(nMySttPosIndex
))
116 pMyFrame
= pMyFrame
->GetFollow();
118 if( !pFrame
|| !pMyFrame
|| pFrame
== pMyFrame
)
121 std::vector
<const SwFrame
*> aRefArr
, aArr
;
122 ::lcl_GetLayTree( pFrame
, aRefArr
);
123 ::lcl_GetLayTree( pMyFrame
, aArr
);
125 size_t nRefCnt
= aRefArr
.size() - 1, nCnt
= aArr
.size() - 1;
129 // Loop as long as a frame does not equal?
130 while( nRefCnt
&& nCnt
&& aRefArr
[ nRefCnt
] == aArr
[ nCnt
] )
132 const SwFrame
* pTmpFrame
= aArr
[ nCnt
];
133 bVert
= pTmpFrame
->IsVertical();
134 bR2L
= pTmpFrame
->IsRightToLeft();
139 // If a counter overflows?
140 if( aRefArr
[ nRefCnt
] == aArr
[ nCnt
] )
148 const SwFrame
* pRefFrame
= aRefArr
[ nRefCnt
];
149 const SwFrame
* pFieldFrame
= aArr
[ nCnt
];
151 // different frames, check their Y-/X-position
152 bool bRefIsLower
= false;
153 if( ( SwFrameType::Column
| SwFrameType::Cell
) & pFieldFrame
->GetType() ||
154 ( SwFrameType::Column
| SwFrameType::Cell
) & pRefFrame
->GetType() )
156 if( pFieldFrame
->GetType() == pRefFrame
->GetType() )
158 // here, the X-pos is more important
162 bRefIsLower
= pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() ||
163 ( pRefFrame
->getFrameArea().Top() == pFieldFrame
->getFrameArea().Top() &&
164 pRefFrame
->getFrameArea().Left() < pFieldFrame
->getFrameArea().Left() );
166 bRefIsLower
= pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() ||
167 ( pRefFrame
->getFrameArea().Top() == pFieldFrame
->getFrameArea().Top() &&
168 pRefFrame
->getFrameArea().Left() > pFieldFrame
->getFrameArea().Left() );
171 bRefIsLower
= pRefFrame
->getFrameArea().Left() > pFieldFrame
->getFrameArea().Left() ||
172 ( pRefFrame
->getFrameArea().Left() == pFieldFrame
->getFrameArea().Left() &&
173 pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() );
175 bRefIsLower
= pRefFrame
->getFrameArea().Left() < pFieldFrame
->getFrameArea().Left() ||
176 ( pRefFrame
->getFrameArea().Left() == pFieldFrame
->getFrameArea().Left() &&
177 pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() );
180 else if( ( SwFrameType::Column
| SwFrameType::Cell
) & pFieldFrame
->GetType() )
181 pFieldFrame
= aArr
[ nCnt
- 1 ];
183 pRefFrame
= aRefArr
[ nRefCnt
- 1 ];
186 if( pRefFrame
) // misuse as flag
191 bRefIsLower
= pRefFrame
->getFrameArea().Left() < pFieldFrame
->getFrameArea().Left() ||
192 ( pRefFrame
->getFrameArea().Left() == pFieldFrame
->getFrameArea().Left() &&
193 pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() );
195 bRefIsLower
= pRefFrame
->getFrameArea().Left() > pFieldFrame
->getFrameArea().Left() ||
196 ( pRefFrame
->getFrameArea().Left() == pFieldFrame
->getFrameArea().Left() &&
197 pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() );
200 bRefIsLower
= pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() ||
201 ( pRefFrame
->getFrameArea().Top() == pFieldFrame
->getFrameArea().Top() &&
202 pRefFrame
->getFrameArea().Left() > pFieldFrame
->getFrameArea().Left() );
204 bRefIsLower
= pRefFrame
->getFrameArea().Top() < pFieldFrame
->getFrameArea().Top() ||
205 ( pRefFrame
->getFrameArea().Top() == pFieldFrame
->getFrameArea().Top() &&
206 pRefFrame
->getFrameArea().Left() < pFieldFrame
->getFrameArea().Left() );
211 // tdf#115319 create alternative reference formats, if the user asked for it
212 // (ReferenceFieldLanguage attribute of the reference field is not empty), and
213 // language of the text and ReferenceFieldLanguage are the same.
214 // Right now only HUNGARIAN seems to need this (as in the related issue,
215 // the reversed caption order in autocaption, solved by #i61007#)
216 static void lcl_formatReferenceLanguage( OUString
& rRefText
,
217 bool bClosingParenthesis
, LanguageType eLang
,
218 std::u16string_view rReferenceLanguage
)
220 if (eLang
!= LANGUAGE_HUNGARIAN
|| (rReferenceLanguage
!= u
"hu" && rReferenceLanguage
!= u
"Hu"))
223 // Add Hungarian definitive article (a/az) before references,
224 // similar to \aref, \apageref etc. of LaTeX Babel package.
228 // "az 1. oldalon" ("on page 1"), but
229 // "a 2. oldalon" ("on page 2")
230 // "a fentebbi", "az alábbi" (above/below)
231 // "a Lorem", "az Ipsum"
233 // Support following numberings of EU publications:
235 // 1., 1a., a), (1), (1a), iii., III., IA.
237 // (http://publications.europa.eu/code/hu/hu-120700.htm,
238 // http://publications.europa.eu/code/hu/hu-4100600.htm)
240 CharClass
aCharClass(( LanguageTag(eLang
) ));
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 const OUString sVowels
= OUString::Concat(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
== u
"hu" )
345 rRefText
= sArticle
+ " " + rRefText
;
349 SwGetRefField::SwGetRefField( SwGetRefFieldType
* pFieldType
,
350 OUString aSetRef
, OUString aSetReferenceLanguage
, sal_uInt16 nSubTyp
,
351 sal_uInt16 nSequenceNo
, sal_uLong nFormat
)
352 : SwField( pFieldType
, nFormat
),
353 m_sSetRefName( std::move(aSetRef
) ),
354 m_sSetReferenceLanguage( std::move(aSetReferenceLanguage
) ),
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
);
401 // strikethrough for tooltips using Unicode combining character
402 static OUString
lcl_formatStringByCombiningCharacter(std::u16string_view sText
, const sal_Unicode cChar
)
404 OUStringBuffer
sRet(sText
.size() * 2);
405 for (size_t i
= 0; i
< sText
.size(); ++i
)
407 sRet
.append(OUStringChar(sText
[i
]) + OUStringChar(cChar
));
409 return sRet
.makeStringAndClear();
413 OUString
SwGetRefField::GetExpandedTextOfReferencedTextNode(
414 SwRootFrame
const& rLayout
) const
416 const SwTextNode
* pReferencedTextNode( GetReferencedTextNode() );
417 if ( !pReferencedTextNode
)
420 // show the referenced text without the deletions, but if the whole text was
421 // deleted, show the original text for the sake of the comfortable reviewing,
422 // but with Unicode strikethrough in the tooltip
423 OUString sRet
= sw::GetExpandTextMerged(&rLayout
, *pReferencedTextNode
, true, false, ExpandMode::HideDeletions
);
424 if ( sRet
.isEmpty() )
426 static const sal_Unicode cStrikethrough
= u
'\x0336';
427 sRet
= sw::GetExpandTextMerged(&rLayout
, *pReferencedTextNode
, true, false, ExpandMode(0));
428 sRet
= lcl_formatStringByCombiningCharacter( sRet
, cStrikethrough
);
433 void SwGetRefField::SetExpand( const OUString
& rStr
)
436 m_sTextRLHidden
= rStr
;
439 OUString
SwGetRefField::ExpandImpl(SwRootFrame
const*const pLayout
) const
441 return pLayout
&& pLayout
->IsHideRedlines() ? m_sTextRLHidden
: m_sText
;
444 OUString
SwGetRefField::GetFieldName() const
446 const OUString aName
= GetTyp()->GetName();
447 if ( !aName
.isEmpty() || !m_sSetRefName
.isEmpty() )
449 return aName
+ " " + m_sSetRefName
;
451 return ExpandImpl(nullptr);
455 static void FilterText(OUString
& rText
, LanguageType
const eLang
,
456 std::u16string_view rSetReferenceLanguage
)
458 // remove all special characters (replace them with blanks)
462 rText
= rText
.replaceAll(u
"\u00ad", "");
463 OUStringBuffer
aBuf(rText
);
464 const sal_Int32 l
= aBuf
.getLength();
465 for (sal_Int32 i
= 0; i
< l
; ++i
)
471 else if (aBuf
[i
] == 0x2011)
476 rText
= aBuf
.makeStringAndClear();
477 if (!rSetReferenceLanguage
.empty())
479 lcl_formatReferenceLanguage(rText
, false, eLang
, rSetReferenceLanguage
);
483 // #i81002# - parameter <pFieldTextAttr> added
484 void SwGetRefField::UpdateField( const SwTextField
* pFieldTextAttr
)
487 m_sTextRLHidden
.clear();
489 SwDoc
& rDoc
= static_cast<SwGetRefFieldType
*>(GetTyp())->GetDoc();
490 // finding the reference target (the number)
491 sal_Int32 nNumStart
= -1;
492 sal_Int32 nNumEnd
= -1;
493 SwTextNode
* pTextNd
= SwGetRefFieldType::FindAnchor(
494 &rDoc
, m_sSetRefName
, m_nSubType
, m_nSeqNo
, &nNumStart
, &nNumEnd
499 m_sText
= SwViewShell::GetShellRes()->aGetRefField_RefItemNotFound
;
500 m_sTextRLHidden
= m_sText
;
504 SwRootFrame
const* pLayout(nullptr);
505 SwRootFrame
const* pLayoutRLHidden(nullptr);
506 for (SwRootFrame
const*const pLay
: rDoc
.GetAllLayouts())
508 if (pLay
->IsHideRedlines())
510 pLayoutRLHidden
= pLay
;
518 // where is the category name (e.g. "Illustration")?
519 const OUString aText
= pTextNd
->GetText();
520 const sal_Int32 nCatStart
= aText
.indexOf(m_sSetRefName
);
521 const bool bHasCat
= nCatStart
>=0;
522 const sal_Int32 nCatEnd
= bHasCat
? nCatStart
+ m_sSetRefName
.getLength() : -1;
524 // length of the referenced text
525 const sal_Int32 nLen
= aText
.getLength();
528 switch( GetFormat() )
532 case REF_ONLYCAPTION
:
535 // needed part of Text
541 case REF_SEQUENCEFLD
:
543 switch( GetFormat() )
545 // "Category and Number"
548 nStart
= std::min(nNumStart
, nCatStart
);
549 nEnd
= std::max(nNumEnd
, nCatEnd
);
557 case REF_ONLYCAPTION
: {
558 // next alphanumeric character after category+number
559 if (const SwTextAttr
* const pTextAttr
=
560 pTextNd
->GetTextAttrForCharAt(nNumStart
, RES_TXTATR_FIELD
)
562 // start searching from nFrom
563 const sal_Int32 nFrom
= bHasCat
564 ? std::max(nNumStart
+ 1, nCatEnd
)
566 nStart
= SwGetExpField::GetReferenceTextPos( pTextAttr
->GetFormatField(), rDoc
, nFrom
);
568 nStart
= bHasCat
? std::max(nNumEnd
, nCatEnd
) : nNumEnd
;
577 nEnd
= std::min(nStart
+ 1, nLen
);
580 // "Reference" (whole Text)
593 // text is spread across multiple nodes - get whole text or only until end of node?
594 nEnd
= nNumEnd
<0 ? nLen
: nNumEnd
;
604 // get number or numString
605 for( size_t i
= 0; i
< rDoc
.GetFootnoteIdxs().size(); ++i
)
607 SwTextFootnote
* const pFootnoteIdx
= rDoc
.GetFootnoteIdxs()[i
];
608 if( m_nSeqNo
== pFootnoteIdx
->GetSeqRefNo() )
610 m_sText
= pFootnoteIdx
->GetFootnote().GetViewNumStr(rDoc
, nullptr);
611 m_sTextRLHidden
= pFootnoteIdx
->GetFootnote().GetViewNumStr(rDoc
, pLayoutRLHidden
);
612 if (!m_sSetReferenceLanguage
.isEmpty())
614 lcl_formatReferenceLanguage(m_sText
, false, GetLanguage(), m_sSetReferenceLanguage
);
615 lcl_formatReferenceLanguage(m_sTextRLHidden
, false, GetLanguage(), m_sSetReferenceLanguage
);
631 if( nStart
!= nEnd
) // a section?
633 m_sText
= pTextNd
->GetExpandText(pLayout
, nStart
, nEnd
- nStart
, false, false, false, ExpandMode::HideDeletions
);
634 // show the referenced text without the deletions, but if the whole text was
635 // deleted, show the original text for the sake of the comfortable reviewing
636 // (with strikethrough in tooltip, see GetExpandedTextOfReferencedTextNode())
637 if ( m_sText
.isEmpty() )
638 m_sText
= pTextNd
->GetExpandText(pLayout
, nStart
, nEnd
- nStart
, false, false, false, ExpandMode(0));
640 if (m_nSubType
== REF_OUTLINE
641 || (m_nSubType
== REF_SEQUENCEFLD
&& REF_CONTENT
== GetFormat()))
643 m_sTextRLHidden
= sw::GetExpandTextMerged(
644 pLayoutRLHidden
, *pTextNd
, false, false, ExpandMode(0));
648 m_sTextRLHidden
= pTextNd
->GetExpandText(pLayoutRLHidden
,
649 nStart
, nEnd
- nStart
, false, false, false, ExpandMode::HideDeletions
);
651 FilterText(m_sText
, GetLanguage(), m_sSetReferenceLanguage
);
652 FilterText(m_sTextRLHidden
, GetLanguage(), m_sSetReferenceLanguage
);
658 case REF_PAGE_PGDESC
:
661 [this, pTextNd
, nNumStart
](OUString
& rText
, SwRootFrame
const*const pLay
)
663 SwTextFrame
const* pFrame
= static_cast<SwTextFrame
*>(pTextNd
->getLayoutFrame(pLay
, nullptr, nullptr));
664 SwTextFrame
const*const pSave
= pFrame
;
667 TextFrameIndex
const nNumStartIndex(pFrame
->MapModelToView(pTextNd
, nNumStart
));
668 while (pFrame
&& !pFrame
->IsInside(nNumStartIndex
))
669 pFrame
= pFrame
->GetFollow();
672 if( pFrame
|| nullptr != ( pFrame
= pSave
))
674 sal_uInt16 nPageNo
= pFrame
->GetVirtPageNum();
675 const SwPageFrame
*pPage
;
676 if( REF_PAGE_PGDESC
== GetFormat() &&
677 nullptr != ( pPage
= pFrame
->FindPageFrame() ) &&
678 pPage
->GetPageDesc() )
680 rText
= pPage
->GetPageDesc()->GetNumType().GetNumStr(nPageNo
);
684 rText
= OUString::number(nPageNo
);
687 if (!m_sSetReferenceLanguage
.isEmpty())
688 lcl_formatReferenceLanguage(rText
, false, GetLanguage(), m_sSetReferenceLanguage
);
691 // sw_redlinehide: currently only one of these layouts will exist,
692 // so the getLayoutFrame will use the same frame in both cases
693 func(m_sText
, pLayout
);
694 func(m_sTextRLHidden
, pLayoutRLHidden
);
701 [this, pTextNd
](OUString
& rText
, SwRootFrame
const*const pLay
)
703 // a bit tricky: search any frame
704 SwFrame
const*const pFrame
= pTextNd
->getLayoutFrame(pLay
);
707 SwChapterFieldType aFieldTyp
;
708 SwChapterField
aField( &aFieldTyp
, 0 );
709 aField
.SetLevel( MAXLEVEL
- 1 );
710 aField
.ChangeExpansion( *pFrame
, pTextNd
, true );
711 rText
= aField
.GetNumber(pLay
);
713 if (!m_sSetReferenceLanguage
.isEmpty())
714 lcl_formatReferenceLanguage(rText
, false, GetLanguage(), m_sSetReferenceLanguage
);
717 func(m_sText
, pLayout
);
718 func(m_sTextRLHidden
, pLayoutRLHidden
);
725 // simplified: use parameter <pFieldTextAttr>
726 if( !pFieldTextAttr
|| !pFieldTextAttr
->GetpTextNode() )
729 LocaleDataWrapper
aLocaleData(( LanguageTag( GetLanguage() ) ));
731 // first a "short" test - in case both are in the same node
732 if( pFieldTextAttr
->GetpTextNode() == pTextNd
)
734 m_sText
= nNumStart
< pFieldTextAttr
->GetStart()
735 ? aLocaleData
.getAboveWord()
736 : aLocaleData
.getBelowWord();
737 m_sTextRLHidden
= m_sText
;
741 m_sText
= ::IsFrameBehind( *pFieldTextAttr
->GetpTextNode(), pFieldTextAttr
->GetStart(),
742 *pTextNd
, nNumStart
)
743 ? aLocaleData
.getAboveWord()
744 : aLocaleData
.getBelowWord();
746 if (!m_sSetReferenceLanguage
.isEmpty())
747 lcl_formatReferenceLanguage(m_sText
, false, GetLanguage(), m_sSetReferenceLanguage
);
749 m_sTextRLHidden
= m_sText
;
754 case REF_NUMBER_NO_CONTEXT
:
755 case REF_NUMBER_FULL_CONTEXT
:
757 if ( pFieldTextAttr
&& pFieldTextAttr
->GetpTextNode() )
760 MakeRefNumStr(pLayout
, pFieldTextAttr
->GetTextNode(), *pTextNd
, GetFormat());
761 m_sText
= result
.first
;
762 // for differentiation of Roman numbers and letters in Hungarian article handling
763 bool bClosingParenthesis
= result
.second
;
764 if (!m_sSetReferenceLanguage
.isEmpty())
766 lcl_formatReferenceLanguage(m_sText
, bClosingParenthesis
, GetLanguage(), m_sSetReferenceLanguage
);
769 MakeRefNumStr(pLayoutRLHidden
, pFieldTextAttr
->GetTextNode(), *pTextNd
, GetFormat());
770 m_sTextRLHidden
= result
.first
;
771 bClosingParenthesis
= result
.second
;
772 if (!m_sSetReferenceLanguage
.isEmpty())
774 lcl_formatReferenceLanguage(m_sTextRLHidden
, bClosingParenthesis
, GetLanguage(), m_sSetReferenceLanguage
);
781 OSL_FAIL("<SwGetRefField::UpdateField(..)> - unknown format type");
786 static std::pair
<OUString
, bool> MakeRefNumStr(
787 SwRootFrame
const*const pLayout
,
788 const SwTextNode
& i_rTextNodeOfField
,
789 const SwTextNode
& i_rTextNodeOfReferencedItem
,
790 const sal_uInt32 nRefNumFormat
)
792 SwTextNode
const& rTextNodeOfField(pLayout
793 ? *sw::GetParaPropsNode(*pLayout
, i_rTextNodeOfField
)
794 : i_rTextNodeOfField
);
795 SwTextNode
const& rTextNodeOfReferencedItem(pLayout
796 ? *sw::GetParaPropsNode(*pLayout
, i_rTextNodeOfReferencedItem
)
797 : i_rTextNodeOfReferencedItem
);
798 if ( rTextNodeOfReferencedItem
.HasNumber(pLayout
) &&
799 rTextNodeOfReferencedItem
.IsCountedInList() )
801 OSL_ENSURE( rTextNodeOfReferencedItem
.GetNum(pLayout
),
802 "<SwGetRefField::MakeRefNumStr(..)> - referenced paragraph has number, but no <SwNodeNum> instance!" );
804 // Determine, up to which level the superior list labels have to be
805 // included - default is to include all superior list labels.
806 int nRestrictInclToThisLevel( 0 );
807 // Determine for format REF_NUMBER the level, up to which the superior
808 // list labels have to be restricted, if the text node of the reference
809 // field and the text node of the referenced item are in the same
811 if ( nRefNumFormat
== REF_NUMBER
&&
812 rTextNodeOfField
.FindFlyStartNode()
813 == rTextNodeOfReferencedItem
.FindFlyStartNode() &&
814 rTextNodeOfField
.FindFootnoteStartNode()
815 == rTextNodeOfReferencedItem
.FindFootnoteStartNode() &&
816 rTextNodeOfField
.FindHeaderStartNode()
817 == rTextNodeOfReferencedItem
.FindHeaderStartNode() &&
818 rTextNodeOfField
.FindFooterStartNode()
819 == rTextNodeOfReferencedItem
.FindFooterStartNode() )
821 const SwNodeNum
* pNodeNumForTextNodeOfField( nullptr );
822 if ( rTextNodeOfField
.HasNumber(pLayout
) &&
823 rTextNodeOfField
.GetNumRule() == rTextNodeOfReferencedItem
.GetNumRule() )
825 pNodeNumForTextNodeOfField
= rTextNodeOfField
.GetNum(pLayout
);
829 pNodeNumForTextNodeOfField
=
830 rTextNodeOfReferencedItem
.GetNum(pLayout
)->GetPrecedingNodeNumOf(rTextNodeOfField
);
832 if ( pNodeNumForTextNodeOfField
)
834 const SwNumberTree::tNumberVector rFieldNumVec
=
835 pNodeNumForTextNodeOfField
->GetNumberVector();
836 const SwNumberTree::tNumberVector rRefItemNumVec
=
837 rTextNodeOfReferencedItem
.GetNum()->GetNumberVector();
838 std::size_t nLevel( 0 );
839 while ( nLevel
< rFieldNumVec
.size() && nLevel
< rRefItemNumVec
.size() )
841 if ( rRefItemNumVec
[nLevel
] == rFieldNumVec
[nLevel
] )
843 nRestrictInclToThisLevel
= nLevel
+ 1;
854 // Determine, if superior list labels have to be included
855 const bool bInclSuperiorNumLabels(
856 ( nRestrictInclToThisLevel
< rTextNodeOfReferencedItem
.GetActualListLevel() &&
857 ( nRefNumFormat
== REF_NUMBER
|| nRefNumFormat
== REF_NUMBER_FULL_CONTEXT
) ) );
859 OSL_ENSURE( rTextNodeOfReferencedItem
.GetNumRule(),
860 "<SwGetRefField::MakeRefNumStr(..)> - referenced numbered paragraph has no numbering rule set!" );
861 return std::make_pair(
862 rTextNodeOfReferencedItem
.GetNumRule()->MakeRefNumString(
863 *(rTextNodeOfReferencedItem
.GetNum(pLayout
)),
864 bInclSuperiorNumLabels
,
865 nRestrictInclToThisLevel
),
866 rTextNodeOfReferencedItem
.GetNumRule()->MakeNumString(
867 *(rTextNodeOfReferencedItem
.GetNum(pLayout
)),
868 true).endsWith(")") );
871 return std::make_pair(OUString(), false);
874 std::unique_ptr
<SwField
> SwGetRefField::Copy() const
876 std::unique_ptr
<SwGetRefField
> pField( new SwGetRefField( static_cast<SwGetRefFieldType
*>(GetTyp()),
877 m_sSetRefName
, m_sSetReferenceLanguage
, m_nSubType
,
878 m_nSeqNo
, GetFormat() ) );
879 pField
->m_sText
= m_sText
;
880 pField
->m_sTextRLHidden
= m_sTextRLHidden
;
881 return std::unique_ptr
<SwField
>(pField
.release());
884 /// get reference name
885 OUString
SwGetRefField::GetPar1() const
887 return m_sSetRefName
;
890 /// set reference name
891 void SwGetRefField::SetPar1( const OUString
& rName
)
893 m_sSetRefName
= rName
;
896 OUString
SwGetRefField::GetPar2() const
898 return ExpandImpl(nullptr);
901 bool SwGetRefField::QueryValue( uno::Any
& rAny
, sal_uInt16 nWhichId
) const
905 case FIELD_PROP_USHORT1
:
910 case REF_PAGE
: nPart
= ReferenceFieldPart::PAGE
; break;
911 case REF_CHAPTER
: nPart
= ReferenceFieldPart::CHAPTER
; break;
912 case REF_CONTENT
: nPart
= ReferenceFieldPart::TEXT
; break;
913 case REF_UPDOWN
: nPart
= ReferenceFieldPart::UP_DOWN
; break;
914 case REF_PAGE_PGDESC
: nPart
= ReferenceFieldPart::PAGE_DESC
; break;
915 case REF_ONLYNUMBER
: nPart
= ReferenceFieldPart::CATEGORY_AND_NUMBER
; break;
916 case REF_ONLYCAPTION
: nPart
= ReferenceFieldPart::ONLY_CAPTION
; break;
917 case REF_ONLYSEQNO
: nPart
= ReferenceFieldPart::ONLY_SEQUENCE_NUMBER
; break;
919 case REF_NUMBER
: nPart
= ReferenceFieldPart::NUMBER
; break;
920 case REF_NUMBER_NO_CONTEXT
: nPart
= ReferenceFieldPart::NUMBER_NO_CONTEXT
; break;
921 case REF_NUMBER_FULL_CONTEXT
: nPart
= ReferenceFieldPart::NUMBER_FULL_CONTEXT
; break;
926 case FIELD_PROP_USHORT2
:
928 sal_Int16 nSource
= 0;
931 case REF_SETREFATTR
: nSource
= ReferenceFieldSource::REFERENCE_MARK
; break;
932 case REF_SEQUENCEFLD
: nSource
= ReferenceFieldSource::SEQUENCE_FIELD
; break;
933 case REF_BOOKMARK
: nSource
= ReferenceFieldSource::BOOKMARK
; break;
934 case REF_OUTLINE
: OSL_FAIL("not implemented"); break;
935 case REF_FOOTNOTE
: nSource
= ReferenceFieldSource::FOOTNOTE
; break;
936 case REF_ENDNOTE
: nSource
= ReferenceFieldSource::ENDNOTE
; break;
941 case FIELD_PROP_PAR1
:
943 OUString
sTmp(GetPar1());
944 if(REF_SEQUENCEFLD
== m_nSubType
)
946 sal_uInt16 nPoolId
= SwStyleNameMapper::GetPoolIdFromUIName( sTmp
, SwGetPoolIdFromName::TxtColl
);
949 case RES_POOLCOLL_LABEL_ABB
:
950 case RES_POOLCOLL_LABEL_TABLE
:
951 case RES_POOLCOLL_LABEL_FRAME
:
952 case RES_POOLCOLL_LABEL_DRAWING
:
953 case RES_POOLCOLL_LABEL_FIGURE
:
954 SwStyleNameMapper::FillProgName(nPoolId
, sTmp
) ;
961 case FIELD_PROP_PAR3
:
962 rAny
<<= ExpandImpl(nullptr);
964 case FIELD_PROP_PAR4
:
965 rAny
<<= m_sSetReferenceLanguage
;
967 case FIELD_PROP_SHORT1
:
968 rAny
<<= static_cast<sal_Int16
>(m_nSeqNo
);
976 bool SwGetRefField::PutValue( const uno::Any
& rAny
, sal_uInt16 nWhichId
)
980 case FIELD_PROP_USHORT1
:
986 case ReferenceFieldPart::PAGE
: nPart
= REF_PAGE
; break;
987 case ReferenceFieldPart::CHAPTER
: nPart
= REF_CHAPTER
; break;
988 case ReferenceFieldPart::TEXT
: nPart
= REF_CONTENT
; break;
989 case ReferenceFieldPart::UP_DOWN
: nPart
= REF_UPDOWN
; break;
990 case ReferenceFieldPart::PAGE_DESC
: nPart
= REF_PAGE_PGDESC
; break;
991 case ReferenceFieldPart::CATEGORY_AND_NUMBER
: nPart
= REF_ONLYNUMBER
; break;
992 case ReferenceFieldPart::ONLY_CAPTION
: nPart
= REF_ONLYCAPTION
; break;
993 case ReferenceFieldPart::ONLY_SEQUENCE_NUMBER
: nPart
= REF_ONLYSEQNO
; break;
995 case ReferenceFieldPart::NUMBER
: nPart
= REF_NUMBER
; break;
996 case ReferenceFieldPart::NUMBER_NO_CONTEXT
: nPart
= REF_NUMBER_NO_CONTEXT
; break;
997 case ReferenceFieldPart::NUMBER_FULL_CONTEXT
: nPart
= REF_NUMBER_FULL_CONTEXT
; break;
998 default: return false;
1003 case FIELD_PROP_USHORT2
:
1005 sal_Int16 nSource
= 0;
1009 case ReferenceFieldSource::REFERENCE_MARK
: m_nSubType
= REF_SETREFATTR
; break;
1010 case ReferenceFieldSource::SEQUENCE_FIELD
:
1012 if(REF_SEQUENCEFLD
== m_nSubType
)
1014 m_nSubType
= REF_SEQUENCEFLD
;
1015 ConvertProgrammaticToUIName();
1018 case ReferenceFieldSource::BOOKMARK
: m_nSubType
= REF_BOOKMARK
; break;
1019 case ReferenceFieldSource::FOOTNOTE
: m_nSubType
= REF_FOOTNOTE
; break;
1020 case ReferenceFieldSource::ENDNOTE
: m_nSubType
= REF_ENDNOTE
; break;
1024 case FIELD_PROP_PAR1
:
1029 ConvertProgrammaticToUIName();
1032 case FIELD_PROP_PAR3
:
1036 SetExpand( sTmpStr
);
1039 case FIELD_PROP_PAR4
:
1040 rAny
>>= m_sSetReferenceLanguage
;
1042 case FIELD_PROP_SHORT1
:
1044 sal_Int16 nSetSeq
= 0;
1056 void SwGetRefField::ConvertProgrammaticToUIName()
1058 if(!(GetTyp() && REF_SEQUENCEFLD
== m_nSubType
))
1061 SwDoc
& rDoc
= static_cast<SwGetRefFieldType
*>(GetTyp())->GetDoc();
1062 const OUString rPar1
= GetPar1();
1063 // don't convert when the name points to an existing field type
1064 if (rDoc
.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp
, rPar1
, false))
1067 sal_uInt16 nPoolId
= SwStyleNameMapper::GetPoolIdFromProgName( rPar1
, SwGetPoolIdFromName::TxtColl
);
1071 case RES_POOLCOLL_LABEL_ABB
:
1072 pResId
= STR_POOLCOLL_LABEL_ABB
;
1074 case RES_POOLCOLL_LABEL_TABLE
:
1075 pResId
= STR_POOLCOLL_LABEL_TABLE
;
1077 case RES_POOLCOLL_LABEL_FRAME
:
1078 pResId
= STR_POOLCOLL_LABEL_FRAME
;
1080 case RES_POOLCOLL_LABEL_DRAWING
:
1081 pResId
= STR_POOLCOLL_LABEL_DRAWING
;
1083 case RES_POOLCOLL_LABEL_FIGURE
:
1084 pResId
= STR_POOLCOLL_LABEL_FIGURE
;
1088 SetPar1(SwResId(pResId
));
1091 SwGetRefFieldType::SwGetRefFieldType( SwDoc
& rDc
)
1092 : SwFieldType( SwFieldIds::GetRef
), m_rDoc( rDc
)
1095 std::unique_ptr
<SwFieldType
> SwGetRefFieldType::Copy() const
1097 return std::make_unique
<SwGetRefFieldType
>( m_rDoc
);
1100 void SwGetRefFieldType::UpdateGetReferences()
1102 std::vector
<SwFormatField
*> vFields
;
1103 GatherFields(vFields
, false);
1104 for(auto pFormatField
: vFields
)
1106 // update only the GetRef fields
1107 //JP 3.4.2001: Task 71231 - we need the correct language
1108 SwGetRefField
* pGRef
= static_cast<SwGetRefField
*>(pFormatField
->GetField());
1109 const SwTextField
* pTField
;
1110 if(!pGRef
->GetLanguage() &&
1111 nullptr != (pTField
= pFormatField
->GetTextField()) &&
1112 pTField
->GetpTextNode())
1114 pGRef
->SetLanguage(pTField
->GetpTextNode()->GetLang(pTField
->GetStart()));
1118 pGRef
->UpdateField(pFormatField
->GetTextField());
1120 CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
1123 void SwGetRefFieldType::SwClientNotify(const SwModify
&, const SfxHint
& rHint
)
1125 if (rHint
.GetId() != SfxHintId::SwLegacyModify
)
1127 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
1128 if(!pLegacy
->m_pNew
&& !pLegacy
->m_pOld
)
1129 // update to all GetReference fields
1130 // hopefully, this codepath is soon dead code, and
1131 // UpdateGetReferences gets only called directly
1132 UpdateGetReferences();
1134 // forward to text fields, they "expand" the text
1135 CallSwClientNotify(rHint
);
1140 bool IsMarkHintHidden(SwRootFrame
const& rLayout
,
1141 SwTextNode
const& rNode
, SwTextAttrEnd
const& rHint
)
1143 if (!rLayout
.HasMergedParas())
1147 SwTextFrame
const*const pFrame(static_cast<SwTextFrame
const*>(
1148 rNode
.getLayoutFrame(&rLayout
)));
1153 sal_Int32
const*const pEnd(rHint
.GetEnd());
1156 return pFrame
->MapModelToView(&rNode
, rHint
.GetStart())
1157 == pFrame
->MapModelToView(&rNode
, *pEnd
);
1161 assert(rHint
.HasDummyChar());
1162 return pFrame
->MapModelToView(&rNode
, rHint
.GetStart())
1163 == pFrame
->MapModelToView(&rNode
, rHint
.GetStart() + 1);
1169 SwTextNode
* SwGetRefFieldType::FindAnchor( SwDoc
* pDoc
, const OUString
& rRefMark
,
1170 sal_uInt16 nSubType
, sal_uInt16 nSeqNo
,
1171 sal_Int32
* pStt
, sal_Int32
* pEnd
,
1172 SwRootFrame
const*const pLayout
)
1174 OSL_ENSURE( pStt
, "Why did no one check the StartPos?" );
1176 IDocumentRedlineAccess
& rIDRA(pDoc
->getIDocumentRedlineAccess());
1177 SwTextNode
* pTextNd
= nullptr;
1180 case REF_SETREFATTR
:
1182 const SwFormatRefMark
*pRef
= pDoc
->GetRefMark( rRefMark
);
1183 SwTextRefMark
const*const pRefMark(pRef
? pRef
->GetTextRefMark() : nullptr);
1184 if (pRefMark
&& (!pLayout
|| !sw::IsMarkHintHidden(*pLayout
,
1185 pRefMark
->GetTextNode(), *pRefMark
)))
1187 pTextNd
= const_cast<SwTextNode
*>(&pRef
->GetTextRefMark()->GetTextNode());
1188 *pStt
= pRef
->GetTextRefMark()->GetStart();
1190 *pEnd
= pRef
->GetTextRefMark()->GetAnyEnd();
1195 case REF_SEQUENCEFLD
:
1197 SwFieldType
* pFieldType
= pDoc
->getIDocumentFieldsAccess().GetFieldType( SwFieldIds::SetExp
, rRefMark
, false );
1198 if( pFieldType
&& pFieldType
->HasWriterListeners() &&
1199 nsSwGetSetExpType::GSE_SEQ
& static_cast<SwSetExpFieldType
*>(pFieldType
)->GetType() )
1201 std::vector
<SwFormatField
*> vFields
;
1202 pFieldType
->GatherFields(vFields
, false);
1203 for(auto pFormatField
: vFields
)
1205 SwTextField
*const pTextField(pFormatField
->GetTextField());
1206 if (pTextField
&& nSeqNo
==
1207 static_cast<SwSetExpField
*>(pFormatField
->GetField())->GetSeqNumber()
1208 && (!pLayout
|| !pLayout
->IsHideRedlines()
1209 || !sw::IsFieldDeletedInModel(rIDRA
, *pTextField
)))
1211 pTextNd
= pTextField
->GetpTextNode();
1212 *pStt
= pTextField
->GetStart();
1214 *pEnd
= (*pStt
) + 1;
1224 IDocumentMarkAccess::const_iterator_t ppMark
= pDoc
->getIDocumentMarkAccess()->findMark(rRefMark
);
1225 if (ppMark
!= pDoc
->getIDocumentMarkAccess()->getAllMarksEnd()
1226 && (!pLayout
|| !pLayout
->IsHideRedlines()
1227 || !sw::IsMarkHidden(*pLayout
, **ppMark
)))
1229 const ::sw::mark::IMark
* pBkmk
= *ppMark
;
1230 const SwPosition
* pPos
= &pBkmk
->GetMarkStart();
1232 pTextNd
= pPos
->GetNode().GetTextNode();
1233 *pStt
= pPos
->GetContentIndex();
1236 if(!pBkmk
->IsExpanded())
1240 if(dynamic_cast< ::sw::mark::CrossRefBookmark
const *>(pBkmk
))
1242 OSL_ENSURE( pTextNd
,
1243 "<SwGetRefFieldType::FindAnchor(..)> - node marked by cross-reference bookmark isn't a text node --> crash" );
1244 *pEnd
= pTextNd
->Len();
1247 else if(pBkmk
->GetOtherMarkPos().GetNode() == pBkmk
->GetMarkPos().GetNode())
1248 *pEnd
= pBkmk
->GetMarkEnd().GetContentIndex();
1262 for( auto pFootnoteIdx
: pDoc
->GetFootnoteIdxs() )
1263 if( nSeqNo
== pFootnoteIdx
->GetSeqRefNo() )
1265 if (pLayout
&& pLayout
->IsHideRedlines()
1266 && sw::IsFootnoteDeleted(rIDRA
, *pFootnoteIdx
))
1270 // otherwise: the position at the start of the footnote
1271 // will be mapped to something visible at least...
1272 const SwNodeIndex
* pIdx
= pFootnoteIdx
->GetStartNode();
1275 SwNodeIndex
aIdx( *pIdx
, 1 );
1276 pTextNd
= aIdx
.GetNode().GetTextNode();
1277 if( nullptr == pTextNd
)
1278 pTextNd
= static_cast<SwTextNode
*>(pDoc
->GetNodes().GoNext( &aIdx
));
1298 std::set
<sal_uInt16
> aIds
;
1299 std::set
<sal_uInt16
> aDstIds
;
1300 std::map
<sal_uInt16
, sal_uInt16
> sequencedIds
; /// ID numbers sorted by sequence number.
1303 void Init(SwDoc
& rDoc
, SwDoc
& rDestDoc
, bool bField
);
1304 static void GetNoteIdsFromDoc( SwDoc
& rDoc
, std::set
<sal_uInt16
> &rIds
);
1305 void GetFieldIdsFromDoc( SwDoc
& rDoc
, std::set
<sal_uInt16
> &rIds
);
1306 void AddId( sal_uInt16 id
, sal_uInt16 seqNum
);
1307 static sal_uInt16
GetFirstUnusedId( std::set
<sal_uInt16
> &rIds
);
1310 explicit RefIdsMap( OUString _aName
) : aName(std::move( _aName
)), bInit( false ) {}
1312 void Check( SwDoc
& rDoc
, SwDoc
& rDestDoc
, SwGetRefField
& rField
, bool bField
);
1314 const OUString
& GetName() const { return aName
; }
1319 /// Get a sorted list of the field IDs from a document.
1320 /// @param[in] rDoc The document to search.
1321 /// @param[in,out] rIds The list of IDs found in the document.
1322 void RefIdsMap::GetFieldIdsFromDoc( SwDoc
& rDoc
, std::set
<sal_uInt16
> &rIds
)
1324 SwFieldType
*const pType
= rDoc
.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp
, aName
, false);
1327 std::vector
<SwFormatField
*> vFields
;
1328 pType
->GatherFields(vFields
);
1329 for(const auto pF
: vFields
)
1330 rIds
.insert(static_cast<SwSetExpField
const*>(pF
->GetField())->GetSeqNumber());
1333 /// Get a sorted list of the footnote/endnote IDs from a document.
1334 /// @param[in] rDoc The document to search.
1335 /// @param[in,out] rIds The list of IDs found in the document.
1336 void RefIdsMap::GetNoteIdsFromDoc( SwDoc
& rDoc
, std::set
<sal_uInt16
> &rIds
)
1338 for( auto n
= rDoc
.GetFootnoteIdxs().size(); n
; )
1339 rIds
.insert( rDoc
.GetFootnoteIdxs()[ --n
]->GetSeqRefNo() );
1342 /// Initialise the aIds and aDestIds collections from the source documents.
1343 /// @param[in] rDoc The source document.
1344 /// @param[in] rDestDoc The destination document.
1345 /// @param[in] bField True if we're interested in all fields, false for footnotes.
1346 void RefIdsMap::Init( SwDoc
& rDoc
, SwDoc
& rDestDoc
, bool bField
)
1353 GetFieldIdsFromDoc( rDestDoc
, aIds
);
1354 GetFieldIdsFromDoc( rDoc
, aDstIds
);
1356 // Map all the new src fields to the next available unused id
1357 for (const auto& rId
: aDstIds
)
1358 AddId( GetFirstUnusedId(aIds
), rId
);
1360 // Change the Sequence number of all SetExp fields in the source document
1361 SwFieldType
* pType
= rDoc
.getIDocumentFieldsAccess().GetFieldType( SwFieldIds::SetExp
, aName
, false );
1364 std::vector
<SwFormatField
*> vFields
;
1365 pType
->GatherFields(vFields
, false);
1366 for(auto pF
: vFields
)
1368 if(!pF
->GetTextField())
1370 SwSetExpField
*const pSetExp(static_cast<SwSetExpField
*>(pF
->GetField()));
1371 sal_uInt16
const n
= pSetExp
->GetSeqNumber();
1372 pSetExp
->SetSeqNumber(sequencedIds
[n
]);
1378 GetNoteIdsFromDoc( rDestDoc
, aIds
);
1379 GetNoteIdsFromDoc( rDoc
, aDstIds
);
1381 for (const auto& rId
: aDstIds
)
1382 AddId( GetFirstUnusedId(aIds
), rId
);
1384 // Change the footnotes/endnotes in the source doc to the new ID
1385 for ( const auto pFootnoteIdx
: rDoc
.GetFootnoteIdxs() )
1387 sal_uInt16
const n
= pFootnoteIdx
->GetSeqRefNo();
1388 pFootnoteIdx
->SetSeqNo(sequencedIds
[n
]);
1394 /// Get the lowest number unused in the passed set.
1395 /// @param[in] rIds The set of used ID numbers.
1396 /// @returns The lowest number unused by the passed set
1397 sal_uInt16
RefIdsMap::GetFirstUnusedId( std::set
<sal_uInt16
> &rIds
)
1401 for( const auto& rId
: rIds
)
1412 /// Add a new ID and sequence number to the "occupied" collection.
1413 /// @param[in] id The ID number.
1414 /// @param[in] seqNum The sequence number.
1415 void RefIdsMap::AddId( sal_uInt16 id
, sal_uInt16 seqNum
)
1418 sequencedIds
[ seqNum
] = id
;
1421 void RefIdsMap::Check( SwDoc
& rDoc
, SwDoc
& rDestDoc
, SwGetRefField
& rField
,
1424 Init( rDoc
, rDestDoc
, bField
);
1426 sal_uInt16
const nSeqNo
= rField
.GetSeqNo();
1428 // check if it needs to be remapped
1429 // if sequencedIds doesn't contain the number, it means there is no
1430 // SetExp field / footnote in the source document: do not modify
1431 // the number, which works well for copy from/paste to same document
1432 // (and if it is not the same document, there's no "correct" result anyway)
1433 if (sequencedIds
.count(nSeqNo
))
1435 rField
.SetSeqNo( sequencedIds
[nSeqNo
] );
1439 /// 1. if _both_ SetExp + GetExp / Footnote + GetExp field are copied,
1440 /// ensure that both get a new unused matching number
1441 /// 2. if only SetExp / Footnote is copied, it gets a new unused number
1442 /// 3. if only GetExp field is copied, for the case of copy from / paste to
1443 /// same document it's desirable to keep the same number;
1444 /// for other cases of copy/paste or master documents it's not obvious
1445 /// what is most desirable since it's going to be wrong anyway
1446 void SwGetRefFieldType::MergeWithOtherDoc( SwDoc
& rDestDoc
)
1448 if (&rDestDoc
== &m_rDoc
)
1451 if (rDestDoc
.IsClipBoard())
1453 // when copying _to_ clipboard, expectation is that no fields exist
1454 // so no re-mapping is required to avoid collisions
1455 assert(!rDestDoc
.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef
)->HasWriterListeners());
1456 return; // don't modify the fields in the source doc
1459 // then there are RefFields in the DescDox - so all RefFields in the SourceDoc
1460 // need to be converted to have unique IDs for both documents
1461 RefIdsMap aFntMap
{ OUString() };
1462 std::vector
<std::unique_ptr
<RefIdsMap
>> aFieldMap
;
1464 std::vector
<SwFormatField
*> vFields
;
1465 GatherFields(vFields
);
1466 for(auto pField
: vFields
)
1468 SwGetRefField
& rRefField
= *static_cast<SwGetRefField
*>(pField
->GetField());
1469 switch( rRefField
.GetSubType() )
1471 case REF_SEQUENCEFLD
:
1473 RefIdsMap
* pMap
= nullptr;
1474 for( auto n
= aFieldMap
.size(); n
; )
1476 if (aFieldMap
[ --n
]->GetName() == rRefField
.GetSetRefName())
1478 pMap
= aFieldMap
[ n
].get();
1484 pMap
= new RefIdsMap( rRefField
.GetSetRefName() );
1485 aFieldMap
.push_back(std::unique_ptr
<RefIdsMap
>(pMap
));
1488 pMap
->Check(m_rDoc
, rDestDoc
, rRefField
, true);
1494 aFntMap
.Check(m_rDoc
, rDestDoc
, rRefField
, false);
1500 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */