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/xmlcnitm.hxx>
26 #include <editeng/rsiditem.hxx>
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 
708  std::set<sal_Int32> aBounds;
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  std::set<sal_Int32>::iterator aStartIter = aBounds.lower_bound( nThisStart );
731  std::set<sal_Int32>::iterator 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.get() )
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  pNew = new SwTextTOXMark( static_cast<SwTOXMark&>(rNew), nStt, &nEnd );
1117  break;
1118  case RES_TXTATR_CJK_RUBY:
1119  pNew = new SwTextRuby( static_cast<SwFormatRuby&>(rNew), nStt, nEnd );
1120  break;
1121  case RES_TXTATR_META:
1122  case RES_TXTATR_METAFIELD:
1123  pNew = SwTextMeta::CreateTextMeta( rDoc.GetMetaFieldManager(), pTextNode,
1124  static_cast<SwFormatMeta&>(rNew), nStt, nEnd, bIsCopy == CopyOrNewType::Copy );
1125  break;
1126  default:
1127  assert(RES_TXTATR_AUTOFMT == rNew.Which());
1128  pNew = new SwTextAttrEnd( rNew, nStt, nEnd );
1129  break;
1130  }
1131 
1132  return pNew;
1133 }
1134 
1135 SwTextAttr* MakeTextAttr( SwDoc & rDoc, const SfxItemSet& rSet,
1136  sal_Int32 nStt, sal_Int32 nEnd )
1137 {
1138  IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
1139  const std::shared_ptr<SfxItemSet> pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
1140  SwFormatAutoFormat aNewAutoFormat;
1141  aNewAutoFormat.SetStyleHandle( pAutoStyle );
1142  SwTextAttr* pNew = MakeTextAttr( rDoc, aNewAutoFormat, nStt, nEnd );
1143  return pNew;
1144 }
1145 
1146 // delete the text attribute and unregister its item at the pool
1148 {
1149  if( pAttr )
1150  {
1151  // some things need to be done before deleting the formatting attribute
1152  SwDoc* pDoc = GetDoc();
1153  switch( pAttr->Which() )
1154  {
1155  case RES_TXTATR_FLYCNT:
1156  {
1157  SwFrameFormat* pFormat = pAttr->GetFlyCnt().GetFrameFormat();
1158  if( pFormat ) // set to 0 by Undo?
1159  pDoc->getIDocumentLayoutAccess().DelLayoutFormat( pFormat );
1160  }
1161  break;
1162 
1163  case RES_CHRATR_HIDDEN:
1165  break;
1166 
1167  case RES_TXTATR_FTN:
1168  static_cast<SwTextFootnote*>(pAttr)->SetStartNode( nullptr );
1169  static_cast<SwFormatFootnote&>(pAttr->GetAttr()).InvalidateFootnote();
1170  break;
1171 
1172  case RES_TXTATR_FIELD:
1173  case RES_TXTATR_ANNOTATION:
1174  case RES_TXTATR_INPUTFIELD:
1175  if( !pDoc->IsInDtor() )
1176  {
1177  SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pAttr));
1178  SwFieldType* pFieldType = pAttr->GetFormatField().GetField()->GetTyp();
1179 
1180  //JP 06-08-95: DDE-fields are an exception
1181  assert(SwFieldIds::Dde == pFieldType->Which() ||
1182  this == pTextField->GetpTextNode());
1183 
1184  // certain fields must update the SwDoc's calculation flags
1185 
1186  // Certain fields (like HiddenParaField) must trigger recalculation of visible flag
1187  if (FieldCanHideParaWeight(pFieldType->Which()))
1189 
1190  switch( pFieldType->Which() )
1191  {
1194  case SwFieldIds::GetExp:
1195  case SwFieldIds::Database:
1196  case SwFieldIds::SetExp:
1198  case SwFieldIds::DbNumSet:
1199  case SwFieldIds::DbNextSet:
1201  pDoc->getIDocumentFieldsAccess().InsDelFieldInFieldLst(false, *pTextField);
1202  break;
1203  case SwFieldIds::Dde:
1204  if (GetNodes().IsDocNodes() && pTextField->GetpTextNode())
1205  static_cast<SwDDEFieldType*>(pFieldType)->DecRefCnt();
1206  break;
1207  case SwFieldIds::Postit:
1208  {
1209  const_cast<SwFormatField&>(pAttr->GetFormatField()).Broadcast(
1211  break;
1212  }
1213  default: break;
1214  }
1215  }
1216  static_cast<SwFormatField&>(pAttr->GetAttr()).InvalidateField();
1217  break;
1218 
1219  case RES_TXTATR_TOXMARK:
1220  static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark();
1221  break;
1222 
1223  case RES_TXTATR_REFMARK:
1224  static_cast<SwFormatRefMark&>(pAttr->GetAttr()).InvalidateRefMark();
1225  break;
1226 
1227  case RES_TXTATR_META:
1228  case RES_TXTATR_METAFIELD:
1229  {
1230  auto pTextMeta = static_txtattr_cast<SwTextMeta*>(pAttr);
1231  SwFormatMeta & rFormatMeta( static_cast<SwFormatMeta &>(pTextMeta->GetAttr()) );
1232  if (::sw::Meta* pMeta = rFormatMeta.GetMeta())
1233  {
1234  if (SwDocShell* pDocSh = pDoc->GetDocShell())
1235  {
1236  static const OUString metaNS("urn:bails");
1237  const css::uno::Reference<css::rdf::XResource> xSubject = pMeta->MakeUnoObject();
1238  uno::Reference<frame::XModel> xModel = pDocSh->GetBaseModel();
1239  SwRDFHelper::clearStatements(xModel, metaNS, xSubject);
1240  }
1241  }
1242 
1243  static_txtattr_cast<SwTextMeta*>(pAttr)->ChgTextNode(nullptr);
1244  }
1245  break;
1246 
1247  default:
1248  break;
1249  }
1250 
1251  SwTextAttr::Destroy( pAttr, pDoc->GetAttrPool() );
1252  }
1253 }
1254 
1256  SfxPoolItem& rAttr,
1257  const sal_Int32 nStart,
1258  const sal_Int32 nEnd,
1259  const SetAttrMode nMode )
1260 {
1261  // character attributes will be inserted as automatic styles:
1262  assert( !isCHRATR(rAttr.Which()) && "AUTOSTYLES - "
1263  "SwTextNode::InsertItem should not be called with character attributes");
1264 
1265  SwTextAttr *const pNew =
1266  MakeTextAttr(
1267  *GetDoc(),
1268  rAttr,
1269  nStart,
1270  nEnd,
1272  this );
1273 
1274  if ( pNew )
1275  {
1276  const bool bSuccess( InsertHint( pNew, nMode ) );
1277  // N.B.: also check that the hint is actually in the hints array,
1278  // because hints of certain types may be merged after successful
1279  // insertion, and thus destroyed!
1280  if (!bSuccess || !m_pSwpHints->Contains( pNew ))
1281  {
1282  return nullptr;
1283  }
1284  }
1285 
1286  return pNew;
1287 }
1288 
1289 // take ownership of pAttr; if insertion fails, delete pAttr
1290 bool SwTextNode::InsertHint( SwTextAttr * const pAttr, const SetAttrMode nMode )
1291 {
1292  bool bHiddenPara = false;
1293 
1294  assert(pAttr && pAttr->GetStart() <= Len());
1295  assert(!pAttr->GetEnd() || (*pAttr->GetEnd() <= Len()));
1296 
1297  // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR)
1298  const SwInsertFlags nInsertFlags =
1299  (nMode & SetAttrMode::NOHINTEXPAND)
1301  : (nMode & SetAttrMode::FORCEHINTEXPAND)
1304 
1305  // need this after TryInsertHint, when pAttr may be deleted
1306  const sal_Int32 nStart( pAttr->GetStart() );
1307  const bool bDummyChar( pAttr->HasDummyChar() );
1308  if (bDummyChar)
1309  {
1310  SetAttrMode nInsMode = nMode;
1311  switch( pAttr->Which() )
1312  {
1313  case RES_TXTATR_FLYCNT:
1314  {
1315  SwTextFlyCnt *pFly = static_cast<SwTextFlyCnt *>(pAttr);
1316  SwFrameFormat* pFormat = pAttr->GetFlyCnt().GetFrameFormat();
1317  if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
1318  {
1319  // Need to insert char first, because SetAnchor() reads
1320  // GetStart().
1321  //JP 11.05.98: if the anchor is already set correctly,
1322  // fix it after inserting the char, so that clients don't
1323  // have to worry about it.
1324  const SwFormatAnchor* pAnchor = nullptr;
1325  (void)pFormat->GetItemState( RES_ANCHOR, false,
1326  reinterpret_cast<const SfxPoolItem**>(&pAnchor) );
1327 
1328  SwIndex aIdx( this, pAttr->GetStart() );
1329  const OUString c(GetCharOfTextAttr(*pAttr));
1330  OUString const ins( InsertText(c, aIdx, nInsertFlags) );
1331  if (ins.isEmpty())
1332  {
1333  // do not record deletion of Format!
1334  ::sw::UndoGuard const ug(
1335  pFormat->GetDoc()->GetIDocumentUndoRedo());
1336  DestroyAttr(pAttr);
1337  return false; // text node full :(
1338  }
1339  nInsMode |= SetAttrMode::NOTXTATRCHR;
1340 
1341  if (pAnchor &&
1342  (RndStdIds::FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
1343  pAnchor->GetContentAnchor() &&
1344  pAnchor->GetContentAnchor()->nNode == *this &&
1345  pAnchor->GetContentAnchor()->nContent == aIdx )
1346  {
1347  --const_cast<SwIndex&>(
1348  pAnchor->GetContentAnchor()->nContent);
1349  }
1350  }
1351  pFly->SetAnchor( this );
1352 
1353  // format pointer could have changed in SetAnchor,
1354  // when copying to other docs!
1355  pFormat = pAttr->GetFlyCnt().GetFrameFormat();
1356  SwDoc *pDoc = pFormat->GetDoc();
1357 
1358  // OD 26.06.2003 - allow drawing objects in header/footer.
1359  // But don't allow control objects in header/footer
1360  if( RES_DRAWFRMFMT == pFormat->Which() &&
1361  pDoc->IsInHeaderFooter( pFormat->GetAnchor().GetContentAnchor()->nNode ) )
1362  {
1363  bool bCheckControlLayer = false;
1364  pFormat->CallSwClientNotify(sw::CheckDrawFrameFormatLayerHint(&bCheckControlLayer));
1365  if( bCheckControlLayer )
1366  {
1367  // This should not be allowed, prevent it here.
1368  // The dtor of the SwTextAttr does not delete the
1369  // char, so delete it explicitly here.
1370  if( SetAttrMode::NOTXTATRCHR & nInsMode )
1371  {
1372  // delete the char from the string
1373  assert(CH_TXTATR_BREAKWORD == m_Text[pAttr->GetStart()]
1374  || CH_TXTATR_INWORD == m_Text[pAttr->GetStart()]);
1375  m_Text = m_Text.replaceAt(pAttr->GetStart(), 1, "");
1376  // Update SwIndexes
1377  SwIndex aTmpIdx( this, pAttr->GetStart() );
1378  Update( aTmpIdx, 1, true );
1379  }
1380  // do not record deletion of Format!
1381  ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1382  DestroyAttr( pAttr );
1383  return false;
1384  }
1385  }
1386  break;
1387  }
1388 
1389  case RES_TXTATR_FTN :
1390  {
1391  // Footnotes: create text node and put it into Inserts-section
1392  SwDoc *pDoc = GetDoc();
1393  SwNodes &rNodes = pDoc->GetNodes();
1394 
1395  // check that footnote is inserted into body or redline section
1396  if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
1397  {
1398  // This should not be allowed, prevent it here.
1399  // The dtor of the SwTextAttr does not delete the
1400  // char, so delete it explicitly here.
1401  if( SetAttrMode::NOTXTATRCHR & nInsMode )
1402  {
1403  // delete the char from the string
1404  assert(CH_TXTATR_BREAKWORD == m_Text[pAttr->GetStart()]
1405  || CH_TXTATR_INWORD == m_Text[pAttr->GetStart()]);
1406  m_Text = m_Text.replaceAt(pAttr->GetStart(), 1, "");
1407  // Update SwIndexes
1408  SwIndex aTmpIdx( this, pAttr->GetStart() );
1409  Update( aTmpIdx, 1, true );
1410  }
1411  DestroyAttr( pAttr );
1412  return false;
1413  }
1414 
1415  // is a new footnote being inserted?
1416  bool bNewFootnote = nullptr == static_cast<SwTextFootnote*>(pAttr)->GetStartNode();
1417  if( bNewFootnote )
1418  {
1419  static_cast<SwTextFootnote*>(pAttr)->MakeNewTextSection( GetNodes() );
1420  SwRegHistory* pHist = GetpSwpHints()
1421  ? GetpSwpHints()->GetHistory() : nullptr;
1422  if( pHist )
1423  pHist->ChangeNodeIndex( GetIndex() );
1424  }
1425  else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
1426  {
1427  // existing footnote: delete all layout frames of its
1428  // footnote section
1429  sal_uLong nSttIdx =
1430  static_cast<SwTextFootnote*>(pAttr)->GetStartNode()->GetIndex();
1431  sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
1432  for( ; nSttIdx < nEndIdx; ++nSttIdx )
1433  {
1434  SwContentNode* pCNd = rNodes[ nSttIdx ]->GetContentNode();
1435  if( nullptr != pCNd )
1436  pCNd->DelFrames(nullptr);
1437  else if (SwTableNode *const pTable = rNodes[nSttIdx]->GetTableNode())
1438  {
1439  pTable->DelFrames();
1440  }
1441  }
1442  }
1443 
1444  if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
1445  {
1446  // must insert first, to prevent identical indexes
1447  // that could later prevent insertion into SwDoc's
1448  // footnote array
1449  SwIndex aNdIdx( this, pAttr->GetStart() );
1450  const OUString c(GetCharOfTextAttr(*pAttr));
1451  OUString const ins( InsertText(c, aNdIdx, nInsertFlags) );
1452  if (ins.isEmpty())
1453  {
1454  DestroyAttr(pAttr);
1455  return false; // text node full :(
1456  }
1457  nInsMode |= SetAttrMode::NOTXTATRCHR;
1458  }
1459 
1460  // insert into SwDoc's footnote index array
1461  SwTextFootnote* pTextFootnote = nullptr;
1462  if( !bNewFootnote )
1463  {
1464  // moving an existing footnote (e.g. SplitNode)
1465  for( size_t n = 0; n < pDoc->GetFootnoteIdxs().size(); ++n )
1466  if( pAttr == pDoc->GetFootnoteIdxs()[n] )
1467  {
1468  // assign new index by removing and re-inserting
1469  pTextFootnote = pDoc->GetFootnoteIdxs()[n];
1470  pDoc->GetFootnoteIdxs().erase( pDoc->GetFootnoteIdxs().begin() + n );
1471  break;
1472  }
1473  // if the Undo set the StartNode, the Index isn't
1474  // in the doc's array yet!
1475  }
1476  if( !pTextFootnote )
1477  pTextFootnote = static_cast<SwTextFootnote*>(pAttr);
1478 
1479  // to update the numbers and for sorting, the Node must be set
1480  static_cast<SwTextFootnote*>(pAttr)->ChgTextNode( this );
1481 
1482  // do not insert footnote in redline section into footnote array
1483  if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
1484  {
1485  const bool bSuccess = pDoc->GetFootnoteIdxs().insert(pTextFootnote).second;
1486  OSL_ENSURE( bSuccess, "FootnoteIdx not inserted." );
1487  }
1488  SwNodeIndex aTmpIndex( *this );
1489  pDoc->GetFootnoteIdxs().UpdateFootnote( aTmpIndex);
1490  static_cast<SwTextFootnote*>(pAttr)->SetSeqRefNo();
1491  }
1492  break;
1493 
1494  case RES_TXTATR_FIELD:
1495  {
1496  // trigger notification for relevant fields, like HiddenParaFields
1498  pAttr->GetFormatField().GetField()->GetTyp()->Which()))
1499  {
1500  bHiddenPara = true;
1501  }
1502  }
1503  break;
1504 
1505  }
1506  // CH_TXTATR_* are inserted for SwTextHints without EndIndex
1507  // If the caller is SwTextNode::Copy, the char has already been copied,
1508  // and SETATTR_NOTXTATRCHR prevents inserting it again here.
1509  if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
1510  {
1511  SwIndex aIdx( this, pAttr->GetStart() );
1512  OUString const ins( InsertText(OUString(GetCharOfTextAttr(*pAttr)),
1513  aIdx, nInsertFlags) );
1514  if (ins.isEmpty())
1515  {
1516  DestroyAttr(pAttr);
1517  return false; // text node full :(
1518  }
1519 
1520  // adjust end of hint to account for inserted CH_TXTATR
1521  const sal_Int32 * const pEnd(pAttr->GetEnd());
1522  if (pEnd)
1523  {
1524  pAttr->SetEnd(*pEnd + 1);
1525  }
1526  }
1527  }
1528 
1529  // handle attributes which provide content
1530  sal_Int32 nEnd = nStart;
1531  bool bInputFieldStartCharInserted = false;
1532  bool bInputFieldEndCharInserted = false;
1533  const bool bHasContent( pAttr->HasContent() );
1534  if ( bHasContent )
1535  {
1536  switch( pAttr->Which() )
1537  {
1538  case RES_TXTATR_INPUTFIELD:
1539  {
1540  SwTextInputField* pTextInputField = dynamic_cast<SwTextInputField*>(pAttr);
1541  if ( pTextInputField )
1542  {
1543  if( !(SetAttrMode::NOTXTATRCHR & nMode) )
1544  {
1545  SwIndex aIdx( this, pAttr->GetStart() );
1546  const OUString aContent = OUStringChar(CH_TXT_ATR_INPUTFIELDSTART)
1547  + pTextInputField->GetFieldContent() + OUStringChar(CH_TXT_ATR_INPUTFIELDEND);
1548  InsertText( aContent, aIdx, nInsertFlags );
1549 
1550  const sal_Int32* const pEnd(pAttr->GetEnd());
1551  assert(pEnd != nullptr);
1552  pAttr->SetEnd(*pEnd + aContent.getLength());
1553  nEnd = *pAttr->GetEnd();
1554  }
1555  else
1556  {
1557  // assure that CH_TXT_ATR_INPUTFIELDSTART and CH_TXT_ATR_INPUTFIELDEND are inserted.
1558  if ( m_Text[ pAttr->GetStart() ] != CH_TXT_ATR_INPUTFIELDSTART )
1559  {
1560  SwIndex aIdx( this, pAttr->GetStart() );
1561  InsertText( OUString(CH_TXT_ATR_INPUTFIELDSTART), aIdx, nInsertFlags );
1562  bInputFieldStartCharInserted = true;
1563  const sal_Int32* const pEnd(pAttr->GetEnd());
1564  assert(pEnd != nullptr);
1565  pAttr->SetEnd(*pEnd + 1);
1566  nEnd = *pAttr->GetEnd();
1567  }
1568 
1569  const sal_Int32* const pEnd(pAttr->GetEnd());
1570  assert(pEnd != nullptr);
1571  if (m_Text[ *pEnd - 1 ] != CH_TXT_ATR_INPUTFIELDEND)
1572  {
1573  SwIndex aIdx( this, *pEnd );
1574  InsertText( OUString(CH_TXT_ATR_INPUTFIELDEND), aIdx, nInsertFlags );
1575  bInputFieldEndCharInserted = true;
1576  pAttr->SetEnd(*pEnd + 1);
1577  nEnd = *pAttr->GetEnd();
1578  }
1579  }
1580  }
1581  }
1582  break;
1583  default:
1584  break;
1585  }
1586  }
1587 
1589 
1590  // handle overlap with an existing InputField
1591  bool bInsertHint = true;
1592  {
1593  const SwTextInputField* pTextInputField = GetOverlappingInputField( *pAttr );
1594  if ( pTextInputField != nullptr )
1595  {
1596  if ( pAttr->End() == nullptr )
1597  {
1598  bInsertHint = false;
1599  }
1600  else
1601  {
1602  if ( pAttr->GetStart() > pTextInputField->GetStart() )
1603  {
1604  pAttr->SetStart( pTextInputField->GetStart() );
1605  }
1606  if ( *(pAttr->End()) < *(pTextInputField->End()) )
1607  {
1608  pAttr->SetEnd(*(pTextInputField->End()));
1609  }
1610  }
1611  }
1612  }
1613 
1614  const bool bRet = bInsertHint
1615  && m_pSwpHints->TryInsertHint( pAttr, *this, nMode );
1616 
1617  if ( !bRet )
1618  {
1619  if ( bDummyChar
1620  && !(SetAttrMode::NOTXTATRCHR & nMode) )
1621  {
1622  // undo insertion of dummy character
1623  // N.B. cannot insert the dummy character after inserting the hint,
1624  // because if the hint has no extent it will be moved in InsertText,
1625  // resulting in infinite recursion
1626  assert((CH_TXTATR_BREAKWORD == m_Text[nStart] ||
1627  CH_TXTATR_INWORD == m_Text[nStart] ));
1628  SwIndex aIdx( this, nStart );
1629  EraseText( aIdx, 1 );
1630  }
1631 
1632  if ( bHasContent )
1633  {
1634  if ( !(SetAttrMode::NOTXTATRCHR & nMode)
1635  && (nEnd - nStart) > 0 )
1636  {
1637  SwIndex aIdx( this, nStart );
1638  EraseText( aIdx, (nEnd - nStart) );
1639  }
1640  else
1641  {
1642  if ( bInputFieldEndCharInserted
1643  && (nEnd - nStart) > 0 )
1644  {
1645  SwIndex aIdx( this, nEnd - 1 );
1646  EraseText( aIdx, 1 );
1647  }
1648 
1649  if ( bInputFieldStartCharInserted )
1650  {
1651  SwIndex aIdx( this, nStart );
1652  EraseText( aIdx, 1 );
1653  }
1654  }
1655  }
1656  }
1657 
1658  if ( bHiddenPara )
1659  {
1661  }
1662 
1663  return bRet;
1664 }
1665 
1667 {
1668  if ( !HasHints() )
1669  {
1670  OSL_FAIL("DeleteAttribute called, but text node without hints?");
1671  return;
1672  }
1673 
1674  if ( pAttr->HasDummyChar() )
1675  {
1676  // copy index!
1677  const SwIndex aIdx( this, pAttr->GetStart() );
1678  // erase the CH_TXTATR, which will also delete pAttr
1679  EraseText( aIdx, 1 );
1680  }
1681  else if ( pAttr->HasContent() )
1682  {
1683  const SwIndex aIdx( this, pAttr->GetStart() );
1684  assert(pAttr->End() != nullptr);
1685  EraseText( aIdx, *pAttr->End() - pAttr->GetStart() );
1686  }
1687  else
1688  {
1689  // create MsgHint before start/end become invalid
1690  SwUpdateAttr aHint(
1691  pAttr->GetStart(),
1692  *pAttr->GetEnd(),
1693  pAttr->Which());
1694 
1695  m_pSwpHints->Delete( pAttr );
1696  SwTextAttr::Destroy( pAttr, GetDoc()->GetAttrPool() );
1697  NotifyClients( nullptr, &aHint );
1698 
1700  }
1701 }
1702 
1703 //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
1705  const sal_uInt16 nWhich,
1706  const sal_Int32 nStart,
1707  const sal_Int32 nEnd )
1708 {
1709  if ( !HasHints() )
1710  return;
1711 
1712  for ( size_t nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); ++nPos )
1713  {
1714  SwTextAttr * const pTextHt = m_pSwpHints->Get( nPos );
1715  const sal_Int32 nHintStart = pTextHt->GetStart();
1716  if (nStart < nHintStart)
1717  {
1718  break; // sorted by start
1719  }
1720  else if ( (nStart == nHintStart) && (nWhich == pTextHt->Which()) )
1721  {
1722  if ( nWhich == RES_CHRATR_HIDDEN )
1723  {
1724  assert(!"hey, that's a CHRATR! how did that get in?");
1726  }
1727  else if ( nWhich == RES_TXTATR_CHARFMT )
1728  {
1729  // Check if character format contains hidden attribute:
1730  const SwCharFormat* pFormat = pTextHt->GetCharFormat().GetCharFormat();
1731  const SfxPoolItem* pItem;
1732  if ( SfxItemState::SET == pFormat->GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) )
1734  }
1735  // #i75430# Recalc hidden flags if necessary
1736  else if ( nWhich == RES_TXTATR_AUTOFMT )
1737  {
1738  // Check if auto style contains hidden attribute:
1739  const SfxPoolItem* pHiddenItem = CharFormat::GetItem( *pTextHt, RES_CHRATR_HIDDEN );
1740  if ( pHiddenItem )
1742  // for auto styles DeleteAttributes is only called from Undo
1743  // so it shouldn't need to care about ignore start/end flags
1744  }
1745 
1746  sal_Int32 const * const pEndIdx = pTextHt->GetEnd();
1747 
1748  if ( pTextHt->HasDummyChar() )
1749  {
1750  // copy index!
1751  const SwIndex aIdx( this, nStart );
1752  // erase the CH_TXTATR, which will also delete pTextHt
1753  EraseText( aIdx, 1 );
1754  }
1755  else if ( pTextHt->HasContent() )
1756  {
1757  const SwIndex aIdx( this, nStart );
1758  OSL_ENSURE( pTextHt->End() != nullptr, "<SwTextNode::DeleteAttributes(..)> - missing End() at <SwTextAttr> instance which has content" );
1759  EraseText( aIdx, *pTextHt->End() - nStart );
1760  }
1761  else if( *pEndIdx == nEnd )
1762  {
1763  // Create MsgHint before Start and End are gone.
1764  // For HiddenParaFields it's not necessary to call
1765  // SetCalcHiddenParaField because the dtor does that.
1766  SwUpdateAttr aHint(
1767  nStart,
1768  *pEndIdx,
1769  nWhich);
1770 
1771  m_pSwpHints->DeleteAtPos( nPos );
1772  SwTextAttr::Destroy( pTextHt, GetDoc()->GetAttrPool() );
1773  NotifyClients( nullptr, &aHint );
1774  }
1775  }
1776  }
1778 }
1779 
1780 void SwTextNode::DelSoftHyph( const sal_Int32 nStt, const sal_Int32 nEnd )
1781 {
1782  sal_Int32 nFndPos = nStt;
1783  sal_Int32 nEndPos = nEnd;
1784  for (;;)
1785  {
1786  nFndPos = m_Text.indexOf(CHAR_SOFTHYPHEN, nFndPos);
1787  if (nFndPos<0 || nFndPos>=nEndPos )
1788  {
1789  break;
1790  }
1791  const SwIndex aIdx( this, nFndPos );
1792  EraseText( aIdx, 1 );
1793  --nEndPos;
1794  }
1795 }
1796 
1797 bool SwTextNode::IsIgnoredCharFormatForNumbering(const sal_uInt16 nWhich)
1798 {
1799  return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_BACKGROUND
1800  || nWhich == RES_CHRATR_ESCAPEMENT);
1801 }
1802 
1803 //In MS Word, following properties of the paragraph end position won't affect the formatting of bullets, so we ignore them:
1804 //Font underline;
1805 //Font Italic of Western, CJK and CTL;
1806 //Font Bold of Wertern, CJK and CTL;
1807 static bool lcl_IsIgnoredCharFormatForBullets(const sal_uInt16 nWhich)
1808 {
1809  return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_POSTURE || nWhich == RES_CHRATR_WEIGHT
1810  || nWhich == RES_CHRATR_CJK_POSTURE || nWhich == RES_CHRATR_CJK_WEIGHT
1811  || nWhich == RES_CHRATR_CTL_POSTURE || nWhich == RES_CHRATR_CTL_WEIGHT);
1812 }
1813 
1814 //Condition for expanding char set to character style of specified number rule level:
1815 //The item inside the set should not conflict to any exist and non-default item inside paragraph properties set (SwContentNode::SwPAttrSet);
1816 //The node should have applied a number rule;
1817 //The node should be counted in a list, if not, make it to be;
1818 //The item should not conflict to any exist and non-default item inside the character of specified number rule level;
1819 //The item should not be ignored depend on the exact number rule type;
1821 {
1822  SfxItemIter aIter( aCharSet );
1823  const SfxPoolItem* pItem = aIter.GetCurItem();
1824  if (!pItem)
1825  return;
1826  const sal_uInt16 nWhich = pItem->Which();
1827 
1828  const SfxPoolItem& rInnerItem = GetAttr(nWhich,false);
1829 
1830  if (!IsDefaultItem(&rInnerItem) && !IsInvalidItem(&rInnerItem))
1831  return;
1832 
1833  if (!IsInList() && GetNumRule() && !GetListId().isEmpty())
1834  {
1835  return;
1836  }
1837 
1838  SwNumRule* pCurrNum = GetNumRule(false);
1839 
1840  int nLevel = GetActualListLevel();
1841 
1842  if (nLevel != -1 && pCurrNum)
1843  {
1844  const SwNumFormat* pCurrNumFormat = pCurrNum->GetNumFormat(static_cast<sal_uInt16>(nLevel));
1845  if (pCurrNumFormat)
1846  {
1847  if (pCurrNumFormat->IsItemize() && lcl_IsIgnoredCharFormatForBullets(nWhich))
1848  return;
1849  if (pCurrNumFormat->IsEnumeration() && SwTextNode::IsIgnoredCharFormatForNumbering(nWhich))
1850  return;
1851  SwCharFormat* pCurrCharFormat =pCurrNumFormat->GetCharFormat();
1852 
1853  if (pCurrCharFormat && pCurrCharFormat->GetItemState(nWhich,false) != SfxItemState::SET)
1854  {
1855  pCurrCharFormat->SetFormatAttr(*pItem);
1856  SwNumFormat aNewNumFormat(*pCurrNumFormat);
1857  aNewNumFormat.SetCharFormat(pCurrCharFormat);
1858  pCurrNum->Set(nLevel,aNewNumFormat);
1859  }
1860  }
1861  }
1862 }
1863 
1864 // Set these attributes on SwTextNode. If they apply to the entire paragraph
1865 // text, set them in the SwTextNode's item set (SwContentNode::SetAttr).
1867  const SfxItemSet& rSet,
1868  const sal_Int32 nStt,
1869  const sal_Int32 nEnd,
1870  const SetAttrMode nMode,
1871  SwTextAttr **ppNewTextAttr )
1872 {
1873  if( !rSet.Count() )
1874  return false;
1875 
1876  // split sets (for selection in nodes)
1877  const SfxItemSet* pSet = &rSet;
1878  SfxItemSet aTextSet( *rSet.GetPool(), svl::Items<RES_TXTATR_BEGIN, RES_TXTATR_END-1>{} );
1879 
1880  // entire paragraph
1881  if ( !nStt && (nEnd == m_Text.getLength()) &&
1882  !(nMode & SetAttrMode::NOFORMATATTR ) )
1883  {
1884  // if the node already has CharFormat hints, the new attributes must
1885  // be set as hints too to override those.
1886  bool bHasCharFormats = false;
1887  if ( HasHints() )
1888  {
1889  for ( size_t n = 0; n < m_pSwpHints->Count(); ++n )
1890  {
1891  if ( m_pSwpHints->Get( n )->IsCharFormatAttr() )
1892  {
1893  bHasCharFormats = true;
1894  break;
1895  }
1896  }
1897  }
1898 
1899  if( !bHasCharFormats )
1900  {
1901  aTextSet.Put( rSet );
1902  // If there are any character attributes in rSet,
1903  // we want to set them at the paragraph:
1904  if( aTextSet.Count() != rSet.Count() )
1905  {
1906  const bool bRet = SetAttr( rSet );
1907  if( !aTextSet.Count() )
1908  return bRet;
1909  }
1910 
1911  // check for auto style:
1912  const SfxPoolItem* pItem;
1913  const bool bAutoStyle = SfxItemState::SET == aTextSet.GetItemState( RES_TXTATR_AUTOFMT, false, &pItem );
1914  if ( bAutoStyle )
1915  {
1916  std::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFormatAutoFormat*>(pItem)->GetStyleHandle();
1917  const bool bRet = SetAttr( *pAutoStyleSet );
1918  if( 1 == aTextSet.Count() )
1919  return bRet;
1920  }
1921 
1922  // Continue with the text attributes:
1923  pSet = &aTextSet;
1924  }
1925  }
1926 
1928 
1929  SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFormatSetRange );
1930 
1931  size_t nCount = 0;
1932  SfxItemIter aIter( *pSet );
1933  const SfxPoolItem* pItem = aIter.GetCurItem();
1934 
1935  do
1936  {
1937  if (!IsInvalidItem(pItem))
1938  {
1939  const sal_uInt16 nWhich = pItem->Which();
1940  OSL_ENSURE( isCHRATR(nWhich) || isTXTATR(nWhich),
1941  "SwTextNode::SetAttr(): unknown attribute" );
1942  if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
1943  {
1944  if ((RES_TXTATR_CHARFMT == nWhich) &&
1945  (GetDoc()->GetDfltCharFormat() ==
1946  static_cast<const SwFormatCharFormat*>(pItem)->GetCharFormat()))
1947  {
1948  SwIndex aIndex( this, nStt );
1949  RstTextAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT );
1950  DontExpandFormat( aIndex );
1951  }
1952  else
1953  {
1954  if (isCHRATR(nWhich) ||
1955  (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1956  {
1957  aCharSet.Put( *pItem );
1958  }
1959  else
1960  {
1961 
1962  SwTextAttr *const pNew = MakeTextAttr( *GetDoc(),
1963  const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
1964  if ( pNew )
1965  {
1966  // store the first one we create into the pp
1967  if (ppNewTextAttr && !*ppNewTextAttr)
1968  *ppNewTextAttr = pNew;
1969  if ( nEnd != nStt && !pNew->GetEnd() )
1970  {
1971  OSL_FAIL("Attribute without end, but area marked");
1972  DestroyAttr( pNew ); // do not insert
1973  }
1974  else if ( InsertHint( pNew, nMode ) )
1975  {
1976  ++nCount;
1977  }
1978  }
1979  }
1980  }
1981  }
1982  }
1983  pItem = aIter.NextItem();
1984  } while(pItem);
1985 
1986  if ( aCharSet.Count() )
1987  {
1988  SwTextAttr* pTmpNew = MakeTextAttr( *GetDoc(), aCharSet, nStt, nEnd );
1989  if ( InsertHint( pTmpNew, nMode ) )
1990  {
1991  ++nCount;
1992  }
1993  }
1994 
1996 
1997  return nCount != 0;
1998 }
1999 
2000 static void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
2001 {
2002  if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
2003  {
2004  const SfxItemSet* pCFSet = CharFormat::GetItemSet( rAttr );
2005  if ( !pCFSet )
2006  return;
2007  SfxWhichIter aIter( *pCFSet );
2008  sal_uInt16 nWhich = aIter.FirstWhich();
2009  while( nWhich )
2010  {
2011  if( ( nWhich < RES_CHRATR_END ||
2012  RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
2013  ( SfxItemState::SET == pCFSet->GetItemState( nWhich ) ) )
2014  rSet.Put( pCFSet->Get( nWhich ) );
2015  nWhich = aIter.NextWhich();
2016  }
2017  }
2018  else
2019  rSet.Put( rAttr );
2020 }
2021 
2022 static void lcl_MergeAttr_ExpandChrFormat( SfxItemSet& rSet, const SfxPoolItem& rAttr )
2023 {
2024  if( RES_TXTATR_CHARFMT == rAttr.Which() ||
2025  RES_TXTATR_INETFMT == rAttr.Which() ||
2026  RES_TXTATR_AUTOFMT == rAttr.Which() )
2027  {
2028  const SfxItemSet* pCFSet = CharFormat::GetItemSet( rAttr );
2029 
2030  if ( pCFSet )
2031  {
2032  SfxWhichIter aIter( *pCFSet );
2033  sal_uInt16 nWhich = aIter.FirstWhich();
2034  while( nWhich )
2035  {
2036  if( ( nWhich < RES_CHRATR_END ||
2037  ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
2038  ( SfxItemState::SET == pCFSet->GetItemState( nWhich ) ) )
2039  rSet.Put( pCFSet->Get( nWhich ) );
2040  nWhich = aIter.NextWhich();
2041  }
2042  }
2043  }
2044 
2045 /* If multiple attributes overlap, the last one wins!
2046  Probably this can only happen between a RES_TXTATR_INETFMT and one of the
2047  other hints, because BuildPortions ensures that CHARFMT/AUTOFMT don't
2048  overlap. But there may be multiple CHARFMT/AUTOFMT with exactly the same
2049  start/end, sorted by BuildPortions, in which case the same logic applies.
2050 
2051  1234567890123456789
2052  |------------| Font1
2053  |------| Font2
2054  ^ ^
2055  |--| query range: -> Font2
2056 */
2057  // merge into set
2058  rSet.Put( rAttr );
2059 }
2060 
2061 namespace {
2062 
2063 struct SwPoolItemEndPair
2064 {
2065 public:
2066  const SfxPoolItem* mpItem;
2067  sal_Int32 mnEndPos;
2068 
2069  SwPoolItemEndPair() : mpItem( nullptr ), mnEndPos( 0 ) {};
2070 };
2071 
2072 }
2073 
2075  SfxItemSet& rSet )
2076 {
2077  if ( rTextNode.AreListLevelIndentsApplicable() )
2078  {
2079  const SwNumRule* pRule = rTextNode.GetNumRule();
2080  if ( pRule && rTextNode.GetActualListLevel() >= 0 )
2081  {
2082  const SwNumFormat& rFormat = pRule->Get(static_cast<sal_uInt16>(rTextNode.GetActualListLevel()));
2084  {
2086  aLR.SetTextLeft( rFormat.GetIndentAt() );
2087  aLR.SetTextFirstLineOfst( static_cast<short>(rFormat.GetFirstLineIndent()) );
2088  rSet.Put( aLR );
2089  }
2090  }
2091  }
2092 }
2093 
2094 // request the attributes of the TextNode at the range
2095 bool SwTextNode::GetParaAttr(SfxItemSet& rSet, sal_Int32 nStt, sal_Int32 nEnd,
2096  const bool bOnlyTextAttr, const bool bGetFromChrFormat,
2097  const bool bMergeIndentValuesOfNumRule,
2098  SwRootFrame const*const pLayout) const
2099 {
2100  assert(!rSet.Count()); // handled inconsistently, typically an error?
2101 
2102  if (pLayout && pLayout->IsHideRedlines())
2103  {
2105  {
2106  return false; // ignore deleted node
2107  }
2108  }
2109 
2110  // get the node's automatic attributes
2111  SfxItemSet aFormatSet( *rSet.GetPool(), rSet.GetRanges() );
2112  if (!bOnlyTextAttr)
2113  {
2114  SwTextNode const& rParaPropsNode(
2115  sw::GetAttrMerged(aFormatSet, *this, pLayout));
2116  if (bMergeIndentValuesOfNumRule)
2117  {
2118  lcl_MergeListLevelIndentAsLRSpaceItem(rParaPropsNode, aFormatSet);
2119  }
2120  }
2121 
2122  if( HasHints() )
2123  {
2124  // First, check which text attributes are valid in the range.
2125  // cases:
2126  // Ambiguous, if
2127  // * the attribute is wholly contained in the range
2128  // * the attribute end is in the range
2129  // * the attribute start is in the range
2130  // Unambiguous (merge into set), if
2131  // * the attribute wholly contains the range
2132  // Ignored, if
2133  // * the attribute is wholly outside the range
2134 
2135  void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
2136  = bGetFromChrFormat ? &lcl_MergeAttr_ExpandChrFormat
2137  : &lcl_MergeAttr;
2138 
2139  const size_t nSize = m_pSwpHints->Count();
2140 
2141  if (nStt == nEnd) // no range:
2142  {
2143  for (size_t n = 0; n < nSize; ++n)
2144  {
2145  const SwTextAttr* pHt = m_pSwpHints->Get(n);
2146  const sal_Int32 nAttrStart = pHt->GetStart();
2147  if (nAttrStart > nEnd) // behind the range
2148  break;
2149 
2150  const sal_Int32* pAttrEnd = pHt->End();
2151  if ( ! pAttrEnd ) // no attributes without end
2152  continue;
2153 
2154  if( ( nAttrStart < nStt &&
2155  ( pHt->DontExpand() ? nStt < *pAttrEnd
2156  : nStt <= *pAttrEnd )) ||
2157  ( nStt == nAttrStart &&
2158  ( nAttrStart == *pAttrEnd || !nStt )))
2159  (*fnMergeAttr)( rSet, pHt->GetAttr() );
2160  }
2161  }
2162  else // a query range is defined
2163  {
2164  // #i75299#
2165  std::unique_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
2166 
2167  const size_t coArrSz = RES_TXTATR_WITHEND_END - RES_CHRATR_BEGIN;
2168 
2169  for (size_t n = 0; n < nSize; ++n)
2170  {
2171  const SwTextAttr* pHt = m_pSwpHints->Get(n);
2172  const sal_Int32 nAttrStart = pHt->GetStart();
2173  if (nAttrStart > nEnd) // outside, behind
2174  break;
2175 
2176  const sal_Int32* pAttrEnd = pHt->End();
2177  if ( ! pAttrEnd ) // no attributes without end
2178  continue;
2179 
2180  bool bChkInvalid = false;
2181  if (nAttrStart <= nStt) // before or exactly Start
2182  {
2183  if (*pAttrEnd <= nStt) // outside, before
2184  continue;
2185 
2186  if (nEnd <= *pAttrEnd) // behind or exactly End
2187  (*fnMergeAttr)( aFormatSet, pHt->GetAttr() );
2188  else
2189 // else if( pHt->GetAttr() != aFormatSet.Get( pHt->Which() ) )
2190  // ambiguous
2191  bChkInvalid = true;
2192  }
2193  else if (nAttrStart < nEnd // starts in the range
2194 )// && pHt->GetAttr() != aFormatSet.Get( pHt->Which() ) )
2195  bChkInvalid = true;
2196 
2197  if( bChkInvalid )
2198  {
2199  // ambiguous?
2200  std::unique_ptr< SfxItemIter > pItemIter;
2201  const SfxPoolItem* pItem = nullptr;
2202 
2203  if ( RES_TXTATR_AUTOFMT == pHt->Which() )
2204  {
2205  const SfxItemSet* pAutoSet = CharFormat::GetItemSet( pHt->GetAttr() );
2206  if ( pAutoSet )
2207  {
2208  pItemIter.reset( new SfxItemIter( *pAutoSet ) );
2209  pItem = pItemIter->GetCurItem();
2210  }
2211  }
2212  else
2213  pItem = &pHt->GetAttr();
2214 
2215  const sal_Int32 nHintEnd = *pAttrEnd;
2216 
2217  for (; pItem; pItem = pItemIter ? pItemIter->NextItem() : nullptr)
2218  {
2219  const sal_uInt16 nHintWhich = pItem->Which();
2220  OSL_ENSURE(!isUNKNOWNATR(nHintWhich),
2221  "SwTextNode::GetAttr(): unknown attribute?");
2222 
2223  if (!pAttrArr)
2224  {
2225  pAttrArr.reset(
2226  new std::vector< SwPoolItemEndPair >(coArrSz));
2227  }
2228 
2229  std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
2230  if (isCHRATR(nHintWhich) ||
2231  isTXTATR_WITHEND(nHintWhich))
2232  {
2233  pPrev += nHintWhich - RES_CHRATR_BEGIN;
2234  }
2235  else
2236  {
2237  pPrev = pAttrArr->end();
2238  }
2239 
2240  if( pPrev != pAttrArr->end() )
2241  {
2242  if( !pPrev->mpItem )
2243  {
2244  if ( bOnlyTextAttr || *pItem != aFormatSet.Get( nHintWhich ) )
2245  {
2246  if( nAttrStart > nStt )
2247  {
2248  rSet.InvalidateItem( nHintWhich );
2249  pPrev->mpItem = INVALID_POOL_ITEM;
2250  }
2251  else
2252  {
2253  pPrev->mpItem = pItem;
2254  pPrev->mnEndPos = nHintEnd;
2255  }
2256  }
2257  }
2258  else if( !IsInvalidItem(pPrev->mpItem) )
2259  {
2260  if( pPrev->mnEndPos == nAttrStart &&
2261  *pPrev->mpItem == *pItem )
2262  {
2263  pPrev->mpItem = pItem;
2264  pPrev->mnEndPos = nHintEnd;
2265  }
2266  else
2267  {
2268  rSet.InvalidateItem( nHintWhich );
2269  pPrev->mpItem = INVALID_POOL_ITEM;
2270  }
2271  }
2272  }
2273  } // end while
2274  }
2275  }
2276 
2277  if (pAttrArr)
2278  {
2279  for (size_t n = 0; n < coArrSz; ++n)
2280  {
2281  const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
2282  if( rItemPair.mpItem && !IsInvalidItem(rItemPair.mpItem) )
2283  {
2284  const sal_uInt16 nWh =
2285  static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
2286 
2287  if (nEnd <= rItemPair.mnEndPos) // behind or exactly end
2288  {
2289  if( *rItemPair.mpItem != aFormatSet.Get( nWh ) )
2290  (*fnMergeAttr)( rSet, *rItemPair.mpItem );
2291  }
2292  else
2293  // ambiguous
2294  rSet.InvalidateItem( nWh );
2295  }
2296  }
2297  }
2298  }
2299  if( aFormatSet.Count() )
2300  {
2301  // remove all from the format-set that are also set in the text-set
2302  aFormatSet.Differentiate( rSet );
2303  }
2304  }
2305 
2306  if (aFormatSet.Count())
2307  {
2308  // now "merge" everything
2309  rSet.Put( aFormatSet );
2310  }
2311 
2312  return rSet.Count() != 0;
2313 }
2314 
2315 namespace
2316 {
2317 
2318 typedef std::pair<sal_Int32, sal_Int32> AttrSpan_t;
2319 typedef std::multimap<AttrSpan_t, const SwTextAttr*> AttrSpanMap_t;
2320 
2321 struct IsAutoStyle
2322 {
2323  bool
2324  operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2325  const
2326  {
2327  return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
2328  }
2329 };
2330 
2334 struct RemovePresentAttrs
2335 {
2336  explicit RemovePresentAttrs(SfxItemSet& io_rAttrSet)
2337  : m_rAttrSet(io_rAttrSet)
2338  {
2339  }
2340 
2341  void
2342  operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2343  const
2344  {
2345  if (!i_rAttrSpan.second)
2346  {
2347  return;
2348  }
2349 
2350  const SwTextAttr* const pAutoStyle(i_rAttrSpan.second);
2351  SfxItemIter aIter(m_rAttrSet);
2352  for (const SfxPoolItem* pItem(aIter.GetCurItem()); pItem; pItem = aIter.NextItem())
2353  {
2354  const sal_uInt16 nWhich(pItem->Which());
2355  if (CharFormat::IsItemIncluded(nWhich, pAutoStyle))
2356  {
2357  m_rAttrSet.ClearItem(nWhich);
2358  }
2359  }
2360  }
2361 
2362 private:
2363  SfxItemSet& m_rAttrSet;
2364 };
2365 
2372 void
2373 lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_Int32 nLength,
2374  AttrSpanMap_t& o_rSpanMap)
2375 {
2376  sal_Int32 nLastEnd(0);
2377 
2378  for (size_t i = 0; i < i_rHints.Count(); ++i)
2379  {
2380  const SwTextAttr* pHint = i_rHints.Get(i);
2381  const sal_uInt16 nWhich(pHint->Which());
2382  if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
2383  {
2384  const AttrSpan_t aSpan(pHint->GetStart(), *pHint->End());
2385  o_rSpanMap.emplace(aSpan, pHint);
2386 
2387  // < not != because there may be multiple CHARFMT at same range
2388  if (nLastEnd < aSpan.first)
2389  {
2390  // insert dummy span covering the gap
2391  o_rSpanMap.emplace( AttrSpan_t(nLastEnd, aSpan.first), nullptr );
2392  }
2393 
2394  nLastEnd = aSpan.second;
2395  }
2396  }
2397 
2398  // no hints at the end (special case: no hints at all in i_rHints)
2399  if (nLastEnd != nLength && nLength != 0)
2400  {
2401  o_rSpanMap.emplace(AttrSpan_t(nLastEnd, nLength), nullptr);
2402  }
2403 }
2404 
2405 void
2406 lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
2407 {
2408  o_rClearIds.reserve(i_rAttrSet.Count());
2409  SfxItemIter aIter(i_rAttrSet);
2410  for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
2411  {
2412  o_rClearIds.push_back(pItem->Which());
2413  }
2414 }
2415 
2416 struct SfxItemSetClearer
2417 {
2418  SfxItemSet & m_rItemSet;
2419  explicit SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
2420  void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
2421 };
2422 
2423 }
2424 
2428 void
2430 {
2431  typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
2432  AttrSpanMap_t aAttrSpanMap;
2433 
2434  if (i_rAttrSet.Count() == 0)
2435  {
2436  return;
2437  }
2438 
2439  // 1. Identify all spans in hints' array
2440 
2441  lcl_CollectHintSpans(*m_pSwpHints, m_Text.getLength(), aAttrSpanMap);
2442 
2443  // 2. Go through all spans and insert new attrs
2444 
2445  AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
2446  const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
2447  while (aCurRange != aEnd)
2448  {
2449  typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
2450  AttrSpanMapRange_t;
2451  AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
2452 
2453  // 2a. Collect attributes to insert
2454 
2455  SfxItemSet aCurSet(i_rAttrSet);
2456  std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
2457 
2458  // 2b. Insert automatic style containing the collected attributes
2459 
2460  if (aCurSet.Count() != 0)
2461  {
2462  AttrSpanMap_iterator_t aAutoStyleIt(
2463  std::find_if(aRange.first, aRange.second, IsAutoStyle()));
2464  if (aAutoStyleIt != aRange.second)
2465  {
2466  // there already is an automatic style on that span:
2467  // create new one and remove the original one
2468  SwTextAttr* const pAutoStyle(const_cast<SwTextAttr*>(aAutoStyleIt->second));
2469  const std::shared_ptr<SfxItemSet> pOldStyle(
2470  static_cast<const SwFormatAutoFormat&>(
2471  pAutoStyle->GetAttr()).GetStyleHandle());
2472  aCurSet.Put(*pOldStyle);
2473 
2474  // remove the old hint
2475  m_pSwpHints->Delete(pAutoStyle);
2476  DestroyAttr(pAutoStyle);
2477  }
2478  m_pSwpHints->Insert(
2479  MakeTextAttr(*GetDoc(), aCurSet,
2480  aCurRange->first.first, aCurRange->first.second));
2481  }
2482 
2483  aCurRange = aRange.second;
2484  }
2485 
2486  // hints were directly inserted, so need to fix the Ignore flags now
2487  m_pSwpHints->MergePortions(*this);
2488 
2489  // 3. Clear items from the node
2490  std::vector<sal_uInt16> aClearedIds;
2491  lcl_FillWhichIds(i_rAttrSet, aClearedIds);
2492  ClearItemsFromAttrSet(aClearedIds);
2493 }
2494 
2496 {
2497  SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFormatSetRange );
2498  if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
2499  aThisSet.Put( *GetpSwAttrSet() );
2500 
2502 
2503  if( pNd == this )
2504  {
2505  impl_FormatToTextAttr(aThisSet);
2506  }
2507  else
2508  {
2509  // There are five possible combinations of items from this and
2510  // pNd (pNd is the 'main' node):
2511 
2512  // case pNd this action
2513 
2514  // 1 - - do nothing
2515  // 2 - a convert item to attr of this
2516  // 3 a - convert item to attr of pNd
2517  // 4 a a clear item in this
2518  // 5 a b convert item to attr of this
2519 
2520  SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFormatSetRange );
2521  if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
2522  aNdSet.Put( *pNd->GetpSwAttrSet() );
2523 
2524  pNd->GetOrCreateSwpHints();
2525 
2526  std::vector<sal_uInt16> aProcessedIds;
2527 
2528  if( aThisSet.Count() )
2529  {
2530  SfxItemIter aIter( aThisSet );
2531  const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = nullptr;
2532  SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFormatSetRange );
2533  std::vector<sal_uInt16> aClearWhichIds;
2534 
2535  do
2536  {
2537  if( SfxItemState::SET == aNdSet.GetItemState( pItem->Which(), false, &pNdItem ) )
2538  {
2539  if (*pItem == *pNdItem) // 4
2540  {
2541  aClearWhichIds.push_back( pItem->Which() );
2542  }
2543  else // 5
2544  {
2545  aConvertSet.Put(*pItem);
2546  }
2547  aProcessedIds.push_back(pItem->Which());
2548  }
2549  else // 2
2550  {
2551  aConvertSet.Put(*pItem);
2552  }
2553 
2554  pItem = aIter.NextItem();
2555  } while (pItem);
2556 
2557  // 4/ clear items of this that are set with the same value on pNd
2558  ClearItemsFromAttrSet( aClearWhichIds );
2559 
2560  // 2, 5/ convert all other items to attrs
2561  impl_FormatToTextAttr(aConvertSet);
2562  }
2563 
2564  {
2565  std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
2566  SfxItemSetClearer(aNdSet));
2567 
2568  // 3/ convert items to attrs
2569  pNd->impl_FormatToTextAttr(aNdSet);
2570 
2571  if( aNdSet.Count() )
2572  {
2573  SwFormatChg aTmp1( pNd->GetFormatColl() );
2574  pNd->NotifyClients( &aTmp1, &aTmp1 );
2575  }
2576  }
2577  }
2578 
2580 
2581  pNd->TryDeleteSwpHints();
2582 }
2583 
2585 {
2586  m_bDDEFields = m_bFootnote = false;
2587  const size_t nSize = Count();
2588  for( size_t nPos = 0; nPos < nSize; ++nPos )
2589  {
2590  const SwTextAttr* pAttr = Get( nPos );
2591  switch( pAttr->Which() )
2592  {
2593  case RES_TXTATR_FTN:
2594  m_bFootnote = true;
2595  if ( m_bDDEFields )
2596  return;
2597  break;
2598  case RES_TXTATR_FIELD:
2599  {
2600  const SwField* pField = pAttr->GetFormatField().GetField();
2601  if( SwFieldIds::Dde == pField->GetTyp()->Which() )
2602  {
2603  m_bDDEFields = true;
2604  if ( m_bFootnote )
2605  return;
2606  }
2607  }
2608  break;
2609  }
2610  }
2611 }
2612 
2614 {
2615  m_bCalcHiddenParaField = false;
2616  const bool bOldHiddenByParaField = m_bHiddenByParaField;
2617  bool bNewHiddenByParaField = false;
2618  int nNewResultWeight = 0;
2619  const size_t nSize = Count();
2620  const SwTextAttr* pTextHt;
2621 
2622  for (size_t nPos = 0; nPos < nSize; ++nPos)
2623  {
2624  pTextHt = Get(nPos);
2625  const sal_uInt16 nWhich = pTextHt->Which();
2626 
2627  if (RES_TXTATR_FIELD == nWhich)
2628  {
2629  // see also SwTextFrame::IsHiddenNow()
2630  const SwFormatField& rField = pTextHt->GetFormatField();
2631  int nCurWeight = m_rParent.FieldCanHideParaWeight(rField.GetField()->GetTyp()->Which());
2632  if (nCurWeight > nNewResultWeight)
2633  {
2634  nNewResultWeight = nCurWeight;
2635  bNewHiddenByParaField = m_rParent.FieldHidesPara(*rField.GetField());
2636  }
2637  else if (nCurWeight == nNewResultWeight && bNewHiddenByParaField)
2638  {
2639  // Currently, for both supported hiding types (HiddenPara, Database), "Don't hide"
2640  // takes precedence - i.e., if there's a "Don't hide" field of that weight, we only
2641  // care about fields of higher weight.
2642  bNewHiddenByParaField = m_rParent.FieldHidesPara(*rField.GetField());
2643  }
2644  }
2645  }
2646  SetHiddenByParaField(bNewHiddenByParaField);
2647  return bOldHiddenByParaField != bNewHiddenByParaField;
2648 }
2649 
2650 void SwpHints::NoteInHistory( SwTextAttr *pAttr, const bool bNew )
2651 {
2652  if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
2653 }
2654 
2656 {
2657  if ( !Count() )
2658  return false;
2659 
2660  // sort before merging
2661  Resort();
2662 
2663  bool bRet = false;
2664  typedef std::multimap< int, std::pair<SwTextAttr*, bool> > PortionMap;
2665  PortionMap aPortionMap;
2666  std::unordered_map<int, bool> RsidOnlyAutoFormatFlagMap;
2667  sal_Int32 nLastPorStart = COMPLETE_STRING;
2668  int nKey = 0;
2669 
2670  // get portions by start position:
2671  for ( size_t i = 0; i < Count(); ++i )
2672  {
2673  SwTextAttr *pHt = Get( i );
2674  if ( RES_TXTATR_CHARFMT != pHt->Which() &&
2675  RES_TXTATR_AUTOFMT != pHt->Which() )
2676  //&&
2677  //RES_TXTATR_INETFMT != pHt->Which() )
2678  continue;
2679 
2680  bool isRsidOnlyAutoFormat(false);
2681  // check for RSID-only AUTOFMT
2682  if (RES_TXTATR_AUTOFMT == pHt->Which())
2683  {
2684  std::shared_ptr<SfxItemSet> const pSet(
2685  pHt->GetAutoFormat().GetStyleHandle());
2686  if ((pSet->Count() == 1) && pSet->GetItem(RES_CHRATR_RSID, false))
2687  {
2688  // fdo#70201: eliminate no-extent RSID-only AUTOFMT
2689  // could be produced by ReplaceText or (maybe?) RstAttr
2690  if (pHt->GetStart() == *pHt->GetEnd())
2691  {
2692  DeleteAtPos(i); // kill it without History!
2693  SwTextAttr::Destroy(pHt, rNode.GetDoc()->GetAttrPool());
2694  --i;
2695  continue;
2696  }
2697  // fdo#52028: this one has _only_ RSID => ignore it completely
2698  if (!pHt->IsFormatIgnoreStart() || !pHt->IsFormatIgnoreEnd())
2699  {
2700  NoteInHistory(pHt);
2701  pHt->SetFormatIgnoreStart(true);
2702  pHt->SetFormatIgnoreEnd (true);
2703  NoteInHistory(pHt, true);
2704  }
2705  isRsidOnlyAutoFormat = true;
2706  }
2707  }
2708 
2709  if (pHt->GetStart() == *pHt->GetEnd())
2710  {
2711  // no-length hints are a disease. ignore them here.
2712  // the SwAttrIter::SeekFwd will not call Rst/Chg for them.
2713  continue;
2714  }
2715 
2716  const sal_Int32 nPorStart = pHt->GetStart();
2717  if (nPorStart != nLastPorStart)
2718  ++nKey;
2719  nLastPorStart = nPorStart;
2720  aPortionMap.insert(std::make_pair(nKey,
2721  std::make_pair(pHt, isRsidOnlyAutoFormat)));
2722  RsidOnlyAutoFormatFlagMap[nKey] = isRsidOnlyAutoFormat;
2723  }
2724 
2725  // check if portion i can be merged with portion i+1:
2726  // note: need to include i=0 to set IgnoreStart and j=nKey+1 to reset
2727  // IgnoreEnd at first / last portion
2728  int i = 0;
2729  int j = i + 1;
2730  while ( i <= nKey )
2731  {
2732  std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
2733  std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
2734  PortionMap::iterator aIter1 = aRange1.first;
2735  PortionMap::iterator aIter2 = aRange2.first;
2736 
2737  enum { MATCH, DIFFER_ONLY_RSID, DIFFER } eMerge(MATCH);
2738  size_t const nAttributesInPor1 = std::distance(aRange1.first, aRange1.second);
2739  size_t const nAttributesInPor2 = std::distance(aRange2.first, aRange2.second);
2740  bool const isRsidOnlyAutoFormat1(RsidOnlyAutoFormatFlagMap[i]);
2741  bool const isRsidOnlyAutoFormat2(RsidOnlyAutoFormatFlagMap[j]);
2742 
2743  // if both have one they could be equal, but not if only one has it
2744  bool const bSkipRsidOnlyAutoFormat(nAttributesInPor1 != nAttributesInPor2);
2745 
2746  // this loop needs to handle the case where one has a CHARFMT and the
2747  // other CHARFMT + RSID-only AUTOFMT, so...
2748  // want to skip over RSID-only AUTOFMT here, hence the -1
2749  if ((nAttributesInPor1 - (isRsidOnlyAutoFormat1 ? 1 : 0)) ==
2750  (nAttributesInPor2 - (isRsidOnlyAutoFormat2 ? 1 : 0))
2751  && (nAttributesInPor1 != 0 || nAttributesInPor2 != 0))
2752  {
2753  // _if_ there is one element more either in aRange1 or aRange2
2754  // it _must_ be an RSID-only AUTOFMT, which can be ignored here...
2755  // But if both have RSID-only AUTOFMT they could be equal, no skip!
2756  while (aIter1 != aRange1.second || aIter2 != aRange2.second)
2757  {
2758  // first of all test if there's no gap (before skipping stuff!)
2759  if (aIter1 != aRange1.second && aIter2 != aRange2.second &&
2760  *aIter1->second.first->End() < aIter2->second.first->GetStart())
2761  {
2762  eMerge = DIFFER;
2763  break;
2764  }
2765  // skip it - cannot be equal if bSkipRsidOnlyAutoFormat is set
2766  if (bSkipRsidOnlyAutoFormat
2767  && aIter1 != aRange1.second && aIter1->second.second)
2768  {
2769  assert(DIFFER != eMerge);
2770  eMerge = DIFFER_ONLY_RSID;
2771  ++aIter1;
2772  continue;
2773  }
2774  if (bSkipRsidOnlyAutoFormat
2775  && aIter2 != aRange2.second && aIter2->second.second)
2776  {
2777  assert(DIFFER != eMerge);
2778  eMerge = DIFFER_ONLY_RSID;
2779  ++aIter2;
2780  continue;
2781  }
2782  assert(aIter1 != aRange1.second && aIter2 != aRange2.second);
2783  SwTextAttr const*const p1 = aIter1->second.first;
2784  SwTextAttr const*const p2 = aIter2->second.first;
2785  if (p1->Which() != p2->Which())
2786  {
2787  eMerge = DIFFER;
2788  break;
2789  }
2790  if (!(*p1 == *p2))
2791  {
2792  // fdo#52028: for auto styles, check if they differ only
2793  // in the RSID, which should have no effect on text layout
2794  if (RES_TXTATR_AUTOFMT == p1->Which())
2795  {
2796  const SfxItemSet& rSet1 = *p1->GetAutoFormat().GetStyleHandle();
2797  const SfxItemSet& rSet2 = *p2->GetAutoFormat().GetStyleHandle();
2798 
2799  // sadly SfxItemSet::operator== does not seem to work?
2800  SfxItemIter iter1(rSet1);
2801  SfxItemIter iter2(rSet2);
2802  for (SfxPoolItem const* pItem1 = iter1.GetCurItem(),
2803  * pItem2 = iter2.GetCurItem();
2804  pItem1 && pItem2;
2805  pItem1 = iter1.NextItem(),
2806  pItem2 = iter2.NextItem())
2807  {
2808  if (pItem1->Which() == RES_CHRATR_RSID)
2809  pItem1 = iter1.NextItem();
2810  if (pItem2->Which() == RES_CHRATR_RSID)
2811  pItem2 = iter2.NextItem();
2812  if (!pItem1 && !pItem2)
2813  break;
2814  if (!pItem1 || !pItem2)
2815  {
2816  eMerge = DIFFER;
2817  break;
2818  }
2819  if (pItem1 != pItem2) // all are poolable
2820  {
2821  assert(IsInvalidItem(pItem1) || IsInvalidItem(pItem2) || pItem1->Which() != pItem2->Which() || *pItem1 != *pItem2);
2822  eMerge = DIFFER;
2823  break;
2824  }
2825  if (iter1.IsAtEnd() || iter2.IsAtEnd())
2826  {
2827  eMerge = DIFFER;
2828  break;
2829  }
2830  }
2831  if (DIFFER == eMerge)
2832  break; // outer loop too
2833  else
2834  eMerge = DIFFER_ONLY_RSID;
2835  }
2836  else
2837  {
2838  eMerge = DIFFER;
2839  break;
2840  }
2841  }
2842  ++aIter1;
2843  ++aIter2;
2844  }
2845  }
2846  else
2847  {
2848  eMerge = DIFFER;
2849  }
2850 
2851  if (MATCH == eMerge)
2852  {
2853  // important: delete second range so any IgnoreStart on the first
2854  // range is still valid
2855  // erase all elements with key i + 1
2856  sal_Int32 nNewPortionEnd = 0;
2857  for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
2858  {
2859  SwTextAttr *const p2 = aIter2->second.first;
2860  nNewPortionEnd = *p2->GetEnd();
2861 
2862  const size_t nCountBeforeDelete = Count();
2863  Delete( p2 );
2864 
2865  // robust: check if deletion actually took place before destroying attribute:
2866  if ( Count() < nCountBeforeDelete )
2867  rNode.DestroyAttr( p2 );
2868  }
2869  aPortionMap.erase( aRange2.first, aRange2.second );
2870  ++j;
2871 
2872  // change all attributes with key i
2873  aRange1 = aPortionMap.equal_range( i );
2874  for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
2875  {
2876  SwTextAttr *const p1 = aIter1->second.first;
2877  NoteInHistory( p1 );
2878  p1->SetEnd(nNewPortionEnd);
2879  NoteInHistory( p1, true );
2880  bRet = true;
2881  }
2882 
2883  if (bRet)
2884  {
2885  Resort();
2886  }
2887  }
2888  else
2889  {
2890  // when not merging the ignore flags need to be either set or reset
2891  // (reset too in case one of the autofmts was recently changed)
2892  bool const bSetIgnoreFlag(DIFFER_ONLY_RSID == eMerge);
2893  for (aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1)
2894  {
2895  if (!aIter1->second.second) // already set above, don't change
2896  {
2897  SwTextAttr *const pCurrent(aIter1->second.first);
2898  if (pCurrent->IsFormatIgnoreEnd() != bSetIgnoreFlag)
2899  {
2900  NoteInHistory(pCurrent);
2901  pCurrent->SetFormatIgnoreEnd(bSetIgnoreFlag);
2902  NoteInHistory(pCurrent, true);
2903  }
2904  }
2905  }
2906  for (aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2)
2907  {
2908  if (!aIter2->second.second) // already set above, don't change
2909  {
2910  SwTextAttr *const pCurrent(aIter2->second.first);
2911  if (pCurrent->IsFormatIgnoreStart() != bSetIgnoreFlag)
2912  {
2913  NoteInHistory(pCurrent);
2914  pCurrent->SetFormatIgnoreStart(bSetIgnoreFlag);
2915  NoteInHistory(pCurrent, true);
2916  }
2917  }
2918  }
2919  i = j; // ++i not enough: i + 1 may have been deleted (MATCH)!
2920  ++j;
2921  }
2922  }
2923 
2924  return bRet;
2925 }
2926 
2927 // check if there is already a character format and adjust the sort numbers
2928 static void lcl_CheckSortNumber( const SwpHints& rHints, SwTextCharFormat& rNewCharFormat )
2929 {
2930  const sal_Int32 nHtStart = rNewCharFormat.GetStart();
2931  const sal_Int32 nHtEnd = *rNewCharFormat.GetEnd();
2932  sal_uInt16 nSortNumber = 0;
2933 
2934  for ( size_t i = 0; i < rHints.Count(); ++i )
2935  {
2936  const SwTextAttr* pOtherHt = rHints.Get(i);
2937 
2938  const sal_Int32 nOtherStart = pOtherHt->GetStart();
2939 
2940  if ( nOtherStart > nHtStart )
2941  break;
2942 
2943  if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
2944  {
2945  const sal_Int32 nOtherEnd = *pOtherHt->End();
2946 
2947  if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
2948  {
2949  nSortNumber = static_txtattr_cast<const SwTextCharFormat*>(pOtherHt)->GetSortNumber() + 1;
2950  }
2951  }
2952  }
2953 
2954  if ( nSortNumber > 0 )
2955  rNewCharFormat.SetSortNumber( nSortNumber );
2956 }
2957 
2958 /*
2959  * Try to insert the new hint.
2960  * Depending on the type of the hint, this either always succeeds, or may fail.
2961  * Depending on the type of the hint, other hints may be deleted or
2962  * overwritten.
2963  * The return value indicates successful insertion.
2964  */
2966  SwTextAttr* const pHint,
2967  SwTextNode &rNode,
2968  const SetAttrMode nMode )
2969 {
2970  if ( MAX_HINTS <= Count() ) // we're sorry, this flight is overbooked...
2971  {
2972  OSL_FAIL("hints array full :-(");
2973  return false;
2974  }
2975 
2976  const sal_Int32 *pHtEnd = pHint->GetEnd();
2977  const sal_uInt16 nWhich = pHint->Which();
2978  std::vector<sal_uInt16> aWhichSublist;
2979 
2980  switch( nWhich )
2981  {
2982  case RES_TXTATR_CHARFMT:
2983  {
2984  // Check if character format contains hidden attribute:
2985  const SwCharFormat* pFormat = pHint->GetCharFormat().GetCharFormat();
2986  const SfxPoolItem* pItem;
2987  if ( SfxItemState::SET == pFormat->GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) )
2988  rNode.SetCalcHiddenCharFlags();
2989 
2990  static_txtattr_cast<SwTextCharFormat*>(pHint)->ChgTextNode( &rNode );
2991  break;
2992  }
2993  // #i75430# Recalc hidden flags if necessary
2994  case RES_TXTATR_AUTOFMT:
2995  {
2996  std::shared_ptr<SfxItemSet> const pSet( pHint->GetAutoFormat().GetStyleHandle() );
2997  if (pHint->GetStart() == *pHint->GetEnd())
2998  {
2999  if (pSet->Count() == 1 && pSet->GetItem(RES_CHRATR_RSID, false))
3000  { // empty range RSID-only hints could cause trouble, there's no
3001  rNode.DestroyAttr(pHint); // need for them so don't insert
3002  return false;
3003  }
3004  }
3005  // Check if auto style contains hidden attribute:
3006  const SfxPoolItem* pHiddenItem = CharFormat::GetItem( *pHint, RES_CHRATR_HIDDEN );
3007  if ( pHiddenItem )
3008  rNode.SetCalcHiddenCharFlags();
3009 
3010  // fdo#71556: populate aWhichFormatAttr member of SwMsgPoolItem
3011  const sal_uInt16 *pRanges = pSet->GetRanges();
3012  while( (*pRanges) != 0 )
3013  {
3014  const sal_uInt16 nBeg = *pRanges;
3015  ++pRanges;
3016  const sal_uInt16 nEnd = *pRanges;
3017  ++pRanges;
3018  for( sal_uInt16 nSubElem = nBeg; nSubElem <= nEnd; ++nSubElem )
3019  if( pSet->HasItem( nSubElem ) )
3020  aWhichSublist.push_back( nSubElem );
3021  }
3022  break;
3023  }
3024  case RES_TXTATR_INETFMT:
3025  static_txtattr_cast<SwTextINetFormat*>(pHint)->InitINetFormat(rNode);
3026  break;
3027 
3028  case RES_TXTATR_FIELD:
3029  case RES_TXTATR_ANNOTATION:
3030  case RES_TXTATR_INPUTFIELD:
3031  {
3032  SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
3033  bool bDelFirst = nullptr != pTextField->GetpTextNode();
3034  pTextField->ChgTextNode( &rNode );
3035  SwDoc* pDoc = rNode.GetDoc();
3036  const SwField* pField = pTextField->GetFormatField().GetField();
3037 
3038  if( !pDoc->getIDocumentFieldsAccess().IsNewFieldLst() )
3039  {
3040  // certain fields must update the SwDoc's calculation flags
3041  switch( pField->GetTyp()->Which() )
3042  {
3043  case SwFieldIds::Database:
3044  case SwFieldIds::SetExp:
3047  case SwFieldIds::DbNumSet:
3048  case SwFieldIds::DbNextSet:
3049  {
3050  if( bDelFirst )
3051  pDoc->getIDocumentFieldsAccess().InsDelFieldInFieldLst(false, *pTextField);
3052  if( rNode.GetNodes().IsDocNodes() )
3053  pDoc->getIDocumentFieldsAccess().InsDelFieldInFieldLst(true, *pTextField);
3054  }
3055  break;
3056  case SwFieldIds::Dde:
3057  if( rNode.GetNodes().IsDocNodes() )
3058  static_cast<SwDDEFieldType*>(pField->GetTyp())->IncRefCnt();
3059  break;
3060  default: break;
3061  }
3062  }
3063 
3064  // insert into real document's nodes-array?
3065  if( rNode.GetNodes().IsDocNodes() )
3066  {
3067  bool bInsFieldType = false;
3068  switch( pField->GetTyp()->Which() )
3069  {
3070  case SwFieldIds::SetExp:
3071  bInsFieldType = static_cast<SwSetExpFieldType*>(pField->GetTyp())->IsDeleted();
3072  if( nsSwGetSetExpType::GSE_SEQ & static_cast<SwSetExpFieldType*>(pField->GetTyp())->GetType() )
3073  {
3074  // register the field at its FieldType before setting
3075  // the sequence reference number!
3076  SwSetExpFieldType* pFieldType = static_cast<SwSetExpFieldType*>(
3077  pDoc->getIDocumentFieldsAccess().InsertFieldType( *pField->GetTyp() ) );
3078  if( pFieldType != pField->GetTyp() )
3079  {
3080  SwFormatField* pFormatField = const_cast<SwFormatField*>(&pTextField->GetFormatField());
3081  pFormatField->RegisterToFieldType( *pFieldType );
3082  pFormatField->GetField()->ChgTyp( pFieldType );
3083  }
3084  pFieldType->SetSeqRefNo( *const_cast<SwSetExpField*>(static_cast<const SwSetExpField*>(pField)) );
3085  }
3086  break;
3087  case SwFieldIds::User:
3088  bInsFieldType = static_cast<SwUserFieldType*>(pField->GetTyp())->IsDeleted();
3089  break;
3090 
3091  case SwFieldIds::Dde:
3092  if( pDoc->getIDocumentFieldsAccess().IsNewFieldLst() )
3093  static_cast<SwDDEFieldType*>(pField->GetTyp())->IncRefCnt();
3094  bInsFieldType = static_cast<SwDDEFieldType*>(pField->GetTyp())->IsDeleted();
3095  break;
3096 
3097  case SwFieldIds::Postit:
3098  if ( pDoc->GetDocShell() )
3099  {
3100  pDoc->GetDocShell()->Broadcast( SwFormatFieldHint(
3102  }
3103  break;
3104  default: break;
3105  }
3106  if( bInsFieldType )
3107  pDoc->getIDocumentFieldsAccess().InsDeletedFieldType( *pField->GetTyp() );
3108  }
3109  }
3110  break;
3111  case RES_TXTATR_FTN :
3112  static_cast<SwTextFootnote*>(pHint)->ChgTextNode( &rNode );
3113  break;
3114  case RES_TXTATR_REFMARK:
3115  static_txtattr_cast<SwTextRefMark*>(pHint)->ChgTextNode( &rNode );
3116  if( rNode.GetNodes().IsDocNodes() )
3117  {
3118  // search for a reference with the same name
3119  SwTextAttr* pTmpHt;
3120  for( size_t n = 0, nEnd = Count(); n < nEnd; ++n )
3121  {
3122  const sal_Int32 *pTmpHtEnd;
3123  const sal_Int32 *pTmpHintEnd;
3124  if (RES_TXTATR_REFMARK == (pTmpHt = Get(n))->Which() &&
3125  pHint->GetAttr() == pTmpHt->GetAttr() &&
3126  nullptr != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
3127  nullptr != ( pTmpHintEnd = pHint->GetEnd() ) )
3128  {
3130  pTmpHt->GetStart(), *pTmpHtEnd,
3131  pHint->GetStart(), *pTmpHintEnd );
3132  bool bDelOld = true, bChgStart = false, bChgEnd = false;
3133  switch( eCmp )
3134  {
3136  case SwComparePosition::Behind: bDelOld = false; break;
3137 
3138  case SwComparePosition::Outside: bChgStart = bChgEnd = true; break;
3139 
3141  case SwComparePosition::OverlapBefore: bChgStart = true; break;
3143  case SwComparePosition::OverlapBehind: bChgEnd = true; break;
3144  default: break;
3145  }
3146 
3147  if( bChgStart )
3148  {
3149  pHint->SetStart( pTmpHt->GetStart() );
3150  }
3151  if( bChgEnd )
3152  pHint->SetEnd(*pTmpHtEnd);
3153 
3154  if( bDelOld )
3155  {
3156  NoteInHistory( pTmpHt );
3157  rNode.DestroyAttr( Cut( n-- ) );
3158  --nEnd;
3159  }
3160  }
3161  }
3162  }
3163  break;
3164  case RES_TXTATR_TOXMARK:
3165  static_txtattr_cast<SwTextTOXMark*>(pHint)->ChgTextNode( &rNode );
3166  break;
3167 
3168  case RES_TXTATR_CJK_RUBY:
3169  static_txtattr_cast<SwTextRuby*>(pHint)->InitRuby(rNode);
3170  break;
3171 
3172  case RES_TXTATR_META:
3173  case RES_TXTATR_METAFIELD:
3174  static_txtattr_cast<SwTextMeta *>(pHint)->ChgTextNode( &rNode );
3175  break;
3176 
3177  case RES_CHRATR_HIDDEN:
3178  rNode.SetCalcHiddenCharFlags();
3179  break;
3180  }
3181 
3182  if( SetAttrMode::DONTEXPAND & nMode )
3183  pHint->SetDontExpand( true );
3184 
3185  // special handling for SwTextAttrs without end:
3186  // 1) they cannot overlap
3187  // 2) if two fields are adjacent, they must not be merged into one
3188  // this is guaranteed by inserting a CH_TXTATR_* into the paragraph text!
3189  sal_Int32 nHtStart = pHint->GetStart();
3190  if( !pHtEnd )
3191  {
3192  Insert( pHint );
3193  NoteInHistory(pHint, true);
3194  CalcFlags();
3195 #ifdef DBG_UTIL
3196  if( !rNode.GetDoc()->IsInReading() )
3197  CHECK;
3198 #endif
3199  // ... and notify listeners
3200  if(rNode.HasWriterListeners())
3201  {
3202  SwUpdateAttr aHint(
3203  nHtStart,
3204  nHtStart,
3205  nWhich);
3206 
3207  rNode.ModifyNotification(nullptr,&aHint);
3208  }
3209 
3210  return true;
3211  }
3212 
3213  // from here on, pHint is known to have an end index!
3214 
3215  if( *pHtEnd < nHtStart )
3216  {
3217  assert(*pHtEnd >= nHtStart);
3218 
3219  // just swap the nonsense:
3220  pHint->SetStart(*pHtEnd);
3221  pHint->SetEnd(nHtStart);
3222  nHtStart = pHint->GetStart();
3223  }
3224 
3225  // I need this value later on for notification but the pointer may become invalid
3226  const sal_Int32 nHintEnd = *pHtEnd;
3227  const bool bNoHintAdjustMode = bool(SetAttrMode::NOHINTADJUST & nMode);
3228 
3229  // handle nesting attributes: inserting may fail due to overlap!
3230  if (pHint->IsNesting())
3231  {
3232  const bool bRet(
3233  TryInsertNesting(rNode, *static_txtattr_cast<SwTextAttrNesting*>(pHint)));
3234  if (!bRet) return false;
3235  }
3236  // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
3237  // These attributes may be inserted directly.
3238  // Also attributes without length may be inserted directly.
3239  // SETATTR_NOHINTADJUST is set e.g., during undo.
3240  // Portion building in not necessary during XML import.
3241  else if ( !bNoHintAdjustMode &&
3242  !pHint->IsOverlapAllowedAttr() &&
3243  !rNode.GetDoc()->IsInXMLImport() &&
3244  ( RES_TXTATR_AUTOFMT == nWhich ||
3245  RES_TXTATR_CHARFMT == nWhich ) )
3246  {
3247  assert( nWhich != RES_TXTATR_AUTOFMT ||
3248  static_cast<const SwFormatAutoFormat&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
3249  &rNode.GetDoc()->GetAttrPool());
3250 
3251  BuildPortions( rNode, *pHint, nMode );
3252 
3253  if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
3254  MergePortions( rNode );
3255  }
3256  else
3257  {
3258  // There may be more than one character style at the current position.
3259  // Take care of the sort number.
3260  // Special case ruby portion: During import, the ruby attribute is set
3261  // multiple times
3262  // Special case hyperlink: During import, the ruby attribute is set
3263  // multiple times
3264  // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
3265  // character attributes directly
3266  if ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode )
3267  {
3268  BuildPortions( rNode, *pHint, nMode );
3269  }
3270  else
3271  {
3272  // #i82989# Check sort numbers in NoHintAdjustMode
3273  if ( RES_TXTATR_CHARFMT == nWhich )
3274  lcl_CheckSortNumber(*this, *static_txtattr_cast<SwTextCharFormat*>(pHint));
3275 
3276  Insert( pHint );
3277  NoteInHistory( pHint, true );
3278  }
3279  }
3280 
3281  // ... and notify listeners
3282  if ( rNode.HasWriterListeners() )
3283  {
3284  SwUpdateAttr aHint(nHtStart, nHintEnd, nWhich, aWhichSublist);
3285 
3286  rNode.ModifyNotification( nullptr, &aHint );
3287  }
3288 
3289 #ifdef DBG_UTIL
3290  if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
3291  CHECK;
3292 #endif
3293 
3294  return true;
3295 }
3296 
3297 void SwpHints::DeleteAtPos( const size_t nPos )
3298 {
3299  assert(!m_bStartMapNeedsSorting && "deleting at pos and the list needs sorting?");
3300 
3301  SwTextAttr *pHint = Get(nPos);
3302  assert( pHint->m_pHints == this );
3303  // ChainDelete( pHint );
3304  NoteInHistory( pHint );
3305 
3306  // optimization: nPos is the position in the Starts array
3307  SwTextAttr *pHt = m_HintsByStart[ nPos ];
3308  m_HintsByStart.erase( m_HintsByStart.begin() + nPos );
3309 
3311  ResortStartMap();
3313  ResortEndMap();
3315  ResortWhichMap();
3316 
3317  auto findIt = std::lower_bound(m_HintsByEnd.begin(), m_HintsByEnd.end(), pHt, CompareSwpHtEnd());
3318  assert(*findIt == pHt);
3319  m_HintsByEnd.erase(findIt);
3320 
3321  auto findIt2 = std::lower_bound(m_HintsByWhichAndStart.begin(), m_HintsByWhichAndStart.end(), pHt, CompareSwpHtWhichStart());
3322  assert(*findIt2 == pHt);
3323  m_HintsByWhichAndStart.erase(findIt2);
3324 
3325  pHt->m_pHints = nullptr;
3326 
3327  if( pHint->Which() == RES_TXTATR_FIELD )
3328  {
3329  SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
3330  const SwFieldType* pFieldTyp = pTextField->GetFormatField().GetField()->GetTyp();
3331  if( SwFieldIds::Dde == pFieldTyp->Which() )
3332  {
3333  const SwTextNode* pNd = pTextField->GetpTextNode();
3334  if( pNd && pNd->GetNodes().IsDocNodes() )
3335  const_cast<SwDDEFieldType*>(static_cast<const SwDDEFieldType*>(pFieldTyp))->DecRefCnt();
3336  pTextField->ChgTextNode(nullptr);
3337  }
3338  else if (m_bHiddenByParaField
3339  && m_rParent.FieldCanHideParaWeight(pFieldTyp->Which()))
3340  {
3341  m_bCalcHiddenParaField = true;
3342  }
3343  }
3344  else if ( pHint->Which() == RES_TXTATR_ANNOTATION )
3345  {
3346  SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
3347  const_cast<SwFormatField&>(pTextField->GetFormatField()).Broadcast(
3349  }
3350 
3351  CalcFlags();
3352  CHECK_NOTMERGED; // called from BuildPortions
3353 }
3354 
3357 void SwpHints::Delete( SwTextAttr const * pTextHt )
3358 {
3359  const size_t nPos = GetIndexOf( pTextHt );
3360  assert(SAL_MAX_SIZE != nPos);
3361  if( SAL_MAX_SIZE != nPos )
3362  DeleteAtPos( nPos );
3363 }
3364 
3365 void SwTextNode::ClearSwpHintsArr( bool bDelFields )
3366 {
3367  if ( HasHints() )
3368  {
3369  size_t nPos = 0;
3370  while ( nPos < m_pSwpHints->Count() )
3371  {
3372  SwTextAttr* pDel = m_pSwpHints->Get( nPos );
3373  bool bDel = false;
3374 
3375  switch( pDel->Which() )
3376  {
3377  case RES_TXTATR_FLYCNT:
3378  case RES_TXTATR_FTN:
3379  break;
3380 
3381  case RES_TXTATR_FIELD:
3382  case RES_TXTATR_ANNOTATION:
3383  case RES_TXTATR_INPUTFIELD:
3384  if( bDelFields )
3385  bDel = true;
3386  break;
3387  default:
3388  bDel = true; break;
3389  }
3390 
3391  if( bDel )
3392  {
3393  m_pSwpHints->DeleteAtPos( nPos );
3394  DestroyAttr( pDel );
3395  }
3396  else
3397  ++nPos;
3398  }
3399  }
3400 }
3401 
3402 LanguageType SwTextNode::GetLang( const sal_Int32 nBegin, const sal_Int32 nLen,
3403  sal_uInt16 nScript ) const
3404 {
3406 
3407  if ( ! nScript )
3408  {
3409  nScript = g_pBreakIt->GetRealScriptOfText( m_Text, nBegin );
3410  }
3411 
3412  // #i91465# Consider nScript if pSwpHints == 0
3413  const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
3414 
3415  if ( HasHints() )
3416  {
3417  const sal_Int32 nEnd = nBegin + nLen;
3418  const size_t nSize = m_pSwpHints->Count();
3419  for ( size_t i = 0; i < nSize; ++i )
3420  {
3421  const SwTextAttr *pHt = m_pSwpHints->Get(i);
3422  const sal_Int32 nAttrStart = pHt->GetStart();
3423  if( nEnd < nAttrStart )
3424  break;
3425 
3426  const sal_uInt16 nWhich = pHt->Which();
3427 
3428  if( nWhichId == nWhich ||
3429  ( ( pHt->IsCharFormatAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFormat::IsItemIncluded( nWhichId, pHt ) ) )
3430  {
3431  const sal_Int32 *pEndIdx = pHt->End();
3432  // do the attribute and the range overlap?
3433  if( !pEndIdx )
3434  continue;
3435  if( nLen )
3436  {
3437  if( nAttrStart >= nEnd || nBegin >= *pEndIdx )
3438  continue;
3439  }
3440  else if( nBegin != nAttrStart || ( nAttrStart != *pEndIdx && nBegin ))
3441  {
3442  if( nAttrStart >= nBegin )
3443  continue;
3444  if( pHt->DontExpand() ? nBegin >= *pEndIdx : nBegin > *pEndIdx)
3445  continue;
3446  }
3447  const SfxPoolItem* pItem = CharFormat::GetItem( *pHt, nWhichId );
3448  const LanguageType nLng = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
3449 
3450  // does the attribute completely cover the range?
3451  if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
3452  nRet = nLng;
3453  else if( LANGUAGE_DONTKNOW == nRet )
3454  nRet = nLng; // partial overlap, the first one wins
3455  }
3456  }
3457  }
3458  if( LANGUAGE_DONTKNOW == nRet )
3459  {
3460  nRet = static_cast<const SvxLanguageItem&>(GetSwAttrSet().Get( nWhichId )).GetLanguage();
3461  if( LANGUAGE_DONTKNOW == nRet )
3462  nRet = GetAppLanguage();
3463  }
3464  return nRet;
3465 }
3466 
3468 {
3470  switch ( rAttr.Which() )
3471  {
3472  case RES_TXTATR_REFMARK:
3473  case RES_TXTATR_TOXMARK:
3474  case RES_TXTATR_ANNOTATION:
3475  cRet = CH_TXTATR_INWORD;
3476  break;
3477 
3478  case RES_TXTATR_FIELD:
3479  case RES_TXTATR_FLYCNT:
3480  case RES_TXTATR_FTN:
3481  case RES_TXTATR_META:
3482  case RES_TXTATR_METAFIELD:
3483  {
3484  cRet = CH_TXTATR_BREAKWORD;
3485  }
3486  break;
3487 
3488  default:
3489  assert(!"GetCharOfTextAttr: unknown attr");
3490  break;
3491  }
3492  return cRet;
3493 }
3494 
3495 /* 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:134
Instances of SwFields and those derived from it occur 0 to n times.
Definition: fldbas.hxx:234
bool isUNKNOWNATR(const sal_uInt16 nWhich)
Definition: hintids.hxx:478
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:270
void DeleteAtPos(size_t nPos)
Definition: thints.cxx:3297
virtual std::shared_ptr< SfxItemSet > getAutomaticStyle(const SfxItemSet &rSet, SwAutoStyleFamily eFamily, const OUString *pParentName=nullptr)=0
#define RES_CHRATR_WEIGHT
Definition: hintids.hxx:177
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:413
sal_uLong GetIndex() const
Definition: node.hxx:282
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:217
void SetDontExpand(bool bDontExpand)
Definition: txatbase.hxx:171
The shared part of a user field.
Definition: usrfld.hxx:35
void DelSoftHyph(const sal_Int32 nStart, const sal_Int32 nEnd)
Definition: thints.cxx:1780
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:70
size_t GetIndexOf(const SwTextAttr *pHt) const
Definition: ndhints.cxx:465
bool IsNesting() const
Definition: txatbase.hxx:100
bool m_bFootnote
footnotes
Definition: ndhints.hxx:89
long GetFirstLineIndent() const
virtual void ModifyNotification(const SfxPoolItem *pOld, const SfxPoolItem *pNew) override
Definition: node.hxx:475
sal_uLong StartOfSectionIndex() const
Definition: node.hxx:673
The inserted item is a copy – intended for use in ndtxt.cxx.
bool isCHRATR(const sal_uInt16 nWhich)
Definition: hintids.hxx:436
SwComparePosition ComparePosition(const T &rStt1, const T &rEnd1, const T &rStt2, const T &rEnd2)
Definition: pam.hxx:77
#define RES_CHRATR_LANGUAGE
Definition: hintids.hxx:172
#define RES_TXTATR_CJK_RUBY
Definition: hintids.hxx:237
#define RES_TXTATR_METAFIELD
Definition: hintids.hxx:233
SwDocShell * GetDocShell()
Definition: doc.hxx:1346
bool FieldHidesPara(const SwField &rField) const
Definition: ndtxt.hxx:715
virtual bool SetAttr(const SfxPoolItem &) override
overriding to handle change of certain paragraph attributes
Definition: ndtxt.cxx:4883
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:218
bool isTXTATR_WITHEND(const sal_uInt16 nWhich)
Definition: hintids.hxx:440
bool isTXTATR(const sal_uInt16 nWhich)
Definition: hintids.hxx:450
virtual SfxPoolItem * Clone(SfxItemPool *pPool=nullptr) const =0
const SwNumFormat * GetNumFormat(sal_uInt16 i) const
Definition: number.cxx:87
SwNodeIndex nNode
Definition: pam.hxx:37
#define RES_CHRATR_CJK_POSTURE
Definition: hintids.hxx:187
const SfxPoolItem * GetItem(const SwTextAttr &rAttr, sal_uInt16 nWhich)
Extracts pool item of type nWhich from rAttr.
Definition: atrstck.cxx:157
virtual const sal_Int32 * GetEnd() const
end position
Definition: txatbase.cxx:48
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:273
sal_uIntPtr sal_uLong
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:280
LanguageType GetLanguage(SfxItemSet const &aSet, sal_uInt16 nLangWhichId)
Definition: langhelper.cxx:399
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:1599
Pos1 completely contained in Pos2.
sal_Int64 n
OUString GetListId() const
Definition: ndtxt.cxx:4369
Definition: doc.hxx:185
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:1730
void InvalidateItem(sal_uInt16 nWhich)
#define RES_TXTATR_UNKNOWN_CONTAINER
Definition: hintids.hxx:238
void SetFormatIgnoreStart(bool bFlag)
Definition: txatbase.hxx:104
#define RES_CHRATR_CJK_WEIGHT
Definition: hintids.hxx:188
static bool lcl_IsIgnoredCharFormatForBullets(const sal_uInt16 nWhich)
Definition: thints.cxx:1807
sal_uInt16 FirstWhich()
bool HasDummyChar() const
Definition: txatbase.hxx:101
void SetTextLeft(const long nL, const sal_uInt16 nProp=100)
bool IsAtEnd() const
void TryDeleteSwpHints()
Definition: ndtxt.hxx:828
SwTextNode * GetpTextNode() const
Definition: txtfld.hxx:49
SW_DLLPUBLIC void ResortWhichMap() const
Definition: ndhints.cxx:440
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:4403
std::vector< SwTextAttrNesting * > NestList_t
Definition: thints.cxx:254
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:143
void SetFormatIgnoreEnd(bool bFlag)
Definition: txatbase.hxx:105
#define RES_TXTATR_CHARFMT
Definition: hintids.hxx:236
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:570
bool HasWriterListeners() const
Definition: calbck.hxx:208
#define RES_TXTATR_END
Definition: hintids.hxx:252
The root element of a Writer document layout.
Definition: rootfrm.hxx:79
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:4088
sal_uInt16 GetRealScriptOfText(const OUString &rText, sal_Int32 nPos) const
Definition: breakit.cxx:83
bool IsInHeaderFooter(const SwNodeIndex &rIdx) const
Definition: doclay.cxx:1542
#define CHECK
Definition: thints.cxx:81
sal_uInt16 NextWhich()
#define CHAR_SOFTHYPHEN
Definition: swtypes.hxx:174
bool TryInsertHint(SwTextAttr *const pHint, SwTextNode &rNode, const SetAttrMode nMode=SetAttrMode::DEFAULT)
try to insert the hint
Definition: thints.cxx:2965
Pos1 end touches at Pos2 start.
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:356
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:136
#define RES_TXTATR_META
Definition: hintids.hxx:232
static bool TextAttrContains(const sal_Int32 nPos, const SwTextAttrEnd *const pAttr)
Definition: thints.cxx:113
sal_uInt16 sal_Unicode
#define RES_CHRATR_END
Definition: hintids.hxx:208
const SfxPoolItem * NextItem()
const SwCharFormat * GetDfltCharFormat() const
Definition: doc.hxx:747
#define CH_TXTATR_INWORD
Definition: hintids.hxx:137
SwTableNode * GetTableNode()
Definition: node.hxx:599
void NoteInHistory(SwTextAttr *pAttr, const bool bNew=false)
records a new attribute in m_pHistory.
Definition: thints.cxx:2650
static void lcl_MergeAttr_ExpandChrFormat(SfxItemSet &rSet, const SfxPoolItem &rAttr)
Definition: thints.cxx:2022
SwIndex nContent
Definition: pam.hxx:38
SwpHints(const SwTextNode &rParent)
Definition: thints.cxx:89
void SetSortNumber(sal_uInt16 nSortNumber)
Definition: txtatr.hxx:49
virtual void InsDelFieldInFieldLst(bool bIns, const SwTextField &rField)=0
void DestroyAttr(SwTextAttr *pAttr)
Definition: thints.cxx:1147
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:425
#define CH_TXT_ATR_INPUTFIELDSTART
Definition: hintids.hxx:140
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:704
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:1255
#define RES_TXTATR_WITHEND_END
Definition: hintids.hxx:240
const SwFormatField & GetFormatField() const
Definition: txatbase.hxx:191
SwRegHistory * m_pHistory
for Undo
Definition: ndhints.hxx:80
#define RES_CHRATR_CASEMAP
Definition: hintids.hxx:163
Pos1 before Pos2.
void ChgTextNode(SwTextNode *pNew)
Definition: txtinet.hxx:49
#define RES_TXTATR_BEGIN
Definition: hintids.hxx:211
size_type size() const
void SetCalcHiddenCharFlags() const
Definition: ndtxt.hxx:727
CopyOrNewType
Definition: ndhints.hxx:33
::cppu::OWeakObject & m_rParent
sal_Unicode GetCharOfTextAttr(const SwTextAttr &rAttr)
Definition: thints.cxx:3467
virtual SwFieldType * ChgTyp(SwFieldType *)
Set new type (used for copying among documents).
Definition: fldbas.cxx:330
SwCharFormat * GetCharFormat() const
Definition: numrule.hxx:73
#define RES_CHRATR_COLOR
Definition: hintids.hxx:165
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:443
OUString GetFieldContent() const
Definition: atrfld.cxx:586
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:356
Style of a layout element.
Definition: frmfmt.hxx:57
size_t Count() const
Definition: ndhints.hxx:142
#define RES_CHRATR_BACKGROUND
Definition: hintids.hxx:183
#define RES_ANCHOR
Definition: hintids.hxx:304
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:2655
bool m_bHiddenByParaField
Definition: ndhints.hxx:88
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
Pos1 start touches at Pos2 end.
bool m_bCalcHiddenParaField
Definition: ndhints.hxx:85
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
#define RES_TXTATR_FTN
Definition: hintids.hxx:246
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
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:2095
void Delete(SwTextAttr const *pTextHt)
Delete the given Hint. The Hint must actually be in the array!
Definition: thints.cxx:3357
Count
SetAttrMode
Definition: swtypes.hxx:143
bool HasContent() const
Definition: txatbase.hxx:106
SW_DLLPUBLIC void ResortEndMap() const
Definition: ndhints.cxx:433
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
int i
const SwTextInputField * GetOverlappingInputField(const SwTextAttr &rTextAttr) const
Definition: ndtxt.cxx:1737
FlyAnchors.
Definition: fmtanchr.hxx:34
sal_uInt16 Count() const
void Insert(SwTextAttr *pHt)
Definition: ndhints.cxx:146
void DelFrames(SwRootFrame const *pLayout)
Method deletes all views of document for the node.
Definition: node.cxx:1345
SwDoc * GetDoc()
Definition: node.hxx:702
bool IsEnumeration() const
Definition: number.cxx:227
Force hint expand (only matters for hints with CH_TXTATR).
Internet normal.
Definition: poolfmt.hxx:121
Marks a character position inside a document model node.
Definition: index.hxx:37
const SfxItemSet * GetItemSet(const SfxPoolItem &rAttr)
Returns the item set associated with a character/inet/auto style.
Definition: atrstck.cxx:133
#define RES_CHRATR_BEGIN
Definition: hintids.hxx:162
SW_DLLPUBLIC void ResortStartMap() const
Definition: ndhints.cxx:426
virtual void InsDeletedFieldType(SwFieldType &)=0
sal_uInt16 GetWhichOfScript(sal_uInt16 nWhich, sal_uInt16 nScript)
Definition: hints.cxx:195
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:2429
SwNumRule * GetNumRule(bool bInParent=true) const
Returns numbering rule of this text node.
Definition: ndtxt.cxx:2804
#define LANGUAGE_DONTKNOW
sal_uInt16 const aCharAutoFormatSetRange[]
Definition: init.cxx:252
#define RES_CHRATR_UNDERLINE
Definition: hintids.hxx:176
bool IsItemize() const
Definition: number.cxx:235
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
Definition: format.cxx:396
#define RES_TXTATR_TOXMARK
Definition: hintids.hxx:231
#define RES_CHRATR_ESCAPEMENT
Definition: hintids.hxx:168
Marks a node in the document model.
Definition: ndindex.hxx:31
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:693
T static_txtattr_cast(S *s)
Definition: txatbase.hxx:237
bool HasSwAttrSet() const
Definition: node.hxx:444
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:119
SwStartNode * GetStartNode()
Definition: node.hxx:591
SvxNumPositionAndSpaceMode GetPositionAndSpaceMode() const
bool m_bEndMapNeedsSorting
Definition: ndhints.hxx:93
#define RES_TXTATR_INETFMT
Definition: hintids.hxx:235
attention: NOHINTADJUST prevents MergePortions! when using this need to pay attention to ignore start...
SfxItemPool * GetPool() const
bool IsInReading() const
Definition: doc.hxx:951
void RegisterToFieldType(SwFieldType &)
Definition: atrfld.cxx:170
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:404
void ChgTextNode(SwTextNode *pNew)
Definition: txtfld.hxx:58
SwFieldType * GetTyp() const
Definition: fldbas.hxx:383
void DeleteAttribute(SwTextAttr *const pTextAttr)
delete the attribute pTextAttr
Definition: thints.cxx:1666
#define RES_LR_SPACE
Definition: hintids.hxx:291
const_iterator begin() const
void NotifyClients(const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue)
Definition: calbck.cxx:167
long GetIndentAt() const
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:458
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:78
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:77
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:2659
OUString InsertText(const OUString &rStr, const SwIndex &rIdx, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
insert text content
Definition: ndtxt.cxx:2276
void ChangeNodeIndex(sal_uLong nNew)
Definition: rolbck.hxx:429
void ClearSwpHintsArr(bool bDelFields)
Definition: thints.cxx:3365
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
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:1704
void AddHint(SwTextAttr *pHt, const bool bNew)
Definition: rolbck.cxx:1368
#define CH_TXT_ATR_INPUTFIELDEND
Definition: hintids.hxx:141
void Set(sal_uInt16 i, const SwNumFormat *)
Definition: number.cxx:585
#define RES_TXTATR_FIELD
Definition: hintids.hxx:244
void SetHiddenByParaField(const bool bNew) const
Definition: ndhints.hxx:111
const SwGetSetExpType GSE_SEQ
Sequence.
Definition: fldbas.hxx:198
SwCharFormat * GetCharFormat() const
Definition: fchrfmt.hxx:70
void SetCharFormat(SwCharFormat *)
Definition: number.cxx:271
#define RES_TXTATR_AUTOFMT
Definition: hintids.hxx:234
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:67
void SetTextFirstLineOfst(const short nF, const sal_uInt16 nProp=100)
SAL_DLLPRIVATE void InitINetFormat(SwTextNode &rNode)
Definition: thints.cxx:210
std::deque< AttacherIndex_Impl > aIndex
void TryCharSetExpandToNum(const SfxItemSet &pCharSet)
Definition: thints.cxx:1820
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)
#define RES_DRAWFRMFMT
Definition: hintids.hxx:372
Pos1 overlaps Pos2 at the end.
#define RES_CHRATR_POSTURE
Definition: hintids.hxx:173
virtual SwFieldType * InsertFieldType(const SwFieldType &)=0
#define RES_CHRATR_CTL_WEIGHT
Definition: hintids.hxx:193
#define RES_CHRATR_CTL_POSTURE
Definition: hintids.hxx:192
static bool isSelfNestable(const sal_uInt16 nWhich)
Definition: thints.cxx:155
#define RES_TXTATR_ANNOTATION
Definition: hintids.hxx:247
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:960
LanguageType GetAppLanguage()
Definition: init.cxx:729
SwNodes & GetNodes()
Definition: doc.hxx:403
sal_uInt16 const aCharFormatSetRange[]
Definition: init.cxx:245
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:1797
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:2074
LanguageType GetLang(const sal_Int32 nBegin, const sal_Int32 nLen=0, sal_uInt16 nScript=0) const
Definition: thints.cxx:3402
static void Destroy(SwTextAttr *pToDestroy, SfxItemPool &rPool)
destroy instance
Definition: txatbase.cxx:58
const sal_Int32 * End() const
Definition: txatbase.hxx:148
::sw::MetaFieldManager & GetMetaFieldManager()
Definition: doc.cxx:127
static const size_t MAX_HINTS
Definition: ndhints.hxx:74
static void lcl_MergeAttr(SfxItemSet &rSet, const SfxPoolItem &rAttr)
Definition: thints.cxx:2000
void ChgTextNode(SwTextNode *pNew)
Definition: txtatr.hxx:89
bool CalcHiddenParaField() const
Definition: thints.cxx:2613
bool IsHideRedlines() const
Replacement for sw::DocumentRedlineManager::GetRedlineFlags() (this is layout-level redline hiding)...
Definition: rootfrm.hxx:416
#define RES_TXTATR_FLYCNT
Definition: hintids.hxx:245
#define RES_TXTATR_REFMARK
Definition: hintids.hxx:230
const SwAttrSet & GetSwAttrSet() const
Does node has already its own auto-attributes? Access to SwAttrSet.
Definition: node.hxx:723
virtual void CallSwClientNotify(const SfxHint &rHint) const override
Definition: calbck.cxx:376
bool InsertHint(SwTextAttr *const pAttr, const SetAttrMode nMode=SetAttrMode::DEFAULT)
Insert pAttr into hints array.
Definition: thints.cxx:1290
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:148
#define RES_CHRATR_HIDDEN
Definition: hintids.hxx:199
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:177
bool IsInDtor() const
Definition: doc.hxx:398
bool DontExpand() const
Definition: txatbase.hxx:92
SwFootnoteIdxs & GetFootnoteIdxs()
Definition: doc.hxx:628
SwFrameFormat * GetFrameFormat() const
Definition: fmtflcnt.hxx:45
#define RES_CHRATR_CROSSEDOUT
Definition: hintids.hxx:167
Reference< XModel > xModel
bool IsDocNodes() const
Is the NodesArray the regular one of Doc? (and not the UndoNds, ...) Implementation in doc...
Definition: nodes.cxx:2313
#define INVALID_POOL_ITEM
void CalcFlags()
Definition: thints.cxx:2584
SwFormatColl * GetFormatColl() const
Definition: node.hxx:447
const SwFormatAutoFormat & GetAutoFormat() const
Definition: txatbase.hxx:185
int FieldCanHideParaWeight(SwFieldIds eFieldId) const
Definition: ndtxt.hxx:711
std::unique_ptr< SwpHints > m_pSwpHints
May be 0.
Definition: ndtxt.hxx:92
bool IsInList() const
Definition: ndtxt.cxx:4335
Pos1 behind Pos2.
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:2495
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:730
static void lcl_CheckSortNumber(const SwpHints &rHints, SwTextCharFormat &rNewCharFormat)
Definition: thints.cxx:2928
IStyleAccess & GetIStyleAccess()
Definition: doc.hxx:751
virtual bool IsNewFieldLst() const =0
#define RES_TXTATR_INPUTFIELD
Definition: hintids.hxx:239
SwFieldIds Which() const
Definition: fldbas.hxx:266
Merge GetRedlineMergeFlag() const
Definition: node.hxx:97
bool IsFormatIgnoreStart() const
Definition: txatbase.hxx:102
OUString m_Text
Definition: ndtxt.hxx:97
std::vector< SwTextAttr * > m_HintsByWhichAndStart
Definition: ndhints.hxx:78
IStyleAccess & getIDocumentStyleAccess()
Provides access to the document automatic styles interface.
Definition: node.cxx:2067
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:1161
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
sal_uInt16 nPos
bool IsInXMLImport() const
Definition: doc.hxx:967
const SfxPoolItem * GetCurItem() const
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1313
SwComparePosition
Definition: pam.hxx:64
bool HasHints() const
Definition: ndtxt.hxx:220
size_type erase(const Value &x)
SwpHints & GetOrCreateSwpHints()
Definition: ndtxt.hxx:819
#define RES_CHRATR_RSID
Definition: hintids.hxx:201
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