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