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 <hintids.hxx>
23 #include <charfmt.hxx>
24 #include <fmtautofmt.hxx>
28 #include <rootfrm.hxx>
29 #include <pagefrm.hxx>
32 #include <viewopt.hxx>
34 #include <viewimp.hxx>
36 #include <swmodule.hxx>
42 #include "itrform2.hxx"
46 #include <docufld.hxx>
47 #include <pagedesc.hxx>
48 #include <fmtmeta.hxx>
51 #include <IDocumentSettingAccess.hxx>
52 #include <IDocumentRedlineAccess.hxx>
53 #include <redline.hxx>
54 #include <sfx2/docfile.hxx>
55 #include <svl/grabbagitem.hxx>
56 #include <svl/itemiter.hxx>
57 #include <svl/whiter.hxx>
58 #include <editeng/colritem.hxx>
59 #include <editeng/udlnitem.hxx>
60 #include <editeng/crossedoutitem.hxx>
61 #include <officecfg/Office/Writer.hxx>
63 static bool lcl_IsInBody( SwFrame
const *pFrame
)
65 if ( pFrame
->IsInDocBody() )
68 while (const SwFlyFrame
* pFly
= pFrame
->FindFlyFrame())
69 pFrame
= pFly
->GetAnchorFrame();
70 return pFrame
->IsInDocBody();
73 static OUString
ExpandField(const SwField
& rField
, const SwTextFormatter
& rFormatter
,
74 const SwTextFormatInfo
& rInf
)
76 if (rInf
.GetOpt().IsFieldName())
77 return rField
.GetFieldName();
79 const SwViewShell
* pSh
= rInf
.GetVsh();
80 const SwDoc
* pDoc(pSh
? pSh
->GetDoc() : nullptr);
81 const bool bInClipboard(!pDoc
|| pDoc
->IsClipBoard());
82 return rField
.ExpandField(bInClipboard
, rFormatter
.GetTextFrame()->getRootFrame());
85 SwExpandPortion
*SwTextFormatter::NewFieldPortion( SwTextFormatInfo
&rInf
,
86 const SwTextAttr
*pHint
) const
88 SwField
*pField
= const_cast<SwField
*>(pHint
->GetFormatField().GetField());
89 const bool bName
= rInf
.GetOpt().IsFieldName();
92 const_cast<SwTextFormatter
*>(this)->SeekAndChg( rInf
);
93 if (pField
->GetLanguage() != GetFnt()->GetLanguage())
95 pField
->SetLanguage( GetFnt()->GetLanguage() );
96 // let the visual note know about its new language
97 if (pField
->GetTyp()->Which()==SwFieldIds::Postit
)
98 const_cast<SwFormatField
*> (&pHint
->GetFormatField())->Broadcast( SwFormatFieldHint( &pHint
->GetFormatField(), SwFormatFieldHintWhich::LANGUAGE
) );
101 SwViewShell
*pSh
= rInf
.GetVsh();
103 switch (pField
->GetTyp()->Which())
105 case SwFieldIds::Script
:
106 case SwFieldIds::Postit
:
107 return new SwPostItsPortion(SwFieldIds::Script
== pField
->GetTyp()->Which());
108 case SwFieldIds::CombinedChars
:
110 return new SwCombinedPortion(ExpandField(*pField
, *this, rInf
));
112 case SwFieldIds::HiddenText
:
113 return new SwHiddenPortion(ExpandField(*pField
, *this, rInf
));
114 case SwFieldIds::Chapter
:
115 if (!bName
&& pSh
&& !pSh
->Imp()->IsUpdateExpFields())
117 static_cast<SwChapterField
*>(pField
)->ChangeExpansion(
118 *m_pFrame
, &static_txtattr_cast
<SwTextField
const*>(pHint
)->GetTextNode());
121 case SwFieldIds::DocStat
:
122 if (!bName
&& pSh
&& !pSh
->Imp()->IsUpdateExpFields())
124 static_cast<SwDocStatField
*>(pField
)->ChangeExpansion(m_pFrame
);
127 case SwFieldIds::PageNumber
:
128 if (!bName
&& pSh
&& pSh
->GetLayout() && !pSh
->Imp()->IsUpdateExpFields())
130 auto pPageNr
= static_cast<SwPageNumberFieldType
*>(pField
->GetTyp());
132 const SwRootFrame
* pTmpRootFrame
= pSh
->GetLayout();
133 const bool bVirt
= pTmpRootFrame
->IsVirtPageNum();
135 sal_uInt16 nVirtNum
= m_pFrame
->GetVirtPageNum();
136 sal_uInt16 nNumPages
= pTmpRootFrame
->GetPageNum();
137 SvxNumType nNumFormat
= SvxNumType(-1);
138 if (SVX_NUM_PAGEDESC
== pField
->GetFormat())
140 = m_pFrame
->FindPageFrame()->GetPageDesc()->GetNumType().GetNumberingType();
141 static_cast<SwPageNumberField
*>(pField
)->ChangeExpansion(nVirtNum
, nNumPages
);
142 pPageNr
->ChangeExpansion(pSh
->GetDoc(), bVirt
,
143 nNumFormat
!= SvxNumType(-1) ? &nNumFormat
: nullptr);
146 case SwFieldIds::GetExp
:
147 if (!bName
&& pSh
&& !pSh
->Imp()->IsUpdateExpFields())
149 auto pExpField
= static_cast<SwGetExpField
*>(pField
);
150 if (!::lcl_IsInBody(m_pFrame
))
152 pExpField
->ChgBodyTextFlag(false);
153 pExpField
->ChangeExpansion(*m_pFrame
,
154 *static_txtattr_cast
<SwTextField
const*>(pHint
));
156 else if (!pExpField
->IsInBodyText())
158 // Was something else previously, thus: expand first, then convert it!
159 pExpField
->ChangeExpansion(*m_pFrame
,
160 *static_txtattr_cast
<SwTextField
const*>(pHint
));
161 pExpField
->ChgBodyTextFlag(true);
165 case SwFieldIds::Database
:
168 static_cast<SwDBField
*>(pField
)->ChgBodyTextFlag(::lcl_IsInBody(m_pFrame
));
171 case SwFieldIds::RefPageGet
:
172 if (!bName
&& pSh
&& !pSh
->Imp()->IsUpdateExpFields())
174 static_cast<SwRefPageGetField
*>(pField
)->ChangeExpansion(
175 *m_pFrame
, static_txtattr_cast
<SwTextField
const*>(pHint
));
178 case SwFieldIds::JumpEdit
:
180 std::unique_ptr
<SwFont
> pFont
;
183 pFont
= std::make_unique
<SwFont
>(*m_pFont
);
185 &static_cast<SwJumpEditField
*>(pField
)->GetCharFormat()->GetAttrSet(),
186 &m_pFrame
->GetDoc().getIDocumentSettingAccess());
188 return new SwJumpFieldPortion(ExpandField(*pField
, *this, rInf
), pField
->GetPar2(),
189 std::move(pFont
), pField
->GetFormat());
191 case SwFieldIds::GetRef
:
196 return new SwFieldPortion(ExpandField(*pField
, *this, rInf
));
199 static SwFieldPortion
* lcl_NewMetaPortion(SwTextAttr
& rHint
, const bool bPrefix
)
201 ::sw::Meta
*const pMeta(
202 static_cast<SwFormatMeta
&>(rHint
.GetAttr()).GetMeta() );
204 ::sw::MetaField
*const pField( dynamic_cast< ::sw::MetaField
* >(pMeta
) );
205 OSL_ENSURE(pField
, "lcl_NewMetaPortion: no meta field?");
209 pField
->GetPrefixAndSuffix(bPrefix
? &fix
: nullptr, bPrefix
? nullptr : &fix
, &color
);
211 return new SwFieldPortion( fix
);
215 * Try to create a new portion with zero length, for an end of a hint
216 * (where there is no CH_TXTATR). Because there may be multiple hint ends at a
217 * given index, m_pByEndIter is used to keep track of the already created
218 * portions. But the portions created here may actually be deleted again,
219 * due to Underflow. In that case, m_pByEndIter must be decremented,
220 * so the portion will be created again on the next line.
222 SwExpandPortion
* SwTextFormatter::TryNewNoLengthPortion(SwTextFormatInfo
const & rInfo
)
224 const TextFrameIndex
nIdx(rInfo
.GetIdx());
226 // sw_redlinehide: because there is a dummy character at the start of these
227 // hints, it's impossible to have ends of hints from different nodes at the
228 // same view position, so it's sufficient to check the hints of the current
229 // node. However, m_pByEndIter exists for the whole text frame, so
230 // it's necessary to iterate all hints for that purpose...
233 m_pByEndIter
.reset(new sw::MergedAttrIterByEnd(*rInfo
.GetTextFrame()));
235 SwTextNode
const* pNode(nullptr);
236 for (SwTextAttr
const* pHint
= m_pByEndIter
->NextAttr(pNode
); pHint
;
237 pHint
= m_pByEndIter
->NextAttr(pNode
))
239 SwTextAttr
& rHint(const_cast<SwTextAttr
&>(*pHint
));
240 TextFrameIndex
const nEnd(
241 rInfo
.GetTextFrame()->MapModelToView(pNode
, rHint
.GetAnyEnd()));
244 m_pByEndIter
->PrevAttr();
249 if (RES_TXTATR_METAFIELD
== rHint
.Which())
251 SwFieldPortion
*const pPortion(
252 lcl_NewMetaPortion(rHint
, false));
253 pPortion
->SetNoLength(); // no CH_TXTATR at hint end!
261 SwLinePortion
*SwTextFormatter::NewExtraPortion( SwTextFormatInfo
&rInf
)
263 SwTextAttr
*pHint
= GetAttr( rInf
.GetIdx() );
264 SwLinePortion
*pRet
= nullptr;
267 pRet
= new SwTextPortion
;
268 pRet
->SetLen(TextFrameIndex(1));
269 rInf
.SetLen(TextFrameIndex(1));
273 switch( pHint
->Which() )
275 case RES_TXTATR_FLYCNT
:
277 pRet
= NewFlyCntPortion( rInf
, pHint
);
280 case RES_TXTATR_FTN
:
282 pRet
= NewFootnotePortion( rInf
, pHint
);
285 case RES_TXTATR_FIELD
:
286 case RES_TXTATR_ANNOTATION
:
288 pRet
= NewFieldPortion( rInf
, pHint
);
291 case RES_TXTATR_REFMARK
:
293 pRet
= new SwIsoRefPortion
;
296 case RES_TXTATR_TOXMARK
:
298 pRet
= new SwIsoToxPortion
;
301 case RES_TXTATR_METAFIELD
:
303 pRet
= lcl_NewMetaPortion( *pHint
, true );
310 auto pFieldPortion
= new SwFieldPortion( "" );
311 if (pHint
->Which() == RES_TXTATR_CONTENTCONTROL
)
313 pFieldPortion
->SetContentControl(true);
315 pRet
= pFieldPortion
;
316 rInf
.SetLen(TextFrameIndex(1));
322 * OOXML spec says that w:rPr inside w:pPr specifies formatting for the paragraph mark symbol (i.e. the control
323 * character than can be configured to be shown). However, in practice MSO also uses it as direct formatting
324 * for numbering in that paragraph. I don't know if the problem is in the spec or in MSWord.
326 static void checkApplyParagraphMarkFormatToNumbering(SwFont
* pNumFnt
, SwTextFormatInfo
& rInf
,
327 const IDocumentSettingAccess
* pIDSA
,
328 const SwAttrSet
* pFormat
)
330 if( !pIDSA
->get(DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING
))
333 SwFormatAutoFormat
const& rListAutoFormat(rInf
.GetTextFrame()->GetTextNodeForParaProps()->GetAttr(RES_PARATR_LIST_AUTOFMT
));
334 std::shared_ptr
<SfxItemSet
> pSet(rListAutoFormat
.GetStyleHandle());
336 // Check each item and in case it should be ignored, then clear it.
340 std::unique_ptr
<SfxItemSet
> const pCleanedSet
= pSet
->Clone();
342 if (pCleanedSet
->HasItem(RES_TXTATR_CHARFMT
))
344 // Insert attributes of referenced char format into current set
345 const SwFormatCharFormat
& rCharFormat
= pCleanedSet
->Get(RES_TXTATR_CHARFMT
);
346 const SwAttrSet
& rStyleAttrs
= static_cast<const SwCharFormat
*>(rCharFormat
.GetRegisteredIn())->GetAttrSet();
347 SfxWhichIter
aIter(rStyleAttrs
);
348 sal_uInt16 nWhich
= aIter
.FirstWhich();
351 if (!SwTextNode::IsIgnoredCharFormatForNumbering(nWhich
, /*bIsCharStyle=*/true)
352 && !pCleanedSet
->HasItem(nWhich
)
353 && !(pFormat
&& pFormat
->HasItem(nWhich
)) )
355 // Copy from parent sets only allowed items which will not overwrite
356 // values explicitly defined in current set (pCleanedSet) or in pFormat
357 if (const SfxPoolItem
* pItem
= rStyleAttrs
.GetItem(nWhich
, true))
358 pCleanedSet
->Put(*pItem
);
360 nWhich
= aIter
.NextWhich();
363 // It is not required here anymore, all referenced items are inserted
364 pCleanedSet
->ClearItem(RES_TXTATR_CHARFMT
);
367 SfxItemIter
aIter(*pSet
);
368 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
371 if (SwTextNode::IsIgnoredCharFormatForNumbering(pItem
->Which()))
372 pCleanedSet
->ClearItem(pItem
->Which());
373 else if (pFormat
&& pFormat
->HasItem(pItem
->Which()))
374 pCleanedSet
->ClearItem(pItem
->Which());
375 else if (pItem
->Which() == RES_CHRATR_BACKGROUND
)
377 bool bShadingWasImported
= false;
378 // If Shading was imported, it should not be converted to a Highlight,
379 // but remain as Shading which is ignored for numbering.
380 if (pCleanedSet
->HasItem(RES_CHRATR_GRABBAG
))
382 SfxGrabBagItem aGrabBag
= pCleanedSet
->Get(RES_CHRATR_GRABBAG
, /*bSrchInParent=*/false);
383 std::map
<OUString
, css::uno::Any
>& rMap
= aGrabBag
.GetGrabBag();
384 auto aIterator
= rMap
.find("CharShadingMarker");
385 if (aIterator
!= rMap
.end())
386 aIterator
->second
>>= bShadingWasImported
;
389 // If used, BACKGROUND is converted to HIGHLIGHT. So also ignore if a highlight already exists.
390 if (bShadingWasImported
391 || pCleanedSet
->HasItem(RES_CHRATR_HIGHLIGHT
)
392 || (pFormat
&& pFormat
->HasItem(RES_CHRATR_HIGHLIGHT
)))
394 pCleanedSet
->ClearItem(pItem
->Which());
397 pItem
= aIter
.NextItem();
400 // SetDiffFnt resets the background color (why?), so capture it and re-apply if it had a value,
401 // because an existing value should override anything inherited from the paragraph marker.
402 const std::optional
<Color
> oFontBackColor
= pNumFnt
->GetBackColor();
403 // The same is true for the highlight color.
404 const Color aHighlight
= pNumFnt
->GetHighlightColor();
406 pNumFnt
->SetDiffFnt(pCleanedSet
.get(), pIDSA
);
409 pNumFnt
->SetBackColor(oFontBackColor
);
410 if (aHighlight
!= COL_TRANSPARENT
)
411 pNumFnt
->SetHighlightColor(aHighlight
);
414 static const SwRangeRedline
* lcl_GetRedlineAtNodeInsertionOrDeletion( const SwTextNode
& rTextNode
,
417 const SwDoc
& rDoc
= rTextNode
.GetDoc();
418 SwRedlineTable::size_type nRedlPos
= rDoc
.getIDocumentRedlineAccess().GetRedlinePos( rTextNode
, RedlineType::Any
);
420 if( SwRedlineTable::npos
!= nRedlPos
)
422 const SwNodeOffset nNdIdx
= rTextNode
.GetIndex();
423 const SwRedlineTable
& rTable
= rDoc
.getIDocumentRedlineAccess().GetRedlineTable();
424 for( ; nRedlPos
< rTable
.size() ; ++nRedlPos
)
426 const SwRangeRedline
* pTmp
= rTable
[ nRedlPos
];
427 SwNodeOffset nStart
= pTmp
->GetPoint()->GetNodeIndex(),
428 nEnd
= pTmp
->GetMark()->GetNodeIndex();
430 std::swap(nStart
, nEnd
);
431 if( RedlineType::Delete
== pTmp
->GetType() ||
432 RedlineType::Insert
== pTmp
->GetType() )
434 if( nStart
<= nNdIdx
&& nEnd
> nNdIdx
)
436 bIsMoved
= pTmp
->IsMoved();
440 if( nStart
> nNdIdx
)
447 static bool lcl_setRedlineAttr( SwTextFormatInfo
&rInf
, const SwTextNode
& rTextNode
, const std::unique_ptr
<SwFont
>& pNumFnt
)
449 if ( rInf
.GetVsh()->GetLayout()->IsHideRedlines() )
453 const SwRangeRedline
* pRedlineNum
= lcl_GetRedlineAtNodeInsertionOrDeletion( rTextNode
, bIsMoved
);
457 // moved text: dark green with double underline or strikethrough
460 pNumFnt
->SetColor(COL_GREEN
);
461 if ( RedlineType::Delete
== pRedlineNum
->GetType() )
462 pNumFnt
->SetStrikeout(STRIKEOUT_DOUBLE
);
464 pNumFnt
->SetUnderline(LINESTYLE_DOUBLE
);
468 SwAttrPool
& rPool
= rInf
.GetVsh()->GetDoc()->GetAttrPool();
469 SfxItemSetFixed
<RES_CHRATR_BEGIN
, RES_CHRATR_END
-1> aSet(rPool
);
471 std::size_t aAuthor
= (1 < pRedlineNum
->GetStackCount())
472 ? pRedlineNum
->GetAuthor( 1 )
473 : pRedlineNum
->GetAuthor();
475 if ( RedlineType::Delete
== pRedlineNum
->GetType() )
476 SW_MOD()->GetDeletedAuthorAttr(aAuthor
, aSet
);
478 SW_MOD()->GetInsertAuthorAttr(aAuthor
, aSet
);
480 if (const SvxColorItem
* pItem
= aSet
.GetItemIfSet(RES_CHRATR_COLOR
))
481 pNumFnt
->SetColor(pItem
->GetValue());
482 if (const SvxUnderlineItem
* pItem
= aSet
.GetItemIfSet(RES_CHRATR_UNDERLINE
))
483 pNumFnt
->SetUnderline(pItem
->GetLineStyle());
484 if (const SvxCrossedOutItem
* pItem
= aSet
.GetItemIfSet(RES_CHRATR_CROSSEDOUT
))
485 pNumFnt
->SetStrikeout( pItem
->GetStrikeout() );
490 SwNumberPortion
*SwTextFormatter::NewNumberPortion( SwTextFormatInfo
&rInf
) const
492 if( rInf
.IsNumDone() || rInf
.GetTextStart() != m_nStart
493 || rInf
.GetTextStart() != rInf
.GetIdx() )
496 SwNumberPortion
*pRet
= nullptr;
497 // sw_redlinehide: at this point it's certain that pTextNd is the node with
498 // the numbering of the frame; only the actual number-vector (GetNumString)
499 // depends on the hide-mode in the layout so other calls don't need to care
500 const SwTextNode
*const pTextNd
= GetTextFrame()->GetTextNodeForParaProps();
501 const SwNumRule
* pNumRule
= pTextNd
->GetNumRule();
503 // Has a "valid" number?
504 // sw_redlinehide: check that pParaPropsNode is the correct one
505 assert(pTextNd
->IsNumbered(m_pFrame
->getRootFrame()) == pTextNd
->IsNumbered(nullptr));
506 if (pTextNd
->IsNumbered(m_pFrame
->getRootFrame()) && pTextNd
->IsCountedInList())
508 int nLevel
= pTextNd
->GetActualListLevel();
513 if (nLevel
>= MAXLEVEL
)
514 nLevel
= MAXLEVEL
- 1;
516 const SwNumFormat
&rNumFormat
= pNumRule
->Get( nLevel
);
517 const bool bLeft
= SvxAdjust::Left
== rNumFormat
.GetNumAdjust();
518 const bool bCenter
= SvxAdjust::Center
== rNumFormat
.GetNumAdjust();
519 const bool bLabelAlignmentPosAndSpaceModeActive(
520 rNumFormat
.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT
);
521 const sal_uInt16 nMinDist
= bLabelAlignmentPosAndSpaceModeActive
522 ? 0 : rNumFormat
.GetCharTextDistance();
524 if( SVX_NUM_BITMAP
== rNumFormat
.GetNumberingType() )
527 if (auto const sh1
= rInf
.GetVsh()) {
528 if (auto const doc
= sh1
->GetDoc()) {
529 auto const sh2
= doc
->GetPersist();
530 if (sh2
!= nullptr && sh2
->HasName()) {
531 referer
= sh2
->GetMedium()->GetName();
535 pRet
= new SwGrfNumPortion( pTextNd
->GetLabelFollowedBy(),
536 rNumFormat
.GetBrush(), referer
,
537 rNumFormat
.GetGraphicOrientation(),
538 rNumFormat
.GetGraphicSize(),
539 bLeft
, bCenter
, nMinDist
,
540 bLabelAlignmentPosAndSpaceModeActive
);
541 tools::Long nTmpA
= rInf
.GetLast()->GetAscent();
542 tools::Long nTmpD
= rInf
.GetLast()->Height() - nTmpA
;
544 static_cast<SwGrfNumPortion
*>(pRet
)->SetBase( nTmpA
, nTmpD
, nTmpA
, nTmpD
);
548 // The SwFont is created dynamically and passed in the ctor,
549 // as the CharFormat only returns an SV-Font.
550 // In the dtor of SwNumberPortion, the SwFont is deleted.
551 const SwAttrSet
* pFormat
= rNumFormat
.GetCharFormat() ?
552 &rNumFormat
.GetCharFormat()->GetAttrSet() :
554 const IDocumentSettingAccess
* pIDSA
= pTextNd
->getIDocumentSettingAccess();
556 if( SVX_NUM_CHAR_SPECIAL
== rNumFormat
.GetNumberingType() )
558 const std::optional
<vcl::Font
> pFormatFnt
= rNumFormat
.GetBulletFont();
560 // Build a new bullet font basing on the current paragraph font:
561 std::unique_ptr
<SwFont
> pNumFnt(new SwFont( &rInf
.GetCharAttr(), pIDSA
));
564 if ( !pIDSA
->get(DocumentSettingId::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT
) )
567 // Underline style of paragraph font should not be considered
568 // Overline style of paragraph font should not be considered
569 // Weight style of paragraph font should not be considered
570 // Posture style of paragraph font should not be considered
571 pNumFnt
->SetUnderline( LINESTYLE_NONE
);
572 pNumFnt
->SetOverline( LINESTYLE_NONE
);
573 pNumFnt
->SetItalic( ITALIC_NONE
, SwFontScript::Latin
);
574 pNumFnt
->SetItalic( ITALIC_NONE
, SwFontScript::CJK
);
575 pNumFnt
->SetItalic( ITALIC_NONE
, SwFontScript::CTL
);
576 pNumFnt
->SetWeight( WEIGHT_NORMAL
, SwFontScript::Latin
);
577 pNumFnt
->SetWeight( WEIGHT_NORMAL
, SwFontScript::CJK
);
578 pNumFnt
->SetWeight( WEIGHT_NORMAL
, SwFontScript::CTL
);
581 // Apply the explicit attributes from the character style
582 // associated with the numbering to the new bullet font.
584 pNumFnt
->SetDiffFnt( pFormat
, pIDSA
);
586 checkApplyParagraphMarkFormatToNumbering(pNumFnt
.get(), rInf
, pIDSA
, pFormat
);
590 const SwFontScript nAct
= pNumFnt
->GetActual();
591 pNumFnt
->SetFamily( pFormatFnt
->GetFamilyType(), nAct
);
592 pNumFnt
->SetName( pFormatFnt
->GetFamilyName(), nAct
);
593 pNumFnt
->SetStyleName( pFormatFnt
->GetStyleName(), nAct
);
594 pNumFnt
->SetCharSet( pFormatFnt
->GetCharSet(), nAct
);
595 pNumFnt
->SetPitch( pFormatFnt
->GetPitch(), nAct
);
598 // we do not allow a vertical font
599 pNumFnt
->SetVertical( pNumFnt
->GetOrientation(),
600 m_pFrame
->IsVertical() );
602 lcl_setRedlineAttr( rInf
, *pTextNd
, pNumFnt
);
604 // --> OD 2008-01-23 #newlistelevelattrs#
605 if (rNumFormat
.GetBulletChar())
607 pRet
= new SwBulletPortion(rNumFormat
.GetBulletChar(),
608 pTextNd
->GetLabelFollowedBy(),
610 bLeft
, bCenter
, nMinDist
,
611 bLabelAlignmentPosAndSpaceModeActive
);
616 // Show Changes mode shows the actual numbering (SwListRedlineType::HIDDEN) and
617 // the original one (SwListRedlineType::ORIGTEXT) instead of the fake numbering
618 // (SwListRedlineType::SHOW, which counts removed and inserted numbered paragraphs
620 bool bHasHiddenNum
= false;
621 OUString
aText( pTextNd
->GetNumString(true, MAXLEVEL
, m_pFrame
->getRootFrame(), SwListRedlineType::HIDDEN
) );
622 const SwDoc
& rDoc
= pTextNd
->GetDoc();
623 const SwRedlineTable
& rTable
= rDoc
.getIDocumentRedlineAccess().GetRedlineTable();
624 if ( rTable
.size() && !rInf
.GetVsh()->GetLayout()->IsHideRedlines() )
626 OUString
aHiddenText( pTextNd
->GetNumString(true, MAXLEVEL
, m_pFrame
->getRootFrame(), SwListRedlineType::ORIGTEXT
) );
628 if ( !aText
.isEmpty() || !aHiddenText
.isEmpty() )
630 bool bDisplayChangedParagraphNumbering
= officecfg::Office::Writer::Comparison::DisplayChangedParagraphNumbering::get();
631 if (bDisplayChangedParagraphNumbering
&& aText
!= aHiddenText
&& !aHiddenText
.isEmpty())
633 bHasHiddenNum
= true;
634 // show also original number after the actual one enclosed in [ and ],
635 // and replace tabulator with space to avoid messy indentation
636 // resulted by the longer numbering, e.g. "1.[2.]" instead of "1.".
637 aText
= aText
+ "[" + aHiddenText
+ "]"
638 + pTextNd
->GetLabelFollowedBy().replaceAll("\t", " ");
640 else if (!aText
.isEmpty())
641 aText
+= pTextNd
->GetLabelFollowedBy();
644 else if (pTextNd
->getIDocumentSettingAccess()->get(DocumentSettingId::NO_NUMBERING_SHOW_FOLLOWBY
)
646 aText
+= pTextNd
->GetLabelFollowedBy();
648 // Not just an optimization ...
649 // A number portion without text will be assigned a width of 0.
650 // The succeeding text portion will flow into the BreakCut in the BreakLine,
651 // although we have rInf.GetLast()->GetFlyPortion()!
652 if( !aText
.isEmpty() )
655 // Build a new numbering font basing on the current paragraph font:
656 std::unique_ptr
<SwFont
> pNumFnt(new SwFont( &rInf
.GetCharAttr(), pIDSA
));
658 const SwTextNode
& rTextNode
= *rInf
.GetTextFrame()->GetTextNodeForParaProps();
659 if (const SwpHints
* pHints
= rTextNode
.GetpSwpHints())
661 // Also look for an empty character hint that sits at the paragraph end:
662 for (size_t i
= 0; i
< pHints
->Count(); ++i
)
664 const SwTextAttr
* pHint
= pHints
->GetSortedByEnd(i
);
665 if (pHint
->Which() == RES_TXTATR_AUTOFMT
&& pHint
->GetEnd()
666 && pHint
->GetStart() == *pHint
->GetEnd()
667 && pHint
->GetStart() == rTextNode
.GetText().getLength())
669 std::shared_ptr
<SfxItemSet
> pSet
670 = pHint
->GetAutoFormat().GetStyleHandle();
673 pNumFnt
->SetDiffFnt(pSet
.get(), pIDSA
);
681 if ( !pIDSA
->get(DocumentSettingId::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT
) )
684 // Underline style of paragraph font should not be considered
685 pNumFnt
->SetUnderline( LINESTYLE_NONE
);
686 // Overline style of paragraph font should not be considered
687 pNumFnt
->SetOverline( LINESTYLE_NONE
);
690 // Apply the explicit attributes from the character style
691 // associated with the numbering to the new bullet font.
693 pNumFnt
->SetDiffFnt( pFormat
, pIDSA
);
695 checkApplyParagraphMarkFormatToNumbering(pNumFnt
.get(), rInf
, pIDSA
, pFormat
);
697 if ( !lcl_setRedlineAttr( rInf
, *pTextNd
, pNumFnt
) && bHasHiddenNum
)
698 pNumFnt
->SetColor(NON_PRINTING_CHARACTER_COLOR
);
700 // we do not allow a vertical font
701 pNumFnt
->SetVertical( pNumFnt
->GetOrientation(), m_pFrame
->IsVertical() );
703 pRet
= new SwNumberPortion( aText
, std::move(pNumFnt
),
704 bLeft
, bCenter
, nMinDist
,
705 bLabelAlignmentPosAndSpaceModeActive
);
713 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */