Line data Source code
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 <hintids.hxx>
21 : #include <sot/factory.hxx>
22 : #include <editeng/xmlcnitm.hxx>
23 : #include <svl/whiter.hxx>
24 : #include <svl/itemiter.hxx>
25 : #include <svl/stylepool.hxx>
26 : #include <editeng/fontitem.hxx>
27 : #include <editeng/langitem.hxx>
28 : #include <editeng/emphasismarkitem.hxx>
29 : #include <editeng/charscaleitem.hxx>
30 : #include <editeng/charrotateitem.hxx>
31 : #include <editeng/lrspitem.hxx>
32 : #include <txtinet.hxx>
33 : #include <txtflcnt.hxx>
34 : #include <fmtfld.hxx>
35 : #include <fmtrfmrk.hxx>
36 : #include <fmtanchr.hxx>
37 : #include <fmtinfmt.hxx>
38 : #include <txtatr.hxx>
39 : #include <fchrfmt.hxx>
40 : #include <fmtautofmt.hxx>
41 : #include <fmtflcnt.hxx>
42 : #include <fmtftn.hxx>
43 : #include <txttxmrk.hxx>
44 : #include <txtrfmrk.hxx>
45 : #include <txtftn.hxx>
46 : #include <txtfld.hxx>
47 : #include <txtannotationfld.hxx>
48 : #include <charatr.hxx>
49 : #include <charfmt.hxx>
50 : #include <frmfmt.hxx>
51 : #include <ftnidx.hxx>
52 : #include <fmtruby.hxx>
53 : #include <fmtmeta.hxx>
54 : #include <breakit.hxx>
55 : #include <doc.hxx>
56 : #include <IDocumentUndoRedo.hxx>
57 : #include <IDocumentFieldsAccess.hxx>
58 : #include <IDocumentLayoutAccess.hxx>
59 : #include <IDocumentStylePoolAccess.hxx>
60 : #include <fldbas.hxx>
61 : #include <pam.hxx>
62 : #include <ndtxt.hxx>
63 : #include <txtfrm.hxx>
64 : #include <rolbck.hxx>
65 : #include <ddefld.hxx>
66 : #include <docufld.hxx>
67 : #include <expfld.hxx>
68 : #include <usrfld.hxx>
69 : #include <poolfmt.hxx>
70 : #include <swfont.hxx>
71 : #include <istyleaccess.hxx>
72 : #include <dcontact.hxx>
73 : #include <docsh.hxx>
74 : #include <svl/smplhint.hxx>
75 : #include <algorithm>
76 : #include <map>
77 : #include <memory>
78 :
79 : #ifdef DBG_UTIL
80 : #define CHECK Check(true);
81 : #define CHECK_NOTMERGED Check(false);
82 : #else
83 : #define CHECK_NOTMERGED
84 : #endif
85 :
86 : using namespace ::com::sun::star::i18n;
87 :
88 72844 : SwpHints::SwpHints()
89 : : m_pHistory(0)
90 : , m_bFontChange(true)
91 : , m_bInSplitNode(false)
92 : , m_bCalcHiddenParaField(false)
93 : , m_bHasHiddenParaField(false)
94 : , m_bFootnote(false)
95 72844 : , m_bDDEFields(false)
96 : {
97 72844 : }
98 :
99 : struct TextAttrDeleter
100 : {
101 : SwAttrPool & m_rPool;
102 2 : explicit TextAttrDeleter( SwDoc & rDoc ) : m_rPool( rDoc.GetAttrPool() ) { }
103 2 : void operator() (SwTextAttr * const pAttr)
104 : {
105 2 : if (RES_TXTATR_META == pAttr->Which() ||
106 0 : RES_TXTATR_METAFIELD == pAttr->Which())
107 : {
108 2 : static_txtattr_cast<SwTextMeta *>(pAttr)->ChgTextNode(0); // prevents ASSERT
109 : }
110 2 : SwTextAttr::Destroy( pAttr, m_rPool );
111 2 : }
112 : };
113 :
114 : struct TextAttrContains
115 : {
116 : sal_Int32 m_nPos;
117 30 : explicit TextAttrContains( const sal_Int32 nPos ) : m_nPos( nPos ) { }
118 39 : bool operator() (SwTextAttrEnd * const pAttr)
119 : {
120 39 : return (pAttr->GetStart() < m_nPos) && (m_nPos < *pAttr->End());
121 : }
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 2291 : bool isOverlap(const sal_Int32 nStart1, const sal_Int32 nEnd1,
142 : const sal_Int32 nStart2, const sal_Int32 nEnd2)
143 : {
144 : return
145 1895 : ((nStart1 > nStart2) && (nStart1 < nEnd2) && (nEnd1 > nEnd2)) // (1)
146 4557 : || ((nStart1 < nStart2) && (nStart2 < nEnd1) && (nEnd1 < nEnd2)); // (2)
147 : }
148 :
149 : /// #i106930#: now asymmetric: empty hint1 is _not_ nested, but empty hint2 is
150 : static
151 2248 : bool isNestedAny(const sal_Int32 nStart1, const sal_Int32 nEnd1,
152 : const sal_Int32 nStart2, const sal_Int32 nEnd2)
153 : {
154 1947 : return ((nStart1 == nStart2) || (nEnd1 == nEnd2))
155 : // same start/end: nested except if hint1 empty and hint2 not empty
156 339 : ? (nStart1 != nEnd1) || (nStart2 == nEnd2)
157 2587 : : ((nStart1 < nStart2) ? (nEnd1 >= nEnd2) : (nEnd1 <= nEnd2));
158 : }
159 :
160 : static
161 2078 : bool isSelfNestable(const sal_uInt16 nWhich)
162 : {
163 2078 : if ((RES_TXTATR_INETFMT == nWhich) ||
164 115 : (RES_TXTATR_CJK_RUBY == nWhich) ||
165 : (RES_TXTATR_INPUTFIELD == nWhich))
166 1981 : return false;
167 : assert((RES_TXTATR_META == nWhich) ||
168 : (RES_TXTATR_METAFIELD == nWhich));
169 97 : return true;
170 : }
171 :
172 : static
173 72 : bool isSplittable(const sal_uInt16 nWhich)
174 : {
175 72 : if ((RES_TXTATR_INETFMT == nWhich) ||
176 : (RES_TXTATR_CJK_RUBY == nWhich))
177 41 : return true;
178 : assert((RES_TXTATR_META == nWhich) ||
179 : (RES_TXTATR_METAFIELD == nWhich) ||
180 : (RES_TXTATR_INPUTFIELD == nWhich));
181 31 : return false;
182 : }
183 :
184 : enum Split_t { FAIL, SPLIT_NEW, SPLIT_OTHER };
185 : /**
186 : Calculate splitting policy for overlapping hints, based on what kind of
187 : hint is inserted, and what kind of existing hint overlaps.
188 : */
189 : static Split_t
190 43 : splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther)
191 : {
192 43 : if (!isSplittable(nWhichOther))
193 : {
194 29 : if (!isSplittable(nWhichNew))
195 2 : return FAIL;
196 : else
197 27 : return SPLIT_NEW;
198 : }
199 : else
200 : {
201 14 : if ( RES_TXTATR_INPUTFIELD == nWhichNew )
202 0 : return FAIL;
203 14 : else if ( (RES_TXTATR_INETFMT == nWhichNew) &&
204 : (RES_TXTATR_CJK_RUBY == nWhichOther) )
205 3 : return SPLIT_NEW;
206 : else
207 11 : return SPLIT_OTHER;
208 : }
209 : }
210 :
211 1812 : void SwTextINetFormat::InitINetFormat(SwTextNode & rNode)
212 : {
213 1812 : ChgTextNode(&rNode);
214 : SwCharFormat * const pFormat(
215 1812 : rNode.GetDoc()->getIDocumentStylePoolAccess().GetCharFormatFromPool(RES_POOLCHR_INET_NORMAL) );
216 1812 : pFormat->Add( this );
217 1812 : }
218 :
219 177 : void SwTextRuby::InitRuby(SwTextNode & rNode)
220 : {
221 177 : ChgTextNode(&rNode);
222 : SwCharFormat * const pFormat(
223 177 : rNode.GetDoc()->getIDocumentStylePoolAccess().GetCharFormatFromPool(RES_POOLCHR_RUBYTEXT) );
224 177 : pFormat->Add( this );
225 177 : }
226 :
227 : /**
228 : Create a new nesting text hint.
229 : */
230 : static SwTextAttrNesting *
231 42 : MakeTextAttrNesting(SwTextNode & rNode, SwTextAttrNesting & rNesting,
232 : const sal_Int32 nStart, const sal_Int32 nEnd)
233 : {
234 : SwTextAttr * const pNew( MakeTextAttr(
235 42 : *rNode.GetDoc(), rNesting.GetAttr(), nStart, nEnd ) );
236 42 : switch (pNew->Which())
237 : {
238 : case RES_TXTATR_INETFMT:
239 : {
240 14 : static_txtattr_cast<SwTextINetFormat*>(pNew)->InitINetFormat(rNode);
241 14 : break;
242 : }
243 : case RES_TXTATR_CJK_RUBY:
244 : {
245 28 : static_txtattr_cast<SwTextRuby*>(pNew)->InitRuby(rNode);
246 28 : break;
247 : }
248 : default:
249 : assert(!"MakeTextAttrNesting: what the hell is that?");
250 0 : break;
251 : }
252 42 : return static_txtattr_cast<SwTextAttrNesting*>(pNew);
253 : }
254 :
255 : typedef ::std::vector<SwTextAttrNesting *> NestList_t;
256 :
257 : static void
258 30 : lcl_DoSplitNew(NestList_t & rSplits, SwTextNode & rNode,
259 : const sal_Int32 nNewStart,
260 : const sal_Int32 nOtherStart, const sal_Int32 nOtherEnd, bool bOtherDummy)
261 : {
262 30 : const bool bSplitAtStart(nNewStart < nOtherStart);
263 30 : 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 30 : TextAttrContains(nSplitPos) ) );
268 30 : if (iter != rSplits.end()) // already split here?
269 : {
270 : const sal_Int32 nStartPos( // skip other's dummy character!
271 28 : (bSplitAtStart && bOtherDummy) ? nSplitPos + 1 : nSplitPos );
272 : SwTextAttrNesting * const pNew( MakeTextAttrNesting(
273 28 : rNode, **iter, nStartPos, *(*iter)->GetEnd() ) );
274 28 : *(*iter)->GetEnd() = nSplitPos;
275 28 : rSplits.insert(iter + 1, pNew);
276 : }
277 30 : }
278 :
279 : /**
280 : Insert nesting hint into the hints array. Also calls NoteInHistory.
281 : @param rNewHint the hint to be inserted (must not overlap existing!)
282 : */
283 2120 : void SwpHints::InsertNesting(SwTextAttrNesting & rNewHint)
284 : {
285 2120 : SwpHintsArray::Insert(& rNewHint);
286 2120 : NoteInHistory( & rNewHint, true );
287 2120 : }
288 :
289 : /**
290 :
291 : The following hints correspond to well-formed XML elements in ODF:
292 : RES_TXTATR_INETFMT, RES_TXTATR_CJK_RUBY, RES_TXTATR_META, RES_TXTATR_METAFIELD
293 :
294 : The writer core must ensure that these do not overlap; if they did,
295 : the document would not be storable as ODF.
296 :
297 : Also, a Hyperlink must not be nested within another Hyperlink,
298 : and a Ruby must not be nested within another Ruby.
299 :
300 : The ODF export in xmloff will only put a hyperlink into a ruby, never a ruby
301 : into a hyperlink.
302 :
303 : Unfortunately the UNO API for Hyperlink and Ruby consists of the properties
304 : Hyperlink* and Ruby* of the css.text.CharacterProperties service. In other
305 : words, they are treated as formatting attributes, not as content entites.
306 : Furthermore, for API users it is not possible to easily test whether a certain
307 : range would be overlapping with other nested attributes, and most importantly,
308 : <em>which ones</em>, so we can hardly refuse to insert these in cases of
309 : overlap.
310 :
311 : It is possible to split Hyperlink and Ruby into multiple portions, such that
312 : the result is properly nested.
313 :
314 : meta and meta-field must not be split, because they have xml:id.
315 :
316 : These constraints result in the following design:
317 :
318 : RES_TXTATR_INETFMT:
319 : always succeeds
320 : inserts n attributes split at RES_TXTATR_CJK_RUBY, RES_TXTATR_META,
321 : RES_TXTATR_METAFIELD
322 : may replace existing RES_TXTATR_INETFMT at overlap
323 : RES_TXTATR_CJK_RUBY:
324 : always succeeds
325 : inserts n attributes split at RES_TXTATR_META, RES_TXTATR_METAFIELD
326 : may replace existing RES_TXTATR_CJK_RUBY at overlap
327 : may split existing overlapping RES_TXTATR_INETFMT
328 : RES_TXTATR_META:
329 : may fail if overlapping existing RES_TXTATR_META/RES_TXTATR_METAFIELD
330 : may split existing overlapping RES_TXTATR_INETFMT or RES_TXTATR_CJK_RUBY
331 : inserts 1 attribute
332 : RES_TXTATR_METAFIELD:
333 : may fail if overlapping existing RES_TXTATR_META/RES_TXTATR_METAFIELD
334 : may split existing overlapping RES_TXTATR_INETFMT or RES_TXTATR_CJK_RUBY
335 : inserts 1 attribute
336 :
337 : The nesting is expressed by the position of the hints.
338 : RES_TXTATR_META and RES_TXTATR_METAFIELD have a CH_TXTATR, and there can
339 : only be one such hint starting and ending at a given position.
340 : Only RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY lack a CH_TXTATR.
341 : The interpretation given is that RES_TXTATR_CJK_RUBY is always around
342 : a RES_TXTATR_INETFMT at the same start and end position (which corresponds
343 : with the UNO API).
344 : Both of these are always around a nesting hint with CH_TXTATR at the same
345 : start and end position (if they should be inside, then the start should be
346 : after the CH_TXTATR).
347 : It would probably be a bad idea to add another nesting hint without
348 : CH_TXTATR; on the other hand, it would be difficult adding a CH_TXTATR to
349 : RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY, due to the overwriting and
350 : splitting of exising hints that is necessary for backward compatibility.
351 :
352 : @param rNode the text node
353 : @param rHint the hint to be inserted
354 : @returns true iff hint was successfully inserted
355 : */
356 : bool
357 2078 : SwpHints::TryInsertNesting( SwTextNode & rNode, SwTextAttrNesting & rNewHint )
358 : {
359 : // INVARIANT: the nestable hints in the array are properly nested
360 2078 : const sal_uInt16 nNewWhich( rNewHint.Which() );
361 2078 : const sal_Int32 nNewStart( rNewHint.GetStart() );
362 2078 : const sal_Int32 nNewEnd ( *rNewHint.GetEnd() );
363 2078 : const bool bNewSelfNestable( isSelfNestable(nNewWhich) );
364 :
365 : assert( (RES_TXTATR_INETFMT == nNewWhich) ||
366 : (RES_TXTATR_CJK_RUBY == nNewWhich) ||
367 : (RES_TXTATR_META == nNewWhich) ||
368 : (RES_TXTATR_METAFIELD == nNewWhich) ||
369 : (RES_TXTATR_INPUTFIELD == nNewWhich));
370 :
371 2078 : NestList_t OverlappingExisting; // existing hints to be split
372 4156 : NestList_t OverwrittenExisting; // existing hints to be replaced
373 4156 : NestList_t SplitNew; // new hints to be inserted
374 :
375 2078 : SplitNew.push_back(& rNewHint);
376 :
377 : // pass 1: split the inserted hint into fragments if necessary
378 12308 : for ( size_t i = 0; i < GetEndCount(); ++i )
379 : {
380 10232 : SwTextAttr * const pOther = GetEnd(i);
381 :
382 10232 : if (pOther->IsNesting())
383 : {
384 2291 : const sal_uInt16 nOtherWhich( pOther->Which() );
385 2291 : const sal_Int32 nOtherStart( pOther->GetStart() );
386 2291 : const sal_Int32 nOtherEnd ( *(pOther)->GetEnd() );
387 2291 : if (isOverlap(nNewStart, nNewEnd, nOtherStart, nOtherEnd ))
388 : {
389 43 : switch (splitPolicy(nNewWhich, nOtherWhich))
390 : {
391 : case FAIL:
392 : SAL_INFO("sw.core", "cannot insert hint: overlap");
393 : ::std::for_each(SplitNew.begin(), SplitNew.end(),
394 2 : TextAttrDeleter(*rNode.GetDoc()));
395 2 : return false;
396 : case SPLIT_NEW:
397 : lcl_DoSplitNew(SplitNew, rNode, nNewStart,
398 30 : nOtherStart, nOtherEnd, pOther->HasDummyChar());
399 30 : break;
400 : case SPLIT_OTHER:
401 : OverlappingExisting.push_back(
402 11 : static_txtattr_cast<SwTextAttrNesting*>(pOther));
403 11 : break;
404 : default:
405 : assert(!"bad code monkey");
406 0 : break;
407 : }
408 : }
409 2248 : else if (isNestedAny(nNewStart, nNewEnd, nOtherStart, nOtherEnd))
410 : {
411 383 : if (!bNewSelfNestable && (nNewWhich == nOtherWhich))
412 : {
413 : // ruby and hyperlink: if there is nesting, _overwrite_
414 : OverwrittenExisting.push_back(
415 291 : static_txtattr_cast<SwTextAttrNesting*>(pOther));
416 : }
417 92 : else if ((nNewStart == nOtherStart) && pOther->HasDummyChar())
418 : {
419 18 : if (rNewHint.HasDummyChar())
420 : {
421 : assert(!"ERROR: inserting duplicate CH_TXTATR hint");
422 0 : return false;
423 18 : } else if (nNewEnd < nOtherEnd) {
424 : // other has dummy char, new is inside other, but
425 : // new contains the other's dummy char?
426 : // should be corrected because it may lead to problems
427 : // in SwXMeta::createEnumeration
428 : // SplitNew is sorted, so this is the first split
429 2 : sal_Int32& rStart(SplitNew.front()->GetStart());
430 : assert(rStart == nNewStart);
431 2 : rStart = nNewStart + 1;
432 : }
433 : }
434 : }
435 : }
436 : }
437 :
438 : assert((isSplittable(nNewWhich) || SplitNew.size() == 1) &&
439 : "splitting the unsplittable ???");
440 :
441 : // pass 2: split existing hints that overlap/nest with new hint
442 : // do not iterate over hints array, but over remembered set of overlapping
443 : // hints, to keep things simple w.r.t. insertion/removal
444 : // N.B: if there is a hint that splits the inserted hint, then
445 : // that hint would also have already split any hint in OverlappingExisting
446 : // so any hint in OverlappingExisting can be split at most by one hint
447 : // in SplitNew, or even not at all (this is not true for existing hints
448 : // that go _around_ new hint, which is the raison d'^etre for pass 4)
449 6261 : for (NestList_t::iterator itOther = OverlappingExisting.begin();
450 4174 : itOther != OverlappingExisting.end(); ++itOther)
451 : {
452 11 : const sal_Int32 nOtherStart( (*itOther)->GetStart() );
453 11 : const sal_Int32 nOtherEnd ( *(*itOther)->GetEnd() );
454 :
455 69 : for (NestList_t::iterator itNew = SplitNew.begin();
456 46 : itNew != SplitNew.end(); ++itNew)
457 : {
458 12 : const sal_Int32 nSplitNewStart( (*itNew)->GetStart() );
459 12 : const sal_Int32 nSplitNewEnd ( *(*itNew)->GetEnd() );
460 : // 4 cases: within, around, overlap l, overlap r, (OTHER: no action)
461 : const bool bRemoveOverlap(
462 12 : !bNewSelfNestable && (nNewWhich == (*itOther)->Which()) );
463 :
464 12 : switch (ComparePosition(nSplitNewStart, nSplitNewEnd,
465 12 : nOtherStart, nOtherEnd))
466 : {
467 : case POS_INSIDE:
468 : {
469 : assert(!bRemoveOverlap &&
470 : "this one should be in OverwrittenExisting?");
471 : }
472 1 : break;
473 : case POS_OUTSIDE:
474 : case POS_EQUAL:
475 : {
476 : assert(!"existing hint inside new hint: why?");
477 : }
478 0 : break;
479 : case POS_OVERLAP_BEFORE:
480 : {
481 5 : Delete( *itOther ); // this also does NoteInHistory!
482 5 : (*itOther)->GetStart() = nSplitNewEnd;
483 5 : InsertNesting( **itOther );
484 5 : if (!bRemoveOverlap)
485 : {
486 3 : if ( MAX_HINTS <= Count() )
487 : {
488 : SAL_INFO("sw.core", "hints array full :-(");
489 0 : return false;
490 : }
491 : SwTextAttrNesting * const pOtherLeft(
492 3 : MakeTextAttrNesting( rNode, **itOther,
493 6 : nOtherStart, nSplitNewEnd ) );
494 3 : InsertNesting( *pOtherLeft );
495 : }
496 : }
497 5 : break;
498 : case POS_OVERLAP_BEHIND:
499 : {
500 5 : Delete( *itOther ); // this also does NoteInHistory!
501 5 : *(*itOther)->GetEnd() = nSplitNewStart;
502 5 : InsertNesting( **itOther );
503 5 : if (!bRemoveOverlap)
504 : {
505 3 : if ( MAX_HINTS <= Count() )
506 : {
507 : SAL_INFO("sw.core", "hints array full :-(");
508 0 : return false;
509 : }
510 : SwTextAttrNesting * const pOtherRight(
511 3 : MakeTextAttrNesting( rNode, **itOther,
512 6 : nSplitNewStart, nOtherEnd ) );
513 3 : InsertNesting( *pOtherRight );
514 : }
515 : }
516 5 : break;
517 : default:
518 1 : break; // overlap resolved by splitting new: nothing to do
519 : }
520 : }
521 : }
522 :
523 2076 : if ( MAX_HINTS <= Count() || MAX_HINTS - Count() <= SplitNew.size() )
524 : {
525 : SAL_INFO("sw.core", "hints array full :-(");
526 0 : return false;
527 : }
528 :
529 : // pass 3: insert new hints
530 12540 : for (NestList_t::iterator iter = SplitNew.begin();
531 8360 : iter != SplitNew.end(); ++iter)
532 : {
533 2104 : InsertNesting(**iter);
534 : }
535 :
536 : // pass 4: handle overwritten hints
537 : // RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY should displace attributes
538 : // of the same kind.
539 7101 : for (NestList_t::iterator itOther = OverwrittenExisting.begin();
540 4734 : itOther != OverwrittenExisting.end(); ++itOther)
541 : {
542 291 : const sal_Int32 nOtherStart( (*itOther)->GetStart() );
543 291 : const sal_Int32 nOtherEnd ( *(*itOther)->GetEnd() );
544 :
545 : // overwritten portion is given by start/end of inserted hint
546 291 : if ((nNewStart <= nOtherStart) && (nOtherEnd <= nNewEnd))
547 : {
548 282 : Delete(*itOther);
549 282 : rNode.DestroyAttr( *itOther );
550 : }
551 : else
552 : {
553 : assert((nOtherStart < nNewStart) || (nNewEnd < nOtherEnd));
554 : // scenario: there is a RUBY, and contained within that a META;
555 : // now a RUBY is inserted within the META => the exising RUBY is split:
556 : // here it is not possible to simply insert the left/right fragment
557 : // of the existing RUBY because they <em>overlap</em> with the META!
558 9 : Delete( *itOther ); // this also does NoteInHistory!
559 9 : if (nNewEnd < nOtherEnd)
560 : {
561 : SwTextAttrNesting * const pOtherRight(
562 : MakeTextAttrNesting(
563 8 : rNode, **itOther, nNewEnd, nOtherEnd ) );
564 8 : bool const bSuccess( TryInsertNesting(rNode, *pOtherRight) );
565 : SAL_WARN_IF(!bSuccess, "sw.core", "recursive call 1 failed?");
566 : }
567 9 : if (nOtherStart < nNewStart)
568 : {
569 8 : *(*itOther)->GetEnd() = nNewStart;
570 8 : bool const bSuccess( TryInsertNesting(rNode, **itOther) );
571 : SAL_WARN_IF(!bSuccess, "sw.core", "recursive call 2 failed?");
572 : }
573 : else
574 : {
575 1 : rNode.DestroyAttr(*itOther);
576 : }
577 : }
578 : }
579 :
580 4154 : return true;
581 : }
582 :
583 : // This function takes care for the following text attribute:
584 : // RES_TXTATR_CHARFMT, RES_TXTATR_AUTOFMT
585 : // These attributes have to be handled in a special way (Portion building).
586 :
587 : // The new attribute will be split by any existing RES_TXTATR_AUTOFMT or
588 : // RES_TXTATR_CHARFMT. The new attribute itself will
589 : // split any existing RES_TXTATR_AUTOFMT or RES_TXTATR_CHARFMT.
590 :
591 72499 : void SwpHints::BuildPortions( SwTextNode& rNode, SwTextAttr& rNewHint,
592 : const SetAttrMode nMode )
593 : {
594 72499 : const sal_uInt16 nWhich = rNewHint.Which();
595 :
596 72499 : const sal_Int32 nThisStart = rNewHint.GetStart();
597 72499 : const sal_Int32 nThisEnd = *rNewHint.GetEnd();
598 72499 : const bool bNoLengthAttribute = nThisStart == nThisEnd;
599 :
600 72499 : std::vector<SwTextAttr*> aInsDelHints;
601 72499 : std::vector<SwTextAttr*>::iterator aIter;
602 :
603 : assert( RES_TXTATR_CHARFMT == rNewHint.Which() ||
604 : RES_TXTATR_AUTOFMT == rNewHint.Which() );
605 :
606 : // 2. Find the hints which cover the start and end position
607 : // of the new hint. These hints have to be split into two portions:
608 :
609 72499 : if ( !bNoLengthAttribute ) // nothing to do for no length attributes
610 : {
611 226813 : for ( size_t i = 0; i < Count(); ++i )
612 : {
613 180595 : SwTextAttr* pOther = GetTextHint(i);
614 :
615 343585 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
616 162990 : RES_TXTATR_AUTOFMT != pOther->Which() )
617 20944 : continue;
618 :
619 159651 : sal_Int32 nOtherStart = pOther->GetStart();
620 159651 : const sal_Int32 nOtherEnd = *pOther->GetEnd();
621 :
622 : // Check if start of new attribute overlaps with pOther:
623 : // Split pOther if necessary:
624 159651 : if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
625 : {
626 311 : SwTextAttr* pNewAttr = MakeTextAttr( *rNode.GetDoc(),
627 622 : pOther->GetAttr(), nOtherStart, nThisStart );
628 311 : if ( RES_TXTATR_CHARFMT == pOther->Which() )
629 : {
630 : static_txtattr_cast<SwTextCharFormat*>(pNewAttr)->SetSortNumber(
631 76 : static_txtattr_cast<SwTextCharFormat*>(pOther)->GetSortNumber() );
632 : }
633 311 : aInsDelHints.push_back( pNewAttr );
634 :
635 311 : NoteInHistory( pOther );
636 311 : pOther->GetStart() = nThisStart;
637 311 : NoteInHistory( pOther, true );
638 :
639 311 : nOtherStart = nThisStart;
640 : }
641 :
642 : // Check if end of new attribute overlaps with pOther:
643 : // Split pOther if necessary:
644 159651 : if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd )
645 : {
646 863 : SwTextAttr* pNewAttr = MakeTextAttr( *rNode.GetDoc(),
647 1726 : pOther->GetAttr(), nOtherStart, nThisEnd );
648 863 : if ( RES_TXTATR_CHARFMT == pOther->Which() )
649 : {
650 : static_txtattr_cast<SwTextCharFormat*>(pNewAttr)->SetSortNumber(
651 0 : static_txtattr_cast<SwTextCharFormat*>(pOther)->GetSortNumber());
652 : }
653 863 : aInsDelHints.push_back( pNewAttr );
654 :
655 863 : NoteInHistory( pOther );
656 863 : pOther->GetStart() = nThisEnd;
657 863 : NoteInHistory( pOther, true );
658 : }
659 : }
660 :
661 : // Insert the newly created attributes:
662 47392 : for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
663 : {
664 1174 : SwpHintsArray::Insert( *aIter );
665 1174 : NoteInHistory( *aIter, true );
666 : }
667 : }
668 :
669 : #ifdef DBG_UTIL
670 : if( !rNode.GetDoc()->IsInReading() )
671 : CHECK_NOTMERGED; // ignore flags not set properly yet, don't check them
672 : #endif
673 :
674 : // 4. Split rNewHint into 1 ... n new hints:
675 :
676 144998 : std::set<sal_Int32> aBounds;
677 72499 : aBounds.insert( nThisStart );
678 72499 : aBounds.insert( nThisEnd );
679 :
680 72499 : if ( !bNoLengthAttribute ) // nothing to do for no length attributes
681 : {
682 227987 : for ( size_t i = 0; i < Count(); ++i )
683 : {
684 181769 : const SwTextAttr* pOther = GetTextHint(i);
685 :
686 345857 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
687 164088 : RES_TXTATR_AUTOFMT != pOther->Which() )
688 20944 : continue;
689 :
690 160825 : const sal_Int32 nOtherStart = pOther->GetStart();
691 160825 : const sal_Int32 nOtherEnd = *pOther->End();
692 :
693 160825 : aBounds.insert( nOtherStart );
694 160825 : aBounds.insert( nOtherEnd );
695 : }
696 : }
697 :
698 72499 : std::set<sal_Int32>::iterator aStartIter = aBounds.lower_bound( nThisStart );
699 72499 : std::set<sal_Int32>::iterator aEndIter = aBounds.upper_bound( nThisEnd );
700 72499 : sal_Int32 nPorStart = *aStartIter;
701 72499 : ++aStartIter;
702 72499 : bool bDestroyHint = true;
703 :
704 : // Insert the 1...n new parts of the new attribute:
705 :
706 192242 : while ( aStartIter != aEndIter || bNoLengthAttribute )
707 : {
708 : OSL_ENSURE( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" );
709 :
710 73525 : const sal_Int32 nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter;
711 73525 : aInsDelHints.clear();
712 :
713 : // Get all hints that are in [nPorStart, nPorEnd[:
714 326703 : for ( size_t i = 0; i < Count(); ++i )
715 : {
716 255486 : SwTextAttr *pOther = GetTextHint(i);
717 :
718 487629 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
719 232143 : RES_TXTATR_AUTOFMT != pOther->Which() )
720 24308 : continue;
721 :
722 231178 : const sal_Int32 nOtherStart = pOther->GetStart();
723 :
724 231178 : if ( nOtherStart > nPorStart )
725 2308 : break;
726 :
727 228870 : if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart )
728 : {
729 : OSL_ENSURE( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" );
730 25725 : aInsDelHints.push_back( pOther );
731 : }
732 : }
733 :
734 73525 : SwTextAttr* pNewAttr = 0;
735 73525 : if ( RES_TXTATR_CHARFMT == nWhich )
736 : {
737 : // pNewHint can be inserted after calculating the sort value.
738 : // This should ensure, that pNewHint comes behind the already present
739 : // character style
740 6242 : sal_uInt16 nCharStyleCount = 0;
741 6242 : aIter = aInsDelHints.begin();
742 13446 : while ( aIter != aInsDelHints.end() )
743 : {
744 962 : if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
745 : {
746 : // #i74589#
747 689 : const SwFormatCharFormat& rOtherCharFormat = (*aIter)->GetCharFormat();
748 689 : const SwFormatCharFormat& rThisCharFormat = rNewHint.GetCharFormat();
749 689 : const bool bSameCharFormat = rOtherCharFormat.GetCharFormat() == rThisCharFormat.GetCharFormat();
750 :
751 : // #i90311#
752 : // Do not remove existing character format hint during XML import
753 3445 : if ( !rNode.GetDoc()->IsInXMLImport() &&
754 2756 : ( !( SetAttrMode::DONTREPLACE & nMode ) ||
755 0 : bNoLengthAttribute ||
756 : bSameCharFormat ) )
757 : {
758 : // Remove old hint
759 689 : Delete( *aIter );
760 689 : rNode.DestroyAttr( *aIter );
761 : }
762 : else
763 0 : ++nCharStyleCount;
764 : }
765 : else
766 : {
767 : // remove all attributes from auto styles, which are explicitly set in
768 : // the new character format:
769 : OSL_ENSURE( RES_TXTATR_AUTOFMT == (*aIter)->Which(), "AUTOSTYLES - Misc trouble" );
770 273 : SwTextAttr* pOther = *aIter;
771 273 : std::shared_ptr<SfxItemSet> pOldStyle = static_cast<const SwFormatAutoFormat&>(pOther->GetAttr()).GetStyleHandle();
772 :
773 : // For each attribute in the automatic style check if it
774 : // is also set the new character style:
775 273 : SfxItemSet aNewSet( *pOldStyle->GetPool(),
776 546 : aCharAutoFormatSetRange);
777 546 : SfxItemIter aItemIter( *pOldStyle );
778 273 : const SfxPoolItem* pItem = aItemIter.GetCurItem();
779 : while( true )
780 : {
781 925 : if ( !CharFormat::IsItemIncluded( pItem->Which(), &rNewHint ) )
782 : {
783 412 : aNewSet.Put( *pItem );
784 : }
785 :
786 925 : if( aItemIter.IsAtEnd() )
787 273 : break;
788 :
789 652 : pItem = aItemIter.NextItem();
790 : }
791 :
792 : // Remove old hint
793 273 : Delete( pOther );
794 273 : rNode.DestroyAttr( pOther );
795 :
796 : // Create new AutoStyle
797 273 : if ( aNewSet.Count() )
798 : {
799 106 : pNewAttr = MakeTextAttr( *rNode.GetDoc(),
800 106 : aNewSet, nPorStart, nPorEnd );
801 106 : SwpHintsArray::Insert( pNewAttr );
802 106 : NoteInHistory( pNewAttr, true );
803 273 : }
804 : }
805 962 : ++aIter;
806 : }
807 :
808 : // If there is no current hint and start and end of rNewHint
809 : // is ok, we do not need to create a new txtattr.
810 12484 : if ( nPorStart == nThisStart &&
811 12484 : nPorEnd == nThisEnd &&
812 : !nCharStyleCount )
813 : {
814 6242 : pNewAttr = &rNewHint;
815 6242 : bDestroyHint = false;
816 : }
817 : else
818 : {
819 0 : pNewAttr = MakeTextAttr( *rNode.GetDoc(), rNewHint.GetAttr(),
820 0 : nPorStart, nPorEnd );
821 0 : static_txtattr_cast<SwTextCharFormat*>(pNewAttr)->SetSortNumber(nCharStyleCount);
822 : }
823 : }
824 : else
825 : {
826 : // Find the current autostyle. Mix attributes if necessary.
827 67283 : SwTextAttr* pCurrentAutoStyle = 0;
828 67283 : SwTextAttr* pCurrentCharFormat = 0;
829 67283 : aIter = aInsDelHints.begin();
830 159329 : while ( aIter != aInsDelHints.end() )
831 : {
832 24763 : if ( RES_TXTATR_AUTOFMT == (*aIter)->Which() )
833 23502 : pCurrentAutoStyle = *aIter;
834 1261 : else if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
835 1261 : pCurrentCharFormat = *aIter;
836 24763 : ++aIter;
837 : }
838 :
839 67283 : std::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFormatAutoFormat&>(rNewHint.GetAttr()).GetStyleHandle();
840 67283 : if ( pCurrentAutoStyle )
841 : {
842 23493 : std::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFormatAutoFormat&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle();
843 :
844 : // Merge attributes
845 46986 : SfxItemSet aNewSet( *pCurrentStyle );
846 23493 : aNewSet.Put( *pNewStyle );
847 :
848 : // #i75750# Remove attributes already set at whole paragraph
849 : // #i81764# This should not be applied for no length attributes!!! <--
850 23493 : if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() )
851 : {
852 8363 : SfxItemIter aIter2( aNewSet );
853 8363 : const SfxPoolItem* pItem = aIter2.GetCurItem();
854 8363 : const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
855 :
856 41618 : do
857 : {
858 41618 : const SfxPoolItem* pTmpItem = 0;
859 41648 : if ( SfxItemState::SET == rWholeParaAttrSet.GetItemState( pItem->Which(), false, &pTmpItem ) &&
860 30 : pTmpItem == pItem )
861 : {
862 : // Do not clear item if the attribute is set in a character format:
863 0 : if ( !pCurrentCharFormat || 0 == CharFormat::GetItem( *pCurrentCharFormat, pItem->Which() ) )
864 0 : aNewSet.ClearItem( pItem->Which() );
865 : }
866 : }
867 49981 : while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
868 : }
869 :
870 : // Remove old hint
871 23493 : Delete( pCurrentAutoStyle );
872 23493 : rNode.DestroyAttr( pCurrentAutoStyle );
873 :
874 : // Create new AutoStyle
875 23493 : if ( aNewSet.Count() )
876 23493 : pNewAttr = MakeTextAttr( *rNode.GetDoc(), aNewSet,
877 46986 : nPorStart, nPorEnd );
878 : }
879 : else
880 : {
881 : // Remove any attributes which are already set at the whole paragraph:
882 43790 : bool bOptimizeAllowed = true;
883 :
884 : // #i75750# Remove attributes already set at whole paragraph
885 : // #i81764# This should not be applied for no length attributes!!! <--
886 43790 : if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() )
887 : {
888 5206 : SfxItemSet* pNewSet = 0;
889 :
890 5206 : SfxItemIter aIter2( *pNewStyle );
891 5206 : const SfxPoolItem* pItem = aIter2.GetCurItem();
892 5206 : const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
893 :
894 23116 : do
895 : {
896 23116 : const SfxPoolItem* pTmpItem = 0;
897 23225 : if ( SfxItemState::SET == rWholeParaAttrSet.GetItemState( pItem->Which(), false, &pTmpItem ) &&
898 109 : pTmpItem == pItem )
899 : {
900 : // Do not clear item if the attribute is set in a character format:
901 89 : if ( !pCurrentCharFormat || 0 == CharFormat::GetItem( *pCurrentCharFormat, pItem->Which() ) )
902 : {
903 89 : if ( !pNewSet )
904 66 : pNewSet = pNewStyle->Clone( true );
905 89 : pNewSet->ClearItem( pItem->Which() );
906 : }
907 : }
908 : }
909 23116 : while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
910 :
911 5206 : if ( pNewSet )
912 : {
913 66 : bOptimizeAllowed = false;
914 66 : if ( pNewSet->Count() )
915 0 : pNewStyle = rNode.getIDocumentStyleAccess().getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
916 : else
917 66 : pNewStyle.reset();
918 :
919 66 : delete pNewSet;
920 5206 : }
921 : }
922 :
923 : // Create new AutoStyle
924 : // If there is no current hint and start and end of rNewHint
925 : // is ok, we do not need to create a new txtattr.
926 87514 : if ( bOptimizeAllowed &&
927 87412 : nPorStart == nThisStart &&
928 43688 : nPorEnd == nThisEnd )
929 : {
930 43683 : pNewAttr = &rNewHint;
931 43683 : bDestroyHint = false;
932 : }
933 107 : else if ( pNewStyle.get() )
934 : {
935 41 : pNewAttr = MakeTextAttr( *rNode.GetDoc(), *pNewStyle,
936 41 : nPorStart, nPorEnd );
937 : }
938 67283 : }
939 : }
940 :
941 73525 : if ( pNewAttr )
942 : {
943 73459 : SwpHintsArray::Insert( pNewAttr );
944 : // if ( bDestroyHint )
945 73459 : NoteInHistory( pNewAttr, true );
946 : }
947 :
948 73525 : if ( !bNoLengthAttribute )
949 : {
950 47244 : nPorStart = *aStartIter;
951 47244 : ++aStartIter;
952 : }
953 : else
954 26281 : break;
955 : }
956 :
957 72499 : if ( bDestroyHint )
958 95073 : rNode.DestroyAttr( &rNewHint );
959 72499 : }
960 :
961 5301 : SwTextAttr* MakeRedlineTextAttr( SwDoc & rDoc, SfxPoolItem & rAttr )
962 : {
963 : // this is intended _only_ for special-purpose redline attributes!
964 5301 : switch (rAttr.Which())
965 : {
966 : case RES_CHRATR_COLOR:
967 : case RES_CHRATR_WEIGHT:
968 : case RES_CHRATR_CJK_WEIGHT:
969 : case RES_CHRATR_CTL_WEIGHT:
970 : case RES_CHRATR_POSTURE:
971 : case RES_CHRATR_CJK_POSTURE:
972 : case RES_CHRATR_CTL_POSTURE:
973 : case RES_CHRATR_UNDERLINE:
974 : case RES_CHRATR_CROSSEDOUT:
975 : case RES_CHRATR_CASEMAP:
976 : case RES_CHRATR_BACKGROUND:
977 5301 : break;
978 : default:
979 : OSL_FAIL("unsupported redline attribute");
980 0 : break;
981 : }
982 :
983 : // Put new attribute into pool
984 : // FIXME: this const_cast is evil!
985 : SfxPoolItem& rNew =
986 5301 : const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
987 5301 : return new SwTextAttrEnd( rNew, 0, 0 );
988 : }
989 :
990 : // create new text attribute
991 107264 : SwTextAttr* MakeTextAttr(
992 : SwDoc & rDoc,
993 : SfxPoolItem& rAttr,
994 : sal_Int32 const nStt,
995 : sal_Int32 const nEnd,
996 : CopyOrNew_t const bIsCopy,
997 : SwTextNode *const pTextNode )
998 : {
999 107264 : if ( isCHRATR(rAttr.Which()) )
1000 : {
1001 : // Somebody wants to build a SwTextAttr for a character attribute.
1002 : // Sorry, this is not allowed any longer.
1003 : // You'll get a brand new autostyle attribute:
1004 0 : SfxItemSet aItemSet( rDoc.GetAttrPool(),
1005 0 : RES_CHRATR_BEGIN, RES_CHRATR_END );
1006 0 : aItemSet.Put( rAttr );
1007 0 : return MakeTextAttr( rDoc, aItemSet, nStt, nEnd );
1008 : }
1009 414623 : else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
1010 : static_cast<const SwFormatAutoFormat&>(rAttr).GetStyleHandle()->
1011 385757 : GetPool() != &rDoc.GetAttrPool() )
1012 : {
1013 : // If the attribute is an auto-style which refers to a pool that is
1014 : // different from rDoc's pool, we have to correct this:
1015 9 : const StylePool::SfxItemSet_Pointer_t pAutoStyle = static_cast<const SwFormatAutoFormat&>(rAttr).GetStyleHandle();
1016 : std::unique_ptr<const SfxItemSet> pNewSet(
1017 18 : pAutoStyle->SfxItemSet::Clone( true, &rDoc.GetAttrPool() ));
1018 9 : SwTextAttr* pNew = MakeTextAttr( rDoc, *pNewSet, nStt, nEnd );
1019 18 : return pNew;
1020 : }
1021 :
1022 : // Put new attribute into pool
1023 : // FIXME: this const_cast is evil!
1024 : SfxPoolItem& rNew =
1025 107255 : const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
1026 :
1027 107255 : SwTextAttr* pNew = 0;
1028 107255 : switch( rNew.Which() )
1029 : {
1030 : case RES_TXTATR_CHARFMT:
1031 : {
1032 6318 : SwFormatCharFormat &rFormatCharFormat = static_cast<SwFormatCharFormat&>(rNew);
1033 6318 : if( !rFormatCharFormat.GetCharFormat() )
1034 : {
1035 0 : rFormatCharFormat.SetCharFormat( rDoc.GetDfltCharFormat() );
1036 : }
1037 :
1038 6318 : pNew = new SwTextCharFormat( rFormatCharFormat, nStt, nEnd );
1039 : }
1040 6318 : break;
1041 : case RES_TXTATR_INETFMT:
1042 1804 : pNew = new SwTextINetFormat( static_cast<SwFormatINetFormat&>(rNew), nStt, nEnd );
1043 1804 : break;
1044 :
1045 : case RES_TXTATR_FIELD:
1046 3766 : pNew = new SwTextField( static_cast<SwFormatField &>(rNew), nStt,
1047 5649 : rDoc.IsClipBoard() );
1048 1883 : break;
1049 :
1050 : case RES_TXTATR_ANNOTATION:
1051 : {
1052 139 : pNew = new SwTextAnnotationField( static_cast<SwFormatField &>(rNew), nStt, rDoc.IsClipBoard() );
1053 139 : if (bIsCopy == COPY)
1054 : {
1055 : // On copy of the annotation field do not keep the annotated text range by removing
1056 : // the relation to its annotation mark (relation established via annotation field's name).
1057 : // If the annotation mark is also copied, the relation and thus the annotated text range will be reestablished,
1058 : // when the annotation mark is created and inserted into the document.
1059 5 : const_cast<SwPostItField&>(dynamic_cast<const SwPostItField&>(*(pNew->GetFormatField().GetField()))).SetName(OUString());
1060 : }
1061 : }
1062 139 : break;
1063 :
1064 : case RES_TXTATR_INPUTFIELD:
1065 36 : pNew = new SwTextInputField( static_cast<SwFormatField &>(rNew), nStt, nEnd,
1066 54 : rDoc.IsClipBoard() );
1067 18 : break;
1068 :
1069 : case RES_TXTATR_FLYCNT:
1070 : {
1071 : // erst hier wird das Frame-Format kopiert (mit Inhalt) !!
1072 3648 : pNew = new SwTextFlyCnt( static_cast<SwFormatFlyCnt&>(rNew), nStt );
1073 : // Kopie von einem Text-Attribut
1074 3648 : if ( static_cast<const SwFormatFlyCnt &>(rAttr).GetTextFlyCnt() )
1075 : {
1076 : // then the format must be copied
1077 176 : static_cast<SwTextFlyCnt *>(pNew)->CopyFlyFormat( &rDoc );
1078 : }
1079 : }
1080 3648 : break;
1081 : case RES_TXTATR_FTN:
1082 138 : pNew = new SwTextFootnote( static_cast<SwFormatFootnote&>(rNew), nStt );
1083 : // ggfs. SeqNo kopieren
1084 138 : if( static_cast<SwFormatFootnote&>(rAttr).GetTextFootnote() )
1085 0 : static_cast<SwTextFootnote*>(pNew)->SetSeqNo( static_cast<SwFormatFootnote&>(rAttr).GetTextFootnote()->GetSeqRefNo() );
1086 138 : break;
1087 : case RES_TXTATR_REFMARK:
1088 78 : pNew = nStt == nEnd
1089 25 : ? new SwTextRefMark( static_cast<SwFormatRefMark&>(rNew), nStt )
1090 53 : : new SwTextRefMark( static_cast<SwFormatRefMark&>(rNew), nStt, &nEnd );
1091 39 : break;
1092 : case RES_TXTATR_TOXMARK:
1093 173 : pNew = new SwTextTOXMark( static_cast<SwTOXMark&>(rNew), nStt, &nEnd );
1094 173 : break;
1095 : case RES_TXTATR_CJK_RUBY:
1096 176 : pNew = new SwTextRuby( static_cast<SwFormatRuby&>(rNew), nStt, nEnd );
1097 176 : break;
1098 : case RES_TXTATR_META:
1099 : case RES_TXTATR_METAFIELD:
1100 194 : pNew = SwTextMeta::CreateTextMeta( rDoc.GetMetaFieldManager(), pTextNode,
1101 291 : static_cast<SwFormatMeta&>(rNew), nStt, nEnd, bIsCopy == COPY );
1102 97 : break;
1103 : default:
1104 : assert(RES_TXTATR_AUTOFMT == rNew.Which());
1105 92822 : pNew = new SwTextAttrEnd( rNew, nStt, nEnd );
1106 92822 : break;
1107 : }
1108 :
1109 107255 : return pNew;
1110 : }
1111 :
1112 87768 : SwTextAttr* MakeTextAttr( SwDoc & rDoc, const SfxItemSet& rSet,
1113 : sal_Int32 nStt, sal_Int32 nEnd )
1114 : {
1115 87768 : IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
1116 87768 : const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
1117 175536 : SwFormatAutoFormat aNewAutoFormat;
1118 87768 : aNewAutoFormat.SetStyleHandle( pAutoStyle );
1119 87768 : SwTextAttr* pNew = MakeTextAttr( rDoc, aNewAutoFormat, nStt, nEnd );
1120 175536 : return pNew;
1121 : }
1122 :
1123 : // loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
1124 107221 : void SwTextNode::DestroyAttr( SwTextAttr* pAttr )
1125 : {
1126 107221 : if( pAttr )
1127 : {
1128 : // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
1129 107221 : SwDoc* pDoc = GetDoc();
1130 107221 : switch( pAttr->Which() )
1131 : {
1132 : case RES_TXTATR_FLYCNT:
1133 : {
1134 : // siehe auch die Anmerkung "Loeschen von Formaten
1135 : // zeichengebundener Frames" in fesh.cxx, SwFEShell::DelFormat()
1136 3647 : SwFrameFormat* pFormat = pAttr->GetFlyCnt().GetFrameFormat();
1137 3647 : if( pFormat ) // vom Undo auf 0 gesetzt ??
1138 1508 : pDoc->getIDocumentLayoutAccess().DelLayoutFormat( pFormat );
1139 : }
1140 3647 : break;
1141 :
1142 : case RES_CHRATR_HIDDEN:
1143 0 : SetCalcHiddenCharFlags();
1144 0 : break;
1145 :
1146 : case RES_TXTATR_FTN:
1147 138 : static_cast<SwTextFootnote*>(pAttr)->SetStartNode( 0 );
1148 138 : static_cast<SwFormatFootnote&>(pAttr->GetAttr()).InvalidateFootnote();
1149 138 : break;
1150 :
1151 : case RES_TXTATR_FIELD:
1152 : case RES_TXTATR_ANNOTATION:
1153 : case RES_TXTATR_INPUTFIELD:
1154 2031 : if( !pDoc->IsInDtor() )
1155 : {
1156 774 : SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pAttr));
1157 : // Wenn wir ein HiddenParaField sind, dann muessen wir
1158 : // ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
1159 774 : const SwField* pField = pAttr->GetFormatField().GetField();
1160 :
1161 : //JP 06-08-95: DDE-Felder bilden eine Ausnahme
1162 : OSL_ENSURE( RES_DDEFLD == pField->GetTyp()->Which() ||
1163 : this == pTextField->GetpTextNode(),
1164 : "Wo steht denn dieses Feld?" );
1165 :
1166 : // bestimmte Felder mussen am Doc das Calculations-Flag updaten
1167 774 : switch( pField->GetTyp()->Which() )
1168 : {
1169 : case RES_HIDDENPARAFLD:
1170 0 : SetCalcHiddenParaField();
1171 : // no break
1172 : case RES_DBSETNUMBERFLD:
1173 : case RES_GETEXPFLD:
1174 : case RES_DBFLD:
1175 : case RES_SETEXPFLD:
1176 : case RES_HIDDENTXTFLD:
1177 : case RES_DBNUMSETFLD:
1178 : case RES_DBNEXTSETFLD:
1179 30 : if( !pDoc->getIDocumentFieldsAccess().IsNewFieldLst() && GetNodes().IsDocNodes() )
1180 30 : pDoc->getIDocumentFieldsAccess().InsDelFieldInFieldLst(false, *pTextField);
1181 30 : break;
1182 : case RES_DDEFLD:
1183 0 : if (GetNodes().IsDocNodes() && pTextField->GetpTextNode())
1184 0 : static_cast<SwDDEFieldType*>(pField->GetTyp())->DecRefCnt();
1185 0 : break;
1186 : case RES_POSTITFLD:
1187 : {
1188 18 : const_cast<SwFormatField&>(pAttr->GetFormatField()).Broadcast(
1189 36 : SwFormatFieldHint(&pTextField->GetFormatField(), SwFormatFieldHintWhich::REMOVED));
1190 18 : break;
1191 : }
1192 : }
1193 : }
1194 2031 : static_cast<SwFormatField&>(pAttr->GetAttr()).InvalidateField();
1195 2031 : break;
1196 :
1197 : case RES_TXTATR_TOXMARK:
1198 173 : static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark();
1199 173 : break;
1200 :
1201 : case RES_TXTATR_REFMARK:
1202 39 : static_cast<SwFormatRefMark&>(pAttr->GetAttr()).InvalidateRefMark();
1203 39 : break;
1204 :
1205 : case RES_TXTATR_META:
1206 : case RES_TXTATR_METAFIELD:
1207 95 : static_txtattr_cast<SwTextMeta*>(pAttr)->ChgTextNode(0);
1208 95 : break;
1209 :
1210 : default:
1211 101098 : break;
1212 : }
1213 :
1214 107221 : SwTextAttr::Destroy( pAttr, pDoc->GetAttrPool() );
1215 : }
1216 107221 : }
1217 :
1218 6563 : SwTextAttr* SwTextNode::InsertItem(
1219 : SfxPoolItem& rAttr,
1220 : const sal_Int32 nStart,
1221 : const sal_Int32 nEnd,
1222 : const SetAttrMode nMode )
1223 : {
1224 : // character attributes will be inserted as automatic styles:
1225 : OSL_ENSURE( !isCHRATR(rAttr.Which()), "AUTOSTYLES - "
1226 : "SwTextNode::InsertItem should not be called with character attributes");
1227 :
1228 : SwTextAttr *const pNew =
1229 : MakeTextAttr(
1230 6563 : *GetDoc(),
1231 : rAttr,
1232 : nStart,
1233 : nEnd,
1234 13126 : (nMode & SetAttrMode::IS_COPY) ? COPY : NEW,
1235 13126 : this );
1236 :
1237 6563 : if ( pNew )
1238 : {
1239 6563 : const bool bSuccess( InsertHint( pNew, nMode ) );
1240 : // N.B.: also check that the hint is actually in the hints array,
1241 : // because hints of certain types may be merged after successful
1242 : // insertion, and thus destroyed!
1243 6563 : if (!bSuccess || !m_pSwpHints->Contains( pNew ))
1244 : {
1245 10 : return 0;
1246 : }
1247 : }
1248 :
1249 6553 : return pNew;
1250 : }
1251 :
1252 : // take ownership of pAttr; if insertion fails, delete pAttr
1253 82499 : bool SwTextNode::InsertHint( SwTextAttr * const pAttr, const SetAttrMode nMode )
1254 : {
1255 82499 : bool bHiddenPara = false;
1256 :
1257 : OSL_ENSURE( pAttr && pAttr->GetStart() <= Len(), "StartIdx out of bounds!" );
1258 : OSL_ENSURE( !pAttr->GetEnd() || (*pAttr->GetEnd() <= Len()),
1259 : "EndIdx out of bounds!" );
1260 :
1261 : // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR)
1262 : const SwInsertFlags nInsertFlags =
1263 164998 : (nMode & SetAttrMode::FORCEHINTEXPAND)
1264 82529 : ? (SwInsertFlags::FORCEHINTEXPAND | SwInsertFlags::EMPTYEXPAND)
1265 82529 : : SwInsertFlags::EMPTYEXPAND;
1266 :
1267 : // need this after TryInsertHint, when pAttr may be deleted
1268 82499 : const sal_Int32 nStart( pAttr->GetStart() );
1269 82499 : const bool bDummyChar( pAttr->HasDummyChar() );
1270 82499 : if (bDummyChar)
1271 : {
1272 6099 : SetAttrMode nInsMode = nMode;
1273 6099 : switch( pAttr->Which() )
1274 : {
1275 : case RES_TXTATR_FLYCNT:
1276 : {
1277 3653 : SwTextFlyCnt *pFly = static_cast<SwTextFlyCnt *>(pAttr);
1278 3653 : SwFrameFormat* pFormat = pAttr->GetFlyCnt().GetFrameFormat();
1279 :
1280 : // In order to maintain data coherency, if the hint is a fly
1281 : // moved from a text node to another, we have to remove it from
1282 : // the first textnode then to add it to the new (this) textnode
1283 3653 : const SwFormatAnchor* pAnchor = 0;
1284 : pFormat->GetItemState( RES_ANCHOR, false,
1285 3653 : reinterpret_cast<const SfxPoolItem**>(&pAnchor) );
1286 :
1287 3653 : SwIndex aIdx( this, pAttr->GetStart() );
1288 :
1289 3653 : bool bChangeFlyParentNode( false );
1290 10979 : if (pAnchor &&
1291 7286 : pAnchor->GetAnchorId() == FLY_AS_CHAR &&
1292 14552 : pAnchor->GetContentAnchor() &&
1293 14552 : pAnchor->GetContentAnchor()->nNode != *this)
1294 : {
1295 : assert(pAnchor->GetContentAnchor()->nNode.GetNode().IsTextNode());
1296 890 : SwTextNode* textNode = pAnchor->GetContentAnchor()->nNode.GetNode().GetTextNode();
1297 :
1298 890 : if ( textNode->IsModifyLocked() )
1299 : {
1300 : // Fly parent has changed but the FlyFormat is locked, so it will
1301 : // not be updated by SetAnchor (that calls Modify that updates
1302 : // relationships)
1303 0 : textNode->RemoveAnchoredFly( pFormat );
1304 0 : bChangeFlyParentNode = true;
1305 : }
1306 : }
1307 :
1308 3653 : if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
1309 : {
1310 :
1311 : // Wir muessen zuerst einfuegen, da in SetAnchor()
1312 : // dem FlyFrm GetStart() uebermittelt wird.
1313 : //JP 11.05.98: falls das Anker-Attribut schon richtig
1314 : // gesetzt ist, dann korrigiere dieses nach dem Einfuegen
1315 : // des Zeichens. Sonst muesste das immer ausserhalb
1316 : // erfolgen (Fehleranfaellig !)
1317 :
1318 3472 : const OUString c(GetCharOfTextAttr(*pAttr));
1319 6944 : OUString const ins( InsertText(c, aIdx, nInsertFlags) );
1320 3472 : if (ins.isEmpty())
1321 : {
1322 : // do not record deletion of Format!
1323 : ::sw::UndoGuard const ug(
1324 0 : pFormat->GetDoc()->GetIDocumentUndoRedo());
1325 0 : DestroyAttr(pAttr);
1326 0 : return false; // text node full :(
1327 : }
1328 3472 : nInsMode |= SetAttrMode::NOTXTATRCHR;
1329 :
1330 10436 : if (pAnchor &&
1331 6924 : (FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
1332 10356 : pAnchor->GetContentAnchor() &&
1333 20043 : pAnchor->GetContentAnchor()->nNode == *this &&
1334 2743 : pAnchor->GetContentAnchor()->nContent == aIdx )
1335 : {
1336 : --const_cast<SwIndex&>(
1337 2680 : pAnchor->GetContentAnchor()->nContent);
1338 3472 : }
1339 : }
1340 3653 : pFly->SetAnchor( this );
1341 :
1342 : // Format-Pointer kann sich im SetAnchor geaendert haben!
1343 : // (Kopieren in andere Docs!)
1344 3653 : pFormat = pAttr->GetFlyCnt().GetFrameFormat();
1345 3653 : SwDoc *pDoc = pFormat->GetDoc();
1346 :
1347 : // OD 26.06.2003 #108784# - allow drawing objects in header/footer.
1348 : // But don't allow control objects in header/footer
1349 6437 : if( RES_DRAWFRMFMT == pFormat->Which() &&
1350 2784 : pDoc->IsInHeaderFooter( pFormat->GetAnchor().GetContentAnchor()->nNode ) )
1351 : {
1352 : SwDrawContact* pDrawContact =
1353 118 : static_cast<SwDrawContact*>(pFormat->FindContactObj());
1354 233 : if ( pDrawContact &&
1355 233 : pDrawContact->GetMaster() &&
1356 115 : ::CheckControlLayer( pDrawContact->GetMaster() ) )
1357 : {
1358 : // das soll nicht meoglich sein; hier verhindern
1359 : // Der Dtor des TextHints loescht nicht das Zeichen.
1360 : // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1361 : // dieses explizit loeschen
1362 0 : if( SetAttrMode::NOTXTATRCHR & nInsMode )
1363 : {
1364 : // loesche das Zeichen aus dem String !
1365 : OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
1366 : m_Text[pAttr->GetStart()] ||
1367 : CH_TXTATR_INWORD ==
1368 : m_Text[pAttr->GetStart()]),
1369 : "where is my attribute character?" );
1370 0 : m_Text = m_Text.replaceAt(pAttr->GetStart(), 1, "");
1371 : // Indizies Updaten
1372 0 : SwIndex aTmpIdx( this, pAttr->GetStart() );
1373 0 : Update( aTmpIdx, 1, true );
1374 : }
1375 : // do not record deletion of Format!
1376 0 : ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1377 0 : DestroyAttr( pAttr );
1378 0 : return false;
1379 : }
1380 : }
1381 :
1382 : // Finish relationships update now that SetAnchor has fixed part of it.
1383 3653 : if (bChangeFlyParentNode)
1384 0 : AddAnchoredFly( pFormat );
1385 :
1386 3653 : break;
1387 : }
1388 :
1389 : case RES_TXTATR_FTN :
1390 : {
1391 : // Fussnoten, man kommt an alles irgendwie heran.
1392 : // ContentNode erzeugen und in die Inserts-Section stellen
1393 140 : SwDoc *pDoc = GetDoc();
1394 140 : SwNodes &rNodes = pDoc->GetNodes();
1395 :
1396 : // FussNote in nicht Content-/Redline-Bereich einfuegen ??
1397 140 : if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
1398 : {
1399 : // das soll nicht meoglich sein; hier verhindern
1400 : // Der Dtor des TextHints loescht nicht das Zeichen.
1401 : // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1402 : // dieses explizit loeschen
1403 0 : if( SetAttrMode::NOTXTATRCHR & nInsMode )
1404 : {
1405 : // loesche das Zeichen aus dem String !
1406 : OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
1407 : m_Text[pAttr->GetStart()] ||
1408 : CH_TXTATR_INWORD ==
1409 : m_Text[pAttr->GetStart()]),
1410 : "where is my attribute character?" );
1411 0 : m_Text = m_Text.replaceAt(pAttr->GetStart(), 1, "");
1412 : // Indizies Updaten
1413 0 : SwIndex aTmpIdx( this, pAttr->GetStart() );
1414 0 : Update( aTmpIdx, 1, true );
1415 : }
1416 0 : DestroyAttr( pAttr );
1417 0 : return false;
1418 : }
1419 :
1420 : // wird eine neue Fussnote eingefuegt ??
1421 140 : bool bNewFootnote = 0 == static_cast<SwTextFootnote*>(pAttr)->GetStartNode();
1422 140 : if( bNewFootnote )
1423 : {
1424 138 : static_cast<SwTextFootnote*>(pAttr)->MakeNewTextSection( GetNodes() );
1425 138 : SwRegHistory* pHist = GetpSwpHints()
1426 138 : ? GetpSwpHints()->GetHistory() : 0;
1427 138 : if( pHist )
1428 18 : pHist->ChangeNodeIndex( GetIndex() );
1429 : }
1430 2 : else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
1431 : {
1432 : // loesche alle Frames der Section, auf die der StartNode zeigt
1433 : sal_uLong nSttIdx =
1434 2 : static_cast<SwTextFootnote*>(pAttr)->GetStartNode()->GetIndex();
1435 2 : sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
1436 4 : for( ; nSttIdx < nEndIdx; ++nSttIdx )
1437 : {
1438 2 : SwContentNode* pCNd = rNodes[ nSttIdx ]->GetContentNode();
1439 2 : if( 0 != pCNd )
1440 2 : pCNd->DelFrms();
1441 : }
1442 : }
1443 :
1444 140 : if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
1445 : {
1446 : // Wir muessen zuerst einfuegen, da sonst gleiche Indizes
1447 : // entstehen koennen und das Attribut im _SortArr_ am
1448 : // Dokument nicht eingetrage wird.
1449 138 : SwIndex aNdIdx( this, pAttr->GetStart() );
1450 276 : const OUString c(GetCharOfTextAttr(*pAttr));
1451 276 : OUString const ins( InsertText(c, aNdIdx, nInsertFlags) );
1452 138 : if (ins.isEmpty())
1453 : {
1454 0 : DestroyAttr(pAttr);
1455 0 : return false; // text node full :(
1456 : }
1457 276 : nInsMode |= SetAttrMode::NOTXTATRCHR;
1458 : }
1459 :
1460 : // Wir tragen uns am FootnoteIdx-Array des Docs ein ...
1461 140 : SwTextFootnote* pTextFootnote = 0;
1462 140 : if( !bNewFootnote )
1463 : {
1464 : // eine alte Footnote wird umgehaengt (z.B. SplitNode)
1465 2 : for( size_t n = 0; n < pDoc->GetFootnoteIdxs().size(); ++n )
1466 2 : if( pAttr == pDoc->GetFootnoteIdxs()[n] )
1467 : {
1468 : // neuen Index zuweisen, dafuer aus dem SortArray
1469 : // loeschen und neu eintragen
1470 2 : pTextFootnote = pDoc->GetFootnoteIdxs()[n];
1471 2 : pDoc->GetFootnoteIdxs().erase( pDoc->GetFootnoteIdxs().begin() + n );
1472 2 : break;
1473 : }
1474 : // wenn ueber Undo der StartNode gesetzt wurde, kann
1475 : // der Index noch gar nicht in der Verwaltung stehen !!
1476 : }
1477 140 : if( !pTextFootnote )
1478 138 : pTextFootnote = static_cast<SwTextFootnote*>(pAttr);
1479 :
1480 : // fuers Update der Nummern und zum Sortieren
1481 : // muss der Node gesetzt sein.
1482 140 : static_cast<SwTextFootnote*>(pAttr)->ChgTextNode( this );
1483 :
1484 : // FussNote im Redline-Bereich NICHT ins FootnoteArray einfuegen!
1485 140 : if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
1486 : {
1487 140 : const bool bSuccess = pDoc->GetFootnoteIdxs().insert(pTextFootnote).second;
1488 : OSL_ENSURE( bSuccess, "FootnoteIdx not inserted." );
1489 : (void) bSuccess; // unused in non-debug
1490 : }
1491 140 : SwNodeIndex aTmpIndex( *this );
1492 140 : pDoc->GetFootnoteIdxs().UpdateFootnote( aTmpIndex);
1493 140 : static_cast<SwTextFootnote*>(pAttr)->SetSeqRefNo();
1494 : }
1495 140 : break;
1496 :
1497 : case RES_TXTATR_FIELD:
1498 : {
1499 : // fuer HiddenParaFields Benachrichtigungsmechanismus
1500 : // anwerfen
1501 1885 : if( RES_HIDDENPARAFLD == pAttr->GetFormatField().GetField()->GetTyp()->Which() )
1502 : {
1503 0 : bHiddenPara = true;
1504 : }
1505 : }
1506 1885 : break;
1507 :
1508 : }
1509 : // Fuer SwTextHints ohne Endindex werden CH_TXTATR_..
1510 : // eingefuegt, aStart muss danach um einen zurueckgesetzt werden.
1511 : // Wenn wir im SwTextNode::Copy stehen, so wurde das Zeichen bereits
1512 : // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden.
1513 6099 : if( !(SetAttrMode::NOTXTATRCHR & nInsMode) )
1514 : {
1515 1541 : SwIndex aIdx( this, pAttr->GetStart() );
1516 1541 : OUString const ins( InsertText(OUString(GetCharOfTextAttr(*pAttr)),
1517 3082 : aIdx, nInsertFlags) );
1518 1541 : if (ins.isEmpty())
1519 : {
1520 0 : DestroyAttr(pAttr);
1521 0 : return false; // text node full :(
1522 : }
1523 :
1524 : // adjust end of hint to account for inserted CH_TXTATR
1525 1541 : sal_Int32 * const pEnd(pAttr->GetEnd());
1526 1541 : if (pEnd)
1527 : {
1528 97 : *pEnd = *pEnd + 1;
1529 1541 : }
1530 : }
1531 : }
1532 :
1533 : // handle attributes which provide content
1534 82499 : sal_Int32 nEnd = nStart;
1535 82499 : bool bInputFieldStartCharInserted = false;
1536 82499 : bool bInputFieldEndCharInserted = false;
1537 82499 : const bool bHasContent( pAttr->HasContent() );
1538 82499 : if ( bHasContent )
1539 : {
1540 18 : switch( pAttr->Which() )
1541 : {
1542 : case RES_TXTATR_INPUTFIELD:
1543 : {
1544 18 : SwTextInputField* pTextInputField = dynamic_cast<SwTextInputField*>(pAttr);
1545 18 : if ( pTextInputField )
1546 : {
1547 18 : if( !(SetAttrMode::NOTXTATRCHR & nMode) )
1548 : {
1549 14 : SwIndex aIdx( this, pAttr->GetStart() );
1550 14 : InsertText( OUString(CH_TXT_ATR_INPUTFIELDSTART), aIdx, nInsertFlags );
1551 28 : const OUString aContent = pTextInputField->GetFieldContent();
1552 14 : InsertText( aContent, aIdx, nInsertFlags );
1553 14 : InsertText( OUString(CH_TXT_ATR_INPUTFIELDEND), aIdx, nInsertFlags );
1554 :
1555 14 : sal_Int32* const pEnd(pAttr->GetEnd());
1556 : OSL_ENSURE( pEnd != NULL, "<SwTextNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1557 14 : if ( pEnd != NULL )
1558 : {
1559 14 : *pEnd = *pEnd + 2 + aContent.getLength();
1560 14 : nEnd = *pEnd;
1561 14 : }
1562 : }
1563 : else
1564 : {
1565 : // assure that CH_TXT_ATR_INPUTFIELDSTART and CH_TXT_ATR_INPUTFIELDEND are inserted.
1566 4 : if ( m_Text[ pAttr->GetStart() ] != CH_TXT_ATR_INPUTFIELDSTART )
1567 : {
1568 0 : SwIndex aIdx( this, pAttr->GetStart() );
1569 0 : InsertText( OUString(CH_TXT_ATR_INPUTFIELDSTART), aIdx, nInsertFlags );
1570 0 : bInputFieldStartCharInserted = true;
1571 0 : sal_Int32* const pEnd(pAttr->GetEnd());
1572 : OSL_ENSURE( pEnd != NULL, "<SwTextNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1573 0 : if ( pEnd != NULL )
1574 : {
1575 0 : *pEnd = *pEnd + 1;
1576 0 : nEnd = *pEnd;
1577 0 : }
1578 : }
1579 :
1580 4 : sal_Int32* const pEnd(pAttr->GetEnd());
1581 : OSL_ENSURE( pEnd != NULL, "<SwTextNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1582 4 : if ( pEnd != NULL
1583 4 : && m_Text[ *(pEnd) - 1 ] != CH_TXT_ATR_INPUTFIELDEND )
1584 : {
1585 0 : SwIndex aIdx( this, *(pEnd) );
1586 0 : InsertText( OUString(CH_TXT_ATR_INPUTFIELDEND), aIdx, nInsertFlags );
1587 0 : bInputFieldEndCharInserted = true;
1588 0 : *pEnd = *pEnd + 1;
1589 0 : nEnd = *pEnd;
1590 : }
1591 : }
1592 : }
1593 : }
1594 18 : break;
1595 : default:
1596 0 : break;
1597 : }
1598 : }
1599 :
1600 82499 : GetOrCreateSwpHints();
1601 :
1602 : // handle overlap with an existing InputField
1603 82499 : bool bInsertHint = true;
1604 : {
1605 82499 : const SwTextInputField* pTextInputField = GetOverlappingInputField( *pAttr );
1606 82499 : if ( pTextInputField != NULL )
1607 : {
1608 0 : if ( pAttr->End() == NULL )
1609 : {
1610 0 : bInsertHint = false;
1611 : }
1612 : else
1613 : {
1614 0 : if ( pAttr->GetStart() > pTextInputField->GetStart() )
1615 : {
1616 0 : pAttr->GetStart() = pTextInputField->GetStart();
1617 : }
1618 0 : if ( *(pAttr->End()) < *(pTextInputField->End()) )
1619 : {
1620 0 : *(pAttr->GetEnd()) = *(pTextInputField->End());
1621 : }
1622 : }
1623 : }
1624 : }
1625 :
1626 : // 4263: AttrInsert durch TextInsert => kein Adjust
1627 : const bool bRet = bInsertHint
1628 82499 : && m_pSwpHints->TryInsertHint( pAttr, *this, nMode );
1629 :
1630 82499 : if ( !bRet )
1631 : {
1632 4 : if ( bDummyChar
1633 6 : && !(SetAttrMode::NOTXTATRCHR & nMode) )
1634 : {
1635 : // undo insertion of dummy character
1636 : // N.B. cannot insert the dummy character after inserting the hint,
1637 : // because if the hint has no extent it will be moved in InsertText,
1638 : // resulting in infinite recursion
1639 : OSL_ENSURE( ( CH_TXTATR_BREAKWORD == m_Text[nStart] ||
1640 : CH_TXTATR_INWORD == m_Text[nStart] ),
1641 : "where is my attribute character?" );
1642 2 : SwIndex aIdx( this, nStart );
1643 2 : EraseText( aIdx, 1 );
1644 : }
1645 :
1646 2 : if ( bHasContent )
1647 : {
1648 0 : if ( !(SetAttrMode::NOTXTATRCHR & nMode)
1649 0 : && (nEnd - nStart) > 0 )
1650 : {
1651 0 : SwIndex aIdx( this, nStart );
1652 0 : EraseText( aIdx, (nEnd - nStart) );
1653 : }
1654 : else
1655 : {
1656 0 : if ( bInputFieldEndCharInserted
1657 0 : && (nEnd - nStart) > 0 )
1658 : {
1659 0 : SwIndex aIdx( this, nEnd - 1 );
1660 0 : EraseText( aIdx, 1 );
1661 : }
1662 :
1663 0 : if ( bInputFieldStartCharInserted )
1664 : {
1665 0 : SwIndex aIdx( this, nStart );
1666 0 : EraseText( aIdx, 1 );
1667 : }
1668 : }
1669 : }
1670 : }
1671 :
1672 82499 : if ( bHiddenPara )
1673 : {
1674 0 : SetCalcHiddenParaField();
1675 : }
1676 :
1677 82499 : return bRet;
1678 : }
1679 :
1680 1368 : void SwTextNode::DeleteAttribute( SwTextAttr * const pAttr )
1681 : {
1682 1368 : if ( !HasHints() )
1683 : {
1684 : OSL_FAIL("DeleteAttribute called, but text node without hints?");
1685 1368 : return;
1686 : }
1687 :
1688 1368 : if ( pAttr->HasDummyChar() )
1689 : {
1690 : // Unbedingt Copy-konstruieren!
1691 1368 : const SwIndex aIdx( this, pAttr->GetStart() );
1692 : // erase the CH_TXTATR, which will also delete pAttr
1693 1368 : EraseText( aIdx, 1 );
1694 : }
1695 0 : else if ( pAttr->HasContent() )
1696 : {
1697 0 : const SwIndex aIdx( this, pAttr->GetStart() );
1698 : OSL_ENSURE( pAttr->End() != NULL, "<SwTextNode::DeleteAttribute(..)> - missing End() at <SwTextAttr> instance which has content" );
1699 0 : EraseText( aIdx, *pAttr->End() - pAttr->GetStart() );
1700 : }
1701 : else
1702 : {
1703 : // create MsgHint before start/end become invalid
1704 : SwUpdateAttr aHint(
1705 0 : pAttr->GetStart(),
1706 0 : *pAttr->GetEnd(),
1707 0 : pAttr->Which());
1708 :
1709 0 : m_pSwpHints->Delete( pAttr );
1710 0 : SwTextAttr::Destroy( pAttr, GetDoc()->GetAttrPool() );
1711 0 : NotifyClients( 0, &aHint );
1712 :
1713 0 : TryDeleteSwpHints();
1714 : }
1715 : }
1716 :
1717 : //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
1718 2264 : void SwTextNode::DeleteAttributes(
1719 : const sal_uInt16 nWhich,
1720 : const sal_Int32 nStart,
1721 : const sal_Int32 nEnd )
1722 : {
1723 2264 : if ( !HasHints() )
1724 2264 : return;
1725 :
1726 4797 : for ( size_t nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); ++nPos )
1727 : {
1728 2569 : SwTextAttr * const pTextHt = m_pSwpHints->GetTextHint( nPos );
1729 2569 : const sal_Int32 nHintStart = pTextHt->GetStart();
1730 2569 : if (nStart < nHintStart)
1731 : {
1732 36 : break; // sorted by start
1733 : }
1734 2533 : else if ( (nStart == nHintStart) && (nWhich == pTextHt->Which()) )
1735 : {
1736 2263 : if ( nWhich == RES_CHRATR_HIDDEN )
1737 : {
1738 : OSL_FAIL("hey, that's a CHRATR! how did that get in?");
1739 0 : SetCalcHiddenCharFlags();
1740 : }
1741 2263 : else if ( nWhich == RES_TXTATR_CHARFMT )
1742 : {
1743 : // Check if character format contains hidden attribute:
1744 0 : const SwCharFormat* pFormat = pTextHt->GetCharFormat().GetCharFormat();
1745 : const SfxPoolItem* pItem;
1746 0 : if ( SfxItemState::SET == pFormat->GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) )
1747 0 : SetCalcHiddenCharFlags();
1748 : }
1749 : // #i75430# Recalc hidden flags if necessary
1750 2263 : else if ( nWhich == RES_TXTATR_AUTOFMT )
1751 : {
1752 : // Check if auto style contains hidden attribute:
1753 1 : const SfxPoolItem* pHiddenItem = CharFormat::GetItem( *pTextHt, RES_CHRATR_HIDDEN );
1754 1 : if ( pHiddenItem )
1755 0 : SetCalcHiddenCharFlags();
1756 : // for auto styles DeleteAttributes is only called from Undo
1757 : // so it shouldn't need to care about ignore start/end flags
1758 : }
1759 :
1760 2263 : sal_Int32 const * const pEndIdx = pTextHt->GetEnd();
1761 :
1762 2263 : if ( pTextHt->HasDummyChar() )
1763 : {
1764 : // Unbedingt Copy-konstruieren!
1765 2262 : const SwIndex aIdx( this, nStart );
1766 : // erase the CH_TXTATR, which will also delete pTextHt
1767 2262 : EraseText( aIdx, 1 );
1768 : }
1769 1 : else if ( pTextHt->HasContent() )
1770 : {
1771 0 : const SwIndex aIdx( this, nStart );
1772 : OSL_ENSURE( pTextHt->End() != NULL, "<SwTextNode::DeleteAttributes(..)> - missing End() at <SwTextAttr> instance which has content" );
1773 0 : EraseText( aIdx, *pTextHt->End() - nStart );
1774 : }
1775 1 : else if( *pEndIdx == nEnd )
1776 : {
1777 : // den MsgHint jetzt fuettern, weil gleich sind
1778 : // Start und End weg.
1779 : // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
1780 : // da dies das Feld im Dtor selbst erledigt.
1781 : SwUpdateAttr aHint(
1782 : nStart,
1783 : *pEndIdx,
1784 1 : nWhich);
1785 :
1786 1 : m_pSwpHints->DeleteAtPos( nPos ); // gefunden, loeschen,
1787 1 : SwTextAttr::Destroy( pTextHt, GetDoc()->GetAttrPool() );
1788 1 : NotifyClients( 0, &aHint );
1789 : }
1790 : }
1791 : }
1792 2264 : TryDeleteSwpHints();
1793 : }
1794 :
1795 0 : void SwTextNode::DelSoftHyph( const sal_Int32 nStt, const sal_Int32 nEnd )
1796 : {
1797 0 : sal_Int32 nFndPos = nStt;
1798 0 : sal_Int32 nEndPos = nEnd;
1799 : for (;;)
1800 : {
1801 0 : nFndPos = m_Text.indexOf(CHAR_SOFTHYPHEN, nFndPos);
1802 0 : if (nFndPos<0 || nFndPos>=nEndPos )
1803 : {
1804 : break;
1805 : }
1806 0 : const SwIndex aIdx( this, nFndPos );
1807 0 : EraseText( aIdx, 1 );
1808 0 : --nEndPos;
1809 0 : }
1810 0 : }
1811 :
1812 3966 : bool SwTextNode::IsIgnoredCharFormatForNumbering(const sal_uInt16 nWhich)
1813 : {
1814 3966 : return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_COLOR || nWhich == RES_CHRATR_BACKGROUND || nWhich == RES_CHRATR_ESCAPEMENT);
1815 : }
1816 :
1817 : //In MS Word, following properties of the paragraph end position wont affect the formatting of bullets, so we ignore them:
1818 : //Font underline;
1819 : //Font Italic of Western, CJK and CTL;
1820 : //Font Bold of Wertern, CJK and CTL;
1821 55 : bool lcl_IsIgnoredCharFormatForBullets(const sal_uInt16 nWhich)
1822 : {
1823 55 : return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_POSTURE || nWhich == RES_CHRATR_WEIGHT
1824 50 : || nWhich == RES_CHRATR_CJK_POSTURE || nWhich == RES_CHRATR_CJK_WEIGHT
1825 100 : || nWhich == RES_CHRATR_CTL_POSTURE || nWhich == RES_CHRATR_CTL_WEIGHT);
1826 : }
1827 :
1828 : //Condition for expanding char set to character style of specified number rule level:
1829 : //The item inside the set should not conflict to any exist and non-default item inside paragraph properties set (SwContentNode::SwPAttrSet);
1830 : //The node should have applied a number rule;
1831 : //The node should be counted in a list, if not, make it to be;
1832 : //The item should not conflict to any exist and non-default item inside the character of specified number rule level;
1833 : //The item should not be ignored depend on the exact number rule type;
1834 5825 : bool SwTextNode::TryCharSetExpandToNum(const SfxItemSet& aCharSet)
1835 : {
1836 5825 : bool bRet = false;
1837 5825 : SfxItemIter aIter( aCharSet );
1838 5825 : const SfxPoolItem* pItem = aIter.FirstItem();
1839 5825 : const sal_uInt16 nWhich = pItem->Which();
1840 :
1841 5825 : const SfxPoolItem& rInnerItem = GetAttr(nWhich,false);
1842 :
1843 5825 : if (!IsDefaultItem(&rInnerItem) && !IsInvalidItem(&rInnerItem))
1844 4849 : return bRet;
1845 :
1846 976 : if (!IsInList() && GetNumRule() && !GetListId().isEmpty())
1847 : {
1848 0 : return bRet;
1849 : }
1850 :
1851 976 : SwNumRule* pCurrNum = GetNumRule(false);
1852 :
1853 976 : int nLevel = GetActualListLevel();
1854 :
1855 976 : if (nLevel != -1 && pCurrNum)
1856 : {
1857 63 : const SwNumFormat* pCurrNumFormat = pCurrNum->GetNumFormat(static_cast<sal_uInt16>(nLevel));
1858 63 : if (pCurrNumFormat)
1859 : {
1860 63 : if (pCurrNumFormat->IsItemize() && lcl_IsIgnoredCharFormatForBullets(nWhich))
1861 15 : return bRet;
1862 48 : if (pCurrNumFormat->IsEnumeration() && SwTextNode::IsIgnoredCharFormatForNumbering(nWhich))
1863 1 : return bRet;
1864 47 : SwCharFormat* pCurrCharFormat =pCurrNumFormat->GetCharFormat();
1865 :
1866 47 : if (pCurrCharFormat && pCurrCharFormat->GetItemState(nWhich,false) != SfxItemState::SET)
1867 : {
1868 11 : pCurrCharFormat->SetFormatAttr(*pItem);
1869 11 : SwNumFormat aNewNumFormat(*pCurrNumFormat);
1870 11 : aNewNumFormat.SetCharFormat(pCurrCharFormat);
1871 11 : pCurrNum->Set(nLevel,aNewNumFormat);
1872 11 : bRet = true;
1873 : }
1874 : }
1875 : }
1876 :
1877 960 : return bRet;
1878 : }
1879 :
1880 : // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
1881 : // dann setze sie nur im AutoAttrSet (SwContentNode:: SetAttr)
1882 101786 : bool SwTextNode::SetAttr(
1883 : const SfxItemSet& rSet,
1884 : const sal_Int32 nStt,
1885 : const sal_Int32 nEnd,
1886 : const SetAttrMode nMode )
1887 : {
1888 101786 : if( !rSet.Count() )
1889 0 : return false;
1890 :
1891 : // teil die Sets auf (fuer Selektion in Nodes)
1892 101786 : const SfxItemSet* pSet = &rSet;
1893 101786 : SfxItemSet aTextSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
1894 :
1895 : // gesamter Bereich
1896 346837 : if ( !nStt && (nEnd == m_Text.getLength()) &&
1897 226223 : !(nMode & SetAttrMode::NOFORMATATTR ) )
1898 : {
1899 : // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
1900 : // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
1901 30468 : bool bHasCharFormats = false;
1902 30468 : if ( HasHints() )
1903 : {
1904 14539 : for ( size_t n = 0; n < m_pSwpHints->Count(); ++n )
1905 : {
1906 9074 : if ( (*m_pSwpHints)[ n ]->IsCharFormatAttr() )
1907 : {
1908 403 : bHasCharFormats = true;
1909 403 : break;
1910 : }
1911 : }
1912 : }
1913 :
1914 30468 : if( !bHasCharFormats )
1915 : {
1916 30065 : aTextSet.Put( rSet );
1917 : // If there are any character attributes in rSet,
1918 : // we want to set them at the paragraph:
1919 30065 : if( aTextSet.Count() != rSet.Count() )
1920 : {
1921 27109 : const bool bRet = SetAttr( rSet );
1922 27109 : if( !aTextSet.Count() )
1923 55580 : return bRet;
1924 : }
1925 :
1926 : // check for auto style:
1927 : const SfxPoolItem* pItem;
1928 3017 : const bool bAutoStyle = SfxItemState::SET == aTextSet.GetItemState( RES_TXTATR_AUTOFMT, false, &pItem );
1929 3017 : if ( bAutoStyle )
1930 : {
1931 1484 : std::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFormatAutoFormat*>(pItem)->GetStyleHandle();
1932 1484 : const bool bRet = SetAttr( *pAutoStyleSet );
1933 1484 : if( 1 == aTextSet.Count() )
1934 1484 : return bRet;
1935 : }
1936 :
1937 : // Continue with the text attributes:
1938 1533 : pSet = &aTextSet;
1939 : }
1940 : }
1941 :
1942 73254 : GetOrCreateSwpHints();
1943 :
1944 146508 : SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFormatSetRange );
1945 :
1946 73254 : size_t nCount = 0;
1947 146508 : SfxItemIter aIter( *pSet );
1948 73254 : const SfxPoolItem* pItem = aIter.GetCurItem();
1949 :
1950 : do
1951 : {
1952 224590 : if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
1953 : {
1954 224590 : const sal_uInt16 nWhich = pItem->Which();
1955 : OSL_ENSURE( isCHRATR(nWhich) || isTXTATR(nWhich),
1956 : "SwTextNode::SetAttr(): unknown attribute" );
1957 224590 : if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
1958 : {
1959 230586 : if ((RES_TXTATR_CHARFMT == nWhich) &&
1960 5996 : (GetDoc()->GetDfltCharFormat() ==
1961 5996 : static_cast<const SwFormatCharFormat*>(pItem)->GetCharFormat()))
1962 : {
1963 0 : SwIndex aIndex( this, nStt );
1964 0 : RstTextAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
1965 0 : DontExpandFormat( aIndex );
1966 : }
1967 : else
1968 : {
1969 224590 : if (isCHRATR(nWhich) ||
1970 : (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1971 : {
1972 212897 : aCharSet.Put( *pItem );
1973 : }
1974 : else
1975 : {
1976 :
1977 11693 : SwTextAttr *const pNew = MakeTextAttr( *GetDoc(),
1978 11693 : const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
1979 11693 : if ( pNew )
1980 : {
1981 11693 : if ( nEnd != nStt && !pNew->GetEnd() )
1982 : {
1983 : OSL_FAIL("Attribut without end, but area marked");
1984 0 : DestroyAttr( pNew ); // do not insert
1985 : }
1986 11693 : else if ( InsertHint( pNew, nMode ) )
1987 : {
1988 11691 : ++nCount;
1989 : }
1990 : }
1991 : }
1992 : }
1993 : }
1994 : }
1995 224590 : if ( aIter.IsAtEnd() )
1996 73254 : break;
1997 151336 : pItem = aIter.NextItem();
1998 : } while( true );
1999 :
2000 73254 : if ( aCharSet.Count() )
2001 : {
2002 62673 : SwTextAttr* pTmpNew = MakeTextAttr( *GetDoc(), aCharSet, nStt, nEnd );
2003 62673 : if ( InsertHint( pTmpNew, nMode ) )
2004 : {
2005 62673 : ++nCount;
2006 : }
2007 : }
2008 :
2009 73254 : TryDeleteSwpHints();
2010 :
2011 175040 : return nCount != 0;
2012 : }
2013 :
2014 5101 : static void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
2015 : {
2016 5101 : if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
2017 : {
2018 4446 : const SfxItemSet* pCFSet = CharFormat::GetItemSet( rAttr );
2019 4446 : if ( !pCFSet )
2020 5101 : return;
2021 4446 : SfxWhichIter aIter( *pCFSet );
2022 4446 : sal_uInt16 nWhich = aIter.FirstWhich();
2023 217849 : while( nWhich )
2024 : {
2025 217844 : if( ( nWhich < RES_CHRATR_END ||
2026 413468 : RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
2027 204511 : ( SfxItemState::SET == pCFSet->GetItemState( nWhich, true ) ) )
2028 30187 : rSet.Put( pCFSet->Get( nWhich ) );
2029 208957 : nWhich = aIter.NextWhich();
2030 4446 : }
2031 : }
2032 : else
2033 655 : rSet.Put( rAttr );
2034 : }
2035 :
2036 57609 : static void lcl_MergeAttr_ExpandChrFormat( SfxItemSet& rSet, const SfxPoolItem& rAttr )
2037 : {
2038 168678 : if( RES_TXTATR_CHARFMT == rAttr.Which() ||
2039 109718 : RES_TXTATR_INETFMT == rAttr.Which() ||
2040 52109 : RES_TXTATR_AUTOFMT == rAttr.Which() )
2041 : {
2042 53763 : const SfxItemSet* pCFSet = CharFormat::GetItemSet( rAttr );
2043 :
2044 53763 : if ( pCFSet )
2045 : {
2046 53702 : SfxWhichIter aIter( *pCFSet );
2047 53702 : sal_uInt16 nWhich = aIter.FirstWhich();
2048 2625942 : while( nWhich )
2049 : {
2050 2620486 : if( ( nWhich < RES_CHRATR_END ||
2051 5079883 : ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
2052 2464836 : ( SfxItemState::SET == pCFSet->GetItemState( nWhich, true ) ) )
2053 249885 : rSet.Put( pCFSet->Get( nWhich ) );
2054 2518538 : nWhich = aIter.NextWhich();
2055 53702 : }
2056 : }
2057 : }
2058 :
2059 : // aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
2060 :
2061 : /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
2062 : z.B
2063 : 1234567890123456789
2064 : |------------| Font1
2065 : |------| Font2
2066 : ^ ^
2067 : |--| Abfragebereich: -> Gueltig ist Font2
2068 : */
2069 57609 : rSet.Put( rAttr );
2070 57609 : }
2071 :
2072 : struct SwPoolItemEndPair
2073 : {
2074 : public:
2075 : const SfxPoolItem* mpItem;
2076 : sal_Int32 mnEndPos;
2077 :
2078 81455 : SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
2079 : };
2080 :
2081 13910 : static void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTextNode& rTextNode,
2082 : SfxItemSet& rSet )
2083 : {
2084 13910 : if ( rTextNode.AreListLevelIndentsApplicable() )
2085 : {
2086 3 : const SwNumRule* pRule = rTextNode.GetNumRule();
2087 3 : if ( pRule && rTextNode.GetActualListLevel() >= 0 )
2088 : {
2089 3 : const SwNumFormat& rFormat = pRule->Get(static_cast<sal_uInt16>(rTextNode.GetActualListLevel()));
2090 3 : if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2091 : {
2092 3 : SvxLRSpaceItem aLR( RES_LR_SPACE );
2093 3 : aLR.SetTextLeft( rFormat.GetIndentAt() );
2094 3 : aLR.SetTextFirstLineOfst( static_cast<short>(rFormat.GetFirstLineIndent()) );
2095 3 : rSet.Put( aLR );
2096 : }
2097 : }
2098 : }
2099 13910 : }
2100 :
2101 : // erfrage die Attribute vom TextNode ueber den Bereich
2102 189192 : bool SwTextNode::GetAttr( SfxItemSet& rSet, sal_Int32 nStt, sal_Int32 nEnd,
2103 : const bool bOnlyTextAttr, const bool bGetFromChrFormat,
2104 : const bool bMergeIndentValuesOfNumRule ) const
2105 : {
2106 189192 : if( HasHints() )
2107 : {
2108 : /* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
2109 : * sind. Dabei gibt es folgende Faelle:
2110 : * UnEindeutig wenn: (wenn != Format-Attribut)
2111 : * - das Attribut liegt vollstaendig im Bereich
2112 : * - das Attributende liegt im Bereich
2113 : * - der Attributanfang liegt im Bereich:
2114 : * Eindeutig (im Set mergen):
2115 : * - das Attrib umfasst den Bereich
2116 : * nichts tun:
2117 : * das Attribut liegt ausserhalb des Bereiches
2118 : */
2119 :
2120 : void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
2121 : = bGetFromChrFormat ? &lcl_MergeAttr_ExpandChrFormat
2122 77020 : : &lcl_MergeAttr;
2123 :
2124 : // dann besorge mal die Auto-(Format)Attribute
2125 77020 : SfxItemSet aFormatSet( *rSet.GetPool(), rSet.GetRanges() );
2126 77020 : if( !bOnlyTextAttr )
2127 : {
2128 72041 : SwContentNode::GetAttr( aFormatSet );
2129 72041 : if ( bMergeIndentValuesOfNumRule )
2130 : {
2131 396 : lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFormatSet );
2132 : }
2133 : }
2134 :
2135 77020 : const size_t nSize = m_pSwpHints->Count();
2136 :
2137 77020 : if( nStt == nEnd ) // kein Bereich:
2138 : {
2139 197883 : for (size_t n = 0; n < nSize; ++n)
2140 : {
2141 168878 : const SwTextAttr* pHt = (*m_pSwpHints)[n];
2142 168878 : const sal_Int32 nAttrStart = pHt->GetStart();
2143 168878 : if( nAttrStart > nEnd ) // ueber den Bereich hinaus
2144 63 : break;
2145 :
2146 168815 : const sal_Int32* pAttrEnd = pHt->End();
2147 168815 : if ( ! pAttrEnd ) // no attributes without end
2148 118971 : continue;
2149 :
2150 86612 : if( ( nAttrStart < nStt &&
2151 38966 : ( pHt->DontExpand() ? nStt < *pAttrEnd
2152 184094 : : nStt <= *pAttrEnd )) ||
2153 13076 : ( nStt == nAttrStart &&
2154 13256 : ( nAttrStart == *pAttrEnd || !nStt )))
2155 34986 : (*fnMergeAttr)( rSet, pHt->GetAttr() );
2156 : }
2157 : }
2158 : else // es ist ein Bereich definiert
2159 : {
2160 : // #i75299#
2161 47952 : std::unique_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
2162 :
2163 47952 : const size_t coArrSz = RES_TXTATR_WITHEND_END - RES_CHRATR_BEGIN;
2164 :
2165 179758 : for (size_t n = 0; n < nSize; ++n)
2166 : {
2167 132814 : const SwTextAttr* pHt = (*m_pSwpHints)[n];
2168 132814 : const sal_Int32 nAttrStart = pHt->GetStart();
2169 132814 : if( nAttrStart > nEnd ) // ueber den Bereich hinaus
2170 1008 : break;
2171 :
2172 131806 : const sal_Int32* pAttrEnd = pHt->End();
2173 131806 : if ( ! pAttrEnd ) // no attributes without end
2174 4976 : continue;
2175 :
2176 126830 : bool bChkInvalid = false;
2177 126830 : if( nAttrStart <= nStt ) // vor oder genau Start
2178 : {
2179 103583 : if( *pAttrEnd <= nStt ) // liegt davor
2180 77146 : continue;
2181 :
2182 26437 : if( nEnd <= *pAttrEnd ) // hinter oder genau Ende
2183 25612 : (*fnMergeAttr)( aFormatSet, pHt->GetAttr() );
2184 : else
2185 : // else if( pHt->GetAttr() != aFormatSet.Get( pHt->Which() ) )
2186 : // uneindeutig
2187 825 : bChkInvalid = true;
2188 : }
2189 23247 : else if( nAttrStart < nEnd // reicht in den Bereich
2190 : )// && pHt->GetAttr() != aFormatSet.Get( pHt->Which() ) )
2191 2359 : bChkInvalid = true;
2192 :
2193 49684 : if( bChkInvalid )
2194 : {
2195 : // uneindeutig ?
2196 3184 : std::unique_ptr< SfxItemIter > pItemIter;
2197 3184 : const SfxPoolItem* pItem = 0;
2198 :
2199 3184 : if ( RES_TXTATR_AUTOFMT == pHt->Which() )
2200 : {
2201 2596 : const SfxItemSet* pAutoSet = CharFormat::GetItemSet( pHt->GetAttr() );
2202 2596 : if ( pAutoSet )
2203 : {
2204 2596 : pItemIter.reset( new SfxItemIter( *pAutoSet ) );
2205 2596 : pItem = pItemIter->GetCurItem();
2206 : }
2207 : }
2208 : else
2209 588 : pItem = &pHt->GetAttr();
2210 :
2211 3184 : const sal_Int32 nHintEnd = *pAttrEnd;
2212 :
2213 16044 : while ( pItem )
2214 : {
2215 9676 : const sal_uInt16 nHintWhich = pItem->Which();
2216 : OSL_ENSURE(!isUNKNOWNATR(nHintWhich),
2217 : "SwTextNode::GetAttr(): unknown attribute?");
2218 :
2219 9676 : if ( !pAttrArr.get() )
2220 : {
2221 : pAttrArr.reset(
2222 1481 : new std::vector< SwPoolItemEndPair >(coArrSz));
2223 : }
2224 :
2225 9676 : std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
2226 10264 : if (isCHRATR(nHintWhich) ||
2227 588 : isTXTATR_WITHEND(nHintWhich))
2228 : {
2229 9676 : pPrev += nHintWhich - RES_CHRATR_BEGIN;
2230 : }
2231 : else
2232 : {
2233 0 : pPrev = pAttrArr->end();
2234 : }
2235 :
2236 9676 : if( pPrev != pAttrArr->end() )
2237 : {
2238 9676 : if( !pPrev->mpItem )
2239 : {
2240 4655 : if ( bOnlyTextAttr || *pItem != aFormatSet.Get( nHintWhich ) )
2241 : {
2242 3842 : if( nAttrStart > nStt )
2243 : {
2244 586 : rSet.InvalidateItem( nHintWhich );
2245 586 : pPrev->mpItem = reinterpret_cast<SfxPoolItem*>(-1);
2246 : }
2247 : else
2248 : {
2249 3256 : pPrev->mpItem = pItem;
2250 3256 : pPrev->mnEndPos = nHintEnd;
2251 : }
2252 : }
2253 : }
2254 5021 : else if( reinterpret_cast<SfxPoolItem*>(-1) != pPrev->mpItem )
2255 : {
2256 8150 : if( pPrev->mnEndPos == nAttrStart &&
2257 4007 : *pPrev->mpItem == *pItem )
2258 : {
2259 3824 : pPrev->mpItem = pItem;
2260 3824 : pPrev->mnEndPos = nHintEnd;
2261 : }
2262 : else
2263 : {
2264 319 : rSet.InvalidateItem( nHintWhich );
2265 319 : pPrev->mpItem = reinterpret_cast<SfxPoolItem*>(-1);
2266 : }
2267 : }
2268 : }
2269 :
2270 18764 : pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
2271 16168 : ? pItemIter->NextItem() : 0;
2272 3184 : } // end while
2273 : }
2274 : }
2275 :
2276 47952 : if ( pAttrArr.get() )
2277 : {
2278 82936 : for (size_t n = 0; n < coArrSz; ++n)
2279 : {
2280 81455 : const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
2281 81455 : if( (0 != rItemPair.mpItem) && (reinterpret_cast<SfxPoolItem*>(-1) != rItemPair.mpItem) )
2282 : {
2283 : const sal_uInt16 nWh =
2284 2937 : static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
2285 :
2286 2937 : if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
2287 : {
2288 2114 : if( *rItemPair.mpItem != aFormatSet.Get( nWh ) )
2289 2112 : (*fnMergeAttr)( rSet, *rItemPair.mpItem );
2290 : }
2291 : else
2292 : // uneindeutig
2293 823 : rSet.InvalidateItem( nWh );
2294 : }
2295 : }
2296 47952 : }
2297 : }
2298 77020 : if( aFormatSet.Count() )
2299 : {
2300 : // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
2301 42287 : aFormatSet.Differentiate( rSet );
2302 : // jetzt alle zusammen "mergen"
2303 42287 : rSet.Put( aFormatSet );
2304 77020 : }
2305 : }
2306 112172 : else if( !bOnlyTextAttr )
2307 : {
2308 : // dann besorge mal die Auto-(Format)Attribute
2309 108955 : SwContentNode::GetAttr( rSet );
2310 108955 : if ( bMergeIndentValuesOfNumRule )
2311 : {
2312 13514 : lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
2313 : }
2314 : }
2315 :
2316 189192 : return rSet.Count() != 0;
2317 : }
2318 :
2319 : namespace
2320 : {
2321 :
2322 : typedef std::pair<sal_Int32, sal_Int32> AttrSpan_t;
2323 : typedef std::multimap<AttrSpan_t, const SwTextAttr*> AttrSpanMap_t;
2324 :
2325 : struct IsAutoStyle
2326 : {
2327 : bool
2328 58 : operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2329 : const
2330 : {
2331 58 : return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
2332 : }
2333 : };
2334 :
2335 : /** Removes from io_rAttrSet all items that are set by style on the
2336 : given span.
2337 : */
2338 : struct RemovePresentAttrs
2339 : {
2340 58 : explicit RemovePresentAttrs(SfxItemSet& io_rAttrSet)
2341 58 : : m_rAttrSet(io_rAttrSet)
2342 : {
2343 58 : }
2344 :
2345 : void
2346 58 : operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2347 : const
2348 : {
2349 58 : if (!i_rAttrSpan.second)
2350 : {
2351 116 : return;
2352 : }
2353 :
2354 0 : const SwTextAttr* const pAutoStyle(i_rAttrSpan.second);
2355 0 : SfxItemIter aIter(m_rAttrSet);
2356 0 : const SfxPoolItem* pItem(aIter.GetCurItem());
2357 0 : while (pItem)
2358 : {
2359 0 : const sal_uInt16 nWhich(pItem->Which());
2360 0 : if (CharFormat::IsItemIncluded(nWhich, pAutoStyle))
2361 : {
2362 0 : m_rAttrSet.ClearItem(nWhich);
2363 : }
2364 :
2365 0 : if (aIter.IsAtEnd())
2366 : {
2367 0 : break;
2368 : }
2369 0 : pItem = aIter.NextItem();
2370 0 : }
2371 : }
2372 :
2373 : private:
2374 : SfxItemSet& m_rAttrSet;
2375 : };
2376 :
2377 : /** Collects all style-covered spans from i_rHints to o_rSpanMap. In
2378 : addition inserts dummy spans with pointer to format equal to 0 for
2379 : all gaps (i.e. spans not covered by any style). This simplifies
2380 : creation of autostyles for all needed spans, but it means all code
2381 : that tries to access the pointer has to check if it's non-null!
2382 : */
2383 : void
2384 64 : lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_Int32 nLength,
2385 : AttrSpanMap_t& o_rSpanMap)
2386 : {
2387 64 : sal_Int32 nLastEnd(0);
2388 :
2389 107 : for (size_t i = 0; i < i_rHints.Count(); ++i)
2390 : {
2391 43 : const SwTextAttr* const pHint(i_rHints[i]);
2392 43 : const sal_uInt16 nWhich(pHint->Which());
2393 43 : if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
2394 : {
2395 0 : const AttrSpan_t aSpan(pHint->GetStart(), *pHint->End());
2396 0 : o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint));
2397 :
2398 : // < not != because there may be multiple CHARFMT at same range
2399 0 : if (nLastEnd < aSpan.first)
2400 : {
2401 : // insert dummy span covering the gap
2402 : o_rSpanMap.insert(AttrSpanMap_t::value_type(
2403 0 : AttrSpan_t(nLastEnd, aSpan.first), nullptr));
2404 : }
2405 :
2406 0 : nLastEnd = aSpan.second;
2407 : }
2408 : }
2409 :
2410 : // no hints at the end (special case: no hints at all in i_rHints)
2411 64 : if (nLastEnd != nLength && nLength != 0)
2412 : {
2413 : o_rSpanMap.insert(
2414 58 : AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), nullptr));
2415 : }
2416 64 : }
2417 :
2418 : void
2419 64 : lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
2420 : {
2421 64 : o_rClearIds.reserve(i_rAttrSet.Count());
2422 64 : SfxItemIter aIter(i_rAttrSet);
2423 64 : const SfxPoolItem* pItem(aIter.GetCurItem());
2424 244 : while (pItem)
2425 : {
2426 180 : o_rClearIds.push_back(pItem->Which());
2427 :
2428 180 : if (aIter.IsAtEnd())
2429 : {
2430 64 : break;
2431 : }
2432 116 : pItem = aIter.NextItem();
2433 64 : }
2434 64 : }
2435 :
2436 : struct SfxItemSetClearer
2437 : {
2438 : SfxItemSet & m_rItemSet;
2439 1586 : explicit SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
2440 174 : void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
2441 : };
2442 :
2443 : }
2444 :
2445 : /** Does the hard work of SwTextNode::FormatToTextAttr: the real conversion
2446 : of items to automatic styles.
2447 : */
2448 : void
2449 75161 : SwTextNode::impl_FormatToTextAttr(const SfxItemSet& i_rAttrSet)
2450 : {
2451 : typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
2452 75161 : AttrSpanMap_t aAttrSpanMap;
2453 :
2454 75161 : if (i_rAttrSet.Count() == 0)
2455 : {
2456 150258 : return;
2457 : }
2458 :
2459 : // 1. Identify all spans in hints' array
2460 :
2461 64 : lcl_CollectHintSpans(*m_pSwpHints, m_Text.getLength(), aAttrSpanMap);
2462 :
2463 : // 2. Go through all spans and insert new attrs
2464 :
2465 64 : AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
2466 64 : const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
2467 186 : while (aCurRange != aEnd)
2468 : {
2469 : typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
2470 : AttrSpanMapRange_t;
2471 58 : AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
2472 :
2473 : // 2a. Collect attributes to insert
2474 :
2475 58 : SfxItemSet aCurSet(i_rAttrSet);
2476 58 : std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
2477 :
2478 : // 2b. Insert automatic style containing the collected attributes
2479 :
2480 58 : if (aCurSet.Count() != 0)
2481 : {
2482 : AttrSpanMap_iterator_t aAutoStyleIt(
2483 58 : std::find_if(aRange.first, aRange.second, IsAutoStyle()));
2484 58 : if (aAutoStyleIt != aRange.second)
2485 : {
2486 : // there already is an automatic style on that span:
2487 : // create new one and remove the original one
2488 0 : SwTextAttr* const pAutoStyle(const_cast<SwTextAttr*>(aAutoStyleIt->second));
2489 : const std::shared_ptr<SfxItemSet> pOldStyle(
2490 : static_cast<const SwFormatAutoFormat&>(
2491 0 : pAutoStyle->GetAttr()).GetStyleHandle());
2492 0 : aCurSet.Put(*pOldStyle);
2493 :
2494 : // remove the old hint
2495 0 : m_pSwpHints->Delete(pAutoStyle);
2496 0 : DestroyAttr(pAutoStyle);
2497 : }
2498 : m_pSwpHints->Insert(
2499 58 : MakeTextAttr(*GetDoc(), aCurSet,
2500 116 : aCurRange->first.first, aCurRange->first.second));
2501 : }
2502 :
2503 58 : aCurRange = aRange.second;
2504 58 : }
2505 :
2506 : // hints were directly inserted, so need to fix the Ignore flags now
2507 64 : m_pSwpHints->MergePortions(*this);
2508 :
2509 : // 3. Clear items from the node
2510 128 : std::vector<sal_uInt16> aClearedIds;
2511 64 : lcl_FillWhichIds(i_rAttrSet, aClearedIds);
2512 128 : ClearItemsFromAttrSet(aClearedIds);
2513 : }
2514 :
2515 74991 : void SwTextNode::FormatToTextAttr( SwTextNode* pNd )
2516 : {
2517 74991 : SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFormatSetRange );
2518 74991 : if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
2519 1767 : aThisSet.Put( *GetpSwAttrSet() );
2520 :
2521 74991 : GetOrCreateSwpHints();
2522 :
2523 74991 : if( pNd == this )
2524 : {
2525 73405 : impl_FormatToTextAttr(aThisSet);
2526 : }
2527 : else
2528 : {
2529 : // There are five possible combinations of items from this and
2530 : // pNd (pNd is the 'main' node):
2531 :
2532 : // case pNd this action
2533 :
2534 : // 1 - - do nothing
2535 : // 2 - a convert item to attr of this
2536 : // 3 a - convert item to attr of pNd
2537 : // 4 a a clear item in this
2538 : // 5 a b convert item to attr of this
2539 :
2540 1586 : SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFormatSetRange );
2541 1586 : if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
2542 1164 : aNdSet.Put( *pNd->GetpSwAttrSet() );
2543 :
2544 1586 : pNd->GetOrCreateSwpHints();
2545 :
2546 3172 : std::vector<sal_uInt16> aProcessedIds;
2547 :
2548 1586 : if( aThisSet.Count() )
2549 : {
2550 170 : SfxItemIter aIter( aThisSet );
2551 170 : const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0;
2552 340 : SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFormatSetRange );
2553 340 : std::vector<sal_uInt16> aClearWhichIds;
2554 :
2555 : while( true )
2556 : {
2557 174 : if( SfxItemState::SET == aNdSet.GetItemState( pItem->Which(), false, &pNdItem ) )
2558 : {
2559 174 : if (*pItem == *pNdItem) // 4
2560 : {
2561 174 : aClearWhichIds.push_back( pItem->Which() );
2562 : }
2563 : else // 5
2564 : {
2565 0 : aConvertSet.Put(*pItem);
2566 : }
2567 174 : aProcessedIds.push_back(pItem->Which());
2568 : }
2569 : else // 2
2570 : {
2571 0 : aConvertSet.Put(*pItem);
2572 : }
2573 :
2574 174 : if( aIter.IsAtEnd() )
2575 170 : break;
2576 4 : pItem = aIter.NextItem();
2577 : }
2578 :
2579 : // 4/ clear items of this that are set with the same value on pNd
2580 170 : ClearItemsFromAttrSet( aClearWhichIds );
2581 :
2582 : // 2, 5/ convert all other items to attrs
2583 340 : impl_FormatToTextAttr(aConvertSet);
2584 : }
2585 :
2586 : {
2587 : std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
2588 1586 : SfxItemSetClearer(aNdSet));
2589 :
2590 : // 3/ convert items to attrs
2591 1586 : pNd->impl_FormatToTextAttr(aNdSet);
2592 :
2593 1586 : if( aNdSet.Count() )
2594 : {
2595 15 : SwFormatChg aTmp1( pNd->GetFormatColl() );
2596 15 : pNd->NotifyClients( &aTmp1, &aTmp1 );
2597 : }
2598 1586 : }
2599 : }
2600 :
2601 74991 : SetCalcHiddenCharFlags();
2602 :
2603 74991 : pNd->TryDeleteSwpHints();
2604 74991 : }
2605 :
2606 51231 : void SwpHints::CalcFlags()
2607 : {
2608 51231 : m_bDDEFields = m_bFootnote = false;
2609 51231 : const size_t nSize = Count();
2610 325598 : for( size_t nPos = 0; nPos < nSize; ++nPos )
2611 : {
2612 274367 : const SwTextAttr* pAttr = (*this)[ nPos ];
2613 274367 : switch( pAttr->Which() )
2614 : {
2615 : case RES_TXTATR_FTN:
2616 253 : m_bFootnote = true;
2617 253 : if ( m_bDDEFields )
2618 0 : return;
2619 253 : break;
2620 : case RES_TXTATR_FIELD:
2621 : {
2622 127138 : const SwField* pField = pAttr->GetFormatField().GetField();
2623 127138 : if( RES_DDEFLD == pField->GetTyp()->Which() )
2624 : {
2625 0 : m_bDDEFields = true;
2626 0 : if ( m_bFootnote )
2627 0 : return;
2628 : }
2629 : }
2630 127138 : break;
2631 : }
2632 : }
2633 : }
2634 :
2635 1239 : bool SwpHints::CalcHiddenParaField()
2636 : {
2637 1239 : m_bCalcHiddenParaField = false;
2638 1239 : bool bOldHasHiddenParaField = m_bHasHiddenParaField;
2639 1239 : bool bNewHasHiddenParaField = false;
2640 1239 : const size_t nSize = Count();
2641 : const SwTextAttr *pTextHt;
2642 :
2643 3838 : for( size_t nPos = 0; nPos < nSize; ++nPos )
2644 : {
2645 2599 : pTextHt = (*this)[ nPos ];
2646 2599 : const sal_uInt16 nWhich = pTextHt->Which();
2647 :
2648 2599 : if( RES_TXTATR_FIELD == nWhich )
2649 : {
2650 1882 : const SwFormatField& rField = pTextHt->GetFormatField();
2651 1882 : if( RES_HIDDENPARAFLD == rField.GetField()->GetTyp()->Which() )
2652 : {
2653 0 : if( !static_cast<const SwHiddenParaField*>(rField.GetField())->IsHidden() )
2654 : {
2655 0 : SetHiddenParaField(false);
2656 0 : return bOldHasHiddenParaField != bNewHasHiddenParaField;
2657 : }
2658 : else
2659 : {
2660 0 : bNewHasHiddenParaField = true;
2661 : }
2662 : }
2663 : }
2664 : }
2665 1239 : SetHiddenParaField( bNewHasHiddenParaField );
2666 1239 : return bOldHasHiddenParaField != bNewHasHiddenParaField;
2667 : }
2668 :
2669 175408 : void SwpHints::NoteInHistory( SwTextAttr *pAttr, const bool bNew )
2670 : {
2671 175408 : if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
2672 175408 : }
2673 :
2674 64476 : bool SwpHints::MergePortions( SwTextNode& rNode )
2675 : {
2676 64476 : if ( !Count() )
2677 107 : return false;
2678 :
2679 : // sort before merging
2680 64369 : SwpHintsArray::Resort();
2681 :
2682 64369 : bool bRet = false;
2683 : typedef std::multimap< int, std::pair<SwTextAttr*, bool> > PortionMap;
2684 64369 : PortionMap aPortionMap;
2685 128738 : std::map<int, bool> RsidOnlyAutoFormatFlagMap;
2686 64369 : sal_Int32 nLastPorStart = COMPLETE_STRING;
2687 64369 : int nKey = 0;
2688 :
2689 : // get portions by start position:
2690 323629 : for ( size_t i = 0; i < Count(); ++i )
2691 : {
2692 259260 : SwTextAttr *pHt = GetTextHint( i );
2693 490191 : if ( RES_TXTATR_CHARFMT != pHt->Which() &&
2694 230931 : RES_TXTATR_AUTOFMT != pHt->Which() )
2695 : //&&
2696 : //RES_TXTATR_INETFMT != pHt->Which() )
2697 71634 : continue;
2698 :
2699 233429 : bool isRsidOnlyAutoFormat(false);
2700 : // check for RSID-only AUTOFMT
2701 233429 : if (RES_TXTATR_AUTOFMT == pHt->Which())
2702 : {
2703 : std::shared_ptr<SfxItemSet> const pSet(
2704 205100 : pHt->GetAutoFormat().GetStyleHandle());
2705 205100 : if ((pSet->Count() == 1) && pSet->GetItem(RES_CHRATR_RSID, false))
2706 : {
2707 : // fdo#70201: eliminate no-extent RSID-only AUTOFMT
2708 : // could be produced by ReplaceText or (maybe?) RstAttr
2709 136 : if (pHt->GetStart() == *pHt->GetEnd())
2710 : {
2711 12 : SwpHintsArray::DeleteAtPos(i); // kill it without History!
2712 12 : SwTextAttr::Destroy(pHt, rNode.GetDoc()->GetAttrPool());
2713 12 : --i;
2714 12 : continue;
2715 : }
2716 : // fdo#52028: this one has _only_ RSID => ignore it completely
2717 124 : if (!pHt->IsFormatIgnoreStart() || !pHt->IsFormatIgnoreEnd())
2718 : {
2719 104 : NoteInHistory(pHt);
2720 104 : pHt->SetFormatIgnoreStart(true);
2721 104 : pHt->SetFormatIgnoreEnd (true);
2722 104 : NoteInHistory(pHt, true);
2723 : }
2724 124 : isRsidOnlyAutoFormat = true;
2725 205088 : }
2726 : }
2727 :
2728 233417 : if (pHt->GetStart() == *pHt->GetEnd())
2729 : {
2730 : // no-length hints are a disease. ignore them here.
2731 : // the SwAttrIter::SeekFwd will not call Rst/Chg for them.
2732 19960 : continue;
2733 : }
2734 :
2735 213457 : const sal_Int32 nPorStart = pHt->GetStart();
2736 213457 : if (nPorStart != nLastPorStart)
2737 204120 : ++nKey;
2738 213457 : nLastPorStart = nPorStart;
2739 : aPortionMap.insert(std::make_pair(nKey,
2740 213457 : std::make_pair(pHt, isRsidOnlyAutoFormat)));
2741 213457 : RsidOnlyAutoFormatFlagMap[nKey] = isRsidOnlyAutoFormat;
2742 : }
2743 :
2744 : // check if portion i can be merged with portion i+1:
2745 : // note: need to include i=0 to set IgnoreStart and j=nKey+1 to reset
2746 : // IgnoreEnd at first / last portion
2747 64369 : int i = 0;
2748 64369 : int j = i + 1;
2749 397227 : while ( i <= nKey )
2750 : {
2751 268489 : std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
2752 268489 : std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
2753 268489 : PortionMap::iterator aIter1 = aRange1.first;
2754 268489 : PortionMap::iterator aIter2 = aRange2.first;
2755 :
2756 268489 : enum { MATCH, DIFFER_ONLY_RSID, DIFFER } eMerge(MATCH);
2757 268489 : size_t const nAttributesInPor1 = std::distance(aRange1.first, aRange1.second);
2758 268489 : size_t const nAttributesInPor2 = std::distance(aRange2.first, aRange2.second);
2759 268489 : bool const isRsidOnlyAutoFormat1(RsidOnlyAutoFormatFlagMap[i]);
2760 268489 : bool const isRsidOnlyAutoFormat2(RsidOnlyAutoFormatFlagMap[j]);
2761 :
2762 : // if both have one they could be equal, but not if only one has it
2763 268489 : bool const bSkipRsidOnlyAutoFormat(nAttributesInPor1 != nAttributesInPor2);
2764 :
2765 : // this loop needs to handle the case where one has a CHARFMT and the
2766 : // other CHARFMT + RSID-only AUTOFMT, so...
2767 : // want to skip over RSID-only AUTOFMT here, hence the -1
2768 536978 : if ((nAttributesInPor1 - ((isRsidOnlyAutoFormat1) ? 1 : 0)) ==
2769 268489 : (nAttributesInPor2 - ((isRsidOnlyAutoFormat2) ? 1 : 0))
2770 137231 : && (nAttributesInPor1 != 0 || nAttributesInPor2 != 0))
2771 : {
2772 : // _if_ there is one element more either in aRange1 or aRange2
2773 : // it _must_ be an RSID-only AUTOFMT, which can be ignored here...
2774 : // But if both have RSID-only AUTOFMT they could be equal, no skip!
2775 280432 : while (aIter1 != aRange1.second || aIter2 != aRange2.second)
2776 : {
2777 : // first of all test if there's no gap (before skipping stuff!)
2778 266517 : if (aIter1 != aRange1.second && aIter2 != aRange2.second &&
2779 133163 : *aIter1->second.first->End() < aIter2->second.first->GetStart())
2780 : {
2781 10062 : eMerge = DIFFER;
2782 10062 : break;
2783 : }
2784 : // skip it - cannot be equal if bSkipRsidOnlyAutoFormat is set
2785 123292 : if (bSkipRsidOnlyAutoFormat
2786 123292 : && aIter1 != aRange1.second && aIter1->second.second)
2787 : {
2788 : assert(DIFFER != eMerge);
2789 94 : eMerge = DIFFER_ONLY_RSID;
2790 94 : ++aIter1;
2791 94 : continue;
2792 : }
2793 123198 : if (bSkipRsidOnlyAutoFormat
2794 123198 : && aIter2 != aRange2.second && aIter2->second.second)
2795 : {
2796 : assert(DIFFER != eMerge);
2797 97 : eMerge = DIFFER_ONLY_RSID;
2798 97 : ++aIter2;
2799 97 : continue;
2800 : }
2801 : assert(aIter1 != aRange1.second && aIter2 != aRange2.second);
2802 123101 : SwTextAttr const*const p1 = aIter1->second.first;
2803 123101 : SwTextAttr const*const p2 = aIter2->second.first;
2804 123101 : if (p1->Which() != p2->Which())
2805 : {
2806 4430 : eMerge = DIFFER;
2807 4430 : break;
2808 : }
2809 118671 : if (!(*p1 == *p2))
2810 : {
2811 : // fdo#52028: for auto styles, check if they differ only
2812 : // in the RSID, which should have no effect on text layout
2813 104285 : if (RES_TXTATR_AUTOFMT == p1->Which())
2814 : {
2815 99870 : SfxItemSet set1(*p1->GetAutoFormat().GetStyleHandle());
2816 99871 : SfxItemSet set2(*p2->GetAutoFormat().GetStyleHandle());
2817 :
2818 99870 : set1.ClearItem(RES_CHRATR_RSID);
2819 99870 : set2.ClearItem(RES_CHRATR_RSID);
2820 :
2821 : // sadly SfxItemSet::operator== does not seem to work?
2822 99871 : SfxItemIter iter1(set1);
2823 99871 : SfxItemIter iter2(set2);
2824 99870 : if (set1.Count() == set2.Count())
2825 : {
2826 34476 : for (SfxPoolItem const* pItem1 = iter1.FirstItem(),
2827 11092 : * pItem2 = iter2.FirstItem();
2828 23383 : pItem1 && pItem2;
2829 : pItem1 = iter1.NextItem(),
2830 : pItem2 = iter2.NextItem())
2831 : {
2832 35675 : if (pItem1 != pItem2 ||
2833 35675 : pItem1->Which() != pItem2->Which() ||
2834 12292 : *pItem1 != *pItem2)
2835 : {
2836 11091 : eMerge = DIFFER;
2837 11091 : break;
2838 : }
2839 12292 : if (iter1.IsAtEnd())
2840 : {
2841 : assert(iter2.IsAtEnd());
2842 0 : eMerge = DIFFER_ONLY_RSID;
2843 : }
2844 : }
2845 11092 : if (DIFFER == eMerge)
2846 11091 : break; // outer loop too
2847 : }
2848 : else
2849 : {
2850 88778 : eMerge = DIFFER;
2851 88778 : break;
2852 1 : }
2853 : }
2854 : else
2855 : {
2856 4415 : eMerge = DIFFER;
2857 4415 : break;
2858 : }
2859 : }
2860 14387 : ++aIter1;
2861 14387 : ++aIter2;
2862 132927 : }
2863 : }
2864 : else
2865 : {
2866 135562 : eMerge = DIFFER;
2867 : }
2868 :
2869 268489 : if (MATCH == eMerge)
2870 : {
2871 : // important: delete second range so any IgnoreStart on the first
2872 : // range is still valid
2873 : // erase all elements with key i + 1
2874 13960 : sal_Int32 nNewPortionEnd = 0;
2875 28163 : for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
2876 : {
2877 14203 : SwTextAttr *const p2 = aIter2->second.first;
2878 14203 : nNewPortionEnd = *p2->GetEnd();
2879 :
2880 14203 : const size_t nCountBeforeDelete = Count();
2881 14203 : Delete( p2 );
2882 :
2883 : // robust: check if deletion actually took place before destroying attribute:
2884 14203 : if ( Count() < nCountBeforeDelete )
2885 14203 : rNode.DestroyAttr( p2 );
2886 : }
2887 13960 : aPortionMap.erase( aRange2.first, aRange2.second );
2888 13960 : ++j;
2889 :
2890 : // change all attributes with key i
2891 13960 : aRange1 = aPortionMap.equal_range( i );
2892 28163 : for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
2893 : {
2894 14203 : SwTextAttr *const p1 = aIter1->second.first;
2895 14203 : NoteInHistory( p1 );
2896 14203 : *p1->GetEnd() = nNewPortionEnd;
2897 14203 : NoteInHistory( p1, true );
2898 14203 : bRet = true;
2899 : }
2900 :
2901 13960 : if (bRet)
2902 : {
2903 13960 : SwpHintsArray::Resort();
2904 : }
2905 : }
2906 : else
2907 : {
2908 : // when not merging the ignore flags need to be either set or reset
2909 : // (reset too in case one of the autofmts was recently changed)
2910 254529 : bool const bSetIgnoreFlag(DIFFER_ONLY_RSID == eMerge);
2911 453783 : for (aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1)
2912 : {
2913 199254 : if (!aIter1->second.second) // already set above, don't change
2914 : {
2915 199146 : SwTextAttr *const pCurrent(aIter1->second.first);
2916 199146 : if (pCurrent->IsFormatIgnoreEnd() != bSetIgnoreFlag)
2917 : {
2918 0 : NoteInHistory(pCurrent);
2919 0 : pCurrent->SetFormatIgnoreEnd(bSetIgnoreFlag);
2920 0 : NoteInHistory(pCurrent, true);
2921 : }
2922 : }
2923 : }
2924 453783 : for (aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2)
2925 : {
2926 199254 : if (!aIter2->second.second) // already set above, don't change
2927 : {
2928 199146 : SwTextAttr *const pCurrent(aIter2->second.first);
2929 199146 : if (pCurrent->IsFormatIgnoreStart() != bSetIgnoreFlag)
2930 : {
2931 0 : NoteInHistory(pCurrent);
2932 0 : pCurrent->SetFormatIgnoreStart(bSetIgnoreFlag);
2933 0 : NoteInHistory(pCurrent, true);
2934 : }
2935 : }
2936 : }
2937 254529 : i = j; // ++i not enough: i + 1 may have been deleted (MATCH)!
2938 254529 : ++j;
2939 : }
2940 : }
2941 :
2942 128738 : return bRet;
2943 : }
2944 :
2945 : // check if there is already a character format and adjust the sort numbers
2946 2 : static void lcl_CheckSortNumber( const SwpHints& rHints, SwTextCharFormat& rNewCharFormat )
2947 : {
2948 2 : const sal_Int32 nHtStart = rNewCharFormat.GetStart();
2949 2 : const sal_Int32 nHtEnd = *rNewCharFormat.GetEnd();
2950 2 : sal_uInt16 nSortNumber = 0;
2951 :
2952 2 : for ( size_t i = 0; i < rHints.Count(); ++i )
2953 : {
2954 0 : const SwTextAttr* pOtherHt = rHints[i];
2955 :
2956 0 : const sal_Int32 nOtherStart = pOtherHt->GetStart();
2957 :
2958 0 : if ( nOtherStart > nHtStart )
2959 0 : break;
2960 :
2961 0 : if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
2962 : {
2963 0 : const sal_Int32 nOtherEnd = *pOtherHt->End();
2964 :
2965 0 : if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
2966 : {
2967 0 : nSortNumber = static_txtattr_cast<const SwTextCharFormat*>(pOtherHt)->GetSortNumber() + 1;
2968 : }
2969 : }
2970 : }
2971 :
2972 2 : if ( nSortNumber > 0 )
2973 0 : rNewCharFormat.SetSortNumber( nSortNumber );
2974 2 : }
2975 :
2976 : /*
2977 : * Try to insert the new hint.
2978 : * Depending on the type of the hint, this either always succeeds, or may fail.
2979 : * Depending on the type of the hint, other hints may be deleted or
2980 : * overwritten.
2981 : * The return value indicates successful insertion.
2982 : */
2983 82501 : bool SwpHints::TryInsertHint(
2984 : SwTextAttr* const pHint,
2985 : SwTextNode &rNode,
2986 : const SetAttrMode nMode )
2987 : {
2988 82501 : if ( MAX_HINTS <= Count() ) // we're sorry, this flight is overbooked...
2989 : {
2990 : OSL_FAIL("hints array full :-(");
2991 0 : return false;
2992 : }
2993 :
2994 : // Felder bilden eine Ausnahme:
2995 : // 1) Sie koennen nie ueberlappen
2996 : // 2) Wenn zwei Felder genau aneinander liegen,
2997 : // sollen sie nicht zu einem verschmolzen werden.
2998 : // Wir koennen also auf die while-Schleife verzichten
2999 :
3000 82501 : sal_Int32 *pHtEnd = pHint->GetEnd();
3001 82501 : const sal_uInt16 nWhich = pHint->Which();
3002 82501 : std::vector<sal_uInt16> aWhichSublist;
3003 :
3004 82501 : switch( nWhich )
3005 : {
3006 : case RES_TXTATR_CHARFMT:
3007 : {
3008 : // Check if character format contains hidden attribute:
3009 6244 : const SwCharFormat* pFormat = pHint->GetCharFormat().GetCharFormat();
3010 : const SfxPoolItem* pItem;
3011 6244 : if ( SfxItemState::SET == pFormat->GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) )
3012 0 : rNode.SetCalcHiddenCharFlags();
3013 :
3014 6244 : static_txtattr_cast<SwTextCharFormat*>(pHint)->ChgTextNode( &rNode );
3015 6244 : break;
3016 : }
3017 : // #i75430# Recalc hidden flags if necessary
3018 : case RES_TXTATR_AUTOFMT:
3019 : {
3020 68165 : std::shared_ptr<SfxItemSet> const pSet( pHint->GetAutoFormat().GetStyleHandle() );
3021 68165 : if (pHint->GetStart() == *pHint->GetEnd())
3022 : {
3023 25692 : if (pSet->Count() == 1 && pSet->GetItem(RES_CHRATR_RSID, false))
3024 : { // empty range RSID-only hints could cause trouble, there's no
3025 0 : rNode.DestroyAttr(pHint); // need for them so don't insert
3026 0 : return false;
3027 : }
3028 : }
3029 : // Check if auto style contains hidden attribute:
3030 68165 : const SfxPoolItem* pHiddenItem = CharFormat::GetItem( *pHint, RES_CHRATR_HIDDEN );
3031 68165 : if ( pHiddenItem )
3032 867 : rNode.SetCalcHiddenCharFlags();
3033 :
3034 : // fdo#71556: populate aWhichFormatAttr member of SwMsgPoolItem
3035 68165 : const sal_uInt16 *pRanges = pSet->GetRanges();
3036 340708 : while( (*pRanges) != 0 )
3037 : {
3038 204378 : const sal_uInt16 nBeg = (*pRanges);
3039 204378 : ++pRanges;
3040 204378 : const sal_uInt16 nEnd = (*pRanges);
3041 204378 : ++pRanges;
3042 3408016 : for( sal_uInt16 nSubElem = nBeg; nSubElem <= nEnd; ++nSubElem )
3043 3203638 : if( pSet->HasItem( nSubElem ) )
3044 240294 : aWhichSublist.push_back( nSubElem );
3045 : }
3046 68165 : break;
3047 : }
3048 : case RES_TXTATR_INETFMT:
3049 1798 : static_txtattr_cast<SwTextINetFormat*>(pHint)->InitINetFormat(rNode);
3050 1798 : break;
3051 :
3052 : case RES_TXTATR_FIELD:
3053 : case RES_TXTATR_ANNOTATION:
3054 : case RES_TXTATR_INPUTFIELD:
3055 : {
3056 2043 : SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
3057 2043 : bool bDelFirst = 0 != pTextField->GetpTextNode();
3058 2043 : pTextField->ChgTextNode( &rNode );
3059 2043 : SwDoc* pDoc = rNode.GetDoc();
3060 2043 : const SwField* pField = pTextField->GetFormatField().GetField();
3061 :
3062 2043 : if( !pDoc->getIDocumentFieldsAccess().IsNewFieldLst() )
3063 : {
3064 : // was fuer ein Feld ist es denn ??
3065 : // bestimmte Felder mussen am Doc das Calculations-Flag updaten
3066 15 : switch( pField->GetTyp()->Which() )
3067 : {
3068 : case RES_DBFLD:
3069 : case RES_SETEXPFLD:
3070 : case RES_HIDDENPARAFLD:
3071 : case RES_HIDDENTXTFLD:
3072 : case RES_DBNUMSETFLD:
3073 : case RES_DBNEXTSETFLD:
3074 : {
3075 0 : if( bDelFirst )
3076 0 : pDoc->getIDocumentFieldsAccess().InsDelFieldInFieldLst(false, *pTextField);
3077 0 : if( rNode.GetNodes().IsDocNodes() )
3078 0 : pDoc->getIDocumentFieldsAccess().InsDelFieldInFieldLst(true, *pTextField);
3079 : }
3080 0 : break;
3081 : case RES_DDEFLD:
3082 0 : if( rNode.GetNodes().IsDocNodes() )
3083 0 : static_cast<SwDDEFieldType*>(pField->GetTyp())->IncRefCnt();
3084 0 : break;
3085 : }
3086 : }
3087 :
3088 : // gehts ins normale Nodes-Array?
3089 2043 : if( rNode.GetNodes().IsDocNodes() )
3090 : {
3091 2043 : bool bInsFieldType = false;
3092 2043 : switch( pField->GetTyp()->Which() )
3093 : {
3094 : case RES_SETEXPFLD:
3095 63 : bInsFieldType = static_cast<SwSetExpFieldType*>(pField->GetTyp())->IsDeleted();
3096 63 : if( nsSwGetSetExpType::GSE_SEQ & static_cast<SwSetExpFieldType*>(pField->GetTyp())->GetType() )
3097 : {
3098 : // bevor die ReferenzNummer gesetzt wird, sollte
3099 : // das Feld am richtigen FeldTypen haengen!
3100 : SwSetExpFieldType* pFieldType = static_cast<SwSetExpFieldType*>(
3101 54 : pDoc->getIDocumentFieldsAccess().InsertFieldType( *pField->GetTyp() ) );
3102 54 : if( pFieldType != pField->GetTyp() )
3103 : {
3104 0 : SwFormatField* pFormatField = const_cast<SwFormatField*>(&pTextField->GetFormatField());
3105 0 : pFormatField->RegisterToFieldType( *pFieldType );
3106 0 : pFormatField->GetField()->ChgTyp( pFieldType );
3107 : }
3108 54 : pFieldType->SetSeqRefNo( *const_cast<SwSetExpField*>(static_cast<const SwSetExpField*>(pField)) );
3109 : }
3110 63 : break;
3111 : case RES_USERFLD:
3112 2 : bInsFieldType = static_cast<SwUserFieldType*>(pField->GetTyp())->IsDeleted();
3113 2 : break;
3114 :
3115 : case RES_DDEFLD:
3116 0 : if( pDoc->getIDocumentFieldsAccess().IsNewFieldLst() )
3117 0 : static_cast<SwDDEFieldType*>(pField->GetTyp())->IncRefCnt();
3118 0 : bInsFieldType = static_cast<SwDDEFieldType*>(pField->GetTyp())->IsDeleted();
3119 0 : break;
3120 :
3121 : case RES_POSTITFLD:
3122 140 : if ( pDoc->GetDocShell() )
3123 : {
3124 140 : pDoc->GetDocShell()->Broadcast( SwFormatFieldHint(
3125 280 : &pTextField->GetFormatField(), SwFormatFieldHintWhich::INSERTED));
3126 : }
3127 140 : break;
3128 : }
3129 2043 : if( bInsFieldType )
3130 0 : pDoc->getIDocumentFieldsAccess().InsDeletedFieldType( *pField->GetTyp() );
3131 : }
3132 : }
3133 2043 : break;
3134 : case RES_TXTATR_FTN :
3135 140 : static_cast<SwTextFootnote*>(pHint)->ChgTextNode( &rNode );
3136 140 : break;
3137 : case RES_TXTATR_REFMARK:
3138 39 : static_txtattr_cast<SwTextRefMark*>(pHint)->ChgTextNode( &rNode );
3139 39 : if( rNode.GetNodes().IsDocNodes() )
3140 : {
3141 : // search for a reference with the same name
3142 : SwTextAttr* pTmpHt;
3143 : sal_Int32 *pTmpHtEnd;
3144 : sal_Int32 *pTmpHintEnd;
3145 94 : for( size_t n = 0, nEnd = Count(); n < nEnd; ++n )
3146 : {
3147 198 : if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
3148 33 : pHint->GetAttr() == pTmpHt->GetAttr() &&
3149 110 : 0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
3150 0 : 0 != ( pTmpHintEnd = pHint->GetEnd() ) )
3151 : {
3152 : SwComparePosition eCmp = ::ComparePosition(
3153 0 : pTmpHt->GetStart(), *pTmpHtEnd,
3154 0 : pHint->GetStart(), *pTmpHintEnd );
3155 0 : bool bDelOld = true, bChgStart = false, bChgEnd = false;
3156 0 : switch( eCmp )
3157 : {
3158 : case POS_BEFORE:
3159 0 : case POS_BEHIND: bDelOld = false; break;
3160 :
3161 0 : case POS_OUTSIDE: bChgStart = bChgEnd = true; break;
3162 :
3163 : case POS_COLLIDE_END:
3164 0 : case POS_OVERLAP_BEFORE: bChgStart = true; break;
3165 : case POS_COLLIDE_START:
3166 0 : case POS_OVERLAP_BEHIND: bChgEnd = true; break;
3167 0 : default: break;
3168 : }
3169 :
3170 0 : if( bChgStart )
3171 0 : pHint->GetStart() = pTmpHt->GetStart();
3172 0 : if( bChgEnd )
3173 0 : *pTmpHintEnd = *pTmpHtEnd;
3174 :
3175 0 : if( bDelOld )
3176 : {
3177 0 : NoteInHistory( pTmpHt );
3178 0 : rNode.DestroyAttr( Cut( n-- ) );
3179 0 : --nEnd;
3180 : }
3181 : }
3182 : }
3183 : }
3184 39 : break;
3185 : case RES_TXTATR_TOXMARK:
3186 173 : static_txtattr_cast<SwTextTOXMark*>(pHint)->ChgTextNode( &rNode );
3187 173 : break;
3188 :
3189 : case RES_TXTATR_CJK_RUBY:
3190 149 : static_txtattr_cast<SwTextRuby*>(pHint)->InitRuby(rNode);
3191 149 : break;
3192 :
3193 : case RES_TXTATR_META:
3194 : case RES_TXTATR_METAFIELD:
3195 97 : static_txtattr_cast<SwTextMeta *>(pHint)->ChgTextNode( &rNode );
3196 97 : break;
3197 :
3198 : case RES_CHRATR_HIDDEN:
3199 0 : rNode.SetCalcHiddenCharFlags();
3200 0 : break;
3201 : }
3202 :
3203 82501 : if( SetAttrMode::DONTEXPAND & nMode )
3204 310 : pHint->SetDontExpand( true );
3205 :
3206 : // SwTextAttrs ohne Ende werden sonderbehandelt:
3207 : // Sie werden natuerlich in das Array insertet, aber sie werden nicht
3208 : // in die pPrev/Next/On/Off-Verkettung aufgenommen.
3209 : // Der Formatierer erkennt diese TextHints an dem CH_TXTATR_.. im Text !
3210 82501 : sal_Int32 nHtStart = pHint->GetStart();
3211 82501 : if( !pHtEnd )
3212 : {
3213 6002 : SwpHintsArray::Insert( pHint );
3214 6002 : CalcFlags();
3215 : #ifdef DBG_UTIL
3216 : if( !rNode.GetDoc()->IsInReading() )
3217 : CHECK;
3218 : #endif
3219 : // ... und die Abhaengigen benachrichtigen
3220 6002 : if(rNode.HasWriterListeners())
3221 : {
3222 : SwUpdateAttr aHint(
3223 : nHtStart,
3224 : nHtStart,
3225 1977 : nWhich);
3226 :
3227 1977 : rNode.ModifyNotification(0,&aHint);
3228 : }
3229 :
3230 6002 : return true;
3231 : }
3232 :
3233 : // Ab hier gibt es nur noch pHint mit einem EndIdx !!!
3234 :
3235 76499 : if( *pHtEnd < nHtStart )
3236 : {
3237 : OSL_ENSURE( *pHtEnd >= nHtStart,
3238 : "+SwpHints::Insert: invalid hint, end < start" );
3239 :
3240 : // Wir drehen den Quatsch einfach um:
3241 3 : pHint->GetStart() = *pHtEnd;
3242 3 : *pHtEnd = nHtStart;
3243 3 : nHtStart = pHint->GetStart();
3244 : }
3245 :
3246 : // I need this value later on for notification but the pointer may become invalid
3247 76499 : const sal_Int32 nHintEnd = *pHtEnd;
3248 76499 : const bool bNoHintAdjustMode = bool(SetAttrMode::NOHINTADJUST & nMode);
3249 :
3250 : // handle nesting attributes: inserting may fail due to overlap!
3251 76499 : if (pHint->IsNesting())
3252 : {
3253 : const bool bRet(
3254 2062 : TryInsertNesting(rNode, *static_txtattr_cast<SwTextAttrNesting*>(pHint)));
3255 2062 : if (!bRet) return false;
3256 : }
3257 : // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
3258 : // These attributes may be inserted directly.
3259 : // Also attributes without length may be inserted directly.
3260 : // SETATTR_NOHINTADJUST is set e.g., during undo.
3261 : // Portion building in not necessary during XML import.
3262 221819 : else if ( !bNoHintAdjustMode &&
3263 145862 : !pHint->IsOverlapAllowedAttr() &&
3264 292236 : !rNode.GetDoc()->IsInXMLImport() &&
3265 6184 : ( RES_TXTATR_AUTOFMT == nWhich ||
3266 : RES_TXTATR_CHARFMT == nWhich ) )
3267 : {
3268 : OSL_ENSURE( nWhich != RES_TXTATR_AUTOFMT ||
3269 : static_cast<const SwFormatAutoFormat&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
3270 : &rNode.GetDoc()->GetAttrPool(),
3271 : "AUTOSTYLES - Pool mismatch" );
3272 :
3273 72441 : BuildPortions( rNode, *pHint, nMode );
3274 :
3275 72441 : if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
3276 46161 : MergePortions( rNode );
3277 : }
3278 : else
3279 : {
3280 : // There may be more than one character style at the current position.
3281 : // Take care of the sort number.
3282 : // Special case ruby portion: During import, the ruby attribute is set
3283 : // multiple times
3284 : // Special case hyperlink: During import, the ruby attribute is set
3285 : // multiple times
3286 : // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
3287 : // character attributes directly
3288 1996 : if ( ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode ) )
3289 : {
3290 58 : BuildPortions( rNode, *pHint, nMode );
3291 : }
3292 : else
3293 : {
3294 : // #i82989# Check sort numbers in NoHintAdjustMode
3295 1938 : if ( RES_TXTATR_CHARFMT == nWhich )
3296 2 : lcl_CheckSortNumber(*this, *static_txtattr_cast<SwTextCharFormat*>(pHint));
3297 :
3298 1938 : SwpHintsArray::Insert( pHint );
3299 1938 : NoteInHistory( pHint, true );
3300 : }
3301 : }
3302 :
3303 : // ... und die Abhaengigen benachrichtigen
3304 76497 : if ( rNode.HasWriterListeners() )
3305 : {
3306 : SwUpdateAttr aHint(
3307 : nHtStart,
3308 : nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd,
3309 60635 : nWhich);
3310 :
3311 60635 : rNode.ModifyNotification( 0, &aHint );
3312 : }
3313 :
3314 : #ifdef DBG_UTIL
3315 : if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
3316 : CHECK;
3317 : #endif
3318 :
3319 76497 : return true;
3320 : }
3321 :
3322 45229 : void SwpHints::DeleteAtPos( const size_t nPos )
3323 : {
3324 45229 : SwTextAttr *pHint = GetTextHint(nPos);
3325 : // ChainDelete( pHint );
3326 45229 : NoteInHistory( pHint );
3327 45229 : SwpHintsArray::DeleteAtPos( nPos );
3328 :
3329 45229 : if( pHint->Which() == RES_TXTATR_FIELD )
3330 : {
3331 86 : SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
3332 86 : const SwFieldType* pFieldTyp = pTextField->GetFormatField().GetField()->GetTyp();
3333 86 : if( RES_DDEFLD == pFieldTyp->Which() )
3334 : {
3335 0 : const SwTextNode* pNd = pTextField->GetpTextNode();
3336 0 : if( pNd && pNd->GetNodes().IsDocNodes() )
3337 0 : const_cast<SwDDEFieldType*>(static_cast<const SwDDEFieldType*>(pFieldTyp))->DecRefCnt();
3338 0 : pTextField->ChgTextNode(0);
3339 : }
3340 86 : else if ( m_bHasHiddenParaField &&
3341 0 : RES_HIDDENPARAFLD == pFieldTyp->Which() )
3342 : {
3343 0 : m_bCalcHiddenParaField = true;
3344 : }
3345 : }
3346 45143 : else if ( pHint->Which() == RES_TXTATR_ANNOTATION )
3347 : {
3348 19 : SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pHint));
3349 19 : const_cast<SwFormatField&>(pTextField->GetFormatField()).Broadcast(
3350 38 : SwFormatFieldHint(&pTextField->GetFormatField(), SwFormatFieldHintWhich::REMOVED));
3351 : }
3352 :
3353 45229 : CalcFlags();
3354 : CHECK_NOTMERGED; // called from BuildPortions
3355 45229 : }
3356 :
3357 : // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
3358 : // Ist er nicht im Array, so gibt es ein OSL_ENSURE(!!
3359 :
3360 41267 : void SwpHints::Delete( SwTextAttr* pTextHt )
3361 : {
3362 : // Attr 2.0: SwpHintsArr::Delete( pTextHt );
3363 41267 : const size_t nPos = GetStartOf( pTextHt );
3364 : OSL_ENSURE( SAL_MAX_SIZE != nPos, "Attribut nicht im Attribut-Array!" );
3365 41267 : if( SAL_MAX_SIZE != nPos )
3366 41267 : DeleteAtPos( nPos );
3367 41267 : }
3368 :
3369 0 : void SwTextNode::ClearSwpHintsArr( bool bDelFields )
3370 : {
3371 0 : if ( HasHints() )
3372 : {
3373 0 : size_t nPos = 0;
3374 0 : while ( nPos < m_pSwpHints->Count() )
3375 : {
3376 0 : SwTextAttr* pDel = m_pSwpHints->GetTextHint( nPos );
3377 0 : bool bDel = false;
3378 :
3379 0 : switch( pDel->Which() )
3380 : {
3381 : case RES_TXTATR_FLYCNT:
3382 : case RES_TXTATR_FTN:
3383 0 : break;
3384 :
3385 : case RES_TXTATR_FIELD:
3386 : case RES_TXTATR_ANNOTATION:
3387 : case RES_TXTATR_INPUTFIELD:
3388 0 : if( bDelFields )
3389 0 : bDel = true;
3390 0 : break;
3391 : default:
3392 0 : bDel = true; break;
3393 : }
3394 :
3395 0 : if( bDel )
3396 : {
3397 0 : m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
3398 0 : DestroyAttr( pDel );
3399 : }
3400 : else
3401 0 : ++nPos;
3402 : }
3403 : }
3404 0 : }
3405 :
3406 188511903 : sal_uInt16 SwTextNode::GetLang( const sal_Int32 nBegin, const sal_Int32 nLen,
3407 : sal_uInt16 nScript ) const
3408 : {
3409 188511903 : sal_uInt16 nRet = LANGUAGE_DONTKNOW;
3410 :
3411 188511903 : if ( ! nScript )
3412 : {
3413 97176669 : nScript = g_pBreakIt->GetRealScriptOfText( m_Text, nBegin );
3414 : }
3415 :
3416 : // #i91465# Consider nScript if pSwpHints == 0
3417 188511903 : const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
3418 :
3419 188511903 : if ( HasHints() )
3420 : {
3421 29534994 : const sal_Int32 nEnd = nBegin + nLen;
3422 29534994 : const size_t nSize = m_pSwpHints->Count();
3423 50648505 : for ( size_t i = 0; i < nSize; ++i )
3424 : {
3425 : // ist der Attribut-Anfang schon groesser als der Idx ?
3426 32568406 : const SwTextAttr *pHt = m_pSwpHints->operator[](i);
3427 32568406 : const sal_Int32 nAttrStart = pHt->GetStart();
3428 32568406 : if( nEnd < nAttrStart )
3429 11454895 : break;
3430 :
3431 21113511 : const sal_uInt16 nWhich = pHt->Which();
3432 :
3433 42232674 : if( nWhichId == nWhich ||
3434 42219816 : ( ( pHt->IsCharFormatAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFormat::IsItemIncluded( nWhichId, pHt ) ) )
3435 : {
3436 5652 : const sal_Int32 *pEndIdx = pHt->End();
3437 : // Ueberlappt das Attribut den Bereich?
3438 :
3439 5652 : if( !pEndIdx )
3440 0 : continue;
3441 5652 : if( nLen )
3442 : {
3443 177 : if( nAttrStart >= nEnd || nBegin >= *pEndIdx )
3444 47 : continue;
3445 : }
3446 5475 : else if( nBegin != nAttrStart || ( nAttrStart != *pEndIdx && nBegin ))
3447 : {
3448 4116 : if( nAttrStart >= nBegin )
3449 63 : continue;
3450 4053 : if( pHt->DontExpand() ? nBegin >= *pEndIdx : nBegin > *pEndIdx)
3451 1869 : continue;
3452 : }
3453 3673 : const SfxPoolItem* pItem = CharFormat::GetItem( *pHt, nWhichId );
3454 3673 : const sal_uInt16 nLng = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
3455 :
3456 : // Umfasst das Attribut den Bereich komplett?
3457 3673 : if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
3458 3673 : nRet = nLng;
3459 0 : else if( LANGUAGE_DONTKNOW == nRet )
3460 0 : nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
3461 : }
3462 : }
3463 : }
3464 188511903 : if( LANGUAGE_DONTKNOW == nRet )
3465 : {
3466 188509315 : nRet = static_cast<const SvxLanguageItem&>(GetSwAttrSet().Get( nWhichId )).GetLanguage();
3467 188509315 : if( LANGUAGE_DONTKNOW == nRet )
3468 1115 : nRet = static_cast<sal_uInt16>(GetAppLanguage());
3469 : }
3470 188511903 : return nRet;
3471 : }
3472 :
3473 5151 : sal_Unicode GetCharOfTextAttr( const SwTextAttr& rAttr )
3474 : {
3475 5151 : sal_Unicode cRet = CH_TXTATR_BREAKWORD;
3476 5151 : switch ( rAttr.Which() )
3477 : {
3478 : case RES_TXTATR_REFMARK:
3479 : case RES_TXTATR_TOXMARK:
3480 184 : cRet = CH_TXTATR_INWORD;
3481 184 : break;
3482 :
3483 : case RES_TXTATR_FIELD:
3484 : case RES_TXTATR_FLYCNT:
3485 : case RES_TXTATR_FTN:
3486 : case RES_TXTATR_META:
3487 : case RES_TXTATR_METAFIELD:
3488 : case RES_TXTATR_ANNOTATION:
3489 : {
3490 4967 : cRet = CH_TXTATR_BREAKWORD;
3491 : }
3492 4967 : break;
3493 :
3494 : default:
3495 : OSL_FAIL("GetCharOfTextAttr: unknown attr");
3496 0 : break;
3497 : }
3498 5151 : return cRet;
3499 177 : }
3500 :
3501 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|