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