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 <boost/scoped_ptr.hpp>
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 129230 : 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 129230 : , m_bDDEFields(false)
96 : {
97 129230 : }
98 :
99 : struct TxtAttrDeleter
100 : {
101 : SwAttrPool & m_rPool;
102 4 : TxtAttrDeleter( SwDoc & rDoc ) : m_rPool( rDoc.GetAttrPool() ) { }
103 4 : void operator() (SwTxtAttr * const pAttr)
104 : {
105 4 : if (RES_TXTATR_META == pAttr->Which() ||
106 0 : RES_TXTATR_METAFIELD == pAttr->Which())
107 : {
108 4 : static_txtattr_cast<SwTxtMeta *>(pAttr)->ChgTxtNode(0); // prevents ASSERT
109 : }
110 4 : SwTxtAttr::Destroy( pAttr, m_rPool );
111 4 : }
112 : };
113 :
114 : struct TxtAttrContains
115 : {
116 : sal_Int32 m_nPos;
117 60 : TxtAttrContains( const sal_Int32 nPos ) : m_nPos( nPos ) { }
118 78 : bool operator() (SwTxtAttrEnd * const pAttr)
119 : {
120 78 : 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 4034 : bool isOverlap(const sal_Int32 nStart1, const sal_Int32 nEnd1,
142 : const sal_Int32 nStart2, const sal_Int32 nEnd2)
143 : {
144 : return
145 3592 : ((nStart1 > nStart2) && (nStart1 < nEnd2) && (nEnd1 > nEnd2)) // (1)
146 8018 : || ((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 3948 : bool isNestedAny(const sal_Int32 nStart1, const sal_Int32 nEnd1,
152 : const sal_Int32 nStart2, const sal_Int32 nEnd2)
153 : {
154 3696 : return ((nStart1 == nStart2) || (nEnd1 == nEnd2))
155 : // same start/end: nested except if hint1 empty and hint2 not empty
156 324 : ? (nStart1 != nEnd1) || (nStart2 == nEnd2)
157 4272 : : ((nStart1 < nStart2) ? (nEnd1 >= nEnd2) : (nEnd1 <= nEnd2));
158 : }
159 :
160 : static
161 3402 : bool isSelfNestable(const sal_uInt16 nWhich)
162 : {
163 3402 : if ((RES_TXTATR_INETFMT == nWhich) ||
164 222 : (RES_TXTATR_CJK_RUBY == nWhich) ||
165 : (RES_TXTATR_INPUTFIELD == nWhich))
166 3208 : return false;
167 : assert((RES_TXTATR_META == nWhich) ||
168 : (RES_TXTATR_METAFIELD == nWhich));
169 194 : return true;
170 : }
171 :
172 : static
173 144 : bool isSplittable(const sal_uInt16 nWhich)
174 : {
175 144 : if ((RES_TXTATR_INETFMT == nWhich) ||
176 : (RES_TXTATR_CJK_RUBY == nWhich))
177 82 : return true;
178 : assert((RES_TXTATR_META == nWhich) ||
179 : (RES_TXTATR_METAFIELD == nWhich) ||
180 : (RES_TXTATR_INPUTFIELD == nWhich));
181 62 : 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 86 : splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther)
191 : {
192 86 : if (!isSplittable(nWhichOther))
193 : {
194 58 : if (!isSplittable(nWhichNew))
195 4 : return FAIL;
196 : else
197 54 : return SPLIT_NEW;
198 : }
199 : else
200 : {
201 28 : if ( RES_TXTATR_INPUTFIELD == nWhichNew )
202 0 : return FAIL;
203 28 : else if ( (RES_TXTATR_INETFMT == nWhichNew) &&
204 : (RES_TXTATR_CJK_RUBY == nWhichOther) )
205 6 : return SPLIT_NEW;
206 : else
207 22 : return SPLIT_OTHER;
208 : }
209 : }
210 :
211 2870 : void SwTxtINetFmt::InitINetFmt(SwTxtNode & rNode)
212 : {
213 2870 : ChgTxtNode(&rNode);
214 : SwCharFmt * const pFmt(
215 2870 : rNode.GetDoc()->getIDocumentStylePoolAccess().GetCharFmtFromPool(RES_POOLCHR_INET_NORMAL) );
216 2870 : pFmt->Add( this );
217 2870 : }
218 :
219 362 : void SwTxtRuby::InitRuby(SwTxtNode & rNode)
220 : {
221 362 : ChgTxtNode(&rNode);
222 : SwCharFmt * const pFmt(
223 362 : rNode.GetDoc()->getIDocumentStylePoolAccess().GetCharFmtFromPool(RES_POOLCHR_RUBYTEXT) );
224 362 : pFmt->Add( this );
225 362 : }
226 :
227 : /**
228 : Create a new nesting text hint.
229 : */
230 : static SwTxtAttrNesting *
231 84 : MakeTxtAttrNesting(SwTxtNode & rNode, SwTxtAttrNesting & rNesting,
232 : const sal_Int32 nStart, const sal_Int32 nEnd)
233 : {
234 : SwTxtAttr * const pNew( MakeTxtAttr(
235 84 : *rNode.GetDoc(), rNesting.GetAttr(), nStart, nEnd ) );
236 84 : switch (pNew->Which())
237 : {
238 : case RES_TXTATR_INETFMT:
239 : {
240 28 : static_txtattr_cast<SwTxtINetFmt*>(pNew)->InitINetFmt(rNode);
241 28 : break;
242 : }
243 : case RES_TXTATR_CJK_RUBY:
244 : {
245 56 : static_txtattr_cast<SwTxtRuby*>(pNew)->InitRuby(rNode);
246 56 : break;
247 : }
248 : default:
249 : assert(!"MakeTxtAttrNesting: what the hell is that?");
250 0 : break;
251 : }
252 84 : return static_txtattr_cast<SwTxtAttrNesting*>(pNew);
253 : }
254 :
255 : typedef ::std::vector<SwTxtAttrNesting *> NestList_t;
256 :
257 : static void
258 60 : lcl_DoSplitNew(NestList_t & rSplits, SwTxtNode & rNode,
259 : const sal_Int32 nNewStart,
260 : const sal_Int32 nOtherStart, const sal_Int32 nOtherEnd, bool bOtherDummy)
261 : {
262 60 : const bool bSplitAtStart(nNewStart < nOtherStart);
263 60 : 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 60 : TxtAttrContains(nSplitPos) ) );
268 60 : if (iter != rSplits.end()) // already split here?
269 : {
270 : const sal_Int32 nStartPos( // skip other's dummy character!
271 56 : (bSplitAtStart && bOtherDummy) ? nSplitPos + 1 : nSplitPos );
272 : SwTxtAttrNesting * const pNew( MakeTxtAttrNesting(
273 56 : rNode, **iter, nStartPos, *(*iter)->GetEnd() ) );
274 56 : *(*iter)->GetEnd() = nSplitPos;
275 56 : rSplits.insert(iter + 1, pNew);
276 : }
277 60 : }
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 3486 : void SwpHints::InsertNesting(SwTxtAttrNesting & rNewHint)
284 : {
285 3486 : SwpHintsArray::Insert(& rNewHint);
286 3486 : NoteInHistory( & rNewHint, true );
287 3486 : }
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 3402 : SwpHints::TryInsertNesting( SwTxtNode & rNode, SwTxtAttrNesting & rNewHint )
358 : {
359 : // INVARIANT: the nestable hints in the array are properly nested
360 3402 : const sal_uInt16 nNewWhich( rNewHint.Which() );
361 3402 : const sal_Int32 nNewStart( rNewHint.GetStart() );
362 3402 : const sal_Int32 nNewEnd ( *rNewHint.GetEnd() );
363 3402 : 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 3402 : NestList_t OverlappingExisting; // existing hints to be split
372 6804 : NestList_t OverwrittenExisting; // existing hints to be replaced
373 6804 : NestList_t SplitNew; // new hints to be inserted
374 :
375 3402 : SplitNew.push_back(& rNewHint);
376 :
377 : // pass 1: split the inserted hint into fragments if necessary
378 21990 : for ( size_t i = 0; i < GetEndCount(); ++i )
379 : {
380 18592 : SwTxtAttr * const pOther = GetEnd(i);
381 :
382 18592 : if (pOther->IsNesting())
383 : {
384 4034 : const sal_uInt16 nOtherWhich( pOther->Which() );
385 4034 : const sal_Int32 nOtherStart( pOther->GetStart() );
386 4034 : const sal_Int32 nOtherEnd ( *(pOther)->GetEnd() );
387 4034 : if (isOverlap(nNewStart, nNewEnd, nOtherStart, nOtherEnd ))
388 : {
389 86 : switch (splitPolicy(nNewWhich, nOtherWhich))
390 : {
391 : case FAIL:
392 : OSL_TRACE("cannot insert hint: overlap detected");
393 : ::std::for_each(SplitNew.begin(), SplitNew.end(),
394 4 : TxtAttrDeleter(*rNode.GetDoc()));
395 4 : return false;
396 : case SPLIT_NEW:
397 : lcl_DoSplitNew(SplitNew, rNode, nNewStart,
398 60 : nOtherStart, nOtherEnd, pOther->HasDummyChar());
399 60 : break;
400 : case SPLIT_OTHER:
401 : OverlappingExisting.push_back(
402 22 : static_txtattr_cast<SwTxtAttrNesting*>(pOther));
403 22 : break;
404 : default:
405 : assert(!"bad code monkey");
406 0 : break;
407 : }
408 : }
409 3948 : else if (isNestedAny(nNewStart, nNewEnd, nOtherStart, nOtherEnd))
410 : {
411 416 : if (!bNewSelfNestable && (nNewWhich == nOtherWhich))
412 : {
413 : // ruby and hyperlink: if there is nesting, _overwrite_
414 : OverwrittenExisting.push_back(
415 222 : static_txtattr_cast<SwTxtAttrNesting*>(pOther));
416 : }
417 194 : else if ((nNewStart == nOtherStart) && pOther->HasDummyChar())
418 : {
419 36 : if (rNewHint.HasDummyChar())
420 : {
421 : assert(!"ERROR: inserting duplicate CH_TXTATR hint");
422 0 : return false;
423 36 : } 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 4 : sal_Int32& rStart(SplitNew.front()->GetStart());
430 : assert(rStart == nNewStart);
431 4 : 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 10260 : for (NestList_t::iterator itOther = OverlappingExisting.begin();
450 6840 : itOther != OverlappingExisting.end(); ++itOther)
451 : {
452 22 : const sal_Int32 nOtherStart( (*itOther)->GetStart() );
453 22 : const sal_Int32 nOtherEnd ( *(*itOther)->GetEnd() );
454 :
455 138 : for (NestList_t::iterator itNew = SplitNew.begin();
456 92 : itNew != SplitNew.end(); ++itNew)
457 : {
458 24 : const sal_Int32 nSplitNewStart( (*itNew)->GetStart() );
459 24 : const sal_Int32 nSplitNewEnd ( *(*itNew)->GetEnd() );
460 : // 4 cases: within, around, overlap l, overlap r, (OTHER: no action)
461 : const bool bRemoveOverlap(
462 24 : !bNewSelfNestable && (nNewWhich == (*itOther)->Which()) );
463 :
464 24 : switch (ComparePosition(nSplitNewStart, nSplitNewEnd,
465 24 : nOtherStart, nOtherEnd))
466 : {
467 : case POS_INSIDE:
468 : {
469 : assert(!bRemoveOverlap &&
470 : "this one should be in OverwrittenExisting?");
471 : }
472 2 : 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 10 : Delete( *itOther ); // this also does NoteInHistory!
482 10 : (*itOther)->GetStart() = nSplitNewEnd;
483 10 : InsertNesting( **itOther );
484 10 : if (!bRemoveOverlap)
485 : {
486 6 : if ( MAX_HINTS <= Count() )
487 : {
488 : OSL_FAIL("hints array full :-(");
489 0 : return false;
490 : }
491 : SwTxtAttrNesting * const pOtherLeft(
492 6 : MakeTxtAttrNesting( rNode, **itOther,
493 12 : nOtherStart, nSplitNewEnd ) );
494 6 : InsertNesting( *pOtherLeft );
495 : }
496 : }
497 10 : break;
498 : case POS_OVERLAP_BEHIND:
499 : {
500 10 : Delete( *itOther ); // this also does NoteInHistory!
501 10 : *(*itOther)->GetEnd() = nSplitNewStart;
502 10 : InsertNesting( **itOther );
503 10 : if (!bRemoveOverlap)
504 : {
505 6 : if ( MAX_HINTS <= Count() )
506 : {
507 : OSL_FAIL("hints array full :-(");
508 0 : return false;
509 : }
510 : SwTxtAttrNesting * const pOtherRight(
511 6 : MakeTxtAttrNesting( rNode, **itOther,
512 12 : nSplitNewStart, nOtherEnd ) );
513 6 : InsertNesting( *pOtherRight );
514 : }
515 : }
516 10 : break;
517 : default:
518 2 : break; // overlap resolved by splitting new: nothing to do
519 : }
520 : }
521 : }
522 :
523 3398 : if ( MAX_HINTS <= Count() || MAX_HINTS - Count() <= SplitNew.size() )
524 : {
525 : OSL_FAIL("hints array full :-(");
526 0 : return false;
527 : }
528 :
529 : // pass 3: insert new hints
530 20556 : for (NestList_t::iterator iter = SplitNew.begin();
531 13704 : iter != SplitNew.end(); ++iter)
532 : {
533 3454 : 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 10860 : for (NestList_t::iterator itOther = OverwrittenExisting.begin();
540 7240 : itOther != OverwrittenExisting.end(); ++itOther)
541 : {
542 222 : const sal_Int32 nOtherStart( (*itOther)->GetStart() );
543 222 : const sal_Int32 nOtherEnd ( *(*itOther)->GetEnd() );
544 :
545 : // overwritten portion is given by start/end of inserted hint
546 222 : if ((nNewStart <= nOtherStart) && (nOtherEnd <= nNewEnd))
547 : {
548 204 : Delete(*itOther);
549 204 : 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 18 : Delete( *itOther ); // this also does NoteInHistory!
559 18 : if (nNewEnd < nOtherEnd)
560 : {
561 : SwTxtAttrNesting * const pOtherRight(
562 : MakeTxtAttrNesting(
563 16 : rNode, **itOther, nNewEnd, nOtherEnd ) );
564 16 : bool const bSuccess( TryInsertNesting(rNode, *pOtherRight) );
565 : SAL_WARN_IF(!bSuccess, "sw.core", "recursive call 1 failed?");
566 : }
567 18 : if (nOtherStart < nNewStart)
568 : {
569 16 : *(*itOther)->GetEnd() = nNewStart;
570 16 : bool const bSuccess( TryInsertNesting(rNode, **itOther) );
571 : SAL_WARN_IF(!bSuccess, "sw.core", "recursive call 2 failed?");
572 : }
573 : else
574 : {
575 2 : rNode.DestroyAttr(*itOther);
576 : }
577 : }
578 : }
579 :
580 6800 : 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 140626 : void SwpHints::BuildPortions( SwTxtNode& rNode, SwTxtAttr& rNewHint,
592 : const SetAttrMode nMode )
593 : {
594 140626 : const sal_uInt16 nWhich = rNewHint.Which();
595 :
596 140626 : const sal_Int32 nThisStart = rNewHint.GetStart();
597 140626 : const sal_Int32 nThisEnd = *rNewHint.GetEnd();
598 140626 : const bool bNoLengthAttribute = nThisStart == nThisEnd;
599 :
600 140626 : std::vector<SwTxtAttr*> aInsDelHints;
601 140626 : std::vector<SwTxtAttr*>::iterator aIter;
602 :
603 : OSL_ENSURE( RES_TXTATR_CHARFMT == rNewHint.Which() ||
604 : RES_TXTATR_AUTOFMT == rNewHint.Which(),
605 : "Expecting CHARFMT or AUTOFMT" );
606 :
607 : // 2. Find the hints which cover the start and end position
608 : // of the new hint. These hints have to be split into two portions:
609 :
610 140626 : if ( !bNoLengthAttribute ) // nothing to do for no length attributes
611 : {
612 443904 : for ( size_t i = 0; i < Count(); ++i )
613 : {
614 354944 : SwTxtAttr* pOther = GetTextHint(i);
615 :
616 673892 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
617 318948 : RES_TXTATR_AUTOFMT != pOther->Which() )
618 41914 : continue;
619 :
620 313030 : sal_Int32 nOtherStart = pOther->GetStart();
621 313030 : const sal_Int32 nOtherEnd = *pOther->GetEnd();
622 :
623 : // Check if start of new attribute overlaps with pOther:
624 : // Split pOther if necessary:
625 313030 : if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
626 : {
627 626 : SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
628 1252 : pOther->GetAttr(), nOtherStart, nThisStart );
629 626 : if ( RES_TXTATR_CHARFMT == pOther->Which() )
630 : {
631 : static_txtattr_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber(
632 152 : static_txtattr_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
633 : }
634 626 : aInsDelHints.push_back( pNewAttr );
635 :
636 626 : NoteInHistory( pOther );
637 626 : pOther->GetStart() = nThisStart;
638 626 : NoteInHistory( pOther, true );
639 :
640 626 : nOtherStart = nThisStart;
641 : }
642 :
643 : // Check if end of new attribute overlaps with pOther:
644 : // Split pOther if necessary:
645 313030 : if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd )
646 : {
647 1730 : SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
648 3460 : pOther->GetAttr(), nOtherStart, nThisEnd );
649 1730 : if ( RES_TXTATR_CHARFMT == pOther->Which() )
650 : {
651 : static_txtattr_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber(
652 0 : static_txtattr_cast<SwTxtCharFmt*>(pOther)->GetSortNumber());
653 : }
654 1730 : aInsDelHints.push_back( pNewAttr );
655 :
656 1730 : NoteInHistory( pOther );
657 1730 : pOther->GetStart() = nThisEnd;
658 1730 : NoteInHistory( pOther, true );
659 : }
660 : }
661 :
662 : // Insert the newly created attributes:
663 91316 : for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
664 : {
665 2356 : SwpHintsArray::Insert( *aIter );
666 2356 : NoteInHistory( *aIter, true );
667 : }
668 : }
669 :
670 : #ifdef DBG_UTIL
671 : if( !rNode.GetDoc()->IsInReading() )
672 : CHECK_NOTMERGED; // ignore flags not set properly yet, don't check them
673 : #endif
674 :
675 : // 4. Split rNewHint into 1 ... n new hints:
676 :
677 281252 : std::set<sal_Int32> aBounds;
678 140626 : aBounds.insert( nThisStart );
679 140626 : aBounds.insert( nThisEnd );
680 :
681 140626 : if ( !bNoLengthAttribute ) // nothing to do for no length attributes
682 : {
683 446260 : for ( size_t i = 0; i < Count(); ++i )
684 : {
685 357300 : const SwTxtAttr* pOther = GetTextHint(i);
686 :
687 678452 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
688 321152 : RES_TXTATR_AUTOFMT != pOther->Which() )
689 41914 : continue;
690 :
691 315386 : const sal_Int32 nOtherStart = pOther->GetStart();
692 315386 : const sal_Int32 nOtherEnd = *pOther->End();
693 :
694 315386 : aBounds.insert( nOtherStart );
695 315386 : aBounds.insert( nOtherEnd );
696 : }
697 : }
698 :
699 140626 : std::set<sal_Int32>::iterator aStartIter = aBounds.lower_bound( nThisStart );
700 140626 : std::set<sal_Int32>::iterator aEndIter = aBounds.upper_bound( nThisEnd );
701 140626 : sal_Int32 nPorStart = *aStartIter;
702 140626 : ++aStartIter;
703 140626 : bool bDestroyHint = true;
704 :
705 : // Insert the 1...n new parts of the new attribute:
706 :
707 372246 : while ( aStartIter != aEndIter || bNoLengthAttribute )
708 : {
709 : OSL_ENSURE( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" );
710 :
711 142660 : const sal_Int32 nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter;
712 142660 : aInsDelHints.clear();
713 :
714 : // Get all hints that are in [nPorStart, nPorEnd[:
715 640960 : for ( size_t i = 0; i < Count(); ++i )
716 : {
717 502862 : SwTxtAttr *pOther = GetTextHint(i);
718 :
719 958304 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
720 455442 : RES_TXTATR_AUTOFMT != pOther->Which() )
721 48784 : continue;
722 :
723 454078 : const sal_Int32 nOtherStart = pOther->GetStart();
724 :
725 454078 : if ( nOtherStart > nPorStart )
726 4562 : break;
727 :
728 449516 : if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart )
729 : {
730 : OSL_ENSURE( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" );
731 50700 : aInsDelHints.push_back( pOther );
732 : }
733 : }
734 :
735 142660 : SwTxtAttr* pNewAttr = 0;
736 142660 : if ( RES_TXTATR_CHARFMT == nWhich )
737 : {
738 : // pNewHint can be inserted after calculating the sort value.
739 : // This should ensure, that pNewHint comes behind the already present
740 : // character style
741 12210 : sal_uInt16 nCharStyleCount = 0;
742 12210 : aIter = aInsDelHints.begin();
743 26302 : while ( aIter != aInsDelHints.end() )
744 : {
745 1882 : if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
746 : {
747 : // #i74589#
748 1356 : const SwFmtCharFmt& rOtherCharFmt = (*aIter)->GetCharFmt();
749 1356 : const SwFmtCharFmt& rThisCharFmt = rNewHint.GetCharFmt();
750 1356 : const bool bSameCharFmt = rOtherCharFmt.GetCharFmt() == rThisCharFmt.GetCharFmt();
751 :
752 : // #i90311#
753 : // Do not remove existing character format hint during XML import
754 4068 : if ( !rNode.GetDoc()->IsInXMLImport() &&
755 1356 : ( !( nsSetAttrMode::SETATTR_DONTREPLACE & nMode ) ||
756 0 : bNoLengthAttribute ||
757 : bSameCharFmt ) )
758 : {
759 : // Remove old hint
760 1356 : Delete( *aIter );
761 1356 : rNode.DestroyAttr( *aIter );
762 : }
763 : else
764 0 : ++nCharStyleCount;
765 : }
766 : else
767 : {
768 : // remove all attributes from auto styles, which are explicitly set in
769 : // the new character format:
770 : OSL_ENSURE( RES_TXTATR_AUTOFMT == (*aIter)->Which(), "AUTOSTYLES - Misc trouble" );
771 526 : SwTxtAttr* pOther = *aIter;
772 526 : boost::shared_ptr<SfxItemSet> pOldStyle = static_cast<const SwFmtAutoFmt&>(pOther->GetAttr()).GetStyleHandle();
773 :
774 : // For each attribute in the automatic style check if it
775 : // is also set the new character style:
776 526 : SfxItemSet aNewSet( *pOldStyle->GetPool(),
777 1052 : aCharAutoFmtSetRange);
778 1052 : SfxItemIter aItemIter( *pOldStyle );
779 526 : const SfxPoolItem* pItem = aItemIter.GetCurItem();
780 : while( true )
781 : {
782 1776 : if ( !CharFmt::IsItemIncluded( pItem->Which(), &rNewHint ) )
783 : {
784 750 : aNewSet.Put( *pItem );
785 : }
786 :
787 1776 : if( aItemIter.IsAtEnd() )
788 526 : break;
789 :
790 1250 : pItem = aItemIter.NextItem();
791 : }
792 :
793 : // Remove old hint
794 526 : Delete( pOther );
795 526 : rNode.DestroyAttr( pOther );
796 :
797 : // Create new AutoStyle
798 526 : if ( aNewSet.Count() )
799 : {
800 192 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
801 192 : aNewSet, nPorStart, nPorEnd );
802 192 : SwpHintsArray::Insert( pNewAttr );
803 192 : NoteInHistory( pNewAttr, true );
804 526 : }
805 : }
806 1882 : ++aIter;
807 : }
808 :
809 : // If there is no current hint and start and end of rNewHint
810 : // is ok, we do not need to create a new txtattr.
811 24420 : if ( nPorStart == nThisStart &&
812 24420 : nPorEnd == nThisEnd &&
813 : !nCharStyleCount )
814 : {
815 12210 : pNewAttr = &rNewHint;
816 12210 : bDestroyHint = false;
817 : }
818 : else
819 : {
820 0 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(), rNewHint.GetAttr(),
821 0 : nPorStart, nPorEnd );
822 0 : static_txtattr_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber(nCharStyleCount);
823 : }
824 : }
825 : else
826 : {
827 : // Find the current autostyle. Mix attributes if necessary.
828 130450 : SwTxtAttr* pCurrentAutoStyle = 0;
829 130450 : SwTxtAttr* pCurrentCharFmt = 0;
830 130450 : aIter = aInsDelHints.begin();
831 309718 : while ( aIter != aInsDelHints.end() )
832 : {
833 48818 : if ( RES_TXTATR_AUTOFMT == (*aIter)->Which() )
834 46384 : pCurrentAutoStyle = *aIter;
835 2434 : else if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
836 2434 : pCurrentCharFmt = *aIter;
837 48818 : ++aIter;
838 : }
839 :
840 130450 : boost::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFmtAutoFmt&>(rNewHint.GetAttr()).GetStyleHandle();
841 130450 : if ( pCurrentAutoStyle )
842 : {
843 46384 : boost::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFmtAutoFmt&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle();
844 :
845 : // Merge attributes
846 92768 : SfxItemSet aNewSet( *pCurrentStyle );
847 46384 : aNewSet.Put( *pNewStyle );
848 :
849 : // #i75750# Remove attributes already set at whole paragraph
850 : // #i81764# This should not be applied for no length attributes!!! <--
851 46384 : if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() )
852 : {
853 16526 : SfxItemIter aIter2( aNewSet );
854 16526 : const SfxPoolItem* pItem = aIter2.GetCurItem();
855 16526 : const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
856 :
857 82962 : do
858 : {
859 82962 : const SfxPoolItem* pTmpItem = 0;
860 83082 : if ( SfxItemState::SET == rWholeParaAttrSet.GetItemState( pItem->Which(), false, &pTmpItem ) &&
861 120 : pTmpItem == pItem )
862 : {
863 : // Do not clear item if the attribute is set in a character format:
864 0 : if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
865 0 : aNewSet.ClearItem( pItem->Which() );
866 : }
867 : }
868 99488 : while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
869 : }
870 :
871 : // Remove old hint
872 46384 : Delete( pCurrentAutoStyle );
873 46384 : rNode.DestroyAttr( pCurrentAutoStyle );
874 :
875 : // Create new AutoStyle
876 46384 : if ( aNewSet.Count() )
877 46384 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(), aNewSet,
878 92768 : nPorStart, nPorEnd );
879 : }
880 : else
881 : {
882 : // Remove any attributes which are already set at the whole paragraph:
883 84066 : bool bOptimizeAllowed = true;
884 :
885 84066 : SfxItemSet* pNewSet = 0;
886 : // #i75750# Remove attributes already set at whole paragraph
887 : // #i81764# This should not be applied for no length attributes!!! <--
888 84066 : if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() )
889 : {
890 9786 : SfxItemIter aIter2( *pNewStyle );
891 9786 : const SfxPoolItem* pItem = aIter2.GetCurItem();
892 9786 : const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
893 :
894 43302 : do
895 : {
896 43302 : const SfxPoolItem* pTmpItem = 0;
897 43330 : if ( SfxItemState::SET == rWholeParaAttrSet.GetItemState( pItem->Which(), false, &pTmpItem ) &&
898 28 : pTmpItem == pItem )
899 : {
900 : // Do not clear item if the attribute is set in a character format:
901 28 : if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
902 : {
903 28 : if ( !pNewSet )
904 16 : pNewSet = pNewStyle->Clone( true );
905 28 : pNewSet->ClearItem( pItem->Which() );
906 : }
907 : }
908 : }
909 43302 : while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
910 :
911 9786 : if ( pNewSet )
912 : {
913 16 : bOptimizeAllowed = false;
914 16 : if ( pNewSet->Count() )
915 0 : pNewStyle = rNode.getIDocumentStyleAccess().getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
916 : else
917 16 : pNewStyle.reset();
918 :
919 16 : delete pNewSet;
920 9786 : }
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 168116 : if ( bOptimizeAllowed &&
927 168034 : nPorStart == nThisStart &&
928 83984 : nPorEnd == nThisEnd )
929 : {
930 83974 : pNewAttr = &rNewHint;
931 83974 : bDestroyHint = false;
932 : }
933 92 : else if ( pNewStyle.get() )
934 : {
935 76 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(), *pNewStyle,
936 76 : nPorStart, nPorEnd );
937 : }
938 130450 : }
939 : }
940 :
941 142660 : if ( pNewAttr )
942 : {
943 142644 : SwpHintsArray::Insert( pNewAttr );
944 : // if ( bDestroyHint )
945 142644 : NoteInHistory( pNewAttr, true );
946 : }
947 :
948 142660 : if ( !bNoLengthAttribute )
949 : {
950 90994 : nPorStart = *aStartIter;
951 90994 : ++aStartIter;
952 : }
953 : else
954 51666 : break;
955 : }
956 :
957 140626 : if ( bDestroyHint )
958 185068 : rNode.DestroyAttr( &rNewHint );
959 140626 : }
960 :
961 9850 : SwTxtAttr* MakeRedlineTxtAttr( SwDoc & rDoc, SfxPoolItem & rAttr )
962 : {
963 : // this is intended _only_ for special-purpose redline attributes!
964 9850 : 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 9850 : 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 9850 : const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
987 9850 : return new SwTxtAttrEnd( rNew, 0, 0 );
988 : }
989 :
990 : // create new text attribute
991 206628 : SwTxtAttr* MakeTxtAttr(
992 : SwDoc & rDoc,
993 : SfxPoolItem& rAttr,
994 : sal_Int32 const nStt,
995 : sal_Int32 const nEnd,
996 : CopyOrNew_t const bIsCopy,
997 : SwTxtNode *const pTxtNode )
998 : {
999 206628 : if ( isCHRATR(rAttr.Which()) )
1000 : {
1001 : // Somebody wants to build a SwTxtAttr 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 MakeTxtAttr( rDoc, aItemSet, nStt, nEnd );
1008 : }
1009 800212 : else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
1010 : static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle()->
1011 747612 : 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 12 : const StylePool::SfxItemSet_Pointer_t pAutoStyle = static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle();
1016 : boost::scoped_ptr<const SfxItemSet> pNewSet(
1017 24 : pAutoStyle->SfxItemSet::Clone( true, &rDoc.GetAttrPool() ));
1018 12 : SwTxtAttr* pNew = MakeTxtAttr( rDoc, *pNewSet, nStt, nEnd );
1019 24 : return pNew;
1020 : }
1021 :
1022 : // Put new attribute into pool
1023 : // FIXME: this const_cast is evil!
1024 : SfxPoolItem& rNew =
1025 206616 : const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
1026 :
1027 206616 : SwTxtAttr* pNew = 0;
1028 206616 : switch( rNew.Which() )
1029 : {
1030 : case RES_TXTATR_CHARFMT:
1031 : {
1032 12362 : SwFmtCharFmt &rFmtCharFmt = (SwFmtCharFmt&) rNew;
1033 12362 : if( !rFmtCharFmt.GetCharFmt() )
1034 : {
1035 0 : rFmtCharFmt.SetCharFmt( rDoc.GetDfltCharFmt() );
1036 : }
1037 :
1038 12362 : pNew = new SwTxtCharFmt( rFmtCharFmt, nStt, nEnd );
1039 : }
1040 12362 : break;
1041 : case RES_TXTATR_INETFMT:
1042 2864 : pNew = new SwTxtINetFmt( (SwFmtINetFmt&)rNew, nStt, nEnd );
1043 2864 : break;
1044 :
1045 : case RES_TXTATR_FIELD:
1046 5476 : pNew = new SwTxtFld( static_cast<SwFmtFld &>(rNew), nStt,
1047 8214 : rDoc.IsClipBoard() );
1048 2738 : break;
1049 :
1050 : case RES_TXTATR_ANNOTATION:
1051 : {
1052 192 : pNew = new SwTxtAnnotationFld( static_cast<SwFmtFld &>(rNew), nStt, rDoc.IsClipBoard() );
1053 192 : 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 10 : const_cast<SwPostItField&>(dynamic_cast<const SwPostItField&>(*(pNew->GetFmtFld().GetField()))).SetName(OUString());
1060 : }
1061 : }
1062 192 : break;
1063 :
1064 : case RES_TXTATR_INPUTFIELD:
1065 56 : pNew = new SwTxtInputFld( static_cast<SwFmtFld &>(rNew), nStt, nEnd,
1066 84 : rDoc.IsClipBoard() );
1067 28 : break;
1068 :
1069 : case RES_TXTATR_FLYCNT:
1070 : {
1071 : // erst hier wird das Frame-Format kopiert (mit Inhalt) !!
1072 6870 : pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt );
1073 : // Kopie von einem Text-Attribut
1074 6870 : if ( static_cast<const SwFmtFlyCnt &>(rAttr).GetTxtFlyCnt() )
1075 : {
1076 : // then the format must be copied
1077 272 : static_cast<SwTxtFlyCnt *>(pNew)->CopyFlyFmt( &rDoc );
1078 : }
1079 : }
1080 6870 : break;
1081 : case RES_TXTATR_FTN:
1082 268 : pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt );
1083 : // ggfs. SeqNo kopieren
1084 268 : if( ((SwFmtFtn&)rAttr).GetTxtFtn() )
1085 0 : ((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() );
1086 268 : break;
1087 : case RES_TXTATR_REFMARK:
1088 164 : pNew = nStt == nEnd
1089 54 : ? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt )
1090 110 : : new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd );
1091 82 : break;
1092 : case RES_TXTATR_TOXMARK:
1093 342 : pNew = new SwTxtTOXMark( (SwTOXMark&)rNew, nStt, &nEnd );
1094 342 : break;
1095 : case RES_TXTATR_CJK_RUBY:
1096 360 : pNew = new SwTxtRuby( (SwFmtRuby&)rNew, nStt, nEnd );
1097 360 : break;
1098 : case RES_TXTATR_META:
1099 : case RES_TXTATR_METAFIELD:
1100 388 : pNew = SwTxtMeta::CreateTxtMeta( rDoc.GetMetaFieldManager(), pTxtNode,
1101 582 : static_cast<SwFmtMeta&>(rNew), nStt, nEnd, bIsCopy == COPY );
1102 194 : break;
1103 : default:
1104 : OSL_ENSURE(RES_TXTATR_AUTOFMT == rNew.Which(), "unknown attribute");
1105 180316 : pNew = new SwTxtAttrEnd( rNew, nStt, nEnd );
1106 180316 : break;
1107 : }
1108 :
1109 206616 : return pNew;
1110 : }
1111 :
1112 171450 : SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, const SfxItemSet& rSet,
1113 : sal_Int32 nStt, sal_Int32 nEnd )
1114 : {
1115 171450 : IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
1116 171450 : const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
1117 342900 : SwFmtAutoFmt aNewAutoFmt;
1118 171450 : aNewAutoFmt.SetStyleHandle( pAutoStyle );
1119 171450 : SwTxtAttr* pNew = MakeTxtAttr( rDoc, aNewAutoFmt, nStt, nEnd );
1120 342900 : return pNew;
1121 : }
1122 :
1123 : // loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
1124 206582 : void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr )
1125 : {
1126 206582 : if( pAttr )
1127 : {
1128 : // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
1129 206582 : SwDoc* pDoc = GetDoc();
1130 206582 : 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::DelFmt()
1136 6868 : SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1137 6868 : if( pFmt ) // vom Undo auf 0 gesetzt ??
1138 2794 : pDoc->getIDocumentLayoutAccess().DelLayoutFmt( pFmt );
1139 : }
1140 6868 : break;
1141 :
1142 : case RES_CHRATR_HIDDEN:
1143 0 : SetCalcHiddenCharFlags();
1144 0 : break;
1145 :
1146 : case RES_TXTATR_FTN:
1147 268 : ((SwTxtFtn*)pAttr)->SetStartNode( 0 );
1148 268 : static_cast<SwFmtFtn&>(pAttr->GetAttr()).InvalidateFootnote();
1149 268 : break;
1150 :
1151 : case RES_TXTATR_FIELD:
1152 : case RES_TXTATR_ANNOTATION:
1153 : case RES_TXTATR_INPUTFIELD:
1154 2940 : if( !pDoc->IsInDtor() )
1155 : {
1156 942 : SwTxtFld *const pTxtFld(static_txtattr_cast<SwTxtFld*>(pAttr));
1157 : // Wenn wir ein HiddenParaField sind, dann muessen wir
1158 : // ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
1159 942 : const SwField* pFld = pAttr->GetFmtFld().GetField();
1160 :
1161 : //JP 06-08-95: DDE-Felder bilden eine Ausnahme
1162 : OSL_ENSURE( RES_DDEFLD == pFld->GetTyp()->Which() ||
1163 : this == pTxtFld->GetpTxtNode(),
1164 : "Wo steht denn dieses Feld?" );
1165 :
1166 : // bestimmte Felder mussen am Doc das Calculations-Flag updaten
1167 942 : switch( pFld->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 18 : if( !pDoc->getIDocumentFieldsAccess().IsNewFldLst() && GetNodes().IsDocNodes() )
1180 16 : pDoc->getIDocumentFieldsAccess().InsDelFldInFldLst(false, *pTxtFld);
1181 18 : break;
1182 : case RES_DDEFLD:
1183 0 : if (GetNodes().IsDocNodes() && pTxtFld->GetpTxtNode())
1184 0 : ((SwDDEFieldType*)pFld->GetTyp())->DecRefCnt();
1185 0 : break;
1186 : case RES_POSTITFLD:
1187 : {
1188 34 : const_cast<SwFmtFld&>(pAttr->GetFmtFld()).Broadcast(
1189 68 : SwFmtFldHint(&pTxtFld->GetFmtFld(), SwFmtFldHintWhich::REMOVED));
1190 34 : break;
1191 : }
1192 : }
1193 : }
1194 2940 : static_cast<SwFmtFld&>(pAttr->GetAttr()).InvalidateField();
1195 2940 : break;
1196 :
1197 : case RES_TXTATR_TOXMARK:
1198 342 : static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark();
1199 342 : break;
1200 :
1201 : case RES_TXTATR_REFMARK:
1202 82 : static_cast<SwFmtRefMark&>(pAttr->GetAttr()).InvalidateRefMark();
1203 82 : break;
1204 :
1205 : case RES_TXTATR_META:
1206 : case RES_TXTATR_METAFIELD:
1207 190 : static_txtattr_cast<SwTxtMeta*>(pAttr)->ChgTxtNode(0);
1208 190 : break;
1209 :
1210 : default:
1211 195892 : break;
1212 : }
1213 :
1214 206582 : SwTxtAttr::Destroy( pAttr, pDoc->GetAttrPool() );
1215 : }
1216 206582 : }
1217 :
1218 11074 : SwTxtAttr* SwTxtNode::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 : "SwTxtNode::InsertItem should not be called with character attributes");
1227 :
1228 : SwTxtAttr *const pNew =
1229 : MakeTxtAttr(
1230 11074 : *GetDoc(),
1231 : rAttr,
1232 : nStart,
1233 : nEnd,
1234 11074 : (nMode & nsSetAttrMode::SETATTR_IS_COPY) ? COPY : NEW,
1235 22148 : this );
1236 :
1237 11074 : if ( pNew )
1238 : {
1239 11074 : 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 11074 : if (!bSuccess || !m_pSwpHints->Contains( pNew ))
1244 : {
1245 0 : return 0;
1246 : }
1247 : }
1248 :
1249 11074 : return pNew;
1250 : }
1251 :
1252 : // take ownership of pAttr; if insertion fails, delete pAttr
1253 157690 : bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode )
1254 : {
1255 157690 : 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 enum IDocumentContentOperations::InsertFlags nInsertFlags =
1263 157690 : (nMode & nsSetAttrMode::SETATTR_FORCEHINTEXPAND)
1264 : ? static_cast<IDocumentContentOperations::InsertFlags>(
1265 : IDocumentContentOperations::INS_FORCEHINTEXPAND |
1266 : IDocumentContentOperations::INS_EMPTYEXPAND)
1267 157690 : : IDocumentContentOperations::INS_EMPTYEXPAND;
1268 :
1269 : // need this after TryInsertHint, when pAttr may be deleted
1270 157690 : const sal_Int32 nStart( pAttr->GetStart() );
1271 157690 : const bool bDummyChar( pAttr->HasDummyChar() );
1272 157690 : if (bDummyChar)
1273 : {
1274 10648 : sal_uInt16 nInsMode = nMode;
1275 10648 : switch( pAttr->Which() )
1276 : {
1277 : case RES_TXTATR_FLYCNT:
1278 : {
1279 6880 : SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr;
1280 6880 : SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1281 6880 : if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1282 : {
1283 : // Wir muessen zuerst einfuegen, da in SetAnchor()
1284 : // dem FlyFrm GetStart() uebermittelt wird.
1285 : //JP 11.05.98: falls das Anker-Attribut schon richtig
1286 : // gesetzt ist, dann korrigiere dieses nach dem Einfuegen
1287 : // des Zeichens. Sonst muesste das immer ausserhalb
1288 : // erfolgen (Fehleranfaellig !)
1289 6598 : const SwFmtAnchor* pAnchor = 0;
1290 : pFmt->GetItemState( RES_ANCHOR, false,
1291 6598 : (const SfxPoolItem**)&pAnchor );
1292 :
1293 6598 : SwIndex aIdx( this, pAttr->GetStart() );
1294 13196 : const OUString c(GetCharOfTxtAttr(*pAttr));
1295 13196 : OUString const ins( InsertText(c, aIdx, nInsertFlags) );
1296 6598 : if (ins.isEmpty())
1297 : {
1298 : // do not record deletion of Format!
1299 : ::sw::UndoGuard const ug(
1300 0 : pFmt->GetDoc()->GetIDocumentUndoRedo());
1301 0 : DestroyAttr(pAttr);
1302 0 : return false; // text node full :(
1303 : }
1304 6598 : nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
1305 :
1306 19834 : if (pAnchor &&
1307 13156 : (FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
1308 19674 : pAnchor->GetCntntAnchor() &&
1309 38068 : pAnchor->GetCntntAnchor()->nNode == *this &&
1310 5198 : pAnchor->GetCntntAnchor()->nContent == aIdx )
1311 : {
1312 : const_cast<SwIndex&>(
1313 5082 : pAnchor->GetCntntAnchor()->nContent)--;
1314 6598 : }
1315 : }
1316 6880 : pFly->SetAnchor( this );
1317 :
1318 : // Format-Pointer kann sich im SetAnchor geaendert haben!
1319 : // (Kopieren in andere Docs!)
1320 6880 : pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1321 6880 : SwDoc *pDoc = pFmt->GetDoc();
1322 :
1323 : // OD 26.06.2003 #108784# - allow drawing objects in header/footer.
1324 : // But don't allow control objects in header/footer
1325 12204 : if( RES_DRAWFRMFMT == pFmt->Which() &&
1326 5324 : pDoc->IsInHeaderFooter( pFmt->GetAnchor().GetCntntAnchor()->nNode ) )
1327 : {
1328 : SwDrawContact* pDrawContact =
1329 220 : static_cast<SwDrawContact*>(pFmt->FindContactObj());
1330 434 : if ( pDrawContact &&
1331 434 : pDrawContact->GetMaster() &&
1332 214 : ::CheckControlLayer( pDrawContact->GetMaster() ) )
1333 : {
1334 : // das soll nicht meoglich sein; hier verhindern
1335 : // Der Dtor des TxtHints loescht nicht das Zeichen.
1336 : // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1337 : // dieses explizit loeschen
1338 0 : if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
1339 : {
1340 : // loesche das Zeichen aus dem String !
1341 : OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
1342 : m_Text[pAttr->GetStart()] ||
1343 : CH_TXTATR_INWORD ==
1344 : m_Text[pAttr->GetStart()]),
1345 : "where is my attribute character?" );
1346 0 : m_Text = m_Text.replaceAt(pAttr->GetStart(), 1, "");
1347 : // Indizies Updaten
1348 0 : SwIndex aTmpIdx( this, pAttr->GetStart() );
1349 0 : Update( aTmpIdx, 1, true );
1350 : }
1351 : // do not record deletion of Format!
1352 0 : ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1353 0 : DestroyAttr( pAttr );
1354 0 : return false;
1355 : }
1356 : }
1357 6880 : break;
1358 : }
1359 :
1360 : case RES_TXTATR_FTN :
1361 : {
1362 : // Fussnoten, man kommt an alles irgendwie heran.
1363 : // CntntNode erzeugen und in die Inserts-Section stellen
1364 272 : SwDoc *pDoc = GetDoc();
1365 272 : SwNodes &rNodes = pDoc->GetNodes();
1366 :
1367 : // FussNote in nicht Content-/Redline-Bereich einfuegen ??
1368 272 : if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
1369 : {
1370 : // das soll nicht meoglich sein; hier verhindern
1371 : // Der Dtor des TxtHints loescht nicht das Zeichen.
1372 : // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1373 : // dieses explizit loeschen
1374 0 : if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
1375 : {
1376 : // loesche das Zeichen aus dem String !
1377 : OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
1378 : m_Text[pAttr->GetStart()] ||
1379 : CH_TXTATR_INWORD ==
1380 : m_Text[pAttr->GetStart()]),
1381 : "where is my attribute character?" );
1382 0 : m_Text = m_Text.replaceAt(pAttr->GetStart(), 1, "");
1383 : // Indizies Updaten
1384 0 : SwIndex aTmpIdx( this, pAttr->GetStart() );
1385 0 : Update( aTmpIdx, 1, true );
1386 : }
1387 0 : DestroyAttr( pAttr );
1388 0 : return false;
1389 : }
1390 :
1391 : // wird eine neue Fussnote eingefuegt ??
1392 272 : bool bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode();
1393 272 : if( bNewFtn )
1394 : {
1395 268 : ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() );
1396 268 : SwRegHistory* pHist = GetpSwpHints()
1397 268 : ? GetpSwpHints()->GetHistory() : 0;
1398 268 : if( pHist )
1399 40 : pHist->ChangeNodeIndex( GetIndex() );
1400 : }
1401 4 : else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
1402 : {
1403 : // loesche alle Frames der Section, auf die der StartNode zeigt
1404 : sal_uLong nSttIdx =
1405 4 : ((SwTxtFtn*)pAttr)->GetStartNode()->GetIndex();
1406 4 : sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
1407 : SwCntntNode* pCNd;
1408 8 : for( ; nSttIdx < nEndIdx; ++nSttIdx )
1409 4 : if( 0 != ( pCNd = rNodes[ nSttIdx ]->GetCntntNode() ))
1410 4 : pCNd->DelFrms();
1411 : }
1412 :
1413 272 : if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1414 : {
1415 : // Wir muessen zuerst einfuegen, da sonst gleiche Indizes
1416 : // entstehen koennen und das Attribut im _SortArr_ am
1417 : // Dokument nicht eingetrage wird.
1418 268 : SwIndex aNdIdx( this, pAttr->GetStart() );
1419 536 : const OUString c(GetCharOfTxtAttr(*pAttr));
1420 536 : OUString const ins( InsertText(c, aNdIdx, nInsertFlags) );
1421 268 : if (ins.isEmpty())
1422 : {
1423 0 : DestroyAttr(pAttr);
1424 0 : return false; // text node full :(
1425 : }
1426 536 : nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
1427 : }
1428 :
1429 : // Wir tragen uns am FtnIdx-Array des Docs ein ...
1430 272 : SwTxtFtn* pTxtFtn = 0;
1431 272 : if( !bNewFtn )
1432 : {
1433 : // eine alte Ftn wird umgehaengt (z.B. SplitNode)
1434 4 : for( size_t n = 0; n < pDoc->GetFtnIdxs().size(); ++n )
1435 4 : if( pAttr == pDoc->GetFtnIdxs()[n] )
1436 : {
1437 : // neuen Index zuweisen, dafuer aus dem SortArray
1438 : // loeschen und neu eintragen
1439 4 : pTxtFtn = pDoc->GetFtnIdxs()[n];
1440 4 : pDoc->GetFtnIdxs().erase( pDoc->GetFtnIdxs().begin() + n );
1441 4 : break;
1442 : }
1443 : // wenn ueber Undo der StartNode gesetzt wurde, kann
1444 : // der Index noch gar nicht in der Verwaltung stehen !!
1445 : }
1446 272 : if( !pTxtFtn )
1447 268 : pTxtFtn = (SwTxtFtn*)pAttr;
1448 :
1449 : // fuers Update der Nummern und zum Sortieren
1450 : // muss der Node gesetzt sein.
1451 272 : ((SwTxtFtn*)pAttr)->ChgTxtNode( this );
1452 :
1453 : // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen!
1454 272 : if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
1455 : {
1456 272 : const bool bSuccess = pDoc->GetFtnIdxs().insert(pTxtFtn).second;
1457 : OSL_ENSURE( bSuccess, "FtnIdx not inserted." );
1458 : (void) bSuccess; // unused in non-debug
1459 : }
1460 272 : SwNodeIndex aTmpIndex( *this );
1461 272 : pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
1462 272 : ((SwTxtFtn*)pAttr)->SetSeqRefNo();
1463 : }
1464 272 : break;
1465 :
1466 : case RES_TXTATR_FIELD:
1467 : {
1468 : // fuer HiddenParaFields Benachrichtigungsmechanismus
1469 : // anwerfen
1470 2740 : if( RES_HIDDENPARAFLD == pAttr->GetFmtFld().GetField()->GetTyp()->Which() )
1471 : {
1472 0 : bHiddenPara = true;
1473 : }
1474 : }
1475 2740 : break;
1476 :
1477 : }
1478 : // Fuer SwTxtHints ohne Endindex werden CH_TXTATR_..
1479 : // eingefuegt, aStart muss danach um einen zurueckgesetzt werden.
1480 : // Wenn wir im SwTxtNode::Copy stehen, so wurde das Zeichen bereits
1481 : // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden.
1482 10648 : if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1483 : {
1484 2600 : SwIndex aIdx( this, pAttr->GetStart() );
1485 2600 : OUString const ins( InsertText(OUString(GetCharOfTxtAttr(*pAttr)),
1486 5200 : aIdx, nInsertFlags) );
1487 2600 : if (ins.isEmpty())
1488 : {
1489 0 : DestroyAttr(pAttr);
1490 0 : return false; // text node full :(
1491 : }
1492 :
1493 : // adjust end of hint to account for inserted CH_TXTATR
1494 2600 : sal_Int32 * const pEnd(pAttr->GetEnd());
1495 2600 : if (pEnd)
1496 : {
1497 194 : *pEnd = *pEnd + 1;
1498 2600 : }
1499 : }
1500 : }
1501 :
1502 : // handle attributes which provide content
1503 157690 : sal_Int32 nEnd = nStart;
1504 157690 : bool bInputFieldStartCharInserted = false;
1505 157690 : bool bInputFieldEndCharInserted = false;
1506 157690 : const bool bHasContent( pAttr->HasContent() );
1507 157690 : if ( bHasContent )
1508 : {
1509 28 : switch( pAttr->Which() )
1510 : {
1511 : case RES_TXTATR_INPUTFIELD:
1512 : {
1513 28 : SwTxtInputFld* pTxtInputFld = dynamic_cast<SwTxtInputFld*>(pAttr);
1514 28 : if ( pTxtInputFld )
1515 : {
1516 28 : if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) )
1517 : {
1518 20 : SwIndex aIdx( this, pAttr->GetStart() );
1519 20 : InsertText( OUString(CH_TXT_ATR_INPUTFIELDSTART), aIdx, nInsertFlags );
1520 40 : const OUString aContent = pTxtInputFld->GetFieldContent();
1521 20 : InsertText( aContent, aIdx, nInsertFlags );
1522 20 : InsertText( OUString(CH_TXT_ATR_INPUTFIELDEND), aIdx, nInsertFlags );
1523 :
1524 20 : sal_Int32* const pEnd(pAttr->GetEnd());
1525 : OSL_ENSURE( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1526 20 : if ( pEnd != NULL )
1527 : {
1528 20 : *pEnd = *pEnd + 2 + aContent.getLength();
1529 20 : nEnd = *pEnd;
1530 20 : }
1531 : }
1532 : else
1533 : {
1534 : // assure that CH_TXT_ATR_INPUTFIELDSTART and CH_TXT_ATR_INPUTFIELDEND are inserted.
1535 8 : if ( m_Text[ pAttr->GetStart() ] != CH_TXT_ATR_INPUTFIELDSTART )
1536 : {
1537 0 : SwIndex aIdx( this, pAttr->GetStart() );
1538 0 : InsertText( OUString(CH_TXT_ATR_INPUTFIELDSTART), aIdx, nInsertFlags );
1539 0 : bInputFieldStartCharInserted = true;
1540 0 : sal_Int32* const pEnd(pAttr->GetEnd());
1541 : OSL_ENSURE( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1542 0 : if ( pEnd != NULL )
1543 : {
1544 0 : *pEnd = *pEnd + 1;
1545 0 : nEnd = *pEnd;
1546 0 : }
1547 : }
1548 :
1549 8 : sal_Int32* const pEnd(pAttr->GetEnd());
1550 : OSL_ENSURE( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" );
1551 8 : if ( pEnd != NULL
1552 8 : && m_Text[ *(pEnd) - 1 ] != CH_TXT_ATR_INPUTFIELDEND )
1553 : {
1554 0 : SwIndex aIdx( this, *(pEnd) );
1555 0 : InsertText( OUString(CH_TXT_ATR_INPUTFIELDEND), aIdx, nInsertFlags );
1556 0 : bInputFieldEndCharInserted = true;
1557 0 : *pEnd = *pEnd + 1;
1558 0 : nEnd = *pEnd;
1559 : }
1560 : }
1561 : }
1562 : }
1563 28 : break;
1564 : default:
1565 0 : break;
1566 : }
1567 : }
1568 :
1569 157690 : GetOrCreateSwpHints();
1570 :
1571 : // handle overlap with an existing InputField
1572 157690 : bool bInsertHint = true;
1573 : {
1574 157690 : const SwTxtInputFld* pTxtInputFld = GetOverlappingInputFld( *pAttr );
1575 157690 : if ( pTxtInputFld != NULL )
1576 : {
1577 0 : if ( pAttr->End() == NULL )
1578 : {
1579 0 : bInsertHint = false;
1580 : }
1581 : else
1582 : {
1583 0 : if ( pAttr->GetStart() > pTxtInputFld->GetStart() )
1584 : {
1585 0 : pAttr->GetStart() = pTxtInputFld->GetStart();
1586 : }
1587 0 : if ( *(pAttr->End()) < *(pTxtInputFld->End()) )
1588 : {
1589 0 : *(pAttr->GetEnd()) = *(pTxtInputFld->End());
1590 : }
1591 : }
1592 : }
1593 : }
1594 :
1595 : // 4263: AttrInsert durch TextInsert => kein Adjust
1596 : const bool bRet = bInsertHint
1597 157690 : ? m_pSwpHints->TryInsertHint( pAttr, *this, nMode )
1598 315380 : : false;
1599 :
1600 157690 : if ( !bRet )
1601 : {
1602 4 : if ( bDummyChar
1603 4 : && !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) )
1604 : {
1605 : // undo insertion of dummy character
1606 : // N.B. cannot insert the dummy character after inserting the hint,
1607 : // because if the hint has no extent it will be moved in InsertText,
1608 : // resulting in infinite recursion
1609 : OSL_ENSURE( ( CH_TXTATR_BREAKWORD == m_Text[nStart] ||
1610 : CH_TXTATR_INWORD == m_Text[nStart] ),
1611 : "where is my attribute character?" );
1612 4 : SwIndex aIdx( this, nStart );
1613 4 : EraseText( aIdx, 1 );
1614 : }
1615 :
1616 4 : if ( bHasContent )
1617 : {
1618 0 : if ( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode)
1619 0 : && (nEnd - nStart) > 0 )
1620 : {
1621 0 : SwIndex aIdx( this, nStart );
1622 0 : EraseText( aIdx, (nEnd - nStart) );
1623 : }
1624 : else
1625 : {
1626 0 : if ( bInputFieldEndCharInserted
1627 0 : && (nEnd - nStart) > 0 )
1628 : {
1629 0 : SwIndex aIdx( this, nEnd - 1 );
1630 0 : EraseText( aIdx, 1 );
1631 : }
1632 :
1633 0 : if ( bInputFieldStartCharInserted )
1634 : {
1635 0 : SwIndex aIdx( this, nStart );
1636 0 : EraseText( aIdx, 1 );
1637 : }
1638 : }
1639 : }
1640 : }
1641 :
1642 157690 : if ( bHiddenPara )
1643 : {
1644 0 : SetCalcHiddenParaField();
1645 : }
1646 :
1647 157690 : return bRet;
1648 : }
1649 :
1650 10 : void SwTxtNode::DeleteAttribute( SwTxtAttr * const pAttr )
1651 : {
1652 10 : if ( !HasHints() )
1653 : {
1654 : OSL_FAIL("DeleteAttribute called, but text node without hints?");
1655 10 : return;
1656 : }
1657 :
1658 10 : if ( pAttr->HasDummyChar() )
1659 : {
1660 : // Unbedingt Copy-konstruieren!
1661 10 : const SwIndex aIdx( this, pAttr->GetStart() );
1662 : // erase the CH_TXTATR, which will also delete pAttr
1663 10 : EraseText( aIdx, 1 );
1664 : }
1665 0 : else if ( pAttr->HasContent() )
1666 : {
1667 0 : const SwIndex aIdx( this, pAttr->GetStart() );
1668 : OSL_ENSURE( pAttr->End() != NULL, "<SwTxtNode::DeleteAttribute(..)> - missing End() at <SwTxtAttr> instance which has content" );
1669 0 : EraseText( aIdx, *pAttr->End() - pAttr->GetStart() );
1670 : }
1671 : else
1672 : {
1673 : // create MsgHint before start/end become invalid
1674 : SwUpdateAttr aHint(
1675 0 : pAttr->GetStart(),
1676 0 : *pAttr->GetEnd(),
1677 0 : pAttr->Which());
1678 :
1679 0 : m_pSwpHints->Delete( pAttr );
1680 0 : SwTxtAttr::Destroy( pAttr, GetDoc()->GetAttrPool() );
1681 0 : NotifyClients( 0, &aHint );
1682 :
1683 0 : TryDeleteSwpHints();
1684 : }
1685 : }
1686 :
1687 : //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
1688 4316 : void SwTxtNode::DeleteAttributes(
1689 : const sal_uInt16 nWhich,
1690 : const sal_Int32 nStart,
1691 : const sal_Int32 nEnd )
1692 : {
1693 4316 : if ( !HasHints() )
1694 4316 : return;
1695 :
1696 9124 : for ( size_t nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); ++nPos )
1697 : {
1698 4858 : SwTxtAttr * const pTxtHt = m_pSwpHints->GetTextHint( nPos );
1699 4858 : const sal_Int32 nHintStart = pTxtHt->GetStart();
1700 4858 : if (nStart < nHintStart)
1701 : {
1702 50 : break; // sorted by start
1703 : }
1704 4808 : else if ( (nStart == nHintStart) && (nWhich == pTxtHt->Which()) )
1705 : {
1706 4316 : if ( nWhich == RES_CHRATR_HIDDEN )
1707 : {
1708 : OSL_FAIL("hey, that's a CHRATR! how did that get in?");
1709 0 : SetCalcHiddenCharFlags();
1710 : }
1711 4316 : else if ( nWhich == RES_TXTATR_CHARFMT )
1712 : {
1713 : // Check if character format contains hidden attribute:
1714 0 : const SwCharFmt* pFmt = pTxtHt->GetCharFmt().GetCharFmt();
1715 : const SfxPoolItem* pItem;
1716 0 : if ( SfxItemState::SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) )
1717 0 : SetCalcHiddenCharFlags();
1718 : }
1719 : // #i75430# Recalc hidden flags if necessary
1720 4316 : else if ( nWhich == RES_TXTATR_AUTOFMT )
1721 : {
1722 : // Check if auto style contains hidden attribute:
1723 0 : const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN );
1724 0 : if ( pHiddenItem )
1725 0 : SetCalcHiddenCharFlags();
1726 : // for auto styles DeleteAttributes is only called from Undo
1727 : // so it shouldn't need to care about ignore start/end flags
1728 : }
1729 :
1730 4316 : sal_Int32 const * const pEndIdx = pTxtHt->GetEnd();
1731 :
1732 4316 : if ( pTxtHt->HasDummyChar() )
1733 : {
1734 : // Unbedingt Copy-konstruieren!
1735 4316 : const SwIndex aIdx( this, nStart );
1736 : // erase the CH_TXTATR, which will also delete pTxtHt
1737 4316 : EraseText( aIdx, 1 );
1738 : }
1739 0 : else if ( pTxtHt->HasContent() )
1740 : {
1741 0 : const SwIndex aIdx( this, nStart );
1742 : OSL_ENSURE( pTxtHt->End() != NULL, "<SwTxtNode::DeleteAttributes(..)> - missing End() at <SwTxtAttr> instance which has content" );
1743 0 : EraseText( aIdx, *pTxtHt->End() - nStart );
1744 : }
1745 0 : else if( *pEndIdx == nEnd )
1746 : {
1747 : // den MsgHint jetzt fuettern, weil gleich sind
1748 : // Start und End weg.
1749 : // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
1750 : // da dies das Feld im Dtor selbst erledigt.
1751 : SwUpdateAttr aHint(
1752 : nStart,
1753 : *pEndIdx,
1754 0 : nWhich);
1755 :
1756 0 : m_pSwpHints->DeleteAtPos( nPos ); // gefunden, loeschen,
1757 0 : SwTxtAttr::Destroy( pTxtHt, GetDoc()->GetAttrPool() );
1758 0 : NotifyClients( 0, &aHint );
1759 : }
1760 : }
1761 : }
1762 4316 : TryDeleteSwpHints();
1763 : }
1764 :
1765 0 : void SwTxtNode::DelSoftHyph( const sal_Int32 nStt, const sal_Int32 nEnd )
1766 : {
1767 0 : sal_Int32 nFndPos = nStt;
1768 0 : sal_Int32 nEndPos = nEnd;
1769 : for (;;)
1770 : {
1771 0 : nFndPos = m_Text.indexOf(CHAR_SOFTHYPHEN, nFndPos);
1772 0 : if (nFndPos<0 || nFndPos>=nEndPos )
1773 : {
1774 : break;
1775 : }
1776 0 : const SwIndex aIdx( this, nFndPos );
1777 0 : EraseText( aIdx, 1 );
1778 0 : --nEndPos;
1779 0 : }
1780 0 : }
1781 :
1782 : //In MS Word, the font underline setting of the paragraph end position wont affect the formatting of numbering, so we ignore it
1783 14 : bool lcl_IsIgnoredCharFmtForNumbering(const sal_uInt16 nWhich)
1784 : {
1785 14 : return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_BACKGROUND || nWhich == RES_CHRATR_ESCAPEMENT);
1786 : }
1787 :
1788 : //In MS Word, following properties of the paragraph end position wont affect the formatting of bullets, so we ignore them:
1789 : //Font underline;
1790 : //Font Italic of Western, CJK and CTL;
1791 : //Font Bold of Wertern, CJK and CTL;
1792 110 : bool lcl_IsIgnoredCharFmtForBullets(const sal_uInt16 nWhich)
1793 : {
1794 110 : return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_POSTURE || nWhich == RES_CHRATR_WEIGHT
1795 100 : || nWhich == RES_CHRATR_CJK_POSTURE || nWhich == RES_CHRATR_CJK_WEIGHT
1796 200 : || nWhich == RES_CHRATR_CTL_POSTURE || nWhich == RES_CHRATR_CTL_WEIGHT);
1797 : }
1798 :
1799 : //Condition for expanding char set to character style of specified number rule level:
1800 : //The item inside the set should not conflict to any exist and non-default item inside paragraph properties set (SwCntntNode::SwPAttrSet);
1801 : //The node should have applied a number rule;
1802 : //The node should be counted in a list, if not, make it to be;
1803 : //The item should not conflict to any exist and non-default item inside the character of specified number rule level;
1804 : //The item should not be ignored depend on the exact number rule type;
1805 10530 : bool SwTxtNode::TryCharSetExpandToNum(const SfxItemSet& aCharSet)
1806 : {
1807 10530 : bool bRet = false;
1808 10530 : SfxItemIter aIter( aCharSet );
1809 10530 : const SfxPoolItem* pItem = aIter.FirstItem();
1810 10530 : const sal_uInt16 nWhich = pItem->Which();
1811 :
1812 10530 : const SfxPoolItem& rInnerItem = GetAttr(nWhich,false);
1813 :
1814 10530 : if (!IsDefaultItem(&rInnerItem) && !IsInvalidItem(&rInnerItem))
1815 8644 : return bRet;
1816 :
1817 1886 : if (!IsInList() && GetNumRule() && !GetListId().isEmpty())
1818 : {
1819 0 : return bRet;
1820 : }
1821 :
1822 1886 : SwNumRule* pCurrNum = GetNumRule(false);
1823 :
1824 1886 : int nLevel = GetActualListLevel();
1825 :
1826 1886 : if (nLevel != -1 && pCurrNum)
1827 : {
1828 124 : const SwNumFmt* pCurrNumFmt = pCurrNum->GetNumFmt(static_cast<sal_uInt16>(nLevel));
1829 124 : if (pCurrNumFmt)
1830 : {
1831 124 : if (pCurrNumFmt->IsItemize() && lcl_IsIgnoredCharFmtForBullets(nWhich))
1832 30 : return bRet;
1833 94 : if (pCurrNumFmt->IsEnumeration() && lcl_IsIgnoredCharFmtForNumbering(nWhich))
1834 2 : return bRet;
1835 92 : SwCharFmt* pCurrCharFmt =pCurrNumFmt->GetCharFmt();
1836 :
1837 92 : if (pCurrCharFmt && pCurrCharFmt->GetItemState(nWhich,false) != SfxItemState::SET)
1838 : {
1839 20 : pCurrCharFmt->SetFmtAttr(*pItem);
1840 20 : SwNumFmt aNewNumFmt(*pCurrNumFmt);
1841 20 : aNewNumFmt.SetCharFmt(pCurrCharFmt);
1842 20 : pCurrNum->Set(nLevel,aNewNumFmt);
1843 20 : bRet = true;
1844 : }
1845 : }
1846 : }
1847 :
1848 1854 : return bRet;
1849 : }
1850 :
1851 : // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
1852 : // dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr)
1853 192028 : bool SwTxtNode::SetAttr(
1854 : const SfxItemSet& rSet,
1855 : const sal_Int32 nStt,
1856 : const sal_Int32 nEnd,
1857 : const SetAttrMode nMode )
1858 : {
1859 192028 : if( !rSet.Count() )
1860 0 : return false;
1861 :
1862 : // teil die Sets auf (fuer Selektion in Nodes)
1863 192028 : const SfxItemSet* pSet = &rSet;
1864 192028 : SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
1865 :
1866 : // gesamter Bereich
1867 266564 : if ( !nStt && (nEnd == m_Text.getLength()) &&
1868 74536 : !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) )
1869 : {
1870 : // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
1871 : // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
1872 54136 : bool bHasCharFmts = false;
1873 54136 : if ( HasHints() )
1874 : {
1875 27896 : for ( size_t n = 0; n < m_pSwpHints->Count(); ++n )
1876 : {
1877 17478 : if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() )
1878 : {
1879 782 : bHasCharFmts = true;
1880 782 : break;
1881 : }
1882 : }
1883 : }
1884 :
1885 54136 : if( !bHasCharFmts )
1886 : {
1887 53354 : aTxtSet.Put( rSet );
1888 : // If there are any character attributes in rSet,
1889 : // we want to set them at the paragraph:
1890 53354 : if( aTxtSet.Count() != rSet.Count() )
1891 : {
1892 47764 : const bool bRet = SetAttr( rSet );
1893 47764 : if( !aTxtSet.Count() )
1894 98246 : return bRet;
1895 : }
1896 :
1897 : // check for auto style:
1898 : const SfxPoolItem* pItem;
1899 5706 : const bool bAutoStyle = SfxItemState::SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, false, &pItem );
1900 5706 : if ( bAutoStyle )
1901 : {
1902 2950 : boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle();
1903 2950 : const bool bRet = SetAttr( *pAutoStyleSet );
1904 2950 : if( 1 == aTxtSet.Count() )
1905 2950 : return bRet;
1906 : }
1907 :
1908 : // Continue with the text attributes:
1909 2756 : pSet = &aTxtSet;
1910 : }
1911 : }
1912 :
1913 141430 : GetOrCreateSwpHints();
1914 :
1915 282860 : SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange );
1916 :
1917 141430 : size_t nCount = 0;
1918 282860 : SfxItemIter aIter( *pSet );
1919 141430 : const SfxPoolItem* pItem = aIter.GetCurItem();
1920 :
1921 : do
1922 : {
1923 430576 : if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
1924 : {
1925 430576 : const sal_uInt16 nWhich = pItem->Which();
1926 : OSL_ENSURE( isCHRATR(nWhich) || isTXTATR(nWhich),
1927 : "SwTxtNode::SetAttr(): unknown attribute" );
1928 430576 : if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
1929 : {
1930 442518 : if ((RES_TXTATR_CHARFMT == nWhich) &&
1931 11942 : (GetDoc()->GetDfltCharFmt() ==
1932 11942 : static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt()))
1933 : {
1934 0 : SwIndex aIndex( this, nStt );
1935 0 : RstTxtAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
1936 0 : DontExpandFmt( aIndex );
1937 : }
1938 : else
1939 : {
1940 430576 : if (isCHRATR(nWhich) ||
1941 : (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1942 : {
1943 408946 : aCharSet.Put( *pItem );
1944 : }
1945 : else
1946 : {
1947 :
1948 21630 : SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(),
1949 21630 : const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
1950 21630 : if ( pNew )
1951 : {
1952 21630 : if ( nEnd != nStt && !pNew->GetEnd() )
1953 : {
1954 : OSL_FAIL("Attribut without end, but area marked");
1955 0 : DestroyAttr( pNew ); // do not insert
1956 : }
1957 21630 : else if ( InsertHint( pNew, nMode ) )
1958 : {
1959 21626 : ++nCount;
1960 : }
1961 : }
1962 : }
1963 : }
1964 : }
1965 : }
1966 430576 : if ( aIter.IsAtEnd() )
1967 141430 : break;
1968 289146 : pItem = aIter.NextItem();
1969 : } while( true );
1970 :
1971 141430 : if ( aCharSet.Count() )
1972 : {
1973 121928 : SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd );
1974 121928 : if ( InsertHint( pTmpNew, nMode ) )
1975 : {
1976 121928 : ++nCount;
1977 : }
1978 : }
1979 :
1980 141430 : TryDeleteSwpHints();
1981 :
1982 333458 : return nCount != 0;
1983 : }
1984 :
1985 9010 : static void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1986 : {
1987 9010 : if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
1988 : {
1989 8192 : const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1990 8192 : if ( !pCFSet )
1991 9010 : return;
1992 8192 : SfxWhichIter aIter( *pCFSet );
1993 8192 : sal_uInt16 nWhich = aIter.FirstWhich();
1994 401404 : while( nWhich )
1995 : {
1996 401400 : if( ( nWhich < RES_CHRATR_END ||
1997 761848 : RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
1998 376828 : ( SfxItemState::SET == pCFSet->GetItemState( nWhich, true ) ) )
1999 57580 : rSet.Put( pCFSet->Get( nWhich ) );
2000 385020 : nWhich = aIter.NextWhich();
2001 8192 : }
2002 : }
2003 : else
2004 818 : rSet.Put( rAttr );
2005 : }
2006 :
2007 108064 : static void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
2008 : {
2009 317005 : if( RES_TXTATR_CHARFMT == rAttr.Which() ||
2010 207116 : RES_TXTATR_INETFMT == rAttr.Which() ||
2011 99052 : RES_TXTATR_AUTOFMT == rAttr.Which() )
2012 : {
2013 100195 : const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
2014 :
2015 100195 : if ( pCFSet )
2016 : {
2017 99985 : SfxWhichIter aIter( *pCFSet );
2018 99985 : sal_uInt16 nWhich = aIter.FirstWhich();
2019 4890435 : while( nWhich )
2020 : {
2021 4881605 : if( ( nWhich < RES_CHRATR_END ||
2022 9463283 : ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
2023 4590480 : ( SfxItemState::SET == pCFSet->GetItemState( nWhich, true ) ) )
2024 473876 : rSet.Put( pCFSet->Get( nWhich ) );
2025 4690465 : nWhich = aIter.NextWhich();
2026 99985 : }
2027 : }
2028 : }
2029 :
2030 : // aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
2031 :
2032 : /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
2033 : z.B
2034 : 1234567890123456789
2035 : |------------| Font1
2036 : |------| Font2
2037 : ^ ^
2038 : |--| Abfragebereich: -> Gueltig ist Font2
2039 : */
2040 108064 : rSet.Put( rAttr );
2041 108064 : }
2042 :
2043 : struct SwPoolItemEndPair
2044 : {
2045 : public:
2046 : const SfxPoolItem* mpItem;
2047 : sal_Int32 mnEndPos;
2048 :
2049 157190 : SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
2050 : };
2051 :
2052 24868 : static void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode,
2053 : SfxItemSet& rSet )
2054 : {
2055 24868 : if ( rTxtNode.AreListLevelIndentsApplicable() )
2056 : {
2057 0 : const SwNumRule* pRule = rTxtNode.GetNumRule();
2058 0 : if ( pRule && rTxtNode.GetActualListLevel() >= 0 )
2059 : {
2060 0 : const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()));
2061 0 : if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2062 : {
2063 0 : SvxLRSpaceItem aLR( RES_LR_SPACE );
2064 0 : aLR.SetTxtLeft( rFmt.GetIndentAt() );
2065 0 : aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) );
2066 0 : rSet.Put( aLR );
2067 : }
2068 : }
2069 : }
2070 24868 : }
2071 :
2072 : // erfrage die Attribute vom TextNode ueber den Bereich
2073 334032 : bool SwTxtNode::GetAttr( SfxItemSet& rSet, sal_Int32 nStt, sal_Int32 nEnd,
2074 : const bool bOnlyTxtAttr, const bool bGetFromChrFmt,
2075 : const bool bMergeIndentValuesOfNumRule ) const
2076 : {
2077 334032 : if( HasHints() )
2078 : {
2079 : /* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
2080 : * sind. Dabei gibt es folgende Faelle:
2081 : * UnEindeutig wenn: (wenn != Format-Attribut)
2082 : * - das Attribut liegt vollstaendig im Bereich
2083 : * - das Attributende liegt im Bereich
2084 : * - der Attributanfang liegt im Bereich:
2085 : * Eindeutig (im Set mergen):
2086 : * - das Attrib umfasst den Bereich
2087 : * nichts tun:
2088 : * das Attribut liegt ausserhalb des Bereiches
2089 : */
2090 :
2091 : void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
2092 : = bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt
2093 143538 : : &lcl_MergeAttr;
2094 :
2095 : // dann besorge mal die Auto-(Fmt)Attribute
2096 143538 : SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
2097 143538 : if( !bOnlyTxtAttr )
2098 : {
2099 134866 : SwCntntNode::GetAttr( aFmtSet );
2100 134866 : if ( bMergeIndentValuesOfNumRule )
2101 : {
2102 1440 : lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet );
2103 : }
2104 : }
2105 :
2106 143538 : const size_t nSize = m_pSwpHints->Count();
2107 :
2108 143538 : if( nStt == nEnd ) // kein Bereich:
2109 : {
2110 382943 : for (size_t n = 0; n < nSize; ++n)
2111 : {
2112 329019 : const SwTxtAttr* pHt = (*m_pSwpHints)[n];
2113 329019 : const sal_Int32 nAttrStart = pHt->GetStart();
2114 329019 : if( nAttrStart > nEnd ) // ueber den Bereich hinaus
2115 118 : break;
2116 :
2117 328901 : const sal_Int32* pAttrEnd = pHt->End();
2118 328901 : if ( ! pAttrEnd ) // no attributes without end
2119 236160 : continue;
2120 :
2121 159950 : if( ( nAttrStart < nStt &&
2122 69914 : ( pHt->DontExpand() ? nStt < *pAttrEnd
2123 342711 : : nStt <= *pAttrEnd )) ||
2124 25532 : ( nStt == nAttrStart &&
2125 25900 : ( nAttrStart == *pAttrEnd || !nStt )))
2126 66424 : (*fnMergeAttr)( rSet, pHt->GetAttr() );
2127 : }
2128 : }
2129 : else // es ist ein Bereich definiert
2130 : {
2131 : // #i75299#
2132 89496 : boost::scoped_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
2133 :
2134 89496 : const size_t coArrSz = RES_TXTATR_WITHEND_END - RES_CHRATR_BEGIN;
2135 :
2136 328636 : for (size_t n = 0; n < nSize; ++n)
2137 : {
2138 239880 : const SwTxtAttr* pHt = (*m_pSwpHints)[n];
2139 239880 : const sal_Int32 nAttrStart = pHt->GetStart();
2140 239880 : if( nAttrStart > nEnd ) // ueber den Bereich hinaus
2141 740 : break;
2142 :
2143 239140 : const sal_Int32* pAttrEnd = pHt->End();
2144 239140 : if ( ! pAttrEnd ) // no attributes without end
2145 7042 : continue;
2146 :
2147 232098 : bool bChkInvalid = false;
2148 232098 : if( nAttrStart <= nStt ) // vor oder genau Start
2149 : {
2150 187628 : if( *pAttrEnd <= nStt ) // liegt davor
2151 139696 : continue;
2152 :
2153 47932 : if( nEnd <= *pAttrEnd ) // hinter oder genau Ende
2154 46398 : (*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
2155 : else
2156 : // else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
2157 : // uneindeutig
2158 1534 : bChkInvalid = true;
2159 : }
2160 44470 : else if( nAttrStart < nEnd // reicht in den Bereich
2161 : )// && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
2162 4148 : bChkInvalid = true;
2163 :
2164 92402 : if( bChkInvalid )
2165 : {
2166 : // uneindeutig ?
2167 5682 : boost::scoped_ptr< SfxItemIter > pItemIter;
2168 5682 : const SfxPoolItem* pItem = 0;
2169 :
2170 5682 : if ( RES_TXTATR_AUTOFMT == pHt->Which() )
2171 : {
2172 4600 : const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() );
2173 4600 : if ( pAutoSet )
2174 : {
2175 4600 : pItemIter.reset( new SfxItemIter( *pAutoSet ) );
2176 4600 : pItem = pItemIter->GetCurItem();
2177 : }
2178 : }
2179 : else
2180 1082 : pItem = &pHt->GetAttr();
2181 :
2182 5682 : const sal_Int32 nHintEnd = *pAttrEnd;
2183 :
2184 29440 : while ( pItem )
2185 : {
2186 18076 : const sal_uInt16 nHintWhich = pItem->Which();
2187 : OSL_ENSURE(!isUNKNOWNATR(nHintWhich),
2188 : "SwTxtNode::GetAttr(): unknown attribute?");
2189 :
2190 18076 : if ( !pAttrArr.get() )
2191 : {
2192 : pAttrArr.reset(
2193 2858 : new std::vector< SwPoolItemEndPair >(coArrSz));
2194 : }
2195 :
2196 18076 : std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
2197 19158 : if (isCHRATR(nHintWhich) ||
2198 1082 : isTXTATR_WITHEND(nHintWhich))
2199 : {
2200 18076 : pPrev += nHintWhich - RES_CHRATR_BEGIN;
2201 : }
2202 : else
2203 : {
2204 0 : pPrev = pAttrArr->end();
2205 : }
2206 :
2207 18076 : if( pPrev != pAttrArr->end() )
2208 : {
2209 18076 : if( !pPrev->mpItem )
2210 : {
2211 9224 : if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) )
2212 : {
2213 7552 : if( nAttrStart > nStt )
2214 : {
2215 1134 : rSet.InvalidateItem( nHintWhich );
2216 1134 : pPrev->mpItem = (SfxPoolItem*)-1;
2217 : }
2218 : else
2219 : {
2220 6418 : pPrev->mpItem = pItem;
2221 6418 : pPrev->mnEndPos = nHintEnd;
2222 : }
2223 : }
2224 : }
2225 8852 : else if( (SfxPoolItem*)-1 != pPrev->mpItem )
2226 : {
2227 14892 : if( pPrev->mnEndPos == nAttrStart &&
2228 7342 : *pPrev->mpItem == *pItem )
2229 : {
2230 7002 : pPrev->mpItem = pItem;
2231 7002 : pPrev->mnEndPos = nHintEnd;
2232 : }
2233 : else
2234 : {
2235 548 : rSet.InvalidateItem( nHintWhich );
2236 548 : pPrev->mpItem = (SfxPoolItem*)-1;
2237 : }
2238 : }
2239 : }
2240 :
2241 35070 : pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
2242 30470 : ? pItemIter->NextItem() : 0;
2243 5682 : } // end while
2244 : }
2245 : }
2246 :
2247 89496 : if ( pAttrArr.get() )
2248 : {
2249 160048 : for (size_t n = 0; n < coArrSz; ++n)
2250 : {
2251 157190 : const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
2252 157190 : if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) )
2253 : {
2254 : const sal_uInt16 nWh =
2255 5870 : static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
2256 :
2257 5870 : if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
2258 : {
2259 4256 : if( *rItemPair.mpItem != aFmtSet.Get( nWh ) )
2260 4252 : (*fnMergeAttr)( rSet, *rItemPair.mpItem );
2261 : }
2262 : else
2263 : // uneindeutig
2264 1614 : rSet.InvalidateItem( nWh );
2265 : }
2266 : }
2267 89496 : }
2268 : }
2269 143538 : if( aFmtSet.Count() )
2270 : {
2271 : // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
2272 78628 : aFmtSet.Differentiate( rSet );
2273 : // jetzt alle zusammen "mergen"
2274 78628 : rSet.Put( aFmtSet );
2275 143538 : }
2276 : }
2277 190494 : else if( !bOnlyTxtAttr )
2278 : {
2279 : // dann besorge mal die Auto-(Fmt)Attribute
2280 185340 : SwCntntNode::GetAttr( rSet );
2281 185340 : if ( bMergeIndentValuesOfNumRule )
2282 : {
2283 23428 : lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
2284 : }
2285 : }
2286 :
2287 334032 : return rSet.Count() != 0;
2288 : }
2289 :
2290 : namespace
2291 : {
2292 :
2293 : typedef std::pair<sal_Int32, sal_Int32> AttrSpan_t;
2294 : typedef std::multimap<AttrSpan_t, const SwTxtAttr*> AttrSpanMap_t;
2295 :
2296 : struct IsAutoStyle
2297 : {
2298 : bool
2299 94 : operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2300 : const
2301 : {
2302 94 : return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
2303 : }
2304 : };
2305 :
2306 : /** Removes from io_rAttrSet all items that are set by style on the
2307 : given span.
2308 : */
2309 : struct RemovePresentAttrs
2310 : {
2311 94 : RemovePresentAttrs(SfxItemSet& io_rAttrSet)
2312 94 : : m_rAttrSet(io_rAttrSet)
2313 : {
2314 94 : }
2315 :
2316 : void
2317 94 : operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2318 : const
2319 : {
2320 94 : if (!i_rAttrSpan.second)
2321 : {
2322 188 : return;
2323 : }
2324 :
2325 0 : const SwTxtAttr* const pAutoStyle(i_rAttrSpan.second);
2326 0 : SfxItemIter aIter(m_rAttrSet);
2327 0 : const SfxPoolItem* pItem(aIter.GetCurItem());
2328 0 : while (pItem)
2329 : {
2330 0 : const sal_uInt16 nWhich(pItem->Which());
2331 0 : if (CharFmt::IsItemIncluded(nWhich, pAutoStyle))
2332 : {
2333 0 : m_rAttrSet.ClearItem(nWhich);
2334 : }
2335 :
2336 0 : if (aIter.IsAtEnd())
2337 : {
2338 0 : break;
2339 : }
2340 0 : pItem = aIter.NextItem();
2341 0 : }
2342 : }
2343 :
2344 : private:
2345 : SfxItemSet& m_rAttrSet;
2346 : };
2347 :
2348 : /** Collects all style-covered spans from i_rHints to o_rSpanMap. In
2349 : addition inserts dummy spans with pointer to format equal to 0 for
2350 : all gaps (i.e. spans not covered by any style). This simplifies
2351 : creation of autostyles for all needed spans, but it means all code
2352 : that tries to access the pointer has to check if it's non-null!
2353 : */
2354 : void
2355 106 : lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_Int32 nLength,
2356 : AttrSpanMap_t& o_rSpanMap)
2357 : {
2358 106 : sal_Int32 nLastEnd(0);
2359 :
2360 182 : for (size_t i = 0; i < i_rHints.Count(); ++i)
2361 : {
2362 76 : const SwTxtAttr* const pHint(i_rHints[i]);
2363 76 : const sal_uInt16 nWhich(pHint->Which());
2364 76 : if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
2365 : {
2366 0 : const AttrSpan_t aSpan(pHint->GetStart(), *pHint->End());
2367 0 : o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint));
2368 :
2369 : // < not != because there may be multiple CHARFMT at same range
2370 0 : if (nLastEnd < aSpan.first)
2371 : {
2372 : // insert dummy span covering the gap
2373 : o_rSpanMap.insert(AttrSpanMap_t::value_type(
2374 0 : AttrSpan_t(nLastEnd, aSpan.first), (const SwTxtAttr *)0));
2375 : }
2376 :
2377 0 : nLastEnd = aSpan.second;
2378 : }
2379 : }
2380 :
2381 : // no hints at the end (special case: no hints at all in i_rHints)
2382 106 : if (nLastEnd != nLength && nLength != 0)
2383 : {
2384 : o_rSpanMap.insert(
2385 94 : AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), (const SwTxtAttr *)0));
2386 : }
2387 106 : }
2388 :
2389 : void
2390 106 : lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
2391 : {
2392 106 : o_rClearIds.reserve(i_rAttrSet.Count());
2393 106 : SfxItemIter aIter(i_rAttrSet);
2394 106 : const SfxPoolItem* pItem(aIter.GetCurItem());
2395 414 : while (pItem)
2396 : {
2397 308 : o_rClearIds.push_back(pItem->Which());
2398 :
2399 308 : if (aIter.IsAtEnd())
2400 : {
2401 106 : break;
2402 : }
2403 202 : pItem = aIter.NextItem();
2404 106 : }
2405 106 : }
2406 :
2407 : struct SfxItemSetClearer
2408 : {
2409 : SfxItemSet & m_rItemSet;
2410 2706 : SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
2411 318 : void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
2412 : };
2413 :
2414 : }
2415 :
2416 : /** Does the hard work of SwTxtNode::FmtToTxtAttr: the real conversion
2417 : of items to automatic styles.
2418 : */
2419 : void
2420 137838 : SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet)
2421 : {
2422 : typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
2423 137838 : AttrSpanMap_t aAttrSpanMap;
2424 :
2425 137838 : if (i_rAttrSet.Count() == 0)
2426 : {
2427 275570 : return;
2428 : }
2429 :
2430 : // 1. Identify all spans in hints' array
2431 :
2432 106 : lcl_CollectHintSpans(*m_pSwpHints, m_Text.getLength(), aAttrSpanMap);
2433 :
2434 : // 2. Go through all spans and insert new attrs
2435 :
2436 106 : AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
2437 106 : const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
2438 306 : while (aCurRange != aEnd)
2439 : {
2440 : typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
2441 : AttrSpanMapRange_t;
2442 94 : AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
2443 :
2444 : // 2a. Collect attributes to insert
2445 :
2446 94 : SfxItemSet aCurSet(i_rAttrSet);
2447 94 : std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
2448 :
2449 : // 2b. Insert automatic style containing the collected attributes
2450 :
2451 94 : if (aCurSet.Count() != 0)
2452 : {
2453 : AttrSpanMap_iterator_t aAutoStyleIt(
2454 94 : std::find_if(aRange.first, aRange.second, IsAutoStyle()));
2455 94 : if (aAutoStyleIt != aRange.second)
2456 : {
2457 : // there already is an automatic style on that span:
2458 : // create new one and remove the original one
2459 0 : SwTxtAttr* const pAutoStyle(const_cast<SwTxtAttr*>(aAutoStyleIt->second));
2460 : const boost::shared_ptr<SfxItemSet> pOldStyle(
2461 : static_cast<const SwFmtAutoFmt&>(
2462 0 : pAutoStyle->GetAttr()).GetStyleHandle());
2463 0 : aCurSet.Put(*pOldStyle);
2464 :
2465 : // remove the old hint
2466 0 : m_pSwpHints->Delete(pAutoStyle);
2467 0 : DestroyAttr(pAutoStyle);
2468 : }
2469 : m_pSwpHints->Insert(
2470 94 : MakeTxtAttr(*GetDoc(), aCurSet,
2471 188 : aCurRange->first.first, aCurRange->first.second));
2472 : }
2473 :
2474 94 : aCurRange = aRange.second;
2475 94 : }
2476 :
2477 : // hints were directly inserted, so need to fix the Ignore flags now
2478 106 : m_pSwpHints->MergePortions(*this);
2479 :
2480 : // 3. Clear items from the node
2481 212 : std::vector<sal_uInt16> aClearedIds;
2482 106 : lcl_FillWhichIds(i_rAttrSet, aClearedIds);
2483 212 : ClearItemsFromAttrSet(aClearedIds);
2484 : }
2485 :
2486 137528 : void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
2487 : {
2488 137528 : SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2489 137528 : if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
2490 3468 : aThisSet.Put( *GetpSwAttrSet() );
2491 :
2492 137528 : GetOrCreateSwpHints();
2493 :
2494 137528 : if( pNd == this )
2495 : {
2496 134822 : impl_FmtToTxtAttr(aThisSet);
2497 : }
2498 : else
2499 : {
2500 : // There are five possible combinations of items from this and
2501 : // pNd (pNd is the 'main' node):
2502 :
2503 : // case pNd this action
2504 :
2505 : // 1 - - do nothing
2506 : // 2 - a convert item to attr of this
2507 : // 3 a - convert item to attr of pNd
2508 : // 4 a a clear item in this
2509 : // 5 a b convert item to attr of this
2510 :
2511 2706 : SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
2512 2706 : if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
2513 1988 : aNdSet.Put( *pNd->GetpSwAttrSet() );
2514 :
2515 2706 : pNd->GetOrCreateSwpHints();
2516 :
2517 5412 : std::vector<sal_uInt16> aProcessedIds;
2518 :
2519 2706 : if( aThisSet.Count() )
2520 : {
2521 310 : SfxItemIter aIter( aThisSet );
2522 310 : const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0;
2523 620 : SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2524 620 : std::vector<sal_uInt16> aClearWhichIds;
2525 :
2526 : while( true )
2527 : {
2528 318 : if( SfxItemState::SET == aNdSet.GetItemState( pItem->Which(), false, &pNdItem ) )
2529 : {
2530 318 : if (*pItem == *pNdItem) // 4
2531 : {
2532 318 : aClearWhichIds.push_back( pItem->Which() );
2533 : }
2534 : else // 5
2535 : {
2536 0 : aConvertSet.Put(*pItem);
2537 : }
2538 318 : aProcessedIds.push_back(pItem->Which());
2539 : }
2540 : else // 2
2541 : {
2542 0 : aConvertSet.Put(*pItem);
2543 : }
2544 :
2545 318 : if( aIter.IsAtEnd() )
2546 310 : break;
2547 8 : pItem = aIter.NextItem();
2548 : }
2549 :
2550 : // 4/ clear items of this that are set with the same value on pNd
2551 310 : ClearItemsFromAttrSet( aClearWhichIds );
2552 :
2553 : // 2, 5/ convert all other items to attrs
2554 620 : impl_FmtToTxtAttr(aConvertSet);
2555 : }
2556 :
2557 : {
2558 : std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
2559 2706 : SfxItemSetClearer(aNdSet));
2560 :
2561 : // 3/ convert items to attrs
2562 2706 : pNd->impl_FmtToTxtAttr(aNdSet);
2563 :
2564 2706 : if( aNdSet.Count() )
2565 : {
2566 18 : SwFmtChg aTmp1( pNd->GetFmtColl() );
2567 18 : pNd->NotifyClients( &aTmp1, &aTmp1 );
2568 : }
2569 2706 : }
2570 : }
2571 :
2572 137528 : SetCalcHiddenCharFlags();
2573 :
2574 137528 : pNd->TryDeleteSwpHints();
2575 137528 : }
2576 :
2577 97028 : void SwpHints::CalcFlags()
2578 : {
2579 97028 : m_bDDEFields = m_bFootnote = false;
2580 97028 : const size_t nSize = Count();
2581 641492 : for( size_t nPos = 0; nPos < nSize; ++nPos )
2582 : {
2583 544464 : const SwTxtAttr* pAttr = (*this)[ nPos ];
2584 544464 : switch( pAttr->Which() )
2585 : {
2586 : case RES_TXTATR_FTN:
2587 502 : m_bFootnote = true;
2588 502 : if ( m_bDDEFields )
2589 0 : return;
2590 502 : break;
2591 : case RES_TXTATR_FIELD:
2592 : {
2593 252668 : const SwField* pFld = pAttr->GetFmtFld().GetField();
2594 252668 : if( RES_DDEFLD == pFld->GetTyp()->Which() )
2595 : {
2596 0 : m_bDDEFields = true;
2597 0 : if ( m_bFootnote )
2598 0 : return;
2599 : }
2600 : }
2601 252668 : break;
2602 : }
2603 : }
2604 : }
2605 :
2606 1274 : bool SwpHints::CalcHiddenParaField()
2607 : {
2608 1274 : m_bCalcHiddenParaField = false;
2609 1274 : bool bOldHasHiddenParaField = m_bHasHiddenParaField;
2610 1274 : bool bNewHasHiddenParaField = false;
2611 1274 : const size_t nSize = Count();
2612 : const SwTxtAttr *pTxtHt;
2613 :
2614 4036 : for( size_t nPos = 0; nPos < nSize; ++nPos )
2615 : {
2616 2762 : pTxtHt = (*this)[ nPos ];
2617 2762 : const sal_uInt16 nWhich = pTxtHt->Which();
2618 :
2619 2762 : if( RES_TXTATR_FIELD == nWhich )
2620 : {
2621 1894 : const SwFmtFld& rFld = pTxtHt->GetFmtFld();
2622 1894 : if( RES_HIDDENPARAFLD == rFld.GetField()->GetTyp()->Which() )
2623 : {
2624 0 : if( !((SwHiddenParaField*)rFld.GetField())->IsHidden() )
2625 : {
2626 0 : SetHiddenParaField(false);
2627 0 : return bOldHasHiddenParaField != bNewHasHiddenParaField;
2628 : }
2629 : else
2630 : {
2631 0 : bNewHasHiddenParaField = true;
2632 : }
2633 : }
2634 : }
2635 : }
2636 1274 : SetHiddenParaField( bNewHasHiddenParaField );
2637 1274 : return bOldHasHiddenParaField != bNewHasHiddenParaField;
2638 : }
2639 :
2640 341088 : void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew )
2641 : {
2642 341088 : if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
2643 341088 : }
2644 :
2645 122856 : bool SwpHints::MergePortions( SwTxtNode& rNode )
2646 : {
2647 122856 : if ( !Count() )
2648 62 : return false;
2649 :
2650 : // sort before merging
2651 122794 : SwpHintsArray::Resort();
2652 :
2653 122794 : bool bRet = false;
2654 : typedef std::multimap< int, std::pair<SwTxtAttr*, bool> > PortionMap;
2655 122794 : PortionMap aPortionMap;
2656 245588 : std::map<int, bool> RsidOnlyAutoFmtFlagMap;
2657 122794 : sal_Int32 nLastPorStart = COMPLETE_STRING;
2658 122794 : int nKey = 0;
2659 :
2660 : // get portions by start position:
2661 625574 : for ( size_t i = 0; i < Count(); ++i )
2662 : {
2663 502780 : SwTxtAttr *pHt = GetTextHint( i );
2664 948508 : if ( RES_TXTATR_CHARFMT != pHt->Which() &&
2665 445728 : RES_TXTATR_AUTOFMT != pHt->Which() )
2666 : //&&
2667 : //RES_TXTATR_INETFMT != pHt->Which() )
2668 138772 : continue;
2669 :
2670 452856 : bool isRsidOnlyAutoFmt(false);
2671 : // check for RSID-only AUTOFMT
2672 452856 : if (RES_TXTATR_AUTOFMT == pHt->Which())
2673 : {
2674 : boost::shared_ptr<SfxItemSet> const pSet(
2675 395804 : pHt->GetAutoFmt().GetStyleHandle());
2676 395804 : if ((pSet->Count() == 1) && pSet->GetItem(RES_CHRATR_RSID, false))
2677 : {
2678 : // fdo#70201: eliminate no-extent RSID-only AUTOFMT
2679 : // could be produced by ReplaceText or (maybe?) RstAttr
2680 146 : if (pHt->GetStart() == *pHt->GetEnd())
2681 : {
2682 0 : SwpHintsArray::DeleteAtPos(i); // kill it without History!
2683 0 : SwTxtAttr::Destroy(pHt, rNode.GetDoc()->GetAttrPool());
2684 0 : --i;
2685 0 : continue;
2686 : }
2687 : // fdo#52028: this one has _only_ RSID => ignore it completely
2688 146 : if (!pHt->IsFormatIgnoreStart() || !pHt->IsFormatIgnoreEnd())
2689 : {
2690 124 : NoteInHistory(pHt);
2691 124 : pHt->SetFormatIgnoreStart(true);
2692 124 : pHt->SetFormatIgnoreEnd (true);
2693 124 : NoteInHistory(pHt, true);
2694 : }
2695 146 : isRsidOnlyAutoFmt = true;
2696 395804 : }
2697 : }
2698 :
2699 452856 : if (pHt->GetStart() == *pHt->GetEnd())
2700 : {
2701 : // no-length hints are a disease. ignore them here.
2702 : // the SwAttrIter::SeekFwd will not call Rst/Chg for them.
2703 38924 : continue;
2704 : }
2705 :
2706 413932 : const sal_Int32 nPorStart = pHt->GetStart();
2707 413932 : if (nPorStart != nLastPorStart)
2708 395068 : ++nKey;
2709 413932 : nLastPorStart = nPorStart;
2710 : aPortionMap.insert(std::make_pair(nKey,
2711 413932 : std::make_pair(pHt, isRsidOnlyAutoFmt)));
2712 413932 : RsidOnlyAutoFmtFlagMap[nKey] = isRsidOnlyAutoFmt;
2713 : }
2714 :
2715 : // check if portion i can be merged with portion i+1:
2716 : // note: need to include i=0 to set IgnoreStart and j=nKey+1 to reset
2717 : // IgnoreEnd at first / last portion
2718 122794 : int i = 0;
2719 122794 : int j = i + 1;
2720 763450 : while ( i <= nKey )
2721 : {
2722 517862 : std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
2723 517862 : std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
2724 517862 : PortionMap::iterator aIter1 = aRange1.first;
2725 517862 : PortionMap::iterator aIter2 = aRange2.first;
2726 :
2727 517862 : enum { MATCH, DIFFER_ONLY_RSID, DIFFER } eMerge(MATCH);
2728 517862 : size_t const nAttributesInPor1 = std::distance(aRange1.first, aRange1.second);
2729 517862 : size_t const nAttributesInPor2 = std::distance(aRange2.first, aRange2.second);
2730 517862 : bool const isRsidOnlyAutoFmt1(RsidOnlyAutoFmtFlagMap[i]);
2731 517862 : bool const isRsidOnlyAutoFmt2(RsidOnlyAutoFmtFlagMap[j]);
2732 :
2733 : // if both have one they could be equal, but not if only one has it
2734 517862 : bool const bSkipRsidOnlyAutoFmt(nAttributesInPor1 != nAttributesInPor2);
2735 :
2736 : // this loop needs to handle the case where one has a CHARFMT and the
2737 : // other CHARFMT + RSID-only AUTOFMT, so...
2738 : // want to skip over RSID-only AUTOFMT here, hence the -1
2739 1035724 : if ((nAttributesInPor1 - ((isRsidOnlyAutoFmt1) ? 1 : 0)) ==
2740 517862 : (nAttributesInPor2 - ((isRsidOnlyAutoFmt2) ? 1 : 0))
2741 264382 : && (nAttributesInPor1 != 0 || nAttributesInPor2 != 0))
2742 : {
2743 : // _if_ there is one element more either in aRange1 or aRange2
2744 : // it _must_ be an RSID-only AUTOFMT, which can be ignored here...
2745 : // But if both have RSID-only AUTOFMT they could be equal, no skip!
2746 543056 : while (aIter1 != aRange1.second || aIter2 != aRange2.second)
2747 : {
2748 : // first of all test if there's no gap (before skipping stuff!)
2749 515162 : if (aIter1 != aRange1.second && aIter2 != aRange2.second &&
2750 257482 : *aIter1->second.first->End() < aIter2->second.first->GetStart())
2751 : {
2752 20142 : eMerge = DIFFER;
2753 20142 : break;
2754 : }
2755 : // skip it - cannot be equal if bSkipRsidOnlyAutoFmt is set
2756 237538 : if (bSkipRsidOnlyAutoFmt
2757 237538 : && aIter1 != aRange1.second && aIter1->second.second)
2758 : {
2759 : assert(DIFFER != eMerge);
2760 96 : eMerge = DIFFER_ONLY_RSID;
2761 96 : ++aIter1;
2762 96 : continue;
2763 : }
2764 237442 : if (bSkipRsidOnlyAutoFmt
2765 237442 : && aIter2 != aRange2.second && aIter2->second.second)
2766 : {
2767 : assert(DIFFER != eMerge);
2768 102 : eMerge = DIFFER_ONLY_RSID;
2769 102 : ++aIter2;
2770 102 : continue;
2771 : }
2772 : assert(aIter1 != aRange1.second && aIter2 != aRange2.second);
2773 237340 : SwTxtAttr const*const p1 = aIter1->second.first;
2774 237340 : SwTxtAttr const*const p2 = aIter2->second.first;
2775 237340 : if (p1->Which() != p2->Which())
2776 : {
2777 8872 : eMerge = DIFFER;
2778 8872 : break;
2779 : }
2780 228468 : if (!(*p1 == *p2))
2781 : {
2782 : // fdo#52028: for auto styles, check if they differ only
2783 : // in the RSID, which should have no effect on text layout
2784 199484 : if (RES_TXTATR_AUTOFMT == p1->Which())
2785 : {
2786 190276 : SfxItemSet set1(*p1->GetAutoFmt().GetStyleHandle());
2787 190278 : SfxItemSet set2(*p2->GetAutoFmt().GetStyleHandle());
2788 :
2789 190276 : set1.ClearItem(RES_CHRATR_RSID);
2790 190276 : set2.ClearItem(RES_CHRATR_RSID);
2791 :
2792 : // sadly SfxItemSet::operator== does not seem to work?
2793 190278 : SfxItemIter iter1(set1);
2794 190278 : SfxItemIter iter2(set2);
2795 190276 : if (set1.Count() == set2.Count())
2796 : {
2797 49218 : for (SfxPoolItem const* pItem1 = iter1.FirstItem(),
2798 14898 : * pItem2 = iter2.FirstItem();
2799 34318 : pItem1 && pItem2;
2800 : pItem1 = iter1.NextItem(),
2801 : pItem2 = iter2.NextItem())
2802 : {
2803 53740 : if (pItem1 != pItem2 ||
2804 53740 : pItem1->Which() != pItem2->Which() ||
2805 19422 : *pItem1 != *pItem2)
2806 : {
2807 14896 : eMerge = DIFFER;
2808 14896 : break;
2809 : }
2810 19422 : if (iter1.IsAtEnd())
2811 : {
2812 : assert(iter2.IsAtEnd());
2813 0 : eMerge = DIFFER_ONLY_RSID;
2814 : }
2815 : }
2816 14898 : if (DIFFER == eMerge)
2817 14896 : break; // outer loop too
2818 : }
2819 : else
2820 : {
2821 175378 : eMerge = DIFFER;
2822 175378 : break;
2823 2 : }
2824 : }
2825 : else
2826 : {
2827 9208 : eMerge = DIFFER;
2828 9208 : break;
2829 : }
2830 : }
2831 28986 : ++aIter1;
2832 28986 : ++aIter2;
2833 256936 : }
2834 : }
2835 : else
2836 : {
2837 260926 : eMerge = DIFFER;
2838 : }
2839 :
2840 517862 : if (MATCH == eMerge)
2841 : {
2842 : // important: delete second range so any IgnoreStart on the first
2843 : // range is still valid
2844 : // erase all elements with key i + 1
2845 28242 : sal_Int32 nNewPortionEnd = 0;
2846 56922 : for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
2847 : {
2848 28680 : SwTxtAttr *const p2 = aIter2->second.first;
2849 28680 : nNewPortionEnd = *p2->GetEnd();
2850 :
2851 28680 : const size_t nCountBeforeDelete = Count();
2852 28680 : Delete( p2 );
2853 :
2854 : // robust: check if deletion actually took place before destroying attribute:
2855 28680 : if ( Count() < nCountBeforeDelete )
2856 28680 : rNode.DestroyAttr( p2 );
2857 : }
2858 28242 : aPortionMap.erase( aRange2.first, aRange2.second );
2859 28242 : ++j;
2860 :
2861 : // change all attributes with key i
2862 28242 : aRange1 = aPortionMap.equal_range( i );
2863 56922 : for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
2864 : {
2865 28680 : SwTxtAttr *const p1 = aIter1->second.first;
2866 28680 : NoteInHistory( p1 );
2867 28680 : *p1->GetEnd() = nNewPortionEnd;
2868 28680 : NoteInHistory( p1, true );
2869 28680 : bRet = true;
2870 : }
2871 : }
2872 : else
2873 : {
2874 : // when not merging the ignore flags need to be either set or reset
2875 : // (reset too in case one of the autofmts was recently changed)
2876 489620 : bool const bSetIgnoreFlag(DIFFER_ONLY_RSID == eMerge);
2877 874872 : for (aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1)
2878 : {
2879 385252 : if (!aIter1->second.second) // already set above, don't change
2880 : {
2881 385138 : SwTxtAttr *const pCurrent(aIter1->second.first);
2882 385138 : if (pCurrent->IsFormatIgnoreEnd() != bSetIgnoreFlag)
2883 : {
2884 0 : NoteInHistory(pCurrent);
2885 0 : pCurrent->SetFormatIgnoreEnd(bSetIgnoreFlag);
2886 0 : NoteInHistory(pCurrent, true);
2887 : }
2888 : }
2889 : }
2890 874872 : for (aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2)
2891 : {
2892 385252 : if (!aIter2->second.second) // already set above, don't change
2893 : {
2894 385138 : SwTxtAttr *const pCurrent(aIter2->second.first);
2895 385138 : if (pCurrent->IsFormatIgnoreStart() != bSetIgnoreFlag)
2896 : {
2897 0 : NoteInHistory(pCurrent);
2898 0 : pCurrent->SetFormatIgnoreStart(bSetIgnoreFlag);
2899 0 : NoteInHistory(pCurrent, true);
2900 : }
2901 : }
2902 : }
2903 489620 : i = j; // ++i not enough: i + 1 may have been deleted (MATCH)!
2904 489620 : ++j;
2905 : }
2906 : }
2907 :
2908 122794 : if ( bRet )
2909 : {
2910 28212 : SwpHintsArray::Resort();
2911 : }
2912 :
2913 245588 : return bRet;
2914 : }
2915 :
2916 : // check if there is already a character format and adjust the sort numbers
2917 4 : static void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt )
2918 : {
2919 4 : const sal_Int32 nHtStart = rNewCharFmt.GetStart();
2920 4 : const sal_Int32 nHtEnd = *rNewCharFmt.GetEnd();
2921 4 : sal_uInt16 nSortNumber = 0;
2922 :
2923 4 : for ( size_t i = 0; i < rHints.Count(); ++i )
2924 : {
2925 0 : const SwTxtAttr* pOtherHt = rHints[i];
2926 :
2927 0 : const sal_Int32 nOtherStart = pOtherHt->GetStart();
2928 :
2929 0 : if ( nOtherStart > nHtStart )
2930 0 : break;
2931 :
2932 0 : if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
2933 : {
2934 0 : const sal_Int32 nOtherEnd = *pOtherHt->End();
2935 :
2936 0 : if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
2937 : {
2938 0 : nSortNumber = static_txtattr_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber() + 1;
2939 : }
2940 : }
2941 : }
2942 :
2943 4 : if ( nSortNumber > 0 )
2944 0 : rNewCharFmt.SetSortNumber( nSortNumber );
2945 4 : }
2946 :
2947 : /*
2948 : * Try to insert the new hint.
2949 : * Depending on the type of the hint, this either always succeeds, or may fail.
2950 : * Depending on the type of the hint, other hints may be deleted or
2951 : * overwritten.
2952 : * The return value indicates successful insertion.
2953 : */
2954 157694 : bool SwpHints::TryInsertHint(
2955 : SwTxtAttr* const pHint,
2956 : SwTxtNode &rNode,
2957 : const SetAttrMode nMode )
2958 : {
2959 157694 : if ( MAX_HINTS <= Count() ) // we're sorry, this flight is overbooked...
2960 : {
2961 : OSL_FAIL("hints array full :-(");
2962 0 : return false;
2963 : }
2964 :
2965 : // Felder bilden eine Ausnahme:
2966 : // 1) Sie koennen nie ueberlappen
2967 : // 2) Wenn zwei Felder genau aneinander liegen,
2968 : // sollen sie nicht zu einem verschmolzen werden.
2969 : // Wir koennen also auf die while-Schleife verzichten
2970 :
2971 157694 : sal_Int32 *pHtEnd = pHint->GetEnd();
2972 157694 : const sal_uInt16 nWhich = pHint->Which();
2973 157694 : std::vector<sal_uInt16> aWhichSublist;
2974 :
2975 157694 : switch( nWhich )
2976 : {
2977 : case RES_TXTATR_CHARFMT:
2978 : {
2979 : // Check if character format contains hidden attribute:
2980 12214 : const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt();
2981 : const SfxPoolItem* pItem;
2982 12214 : if ( SfxItemState::SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, true, &pItem ) )
2983 0 : rNode.SetCalcHiddenCharFlags();
2984 :
2985 12214 : static_txtattr_cast<SwTxtCharFmt*>(pHint)->ChgTxtNode( &rNode );
2986 12214 : break;
2987 : }
2988 : // #i75430# Recalc hidden flags if necessary
2989 : case RES_TXTATR_AUTOFMT:
2990 : {
2991 131600 : boost::shared_ptr<SfxItemSet> const pSet( pHint->GetAutoFmt().GetStyleHandle() );
2992 131600 : if (pHint->GetStart() == *pHint->GetEnd())
2993 : {
2994 50584 : if (pSet->Count() == 1 && pSet->GetItem(RES_CHRATR_RSID, false))
2995 : { // empty range RSID-only hints could cause trouble, there's no
2996 0 : rNode.DestroyAttr(pHint); // need for them so don't insert
2997 0 : return false;
2998 : }
2999 : }
3000 : // Check if auto style contains hidden attribute:
3001 131600 : const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
3002 131600 : if ( pHiddenItem )
3003 1676 : rNode.SetCalcHiddenCharFlags();
3004 :
3005 : // fdo#71556: populate aWhichFmtAttr member of SwMsgPoolItem
3006 131600 : const sal_uInt16 *pRanges = pSet->GetRanges();
3007 657870 : while( (*pRanges) != 0 )
3008 : {
3009 394670 : const sal_uInt16 nBeg = (*pRanges);
3010 394670 : ++pRanges;
3011 394670 : const sal_uInt16 nEnd = (*pRanges);
3012 394670 : ++pRanges;
3013 6579740 : for( sal_uInt16 nSubElem = nBeg; nSubElem <= nEnd; ++nSubElem )
3014 6185070 : if( pSet->HasItem( nSubElem ) )
3015 458852 : aWhichSublist.push_back( nSubElem );
3016 : }
3017 131600 : break;
3018 : }
3019 : case RES_TXTATR_INETFMT:
3020 2842 : static_txtattr_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode);
3021 2842 : break;
3022 :
3023 : case RES_TXTATR_FIELD:
3024 : case RES_TXTATR_ANNOTATION:
3025 : case RES_TXTATR_INPUTFIELD:
3026 : {
3027 2962 : SwTxtFld *const pTxtFld(static_txtattr_cast<SwTxtFld*>(pHint));
3028 2962 : bool bDelFirst = 0 != pTxtFld->GetpTxtNode();
3029 2962 : pTxtFld->ChgTxtNode( &rNode );
3030 2962 : SwDoc* pDoc = rNode.GetDoc();
3031 2962 : const SwField* pFld = pTxtFld->GetFmtFld().GetField();
3032 :
3033 2962 : if( !pDoc->getIDocumentFieldsAccess().IsNewFldLst() )
3034 : {
3035 : // was fuer ein Feld ist es denn ??
3036 : // bestimmte Felder mussen am Doc das Calculations-Flag updaten
3037 4 : switch( pFld->GetTyp()->Which() )
3038 : {
3039 : case RES_DBFLD:
3040 : case RES_SETEXPFLD:
3041 : case RES_HIDDENPARAFLD:
3042 : case RES_HIDDENTXTFLD:
3043 : case RES_DBNUMSETFLD:
3044 : case RES_DBNEXTSETFLD:
3045 : {
3046 0 : if( bDelFirst )
3047 0 : pDoc->getIDocumentFieldsAccess().InsDelFldInFldLst(false, *pTxtFld);
3048 0 : if( rNode.GetNodes().IsDocNodes() )
3049 0 : pDoc->getIDocumentFieldsAccess().InsDelFldInFldLst(true, *pTxtFld);
3050 : }
3051 0 : break;
3052 : case RES_DDEFLD:
3053 0 : if( rNode.GetNodes().IsDocNodes() )
3054 0 : ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
3055 0 : break;
3056 : }
3057 : }
3058 :
3059 : // gehts ins normale Nodes-Array?
3060 2962 : if( rNode.GetNodes().IsDocNodes() )
3061 : {
3062 2962 : bool bInsFldType = false;
3063 2962 : switch( pFld->GetTyp()->Which() )
3064 : {
3065 : case RES_SETEXPFLD:
3066 102 : bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted();
3067 102 : if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() )
3068 : {
3069 : // bevor die ReferenzNummer gesetzt wird, sollte
3070 : // das Feld am richtigen FeldTypen haengen!
3071 : SwSetExpFieldType* pFldType = (SwSetExpFieldType*)
3072 88 : pDoc->getIDocumentFieldsAccess().InsertFldType( *pFld->GetTyp() );
3073 88 : if( pFldType != pFld->GetTyp() )
3074 : {
3075 0 : SwFmtFld* pFmtFld = const_cast<SwFmtFld*>(&pTxtFld->GetFmtFld());
3076 0 : pFmtFld->RegisterToFieldType( *pFldType );
3077 0 : pFmtFld->GetField()->ChgTyp( pFldType );
3078 : }
3079 88 : pFldType->SetSeqRefNo( *(SwSetExpField*)pFld );
3080 : }
3081 102 : break;
3082 : case RES_USERFLD:
3083 4 : bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted();
3084 4 : break;
3085 :
3086 : case RES_DDEFLD:
3087 0 : if( pDoc->getIDocumentFieldsAccess().IsNewFldLst() )
3088 0 : ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
3089 0 : bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted();
3090 0 : break;
3091 :
3092 : case RES_POSTITFLD:
3093 194 : if ( pDoc->GetDocShell() )
3094 : {
3095 194 : pDoc->GetDocShell()->Broadcast( SwFmtFldHint(
3096 388 : &pTxtFld->GetFmtFld(), SwFmtFldHintWhich::INSERTED));
3097 : }
3098 194 : break;
3099 : }
3100 2962 : if( bInsFldType )
3101 0 : pDoc->getIDocumentFieldsAccess().InsDeletedFldType( *pFld->GetTyp() );
3102 : }
3103 : }
3104 2962 : break;
3105 : case RES_TXTATR_FTN :
3106 272 : ((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
3107 272 : break;
3108 : case RES_TXTATR_REFMARK:
3109 82 : static_txtattr_cast<SwTxtRefMark*>(pHint)->ChgTxtNode( &rNode );
3110 82 : if( rNode.GetNodes().IsDocNodes() )
3111 : {
3112 : // search for a reference with the same name
3113 : SwTxtAttr* pTmpHt;
3114 : sal_Int32 *pTmpHtEnd;
3115 : sal_Int32 *pTmpHintEnd;
3116 192 : for( size_t n = 0, nEnd = Count(); n < nEnd; ++n )
3117 : {
3118 396 : if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
3119 66 : pHint->GetAttr() == pTmpHt->GetAttr() &&
3120 220 : 0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
3121 0 : 0 != ( pTmpHintEnd = pHint->GetEnd() ) )
3122 : {
3123 : SwComparePosition eCmp = ::ComparePosition(
3124 0 : pTmpHt->GetStart(), *pTmpHtEnd,
3125 0 : pHint->GetStart(), *pTmpHintEnd );
3126 0 : bool bDelOld = true, bChgStart = false, bChgEnd = false;
3127 0 : switch( eCmp )
3128 : {
3129 : case POS_BEFORE:
3130 0 : case POS_BEHIND: bDelOld = false; break;
3131 :
3132 0 : case POS_OUTSIDE: bChgStart = bChgEnd = true; break;
3133 :
3134 : case POS_COLLIDE_END:
3135 0 : case POS_OVERLAP_BEFORE: bChgStart = true; break;
3136 : case POS_COLLIDE_START:
3137 0 : case POS_OVERLAP_BEHIND: bChgEnd = true; break;
3138 0 : default: break;
3139 : }
3140 :
3141 0 : if( bChgStart )
3142 0 : pHint->GetStart() = pTmpHt->GetStart();
3143 0 : if( bChgEnd )
3144 0 : *pTmpHintEnd = *pTmpHtEnd;
3145 :
3146 0 : if( bDelOld )
3147 : {
3148 0 : NoteInHistory( pTmpHt );
3149 0 : rNode.DestroyAttr( Cut( n-- ) );
3150 0 : --nEnd;
3151 : }
3152 : }
3153 : }
3154 : }
3155 82 : break;
3156 : case RES_TXTATR_TOXMARK:
3157 342 : static_txtattr_cast<SwTxtTOXMark*>(pHint)->ChgTxtNode( &rNode );
3158 342 : break;
3159 :
3160 : case RES_TXTATR_CJK_RUBY:
3161 306 : static_txtattr_cast<SwTxtRuby*>(pHint)->InitRuby(rNode);
3162 306 : break;
3163 :
3164 : case RES_TXTATR_META:
3165 : case RES_TXTATR_METAFIELD:
3166 194 : static_txtattr_cast<SwTxtMeta *>(pHint)->ChgTxtNode( &rNode );
3167 194 : break;
3168 :
3169 : case RES_CHRATR_HIDDEN:
3170 0 : rNode.SetCalcHiddenCharFlags();
3171 0 : break;
3172 : }
3173 :
3174 157694 : if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode )
3175 620 : pHint->SetDontExpand( true );
3176 :
3177 : // SwTxtAttrs ohne Ende werden sonderbehandelt:
3178 : // Sie werden natuerlich in das Array insertet, aber sie werden nicht
3179 : // in die pPrev/Next/On/Off-Verkettung aufgenommen.
3180 : // Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text !
3181 157694 : sal_Int32 nHtStart = pHint->GetStart();
3182 157694 : if( !pHtEnd )
3183 : {
3184 10454 : SwpHintsArray::Insert( pHint );
3185 10454 : CalcFlags();
3186 : #ifdef DBG_UTIL
3187 : if( !rNode.GetDoc()->IsInReading() )
3188 : CHECK;
3189 : #endif
3190 : // ... und die Abhaengigen benachrichtigen
3191 10454 : if(rNode.GetDepends())
3192 : {
3193 : SwUpdateAttr aHint(
3194 : nHtStart,
3195 : nHtStart,
3196 3444 : nWhich);
3197 :
3198 3444 : rNode.ModifyNotification(0,&aHint);
3199 : }
3200 :
3201 10454 : return true;
3202 : }
3203 :
3204 : // Ab hier gibt es nur noch pHint mit einem EndIdx !!!
3205 :
3206 147240 : if( *pHtEnd < nHtStart )
3207 : {
3208 : OSL_ENSURE( *pHtEnd >= nHtStart,
3209 : "+SwpHints::Insert: invalid hint, end < start" );
3210 :
3211 : // Wir drehen den Quatsch einfach um:
3212 6 : pHint->GetStart() = *pHtEnd;
3213 6 : *pHtEnd = nHtStart;
3214 6 : nHtStart = pHint->GetStart();
3215 : }
3216 :
3217 : // I need this value later on for notification but the pointer may become invalid
3218 147240 : const sal_Int32 nHintEnd = *pHtEnd;
3219 147240 : const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode);
3220 :
3221 : // handle nesting attributes: inserting may fail due to overlap!
3222 147240 : if (pHint->IsNesting())
3223 : {
3224 : const bool bRet(
3225 3370 : TryInsertNesting(rNode, *static_txtattr_cast<SwTxtAttrNesting*>(pHint)));
3226 3370 : if (!bRet) return false;
3227 : }
3228 : // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
3229 : // These attributes may be inserted directly.
3230 : // Also attributes without length may be inserted directly.
3231 : // SETATTR_NOHINTADJUST is set e.g., during undo.
3232 : // Portion building in not necessary during XML import.
3233 428672 : else if ( !bNoHintAdjustMode &&
3234 281808 : !pHint->IsOverlapAllowedAttr() &&
3235 565982 : !rNode.GetDoc()->IsInXMLImport() &&
3236 12202 : ( RES_TXTATR_AUTOFMT == nWhich ||
3237 : RES_TXTATR_CHARFMT == nWhich ) )
3238 : {
3239 : OSL_ENSURE( nWhich != RES_TXTATR_AUTOFMT ||
3240 : static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
3241 : &rNode.GetDoc()->GetAttrPool(),
3242 : "AUTOSTYLES - Pool mismatch" );
3243 :
3244 140618 : BuildPortions( rNode, *pHint, nMode );
3245 :
3246 140618 : if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
3247 88954 : MergePortions( rNode );
3248 : }
3249 : else
3250 : {
3251 : // There may be more than one character style at the current position.
3252 : // Take care of the sort number.
3253 : // Special case ruby portion: During import, the ruby attribute is set
3254 : // multiple times
3255 : // Special case hyperlink: During import, the ruby attribute is set
3256 : // multiple times
3257 : // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
3258 : // character attributes directly
3259 3252 : if ( ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode ) )
3260 : {
3261 8 : BuildPortions( rNode, *pHint, nMode );
3262 : }
3263 : else
3264 : {
3265 : // #i82989# Check sort numbers in NoHintAdjustMode
3266 3244 : if ( RES_TXTATR_CHARFMT == nWhich )
3267 4 : lcl_CheckSortNumber(*this, *static_txtattr_cast<SwTxtCharFmt*>(pHint));
3268 :
3269 3244 : SwpHintsArray::Insert( pHint );
3270 3244 : NoteInHistory( pHint, true );
3271 : }
3272 : }
3273 :
3274 : // ... und die Abhaengigen benachrichtigen
3275 147236 : if ( rNode.GetDepends() )
3276 : {
3277 : SwUpdateAttr aHint(
3278 : nHtStart,
3279 : nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd,
3280 118388 : nWhich);
3281 :
3282 118388 : rNode.ModifyNotification( 0, &aHint );
3283 : }
3284 :
3285 : #ifdef DBG_UTIL
3286 : if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
3287 : CHECK;
3288 : #endif
3289 :
3290 147236 : return true;
3291 : }
3292 :
3293 86574 : void SwpHints::DeleteAtPos( const size_t nPos )
3294 : {
3295 86574 : SwTxtAttr *pHint = GetTextHint(nPos);
3296 : // ChainDelete( pHint );
3297 86574 : NoteInHistory( pHint );
3298 86574 : SwpHintsArray::DeleteAtPos( nPos );
3299 :
3300 86574 : if( pHint->Which() == RES_TXTATR_FIELD )
3301 : {
3302 102 : SwTxtFld *const pTxtFld(static_txtattr_cast<SwTxtFld*>(pHint));
3303 102 : const SwFieldType* pFldTyp = pTxtFld->GetFmtFld().GetField()->GetTyp();
3304 102 : if( RES_DDEFLD == pFldTyp->Which() )
3305 : {
3306 0 : const SwTxtNode* pNd = pTxtFld->GetpTxtNode();
3307 0 : if( pNd && pNd->GetNodes().IsDocNodes() )
3308 0 : ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
3309 0 : pTxtFld->ChgTxtNode(0);
3310 : }
3311 102 : else if ( m_bHasHiddenParaField &&
3312 0 : RES_HIDDENPARAFLD == pFldTyp->Which() )
3313 : {
3314 0 : m_bCalcHiddenParaField = true;
3315 : }
3316 : }
3317 86472 : else if ( pHint->Which() == RES_TXTATR_ANNOTATION )
3318 : {
3319 36 : SwTxtFld *const pTxtFld(static_txtattr_cast<SwTxtFld*>(pHint));
3320 36 : const_cast<SwFmtFld&>(pTxtFld->GetFmtFld()).Broadcast(
3321 72 : SwFmtFldHint(&pTxtFld->GetFmtFld(), SwFmtFldHintWhich::REMOVED));
3322 : }
3323 :
3324 86574 : CalcFlags();
3325 : CHECK_NOTMERGED; // called from BuildPortions
3326 86574 : }
3327 :
3328 : // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
3329 : // Ist er nicht im Array, so gibt es ein OSL_ENSURE(!!
3330 :
3331 77270 : void SwpHints::Delete( SwTxtAttr* pTxtHt )
3332 : {
3333 : // Attr 2.0: SwpHintsArr::Delete( pTxtHt );
3334 77270 : const size_t nPos = GetStartOf( pTxtHt );
3335 : OSL_ENSURE( SAL_MAX_SIZE != nPos, "Attribut nicht im Attribut-Array!" );
3336 77270 : if( SAL_MAX_SIZE != nPos )
3337 77270 : DeleteAtPos( nPos );
3338 77270 : }
3339 :
3340 0 : void SwTxtNode::ClearSwpHintsArr( bool bDelFields )
3341 : {
3342 0 : if ( HasHints() )
3343 : {
3344 0 : size_t nPos = 0;
3345 0 : while ( nPos < m_pSwpHints->Count() )
3346 : {
3347 0 : SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos );
3348 0 : bool bDel = false;
3349 :
3350 0 : switch( pDel->Which() )
3351 : {
3352 : case RES_TXTATR_FLYCNT:
3353 : case RES_TXTATR_FTN:
3354 0 : break;
3355 :
3356 : case RES_TXTATR_FIELD:
3357 : case RES_TXTATR_ANNOTATION:
3358 : case RES_TXTATR_INPUTFIELD:
3359 0 : if( bDelFields )
3360 0 : bDel = true;
3361 0 : break;
3362 : default:
3363 0 : bDel = true; break;
3364 : }
3365 :
3366 0 : if( bDel )
3367 : {
3368 0 : m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
3369 0 : DestroyAttr( pDel );
3370 : }
3371 : else
3372 0 : ++nPos;
3373 : }
3374 : }
3375 0 : }
3376 :
3377 294860 : sal_uInt16 SwTxtNode::GetLang( const sal_Int32 nBegin, const sal_Int32 nLen,
3378 : sal_uInt16 nScript ) const
3379 : {
3380 294860 : sal_uInt16 nRet = LANGUAGE_DONTKNOW;
3381 :
3382 294860 : if ( ! nScript )
3383 : {
3384 270787 : nScript = g_pBreakIt->GetRealScriptOfText( m_Text, nBegin );
3385 : }
3386 :
3387 : // #i91465# Consider nScript if pSwpHints == 0
3388 294860 : const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
3389 :
3390 294860 : if ( HasHints() )
3391 : {
3392 46610 : const sal_Int32 nEnd = nBegin + nLen;
3393 46610 : const size_t nSize = m_pSwpHints->Count();
3394 139400 : for ( size_t i = 0; i < nSize; ++i )
3395 : {
3396 : // ist der Attribut-Anfang schon groesser als der Idx ?
3397 95903 : const SwTxtAttr *pHt = m_pSwpHints->operator[](i);
3398 95903 : const sal_Int32 nAttrStart = pHt->GetStart();
3399 95903 : if( nEnd < nAttrStart )
3400 3113 : break;
3401 :
3402 92790 : const sal_uInt16 nWhich = pHt->Which();
3403 :
3404 196630 : if( nWhichId == nWhich ||
3405 173224 : ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) )
3406 : {
3407 11050 : const sal_Int32 *pEndIdx = pHt->End();
3408 : // Ueberlappt das Attribut den Bereich?
3409 :
3410 11050 : if (!pEndIdx)
3411 0 : continue;
3412 :
3413 21900 : if( nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
3414 8314 : : (( nAttrStart < nBegin &&
3415 8932 : ( pHt->DontExpand() ? nBegin < *pEndIdx
3416 40130 : : nBegin <= *pEndIdx )) ||
3417 2536 : ( nBegin == nAttrStart &&
3418 2712 : ( nAttrStart == *pEndIdx || !nBegin ))) )
3419 : {
3420 7160 : const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId );
3421 7160 : const sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
3422 :
3423 : // Umfasst das Attribut den Bereich komplett?
3424 7160 : if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
3425 7160 : nRet = nLng;
3426 0 : else if( LANGUAGE_DONTKNOW == nRet )
3427 0 : nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
3428 : }
3429 : }
3430 : }
3431 : }
3432 294860 : if( LANGUAGE_DONTKNOW == nRet )
3433 : {
3434 289974 : nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
3435 289974 : if( LANGUAGE_DONTKNOW == nRet )
3436 2222 : nRet = static_cast<sal_uInt16>(GetAppLanguage());
3437 : }
3438 294860 : return nRet;
3439 : }
3440 :
3441 9466 : sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
3442 : {
3443 9466 : sal_Unicode cRet = CH_TXTATR_BREAKWORD;
3444 9466 : switch ( rAttr.Which() )
3445 : {
3446 : case RES_TXTATR_REFMARK:
3447 : case RES_TXTATR_TOXMARK:
3448 368 : cRet = CH_TXTATR_INWORD;
3449 368 : break;
3450 :
3451 : case RES_TXTATR_FIELD:
3452 : case RES_TXTATR_FLYCNT:
3453 : case RES_TXTATR_FTN:
3454 : case RES_TXTATR_META:
3455 : case RES_TXTATR_METAFIELD:
3456 : case RES_TXTATR_ANNOTATION:
3457 : {
3458 9098 : cRet = CH_TXTATR_BREAKWORD;
3459 : }
3460 9098 : break;
3461 :
3462 : default:
3463 : OSL_FAIL("GetCharOfTxtAttr: unknown attr");
3464 0 : break;
3465 : }
3466 9466 : return cRet;
3467 270 : }
3468 :
3469 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|