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