Bug Summary

File:home/maarten/src/libreoffice/core/sw/inc/node.hxx
Warning:line 724, column 5
Returning null reference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ndtxt.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx

/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <hintids.hxx>
21#include <hints.hxx>
22
23#include <comphelper/lok.hxx>
24#include <comphelper/string.hxx>
25#include <editeng/fontitem.hxx>
26#include <editeng/escapementitem.hxx>
27#include <editeng/lrspitem.hxx>
28#include <editeng/rsiditem.hxx>
29#include <sal/log.hxx>
30#include <anchoredobject.hxx>
31#include <txtfld.hxx>
32#include <txtinet.hxx>
33#include <fmtanchr.hxx>
34#include <fmtinfmt.hxx>
35#include <fmtrfmrk.hxx>
36#include <txttxmrk.hxx>
37#include <fchrfmt.hxx>
38#include <txtftn.hxx>
39#include <fmtflcnt.hxx>
40#include <fmtfld.hxx>
41#include <frmatr.hxx>
42#include <ftnidx.hxx>
43#include <ftninfo.hxx>
44#include <fmtftn.hxx>
45#include <fmtmeta.hxx>
46#include <charfmt.hxx>
47#include <ndtxt.hxx>
48#include <doc.hxx>
49#include <IDocumentUndoRedo.hxx>
50#include <IDocumentSettingAccess.hxx>
51#include <IDocumentListsAccess.hxx>
52#include <IDocumentRedlineAccess.hxx>
53#include <IDocumentLayoutAccess.hxx>
54#include <docary.hxx>
55#include <pam.hxx>
56#include <fldbas.hxx>
57#include <paratr.hxx>
58#include <txtfrm.hxx>
59#include <ftnfrm.hxx>
60#include <rootfrm.hxx>
61#include <expfld.hxx>
62#include <section.hxx>
63#include <mvsave.hxx>
64#include <swcache.hxx>
65#include <SwGrammarMarkUp.hxx>
66#include <redline.hxx>
67#include <IMark.hxx>
68#include <scriptinfo.hxx>
69#include <istyleaccess.hxx>
70#include <SwStyleNameMapper.hxx>
71#include <numrule.hxx>
72#include <docsh.hxx>
73#include <SwNodeNum.hxx>
74#include <svl/grabbagitem.hxx>
75#include <svl/intitem.hxx>
76#include <list.hxx>
77#include <sortedobjs.hxx>
78#include <calbck.hxx>
79#include <attrhint.hxx>
80#include <memory>
81#include <unoparagraph.hxx>
82#include <wrtsh.hxx>
83#include <frameformats.hxx>
84#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
85#include <svl/itemiter.hxx>
86
87using namespace ::com::sun::star;
88
89typedef std::vector<SwTextAttr*> SwpHts;
90
91
92// unfortunately everyone can change Hints without ensuring order or the linking between them
93#ifdef DBG_UTIL
94#define CHECK_SWPHINTS(pNd) { if( pNd->GetpSwpHints() && \
95 !pNd->GetDoc().IsInReading() ) \
96 pNd->GetpSwpHints()->Check(true); }
97#define CHECK_SWPHINTS_IF_FRM(pNd) { if( pNd->GetpSwpHints() && \
98 !pNd->GetDoc().IsInReading() ) \
99 pNd->GetpSwpHints()->Check(getLayoutFrame(nullptr, nullptr, nullptr) != nullptr); }
100#else
101#define CHECK_SWPHINTS(pNd)
102#define CHECK_SWPHINTS_IF_FRM(pNd)
103#endif
104
105SwTextNode *SwNodes::MakeTextNode( const SwNodeIndex & rWhere,
106 SwTextFormatColl *pColl, bool const bNewFrames)
107{
108 OSL_ENSURE( pColl, "Collection pointer is 0." )do { if (true && (!(pColl))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "108" ": "), "%s", "Collection pointer is 0."); } } while
(false)
;
109
110 SwTextNode *pNode = new SwTextNode( rWhere, pColl, nullptr );
111
112 SwNodeIndex aIdx( *pNode );
113
114 // call method <UpdateOutlineNode(..)> only for the document nodes array
115 if ( IsDocNodes() )
116 UpdateOutlineNode(*pNode);
117
118 // if there is no layout or it is in a hidden section, MakeFrames is not needed
119 const SwSectionNode* pSectNd;
120 if (!bNewFrames ||
121 !GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell() ||
122 ( nullptr != (pSectNd = pNode->FindSectionNode()) &&
123 pSectNd->GetSection().IsHiddenFlag() ))
124 return pNode;
125
126 SwNodeIndex aTmp( rWhere );
127 do {
128 // max. 2 loops:
129 // 1. take the successor
130 // 2. take the predecessor
131
132 SwNode * pNd = & aTmp.GetNode();
133 switch (pNd->GetNodeType())
134 {
135 case SwNodeType::Table:
136 static_cast<SwTableNode*>(pNd)->MakeFramesForAdjacentContentNode(aIdx);
137 return pNode;
138
139 case SwNodeType::Section:
140 if( static_cast<SwSectionNode*>(pNd)->GetSection().IsHidden() ||
141 static_cast<SwSectionNode*>(pNd)->IsContentHidden() )
142 {
143 SwNodeIndex aTmpIdx( *pNode );
144 pNd = FindPrvNxtFrameNode( aTmpIdx, pNode );
145 if( !pNd )
146 return pNode;
147 aTmp = *pNd;
148 break;
149 }
150 static_cast<SwSectionNode*>(pNd)->MakeFramesForAdjacentContentNode(aIdx);
151 return pNode;
152
153 case SwNodeType::Text:
154 case SwNodeType::Grf:
155 case SwNodeType::Ole:
156 static_cast<SwContentNode*>(pNd)->MakeFramesForAdjacentContentNode(*pNode);
157 return pNode;
158
159 case SwNodeType::End:
160 if( pNd->StartOfSectionNode()->IsSectionNode() &&
161 aTmp.GetIndex() < rWhere.GetIndex() )
162 {
163 if( pNd->StartOfSectionNode()->GetSectionNode()->GetSection().IsHiddenFlag())
164 {
165 if( !GoPrevSection( &aTmp, true, false ) ||
166 aTmp.GetNode().FindTableNode() !=
167 pNode->FindTableNode() )
168 return pNode;
169 }
170 else
171 aTmp = *pNd->StartOfSectionNode();
172 break;
173 }
174 else if( pNd->StartOfSectionNode()->IsTableNode() &&
175 aTmp.GetIndex() < rWhere.GetIndex() )
176 {
177 // after a table node
178 aTmp = *pNd->StartOfSectionNode();
179 break;
180 }
181 [[fallthrough]];
182 default:
183 if( rWhere == aTmp )
184 aTmp -= 2;
185 else
186 return pNode;
187 break;
188 }
189 } while( true );
190}
191
192SwTextNode::SwTextNode( const SwNodeIndex &rWhere, SwTextFormatColl *pTextColl, const SfxItemSet* pAutoAttr )
193: SwContentNode( rWhere, SwNodeType::Text, pTextColl ),
194 m_Text(),
195 m_pParaIdleData_Impl(nullptr),
196 m_bContainsHiddenChars(false),
197 m_bHiddenCharsHidePara(false),
198 m_bRecalcHiddenCharFlags(false),
199 m_bLastOutlineState( false ),
200 m_bNotifiable( false ),
201 mbEmptyListStyleSetDueToSetOutlineLevelAttr( false ),
202 mbInSetOrResetAttr( false ),
203 m_pNumStringCache(),
204 m_wXParagraph(),
205 maFillAttributes()
206{
207 InitSwParaStatistics( true );
208
209 if( pAutoAttr
16.1
'pAutoAttr' is non-null
16.1
'pAutoAttr' is non-null
)
17
Taking true branch
210 SetAttr( *pAutoAttr );
18
Calling 'SwTextNode::SetAttr'
211
212 if (!IsInList() && GetNumRule() && !GetListId().isEmpty())
213 {
214 // #i101516#
215 // apply paragraph style's assigned outline style list level as
216 // list level of the paragraph, if it has none set already.
217 if ( !HasAttrListLevel() &&
218 pTextColl && pTextColl->IsAssignedToListLevelOfOutlineStyle() )
219 {
220 SetAttrListLevel( pTextColl->GetAssignedOutlineStyleLevel() );
221 }
222 AddToList();
223 }
224 GetNodes().UpdateOutlineNode(*this);
225
226 m_bNotifiable = true;
227
228 m_bContainsHiddenChars = m_bHiddenCharsHidePara = false;
229 m_bRecalcHiddenCharFlags = true;
230}
231
232SwTextNode::~SwTextNode()
233{
234 // delete only removes the pointer not the array elements!
235 if ( m_pSwpHints )
236 {
237 // do not delete attributes twice when those delete their content
238 std::unique_ptr<SwpHints> pTmpHints(std::move(m_pSwpHints));
239
240 for( size_t j = pTmpHints->Count(); j; )
241 {
242 // first remove the attribute from the array otherwise
243 // if would delete itself
244 DestroyAttr( pTmpHints->Get( --j ) );
245 }
246 }
247
248 // must be removed from outline nodes by now
249#if OSL_DEBUG_LEVEL1 > 0 && !defined NDEBUG
250 SwOutlineNodes::size_type foo;
251 assert(!GetNodes().GetOutLineNds().Seek_Entry(this, &foo))(static_cast <bool> (!GetNodes().GetOutLineNds().Seek_Entry
(this, &foo)) ? void (0) : __assert_fail ("!GetNodes().GetOutLineNds().Seek_Entry(this, &foo)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 251, __extension__ __PRETTY_FUNCTION__))
;
252#endif
253
254 RemoveFromList();
255
256 InitSwParaStatistics( false );
257 DelFrames(nullptr); // must be called here while it's still a SwTextNode
258 DelFrames_TextNodePart();
259}
260
261void SwTextNode::FileLoadedInitHints()
262{
263 if (m_pSwpHints)
264 {
265 m_pSwpHints->MergePortions(*this);
266 }
267}
268
269SwContentFrame *SwTextNode::MakeFrame( SwFrame* pSib )
270{
271 SwContentFrame *pFrame = sw::MakeTextFrame(*this, pSib, sw::FrameMode::New);
272 return pFrame;
273}
274
275sal_Int32 SwTextNode::Len() const
276{
277 return m_Text.getLength();
278}
279
280// After a split node, it's necessary to actualize the ref-pointer of the ftnfrms.
281static void lcl_ChangeFootnoteRef( SwTextNode &rNode )
282{
283 SwpHints *pSwpHints = rNode.GetpSwpHints();
284 if( !(pSwpHints && rNode.GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell()) )
285 return;
286
287 SwContentFrame* pFrame = nullptr;
288 // OD 07.11.2002 #104840# - local variable to remember first footnote
289 // of node <rNode> in order to invalidate position of its first content.
290 // Thus, in its <MakeAll()> it will checked its position relative to its reference.
291 SwFootnoteFrame* pFirstFootnoteOfNode = nullptr;
292 for( size_t j = pSwpHints->Count(); j; )
293 {
294 SwTextAttr* pHt = pSwpHints->Get(--j);
295 if (RES_TXTATR_FTN == pHt->Which())
296 {
297 if( !pFrame )
298 {
299 pFrame = SwIterator<SwContentFrame, SwTextNode, sw::IteratorMode::UnwrapMulti>(rNode).First();
300 if (!pFrame)
301 return;
302 }
303 SwTextFootnote *pAttr = static_cast<SwTextFootnote*>(pHt);
304 OSL_ENSURE( pAttr->GetStartNode(), "FootnoteAtr without StartNode." )do { if (true && (!(pAttr->GetStartNode()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "304" ": "), "%s", "FootnoteAtr without StartNode."); } }
while (false)
;
305 SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 );
306 SwContentNode *pNd = aIdx.GetNode().GetContentNode();
307 if ( !pNd )
308 pNd = pFrame->GetAttrSet()->GetDoc()->
309 GetNodes().GoNextSection( &aIdx, true, false );
310 if ( !pNd )
311 continue;
312
313 SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
314 SwContentFrame* pContent = aIter.First();
315 if( pContent )
316 {
317 OSL_ENSURE( pContent->getRootFrame() == pFrame->getRootFrame(),do { if (true && (!(pContent->getRootFrame() == pFrame
->getRootFrame()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "318" ": "), "%s", "lcl_ChangeFootnoteRef: Layout double?"
); } } while (false)
318 "lcl_ChangeFootnoteRef: Layout double?" )do { if (true && (!(pContent->getRootFrame() == pFrame
->getRootFrame()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "318" ": "), "%s", "lcl_ChangeFootnoteRef: Layout double?"
); } } while (false)
;
319 SwFootnoteFrame *pFootnote = pContent->FindFootnoteFrame();
320 if( pFootnote && pFootnote->GetAttr() == pAttr )
321 {
322 while( pFootnote->GetMaster() )
323 pFootnote = pFootnote->GetMaster();
324 // #104840# - remember footnote frame
325 pFirstFootnoteOfNode = pFootnote;
326 while ( pFootnote )
327 {
328 pFootnote->SetRef( pFrame );
329 pFootnote = pFootnote->GetFollow();
330 static_cast<SwTextFrame*>(pFrame)->SetFootnote( true );
331 }
332 }
333#if OSL_DEBUG_LEVEL1 > 0
334 while( nullptr != (pContent = aIter.Next()) )
335 {
336 SwFootnoteFrame *pDbgFootnote = pContent->FindFootnoteFrame();
337 OSL_ENSURE( !pDbgFootnote || pDbgFootnote->GetRef() == pFrame,do { if (true && (!(!pDbgFootnote || pDbgFootnote->
GetRef() == pFrame))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "338" ": "), "%s", "lcl_ChangeFootnoteRef: Who's that guy?"
); } } while (false)
338 "lcl_ChangeFootnoteRef: Who's that guy?" )do { if (true && (!(!pDbgFootnote || pDbgFootnote->
GetRef() == pFrame))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "338" ": "), "%s", "lcl_ChangeFootnoteRef: Who's that guy?"
); } } while (false)
;
339 }
340#endif
341 }
342 }
343 } // end of for-loop on <SwpHints>
344 // #104840# - invalidate
345 if ( pFirstFootnoteOfNode )
346 {
347 SwContentFrame* pContent = pFirstFootnoteOfNode->ContainsContent();
348 if ( pContent )
349 {
350 pContent->InvalidatePos_();
351 }
352 }
353}
354
355namespace sw {
356
357// check if there are flys on the existing frames (now on "pNode")
358// that need to be moved to the new frames of "this"
359void MoveMergedFlysAndFootnotes(std::vector<SwTextFrame*> const& rFrames,
360 SwTextNode const& rFirstNode, SwTextNode & rSecondNode,
361 bool isSplitNode)
362{
363 if (!isSplitNode)
364 {
365 lcl_ChangeFootnoteRef(rSecondNode);
366 }
367 for (sal_uLong nIndex = rSecondNode.GetIndex() + 1; ; ++nIndex)
368 {
369 SwNode *const pTmp(rSecondNode.GetNodes()[nIndex]);
370 if (pTmp->IsCreateFrameWhenHidingRedlines() || pTmp->IsEndNode())
371 {
372 break;
373 }
374 else if (pTmp->IsStartNode())
375 {
376 nIndex = pTmp->EndOfSectionIndex();
377 }
378 else if (pTmp->GetRedlineMergeFlag() == SwNode::Merge::NonFirst
379 && pTmp->IsTextNode())
380 {
381 lcl_ChangeFootnoteRef(*pTmp->GetTextNode());
382 }
383 }
384 for (SwTextFrame *const pFrame : rFrames)
385 {
386 if (SwSortedObjs *const pObjs = pFrame->GetDrawObjs())
387 {
388 std::vector<SwAnchoredObject*> objs;
389 objs.reserve(pObjs->size());
390 for (SwAnchoredObject *const pObj : *pObjs)
391 {
392 objs.push_back(pObj);
393 }
394 for (SwAnchoredObject *const pObj : objs)
395 {
396 SwFrameFormat & rFormat(pObj->GetFrameFormat());
397 SwFormatAnchor const& rAnchor(rFormat.GetAnchor());
398 if (rFirstNode.GetIndex() < rAnchor.GetContentAnchor()->nNode.GetIndex())
399 {
400 // move it to the new frame of "this"
401 rFormat.NotifyClients(&rAnchor, &rAnchor);
402 // note pObjs will be deleted if it becomes empty
403 assert(!pFrame->GetDrawObjs() || !pObjs->Contains(*pObj))(static_cast <bool> (!pFrame->GetDrawObjs() || !pObjs
->Contains(*pObj)) ? void (0) : __assert_fail ("!pFrame->GetDrawObjs() || !pObjs->Contains(*pObj)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 403, __extension__ __PRETTY_FUNCTION__))
;
404 }
405 }
406 }
407 }
408}
409
410} // namespace
411
412SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
413 std::function<void (SwTextNode *, sw::mark::RestoreMode)> const*const pContentIndexRestore)
414{
415 bool isHide(false);
416 SwNode::Merge const eOldMergeFlag(GetRedlineMergeFlag());
417 bool parentIsOutline = IsOutline();
418
419 // create a node "in front" of me
420 const sal_Int32 nSplitPos = rPos.nContent.GetIndex();
421 const sal_Int32 nTextLen = m_Text.getLength();
422 SwTextNode* const pNode =
423 MakeNewTextNode( rPos.nNode, false, nSplitPos==nTextLen );
424
425 // the first paragraph gets the XmlId,
426 // _except_ if it is empty and the second is not empty
427 if (nSplitPos != 0) {
428 pNode->RegisterAsCopyOf(*this, true);
429 if (nSplitPos == nTextLen)
430 {
431 RemoveMetadataReference();
432 // NB: SwUndoSplitNode will call pNode->JoinNext,
433 // which is sufficient even in this case!
434 }
435 }
436
437 ResetAttr( RES_PARATR_LIST_ISRESTART );
438 ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
439 ResetAttr( RES_PARATR_LIST_ISCOUNTED );
440 if ( GetNumRule() == nullptr || (parentIsOutline && !IsOutline()) )
441 {
442 ResetAttr( RES_PARATR_LIST_ID );
443 ResetAttr( RES_PARATR_LIST_LEVEL );
444 }
445
446 if ( HasWriterListeners() && !m_Text.isEmpty() && (nTextLen / 2) < nSplitPos )
447 {
448 // optimization for SplitNode: If a split is at the end of a node then
449 // move the frames from the current to the new one and create new ones
450 // for the current one. As a result, no need for recreating the layout.
451
452 LockModify(); // disable notifications
453
454 // If fly frames are moved, they don't need to destroy their layout
455 // frames. Set a flag that is checked in SwTextFlyCnt::SetAnchor.
456 if ( HasHints() )
457 {
458 pNode->GetOrCreateSwpHints().SetInSplitNode(true);
459 }
460
461 // Move the first part of the content to the new node and delete
462 // it in the old node.
463 SwIndex aIdx( this );
464 CutText( pNode, aIdx, nSplitPos );
465
466 if( GetWrong() )
467 {
468 pNode->SetWrong( GetWrong()->SplitList( nSplitPos ) );
469 }
470 SetWrongDirty(WrongState::TODO);
471
472 if( GetGrammarCheck() )
473 {
474 pNode->SetGrammarCheck( GetGrammarCheck()->SplitGrammarList( nSplitPos ) );
475 }
476 SetGrammarCheckDirty( true );
477
478 SetWordCountDirty( true );
479
480 if( GetSmartTags() )
481 {
482 pNode->SetSmartTags( GetSmartTags()->SplitList( nSplitPos ) );
483 }
484 SetSmartTagDirty( true );
485
486 if ( pNode->HasHints() )
487 {
488 if ( pNode->m_pSwpHints->CanBeDeleted() )
489 {
490 pNode->m_pSwpHints.reset();
491 }
492 else
493 {
494 pNode->m_pSwpHints->SetInSplitNode(false);
495 }
496
497 // All fly frames anchored as char that are moved to the new
498 // node must have their layout frames deleted.
499 // This comment is sort of silly because we actually delete the
500 // layout frames of those which were not moved?
501 // JP 01.10.96: delete all empty and not-to-be-expanded attributes
502 if ( HasHints() )
503 {
504 for ( size_t j = m_pSwpHints->Count(); j; )
505 {
506 SwTextAttr* const pHt = m_pSwpHints->Get( --j );
507 if ( RES_TXTATR_FLYCNT == pHt ->Which() )
508 {
509 pHt->GetFlyCnt().GetFrameFormat()->DelFrames();
510 }
511 else if ( pHt->DontExpand() )
512 {
513 const sal_Int32* const pEnd = pHt->GetEnd();
514 if (pEnd && pHt->GetStart() == *pEnd )
515 {
516 // delete it!
517 m_pSwpHints->DeleteAtPos( j );
518 DestroyAttr( pHt );
519 }
520 }
521 }
522 }
523
524 }
525
526 if (pContentIndexRestore)
527 { // call before making frames and before RegisterToNode
528 (*pContentIndexRestore)(pNode, sw::mark::RestoreMode::NonFlys);
529 }
530 if (eOldMergeFlag != SwNode::Merge::None)
531 { // clear before making frames and before RegisterToNode
532 SetRedlineMergeFlag(SwNode::Merge::None);
533 } // now RegisterToNode will set merge flags in both nodes properly!
534
535 std::vector<SwTextFrame*> frames;
536 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
537 for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
538 {
539 if (pFrame->getRootFrame()->IsHideRedlines())
540 {
541 isHide = true;
542 }
543 frames.push_back(pFrame);
544 }
545 for (SwTextFrame * pFrame : frames)
546 {
547 pFrame->RegisterToNode( *pNode );
548 if (!pFrame->IsFollow() && pFrame->GetOffset())
549 {
550 pFrame->SetOffset( TextFrameIndex(0) );
551 }
552 }
553
554 if ( IsInCache() )
555 {
556 SwFrame::GetCache().Delete( this );
557 SetInCache( false );
558 }
559
560 UnlockModify(); // enable notify again
561
562 // If there is an accessible layout we must call modify even
563 // with length zero, because we have to notify about the changed
564 // text node.
565 const SwRootFrame *pRootFrame;
566 if ( (nTextLen != nSplitPos) ||
567 ( (pRootFrame = pNode->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout()) != nullptr &&
568 pRootFrame->IsAnyShellAccessible() ) )
569 {
570 // tell the frames that something was "deleted" at the end
571 if( 1 == nTextLen - nSplitPos )
572 {
573 SwDelChr aHint( nSplitPos );
574 pNode->NotifyClients( nullptr, &aHint );
575 }
576 else
577 {
578 SwDelText aHint( nSplitPos, nTextLen - nSplitPos );
579 pNode->NotifyClients( nullptr, &aHint );
580 }
581 }
582 if ( HasHints() )
583 {
584 MoveTextAttr_To_AttrSet();
585 }
586 // in case there are frames, the RegisterToNode has set the merge flag
587 pNode->MakeFramesForAdjacentContentNode(*this);
588 lcl_ChangeFootnoteRef( *this );
589 if (pContentIndexRestore)
590 { // call after making frames; listeners will take care of adding to the right frame
591 (*pContentIndexRestore)(pNode, sw::mark::RestoreMode::Flys);
592 }
593 if (eOldMergeFlag != SwNode::Merge::None)
594 {
595 MoveMergedFlysAndFootnotes(frames, *pNode, *this, true);
596 }
597 }
598 else
599 {
600 SwWrongList *pList = GetWrong();
601 SetWrong( nullptr, false );
602 SetWrongDirty(WrongState::TODO);
603
604 SwGrammarMarkUp *pList3 = GetGrammarCheck();
605 SetGrammarCheck( nullptr, false );
606 SetGrammarCheckDirty( true );
607
608 SetWordCountDirty( true );
609
610 SwWrongList *pList2 = GetSmartTags();
611 SetSmartTags( nullptr, false );
612 SetSmartTagDirty( true );
613
614 SwIndex aIdx( this );
615 CutText( pNode, aIdx, nSplitPos );
616
617 // JP 01.10.96: delete all empty and not-to-be-expanded attributes
618 if ( HasHints() )
619 {
620 for ( size_t j = m_pSwpHints->Count(); j; )
621 {
622 SwTextAttr* const pHt = m_pSwpHints->Get( --j );
623 const sal_Int32* const pEnd = pHt->GetEnd();
624 if ( pHt->DontExpand() && pEnd && (pHt->GetStart() == *pEnd) )
625 {
626 // delete it!
627 m_pSwpHints->DeleteAtPos( j );
628 DestroyAttr( pHt );
629 }
630 }
631 MoveTextAttr_To_AttrSet();
632 }
633
634 if( pList )
635 {
636 pNode->SetWrong( pList->SplitList( nSplitPos ) );
637 SetWrong( pList, false );
638 }
639
640 if( pList3 )
641 {
642 pNode->SetGrammarCheck( pList3->SplitGrammarList( nSplitPos ) );
643 SetGrammarCheck( pList3, false );
644 }
645
646 if( pList2 )
647 {
648 pNode->SetSmartTags( pList2->SplitList( nSplitPos ) );
649 SetSmartTags( pList2, false );
650 }
651
652 if (pContentIndexRestore)
653 { // call before making frames and before RegisterToNode
654 (*pContentIndexRestore)(pNode, sw::mark::RestoreMode::NonFlys);
655 }
656
657 std::vector<SwTextFrame*> frames;
658 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
659 for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
660 {
661 frames.push_back(pFrame);
662 if (pFrame->getRootFrame()->IsHideRedlines())
663 {
664 isHide = true;
665 }
666 }
667 bool bNonMerged(false);
668 bool bRecreateThis(false);
669 for (SwTextFrame * pFrame : frames)
670 {
671 // sw_redlinehide: for this to work properly with hidden nodes,
672 // the frame needs to listen on them too.
673 // also: have to check the frame; this->GetRedlineMergeFlag()
674 // is None in case there's a delete redline inside the paragraph,
675 // but that could still result in a merged frame after split...
676 if (pFrame->GetMergedPara())
677 {
678 // Can't special case this == First here - that could (if
679 // both nodes are still merged by redline) lead to
680 // duplicate frames on "this".
681 // Update the extents with new node; also inits merge flag,
682 // so the MakeFramesForAdjacentContentNode below respects it
683 pFrame->RegisterToNode(*pNode);
684 if (pFrame->GetText().isEmpty())
685 {
686 // turns out it's empty - in this case, it was not
687 // invalidated because Cut didn't sent it any hints,
688 // so we have to invalidate it here!
689 pFrame->Prepare(PrepareHint::Clear, nullptr, false);
690 }
691 if (!pFrame->GetMergedPara() ||
692 !pFrame->GetMergedPara()->listener.IsListeningTo(this))
693 {
694 // it's no longer listening - need to recreate frame
695 // (note this is idempotent, can be done once per frame)
696 SetRedlineMergeFlag(SwNode::Merge::None);
697 bRecreateThis = true;
698 }
699 }
700 else
701 {
702 bNonMerged = true;
703 }
704 }
705 assert(!(bNonMerged && bRecreateThis))(static_cast <bool> (!(bNonMerged && bRecreateThis
)) ? void (0) : __assert_fail ("!(bNonMerged && bRecreateThis)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 705, __extension__ __PRETTY_FUNCTION__))
; // 2 layouts not handled yet - maybe best to simply use the other branch then?
706 if (!frames.empty() && bNonMerged)
707 {
708 // the existing frame on "this" should have been updated by Cut
709 MakeFramesForAdjacentContentNode(*pNode);
710 lcl_ChangeFootnoteRef(*pNode);
711 }
712 else if (bRecreateThis)
713 {
714 assert(pNode->HasWriterListeners())(static_cast <bool> (pNode->HasWriterListeners()) ? void
(0) : __assert_fail ("pNode->HasWriterListeners()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 714, __extension__ __PRETTY_FUNCTION__))
; // was just moved there
715 pNode->MakeFramesForAdjacentContentNode(*this);
716 lcl_ChangeFootnoteRef(*this);
717 }
718
719 if (pContentIndexRestore)
720 { // call after making frames; listeners will take care of adding to the right frame
721 (*pContentIndexRestore)(pNode, sw::mark::RestoreMode::Flys);
722 }
723
724 if (bRecreateThis)
725 {
726 MoveMergedFlysAndFootnotes(frames, *pNode, *this, true);
727 }
728 }
729
730#ifndef NDEBUG
731 if (isHide) // otherwise flags won't be set anyway
732 {
733 // First
734 // -> First,NonFirst
735 // -> First,Hidden
736 // -> None,First
737 // Hidden
738 // -> Hidden,Hidden (if still inside merge rl)
739 // -> NonFirst,First (if redline was split)
740 // NonFirst
741 // -> NonFirst,First (if split after end of "incoming" redline &
742 // before start of "outgoing" redline)
743 // -> NonFirst,None (if split after end of "incoming" redline)
744 // -> NonFirst,Hidden (if split after start of "outgoing" redline)
745 // -> Hidden, NonFirst (if split before end of "incoming" redline)
746 // None
747 // -> None,None
748 // -> First,NonFirst (if splitting inside a delete redline)
749 SwNode::Merge const eFirst(pNode->GetRedlineMergeFlag());
750 SwNode::Merge const eSecond(GetRedlineMergeFlag());
751 switch (eOldMergeFlag)
752 {
753 case Merge::First:
754 assert((eFirst == Merge::First && eSecond == Merge::NonFirst)(static_cast <bool> ((eFirst == Merge::First &&
eSecond == Merge::NonFirst) || (eFirst == Merge::First &&
eSecond == Merge::Hidden) || (eFirst == Merge::None &&
eSecond == Merge::First)) ? void (0) : __assert_fail ("(eFirst == Merge::First && eSecond == Merge::NonFirst) || (eFirst == Merge::First && eSecond == Merge::Hidden) || (eFirst == Merge::None && eSecond == Merge::First)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 756, __extension__ __PRETTY_FUNCTION__))
755 || (eFirst == Merge::First && eSecond == Merge::Hidden)(static_cast <bool> ((eFirst == Merge::First &&
eSecond == Merge::NonFirst) || (eFirst == Merge::First &&
eSecond == Merge::Hidden) || (eFirst == Merge::None &&
eSecond == Merge::First)) ? void (0) : __assert_fail ("(eFirst == Merge::First && eSecond == Merge::NonFirst) || (eFirst == Merge::First && eSecond == Merge::Hidden) || (eFirst == Merge::None && eSecond == Merge::First)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 756, __extension__ __PRETTY_FUNCTION__))
756 || (eFirst == Merge::None && eSecond == Merge::First))(static_cast <bool> ((eFirst == Merge::First &&
eSecond == Merge::NonFirst) || (eFirst == Merge::First &&
eSecond == Merge::Hidden) || (eFirst == Merge::None &&
eSecond == Merge::First)) ? void (0) : __assert_fail ("(eFirst == Merge::First && eSecond == Merge::NonFirst) || (eFirst == Merge::First && eSecond == Merge::Hidden) || (eFirst == Merge::None && eSecond == Merge::First)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 756, __extension__ __PRETTY_FUNCTION__))
;
757 break;
758 case Merge::Hidden:
759 assert((eFirst == Merge::Hidden && eSecond == Merge::Hidden)(static_cast <bool> ((eFirst == Merge::Hidden &&
eSecond == Merge::Hidden) || (eFirst == Merge::NonFirst &&
eSecond == Merge::First) || (eFirst == Merge::Hidden &&
eSecond == Merge::NonFirst) || (eFirst == Merge::NonFirst &&
eSecond == Merge::None)) ? void (0) : __assert_fail ("(eFirst == Merge::Hidden && eSecond == Merge::Hidden) || (eFirst == Merge::NonFirst && eSecond == Merge::First) || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst) || (eFirst == Merge::NonFirst && eSecond == Merge::None)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 763, __extension__ __PRETTY_FUNCTION__))
760 || (eFirst == Merge::NonFirst && eSecond == Merge::First)(static_cast <bool> ((eFirst == Merge::Hidden &&
eSecond == Merge::Hidden) || (eFirst == Merge::NonFirst &&
eSecond == Merge::First) || (eFirst == Merge::Hidden &&
eSecond == Merge::NonFirst) || (eFirst == Merge::NonFirst &&
eSecond == Merge::None)) ? void (0) : __assert_fail ("(eFirst == Merge::Hidden && eSecond == Merge::Hidden) || (eFirst == Merge::NonFirst && eSecond == Merge::First) || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst) || (eFirst == Merge::NonFirst && eSecond == Merge::None)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 763, __extension__ __PRETTY_FUNCTION__))
761 // next ones can happen temp. in UndoDelete :((static_cast <bool> ((eFirst == Merge::Hidden &&
eSecond == Merge::Hidden) || (eFirst == Merge::NonFirst &&
eSecond == Merge::First) || (eFirst == Merge::Hidden &&
eSecond == Merge::NonFirst) || (eFirst == Merge::NonFirst &&
eSecond == Merge::None)) ? void (0) : __assert_fail ("(eFirst == Merge::Hidden && eSecond == Merge::Hidden) || (eFirst == Merge::NonFirst && eSecond == Merge::First) || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst) || (eFirst == Merge::NonFirst && eSecond == Merge::None)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 763, __extension__ __PRETTY_FUNCTION__))
762 || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst)(static_cast <bool> ((eFirst == Merge::Hidden &&
eSecond == Merge::Hidden) || (eFirst == Merge::NonFirst &&
eSecond == Merge::First) || (eFirst == Merge::Hidden &&
eSecond == Merge::NonFirst) || (eFirst == Merge::NonFirst &&
eSecond == Merge::None)) ? void (0) : __assert_fail ("(eFirst == Merge::Hidden && eSecond == Merge::Hidden) || (eFirst == Merge::NonFirst && eSecond == Merge::First) || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst) || (eFirst == Merge::NonFirst && eSecond == Merge::None)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 763, __extension__ __PRETTY_FUNCTION__))
763 || (eFirst == Merge::NonFirst && eSecond == Merge::None))(static_cast <bool> ((eFirst == Merge::Hidden &&
eSecond == Merge::Hidden) || (eFirst == Merge::NonFirst &&
eSecond == Merge::First) || (eFirst == Merge::Hidden &&
eSecond == Merge::NonFirst) || (eFirst == Merge::NonFirst &&
eSecond == Merge::None)) ? void (0) : __assert_fail ("(eFirst == Merge::Hidden && eSecond == Merge::Hidden) || (eFirst == Merge::NonFirst && eSecond == Merge::First) || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst) || (eFirst == Merge::NonFirst && eSecond == Merge::None)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 763, __extension__ __PRETTY_FUNCTION__))
;
764 break;
765 case Merge::NonFirst:
766 assert((eFirst == Merge::NonFirst && eSecond == Merge::First)(static_cast <bool> ((eFirst == Merge::NonFirst &&
eSecond == Merge::First) || (eFirst == Merge::NonFirst &&
eSecond == Merge::None) || (eFirst == Merge::NonFirst &&
eSecond == Merge::Hidden) || (eFirst == Merge::Hidden &&
eSecond == Merge::NonFirst)) ? void (0) : __assert_fail ("(eFirst == Merge::NonFirst && eSecond == Merge::First) || (eFirst == Merge::NonFirst && eSecond == Merge::None) || (eFirst == Merge::NonFirst && eSecond == Merge::Hidden) || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 769, __extension__ __PRETTY_FUNCTION__))
767 || (eFirst == Merge::NonFirst && eSecond == Merge::None)(static_cast <bool> ((eFirst == Merge::NonFirst &&
eSecond == Merge::First) || (eFirst == Merge::NonFirst &&
eSecond == Merge::None) || (eFirst == Merge::NonFirst &&
eSecond == Merge::Hidden) || (eFirst == Merge::Hidden &&
eSecond == Merge::NonFirst)) ? void (0) : __assert_fail ("(eFirst == Merge::NonFirst && eSecond == Merge::First) || (eFirst == Merge::NonFirst && eSecond == Merge::None) || (eFirst == Merge::NonFirst && eSecond == Merge::Hidden) || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 769, __extension__ __PRETTY_FUNCTION__))
768 || (eFirst == Merge::NonFirst && eSecond == Merge::Hidden)(static_cast <bool> ((eFirst == Merge::NonFirst &&
eSecond == Merge::First) || (eFirst == Merge::NonFirst &&
eSecond == Merge::None) || (eFirst == Merge::NonFirst &&
eSecond == Merge::Hidden) || (eFirst == Merge::Hidden &&
eSecond == Merge::NonFirst)) ? void (0) : __assert_fail ("(eFirst == Merge::NonFirst && eSecond == Merge::First) || (eFirst == Merge::NonFirst && eSecond == Merge::None) || (eFirst == Merge::NonFirst && eSecond == Merge::Hidden) || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 769, __extension__ __PRETTY_FUNCTION__))
769 || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst))(static_cast <bool> ((eFirst == Merge::NonFirst &&
eSecond == Merge::First) || (eFirst == Merge::NonFirst &&
eSecond == Merge::None) || (eFirst == Merge::NonFirst &&
eSecond == Merge::Hidden) || (eFirst == Merge::Hidden &&
eSecond == Merge::NonFirst)) ? void (0) : __assert_fail ("(eFirst == Merge::NonFirst && eSecond == Merge::First) || (eFirst == Merge::NonFirst && eSecond == Merge::None) || (eFirst == Merge::NonFirst && eSecond == Merge::Hidden) || (eFirst == Merge::Hidden && eSecond == Merge::NonFirst)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 769, __extension__ __PRETTY_FUNCTION__))
;
770 break;
771 case Merge::None:
772 assert((eFirst == Merge::None && eSecond == Merge::None)(static_cast <bool> ((eFirst == Merge::None && eSecond
== Merge::None) || (eFirst == Merge::First && eSecond
== Merge::NonFirst)) ? void (0) : __assert_fail ("(eFirst == Merge::None && eSecond == Merge::None) || (eFirst == Merge::First && eSecond == Merge::NonFirst)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 773, __extension__ __PRETTY_FUNCTION__))
773 || (eFirst == Merge::First && eSecond == Merge::NonFirst))(static_cast <bool> ((eFirst == Merge::None && eSecond
== Merge::None) || (eFirst == Merge::First && eSecond
== Merge::NonFirst)) ? void (0) : __assert_fail ("(eFirst == Merge::None && eSecond == Merge::None) || (eFirst == Merge::First && eSecond == Merge::NonFirst)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 773, __extension__ __PRETTY_FUNCTION__))
;
774 break;
775 }
776 }
777#else
778 (void) isHide;
779#endif
780
781 {
782 // Send Hint for PageDesc. This should be done in the Layout when
783 // pasting the frames, but that causes other problems that look
784 // expensive to solve.
785 const SfxPoolItem *pItem;
786 if( HasWriterListeners() && SfxItemState::SET == pNode->GetSwAttrSet().
787 GetItemState( RES_PAGEDESC, true, &pItem ) )
788 {
789 pNode->ModifyNotification( pItem, pItem );
790 }
791 }
792 return pNode;
793}
794
795void SwTextNode::MoveTextAttr_To_AttrSet()
796{
797 OSL_ENSURE( m_pSwpHints, "MoveTextAttr_To_AttrSet without SwpHints?" )do { if (true && (!(m_pSwpHints))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "797" ": "), "%s", "MoveTextAttr_To_AttrSet without SwpHints?"
); } } while (false)
;
798 for ( size_t i = 0; m_pSwpHints && i < m_pSwpHints->Count(); ++i )
799 {
800 SwTextAttr *pHt = m_pSwpHints->Get(i);
801
802 if( pHt->GetStart() )
803 break;
804
805 const sal_Int32* pHtEndIdx = pHt->GetEnd();
806
807 if( !pHtEndIdx )
808 continue;
809
810 if (*pHtEndIdx < m_Text.getLength() || pHt->IsCharFormatAttr())
811 break;
812
813 if( !pHt->IsDontMoveAttr() &&
814 SetAttr( pHt->GetAttr() ) )
815 {
816 m_pSwpHints->DeleteAtPos(i);
817 DestroyAttr( pHt );
818 --i;
819 }
820 }
821
822}
823
824namespace sw {
825
826/// if first node is deleted & second survives, then the first node's frame
827/// will be deleted too; prevent this by moving the frame to the second node
828/// if necessary.
829void MoveDeletedPrevFrames(const SwTextNode & rDeletedPrev, SwTextNode & rNode)
830{
831 std::vector<SwTextFrame*> frames;
832 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rDeletedPrev);
833 for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
834 {
835 if (pFrame->getRootFrame()->IsHideRedlines())
836 {
837 frames.push_back(pFrame);
838 }
839 }
840 {
841 auto frames2(frames);
842 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIt(rNode);
843 for (SwTextFrame* pFrame = aIt.First(); pFrame; pFrame = aIt.Next())
844 {
845 if (pFrame->getRootFrame()->IsHideRedlines())
846 {
847 auto const it(std::find(frames2.begin(), frames2.end(), pFrame));
848 assert(it != frames2.end())(static_cast <bool> (it != frames2.end()) ? void (0) : __assert_fail
("it != frames2.end()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 848, __extension__ __PRETTY_FUNCTION__))
;
849 frames2.erase(it);
850 }
851 }
852 assert(frames2.empty())(static_cast <bool> (frames2.empty()) ? void (0) : __assert_fail
("frames2.empty()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 852, __extension__ __PRETTY_FUNCTION__))
;
853 }
854 for (SwTextFrame *const pFrame : frames)
855 {
856 pFrame->RegisterToNode(rNode, true);
857 }
858}
859
860// typical Join:
861// None,Node->None
862// None,First->First
863// First,NonFirst->First
864// NonFirst,First->NonFirst
865// NonFirst,None->NonFirst
866
867/// if first node is First, its frames may need to be moved, never deleted.
868/// if first node is NonFirst, second node's own frames (First/None) must be deleted
869void CheckResetRedlineMergeFlag(SwTextNode & rNode, Recreate const eRecreateMerged)
870{
871 if (eRecreateMerged != sw::Recreate::No)
872 {
873 SwTextNode * pMergeNode(&rNode);
874 if (eRecreateMerged == sw::Recreate::Predecessor
875 // tdf#135018 check that there is a predecessor node, i.e. rNode
876 // isn't the first node after the body start node
877 && rNode.GetNodes()[rNode.GetIndex() - 1]->StartOfSectionIndex() != 0)
878 {
879 for (sal_uLong i = rNode.GetIndex() - 1; ; --i)
880 {
881 SwNode *const pNode(rNode.GetNodes()[i]);
882 assert(!pNode->IsStartNode())(static_cast <bool> (!pNode->IsStartNode()) ? void (
0) : __assert_fail ("!pNode->IsStartNode()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 882, __extension__ __PRETTY_FUNCTION__))
;
883 if (pNode->IsEndNode())
884 {
885 i = pNode->StartOfSectionIndex();
886 }
887 else if (pNode->IsTextNode())
888 {
889 pMergeNode = pNode->GetTextNode(); // use predecessor to merge
890 break;
891 }
892 }
893 }
894 std::vector<SwTextFrame*> frames;
895 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pMergeNode);
896 for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
897 {
898 if (pFrame->getRootFrame()->IsHideRedlines())
899 {
900 frames.push_back(pFrame);
901 }
902 }
903 auto eMode(sw::FrameMode::Existing);
904 for (SwTextFrame * pFrame : frames)
905 {
906 SwTextNode & rFirstNode(pFrame->GetMergedPara()
907 ? *pFrame->GetMergedPara()->pFirstNode
908 : *pMergeNode);
909 assert(rFirstNode.GetIndex() <= rNode.GetIndex())(static_cast <bool> (rFirstNode.GetIndex() <= rNode.
GetIndex()) ? void (0) : __assert_fail ("rFirstNode.GetIndex() <= rNode.GetIndex()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 909, __extension__ __PRETTY_FUNCTION__))
;
910 pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
911 *pFrame, rFirstNode, eMode));
912 assert(pFrame->GetMergedPara())(static_cast <bool> (pFrame->GetMergedPara()) ? void
(0) : __assert_fail ("pFrame->GetMergedPara()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 912, __extension__ __PRETTY_FUNCTION__))
;
913 assert(pFrame->GetMergedPara()->listener.IsListeningTo(&rNode))(static_cast <bool> (pFrame->GetMergedPara()->listener
.IsListeningTo(&rNode)) ? void (0) : __assert_fail ("pFrame->GetMergedPara()->listener.IsListeningTo(&rNode)"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 913, __extension__ __PRETTY_FUNCTION__))
;
914 assert(rNode.GetIndex() <= pFrame->GetMergedPara()->pLastNode->GetIndex())(static_cast <bool> (rNode.GetIndex() <= pFrame->
GetMergedPara()->pLastNode->GetIndex()) ? void (0) : __assert_fail
("rNode.GetIndex() <= pFrame->GetMergedPara()->pLastNode->GetIndex()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 914, __extension__ __PRETTY_FUNCTION__))
;
915 eMode = sw::FrameMode::New; // Existing is not idempotent!
916 }
917 }
918 else if (rNode.GetRedlineMergeFlag() != SwNode::Merge::None)
919 {
920 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rNode);
921 for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
922 {
923 if (auto const pMergedPara = pFrame->GetMergedPara())
924 {
925 if (pMergedPara->pFirstNode == pMergedPara->pLastNode)
926 {
927 assert(pMergedPara->pFirstNode == &rNode)(static_cast <bool> (pMergedPara->pFirstNode == &
rNode) ? void (0) : __assert_fail ("pMergedPara->pFirstNode == &rNode"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 927, __extension__ __PRETTY_FUNCTION__))
;
928 rNode.SetRedlineMergeFlag(SwNode::Merge::None);
929 }
930 break; // checking once is enough
931 }
932 else if (pFrame->getRootFrame()->IsHideRedlines())
933 {
934 rNode.SetRedlineMergeFlag(SwNode::Merge::None);
935 break; // checking once is enough
936 }
937 }
938 }
939}
940
941} // namespace
942
943SwContentNode *SwTextNode::JoinNext()
944{
945 SwNodes& rNds = GetNodes();
946 SwNodeIndex aIdx( *this );
947 if( SwContentNode::CanJoinNext( &aIdx ) )
948 {
949 SwDoc& rDoc = rNds.GetDoc();
950 const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
951 pContentStore->Save(rDoc, aIdx.GetIndex(), SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF));
952 SwTextNode *pTextNode = aIdx.GetNode().GetTextNode();
953 sal_Int32 nOldLen = m_Text.getLength();
954
955 // METADATA: merge
956 JoinMetadatable(*pTextNode, !Len(), !pTextNode->Len());
957
958 SwWrongList *pList = GetWrong();
959 if( pList )
960 {
961 pList->JoinList( pTextNode->GetWrong(), nOldLen );
962 SetWrongDirty(WrongState::TODO);
963 SetWrong( nullptr, false );
964 }
965 else
966 {
967 pList = pTextNode->GetWrong();
968 if( pList )
969 {
970 pList->Move( 0, nOldLen );
971 SetWrongDirty(WrongState::TODO);
972 pTextNode->SetWrong( nullptr, false );
973 }
974 }
975
976 SwGrammarMarkUp *pList3 = GetGrammarCheck();
977 if( pList3 )
978 {
979 pList3->JoinGrammarList( pTextNode->GetGrammarCheck(), nOldLen );
980 SetGrammarCheckDirty( true );
981 SetGrammarCheck( nullptr, false );
982 }
983 else
984 {
985 pList3 = pTextNode->GetGrammarCheck();
986 if( pList3 )
987 {
988 pList3->MoveGrammar( 0, nOldLen );
989 SetGrammarCheckDirty( true );
990 pTextNode->SetGrammarCheck( nullptr, false );
991 }
992 }
993
994 SwWrongList *pList2 = GetSmartTags();
995 if( pList2 )
996 {
997 pList2->JoinList( pTextNode->GetSmartTags(), nOldLen );
998 SetSmartTagDirty( true );
999 SetSmartTags( nullptr, false );
1000 }
1001 else
1002 {
1003 pList2 = pTextNode->GetSmartTags();
1004 if( pList2 )
1005 {
1006 pList2->Move( 0, nOldLen );
1007 SetSmartTagDirty( true );
1008 pTextNode->SetSmartTags( nullptr, false );
1009 }
1010 }
1011
1012 { // scope for SwIndex
1013 pTextNode->CutText( this, SwIndex(pTextNode), pTextNode->Len() );
1014 }
1015 // move all Bookmarks/TOXMarks
1016 if( !pContentStore->Empty())
1017 pContentStore->Restore( rDoc, GetIndex(), nOldLen );
1018
1019 if( pTextNode->HasAnyIndex() )
1020 {
1021 // move all ShellCursor/StackCursor/UnoCursor out of delete range
1022 rDoc.CorrAbs( aIdx, SwPosition( *this ), nOldLen, true );
1023 }
1024 SwNode::Merge const eOldMergeFlag(pTextNode->GetRedlineMergeFlag());
1025 rNds.Delete(aIdx);
1026 SetWrong( pList, false );
1027 SetGrammarCheck( pList3, false );
1028 SetSmartTags( pList2, false );
1029 InvalidateNumRule();
1030 CheckResetRedlineMergeFlag(*this, eOldMergeFlag == SwNode::Merge::First
1031 ? sw::Recreate::ThisNode
1032 : sw::Recreate::No);
1033 }
1034 else {
1035 OSL_FAIL( "No TextNode." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "1035" ": "), "%s", "No TextNode."); } } while (false)
;
1036 }
1037
1038 return this;
1039}
1040
1041void SwTextNode::JoinPrev()
1042{
1043 SwNodes& rNds = GetNodes();
1044 SwNodeIndex aIdx( *this );
1045 if( SwContentNode::CanJoinPrev( &aIdx ) )
1046 {
1047 SwDoc& rDoc = rNds.GetDoc();
1048 const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
1049 pContentStore->Save( rDoc, aIdx.GetIndex(), SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF));
1050 SwTextNode *pTextNode = aIdx.GetNode().GetTextNode();
1051 const sal_Int32 nLen = pTextNode->Len();
1052
1053 SwWrongList *pList = pTextNode->GetWrong();
1054 if( pList )
1055 {
1056 pList->JoinList( GetWrong(), Len() );
1057 SetWrongDirty(WrongState::TODO);
1058 pTextNode->SetWrong( nullptr, false );
1059 SetWrong( nullptr );
1060 }
1061 else
1062 {
1063 pList = GetWrong();
1064 if( pList )
1065 {
1066 pList->Move( 0, nLen );
1067 SetWrongDirty(WrongState::TODO);
1068 SetWrong( nullptr, false );
1069 }
1070 }
1071
1072 SwGrammarMarkUp *pList3 = pTextNode->GetGrammarCheck();
1073 if( pList3 )
1074 {
1075 pList3->JoinGrammarList( GetGrammarCheck(), Len() );
1076 SetGrammarCheckDirty( true );
1077 pTextNode->SetGrammarCheck( nullptr, false );
1078 SetGrammarCheck( nullptr );
1079 }
1080 else
1081 {
1082 pList3 = GetGrammarCheck();
1083 if( pList3 )
1084 {
1085 pList3->MoveGrammar( 0, nLen );
1086 SetGrammarCheckDirty( true );
1087 SetGrammarCheck( nullptr, false );
1088 }
1089 }
1090
1091 SwWrongList *pList2 = pTextNode->GetSmartTags();
1092 if( pList2 )
1093 {
1094 pList2->JoinList( GetSmartTags(), Len() );
1095 SetSmartTagDirty( true );
1096 pTextNode->SetSmartTags( nullptr, false );
1097 SetSmartTags( nullptr );
1098 }
1099 else
1100 {
1101 pList2 = GetSmartTags();
1102 if( pList2 )
1103 {
1104 pList2->Move( 0, nLen );
1105 SetSmartTagDirty( true );
1106 SetSmartTags( nullptr, false );
1107 }
1108 }
1109
1110 { // scope for SwIndex
1111 pTextNode->CutText( this, SwIndex(this), SwIndex(pTextNode), nLen );
1112 }
1113 // move all Bookmarks/TOXMarks
1114 if( !pContentStore->Empty() )
1115 pContentStore->Restore( rDoc, GetIndex() );
1116
1117 if( pTextNode->HasAnyIndex() )
1118 {
1119 // move all ShellCursor/StackCursor/UnoCursor out of delete range
1120 rDoc.CorrAbs( aIdx, SwPosition( *this ), nLen, true );
1121 }
1122 SwNode::Merge const eOldMergeFlag(pTextNode->GetRedlineMergeFlag());
1123 if (eOldMergeFlag == SwNode::Merge::First
1124 && !IsCreateFrameWhenHidingRedlines())
1125 {
1126 sw::MoveDeletedPrevFrames(*pTextNode, *this);
1127 }
1128 rNds.Delete(aIdx);
1129 SetWrong( pList, false );
1130 SetGrammarCheck( pList3, false );
1131 SetSmartTags( pList2, false );
1132 InvalidateNumRule();
1133 sw::CheckResetRedlineMergeFlag(*this,
1134 eOldMergeFlag == SwNode::Merge::NonFirst
1135 ? sw::Recreate::Predecessor
1136 : sw::Recreate::No);
1137 }
1138 else {
1139 OSL_FAIL( "No TextNode." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "1139" ": "), "%s", "No TextNode."); } } while (false)
;
1140 }
1141}
1142
1143// create an AttrSet with ranges for Frame-/Para/Char-attributes
1144void SwTextNode::NewAttrSet( SwAttrPool& rPool )
1145{
1146 OSL_ENSURE( !mpAttrSet, "AttrSet is set after all" )do { if (true && (!(!mpAttrSet))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "1146" ": "), "%s", "AttrSet is set after all"); } } while
(false)
;
1147 SwAttrSet aNewAttrSet( rPool, aTextNodeSetRange );
1148
1149 // put names of parent style and conditional style:
1150 const SwFormatColl* pAnyFormatColl = &GetAnyFormatColl();
1151 const SwFormatColl* pFormatColl = GetFormatColl();
1152 OUString sVal;
1153 SwStyleNameMapper::FillProgName( pAnyFormatColl->GetName(), sVal, SwGetPoolIdFromName::TxtColl );
1154 SfxStringItem aAnyFormatColl( RES_FRMATR_STYLE_NAME, sVal );
1155 if ( pFormatColl != pAnyFormatColl )
1156 SwStyleNameMapper::FillProgName( pFormatColl->GetName(), sVal, SwGetPoolIdFromName::TxtColl );
1157 SfxStringItem aFormatColl( RES_FRMATR_CONDITIONAL_STYLE_NAME, sVal );
1158 aNewAttrSet.Put( aAnyFormatColl );
1159 aNewAttrSet.Put( aFormatColl );
1160
1161 aNewAttrSet.SetParent( &pAnyFormatColl->GetAttrSet() );
1162 mpAttrSet = GetDoc().GetIStyleAccess().getAutomaticStyle( aNewAttrSet, IStyleAccess::AUTO_STYLE_PARA, &sVal );
1163}
1164
1165// override SwIndexReg::Update => text hints do not need SwIndex for start/end!
1166void SwTextNode::Update(
1167 SwIndex const & rPos,
1168 const sal_Int32 nChangeLen,
1169 const bool bNegative,
1170 const bool bDelete )
1171{
1172 SetAutoCompleteWordDirty( true );
1173
1174 std::unique_ptr<SwpHts> pCollector;
1175 const sal_Int32 nChangePos = rPos.GetIndex();
1176
1177 if ( HasHints() )
1178 {
1179 if ( bNegative )
1180 {
1181 std::vector<SwTextInputField*> aTextInputFields;
1182
1183 const sal_Int32 nChangeEnd = nChangePos + nChangeLen;
1184 for ( size_t n = 0; n < m_pSwpHints->Count(); ++n )
1185 {
1186 bool bTextAttrChanged = false;
1187 bool bStartOfTextAttrChanged = false;
1188 SwTextAttr * const pHint = m_pSwpHints->GetWithoutResorting(n);
1189 if ( pHint->GetStart() > nChangePos )
1190 {
1191 if ( pHint->GetStart() > nChangeEnd )
1192 {
1193 pHint->SetStart( pHint->GetStart() - nChangeLen );
1194 }
1195 else
1196 {
1197 pHint->SetStart( nChangePos );
1198 }
1199 bStartOfTextAttrChanged = true;
1200 }
1201
1202 const sal_Int32 * const pEnd = pHint->GetEnd();
1203 if (pEnd && *pEnd > nChangePos )
1204 {
1205 if( *pEnd > nChangeEnd )
1206 {
1207 pHint->SetEnd(*pEnd - nChangeLen);
1208 }
1209 else
1210 {
1211 pHint->SetEnd(nChangePos);
1212 }
1213 bTextAttrChanged = !bStartOfTextAttrChanged;
1214 }
1215
1216 if ( bTextAttrChanged
1217 && pHint->Which() == RES_TXTATR_INPUTFIELD )
1218 {
1219 SwTextInputField* pTextInputField = dynamic_cast<SwTextInputField*>(pHint);
1220 if ( pTextInputField )
1221 aTextInputFields.push_back(pTextInputField);
1222 }
1223 }
1224
1225 //wait until all the attribute positions are correct
1226 //before updating the field contents
1227 for (SwTextInputField* pTextInputField : aTextInputFields)
1228 {
1229 pTextInputField->UpdateFieldContent();
1230 }
1231
1232 m_pSwpHints->MergePortions( *this );
1233 }
1234 else
1235 {
1236 bool bNoExp = false;
1237 bool bResort = false;
1238 bool bMergePortionsNeeded = false;
1239 const int coArrSz = RES_TXTATR_WITHEND_END - RES_CHRATR_BEGIN;
1240 std::vector<SwTextInputField*> aTextInputFields;
1241
1242 bool aDontExp[ coArrSz ] = {};
1243
1244 for ( size_t n = 0; n < m_pSwpHints->Count(); ++n )
1245 {
1246 bool bTextAttrChanged = false;
1247 SwTextAttr * const pHint = m_pSwpHints->GetWithoutResorting(n);
1248 const sal_Int32 * const pEnd = pHint->GetEnd();
1249 if ( pHint->GetStart() >= nChangePos )
1250 {
1251 pHint->SetStart( pHint->GetStart() + nChangeLen );
1252 if ( pEnd )
1253 {
1254 pHint->SetEnd(*pEnd + nChangeLen);
1255 }
1256 }
1257 else if ( pEnd && (*pEnd >= nChangePos) )
1258 {
1259 if ( (*pEnd > nChangePos) || IsIgnoreDontExpand() )
1260 {
1261 pHint->SetEnd(*pEnd + nChangeLen);
1262 bTextAttrChanged = true;
1263 }
1264 else // *pEnd == nChangePos
1265 {
1266 const sal_uInt16 nWhich = pHint->Which();
1267
1268 OSL_ENSURE(!isCHRATR(nWhich), "Update: char attr hint?")do { if (true && (!(!isCHRATR(nWhich)))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "1268" ": "), "%s", "Update: char attr hint?"); } } while
(false)
;
1269 if (!(isCHRATR(nWhich) || isTXTATR_WITHEND(nWhich)))
1270 continue;
1271
1272 const sal_uInt16 nWhPos = nWhich - RES_CHRATR_BEGIN;
1273
1274 if( aDontExp[ nWhPos ] )
1275 continue;
1276
1277 if ( pHint->DontExpand() )
1278 {
1279 pHint->SetDontExpand( false );
1280 bResort = true;
1281 // could have a continuation with IgnoreStart()...
1282 if (pHint->IsFormatIgnoreEnd())
1283 {
1284 bMergePortionsNeeded = true;
1285 }
1286 if ( pHint->IsCharFormatAttr() )
1287 {
1288 bNoExp = true;
1289 aDontExp[ RES_TXTATR_CHARFMT - RES_CHRATR_BEGIN ] = true;
1290 aDontExp[ RES_TXTATR_INETFMT - RES_CHRATR_BEGIN ] = true;
1291 }
1292 else
1293 aDontExp[ nWhPos ] = true;
1294 }
1295 else if( bNoExp )
1296 {
1297 if (!pCollector)
1298 {
1299 pCollector.reset( new SwpHts );
1300 }
1301 auto it = std::find_if(pCollector->begin(), pCollector->end(),
1302 [nWhich](const SwTextAttr *pTmp) { return nWhich == pTmp->Which(); });
1303 if (it != pCollector->end())
1304 {
1305 SwTextAttr *pTmp = *it;
1306 pCollector->erase( it );
1307 SwTextAttr::Destroy( pTmp, GetDoc().GetAttrPool() );
1308 }
1309 SwTextAttr * const pTmp =
1310 MakeTextAttr( GetDoc(),
1311 pHint->GetAttr(), nChangePos, nChangePos + nChangeLen);
1312 pCollector->push_back( pTmp );
1313 }
1314 else
1315 {
1316 pHint->SetEnd(*pEnd + nChangeLen);
1317 bTextAttrChanged = true;
1318 }
1319 }
1320 }
1321
1322 if ( bTextAttrChanged
1323 && pHint->Which() == RES_TXTATR_INPUTFIELD )
1324 {
1325 SwTextInputField* pTextInputField = dynamic_cast<SwTextInputField*>(pHint);
1326 if ( pTextInputField )
1327 aTextInputFields.push_back(pTextInputField);
1328 }
1329 }
1330
1331 //wait until all the attribute positions are correct
1332 //before updating the field contents
1333 for (SwTextInputField* pTextInputField : aTextInputFields)
1334 {
1335 pTextInputField->UpdateFieldContent();
1336 }
1337
1338 if (bMergePortionsNeeded)
1339 {
1340 m_pSwpHints->MergePortions(*this); // does Resort too
1341 }
1342 else if (bResort)
1343 {
1344 m_pSwpHints->Resort();
1345 }
1346 }
1347 }
1348
1349 bool bSortMarks = false;
1350 SwIndexReg aTmpIdxReg;
1351 if ( !bNegative && !bDelete )
1352 {
1353 const SwRedlineTable& rTable = GetDoc().getIDocumentRedlineAccess().GetRedlineTable();
1354 for (SwRangeRedline* pRedl : rTable)
1355 {
1356 if ( pRedl->HasMark() )
1357 {
1358 SwPosition* const pEnd = pRedl->End();
1359 if ( this == &pEnd->nNode.GetNode() &&
1360 *pRedl->GetPoint() != *pRedl->GetMark() )
1361 {
1362 SwIndex & rIdx = pEnd->nContent;
1363 if (nChangePos == rIdx.GetIndex())
1364 {
1365 rIdx.Assign( &aTmpIdxReg, rIdx.GetIndex() );
1366 }
1367 }
1368 }
1369 else if ( this == &pRedl->GetPoint()->nNode.GetNode() )
1370 {
1371 SwIndex & rIdx = pRedl->GetPoint()->nContent;
1372 if (nChangePos == rIdx.GetIndex())
1373 {
1374 rIdx.Assign( &aTmpIdxReg, rIdx.GetIndex() );
1375 }
1376 // the unused position must not be on a SwTextNode
1377 bool const isOneUsed(&pRedl->GetBound() == pRedl->GetPoint());
1378 assert(!pRedl->GetBound(!isOneUsed).nNode.GetNode().IsTextNode())(static_cast <bool> (!pRedl->GetBound(!isOneUsed).nNode
.GetNode().IsTextNode()) ? void (0) : __assert_fail ("!pRedl->GetBound(!isOneUsed).nNode.GetNode().IsTextNode()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1378, __extension__ __PRETTY_FUNCTION__))
;
1379 assert(!pRedl->GetBound(!isOneUsed).nContent.GetIdxReg())(static_cast <bool> (!pRedl->GetBound(!isOneUsed).nContent
.GetIdxReg()) ? void (0) : __assert_fail ("!pRedl->GetBound(!isOneUsed).nContent.GetIdxReg()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1379, __extension__ __PRETTY_FUNCTION__))
; (void)isOneUsed;
1380 }
1381 }
1382
1383 // Bookmarks must never grow to either side, when editing (directly)
1384 // to the left or right (i#29942)! Exception: if the bookmark has
1385 // 2 positions and start == end, then expand it (tdf#96479)
1386 {
1387 bool bAtLeastOneBookmarkMoved = false;
1388 bool bAtLeastOneExpandedBookmarkAtInsertionPosition = false;
1389 // A text node already knows its marks via its SwIndexes.
1390 o3tl::sorted_vector<const sw::mark::IMark*> aSeenMarks;
1391 const SwIndex* next;
1392 for (const SwIndex* pIndex = GetFirstIndex(); pIndex; pIndex = next )
1393 {
1394 next = pIndex->GetNext();
1395 const sw::mark::IMark* pMark = pIndex->GetMark();
1396 if (!pMark)
1397 continue;
1398 // Only handle bookmarks once, if they start and end at this node as well.
1399 if (!aSeenMarks.insert(pMark).second)
1400 continue;
1401 const SwPosition* pEnd = &pMark->GetMarkEnd();
1402 SwIndex & rEndIdx = const_cast<SwIndex&>(pEnd->nContent);
1403 if( this == &pEnd->nNode.GetNode() &&
1404 rPos.GetIndex() == rEndIdx.GetIndex() )
1405 {
1406 if (&rEndIdx == next) // nasty corner case:
1407 { // don't switch to iterating aTmpIdxReg!
1408 next = rEndIdx.GetNext();
1409 }
1410 // tdf#96479: if start == end, ignore the other position
1411 // so it is moved!
1412 rEndIdx.Assign( &aTmpIdxReg, rEndIdx.GetIndex() );
1413 bAtLeastOneBookmarkMoved = true;
1414 }
1415 else if ( !bAtLeastOneExpandedBookmarkAtInsertionPosition )
1416 {
1417 if ( pMark->IsExpanded() )
1418 {
1419 const SwPosition* pStart = &pMark->GetMarkStart();
1420 if ( this == &pStart->nNode.GetNode()
1421 && rPos.GetIndex() == pStart->nContent.GetIndex() )
1422 {
1423 bAtLeastOneExpandedBookmarkAtInsertionPosition = true;
1424 }
1425 }
1426 }
1427 }
1428
1429 bSortMarks = bAtLeastOneBookmarkMoved && bAtLeastOneExpandedBookmarkAtInsertionPosition;
1430 }
1431
1432 // at-char anchored flys shouldn't be moved, either.
1433#if OSL_DEBUG_LEVEL1 > 0
1434 std::vector<SwFrameFormat*> checkFormats;
1435 const SwFrameFormats& rFormats = *GetDoc().GetSpzFrameFormats();
1436 for (auto& rpFormat : rFormats)
1437 {
1438 const SwFormatAnchor& rAnchor = rpFormat->GetAnchor();
1439 const SwPosition* pContentAnchor = rAnchor.GetContentAnchor();
1440 if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR && pContentAnchor)
1441 {
1442 // The fly is at-char anchored and has an anchor position.
1443 SwIndex& rEndIdx = const_cast<SwIndex&>(pContentAnchor->nContent);
1444 if (&pContentAnchor->nNode.GetNode() == this && rEndIdx.GetIndex() == rPos.GetIndex())
1445 {
1446 // The anchor position is exactly our insert position.
1447 #if 0
1448 rEndIdx.Assign(&aTmpIdxReg, rEndIdx.GetIndex());
1449 #endif
1450 checkFormats.push_back( rpFormat );
1451 }
1452 }
1453 }
1454#endif
1455 std::vector<SwFrameFormat*> const*const pFlys(GetAnchoredFlys());
1456 for (size_t i = 0; pFlys && i != pFlys->size(); ++i)
1457 {
1458 SwFrameFormat const*const pFormat = (*pFlys)[i];
1459 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
1460 const SwPosition* pContentAnchor = rAnchor.GetContentAnchor();
1461 if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR && pContentAnchor)
1462 {
1463 // The fly is at-char anchored and has an anchor position.
1464 SwIndex& rEndIdx = const_cast<SwIndex&>(pContentAnchor->nContent);
1465 if (&pContentAnchor->nNode.GetNode() == this && rEndIdx.GetIndex() == rPos.GetIndex())
1466 {
1467 // The anchor position is exactly our insert position.
1468 rEndIdx.Assign(&aTmpIdxReg, rEndIdx.GetIndex());
1469#if OSL_DEBUG_LEVEL1 > 0
1470 auto checkPos = std::find( checkFormats.begin(), checkFormats.end(), pFormat );
1471 assert( checkPos != checkFormats.end())(static_cast <bool> (checkPos != checkFormats.end()) ? void
(0) : __assert_fail ("checkPos != checkFormats.end()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1471, __extension__ __PRETTY_FUNCTION__))
;
1472 checkFormats.erase( checkPos );
1473#endif
1474 }
1475 }
1476 }
1477#if OSL_DEBUG_LEVEL1 > 0
1478 assert( checkFormats.empty())(static_cast <bool> (checkFormats.empty()) ? void (0) :
__assert_fail ("checkFormats.empty()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1478, __extension__ __PRETTY_FUNCTION__))
;
1479#endif
1480
1481 // The cursors of other shells shouldn't be moved, either.
1482 if (SwDocShell* pDocShell = GetDoc().GetDocShell())
1483 {
1484 if (pDocShell->GetWrtShell())
1485 {
1486 for (SwViewShell& rShell : pDocShell->GetWrtShell()->GetRingContainer())
1487 {
1488 auto pWrtShell = dynamic_cast<SwWrtShell*>(&rShell);
1489 if (!pWrtShell || pWrtShell == pDocShell->GetWrtShell())
1490 continue;
1491
1492 SwShellCursor* pCursor = pWrtShell->GetCursor_();
1493 if (!pCursor)
1494 continue;
1495
1496 SwIndex& rIndex = pCursor->Start()->nContent;
1497 if (&pCursor->Start()->nNode.GetNode() == this && rIndex.GetIndex() == rPos.GetIndex())
1498 {
1499 // The cursor position of this other shell is exactly our insert position.
1500 rIndex.Assign(&aTmpIdxReg, rIndex.GetIndex());
1501 }
1502 }
1503 }
1504 }
1505 }
1506
1507 // base class
1508 SwIndexReg::Update( rPos, nChangeLen, bNegative, bDelete );
1509
1510 if (pCollector)
1511 {
1512 const size_t nCount = pCollector->size();
1513 for ( size_t i = 0; i < nCount; ++i )
1514 {
1515 m_pSwpHints->TryInsertHint( (*pCollector)[ i ], *this );
1516 }
1517 }
1518
1519 aTmpIdxReg.MoveTo( *this );
1520 if ( bSortMarks )
1521 {
1522 getIDocumentMarkAccess()->assureSortedMarkContainers();
1523 }
1524
1525 //Any drawing objects anchored into this text node may be sorted by their
1526 //anchor position which may have changed here, so resort them
1527 SwContentFrame* pContentFrame = getLayoutFrame(GetDoc().getIDocumentLayoutAccess().GetCurrentLayout());
1528 SwSortedObjs* pSortedObjs = pContentFrame ? pContentFrame->GetDrawObjs() : nullptr;
1529 if (pSortedObjs)
1530 pSortedObjs->UpdateAll();
1531
1532 // Update the paragraph signatures.
1533 if (SwEditShell* pEditShell = GetDoc().GetEditShell())
1534 {
1535 pEditShell->ValidateParagraphSignatures(this, true);
1536 }
1537
1538 // Inform LOK clients about change in position of redlines (if any)
1539 // Don't emit notifications during save: redline flags are temporarily changed during save, but
1540 // it's not useful to let clients know about such changes.
1541 if (!comphelper::LibreOfficeKit::isActive() || GetDoc().IsInWriting())
1542 return;
1543
1544 const SwRedlineTable& rTable = GetDoc().getIDocumentRedlineAccess().GetRedlineTable();
1545 for (SwRedlineTable::size_type nRedlnPos = 0; nRedlnPos < rTable.size(); ++nRedlnPos)
1546 {
1547 SwRangeRedline* pRedln = rTable[nRedlnPos];
1548 if (pRedln->HasMark())
1549 {
1550 if (this == &pRedln->End()->nNode.GetNode() && *pRedln->GetPoint() != *pRedln->GetMark())
1551 {
1552 // Redline is changed only when some change occurs before it
1553 if (nChangePos <= pRedln->Start()->nContent.GetIndex())
1554 {
1555 SwRedlineTable::LOKRedlineNotification(RedlineNotification::Modify, pRedln);
1556 }
1557 }
1558 }
1559 else if (this == &pRedln->GetPoint()->nNode.GetNode())
1560 SwRedlineTable::LOKRedlineNotification(RedlineNotification::Modify, pRedln);
1561 }
1562}
1563
1564void SwTextNode::ChgTextCollUpdateNum( const SwTextFormatColl *pOldColl,
1565 const SwTextFormatColl *pNewColl)
1566{
1567 SwDoc& rDoc = GetDoc();
1568 // query the OutlineLevel and if it changed, notify the Nodes-Array!
1569 const int nOldLevel = pOldColl && pOldColl->IsAssignedToListLevelOfOutlineStyle() ?
1570 pOldColl->GetAssignedOutlineStyleLevel() : MAXLEVEL;
1571 const int nNewLevel = pNewColl && pNewColl->IsAssignedToListLevelOfOutlineStyle() ?
1572 pNewColl->GetAssignedOutlineStyleLevel() : MAXLEVEL;
1573
1574 if ( MAXLEVEL != nNewLevel && -1 != nNewLevel )
1575 {
1576 SetAttrListLevel(nNewLevel);
1577 }
1578 rDoc.GetNodes().UpdateOutlineNode(*this);
1579
1580 SwNodes& rNds = GetNodes();
1581 // If Level 0 (Chapter), update the footnotes!
1582 if( ( !nNewLevel || !nOldLevel) && !rDoc.GetFootnoteIdxs().empty() &&
1583 FTNNUM_CHAPTER == rDoc.GetFootnoteInfo().m_eNum &&
1584 rNds.IsDocNodes() )
1585 {
1586 SwNodeIndex aTmpIndex( rNds, GetIndex());
1587
1588 rDoc.GetFootnoteIdxs().UpdateFootnote( aTmpIndex);
1589 }
1590
1591 if( pNewColl && RES_CONDTXTFMTCOLL == pNewColl->Which() )
1592 {
1593 // check the condition of the text node again
1594 ChkCondColl();
1595 }
1596}
1597
1598// If positioned exactly at the end of a CharStyle or Hyperlink,
1599// set its DontExpand flag.
1600bool SwTextNode::DontExpandFormat( const SwIndex& rIdx, bool bFlag,
1601 bool bFormatToTextAttributes )
1602{
1603 const sal_Int32 nIdx = rIdx.GetIndex();
1604 if (bFormatToTextAttributes && nIdx == m_Text.getLength())
1605 {
1606 FormatToTextAttr( this );
1607 }
1608
1609 bool bRet = false;
1610 if ( HasHints() )
1611 {
1612 m_pSwpHints->SortIfNeedBe();
1613 int nPos = m_pSwpHints->GetLastPosSortedByEnd(nIdx);
1614 for ( ; nPos >= 0; --nPos)
1615 {
1616 SwTextAttr *pTmp = m_pSwpHints->GetSortedByEnd( nPos );
1617 const sal_Int32 *pEnd = pTmp->GetEnd();
1618 if( !pEnd )
1619 continue;
1620 assert( *pEnd <= nIdx )(static_cast <bool> (*pEnd <= nIdx) ? void (0) : __assert_fail
("*pEnd <= nIdx", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1620, __extension__ __PRETTY_FUNCTION__))
;
1621 if( nIdx != *pEnd )
1622 break;
1623 if( bFlag != pTmp->DontExpand() && !pTmp->IsLockExpandFlag()
1624 && *pEnd > pTmp->GetStart())
1625 {
1626 bRet = true;
1627 m_pSwpHints->NoteInHistory( pTmp );
1628 pTmp->SetDontExpand( bFlag );
1629 }
1630 }
1631 }
1632 return bRet;
1633}
1634
1635static bool lcl_GetTextAttrDefault(sal_Int32 nIndex, sal_Int32 nHintStart, sal_Int32 nHintEnd)
1636{
1637 return ((nHintStart <= nIndex) && (nIndex < nHintEnd));
1638}
1639static bool lcl_GetTextAttrExpand(sal_Int32 nIndex, sal_Int32 nHintStart, sal_Int32 nHintEnd)
1640{
1641 return ((nHintStart < nIndex) && (nIndex <= nHintEnd));
1642}
1643static bool lcl_GetTextAttrParent(sal_Int32 nIndex, sal_Int32 nHintStart, sal_Int32 nHintEnd)
1644{
1645 return ((nHintStart < nIndex) && (nIndex < nHintEnd));
1646}
1647
1648static void
1649lcl_GetTextAttrs(
1650 std::vector<SwTextAttr *> *const pVector,
1651 SwTextAttr **const ppTextAttr,
1652 SwpHints const *const pSwpHints,
1653 sal_Int32 const nIndex, sal_uInt16 const nWhich,
1654 enum SwTextNode::GetTextAttrMode const eMode)
1655{
1656 assert(nWhich >= RES_TXTATR_BEGIN && nWhich < RES_TXTATR_END)(static_cast <bool> (nWhich >= RES_TXTATR_BEGIN &&
nWhich < RES_TXTATR_END) ? void (0) : __assert_fail ("nWhich >= RES_TXTATR_BEGIN && nWhich < RES_TXTATR_END"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1656, __extension__ __PRETTY_FUNCTION__))
;
1657 if (!pSwpHints)
1658 return;
1659 size_t const nSize = pSwpHints->Count();
1660 sal_Int32 nPreviousIndex(0); // index of last hint with nWhich
1661 bool (*pMatchFunc)(sal_Int32, sal_Int32, sal_Int32)=nullptr;
1662 switch (eMode)
1663 {
1664 case SwTextNode::DEFAULT: pMatchFunc = &lcl_GetTextAttrDefault; break;
1665 case SwTextNode::EXPAND: pMatchFunc = &lcl_GetTextAttrExpand; break;
1666 case SwTextNode::PARENT: pMatchFunc = &lcl_GetTextAttrParent; break;
1667 default: assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1667, __extension__ __PRETTY_FUNCTION__))
;
1668 }
1669
1670 for( size_t i = pSwpHints->GetFirstPosSortedByWhichAndStart(nWhich); i < nSize; ++i )
1671 {
1672 SwTextAttr *const pHint = pSwpHints->GetSortedByWhichAndStart(i);
1673 if (pHint->Which() != nWhich)
1674 break; // hints are sorted by which&start, so we are done...
1675
1676 sal_Int32 const nHintStart = pHint->GetStart();
1677 if (nIndex < nHintStart)
1678 break; // hints are sorted by which&start, so we are done...
1679
1680 sal_Int32 const*const pEndIdx = pHint->GetEnd();
1681 // cannot have hint with no end and no dummy char
1682 assert(pEndIdx || pHint->HasDummyChar())(static_cast <bool> (pEndIdx || pHint->HasDummyChar(
)) ? void (0) : __assert_fail ("pEndIdx || pHint->HasDummyChar()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1682, __extension__ __PRETTY_FUNCTION__))
;
1683 // If EXPAND is set, simulate the text input behavior, i.e.
1684 // move the start, and expand the end.
1685 bool const bContained( pEndIdx
1686 ? (*pMatchFunc)(nIndex, nHintStart, *pEndIdx)
1687 : (nHintStart == nIndex) );
1688 if (bContained)
1689 {
1690 if (pVector)
1691 {
1692 if (nPreviousIndex < nHintStart)
1693 {
1694 pVector->clear(); // clear hints that are outside pHint
1695 nPreviousIndex = nHintStart;
1696 }
1697 pVector->push_back(pHint);
1698 }
1699 else
1700 {
1701 *ppTextAttr = pHint; // and possibly overwrite outer hint
1702 }
1703 if (!pEndIdx)
1704 {
1705 break;
1706 }
1707 }
1708 }
1709}
1710
1711std::vector<SwTextAttr *>
1712SwTextNode::GetTextAttrsAt(sal_Int32 const nIndex, sal_uInt16 const nWhich) const
1713{
1714 assert(nWhich >= RES_TXTATR_BEGIN && nWhich < RES_TXTATR_END)(static_cast <bool> (nWhich >= RES_TXTATR_BEGIN &&
nWhich < RES_TXTATR_END) ? void (0) : __assert_fail ("nWhich >= RES_TXTATR_BEGIN && nWhich < RES_TXTATR_END"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1714, __extension__ __PRETTY_FUNCTION__))
;
1715 std::vector<SwTextAttr *> ret;
1716 lcl_GetTextAttrs(&ret, nullptr, m_pSwpHints.get(), nIndex, nWhich, DEFAULT);
1717 return ret;
1718}
1719
1720SwTextAttr *
1721SwTextNode::GetTextAttrAt(sal_Int32 const nIndex, sal_uInt16 const nWhich,
1722 enum GetTextAttrMode const eMode) const
1723{
1724 assert( (nWhich == RES_TXTATR_META)(static_cast <bool> ((nWhich == RES_TXTATR_META) || (nWhich
== RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) ||
(nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY
) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD
)) ? void (0) : __assert_fail ("(nWhich == RES_TXTATR_META) || (nWhich == RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) || (nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD )"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1730, __extension__ __PRETTY_FUNCTION__))
1725 || (nWhich == RES_TXTATR_METAFIELD)(static_cast <bool> ((nWhich == RES_TXTATR_META) || (nWhich
== RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) ||
(nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY
) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD
)) ? void (0) : __assert_fail ("(nWhich == RES_TXTATR_META) || (nWhich == RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) || (nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD )"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1730, __extension__ __PRETTY_FUNCTION__))
1726 || (nWhich == RES_TXTATR_AUTOFMT)(static_cast <bool> ((nWhich == RES_TXTATR_META) || (nWhich
== RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) ||
(nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY
) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD
)) ? void (0) : __assert_fail ("(nWhich == RES_TXTATR_META) || (nWhich == RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) || (nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD )"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1730, __extension__ __PRETTY_FUNCTION__))
1727 || (nWhich == RES_TXTATR_INETFMT)(static_cast <bool> ((nWhich == RES_TXTATR_META) || (nWhich
== RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) ||
(nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY
) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD
)) ? void (0) : __assert_fail ("(nWhich == RES_TXTATR_META) || (nWhich == RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) || (nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD )"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1730, __extension__ __PRETTY_FUNCTION__))
1728 || (nWhich == RES_TXTATR_CJK_RUBY)(static_cast <bool> ((nWhich == RES_TXTATR_META) || (nWhich
== RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) ||
(nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY
) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD
)) ? void (0) : __assert_fail ("(nWhich == RES_TXTATR_META) || (nWhich == RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) || (nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD )"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1730, __extension__ __PRETTY_FUNCTION__))
1729 || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER)(static_cast <bool> ((nWhich == RES_TXTATR_META) || (nWhich
== RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) ||
(nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY
) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD
)) ? void (0) : __assert_fail ("(nWhich == RES_TXTATR_META) || (nWhich == RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) || (nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD )"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1730, __extension__ __PRETTY_FUNCTION__))
1730 || (nWhich == RES_TXTATR_INPUTFIELD ) )(static_cast <bool> ((nWhich == RES_TXTATR_META) || (nWhich
== RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) ||
(nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY
) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD
)) ? void (0) : __assert_fail ("(nWhich == RES_TXTATR_META) || (nWhich == RES_TXTATR_METAFIELD) || (nWhich == RES_TXTATR_AUTOFMT) || (nWhich == RES_TXTATR_INETFMT) || (nWhich == RES_TXTATR_CJK_RUBY) || (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) || (nWhich == RES_TXTATR_INPUTFIELD )"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1730, __extension__ __PRETTY_FUNCTION__))
;
1731 // "GetTextAttrAt() will give wrong result for this hint!")
1732
1733 SwTextAttr * pRet(nullptr);
1734 lcl_GetTextAttrs(nullptr, & pRet, m_pSwpHints.get(), nIndex, nWhich, eMode);
1735 return pRet;
1736}
1737
1738const SwTextInputField* SwTextNode::GetOverlappingInputField( const SwTextAttr& rTextAttr ) const
1739{
1740 const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt( rTextAttr.GetStart(), RES_TXTATR_INPUTFIELD, PARENT ));
1741
1742 if ( pTextInputField == nullptr && rTextAttr.End() != nullptr )
1743 {
1744 pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt( *(rTextAttr.End()), RES_TXTATR_INPUTFIELD, PARENT ));
1745 }
1746
1747 return pTextInputField;
1748}
1749
1750void SwTextNode::DelFrames_TextNodePart()
1751{
1752 SetWrong( nullptr );
1753 SetWrongDirty(WrongState::TODO);
1754
1755 SetGrammarCheck( nullptr );
1756 SetGrammarCheckDirty( true );
1757
1758 SetSmartTags( nullptr );
1759 SetSmartTagDirty( true );
1760
1761 SetWordCountDirty( true );
1762 SetAutoCompleteWordDirty( true );
1763}
1764
1765SwTextField* SwTextNode::GetFieldTextAttrAt(
1766 const sal_Int32 nIndex,
1767 const bool bIncludeInputFieldAtStart ) const
1768{
1769 SwTextField* pTextField = dynamic_cast<SwTextField*>(GetTextAttrForCharAt( nIndex, RES_TXTATR_FIELD ));
1770 if ( pTextField == nullptr )
1771 {
1772 pTextField = dynamic_cast<SwTextField*>(GetTextAttrForCharAt( nIndex, RES_TXTATR_ANNOTATION ));
1773 }
1774 if ( pTextField == nullptr )
1775 {
1776 pTextField =
1777 dynamic_cast<SwTextField*>( GetTextAttrAt(
1778 nIndex,
1779 RES_TXTATR_INPUTFIELD,
1780 bIncludeInputFieldAtStart ? DEFAULT : EXPAND ));
1781 }
1782
1783 return pTextField;
1784}
1785
1786static SwCharFormat* lcl_FindCharFormat( const SwCharFormats* pCharFormats, const OUString& rName )
1787{
1788 if( !rName.isEmpty() )
1789 {
1790 const size_t nArrLen = pCharFormats->size();
1791 for( size_t i = 1; i < nArrLen; i++ )
1792 {
1793 SwCharFormat* pFormat = (*pCharFormats)[ i ];
1794 if( pFormat->GetName()==rName )
1795 return pFormat;
1796 }
1797 }
1798 return nullptr;
1799}
1800
1801static void lcl_CopyHint(
1802 const sal_uInt16 nWhich,
1803 const SwTextAttr * const pHt,
1804 SwTextAttr *const pNewHt,
1805 SwDoc *const pOtherDoc,
1806 SwTextNode *const pDest )
1807{
1808 assert(nWhich == pHt->Which())(static_cast <bool> (nWhich == pHt->Which()) ? void (
0) : __assert_fail ("nWhich == pHt->Which()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1808, __extension__ __PRETTY_FUNCTION__))
; // wrong hint-id
1809 switch( nWhich )
1810 {
1811 // copy nodesarray section with footnote content
1812 case RES_TXTATR_FTN :
1813 assert(pDest)(static_cast <bool> (pDest) ? void (0) : __assert_fail (
"pDest", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 1813, __extension__ __PRETTY_FUNCTION__))
; // "lcl_CopyHint: no destination text node?"
1814 static_cast<const SwTextFootnote*>(pHt)->CopyFootnote( *static_cast<SwTextFootnote*>(pNewHt), *pDest);
1815 break;
1816
1817 // Fields that are copied into different SwDocs must be registered
1818 // at their new FieldTypes.
1819
1820 case RES_TXTATR_FIELD :
1821 {
1822 if( pOtherDoc != nullptr )
1823 {
1824 static_txtattr_cast<const SwTextField*>(pHt)->CopyTextField(
1825 static_txtattr_cast<SwTextField*>(pNewHt));
1826 }
1827
1828 // Table Formula must be copied relative.
1829 const SwFormatField& rField = pHt->GetFormatField();
1830 if( SwFieldIds::Table == rField.GetField()->GetTyp()->Which()
1831 && static_cast<const SwTableField*>(rField.GetField())->IsIntrnlName())
1832 {
1833 // convert internal formula to external
1834 const SwTableNode* const pDstTableNd =
1835 static_txtattr_cast<const SwTextField*>(pHt)->GetTextNode().FindTableNode();
1836 if( pDstTableNd )
1837 {
1838 SwTableField* const pTableField =
1839 const_cast<SwTableField*>(static_cast<const SwTableField*>(
1840 pNewHt->GetFormatField().GetField()));
1841 pTableField->PtrToBoxNm( &pDstTableNd->GetTable() );
1842 }
1843 }
1844 }
1845 break;
1846
1847 case RES_TXTATR_INPUTFIELD :
1848 case RES_TXTATR_ANNOTATION :
1849 if( pOtherDoc != nullptr )
1850 {
1851 static_txtattr_cast<const SwTextField*>(pHt)->CopyTextField(
1852 static_txtattr_cast<SwTextField*>(pNewHt));
1853 }
1854 break;
1855
1856 case RES_TXTATR_TOXMARK :
1857 if( pOtherDoc && pDest && pDest->GetpSwpHints()
1858 && pDest->GetpSwpHints()->Contains( pNewHt ) )
1859 {
1860 // ToXMarks that are copied to different SwDocs must register
1861 // at their new ToX (SwModify).
1862 static_txtattr_cast<SwTextTOXMark*>(pNewHt)->CopyTOXMark(*pOtherDoc);
1863 }
1864 break;
1865
1866 case RES_TXTATR_CHARFMT :
1867 // For CharacterStyles, the format must be copied too.
1868 if( pDest && pDest->GetpSwpHints()
1869 && pDest->GetpSwpHints()->Contains( pNewHt ) )
1870 {
1871 SwCharFormat* pFormat = pHt->GetCharFormat().GetCharFormat();
1872
1873 if (pOtherDoc)
1874 {
1875 pFormat = pOtherDoc->CopyCharFormat( *pFormat );
1876 }
1877 const_cast<SwFormatCharFormat&>(
1878 pNewHt->GetCharFormat() ).SetCharFormat( pFormat );
1879 }
1880 break;
1881 case RES_TXTATR_INETFMT :
1882 {
1883 // For Hyperlinks, the format must be copied too.
1884 if( pOtherDoc && pDest && pDest->GetpSwpHints()
1885 && pDest->GetpSwpHints()->Contains( pNewHt ) )
1886 {
1887 const SwDoc& rDoc = static_txtattr_cast<
1888 const SwTextINetFormat*>(pHt)->GetTextNode().GetDoc();
1889 const SwCharFormats* pCharFormats = rDoc.GetCharFormats();
1890 const SwFormatINetFormat& rFormat = pHt->GetINetFormat();
1891 SwCharFormat* pFormat;
1892 pFormat = lcl_FindCharFormat( pCharFormats, rFormat.GetINetFormat() );
1893 if( pFormat )
1894 pOtherDoc->CopyCharFormat( *pFormat );
1895 pFormat = lcl_FindCharFormat( pCharFormats, rFormat.GetVisitedFormat() );
1896 if( pFormat )
1897 pOtherDoc->CopyCharFormat( *pFormat );
1898 }
1899 //JP 24.04.98: The attribute must point to a text node, so that
1900 // the styles can be created.
1901 SwTextINetFormat *const pINetHt = static_txtattr_cast<SwTextINetFormat*>(pNewHt);
1902 if ( !pINetHt->GetpTextNode() )
1903 {
1904 pINetHt->ChgTextNode( pDest );
1905 }
1906
1907 //JP 22.10.97: set up link to char style
1908 pINetHt->GetCharFormat();
1909 break;
1910 }
1911 case RES_TXTATR_META:
1912 case RES_TXTATR_METAFIELD:
1913 OSL_ENSURE( pNewHt, "copying Meta should not fail!" )do { if (true && (!(pNewHt))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "1913" ": "), "%s", "copying Meta should not fail!"); } }
while (false)
;
1914 OSL_ENSURE( pDestdo { if (true && (!(pDest && (u'\xFFF9' == pDest
->GetText()[pNewHt->GetStart()])))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "1916" ": "), "%s", "missing CH_TXTATR?"); } } while (false
)
1915 && (CH_TXTATR_INWORD == pDest->GetText()[pNewHt->GetStart()]),do { if (true && (!(pDest && (u'\xFFF9' == pDest
->GetText()[pNewHt->GetStart()])))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "1916" ": "), "%s", "missing CH_TXTATR?"); } } while (false
)
1916 "missing CH_TXTATR?")do { if (true && (!(pDest && (u'\xFFF9' == pDest
->GetText()[pNewHt->GetStart()])))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "1916" ": "), "%s", "missing CH_TXTATR?"); } } while (false
)
;
1917 break;
1918 }
1919}
1920
1921/// copy attributes at position nTextStartIdx to node pDest
1922// BP 7.6.93: Intentionally copy only attributes _with_ EndIdx!
1923// CopyAttr is usually called when attributes are set on a
1924// node with no text.
1925void SwTextNode::CopyAttr( SwTextNode *pDest, const sal_Int32 nTextStartIdx,
1926 const sal_Int32 nOldPos )
1927{
1928 if ( HasHints() )
1929 {
1930 SwDoc* const pOtherDoc = (&pDest->GetDoc() != &GetDoc()) ?
1931 &pDest->GetDoc() : nullptr;
1932
1933 for ( size_t i = 0; i < m_pSwpHints->Count(); ++i )
1934 {
1935 SwTextAttr *const pHt = m_pSwpHints->Get(i);
1936 sal_Int32 const nAttrStartIdx = pHt->GetStart();
1937 if ( nTextStartIdx < nAttrStartIdx )
1938 break; // beyond end of text, because nLen == 0
1939
1940 const sal_Int32 *const pEndIdx = pHt->GetEnd();
1941 if ( pEndIdx && !pHt->HasDummyChar() )
1942 {
1943 sal_uInt16 const nWhich = pHt->Which();
1944 if (RES_TXTATR_INPUTFIELD != nWhich // fdo#74981 skip fields
1945 && ( *pEndIdx > nTextStartIdx
1946 || (*pEndIdx == nTextStartIdx
1947 && nAttrStartIdx == nTextStartIdx)))
1948 {
1949 if ( RES_TXTATR_REFMARK != nWhich )
1950 {
1951 // attribute in the area => copy
1952 SwTextAttr *const pNewHt =
1953 pDest->InsertItem( pHt->GetAttr(), nOldPos, nOldPos, SetAttrMode::IS_COPY);
1954 if ( pNewHt )
1955 {
1956 lcl_CopyHint( nWhich, pHt, pNewHt,
1957 pOtherDoc, pDest );
1958 }
1959 }
1960 else if( !pOtherDoc
1961 ? GetDoc().IsCopyIsMove()
1962 : nullptr == pOtherDoc->GetRefMark( pHt->GetRefMark().GetRefName() ) )
1963 {
1964 pDest->InsertItem(
1965 pHt->GetAttr(), nOldPos, nOldPos, SetAttrMode::IS_COPY);
1966 }
1967 }
1968 }
1969 }
1970 }
1971
1972 if( this != pDest )
1973 {
1974 // notify layout frames, to prevent disappearance of footnote numbers
1975 SwUpdateAttr aHint(
1976 nOldPos,
1977 nOldPos,
1978 0);
1979
1980 pDest->ModifyNotification( nullptr, &aHint );
1981 }
1982}
1983
1984/// copy text and attributes to node pDest
1985void SwTextNode::CopyText( SwTextNode *const pDest,
1986 const SwIndex &rStart,
1987 const sal_Int32 nLen,
1988 const bool bForceCopyOfAllAttrs )
1989{
1990 SwIndex const aIdx( pDest, pDest->m_Text.getLength() );
1991 CopyText( pDest, aIdx, rStart, nLen, bForceCopyOfAllAttrs );
1992}
1993
1994void SwTextNode::CopyText( SwTextNode *const pDest,
1995 const SwIndex &rDestStart,
1996 const SwIndex &rStart,
1997 sal_Int32 nLen,
1998 const bool bForceCopyOfAllAttrs )
1999{
2000 CHECK_SWPHINTS_IF_FRM(this);
2001 CHECK_SWPHINTS(pDest);
2002 sal_Int32 nTextStartIdx = rStart.GetIndex();
2003 sal_Int32 nDestStart = rDestStart.GetIndex(); // remember old Pos
2004
2005 if (pDest->GetDoc().IsClipBoard() && GetNum())
2006 {
2007 // #i111677# cache expansion of source (for clipboard)
2008 pDest->m_pNumStringCache.reset( (nTextStartIdx != 0)
2009 ? new OUString // fdo#49076: numbering only if copy from para start
2010 : new OUString(GetNumString()));
2011 }
2012
2013 if( !nLen )
2014 {
2015 // if no length is given, copy attributes at position rStart
2016 CopyAttr( pDest, nTextStartIdx, nDestStart );
2017
2018 // copy hard attributes on whole paragraph
2019 if( HasSwAttrSet() )
2020 {
2021 // i#96213 all or just the Char attributes?
2022 if ( !bForceCopyOfAllAttrs &&
2023 ( nDestStart ||
2024 pDest->HasSwAttrSet() ||
2025 nLen != pDest->GetText().getLength()))
2026 {
2027 SfxItemSet aCharSet(
2028 pDest->GetDoc().GetAttrPool(),
2029 svl::Items<
2030 RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
2031 RES_TXTATR_INETFMT, RES_TXTATR_CHARFMT,
2032 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END - 1>{} );
2033 aCharSet.Put( *GetpSwAttrSet() );
2034 if( aCharSet.Count() )
2035 {
2036 pDest->SetAttr( aCharSet, nDestStart, nDestStart );
2037 }
2038 }
2039 else
2040 {
2041 GetpSwAttrSet()->CopyToModify( *pDest );
2042 }
2043 }
2044 return;
2045 }
2046
2047 // 1. copy text
2048 const sal_Int32 oldLen = pDest->m_Text.getLength();
2049 // JP 15.02.96: missing attribute handling at the end!
2050 // hence call InsertText and don't modify m_Text directly
2051 pDest->InsertText( m_Text.copy(nTextStartIdx, nLen), rDestStart,
2052 SwInsertFlags::EMPTYEXPAND );
2053
2054 // update with actual new size
2055 nLen = pDest->m_Text.getLength() - oldLen;
2056 if ( !nLen ) // string not longer?
2057 return;
2058
2059 SwDoc* const pOtherDoc = (&pDest->GetDoc() != &GetDoc()) ? &pDest->GetDoc() : nullptr;
2060
2061 // copy hard attributes on whole paragraph
2062 if( HasSwAttrSet() )
2063 {
2064 // i#96213 all or just the Char attributes?
2065 if ( !bForceCopyOfAllAttrs &&
2066 ( nDestStart ||
2067 pDest->HasSwAttrSet() ||
2068 nLen != pDest->GetText().getLength()))
2069 {
2070 SfxItemSet aCharSet(
2071 pDest->GetDoc().GetAttrPool(),
2072 svl::Items<
2073 RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
2074 RES_TXTATR_INETFMT, RES_TXTATR_CHARFMT,
2075 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END - 1>{});
2076 aCharSet.Put( *GetpSwAttrSet() );
2077 if( aCharSet.Count() )
2078 {
2079 pDest->SetAttr( aCharSet, nDestStart, nDestStart + nLen );
2080 }
2081 }
2082 else
2083 {
2084 GetpSwAttrSet()->CopyToModify( *pDest );
2085 }
2086 }
2087
2088 bool const bUndoNodes = !pOtherDoc
2089 && GetDoc().GetIDocumentUndoRedo().IsUndoNodes(GetNodes());
2090
2091 // Fetch end only now, because copying into self updates the start index
2092 // and all attributes
2093 nTextStartIdx = rStart.GetIndex();
2094 const sal_Int32 nEnd = nTextStartIdx + nLen;
2095
2096 // 2. copy attributes
2097 // Iterate over attribute array until the start of the attribute
2098 // is behind the copied range
2099 const size_t nSize = m_pSwpHints ? m_pSwpHints->Count() : 0;
2100
2101 // If copying into self, inserting can delete attributes!
2102 // Hence first copy into temp-array, and then move that into hints array.
2103 SwpHts aArr;
2104
2105 // Del-Array for all RefMarks without extent
2106 SwpHts aRefMrkArr;
2107
2108 std::vector<std::pair<sal_Int32, sal_Int32>> metaFieldRanges;
2109 sal_Int32 nDeletedDummyChars(0);
2110 for (size_t n = 0; n < nSize; ++n)
2111 {
2112 SwTextAttr * const pHt = m_pSwpHints->Get(n);
2113
2114 const sal_Int32 nAttrStartIdx = pHt->GetStart();
2115 if ( nAttrStartIdx >= nEnd )
2116 break;
2117
2118 const sal_Int32 * const pEndIdx = pHt->GetEnd();
2119 const sal_uInt16 nWhich = pHt->Which();
2120
2121 // JP 26.04.94: RefMarks are never copied. If the refmark doesn't have
2122 // an extent, there is a dummy char in the text, which
2123 // must be removed. So we first copy the attribute,
2124 // but remember it, and when we're done delete it,
2125 // which also deletes the dummy character!
2126 // JP 14.08.95: May RefMarks be moved?
2127 const bool bCopyRefMark = RES_TXTATR_REFMARK == nWhich
2128 && ( bUndoNodes
2129 || ( !pOtherDoc
2130 ? GetDoc().IsCopyIsMove()
2131 : nullptr == pOtherDoc->GetRefMark( pHt->GetRefMark().GetRefName() ) ) );
2132
2133 if ( pEndIdx
2134 && RES_TXTATR_REFMARK == nWhich
2135 && !bCopyRefMark )
2136 {
2137 continue;
2138 }
2139
2140 // Input Fields are only copied, if completely covered by copied text
2141 if ( nWhich == RES_TXTATR_INPUTFIELD )
2142 {
2143 assert(pEndIdx != nullptr &&(static_cast <bool> (pEndIdx != nullptr && "<SwTextNode::CopyText(..)> - RES_TXTATR_INPUTFIELD without EndIndex!"
) ? void (0) : __assert_fail ("pEndIdx != nullptr && \"<SwTextNode::CopyText(..)> - RES_TXTATR_INPUTFIELD without EndIndex!\""
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2144, __extension__ __PRETTY_FUNCTION__))
2144 "<SwTextNode::CopyText(..)> - RES_TXTATR_INPUTFIELD without EndIndex!" )(static_cast <bool> (pEndIdx != nullptr && "<SwTextNode::CopyText(..)> - RES_TXTATR_INPUTFIELD without EndIndex!"
) ? void (0) : __assert_fail ("pEndIdx != nullptr && \"<SwTextNode::CopyText(..)> - RES_TXTATR_INPUTFIELD without EndIndex!\""
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2144, __extension__ __PRETTY_FUNCTION__))
;
2145 if ( nAttrStartIdx < nTextStartIdx
2146 || ( pEndIdx != nullptr
2147 && *pEndIdx > nEnd ) )
2148 {
2149 continue;
2150 }
2151 }
2152
2153 if (nWhich == RES_TXTATR_METAFIELD)
2154 {
2155 // Skip metadata fields. Also remember the range to strip the text later.
2156 metaFieldRanges.emplace_back(nAttrStartIdx, pEndIdx ? *pEndIdx : nEnd);
2157 continue;
2158 }
2159
2160 sal_Int32 nAttrStt = 0;
2161 sal_Int32 nAttrEnd = 0;
2162
2163 if( nAttrStartIdx < nTextStartIdx )
2164 {
2165 // start is before selection
2166 // copy hints with end and CH_TXTATR only if dummy char is copied
2167 if ( pEndIdx && (*pEndIdx > nTextStartIdx) && !pHt->HasDummyChar() )
2168 {
2169 // attribute with extent and the end is in the selection
2170 nAttrStt = nDestStart;
2171 nAttrEnd = (*pEndIdx > nEnd)
2172 ? rDestStart.GetIndex()
2173 : nDestStart + (*pEndIdx) - nTextStartIdx;
2174 }
2175 else
2176 {
2177 continue;
2178 }
2179 }
2180 else
2181 {
2182 // start is in the selection
2183 nAttrStt = nDestStart + ( nAttrStartIdx - nTextStartIdx );
2184 if( pEndIdx )
2185 {
2186 nAttrEnd = *pEndIdx > nEnd
2187 ? rDestStart.GetIndex()
2188 : nDestStart + ( *pEndIdx - nTextStartIdx );
2189 }
2190 else
2191 {
2192 nAttrEnd = nAttrStt;
2193 }
2194 }
2195
2196 SwTextAttr * pNewHt = nullptr;
2197
2198 if( pDest == this )
2199 {
2200 // copy the hint here, but insert it later
2201 pNewHt = MakeTextAttr( GetDoc(), pHt->GetAttr(),
2202 nAttrStt, nAttrEnd, CopyOrNewType::Copy, pDest );
2203
2204 lcl_CopyHint(nWhich, pHt, pNewHt, nullptr, pDest);
2205 aArr.push_back( pNewHt );
2206 }
2207 else
2208 {
2209 pNewHt = pDest->InsertItem(
2210 pHt->GetAttr(),
2211 nAttrStt - nDeletedDummyChars,
2212 nAttrEnd - nDeletedDummyChars,
2213 SetAttrMode::NOTXTATRCHR | SetAttrMode::IS_COPY);
2214 if (pNewHt)
2215 {
2216 lcl_CopyHint( nWhich, pHt, pNewHt, pOtherDoc, pDest );
2217 }
2218 else if (pHt->HasDummyChar())
2219 {
2220 // The attribute that has failed to be copied would insert
2221 // dummy char, so positions of the following attributes have
2222 // to be shifted by one to compensate for that missing char.
2223 ++nDeletedDummyChars;
2224 }
2225 }
2226
2227 if( RES_TXTATR_REFMARK == nWhich && !pEndIdx && !bCopyRefMark )
2228 {
2229 aRefMrkArr.push_back( pNewHt );
2230 }
2231 }
2232
2233 // Strip the metadata fields, since we don't copy the RDF entries
2234 // yet and so they are inconsistent upon copy/pasting.
2235 if (!metaFieldRanges.empty())
2236 {
2237 // Reverse to remove without messing the offsets.
2238 std::reverse(metaFieldRanges.begin(), metaFieldRanges.end());
2239 for (const auto& pair : metaFieldRanges)
2240 {
2241 const SwIndex aIdx(pDest, pair.first);
2242 pDest->EraseText(aIdx, pair.second - pair.first);
2243 }
2244 }
2245
2246 // this can only happen when copying into self
2247 for (SwTextAttr* i : aArr)
2248 {
2249 InsertHint( i, SetAttrMode::NOTXTATRCHR );
2250 }
2251
2252 if( pDest->GetpSwpHints() )
2253 {
2254 for (SwTextAttr* pNewHt : aRefMrkArr)
2255 {
2256 if( pNewHt->GetEnd() )
2257 {
2258 pDest->GetpSwpHints()->Delete( pNewHt );
2259 pDest->DestroyAttr( pNewHt );
2260 }
2261 else
2262 {
2263 const SwIndex aIdx( pDest, pNewHt->GetStart() );
2264 pDest->EraseText( aIdx, 1 );
2265 }
2266 }
2267 }
2268
2269 CHECK_SWPHINTS_IF_FRM(this);
2270 CHECK_SWPHINTS(pDest);
2271}
2272
2273OUString SwTextNode::InsertText( const OUString & rStr, const SwIndex & rIdx,
2274 const SwInsertFlags nMode )
2275{
2276 assert(rIdx <= m_Text.getLength())(static_cast <bool> (rIdx <= m_Text.getLength()) ? void
(0) : __assert_fail ("rIdx <= m_Text.getLength()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2276, __extension__ __PRETTY_FUNCTION__))
; // invalid index
2277
2278 const sal_Int32 aPos = rIdx.GetIndex();
2279 sal_Int32 nLen = m_Text.getLength() - aPos;
2280 sal_Int32 const nOverflow(rStr.getLength() - GetSpaceLeft());
2281 SAL_WARN_IF(nOverflow > 0, "sw.core",do { if (true && (nOverflow > 0)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "SwTextNode::InsertText: node text with insertion > capacity."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2282" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::InsertText: node text with insertion > capacity."
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::InsertText: node text with insertion > capacity."
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2282" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SwTextNode::InsertText: node text with insertion > capacity."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2282" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::InsertText: node text with insertion > capacity."
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::InsertText: node text with insertion > capacity."
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2282" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
2282 "SwTextNode::InsertText: node text with insertion > capacity.")do { if (true && (nOverflow > 0)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "SwTextNode::InsertText: node text with insertion > capacity."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2282" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::InsertText: node text with insertion > capacity."
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::InsertText: node text with insertion > capacity."
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2282" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SwTextNode::InsertText: node text with insertion > capacity."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2282" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::InsertText: node text with insertion > capacity."
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::InsertText: node text with insertion > capacity."
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2282" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2283 OUString const sInserted(
2284 (nOverflow > 0) ? rStr.copy(0, rStr.getLength() - nOverflow) : rStr);
2285 if (sInserted.isEmpty())
2286 {
2287 return sInserted;
2288 }
2289 m_Text = m_Text.replaceAt(aPos, 0, sInserted);
2290 assert(GetSpaceLeft()>=0)(static_cast <bool> (GetSpaceLeft()>=0) ? void (0) :
__assert_fail ("GetSpaceLeft()>=0", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2290, __extension__ __PRETTY_FUNCTION__))
;
2291 nLen = m_Text.getLength() - aPos - nLen;
2292 assert(nLen != 0)(static_cast <bool> (nLen != 0) ? void (0) : __assert_fail
("nLen != 0", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2292, __extension__ __PRETTY_FUNCTION__))
;
2293
2294 bool bOldExpFlg = IsIgnoreDontExpand();
2295 if (nMode & SwInsertFlags::FORCEHINTEXPAND)
2296 {
2297 SetIgnoreDontExpand( true );
2298 }
2299
2300 Update( rIdx, nLen ); // text content changed!
2301
2302 if (nMode & SwInsertFlags::FORCEHINTEXPAND)
2303 {
2304 SetIgnoreDontExpand( bOldExpFlg );
2305 }
2306
2307 if ( HasWriterListeners() )
2308 { // send this before messing with hints, which will send RES_UPDATE_ATTR
2309 SwInsText aHint( aPos, nLen );
2310 NotifyClients( nullptr, &aHint );
2311 }
2312
2313 if ( HasHints() )
2314 {
2315 m_pSwpHints->SortIfNeedBe();
2316 bool const bHadHints(!m_pSwpHints->CanBeDeleted());
2317 bool bMergePortionsNeeded(false);
2318 for ( size_t i = 0; i < m_pSwpHints->Count() &&
2319 rIdx >= m_pSwpHints->GetWithoutResorting(i)->GetStart(); ++i )
2320 {
2321 SwTextAttr * const pHt = m_pSwpHints->GetWithoutResorting( i );
2322 const sal_Int32 * const pEndIdx = pHt->GetEnd();
2323 if( !pEndIdx )
2324 continue;
2325
2326 if( rIdx == *pEndIdx )
2327 {
2328 if ( (nMode & SwInsertFlags::NOHINTEXPAND) ||
2329 (!(nMode & SwInsertFlags::FORCEHINTEXPAND)
2330 && pHt->DontExpand()) )
2331 {
2332 m_pSwpHints->DeleteAtPos(i);
2333 // on empty attributes also adjust Start
2334 if( rIdx == pHt->GetStart() )
2335 pHt->SetStart( pHt->GetStart() - nLen );
2336 pHt->SetEnd(*pEndIdx - nLen);
2337 // could be that pHt has IsFormatIgnoreEnd set, and it's
2338 // not a RSID-only hint - now we have the inserted text
2339 // between pHt and its continuation... which we don't know.
2340 // punt the job to MergePortions below.
2341 if (pHt->IsFormatIgnoreEnd())
2342 {
2343 bMergePortionsNeeded = true;
2344 }
2345 InsertHint( pHt, SetAttrMode::NOHINTADJUST );
2346 }
2347 // empty hints at insert position?
2348 else if ( (nMode & SwInsertFlags::EMPTYEXPAND)
2349 && (*pEndIdx == pHt->GetStart()) )
2350 {
2351 m_pSwpHints->DeleteAtPos(i);
2352 pHt->SetStart( pHt->GetStart() - nLen );
2353 const size_t nCurrentLen = m_pSwpHints->Count();
2354 InsertHint( pHt/* AUTOSTYLES:, SetAttrMode::NOHINTADJUST*/ );
2355 if ( nCurrentLen > m_pSwpHints->Count() && i )
2356 {
2357 --i;
2358 }
2359 continue;
2360 }
2361 else
2362 {
2363 continue;
2364 }
2365 }
2366 if ( !(nMode & SwInsertFlags::NOHINTEXPAND) &&
2367 rIdx == nLen && pHt->GetStart() == rIdx.GetIndex() &&
2368 !pHt->IsDontExpandStartAttr() )
2369 {
2370 // no field, at paragraph start, HintExpand
2371 m_pSwpHints->DeleteAtPos(i);
2372 pHt->SetStart( pHt->GetStart() - nLen );
2373 // no effect on format ignore flags here (para start)
2374 InsertHint( pHt, SetAttrMode::NOHINTADJUST );
2375 }
2376 }
2377 if (bMergePortionsNeeded)
2378 {
2379 m_pSwpHints->MergePortions(*this);
2380 }
2381 SAL_WARN_IF(bHadHints && m_pSwpHints->CanBeDeleted(), "sw.core",do { if (true && (bHadHints && m_pSwpHints->
CanBeDeleted())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "SwTextNode::InsertText: unexpected loss of hints"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2382" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::InsertText: unexpected loss of hints"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::InsertText: unexpected loss of hints";
::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2382" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SwTextNode::InsertText: unexpected loss of hints"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2382" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::InsertText: unexpected loss of hints"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::InsertText: unexpected loss of hints";
::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2382" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
2382 "SwTextNode::InsertText: unexpected loss of hints")do { if (true && (bHadHints && m_pSwpHints->
CanBeDeleted())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "SwTextNode::InsertText: unexpected loss of hints"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2382" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::InsertText: unexpected loss of hints"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::InsertText: unexpected loss of hints";
::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2382" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SwTextNode::InsertText: unexpected loss of hints"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2382" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::InsertText: unexpected loss of hints"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::InsertText: unexpected loss of hints";
::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2382" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2383 }
2384
2385 // By inserting a character, the hidden flags
2386 // at the TextNode can become invalid:
2387 SetCalcHiddenCharFlags();
2388
2389 CHECK_SWPHINTS(this);
2390 return sInserted;
2391}
2392
2393void SwTextNode::CutText( SwTextNode * const pDest,
2394 const SwIndex & rStart, const sal_Int32 nLen )
2395{
2396 assert(pDest)(static_cast <bool> (pDest) ? void (0) : __assert_fail (
"pDest", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2396, __extension__ __PRETTY_FUNCTION__))
; // Cut requires a destination
2397 SwIndex aDestStt(pDest, pDest->GetText().getLength());
2398 CutImpl( pDest, aDestStt, rStart, nLen, false );
2399}
2400
2401void SwTextNode::CutImpl( SwTextNode * const pDest, const SwIndex & rDestStart,
2402 const SwIndex & rStart, sal_Int32 nLen, const bool bUpdate )
2403{
2404 assert(pDest)(static_cast <bool> (pDest) ? void (0) : __assert_fail (
"pDest", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2404, __extension__ __PRETTY_FUNCTION__))
; // Cut requires a destination
2405
2406 assert(&GetDoc() == &pDest->GetDoc())(static_cast <bool> (&GetDoc() == &pDest->GetDoc
()) ? void (0) : __assert_fail ("&GetDoc() == &pDest->GetDoc()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2406, __extension__ __PRETTY_FUNCTION__))
; // must be same document
2407
2408 assert(pDest != this)(static_cast <bool> (pDest != this) ? void (0) : __assert_fail
("pDest != this", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2408, __extension__ __PRETTY_FUNCTION__))
; // destination must be different node
2409
2410 if( !nLen )
2411 {
2412 // if no length is given, copy attributes at position rStart
2413 CopyAttr( pDest, rStart.GetIndex(), rDestStart.GetIndex() );
2414 return;
2415 }
2416
2417 sal_Int32 nTextStartIdx = rStart.GetIndex();
2418 sal_Int32 nDestStart = rDestStart.GetIndex(); // remember old Pos
2419 const sal_Int32 nInitSize = pDest->m_Text.getLength();
2420
2421 if (pDest->GetSpaceLeft() < nLen)
2422 { // FIXME: could only happen when called from SwRangeRedline::Show.
2423 // unfortunately can't really do anything here to handle that...
2424 abort();
2425 }
2426 pDest->m_Text = pDest->m_Text.replaceAt(nDestStart, 0,
2427 m_Text.copy(nTextStartIdx, nLen));
2428 OUString const newText = m_Text.replaceAt(nTextStartIdx, nLen, "");
2429 nLen = pDest->m_Text.getLength() - nInitSize; // update w/ current size!
2430 if (!nLen) // String didn't grow?
2431 return;
2432
2433 if (bUpdate)
2434 {
2435 // Update all SwIndex
2436 pDest->Update( rDestStart, nLen, false, false/*??? why was it true*/);
2437 }
2438
2439 CHECK_SWPHINTS(pDest);
2440
2441 const sal_Int32 nEnd = rStart.GetIndex() + nLen;
2442 bool const bUndoNodes =
2443 GetDoc().GetIDocumentUndoRedo().IsUndoNodes(GetNodes());
2444
2445 // copy hard attributes on whole paragraph
2446 if (HasSwAttrSet())
2447 {
2448 bool hasSwAttrSet = pDest->HasSwAttrSet();
2449 if (hasSwAttrSet)
2450 {
2451 // if we have our own property set it doesn't mean
2452 // that this set defines any style different to Standard one.
2453 hasSwAttrSet = false;
2454
2455 // so, let's check deeper if property set has defined any property
2456 if (pDest->GetpSwAttrSet())
2457 {
2458 // check all items in the property set
2459 SfxItemIter aIter( *pDest->GetpSwAttrSet() );
2460 const SfxPoolItem* pItem = aIter.GetCurItem();
2461 do
2462 {
2463 // check current item
2464 sal_uInt16 nWhich = IsInvalidItem( pItem )
2465 ? pDest->GetpSwAttrSet()->GetWhichByPos( aIter.GetCurPos() )
2466 : pItem->Which();
2467 if( RES_FRMATR_STYLE_NAME != nWhich &&
2468 RES_FRMATR_CONDITIONAL_STYLE_NAME != nWhich &&
2469 SfxItemState::SET == pDest->GetpSwAttrSet()->GetItemState( nWhich, false ) )
2470 {
2471 // check if parent value (original value in style) has the same value as in [pItem]
2472 const SfxPoolItem& rParentItem = pDest->GetpSwAttrSet()->GetParent()->Get( nWhich, true );
2473
2474 hasSwAttrSet = (rParentItem != *pItem);
2475
2476 // property set is not empty => no need to make anymore checks
2477 if (hasSwAttrSet)
2478 break;
2479 }
2480
2481 // let's check next item
2482 pItem = aIter.NextItem();
2483 } while (pItem);
2484 }
2485 }
2486
2487 // all or just the Char attributes?
2488 if( nInitSize || hasSwAttrSet ||
2489 nLen != pDest->GetText().getLength())
2490 {
2491 SfxItemSet aCharSet(
2492 pDest->GetDoc().GetAttrPool(),
2493 svl::Items<
2494 RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
2495 RES_TXTATR_INETFMT, RES_TXTATR_CHARFMT,
2496 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END - 1>{});
2497 aCharSet.Put( *GetpSwAttrSet() );
2498 if( aCharSet.Count() )
2499 pDest->SetAttr( aCharSet, nDestStart, nDestStart + nLen );
2500 }
2501 else
2502 {
2503 GetpSwAttrSet()->CopyToModify( *pDest );
2504 }
2505 }
2506
2507 // notify frames - before moving hints, because footnotes
2508 // want to find their anchor text frame in the follow chain
2509 SwInsText aInsHint( nDestStart, nLen );
2510 pDest->ModifyNotification( nullptr, &aInsHint );
2511 sw::MoveText const moveHint(pDest, nDestStart, nTextStartIdx, nLen);
2512 CallSwClientNotify(moveHint);
2513 SwDelText aDelHint( nTextStartIdx, nLen );
2514 ModifyNotification( nullptr, &aDelHint );
2515
2516 // 2. move attributes
2517 // Iterate over attribute array until the start of the attribute
2518 // is behind the moved range
2519 bool bMergePortionsNeeded(false);
2520 size_t nAttrCnt = 0;
2521 while (m_pSwpHints && (nAttrCnt < m_pSwpHints->Count()))
2522 {
2523 SwTextAttr * const pHt = m_pSwpHints->Get(nAttrCnt);
2524 const sal_Int32 nAttrStartIdx = pHt->GetStart();
2525 if ( nAttrStartIdx >= nEnd )
2526 break;
2527 const sal_Int32 * const pEndIdx = pHt->GetEnd();
2528 const sal_uInt16 nWhich = pHt->Which();
2529 SwTextAttr *pNewHt = nullptr;
2530
2531 // if the hint has a dummy character, then it must not be split!
2532 if(nAttrStartIdx < nTextStartIdx)
2533 {
2534 // start is before the range
2535 if (!pHt->HasDummyChar() && ( RES_TXTATR_REFMARK != nWhich
2536 || bUndoNodes ) && pEndIdx && *pEndIdx > nTextStartIdx)
2537 {
2538 // attribute with extent and end of attribute is in the range
2539 pNewHt = MakeTextAttr( pDest->GetDoc(), pHt->GetAttr(),
2540 nDestStart,
2541 nDestStart + (
2542 *pEndIdx > nEnd
2543 ? nLen
2544 : *pEndIdx - nTextStartIdx ) );
2545 }
2546 }
2547 else
2548 {
2549 // start is inside the range
2550 if (!pEndIdx || *pEndIdx < nEnd ||
2551 (!bUndoNodes && RES_TXTATR_REFMARK == nWhich)
2552 || pHt->HasDummyChar() )
2553 {
2554 // do not delete note and later add it -> sidebar flickering
2555 if (GetDoc().GetDocShell())
2556 {
2557 GetDoc().GetDocShell()->Broadcast( SfxHint(SfxHintId::SwSplitNodeOperation));
2558 }
2559 // move attribute
2560 m_pSwpHints->Delete( pHt );
2561 // reset start/end indexes
2562 if (pHt->IsFormatIgnoreStart() || pHt->IsFormatIgnoreEnd())
2563 {
2564 bMergePortionsNeeded = true;
2565 }
2566 pHt->SetStart(nDestStart + (nAttrStartIdx - nTextStartIdx));
2567 if (pEndIdx)
2568 {
2569 pHt->SetEnd( nDestStart + (
2570 *pEndIdx > nEnd
2571 ? nLen
2572 : *pEndIdx - nTextStartIdx ) );
2573 }
2574 pDest->InsertHint( pHt,
2575 SetAttrMode::NOTXTATRCHR
2576 | SetAttrMode::DONTREPLACE );
2577 if (GetDoc().GetDocShell())
2578 {
2579 GetDoc().GetDocShell()->Broadcast( SfxHint(SfxHintId::SwSplitNodeOperation));
2580 }
2581 continue; // iterate while loop, no ++ !
2582 }
2583 // the end is behind the range
2584 else if (RES_TXTATR_REFMARK != nWhich || bUndoNodes)
2585 {
2586 pNewHt = MakeTextAttr( GetDoc(), pHt->GetAttr(),
2587 nDestStart + (nAttrStartIdx - nTextStartIdx),
2588 nDestStart + (*pEndIdx > nEnd
2589 ? nLen
2590 : *pEndIdx - nTextStartIdx));
2591 }
2592 }
2593 if (pNewHt)
2594 {
2595 const bool bSuccess( pDest->InsertHint( pNewHt,
2596 SetAttrMode::NOTXTATRCHR
2597 | SetAttrMode::DONTREPLACE
2598 | SetAttrMode::IS_COPY) );
2599 if (bSuccess)
2600 {
2601 lcl_CopyHint( nWhich, pHt, pNewHt, nullptr, pDest );
2602 }
2603 }
2604 ++nAttrCnt;
2605 }
2606 // If there are still empty attributes around, they have a higher priority
2607 // than any attributes that become empty due to the move.
2608 // So temporarily remove them and Update the array, then re-insert the
2609 // removed ones so they overwrite the others.
2610 if (m_pSwpHints && nAttrCnt < m_pSwpHints->Count())
2611 {
2612 SwpHts aArr;
2613 while (nAttrCnt < m_pSwpHints->Count())
2614 {
2615 SwTextAttr * const pHt = m_pSwpHints->Get(nAttrCnt);
2616 if (nEnd != pHt->GetStart())
2617 break;
2618 const sal_Int32 * const pEndIdx = pHt->GetEnd();
2619 if (pEndIdx && *pEndIdx == nEnd)
2620 {
2621 aArr.push_back( pHt );
2622 m_pSwpHints->Delete( pHt );
2623 }
2624 else
2625 {
2626 ++nAttrCnt;
2627 }
2628 }
2629 Update( rStart, nLen, true, true );
2630
2631 for (SwTextAttr* pHt : aArr)
2632 {
2633 pHt->SetStart( rStart.GetIndex() );
2634 pHt->SetEnd( rStart.GetIndex() );
2635 InsertHint( pHt );
2636 }
2637 }
2638 else
2639 {
2640 Update( rStart, nLen, true, true );
2641 }
2642
2643 // set after moving hints
2644 m_Text = newText;
2645
2646 if (bMergePortionsNeeded)
2647 {
2648 m_pSwpHints->MergePortions(*this);
2649 }
2650
2651 CHECK_SWPHINTS(this);
2652
2653 TryDeleteSwpHints();
2654}
2655
2656void SwTextNode::EraseText(const SwIndex &rIdx, const sal_Int32 nCount,
2657 const SwInsertFlags nMode )
2658{
2659 assert(rIdx <= m_Text.getLength())(static_cast <bool> (rIdx <= m_Text.getLength()) ? void
(0) : __assert_fail ("rIdx <= m_Text.getLength()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2659, __extension__ __PRETTY_FUNCTION__))
; // invalid index
2660
2661 const sal_Int32 nStartIdx = rIdx.GetIndex();
2662 const sal_Int32 nCnt = (nCount==SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF))
2663 ? m_Text.getLength() - nStartIdx : nCount;
2664 const sal_Int32 nEndIdx = nStartIdx + nCnt;
2665 if (nEndIdx <= m_Text.getLength())
2666 m_Text = m_Text.replaceAt(nStartIdx, nCnt, "");
2667
2668 // GCAttr(); don't remove all empty ones, just the ones that are in the
2669 // range but not at the end of the range.
2670
2671 for ( size_t i = 0; m_pSwpHints && i < m_pSwpHints->Count(); ++i )
2672 {
2673 SwTextAttr *pHt = m_pSwpHints->Get(i);
2674
2675 const sal_Int32 nHintStart = pHt->GetStart();
2676
2677 if ( nHintStart < nStartIdx )
2678 continue;
2679
2680 if ( nHintStart > nEndIdx )
2681 break; // hints are sorted by end, so break here
2682
2683 const sal_Int32* pHtEndIdx = pHt->GetEnd();
2684 const sal_uInt16 nWhich = pHt->Which();
2685
2686 if( !pHtEndIdx )
2687 {
2688 // attribute with neither end nor CH_TXTATR?
2689 assert(pHt->HasDummyChar())(static_cast <bool> (pHt->HasDummyChar()) ? void (0)
: __assert_fail ("pHt->HasDummyChar()", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2689, __extension__ __PRETTY_FUNCTION__))
;
2690 if (isTXTATR(nWhich) && (nHintStart < nEndIdx))
2691 {
2692 m_pSwpHints->DeleteAtPos(i);
2693 DestroyAttr( pHt );
2694 --i;
2695 }
2696 continue;
2697 }
2698
2699 assert(!( (nHintStart < nEndIdx) && (*pHtEndIdx > nEndIdx)(static_cast <bool> (!( (nHintStart < nEndIdx) &&
(*pHtEndIdx > nEndIdx) && pHt->HasDummyChar() )
|| ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx
))) ? void (0) : __assert_fail ("!( (nHintStart < nEndIdx) && (*pHtEndIdx > nEndIdx) && pHt->HasDummyChar() ) || ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx))"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2702, __extension__ __PRETTY_FUNCTION__))
2700 && pHt->HasDummyChar() )(static_cast <bool> (!( (nHintStart < nEndIdx) &&
(*pHtEndIdx > nEndIdx) && pHt->HasDummyChar() )
|| ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx
))) ? void (0) : __assert_fail ("!( (nHintStart < nEndIdx) && (*pHtEndIdx > nEndIdx) && pHt->HasDummyChar() ) || ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx))"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2702, __extension__ __PRETTY_FUNCTION__))
2701 // next line: deleting exactly dummy char: DeleteAttributes(static_cast <bool> (!( (nHintStart < nEndIdx) &&
(*pHtEndIdx > nEndIdx) && pHt->HasDummyChar() )
|| ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx
))) ? void (0) : __assert_fail ("!( (nHintStart < nEndIdx) && (*pHtEndIdx > nEndIdx) && pHt->HasDummyChar() ) || ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx))"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2702, __extension__ __PRETTY_FUNCTION__))
2702 || ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx)))(static_cast <bool> (!( (nHintStart < nEndIdx) &&
(*pHtEndIdx > nEndIdx) && pHt->HasDummyChar() )
|| ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx
))) ? void (0) : __assert_fail ("!( (nHintStart < nEndIdx) && (*pHtEndIdx > nEndIdx) && pHt->HasDummyChar() ) || ((nHintStart == nStartIdx) && (nHintStart + 1 == nEndIdx))"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 2702, __extension__ __PRETTY_FUNCTION__))
;
2703 // "ERROR: deleting left-overlapped attribute with CH_TXTATR");
2704
2705 // Delete the hint if:
2706 // 1. The hint ends before the deletion end position or
2707 // 2. The hint ends at the deletion end position and
2708 // we are not in empty expand mode and
2709 // the hint is a [toxmark|refmark|ruby|inputfield] text attribute
2710 // 3. deleting exactly the dummy char of an hint with end and dummy
2711 // char deletes the hint
2712 if ( (*pHtEndIdx < nEndIdx)
2713 || ( (*pHtEndIdx == nEndIdx) &&
2714 !(SwInsertFlags::EMPTYEXPAND & nMode) &&
2715 ( (RES_TXTATR_TOXMARK == nWhich) ||
2716 (RES_TXTATR_REFMARK == nWhich) ||
2717 (RES_TXTATR_CJK_RUBY == nWhich) ||
2718 (RES_TXTATR_INPUTFIELD == nWhich) ) )
2719 || ( (nHintStart < nEndIdx) &&
2720 pHt->HasDummyChar() )
2721 )
2722 {
2723 m_pSwpHints->DeleteAtPos(i);
2724 DestroyAttr( pHt );
2725 --i;
2726 }
2727 }
2728
2729 OSL_ENSURE(rIdx.GetIndex() == nStartIdx, "huh? start index has changed?")do { if (true && (!(rIdx.GetIndex() == nStartIdx))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2729" ": "), "%s", "huh? start index has changed?"); } }
while (false)
;
2730
2731 TryDeleteSwpHints();
2732
2733 Update( rIdx, nCnt, true );
2734
2735 if( 1 == nCnt )
2736 {
2737 SwDelChr aHint( nStartIdx );
2738 NotifyClients( nullptr, &aHint );
2739 }
2740 else
2741 {
2742 SwDelText aHint( nStartIdx, nCnt );
2743 NotifyClients( nullptr, &aHint );
2744 }
2745
2746 OSL_ENSURE(rIdx.GetIndex() == nStartIdx, "huh? start index has changed?")do { if (true && (!(rIdx.GetIndex() == nStartIdx))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "2746" ": "), "%s", "huh? start index has changed?"); } }
while (false)
;
2747
2748 // By deleting a character, the hidden flags
2749 // at the TextNode can become invalid:
2750 SetCalcHiddenCharFlags();
2751
2752 CHECK_SWPHINTS(this);
2753}
2754
2755void SwTextNode::GCAttr()
2756{
2757 if ( !HasHints() )
2758 return;
2759
2760 bool bChanged = false;
2761 sal_Int32 nMin = m_Text.getLength();
2762 sal_Int32 nMax = 0;
2763 const bool bAll = nMin != 0; // on empty paragraphs only remove INetFormats
2764
2765 for ( size_t i = 0; m_pSwpHints && i < m_pSwpHints->Count(); ++i )
2766 {
2767 SwTextAttr * const pHt = m_pSwpHints->Get(i);
2768
2769 // if end and start are equal, delete it
2770 const sal_Int32 * const pEndIdx = pHt->GetEnd();
2771 if (pEndIdx && !pHt->HasDummyChar() && (*pEndIdx == pHt->GetStart())
2772 && ( bAll || pHt->Which() == RES_TXTATR_INETFMT ) )
2773 {
2774 bChanged = true;
2775 nMin = std::min( nMin, pHt->GetStart() );
2776 nMax = std::max( nMax, *pHt->GetEnd() );
2777 DestroyAttr( m_pSwpHints->Cut(i) );
2778 --i;
2779 }
2780 else
2781 {
2782 pHt->SetDontExpand( false );
2783 }
2784 }
2785 TryDeleteSwpHints();
2786
2787 if(bChanged)
2788 {
2789 // textframes react to aHint, others to aNew
2790 SwUpdateAttr aHint(
2791 nMin,
2792 nMax,
2793 0);
2794
2795 NotifyClients( nullptr, &aHint );
2796 SwFormatChg aNew( GetTextColl() );
2797 NotifyClients( nullptr, &aNew );
2798 }
2799}
2800
2801SwNumRule* SwTextNode::GetNumRule(bool bInParent) const
2802{
2803 SwNumRule* pRet = nullptr;
2804
2805 const SfxPoolItem* pItem = GetNoCondAttr( RES_PARATR_NUMRULE, bInParent );
2806 bool bNoNumRule = false;
2807 if ( pItem )
2808 {
2809 OUString sNumRuleName =
2810 static_cast<const SwNumRuleItem *>(pItem)->GetValue();
2811 if (!sNumRuleName.isEmpty())
2812 {
2813 pRet = GetDoc().FindNumRulePtr( sNumRuleName );
2814 }
2815 else // numbering is turned off
2816 bNoNumRule = true;
2817 }
2818
2819 if ( !bNoNumRule )
2820 {
2821 if ( pRet && pRet == GetDoc().GetOutlineNumRule() &&
2822 ( !HasSwAttrSet() ||
2823 SfxItemState::SET !=
2824 GetpSwAttrSet()->GetItemState( RES_PARATR_NUMRULE, false ) ) )
2825 {
2826 SwTextFormatColl* pColl = GetTextColl();
2827 if ( pColl )
2828 {
2829 const SwNumRuleItem& rDirectItem = pColl->GetNumRule( false );
2830 if ( rDirectItem.GetValue().isEmpty() )
2831 {
2832 pRet = nullptr;
2833 }
2834 }
2835 }
2836 }
2837
2838 return pRet;
2839}
2840
2841void SwTextNode::NumRuleChgd()
2842{
2843 if ( IsInList() )
2844 {
2845 SwNumRule* pNumRule = GetNumRule();
2846 if ( pNumRule && pNumRule != GetNum()->GetNumRule() )
2847 {
2848 mpNodeNum->ChangeNumRule( *pNumRule );
2849 if (mpNodeNumRLHidden)
2850 {
2851 mpNodeNumRLHidden->ChangeNumRule(*pNumRule);
2852 }
2853 }
2854 }
2855
2856 if( IsInCache() )
2857 {
2858 SwFrame::GetCache().Delete( this );
2859 SetInCache( false );
2860 }
2861 SetInSwFntCache( false );
2862
2863 // Sending "noop" modify in order to cause invalidations of registered
2864 // <SwTextFrame> instances to get the list style change respectively the change
2865 // in the list tree reflected in the layout.
2866 // Important note:
2867 {
2868 SvxLRSpaceItem& rLR = const_cast<SvxLRSpaceItem&>(GetSwAttrSet().GetLRSpace());
2869 NotifyClients( &rLR, &rLR );
2870 }
2871
2872 SetWordCountDirty( true );
2873}
2874
2875// -> #i27615#
2876bool SwTextNode::IsNumbered(SwRootFrame const*const pLayout) const
2877{
2878 SwNumRule* pRule = GetNum(pLayout) ? GetNum(pLayout)->GetNumRule() : nullptr;
2879 return pRule && IsCountedInList();
2880}
2881
2882bool SwTextNode::HasMarkedLabel() const
2883{
2884 bool bResult = false;
2885
2886 if ( IsInList() )
2887 {
2888 bResult =
2889 GetDoc().getIDocumentListsAccess().getListByName( GetListId() )->IsListLevelMarked( GetActualListLevel() );
2890 }
2891
2892 return bResult;
2893}
2894// <- #i27615#
2895
2896SwTextNode* SwTextNode::MakeNewTextNode( const SwNodeIndex& rPos, bool bNext,
2897 bool bChgFollow )
2898{
2899 // ignore hard PageBreak/PageDesc/ColumnBreak from Auto-Set
2900 std::unique_ptr<SwAttrSet> pNewAttrSet;
2901 // #i75353#
2902 bool bClearHardSetNumRuleWhenFormatCollChanges( false );
2903 if( HasSwAttrSet() )
2
Taking true branch
2904 {
2905 pNewAttrSet.reset(new SwAttrSet( *GetpSwAttrSet() ));
2906 const SfxItemSet* pTmpSet = GetpSwAttrSet();
2907
2908 if (bNext
2.1
'bNext' is true
2.1
'bNext' is true
) // successor doesn't inherit breaks!
3
Taking true branch
2909 pTmpSet = pNewAttrSet.get();
2910
2911 // !bNext: remove PageBreaks/PageDesc/ColBreak from this
2912 bool bRemoveFromCache = false;
2913 std::vector<sal_uInt16> aClearWhichIds;
2914 if ( bNext
3.1
'bNext' is true
3.1
'bNext' is true
)
4
Taking true branch
2915 bRemoveFromCache = ( 0 != pNewAttrSet->ClearItem( RES_PAGEDESC ) );
5
Assuming the condition is false
2916 else
2917 aClearWhichIds.push_back( RES_PAGEDESC );
2918
2919 if( SfxItemState::SET == pTmpSet->GetItemState( RES_BREAK, false ) )
6
Assuming the condition is false
7
Taking false branch
2920 {
2921 if ( bNext )
2922 pNewAttrSet->ClearItem( RES_BREAK );
2923 else
2924 aClearWhichIds.push_back( RES_BREAK );
2925 bRemoveFromCache = true;
2926 }
2927 if( SfxItemState::SET == pTmpSet->GetItemState( RES_KEEP, false ) )
8
Assuming the condition is false
9
Taking false branch
2928 {
2929 if ( bNext )
2930 pNewAttrSet->ClearItem( RES_KEEP );
2931 else
2932 aClearWhichIds.push_back( RES_KEEP );
2933 bRemoveFromCache = true;
2934 }
2935 if( SfxItemState::SET == pTmpSet->GetItemState( RES_PARATR_SPLIT, false ) )
10
Assuming the condition is false
11
Taking false branch
2936 {
2937 if ( bNext )
2938 pNewAttrSet->ClearItem( RES_PARATR_SPLIT );
2939 else
2940 aClearWhichIds.push_back( RES_PARATR_SPLIT );
2941 bRemoveFromCache = true;
2942 }
2943 if(SfxItemState::SET == pTmpSet->GetItemState(RES_PARATR_NUMRULE, false))
12
Assuming the condition is false
13
Taking false branch
2944 {
2945 SwNumRule * pRule = GetNumRule();
2946
2947 if (pRule && IsOutline())
2948 {
2949 if ( bNext )
2950 pNewAttrSet->ClearItem(RES_PARATR_NUMRULE);
2951 else
2952 {
2953 // #i75353#
2954 // No clear of hard set numbering rule at an outline paragraph at this point.
2955 // Only if the paragraph style changes - see below.
2956 bClearHardSetNumRuleWhenFormatCollChanges = true;
2957 }
2958 bRemoveFromCache = true;
2959 }
2960 }
2961
2962 if ( !aClearWhichIds.empty() )
14
Assuming the condition is false
15
Taking false branch
2963 bRemoveFromCache = 0 != ClearItemsFromAttrSet( aClearWhichIds );
2964
2965 if( !bNext
15.1
'bNext' is true
15.1
'bNext' is true
&& bRemoveFromCache && IsInCache() )
2966 {
2967 SwFrame::GetCache().Delete( this );
2968 SetInCache( false );
2969 }
2970 }
2971 SwNodes& rNds = GetNodes();
2972
2973 SwTextFormatColl* pColl = GetTextColl();
2974
2975 SwTextNode *pNode = new SwTextNode( rPos, pColl, pNewAttrSet.get() );
16
Calling constructor for 'SwTextNode'
2976
2977 pNewAttrSet.reset();
2978
2979 const SwNumRule* pRule = GetNumRule();
2980 if( pRule && pRule == pNode->GetNumRule() && rNds.IsDocNodes() )
2981 {
2982 // #i55459#
2983 // - correction: parameter <bNext> has to be checked, as it was in the
2984 // previous implementation.
2985 if ( !bNext && !IsCountedInList() )
2986 SetCountedInList(true);
2987 }
2988
2989 // In case the numbering caused a style from the pool to be assigned to
2990 // the new node, don't overwrite that here!
2991 if( pColl != pNode->GetTextColl() ||
2992 ( bChgFollow && pColl != GetTextColl() ))
2993 return pNode; // that ought to be enough?
2994
2995 pNode->ChgTextCollUpdateNum( nullptr, pColl ); // for numbering/outline
2996 if( bNext || !bChgFollow )
2997 return pNode;
2998
2999 SwTextFormatColl *pNextColl = &pColl->GetNextTextFormatColl();
3000 // i#101870 perform action on different paragraph styles before applying
3001 // the new paragraph style
3002 if (pNextColl != pColl)
3003 {
3004 // #i75353#
3005 if ( bClearHardSetNumRuleWhenFormatCollChanges )
3006 {
3007 std::vector<sal_uInt16> aClearWhichIds;
3008 aClearWhichIds.push_back( RES_PARATR_NUMRULE );
3009 if ( ClearItemsFromAttrSet( aClearWhichIds ) != 0 && IsInCache() )
3010 {
3011 SwFrame::GetCache().Delete( this );
3012 SetInCache( false );
3013 }
3014 }
3015 }
3016 ChgFormatColl( pNextColl );
3017
3018 return pNode;
3019}
3020
3021SwContentNode* SwTextNode::AppendNode( const SwPosition & rPos )
3022{
3023 // position behind which it will be inserted
3024 SwNodeIndex aIdx( rPos.nNode, 1 );
3025 SwTextNode* pNew = MakeNewTextNode( aIdx );
1
Calling 'SwTextNode::MakeNewTextNode'
3026
3027 // reset list attributes at appended text node
3028 pNew->ResetAttr( RES_PARATR_LIST_ISRESTART );
3029 pNew->ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
3030 pNew->ResetAttr( RES_PARATR_LIST_ISCOUNTED );
3031 if ( pNew->GetNumRule() == nullptr )
3032 {
3033 pNew->ResetAttr( RES_PARATR_LIST_ID );
3034 pNew->ResetAttr( RES_PARATR_LIST_LEVEL );
3035 }
3036
3037 if (!IsInList() && GetNumRule() && !GetListId().isEmpty())
3038 {
3039 AddToList();
3040 }
3041
3042 if( HasWriterListeners() )
3043 MakeFramesForAdjacentContentNode(*pNew);
3044 return pNew;
3045}
3046
3047SwTextAttr * SwTextNode::GetTextAttrForCharAt(
3048 const sal_Int32 nIndex,
3049 const sal_uInt16 nWhich ) const
3050{
3051 assert(nWhich >= RES_TXTATR_BEGIN && nWhich <= RES_TXTATR_END)(static_cast <bool> (nWhich >= RES_TXTATR_BEGIN &&
nWhich <= RES_TXTATR_END) ? void (0) : __assert_fail ("nWhich >= RES_TXTATR_BEGIN && nWhich <= RES_TXTATR_END"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 3051, __extension__ __PRETTY_FUNCTION__))
;
3052 if ( HasHints() )
3053 {
3054 for ( size_t i = 0; i < m_pSwpHints->Count(); ++i )
3055 {
3056 SwTextAttr * const pHint = m_pSwpHints->Get(i);
3057 const sal_Int32 nStartPos = pHint->GetStart();
3058 if ( nIndex < nStartPos )
3059 {
3060 return nullptr;
3061 }
3062 if ( (nIndex == nStartPos) && pHint->HasDummyChar() )
3063 {
3064 return ( RES_TXTATR_END == nWhich || nWhich == pHint->Which() )
3065 ? pHint : nullptr;
3066 }
3067 }
3068 }
3069 return nullptr;
3070}
3071
3072namespace
3073{
3074
3075sal_uInt16 lcl_BoundListLevel(const int nActualLevel)
3076{
3077 return static_cast<sal_uInt16>( std::min( std::max(nActualLevel, 0), MAXLEVEL-1 ) );
3078}
3079
3080}
3081
3082// -> #i29560#
3083bool SwTextNode::HasNumber() const
3084{
3085 bool bResult = false;
3086
3087 const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : nullptr;
3088 if ( pRule )
3089 {
3090 const SwNumFormat& aFormat(pRule->Get(lcl_BoundListLevel(GetActualListLevel())));
3091
3092 // #i40041#
3093 bResult = aFormat.IsEnumeration() &&
3094 SVX_NUM_NUMBER_NONE != aFormat.GetNumberingType();
3095 }
3096
3097 return bResult;
3098}
3099
3100bool SwTextNode::HasBullet() const
3101{
3102 bool bResult = false;
3103
3104 const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : nullptr;
3105 if ( pRule )
3106 {
3107 const SwNumFormat& aFormat(pRule->Get(lcl_BoundListLevel(GetActualListLevel())));
3108
3109 bResult = aFormat.IsItemize();
3110 }
3111
3112 return bResult;
3113}
3114// <- #i29560#
3115
3116// #128041# - introduce parameter <_bInclPrefixAndSuffixStrings>
3117//i53420 added max outline parameter
3118OUString SwTextNode::GetNumString( const bool _bInclPrefixAndSuffixStrings,
3119 const unsigned int _nRestrictToThisLevel,
3120 SwRootFrame const*const pLayout) const
3121{
3122 if (GetDoc().IsClipBoard() && m_pNumStringCache)
3123 {
3124 // #i111677# do not expand number strings in clipboard documents
3125 return *m_pNumStringCache;
3126 }
3127 const SwNumRule* pRule = GetNum(pLayout) ? GetNum(pLayout)->GetNumRule() : nullptr;
3128 if ( pRule &&
3129 IsCountedInList() )
3130 {
3131 SvxNumberType const& rNumberType(
3132 pRule->Get( lcl_BoundListLevel(GetActualListLevel()) ) );
3133 if (rNumberType.IsTextFormat() ||
3134
3135 (style::NumberingType::NUMBER_NONE == rNumberType.GetNumberingType()))
3136 {
3137 return pRule->MakeNumString( GetNum(pLayout)->GetNumberVector(),
3138 _bInclPrefixAndSuffixStrings,
3139 false,
3140 _nRestrictToThisLevel,
3141 nullptr,
3142 GetLang(0));
3143 }
3144 }
3145
3146 return OUString();
3147}
3148
3149long SwTextNode::GetLeftMarginWithNum( bool bTextLeft ) const
3150{
3151 long nRet = 0;
3152 const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : nullptr;
3153 if( pRule )
3154 {
3155 const SwNumFormat& rFormat = pRule->Get(lcl_BoundListLevel(GetActualListLevel()));
3156
3157 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
3158 {
3159 nRet = rFormat.GetAbsLSpace();
3160
3161 if( !bTextLeft )
3162 {
3163 if( 0 > rFormat.GetFirstLineOffset() &&
3164 nRet > -rFormat.GetFirstLineOffset() )
3165 nRet = nRet + rFormat.GetFirstLineOffset();
3166 else
3167 nRet = 0;
3168 }
3169
3170 if( pRule->IsAbsSpaces() )
3171 nRet = nRet - GetSwAttrSet().GetLRSpace().GetLeft();
3172 }
3173 else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
3174 {
3175 if ( AreListLevelIndentsApplicable() )
3176 {
3177 nRet = rFormat.GetIndentAt();
3178 // #i90401#
3179 // Only negative first line indents have consider for the left margin
3180 if ( !bTextLeft &&
3181 rFormat.GetFirstLineIndent() < 0 )
3182 {
3183 nRet = nRet + rFormat.GetFirstLineIndent();
3184 }
3185 }
3186 }
3187 }
3188
3189 return nRet;
3190}
3191
3192bool SwTextNode::GetFirstLineOfsWithNum( short& rFLOffset ) const
3193{
3194 // #i95907#
3195 rFLOffset = 0;
3196
3197 // #i51089#
3198 const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : nullptr;
3199 if ( pRule )
3200 {
3201 if ( IsCountedInList() )
3202 {
3203 const SwNumFormat& rFormat = pRule->Get(lcl_BoundListLevel(GetActualListLevel()));
3204 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
3205 {
3206 rFLOffset = rFormat.GetFirstLineOffset(); //TODO: overflow
3207
3208 if (!getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
3209 {
3210 SvxLRSpaceItem aItem = GetSwAttrSet().GetLRSpace();
3211 rFLOffset = rFLOffset + aItem.GetTextFirstLineOffset();
3212 }
3213 }
3214 else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
3215 {
3216 if ( AreListLevelIndentsApplicable() )
3217 {
3218 rFLOffset = rFormat.GetFirstLineIndent();
3219 }
3220 else if (!getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
3221 {
3222 SvxLRSpaceItem aItem = GetSwAttrSet().GetLRSpace();
3223 rFLOffset = aItem.GetTextFirstLineOffset();
3224 }
3225 }
3226 }
3227
3228 return true;
3229 }
3230
3231 rFLOffset = GetSwAttrSet().GetLRSpace().GetTextFirstLineOffset();
3232 return false;
3233}
3234
3235SwTwips SwTextNode::GetAdditionalIndentForStartingNewList() const
3236{
3237 SwTwips nAdditionalIndent = 0;
3238
3239 const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : nullptr;
3240 if ( pRule )
3241 {
3242 const SwNumFormat& rFormat = pRule->Get(lcl_BoundListLevel(GetActualListLevel()));
3243 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
3244 {
3245 nAdditionalIndent = GetSwAttrSet().GetLRSpace().GetLeft();
3246
3247 if (getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
3248 {
3249 nAdditionalIndent = nAdditionalIndent -
3250 GetSwAttrSet().GetLRSpace().GetTextFirstLineOffset();
3251 }
3252 }
3253 else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
3254 {
3255 if ( AreListLevelIndentsApplicable() )
3256 {
3257 nAdditionalIndent = rFormat.GetIndentAt() + rFormat.GetFirstLineIndent();
3258 }
3259 else
3260 {
3261 nAdditionalIndent = GetSwAttrSet().GetLRSpace().GetLeft();
3262 if (getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
3263 {
3264 nAdditionalIndent = nAdditionalIndent -
3265 GetSwAttrSet().GetLRSpace().GetTextFirstLineOffset();
3266 }
3267 }
3268 }
3269 }
3270 else
3271 {
3272 nAdditionalIndent = GetSwAttrSet().GetLRSpace().GetLeft();
3273 }
3274
3275 return nAdditionalIndent;
3276}
3277
3278// #i96772#
3279void SwTextNode::ClearLRSpaceItemDueToListLevelIndents( std::shared_ptr<SvxLRSpaceItem>& o_rLRSpaceItem ) const
3280{
3281 if ( AreListLevelIndentsApplicable() )
3282 {
3283 const SwNumRule* pRule = GetNumRule();
3284 if ( pRule && GetActualListLevel() >= 0 )
3285 {
3286 const SwNumFormat& rFormat = pRule->Get(lcl_BoundListLevel(GetActualListLevel()));
3287 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
3288 {
3289 o_rLRSpaceItem = std::make_shared<SvxLRSpaceItem>(RES_LR_SPACE);
3290 }
3291 }
3292 }
3293}
3294
3295// #i91133#
3296long SwTextNode::GetLeftMarginForTabCalculation() const
3297{
3298 long nLeftMarginForTabCalc = 0;
3299
3300 bool bLeftMarginForTabCalcSetToListLevelIndent( false );
3301 const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : nullptr;
3302 if( pRule )
3303 {
3304 const SwNumFormat& rFormat = pRule->Get(lcl_BoundListLevel(GetActualListLevel()));
3305 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
3306 {
3307 if ( AreListLevelIndentsApplicable() )
3308 {
3309 nLeftMarginForTabCalc = rFormat.GetIndentAt();
3310 bLeftMarginForTabCalcSetToListLevelIndent = true;
3311 }
3312 }
3313 }
3314 if ( !bLeftMarginForTabCalcSetToListLevelIndent )
3315 {
3316 nLeftMarginForTabCalc = GetSwAttrSet().GetLRSpace().GetTextLeft();
3317 }
3318
3319 return nLeftMarginForTabCalc;
3320}
3321
3322static void Replace0xFF(
3323 SwTextNode const& rNode,
3324 OUStringBuffer & rText,
3325 sal_Int32 & rTextStt,
3326 sal_Int32 nEndPos )
3327{
3328 if (!rNode.GetpSwpHints())
3329 return;
3330
3331 sal_Unicode cSrchChr = CH_TXTATR_BREAKWORDu'\x0001';
3332 for( int nSrchIter = 0; 2 > nSrchIter; ++nSrchIter, cSrchChr = CH_TXTATR_INWORDu'\xFFF9' )
3333 {
3334 sal_Int32 nPos = rText.indexOf(cSrchChr);
3335 while (-1 != nPos && nPos < nEndPos)
3336 {
3337 const SwTextAttr* const pAttr =
3338 rNode.GetTextAttrForCharAt(rTextStt + nPos);
3339 if( pAttr )
3340 {
3341 switch( pAttr->Which() )
3342 {
3343 case RES_TXTATR_FIELD:
3344 case RES_TXTATR_ANNOTATION:
3345 rText.remove(nPos, 1);
3346 ++rTextStt;
3347 break;
3348
3349 case RES_TXTATR_FTN:
3350 rText.remove(nPos, 1);
3351 ++rTextStt;
3352 break;
3353
3354 default:
3355 rText.remove(nPos, 1);
3356 ++rTextStt;
3357 }
3358 }
3359 else
3360 {
3361 ++nPos;
3362 ++nEndPos;
3363 }
3364 nPos = rText.indexOf(cSrchChr, nPos);
3365 }
3366 }
3367}
3368
3369// Expand fields
3370// #i83479# - handling of new parameters
3371OUString SwTextNode::GetExpandText(SwRootFrame const*const pLayout,
3372 const sal_Int32 nIdx,
3373 const sal_Int32 nLen,
3374 const bool bWithNum,
3375 const bool bAddSpaceAfterListLabelStr,
3376 const bool bWithSpacesForLevel,
3377 const ExpandMode eAdditionalMode) const
3378
3379{
3380 ExpandMode eMode = ExpandMode::ExpandFields | eAdditionalMode;
3381 if (pLayout && pLayout->IsHideRedlines())
3382 {
3383 eMode |= ExpandMode::HideDeletions;
3384 }
3385
3386 ModelToViewHelper aConversionMap(*this, pLayout, eMode);
3387 const OUString aExpandText = aConversionMap.getViewText();
3388 const sal_Int32 nExpandBegin = aConversionMap.ConvertToViewPosition( nIdx );
3389 sal_Int32 nEnd = nLen == -1 ? GetText().getLength() : nIdx + nLen;
3390 const sal_Int32 nExpandEnd = aConversionMap.ConvertToViewPosition( nEnd );
3391 OUStringBuffer aText(aExpandText.copy(nExpandBegin, nExpandEnd-nExpandBegin));
3392
3393 // remove dummy characters of Input Fields
3394 comphelper::string::remove(aText, CH_TXT_ATR_INPUTFIELDSTARTu'\x0004');
3395 comphelper::string::remove(aText, CH_TXT_ATR_INPUTFIELDENDu'\x0005');
3396
3397 if( bWithNum )
3398 {
3399 if (!GetNumString(true, MAXLEVEL, pLayout).isEmpty())
3400 {
3401 if ( bAddSpaceAfterListLabelStr )
3402 {
3403 const sal_Unicode aSpace = ' ';
3404 aText.insert(0, aSpace);
3405 }
3406 aText.insert(0, GetNumString(true, MAXLEVEL, pLayout));
3407 }
3408 }
3409
3410 if (bWithSpacesForLevel)
3411 {
3412 const sal_Unicode aSpace = ' ';
3413 for (int nLevel = GetActualListLevel(); nLevel > 0; --nLevel)
3414 {
3415 aText.insert(0, aSpace);
3416 aText.insert(0, aSpace);
3417 }
3418 }
3419
3420 return aText.makeStringAndClear();
3421}
3422
3423bool SwTextNode::CopyExpandText(SwTextNode& rDestNd, const SwIndex* pDestIdx,
3424 sal_Int32 nIdx, sal_Int32 nLen,
3425 SwRootFrame const*const pLayout, bool bWithNum,
3426 bool bWithFootnote, bool bReplaceTabsWithSpaces ) const
3427{
3428 if( &rDestNd == this )
3429 return false;
3430
3431 SwIndex aDestIdx(&rDestNd, rDestNd.GetText().getLength());
3432 if( pDestIdx )
3433 aDestIdx = *pDestIdx;
3434 const sal_Int32 nDestStt = aDestIdx.GetIndex();
3435
3436 // first, start with the text
3437 OUStringBuffer buf(GetText());
3438 if( bReplaceTabsWithSpaces )
3439 buf.replace('\t', ' ');
3440
3441 // mask hidden characters
3442 const sal_Unicode cChar = CH_TXTATR_BREAKWORDu'\x0001';
3443 SwScriptInfo::MaskHiddenRanges(*this, buf, 0, buf.getLength(), cChar);
3444
3445 buf.remove(0, nIdx);
3446 if (nLen != -1)
3447 {
3448 buf.truncate(nLen);
3449 }
3450 // remove dummy characters of Input Fields
3451 {
3452 comphelper::string::remove(buf, CH_TXT_ATR_INPUTFIELDSTARTu'\x0004');
3453 comphelper::string::remove(buf, CH_TXT_ATR_INPUTFIELDENDu'\x0005');
3454 }
3455 rDestNd.InsertText(buf.makeStringAndClear(), aDestIdx);
3456 nLen = aDestIdx.GetIndex() - nDestStt;
3457
3458 // set all char attributes with Symbol font
3459 if ( HasHints() )
3460 {
3461 sal_Int32 nInsPos = nDestStt - nIdx;
3462 for ( size_t i = 0; i < m_pSwpHints->Count(); ++i )
3463 {
3464 const SwTextAttr* pHt = m_pSwpHints->Get(i);
3465 const sal_Int32 nAttrStartIdx = pHt->GetStart();
3466 const sal_uInt16 nWhich = pHt->Which();
3467 if (nIdx + nLen <= nAttrStartIdx)
3468 break; // behind end of text
3469
3470 const sal_Int32 *pEndIdx = pHt->End();
3471 if( pEndIdx && *pEndIdx > nIdx &&
3472 ( RES_CHRATR_FONT == nWhich ||
3473 RES_TXTATR_CHARFMT == nWhich ||
3474 RES_TXTATR_AUTOFMT == nWhich ))
3475 {
3476 const SvxFontItem* const pFont =
3477 CharFormat::GetItem( *pHt, RES_CHRATR_FONT );
3478 if ( pFont && RTL_TEXTENCODING_SYMBOL(((rtl_TextEncoding) 10)) == pFont->GetCharSet() )
3479 {
3480 // attribute in area => copy
3481 rDestNd.InsertItem( *const_cast<SvxFontItem*>(pFont),
3482 nInsPos + nAttrStartIdx, nInsPos + *pEndIdx );
3483 }
3484 }
3485 else if ( pHt->HasDummyChar() && (nAttrStartIdx >= nIdx) )
3486 {
3487 aDestIdx = nInsPos + nAttrStartIdx;
3488 switch( nWhich )
3489 {
3490 case RES_TXTATR_FIELD:
3491 case RES_TXTATR_ANNOTATION:
3492 {
3493 OUString const aExpand(
3494 static_txtattr_cast<SwTextField const*>(pHt)->GetFormatField().GetField()->ExpandField(true, pLayout));
3495 if (!aExpand.isEmpty())
3496 {
3497 ++aDestIdx; // insert behind
3498 OUString const ins(
3499 rDestNd.InsertText( aExpand, aDestIdx));
3500 SAL_INFO_IF(ins.getLength() != aExpand.getLength(),do { if (true && (ins.getLength() != aExpand.getLength
())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "GetExpandText lossage"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3501" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetExpandText lossage"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetExpandText lossage"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3501" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetExpandText lossage") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3501" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetExpandText lossage"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetExpandText lossage"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3501" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3501 "sw.core", "GetExpandText lossage")do { if (true && (ins.getLength() != aExpand.getLength
())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "GetExpandText lossage"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3501" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetExpandText lossage"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetExpandText lossage"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3501" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetExpandText lossage") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3501" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetExpandText lossage"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetExpandText lossage"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3501" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3502 aDestIdx = nInsPos + nAttrStartIdx;
3503 nInsPos += ins.getLength();
3504 }
3505 rDestNd.EraseText( aDestIdx, 1 );
3506 --nInsPos;
3507 }
3508 break;
3509
3510 case RES_TXTATR_FTN:
3511 {
3512 if ( bWithFootnote )
3513 {
3514 const SwFormatFootnote& rFootnote = pHt->GetFootnote();
3515 OUString sExpand;
3516 auto const number(pLayout && pLayout->IsHideRedlines()
3517 ? rFootnote.GetNumberRLHidden()
3518 : rFootnote.GetNumber());
3519 if( !rFootnote.GetNumStr().isEmpty() )
3520 sExpand = rFootnote.GetNumStr();
3521 else if( rFootnote.IsEndNote() )
3522 sExpand = GetDoc().GetEndNoteInfo().m_aFormat.
3523 GetNumStr(number);
3524 else
3525 sExpand = GetDoc().GetFootnoteInfo().m_aFormat.
3526 GetNumStr(number);
3527 if( !sExpand.isEmpty() )
3528 {
3529 ++aDestIdx; // insert behind
3530 SvxEscapementItem aItem( SvxEscapement::Superscript, RES_CHRATR_ESCAPEMENT );
3531 rDestNd.InsertItem(
3532 aItem,
3533 aDestIdx.GetIndex(),
3534 aDestIdx.GetIndex() );
3535 OUString const ins( rDestNd.InsertText(sExpand, aDestIdx, SwInsertFlags::EMPTYEXPAND));
3536 SAL_INFO_IF(ins.getLength() != sExpand.getLength(),do { if (true && (ins.getLength() != sExpand.getLength
())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "GetExpandText lossage"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3537" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetExpandText lossage"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetExpandText lossage"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3537" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetExpandText lossage") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3537" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetExpandText lossage"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetExpandText lossage"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3537" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3537 "sw.core", "GetExpandText lossage")do { if (true && (ins.getLength() != sExpand.getLength
())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "GetExpandText lossage"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3537" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetExpandText lossage"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetExpandText lossage"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3537" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetExpandText lossage") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3537" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetExpandText lossage"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetExpandText lossage"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3537" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3538 aDestIdx = nInsPos + nAttrStartIdx;
3539 nInsPos += ins.getLength();
3540 }
3541 }
3542 rDestNd.EraseText( aDestIdx, 1 );
3543 --nInsPos;
3544 }
3545 break;
3546
3547 default:
3548 rDestNd.EraseText( aDestIdx, 1 );
3549 --nInsPos;
3550 }
3551 }
3552 }
3553 }
3554
3555 if( bWithNum )
3556 {
3557 aDestIdx = nDestStt;
3558 rDestNd.InsertText( GetNumString(true, MAXLEVEL, pLayout), aDestIdx );
3559 }
3560
3561 aDestIdx = 0;
3562 sal_Int32 nStartDelete(-1);
3563 while (aDestIdx < rDestNd.GetText().getLength())
3564 {
3565 sal_Unicode const cur(rDestNd.GetText()[aDestIdx.GetIndex()]);
3566 if ( (cChar == cur) // filter substituted hidden text
3567 || (CH_TXT_ATR_FIELDSTARTu'\x0007' == cur) // filter all fieldmarks
3568 || (CH_TXT_ATR_FIELDSEPu'\x0003' == cur)
3569 || (CH_TXT_ATR_FIELDENDu'\x0008' == cur)
3570 || (CH_TXT_ATR_FORMELEMENTu'\x0006' == cur))
3571 {
3572 if (-1 == nStartDelete)
3573 {
3574 nStartDelete = aDestIdx.GetIndex(); // start deletion range
3575 }
3576 ++aDestIdx;
3577 if (aDestIdx < rDestNd.GetText().getLength())
3578 {
3579 continue;
3580 } // else: end of paragraph => delete, see below
3581 }
3582 else
3583 {
3584 if (-1 == nStartDelete)
3585 {
3586 ++aDestIdx;
3587 continue;
3588 } // else: delete, see below
3589 }
3590 assert(-1 != nStartDelete)(static_cast <bool> (-1 != nStartDelete) ? void (0) : __assert_fail
("-1 != nStartDelete", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 3590, __extension__ __PRETTY_FUNCTION__))
; // without delete range, would have continued
3591 rDestNd.EraseText(
3592 SwIndex(&rDestNd, nStartDelete),
3593 aDestIdx.GetIndex() - nStartDelete);
3594 assert(aDestIdx.GetIndex() == nStartDelete)(static_cast <bool> (aDestIdx.GetIndex() == nStartDelete
) ? void (0) : __assert_fail ("aDestIdx.GetIndex() == nStartDelete"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 3594, __extension__ __PRETTY_FUNCTION__))
;
3595 nStartDelete = -1; // reset
3596 }
3597
3598 return true;
3599}
3600
3601OUString SwTextNode::GetRedlineText() const
3602{
3603 std::vector<sal_Int32> aRedlArr;
3604 const SwDoc& rDoc = GetDoc();
3605 SwRedlineTable::size_type nRedlPos = rDoc.getIDocumentRedlineAccess().GetRedlinePos( *this, RedlineType::Delete );
3606 if( SwRedlineTable::npos != nRedlPos )
3607 {
3608 // some redline-delete object exists for the node
3609 const sal_uLong nNdIdx = GetIndex();
3610 for( ; nRedlPos < rDoc.getIDocumentRedlineAccess().GetRedlineTable().size() ; ++nRedlPos )
3611 {
3612 const SwRangeRedline* pTmp = rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ nRedlPos ];
3613 if( RedlineType::Delete == pTmp->GetType() )
3614 {
3615 const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End();
3616 if( pRStt->nNode < nNdIdx )
3617 {
3618 if( pREnd->nNode > nNdIdx )
3619 // paragraph is fully deleted
3620 return OUString();
3621 else if( pREnd->nNode == nNdIdx )
3622 {
3623 // deleted from 0 to nContent
3624 aRedlArr.push_back( 0 );
3625 aRedlArr.push_back( pREnd->nContent.GetIndex() );
3626 }
3627 }
3628 else if( pRStt->nNode == nNdIdx )
3629 {
3630 //aRedlArr.Insert( pRStt->nContent.GetIndex(), aRedlArr.Count() );
3631 aRedlArr.push_back( pRStt->nContent.GetIndex() );
3632 if( pREnd->nNode == nNdIdx )
3633 aRedlArr.push_back( pREnd->nContent.GetIndex() );
3634 else
3635 {
3636 aRedlArr.push_back(GetText().getLength());
3637 break; // that was all
3638 }
3639 }
3640 else
3641 break; // that was all
3642 }
3643 }
3644 }
3645
3646 OUStringBuffer aText(GetText());
3647
3648 sal_Int32 nTextStt = 0;
3649 sal_Int32 nIdxEnd = aText.getLength();
3650 for( size_t n = 0; n < aRedlArr.size(); n += 2 )
3651 {
3652 sal_Int32 nStt = aRedlArr[ n ];
3653 sal_Int32 nEnd = aRedlArr[ n+1 ];
3654 if( ( 0 <= nStt && nStt <= nIdxEnd ) ||
3655 ( 0 <= nEnd && nEnd <= nIdxEnd ))
3656 {
3657 if( nStt < 0 ) nStt = 0;
3658 if( nIdxEnd < nEnd ) nEnd = nIdxEnd;
3659 const sal_Int32 nDelCnt = nEnd - nStt;
3660 aText.remove(nStt - nTextStt, nDelCnt);
3661 Replace0xFF(*this, aText, nTextStt, nStt - nTextStt);
3662 nTextStt += nDelCnt;
3663 }
3664 else if( nStt >= nIdxEnd )
3665 break;
3666 }
3667 Replace0xFF(*this, aText, nTextStt, aText.getLength());
3668
3669 return aText.makeStringAndClear();
3670}
3671
3672void SwTextNode::ReplaceText( const SwIndex& rStart, const sal_Int32 nDelLen,
3673 const OUString & rStr)
3674{
3675 assert( rStart.GetIndex() < m_Text.getLength() // index out of bounds(static_cast <bool> (rStart.GetIndex() < m_Text.getLength
() && rStart.GetIndex() + nDelLen <= m_Text.getLength
()) ? void (0) : __assert_fail ("rStart.GetIndex() < m_Text.getLength() && rStart.GetIndex() + nDelLen <= m_Text.getLength()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 3676, __extension__ __PRETTY_FUNCTION__))
3676 && rStart.GetIndex() + nDelLen <= m_Text.getLength())(static_cast <bool> (rStart.GetIndex() < m_Text.getLength
() && rStart.GetIndex() + nDelLen <= m_Text.getLength
()) ? void (0) : __assert_fail ("rStart.GetIndex() < m_Text.getLength() && rStart.GetIndex() + nDelLen <= m_Text.getLength()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 3676, __extension__ __PRETTY_FUNCTION__))
;
3677
3678 sal_Int32 const nOverflow(rStr.getLength() - nDelLen - GetSpaceLeft());
3679 SAL_WARN_IF(nOverflow > 0, "sw.core",do { if (true && (nOverflow > 0)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "SwTextNode::ReplaceText: node text with insertion > node capacity."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3680" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::ReplaceText: node text with insertion > node capacity."
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::ReplaceText: node text with insertion > node capacity."
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3680" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SwTextNode::ReplaceText: node text with insertion > node capacity."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3680" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::ReplaceText: node text with insertion > node capacity."
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::ReplaceText: node text with insertion > node capacity."
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3680" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
3680 "SwTextNode::ReplaceText: node text with insertion > node capacity.")do { if (true && (nOverflow > 0)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "SwTextNode::ReplaceText: node text with insertion > node capacity."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3680" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::ReplaceText: node text with insertion > node capacity."
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::ReplaceText: node text with insertion > node capacity."
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3680" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SwTextNode::ReplaceText: node text with insertion > node capacity."
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3680" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SwTextNode::ReplaceText: node text with insertion > node capacity."
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SwTextNode::ReplaceText: node text with insertion > node capacity."
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3680" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3681 OUString const sInserted(
3682 (nOverflow > 0) ? rStr.copy(0, rStr.getLength() - nOverflow) : rStr);
3683 if (sInserted.isEmpty() && 0 == nDelLen)
3684 {
3685 return; // nothing to do
3686 }
3687
3688 const sal_Int32 nStartPos = rStart.GetIndex();
3689 sal_Int32 nEndPos = nStartPos + nDelLen;
3690 sal_Int32 nLen = nDelLen;
3691 for( sal_Int32 nPos = nStartPos; nPos < nEndPos; ++nPos )
3692 {
3693 if ((CH_TXTATR_BREAKWORDu'\x0001' == m_Text[nPos]) ||
3694 (CH_TXTATR_INWORDu'\xFFF9' == m_Text[nPos]))
3695 {
3696 SwTextAttr *const pHint = GetTextAttrForCharAt( nPos );
3697 if (pHint)
3698 {
3699 assert(!( pHint->GetEnd() && pHint->HasDummyChar()(static_cast <bool> (!( pHint->GetEnd() && pHint
->HasDummyChar() && (pHint->GetStart() < nEndPos
) && (*pHint->GetEnd() > nEndPos) )) ? void (0)
: __assert_fail ("!( pHint->GetEnd() && pHint->HasDummyChar() && (pHint->GetStart() < nEndPos) && (*pHint->GetEnd() > nEndPos) )"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 3701, __extension__ __PRETTY_FUNCTION__))
3700 && (pHint->GetStart() < nEndPos)(static_cast <bool> (!( pHint->GetEnd() && pHint
->HasDummyChar() && (pHint->GetStart() < nEndPos
) && (*pHint->GetEnd() > nEndPos) )) ? void (0)
: __assert_fail ("!( pHint->GetEnd() && pHint->HasDummyChar() && (pHint->GetStart() < nEndPos) && (*pHint->GetEnd() > nEndPos) )"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 3701, __extension__ __PRETTY_FUNCTION__))
3701 && (*pHint->GetEnd() > nEndPos) ))(static_cast <bool> (!( pHint->GetEnd() && pHint
->HasDummyChar() && (pHint->GetStart() < nEndPos
) && (*pHint->GetEnd() > nEndPos) )) ? void (0)
: __assert_fail ("!( pHint->GetEnd() && pHint->HasDummyChar() && (pHint->GetStart() < nEndPos) && (*pHint->GetEnd() > nEndPos) )"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 3701, __extension__ __PRETTY_FUNCTION__))
;
3702 // "deleting left-overlapped attribute with CH_TXTATR"
3703 DeleteAttribute( pHint );
3704 --nEndPos;
3705 --nLen;
3706 }
3707 }
3708 }
3709
3710 bool bOldExpFlg = IsIgnoreDontExpand();
3711 SetIgnoreDontExpand( true );
3712
3713 if (nLen && sInserted.getLength())
3714 {
3715 // Replace the 1st char, then delete the rest and insert.
3716 // This way the attributes of the 1st char are expanded!
3717 m_Text = m_Text.replaceAt(nStartPos, 1, sInserted.copy(0, 1));
3718
3719 ++const_cast<SwIndex&>(rStart);
3720 m_Text = m_Text.replaceAt(rStart.GetIndex(), nLen - 1, "");
3721 Update( rStart, nLen - 1, true );
3722
3723 OUString aTmpText( sInserted.copy(1) );
3724 m_Text = m_Text.replaceAt(rStart.GetIndex(), 0, aTmpText);
3725 Update( rStart, aTmpText.getLength() );
3726 }
3727 else
3728 {
3729 m_Text = m_Text.replaceAt(nStartPos, nLen, "");
3730 Update( rStart, nLen, true );
3731
3732 m_Text = m_Text.replaceAt(nStartPos, 0, sInserted);
3733 Update( rStart, sInserted.getLength() );
3734 }
3735
3736 SetIgnoreDontExpand( bOldExpFlg );
3737 SwDelText aDelHint( nStartPos, nDelLen );
3738 NotifyClients( nullptr, &aDelHint );
3739
3740 SwInsText aHint( nStartPos, sInserted.getLength() );
3741 NotifyClients( nullptr, &aHint );
3742}
3743
3744namespace {
3745 void lcl_ResetParAttrs( SwTextNode &rTextNode )
3746 {
3747 std::set<sal_uInt16> aAttrs;
3748 aAttrs.insert( aAttrs.end(), RES_PARATR_LIST_ID );
3749 aAttrs.insert( aAttrs.end(), RES_PARATR_LIST_LEVEL );
3750 aAttrs.insert( aAttrs.end(), RES_PARATR_LIST_ISRESTART );
3751 aAttrs.insert( aAttrs.end(), RES_PARATR_LIST_RESTARTVALUE );
3752 aAttrs.insert( aAttrs.end(), RES_PARATR_LIST_ISCOUNTED );
3753 SwPaM aPam( rTextNode );
3754 // #i96644#
3755 // suppress side effect "send data changed events"
3756 rTextNode.GetDoc().ResetAttrs( aPam, false, aAttrs, false );
3757 }
3758
3759 // Helper method for special handling of modified attributes at text node.
3760 // The following is handled:
3761 // (1) on changing the paragraph style - RES_FMT_CHG:
3762 // Check, if list style of the text node is changed. If yes, add respectively
3763 // remove the text node to the corresponding list.
3764 // (2) on changing the attributes - RES_ATTRSET_CHG:
3765 // Same as (1).
3766 // (3) on changing the list style - RES_PARATR_NUMRULE:
3767 // Same as (1).
3768 void HandleModifyAtTextNode( SwTextNode& rTextNode,
3769 const SfxPoolItem* pOldValue,
3770 const SfxPoolItem* pNewValue )
3771 {
3772 const sal_uInt16 nWhich = pOldValue ? pOldValue->Which() :
3773 pNewValue ? pNewValue->Which() : 0 ;
3774 bool bNumRuleSet = false;
3775 bool bParagraphStyleChanged = false;
3776 OUString sNumRule;
3777 OUString sOldNumRule;
3778 switch ( nWhich )
3779 {
3780 case RES_FMT_CHG:
3781 {
3782 bParagraphStyleChanged = true;
3783 if( rTextNode.GetNodes().IsDocNodes() )
3784 {
3785 const SwNumRule* pFormerNumRuleAtTextNode =
3786 rTextNode.GetNum() ? rTextNode.GetNum()->GetNumRule() : nullptr;
3787 if ( pFormerNumRuleAtTextNode )
3788 {
3789 sOldNumRule = pFormerNumRuleAtTextNode->GetName();
3790 }
3791 if ( rTextNode.IsEmptyListStyleDueToSetOutlineLevelAttr() )
3792 {
3793 const SwNumRuleItem& rNumRuleItem = rTextNode.GetTextColl()->GetNumRule();
3794 if ( !rNumRuleItem.GetValue().isEmpty() )
3795 {
3796 rTextNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
3797 }
3798 }
3799 const SwNumRule* pNumRuleAtTextNode = rTextNode.GetNumRule();
3800 if ( pNumRuleAtTextNode )
3801 {
3802 bNumRuleSet = true;
3803 sNumRule = pNumRuleAtTextNode->GetName();
3804 }
3805 }
3806 break;
3807 }
3808 case RES_ATTRSET_CHG:
3809 {
3810 const SfxPoolItem* pItem = nullptr;
3811 const SwNumRule* pFormerNumRuleAtTextNode =
3812 rTextNode.GetNum() ? rTextNode.GetNum()->GetNumRule() : nullptr;
3813 if ( pFormerNumRuleAtTextNode )
3814 {
3815 sOldNumRule = pFormerNumRuleAtTextNode->GetName();
3816 }
3817
3818 const SwAttrSetChg* pSet = dynamic_cast<const SwAttrSetChg*>(pNewValue);
3819 if ( pSet && pSet->GetChgSet()->GetItemState( RES_PARATR_NUMRULE, false, &pItem ) ==
3820 SfxItemState::SET )
3821 {
3822 // #i70748#
3823 rTextNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
3824 bNumRuleSet = true;
3825 }
3826 // #i70748#
3827 // The new list style set at the paragraph.
3828 const SwNumRule* pNumRuleAtTextNode = rTextNode.GetNumRule();
3829 if ( pNumRuleAtTextNode )
3830 {
3831 sNumRule = pNumRuleAtTextNode->GetName();
3832 }
3833 break;
3834 }
3835 case RES_PARATR_NUMRULE:
3836 {
3837 if ( rTextNode.GetNodes().IsDocNodes() )
3838 {
3839 const SwNumRule* pFormerNumRuleAtTextNode =
3840 rTextNode.GetNum() ? rTextNode.GetNum()->GetNumRule() : nullptr;
3841 if ( pFormerNumRuleAtTextNode )
3842 {
3843 sOldNumRule = pFormerNumRuleAtTextNode->GetName();
3844 }
3845
3846 if ( pNewValue )
3847 {
3848 // #i70748#
3849 rTextNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
3850 bNumRuleSet = true;
3851 }
3852 // #i70748#
3853 // The new list style set at the paragraph.
3854 const SwNumRule* pNumRuleAtTextNode = rTextNode.GetNumRule();
3855 if ( pNumRuleAtTextNode )
3856 {
3857 sNumRule = pNumRuleAtTextNode->GetName();
3858 }
3859 }
3860 break;
3861 }
3862 }
3863 if ( sNumRule != sOldNumRule )
3864 {
3865 if ( bNumRuleSet )
3866 {
3867 if (sNumRule.isEmpty())
3868 {
3869 rTextNode.RemoveFromList();
3870 if ( bParagraphStyleChanged )
3871 {
3872 lcl_ResetParAttrs(rTextNode);
3873 }
3874 }
3875 else
3876 {
3877 rTextNode.RemoveFromList();
3878 // If new list style is the outline style, apply outline
3879 // level as the list level.
3880 if (sNumRule==SwNumRule::GetOutlineRuleName())
3881 {
3882 // #i70748#
3883 OSL_ENSURE( rTextNode.GetTextColl()->IsAssignedToListLevelOfOutlineStyle(),do { if (true && (!(rTextNode.GetTextColl()->IsAssignedToListLevelOfOutlineStyle
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3884" ": "), "%s", "<HandleModifyAtTextNode()> - text node with outline style, but its paragraph style is not assigned to outline style."
); } } while (false)
3884 "<HandleModifyAtTextNode()> - text node with outline style, but its paragraph style is not assigned to outline style." )do { if (true && (!(rTextNode.GetTextColl()->IsAssignedToListLevelOfOutlineStyle
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3884" ": "), "%s", "<HandleModifyAtTextNode()> - text node with outline style, but its paragraph style is not assigned to outline style."
); } } while (false)
;
3885 const int nNewListLevel =
3886 rTextNode.GetTextColl()->GetAssignedOutlineStyleLevel();
3887 if ( 0 <= nNewListLevel && nNewListLevel < MAXLEVEL )
3888 {
3889 rTextNode.SetAttrListLevel( nNewListLevel );
3890 }
3891 }
3892 rTextNode.AddToList();
3893 }
3894 }
3895 else // <sNumRule.Len() == 0 && sOldNumRule.Len() != 0>
3896 {
3897 rTextNode.RemoveFromList();
3898 if ( bParagraphStyleChanged )
3899 {
3900 lcl_ResetParAttrs(rTextNode);
3901 // #i70748#
3902 if ( dynamic_cast<const SfxUInt16Item &>(rTextNode.GetAttr( RES_PARATR_OUTLINELEVEL, false )).GetValue() > 0 )
3903 {
3904 rTextNode.SetEmptyListStyleDueToSetOutlineLevelAttr();
3905 }
3906 }
3907 }
3908 }
3909 else if (!sNumRule.isEmpty() && !rTextNode.IsInList())
3910 {
3911 rTextNode.AddToList();
3912 }
3913 }
3914 // End of method <HandleModifyAtTextNode>
3915}
3916
3917SwFormatColl* SwTextNode::ChgFormatColl( SwFormatColl *pNewColl )
3918{
3919 OSL_ENSURE( pNewColl,"ChgFormatColl: Collectionpointer has value 0." )do { if (true && (!(pNewColl))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3919" ": "), "%s", "ChgFormatColl: Collectionpointer has value 0."
); } } while (false)
;
3920 OSL_ENSURE( dynamic_cast<const SwTextFormatColl *>(pNewColl) != nullptr,do { if (true && (!(dynamic_cast<const SwTextFormatColl
*>(pNewColl) != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3921" ": "), "%s", "ChgFormatColl: is not a Text Collection pointer."
); } } while (false)
3921 "ChgFormatColl: is not a Text Collection pointer." )do { if (true && (!(dynamic_cast<const SwTextFormatColl
*>(pNewColl) != nullptr))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3921" ": "), "%s", "ChgFormatColl: is not a Text Collection pointer."
); } } while (false)
;
3922
3923 SwTextFormatColl *pOldColl = GetTextColl();
3924 if( pNewColl != pOldColl )
3925 {
3926 SetCalcHiddenCharFlags();
3927 SwContentNode::ChgFormatColl( pNewColl );
3928 OSL_ENSURE( !mbInSetOrResetAttr,do { if (true && (!(!mbInSetOrResetAttr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3929" ": "), "%s", "DEBUG OSL_ENSURE(ON - <SwTextNode::ChgFormatColl(..)> called during <Set/ResetAttr(..)>"
); } } while (false)
3929 "DEBUG OSL_ENSURE(ON - <SwTextNode::ChgFormatColl(..)> called during <Set/ResetAttr(..)>" )do { if (true && (!(!mbInSetOrResetAttr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "3929" ": "), "%s", "DEBUG OSL_ENSURE(ON - <SwTextNode::ChgFormatColl(..)> called during <Set/ResetAttr(..)>"
); } } while (false)
;
3930 if ( !mbInSetOrResetAttr )
3931 {
3932 SwFormatChg aTmp1( pOldColl );
3933 SwFormatChg aTmp2( pNewColl );
3934 HandleModifyAtTextNode( *this, &aTmp1, &aTmp2 );
3935 }
3936
3937 // reset fill information on parent style change
3938 if(maFillAttributes)
3939 {
3940 maFillAttributes.reset();
3941 }
3942 }
3943
3944 // only for real nodes-array
3945 if( GetNodes().IsDocNodes() )
3946 {
3947 ChgTextCollUpdateNum( pOldColl, static_cast<SwTextFormatColl *>(pNewColl) );
3948 }
3949
3950 GetNodes().UpdateOutlineNode(*this);
3951
3952 return pOldColl;
3953}
3954
3955const SwNodeNum* SwTextNode::GetNum(SwRootFrame const*const pLayout) const
3956{
3957 // invariant: it's only in list in Hide mode if it's in list in normal mode
3958 assert(mpNodeNum || !mpNodeNumRLHidden)(static_cast <bool> (mpNodeNum || !mpNodeNumRLHidden) ?
void (0) : __assert_fail ("mpNodeNum || !mpNodeNumRLHidden",
"/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 3958, __extension__ __PRETTY_FUNCTION__))
;
3959 return pLayout && pLayout->IsHideRedlines() ? mpNodeNumRLHidden.get() : mpNodeNum.get();
3960}
3961
3962void SwTextNode::DoNum(std::function<void (SwNodeNum &)> const& rFunc)
3963{
3964 // temp. clear because GetActualListLevel() may be called and the assert
3965 // there triggered during update, which is unhelpful
3966 std::unique_ptr<SwNodeNum> pBackup = std::move(mpNodeNumRLHidden);
3967 assert(mpNodeNum)(static_cast <bool> (mpNodeNum) ? void (0) : __assert_fail
("mpNodeNum", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 3967, __extension__ __PRETTY_FUNCTION__))
;
3968 rFunc(*mpNodeNum);
3969 if (pBackup)
3970 {
3971 mpNodeNumRLHidden = std::move(pBackup);
3972 rFunc(*mpNodeNumRLHidden);
3973 }
3974}
3975
3976SwNumberTree::tNumberVector
3977SwTextNode::GetNumberVector(SwRootFrame const*const pLayout) const
3978{
3979 if (SwNodeNum const*const pNum = GetNum(pLayout))
3980 {
3981 return pNum->GetNumberVector();
3982 }
3983 else
3984 {
3985 SwNumberTree::tNumberVector aResult;
3986 return aResult;
3987 }
3988}
3989
3990bool SwTextNode::IsOutline() const
3991{
3992 bool bResult = false;
3993
3994 if ( GetAttrOutlineLevel() > 0 )
3995 {
3996 bResult = !IsInRedlines();
3997 }
3998 else
3999 {
4000 const SwNumRule* pRule( GetNum() ? GetNum()->GetNumRule() : nullptr );
4001 if ( pRule && pRule->IsOutlineRule() )
4002 {
4003 bResult = !IsInRedlines();
4004 }
4005 }
4006
4007 return bResult;
4008}
4009
4010bool SwTextNode::IsOutlineStateChanged() const
4011{
4012 return IsOutline() != m_bLastOutlineState;
4013}
4014
4015void SwTextNode::UpdateOutlineState()
4016{
4017 m_bLastOutlineState = IsOutline();
4018}
4019
4020int SwTextNode::GetAttrOutlineLevel() const
4021{
4022 return static_cast<const SfxUInt16Item &>(GetAttr(RES_PARATR_OUTLINELEVEL)).GetValue();
4023}
4024
4025void SwTextNode::SetAttrOutlineLevel(int nLevel)
4026{
4027 assert(0 <= nLevel && nLevel <= MAXLEVEL)(static_cast <bool> (0 <= nLevel && nLevel <=
MAXLEVEL) ? void (0) : __assert_fail ("0 <= nLevel && nLevel <= MAXLEVEL"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 4027, __extension__ __PRETTY_FUNCTION__))
; // Level Out Of Range
4028 if ( 0 <= nLevel && nLevel <= MAXLEVEL )
4029 {
4030 SetAttr( SfxUInt16Item( RES_PARATR_OUTLINELEVEL,
4031 static_cast<sal_uInt16>(nLevel) ) );
4032 }
4033}
4034
4035bool SwTextNode::GetAttrOutlineContentVisible(bool& bOutlineContentVisibleAttr)
4036{
4037 SfxGrabBagItem aGrabBagItem(dynamic_cast<const SfxGrabBagItem&>(GetAttr(RES_PARATR_GRABBAG)));
4038 auto it = aGrabBagItem.GetGrabBag().find("OutlineContentVisibleAttr");
4039 if (it != aGrabBagItem.GetGrabBag().end())
4040 {
4041 it->second >>= bOutlineContentVisibleAttr;
4042 return true;
4043 }
4044 return false;
4045}
4046
4047void SwTextNode::SetAttrOutlineContentVisible(bool bVisible)
4048{
4049 SfxGrabBagItem aGrabBagItem(RES_PARATR_GRABBAG);
4050 aGrabBagItem.GetGrabBag()["OutlineContentVisibleAttr"] <<= bVisible;
4051 GetTextNode()->SetAttr(aGrabBagItem);
4052}
4053
4054// #i70748#
4055
4056void SwTextNode::SetEmptyListStyleDueToSetOutlineLevelAttr()
4057{
4058 if ( !mbEmptyListStyleSetDueToSetOutlineLevelAttr )
4059 {
4060 SetAttr( SwNumRuleItem() );
4061 mbEmptyListStyleSetDueToSetOutlineLevelAttr = true;
4062 }
4063}
4064
4065void SwTextNode::ResetEmptyListStyleDueToResetOutlineLevelAttr()
4066{
4067 if ( mbEmptyListStyleSetDueToSetOutlineLevelAttr )
4068 {
4069 ResetAttr( RES_PARATR_NUMRULE );
4070 mbEmptyListStyleSetDueToSetOutlineLevelAttr = false;
4071 }
4072}
4073
4074void SwTextNode::SetAttrListLevel( int nLevel )
4075{
4076 if ( nLevel < 0 || nLevel >= MAXLEVEL )
4077 {
4078 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 4078, __extension__ __PRETTY_FUNCTION__))
; // invalid level
4079 return;
4080 }
4081
4082 SfxInt16Item aNewListLevelItem( RES_PARATR_LIST_LEVEL,
4083 static_cast<sal_Int16>(nLevel) );
4084 SetAttr( aNewListLevelItem );
4085}
4086
4087bool SwTextNode::HasAttrListLevel() const
4088{
4089 return GetpSwAttrSet() &&
4090 GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_LEVEL, false ) == SfxItemState::SET;
4091}
4092
4093int SwTextNode::GetAttrListLevel() const
4094{
4095 int nAttrListLevel = 0;
4096
4097 const SfxInt16Item& aListLevelItem =
4098 dynamic_cast<const SfxInt16Item&>(GetAttr( RES_PARATR_LIST_LEVEL ));
4099 nAttrListLevel = static_cast<int>(aListLevelItem.GetValue());
4100
4101 return nAttrListLevel;
4102}
4103
4104int SwTextNode::GetActualListLevel() const
4105{
4106 assert(!GetNum() || !mpNodeNumRLHidden || // must be in sync(static_cast <bool> (!GetNum() || !mpNodeNumRLHidden ||
GetNum()->GetLevelInListTree() == mpNodeNumRLHidden->GetLevelInListTree
()) ? void (0) : __assert_fail ("!GetNum() || !mpNodeNumRLHidden || GetNum()->GetLevelInListTree() == mpNodeNumRLHidden->GetLevelInListTree()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 4107, __extension__ __PRETTY_FUNCTION__))
4107 GetNum()->GetLevelInListTree() == mpNodeNumRLHidden->GetLevelInListTree())(static_cast <bool> (!GetNum() || !mpNodeNumRLHidden ||
GetNum()->GetLevelInListTree() == mpNodeNumRLHidden->GetLevelInListTree
()) ? void (0) : __assert_fail ("!GetNum() || !mpNodeNumRLHidden || GetNum()->GetLevelInListTree() == mpNodeNumRLHidden->GetLevelInListTree()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 4107, __extension__ __PRETTY_FUNCTION__))
;
4108 return GetNum() ? GetNum()->GetLevelInListTree() : -1;
4109}
4110
4111void SwTextNode::SetListRestart( bool bRestart )
4112{
4113 if ( !bRestart )
4114 {
4115 // attribute not contained in paragraph style's attribute set. Thus,
4116 // it can be reset to the attribute pool default by resetting the attribute.
4117 ResetAttr( RES_PARATR_LIST_ISRESTART );
4118 }
4119 else
4120 {
4121 SfxBoolItem aNewIsRestartItem( RES_PARATR_LIST_ISRESTART,
4122 true );
4123 SetAttr( aNewIsRestartItem );
4124 }
4125}
4126
4127bool SwTextNode::IsListRestart() const
4128{
4129 const SfxBoolItem& aIsRestartItem =
4130 dynamic_cast<const SfxBoolItem&>(GetAttr( RES_PARATR_LIST_ISRESTART ));
4131
4132 return aIsRestartItem.GetValue();
4133}
4134
4135/** Returns if the paragraph has a visible numbering or bullet.
4136 This includes all kinds of numbering/bullet/outlines.
4137 The concrete list label string has to be checked, too.
4138 */
4139bool SwTextNode::HasVisibleNumberingOrBullet() const
4140{
4141 const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : nullptr;
4142 if ( pRule && IsCountedInList())
4143 {
4144 // #i87154#
4145 // Correction of #newlistlevelattrs#:
4146 // The numbering type has to be checked for bullet lists.
4147 const SwNumFormat& rFormat = pRule->Get( lcl_BoundListLevel(GetActualListLevel()) );
4148 return SVX_NUM_NUMBER_NONE != rFormat.GetNumberingType() ||
4149 !pRule->MakeNumString( *(GetNum()) ).isEmpty();
4150 }
4151
4152 return false;
4153}
4154
4155void SwTextNode::SetAttrListRestartValue( SwNumberTree::tSwNumTreeNumber nNumber )
4156{
4157 const bool bChanged( HasAttrListRestartValue()
4158 ? GetAttrListRestartValue() != nNumber
4159 : nNumber != USHRT_MAX(32767 *2 +1) );
4160
4161 if ( !bChanged && HasAttrListRestartValue() )
4162 return;
4163
4164 if ( nNumber == USHRT_MAX(32767 *2 +1) )
4165 {
4166 ResetAttr( RES_PARATR_LIST_RESTARTVALUE );
4167 }
4168 else
4169 {
4170 SfxInt16Item aNewListRestartValueItem( RES_PARATR_LIST_RESTARTVALUE,
4171 static_cast<sal_Int16>(nNumber) );
4172 SetAttr( aNewListRestartValueItem );
4173 }
4174}
4175
4176bool SwTextNode::HasAttrListRestartValue() const
4177{
4178 return GetpSwAttrSet() &&
4179 GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_RESTARTVALUE, false ) == SfxItemState::SET;
4180}
4181SwNumberTree::tSwNumTreeNumber SwTextNode::GetAttrListRestartValue() const
4182{
4183 OSL_ENSURE( HasAttrListRestartValue(),do { if (true && (!(HasAttrListRestartValue()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4184" ": "), "%s", "<SwTextNode::GetAttrListRestartValue()> - only ask for list restart value, if attribute is set at text node."
); } } while (false)
4184 "<SwTextNode::GetAttrListRestartValue()> - only ask for list restart value, if attribute is set at text node." )do { if (true && (!(HasAttrListRestartValue()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4184" ": "), "%s", "<SwTextNode::GetAttrListRestartValue()> - only ask for list restart value, if attribute is set at text node."
); } } while (false)
;
4185
4186 const SfxInt16Item& aListRestartValueItem =
4187 dynamic_cast<const SfxInt16Item&>(GetAttr( RES_PARATR_LIST_RESTARTVALUE ));
4188 return static_cast<SwNumberTree::tSwNumTreeNumber>(aListRestartValueItem.GetValue());
4189}
4190
4191SwNumberTree::tSwNumTreeNumber SwTextNode::GetActualListStartValue() const
4192{
4193 SwNumberTree::tSwNumTreeNumber nListRestartValue = 1;
4194
4195 if ( IsListRestart() && HasAttrListRestartValue() )
4196 {
4197 nListRestartValue = GetAttrListRestartValue();
4198 }
4199 else
4200 {
4201 SwNumRule* pRule = GetNumRule();
4202 if ( pRule )
4203 {
4204 const SwNumFormat* pFormat =
4205 pRule->GetNumFormat( static_cast<sal_uInt16>(GetAttrListLevel()) );
4206 if ( pFormat )
4207 {
4208 nListRestartValue = pFormat->GetStart();
4209 }
4210 }
4211 }
4212
4213 return nListRestartValue;
4214}
4215
4216bool SwTextNode::IsNotifiable() const
4217{
4218 return m_bNotifiable && IsNotificationEnabled();
4219}
4220
4221bool SwTextNode::IsNotificationEnabled() const
4222{
4223 const SwDoc& rDoc = GetDoc();
4224 return !(rDoc.IsInReading() || rDoc.IsInDtor());
4225}
4226
4227void SwTextNode::SetCountedInList( bool bCounted )
4228{
4229 if ( bCounted )
4230 {
4231 // attribute not contained in paragraph style's attribute set. Thus,
4232 // it can be reset to the attribute pool default by resetting the attribute.
4233 ResetAttr( RES_PARATR_LIST_ISCOUNTED );
4234 }
4235 else
4236 {
4237 SfxBoolItem aIsCountedInListItem( RES_PARATR_LIST_ISCOUNTED, false );
4238 SetAttr( aIsCountedInListItem );
4239 }
4240}
4241
4242bool SwTextNode::IsCountedInList() const
4243{
4244 const SfxBoolItem& aIsCountedInListItem =
4245 dynamic_cast<const SfxBoolItem&>(GetAttr( RES_PARATR_LIST_ISCOUNTED ));
34
Calling 'SwContentNode::GetAttr'
4246
4247 return aIsCountedInListItem.GetValue();
4248}
4249
4250static SwList * FindList(SwTextNode *const pNode)
4251{
4252 const OUString sListId = pNode->GetListId();
4253 if (!sListId.isEmpty())
4254 {
4255 auto & rIDLA(pNode->GetDoc().getIDocumentListsAccess());
4256 SwList* pList = rIDLA.getListByName( sListId );
4257 if ( pList == nullptr )
4258 {
4259 // Create corresponding list.
4260 SwNumRule* pNumRule = pNode->GetNumRule();
4261 if ( pNumRule )
4262 {
4263 pList = rIDLA.createList(sListId, pNode->GetNumRule()->GetName());
4264 }
4265 }
4266 OSL_ENSURE( pList != nullptr,do { if (true && (!(pList != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4267" ": "), "%s", "<SwTextNode::AddToList()> - no list for given list id. Serious defect"
); } } while (false)
4267 "<SwTextNode::AddToList()> - no list for given list id. Serious defect" )do { if (true && (!(pList != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4267" ": "), "%s", "<SwTextNode::AddToList()> - no list for given list id. Serious defect"
); } } while (false)
;
4268 return pList;
4269 }
4270 return nullptr;
4271}
4272
4273void SwTextNode::AddToList()
4274{
4275 if ( IsInList() )
4276 {
4277 OSL_FAIL( "<SwTextNode::AddToList()> - the text node is already added to a list. Serious defect" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4277" ": "), "%s", "<SwTextNode::AddToList()> - the text node is already added to a list. Serious defect"
); } } while (false)
;
4278 return;
4279 }
4280
4281 SwList *const pList(FindList(this));
4282 if (!(pList && GetNodes().IsDocNodes())) // not for undo nodes
4283 return;
4284
4285 assert(!mpNodeNum)(static_cast <bool> (!mpNodeNum) ? void (0) : __assert_fail
("!mpNodeNum", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 4285, __extension__ __PRETTY_FUNCTION__))
;
4286 mpNodeNum.reset(new SwNodeNum(this, false));
4287 pList->InsertListItem(*mpNodeNum, false, GetAttrListLevel());
4288 // iterate all frames & if there's one with hidden layout...
4289 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> iter(*this);
4290 for (SwTextFrame* pFrame = iter.First(); pFrame; pFrame = iter.Next())
4291 {
4292 if (pFrame->getRootFrame()->IsHideRedlines())
4293 {
4294 if (pFrame->GetTextNodeForParaProps() == this)
4295 {
4296 AddToListRLHidden();
4297 }
4298 break; // assume it's consistent, need to check only once
4299 }
4300 }
4301}
4302
4303void SwTextNode::AddToListRLHidden()
4304{
4305 if (mpNodeNumRLHidden)
4306 {
4307 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 4307, __extension__ __PRETTY_FUNCTION__))
;
4308 OSL_FAIL( "<SwTextNode::AddToListRLHidden()> - the text node is already added to a list. Serious defect" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4308" ": "), "%s", "<SwTextNode::AddToListRLHidden()> - the text node is already added to a list. Serious defect"
); } } while (false)
;
4309 return;
4310 }
4311
4312 SwList *const pList(FindList(this));
4313 if (pList)
4314 {
4315 assert(!mpNodeNumRLHidden)(static_cast <bool> (!mpNodeNumRLHidden) ? void (0) : __assert_fail
("!mpNodeNumRLHidden", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 4315, __extension__ __PRETTY_FUNCTION__))
;
4316 mpNodeNumRLHidden.reset(new SwNodeNum(this, true));
4317 pList->InsertListItem(*mpNodeNumRLHidden, true, GetAttrListLevel());
4318 }
4319}
4320
4321void SwTextNode::RemoveFromList()
4322{
4323 // sw_redlinehide: ensure it's removed from the other half too!
4324 RemoveFromListRLHidden();
4325 if ( IsInList() )
4326 {
4327 SwList::RemoveListItem( *mpNodeNum );
4328 mpNodeNum.reset();
4329
4330 SetWordCountDirty( true );
4331 }
4332}
4333
4334void SwTextNode::RemoveFromListRLHidden()
4335{
4336 if (mpNodeNumRLHidden) // direct access because RemoveFromList doesn't have layout
4337 {
4338 assert(mpNodeNumRLHidden->GetParent() || !GetNodes().IsDocNodes())(static_cast <bool> (mpNodeNumRLHidden->GetParent() ||
!GetNodes().IsDocNodes()) ? void (0) : __assert_fail ("mpNodeNumRLHidden->GetParent() || !GetNodes().IsDocNodes()"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 4338, __extension__ __PRETTY_FUNCTION__))
;
4339 SwList::RemoveListItem(*mpNodeNumRLHidden);
4340 mpNodeNumRLHidden.reset();
4341
4342 SetWordCountDirty( true );
4343 }
4344}
4345
4346bool SwTextNode::IsInList() const
4347{
4348 return GetNum() != nullptr && GetNum()->GetParent() != nullptr;
4349}
4350
4351bool SwTextNode::IsFirstOfNumRule(SwRootFrame const& rLayout) const
4352{
4353 bool bResult = false;
4354
4355 SwNodeNum const*const pNum(GetNum(&rLayout));
4356 if (pNum && pNum->GetNumRule())
4357 bResult = pNum->IsFirst();
4358
4359 return bResult;
4360}
4361
4362void SwTextNode::SetListId(OUString const& rListId)
4363{
4364 const SfxStringItem& rListIdItem =
4365 dynamic_cast<const SfxStringItem&>(GetAttr( RES_PARATR_LIST_ID ));
4366 if (rListIdItem.GetValue() != rListId)
4367 {
4368 if (rListId.isEmpty())
4369 {
4370 ResetAttr( RES_PARATR_LIST_ID );
4371 }
4372 else
4373 {
4374 SfxStringItem aNewListIdItem(RES_PARATR_LIST_ID, rListId);
4375 SetAttr( aNewListIdItem );
4376 }
4377 }
4378}
4379
4380OUString SwTextNode::GetListId() const
4381{
4382 const SfxStringItem& rListIdItem =
4383 dynamic_cast<const SfxStringItem&>(GetAttr( RES_PARATR_LIST_ID ));
4384 const OUString& sListId {rListIdItem.GetValue()};
4385
4386 // As long as no explicit list id attribute is set, use the list id of
4387 // the list, which has been created for the applied list style.
4388 if (sListId.isEmpty())
4389 {
4390 SwNumRule* pRule = GetNumRule();
4391 if ( pRule )
4392 {
4393 return pRule->GetDefaultListId();
4394 }
4395 }
4396
4397 return sListId;
4398}
4399
4400/** Determines, if the list level indent attributes can be applied to the
4401 paragraph.
4402
4403 The list level indents can be applied to the paragraph under the one
4404 of following conditions:
4405 - the list style is directly applied to the paragraph and the paragraph
4406 has no own indent attributes.
4407 - the list style is applied to the paragraph through one of its paragraph
4408 styles, the paragraph has no own indent attributes and on the paragraph
4409 style hierarchy from the paragraph to the paragraph style with the
4410 list style no indent attributes are found.
4411
4412 @return boolean
4413*/
4414bool SwTextNode::AreListLevelIndentsApplicable() const
4415{
4416 bool bAreListLevelIndentsApplicable( true );
4417
4418 if ( !GetNum() || !GetNum()->GetNumRule() )
4419 {
4420 // no list style applied to paragraph
4421 bAreListLevelIndentsApplicable = false;
4422 }
4423 else if ( HasSwAttrSet() &&
4424 GetpSwAttrSet()->GetItemState( RES_LR_SPACE, false ) == SfxItemState::SET )
4425 {
4426 // paragraph has hard-set indent attributes
4427 bAreListLevelIndentsApplicable = false;
4428 }
4429 else if ( HasSwAttrSet() &&
4430 GetpSwAttrSet()->GetItemState( RES_PARATR_NUMRULE, false ) == SfxItemState::SET )
4431 {
4432 // list style is directly applied to paragraph and paragraph has no
4433 // hard-set indent attributes
4434 bAreListLevelIndentsApplicable = true;
4435 }
4436 else
4437 {
4438 // list style is applied through one of the paragraph styles and
4439 // paragraph has no hard-set indent attributes
4440
4441 // check, paragraph's
4442 const SwTextFormatColl* pColl = GetTextColl();
4443 while ( pColl )
4444 {
4445 if ( pColl->GetAttrSet().GetItemState( RES_LR_SPACE, false ) == SfxItemState::SET )
4446 {
4447 // indent attributes found in the paragraph style hierarchy.
4448 bAreListLevelIndentsApplicable = false;
4449 break;
4450 }
4451
4452 if ( pColl->GetAttrSet().GetItemState( RES_PARATR_NUMRULE, false ) == SfxItemState::SET )
4453 {
4454 // paragraph style with the list style found and until now no
4455 // indent attributes are found in the paragraph style hierarchy.
4456 bAreListLevelIndentsApplicable = true;
4457 break;
4458 }
4459
4460 pColl = dynamic_cast<const SwTextFormatColl*>(pColl->DerivedFrom());
4461 OSL_ENSURE( pColl,do { if (true && (!(pColl))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4462" ": "), "%s", "<SwTextNode::AreListLevelIndentsApplicable()> - something wrong in paragraph's style hierarchy. The applied list style is not found."
); } } while (false)
4462 "<SwTextNode::AreListLevelIndentsApplicable()> - something wrong in paragraph's style hierarchy. The applied list style is not found." )do { if (true && (!(pColl))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4462" ": "), "%s", "<SwTextNode::AreListLevelIndentsApplicable()> - something wrong in paragraph's style hierarchy. The applied list style is not found."
); } } while (false)
;
4463 }
4464 }
4465
4466 return bAreListLevelIndentsApplicable;
4467}
4468
4469/** Retrieves the list tab stop position, if the paragraph's list level defines
4470 one and this list tab stop has to merged into the tap stops of the paragraph
4471
4472 @param nListTabStopPosition
4473 output parameter - containing the list tab stop position
4474
4475 @return boolean - indicating, if a list tab stop position is provided
4476*/
4477bool SwTextNode::GetListTabStopPosition( long& nListTabStopPosition ) const
4478{
4479 bool bListTabStopPositionProvided(false);
4480
4481 const SwNumRule* pNumRule = GetNum() ? GetNum()->GetNumRule() : nullptr;
4482 if ( pNumRule && HasVisibleNumberingOrBullet() && GetActualListLevel() >= 0 )
4483 {
4484 const SwNumFormat& rFormat = pNumRule->Get( static_cast<sal_uInt16>(GetActualListLevel()) );
4485 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT &&
4486 rFormat.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB )
4487 {
4488 bListTabStopPositionProvided = true;
4489 nListTabStopPosition = rFormat.GetListtabPos();
4490
4491 if ( getIDocumentSettingAccess()->get(DocumentSettingId::TABS_RELATIVE_TO_INDENT) )
4492 {
4493 // tab stop position are treated to be relative to the "before text"
4494 // indent value of the paragraph. Thus, adjust <nListTabStopPos>.
4495 if ( AreListLevelIndentsApplicable() )
4496 {
4497 nListTabStopPosition -= rFormat.GetIndentAt();
4498 }
4499 else if (!getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
4500 {
4501 SvxLRSpaceItem aItem = GetSwAttrSet().GetLRSpace();
4502 nListTabStopPosition -= aItem.GetTextLeft();
4503 }
4504 }
4505 }
4506 }
4507
4508 return bListTabStopPositionProvided;
4509}
4510
4511OUString SwTextNode::GetLabelFollowedBy() const
4512{
4513 const SwNumRule* pNumRule = GetNum() ? GetNum()->GetNumRule() : nullptr;
4514 if ( pNumRule && HasVisibleNumberingOrBullet() && GetActualListLevel() >= 0 )
4515 {
4516 const SwNumFormat& rFormat = pNumRule->Get( static_cast<sal_uInt16>(GetActualListLevel()) );
4517 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
4518 {
4519 switch ( rFormat.GetLabelFollowedBy() )
4520 {
4521 case SvxNumberFormat::LISTTAB:
4522 {
4523 return "\t";
4524 }
4525 break;
4526 case SvxNumberFormat::SPACE:
4527 {
4528 return " ";
4529 }
4530 break;
4531 case SvxNumberFormat::NEWLINE:
4532 {
4533 return "\n";
4534 }
4535 break;
4536 case SvxNumberFormat::NOTHING:
4537 {
4538 // intentionally left blank.
4539 }
4540 break;
4541 default:
4542 {
4543 OSL_FAIL( "<SwTextNode::GetLabelFollowedBy()> - unknown SvxNumberFormat::GetLabelFollowedBy() return value" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4543" ": "), "%s", "<SwTextNode::GetLabelFollowedBy()> - unknown SvxNumberFormat::GetLabelFollowedBy() return value"
); } } while (false)
;
4544 }
4545 }
4546 }
4547 }
4548
4549 return OUString();
4550}
4551
4552void SwTextNode::CalcHiddenCharFlags() const
4553{
4554 sal_Int32 nStartPos;
4555 sal_Int32 nEndPos;
4556 // Update of the flags is done inside GetBoundsOfHiddenRange()
4557 SwScriptInfo::GetBoundsOfHiddenRange( *this, 0, nStartPos, nEndPos );
4558}
4559
4560// #i12836# enhanced pdf export
4561bool SwTextNode::IsHidden() const
4562{
4563 if ( IsHiddenByParaField() || HasHiddenCharAttribute( true ) )
4564 return true;
4565
4566 const SwSectionNode* pSectNd = FindSectionNode();
4567 return pSectNd && pSectNd->GetSection().IsHiddenFlag();
4568}
4569
4570namespace {
4571 // Helper class for special handling of setting attributes at text node:
4572 // In constructor an instance of the helper class recognize whose attributes
4573 // are set and perform corresponding actions before the intrinsic set of
4574 // attributes has been taken place.
4575 // In the destructor - after the attributes have been set at the text
4576 // node - corresponding actions are performed.
4577 // The following is handled:
4578 // (1) When the list style attribute - RES_PARATR_NUMRULE - is set,
4579 // (A) list style attribute is empty -> the text node is removed from
4580 // its list.
4581 // (B) list style attribute is not empty
4582 // (a) text node has no list style -> add text node to its list after
4583 // the attributes have been set.
4584 // (b) text node has list style -> change of list style is notified
4585 // after the attributes have been set.
4586 // (2) When the list id attribute - RES_PARATR_LIST_ID - is set and changed,
4587 // the text node is removed from its current list before the attributes
4588 // are set and added to its new list after the attributes have been set.
4589 // (3) Notify list tree, if list level - RES_PARATR_LIST_LEVEL - is set
4590 // and changed after the attributes have been set
4591 // (4) Notify list tree, if list restart - RES_PARATR_LIST_ISRESTART - is set
4592 // and changed after the attributes have been set
4593 // (5) Notify list tree, if list restart value - RES_PARATR_LIST_RESTARTVALUE -
4594 // is set and changed after the attributes have been set
4595 // (6) Notify list tree, if count in list - RES_PARATR_LIST_ISCOUNTED - is set
4596 // and changed after the attributes have been set
4597 // (7) Set or Reset empty list style due to changed outline level - RES_PARATR_OUTLINELEVEL.
4598 class HandleSetAttrAtTextNode
4599 {
4600 public:
4601 HandleSetAttrAtTextNode( SwTextNode& rTextNode,
4602 const SfxPoolItem& pItem );
4603 HandleSetAttrAtTextNode( SwTextNode& rTextNode,
4604 const SfxItemSet& rItemSet );
4605 ~HandleSetAttrAtTextNode() COVERITY_NOEXCEPT_FALSE;
4606
4607 private:
4608 SwTextNode& mrTextNode;
4609 bool mbAddTextNodeToList;
4610 bool mbUpdateListLevel;
4611 bool mbUpdateListRestart;
4612 bool mbUpdateListCount;
4613 // #i70748#
4614 bool mbOutlineLevelSet;
4615 };
4616
4617 HandleSetAttrAtTextNode::HandleSetAttrAtTextNode( SwTextNode& rTextNode,
4618 const SfxPoolItem& pItem )
4619 : mrTextNode( rTextNode ),
4620 mbAddTextNodeToList( false ),
4621 mbUpdateListLevel( false ),
4622 mbUpdateListRestart( false ),
4623 mbUpdateListCount( false ),
4624 // #i70748#
4625 mbOutlineLevelSet( false )
4626 {
4627 switch ( pItem.Which() )
4628 {
4629 // handle RES_PARATR_NUMRULE
4630 case RES_PARATR_NUMRULE:
4631 {
4632 mrTextNode.RemoveFromList();
4633
4634 const SwNumRuleItem& rNumRuleItem =
4635 dynamic_cast<const SwNumRuleItem&>(pItem);
4636 if ( !rNumRuleItem.GetValue().isEmpty() )
4637 {
4638 mbAddTextNodeToList = true;
4639 // #i105562#
4640
4641 mrTextNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
4642 }
4643 }
4644 break;
4645
4646 // handle RES_PARATR_LIST_ID
4647 case RES_PARATR_LIST_ID:
4648 {
4649 const SfxStringItem& rListIdItem =
4650 dynamic_cast<const SfxStringItem&>(pItem);
4651 OSL_ENSURE( rListIdItem.GetValue().getLength() > 0,do { if (true && (!(rListIdItem.GetValue().getLength(
) > 0))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4652" ": "), "%s", "<HandleSetAttrAtTextNode(..)> - empty list id attribute not expected. Serious defect."
); } } while (false)
4652 "<HandleSetAttrAtTextNode(..)> - empty list id attribute not expected. Serious defect." )do { if (true && (!(rListIdItem.GetValue().getLength(
) > 0))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
":" "4652" ": "), "%s", "<HandleSetAttrAtTextNode(..)> - empty list id attribute not expected. Serious defect."
); } } while (false)
;
4653 const OUString sListIdOfTextNode = rTextNode.GetListId();
4654 if ( rListIdItem.GetValue() != sListIdOfTextNode )
4655 {
4656 mbAddTextNodeToList = true;
4657 if ( mrTextNode.IsInList() )
4658 {
4659 mrTextNode.RemoveFromList();
4660 }
4661 }
4662 }
4663 break;
4664
4665 // handle RES_PARATR_LIST_LEVEL
4666 case RES_PARATR_LIST_LEVEL:
4667 {
4668 const SfxInt16Item& aListLevelItem =
4669 dynamic_cast<const SfxInt16Item&>(pItem);
4670 if ( aListLevelItem.GetValue() != mrTextNode.GetAttrListLevel() )
4671 {
4672 mbUpdateListLevel = true;
4673 }
4674 }
4675 break;
4676
4677 // handle RES_PARATR_LIST_ISRESTART
4678 case RES_PARATR_LIST_ISRESTART:
4679 {
4680 const SfxBoolItem& aListIsRestartItem =
4681 dynamic_cast<const SfxBoolItem&>(pItem);
4682 if ( aListIsRestartItem.GetValue() !=
4683 mrTextNode.IsListRestart() )
4684 {
4685 mbUpdateListRestart = true;
4686 }
4687 }
4688 break;
4689
4690 // handle RES_PARATR_LIST_RESTARTVALUE
4691 case RES_PARATR_LIST_RESTARTVALUE:
4692 {
4693 const SfxInt16Item& aListRestartValueItem =
4694 dynamic_cast<const SfxInt16Item&>(pItem);
4695 if ( !mrTextNode.HasAttrListRestartValue() ||
4696 aListRestartValueItem.GetValue() != mrTextNode.GetAttrListRestartValue() )
4697 {
4698 mbUpdateListRestart = true;
4699 }
4700 }
4701 break;
4702
4703 // handle RES_PARATR_LIST_ISCOUNTED
4704 case RES_PARATR_LIST_ISCOUNTED:
4705 {
4706 const SfxBoolItem& aIsCountedInListItem =
4707 dynamic_cast<const SfxBoolItem&>(pItem);
4708 if ( aIsCountedInListItem.GetValue() !=
4709 mrTextNode.IsCountedInList() )
4710 {
4711 mbUpdateListCount = true;
4712 }
4713 }
4714 break;
4715
4716 // #i70748#
4717 // handle RES_PARATR_OUTLINELEVEL
4718 case RES_PARATR_OUTLINELEVEL:
4719 {
4720 const SfxUInt16Item& aOutlineLevelItem =
4721 dynamic_cast<const SfxUInt16Item&>(pItem);
4722 if ( aOutlineLevelItem.GetValue() != mrTextNode.GetAttrOutlineLevel() )
4723 {
4724 mbOutlineLevelSet = true;
4725 }
4726 }
4727 break;
4728 }
4729
4730 }
4731
4732 HandleSetAttrAtTextNode::HandleSetAttrAtTextNode( SwTextNode& rTextNode,
4733 const SfxItemSet& rItemSet )
4734 : mrTextNode( rTextNode ),
4735 mbAddTextNodeToList( false ),
4736 mbUpdateListLevel( false ),
4737 mbUpdateListRestart( false ),
4738 mbUpdateListCount( false ),
4739 // #i70748#
4740 mbOutlineLevelSet( false )
4741 {
4742 const SfxPoolItem* pItem = nullptr;
4743 // handle RES_PARATR_NUMRULE
4744 if ( rItemSet.GetItemState( RES_PARATR_NUMRULE, false, &pItem ) == SfxItemState::SET )
20
Assuming the condition is false
21
Taking false branch
4745 {
4746 mrTextNode.RemoveFromList();
4747
4748 const SwNumRuleItem* pNumRuleItem =
4749 dynamic_cast<const SwNumRuleItem*>(pItem);
4750 assert(pNumRuleItem)(static_cast <bool> (pNumRuleItem) ? void (0) : __assert_fail
("pNumRuleItem", "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 4750, __extension__ __PRETTY_FUNCTION__))
;
4751 if ( !pNumRuleItem->GetValue().isEmpty() )
4752 {
4753 mbAddTextNodeToList = true;
4754 // #i70748#
4755 mrTextNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
4756 }
4757 }
4758
4759 // handle RES_PARATR_LIST_ID
4760 if ( rItemSet.GetItemState( RES_PARATR_LIST_ID, false, &pItem ) == SfxItemState::SET )
22
Assuming the condition is false
23
Taking false branch
4761 {
4762 const SfxStringItem* pListIdItem =
4763 dynamic_cast<const SfxStringItem*>(pItem);
4764 const OUString sListIdOfTextNode = mrTextNode.GetListId();
4765 if ( pListIdItem &&
4766 pListIdItem->GetValue() != sListIdOfTextNode )
4767 {
4768 mbAddTextNodeToList = true;
4769 if ( mrTextNode.IsInList() )
4770 {
4771 mrTextNode.RemoveFromList();
4772 }
4773 }
4774 }
4775
4776 // handle RES_PARATR_LIST_LEVEL
4777 if ( rItemSet.GetItemState( RES_PARATR_LIST_LEVEL, false, &pItem ) == SfxItemState::SET )
24
Assuming the condition is false
25
Taking false branch
4778 {
4779 const SfxInt16Item* pListLevelItem =
4780 dynamic_cast<const SfxInt16Item*>(pItem);
4781 if (pListLevelItem && pListLevelItem->GetValue() != mrTextNode.GetAttrListLevel())
4782 {
4783 mbUpdateListLevel = true;
4784 }
4785 }
4786
4787 // handle RES_PARATR_LIST_ISRESTART
4788 if ( rItemSet.GetItemState( RES_PARATR_LIST_ISRESTART, false, &pItem ) == SfxItemState::SET )
26
Assuming the condition is false
27
Taking false branch
4789 {
4790 const SfxBoolItem* pListIsRestartItem =
4791 dynamic_cast<const SfxBoolItem*>(pItem);
4792 if (pListIsRestartItem && pListIsRestartItem->GetValue() != mrTextNode.IsListRestart())
4793 {
4794 mbUpdateListRestart = true;
4795 }
4796 }
4797
4798 // handle RES_PARATR_LIST_RESTARTVALUE
4799 if ( rItemSet.GetItemState( RES_PARATR_LIST_RESTARTVALUE, false, &pItem ) == SfxItemState::SET )
28
Assuming the condition is true
29
Taking true branch
4800 {
4801 const SfxInt16Item* pListRestartValueItem =
4802 dynamic_cast<const SfxInt16Item*>(pItem);
4803 if ( !mrTextNode.HasAttrListRestartValue() || (pListRestartValueItem &&
4804 pListRestartValueItem->GetValue() != mrTextNode.GetAttrListRestartValue()) )
4805 {
4806 mbUpdateListRestart = true;
4807 }
4808 }
4809
4810 // handle RES_PARATR_LIST_ISCOUNTED
4811 if ( rItemSet.GetItemState( RES_PARATR_LIST_ISCOUNTED, false, &pItem ) == SfxItemState::SET )
30
Assuming the condition is true
31
Taking true branch
4812 {
4813 const SfxBoolItem* pIsCountedInListItem =
4814 dynamic_cast<const SfxBoolItem*>(pItem);
4815 if (pIsCountedInListItem && pIsCountedInListItem->GetValue() !=
32
Assuming 'pIsCountedInListItem' is non-null
4816 mrTextNode.IsCountedInList())
33
Calling 'SwTextNode::IsCountedInList'
4817 {
4818 mbUpdateListCount = true;
4819 }
4820 }
4821
4822 // #i70748#
4823 // handle RES_PARATR_OUTLINELEVEL
4824 if ( rItemSet.GetItemState( RES_PARATR_OUTLINELEVEL, false, &pItem ) == SfxItemState::SET )
4825 {
4826 const SfxUInt16Item* pOutlineLevelItem =
4827 dynamic_cast<const SfxUInt16Item*>(pItem);
4828 if (pOutlineLevelItem && pOutlineLevelItem->GetValue() !=
4829 mrTextNode.GetAttrOutlineLevel())
4830 {
4831 mbOutlineLevelSet = true;
4832 }
4833 }
4834 }
4835
4836 HandleSetAttrAtTextNode::~HandleSetAttrAtTextNode() COVERITY_NOEXCEPT_FALSE
4837 {
4838 if ( mbAddTextNodeToList )
4839 {
4840 SwNumRule* pNumRuleAtTextNode = mrTextNode.GetNumRule();
4841 if ( pNumRuleAtTextNode )
4842 {
4843 mrTextNode.AddToList();
4844 }
4845 }
4846 else
4847 {
4848 if ( mbUpdateListLevel && mrTextNode.IsInList() )
4849 {
4850 auto const nLevel(mrTextNode.GetAttrListLevel());
4851 mrTextNode.DoNum(
4852 [nLevel](SwNodeNum & rNum) { rNum.SetLevelInListTree(nLevel); });
4853 }
4854
4855 if ( mbUpdateListRestart && mrTextNode.IsInList() )
4856 {
4857 mrTextNode.DoNum(
4858 [](SwNodeNum & rNum) {
4859 rNum.InvalidateMe();
4860 rNum.NotifyInvalidSiblings();
4861 });
4862 }
4863
4864 if ( mbUpdateListCount && mrTextNode.IsInList() )
4865 {
4866 mrTextNode.DoNum(
4867 [](SwNodeNum & rNum) { rNum.InvalidateAndNotifyTree(); });
4868 }
4869 }
4870
4871 // #i70748#
4872 if (!mbOutlineLevelSet)
4873 return;
4874
4875 mrTextNode.GetNodes().UpdateOutlineNode(mrTextNode);
4876 if (mrTextNode.GetAttrOutlineLevel() == 0)
4877 {
4878 mrTextNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
4879 }
4880 else
4881 {
4882 const SfxPoolItem* pItem = nullptr;
4883 if ( mrTextNode.GetSwAttrSet().GetItemState( RES_PARATR_NUMRULE,
4884 true, &pItem )
4885 != SfxItemState::SET )
4886 {
4887 mrTextNode.SetEmptyListStyleDueToSetOutlineLevelAttr();
4888 }
4889 }
4890 }
4891 // End of class <HandleSetAttrAtTextNode>
4892}
4893
4894bool SwTextNode::SetAttr( const SfxPoolItem& pItem )
4895{
4896 const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
4897 mbInSetOrResetAttr = true;
4898
4899 HandleSetAttrAtTextNode aHandleSetAttr( *this, pItem );
4900
4901 bool bRet = SwContentNode::SetAttr( pItem );
4902
4903 mbInSetOrResetAttr = bOldIsSetOrResetAttr;
4904
4905 return bRet;
4906}
4907
4908bool SwTextNode::SetAttr( const SfxItemSet& rSet )
4909{
4910 const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
4911 mbInSetOrResetAttr = true;
4912
4913 HandleSetAttrAtTextNode aHandleSetAttr( *this, rSet );
19
Calling constructor for 'HandleSetAttrAtTextNode'
4914
4915 bool bRet = SwContentNode::SetAttr( rSet );
4916
4917 mbInSetOrResetAttr = bOldIsSetOrResetAttr;
4918
4919 return bRet;
4920}
4921
4922namespace {
4923 // Helper class for special handling of resetting attributes at text node:
4924 // In constructor an instance of the helper class recognize whose attributes
4925 // are reset and perform corresponding actions before the intrinsic reset of
4926 // attributes has been taken place.
4927 // In the destructor - after the attributes have been reset at the text
4928 // node - corresponding actions are performed.
4929 // The following is handled:
4930 // (1) When the list style attribute - RES_PARATR_NUMRULE - is reset,
4931 // the text is removed from its list before the attributes have been reset.
4932 // (2) When the list id attribute - RES_PARATR_LIST_ID - is reset,
4933 // the text is removed from its list before the attributes have been reset.
4934 // (3) Notify list tree, if list level - RES_PARATR_LIST_LEVEL - is reset.
4935 // (4) Notify list tree, if list restart - RES_PARATR_LIST_ISRESTART - is reset.
4936 // (5) Notify list tree, if list restart value - RES_PARATR_LIST_RESTARTVALUE - is reset.
4937 // (6) Notify list tree, if count in list - RES_PARATR_LIST_ISCOUNTED - is reset.
4938 // (7) Reset empty list style, if outline level attribute - RES_PARATR_OUTLINELEVEL - is reset.
4939 class HandleResetAttrAtTextNode
4940 {
4941 public:
4942 HandleResetAttrAtTextNode( SwTextNode& rTextNode,
4943 const sal_uInt16 nWhich1,
4944 sal_uInt16 nWhich2 );
4945 HandleResetAttrAtTextNode( SwTextNode& rTextNode,
4946 const std::vector<sal_uInt16>& rWhichArr );
4947 explicit HandleResetAttrAtTextNode( SwTextNode& rTextNode );
4948
4949 ~HandleResetAttrAtTextNode() COVERITY_NOEXCEPT_FALSE;
4950
4951 private:
4952 SwTextNode& mrTextNode;
4953 bool mbListStyleOrIdReset;
4954 bool mbUpdateListLevel;
4955 bool mbUpdateListRestart;
4956 bool mbUpdateListCount;
4957
4958 void init( const std::vector<sal_uInt16>& rWhichArr );
4959 };
4960
4961 HandleResetAttrAtTextNode::HandleResetAttrAtTextNode( SwTextNode& rTextNode,
4962 const sal_uInt16 nWhich1,
4963 sal_uInt16 nWhich2 )
4964 : mrTextNode( rTextNode ),
4965 mbListStyleOrIdReset( false ),
4966 mbUpdateListLevel( false ),
4967 mbUpdateListRestart( false ),
4968 mbUpdateListCount( false )
4969 {
4970 if ( nWhich2 < nWhich1 )
4971 nWhich2 = nWhich1;
4972 std::vector<sal_uInt16> rWhichArr;
4973 for ( sal_uInt16 nWhich = nWhich1; nWhich <= nWhich2; ++nWhich )
4974 rWhichArr.push_back( nWhich );
4975
4976 init( rWhichArr );
4977 }
4978
4979 HandleResetAttrAtTextNode::HandleResetAttrAtTextNode( SwTextNode& rTextNode,
4980 const std::vector<sal_uInt16>& rWhichArr )
4981 : mrTextNode( rTextNode ),
4982 mbListStyleOrIdReset( false ),
4983 mbUpdateListLevel( false ),
4984 mbUpdateListRestart( false ),
4985 mbUpdateListCount( false )
4986 {
4987 init( rWhichArr );
4988 }
4989
4990 HandleResetAttrAtTextNode::HandleResetAttrAtTextNode( SwTextNode& rTextNode )
4991 : mrTextNode( rTextNode ),
4992 mbListStyleOrIdReset( true ),
4993 mbUpdateListLevel( false ),
4994 mbUpdateListRestart( false ),
4995 mbUpdateListCount( false )
4996 {
4997 if ( rTextNode.IsInList() )
4998 {
4999 rTextNode.RemoveFromList();
5000 }
5001 // #i70748#
5002 mrTextNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
5003 }
5004
5005 void HandleResetAttrAtTextNode::init( const std::vector<sal_uInt16>& rWhichArr )
5006 {
5007 bool bRemoveFromList( false );
5008 {
5009 for (const auto& rWhich : rWhichArr)
5010 {
5011 if ( rWhich == RES_PARATR_NUMRULE )
5012 {
5013 bRemoveFromList = bRemoveFromList ||
5014 mrTextNode.GetNumRule() != nullptr;
5015 mbListStyleOrIdReset = true;
5016 }
5017 else if ( rWhich == RES_PARATR_LIST_ID )
5018 {
5019 bRemoveFromList = bRemoveFromList ||
5020 ( mrTextNode.GetpSwAttrSet() &&
5021 mrTextNode.GetpSwAttrSet()->GetItemState( RES_PARATR_LIST_ID, false ) == SfxItemState::SET );
5022 mbListStyleOrIdReset = true;
5023 }
5024 else if ( rWhich == RES_PARATR_OUTLINELEVEL )
5025 mrTextNode.ResetEmptyListStyleDueToResetOutlineLevelAttr();
5026 else if ( rWhich == RES_BACKGROUND )
5027 mrTextNode.ResetAttr( XATTR_FILL_FIRST, XATTR_FILL_LAST );
5028
5029 if ( !bRemoveFromList )
5030 {
5031 // RES_PARATR_LIST_LEVEL
5032 mbUpdateListLevel = mbUpdateListLevel ||
5033 ( rWhich == RES_PARATR_LIST_LEVEL &&
5034 mrTextNode.HasAttrListLevel() );
5035
5036 // RES_PARATR_LIST_ISRESTART and RES_PARATR_LIST_RESTARTVALUE
5037 mbUpdateListRestart = mbUpdateListRestart ||
5038 ( rWhich == RES_PARATR_LIST_ISRESTART &&
5039 mrTextNode.IsListRestart() ) ||
5040 ( rWhich == RES_PARATR_LIST_RESTARTVALUE &&
5041 mrTextNode.HasAttrListRestartValue() );
5042
5043 // RES_PARATR_LIST_ISCOUNTED
5044 mbUpdateListCount = mbUpdateListCount ||
5045 ( rWhich == RES_PARATR_LIST_ISCOUNTED &&
5046 !mrTextNode.IsCountedInList() );
5047 }
5048 }
5049 }
5050
5051 if ( bRemoveFromList && mrTextNode.IsInList() )
5052 {
5053 mrTextNode.RemoveFromList();
5054 }
5055 }
5056
5057 HandleResetAttrAtTextNode::~HandleResetAttrAtTextNode() COVERITY_NOEXCEPT_FALSE
5058 {
5059 if ( mbListStyleOrIdReset && !mrTextNode.IsInList() )
5060 {
5061 // check, if in spite of the reset of the list style or the list id
5062 // the paragraph still has to be added to a list.
5063 if (mrTextNode.GetNumRule() && !mrTextNode.GetListId().isEmpty())
5064 {
5065 // #i96062#
5066 // If paragraph has no list level attribute set and list style
5067 // is the outline style, apply outline level as the list level.
5068 if ( !mrTextNode.HasAttrListLevel() &&
5069 mrTextNode.GetNumRule()->GetName()==SwNumRule::GetOutlineRuleName() &&
5070 mrTextNode.GetTextColl()->IsAssignedToListLevelOfOutlineStyle() )
5071 {
5072 int nNewListLevel = mrTextNode.GetTextColl()->GetAssignedOutlineStyleLevel();
5073 if ( 0 <= nNewListLevel && nNewListLevel < MAXLEVEL )
5074 {
5075 mrTextNode.SetAttrListLevel( nNewListLevel );
5076 }
5077 }
5078 mrTextNode.AddToList();
5079 }
5080 // #i70748#
5081 // #i105562#
5082 else
5083 {
5084 assert(!mrTextNode.GetpSwAttrSet()(static_cast <bool> (!mrTextNode.GetpSwAttrSet() || dynamic_cast
<const SfxUInt16Item*>( &mrTextNode.GetAttr(RES_PARATR_OUTLINELEVEL
, false))) ? void (0) : __assert_fail ("!mrTextNode.GetpSwAttrSet() || dynamic_cast<const SfxUInt16Item*>( &mrTextNode.GetAttr(RES_PARATR_OUTLINELEVEL, false))"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 5086, __extension__ __PRETTY_FUNCTION__))
5085 || dynamic_cast<const SfxUInt16Item*>((static_cast <bool> (!mrTextNode.GetpSwAttrSet() || dynamic_cast
<const SfxUInt16Item*>( &mrTextNode.GetAttr(RES_PARATR_OUTLINELEVEL
, false))) ? void (0) : __assert_fail ("!mrTextNode.GetpSwAttrSet() || dynamic_cast<const SfxUInt16Item*>( &mrTextNode.GetAttr(RES_PARATR_OUTLINELEVEL, false))"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 5086, __extension__ __PRETTY_FUNCTION__))
5086 &mrTextNode.GetAttr(RES_PARATR_OUTLINELEVEL, false)))(static_cast <bool> (!mrTextNode.GetpSwAttrSet() || dynamic_cast
<const SfxUInt16Item*>( &mrTextNode.GetAttr(RES_PARATR_OUTLINELEVEL
, false))) ? void (0) : __assert_fail ("!mrTextNode.GetpSwAttrSet() || dynamic_cast<const SfxUInt16Item*>( &mrTextNode.GetAttr(RES_PARATR_OUTLINELEVEL, false))"
, "/home/maarten/src/libreoffice/core/sw/source/core/txtnode/ndtxt.cxx"
, 5086, __extension__ __PRETTY_FUNCTION__))
;
5087 if (mrTextNode.GetpSwAttrSet()
5088 && static_cast<const SfxUInt16Item&>(
5089 mrTextNode.GetAttr(RES_PARATR_OUTLINELEVEL, false)).GetValue() > 0)
5090 {
5091 mrTextNode.SetEmptyListStyleDueToSetOutlineLevelAttr();
5092 }
5093 }
5094 }
5095
5096 if ( !mrTextNode.IsInList() )
5097 return;
5098
5099 if ( mbUpdateListLevel )
5100 {
5101 auto const nLevel(mrTextNode.GetAttrListLevel());
5102 mrTextNode.DoNum(
5103 [nLevel](SwNodeNum & rNum) { rNum.SetLevelInListTree(nLevel); });
5104 }
5105
5106 if ( mbUpdateListRestart )
5107 {
5108 mrTextNode.DoNum(
5109 [](SwNodeNum & rNum) {
5110 rNum.InvalidateMe();
5111 rNum.NotifyInvalidSiblings();
5112 });
5113 }
5114
5115 if ( mbUpdateListCount )
5116 {
5117 mrTextNode.DoNum(
5118 [](SwNodeNum & rNum) { rNum.InvalidateAndNotifyTree(); });
5119 }
5120 }
5121 // End of class <HandleResetAttrAtTextNode>
5122}
5123
5124bool SwTextNode::ResetAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 )
5125{
5126 const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
5127 mbInSetOrResetAttr = true;
5128
5129 HandleResetAttrAtTextNode aHandleResetAttr( *this, nWhich1, nWhich2 );
5130
5131 bool bRet = SwContentNode::ResetAttr( nWhich1, nWhich2 );
5132
5133 mbInSetOrResetAttr = bOldIsSetOrResetAttr;
5134
5135 return bRet;
5136}
5137
5138bool SwTextNode::ResetAttr( const std::vector<sal_uInt16>& rWhichArr )
5139{
5140 const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
5141 mbInSetOrResetAttr = true;
5142
5143 HandleResetAttrAtTextNode aHandleResetAttr( *this, rWhichArr );
5144
5145 bool bRet = SwContentNode::ResetAttr( rWhichArr );
5146
5147 mbInSetOrResetAttr = bOldIsSetOrResetAttr;
5148
5149 return bRet;
5150}
5151
5152sal_uInt16 SwTextNode::ResetAllAttr()
5153{
5154 const bool bOldIsSetOrResetAttr( mbInSetOrResetAttr );
5155 mbInSetOrResetAttr = true;
5156
5157 HandleResetAttrAtTextNode aHandleResetAttr( *this );
5158
5159 const sal_uInt16 nRet = SwContentNode::ResetAllAttr();
5160
5161 mbInSetOrResetAttr = bOldIsSetOrResetAttr;
5162
5163 return nRet;
5164}
5165
5166void SwTextNode::dumpAsXml(xmlTextWriterPtr pWriter) const
5167{
5168 xmlTextWriterStartElement(pWriter, BAD_CAST(xmlChar *)("SwTextNode"));
5169 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST(xmlChar *)("ptr"), "%p", this);
5170 xmlTextWriterWriteAttribute(pWriter, BAD_CAST(xmlChar *)("index"), BAD_CAST(xmlChar *)(OString::number(GetIndex()).getStr()));
5171
5172 OUString sText = GetText();
5173 for (int i = 0; i < 32; ++i)
5174 sText = sText.replace(i, '*');
5175 xmlTextWriterStartElement(pWriter, BAD_CAST(xmlChar *)("m_Text"));
5176 xmlTextWriterWriteString(pWriter, BAD_CAST(xmlChar *)(sText.toUtf8().getStr()));
5177 xmlTextWriterEndElement(pWriter);
5178
5179 if (GetFormatColl())
5180 {
5181 xmlTextWriterStartElement(pWriter, BAD_CAST(xmlChar *)("SwTextFormatColl"));
5182 xmlTextWriterWriteAttribute(pWriter, BAD_CAST(xmlChar *)("name"), BAD_CAST(xmlChar *)(GetFormatColl()->GetName().toUtf8().getStr()));
5183 xmlTextWriterEndElement(pWriter);
5184 }
5185
5186 if (HasSwAttrSet())
5187 {
5188 xmlTextWriterStartElement(pWriter, BAD_CAST(xmlChar *)("SwAttrSet"));
5189 GetSwAttrSet().dumpAsXml(pWriter);
5190 xmlTextWriterEndElement(pWriter);
5191 }
5192
5193 if (HasHints())
5194 {
5195 xmlTextWriterStartElement(pWriter, BAD_CAST(xmlChar *)("SwpHints"));
5196 const SwpHints& rHints = GetSwpHints();
5197 for (size_t i = 0; i < rHints.Count(); ++i)
5198 rHints.Get(i)->dumpAsXml(pWriter);
5199 xmlTextWriterEndElement(pWriter);
5200 }
5201
5202 if (GetNumRule())
5203 GetNumRule()->dumpAsXml(pWriter);
5204
5205 xmlTextWriterEndElement(pWriter);
5206}
5207
5208sal_uInt32 SwTextNode::GetRsid( sal_Int32 nStt, sal_Int32 nEnd ) const
5209{
5210 SfxItemSet aSet( const_cast<SfxItemPool&>(static_cast<SfxItemPool const &>(GetDoc().GetAttrPool())), svl::Items<RES_CHRATR_RSID, RES_CHRATR_RSID>{} );
5211 if (GetParaAttr(aSet, nStt, nEnd))
5212 {
5213 const SvxRsidItem* pRsid = aSet.GetItem<SvxRsidItem>(RES_CHRATR_RSID);
5214 if( pRsid )
5215 return pRsid->GetValue();
5216 }
5217
5218 return 0;
5219}
5220
5221sal_uInt32 SwTextNode::GetParRsid() const
5222{
5223 return reinterpret_cast<const SvxRsidItem&>(GetAttr( RES_PARATR_RSID )).GetValue();
5224}
5225
5226bool SwTextNode::CompareParRsid( const SwTextNode &rTextNode ) const
5227{
5228 sal_uInt32 nThisRsid = GetParRsid();
5229 sal_uInt32 nRsid = rTextNode.GetParRsid();
5230
5231 return nThisRsid == nRsid;
5232}
5233
5234bool SwTextNode::CompareRsid( const SwTextNode &rTextNode, sal_Int32 nStt1, sal_Int32 nStt2 ) const
5235{
5236 sal_uInt32 nThisRsid = GetRsid( nStt1, nStt1 );
5237 sal_uInt32 nRsid = rTextNode.GetRsid( nStt2, nStt2 );
5238
5239 return nThisRsid == nRsid;
5240}
5241
5242// sw::Metadatable
5243::sfx2::IXmlIdRegistry& SwTextNode::GetRegistry()
5244{
5245 return GetDoc().GetXmlIdRegistry();
5246}
5247
5248bool SwTextNode::IsInClipboard() const
5249{
5250 return GetDoc().IsClipBoard();
5251}
5252
5253bool SwTextNode::IsInUndo() const
5254{
5255 return GetDoc().GetIDocumentUndoRedo().IsUndoNodes(GetNodes());
5256}
5257
5258bool SwTextNode::IsInContent() const
5259{
5260 return !GetDoc().IsInHeaderFooter( SwNodeIndex(*this) );
5261}
5262
5263void SwTextNode::SwClientNotify( const SwModify& rModify, const SfxHint& rHint )
5264{
5265 if (auto pLegacyHint = dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
5266 {
5267 bool bWasNotifiable = m_bNotifiable;
5268 m_bNotifiable = false;
5269
5270 const auto pOldValue = pLegacyHint->m_pOld;
5271 const auto pNewValue = pLegacyHint->m_pNew;
5272 // Override Modify so that deleting styles works properly (outline
5273 // numbering!).
5274 // Never call ChgTextCollUpdateNum for Nodes in Undo.
5275 if( pOldValue
5276 && pNewValue
5277 && RES_FMT_CHG == pOldValue->Which()
5278 && GetRegisteredIn() == static_cast<const SwFormatChg*>(pNewValue)->pChangedFormat
5279 && GetNodes().IsDocNodes() )
5280 {
5281 ChgTextCollUpdateNum(
5282 static_cast<const SwTextFormatColl*>(static_cast<const SwFormatChg*>(pOldValue)->pChangedFormat),
5283 static_cast<const SwTextFormatColl*>(static_cast<const SwFormatChg*>(pNewValue)->pChangedFormat) );
5284 }
5285
5286 // reset fill information
5287 if (maFillAttributes && pNewValue)
5288 {
5289 const sal_uInt16 nWhich = pNewValue->Which();
5290 bool bReset(RES_FMT_CHG == nWhich); // ..on format change (e.g. style changed)
5291
5292 if(!bReset && RES_ATTRSET_CHG == nWhich) // ..on ItemChange from DrawingLayer FillAttributes
5293 {
5294 SfxItemIter aIter(*static_cast<const SwAttrSetChg*>(pNewValue)->GetChgSet());
5295
5296 for(const SfxPoolItem* pItem = aIter.GetCurItem(); pItem && !bReset; pItem = aIter.NextItem())
5297 {
5298 bReset = !IsInvalidItem(pItem) && pItem->Which() >= XATTR_FILL_FIRST && pItem->Which() <= XATTR_FILL_LAST;
5299 }
5300 }
5301
5302 if(bReset)
5303 {
5304 maFillAttributes.reset();
5305 }
5306 }
5307
5308 if ( !mbInSetOrResetAttr )
5309 {
5310 HandleModifyAtTextNode( *this, pOldValue, pNewValue );
5311 }
5312
5313 SwContentNode::SwClientNotify(rModify, rHint);
5314
5315 SwDoc& rDoc = GetDoc();
5316 // #125329# - assure that text node is in document nodes array
5317 if ( !rDoc.IsInDtor() && &rDoc.GetNodes() == &GetNodes() )
5318 {
5319 rDoc.GetNodes().UpdateOutlineNode(*this);
5320 }
5321
5322 m_bNotifiable = bWasNotifiable;
5323
5324 if (pOldValue && (RES_REMOVE_UNO_OBJECT == pOldValue->Which()))
5325 { // invalidate cached uno object
5326 SetXParagraph(css::uno::Reference<css::text::XTextContent>(nullptr));
5327 }
5328 }
5329 else if (dynamic_cast<const SwAttrHint*>(&rHint))
5330 {
5331 if (&rModify == GetRegisteredIn())
5332 ChkCondColl();
5333 }
5334}
5335
5336uno::Reference< rdf::XMetadatable >
5337SwTextNode::MakeUnoObject()
5338{
5339 const uno::Reference<rdf::XMetadatable> xMeta(
5340 SwXParagraph::CreateXParagraph(GetDoc(), this), uno::UNO_QUERY);
5341 return xMeta;
5342}
5343
5344drawinglayer::attribute::SdrAllFillAttributesHelperPtr SwTextNode::getSdrAllFillAttributesHelper() const
5345{
5346 // create SdrAllFillAttributesHelper on demand
5347 if(!maFillAttributes)
5348 {
5349 const_cast< SwTextNode* >(this)->maFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(GetSwAttrSet());
5350 }
5351
5352 return maFillAttributes;
5353}
5354
5355/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/inc/node.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#ifndef INCLUDED_SW_INC_NODE_HXX
21#define INCLUDED_SW_INC_NODE_HXX
22
23#include <sal/types.h>
24
25#include "swdllapi.h"
26#include "ndarr.hxx"
27#include "ndtyp.hxx"
28#include "index.hxx"
29#include "fmtcol.hxx"
30
31#include <memory>
32#include <vector>
33
34class SwContentFrame;
35class SwContentNode;
36class SwDoc;
37class SwEndNode;
38class SwFrame;
39class SwFrameFormat;
40class SwGrfNode;
41class SwNoTextNode;
42class SwNodeIndex;
43class SwOLENode;
44class SwRect;
45class SwSection;
46class SwSectionFormat;
47class SwTOXBase;
48class SwSectionNode;
49class SwStartNode;
50class SwTabFrame;
51class SwRootFrame;
52class SwTable;
53class SwTableNode;
54class SwTableBox;
55class SwTextNode;
56class SwPageDesc;
57class SwViewShell;
58struct SwPosition;
59class IStyleAccess;
60class IDocumentSettingAccess;
61class IDocumentDeviceAccess;
62class IDocumentMarkAccess;
63class IDocumentRedlineAccess;
64class IDocumentStylePoolAccess;
65class IDocumentLinksAdministration;
66class IDocumentFieldsAccess;
67class IDocumentContentOperations;
68class IDocumentListItems;
69class Point;
70enum class SvxFrameDirection;
71typedef std::vector<SwOLENode*> SwOLENodes; // docary.hxx
72
73namespace drawinglayer::attribute {
74 class SdrAllFillAttributesHelper;
75 typedef std::shared_ptr< SdrAllFillAttributesHelper > SdrAllFillAttributesHelperPtr;
76}
77
78/// Base class of the Writer document model elements.
79class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwNode
80 : private BigPtrEntry
81{
82 friend class SwNodes;
83
84 SwNodeType m_nNodeType;
85
86 /// For text nodes: level of auto format. Was put here because we had still free bits.
87 sal_uInt8 m_nAFormatNumLvl : 3;
88 bool m_bIgnoreDontExpand : 1; ///< for Text Attributes - ignore the flag
89
90public:
91 /// sw_redlinehide: redline node merge state
92 enum class Merge { None, First, NonFirst, Hidden };
93 bool IsCreateFrameWhenHidingRedlines() const {
94 return m_eMerge == Merge::None || m_eMerge == Merge::First;
95 }
96 void SetRedlineMergeFlag(Merge const eMerge) { m_eMerge = eMerge; }
97 Merge GetRedlineMergeFlag() const { return m_eMerge; }
98private:
99 Merge m_eMerge;
100
101#ifdef DBG_UTIL
102 static long s_nSerial;
103 long m_nSerial;
104#endif
105
106 /// all SwFrameFormat that are anchored at the node
107 /// invariant: SwFrameFormat is in the list iff
108 /// SwFrameFormat::GetAnchor().GetContentAnchor() points to this node
109 std::unique_ptr<std::vector<SwFrameFormat*>> m_pAnchoredFlys;
110
111protected:
112 SwStartNode* m_pStartOfSection;
113
114 SwNode( const SwNodeIndex &rWhere, const SwNodeType nNodeId );
115
116 /// for the initial StartNode
117 SwNode( SwNodes& rNodes, sal_uLong nPos, const SwNodeType nNodeId );
118
119public:
120 /** the = 0 forces the class to be an abstract base class, but the dtor can be still called
121 from subclasses */
122 virtual ~SwNode() override = 0;
123
124#ifdef DBG_UTIL
125 long GetSerial() const { return m_nSerial; }
126#endif
127
128 sal_uInt16 GetSectionLevel() const;
129
130 inline sal_uLong StartOfSectionIndex() const;
131 const SwStartNode* StartOfSectionNode() const { return m_pStartOfSection; }
132 SwStartNode* StartOfSectionNode() { return m_pStartOfSection; }
133
134 inline sal_uLong EndOfSectionIndex() const;
135 inline const SwEndNode* EndOfSectionNode() const;
136 inline SwEndNode* EndOfSectionNode();
137
138 sal_uInt8 GetAutoFormatLvl() const { return m_nAFormatNumLvl; }
139 void SetAutoFormatLvl( sal_uInt8 nVal ) { m_nAFormatNumLvl = nVal; }
140
141 bool IsIgnoreDontExpand() const { return m_bIgnoreDontExpand; }
142 void SetIgnoreDontExpand( bool bNew ) { m_bIgnoreDontExpand = bNew; }
143
144 SwNodeType GetNodeType() const { return m_nNodeType; }
145
146 inline SwStartNode *GetStartNode();
147 inline const SwStartNode *GetStartNode() const;
148 inline SwContentNode *GetContentNode();
149 inline const SwContentNode *GetContentNode() const;
150 inline SwEndNode *GetEndNode();
151 inline const SwEndNode *GetEndNode() const;
152 inline SwTextNode *GetTextNode();
153 inline const SwTextNode *GetTextNode() const;
154 inline SwOLENode *GetOLENode();
155 inline const SwOLENode *GetOLENode() const;
156 inline SwNoTextNode *GetNoTextNode();
157 inline const SwNoTextNode *GetNoTextNode() const;
158 inline SwGrfNode *GetGrfNode();
159 inline const SwGrfNode *GetGrfNode() const;
160 inline SwTableNode *GetTableNode();
161 inline const SwTableNode *GetTableNode() const;
162 inline SwSectionNode *GetSectionNode();
163 inline const SwSectionNode *GetSectionNode() const;
164
165 inline bool IsStartNode() const;
166 inline bool IsContentNode() const;
167 inline bool IsEndNode() const;
168 inline bool IsTextNode() const;
169 inline bool IsTableNode() const;
170 inline bool IsSectionNode() const;
171 inline bool IsOLENode() const;
172 inline bool IsNoTextNode() const;
173 inline bool IsGrfNode() const;
174
175 /**
176 Checks if this node is in redlines.
177
178 @retval true this node is in redlines
179 @retval false else
180 */
181 bool IsInRedlines() const;
182
183 /** Search table node, in which it is. If it is in no table
184 @return 0. */
185 SwTableNode *FindTableNode();
186 inline const SwTableNode *FindTableNode() const;
187
188 /** Search section node, in which it is. If it is in no section
189 @return 0. */
190 SwSectionNode *FindSectionNode();
191 inline const SwSectionNode *FindSectionNode() const;
192
193 SwStartNode* FindSttNodeByType( SwStartNodeType eTyp );
194 inline const SwStartNode* FindSttNodeByType( SwStartNodeType eTyp ) const;
195
196 const SwStartNode* FindTableBoxStartNode() const
197 { return FindSttNodeByType( SwTableBoxStartNode ); }
198 const SwStartNode* FindFlyStartNode() const
199 { return FindSttNodeByType( SwFlyStartNode ); }
200 const SwStartNode* FindFootnoteStartNode() const
201 { return FindSttNodeByType( SwFootnoteStartNode ); }
202 const SwStartNode* FindHeaderStartNode() const
203 { return FindSttNodeByType( SwHeaderStartNode ); }
204 const SwStartNode* FindFooterStartNode() const
205 { return FindSttNodeByType( SwFooterStartNode ); }
206
207 /// Node is in which nodes-array/doc?
208 inline SwNodes& GetNodes();
209 inline const SwNodes& GetNodes() const;
210
211 SwDoc& GetDoc()
212 {
213 return GetNodes().GetDoc();
214 }
215
216 const SwDoc& GetDoc() const
217 {
218 return GetNodes().GetDoc();
219 }
220
221 /** Provides access to the document setting interface
222 */
223 const IDocumentSettingAccess* getIDocumentSettingAccess() const;
224
225 /** Provides access to the document device interface
226 */
227 const IDocumentDeviceAccess& getIDocumentDeviceAccess() const;
228
229 /** Provides access to the document bookmark interface
230 */
231 const IDocumentMarkAccess* getIDocumentMarkAccess() const;
232
233 /** Provides access to the document redline interface
234 */
235 const IDocumentRedlineAccess& getIDocumentRedlineAccess() const;
236
237 /** Provides access to the document style pool interface
238 */
239 const IDocumentStylePoolAccess& getIDocumentStylePoolAccess() const;
240
241 /** Provides access to the document draw model interface
242 */
243 const IDocumentDrawModelAccess& getIDocumentDrawModelAccess() const;
244
245 /** Provides access to the document layout interface
246 */
247 const IDocumentLayoutAccess& getIDocumentLayoutAccess() const;
248 IDocumentLayoutAccess& getIDocumentLayoutAccess();
249
250 /** Provides access to the document links administration interface
251 */
252 const IDocumentLinksAdministration& getIDocumentLinksAdministration() const;
253 IDocumentLinksAdministration& getIDocumentLinksAdministration();
254
255 /** Provides access to the document fields administration interface
256 */
257 const IDocumentFieldsAccess& getIDocumentFieldsAccess() const;
258 IDocumentFieldsAccess& getIDocumentFieldsAccess();
259
260 /** Provides access to the document content operations interface
261 */
262 IDocumentContentOperations& getIDocumentContentOperations();
263
264 /** Provides access to the document automatic styles interface
265 */
266 IStyleAccess& getIDocumentStyleAccess();
267
268 /** Provides access to the document's numbered items interface */
269 IDocumentListItems& getIDocumentListItems();
270
271 /// Is node in the visible area of the Shell?
272 bool IsInVisibleArea( SwViewShell const * pSh ) const;
273 /// Is node in a protected area?
274 bool IsInProtectSect() const;
275 /** Is node in something that is protected (range, frame,
276 table cells ... including anchor in case of frames or footnotes)? */
277 bool IsProtect() const;
278
279 /** Search PageDesc with which this node is formatted. If layout is existent
280 search over layout, else only the hard way is left: search over the nodes
281 to the front!! */
282 const SwPageDesc* FindPageDesc( size_t* pPgDescNdIdx = nullptr ) const;
283
284 /// If node is in a fly return the respective format.
285 SwFrameFormat* GetFlyFormat() const;
286
287 /// If node is in a table return the respective table box.
288 SwTableBox* GetTableBox() const;
289
290 sal_uLong GetIndex() const { return GetPos(); }
291
292 const SwTextNode* FindOutlineNodeOfLevel(sal_uInt8 nLvl, SwRootFrame const* pLayout = nullptr) const;
293
294 sal_uInt8 HasPrevNextLayNode() const;
295
296 std::vector<SwFrameFormat *> const* GetAnchoredFlys() const { return m_pAnchoredFlys.get(); }
297 void AddAnchoredFly(SwFrameFormat *);
298 void RemoveAnchoredFly(SwFrameFormat *);
299
300 /**
301 * Dumps the node structure to the given destination (file nodes.xml in the current directory by default)
302 */
303 virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
304
305private:
306 SwNode( const SwNode & rNodes ) = delete;
307 SwNode & operator= ( const SwNode & rNodes ) = delete;
308};
309
310/// Starts a section of nodes in the document model.
311class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SwStartNode: public SwNode
312{
313 friend class SwNode;
314 friend class SwNodes;
315 friend class SwEndNode; ///< to set the theEndOfSection !!
316
317 SwEndNode* m_pEndOfSection;
318 SwStartNodeType m_eStartNodeType;
319
320 /// for the initial StartNode
321 SwStartNode( SwNodes& rNodes, sal_uLong nPos );
322
323protected:
324 SwStartNode( const SwNodeIndex &rWhere,
325 const SwNodeType nNodeType = SwNodeType::Start,
326 SwStartNodeType = SwNormalStartNode );
327public:
328 SwStartNodeType GetStartNodeType() const { return m_eStartNodeType; }
329
330 /// Call ChkCondcoll to all ContentNodes of section.
331 void CheckSectionCondColl() const;
332
333 virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
334
335private:
336 SwStartNode( const SwStartNode & rNode ) = delete;
337 SwStartNode & operator= ( const SwStartNode & rNode ) = delete;
338};
339
340/// Ends a section of nodes in the document model.
341class SwEndNode : public SwNode
342{
343 friend class SwNodes;
344 friend class SwTableNode; ///< To enable creation of its EndNote.
345 friend class SwSectionNode; ///< To enable creation of its EndNote.
346
347 /// for the initial StartNode
348 SwEndNode( SwNodes& rNodes, sal_uLong nPos, SwStartNode& rSttNd );
349
350protected:
351 SwEndNode( const SwNodeIndex &rWhere, SwStartNode& rSttNd );
352
353private:
354 SwEndNode( const SwEndNode & rNode ) = delete;
355 SwEndNode & operator= ( const SwEndNode & rNode ) = delete;
356};
357
358// SwContentNode
359
360class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwContentNode: public sw::BroadcastingModify, public SwNode, public SwIndexReg
361{
362
363 sw::WriterMultiListener m_aCondCollListener;
364 SwFormatColl* m_pCondColl;
365 mutable bool mbSetModifyAtAttr;
366
367protected:
368 SwContentNode( const SwNodeIndex &rWhere, const SwNodeType nNodeType,
369 SwFormatColl *pFormatColl );
370 /** the = 0 forces the class to be an abstract base class, but the dtor can be still called
371 from subclasses */
372 virtual ~SwContentNode() override = 0;
373
374 /** Attribute-set for all auto attributes of a ContentNode.
375 (e.g. TextNode or NoTextNode). */
376 std::shared_ptr<const SfxItemSet> mpAttrSet;
377
378 /// Make respective nodes create the specific AttrSets.
379 virtual void NewAttrSet( SwAttrPool& ) = 0;
380
381 /** There some functions that like to remove items from the internal
382 SwAttrSet (handle): */
383 sal_uInt16 ClearItemsFromAttrSet( const std::vector<sal_uInt16>& rWhichIds );
384
385 virtual void SwClientNotify( const SwModify&, const SfxHint& rHint) override;
386
387public:
388
389 /** MakeFrame will be called for a certain layout
390 pSib is another SwFrame of the same layout (e.g. the SwRootFrame itself, a sibling, the parent) */
391 virtual SwContentFrame *MakeFrame( SwFrame* pSib ) = 0;
392
393 virtual SwContentNode *JoinNext();
394 /** Is it possible to join two nodes?
395 In pIdx the second position can be returned. */
396 bool CanJoinNext( SwNodeIndex* pIdx =nullptr ) const;
397 bool CanJoinPrev( SwNodeIndex* pIdx =nullptr ) const;
398
399 void MakeStartIndex( SwIndex * pIdx ) { pIdx->Assign( this, 0 ); }
400 void MakeEndIndex( SwIndex * pIdx ) { pIdx->Assign( this, Len() ); }
401
402 bool GoNext(SwIndex *, sal_uInt16 nMode ) const;
403 bool GoPrevious(SwIndex *, sal_uInt16 nMode ) const;
404
405 /// @see GetFrameOfModify
406 SwContentFrame *getLayoutFrame( const SwRootFrame*,
407 const SwPosition *pPos = nullptr,
408 std::pair<Point, bool> const* pViewPosAndCalcFrame = nullptr) const;
409 /** @return the real size of the frame or an empty rectangle if
410 no layout exists. Needed for export filters. */
411 SwRect FindLayoutRect( const bool bPrtArea = false,
412 const Point* pPoint = nullptr ) const;
413 SwRect FindPageFrameRect() const;
414
415 /** Method creates all views of document for given node. The content
416 frames that are created are put in the respective layout. */
417 void MakeFramesForAdjacentContentNode(SwContentNode& rNode);
418
419 /** Method deletes all views of document for the node. The content-
420 frames are removed from the respective layout.
421 */
422 void DelFrames(SwRootFrame const* pLayout);
423
424 /** @return count of elements of node content. Default is 1.
425 There are differences between text node and formula node. */
426 virtual sal_Int32 Len() const;
427
428 virtual SwContentNode* MakeCopy(SwDoc&, const SwNodeIndex&, bool bNewFrames) const = 0;
429
430 /// Get information from Client.
431 virtual bool GetInfo( SfxPoolItem& ) const override;
432
433 /// SS for PoolItems: hard attributation.
434
435 /// If bInParent is FALSE search for attribute only in this node.
436 const SfxPoolItem& GetAttr( sal_uInt16 nWhich, bool bInParent=true ) const;
437 bool GetAttr( SfxItemSet& rSet ) const;
438 /// made virtual
439 virtual bool SetAttr( const SfxPoolItem& );
440 virtual bool SetAttr( const SfxItemSet& rSet );
441 virtual bool ResetAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 = 0 );
442 virtual bool ResetAttr( const std::vector<sal_uInt16>& rWhichArr );
443 virtual sal_uInt16 ResetAllAttr();
444
445 /// Obtains attribute that is not delivered via conditional style!
446 const SfxPoolItem* GetNoCondAttr( sal_uInt16 nWhich, bool bInParents ) const;
447
448 /** Does node has already its own auto-attributes?
449 Access to SwAttrSet. */
450 inline const SwAttrSet &GetSwAttrSet() const;
451 const SwAttrSet *GetpSwAttrSet() const { return static_cast<const SwAttrSet*>(mpAttrSet.get()); }
452 bool HasSwAttrSet() const { return mpAttrSet != nullptr; }
453
454 virtual SwFormatColl* ChgFormatColl( SwFormatColl* );
455 SwFormatColl* GetFormatColl() const { return const_cast<SwFormatColl*>(static_cast<const SwFormatColl*>(GetRegisteredIn())); }
456
457//FEATURE::CONDCOLL
458 inline SwFormatColl& GetAnyFormatColl() const;
459 void SetCondFormatColl( SwFormatColl* );
460 inline SwFormatColl* GetCondFormatColl() const;
461
462 bool IsAnyCondition( SwCollCondition& rTmp ) const;
463 void ChkCondColl();
464//FEATURE::CONDCOLL
465
466 /** Invalidates NumRule at the node. NumRule is updated
467 on EndAction of a Shell at the latest. */
468 bool InvalidateNumRule();
469
470 /** determines the text direction for a certain
471 position. @return -1, if text direction could *not* be determined. */
472 SvxFrameDirection GetTextDirection( const SwPosition& rPos,
473 const Point* pPt ) const;
474
475 void SetModifyAtAttr( bool bSetModifyAtAttr ) const { mbSetModifyAtAttr = bSetModifyAtAttr; }
476 bool GetModifyAtAttr() const { return mbSetModifyAtAttr; }
477
478 static std::unique_ptr<SwOLENodes> CreateOLENodesArray( const SwFormatColl& rColl, bool bOnlyWithInvalidSize );
479
480 // Access to DrawingLayer FillAttributes in a preprocessed form for primitive usage
481 virtual drawinglayer::attribute::SdrAllFillAttributesHelperPtr getSdrAllFillAttributesHelper() const;
482
483 virtual void ModifyNotification(const SfxPoolItem* pOld, const SfxPoolItem* pNew) override
484 {
485 SwClientNotify(*this, sw::LegacyModifyHint(pOld, pNew));
486 }
487
488private:
489 SwContentNode( const SwContentNode & rNode ) = delete;
490 SwContentNode & operator= ( const SwContentNode & rNode ) = delete;
491};
492
493// SwTableNode
494
495class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwTableNode : public SwStartNode, public sw::BroadcastingModify
496{
497 friend class SwNodes;
498 std::unique_ptr<SwTable> m_pTable;
499protected:
500 virtual ~SwTableNode() override;
501
502public:
503 SwTableNode( const SwNodeIndex & );
504
505 const SwTable& GetTable() const { return *m_pTable; }
506 SwTable& GetTable() { return *m_pTable; }
507 SwTabFrame *MakeFrame( SwFrame* );
508
509 /// Creates the frms for the table node (i.e. the TabFrames).
510 void MakeOwnFrames(SwNodeIndex* pIdxBehind);
511
512 /** Method deletes all views of document for the node.
513 The content frames are removed from the respective layout. */
514 void DelFrames(SwRootFrame const* pLayout = nullptr);
515
516 /** Method creates all views of the document for the previous node.
517 The content frames that are created are put into the respective layout. */
518 void MakeFramesForAdjacentContentNode(const SwNodeIndex & rIdx);
519
520 SwTableNode* MakeCopy( SwDoc&, const SwNodeIndex& ) const;
521 void SetNewTable( std::unique_ptr<SwTable> , bool bNewFrames=true );
522
523 // Removes redline objects that relate to this table from the 'Extra Redlines' table
524 void RemoveRedlines();
525
526private:
527 SwTableNode( const SwTableNode & rNode ) = delete;
528 SwTableNode & operator= ( const SwTableNode & rNode ) = delete;
529};
530
531class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SwSectionNode
532 : public SwStartNode
533{
534 friend class SwNodes;
535
536private:
537 SwSectionNode(const SwSectionNode&) = delete;
538 SwSectionNode& operator=(const SwSectionNode&) = delete;
539
540 std::unique_ptr<SwSection> const m_pSection;
541
542protected:
543 virtual ~SwSectionNode() override;
544
545public:
546 SwSectionNode(SwNodeIndex const&,
547 SwSectionFormat & rFormat, SwTOXBase const*const pTOXBase);
548
549 const SwSection& GetSection() const { return *m_pSection; }
550 SwSection& GetSection() { return *m_pSection; }
551
552 SwFrame *MakeFrame( SwFrame* );
553
554 /** Creates the frms for the SectionNode (i.e. the SectionFrames).
555 On default the frames are created until the end of the range.
556 When another NodeIndex pEnd is passed a MakeFrames is called up to it.
557 Used by TableToText. */
558 void MakeOwnFrames(SwNodeIndex* pIdxBehind, SwNodeIndex* pEnd = nullptr);
559
560 /** Method deletes all views of document for the node. The
561 content frames are removed from the respective layout. */
562 void DelFrames(SwRootFrame const* pLayout = nullptr, bool bForce = false);
563
564 /** Method creates all views of document for the previous node.
565 The content frames created are put into the respective layout. */
566 void MakeFramesForAdjacentContentNode(const SwNodeIndex & rIdx);
567
568 SwSectionNode* MakeCopy( SwDoc&, const SwNodeIndex& ) const;
569
570 /// Set pointer in format of section on itself.
571 void NodesArrChgd();
572
573 /** Check for not hidden areas whether there is content that is not in
574 a hidden sub-area. */
575 bool IsContentHidden() const;
576
577};
578
579/** This class is internal, used only during DocumentContentOperationsManager::CopyWithFlyInFly(), and for undo.
580
581Some of the nodes are then replaced with SwPlaceholderNode, and at the end of the operation, removed again.
582FIXME find out if this is really necessary, and if we can avoid creation of the SwPlaceholderNodes in the first place.
583*/
584class SwPlaceholderNode final : private SwNode
585{
586private:
587 friend class SwNodes;
588 SwPlaceholderNode(const SwNodeIndex &rWhere);
589};
590
591inline SwEndNode *SwNode::GetEndNode()
592{
593 return SwNodeType::End == m_nNodeType ? static_cast<SwEndNode*>(this) : nullptr;
594}
595inline const SwEndNode *SwNode::GetEndNode() const
596{
597 return SwNodeType::End == m_nNodeType ? static_cast<const SwEndNode*>(this) : nullptr;
598}
599inline SwStartNode *SwNode::GetStartNode()
600{
601 return SwNodeType::Start & m_nNodeType ? static_cast<SwStartNode*>(this) : nullptr;
602}
603inline const SwStartNode *SwNode::GetStartNode() const
604{
605 return SwNodeType::Start & m_nNodeType ? static_cast<const SwStartNode*>(this) : nullptr;
606}
607inline SwTableNode *SwNode::GetTableNode()
608{
609 return SwNodeType::Table == m_nNodeType ? static_cast<SwTableNode*>(this) : nullptr;
610}
611inline const SwTableNode *SwNode::GetTableNode() const
612{
613 return SwNodeType::Table == m_nNodeType ? static_cast<const SwTableNode*>(this) : nullptr;
614}
615inline SwSectionNode *SwNode::GetSectionNode()
616{
617 return SwNodeType::Section == m_nNodeType ? static_cast<SwSectionNode*>(this) : nullptr;
618}
619inline const SwSectionNode *SwNode::GetSectionNode() const
620{
621 return SwNodeType::Section == m_nNodeType ? static_cast<const SwSectionNode*>(this) : nullptr;
622}
623inline SwContentNode *SwNode::GetContentNode()
624{
625 return SwNodeType::ContentMask & m_nNodeType ? static_cast<SwContentNode*>(this) : nullptr;
626}
627inline const SwContentNode *SwNode::GetContentNode() const
628{
629 return SwNodeType::ContentMask & m_nNodeType ? static_cast<const SwContentNode*>(this) : nullptr;
630}
631
632inline bool SwNode::IsStartNode() const
633{
634 return bool(SwNodeType::Start & m_nNodeType);
635}
636inline bool SwNode::IsContentNode() const
637{
638 return bool(SwNodeType::ContentMask & m_nNodeType);
639}
640inline bool SwNode::IsEndNode() const
641{
642 return SwNodeType::End == m_nNodeType;
643}
644inline bool SwNode::IsTextNode() const
645{
646 return SwNodeType::Text == m_nNodeType;
647}
648inline bool SwNode::IsTableNode() const
649{
650 return SwNodeType::Table == m_nNodeType;
651}
652inline bool SwNode::IsSectionNode() const
653{
654 return SwNodeType::Section == m_nNodeType;
655}
656inline bool SwNode::IsNoTextNode() const
657{
658 return bool(SwNodeType::NoTextMask & m_nNodeType);
659}
660inline bool SwNode::IsOLENode() const
661{
662 return SwNodeType::Ole == m_nNodeType;
663}
664inline bool SwNode::IsGrfNode() const
665{
666 return SwNodeType::Grf == m_nNodeType;
667}
668
669inline const SwStartNode* SwNode::FindSttNodeByType( SwStartNodeType eTyp ) const
670{
671 return const_cast<SwNode*>(this)->FindSttNodeByType( eTyp );
672}
673inline const SwTableNode* SwNode::FindTableNode() const
674{
675 return const_cast<SwNode*>(this)->FindTableNode();
676}
677inline const SwSectionNode* SwNode::FindSectionNode() const
678{
679 return const_cast<SwNode*>(this)->FindSectionNode();
680}
681inline sal_uLong SwNode::StartOfSectionIndex() const
682{
683 return m_pStartOfSection->GetIndex();
684}
685inline sal_uLong SwNode::EndOfSectionIndex() const
686{
687 const SwStartNode* pStNd = IsStartNode() ? static_cast<const SwStartNode*>(this) : m_pStartOfSection;
688 return pStNd->m_pEndOfSection->GetIndex();
689}
690inline const SwEndNode* SwNode::EndOfSectionNode() const
691{
692 const SwStartNode* pStNd = IsStartNode() ? static_cast<const SwStartNode*>(this) : m_pStartOfSection;
693 return pStNd->m_pEndOfSection;
694}
695inline SwEndNode* SwNode::EndOfSectionNode()
696{
697 const SwStartNode* pStNd = IsStartNode() ? static_cast<const SwStartNode*>(this) : m_pStartOfSection;
698 return pStNd->m_pEndOfSection;
699}
700
701inline SwNodes& SwNode::GetNodes()
702{
703 return static_cast<SwNodes&>(GetArray());
704}
705inline const SwNodes& SwNode::GetNodes() const
706{
707 return static_cast<SwNodes&>(GetArray());
708}
709
710inline SwFormatColl* SwContentNode::GetCondFormatColl() const
711{
712 return m_pCondColl;
713}
714
715inline SwFormatColl& SwContentNode::GetAnyFormatColl() const
716{
717 return m_pCondColl
718 ? *m_pCondColl
719 : *const_cast<SwFormatColl*>(static_cast<const SwFormatColl*>(GetRegisteredIn()));
720}
721
722inline const SwAttrSet& SwContentNode::GetSwAttrSet() const
723{
724 return mpAttrSet ? *GetpSwAttrSet() : GetAnyFormatColl().GetAttrSet();
36
Assuming the condition is true
37
'?' condition is true
38
Returning null reference
725}
726
727//FEATURE::CONDCOLL
728
729inline const SfxPoolItem& SwContentNode::GetAttr( sal_uInt16 nWhich,
730 bool bInParents ) const
731{
732 return GetSwAttrSet().Get( nWhich, bInParents );
35
Calling 'SwContentNode::GetSwAttrSet'
733}
734
735inline SwPlaceholderNode::SwPlaceholderNode(const SwNodeIndex &rWhere)
736 : SwNode(rWhere, SwNodeType::PlaceHolder)
737{
738}
739
740inline SwNodePtr SwNodes::operator[]( sal_uLong n ) const
741{
742 return static_cast<SwNodePtr>(BigPtrArray::operator[] ( n ));
743}
744
745#endif
746
747/* vim:set shiftwidth=4 softtabstop=4 expandtab: */