sc: factor out some more code
[LibreOffice.git] / sw / source / core / fields / reffld.cxx
blob35480504f17f10938a795db3e6d444fa8e556a9a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
25 #include <doc.hxx>
26 #include <IDocumentFieldsAccess.hxx>
27 #include <IDocumentLayoutAccess.hxx>
28 #include <IDocumentMarkAccess.hxx>
29 #include <pam.hxx>
30 #include <cntfrm.hxx>
31 #include <pagefrm.hxx>
32 #include <rootfrm.hxx>
33 #include <modeltoviewhelper.hxx>
34 #include <fmtfld.hxx>
35 #include <txtfld.hxx>
36 #include <txtftn.hxx>
37 #include <fmtrfmrk.hxx>
38 #include <txtrfmrk.hxx>
39 #include <fmtftn.hxx>
40 #include <ndtxt.hxx>
41 #include <chpfld.hxx>
42 #include <reffld.hxx>
43 #include <expfld.hxx>
44 #include <txtfrm.hxx>
45 #include <notxtfrm.hxx>
46 #include <flyfrm.hxx>
47 #include <pagedesc.hxx>
48 #include <IMark.hxx>
49 #include <crossrefbookmark.hxx>
50 #include <ftnidx.hxx>
51 #include <utility>
52 #include <viewsh.hxx>
53 #include <unofldmid.h>
54 #include <SwStyleNameMapper.hxx>
55 #include <shellres.hxx>
56 #include <poolfmt.hxx>
57 #include <strings.hrc>
58 #include <numrule.hxx>
59 #include <SwNodeNum.hxx>
60 #include <calbck.hxx>
61 #include <names.hxx>
63 #include <cstddef>
64 #include <memory>
65 #include <vector>
66 #include <set>
67 #include <string_view>
68 #include <map>
69 #include <algorithm>
70 #include <deque>
72 using namespace ::com::sun::star;
73 using namespace ::com::sun::star::text;
75 static std::pair<OUString, bool> MakeRefNumStr(SwRootFrame const* pLayout,
76 const SwTextNode& rTextNodeOfField,
77 const SwTextNode& rTextNodeOfReferencedItem,
78 sal_uInt16 nSubType,
79 sal_uInt32 nRefNumFormat,
80 sal_uInt16 nFlags);
82 static void lcl_GetLayTree( const SwFrame* pFrame, std::vector<const SwFrame*>& rArr )
84 while( pFrame )
86 if( pFrame->IsBodyFrame() ) // unspectacular
87 pFrame = pFrame->GetUpper();
88 else
90 rArr.push_back( pFrame );
92 // this is the last page
93 if( pFrame->IsPageFrame() )
94 break;
96 if( pFrame->IsFlyFrame() )
97 pFrame = static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame();
98 else
99 pFrame = pFrame->GetUpper();
104 bool IsFrameBehind( const SwTextNode& rMyNd, sal_Int32 nMySttPos,
105 const SwTextNode& rBehindNd, sal_Int32 nSttPos )
107 const SwTextFrame * pMyFrame = static_cast<SwTextFrame*>(rMyNd.getLayoutFrame(
108 rMyNd.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr));
109 const SwTextFrame * pFrame = static_cast<SwTextFrame*>(rBehindNd.getLayoutFrame(
110 rBehindNd.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr));
112 if( !pFrame || !pMyFrame)
113 return false;
115 TextFrameIndex const nMySttPosIndex(pMyFrame->MapModelToView(&rMyNd, nMySttPos));
116 TextFrameIndex const nSttPosIndex(pFrame->MapModelToView(&rBehindNd, nSttPos));
117 while (pFrame && !pFrame->IsInside(nSttPosIndex))
118 pFrame = pFrame->GetFollow();
119 while (pMyFrame && !pMyFrame->IsInside(nMySttPosIndex))
120 pMyFrame = pMyFrame->GetFollow();
122 if( !pFrame || !pMyFrame || pFrame == pMyFrame )
123 return false;
125 std::vector<const SwFrame*> aRefArr, aArr;
126 ::lcl_GetLayTree( pFrame, aRefArr );
127 ::lcl_GetLayTree( pMyFrame, aArr );
129 size_t nRefCnt = aRefArr.size() - 1, nCnt = aArr.size() - 1;
130 bool bVert = false;
131 bool bR2L = false;
133 // Loop as long as a frame does not equal?
134 while( nRefCnt && nCnt && aRefArr[ nRefCnt ] == aArr[ nCnt ] )
136 const SwFrame* pTmpFrame = aArr[ nCnt ];
137 bVert = pTmpFrame->IsVertical();
138 bR2L = pTmpFrame->IsRightToLeft();
139 --nCnt;
140 --nRefCnt;
143 // If a counter overflows?
144 if( aRefArr[ nRefCnt ] == aArr[ nCnt ] )
146 if( nCnt )
147 --nCnt;
148 else
149 --nRefCnt;
152 const SwFrame* pRefFrame = aRefArr[ nRefCnt ];
153 const SwFrame* pFieldFrame = aArr[ nCnt ];
155 // different frames, check their Y-/X-position
156 bool bRefIsLower = false;
157 if( ( SwFrameType::Column | SwFrameType::Cell ) & pFieldFrame->GetType() ||
158 ( SwFrameType::Column | SwFrameType::Cell ) & pRefFrame->GetType() )
160 if( pFieldFrame->GetType() == pRefFrame->GetType() )
162 // here, the X-pos is more important
163 if( bVert )
165 if( bR2L )
166 bRefIsLower = pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() ||
167 ( pRefFrame->getFrameArea().Top() == pFieldFrame->getFrameArea().Top() &&
168 pRefFrame->getFrameArea().Left() < pFieldFrame->getFrameArea().Left() );
169 else
170 bRefIsLower = pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() ||
171 ( pRefFrame->getFrameArea().Top() == pFieldFrame->getFrameArea().Top() &&
172 pRefFrame->getFrameArea().Left() > pFieldFrame->getFrameArea().Left() );
174 else if( bR2L )
175 bRefIsLower = pRefFrame->getFrameArea().Left() > pFieldFrame->getFrameArea().Left() ||
176 ( pRefFrame->getFrameArea().Left() == pFieldFrame->getFrameArea().Left() &&
177 pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() );
178 else
179 bRefIsLower = pRefFrame->getFrameArea().Left() < pFieldFrame->getFrameArea().Left() ||
180 ( pRefFrame->getFrameArea().Left() == pFieldFrame->getFrameArea().Left() &&
181 pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() );
182 pRefFrame = nullptr;
184 else if( ( SwFrameType::Column | SwFrameType::Cell ) & pFieldFrame->GetType() )
185 pFieldFrame = aArr[ nCnt - 1 ];
186 else
187 pRefFrame = aRefArr[ nRefCnt - 1 ];
190 if( pRefFrame ) // misuse as flag
192 if( bVert )
194 if( bR2L )
195 bRefIsLower = pRefFrame->getFrameArea().Left() < pFieldFrame->getFrameArea().Left() ||
196 ( pRefFrame->getFrameArea().Left() == pFieldFrame->getFrameArea().Left() &&
197 pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() );
198 else
199 bRefIsLower = pRefFrame->getFrameArea().Left() > pFieldFrame->getFrameArea().Left() ||
200 ( pRefFrame->getFrameArea().Left() == pFieldFrame->getFrameArea().Left() &&
201 pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() );
203 else if( bR2L )
204 bRefIsLower = pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() ||
205 ( pRefFrame->getFrameArea().Top() == pFieldFrame->getFrameArea().Top() &&
206 pRefFrame->getFrameArea().Left() > pFieldFrame->getFrameArea().Left() );
207 else
208 bRefIsLower = pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() ||
209 ( pRefFrame->getFrameArea().Top() == pFieldFrame->getFrameArea().Top() &&
210 pRefFrame->getFrameArea().Left() < pFieldFrame->getFrameArea().Left() );
212 return bRefIsLower;
215 // tdf#115319 create alternative reference formats, if the user asked for it
216 // (ReferenceFieldLanguage attribute of the reference field is not empty), and
217 // language of the text and ReferenceFieldLanguage are the same.
218 // Right now only HUNGARIAN seems to need this (as in the related issue,
219 // the reversed caption order in autocaption, solved by #i61007#)
220 static void lcl_formatReferenceLanguage( OUString& rRefText,
221 bool bClosingParenthesis, LanguageType eLang,
222 std::u16string_view rReferenceLanguage)
224 if (eLang != LANGUAGE_HUNGARIAN || (rReferenceLanguage != u"hu" && rReferenceLanguage != u"Hu"))
225 return;
227 // Add Hungarian definitive article (a/az) before references,
228 // similar to \aref, \apageref etc. of LaTeX Babel package.
230 // for example:
232 // "az 1. oldalon" ("on page 1"), but
233 // "a 2. oldalon" ("on page 2")
234 // "a fentebbi", "az alábbi" (above/below)
235 // "a Lorem", "az Ipsum"
237 // Support following numberings of EU publications:
239 // 1., 1a., a), (1), (1a), iii., III., IA.
241 // (http://publications.europa.eu/code/hu/hu-120700.htm,
242 // http://publications.europa.eu/code/hu/hu-4100600.htm)
244 CharClass aCharClass(( LanguageTag(eLang) ));
245 sal_Int32 nLen = rRefText.getLength();
246 sal_Int32 i;
247 // substring of rRefText starting with letter or number
248 OUString sNumbering;
249 // is article "az"?
250 bool bArticleAz = false;
251 // is numbering a number?
252 bool bNum = false;
254 // search first member of the numbering (numbers or letters)
255 for (i=0; i<nLen && (sNumbering.isEmpty() ||
256 ((bNum && aCharClass.isDigit(rRefText, i)) ||
257 (!bNum && aCharClass.isLetter(rRefText, i)))); ++i)
259 // start of numbering within the field text
260 if (sNumbering.isEmpty() && aCharClass.isLetterNumeric(rRefText, i)) {
261 sNumbering = rRefText.copy(i);
262 bNum = aCharClass.isDigit(rRefText, i);
266 // length of numbering
267 nLen = i - (rRefText.getLength() - sNumbering.getLength());
269 if (bNum)
271 // az 1, 1000, 1000000, 1000000000...
272 // az 5, 50, 500...
273 if ((sNumbering.startsWith("1") && (nLen == 1 || nLen == 4 || nLen == 7 || nLen == 10)) ||
274 sNumbering.startsWith("5"))
275 bArticleAz = true;
277 else if (nLen == 1 && sNumbering[0] < 128)
279 // ASCII 1-letter numbering
280 // az a), e), f) ... x)
281 // az i., v. (but, a x.)
282 static const std::u16string_view sLettersStartingWithVowels = u"aefilmnorsuxyAEFILMNORSUXY";
283 if (sLettersStartingWithVowels.find(sNumbering[0]) != std::u16string_view::npos)
285 // x), X) are letters, but x. and X. etc. are Roman numbers
286 if (bClosingParenthesis ||
287 (sNumbering[0] != 'x' && sNumbering[0] != 'X'))
288 bArticleAz = true;
289 } else if ((sNumbering[0] == 'v' || sNumbering[0] == 'V') && !bClosingParenthesis)
290 // v), V) are letters, but v. and V. are Roman numbers
291 bArticleAz = true;
293 else
295 static const sal_Unicode sVowelsWithDiacritic[] = {
296 0x00E1, 0x00C1, 0x00E9, 0x00C9, 0x00ED, 0x00CD,
297 0x00F3, 0x00D3, 0x00F6, 0x00D6, 0x0151, 0x0150,
298 0x00FA, 0x00DA, 0x00FC, 0x00DC, 0x0171, 0x0170, 0 };
299 static const OUString sVowels = OUString::Concat(u"aAeEiIoOuU") + sVowelsWithDiacritic;
301 // handle more than 1-letter long Roman numbers and
302 // their possible combinations with letters:
303 // az IA, a IIB, a IIIC., az Ia, a IIb., a iiic), az LVIII. szonett
304 bool bRomanNumber = false;
305 if (nLen > 1 && (nLen + 1 >= sNumbering.getLength() || sNumbering[nLen] == '.'))
307 sal_Unicode last = sNumbering[nLen - 1];
308 OUString sNumberingTrim;
309 if ((last >= 'A' && last < 'I') || (last >= 'a' && last < 'i'))
310 sNumberingTrim = sNumbering.copy(0, nLen - 1);
311 else
312 sNumberingTrim = sNumbering.copy(0, nLen);
313 bRomanNumber =
314 sNumberingTrim.replaceAll("i", "").replaceAll("v", "").replaceAll("x", "").replaceAll("l", "").replaceAll("c", "").isEmpty() ||
315 sNumberingTrim.replaceAll("I", "").replaceAll("V", "").replaceAll("X", "").replaceAll("L", "").replaceAll("C", "").isEmpty();
318 if (
319 // Roman number and a letter optionally
320 ( bRomanNumber && (
321 (sNumbering[0] == 'i' && sNumbering[1] != 'i' && sNumbering[1] != 'v' && sNumbering[1] != 'x') ||
322 (sNumbering[0] == 'I' && sNumbering[1] != 'I' && sNumbering[1] != 'V' && sNumbering[1] != 'X') ||
323 (sNumbering[0] == 'v' && sNumbering[1] != 'i') ||
324 (sNumbering[0] == 'V' && sNumbering[1] != 'I') ||
325 (sNumbering[0] == 'l' && sNumbering[1] != 'x') ||
326 (sNumbering[0] == 'L' && sNumbering[1] != 'X')) ) ||
327 // a word starting with vowel (not Roman number)
328 ( !bRomanNumber && sVowels.indexOf(sNumbering[0]) != -1))
330 bArticleAz = true;
333 // not a title text starting already with a definitive article
334 if ( sNumbering.startsWith("A ") || sNumbering.startsWith("Az ") ||
335 sNumbering.startsWith("a ") || sNumbering.startsWith("az ") )
336 return;
338 // lowercase, if rReferenceLanguage == "hu", not "Hu"
339 OUString sArticle;
341 if ( rReferenceLanguage == u"hu" )
342 sArticle = "a";
343 else
344 sArticle = "A";
346 if (bArticleAz)
347 sArticle += "z";
349 rRefText = sArticle + " " + rRefText;
352 /// get references
353 SwGetRefField::SwGetRefField( SwGetRefFieldType* pFieldType,
354 OUString aSetRef, OUString aSetReferenceLanguage, sal_uInt16 nSubTyp,
355 sal_uInt16 nSequenceNo, sal_uInt16 nFlags, sal_uLong nFormat )
356 : SwField(pFieldType, nFormat),
357 m_sSetRefName(std::move(aSetRef)),
358 m_sSetReferenceLanguage(std::move(aSetReferenceLanguage)),
359 m_nSubType(nSubTyp),
360 m_nSeqNo(nSequenceNo),
361 m_nFlags(nFlags)
365 SwGetRefField::~SwGetRefField()
369 OUString SwGetRefField::GetDescription() const
371 return SwResId(STR_REFERENCE);
374 sal_uInt16 SwGetRefField::GetSubType() const
376 return m_nSubType;
379 void SwGetRefField::SetSubType( sal_uInt16 n )
381 m_nSubType = n;
384 // #i81002#
385 bool SwGetRefField::IsRefToHeadingCrossRefBookmark() const
387 return GetSubType() == REF_BOOKMARK &&
388 ::sw::mark::CrossRefHeadingBookmark::IsLegalName(m_sSetRefName);
391 bool SwGetRefField::IsRefToNumItemCrossRefBookmark() const
393 return GetSubType() == REF_BOOKMARK &&
394 ::sw::mark::CrossRefNumItemBookmark::IsLegalName(m_sSetRefName);
397 const SwTextNode* SwGetRefField::GetReferencedTextNode(SwTextNode* pTextNode, SwFrame* pFrame) const
399 SwGetRefFieldType *pTyp = dynamic_cast<SwGetRefFieldType*>(GetTyp());
400 if (!pTyp)
401 return nullptr;
402 sal_Int32 nDummy = -1;
403 return SwGetRefFieldType::FindAnchor( &pTyp->GetDoc(), m_sSetRefName, m_nSubType, m_nSeqNo, m_nFlags, &nDummy,
404 nullptr, nullptr, pTextNode, pFrame );
407 // strikethrough for tooltips using Unicode combining character
408 static OUString lcl_formatStringByCombiningCharacter(std::u16string_view sText, const sal_Unicode cChar)
410 OUStringBuffer sRet(sText.size() * 2);
411 for (size_t i = 0; i < sText.size(); ++i)
413 sRet.append(OUStringChar(sText[i]) + OUStringChar(cChar));
415 return sRet.makeStringAndClear();
418 // #i85090#
419 OUString SwGetRefField::GetExpandedTextOfReferencedTextNode(
420 SwRootFrame const& rLayout) const
422 const SwTextNode* pReferencedTextNode( GetReferencedTextNode(/*pTextNode*/nullptr, /*pFrame*/nullptr) );
423 if ( !pReferencedTextNode )
424 return OUString();
426 // show the referenced text without the deletions, but if the whole text was
427 // deleted, show the original text for the sake of the comfortable reviewing,
428 // but with Unicode strikethrough in the tooltip
429 OUString sRet = sw::GetExpandTextMerged(&rLayout, *pReferencedTextNode, true, false, ExpandMode::HideDeletions);
430 if ( sRet.isEmpty() )
432 static const sal_Unicode cStrikethrough = u'\x0336';
433 sRet = sw::GetExpandTextMerged(&rLayout, *pReferencedTextNode, true, false, ExpandMode(0));
434 sRet = lcl_formatStringByCombiningCharacter( sRet, cStrikethrough );
437 return sRet;
440 void SwGetRefField::SetExpand( const OUString& rStr )
442 m_sText = rStr;
443 m_sTextRLHidden = rStr;
446 OUString SwGetRefField::ExpandImpl(SwRootFrame const*const pLayout) const
448 return pLayout && pLayout->IsHideRedlines() ? m_sTextRLHidden : m_sText;
451 OUString SwGetRefField::GetFieldName() const
453 const OUString aName = GetTyp()->GetName();
454 if ( !aName.isEmpty() || !m_sSetRefName.isEmpty() )
456 return aName + " " + m_sSetRefName;
458 return ExpandImpl(nullptr);
462 static void FilterText(OUString & rText, LanguageType const eLang,
463 std::u16string_view rSetReferenceLanguage)
465 // remove all special characters (replace them with blanks)
466 if (rText.isEmpty())
467 return;
469 rText = rText.replaceAll(u"\u00ad", "");
470 OUStringBuffer aBuf(rText);
471 const sal_Int32 l = aBuf.getLength();
472 for (sal_Int32 i = 0; i < l; ++i)
474 if (aBuf[i] < ' ')
476 aBuf[i] = ' ';
478 else if (aBuf[i] == 0x2011)
480 aBuf[i] = '-';
483 rText = aBuf.makeStringAndClear();
484 if (!rSetReferenceLanguage.empty())
486 lcl_formatReferenceLanguage(rText, false, eLang, rSetReferenceLanguage);
490 // #i81002# - parameter <pFieldTextAttr> added
491 void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr, SwFrame* pFrame )
493 SwDoc& rDoc = static_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
495 for (SwRootFrame const* const pLay : rDoc.GetAllLayouts())
497 if (pLay->IsHideRedlines())
499 UpdateField(pFieldTextAttr, pFrame, pLay, m_sTextRLHidden);
501 else
503 UpdateField(pFieldTextAttr, pFrame, pLay, m_sText);
508 void SwGetRefField::UpdateField(const SwTextField* pFieldTextAttr, SwFrame* pFrameContainingField,
509 const SwRootFrame* const pLayout, OUString& rText)
511 SwDoc& rDoc = static_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
513 rText.clear();
515 // finding the reference target (the number)
516 sal_Int32 nNumStart = -1;
517 sal_Int32 nNumEnd = -1;
518 SwTextNode* pTextNd = SwGetRefFieldType::FindAnchor(
519 &rDoc, m_sSetRefName, m_nSubType, m_nSeqNo, m_nFlags, &nNumStart, &nNumEnd,
520 pLayout, pFieldTextAttr ? pFieldTextAttr->GetpTextNode() : nullptr, pFrameContainingField
522 // not found?
523 if ( !pTextNd )
525 rText = SwViewShell::GetShellRes()->aGetRefField_RefItemNotFound;
527 return;
530 // where is the category name (e.g. "Illustration")?
531 const OUString aText = pTextNd->GetText();
532 const sal_Int32 nCatStart = aText.indexOf(m_sSetRefName);
533 const bool bHasCat = nCatStart>=0;
534 const sal_Int32 nCatEnd = bHasCat ? nCatStart + m_sSetRefName.getLength() : -1;
536 // length of the referenced text
537 const sal_Int32 nLen = aText.getLength();
539 // which format?
540 switch( GetFormat() )
542 case REF_CONTENT:
543 case REF_ONLYNUMBER:
544 case REF_ONLYCAPTION:
545 case REF_ONLYSEQNO:
547 // needed part of Text
548 sal_Int32 nStart;
549 sal_Int32 nEnd;
551 switch( m_nSubType )
553 case REF_SEQUENCEFLD:
555 switch( GetFormat() )
557 // "Category and Number"
558 case REF_ONLYNUMBER:
559 if (bHasCat) {
560 nStart = std::min(nNumStart, nCatStart);
561 nEnd = std::max(nNumEnd, nCatEnd);
562 } else {
563 nStart = nNumStart;
564 nEnd = nNumEnd;
566 break;
568 // "Caption Text"
569 case REF_ONLYCAPTION: {
570 // next alphanumeric character after category+number
571 if (const SwTextAttr* const pTextAttr =
572 pTextNd->GetTextAttrForCharAt(nNumStart, RES_TXTATR_FIELD)
574 // start searching from nFrom
575 const sal_Int32 nFrom = bHasCat
576 ? std::max(nNumStart + 1, nCatEnd)
577 : nNumStart + 1;
578 nStart = SwGetExpField::GetReferenceTextPos( pTextAttr->GetFormatField(), rDoc, nFrom );
579 } else {
580 nStart = bHasCat ? std::max(nNumEnd, nCatEnd) : nNumEnd;
582 nEnd = nLen;
583 break;
586 // "Numbering"
587 case REF_ONLYSEQNO:
588 nStart = nNumStart;
589 nEnd = std::min(nStart + 1, nLen);
590 break;
592 // "Reference" (whole Text)
593 case REF_CONTENT:
594 nStart = 0;
595 nEnd = nLen;
596 break;
598 default:
599 O3TL_UNREACHABLE;
601 break;
603 case REF_BOOKMARK:
604 nStart = nNumStart;
605 // text is spread across multiple nodes - get whole text or only until end of node?
606 nEnd = nNumEnd<0 ? nLen : nNumEnd;
607 break;
609 case REF_OUTLINE:
610 case REF_SETREFATTR:
611 nStart = nNumStart;
612 nEnd = nNumEnd;
613 break;
615 case REF_FOOTNOTE:
616 case REF_ENDNOTE:
617 // get number or numString
618 for( size_t i = 0; i < rDoc.GetFootnoteIdxs().size(); ++i )
620 SwTextFootnote* const pFootnoteIdx = rDoc.GetFootnoteIdxs()[i];
621 if( m_nSeqNo == pFootnoteIdx->GetSeqRefNo() )
623 rText = pFootnoteIdx->GetFootnote().GetViewNumStr(rDoc, pLayout);
624 if (!m_sSetReferenceLanguage.isEmpty())
626 lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
628 break;
631 return;
633 case REF_STYLE:
634 nStart = 0;
635 nEnd = nLen;
636 break;
638 default:
639 O3TL_UNREACHABLE;
642 if( nStart != nEnd ) // a section?
644 if (pLayout->IsHideRedlines())
646 if (m_nSubType == REF_OUTLINE
647 || (m_nSubType == REF_SEQUENCEFLD && REF_CONTENT == GetFormat()))
649 rText = sw::GetExpandTextMerged(pLayout, *pTextNd, false, false,
650 ExpandMode(0));
652 else
654 rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false,
655 false, ExpandMode::HideDeletions);
658 else
660 rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false,
661 false, ExpandMode::HideDeletions);
662 // show the referenced text without the deletions, but if the whole text was
663 // deleted, show the original text for the sake of the comfortable reviewing
664 // (with strikethrough in tooltip, see GetExpandedTextOfReferencedTextNode())
665 if (rText.isEmpty())
666 rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false,
667 false, ExpandMode(0));
669 FilterText(rText, GetLanguage(), m_sSetReferenceLanguage);
672 break;
674 case REF_PAGE:
675 case REF_PAGE_PGDESC:
677 SwTextFrame const* pFrame = static_cast<SwTextFrame*>(pTextNd->getLayoutFrame(pLayout, nullptr, nullptr));
678 SwTextFrame const*const pSave = pFrame;
679 if (pFrame)
681 TextFrameIndex const nNumStartIndex(pFrame->MapModelToView(pTextNd, nNumStart));
682 while (pFrame && !pFrame->IsInside(nNumStartIndex))
683 pFrame = pFrame->GetFollow();
686 if( pFrame || nullptr != ( pFrame = pSave ))
688 sal_uInt16 nPageNo = pFrame->GetVirtPageNum();
689 const SwPageFrame *pPage;
690 if( REF_PAGE_PGDESC == GetFormat() &&
691 nullptr != ( pPage = pFrame->FindPageFrame() ) &&
692 pPage->GetPageDesc() )
694 rText = pPage->GetPageDesc()->GetNumType().GetNumStr(nPageNo);
696 else
698 rText = OUString::number(nPageNo);
701 if (!m_sSetReferenceLanguage.isEmpty())
702 lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
705 break;
707 case REF_CHAPTER:
709 // a bit tricky: search any frame
710 SwFrame const* const pFrame = pTextNd->getLayoutFrame(pLayout);
711 if (pFrame)
713 SwChapterFieldType aFieldTyp;
714 SwChapterField aField(&aFieldTyp, 0);
715 aField.SetLevel(MAXLEVEL - 1);
716 aField.ChangeExpansion(*pFrame, pTextNd, true);
718 rText = aField.GetNumber(pLayout);
720 if (!m_sSetReferenceLanguage.isEmpty())
721 lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
724 break;
726 case REF_UPDOWN:
728 // #i81002#
729 // simplified: use parameter <pFieldTextAttr>
730 if( !pFieldTextAttr || !pFieldTextAttr->GetpTextNode() )
731 break;
733 LocaleDataWrapper aLocaleData(( LanguageTag( GetLanguage() ) ));
735 // first a "short" test - in case both are in the same node
736 if( pFieldTextAttr->GetpTextNode() == pTextNd )
738 rText = nNumStart < pFieldTextAttr->GetStart()
739 ? aLocaleData.getAboveWord()
740 : aLocaleData.getBelowWord();
741 break;
744 rText = ::IsFrameBehind( *pFieldTextAttr->GetpTextNode(), pFieldTextAttr->GetStart(),
745 *pTextNd, nNumStart )
746 ? aLocaleData.getAboveWord()
747 : aLocaleData.getBelowWord();
749 if (!m_sSetReferenceLanguage.isEmpty())
750 lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
752 break;
753 // #i81002#
754 case REF_NUMBER:
755 case REF_NUMBER_NO_CONTEXT:
756 case REF_NUMBER_FULL_CONTEXT:
758 if ( pFieldTextAttr && pFieldTextAttr->GetpTextNode() )
760 auto result =
761 MakeRefNumStr(pLayout, pFieldTextAttr->GetTextNode(), *pTextNd, m_nSubType, GetFormat(), GetFlags());
762 rText = result.first;
763 // for differentiation of Roman numbers and letters in Hungarian article handling
764 bool bClosingParenthesis = result.second;
765 if (!m_sSetReferenceLanguage.isEmpty())
767 lcl_formatReferenceLanguage(rText, bClosingParenthesis, GetLanguage(), m_sSetReferenceLanguage);
772 break;
774 default:
775 OSL_FAIL("<SwGetRefField::UpdateField(..)> - unknown format type");
780 // #i81002#
781 static std::pair<OUString, bool> MakeRefNumStr(
782 SwRootFrame const*const pLayout,
783 const SwTextNode& i_rTextNodeOfField,
784 const SwTextNode& i_rTextNodeOfReferencedItem,
785 const sal_uInt16 nSubType,
786 const sal_uInt32 nRefNumFormat,
787 const sal_uInt16 nFlags)
789 bool bHideNonNumerical = (nSubType == REF_STYLE) && ((nFlags & REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL) == REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL);
790 SwTextNode const& rTextNodeOfField(pLayout
791 ? *sw::GetParaPropsNode(*pLayout, i_rTextNodeOfField)
792 : i_rTextNodeOfField);
793 SwTextNode const& rTextNodeOfReferencedItem(pLayout
794 ? *sw::GetParaPropsNode(*pLayout, i_rTextNodeOfReferencedItem)
795 : i_rTextNodeOfReferencedItem);
796 if ( rTextNodeOfReferencedItem.HasNumber(pLayout) &&
797 rTextNodeOfReferencedItem.IsCountedInList() )
799 OSL_ENSURE( rTextNodeOfReferencedItem.GetNum(pLayout),
800 "<SwGetRefField::MakeRefNumStr(..)> - referenced paragraph has number, but no <SwNodeNum> instance!" );
802 // Determine, up to which level the superior list labels have to be
803 // included - default is to include all superior list labels.
804 int nRestrictInclToThisLevel( 0 );
805 // Determine for format REF_NUMBER the level, up to which the superior
806 // list labels have to be restricted, if the text node of the reference
807 // field and the text node of the referenced item are in the same
808 // document context.
809 if ( nRefNumFormat == REF_NUMBER &&
810 rTextNodeOfField.FindFlyStartNode()
811 == rTextNodeOfReferencedItem.FindFlyStartNode() &&
812 rTextNodeOfField.FindFootnoteStartNode()
813 == rTextNodeOfReferencedItem.FindFootnoteStartNode() &&
814 rTextNodeOfField.FindHeaderStartNode()
815 == rTextNodeOfReferencedItem.FindHeaderStartNode() &&
816 rTextNodeOfField.FindFooterStartNode()
817 == rTextNodeOfReferencedItem.FindFooterStartNode() )
819 const SwNodeNum* pNodeNumForTextNodeOfField( nullptr );
820 if ( rTextNodeOfField.HasNumber(pLayout) &&
821 rTextNodeOfField.GetNumRule() == rTextNodeOfReferencedItem.GetNumRule() )
823 pNodeNumForTextNodeOfField = rTextNodeOfField.GetNum(pLayout);
825 else
827 pNodeNumForTextNodeOfField =
828 rTextNodeOfReferencedItem.GetNum(pLayout)->GetPrecedingNodeNumOf(rTextNodeOfField);
830 if ( pNodeNumForTextNodeOfField )
832 const SwNumberTree::tNumberVector rFieldNumVec =
833 pNodeNumForTextNodeOfField->GetNumberVector();
834 const SwNumberTree::tNumberVector rRefItemNumVec =
835 rTextNodeOfReferencedItem.GetNum()->GetNumberVector();
836 std::size_t nLevel( 0 );
837 while ( nLevel < rFieldNumVec.size() && nLevel < rRefItemNumVec.size() )
839 if ( rRefItemNumVec[nLevel] == rFieldNumVec[nLevel] )
841 nRestrictInclToThisLevel = nLevel + 1;
843 else
845 break;
847 ++nLevel;
852 // Determine, if superior list labels have to be included
853 const bool bInclSuperiorNumLabels(
854 ( nRestrictInclToThisLevel < rTextNodeOfReferencedItem.GetActualListLevel() &&
855 ( nRefNumFormat == REF_NUMBER || nRefNumFormat == REF_NUMBER_FULL_CONTEXT ) ) );
857 OSL_ENSURE( rTextNodeOfReferencedItem.GetNumRule(),
858 "<SwGetRefField::MakeRefNumStr(..)> - referenced numbered paragraph has no numbering rule set!" );
859 return std::make_pair(
860 rTextNodeOfReferencedItem.GetNumRule()->MakeRefNumString(
861 *(rTextNodeOfReferencedItem.GetNum(pLayout)),
862 bInclSuperiorNumLabels,
863 nRestrictInclToThisLevel,
864 bHideNonNumerical ),
865 rTextNodeOfReferencedItem.GetNumRule()->MakeNumString(
866 *(rTextNodeOfReferencedItem.GetNum(pLayout)),
867 true).endsWith(")") );
870 return std::make_pair(OUString(), false);
873 std::unique_ptr<SwField> SwGetRefField::Copy() const
875 std::unique_ptr<SwGetRefField> pField( new SwGetRefField( static_cast<SwGetRefFieldType*>(GetTyp()),
876 m_sSetRefName, m_sSetReferenceLanguage, m_nSubType,
877 m_nSeqNo, m_nFlags, GetFormat() ) );
878 pField->m_sText = m_sText;
879 pField->m_sTextRLHidden = m_sTextRLHidden;
880 return std::unique_ptr<SwField>(pField.release());
883 /// get reference name
884 OUString SwGetRefField::GetPar1() const
886 return m_sSetRefName;
889 /// set reference name
890 void SwGetRefField::SetPar1( const OUString& rName )
892 m_sSetRefName = rName;
895 OUString SwGetRefField::GetPar2() const
897 return ExpandImpl(nullptr);
900 bool SwGetRefField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
902 switch( nWhichId )
904 case FIELD_PROP_USHORT1:
906 sal_Int16 nPart = 0;
907 switch(GetFormat())
909 case REF_PAGE : nPart = ReferenceFieldPart::PAGE ; break;
910 case REF_CHAPTER : nPart = ReferenceFieldPart::CHAPTER ; break;
911 case REF_CONTENT : nPart = ReferenceFieldPart::TEXT ; break;
912 case REF_UPDOWN : nPart = ReferenceFieldPart::UP_DOWN ; break;
913 case REF_PAGE_PGDESC: nPart = ReferenceFieldPart::PAGE_DESC ; break;
914 case REF_ONLYNUMBER : nPart = ReferenceFieldPart::CATEGORY_AND_NUMBER ; break;
915 case REF_ONLYCAPTION: nPart = ReferenceFieldPart::ONLY_CAPTION ; break;
916 case REF_ONLYSEQNO : nPart = ReferenceFieldPart::ONLY_SEQUENCE_NUMBER; break;
917 // #i81002#
918 case REF_NUMBER: nPart = ReferenceFieldPart::NUMBER; break;
919 case REF_NUMBER_NO_CONTEXT: nPart = ReferenceFieldPart::NUMBER_NO_CONTEXT; break;
920 case REF_NUMBER_FULL_CONTEXT: nPart = ReferenceFieldPart::NUMBER_FULL_CONTEXT; break;
922 rAny <<= nPart;
924 break;
925 case FIELD_PROP_USHORT2:
927 sal_Int16 nSource = 0;
928 switch(m_nSubType)
930 case REF_SETREFATTR : nSource = ReferenceFieldSource::REFERENCE_MARK; break;
931 case REF_SEQUENCEFLD: nSource = ReferenceFieldSource::SEQUENCE_FIELD; break;
932 case REF_BOOKMARK : nSource = ReferenceFieldSource::BOOKMARK; break;
933 case REF_OUTLINE : OSL_FAIL("not implemented"); break;
934 case REF_FOOTNOTE : nSource = ReferenceFieldSource::FOOTNOTE; break;
935 case REF_ENDNOTE : nSource = ReferenceFieldSource::ENDNOTE; break;
936 case REF_STYLE : nSource = ReferenceFieldSource::STYLE; break;
938 rAny <<= nSource;
940 break;
941 case FIELD_PROP_USHORT3:
942 rAny <<= m_nFlags;
943 break;
944 case FIELD_PROP_PAR1:
946 OUString sTmp(GetPar1());
947 if(REF_SEQUENCEFLD == m_nSubType)
949 sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromUIName( sTmp, SwGetPoolIdFromName::TxtColl );
950 switch( nPoolId )
952 case RES_POOLCOLL_LABEL_ABB:
953 case RES_POOLCOLL_LABEL_TABLE:
954 case RES_POOLCOLL_LABEL_FRAME:
955 case RES_POOLCOLL_LABEL_DRAWING:
956 case RES_POOLCOLL_LABEL_FIGURE:
958 ProgName sTmp2(sTmp);
959 SwStyleNameMapper::FillProgName(nPoolId, sTmp2) ;
960 sTmp = sTmp2.toString();
962 break;
965 rAny <<= sTmp;
967 break;
968 case FIELD_PROP_PAR3:
969 rAny <<= ExpandImpl(nullptr);
970 break;
971 case FIELD_PROP_PAR4:
972 rAny <<= m_sSetReferenceLanguage;
973 break;
974 case FIELD_PROP_SHORT1:
975 rAny <<= static_cast<sal_Int16>(m_nSeqNo);
976 break;
977 default:
978 assert(false);
980 return true;
983 bool SwGetRefField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
985 switch( nWhichId )
987 case FIELD_PROP_USHORT1:
989 sal_Int16 nPart = 0;
990 rAny >>= nPart;
991 switch(nPart)
993 case ReferenceFieldPart::PAGE: nPart = REF_PAGE; break;
994 case ReferenceFieldPart::CHAPTER: nPart = REF_CHAPTER; break;
995 case ReferenceFieldPart::TEXT: nPart = REF_CONTENT; break;
996 case ReferenceFieldPart::UP_DOWN: nPart = REF_UPDOWN; break;
997 case ReferenceFieldPart::PAGE_DESC: nPart = REF_PAGE_PGDESC; break;
998 case ReferenceFieldPart::CATEGORY_AND_NUMBER: nPart = REF_ONLYNUMBER; break;
999 case ReferenceFieldPart::ONLY_CAPTION: nPart = REF_ONLYCAPTION; break;
1000 case ReferenceFieldPart::ONLY_SEQUENCE_NUMBER : nPart = REF_ONLYSEQNO; break;
1001 // #i81002#
1002 case ReferenceFieldPart::NUMBER: nPart = REF_NUMBER; break;
1003 case ReferenceFieldPart::NUMBER_NO_CONTEXT: nPart = REF_NUMBER_NO_CONTEXT; break;
1004 case ReferenceFieldPart::NUMBER_FULL_CONTEXT: nPart = REF_NUMBER_FULL_CONTEXT; break;
1005 default: return false;
1007 SetFormat(nPart);
1009 break;
1010 case FIELD_PROP_USHORT2:
1012 sal_Int16 nSource = 0;
1013 rAny >>= nSource;
1014 switch(nSource)
1016 case ReferenceFieldSource::REFERENCE_MARK : m_nSubType = REF_SETREFATTR ; break;
1017 case ReferenceFieldSource::SEQUENCE_FIELD :
1019 if(REF_SEQUENCEFLD == m_nSubType)
1020 break;
1021 m_nSubType = REF_SEQUENCEFLD;
1022 ConvertProgrammaticToUIName();
1024 break;
1025 case ReferenceFieldSource::BOOKMARK : m_nSubType = REF_BOOKMARK ; break;
1026 case ReferenceFieldSource::FOOTNOTE : m_nSubType = REF_FOOTNOTE ; break;
1027 case ReferenceFieldSource::ENDNOTE : m_nSubType = REF_ENDNOTE ; break;
1028 case ReferenceFieldSource::STYLE : m_nSubType = REF_STYLE ; break;
1031 break;
1032 case FIELD_PROP_PAR1:
1034 OUString sTmpStr;
1035 rAny >>= sTmpStr;
1036 SetPar1(sTmpStr);
1037 ConvertProgrammaticToUIName();
1039 break;
1040 case FIELD_PROP_PAR3:
1042 OUString sTmpStr;
1043 rAny >>= sTmpStr;
1044 SetExpand( sTmpStr );
1046 break;
1047 case FIELD_PROP_PAR4:
1048 rAny >>= m_sSetReferenceLanguage;
1049 break;
1050 case FIELD_PROP_USHORT3:
1052 sal_uInt16 nSetFlags = 0;
1053 rAny >>= nSetFlags;
1054 m_nFlags = nSetFlags;
1056 break;
1057 case FIELD_PROP_SHORT1:
1059 sal_Int16 nSetSeq = 0;
1060 rAny >>= nSetSeq;
1061 if(nSetSeq >= 0)
1062 m_nSeqNo = nSetSeq;
1064 break;
1065 default:
1066 assert(false);
1068 return true;
1071 void SwGetRefField::ConvertProgrammaticToUIName()
1073 if(!(GetTyp() && REF_SEQUENCEFLD == m_nSubType))
1074 return;
1076 SwDoc& rDoc = static_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
1077 const OUString rPar1 = GetPar1();
1078 // don't convert when the name points to an existing field type
1079 if (rDoc.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp, rPar1, false))
1080 return;
1082 sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromProgName( ProgName(rPar1), SwGetPoolIdFromName::TxtColl );
1083 TranslateId pResId;
1084 switch( nPoolId )
1086 case RES_POOLCOLL_LABEL_ABB:
1087 pResId = STR_POOLCOLL_LABEL_ABB;
1088 break;
1089 case RES_POOLCOLL_LABEL_TABLE:
1090 pResId = STR_POOLCOLL_LABEL_TABLE;
1091 break;
1092 case RES_POOLCOLL_LABEL_FRAME:
1093 pResId = STR_POOLCOLL_LABEL_FRAME;
1094 break;
1095 case RES_POOLCOLL_LABEL_DRAWING:
1096 pResId = STR_POOLCOLL_LABEL_DRAWING;
1097 break;
1098 case RES_POOLCOLL_LABEL_FIGURE:
1099 pResId = STR_POOLCOLL_LABEL_FIGURE;
1100 break;
1102 if (pResId)
1103 SetPar1(SwResId(pResId));
1106 SwGetRefFieldType::SwGetRefFieldType( SwDoc& rDc )
1107 : SwFieldType( SwFieldIds::GetRef ), m_rDoc( rDc )
1110 std::unique_ptr<SwFieldType> SwGetRefFieldType::Copy() const
1112 return std::make_unique<SwGetRefFieldType>( m_rDoc );
1115 void SwGetRefFieldType::UpdateGetReferences()
1117 std::vector<SwFormatField*> vFields;
1118 GatherFields(vFields, false);
1119 for(auto pFormatField: vFields)
1121 // update only the GetRef fields
1122 //JP 3.4.2001: Task 71231 - we need the correct language
1123 SwGetRefField* pGRef = static_cast<SwGetRefField*>(pFormatField->GetField());
1124 const SwTextField* pTField;
1125 if(!pGRef->GetLanguage() &&
1126 nullptr != (pTField = pFormatField->GetTextField()) &&
1127 pTField->GetpTextNode())
1129 pGRef->SetLanguage(pTField->GetpTextNode()->GetLang(pTField->GetStart()));
1132 // #i81002#
1133 pGRef->UpdateField(pFormatField->GetTextField(), nullptr);
1135 CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
1138 void SwGetRefFieldType::UpdateStyleReferences()
1140 std::vector<SwFormatField*> vFields;
1141 GatherFields(vFields, false);
1142 bool bModified = false;
1143 for(auto pFormatField: vFields)
1145 // update only the GetRef fields which are also STYLEREF fields
1146 SwGetRefField* pGRef = static_cast<SwGetRefField*>(pFormatField->GetField());
1148 if (pGRef->GetSubType() != REF_STYLE) continue;
1150 const SwTextField* pTField;
1151 if(!pGRef->GetLanguage() &&
1152 nullptr != (pTField = pFormatField->GetTextField()) &&
1153 pTField->GetpTextNode())
1155 pGRef->SetLanguage(pTField->GetpTextNode()->GetLang(pTField->GetStart()));
1158 pGRef->UpdateField(pFormatField->GetTextField(), nullptr);
1159 bModified = true;
1161 if (bModified)
1162 CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
1165 void SwGetRefFieldType::SwClientNotify(const SwModify&, const SfxHint& rHint)
1167 if (rHint.GetId() == SfxHintId::SwFormatChange || rHint.GetId() == SfxHintId::SwObjectDying)
1169 // forward to text fields, they "expand" the text
1170 CallSwClientNotify(rHint);
1171 return;
1173 if (rHint.GetId() == SfxHintId::SwAttrSetChange)
1175 auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint);
1176 if(!pChangeHint->m_pNew && !pChangeHint->m_pOld)
1177 // update to all GetReference fields
1178 // hopefully, this codepath is soon dead code, and
1179 // UpdateGetReferences gets only called directly
1180 UpdateGetReferences();
1181 else
1182 // forward to text fields, they "expand" the text
1183 CallSwClientNotify(rHint);
1184 return;
1186 if (rHint.GetId() == SfxHintId::SwUpdateAttr)
1188 auto pChangeHint = static_cast<const sw::UpdateAttrHint*>(&rHint);
1189 if(!pChangeHint->m_pNew && !pChangeHint->m_pOld)
1190 // update to all GetReference fields
1191 // hopefully, this codepath is soon dead code, and
1192 // UpdateGetReferences gets only called directly
1193 UpdateGetReferences();
1194 else
1195 // forward to text fields, they "expand" the text
1196 CallSwClientNotify(rHint);
1197 return;
1199 if (rHint.GetId() != SfxHintId::SwLegacyModify)
1200 return;
1201 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
1202 if(!pLegacy->m_pNew && !pLegacy->m_pOld)
1203 // update to all GetReference fields
1204 // hopefully, this codepath is soon dead code, and
1205 // UpdateGetReferences gets only called directly
1206 UpdateGetReferences();
1207 else
1208 // forward to text fields, they "expand" the text
1209 CallSwClientNotify(rHint);
1212 namespace sw {
1214 bool IsMarkHintHidden(SwRootFrame const& rLayout,
1215 SwTextNode const& rNode, SwTextAttrEnd const& rHint)
1217 if (!rLayout.HasMergedParas())
1219 return false;
1221 SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
1222 rNode.getLayoutFrame(&rLayout)));
1223 if (!pFrame)
1225 return true;
1227 sal_Int32 const*const pEnd(rHint.GetEnd());
1228 if (pEnd)
1230 return pFrame->MapModelToView(&rNode, rHint.GetStart())
1231 == pFrame->MapModelToView(&rNode, *pEnd);
1233 else
1235 assert(rHint.HasDummyChar());
1236 return pFrame->MapModelToView(&rNode, rHint.GetStart())
1237 == pFrame->MapModelToView(&rNode, rHint.GetStart() + 1);
1241 } // namespace sw
1243 namespace
1245 enum StyleRefElementType
1247 Default,
1248 Reference, /* e.g. footnotes, endnotes */
1249 Marginal, /* headers, footers */
1252 SwTextNode* SearchForStyleAnchor(SwTextNode* pSelf, SwNode* pCurrent,
1253 std::u16string_view rStyleName,
1254 sal_Int32 *const pStart, sal_Int32 *const pEnd,
1255 bool bCaseSensitive = true)
1257 if (pCurrent == pSelf)
1258 return nullptr;
1260 SwTextNode* pTextNode = pCurrent->GetTextNode();
1261 if (!pTextNode)
1262 return nullptr;
1264 auto const & rFormatName = pTextNode->GetFormatColl()->GetName();
1265 if (bCaseSensitive
1266 ? rFormatName == rStyleName
1267 : rFormatName.equalsIgnoreAsciiCase(rStyleName))
1269 *pStart = 0;
1270 if (pEnd)
1272 *pEnd = pTextNode->GetText().getLength();
1274 return pTextNode;
1277 if (auto const pHints = pTextNode->GetpSwpHints())
1279 for (size_t i = 0, nCnt = pHints->Count(); i < nCnt; ++i)
1281 auto const*const pHint(pHints->Get(i));
1282 if (pHint->Which() == RES_TXTATR_CHARFMT)
1284 if (bCaseSensitive
1285 ? pHint->GetCharFormat().GetCharFormat()->HasName(rStyleName)
1286 : pHint->GetCharFormat().GetCharFormat()->GetName().equalsIgnoreAsciiCase(rStyleName))
1288 *pStart = pHint->GetStart();
1289 if (pEnd)
1291 *pEnd = *pHint->End();
1293 return pTextNode;
1299 return nullptr;
1301 /// Picks the first text node with a matching style from the specified node range
1302 SwTextNode* SearchForStyleAnchor(SwTextNode* pSelf, const SwNodes& rNodes, SwNodeOffset nNodeStart, SwNodeOffset nNodeEnd, bool bSearchBackward,
1303 std::u16string_view rStyleName,
1304 sal_Int32 *const pStart, sal_Int32 *const pEnd,
1305 bool bCaseSensitive = true)
1307 if (!bSearchBackward)
1309 for (SwNodeOffset nCurrent = nNodeStart; nCurrent <= nNodeEnd; ++nCurrent)
1311 SwNode* pCurrent = rNodes[nCurrent];
1312 SwTextNode* pFound = SearchForStyleAnchor(pSelf, pCurrent, rStyleName, pStart, pEnd, bCaseSensitive);
1313 if (pFound)
1314 return pFound;
1317 else
1319 for (SwNodeOffset nCurrent = nNodeEnd; nCurrent >= nNodeStart; --nCurrent)
1321 SwNode* pCurrent = rNodes[nCurrent];
1322 SwTextNode* pFound = SearchForStyleAnchor(pSelf, pCurrent, rStyleName, pStart, pEnd, bCaseSensitive);
1323 if (pFound)
1324 return pFound;
1327 return nullptr;
1331 SwTextNode* SwGetRefFieldType::FindAnchor(SwDoc* pDoc, const OUString& rRefMark,
1332 sal_uInt16 nSubType, sal_uInt16 nSeqNo, sal_uInt16 nFlags,
1333 sal_Int32* pStart, sal_Int32* pEnd, SwRootFrame const* const pLayout,
1334 SwTextNode* pSelf, SwFrame* pContentFrame)
1336 assert( pStart && "Why did no one check the StartPos?" );
1338 IDocumentRedlineAccess & rIDRA(pDoc->getIDocumentRedlineAccess());
1339 SwTextNode* pTextNd = nullptr;
1340 switch( nSubType )
1342 case REF_SETREFATTR:
1344 const SwFormatRefMark *pRef = pDoc->GetRefMark( rRefMark );
1345 SwTextRefMark const*const pRefMark(pRef ? pRef->GetTextRefMark() : nullptr);
1346 if (pRefMark && (!pLayout || !sw::IsMarkHintHidden(*pLayout,
1347 pRefMark->GetTextNode(), *pRefMark)))
1349 pTextNd = const_cast<SwTextNode*>(&pRef->GetTextRefMark()->GetTextNode());
1350 *pStart = pRef->GetTextRefMark()->GetStart();
1351 if( pEnd )
1352 *pEnd = pRef->GetTextRefMark()->GetAnyEnd();
1355 break;
1357 case REF_SEQUENCEFLD:
1359 SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetFieldType( SwFieldIds::SetExp, rRefMark, false );
1360 if( pFieldType && pFieldType->HasWriterListeners() &&
1361 nsSwGetSetExpType::GSE_SEQ & static_cast<SwSetExpFieldType*>(pFieldType)->GetType() )
1363 std::vector<SwFormatField*> vFields;
1364 pFieldType->GatherFields(vFields, false);
1365 for(auto pFormatField: vFields)
1367 SwTextField *const pTextField(pFormatField->GetTextField());
1368 if (pTextField && nSeqNo ==
1369 static_cast<SwSetExpField*>(pFormatField->GetField())->GetSeqNumber()
1370 && (!pLayout || !pLayout->IsHideRedlines()
1371 || !sw::IsFieldDeletedInModel(rIDRA, *pTextField)))
1373 pTextNd = pTextField->GetpTextNode();
1374 *pStart = pTextField->GetStart();
1375 if( pEnd )
1376 *pEnd = (*pStart) + 1;
1377 break;
1382 break;
1384 case REF_BOOKMARK:
1386 auto ppMark = pDoc->getIDocumentMarkAccess()->findMark(rRefMark);
1387 if (ppMark != pDoc->getIDocumentMarkAccess()->getAllMarksEnd()
1388 && (!pLayout || !pLayout->IsHideRedlines()
1389 || !sw::IsMarkHidden(*pLayout, **ppMark)))
1391 const ::sw::mark::MarkBase* pBkmk = *ppMark;
1392 const SwPosition* pPos = &pBkmk->GetMarkStart();
1394 pTextNd = pPos->GetNode().GetTextNode();
1395 *pStart = pPos->GetContentIndex();
1396 if(pEnd)
1398 if(!pBkmk->IsExpanded())
1400 *pEnd = *pStart;
1401 // #i81002#
1402 if(dynamic_cast< ::sw::mark::CrossRefBookmark const *>(pBkmk))
1404 assert(pTextNd &&
1405 "<SwGetRefFieldType::FindAnchor(..)> - node marked by cross-reference bookmark isn't a text node --> crash");
1406 *pEnd = pTextNd->Len();
1409 else if(pBkmk->GetOtherMarkPos().GetNode() == pBkmk->GetMarkPos().GetNode())
1410 *pEnd = pBkmk->GetMarkEnd().GetContentIndex();
1411 else
1412 *pEnd = -1;
1416 break;
1418 case REF_OUTLINE:
1419 break;
1421 case REF_FOOTNOTE:
1422 case REF_ENDNOTE:
1424 for( auto pFootnoteIdx : pDoc->GetFootnoteIdxs() )
1425 if( nSeqNo == pFootnoteIdx->GetSeqRefNo() )
1427 if (pLayout && pLayout->IsHideRedlines()
1428 && sw::IsFootnoteDeleted(rIDRA, *pFootnoteIdx))
1430 return nullptr;
1432 // otherwise: the position at the start of the footnote
1433 // will be mapped to something visible at least...
1434 const SwNodeIndex* pIdx = pFootnoteIdx->GetStartNode();
1435 if( pIdx )
1437 SwNodeIndex aIdx( *pIdx, 1 );
1438 pTextNd = aIdx.GetNode().GetTextNode();
1439 if( nullptr == pTextNd )
1440 pTextNd = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
1442 *pStart = 0;
1443 if( pEnd )
1444 *pEnd = 0;
1445 break;
1448 break;
1449 case REF_STYLE:
1450 pTextNd = FindAnchorRefStyle(pDoc, rRefMark, nFlags,
1451 pStart, pEnd, pLayout, pSelf, pContentFrame);
1452 break;
1455 return pTextNd;
1458 SwTextNode* SwGetRefFieldType::FindAnchorRefStyle(SwDoc* pDoc, const OUString& rRefMark,
1459 sal_uInt16 nFlags,
1460 sal_Int32* pStart, sal_Int32* pEnd, SwRootFrame const* const pLayout,
1461 SwTextNode* pSelf, SwFrame* pContentFrame)
1463 if (!pSelf)
1464 return nullptr;
1466 SwTextNode* pTextNd = nullptr;
1468 StyleRefElementType elementType = StyleRefElementType::Default;
1469 const SwTextNode* pReference = nullptr;
1470 IDocumentRedlineAccess & rIDRA(pDoc->getIDocumentRedlineAccess());
1472 /* Check if we're a footnote/endnote */
1473 for (SwTextFootnote* pFootnoteIdx : pDoc->GetFootnoteIdxs())
1475 if (pLayout && pLayout->IsHideRedlines()
1476 && sw::IsFootnoteDeleted(rIDRA, *pFootnoteIdx))
1478 continue;
1480 const SwNodeIndex* pIdx = pFootnoteIdx->GetStartNode();
1481 if (pIdx)
1483 SwNodeIndex aIdx(*pIdx, 1);
1484 SwTextNode* pFootnoteNode = aIdx.GetNode().GetTextNode();
1485 if (nullptr == pFootnoteNode)
1486 pFootnoteNode = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
1488 if (*pSelf == *pFootnoteNode)
1490 elementType = StyleRefElementType::Reference;
1491 pReference = &pFootnoteIdx->GetTextNode();
1496 if (pDoc->IsInHeaderFooter(*pSelf))
1498 elementType = StyleRefElementType::Marginal;
1501 if (pReference == nullptr)
1503 pReference = pSelf;
1506 // undocumented Word feature: 1 = "Heading 1" etc.
1507 OUString const styleName(
1508 (rRefMark.getLength() == 1 && '1' <= rRefMark[0] && rRefMark[0] <= '9')
1509 ? SwStyleNameMapper::GetProgName(RES_POOLCOLL_HEADLINE1 + rRefMark[0] - '1', rRefMark).toString()
1510 : rRefMark);
1512 switch (elementType)
1514 case Marginal:
1515 pTextNd = FindAnchorRefStyleMarginal(pDoc, nFlags,
1516 pStart, pEnd, pSelf, pContentFrame, pReference, styleName);
1517 break;
1518 case Reference:
1519 case Default:
1520 pTextNd = FindAnchorRefStyleOther(pDoc,
1521 pStart, pEnd, pSelf, pReference, styleName);
1522 break;
1523 default:
1524 OSL_FAIL("<SwGetRefFieldType::FindAnchorRefStyle(..)> - unknown getref element type");
1526 return pTextNd;
1529 SwTextNode* SwGetRefFieldType::FindAnchorRefStyleMarginal(SwDoc* pDoc,
1530 sal_uInt16 nFlags,
1531 sal_Int32* pStart, sal_Int32* pEnd,
1532 SwTextNode* pSelf, SwFrame* pContentFrame,
1533 const SwTextNode* pReference, std::u16string_view styleName)
1535 // For marginals, styleref tries to act on the current page first
1536 // 1. Get the page we're on, search it from top to bottom
1538 SwTextNode* pTextNd = nullptr;
1540 bool bFlagFromBottom = (nFlags & REFFLDFLAG_STYLE_FROM_BOTTOM) == REFFLDFLAG_STYLE_FROM_BOTTOM;
1542 Point aPt;
1543 std::pair<Point, bool> const tmp(aPt, false);
1545 if (!pContentFrame) SAL_WARN("xmloff.text", "<SwGetRefFieldType::FindAnchorRefStyleMarginal(..)>: Missing content frame for marginal styleref");
1546 const SwPageFrame* pPageFrame = nullptr;
1548 if (pContentFrame)
1549 pPageFrame = pContentFrame->FindPageFrame();
1551 const SwNode* pPageStart(nullptr);
1552 const SwNode* pPageEnd(nullptr);
1554 if (pPageFrame)
1556 const SwContentFrame* pPageStartFrame = pPageFrame->FindFirstBodyContent();
1557 const SwContentFrame* pPageEndFrame = pPageFrame->FindLastBodyContent();
1559 if (pPageStartFrame)
1561 if (pPageStartFrame->IsTextFrame())
1563 pPageStart = static_cast<const SwTextFrame*>(pPageStartFrame)
1564 ->GetTextNodeFirst();
1566 else
1568 pPageStart
1569 = static_cast<const SwNoTextFrame*>(pPageStartFrame)->GetNode();
1573 if (pPageEndFrame)
1575 if (pPageEndFrame->IsTextFrame())
1577 pPageEnd = static_cast<const SwTextFrame*>(pPageEndFrame)
1578 ->GetTextNodeFirst();
1580 else
1582 pPageEnd = static_cast<const SwNoTextFrame*>(pPageEndFrame)->GetNode();
1587 if (!pPageStart || !pPageEnd)
1589 pPageStart = pReference;
1590 pPageEnd = pReference;
1593 SwNodeOffset nPageStart = pPageStart->GetIndex();
1594 SwNodeOffset nPageEnd = pPageEnd->GetIndex();
1595 const SwNodes& nodes = pDoc->GetNodes();
1597 pTextNd = SearchForStyleAnchor(pSelf, nodes, nPageStart, nPageEnd, bFlagFromBottom, styleName, pStart, pEnd);
1598 if (pTextNd)
1599 return pTextNd;
1601 // 2. Search up from the top of the page
1602 pTextNd = SearchForStyleAnchor(pSelf, nodes, SwNodeOffset(0), nPageStart - 1, /*bBackwards*/true, styleName, pStart, pEnd);
1603 if (pTextNd)
1604 return pTextNd;
1606 // 3. Search down from the bottom of the page
1607 pTextNd = SearchForStyleAnchor(pSelf, nodes, nPageEnd + 1, nodes.Count() - 1, /*bBackwards*/false, styleName, pStart, pEnd);
1608 if (pTextNd)
1609 return pTextNd;
1611 // Word has case insensitive styles. LO has case sensitive styles. If we didn't find
1612 // it yet, maybe we could with a case insensitive search. Let's do that
1614 pTextNd = SearchForStyleAnchor(pSelf, nodes, nPageStart, nPageEnd, bFlagFromBottom, styleName, pStart, pEnd,
1615 false /* bCaseSensitive */);
1616 if (pTextNd)
1617 return pTextNd;
1619 pTextNd = SearchForStyleAnchor(pSelf, nodes, SwNodeOffset(0), nPageStart - 1, /*bBackwards*/true, styleName, pStart, pEnd,
1620 false /* bCaseSensitive */);
1621 if (pTextNd)
1622 return pTextNd;
1624 pTextNd = SearchForStyleAnchor(pSelf, nodes, nPageEnd + 1, nodes.Count() - 1, /*bBackwards*/false, styleName, pStart, pEnd,
1625 false /* bCaseSensitive */);
1626 return pTextNd;
1629 SwTextNode* SwGetRefFieldType::FindAnchorRefStyleOther(SwDoc* pDoc,
1630 sal_Int32* pStart, sal_Int32* pEnd,
1631 SwTextNode* pSelf,
1632 const SwTextNode* pReference, std::u16string_view styleName)
1634 // Normally, styleref does searches around the field position
1635 // For references, styleref acts from the position of the reference not the field
1636 // Happily, the previous code saves either one into pReference, so the following is generic for both
1638 const SwNodes& nodes = pDoc->GetNodes();
1640 // It is possible to end up here, with a pReference pointer which points to a node which has already been
1641 // removed from the nodes array, which means that calling GetIndex() returns an incorrect index.
1642 SwNodeOffset nReference;
1643 if (!pReference->IsDisconnected())
1644 nReference = pReference->GetIndex();
1645 else
1646 nReference = nodes.Count() - 1;
1648 SwTextNode* pTextNd = nullptr;
1650 // 1. Search up until we hit the top of the document
1652 pTextNd = SearchForStyleAnchor(pSelf, nodes, SwNodeOffset(0), nReference, /*bBackwards*/true, styleName, pStart, pEnd);
1653 if (pTextNd)
1654 return pTextNd;
1656 // 2. Search down until we hit the bottom of the document
1658 pTextNd = SearchForStyleAnchor(pSelf, nodes, nReference + 1, nodes.Count() - 1, /*bBackwards*/false, styleName, pStart, pEnd);
1659 if (pTextNd)
1660 return pTextNd;
1662 // Again, we need to remember that Word styles are not case sensitive
1664 pTextNd = SearchForStyleAnchor(pSelf, nodes, SwNodeOffset(0), nReference, /*bBackwards*/true, styleName, pStart, pEnd,
1665 false /* bCaseSensitive */);
1666 if (pTextNd)
1667 return pTextNd;
1669 pTextNd = SearchForStyleAnchor(pSelf, nodes, nReference + 1, nodes.Count() - 1, /*bBackwards*/false, styleName, pStart, pEnd,
1670 false /* bCaseSensitive */);
1671 return pTextNd;
1674 namespace {
1676 struct RefIdsMap
1678 private:
1679 OUString aName;
1680 std::set<sal_uInt16> aIds;
1681 std::set<sal_uInt16> aDstIds;
1682 std::map<sal_uInt16, sal_uInt16> sequencedIds; /// ID numbers sorted by sequence number.
1683 bool bInit;
1685 void Init(SwDoc& rDoc, SwDoc& rDestDoc, bool bField );
1686 static void GetNoteIdsFromDoc( SwDoc& rDoc, std::set<sal_uInt16> &rIds );
1687 void GetFieldIdsFromDoc( SwDoc& rDoc, std::set<sal_uInt16> &rIds );
1688 void AddId( sal_uInt16 id, sal_uInt16 seqNum );
1689 static sal_uInt16 GetFirstUnusedId( std::set<sal_uInt16> &rIds );
1691 public:
1692 explicit RefIdsMap( OUString _aName ) : aName(std::move( _aName )), bInit( false ) {}
1694 void Check( SwDoc& rDoc, SwDoc& rDestDoc, SwGetRefField& rField, bool bField );
1696 const OUString& GetName() const { return aName; }
1701 /// Get a sorted list of the field IDs from a document.
1702 /// @param[in] rDoc The document to search.
1703 /// @param[in,out] rIds The list of IDs found in the document.
1704 void RefIdsMap::GetFieldIdsFromDoc( SwDoc& rDoc, std::set<sal_uInt16> &rIds)
1706 SwFieldType *const pType = rDoc.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp, aName, false);
1707 if (!pType)
1708 return;
1709 std::vector<SwFormatField*> vFields;
1710 pType->GatherFields(vFields);
1711 for(const auto pF: vFields)
1712 rIds.insert(static_cast<SwSetExpField const*>(pF->GetField())->GetSeqNumber());
1715 /// Get a sorted list of the footnote/endnote IDs from a document.
1716 /// @param[in] rDoc The document to search.
1717 /// @param[in,out] rIds The list of IDs found in the document.
1718 void RefIdsMap::GetNoteIdsFromDoc( SwDoc& rDoc, std::set<sal_uInt16> &rIds)
1720 for( auto n = rDoc.GetFootnoteIdxs().size(); n; )
1721 rIds.insert( rDoc.GetFootnoteIdxs()[ --n ]->GetSeqRefNo() );
1724 /// Initialise the aIds and aDestIds collections from the source documents.
1725 /// @param[in] rDoc The source document.
1726 /// @param[in] rDestDoc The destination document.
1727 /// @param[in] bField True if we're interested in all fields, false for footnotes.
1728 void RefIdsMap::Init( SwDoc& rDoc, SwDoc& rDestDoc, bool bField )
1730 if( bInit )
1731 return;
1733 if( bField )
1735 GetFieldIdsFromDoc( rDestDoc, aIds );
1736 GetFieldIdsFromDoc( rDoc, aDstIds );
1738 // Map all the new src fields to the next available unused id
1739 for (const auto& rId : aDstIds)
1740 AddId( GetFirstUnusedId(aIds), rId );
1742 // Change the Sequence number of all SetExp fields in the source document
1743 SwFieldType* pType = rDoc.getIDocumentFieldsAccess().GetFieldType( SwFieldIds::SetExp, aName, false );
1744 if(pType)
1746 std::vector<SwFormatField*> vFields;
1747 pType->GatherFields(vFields, false);
1748 for(auto pF: vFields)
1750 if(!pF->GetTextField())
1751 continue;
1752 SwSetExpField *const pSetExp(static_cast<SwSetExpField *>(pF->GetField()));
1753 sal_uInt16 const n = pSetExp->GetSeqNumber();
1754 pSetExp->SetSeqNumber(sequencedIds[n]);
1758 else
1760 GetNoteIdsFromDoc( rDestDoc, aIds );
1761 GetNoteIdsFromDoc( rDoc, aDstIds );
1763 for (const auto& rId : aDstIds)
1764 AddId( GetFirstUnusedId(aIds), rId );
1766 // Change the footnotes/endnotes in the source doc to the new ID
1767 for ( const auto pFootnoteIdx : rDoc.GetFootnoteIdxs() )
1769 sal_uInt16 const n = pFootnoteIdx->GetSeqRefNo();
1770 pFootnoteIdx->SetSeqNo(sequencedIds[n]);
1773 bInit = true;
1776 /// Get the lowest number unused in the passed set.
1777 /// @param[in] rIds The set of used ID numbers.
1778 /// @returns The lowest number unused by the passed set
1779 sal_uInt16 RefIdsMap::GetFirstUnusedId( std::set<sal_uInt16> &rIds )
1781 sal_uInt16 num(0);
1783 for( const auto& rId : rIds )
1785 if( num != rId )
1787 return num;
1789 ++num;
1791 return num;
1794 /// Add a new ID and sequence number to the "occupied" collection.
1795 /// @param[in] id The ID number.
1796 /// @param[in] seqNum The sequence number.
1797 void RefIdsMap::AddId( sal_uInt16 id, sal_uInt16 seqNum )
1799 aIds.insert( id );
1800 sequencedIds[ seqNum ] = id;
1803 void RefIdsMap::Check( SwDoc& rDoc, SwDoc& rDestDoc, SwGetRefField& rField,
1804 bool bField )
1806 Init( rDoc, rDestDoc, bField);
1808 sal_uInt16 const nSeqNo = rField.GetSeqNo();
1810 // check if it needs to be remapped
1811 // if sequencedIds doesn't contain the number, it means there is no
1812 // SetExp field / footnote in the source document: do not modify
1813 // the number, which works well for copy from/paste to same document
1814 // (and if it is not the same document, there's no "correct" result anyway)
1815 if (sequencedIds.count(nSeqNo))
1817 rField.SetSeqNo( sequencedIds[nSeqNo] );
1821 /// 1. if _both_ SetExp + GetExp / Footnote + GetExp field are copied,
1822 /// ensure that both get a new unused matching number
1823 /// 2. if only SetExp / Footnote is copied, it gets a new unused number
1824 /// 3. if only GetExp field is copied, for the case of copy from / paste to
1825 /// same document it's desirable to keep the same number;
1826 /// for other cases of copy/paste or master documents it's not obvious
1827 /// what is most desirable since it's going to be wrong anyway
1828 void SwGetRefFieldType::MergeWithOtherDoc( SwDoc& rDestDoc )
1830 if (&rDestDoc == &m_rDoc)
1831 return;
1833 if (rDestDoc.IsClipBoard())
1835 // when copying _to_ clipboard, expectation is that no fields exist
1836 // so no re-mapping is required to avoid collisions
1837 assert(!rDestDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef)->HasWriterListeners());
1838 return; // don't modify the fields in the source doc
1841 // then there are RefFields in the DescDox - so all RefFields in the SourceDoc
1842 // need to be converted to have unique IDs for both documents
1843 RefIdsMap aFntMap { OUString() };
1844 std::vector<std::unique_ptr<RefIdsMap>> aFieldMap;
1846 std::vector<SwFormatField*> vFields;
1847 GatherFields(vFields);
1848 for(auto pField: vFields)
1850 SwGetRefField& rRefField = *static_cast<SwGetRefField*>(pField->GetField());
1851 switch( rRefField.GetSubType() )
1853 case REF_SEQUENCEFLD:
1855 RefIdsMap* pMap = nullptr;
1856 for( auto n = aFieldMap.size(); n; )
1858 if (aFieldMap[ --n ]->GetName() == rRefField.GetSetRefName())
1860 pMap = aFieldMap[ n ].get();
1861 break;
1864 if( !pMap )
1866 pMap = new RefIdsMap( rRefField.GetSetRefName() );
1867 aFieldMap.push_back(std::unique_ptr<RefIdsMap>(pMap));
1870 pMap->Check(m_rDoc, rDestDoc, rRefField, true);
1872 break;
1874 case REF_FOOTNOTE:
1875 case REF_ENDNOTE:
1876 aFntMap.Check(m_rDoc, rDestDoc, rRefField, false);
1877 break;
1882 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */