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