LibreOffice Module sw (master)  1
thints.cxx
Go to the documentation of this file.
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 <sal/config.h>
21 #include <sal/log.hxx>
22 
24 #include <hintids.hxx>
25 #include <editeng/rsiditem.hxx>
26 #include <osl/diagnose.h>
27 #include <svl/whiter.hxx>
28 #include <svl/itemiter.hxx>
30 #include <editeng/langitem.hxx>
31 #include <editeng/lrspitem.hxx>
32 #include <txtinet.hxx>
33 #include <txtflcnt.hxx>
34 #include <fmtfld.hxx>
35 #include <fmtrfmrk.hxx>
36 #include <fmtanchr.hxx>
37 #include <fmtinfmt.hxx>
38 #include <txtatr.hxx>
39 #include <fchrfmt.hxx>
40 #include <fmtautofmt.hxx>
41 #include <fmtflcnt.hxx>
42 #include <fmtftn.hxx>
43 #include <txttxmrk.hxx>
44 #include <txtrfmrk.hxx>
45 #include <txtftn.hxx>
46 #include <txtfld.hxx>
47 #include <txtannotationfld.hxx>
48 #include <charfmt.hxx>
49 #include <frmfmt.hxx>
50 #include <ftnidx.hxx>
51 #include <fmtruby.hxx>
52 #include <fmtmeta.hxx>
53 #include <breakit.hxx>
54 #include <doc.hxx>
55 #include <IDocumentUndoRedo.hxx>
59 #include <fldbas.hxx>
60 #include <pam.hxx>
61 #include <ndtxt.hxx>
62 #include <txtfrm.hxx>
63 #include <rootfrm.hxx>
64 #include <rolbck.hxx>
65 #include <ddefld.hxx>
66 #include <docufld.hxx>
67 #include <expfld.hxx>
68 #include <usrfld.hxx>
69 #include <poolfmt.hxx>
70 #include <istyleaccess.hxx>
71 #include <docsh.hxx>
72 #include <algorithm>
73 #include <map>
74 #include <memory>
75 #include <unordered_map>
76 
77 #include <rdfhelper.hxx>
78 #include <hints.hxx>
79 
80 #ifdef DBG_UTIL
81 #define CHECK Check(true);
82 #define CHECK_NOTMERGED Check(false);
83 #else
84 #define CHECK_NOTMERGED
85 #endif
86 
87 using namespace ::com::sun::star::i18n;
88 
90  : m_rParent(rParent)
91  , m_pHistory(nullptr)
92  , m_bInSplitNode(false)
93  , m_bCalcHiddenParaField(false)
94  , m_bHiddenByParaField(false)
95  , m_bFootnote(false)
96  , m_bDDEFields(false)
97  , m_bStartMapNeedsSorting(false)
98  , m_bEndMapNeedsSorting(false)
99  , m_bWhichMapNeedsSorting(false)
100 {
101 }
102 
103 static void TextAttrDelete( SwDoc & rDoc, SwTextAttr * const pAttr )
104 {
105  if (RES_TXTATR_META == pAttr->Which() ||
106  RES_TXTATR_METAFIELD == pAttr->Which())
107  {
108  static_txtattr_cast<SwTextMeta *>(pAttr)->ChgTextNode(nullptr); // prevents ASSERT
109  }
110  SwTextAttr::Destroy( pAttr, rDoc.GetAttrPool() );
111 }
112 
113 static bool TextAttrContains(const sal_Int32 nPos, const SwTextAttrEnd * const pAttr)
114 {
115  return (pAttr->GetStart() < nPos) && (nPos < *pAttr->End());
116 }
117 
118 // a: |-----|
119 // b:
120 // |---| => valid: b before a
121 // |-----| => valid: start == end; b before a
122 // |---------| => invalid: overlap (1)
123 // |-----------| => valid: same end; b around a
124 // |-----------------| => valid: b around a
125 // |---| => valid; same start; b within a
126 // |-----| => valid; same start and end; b around or within a?
127 // |-----------| => valid: same start: b around a
128 // |-| => valid: b within a
129 // |---| => valid: same end; b within a
130 // |---------| => invalid: overlap (2)
131 // |-----| => valid: end == start; b after a
132 // |---| => valid: b after a
133 // ===> 2 invalid overlap cases
134 static
135 bool isOverlap(const sal_Int32 nStart1, const sal_Int32 nEnd1,
136  const sal_Int32 nStart2, const sal_Int32 nEnd2)
137 {
138  return
139  ((nStart1 > nStart2) && (nStart1 < nEnd2) && (nEnd1 > nEnd2)) // (1)
140  || ((nStart1 < nStart2) && (nStart2 < nEnd1) && (nEnd1 < nEnd2)); // (2)
141 }
142 
144 static
145 bool isNestedAny(const sal_Int32 nStart1, const sal_Int32 nEnd1,
146  const sal_Int32 nStart2, const sal_Int32 nEnd2)
147 {
148  return ((nStart1 == nStart2) || (nEnd1 == nEnd2))
149  // same start/end: nested except if hint1 empty and hint2 not empty
150  ? (nStart1 != nEnd1) || (nStart2 == nEnd2)
151  : ((nStart1 < nStart2) ? (nEnd1 >= nEnd2) : (nEnd1 <= nEnd2));
152 }
153 
154 static
155 bool isSelfNestable(const sal_uInt16 nWhich)
156 {
157  if ((RES_TXTATR_INETFMT == nWhich) ||
158  (RES_TXTATR_CJK_RUBY == nWhich) ||
159  (RES_TXTATR_INPUTFIELD == nWhich))
160  return false;
161  assert((RES_TXTATR_META == nWhich) ||
162  (RES_TXTATR_METAFIELD == nWhich));
163  return true;
164 }
165 
166 static
167 bool isSplittable(const sal_uInt16 nWhich)
168 {
169  if ((RES_TXTATR_INETFMT == nWhich) ||
170  (RES_TXTATR_CJK_RUBY == nWhich))
171  return true;
172  assert((RES_TXTATR_META == nWhich) ||
173  (RES_TXTATR_METAFIELD == nWhich) ||
174  (RES_TXTATR_INPUTFIELD == nWhich));
175  return false;
176 }
177 
178 namespace {
179 
180 enum Split_t { FAIL, SPLIT_NEW, SPLIT_OTHER };
181 
182 }
183 
188 static Split_t
189 splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther)
190 {
191  if (!isSplittable(nWhichOther))
192  {
193  if (!isSplittable(nWhichNew))
194  return FAIL;
195  else
196  return SPLIT_NEW;
197  }
198  else
199  {
200  if ( RES_TXTATR_INPUTFIELD == nWhichNew )
201  return FAIL;
202  else if ( (RES_TXTATR_INETFMT == nWhichNew) &&
203  (RES_TXTATR_CJK_RUBY == nWhichOther) )
204  return SPLIT_NEW;
205  else
206  return SPLIT_OTHER;
207  }
208 }
209 
211 {
212  ChgTextNode(&rNode);
213  SwCharFormat * const pFormat(
215  pFormat->Add( this );
216 }
217 
219 {
220  ChgTextNode(&rNode);
221  SwCharFormat * const pFormat(
223  pFormat->Add( this );
224 }
225 
229 static SwTextAttrNesting *
231  const sal_Int32 nStart, const sal_Int32 nEnd)
232 {
233  SwTextAttr * const pNew( MakeTextAttr(
234  rNode.GetDoc(), rNesting.GetAttr(), nStart, nEnd ) );
235  switch (pNew->Which())
236  {
237  case RES_TXTATR_INETFMT:
238  {
239  static_txtattr_cast<SwTextINetFormat*>(pNew)->InitINetFormat(rNode);
240  break;
241  }
242  case RES_TXTATR_CJK_RUBY:
243  {
244  static_txtattr_cast<SwTextRuby*>(pNew)->InitRuby(rNode);
245  break;
246  }
247  default:
248  assert(!"MakeTextAttrNesting: what the hell is that?");
249  break;
250  }
251  return static_txtattr_cast<SwTextAttrNesting*>(pNew);
252 }
253 
254 typedef std::vector<SwTextAttrNesting *> NestList_t;
255 
256 static NestList_t::iterator
258  NestList_t::iterator const iter, sal_Int32 const nSplitPos,
259  bool const bSplitAtStart, bool const bOtherDummy)
260 {
261  const sal_Int32 nStartPos( // skip other's dummy character!
262  (bSplitAtStart && bOtherDummy) ? nSplitPos + 1 : nSplitPos );
264  rNode, **iter, nStartPos, *(*iter)->GetEnd() ) );
265  (*iter)->SetEnd(nSplitPos);
266  return rSplits.insert(iter + 1, pNew);
267 }
268 
269 static void
271  const sal_Int32 nNewStart,
272  const sal_Int32 nOtherStart, const sal_Int32 nOtherEnd, bool bOtherDummy)
273 {
274  const bool bSplitAtStart(nNewStart < nOtherStart);
275  const sal_Int32 nSplitPos( bSplitAtStart ? nOtherStart : nOtherEnd );
276  // first find the portion that is split (not necessarily the last one!)
277  NestList_t::iterator const iter(
278  std::find_if( rSplits.begin(), rSplits.end(),
279  [nSplitPos](SwTextAttrEnd * const pAttr) {
280  return TextAttrContains(nSplitPos, pAttr);
281  } ) );
282  if (iter != rSplits.end()) // already split here?
283  {
284  lcl_DoSplitImpl(rSplits, rNode, iter, nSplitPos, bSplitAtStart, bOtherDummy);
285  }
286 }
287 
293 {
294  Insert(& rNewHint);
295  NoteInHistory( & rNewHint, true );
296 }
297 
365 bool
367 {
368 // INVARIANT: the nestable hints in the array are properly nested
369  const sal_uInt16 nNewWhich( rNewHint.Which() );
370  const sal_Int32 nNewStart( rNewHint.GetStart() );
371  const sal_Int32 nNewEnd ( *rNewHint.GetEnd() );
372  const bool bNewSelfNestable( isSelfNestable(nNewWhich) );
373 
374  assert( (RES_TXTATR_INETFMT == nNewWhich) ||
375  (RES_TXTATR_CJK_RUBY == nNewWhich) ||
376  (RES_TXTATR_META == nNewWhich) ||
377  (RES_TXTATR_METAFIELD == nNewWhich) ||
378  (RES_TXTATR_INPUTFIELD == nNewWhich));
379 
380  NestList_t OverlappingExisting; // existing hints to be split
381  NestList_t OverwrittenExisting; // existing hints to be replaced
382  NestList_t SplitNew; // new hints to be inserted
383 
384  SplitNew.push_back(& rNewHint);
385 
386  // pass 1: split the inserted hint into fragments if necessary
387  for ( size_t i = 0; i < Count(); ++i )
388  {
389  SwTextAttr * const pOther = GetSortedByEnd(i);
390 
391  if (pOther->IsNesting())
392  {
393  const sal_uInt16 nOtherWhich( pOther->Which() );
394  const sal_Int32 nOtherStart( pOther->GetStart() );
395  const sal_Int32 nOtherEnd ( *pOther->GetEnd() );
396  if (isOverlap(nNewStart, nNewEnd, nOtherStart, nOtherEnd ))
397  {
398  switch (splitPolicy(nNewWhich, nOtherWhich))
399  {
400  case FAIL:
401  SAL_INFO("sw.core", "cannot insert hint: overlap");
402  for (const auto& aSplit : SplitNew)
403  TextAttrDelete(rNode.GetDoc(), aSplit);
404  return false;
405  case SPLIT_NEW:
406  lcl_DoSplitNew(SplitNew, rNode, nNewStart,
407  nOtherStart, nOtherEnd, pOther->HasDummyChar());
408  break;
409  case SPLIT_OTHER:
410  OverlappingExisting.push_back(
411  static_txtattr_cast<SwTextAttrNesting*>(pOther));
412  break;
413  default:
414  assert(!"bad code monkey");
415  break;
416  }
417  }
418  else if (isNestedAny(nNewStart, nNewEnd, nOtherStart, nOtherEnd))
419  {
420  if (!bNewSelfNestable && (nNewWhich == nOtherWhich))
421  {
422  // ruby and hyperlink: if there is nesting, _overwrite_
423  OverwrittenExisting.push_back(
424  static_txtattr_cast<SwTextAttrNesting*>(pOther));
425  }
426  else if ((nNewStart == nOtherStart) && pOther->HasDummyChar())
427  {
428  if (rNewHint.HasDummyChar())
429  {
430  assert(!"ERROR: inserting duplicate CH_TXTATR hint");
431  return false;
432  } else if (nNewEnd < nOtherEnd) {
433  // other has dummy char, new is inside other, but
434  // new contains the other's dummy char?
435  // should be corrected because it may lead to problems
436  // in SwXMeta::createEnumeration
437  // SplitNew is sorted, so this is the first split
438  assert(SplitNew.front()->GetStart() == nNewStart);
439  SplitNew.front()->SetStart(nNewStart + 1);
440  }
441  }
442  }
443  }
444  }
445 
446  // pass 1b: tragically need to check for fieldmarks here too
447  for (auto iter = SplitNew.begin(); iter != SplitNew.end(); ++iter)
448  {
449  SwPaM const temp(rNode, (*iter)->GetStart(), rNode, *(*iter)->GetEnd());
450  std::vector<std::pair<sal_uLong, sal_Int32>> Breaks;
451  sw::CalcBreaks(Breaks, temp, true);
452  if (!Breaks.empty())
453  {
454  if (!isSplittable(nNewWhich))
455  {
456  SAL_INFO("sw.core", "cannot insert hint: fieldmark overlap");
457  assert(SplitNew.size() == 1);
458  TextAttrDelete(rNode.GetDoc(), &rNewHint);
459  return false;
460  }
461  else
462  {
463  for (auto const& rPos : Breaks)
464  {
465  assert(rPos.first == rNode.GetIndex());
466  iter = lcl_DoSplitImpl(SplitNew, rNode, iter,
467  rPos.second, true, true);
468  }
469  }
470  }
471  }
472 
473  assert((isSplittable(nNewWhich) || SplitNew.size() == 1) &&
474  "splitting the unsplittable ???");
475 
476  // pass 2: split existing hints that overlap/nest with new hint
477  // do not iterate over hints array, but over remembered set of overlapping
478  // hints, to keep things simple w.r.t. insertion/removal
479  // N.B: if there is a hint that splits the inserted hint, then
480  // that hint would also have already split any hint in OverlappingExisting
481  // so any hint in OverlappingExisting can be split at most by one hint
482  // in SplitNew, or even not at all (this is not true for existing hints
483  // that go _around_ new hint, which is the reason d'^etre for pass 4)
484  for (auto& rpOther : OverlappingExisting)
485  {
486  const sal_Int32 nOtherStart( rpOther->GetStart() );
487  const sal_Int32 nOtherEnd ( *rpOther->GetEnd() );
488 
489  for (const auto& rpNew : SplitNew)
490  {
491  const sal_Int32 nSplitNewStart( rpNew->GetStart() );
492  const sal_Int32 nSplitNewEnd ( *rpNew->GetEnd() );
493  // 4 cases: within, around, overlap l, overlap r, (OTHER: no action)
494  const bool bRemoveOverlap(
495  !bNewSelfNestable && (nNewWhich == rpOther->Which()) );
496 
497  switch (ComparePosition(nSplitNewStart, nSplitNewEnd,
498  nOtherStart, nOtherEnd))
499  {
501  {
502  assert(!bRemoveOverlap &&
503  "this one should be in OverwrittenExisting?");
504  }
505  break;
508  {
509  assert(!"existing hint inside new hint: why?");
510  }
511  break;
513  {
514  Delete( rpOther ); // this also does NoteInHistory!
515  rpOther->SetStart(nSplitNewEnd);
516  InsertNesting( *rpOther );
517  if (!bRemoveOverlap)
518  {
519  if ( MAX_HINTS <= Count() )
520  {
521  SAL_INFO("sw.core", "hints array full :-(");
522  return false;
523  }
524  SwTextAttrNesting * const pOtherLeft(
525  MakeTextAttrNesting( rNode, *rpOther,
526  nOtherStart, nSplitNewEnd ) );
527  InsertNesting( *pOtherLeft );
528  }
529  }
530  break;
532  {
533  Delete( rpOther ); // this also does NoteInHistory!
534  rpOther->SetEnd(nSplitNewStart);
535  InsertNesting( *rpOther );
536  if (!bRemoveOverlap)
537  {
538  if ( MAX_HINTS <= Count() )
539  {
540  SAL_INFO("sw.core", "hints array full :-(");
541  return false;
542  }
543  SwTextAttrNesting * const pOtherRight(
544  MakeTextAttrNesting( rNode, *rpOther,
545  nSplitNewStart, nOtherEnd ) );
546  InsertNesting( *pOtherRight );
547  }
548  }
549  break;
550  default:
551  break; // overlap resolved by splitting new: nothing to do
552  }
553  }
554  }
555 
556  if ( MAX_HINTS <= Count() || MAX_HINTS - Count() <= SplitNew.size() )
557  {
558  SAL_INFO("sw.core", "hints array full :-(");
559  return false;
560  }
561 
562  // pass 3: insert new hints
563  for (const auto& rpHint : SplitNew)
564  {
565  InsertNesting(*rpHint);
566  }
567 
568  // pass 4: handle overwritten hints
569  // RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY should displace attributes
570  // of the same kind.
571  for (auto& rpOther : OverwrittenExisting)
572  {
573  const sal_Int32 nOtherStart( rpOther->GetStart() );
574  const sal_Int32 nOtherEnd ( *rpOther->GetEnd() );
575 
576  // overwritten portion is given by start/end of inserted hint
577  if ((nNewStart <= nOtherStart) && (nOtherEnd <= nNewEnd))
578  {
579  Delete(rpOther);
580  rNode.DestroyAttr( rpOther );
581  }
582  else
583  {
584  assert((nOtherStart < nNewStart) || (nNewEnd < nOtherEnd));
585  // scenario: there is a RUBY, and contained within that a META;
586  // now a RUBY is inserted within the META => the existing RUBY is split:
587  // here it is not possible to simply insert the left/right fragment
588  // of the existing RUBY because they <em>overlap</em> with the META!
589  Delete( rpOther ); // this also does NoteInHistory!
590  if (nNewEnd < nOtherEnd)
591  {
592  SwTextAttrNesting * const pOtherRight(
594  rNode, *rpOther, nNewEnd, nOtherEnd ) );
595  bool const bSuccess( TryInsertNesting(rNode, *pOtherRight) );
596  SAL_WARN_IF(!bSuccess, "sw.core", "recursive call 1 failed?");
597  }
598  if (nOtherStart < nNewStart)
599  {
600  rpOther->SetEnd(nNewStart);
601  bool const bSuccess( TryInsertNesting(rNode, *rpOther) );
602  SAL_WARN_IF(!bSuccess, "sw.core", "recursive call 2 failed?");
603  }
604  else
605  {
606  rNode.DestroyAttr(rpOther);
607  }
608  }
609  }
610 
611  return true;
612 }
613 
614 // This function takes care for the following text attribute:
615 // RES_TXTATR_CHARFMT, RES_TXTATR_AUTOFMT
616 // These attributes have to be handled in a special way (Portion building).
617 
618 // The new attribute will be split by any existing RES_TXTATR_AUTOFMT or
619 // RES_TXTATR_CHARFMT. The new attribute itself will
620 // split any existing RES_TXTATR_AUTOFMT or RES_TXTATR_CHARFMT.
621 
623  const SetAttrMode nMode )
624 {
625  const sal_uInt16 nWhich = rNewHint.Which();
626 
627  const sal_Int32 nThisStart = rNewHint.GetStart();
628  const sal_Int32 nThisEnd = *rNewHint.GetEnd();
629  const bool bNoLengthAttribute = nThisStart == nThisEnd;
630 
631  std::vector<SwTextAttr*> aInsDelHints;
632 
633  assert( RES_TXTATR_CHARFMT == rNewHint.Which() ||
634  RES_TXTATR_AUTOFMT == rNewHint.Which() );
635 
636  // 2. Find the hints which cover the start and end position
637  // of the new hint. These hints have to be split into two portions:
638 
639  if ( !bNoLengthAttribute ) // nothing to do for no length attributes
640  {
641  for ( size_t i = 0; i < Count(); ++i )
642  {
643  // we're modifying stuff here which affects the sorting, and we
644  // don't want it changing underneath us
645  SwTextAttr* pOther = GetWithoutResorting(i);
646 
647  if ( RES_TXTATR_CHARFMT != pOther->Which() &&
648  RES_TXTATR_AUTOFMT != pOther->Which() )
649  continue;
650 
651  sal_Int32 nOtherStart = pOther->GetStart();
652  const sal_Int32 nOtherEnd = *pOther->GetEnd();
653 
654  // Check if start of new attribute overlaps with pOther:
655  // Split pOther if necessary:
656  if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
657  {
658  SwTextAttr* pNewAttr = MakeTextAttr( rNode.GetDoc(),
659  pOther->GetAttr(), nOtherStart, nThisStart );
660  if ( RES_TXTATR_CHARFMT == pOther->Which() )
661  {
662  static_txtattr_cast<SwTextCharFormat*>(pNewAttr)->SetSortNumber(
663  static_txtattr_cast<SwTextCharFormat*>(pOther)->GetSortNumber() );
664  }
665  aInsDelHints.push_back( pNewAttr );
666 
667  NoteInHistory( pOther );
668  pOther->SetStart(nThisStart);
669  NoteInHistory( pOther, true );
670 
671  nOtherStart = nThisStart;
672  }
673 
674  // Check if end of new attribute overlaps with pOther:
675  // Split pOther if necessary:
676  if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd )
677  {
678  SwTextAttr* pNewAttr = MakeTextAttr( rNode.GetDoc(),
679  pOther->GetAttr(), nOtherStart, nThisEnd );
680  if ( RES_TXTATR_CHARFMT == pOther->Which() )
681  {
682  static_txtattr_cast<SwTextCharFormat*>(pNewAttr)->SetSortNumber(
683  static_txtattr_cast<SwTextCharFormat*>(pOther)->GetSortNumber());
684  }
685  aInsDelHints.push_back( pNewAttr );
686 
687  NoteInHistory( pOther );
688  pOther->SetStart(nThisEnd);
689  NoteInHistory( pOther, true );
690  }
691  }
692 
693  // Insert the newly created attributes:
694  for ( const auto& rpHint : aInsDelHints )
695  {
696  Insert( rpHint );
697  NoteInHistory( rpHint, true );
698  }
699  }
700 
701 #ifdef DBG_UTIL
702  if( !rNode.GetDoc().IsInReading() )
703  CHECK_NOTMERGED; // ignore flags not set properly yet, don't check them
704 #endif
705 
706  // 4. Split rNewHint into 1 ... n new hints:
707 
709  aBounds.insert( nThisStart );
710  aBounds.insert( nThisEnd );
711 
712  if ( !bNoLengthAttribute ) // nothing to do for no length attributes
713  {
714  for ( size_t i = 0; i < Count(); ++i )
715  {
716  const SwTextAttr* pOther = Get(i);
717 
718  if ( RES_TXTATR_CHARFMT != pOther->Which() &&
719  RES_TXTATR_AUTOFMT != pOther->Which() )
720  continue;
721 
722  const sal_Int32 nOtherStart = pOther->GetStart();
723  const sal_Int32 nOtherEnd = *pOther->End();
724 
725  aBounds.insert( nOtherStart );
726  aBounds.insert( nOtherEnd );
727  }
728  }
729 
730  auto aStartIter = aBounds.lower_bound( nThisStart );
731  auto aEndIter = aBounds.upper_bound( nThisEnd );
732  sal_Int32 nPorStart = *aStartIter;
733  ++aStartIter;
734  bool bDestroyHint = true;
735 
736  // Insert the 1...n new parts of the new attribute:
737 
738  while ( aStartIter != aEndIter || bNoLengthAttribute )
739  {
740  OSL_ENSURE( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" );
741 
742  const sal_Int32 nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter;
743  aInsDelHints.clear();
744 
745  // Get all hints that are in [nPorStart, nPorEnd[:
746  for ( size_t i = 0; i < Count(); ++i )
747  {
748  // we get called from TryInsertHint, which changes ordering
749  SwTextAttr *pOther = GetWithoutResorting(i);
750 
751  if ( RES_TXTATR_CHARFMT != pOther->Which() &&
752  RES_TXTATR_AUTOFMT != pOther->Which() )
753  continue;
754 
755  const sal_Int32 nOtherStart = pOther->GetStart();
756 
757  if ( nOtherStart > nPorStart )
758  break;
759 
760  if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart )
761  {
762  OSL_ENSURE( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" );
763  aInsDelHints.push_back( pOther );
764  }
765  }
766 
767  SwTextAttr* pNewAttr = nullptr;
768  if ( RES_TXTATR_CHARFMT == nWhich )
769  {
770  // pNewHint can be inserted after calculating the sort value.
771  // This should ensure, that pNewHint comes behind the already present
772  // character style
773  sal_uInt16 nCharStyleCount = 0;
774  for ( const auto& rpHint : aInsDelHints )
775  {
776  if ( RES_TXTATR_CHARFMT == rpHint->Which() )
777  {
778  // #i74589#
779  const SwFormatCharFormat& rOtherCharFormat = rpHint->GetCharFormat();
780  const SwFormatCharFormat& rThisCharFormat = rNewHint.GetCharFormat();
781  const bool bSameCharFormat = rOtherCharFormat.GetCharFormat() == rThisCharFormat.GetCharFormat();
782 
783  // #i90311#
784  // Do not remove existing character format hint during XML import
785  if ( !rNode.GetDoc().IsInXMLImport() &&
786  ( !( SetAttrMode::DONTREPLACE & nMode ) ||
787  bNoLengthAttribute ||
788  bSameCharFormat ) )
789  {
790  // Remove old hint
791  Delete( rpHint );
792  rNode.DestroyAttr( rpHint );
793  }
794  else
795  ++nCharStyleCount;
796  }
797  else
798  {
799  // remove all attributes from auto styles, which are explicitly set in
800  // the new character format:
801  OSL_ENSURE( RES_TXTATR_AUTOFMT == rpHint->Which(), "AUTOSTYLES - Misc trouble" );
802  SwTextAttr* pOther = rpHint;
803  std::shared_ptr<SfxItemSet> pOldStyle = static_cast<const SwFormatAutoFormat&>(pOther->GetAttr()).GetStyleHandle();
804 
805  // For each attribute in the automatic style check if it
806  // is also set the new character style:
807  SfxItemSet aNewSet( *pOldStyle->GetPool(),
809  SfxItemIter aItemIter( *pOldStyle );
810  const SfxPoolItem* pItem = aItemIter.GetCurItem();
811  do
812  {
813  if ( !CharFormat::IsItemIncluded( pItem->Which(), &rNewHint ) )
814  {
815  aNewSet.Put( *pItem );
816  }
817 
818  pItem = aItemIter.NextItem();
819  } while (pItem);
820 
821  // Remove old hint
822  Delete( pOther );
823  rNode.DestroyAttr( pOther );
824 
825  // Create new AutoStyle
826  if ( aNewSet.Count() )
827  {
828  pNewAttr = MakeTextAttr( rNode.GetDoc(),
829  aNewSet, nPorStart, nPorEnd );
830  Insert( pNewAttr );
831  NoteInHistory( pNewAttr, true );
832  }
833  }
834  }
835 
836  // If there is no current hint and start and end of rNewHint
837  // is ok, we do not need to create a new txtattr.
838  if ( nPorStart == nThisStart &&
839  nPorEnd == nThisEnd &&
840  !nCharStyleCount )
841  {
842  pNewAttr = &rNewHint;
843  bDestroyHint = false;
844  }
845  else
846  {
847  pNewAttr = MakeTextAttr( rNode.GetDoc(), rNewHint.GetAttr(),
848  nPorStart, nPorEnd );
849  static_txtattr_cast<SwTextCharFormat*>(pNewAttr)->SetSortNumber(nCharStyleCount);
850  }
851  }
852  else
853  {
854  // Find the current autostyle. Mix attributes if necessary.
855  SwTextAttr* pCurrentAutoStyle = nullptr;
856  SwTextAttr* pCurrentCharFormat = nullptr;
857  for ( const auto& rpHint : aInsDelHints )
858  {
859  if ( RES_TXTATR_AUTOFMT == rpHint->Which() )
860  pCurrentAutoStyle = rpHint;
861  else if ( RES_TXTATR_CHARFMT == rpHint->Which() )
862  pCurrentCharFormat = rpHint;
863  }
864 
865  std::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFormatAutoFormat&>(rNewHint.GetAttr()).GetStyleHandle();
866  if ( pCurrentAutoStyle )
867  {
868  std::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFormatAutoFormat&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle();
869 
870  // Merge attributes
871  SfxItemSet aNewSet( *pCurrentStyle );
872  aNewSet.Put( *pNewStyle );
873 
874  // #i75750# Remove attributes already set at whole paragraph
875  // #i81764# This should not be applied for no length attributes!!! <--
876  if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() )
877  {
878  SfxItemIter aIter2( aNewSet );
879  const SfxPoolItem* pItem = aIter2.GetCurItem();
880  const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
881 
882  do
883  {
884  const SfxPoolItem* pTmpItem = nullptr;
885  if ( SfxItemState::SET == rWholeParaAttrSet.GetItemState( pItem->Which(), false, &pTmpItem ) &&
886  pTmpItem == pItem )
887  {
888  // Do not clear item if the attribute is set in a character format:
889  if ( !pCurrentCharFormat || nullptr == CharFormat::GetItem( *pCurrentCharFormat, pItem->Which() ) )
890  aNewSet.ClearItem( pItem->Which() );
891  }
892  }
893  while ((pItem = aIter2.NextItem()));
894  }
895 
896  // Remove old hint
897  Delete( pCurrentAutoStyle );
898  rNode.DestroyAttr( pCurrentAutoStyle );
899 
900  // Create new AutoStyle
901  if ( aNewSet.Count() )
902  pNewAttr = MakeTextAttr( rNode.GetDoc(), aNewSet,
903  nPorStart, nPorEnd );
904  }
905  else
906  {
907  // Remove any attributes which are already set at the whole paragraph:
908  bool bOptimizeAllowed = true;
909 
910  // #i75750# Remove attributes already set at whole paragraph
911  // #i81764# This should not be applied for no length attributes!!! <--
912  if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() )
913  {
914  std::unique_ptr<SfxItemSet> pNewSet;
915 
916  SfxItemIter aIter2( *pNewStyle );
917  const SfxPoolItem* pItem = aIter2.GetCurItem();
918  const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
919 
920  do
921  {
922  const SfxPoolItem* pTmpItem = nullptr;
923  if ( SfxItemState::SET == rWholeParaAttrSet.GetItemState( pItem->Which(), false, &pTmpItem ) &&
924  pTmpItem == pItem )
925  {
926  // Do not clear item if the attribute is set in a character format:
927  if ( !pCurrentCharFormat || nullptr == CharFormat::GetItem( *pCurrentCharFormat, pItem->Which() ) )
928  {
929  if ( !pNewSet )
930  pNewSet = pNewStyle->Clone();
931  pNewSet->ClearItem( pItem->Which() );
932  }
933  }
934  }
935  while ((pItem = aIter2.NextItem()));
936 
937  if ( pNewSet )
938  {
939  bOptimizeAllowed = false;
940  if ( pNewSet->Count() )
942  else
943  pNewStyle.reset();
944  }
945  }
946 
947  // Create new AutoStyle
948  // If there is no current hint and start and end of rNewHint
949  // is ok, we do not need to create a new txtattr.
950  if ( bOptimizeAllowed &&
951  nPorStart == nThisStart &&
952  nPorEnd == nThisEnd )
953  {
954  pNewAttr = &rNewHint;
955  bDestroyHint = false;
956  }
957  else if ( pNewStyle )
958  {
959  pNewAttr = MakeTextAttr( rNode.GetDoc(), *pNewStyle,
960  nPorStart, nPorEnd );
961  }
962  }
963  }
964 
965  if ( pNewAttr )
966  {
967  Insert( pNewAttr );
968 // if ( bDestroyHint )
969  NoteInHistory( pNewAttr, true );
970  }
971 
972  if ( !bNoLengthAttribute )
973  {
974  nPorStart = *aStartIter;
975  ++aStartIter;
976  }
977  else
978  break;
979  }
980 
981  if ( bDestroyHint )
982  rNode.DestroyAttr( &rNewHint );
983 }
984 
986 {
987  // this is intended _only_ for special-purpose redline attributes!
988  switch (rAttr.Which())
989  {
990  case RES_CHRATR_COLOR:
991  case RES_CHRATR_WEIGHT:
994  case RES_CHRATR_POSTURE:
999  case RES_CHRATR_CASEMAP:
1000  case RES_CHRATR_BACKGROUND:
1001  break;
1002  default:
1003  assert(!"unsupported redline attribute");
1004  break;
1005  }
1006 
1007  // Put new attribute into pool
1008  // FIXME: this const_cast is evil!
1009  SfxPoolItem& rNew =
1010  const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
1011  return new SwTextAttrEnd( rNew, 0, 0 );
1012 }
1013 
1014 // create new text attribute
1016  SwDoc & rDoc,
1017  SfxPoolItem& rAttr,
1018  sal_Int32 const nStt,
1019  sal_Int32 const nEnd,
1020  CopyOrNewType const bIsCopy,
1021  SwTextNode *const pTextNode )
1022 {
1023  if ( isCHRATR(rAttr.Which()) )
1024  {
1025  // Somebody wants to build a SwTextAttr for a character attribute.
1026  // Sorry, this is not allowed any longer.
1027  // You'll get a brand new autostyle attribute:
1028  SfxItemSet aItemSet( rDoc.GetAttrPool(),
1030  aItemSet.Put( rAttr );
1031  return MakeTextAttr( rDoc, aItemSet, nStt, nEnd );
1032  }
1033  else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
1034  static_cast<const SwFormatAutoFormat&>(rAttr).GetStyleHandle()->
1035  GetPool() != &rDoc.GetAttrPool() )
1036  {
1037  // If the attribute is an auto-style which refers to a pool that is
1038  // different from rDoc's pool, we have to correct this:
1039  const std::shared_ptr<SfxItemSet> pAutoStyle = static_cast<const SwFormatAutoFormat&>(rAttr).GetStyleHandle();
1040  std::unique_ptr<const SfxItemSet> pNewSet(
1041  pAutoStyle->SfxItemSet::Clone( true, &rDoc.GetAttrPool() ));
1042  SwTextAttr* pNew = MakeTextAttr( rDoc, *pNewSet, nStt, nEnd );
1043  return pNew;
1044  }
1045 
1046  // Put new attribute into pool
1047  // FIXME: this const_cast is evil!
1048  SfxPoolItem& rNew =
1049  const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
1050 
1051  SwTextAttr* pNew = nullptr;
1052  switch( rNew.Which() )
1053  {
1054  case RES_TXTATR_CHARFMT:
1055  {
1056  SwFormatCharFormat &rFormatCharFormat = static_cast<SwFormatCharFormat&>(rNew);
1057  if( !rFormatCharFormat.GetCharFormat() )
1058  {
1059  rFormatCharFormat.SetCharFormat( rDoc.GetDfltCharFormat() );
1060  }
1061 
1062  pNew = new SwTextCharFormat( rFormatCharFormat, nStt, nEnd );
1063  }
1064  break;
1065  case RES_TXTATR_INETFMT:
1066  pNew = new SwTextINetFormat( static_cast<SwFormatINetFormat&>(rNew), nStt, nEnd );
1067  break;
1068 
1069  case RES_TXTATR_FIELD:
1070  pNew = new SwTextField( static_cast<SwFormatField &>(rNew), nStt,
1071  rDoc.IsClipBoard() );
1072  break;
1073 
1074  case RES_TXTATR_ANNOTATION:
1075  {
1076  pNew = new SwTextAnnotationField( static_cast<SwFormatField &>(rNew), nStt, rDoc.IsClipBoard() );
1077  if (bIsCopy == CopyOrNewType::Copy)
1078  {
1079  // On copy of the annotation field do not keep the annotated text range by removing
1080  // the relation to its annotation mark (relation established via annotation field's name).
1081  // If the annotation mark is also copied, the relation and thus the annotated text range will be reestablished,
1082  // when the annotation mark is created and inserted into the document.
1083  const_cast<SwPostItField&>(dynamic_cast<const SwPostItField&>(*(pNew->GetFormatField().GetField()))).SetName(OUString());
1084  }
1085  }
1086  break;
1087 
1088  case RES_TXTATR_INPUTFIELD:
1089  pNew = new SwTextInputField( static_cast<SwFormatField &>(rNew), nStt, nEnd,
1090  rDoc.IsClipBoard() );
1091  break;
1092 
1093  case RES_TXTATR_FLYCNT:
1094  {
1095  // finally, copy the frame format (with content)
1096  pNew = new SwTextFlyCnt( static_cast<SwFormatFlyCnt&>(rNew), nStt );
1097  if ( static_cast<const SwFormatFlyCnt &>(rAttr).GetTextFlyCnt() )
1098  {
1099  // if it has an existing attr then the format must be copied
1100  static_cast<SwTextFlyCnt *>(pNew)->CopyFlyFormat( rDoc );
1101  }
1102  }
1103  break;
1104  case RES_TXTATR_FTN:
1105  pNew = new SwTextFootnote( static_cast<SwFormatFootnote&>(rNew), nStt );
1106  // copy note's SeqNo
1107  if( static_cast<SwFormatFootnote&>(rAttr).GetTextFootnote() )
1108  static_cast<SwTextFootnote*>(pNew)->SetSeqNo( static_cast<SwFormatFootnote&>(rAttr).GetTextFootnote()->GetSeqRefNo() );
1109  break;
1110  case RES_TXTATR_REFMARK:
1111  pNew = nStt == nEnd
1112  ? new SwTextRefMark( static_cast<SwFormatRefMark&>(rNew), nStt )
1113  : new SwTextRefMark( static_cast<SwFormatRefMark&>(rNew), nStt, &nEnd );
1114  break;
1115  case RES_TXTATR_TOXMARK:
1116  {
1117  SwTOXMark& rMark = static_cast<SwTOXMark&>(rNew);
1118 
1119  // tdf#98868 if the SwTOXType is from a different document that the
1120  // target, re-register the TOXMark against a matching SwTOXType from
1121  // the target document instead
1122  const SwTOXType* pTOXType = rMark.GetTOXType();
1123  if (pTOXType && &pTOXType->GetDoc() != &rDoc)
1124  {
1125  SwTOXType* pToxType = SwHistorySetTOXMark::GetSwTOXType(rDoc, pTOXType->GetType(),
1126  pTOXType->GetTypeName());
1127  rMark.RegisterToTOXType(*pToxType);
1128  }
1129 
1130  pNew = new SwTextTOXMark(rMark, nStt, &nEnd);
1131  break;
1132  }
1133  case RES_TXTATR_CJK_RUBY:
1134  pNew = new SwTextRuby( static_cast<SwFormatRuby&>(rNew), nStt, nEnd );
1135  break;
1136  case RES_TXTATR_META:
1137  case RES_TXTATR_METAFIELD:
1138  pNew = SwTextMeta::CreateTextMeta( rDoc.GetMetaFieldManager(), pTextNode,
1139  static_cast<SwFormatMeta&>(rNew), nStt, nEnd, bIsCopy == CopyOrNewType::Copy );
1140  break;
1141  default:
1142  assert(RES_TXTATR_AUTOFMT == rNew.Which());
1143  pNew = new SwTextAttrEnd( rNew, nStt, nEnd );
1144  break;
1145  }
1146 
1147  return pNew;
1148 }
1149 
1150 SwTextAttr* MakeTextAttr( SwDoc & rDoc, const SfxItemSet& rSet,
1151  sal_Int32 nStt, sal_Int32 nEnd )
1152 {
1153  IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
1154  const std::shared_ptr<SfxItemSet> pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
1155  SwFormatAutoFormat aNewAutoFormat;
1156  aNewAutoFormat.SetStyleHandle( pAutoStyle );
1157  SwTextAttr* pNew = MakeTextAttr( rDoc, aNewAutoFormat, nStt, nEnd );
1158  return pNew;
1159 }
1160 
1161 // delete the text attribute and unregister its item at the pool
1163 {
1164  if( !pAttr )
1165  return;
1166 
1167  // some things need to be done before deleting the formatting attribute
1168  SwDoc& rDoc = GetDoc();
1169  switch( pAttr->Which() )
1170  {
1171  case RES_TXTATR_FLYCNT:
1172  {
1173  SwFrameFormat* pFormat = pAttr->GetFlyCnt().GetFrameFormat();
1174  if( pFormat ) // set to 0 by Undo?
1175  rDoc.getIDocumentLayoutAccess().DelLayoutFormat( pFormat );
1176  }
1177  break;
1178 
1179  case RES_CHRATR_HIDDEN:
1181  break;
1182 
1183  case RES_TXTATR_FTN:
1184  static_cast<SwTextFootnote*>(pAttr)->SetStartNode( nullptr );
1185  static_cast<SwFormatFootnote&>(pAttr->GetAttr()).InvalidateFootnote();
1186  break;
1187 
1188  case RES_TXTATR_FIELD:
1189  case RES_TXTATR_ANNOTATION:
1190  case RES_TXTATR_INPUTFIELD:
1191  if( !rDoc.IsInDtor() )
1192  {
1193  SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pAttr));
1194  SwFieldType* pFieldType = pAttr->GetFormatField().GetField()->GetTyp();
1195 
1196  //JP 06-08-95: DDE-fields are an exception
1197  assert(SwFieldIds::Dde == pFieldType->Which() ||
1198  this == pTextField->GetpTextNode());
1199 
1200  // certain fields must update the SwDoc's calculation flags
1201 
1202  // Certain fields (like HiddenParaField) must trigger recalculation of visible flag
1203  if (GetDoc().FieldCanHideParaWeight(pFieldType->Which()))
1205 
1206  switch( pFieldType->Which() )
1207  {
1210  case SwFieldIds::GetExp:
1211  case SwFieldIds::Database:
1212  case SwFieldIds::SetExp:
1214  case SwFieldIds::DbNumSet:
1215  case SwFieldIds::DbNextSet:
1217  rDoc.getIDocumentFieldsAccess().InsDelFieldInFieldLst(false, *pTextField);
1218  break;
1219  case SwFieldIds::Dde:
1220  if (GetNodes().IsDocNodes() && pTextField->GetpTextNode())
1221  static_cast<SwDDEFieldType*>(pFieldType)->DecRefCnt();
1222  break;
1223  case SwFieldIds::Postit:
1224  {
1225  const_cast<SwFormatField&>(pAttr->GetFormatField()).Broadcast(
1227  break;
1228  }
1229  default: break;
1230  }
1231  }
1232  static_cast<SwFormatField&>(pAttr->GetAttr()).InvalidateField();
1233  break;
1234 
1235  case RES_TXTATR_TOXMARK:
1236  static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark();
1237  break;
1238 
1239  case RES_TXTATR_REFMARK:
1240  static_cast<SwFormatRefMark&>(pAttr->GetAttr()).InvalidateRefMark();
1241  break;
1242 
1243  case RES_TXTATR_META:
1244  case RES_TXTATR_METAFIELD:
1245  {
1246  auto pTextMeta = static_txtattr_cast<SwTextMeta*>(pAttr);
1247  SwFormatMeta & rFormatMeta( static_cast<SwFormatMeta &>(pTextMeta->GetAttr()) );
1248  if (::sw::Meta* pMeta = rFormatMeta.GetMeta())
1249  {
1250  if (SwDocShell* pDocSh = rDoc.GetDocShell())
1251  {
1252  static constexpr OUStringLiteral metaNS(u"urn:bails");
1253  const css::uno::Reference<css::rdf::XResource> xSubject = pMeta->MakeUnoObject();
1254  uno::Reference<frame::XModel> xModel = pDocSh->GetBaseModel();
1255  SwRDFHelper::clearStatements(xModel, metaNS, xSubject);
1256  }
1257  }
1258 
1259  static_txtattr_cast<SwTextMeta*>(pAttr)->ChgTextNode(nullptr);
1260  }
1261  break;
1262 
1263  default:
1264  break;
1265  }
1266 
1267  SwTextAttr::Destroy( pAttr, rDoc.GetAttrPool() );
1268 }
1269 
1271  SfxPoolItem& rAttr,
1272  const sal_Int32 nStart,
1273  const sal_Int32 nEnd,
1274  const SetAttrMode nMode )
1275 {
1276  // character attributes will be inserted as automatic styles:
1277  assert( !isCHRATR(rAttr.Which()) && "AUTOSTYLES - "
1278  "SwTextNode::InsertItem should not be called with character attributes");
1279 
1280  SwTextAttr *const pNew =
1281  MakeTextAttr(
1282  GetDoc(),
1283  rAttr,
1284  nStart,
1285  nEnd,
1287  this );
1288 
1289  if ( pNew )
1290  {
1291  const bool bSuccess( InsertHint( pNew, nMode ) );
1292  // N.B.: also check that the hint is actually in the hints array,
1293  // because hints of certain types may be merged after successful
1294  // insertion, and thus destroyed!
1295  if (!bSuccess || !m_pSwpHints->Contains( pNew ))
1296  {
1297  return nullptr;
1298  }
1299  }
1300 
1301  return pNew;
1302 }
1303 
1304 // take ownership of pAttr; if insertion fails, delete pAttr
1305 bool SwTextNode::InsertHint( SwTextAttr * const pAttr, const SetAttrMode nMode )
1306 {
1307  bool bHiddenPara = false;
1308 
1309  assert(pAttr && pAttr->GetStart() <= Len());
1310  assert(!pAttr->GetEnd() || (*pAttr->GetEnd() <= Len()));
1311 
1312  // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR)
1313  const SwInsertFlags nInsertFlags =
1314  (nMode & SetAttrMode::NOHINTEXPAND)
1316  : (nMode & SetAttrMode::FORCEHINTEXPAND)
1319 
1320  // need this after TryInsertHint, when pAttr may be deleted
1321  const sal_Int32 nStart( pAttr->GetStart() );
1322  const bool bDummyChar( pAttr->HasDummyChar() );
1323  if (bDummyChar)
1324  {
1325  SetAttrMode nInsMode = nMode;
1326  switch( pAttr->Which() )
1327  {
1328  case RES_TXTATR_FLYCNT:
1329  {
1330  SwTextFlyCnt *pFly = static_cast<SwTextFlyCnt *>(pAttr);
1331  SwFrameFormat* pFormat = pAttr->GetFlyCnt().GetFrameFormat();
1332  if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
1333  {
1334  // Need to insert char first, because SetAnchor() reads
1335  // GetStart().
1336  //JP 11.05.98: if the anchor is already set correctly,
1337  // fix it after inserting the char, so that clients don't
1338  // have to worry about it.
1339  const SwFormatAnchor* pAnchor = nullptr;
1340  (void)pFormat->GetItemState( RES_ANCHOR, false,
1341  reinterpret_cast<const SfxPoolItem**>(&pAnchor) );
1342 
1343  SwIndex aIdx( this, pAttr->GetStart() );
1344  const OUString c(GetCharOfTextAttr(*pAttr));
1345  OUString const ins( InsertText(c, aIdx, nInsertFlags) );
1346  if (ins.isEmpty())
1347  {
1348  // do not record deletion of Format!
1349  ::sw::UndoGuard const ug(
1350  pFormat->GetDoc()->GetIDocumentUndoRedo());
1351  DestroyAttr(pAttr);
1352  return false; // text node full :(
1353  }
1354  nInsMode |= SetAttrMode::NOTXTATRCHR;
1355 
1356  if (pAnchor &&
1357  (RndStdIds::FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
1358  pAnchor->GetContentAnchor() &&
1359  pAnchor->GetContentAnchor()->nNode == *this &&
1360  pAnchor->GetContentAnchor()->nContent == aIdx )
1361  {
1362  --const_cast<SwIndex&>(
1363  pAnchor->GetContentAnchor()->nContent);
1364  }
1365  }
1366  pFly->SetAnchor( this );
1367 
1368  // format pointer could have changed in SetAnchor,
1369  // when copying to other docs!
1370  pFormat = pAttr->GetFlyCnt().GetFrameFormat();
1371  SwDoc *pDoc = pFormat->GetDoc();
1372 
1373  // OD 26.06.2003 - allow drawing objects in header/footer.
1374  // But don't allow control objects in header/footer
1375  if( RES_DRAWFRMFMT == pFormat->Which() &&
1376  pDoc->IsInHeaderFooter( pFormat->GetAnchor().GetContentAnchor()->nNode ) )
1377  {
1378  bool bCheckControlLayer = false;
1379  pFormat->CallSwClientNotify(sw::CheckDrawFrameFormatLayerHint(&bCheckControlLayer));
1380  if( bCheckControlLayer )
1381  {
1382  // This should not be allowed, prevent it here.
1383  // The dtor of the SwTextAttr does not delete the
1384  // char, so delete it explicitly here.
1385  if( SetAttrMode::NOTXTATRCHR & nInsMode )
1386  {
1387  // delete the char from the string
1388  assert(CH_TXTATR_BREAKWORD == m_Text[pAttr->GetStart()]
1389  || CH_TXTATR_INWORD == m_Text[pAttr->GetStart()]);
1390  m_Text = m_Text.replaceAt(pAttr->GetStart(), 1, "");
1391  // Update SwIndexes
1392  SwIndex aTmpIdx( this, pAttr->GetStart() );
1393  Update( aTmpIdx, 1, true );
1394  }
1395  // do not record deletion of Format!
1396  ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1397  DestroyAttr( pAttr );
1398  return false;
1399  }
1400  }
1401  break;
1402  }
1403 
1404  case RES_TXTATR_FTN :
1405  {
1406  // Footnotes: create text node and put it into Inserts-section
1407  SwDoc& rDoc = GetDoc();
1408  SwNodes &rNodes = rDoc.GetNodes();
1409 
1410  // check that footnote is inserted into body or redline section
1411  if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
1412  {
1413  // This should not be allowed, prevent it here.
1414  // The dtor of the SwTextAttr does not delete the
1415  // char, so delete it explicitly here.
1416  if( SetAttrMode::NOTXTATRCHR & nInsMode )
1417  {
1418  // delete the char from the string
1419  assert(CH_TXTATR_BREAKWORD == m_Text[pAttr->GetStart()]
1420  || CH_TXTATR_INWORD == m_Text[pAttr->GetStart()]);
1421  m_Text = m_Text.replaceAt(pAttr->GetStart(), 1, "");
1422  // Update SwIndexes
1423  SwIndex aTmpIdx( this, pAttr->GetStart() );
1424  Update( aTmpIdx, 1, true );
1425  }
1426  DestroyAttr( pAttr );
1427  return false;
1428  }
1429 
1430  // is a new footnote being inserted?
1431  bool bNewFootnote = nullptr == static_cast<SwTextFootnote*>(pAttr)->GetStartNode();
1432  if( bNewFootnote )
1433  {
1434  static_cast<SwTextFootnote*>(pAttr)->MakeNewTextSection( GetNodes() );
1435  SwRegHistory* pHist = GetpSwpHints()
1436  ? GetpSwpHints()->GetHistory() : nullptr;
1437  if( pHist )
1438  pHist->ChangeNodeIndex( GetIndex() );
1439  }
1440  else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
1441  {
1442  // existing footnote: delete all layout frames of its
1443  // footnote section
1444  sal_uLong nSttIdx =
1445  static_cast<SwTextFootnote*>(pAttr)->GetStartNode()->GetIndex();
1446  sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
1447  for( ; nSttIdx < nEndIdx; ++nSttIdx )
1448  {
1449  SwContentNode* pCNd = rNodes[ nSttIdx ]->GetContentNode();
1450  if( nullptr != pCNd )
1451  pCNd->DelFrames(nullptr);
1452  else if (SwTableNode *const pTable = rNodes[nSttIdx]->GetTableNode())
1453  {
1454  pTable->DelFrames();
1455  }
1456  }
1457  }
1458 
1459  if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
1460  {
1461  // must insert first, to prevent identical indexes
1462  // that could later prevent insertion into SwDoc's
1463  // footnote array
1464  SwIndex aNdIdx( this, pAttr->GetStart() );
1465  const OUString c(GetCharOfTextAttr(*pAttr));
1466  OUString const ins( InsertText(c, aNdIdx, nInsertFlags) );
1467  if (ins.isEmpty())
1468  {
1469  DestroyAttr(pAttr);
1470  return false; // text node full :(
1471  }
1472  nInsMode |= SetAttrMode::NOTXTATRCHR;
1473  }
1474 
1475  // insert into SwDoc's footnote index array
1476  SwTextFootnote* pTextFootnote = nullptr;
1477  if( !bNewFootnote )
1478  {
1479  // moving an existing footnote (e.g. SplitNode)
1480  for( size_t n = 0; n < rDoc.GetFootnoteIdxs().size(); ++n )
1481  if( pAttr == rDoc.GetFootnoteIdxs()[n] )
1482  {
1483  // assign new index by removing and re-inserting
1484  pTextFootnote = rDoc.GetFootnoteIdxs()[n];
1485  rDoc.GetFootnoteIdxs().erase( rDoc.GetFootnoteIdxs().begin() + n );
1486  break;
1487  }
1488  // if the Undo set the StartNode, the Index isn't
1489  // in the doc's array yet!
1490  }
1491  if( !pTextFootnote )
1492  pTextFootnote = static_cast<SwTextFootnote*>(pAttr);
1493 
1494  // to update the numbers and for sorting, the Node must be set
1495  static_cast<SwTextFootnote*>(pAttr)->ChgTextNode( this );
1496 
1497  // do not insert footnote in redline section into footnote array
1498  if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
1499  {
1500  const bool bSuccess = rDoc.GetFootnoteIdxs().insert(pTextFootnote).second;
1501  OSL_ENSURE( bSuccess, "FootnoteIdx not inserted." );
1502  }
1503  SwNodeIndex aTmpIndex( *this );
1504  rDoc.GetFootnoteIdxs().UpdateFootnote( aTmpIndex);
1505  static_cast<SwTextFootnote*>(pAttr)->SetSeqRefNo();
1506  }
1507  break;
1508 
1509  case RES_TXTATR_FIELD:
1510  {
1511  // trigger notification for relevant fields, like HiddenParaFields
1513  pAttr->GetFormatField().GetField()->GetTyp()->Which()))
1514  {
1515  bHiddenPara = true;
1516  }
1517  }
1518  break;
1519 
1520  }
1521  // CH_TXTATR_* are inserted for SwTextHints without EndIndex
1522  // If the caller is SwTextNode::Copy, the char has already been copied,
1523  // and SETATTR_NOTXTATRCHR prevents inserting it again here.
1524  if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
1525  {
1526  SwIndex aIdx( this, pAttr->GetStart() );
1527  OUString const ins( InsertText(OUString(GetCharOfTextAttr(*pAttr)),
1528  aIdx, nInsertFlags) );
1529  if (ins.isEmpty())
1530  {
1531  DestroyAttr(pAttr);
1532  return false; // text node full :(
1533  }
1534 
1535  // adjust end of hint to account for inserted CH_TXTATR
1536  const sal_Int32 * const pEnd(pAttr->GetEnd());
1537  if (pEnd)
1538  {
1539  pAttr->SetEnd(*pEnd + 1);
1540  }
1541  }
1542  }
1543 
1544  // handle attributes which provide content
1545  sal_Int32 nEnd = nStart;
1546  bool bInputFieldStartCharInserted = false;
1547  bool bInputFieldEndCharInserted = false;
1548  const bool bHasContent( pAttr->HasContent() );
1549  if ( bHasContent )
1550  {
1551  switch( pAttr->Which() )
1552  {
1553  case RES_TXTATR_INPUTFIELD:
1554  {
1555  SwTextInputField* pTextInputField = dynamic_cast<SwTextInputField*>(pAttr);
1556  if ( pTextInputField )
1557  {
1558  if( !(SetAttrMode::NOTXTATRCHR & nMode) )
1559  {
1560  SwIndex aIdx( this, pAttr->GetStart() );
1561  const OUString aContent = OUStringChar(CH_TXT_ATR_INPUTFIELDSTART)
1562  + pTextInputField->GetFieldContent() + OUStringChar(CH_TXT_ATR_INPUTFIELDEND);
1563  InsertText( aContent, aIdx, nInsertFlags );
1564 
1565  const sal_Int32* const pEnd(pAttr->GetEnd());
1566  assert(pEnd != nullptr);
1567  pAttr->SetEnd(*pEnd + aContent.getLength());
1568  nEnd = *pAttr->GetEnd();
1569  }
1570  else
1571  {
1572  // assure that CH_TXT_ATR_INPUTFIELDSTART and CH_TXT_ATR_INPUTFIELDEND are inserted.
1573  if ( m_Text[ pAttr->GetStart() ] != CH_TXT_ATR_INPUTFIELDSTART )
1574  {
1575  SwIndex aIdx( this, pAttr->GetStart() );
1576  InsertText( OUString(CH_TXT_ATR_INPUTFIELDSTART), aIdx, nInsertFlags );
1577  bInputFieldStartCharInserted = true;
1578  const sal_Int32* const pEnd(pAttr->GetEnd());
1579  assert(pEnd != nullptr);
1580  pAttr->SetEnd(*pEnd + 1);
1581  nEnd = *pAttr->GetEnd();
1582  }
1583 
1584  const sal_Int32* const pEnd(pAttr->GetEnd());
1585  assert(pEnd != nullptr);
1586  if (m_Text[ *pEnd - 1 ] != CH_TXT_ATR_INPUTFIELDEND)
1587  {
1588  SwIndex aIdx( this, *pEnd );
1589  InsertText( OUString(CH_TXT_ATR_INPUTFIELDEND), aIdx, nInsertFlags );
1590  bInputFieldEndCharInserted = true;
1591  pAttr->SetEnd(*pEnd + 1);
1592  nEnd = *pAttr->GetEnd();
1593  }
1594  }
1595  }
1596  }
1597  break;
1598  default:
1599  break;
1600  }
1601  }
1602 
1604 
1605  // handle overlap with an existing InputField
1606  bool bInsertHint = true;
1607  {
1608  const SwTextInputField* pTextInputField = GetOverlappingInputField( *pAttr );
1609  if ( pTextInputField != nullptr )
1610  {
1611  if ( pAttr->End() == nullptr )
1612  {
1613  bInsertHint = false;
1614  }
1615  else
1616  {
1617  if ( pAttr->GetStart() > pTextInputField->GetStart() )
1618  {
1619  pAttr->SetStart( pTextInputField->GetStart() );
1620  }
1621  if ( *(pAttr->End()) < *(pTextInputField->End()) )
1622  {
1623  pAttr->SetEnd(*(pTextInputField->End()));
1624  }
1625  }
1626  }
1627  }
1628 
1629  const bool bRet = bInsertHint
1630  && m_pSwpHints->TryInsertHint( pAttr, *this, nMode );
1631 
1632  if ( !bRet )
1633  {
1634  if ( bDummyChar
1635  && !(SetAttrMode::NOTXTATRCHR & nMode) )
1636  {
1637  // undo insertion of dummy character
1638  // N.B. cannot insert the dummy character after inserting the hint,
1639  // because if the hint has no extent it will be moved in InsertText,
1640  // resulting in infinite recursion
1641  assert((CH_TXTATR_BREAKWORD == m_Text[nStart] ||
1642  CH_TXTATR_INWORD == m_Text[nStart] ));
1643  SwIndex aIdx( this, nStart );
1644  EraseText( aIdx, 1 );
1645  }
1646 
1647  if ( bHasContent )
1648  {
1649  if ( !(SetAttrMode::NOTXTATRCHR & nMode)
1650  && (nEnd - nStart) > 0 )
1651  {
1652  SwIndex aIdx( this, nStart );
1653  EraseText( aIdx, (nEnd - nStart) );
1654  }
1655  else
1656  {
1657  if ( bInputFieldEndCharInserted
1658  && (nEnd - nStart) > 0 )
1659  {
1660  SwIndex aIdx( this, nEnd - 1 );
1661  EraseText( aIdx, 1 );
1662  }
1663 
1664  if ( bInputFieldStartCharInserted )
1665  {
1666  SwIndex aIdx( this, nStart );
1667  EraseText( aIdx, 1 );
1668  }
1669  }
1670  }
1671  }
1672 
1673  if ( bHiddenPara )
1674  {
1676  }
1677 
1678  return bRet;
1679 }
1680 
1682 {
1683  if ( !HasHints() )
1684  {
1685  OSL_FAIL("DeleteAttribute called, but text node without hints?");
1686  return;
1687  }
1688 
1689  if ( pAttr->HasDummyChar() )
1690  {
1691  // copy index!
1692  const SwIndex aIdx( this, pAttr->GetStart() );
1693  // erase the CH_TXTATR, which will also delete pAttr
1694  EraseText( aIdx, 1 );
1695  }
1696  else if ( pAttr->HasContent() )
1697  {
1698  const SwIndex aIdx( this, pAttr->GetStart() );
1699  assert(pAttr->End() != nullptr);
1700  EraseText( aIdx, *pAttr->End() - pAttr->GetStart() );
1701  }
1702  else
1703  {
1704  // create MsgHint before start/end become invalid
1705  SwUpdateAttr aHint(
1706  pAttr->GetStart(),
1707  *pAttr->GetEnd(),
1708  pAttr->Which());
1709 
1710  m_pSwpHints->Delete( pAttr );
1711  SwTextAttr::Destroy( pAttr, GetDoc().GetAttrPool() );
1712  CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aHint));
1713 
1715  }
1716 }
1717 
1718 //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
1720  const sal_uInt16 nWhich,
1721  const sal_Int32 nStart,
1722  const sal_Int32 nEnd )
1723 {
1724  if ( !HasHints() )
1725  return;
1726 
1727  for ( size_t nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); ++nPos )
1728  {
1729  SwTextAttr * const pTextHt = m_pSwpHints->Get( nPos );
1730  const sal_Int32 nHintStart = pTextHt->GetStart();
1731  if (nStart < nHintStart)
1732  {
1733  break; // sorted by start
1734  }
1735  else if ( (nStart == nHintStart) && (nWhich == pTextHt->Which()) )
1736  {
1737  if ( nWhich == RES_CHRATR_HIDDEN )
1738  {
1739  assert(!"hey, that's a CHRATR! how did that get in?");
1741  }
1742  else if ( nWhich == RES_TXTATR_CHARFMT )
1743  {
1744  // Check if character format contains hidden attribute:
1745  const SwCharFormat* pFormat = pTextHt->GetCharFormat().GetCharFormat();
1746  const SfxPoolItem* pItem;
1747  if ( SfxItemState::SET == pFormat->GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) )
1749  }
1750  // #i75430# Recalc hidden flags if necessary
1751  else if ( nWhich == RES_TXTATR_AUTOFMT )
1752  {
1753  // Check if auto style contains hidden attribute:
1754  const SfxPoolItem* pHiddenItem = CharFormat::GetItem( *pTextHt, RES_CHRATR_HIDDEN );
1755  if ( pHiddenItem )
1757  // for auto styles DeleteAttributes is only called from Undo
1758  // so it shouldn't need to care about ignore start/end flags
1759  }
1760 
1761  sal_Int32 const * const pEndIdx = pTextHt->GetEnd();
1762 
1763  if ( pTextHt->HasDummyChar() )
1764  {
1765  // copy index!
1766  const SwIndex aIdx( this, nStart );
1767  // erase the CH_TXTATR, which will also delete pTextHt
1768  EraseText( aIdx, 1 );
1769  }
1770  else if ( pTextHt->HasContent() )
1771  {
1772  const SwIndex aIdx( this, nStart );
1773  OSL_ENSURE( pTextHt->End() != nullptr, "<SwTextNode::DeleteAttributes(..)> - missing End() at <SwTextAttr> instance which has content" );
1774  EraseText( aIdx, *pTextHt->End() - nStart );
1775  }
1776  else if( *pEndIdx == nEnd )
1777  {
1778  // Create MsgHint before Start and End are gone.
1779  // For HiddenParaFields it's not necessary to call
1780  // SetCalcHiddenParaField because the dtor does that.
1781  SwUpdateAttr aHint(
1782  nStart,
1783  *pEndIdx,
1784  nWhich);
1785 
1786  m_pSwpHints->DeleteAtPos( nPos );
1787  SwTextAttr::Destroy( pTextHt, GetDoc().GetAttrPool() );
1788  CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aHint));
1789  }
1790  }
1791  }
1793 }
1794 
1795 void SwTextNode::DelSoftHyph( const sal_Int32 nStt, const sal_Int32 nEnd )
1796 {
1797  sal_Int32 nFndPos = nStt;
1798  sal_Int32 nEndPos = nEnd;
1799  for (;;)
1800  {
1801  nFndPos = m_Text.indexOf(CHAR_SOFTHYPHEN, nFndPos);
1802  if (nFndPos<0 || nFndPos>=nEndPos )
1803  {
1804  break;
1805  }
1806  const SwIndex aIdx( this, nFndPos );
1807  EraseText( aIdx, 1 );
1808  --nEndPos;
1809  }
1810 }
1811 
1812 bool SwTextNode::IsIgnoredCharFormatForNumbering(const sal_uInt16 nWhich)
1813 {
1814  return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_BACKGROUND
1815  || nWhich == RES_CHRATR_ESCAPEMENT);
1816 }
1817 
1818 //In MS Word, following properties of the paragraph end position won't affect the formatting of bullets, so we ignore them:
1819 //Font underline;
1820 //Font Italic of Western, CJK and CTL;
1821 //Font Bold of Wertern, CJK and CTL;
1822 static bool lcl_IsIgnoredCharFormatForBullets(const sal_uInt16 nWhich)
1823 {
1824  return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_POSTURE || nWhich == RES_CHRATR_WEIGHT
1825  || nWhich == RES_CHRATR_CJK_POSTURE || nWhich == RES_CHRATR_CJK_WEIGHT
1826  || nWhich == RES_CHRATR_CTL_POSTURE || nWhich == RES_CHRATR_CTL_WEIGHT);
1827 }
1828 
1829 //Condition for expanding char set to character style of specified number rule level:
1830 //The item inside the set should not conflict to any exist and non-default item inside paragraph properties set (SwContentNode::SwPAttrSet);
1831 //The node should have applied a number rule;
1832 //The node should be counted in a list, if not, make it to be;
1833 //The item should not conflict to any exist and non-default item inside the character of specified number rule level;
1834 //The item should not be ignored depend on the exact number rule type;
1836 {
1837  SfxItemIter aIter( aCharSet );
1838  const SfxPoolItem* pItem = aIter.GetCurItem();
1839  if (!pItem)
1840  return;
1841  const sal_uInt16 nWhich = pItem->Which();
1842 
1843  const SfxPoolItem& rInnerItem = GetAttr(nWhich,false);
1844 
1845  if (!IsDefaultItem(&rInnerItem) && !IsInvalidItem(&rInnerItem))
1846  return;
1847 
1848  if (!IsInList() && GetNumRule() && !GetListId().isEmpty())
1849  {
1850  return;
1851  }
1852 
1853  SwNumRule* pCurrNum = GetNumRule(false);
1854 
1855  int nLevel = GetActualListLevel();
1856 
1857  if (!(nLevel != -1 && pCurrNum))
1858  return;
1859 
1860  const SwNumFormat* pCurrNumFormat = pCurrNum->GetNumFormat(static_cast<sal_uInt16>(nLevel));
1861  if (!pCurrNumFormat)
1862  return;
1863 
1864  if (pCurrNumFormat->IsItemize() && lcl_IsIgnoredCharFormatForBullets(nWhich))
1865  return;
1866  if (pCurrNumFormat->IsEnumeration() && SwTextNode::IsIgnoredCharFormatForNumbering(nWhich))
1867  return;
1868  SwCharFormat* pCurrCharFormat =pCurrNumFormat->GetCharFormat();
1869 
1870  if (pCurrCharFormat && pCurrCharFormat->GetItemState(nWhich,false) != SfxItemState::SET)
1871  {
1872  pCurrCharFormat->SetFormatAttr(*pItem);
1873  SwNumFormat aNewNumFormat(*pCurrNumFormat);
1874  aNewNumFormat.SetCharFormat(pCurrCharFormat);
1875  pCurrNum->Set(nLevel,aNewNumFormat);
1876  }
1877 }
1878 
1879 // Set these attributes on SwTextNode. If they apply to the entire paragraph
1880 // text, set them in the SwTextNode's item set (SwContentNode::SetAttr).
1882  const SfxItemSet& rSet,
1883  const sal_Int32 nStt,
1884  const sal_Int32 nEnd,
1885  const SetAttrMode nMode,
1886  SwTextAttr **ppNewTextAttr )
1887 {
1888  if( !rSet.Count() )
1889  return false;
1890 
1891  // split sets (for selection in nodes)
1892  const SfxItemSet* pSet = &rSet;
1893  SfxItemSet aTextSet( *rSet.GetPool(), svl::Items<RES_TXTATR_BEGIN, RES_TXTATR_END-1>{} );
1894 
1895  // entire paragraph
1896  if ( !nStt && (nEnd == m_Text.getLength()) &&
1897  !(nMode & SetAttrMode::NOFORMATATTR ) )
1898  {
1899  // if the node already has CharFormat hints, the new attributes must
1900  // be set as hints too to override those.
1901  bool bHasCharFormats = false;
1902  if ( HasHints() )
1903  {
1904  for ( size_t n = 0; n < m_pSwpHints->Count(); ++n )
1905  {
1906  if ( m_pSwpHints->Get( n )->IsCharFormatAttr() )
1907  {
1908  bHasCharFormats = true;
1909  break;
1910  }
1911  }
1912  }
1913 
1914  if( !bHasCharFormats )
1915  {
1916  aTextSet.Put( rSet );
1917  // If there are any character attributes in rSet,
1918  // we want to set them at the paragraph:
1919  if( aTextSet.Count() != rSet.Count() )
1920  {
1921  const bool bRet = SetAttr( rSet );
1922  if( !aTextSet.Count() )
1923  return bRet;
1924  }
1925 
1926  // check for auto style:
1927  const SfxPoolItem* pItem;
1928  const bool bAutoStyle = SfxItemState::SET == aTextSet.GetItemState( RES_TXTATR_AUTOFMT, false, &pItem );
1929  if ( bAutoStyle )
1930  {
1931  std::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFormatAutoFormat*>(pItem)->GetStyleHandle();
1932  const bool bRet = SetAttr( *pAutoStyleSet );
1933  if( 1 == aTextSet.Count() )
1934  return bRet;
1935  }
1936 
1937  // Continue with the text attributes:
1938  pSet = &aTextSet;
1939  }
1940  }
1941 
1943 
1944  SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFormatSetRange );
1945 
1946  size_t nCount = 0;
1947  SfxItemIter aIter( *pSet );
1948  const SfxPoolItem* pItem = aIter.GetCurItem();
1949 
1950  do
1951  {
1952  if (!IsInvalidItem(pItem))
1953  {
1954  const sal_uInt16 nWhich = pItem->Which();
1955  OSL_ENSURE( isCHRATR(nWhich) || isTXTATR(nWhich),
1956  "SwTextNode::SetAttr(): unknown attribute" );
1957  if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
1958  {
1959  if ((RES_TXTATR_CHARFMT == nWhich) &&
1960  (GetDoc().GetDfltCharFormat() ==
1961  static_cast<const SwFormatCharFormat*>(pItem)->GetCharFormat()))
1962  {
1963  SwIndex aIndex( this, nStt );
1964  RstTextAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT );
1965  DontExpandFormat( aIndex );
1966  }
1967  else
1968  {
1969  if (isCHRATR(nWhich) ||
1970  (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1971  {
1972  aCharSet.Put( *pItem );
1973  }
1974  else
1975  {
1976 
1977  SwTextAttr *const pNew = MakeTextAttr( GetDoc(),
1978  const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
1979  if ( pNew )
1980  {
1981  // store the first one we create into the pp
1982  if (ppNewTextAttr && !*ppNewTextAttr)
1983  *ppNewTextAttr = pNew;
1984  if ( nEnd != nStt && !pNew->GetEnd() )
1985  {
1986  OSL_FAIL("Attribute without end, but area marked");
1987  DestroyAttr( pNew ); // do not insert
1988  }
1989  else if ( InsertHint( pNew, nMode ) )
1990  {
1991  ++nCount;
1992  }
1993  }
1994  }
1995  }
1996  }
1997  }
1998  pItem = aIter.NextItem();
1999  } while(pItem);
2000 
2001  if ( aCharSet.Count() )
2002  {
2003  SwTextAttr* pTmpNew = MakeTextAttr( GetDoc(), aCharSet, nStt, nEnd );
2004  if ( InsertHint( pTmpNew, nMode ) )
2005  {
2006  ++nCount;
2007  }
2008  }
2009 
2011 
2012  return nCount != 0;
2013 }
2014 
2015 static void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
2016 {
2017  if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
2018  {
2019  const SfxItemSet* pCFSet = CharFormat::GetItemSet( rAttr );
2020  if ( !pCFSet )
2021  return;
2022  SfxWhichIter aIter( *pCFSet );
2023  sal_uInt16 nWhich = aIter.FirstWhich();
2024  while( nWhich )
2025  {
2026  if( ( nWhich < RES_CHRATR_END ||
2027  RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
2028  ( SfxItemState::SET == pCFSet->GetItemState( nWhich ) ) )
2029  rSet.Put( pCFSet->Get( nWhich ) );
2030  nWhich = aIter.NextWhich();
2031  }
2032  }
2033  else
2034  rSet.Put( rAttr );
2035 }
2036 
2037 static void lcl_MergeAttr_ExpandChrFormat( SfxItemSet& rSet, const SfxPoolItem& rAttr )
2038 {
2039  if( RES_TXTATR_CHARFMT == rAttr.Which() ||
2040  RES_TXTATR_INETFMT == rAttr.Which() ||
2041  RES_TXTATR_AUTOFMT == rAttr.Which() )
2042  {
2043  const SfxItemSet* pCFSet = CharFormat::GetItemSet( rAttr );
2044 
2045  if ( pCFSet )
2046  {
2047  SfxWhichIter aIter( *pCFSet );
2048  sal_uInt16 nWhich = aIter.FirstWhich();
2049  while( nWhich )
2050  {
2051  if( ( nWhich < RES_CHRATR_END ||
2052  ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
2053  ( SfxItemState::SET == pCFSet->GetItemState( nWhich ) ) )
2054  rSet.Put( pCFSet->Get( nWhich ) );
2055  nWhich = aIter.NextWhich();
2056  }
2057  }
2058  }
2059 
2060 /* If multiple attributes overlap, the last one wins!
2061  Probably this can only happen between a RES_TXTATR_INETFMT and one of the
2062  other hints, because BuildPortions ensures that CHARFMT/AUTOFMT don't
2063  overlap. But there may be multiple CHARFMT/AUTOFMT with exactly the same
2064  start/end, sorted by BuildPortions, in which case the same logic applies.
2065 
2066  1234567890123456789
2067  |------------| Font1
2068  |------| Font2
2069  ^ ^
2070  |--| query range: -> Font2
2071 */
2072  // merge into set
2073  rSet.Put( rAttr );
2074 }
2075 
2076 namespace {
2077 
2078 struct SwPoolItemEndPair
2079 {
2080 public:
2081  const SfxPoolItem* mpItem;
2082  sal_Int32 mnEndPos;
2083 
2084  SwPoolItemEndPair() : mpItem( nullptr ), mnEndPos( 0 ) {};
2085 };
2086 
2087 }
2088 
2090  SfxItemSet& rSet )
2091 {
2092  if ( !rTextNode.AreListLevelIndentsApplicable() )
2093  return;
2094 
2095  const SwNumRule* pRule = rTextNode.GetNumRule();
2096  if ( pRule && rTextNode.GetActualListLevel() >= 0 )
2097  {
2098  const SwNumFormat& rFormat = pRule->Get(static_cast<sal_uInt16>(rTextNode.GetActualListLevel()));
2100  {
2102  aLR.SetTextLeft( rFormat.GetIndentAt() );
2103  aLR.SetTextFirstLineOffset( static_cast<short>(rFormat.GetFirstLineIndent()) );
2104  rSet.Put( aLR );
2105  }
2106  }
2107 }
2108 
2109 // request the attributes of the TextNode at the range
2110 bool SwTextNode::GetParaAttr(SfxItemSet& rSet, sal_Int32 nStt, sal_Int32 nEnd,
2111  const bool bOnlyTextAttr, const bool bGetFromChrFormat,
2112  const bool bMergeIndentValuesOfNumRule,
2113  SwRootFrame const*const pLayout) const
2114 {
2115  assert(!rSet.Count()); // handled inconsistently, typically an error?
2116 
2117  if (pLayout && pLayout->HasMergedParas())
2118  {
2120  {
2121  return false; // ignore deleted node
2122  }
2123  }
2124 
2125  // get the node's automatic attributes
2126  SfxItemSet aFormatSet( *rSet.GetPool(), rSet.GetRanges() );
2127  if (!bOnlyTextAttr)
2128  {
2129  SwTextNode const& rParaPropsNode(
2130  sw::GetAttrMerged(aFormatSet, *this, pLayout));
2131  if (bMergeIndentValuesOfNumRule)
2132  {
2133  lcl_MergeListLevelIndentAsLRSpaceItem(rParaPropsNode, aFormatSet);
2134  }
2135  }
2136 
2137  if( HasHints() )
2138  {
2139  // First, check which text attributes are valid in the range.
2140  // cases:
2141  // Ambiguous, if
2142  // * the attribute is wholly contained in the range
2143  // * the attribute end is in the range
2144  // * the attribute start is in the range
2145  // Unambiguous (merge into set), if
2146  // * the attribute wholly contains the range
2147  // Ignored, if
2148  // * the attribute is wholly outside the range
2149 
2150  void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
2151  = bGetFromChrFormat ? &lcl_MergeAttr_ExpandChrFormat
2152  : &lcl_MergeAttr;
2153 
2154  const size_t nSize = m_pSwpHints->Count();
2155 
2156  if (nStt == nEnd) // no range:
2157  {
2158  for (size_t n = 0; n < nSize; ++n)
2159  {
2160  const SwTextAttr* pHt = m_pSwpHints->Get(n);
2161  const sal_Int32 nAttrStart = pHt->GetStart();
2162  if (nAttrStart > nEnd) // behind the range
2163  break;
2164 
2165  const sal_Int32* pAttrEnd = pHt->End();
2166  if ( ! pAttrEnd ) // no attributes without end
2167  continue;
2168 
2169  if( ( nAttrStart < nStt &&
2170  ( pHt->DontExpand() ? nStt < *pAttrEnd
2171  : nStt <= *pAttrEnd )) ||
2172  ( nStt == nAttrStart &&
2173  ( nAttrStart == *pAttrEnd || !nStt )))
2174  (*fnMergeAttr)( rSet, pHt->GetAttr() );
2175  }
2176  }
2177  else // a query range is defined
2178  {
2179  // #i75299#
2180  std::unique_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
2181 
2182  const size_t coArrSz = RES_TXTATR_WITHEND_END - RES_CHRATR_BEGIN;
2183 
2184  for (size_t n = 0; n < nSize; ++n)
2185  {
2186  const SwTextAttr* pHt = m_pSwpHints->Get(n);
2187  const sal_Int32 nAttrStart = pHt->GetStart();
2188  if (nAttrStart > nEnd) // outside, behind
2189  break;
2190 
2191  const sal_Int32* pAttrEnd = pHt->End();
2192  if ( ! pAttrEnd ) // no attributes without end
2193  continue;
2194 
2195  bool bChkInvalid = false;
2196  if (nAttrStart <= nStt) // before or exactly Start
2197  {
2198  if (*pAttrEnd <= nStt) // outside, before
2199  continue;
2200 
2201  if (nEnd <= *pAttrEnd) // behind or exactly End
2202  (*fnMergeAttr)( aFormatSet, pHt->GetAttr() );
2203  else
2204 // else if( pHt->GetAttr() != aFormatSet.Get( pHt->Which() ) )
2205  // ambiguous
2206  bChkInvalid = true;
2207  }
2208  else if (nAttrStart < nEnd // starts in the range
2209 )// && pHt->GetAttr() != aFormatSet.Get( pHt->Which() ) )
2210  bChkInvalid = true;
2211 
2212  if( bChkInvalid )
2213  {
2214  // ambiguous?
2215  std::unique_ptr< SfxItemIter > pItemIter;
2216  const SfxPoolItem* pItem = nullptr;
2217 
2218  if ( RES_TXTATR_AUTOFMT == pHt->Which() )
2219  {
2220  const SfxItemSet* pAutoSet = CharFormat::GetItemSet( pHt->GetAttr() );
2221  if ( pAutoSet )
2222  {
2223  pItemIter.reset( new SfxItemIter( *pAutoSet ) );
2224  pItem = pItemIter->GetCurItem();
2225  }
2226  }
2227  else
2228  pItem = &pHt->GetAttr();
2229 
2230  const sal_Int32 nHintEnd = *pAttrEnd;
2231 
2232  for (; pItem; pItem = pItemIter ? pItemIter->NextItem() : nullptr)
2233  {
2234  const sal_uInt16 nHintWhich = pItem->Which();
2235  OSL_ENSURE(!isUNKNOWNATR(nHintWhich),
2236  "SwTextNode::GetAttr(): unknown attribute?");
2237 
2238  if (!pAttrArr)
2239  {
2240  pAttrArr.reset(
2241  new std::vector< SwPoolItemEndPair >(coArrSz));
2242  }
2243 
2244  std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
2245  if (isCHRATR(nHintWhich) ||
2246  isTXTATR_WITHEND(nHintWhich))
2247  {
2248  pPrev += nHintWhich - RES_CHRATR_BEGIN;
2249  }
2250  else
2251  {
2252  pPrev = pAttrArr->end();
2253  }
2254 
2255  if( pPrev != pAttrArr->end() )
2256  {
2257  if( !pPrev->mpItem )
2258  {
2259  if ( bOnlyTextAttr || *pItem != aFormatSet.Get( nHintWhich ) )
2260  {
2261  if( nAttrStart > nStt )
2262  {
2263  rSet.InvalidateItem( nHintWhich );
2264  pPrev->mpItem = INVALID_POOL_ITEM;
2265  }
2266  else
2267  {
2268  pPrev->mpItem = pItem;
2269  pPrev->mnEndPos = nHintEnd;
2270  }
2271  }
2272  }
2273  else if( !IsInvalidItem(pPrev->mpItem) )
2274  {
2275  if( pPrev->mnEndPos == nAttrStart &&
2276  *pPrev->mpItem == *pItem )
2277  {
2278  pPrev->mpItem = pItem;
2279  pPrev->mnEndPos = nHintEnd;
2280  }
2281  else
2282  {
2283  rSet.InvalidateItem( nHintWhich );
2284  pPrev->mpItem = INVALID_POOL_ITEM;
2285  }
2286  }
2287  }
2288  } // end while
2289  }
2290  }
2291 
2292  if (pAttrArr)
2293  {
2294  for (size_t n = 0; n < coArrSz; ++n)
2295  {
2296  const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
2297  if( rItemPair.mpItem && !IsInvalidItem(rItemPair.mpItem) )
2298  {
2299  const sal_uInt16 nWh =
2300  static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
2301 
2302  if (nEnd <= rItemPair.mnEndPos) // behind or exactly end
2303  {
2304  if( *rItemPair.mpItem != aFormatSet.Get( nWh ) )
2305  (*fnMergeAttr)( rSet, *rItemPair.mpItem );
2306  }
2307  else
2308  // ambiguous
2309  rSet.InvalidateItem( nWh );
2310  }
2311  }
2312  }
2313  }
2314  if( aFormatSet.Count() )
2315  {
2316  // remove all from the format-set that are also set in the text-set
2317  aFormatSet.Differentiate( rSet );
2318  }
2319  }
2320 
2321  if (aFormatSet.Count())
2322  {
2323  // now "merge" everything
2324  rSet.Put( aFormatSet );
2325  }
2326 
2327  return rSet.Count() != 0;
2328 }
2329 
2330 namespace
2331 {
2332 
2333 typedef std::pair<sal_Int32, sal_Int32> AttrSpan_t;
2334 typedef std::multimap<AttrSpan_t, const SwTextAttr*> AttrSpanMap_t;
2335 
2336 struct IsAutoStyle
2337 {
2338  bool
2339  operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2340  const
2341  {
2342  return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
2343  }
2344 };
2345 
2349 struct RemovePresentAttrs
2350 {
2351  explicit RemovePresentAttrs(SfxItemSet& io_rAttrSet)
2352  : m_rAttrSet(io_rAttrSet)
2353  {
2354  }
2355 
2356  void
2357  operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2358  const
2359  {
2360  if (!i_rAttrSpan.second)
2361  {
2362  return;
2363  }
2364 
2365  const SwTextAttr* const pAutoStyle(i_rAttrSpan.second);
2366  SfxItemIter aIter(m_rAttrSet);
2367  for (const SfxPoolItem* pItem(aIter.GetCurItem()); pItem; pItem = aIter.NextItem())
2368  {
2369  const sal_uInt16 nWhich(pItem->Which());
2370  if (CharFormat::IsItemIncluded(nWhich, pAutoStyle))
2371  {
2372  m_rAttrSet.ClearItem(nWhich);
2373  }
2374  }
2375  }
2376 
2377 private:
2378  SfxItemSet& m_rAttrSet;
2379 };
2380 
2387 void
2388 lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_Int32 nLength,
2389  AttrSpanMap_t& o_rSpanMap)
2390 {
2391  sal_Int32 nLastEnd(0);
2392 
2393  for (size_t i = 0; i < i_rHints.Count(); ++i)
2394  {
2395  const SwTextAttr* pHint = i_rHints.Get(i);
2396  const sal_uInt16 nWhich(pHint->Which());
2397  if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
2398  {
2399  const AttrSpan_t aSpan(pHint->GetStart(), *pHint->End());
2400  o_rSpanMap.emplace(aSpan, pHint);
2401 
2402  // < not != because there may be multiple CHARFMT at same range
2403  if (nLastEnd < aSpan.first)
2404  {
2405  // insert dummy span covering the gap
2406  o_rSpanMap.emplace( AttrSpan_t(nLastEnd, aSpan.first), nullptr );
2407  }
2408 
2409  nLastEnd = aSpan.second;
2410  }
2411  }
2412 
2413  // no hints at the end (special case: no hints at all in i_rHints)
2414  if (nLastEnd != nLength && nLength != 0)
2415  {
2416  o_rSpanMap.emplace(AttrSpan_t(nLastEnd, nLength), nullptr);
2417  }
2418 }
2419 
2420 void
2421 lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
2422 {
2423  o_rClearIds.reserve(i_rAttrSet.Count());
2424  SfxItemIter aIter(i_rAttrSet);
2425  for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
2426  {
2427  o_rClearIds.push_back(pItem->Which());
2428  }
2429 }
2430 
2431 struct SfxItemSetClearer
2432 {
2433  SfxItemSet & m_rItemSet;
2434  explicit SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
2435  void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
2436 };
2437 
2438 }
2439 
2443 void
2445 {
2446  typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
2447  AttrSpanMap_t aAttrSpanMap;
2448 
2449  if (i_rAttrSet.Count() == 0)
2450  {
2451  return;
2452  }
2453 
2454  // 1. Identify all spans in hints' array
2455 
2456  lcl_CollectHintSpans(*m_pSwpHints, m_Text.getLength(), aAttrSpanMap);
2457 
2458  // 2. Go through all spans and insert new attrs
2459 
2460  AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
2461  const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
2462  while (aCurRange != aEnd)
2463  {
2464  typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
2465  AttrSpanMapRange_t;
2466  AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
2467 
2468  // 2a. Collect attributes to insert
2469 
2470  SfxItemSet aCurSet(i_rAttrSet);
2471  std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
2472 
2473  // 2b. Insert automatic style containing the collected attributes
2474 
2475  if (aCurSet.Count() != 0)
2476  {
2477  AttrSpanMap_iterator_t aAutoStyleIt(
2478  std::find_if(aRange.first, aRange.second, IsAutoStyle()));
2479  if (aAutoStyleIt != aRange.second)
2480  {
2481  // there already is an automatic style on that span:
2482  // create new one and remove the original one
2483  SwTextAttr* const pAutoStyle(const_cast<SwTextAttr*>(aAutoStyleIt->second));
2484  const std::shared_ptr<SfxItemSet> pOldStyle(
2485  static_cast<const SwFormatAutoFormat&>(
2486  pAutoStyle->GetAttr()).GetStyleHandle());
2487  aCurSet.Put(*pOldStyle);
2488 
2489  // remove the old hint
2490  m_pSwpHints->Delete(pAutoStyle);
2491  DestroyAttr(pAutoStyle);
2492  }
2493  m_pSwpHints->Insert(
2494  MakeTextAttr(GetDoc(), aCurSet,
2495  aCurRange->first.first, aCurRange->first.second));
2496  }
2497 
2498  aCurRange = aRange.second;
2499  }
2500 
2501  // hints were directly inserted, so need to fix the Ignore flags now
2502  m_pSwpHints->MergePortions(*this);
2503 
2504  // 3. Clear items from the node
2505  std::vector<sal_uInt16> aClearedIds;
2506  lcl_FillWhichIds(i_rAttrSet, aClearedIds);
2507  ClearItemsFromAttrSet(aClearedIds);
2508 }
2509 
2511 {
2512  SfxItemSet aThisSet( GetDoc().GetAttrPool(), aCharFormatSetRange );
2513  if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
2514  aThisSet.Put( *GetpSwAttrSet() );
2515 
2517 
2518  if( pNd == this )
2519  {
2520  impl_FormatToTextAttr(aThisSet);
2521  }
2522  else
2523  {
2524  // There are five possible combinations of items from this and
2525  // pNd (pNd is the 'main' node):
2526 
2527  // case pNd this action
2528 
2529  // 1 - - do nothing
2530  // 2 - a convert item to attr of this
2531  // 3 a - convert item to attr of pNd
2532  // 4 a a clear item in this
2533  // 5 a b convert item to attr of this
2534 
2535  SfxItemSet aNdSet( pNd->GetDoc().GetAttrPool(), aCharFormatSetRange );
2536  if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
2537  aNdSet.Put( *pNd->GetpSwAttrSet() );
2538 
2539  pNd->GetOrCreateSwpHints();
2540 
2541  std::vector<sal_uInt16> aProcessedIds;
2542 
2543  if( aThisSet.Count() )
2544  {
2545  SfxItemIter aIter( aThisSet );
2546  const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = nullptr;
2547  SfxItemSet aConvertSet( GetDoc().GetAttrPool(), aCharFormatSetRange );
2548  std::vector<sal_uInt16> aClearWhichIds;
2549 
2550  do
2551  {
2552  if( SfxItemState::SET == aNdSet.GetItemState( pItem->Which(), false, &pNdItem ) )
2553  {
2554  if (*pItem == *pNdItem) // 4
2555  {
2556  aClearWhichIds.push_back( pItem->Which() );
2557  }
2558  else // 5
2559  {
2560  aConvertSet.Put(*pItem);
2561  }
2562  aProcessedIds.push_back(pItem->Which());
2563  }
2564  else // 2
2565  {
2566  aConvertSet.Put(*pItem);
2567  }
2568 
2569  pItem = aIter.NextItem();
2570  } while (pItem);
2571 
2572  // 4/ clear items of this that are set with the same value on pNd
2573  ClearItemsFromAttrSet( aClearWhichIds );
2574 
2575  // 2, 5/ convert all other items to attrs
2576  impl_FormatToTextAttr(aConvertSet);
2577  }
2578 
2579  {
2580  std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
2581  SfxItemSetClearer(aNdSet));
2582 
2583  // 3/ convert items to attrs
2584  pNd->impl_FormatToTextAttr(aNdSet);
2585 
2586  if( aNdSet.Count() )
2587  {
2588  SwFormatChg aTmp1( pNd->GetFormatColl() );
2589  pNd->CallSwClientNotify(sw::LegacyModifyHint(&aTmp1, &aTmp1));
2590  }
2591  }
2592  }
2593 
2595 
2596  pNd->TryDeleteSwpHints();
2597 }
2598 
2600 {
2601  m_bDDEFields = m_bFootnote = false;
2602  const size_t nSize = Count();
2603  for( size_t nPos = 0; nPos < nSize; ++nPos )
2604  {
2605  const SwTextAttr* pAttr = Get( nPos );
2606  switch( pAttr->Which() )
2607  {
2608  case RES_TXTATR_FTN:
2609  m_bFootnote = true;
2610  if ( m_bDDEFields )
2611  return;
2612  break;
2613  case RES_TXTATR_FIELD:
2614  {
2615  const SwField* pField = pAttr->GetFormatField().GetField();
2616  if( SwFieldIds::Dde == pField->GetTyp()->Which() )
2617  {
2618  m_bDDEFields = true;
2619  if ( m_bFootnote )
2620  return;
2621  }
2622  }
2623  break;
2624  }
2625  }
2626 }
2627 
2629 {
2630  m_bCalcHiddenParaField = false;
2631  const bool bOldHiddenByParaField = m_bHiddenByParaField;
2632  bool bNewHiddenByParaField = false;
2633  int nNewResultWeight = 0;
2634  const size_t nSize = Count();
2635  const SwTextAttr* pTextHt;
2636 
2637  for (size_t nPos = 0; nPos < nSize; ++nPos)
2638  {
2639  pTextHt = Get(nPos);
2640  const sal_uInt16 nWhich = pTextHt->Which();
2641 
2642  if (RES_TXTATR_FIELD == nWhich)
2643  {
2644  // see also SwTextFrame::IsHiddenNow()
2645  const SwFormatField& rField = pTextHt->GetFormatField();
2646  int nCurWeight = m_rParent.GetDoc().FieldCanHideParaWeight(rField.GetField()->GetTyp()->Which());
2647  if (nCurWeight > nNewResultWeight)
2648  {
2649  nNewResultWeight = nCurWeight;
2650  bNewHiddenByParaField = m_rParent.GetDoc().FieldHidesPara(*rField.GetField());
2651  }
2652  else if (nCurWeight == nNewResultWeight && bNewHiddenByParaField)
2653  {
2654  // Currently, for both supported hiding types (HiddenPara, Database), "Don't hide"
2655  // takes precedence - i.e., if there's a "Don't hide" field of that weight, we only
2656  // care about fields of higher weight.
2657  bNewHiddenByParaField = m_rParent.GetDoc().FieldHidesPara(*rField.GetField());
2658  }
2659  }
2660  }
2661  SetHiddenByParaField(bNewHiddenByParaField);
2662  return bOldHiddenByParaField != bNewHiddenByParaField;
2663 }
2664 
2665 void SwpHints::NoteInHistory( SwTextAttr *pAttr, const bool bNew )
2666 {
2667  if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
2668 }
2669 
2671 {
2672  if ( !Count() )
2673  return false;
2674 
2675  // sort before merging
2676  Resort();
2677 
2678  bool bRet = false;
2679  typedef std::multimap< int, std::pair<SwTextAttr*, bool> > PortionMap;
2680  PortionMap aPortionMap;
2681  std::unordered_map<int, bool> RsidOnlyAutoFormatFlagMap;
2682  sal_Int32 nLastPorStart = COMPLETE_STRING;
2683  int nKey = 0;
2684 
2685  // get portions by start position:
2686  for ( size_t i = 0; i < Count(); ++i )
2687  {
2688  SwTextAttr *pHt = Get( i );
2689  if ( RES_TXTATR_CHARFMT != pHt->Which() &&
2690  RES_TXTATR_AUTOFMT != pHt->Which() )
2691  //&&
2692  //RES_TXTATR_INETFMT != pHt->Which() )
2693  continue;
2694 
2695  bool isRsidOnlyAutoFormat(false);
2696  // check for RSID-only AUTOFMT
2697  if (RES_TXTATR_AUTOFMT == pHt->Which())
2698  {
2699  std::shared_ptr<SfxItemSet> const pSet(
2700  pHt->GetAutoFormat().GetStyleHandle());
2701  if ((pSet->Count() == 1) && pSet->GetItem(RES_CHRATR_RSID, false))
2702  {
2703  // fdo#70201: eliminate no-extent RSID-only AUTOFMT
2704  // could be produced by ReplaceText or (maybe?) RstAttr
2705  if (pHt->GetStart() == *pHt->GetEnd())
2706  {
2707  DeleteAtPos(i); // kill it without History!
2708  SwTextAttr::Destroy(pHt, rNode.GetDoc().GetAttrPool());
2709  --i;
2710  continue;
2711  }
2712  // fdo#52028: this one has _only_ RSID => ignore it completely
2713  if (!pHt->IsFormatIgnoreStart() || !pHt->IsFormatIgnoreEnd())
2714  {
2715  NoteInHistory(pHt);
2716  pHt->SetFormatIgnoreStart(true);
2717  pHt->SetFormatIgnoreEnd (true);
2718  NoteInHistory(pHt, true);
2719  }
2720  isRsidOnlyAutoFormat = true;
2721  }
2722  }
2723 
2724  if (pHt->GetStart() == *pHt->GetEnd())
2725  {
2726  // no-length hints are a disease. ignore them here.
2727  // the SwAttrIter::SeekFwd will not call Rst/Chg for them.
2728  continue;
2729  }
2730 
2731  const sal_Int32 nPorStart = pHt->GetStart();
2732  if (nPorStart != nLastPorStart)
2733  ++nKey;
2734  nLastPorStart = nPorStart;
2735  aPortionMap.insert(std::make_pair(nKey,
2736  std::make_pair(pHt, isRsidOnlyAutoFormat)));
2737  RsidOnlyAutoFormatFlagMap[nKey] = isRsidOnlyAutoFormat;
2738  }
2739 
2740  // check if portion i can be merged with portion i+1:
2741  // note: need to include i=0 to set IgnoreStart and j=nKey+1 to reset
2742  // IgnoreEnd at first / last portion
2743  int i = 0;
2744  int j = i + 1;
2745  while ( i <= nKey )
2746  {
2747  std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
2748  std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
2749  PortionMap::iterator aIter1 = aRange1.first;
2750  PortionMap::iterator aIter2 = aRange2.first;
2751 
2752  enum { MATCH, DIFFER_ONLY_RSID, DIFFER } eMerge(MATCH);
2753  size_t const nAttributesInPor1 = std::distance(aRange1.first, aRange1.second);
2754  size_t const nAttributesInPor2 = std::distance(aRange2.first, aRange2.second);
2755  bool const isRsidOnlyAutoFormat1(RsidOnlyAutoFormatFlagMap[i]);
2756  bool const isRsidOnlyAutoFormat2(RsidOnlyAutoFormatFlagMap[j]);
2757 
2758  // if both have one they could be equal, but not if only one has it
2759  bool const bSkipRsidOnlyAutoFormat(nAttributesInPor1 != nAttributesInPor2);
2760 
2761  // this loop needs to handle the case where one has a CHARFMT and the
2762  // other CHARFMT + RSID-only AUTOFMT, so...
2763  // want to skip over RSID-only AUTOFMT here, hence the -1
2764  if ((nAttributesInPor1 - (isRsidOnlyAutoFormat1 ? 1 : 0)) ==
2765  (nAttributesInPor2 - (isRsidOnlyAutoFormat2 ? 1 : 0))
2766  && (nAttributesInPor1 != 0 || nAttributesInPor2 != 0))
2767  {
2768  // _if_ there is one element more either in aRange1 or aRange2
2769  // it _must_ be an RSID-only AUTOFMT, which can be ignored here...
2770  // But if both have RSID-only AUTOFMT they could be equal, no skip!
2771  while (aIter1 != aRange1.second || aIter2 != aRange2.second)
2772  {
2773  // first of all test if there's no gap (before skipping stuff!)
2774  if (aIter1 != aRange1.second && aIter2 != aRange2.second &&
2775  *aIter1->second.first->End() < aIter2->second.first->GetStart())
2776  {
2777  eMerge = DIFFER;
2778  break;
2779  }
2780  // skip it - cannot be equal if bSkipRsidOnlyAutoFormat is set
2781  if (bSkipRsidOnlyAutoFormat
2782  && aIter1 != aRange1.second && aIter1->second.second)
2783  {
2784  assert(DIFFER != eMerge);
2785  eMerge = DIFFER_ONLY_RSID;
2786  ++aIter1;
2787  continue;
2788  }
2789  if (bSkipRsidOnlyAutoFormat
2790  && aIter2 != aRange2.second && aIter2->second.second)
2791  {
2792  assert(DIFFER != eMerge);
2793  eMerge = DIFFER_ONLY_RSID;
2794  ++aIter2;
2795  continue;
2796  }
2797  assert(aIter1 != aRange1.second && aIter2 != aRange2.second);
2798  SwTextAttr const*const p1 = aIter1->second.first;
2799  SwTextAttr const*const p2 = aIter2->second.first;
2800  if (p1->Which() != p2->Which())
2801  {
2802  eMerge = DIFFER;
2803  break;
2804  }
2805  if (!(*p1 == *p2))
2806  {
2807  // fdo#52028: for auto styles, check if they differ only
2808  // in the RSID, which should have no effect on text layout
2809  if (RES_TXTATR_AUTOFMT == p1->Which())
2810  {
2811  const SfxItemSet& rSet1 = *p1->GetAutoFormat().GetStyleHandle();
2812  const SfxItemSet& rSet2 = *p2->GetAutoFormat().GetStyleHandle();
2813 
2814  // sadly SfxItemSet::operator== does not seem to work?
2815  SfxItemIter iter1(rSet1);
2816  SfxItemIter iter2(rSet2);
2817  for (SfxPoolItem const* pItem1 = iter1.GetCurItem(),
2818  * pItem2 = iter2.GetCurItem();
2819  pItem1 && pItem2;
2820  pItem1 = iter1.NextItem(),
2821  pItem2 = iter2.NextItem())
2822  {
2823  if (pItem1->Which() == RES_CHRATR_RSID)
2824  pItem1 = iter1.NextItem();
2825  if (pItem2->Which() == RES_CHRATR_RSID)
2826  pItem2 = iter2.NextItem();
2827  if (!pItem1 && !pItem2)
2828  break;
2829  if (!pItem1 || !pItem2)
2830  {
2831  eMerge = DIFFER;
2832  break;
2833  }
2834  if (pItem1 != pItem2) // all are poolable
2835  {
2836  assert(IsInvalidItem(pItem1) || IsInvalidItem(pItem2) || pItem1->Which() != pItem2->Which() || *pItem1 != *pItem2);
2837  eMerge = DIFFER;
2838  break;
2839  }
2840  if (iter1.IsAtEnd() && iter2.IsAtEnd())
2841  break;
2842  if (iter1.IsAtEnd() || iter2.IsAtEnd())
2843  {
2844  eMerge = DIFFER;
2845  break;
2846  }
2847  }
2848  if (DIFFER == eMerge)
2849  break; // outer loop too
2850  else
2851  eMerge = DIFFER_ONLY_RSID;
2852  }
2853  else
2854  {
2855  eMerge = DIFFER;
2856  break;
2857  }
2858  }
2859  ++aIter1;
2860  ++aIter2;
2861  }
2862  }
2863  else
2864  {
2865  eMerge = DIFFER;
2866  }
2867 
2868  if (MATCH == eMerge)
2869  {
2870  // important: delete second range so any IgnoreStart on the first
2871  // range is still valid
2872  // erase all elements with key i + 1
2873  sal_Int32 nNewPortionEnd = 0;
2874  for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
2875  {
2876  SwTextAttr *const p2 = aIter2->second.first;
2877  nNewPortionEnd = *p2->GetEnd();
2878 
2879  const size_t nCountBeforeDelete = Count();
2880  Delete( p2 );
2881 
2882  // robust: check if deletion actually took place before destroying attribute:
2883  if ( Count() < nCountBeforeDelete )
2884  rNode.DestroyAttr( p2 );
2885  }
2886  aPortionMap.erase( aRange2.first, aRange2.second );
2887  ++j;
2888 
2889  // change all attributes with key i
2890  aRange1 = aPortionMap.equal_range( i );
2891  for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
2892  {
2893  SwTextAttr *const p1 = aIter1->second.first;
2894  NoteInHistory( p1 );
2895  p1->SetEnd(nNewPortionEnd);
2896  NoteInHistory( p1, true );
2897  bRet = true;
2898  }
2899 
2900  if (bRet)
2901  {
2902  Resort();
2903  }
2904  }
2905  else
2906  {
2907  // when not merging the ignore flags need to be either set or reset
2908  // (reset too in case one of the autofmts was recently changed)
2909  bool const bSetIgnoreFlag(DIFFER_ONLY_RSID == eMerge);
2910  for (aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1)
2911  {
2912  if (!aIter1->second.second) // already set above, don't change
2913  {
2914  SwTextAttr *const pCurrent(aIter1->second.first);
2915  if (pCurrent->IsFormatIgnoreEnd() != bSetIgnoreFlag)
2916  {
2917  NoteInHistory(pCurrent);
2918  pCurrent->SetFormatIgnoreEnd(bSetIgnoreFlag);
2919  NoteInHistory(pCurrent, true);
2920  }
2921  }
2922  }
2923  for (aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2)
2924  {
2925  if (!aIter2->second.second) // already set above, don't change
2926  {
2927  SwTextAttr *const pCurrent(aIter2->second.first);
2928  if (pCurrent->IsFormatIgnoreStart() != bSetIgnoreFlag)
2929  {
2930  NoteInHistory(pCurrent);
2931  pCurrent->SetFormatIgnoreStart(bSetIgnoreFlag);
2932  NoteInHistory(pCurrent, true);
2933  }
2934  }
2935  }
2936  i = j; // ++i not enough: i + 1 may have been deleted (MATCH)!
2937  ++j;
2938  }
2939  }
2940 
2941  return bRet;
2942 }
2943 
2944 // check if there is already a character format and adjust the sort numbers
2945 static void lcl_CheckSortNumber( const SwpHints& rHints, SwTextCharFormat& rNewCharFormat )
2946 {
2947  const sal_Int32 nHtStart = rNewCharFormat.GetStart();
2948  const sal_Int32 nHtEnd = *rNewCharFormat.GetEnd();
2949  sal_uInt16 nSortNumber = 0;
2950 
2951  for ( size_t i = 0; i < rHints.Count(); ++i )
2952  {
2953  const SwTextAttr* pOtherHt = rHints.Get(i);
2954 
2955  const sal_Int32 nOtherStart = pOtherHt->GetStart();
2956 
2957  if ( nOtherStart > nHtStart )
2958  break;
2959 
2960  if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
2961  {
2962  const sal_Int32 nOtherEnd = *pOtherHt->End();
2963 
2964  if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
2965  {
2966  nSortNumber = static_txtattr_cast<const SwTextCharFormat*>(pOtherHt)->GetSortNumber() + 1;
2967  }
2968  }
2969  }
2970 
2971  if ( nSortNumber > 0 )
2972  rNewCharFormat.SetSortNumber( nSortNumber );
2973 }
2974 
2975 /*
2976  * Try to insert the new hint.
2977  * Depending on the type of the hint, this either always succeeds, or may fail.
2978  * Depending on the type of the hint, other hints may be deleted or
2979  * overwritten.
2980  * The return value indicates successful insertion.
2981  */
2983  SwTextAttr* const pHint,
2984  SwTextNode &rNode,
2985  const SetAttrMode nMode )
2986 {
2987  if ( MAX_HINTS <= Count() ) // we're sorry, this flight is overbooked...
2988  {
2989  OSL_FAIL("hints array full :-(");
2990  return false;
2991  }
2992 
2993  const sal_Int32 *pHtEnd = pHint->GetEnd();
2994  const sal_uInt16 nWhich = pHint->Which();
2995  std::vector<sal_uInt16> aWhichSublist;
2996 
2997  switch( nWhich )
2998  {
2999  case RES_TXTATR_CHARFMT:
3000  {
3001  // Check if character format contains hidden attribute:
3002  const SwCharFormat* pFormat = pHint->GetCharFormat().GetCharFormat();
3003  const SfxPoolItem* pItem;
3004  if ( SfxItemState::SET == pFormat->GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) )
3005  rNode.SetCalcHiddenCharFlags();
3006 
3007  static_txtattr_cast<SwTextCharFormat*>(pHint)->ChgTextNode( &rNode );
3008  break;
3009  }
3010  // #i75430# Recalc hidden flags if necessary
3011  case RES_TXTATR_AUTOFMT:
3012  {
3013  std::shared_ptr<SfxItemSet> const pSet( pHint->GetAutoFormat().GetStyleHandle() );
3014  if (pHint->GetStart() == *pHint->GetEnd())
3015  {
3016  if (pSet->Count() == 1 && pSet->GetItem(RES_CHRATR_RSID, false))
3017  { // empty range RSID-only hints could cause trouble, there's no
3018  rNode.DestroyAttr(pHint); // need for them so don't insert
3019  return false;
3020  }
3021  }
3022  // Check if auto style contains hidden attribute:
3023  const SfxPoolItem* pHiddenItem = CharFormat::GetItem( *pHint, RES_CHRATR_HIDDEN );
3024  if ( pHiddenItem )
3025  rNode.SetCalcHiddenCharFlags();
3026 
3027  // fdo#71556: populate aWhichFormatAttr member of SwMsgPoolItem
3028  const sal_uInt16 *pRanges = pSet->GetRanges();
3029  while( (*pRanges) != 0 )
3030  {
3031  const sal_uInt16 nBeg = *pRanges;
3032  ++pRanges;
3033  const sal_uInt16 nEnd = *pRanges;
3034  ++pRanges;
3035  for( sal_uInt16 nSubElem = nBeg; nSubElem <= nEnd; ++nSubElem )
3036  if( pSet->HasItem( nSubElem ) )
3037  aWhichSublist.push_back( nSubElem );
3038  }
3039  break;
3040  }
3041  case RES_TXTATR_INETFMT:
3042  static_txtattr_cast<SwTextINetFormat*>(pHint)->InitINetFormat(rNode);
3043  break;
3044 
3045  case RES_TXTATR_FIELD:
3046  case RES_TXTATR_ANNOTATION:
3047  case RES_TXTATR_INPUTFIELD:
3048  {
3049  SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
3050  bool bDelFirst = nullptr != pTextField->GetpTextNode();
3051  pTextField->ChgTextNode( &rNode );
3052  SwDoc& rDoc = rNode.GetDoc();
3053  const SwField* pField = pTextField->GetFormatField().GetField();
3054 
3055  if( !rDoc.getIDocumentFieldsAccess().IsNewFieldLst() )
3056  {
3057  // certain fields must update the SwDoc's calculation flags
3058  switch( pField->GetTyp()->Which() )
3059  {
3060  case SwFieldIds::Database:
3061  case SwFieldIds::SetExp:
3064  case SwFieldIds::DbNumSet:
3065  case SwFieldIds::DbNextSet:
3066  {
3067  if( bDelFirst )
3068  rDoc.getIDocumentFieldsAccess().InsDelFieldInFieldLst(false, *pTextField);
3069  if( rNode.GetNodes().IsDocNodes() )
3070  rDoc.getIDocumentFieldsAccess().InsDelFieldInFieldLst(true, *pTextField);
3071  }
3072  break;
3073  case SwFieldIds::Dde:
3074  if( rNode.GetNodes().IsDocNodes() )
3075  static_cast<SwDDEFieldType*>(pField->GetTyp())->IncRefCnt();
3076  break;
3077  default: break;
3078  }
3079  }
3080 
3081  // insert into real document's nodes-array?
3082  if( rNode.GetNodes().IsDocNodes() )
3083  {
3084  bool bInsFieldType = false;
3085  switch( pField->GetTyp()->Which() )
3086  {
3087  case SwFieldIds::SetExp:
3088  bInsFieldType = static_cast<SwSetExpFieldType*>(pField->GetTyp())->IsDeleted();
3089  if( nsSwGetSetExpType::GSE_SEQ & static_cast<SwSetExpFieldType*>(pField->GetTyp())->GetType() )
3090  {
3091  // register the field at its FieldType before setting
3092  // the sequence reference number!
3093  SwSetExpFieldType* pFieldType = static_cast<SwSetExpFieldType*>(
3094  rDoc.getIDocumentFieldsAccess().InsertFieldType( *pField->GetTyp() ) );
3095  if( pFieldType != pField->GetTyp() )
3096  {
3097  SwFormatField* pFormatField = const_cast<SwFormatField*>(&pTextField->GetFormatField());
3098  pFormatField->RegisterToFieldType( *pFieldType );
3099  pFormatField->GetField()->ChgTyp( pFieldType );
3100  }
3101  pFieldType->SetSeqRefNo( *const_cast<SwSetExpField*>(static_cast<const SwSetExpField*>(pField)) );
3102  }
3103  break;
3104  case SwFieldIds::User:
3105  bInsFieldType = static_cast<SwUserFieldType*>(pField->GetTyp())->IsDeleted();
3106  break;
3107 
3108  case SwFieldIds::Dde:
3110  static_cast<SwDDEFieldType*>(pField->GetTyp())->IncRefCnt();
3111  bInsFieldType = static_cast<SwDDEFieldType*>(pField->GetTyp())->IsDeleted();
3112  break;
3113 
3114  case SwFieldIds::Postit:
3115  if ( rDoc.GetDocShell() )
3116  {
3117  rDoc.GetDocShell()->Broadcast( SwFormatFieldHint(
3119  }
3120  break;
3121  default: break;
3122  }
3123  if( bInsFieldType )
3125  }
3126  }
3127  break;
3128  case RES_TXTATR_FTN :
3129  static_cast<SwTextFootnote*>(pHint)->ChgTextNode( &rNode );
3130  break;
3131  case RES_TXTATR_REFMARK:
3132  static_txtattr_cast<SwTextRefMark*>(pHint)->ChgTextNode( &rNode );
3133  if( rNode.GetNodes().IsDocNodes() )
3134  {
3135  // search for a reference with the same name
3136  SwTextAttr* pTmpHt;
3137  for( size_t n = 0, nEnd = Count(); n < nEnd; ++n )
3138  {
3139  const sal_Int32 *pTmpHtEnd;
3140  const sal_Int32 *pTmpHintEnd;
3141  if (RES_TXTATR_REFMARK == (pTmpHt = Get(n))->Which() &&
3142  pHint->GetAttr() == pTmpHt->GetAttr() &&
3143  nullptr != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
3144  nullptr != ( pTmpHintEnd = pHint->GetEnd() ) )
3145  {
3147  pTmpHt->GetStart(), *pTmpHtEnd,
3148  pHint->GetStart(), *pTmpHintEnd );
3149  bool bDelOld = true, bChgStart = false, bChgEnd = false;
3150  switch( eCmp )
3151  {
3153  case SwComparePosition::Behind: bDelOld = false; break;
3154 
3155  case SwComparePosition::Outside: bChgStart = bChgEnd = true; break;
3156 
3158  case SwComparePosition::OverlapBefore: bChgStart = true; break;
3160  case SwComparePosition::OverlapBehind: bChgEnd = true; break;
3161  default: break;
3162  }
3163 
3164  if( bChgStart )
3165  {
3166  pHint->SetStart( pTmpHt->GetStart() );
3167  }
3168  if( bChgEnd )
3169  pHint->SetEnd(*pTmpHtEnd);
3170 
3171  if( bDelOld )
3172  {
3173  NoteInHistory( pTmpHt );
3174  rNode.DestroyAttr( Cut( n-- ) );
3175  --nEnd;
3176  }
3177  }
3178  }
3179  }
3180  break;
3181  case RES_TXTATR_TOXMARK:
3182  static_txtattr_cast<SwTextTOXMark*>(pHint)->ChgTextNode( &rNode );
3183  break;
3184 
3185  case RES_TXTATR_CJK_RUBY:
3186  static_txtattr_cast<SwTextRuby*>(pHint)->InitRuby(rNode);
3187  break;
3188 
3189  case RES_TXTATR_META:
3190  case RES_TXTATR_METAFIELD:
3191  static_txtattr_cast<SwTextMeta *>(pHint)->ChgTextNode( &rNode );
3192  break;
3193 
3194  case RES_CHRATR_HIDDEN:
3195  rNode.SetCalcHiddenCharFlags();
3196  break;
3197  }
3198 
3199  if( SetAttrMode::DONTEXPAND & nMode )
3200  pHint->SetDontExpand( true );
3201 
3202  // special handling for SwTextAttrs without end:
3203  // 1) they cannot overlap
3204  // 2) if two fields are adjacent, they must not be merged into one
3205  // this is guaranteed by inserting a CH_TXTATR_* into the paragraph text!
3206  sal_Int32 nHtStart = pHint->GetStart();
3207  if( !pHtEnd )
3208  {
3209  Insert( pHint );
3210  NoteInHistory(pHint, true);
3211  CalcFlags();
3212 #ifdef DBG_UTIL
3213  if( !rNode.GetDoc().IsInReading() )
3214  CHECK;
3215 #endif
3216  // ... and notify listeners
3217  if(rNode.HasWriterListeners())
3218  {
3219  SwUpdateAttr aHint(
3220  nHtStart,
3221  nHtStart,
3222  nWhich);
3223 
3224  rNode.TriggerNodeUpdate(sw::LegacyModifyHint(&aHint, &aHint));
3225  }
3226 
3227  return true;
3228  }
3229 
3230  // from here on, pHint is known to have an end index!
3231 
3232  if( *pHtEnd < nHtStart )
3233  {
3234  assert(*pHtEnd >= nHtStart);
3235 
3236  // just swap the nonsense:
3237  pHint->SetStart(*pHtEnd);
3238  pHint->SetEnd(nHtStart);
3239  nHtStart = pHint->GetStart();
3240  }
3241 
3242  // I need this value later on for notification but the pointer may become invalid
3243  const sal_Int32 nHintEnd = *pHtEnd;
3244  const bool bNoHintAdjustMode = bool(SetAttrMode::NOHINTADJUST & nMode);
3245 
3246  // handle nesting attributes: inserting may fail due to overlap!
3247  if (pHint->IsNesting())
3248  {
3249  const bool bRet(
3250  TryInsertNesting(rNode, *static_txtattr_cast<SwTextAttrNesting*>(pHint)));
3251  if (!bRet) return false;
3252  }
3253  // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
3254  // These attributes may be inserted directly.
3255  // Also attributes without length may be inserted directly.
3256  // SETATTR_NOHINTADJUST is set e.g., during undo.
3257  // Portion building in not necessary during XML import.
3258  else if ( !bNoHintAdjustMode &&
3259  !pHint->IsOverlapAllowedAttr() &&
3260  !rNode.GetDoc().IsInXMLImport() &&
3261  ( RES_TXTATR_AUTOFMT == nWhich ||
3262  RES_TXTATR_CHARFMT == nWhich ) )
3263  {
3264  assert( nWhich != RES_TXTATR_AUTOFMT ||
3265  static_cast<const SwFormatAutoFormat&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
3266  &rNode.GetDoc().GetAttrPool());
3267 
3268  BuildPortions( rNode, *pHint, nMode );
3269 
3270  if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
3271  MergePortions( rNode );
3272  }
3273  else
3274  {
3275  // There may be more than one character style at the current position.
3276  // Take care of the sort number.
3277  // Special case ruby portion: During import, the ruby attribute is set
3278  // multiple times
3279  // Special case hyperlink: During import, the ruby attribute is set
3280  // multiple times
3281  // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
3282  // character attributes directly
3283  if ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode )
3284  {
3285  BuildPortions( rNode, *pHint, nMode );
3286  }
3287  else
3288  {
3289  // #i82989# Check sort numbers in NoHintAdjustMode
3290  if ( RES_TXTATR_CHARFMT == nWhich )
3291  lcl_CheckSortNumber(*this, *static_txtattr_cast<SwTextCharFormat*>(pHint));
3292 
3293  Insert( pHint );
3294  NoteInHistory( pHint, true );
3295  }
3296  }
3297 
3298  // ... and notify listeners
3299  if ( rNode.HasWriterListeners() )
3300  {
3301  const SwUpdateAttr aHint(nHtStart, nHintEnd, nWhich, aWhichSublist);
3302  rNode.TriggerNodeUpdate(sw::LegacyModifyHint(&aHint, &aHint));
3303  }
3304 
3305 #ifdef DBG_UTIL
3306  if( !bNoHintAdjustMode && !rNode.GetDoc().IsInReading() )
3307  CHECK;
3308 #endif
3309 
3310  return true;
3311 }
3312 
3313 void SwpHints::DeleteAtPos( const size_t nPos )
3314 {
3315  assert(!m_bStartMapNeedsSorting && "deleting at pos and the list needs sorting?");
3316 
3317  SwTextAttr *pHint = Get(nPos);
3318  assert( pHint->m_pHints == this );
3319  // ChainDelete( pHint );
3320  NoteInHistory( pHint );
3321 
3322  // optimization: nPos is the position in the Starts array
3323  SwTextAttr *pHt = m_HintsByStart[ nPos ];
3324  m_HintsByStart.erase( m_HintsByStart.begin() + nPos );
3325 
3327  ResortStartMap();
3329  ResortEndMap();
3331  ResortWhichMap();
3332 
3333  auto findIt = std::lower_bound(m_HintsByEnd.begin(), m_HintsByEnd.end(), pHt, CompareSwpHtEnd());
3334  assert(*findIt == pHt);
3335  m_HintsByEnd.erase(findIt);
3336 
3337  auto findIt2 = std::lower_bound(m_HintsByWhichAndStart.begin(), m_HintsByWhichAndStart.end(), pHt, CompareSwpHtWhichStart());
3338  assert(*findIt2 == pHt);
3339  m_HintsByWhichAndStart.erase(findIt2);
3340 
3341  pHt->m_pHints = nullptr;
3342 
3343  if( pHint->Which() == RES_TXTATR_FIELD )
3344  {
3345  SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
3346  const SwFieldType* pFieldTyp = pTextField->GetFormatField().GetField()->GetTyp();
3347  if( SwFieldIds::Dde == pFieldTyp->Which() )
3348  {
3349  const SwTextNode* pNd = pTextField->GetpTextNode();
3350  if( pNd && pNd->GetNodes().IsDocNodes() )
3351  const_cast<SwDDEFieldType*>(static_cast<const SwDDEFieldType*>(pFieldTyp))->DecRefCnt();
3352  pTextField->ChgTextNode(nullptr);
3353  }
3354  else if (m_bHiddenByParaField
3355  && m_rParent.GetDoc().FieldCanHideParaWeight(pFieldTyp->Which()))
3356  {
3357  m_bCalcHiddenParaField = true;
3358  }
3359  }
3360  else if ( pHint->Which() == RES_TXTATR_ANNOTATION )
3361  {
3362  SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
3363  const_cast<SwFormatField&>(pTextField->GetFormatField()).Broadcast(
3365  }
3366 
3367  CalcFlags();
3368  CHECK_NOTMERGED; // called from BuildPortions
3369 }
3370 
3373 void SwpHints::Delete( SwTextAttr const * pTextHt )
3374 {
3375  const size_t nPos = GetIndexOf( pTextHt );
3376  assert(SAL_MAX_SIZE != nPos);
3377  if( SAL_MAX_SIZE != nPos )
3378  DeleteAtPos( nPos );
3379 }
3380 
3381 void SwTextNode::ClearSwpHintsArr( bool bDelFields )
3382 {
3383  if ( !HasHints() )
3384  return;
3385 
3386  size_t nPos = 0;
3387  while ( nPos < m_pSwpHints->Count() )
3388  {
3389  SwTextAttr* pDel = m_pSwpHints->Get( nPos );
3390  bool bDel = false;
3391 
3392  switch( pDel->Which() )
3393  {
3394  case RES_TXTATR_FLYCNT:
3395  case RES_TXTATR_FTN:
3396  break;
3397 
3398  case RES_TXTATR_FIELD:
3399  case RES_TXTATR_ANNOTATION:
3400  case RES_TXTATR_INPUTFIELD:
3401  if( bDelFields )
3402  bDel = true;
3403  break;
3404  default:
3405  bDel = true; break;
3406  }
3407 
3408  if( bDel )
3409  {
3410  m_pSwpHints->DeleteAtPos( nPos );
3411  DestroyAttr( pDel );
3412  }
3413  else
3414  ++nPos;
3415  }
3416 }
3417 
3418 LanguageType SwTextNode::GetLang( const sal_Int32 nBegin, const sal_Int32 nLen,
3419  sal_uInt16 nScript ) const
3420 {
3422 
3423  if ( ! nScript )
3424  {
3425  nScript = g_pBreakIt->GetRealScriptOfText( m_Text, nBegin );
3426  }
3427 
3428  // #i91465# Consider nScript if pSwpHints == 0
3429  const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
3430 
3431  if ( HasHints() )
3432  {
3433  const sal_Int32 nEnd = nBegin + nLen;
3434  const size_t nSize = m_pSwpHints->Count();
3435  for ( size_t i = 0; i < nSize; ++i )
3436  {
3437  const SwTextAttr *pHt = m_pSwpHints->Get(i);
3438  const sal_Int32 nAttrStart = pHt->GetStart();
3439  if( nEnd < nAttrStart )
3440  break;
3441 
3442  const sal_uInt16 nWhich = pHt->Which();
3443 
3444  if( nWhichId == nWhich ||
3445  ( ( pHt->IsCharFormatAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFormat::IsItemIncluded( nWhichId, pHt ) ) )
3446  {
3447  const sal_Int32 *pEndIdx = pHt->End();
3448  // do the attribute and the range overlap?
3449  if( !pEndIdx )
3450  continue;
3451  if( nLen )
3452  {
3453  if( nAttrStart >= nEnd || nBegin >= *pEndIdx )
3454  continue;
3455  }
3456  else if( nBegin != nAttrStart || ( nAttrStart != *pEndIdx && nBegin ))
3457  {
3458  if( nAttrStart >= nBegin )
3459  continue;
3460  if( pHt->DontExpand() ? nBegin >= *pEndIdx : nBegin > *pEndIdx)
3461  continue;
3462  }
3463  const SfxPoolItem* pItem = CharFormat::GetItem( *pHt, nWhichId );
3464  const LanguageType nLng = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
3465 
3466  // does the attribute completely cover the range?
3467  if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
3468  nRet = nLng;
3469  else if( LANGUAGE_DONTKNOW == nRet )
3470  nRet = nLng; // partial overlap, the first one wins
3471  }
3472  }
3473  }
3474  if( LANGUAGE_DONTKNOW == nRet )
3475  {
3476  nRet = static_cast<const SvxLanguageItem&>(GetSwAttrSet().Get( nWhichId )).GetLanguage();
3477  if( LANGUAGE_DONTKNOW == nRet )
3478  nRet = GetAppLanguage();
3479  }
3480  return nRet;
3481 }
3482 
3484 {
3486  switch ( rAttr.Which() )
3487  {
3488  case RES_TXTATR_REFMARK:
3489  case RES_TXTATR_TOXMARK:
3490  case RES_TXTATR_ANNOTATION:
3491  cRet = CH_TXTATR_INWORD;
3492  break;
3493 
3494  case RES_TXTATR_FIELD:
3495  case RES_TXTATR_FLYCNT:
3496  case RES_TXTATR_FTN:
3497  case RES_TXTATR_META:
3498  case RES_TXTATR_METAFIELD:
3499  {
3500  cRet = CH_TXTATR_BREAKWORD;
3501  }
3502  break;
3503 
3504  default:
3505  assert(!"GetCharOfTextAttr: unknown attr");
3506  break;
3507  }
3508  return cRet;
3509 }
3510 
3511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual SwCharFormat * GetCharFormatFromPool(sal_uInt16 nId)=0
void SetAnchor(const SwTextNode *pNode)
SetAnchor() is called by SwTextNode::InsertHint() and sets the anchor position in the SwFlyFrameForma...
Definition: atrflyin.cxx:135
Instances of SwFields and those derived from it occur 0 to n times.
Definition: fldbas.hxx:240
bool isUNKNOWNATR(const sal_uInt16 nWhich)
Definition: hintids.hxx:509
void BuildPortions(SwTextNode &rNode, SwTextAttr &rNewHint, const SetAttrMode nMode)
Definition: thints.cxx:622
static SwTextMeta * CreateTextMeta(::sw::MetaFieldManager &i_rTargetDocManager, SwTextNode *const i_pTargetTextNode, SwFormatMeta &i_rAttr, sal_Int32 const i_nStart, sal_Int32 const i_nEnd, bool const i_bIsCopy)
Definition: txtatr2.cxx:267
void DeleteAtPos(size_t nPos)
Definition: thints.cxx:3313
virtual std::shared_ptr< SfxItemSet > getAutomaticStyle(const SfxItemSet &rSet, SwAutoStyleFamily eFamily, const OUString *pParentName=nullptr)=0
tools::Long GetFirstLineIndent() const
constexpr TypedWhichId< SvxCrossedOutItem > RES_CHRATR_CROSSEDOUT(5)
void CalcBreaks(std::vector< std::pair< sal_uLong, sal_Int32 >> &rBreaks, SwPaM const &rPam, bool const isOnlyFieldmarks)
#define CHECK_NOTMERGED
Definition: thints.cxx:82
std::vector< SwTextAttr * > m_HintsByEnd
Definition: ndhints.hxx:77
SW_DLLPUBLIC void Resort() const
Definition: ndhints.cxx:412
const_iterator lower_bound(const Value &x) const
sal_uLong GetIndex() const
Definition: node.hxx:290
bool IsFormatIgnoreEnd() const
Definition: txatbase.hxx:103
SwNode & GetEndOfAutotext() const
Section for all Flys/Header/Footers.
Definition: ndarr.hxx:156
void Add(SwClient *pDepend)
Definition: calbck.cxx:186
void SetDontExpand(bool bDontExpand)
Definition: txatbase.hxx:171
The shared part of a user field.
Definition: usrfld.hxx:34
void DelSoftHyph(const sal_Int32 nStart, const sal_Int32 nEnd)
Definition: thints.cxx:1795
SwTextNode const & GetAttrMerged(SfxItemSet &rFormatSet, SwTextNode const &rNode, SwRootFrame const *pLayout)
Definition: txtfrm.cxx:367
static bool isOverlap(const sal_Int32 nStart1, const sal_Int32 nEnd1, const sal_Int32 nStart2, const sal_Int32 nEnd2)
Definition: thints.cxx:135
bool TryInsertNesting(SwTextNode &rNode, SwTextAttrNesting &rNewHint)
The following hints correspond to well-formed XML elements in ODF: RES_TXTATR_INETFMT, RES_TXTATR_CJK_RUBY, RES_TXTATR_META, RES_TXTATR_METAFIELD.
Definition: thints.cxx:366
const SwField * GetField() const
Definition: fmtfld.hxx:110
constexpr TypedWhichId< SvxEscapementItem > RES_CHRATR_ESCAPEMENT(6)
size_t GetIndexOf(const SwTextAttr *pHt) const
Definition: ndhints.cxx:464
bool IsNesting() const
Definition: txatbase.hxx:100
bool m_bFootnote
footnotes
Definition: ndhints.hxx:89
sal_uLong StartOfSectionIndex() const
Definition: node.hxx:676
The inserted item is a copy – intended for use in ndtxt.cxx.
bool isCHRATR(const sal_uInt16 nWhich)
Definition: hintids.hxx:469
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_METAFIELD(49)
SwComparePosition ComparePosition(const T &rStt1, const T &rEnd1, const T &rStt2, const T &rEnd2)
Definition: pam.hxx:77
SwDocShell * GetDocShell()
Definition: doc.hxx:1352
virtual bool SetAttr(const SfxPoolItem &) override
overriding to handle change of certain paragraph attributes
Definition: ndtxt.cxx:4866
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:219
bool isTXTATR_WITHEND(const sal_uInt16 nWhich)
Definition: hintids.hxx:473
bool isTXTATR(const sal_uInt16 nWhich)
Definition: hintids.hxx:481
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_META(48)
void TriggerNodeUpdate(const sw::LegacyModifyHint &)
for hanging TextFormatCollections somewhere else (Outline-Numbering!)
Definition: ndtxt.cxx:5235
virtual SfxPoolItem * Clone(SfxItemPool *pPool=nullptr) const =0
const SwNumFormat * GetNumFormat(sal_uInt16 i) const
Definition: number.cxx:89
SwNodeIndex nNode
Definition: pam.hxx:37
const SfxPoolItem * GetItem(const SwTextAttr &rAttr, sal_uInt16 nWhich)
Extracts pool item of type nWhich from rAttr.
Definition: atrstck.cxx:156
virtual const sal_Int32 * GetEnd() const
end position
Definition: txatbase.cxx:48
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:274
sal_uIntPtr sal_uLong
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_LANGUAGE(10)
static NestList_t::iterator lcl_DoSplitImpl(NestList_t &rSplits, SwTextNode &rNode, NestList_t::iterator const iter, sal_Int32 const nSplitPos, bool const bSplitAtStart, bool const bOtherDummy)
Definition: thints.cxx:257
Pos1 is as large as Pos2.
void SetStart(sal_Int32 n)
start position
Definition: txatbase.hxx:81
Base class of all fields.
Definition: fldbas.hxx:289
LanguageType GetLanguage(SfxItemSet const &aSet, sal_uInt16 nLangWhichId)
Definition: langhelper.cxx:395
void SetStyleHandle(const std::shared_ptr< SfxItemSet > &pHandle)
Definition: fmtautofmt.hxx:48
SwpHints * m_pHints
Definition: txatbase.hxx:61
bool DontExpandFormat(const SwIndex &rIdx, bool bFlag=true, bool bFormatToTextAttributes=true)
When appropriate set DontExpand-flag at INet or character styles respectively.
Definition: ndtxt.cxx:1572
Pos1 completely contained in Pos2.
sal_Int64 n
OUString GetListId() const
Definition: ndtxt.cxx:4352
Definition: doc.hxx:186
sal_uInt16 ClearItemsFromAttrSet(const std::vector< sal_uInt16 > &rWhichIds)
There some functions that like to remove items from the internal SwAttrSet (handle): ...
Definition: node.cxx:1786
void InvalidateItem(sal_uInt16 nWhich)
void SetFormatIgnoreStart(bool bFlag)
Definition: txatbase.hxx:104
constexpr TypedWhichId< SwFormatFlyCnt > RES_TXTATR_FLYCNT(57)
static bool lcl_IsIgnoredCharFormatForBullets(const sal_uInt16 nWhich)
Definition: thints.cxx:1822
sal_uInt16 FirstWhich()
constexpr TypedWhichId< SvxUnderlineItem > RES_CHRATR_UNDERLINE(14)
bool HasDummyChar() const
Definition: txatbase.hxx:101
bool IsAtEnd() const
void TryDeleteSwpHints()
Definition: ndtxt.hxx:832
SwTextNode * GetpTextNode() const
Definition: txtfld.hxx:49
SW_DLLPUBLIC void ResortWhichMap() const
Definition: ndhints.cxx:439
const std::shared_ptr< SfxItemSet > & GetStyleHandle() const
Definition: fmtautofmt.hxx:49
SwTextAttr * GetSortedByEnd(size_t nPos) const
Definition: ndhints.hxx:158
bool AreListLevelIndentsApplicable() const
Determines, if the list level indent attributes can be applied to the paragraph.
Definition: ndtxt.cxx:4386
std::vector< SwTextAttrNesting * > NestList_t
Definition: thints.cxx:254
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
const SwTOXType * GetTOXType() const
Definition: tox.hxx:580
void SetFormatIgnoreEnd(bool bFlag)
Definition: txatbase.hxx:105
sal_uInt16 Which() const
Definition: txatbase.hxx:110
virtual const sal_Int32 * GetEnd() const override
end position
Definition: txatbase.cxx:77
static bool isNestedAny(const sal_Int32 nStart1, const sal_Int32 nEnd1, const sal_Int32 nStart2, const sal_Int32 nEnd2)
#i106930#: now asymmetric: empty hint1 is not nested, but empty hint2 is
Definition: thints.cxx:145
void SetSeqRefNo(SwSetExpField &rField)
Definition: expfld.cxx:574
bool HasWriterListeners() const
Definition: calbck.hxx:198
constexpr TypedWhichId< SwFormatField > RES_TXTATR_ANNOTATION(59)
The root element of a Writer document layout.
Definition: rootfrm.hxx:82
constexpr TypedWhichId< SvxPostureItem > RES_CHRATR_CJK_POSTURE(25)
For old documents the Field-Which IDs must be preserved !!!
int GetActualListLevel() const
Returns the actual list level of this text node, when it is a list item.
Definition: ndtxt.cxx:4076
sal_uInt16 GetRealScriptOfText(const OUString &rText, sal_Int32 nPos) const
Definition: breakit.cxx:83
bool IsInHeaderFooter(const SwNodeIndex &rIdx) const
Definition: doclay.cxx:1551
#define CHECK
Definition: thints.cxx:81
sal_uInt16 NextWhich()
constexpr sal_uInt16 RES_TXTATR_BEGIN(RES_CHRATR_END)
#define CHAR_SOFTHYPHEN
Definition: swtypes.hxx:166
bool TryInsertHint(SwTextAttr *const pHint, SwTextNode &rNode, const SetAttrMode nMode=SetAttrMode::DEFAULT)
try to insert the hint
Definition: thints.cxx:2982
constexpr TypedWhichId< SvxCaseMapItem > RES_CHRATR_CASEMAP(RES_CHRATR_BEGIN)
Pos1 end touches at Pos2 start.
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:357
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:169
static bool TextAttrContains(const sal_Int32 nPos, const SwTextAttrEnd *const pAttr)
Definition: thints.cxx:113
sal_uInt16 sal_Unicode
const SfxPoolItem * NextItem()
void SetTextLeft(const tools::Long nL, const sal_uInt16 nProp=100)
const SwCharFormat * GetDfltCharFormat() const
Definition: doc.hxx:752
#define CH_TXTATR_INWORD
Definition: hintids.hxx:170
SwTableNode * GetTableNode()
Definition: node.hxx:602
void NoteInHistory(SwTextAttr *pAttr, const bool bNew=false)
records a new attribute in m_pHistory.
Definition: thints.cxx:2665
static void lcl_MergeAttr_ExpandChrFormat(SfxItemSet &rSet, const SfxPoolItem &rAttr)
Definition: thints.cxx:2037
SwIndex nContent
Definition: pam.hxx:38
SwDoc & GetDoc() const
Definition: tox.hxx:185
SwpHints(const SwTextNode &rParent)
Definition: thints.cxx:89
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
void SetSortNumber(sal_uInt16 nSortNumber)
Definition: txtatr.hxx:48
virtual void InsDelFieldInFieldLst(bool bIns, const SwTextField &rField)=0
void DestroyAttr(SwTextAttr *pAttr)
Definition: thints.cxx:1162
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:426
#define CH_TXT_ATR_INPUTFIELDSTART
Definition: hintids.hxx:173
for Undo, translated to SwInsertFlags::NOHINTEXPAND
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:33
int nCount
const SwTextNode & m_rParent
Definition: ndhints.hxx:70
virtual void DelLayoutFormat(SwFrameFormat *pFormat)=0
static void TextAttrDelete(SwDoc &rDoc, SwTextAttr *const pAttr)
Definition: thints.cxx:103
sal_Int32 GetStart() const
Definition: txatbase.hxx:82
bool IsOverlapAllowedAttr() const
Definition: txatbase.hxx:96
void SetCalcHiddenParaField()
set CalcVisible flags
Definition: ndtxt.hxx:713
Pos2 completely contained in Pos1.
SwTextAttr * InsertItem(SfxPoolItem &rAttr, const sal_Int32 nStart, const sal_Int32 nEnd, const SetAttrMode nMode=SetAttrMode::DEFAULT)
create new text attribute from rAttr and insert it
Definition: thints.cxx:1270
constexpr TypedWhichId< SwFormatRuby > RES_TXTATR_CJK_RUBY(53)
constexpr TypedWhichId< SwFormatCharFormat > RES_TXTATR_CHARFMT(52)
const SwFormatField & GetFormatField() const
Definition: txatbase.hxx:191
SwRegHistory * m_pHistory
for Undo
Definition: ndhints.hxx:80
constexpr TypedWhichId< SwFormatAutoFormat > RES_TXTATR_AUTOFMT(50)
Pos1 before Pos2.
void ChgTextNode(SwTextNode *pNew)
Definition: txtinet.hxx:48
size_type size() const
constexpr TypedWhichId< SwFormatFootnote > RES_TXTATR_FTN(58)
void SetCalcHiddenCharFlags() const
Definition: ndtxt.hxx:729
CopyOrNewType
Definition: ndhints.hxx:33
constexpr TypedWhichId< SwFormatINetFormat > RES_TXTATR_INETFMT(51)
constexpr TypedWhichId< SvxWeightItem > RES_CHRATR_WEIGHT(15)
::cppu::OWeakObject & m_rParent
sal_Unicode GetCharOfTextAttr(const SwTextAttr &rAttr)
Definition: thints.cxx:3483
const_iterator upper_bound(const Value &x) const
virtual SwFieldType * ChgTyp(SwFieldType *)
Set new type (used for copying among documents).
Definition: fldbas.cxx:381
SwCharFormat * GetCharFormat() const
Definition: numrule.hxx:74
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:451
OUString GetFieldContent() const
Definition: atrfld.cxx:646
constexpr TypedWhichId< SwFormatField > RES_TXTATR_FIELD(RES_TXTATR_NOEND_BEGIN)
bool IsCharFormatAttr() const
Definition: txatbase.hxx:95
sal_uInt16 ClearItem(sal_uInt16 nWhich=0)
void RstTextAttr(const SwIndex &rIdx, const sal_Int32 nLen, const sal_uInt16 nWhich=0, const SfxItemSet *pSet=nullptr, const bool bInclRefToxMark=false, const bool bExactRange=false)
delete all attributes.
Definition: txtedt.cxx:355
Style of a layout element.
Definition: frmfmt.hxx:58
size_t Count() const
Definition: ndhints.hxx:142
SwTextAttr * Get(size_t nPos) const
Definition: ndhints.hxx:144
static SwTextAttrNesting * MakeTextAttrNesting(SwTextNode &rNode, SwTextAttrNesting &rNesting, const sal_Int32 nStart, const sal_Int32 nEnd)
Create a new nesting text hint.
Definition: thints.cxx:230
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
bool MergePortions(SwTextNode &rNode)
Definition: thints.cxx:2670
bool m_bHiddenByParaField
Definition: ndhints.hxx:88
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
int i
SwDoc & GetDoc()
Definition: node.hxx:211
Pos1 start touches at Pos2 end.
bool m_bCalcHiddenParaField
Definition: ndhints.hxx:85
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
SwTextAttr * MakeTextAttr(SwDoc &rDoc, SfxPoolItem &rAttr, sal_Int32 const nStt, sal_Int32 const nEnd, CopyOrNewType const bIsCopy, SwTextNode *const pTextNode)
if COPY then pTextNode must be given!
Definition: thints.cxx:1015
constexpr sal_uInt16 RES_TXTATR_WITHEND_END(56)
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
bool GetParaAttr(SfxItemSet &rSet, sal_Int32 nStt, sal_Int32 nEnd, const bool bOnlyTextAttr=false, const bool bGetFromChrFormat=true, const bool bMergeIndentValuesOfNumRule=false, SwRootFrame const *pLayout=nullptr) const
Query the attributes of textnode over the range.
Definition: thints.cxx:2110
void Delete(SwTextAttr const *pTextHt)
Delete the given Hint. The Hint must actually be in the array!
Definition: thints.cxx:3373
Count
SetAttrMode
Definition: swtypes.hxx:135
bool HasContent() const
Definition: txatbase.hxx:106
SW_DLLPUBLIC void ResortEndMap() const
Definition: ndhints.cxx:432
static Split_t splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther)
Calculate splitting policy for overlapping hints, based on what kind of hint is inserted, and what kind of existing hint overlaps.
Definition: thints.cxx:189
const SwTextInputField * GetOverlappingInputField(const SwTextAttr &rTextAttr) const
Definition: ndtxt.cxx:1710
FlyAnchors.
Definition: fmtanchr.hxx:34
sal_uInt16 Count() const
void Insert(SwTextAttr *pHt)
Definition: ndhints.cxx:145
void DelFrames(SwRootFrame const *pLayout)
Method deletes all views of document for the node.
Definition: node.cxx:1406
void RegisterToTOXType(SwTOXType &rMark)
Definition: tox.cxx:137
void SetTextFirstLineOffset(const short nF, const sal_uInt16 nProp=100)
bool IsEnumeration() const
Definition: number.cxx:229
Force hint expand (only matters for hints with CH_TXTATR).
Internet normal.
Definition: poolfmt.hxx:120
Marks a character position inside a document model node.
Definition: index.hxx:33
const SfxItemSet * GetItemSet(const SfxPoolItem &rAttr)
Returns the item set associated with a character/inet/auto style.
Definition: atrstck.cxx:132
float u
SW_DLLPUBLIC void ResortStartMap() const
Definition: ndhints.cxx:425
virtual void InsDeletedFieldType(SwFieldType &)=0
sal_uInt16 GetWhichOfScript(sal_uInt16 nWhich, sal_uInt16 nScript)
Definition: hints.cxx:190
SAL_DLLPRIVATE void impl_FormatToTextAttr(const SfxItemSet &i_rAttrSet)
Does the hard work of SwTextNode::FormatToTextAttr: the real conversion of items to automatic styles...
Definition: thints.cxx:2444
SwNumRule * GetNumRule(bool bInParent=true) const
Returns numbering rule of this text node.
Definition: ndtxt.cxx:2775
const OUString & GetTypeName() const
Definition: tox.hxx:698
#define LANGUAGE_DONTKNOW
sal_uInt16 const aCharAutoFormatSetRange[]
Definition: init.cxx:251
bool IsItemize() const
Definition: number.cxx:237
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
Definition: format.cxx:401
Marks a node in the document model.
Definition: ndindex.hxx:31
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:696
T static_txtattr_cast(S *s)
Definition: txatbase.hxx:237
bool HasSwAttrSet() const
Definition: node.hxx:452
std::vector< SwTextAttr * > m_HintsByStart
Definition: ndhints.hxx:76
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:140
int FieldCanHideParaWeight(SwFieldIds eFieldId) const
Definition: doc.cxx:1337
SwStartNode * GetStartNode()
Definition: node.hxx:594
SvxNumPositionAndSpaceMode GetPositionAndSpaceMode() const
bool m_bEndMapNeedsSorting
Definition: ndhints.hxx:93
attention: NOHINTADJUST prevents MergePortions! when using this need to pay attention to ignore start...
SfxItemPool * GetPool() const
bool IsInReading() const
Definition: doc.hxx:955
void RegisterToFieldType(SwFieldType &)
Definition: atrfld.cxx:170
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:405
void ChgTextNode(SwTextNode *pNew)
Definition: txtfld.hxx:58
SwFieldType * GetTyp() const
Definition: fldbas.hxx:392
constexpr TypedWhichId< SvxCharHiddenItem > RES_CHRATR_HIDDEN(37)
void DeleteAttribute(SwTextAttr *const pTextAttr)
delete the attribute pTextAttr
Definition: thints.cxx:1681
const_iterator begin() const
constexpr TypedWhichId< SvxRsidItem > RES_CHRATR_RSID(39)
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:463
virtual void SetEnd(sal_Int32)
Definition: txatbase.cxx:53
bool m_bStartMapNeedsSorting
Definition: ndhints.hxx:92
sal_uInt16 Which() const
for Querying of Writer-functions.
Definition: format.hxx:97
constexpr TypedWhichId< SvxColorItem > RES_CHRATR_COLOR(3)
SwRegHistory * GetHistory() const
Definition: ndhints.hxx:198
void UpdateFootnote(const SwNodeIndex &rStt)
Definition: ftnidx.cxx:60
const SwNumFormat & Get(sal_uInt16 i) const
Definition: number.cxx:79
void EraseText(const SwIndex &rIdx, const sal_Int32 nCount=SAL_MAX_INT32, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
delete text content ATTENTION: must not be called with a range that overlaps the start of an attribut...
Definition: ndtxt.cxx:2630
OUString InsertText(const OUString &rStr, const SwIndex &rIdx, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
insert text content
Definition: ndtxt.cxx:2245
void ChangeNodeIndex(sal_uLong nNew)
Definition: rolbck.hxx:436
void ClearSwpHintsArr(bool bDelFields)
Definition: thints.cxx:3381
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
constexpr TypedWhichId< SvxBrushItem > RES_CHRATR_BACKGROUND(21)
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:80
void DeleteAttributes(const sal_uInt16 nWhich, const sal_Int32 nStart, const sal_Int32 nEnd=0)
delete all attributes of type nWhich at nStart (opt. end nEnd)
Definition: thints.cxx:1719
void AddHint(SwTextAttr *pHt, const bool bNew)
Definition: rolbck.cxx:1431
#define CH_TXT_ATR_INPUTFIELDEND
Definition: hintids.hxx:174
void Set(sal_uInt16 i, const SwNumFormat *)
Definition: number.cxx:591
void SetHiddenByParaField(const bool bNew) const
Definition: ndhints.hxx:111
const SwGetSetExpType GSE_SEQ
Sequence.
Definition: fldbas.hxx:204
SwCharFormat * GetCharFormat() const
Definition: fchrfmt.hxx:70
void SetCharFormat(SwCharFormat *)
Definition: number.cxx:273
constexpr sal_uInt16 RES_TXTATR_END(RES_TXTATR_NOEND_END)
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:67
constexpr sal_uInt16 RES_CHRATR_BEGIN(HINT_BEGIN)
SAL_DLLPRIVATE void InitINetFormat(SwTextNode &rNode)
Definition: thints.cxx:210
std::deque< AttacherIndex_Impl > aIndex
constexpr TypedWhichId< SvxWeightItem > RES_CHRATR_CJK_WEIGHT(26)
void TryCharSetExpandToNum(const SfxItemSet &pCharSet)
Definition: thints.cxx:1835
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
void InsertNesting(SwTextAttrNesting &rNewHint)
Insert nesting hint into the hints array.
Definition: thints.cxx:292
#define SAL_WARN_IF(condition, area, stream)
Pos1 overlaps Pos2 at the end.
virtual SwFieldType * InsertFieldType(const SwFieldType &)=0
constexpr TypedWhichId< SvxWeightItem > RES_CHRATR_CTL_WEIGHT(31)
static bool isSelfNestable(const sal_uInt16 nWhich)
Definition: thints.cxx:155
static void lcl_DoSplitNew(NestList_t &rSplits, SwTextNode &rNode, const sal_Int32 nNewStart, const sal_Int32 nOtherStart, const sal_Int32 nOtherEnd, bool bOtherDummy)
Definition: thints.cxx:270
#define SAL_INFO(area, stream)
SAL_DLLPRIVATE void InitRuby(SwTextNode &rNode)
Definition: thints.cxx:218
void SetCharFormat(SwFormat *pFormat)
Definition: fchrfmt.hxx:65
bool IsClipBoard() const
Definition: doc.hxx:964
LanguageType GetAppLanguage()
Definition: init.cxx:728
SwNodes & GetNodes()
Definition: doc.hxx:407
constexpr TypedWhichId< SvxPostureItem > RES_CHRATR_CTL_POSTURE(30)
sal_uInt16 const aCharFormatSetRange[]
Definition: init.cxx:244
static bool IsIgnoredCharFormatForNumbering(const sal_uInt16 nWhich)
In MS Word, the font underline setting of the paragraph end position won't affect the formatting of n...
Definition: thints.cxx:1812
const T & Put(std::unique_ptr< T > xItem, sal_uInt16 nWhich=0)
Split_t
Definition: thints.cxx:180
static void lcl_MergeListLevelIndentAsLRSpaceItem(const SwTextNode &rTextNode, SfxItemSet &rSet)
Definition: thints.cxx:2089
LanguageType GetLang(const sal_Int32 nBegin, const sal_Int32 nLen=0, sal_uInt16 nScript=0) const
Definition: thints.cxx:3418
static void Destroy(SwTextAttr *pToDestroy, SfxItemPool &rPool)
destroy instance
Definition: txatbase.cxx:58
bool FieldHidesPara(const SwField &rField) const
Definition: doc.cxx:1352
const sal_Int32 * End() const
Definition: txatbase.hxx:148
::sw::MetaFieldManager & GetMetaFieldManager()
Definition: doc.cxx:128
static const size_t MAX_HINTS
Definition: ndhints.hxx:74
static void lcl_MergeAttr(SfxItemSet &rSet, const SfxPoolItem &rAttr)
Definition: thints.cxx:2015
constexpr TypedWhichId< SwTOXMark > RES_TXTATR_TOXMARK(47)
constexpr TypedWhichId< SvxLRSpaceItem > RES_LR_SPACE(91)
void ChgTextNode(SwTextNode *pNew)
Definition: txtatr.hxx:87
constexpr TypedWhichId< SwDrawFrameFormat > RES_DRAWFRMFMT(157)
bool CalcHiddenParaField() const
Definition: thints.cxx:2628
constexpr TypedWhichId< SwFormatField > RES_TXTATR_INPUTFIELD(55)
constexpr sal_uInt16 RES_CHRATR_END(46)
TOXTypes GetType() const
Definition: tox.hxx:701
const SwAttrSet & GetSwAttrSet() const
Does node has already its own auto-attributes? Access to SwAttrSet.
Definition: node.hxx:717
virtual void CallSwClientNotify(const SfxHint &rHint) const override
Definition: calbck.cxx:363
bool InsertHint(SwTextAttr *const pAttr, const SetAttrMode nMode=SetAttrMode::DEFAULT)
Insert pAttr into hints array.
Definition: thints.cxx:1305
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:159
static void clearStatements(const css::uno::Reference< css::frame::XModel > &xModel, const OUString &rType, const css::uno::Reference< css::rdf::XResource > &xSubject)
Remove all statements in the graph of type rType, if any exists.
Definition: rdfhelper.cxx:149
const sal_uInt16 * GetRanges() const
bool IsItemIncluded(const sal_uInt16 nWhich, const SwTextAttr *pAttr)
Checks if item is included in character/inet/auto style.
Definition: atrstck.cxx:176
bool IsInDtor() const
Definition: doc.hxx:402
bool DontExpand() const
Definition: txatbase.hxx:92
SwFootnoteIdxs & GetFootnoteIdxs()
Definition: doc.hxx:632
SwFrameFormat * GetFrameFormat() const
Definition: fmtflcnt.hxx:45
Reference< XModel > xModel
bool IsDocNodes() const
Is the NodesArray the regular one of Doc? (and not the UndoNds, ...) Implementation in doc...
Definition: nodes.cxx:2320
#define INVALID_POOL_ITEM
void CalcFlags()
Definition: thints.cxx:2599
SwFormatColl * GetFormatColl() const
Definition: node.hxx:455
const SwFormatAutoFormat & GetAutoFormat() const
Definition: txatbase.hxx:185
std::unique_ptr< SwpHints > m_pSwpHints
May be 0.
Definition: ndtxt.hxx:94
bool IsInList() const
Definition: ndtxt.cxx:4318
bool HasMergedParas() const
Definition: rootfrm.hxx:424
Pos1 behind Pos2.
constexpr TypedWhichId< SwFormatRefMark > RES_TXTATR_REFMARK(RES_TXTATR_WITHEND_BEGIN)
bool m_bDDEFields
the TextNode has DDE fields
Definition: ndhints.hxx:90
void FormatToTextAttr(SwTextNode *pNd)
Convey attributes of an AttrSet (AutoFormat) to SwpHintsArray.
Definition: thints.cxx:2510
SwNode & GetEndOfRedlines() const
Section for all Redlines.
Definition: ndarr.hxx:158
const SwFormatCharFormat & GetCharFormat() const
Definition: txatbase.hxx:179
std::pair< const_iterator, bool > insert(Value &&x)
bool IsInvalidItem(const SfxPoolItem *pItem)
const SfxPoolItem & GetAttr(sal_uInt16 nWhich, bool bInParent=true) const
SS for PoolItems: hard attributation.
Definition: node.hxx:724
static void lcl_CheckSortNumber(const SwpHints &rHints, SwTextCharFormat &rNewCharFormat)
Definition: thints.cxx:2945
IStyleAccess & GetIStyleAccess()
Definition: doc.hxx:756
tools::Long GetIndentAt() const
virtual bool IsNewFieldLst() const =0
SwFieldIds Which() const
Definition: fldbas.hxx:272
Merge GetRedlineMergeFlag() const
Definition: node.hxx:97
bool IsFormatIgnoreStart() const
Definition: txatbase.hxx:102
OUString m_Text
Definition: ndtxt.hxx:99
static SwTOXType * GetSwTOXType(SwDoc &rDoc, TOXTypes eTOXTypes, const OUString &rTOXName)
Definition: rolbck.cxx:379
constexpr TypedWhichId< SvxPostureItem > RES_CHRATR_POSTURE(11)
std::vector< SwTextAttr * > m_HintsByWhichAndStart
Definition: ndhints.hxx:78
IStyleAccess & getIDocumentStyleAccess()
Provides access to the document automatic styles interface.
Definition: node.cxx:2133
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
sal_uInt16 Which() const
SwTextAttr * GetWithoutResorting(size_t nPos) const
Definition: ndhints.hxx:152
virtual void Update(SwIndex const &rPos, const sal_Int32 nChangeLen, const bool bNegative=false, const bool bDelete=false) override
override SwIndexReg
Definition: ndtxt.cxx:1138
Pos1 overlaps Pos2 at the beginning.
SwTextAttr * Cut(const size_t nPosInStart)
Definition: ndhints.hxx:185
static bool isSplittable(const sal_uInt16 nWhich)
Definition: thints.cxx:167
constexpr TypedWhichId< SvXMLAttrContainerItem > RES_TXTATR_UNKNOWN_CONTAINER(54)
sal_uInt16 nPos
bool IsInXMLImport() const
Definition: doc.hxx:971
const SfxPoolItem * GetCurItem() const
constexpr TypedWhichId< SwFormatAnchor > RES_ANCHOR(104)
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1319
SwComparePosition
Definition: pam.hxx:64
bool HasHints() const
Definition: ndtxt.hxx:221
size_type erase(const Value &x)
SwpHints & GetOrCreateSwpHints()
Definition: ndtxt.hxx:823
bool IsDefaultItem(const SfxPoolItem *pItem)
bool m_bWhichMapNeedsSorting
Definition: ndhints.hxx:94
const SwFormatFlyCnt & GetFlyCnt() const
Definition: txatbase.hxx:206
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo
SwTextAttr * MakeRedlineTextAttr(SwDoc &rDoc, SfxPoolItem const &rAttr)
create redline dummy text hint that must not be inserted into hints array
Definition: thints.cxx:985