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/emphitem.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 : // OD 26.06.2003 #108784#
68 : #include <dcontact.hxx>
69 : #include <docsh.hxx>
70 : #include <svl/smplhint.hxx>
71 : #include <algorithm>
72 : #include <map>
73 :
74 : #ifdef DBG_UTIL
75 : #define CHECK Check();
76 : #else
77 : #define CHECK
78 : #endif
79 :
80 : using namespace ::com::sun::star::i18n;
81 :
82 :
83 2459 : 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 2459 : , m_bDDEFields(false)
91 : {
92 2459 : }
93 :
94 : struct TxtAttrDeleter
95 : {
96 : SwAttrPool & m_rPool;
97 0 : TxtAttrDeleter( SwDoc & rDoc ) : m_rPool( rDoc.GetAttrPool() ) { }
98 0 : void operator() (SwTxtAttr * const pAttr)
99 : {
100 0 : if (RES_TXTATR_META == pAttr->Which() ||
101 0 : RES_TXTATR_METAFIELD == pAttr->Which())
102 : {
103 0 : static_cast<SwTxtMeta *>(pAttr)->ChgTxtNode(0); // prevents ASSERT
104 : }
105 0 : SwTxtAttr::Destroy( pAttr, m_rPool );
106 0 : }
107 : };
108 :
109 : struct TxtAttrContains
110 : {
111 : xub_StrLen m_nPos;
112 0 : TxtAttrContains( const xub_StrLen nPos ) : m_nPos( nPos ) { }
113 0 : bool operator() (SwTxtAttrEnd * const pAttr)
114 : {
115 0 : 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 0 : bool isOverlap(const xub_StrLen nStart1, const xub_StrLen nEnd1,
137 : const xub_StrLen nStart2, const xub_StrLen nEnd2)
138 : {
139 : return
140 : ((nStart1 > nStart2) && (nStart1 < nEnd2) && (nEnd1 > nEnd2)) // (1)
141 0 : || ((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 0 : bool isNestedAny(const xub_StrLen nStart1, const xub_StrLen nEnd1,
147 : const xub_StrLen nStart2, const xub_StrLen nEnd2)
148 : {
149 : return ((nStart1 == nStart2) || (nEnd1 == nEnd2))
150 : // same start/end: nested except if hint1 empty and hint2 not empty
151 : ? (nStart1 != nEnd1) || (nStart2 == nEnd2)
152 0 : : ((nStart1 < nStart2) ? (nEnd1 >= nEnd2) : (nEnd1 <= nEnd2));
153 : }
154 :
155 : static
156 11 : bool isSelfNestable(const sal_uInt16 nWhich)
157 : {
158 11 : if ((RES_TXTATR_INETFMT == nWhich) ||
159 : (RES_TXTATR_CJK_RUBY == nWhich))
160 11 : return false;
161 : OSL_ENSURE((RES_TXTATR_META == nWhich) ||
162 : (RES_TXTATR_METAFIELD == nWhich), "???");
163 0 : return true;
164 : }
165 :
166 : static
167 0 : bool isSplittable(const sal_uInt16 nWhich)
168 : {
169 0 : if ((RES_TXTATR_INETFMT == nWhich) ||
170 : (RES_TXTATR_CJK_RUBY == nWhich))
171 0 : return true;
172 : OSL_ENSURE((RES_TXTATR_META == nWhich) ||
173 : (RES_TXTATR_METAFIELD == nWhich), "???");
174 0 : 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 0 : splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther)
184 : {
185 0 : if (!isSplittable(nWhichOther))
186 : {
187 0 : if (!isSplittable(nWhichNew))
188 0 : return FAIL;
189 : else
190 0 : return SPLIT_NEW;
191 : }
192 : else
193 : {
194 0 : if ((RES_TXTATR_INETFMT == nWhichNew) &&
195 : (RES_TXTATR_CJK_RUBY == nWhichOther))
196 0 : return SPLIT_NEW;
197 : else
198 0 : return SPLIT_OTHER;
199 : }
200 : }
201 :
202 11 : void SwTxtINetFmt::InitINetFmt(SwTxtNode & rNode)
203 : {
204 11 : ChgTxtNode(&rNode);
205 : SwCharFmt * const pFmt(
206 11 : rNode.GetDoc()->GetCharFmtFromPool(RES_POOLCHR_INET_NORMAL) );
207 11 : pFmt->Add( this );
208 11 : }
209 :
210 0 : void SwTxtRuby::InitRuby(SwTxtNode & rNode)
211 : {
212 0 : ChgTxtNode(&rNode);
213 : SwCharFmt * const pFmt(
214 0 : rNode.GetDoc()->GetCharFmtFromPool(RES_POOLCHR_RUBYTEXT) );
215 0 : pFmt->Add( this );
216 0 : }
217 :
218 : /**
219 : Create a new nesting text hint.
220 : */
221 : static SwTxtAttrNesting *
222 0 : MakeTxtAttrNesting(SwTxtNode & rNode, SwTxtAttrNesting & rNesting,
223 : const xub_StrLen nStart, const xub_StrLen nEnd)
224 : {
225 : SwTxtAttr * const pNew( MakeTxtAttr(
226 0 : *rNode.GetDoc(), rNesting.GetAttr(), nStart, nEnd ) );
227 0 : switch (pNew->Which())
228 : {
229 : case RES_TXTATR_INETFMT:
230 : {
231 0 : static_cast<SwTxtINetFmt*>(pNew)->InitINetFmt(rNode);
232 0 : break;
233 : }
234 : case RES_TXTATR_CJK_RUBY:
235 : {
236 0 : static_cast<SwTxtRuby*>(pNew)->InitRuby(rNode);
237 0 : break;
238 : }
239 : default:
240 : OSL_FAIL("MakeTxtAttrNesting: what the hell is that?");
241 0 : break;
242 : }
243 0 : return static_cast<SwTxtAttrNesting*>(pNew);
244 : }
245 :
246 : typedef ::std::vector<SwTxtAttrNesting *> NestList_t;
247 :
248 : static void
249 0 : 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 0 : const bool bSplitAtStart(nNewStart < nOtherStart);
254 0 : 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 0 : TxtAttrContains(nSplitPos) ) );
259 0 : if (iter != rSplits.end()) // already split here?
260 : {
261 : const xub_StrLen nStartPos( // skip other's dummy character!
262 0 : (bSplitAtStart && bOtherDummy) ? nSplitPos + 1 : nSplitPos );
263 : SwTxtAttrNesting * const pNew( MakeTxtAttrNesting(
264 0 : rNode, **iter, nStartPos, *(*iter)->GetEnd() ) );
265 0 : *(*iter)->GetEnd() = nSplitPos;
266 0 : rSplits.insert(iter + 1, pNew);
267 : }
268 0 : }
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 11 : void SwpHints::InsertNesting(SwTxtAttrNesting & rNewHint)
275 : {
276 11 : SwpHintsArray::Insert(& rNewHint);
277 11 : NoteInHistory( & rNewHint, true );
278 11 : }
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 11 : SwpHints::TryInsertNesting( SwTxtNode & rNode, SwTxtAttrNesting & rNewHint )
349 : {
350 : // INVARIANT: the nestable hints in the array are properly nested
351 11 : const sal_uInt16 nNewWhich( rNewHint.Which() );
352 11 : const xub_StrLen nNewStart( *rNewHint.GetStart() );
353 11 : const xub_StrLen nNewEnd ( *rNewHint.GetEnd() );
354 : //??? const bool bNoLengthAttribute( nNewStart == nNewEnd );
355 11 : 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 11 : NestList_t OverlappingExisting; // existing hints to be split
364 11 : NestList_t OverwrittenExisting; // existing hints to be replaced
365 11 : NestList_t SplitNew; // new hints to be inserted
366 :
367 11 : SplitNew.push_back(& rNewHint);
368 :
369 : // pass 1: split the inserted hint into fragments if necessary
370 486 : for ( sal_uInt16 i = 0; i < GetEndCount(); ++i )
371 : {
372 475 : SwTxtAttr * const pOther = GetEnd(i);
373 :
374 475 : if (pOther->IsNesting())
375 : {
376 0 : const sal_uInt16 nOtherWhich( pOther->Which() );
377 0 : const xub_StrLen nOtherStart( *(pOther)->GetStart() );
378 0 : const xub_StrLen nOtherEnd ( *(pOther)->GetEnd() );
379 0 : if (isOverlap(nNewStart, nNewEnd, nOtherStart, nOtherEnd ))
380 : {
381 0 : 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 0 : TxtAttrDeleter(*rNode.GetDoc()));
387 0 : return false;
388 : case SPLIT_NEW:
389 : lcl_DoSplitNew(SplitNew, rNode, nNewStart,
390 0 : nOtherStart, nOtherEnd, pOther->HasDummyChar());
391 0 : break;
392 : case SPLIT_OTHER:
393 : OverlappingExisting.push_back(
394 0 : static_cast<SwTxtAttrNesting*>(pOther));
395 0 : break;
396 : default:
397 : OSL_FAIL("bad code monkey");
398 0 : break;
399 : }
400 : }
401 0 : else if (isNestedAny(nNewStart, nNewEnd, nOtherStart, nOtherEnd))
402 : {
403 0 : if (!bNewSelfNestable && (nNewWhich == nOtherWhich))
404 : {
405 : // ruby and hyperlink: if there is nesting, _overwrite_
406 : OverwrittenExisting.push_back(
407 0 : static_cast<SwTxtAttrNesting*>(pOther));
408 : }
409 0 : else if ((nNewStart == nOtherStart) && pOther->HasDummyChar())
410 : {
411 0 : if (rNewHint.HasDummyChar())
412 : {
413 : OSL_FAIL("ERROR: inserting duplicate CH_TXTATR hint");
414 0 : return false;
415 0 : } 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 0 : xub_StrLen *const pStart(SplitNew.front()->GetStart());
422 : OSL_ENSURE(*pStart == nNewStart, "how did that happen?");
423 0 : *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 33 : for (NestList_t::iterator itOther = OverlappingExisting.begin();
442 22 : itOther != OverlappingExisting.end(); ++itOther)
443 : {
444 0 : const xub_StrLen nOtherStart( *(*itOther)->GetStart() );
445 0 : const xub_StrLen nOtherEnd ( *(*itOther)->GetEnd() );
446 :
447 0 : for (NestList_t::iterator itNew = SplitNew.begin();
448 0 : itNew != SplitNew.end(); ++itNew)
449 : {
450 0 : const xub_StrLen nSplitNewStart( *(*itNew)->GetStart() );
451 0 : const xub_StrLen nSplitNewEnd ( *(*itNew)->GetEnd() );
452 : // 4 cases: within, around, overlap l, overlap r, (OTHER: no action)
453 : const bool bRemoveOverlap(
454 0 : !bNewSelfNestable && (nNewWhich == (*itOther)->Which()) );
455 :
456 0 : switch (ComparePosition(nSplitNewStart, nSplitNewEnd,
457 0 : nOtherStart, nOtherEnd))
458 : {
459 : case POS_INSIDE:
460 : {
461 : OSL_ENSURE(!bRemoveOverlap,
462 : "this one should be in OverwrittenExisting?");
463 : }
464 0 : 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 0 : Delete( *itOther ); // this also does NoteInHistory!
474 0 : *(*itOther)->GetStart() = nSplitNewEnd;
475 0 : InsertNesting( **itOther );
476 0 : if (!bRemoveOverlap)
477 : {
478 0 : if ( USHRT_MAX == Count() )
479 : {
480 : OSL_FAIL("hints array full :-(");
481 0 : return false;
482 : }
483 : SwTxtAttrNesting * const pOtherLeft(
484 0 : MakeTxtAttrNesting( rNode, **itOther,
485 0 : nOtherStart, nSplitNewEnd ) );
486 0 : InsertNesting( *pOtherLeft );
487 : }
488 : }
489 0 : break;
490 : case POS_OVERLAP_BEHIND:
491 : {
492 0 : Delete( *itOther ); // this also does NoteInHistory!
493 0 : *(*itOther)->GetEnd() = nSplitNewStart;
494 0 : InsertNesting( **itOther );
495 0 : if (!bRemoveOverlap)
496 : {
497 0 : if ( USHRT_MAX == Count() )
498 : {
499 : OSL_FAIL("hints array full :-(");
500 0 : return false;
501 : }
502 : SwTxtAttrNesting * const pOtherRight(
503 0 : MakeTxtAttrNesting( rNode, **itOther,
504 0 : nSplitNewStart, nOtherEnd ) );
505 0 : InsertNesting( *pOtherRight );
506 : }
507 : }
508 0 : break;
509 : default:
510 0 : break; // overlap resolved by splitting new: nothing to do
511 : }
512 : }
513 : }
514 :
515 11 : 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 66 : for (NestList_t::iterator iter = SplitNew.begin();
523 44 : iter != SplitNew.end(); ++iter)
524 : {
525 11 : 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 33 : for (NestList_t::iterator itOther = OverwrittenExisting.begin();
532 22 : itOther != OverwrittenExisting.end(); ++itOther)
533 : {
534 0 : const xub_StrLen nOtherStart( *(*itOther)->GetStart() );
535 0 : const xub_StrLen nOtherEnd ( *(*itOther)->GetEnd() );
536 :
537 : // overwritten portion is given by start/end of inserted hint
538 0 : if ((nNewStart <= nOtherStart) && (nOtherEnd <= nNewEnd))
539 : {
540 0 : Delete(*itOther);
541 0 : 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 0 : Delete( *itOther ); // this also does NoteInHistory!
551 0 : *(*itOther)->GetEnd() = nNewStart;
552 0 : bool bSuccess( TryInsertNesting(rNode, **itOther) );
553 : OSL_ENSURE(bSuccess, "recursive call 1 failed?");
554 : SwTxtAttrNesting * const pOtherRight(
555 : MakeTxtAttrNesting(
556 0 : rNode, **itOther, nNewEnd, nOtherEnd ) );
557 0 : bSuccess = TryInsertNesting(rNode, *pOtherRight);
558 : OSL_ENSURE(bSuccess, "recursive call 2 failed?");
559 : (void)bSuccess;
560 : }
561 :
562 : }
563 :
564 11 : 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 10042 : void SwpHints::BuildPortions( SwTxtNode& rNode, SwTxtAttr& rNewHint,
577 : const SetAttrMode nMode )
578 : {
579 10042 : const sal_uInt16 nWhich = rNewHint.Which();
580 :
581 10042 : const xub_StrLen nThisStart = *rNewHint.GetStart();
582 10042 : const xub_StrLen nThisEnd = *rNewHint.GetEnd();
583 10042 : const bool bNoLengthAttribute = nThisStart == nThisEnd;
584 :
585 10042 : std::vector<SwTxtAttr*> aInsDelHints;
586 10042 : 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 10042 : if ( !bNoLengthAttribute ) // nothing to do for no length attributes
597 : {
598 83698 : for ( sal_uInt16 i = 0; i < Count(); ++i )
599 : {
600 73950 : SwTxtAttr* pOther = GetTextHint(i);
601 :
602 147894 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
603 73944 : RES_TXTATR_AUTOFMT != pOther->Which() )
604 14650 : continue;
605 :
606 59300 : xub_StrLen nOtherStart = *pOther->GetStart();
607 59300 : const xub_StrLen nOtherEnd = *pOther->GetEnd();
608 :
609 : // Check if start of new attribute overlaps with pOther:
610 : // Split pOther if necessary:
611 59300 : if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
612 : {
613 28 : SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
614 56 : pOther->GetAttr(), nOtherStart, nThisStart );
615 28 : if ( RES_TXTATR_CHARFMT == pOther->Which() )
616 0 : static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
617 28 : aInsDelHints.push_back( pNewAttr );
618 :
619 28 : NoteInHistory( pOther );
620 28 : *pOther->GetStart() = nThisStart;
621 28 : NoteInHistory( pOther, true );
622 :
623 28 : nOtherStart = nThisStart;
624 : }
625 :
626 : // Check if end of new attribute overlaps with pOther:
627 : // Split pOther if necessary:
628 59300 : 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 10591 : for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
644 : {
645 843 : SwpHintsArray::Insert( *aIter );
646 843 : NoteInHistory( *aIter, true );
647 : }
648 : }
649 :
650 : #ifdef DBG_UTIL
651 : if( !rNode.GetDoc()->IsInReading() )
652 : CHECK;
653 : #endif
654 :
655 : //
656 : // 4. Split rNewHint into 1 ... n new hints:
657 : //
658 10042 : std::set<xub_StrLen> aBounds;
659 10042 : aBounds.insert( nThisStart );
660 10042 : aBounds.insert( nThisEnd );
661 :
662 10042 : if ( !bNoLengthAttribute ) // nothing to do for no length attributes
663 : {
664 84541 : for ( sal_uInt16 i = 0; i < Count(); ++i )
665 : {
666 74793 : const SwTxtAttr* pOther = GetTextHint(i);
667 :
668 149580 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
669 74787 : RES_TXTATR_AUTOFMT != pOther->Which() )
670 14650 : continue;
671 :
672 60143 : const xub_StrLen nOtherStart = *pOther->GetStart();
673 60143 : const xub_StrLen nOtherEnd = *pOther->GetEnd();
674 :
675 60143 : aBounds.insert( nOtherStart );
676 60143 : aBounds.insert( nOtherEnd );
677 : }
678 : }
679 :
680 10042 : std::set<xub_StrLen>::iterator aStartIter = aBounds.lower_bound( nThisStart );
681 10042 : std::set<xub_StrLen>::iterator aEndIter = aBounds.upper_bound( nThisEnd );
682 10042 : xub_StrLen nPorStart = *aStartIter;
683 10042 : ++aStartIter;
684 10042 : bool bDestroyHint = true;
685 :
686 : //
687 : // Insert the 1...n new parts of the new attribute:
688 : //
689 30418 : while ( aStartIter != aEndIter || bNoLengthAttribute )
690 : {
691 : OSL_ENSURE( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" );
692 :
693 10628 : const xub_StrLen nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter;
694 10628 : aInsDelHints.clear();
695 :
696 : // Get all hints that are in [nPorStart, nPorEnd[:
697 94265 : for ( sal_uInt16 i = 0; i < Count(); ++i )
698 : {
699 85326 : SwTxtAttr *pOther = GetTextHint(i);
700 :
701 170646 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
702 85320 : RES_TXTATR_AUTOFMT != pOther->Which() )
703 14696 : continue;
704 :
705 70630 : const xub_StrLen nOtherStart = *pOther->GetStart();
706 :
707 70630 : if ( nOtherStart > nPorStart )
708 : break;
709 :
710 68941 : if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart )
711 : {
712 : OSL_ENSURE( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" );
713 8167 : aInsDelHints.push_back( pOther );
714 : }
715 : }
716 :
717 10628 : SwTxtAttr* pNewAttr = 0;
718 10628 : 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 12 : sal_uInt16 nCharStyleCount = 0;
724 12 : aIter = aInsDelHints.begin();
725 24 : while ( aIter != aInsDelHints.end() )
726 : {
727 0 : 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 : 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 0 : SwTxtAttr* pOther = *aIter;
754 0 : 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 the new character style:
758 0 : SfxItemSet aNewSet( *pOldStyle->GetPool(),
759 0 : aCharAutoFmtSetRange);
760 0 : SfxItemIter aItemIter( *pOldStyle );
761 0 : const SfxPoolItem* pItem = aItemIter.GetCurItem();
762 0 : while( true )
763 : {
764 0 : if ( !CharFmt::IsItemIncluded( pItem->Which(), &rNewHint ) )
765 : {
766 0 : aNewSet.Put( *pItem );
767 : }
768 :
769 0 : if( aItemIter.IsAtEnd() )
770 0 : break;
771 :
772 0 : pItem = aItemIter.NextItem();
773 : }
774 :
775 : // Remove old hint
776 0 : Delete( pOther );
777 0 : rNode.DestroyAttr( pOther );
778 :
779 : // Create new AutoStyle
780 0 : if ( aNewSet.Count() )
781 : {
782 0 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
783 0 : aNewSet, nPorStart, nPorEnd );
784 0 : SwpHintsArray::Insert( pNewAttr );
785 0 : NoteInHistory( pNewAttr, true );
786 0 : }
787 : }
788 0 : ++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 12 : if ( nPorStart == nThisStart &&
794 : nPorEnd == nThisEnd &&
795 : !nCharStyleCount )
796 : {
797 12 : pNewAttr = &rNewHint;
798 12 : 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 10616 : SwTxtAttr* pCurrentAutoStyle = 0;
811 10616 : SwTxtAttr* pCurrentCharFmt = 0;
812 10616 : aIter = aInsDelHints.begin();
813 29399 : while ( aIter != aInsDelHints.end() )
814 : {
815 8167 : if ( RES_TXTATR_AUTOFMT == (*aIter)->Which() )
816 8164 : pCurrentAutoStyle = *aIter;
817 3 : else if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
818 3 : pCurrentCharFmt = *aIter;
819 8167 : ++aIter;
820 : }
821 :
822 10616 : boost::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFmtAutoFmt&>(rNewHint.GetAttr()).GetStyleHandle();
823 10616 : if ( pCurrentAutoStyle )
824 : {
825 8164 : boost::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFmtAutoFmt&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle();
826 :
827 : // Merge attributes
828 8164 : SfxItemSet aNewSet( *pCurrentStyle );
829 8164 : 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 8164 : if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() )
834 : {
835 5276 : SfxItemIter aIter2( aNewSet );
836 5276 : const SfxPoolItem* pItem = aIter2.GetCurItem();
837 5276 : const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
838 :
839 20971 : do
840 : {
841 20971 : const SfxPoolItem* pTmpItem = 0;
842 20971 : if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), sal_False, &pTmpItem ) &&
843 : 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 26247 : while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
851 : }
852 :
853 : // Remove old hint
854 8164 : Delete( pCurrentAutoStyle );
855 8164 : rNode.DestroyAttr( pCurrentAutoStyle );
856 :
857 : // Create new AutoStyle
858 8164 : if ( aNewSet.Count() )
859 8164 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(), aNewSet,
860 16328 : nPorStart, nPorEnd );
861 : }
862 : else
863 : {
864 : // Remove any attributes which are already set at the whole paragraph:
865 2452 : bool bOptimizeAllowed = true;
866 :
867 2452 : SfxItemSet* pNewSet = 0;
868 : // #i75750# Remove attributes already set at whole paragraph
869 : // #i81764# This should not be applied for no length attributes!!! <--
870 2452 : if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() )
871 : {
872 1766 : SfxItemIter aIter2( *pNewStyle );
873 1766 : const SfxPoolItem* pItem = aIter2.GetCurItem();
874 1766 : const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
875 :
876 1859 : do
877 : {
878 1859 : const SfxPoolItem* pTmpItem = 0;
879 1859 : if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), sal_False, &pTmpItem ) &&
880 : pTmpItem == pItem )
881 : {
882 : // Do not clear item if the attribute is set in a character format:
883 0 : if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
884 : {
885 0 : if ( !pNewSet )
886 0 : pNewSet = pNewStyle->Clone( sal_True );
887 0 : pNewSet->ClearItem( pItem->Which() );
888 : }
889 : }
890 : }
891 1859 : while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
892 :
893 1766 : if ( pNewSet )
894 : {
895 0 : bOptimizeAllowed = false;
896 0 : if ( pNewSet->Count() )
897 0 : pNewStyle = rNode.getIDocumentStyleAccess().getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
898 : else
899 0 : pNewStyle.reset();
900 :
901 0 : delete pNewSet;
902 1766 : }
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 2452 : if ( bOptimizeAllowed &&
909 : nPorStart == nThisStart &&
910 : nPorEnd == nThisEnd )
911 : {
912 2304 : pNewAttr = &rNewHint;
913 2304 : bDestroyHint = false;
914 : }
915 148 : else if ( pNewStyle.get() )
916 : {
917 148 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(), *pNewStyle,
918 296 : nPorStart, nPorEnd );
919 : }
920 10616 : }
921 : }
922 :
923 10628 : if ( pNewAttr )
924 : {
925 10628 : SwpHintsArray::Insert( pNewAttr );
926 : // if ( bDestroyHint )
927 10628 : NoteInHistory( pNewAttr, true );
928 : }
929 :
930 10628 : if ( !bNoLengthAttribute )
931 : {
932 10334 : nPorStart = *aStartIter;
933 10334 : ++aStartIter;
934 : }
935 : else
936 294 : break;
937 : }
938 :
939 10042 : if ( bDestroyHint )
940 7726 : rNode.DestroyAttr( &rNewHint );
941 10042 : }
942 :
943 : /*************************************************************************
944 : * SwTxtNode::MakeTxtAttr()
945 : *************************************************************************/
946 :
947 10 : SwTxtAttr* MakeRedlineTxtAttr( SwDoc & rDoc, SfxPoolItem & rAttr )
948 : {
949 : // this is intended _only_ for special-purpose redline attributes!
950 10 : 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 10 : 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 10 : const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
973 10 : return new SwTxtAttrEnd( rNew, 0, 0 );
974 : }
975 :
976 : // create new text attribute
977 20342 : 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 20342 : 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 277 : SfxItemSet aItemSet( rDoc.GetAttrPool(),
987 277 : RES_CHRATR_BEGIN, RES_CHRATR_END );
988 277 : aItemSet.Put( rAttr );
989 277 : return MakeTxtAttr( rDoc, aItemSet, nStt, nEnd );
990 : }
991 78842 : else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
992 : static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle()->
993 58777 : 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 20065 : const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
1008 :
1009 20065 : SwTxtAttr* pNew = 0;
1010 20065 : switch( rNew.Which() )
1011 : {
1012 : case RES_TXTATR_CHARFMT:
1013 : {
1014 12 : SwFmtCharFmt &rFmtCharFmt = (SwFmtCharFmt&) rNew;
1015 12 : if( !rFmtCharFmt.GetCharFmt() )
1016 : {
1017 0 : rFmtCharFmt.SetCharFmt( rDoc.GetDfltCharFmt() );
1018 : }
1019 :
1020 12 : pNew = new SwTxtCharFmt( rFmtCharFmt, nStt, nEnd );
1021 : }
1022 12 : break;
1023 : case RES_TXTATR_INETFMT:
1024 11 : pNew = new SwTxtINetFmt( (SwFmtINetFmt&)rNew, nStt, nEnd );
1025 11 : break;
1026 : case RES_TXTATR_FIELD:
1027 : pNew = new SwTxtFld( static_cast<SwFmtFld &>(rNew), nStt,
1028 491 : rDoc.IsClipBoard() );
1029 491 : break;
1030 : case RES_TXTATR_FLYCNT:
1031 : {
1032 : // erst hier wird das Frame-Format kopiert (mit Inhalt) !!
1033 186 : pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt );
1034 : // Kopie von einem Text-Attribut
1035 186 : if ( static_cast<const SwFmtFlyCnt &>(rAttr).GetTxtFlyCnt() )
1036 : {
1037 : // then the format must be copied
1038 1 : static_cast<SwTxtFlyCnt *>(pNew)->CopyFlyFmt( &rDoc );
1039 : }
1040 : }
1041 186 : break;
1042 : case RES_TXTATR_FTN:
1043 8 : pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt );
1044 : // ggfs. SeqNo kopieren
1045 8 : if( ((SwFmtFtn&)rAttr).GetTxtFtn() )
1046 0 : ((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() );
1047 8 : break;
1048 : case RES_TXTATR_REFMARK:
1049 : pNew = nStt == nEnd
1050 1 : ? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt )
1051 2 : : new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd );
1052 1 : break;
1053 : case RES_TXTATR_TOXMARK:
1054 0 : pNew = new SwTxtTOXMark( (SwTOXMark&)rNew, nStt, &nEnd );
1055 0 : break;
1056 : case RES_TXTATR_CJK_RUBY:
1057 0 : pNew = new SwTxtRuby( (SwFmtRuby&)rNew, nStt, nEnd );
1058 0 : break;
1059 : case RES_TXTATR_META:
1060 : case RES_TXTATR_METAFIELD:
1061 0 : pNew = SwTxtMeta::CreateTxtMeta( rDoc.GetMetaFieldManager(), pTxtNode,
1062 0 : static_cast<SwFmtMeta&>(rNew), nStt, nEnd, bIsCopy );
1063 0 : break;
1064 : default:
1065 : OSL_ENSURE(RES_TXTATR_AUTOFMT == rNew.Which(), "unknown attribute");
1066 19356 : pNew = new SwTxtAttrEnd( rNew, nStt, nEnd );
1067 19356 : break;
1068 : }
1069 :
1070 20065 : return pNew;
1071 : }
1072 :
1073 18219 : SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, const SfxItemSet& rSet,
1074 : xub_StrLen nStt, xub_StrLen nEnd )
1075 : {
1076 18219 : IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
1077 18219 : const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
1078 18219 : SwFmtAutoFmt aNewAutoFmt;
1079 18219 : aNewAutoFmt.SetStyleHandle( pAutoStyle );
1080 18219 : SwTxtAttr* pNew = MakeTxtAttr( rDoc, aNewAutoFmt, nStt, nEnd );
1081 18219 : return pNew;
1082 : }
1083 :
1084 :
1085 : // loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
1086 19725 : void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr )
1087 : {
1088 19725 : if( pAttr )
1089 : {
1090 : // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
1091 19725 : SwDoc* pDoc = GetDoc();
1092 19725 : sal_uInt16 nDelMsg = 0;
1093 19725 : 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 90 : SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1100 90 : if( pFmt ) // vom Undo auf 0 gesetzt ??
1101 85 : pDoc->DelLayoutFmt( (SwFlyFrmFmt*)pFmt );
1102 : }
1103 90 : break;
1104 :
1105 : case RES_CHRATR_HIDDEN:
1106 0 : SetCalcHiddenCharFlags();
1107 0 : break;
1108 :
1109 : case RES_TXTATR_FTN:
1110 6 : ((SwTxtFtn*)pAttr)->SetStartNode( 0 );
1111 6 : nDelMsg = RES_FOOTNOTE_DELETED;
1112 6 : break;
1113 :
1114 : case RES_TXTATR_FIELD:
1115 481 : if( !pDoc->IsInDtor() )
1116 : {
1117 : // Wenn wir ein HiddenParaField sind, dann muessen wir
1118 : // ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
1119 2 : 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 2 : 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 0 : if( !pDoc->IsNewFldLst() && GetNodes().IsDocNodes() )
1140 0 : pDoc->InsDelFldInFldLst( false, *(SwTxtFld*)pAttr );
1141 0 : 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 2 : const_cast<SwFmtFld&>(pAttr->GetFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pAttr)->GetFld(), SWFMTFLD_REMOVED ) );
1150 2 : break;
1151 : }
1152 : }
1153 : }
1154 481 : nDelMsg = RES_FIELD_DELETED;
1155 481 : break;
1156 :
1157 : case RES_TXTATR_TOXMARK:
1158 0 : static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark();
1159 0 : break;
1160 :
1161 : case RES_TXTATR_REFMARK:
1162 1 : nDelMsg = RES_REFMARK_DELETED;
1163 1 : break;
1164 :
1165 : case RES_TXTATR_META:
1166 : case RES_TXTATR_METAFIELD:
1167 0 : static_cast<SwTxtMeta*>(pAttr)->ChgTxtNode(0);
1168 0 : break;
1169 :
1170 : default:
1171 19147 : break;
1172 : }
1173 :
1174 19725 : if( nDelMsg && !pDoc->IsInDtor() && GetNodes().IsDocNodes() )
1175 : {
1176 2 : SwPtrMsgPoolItem aMsgHint( nDelMsg, (void*)&pAttr->GetAttr() );
1177 2 : pDoc->GetUnoCallBack()->ModifyNotification( &aMsgHint, &aMsgHint );
1178 : }
1179 :
1180 19725 : SwTxtAttr::Destroy( pAttr, pDoc->GetAttrPool() );
1181 : }
1182 19725 : }
1183 :
1184 : /*************************************************************************
1185 : * SwTxtNode::Insert()
1186 : *************************************************************************/
1187 :
1188 : SwTxtAttr*
1189 220 : 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 220 : SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(), rAttr, nStart, nEnd,
1197 440 : (nMode & nsSetAttrMode::SETATTR_IS_COPY) ? COPY : NEW, this );
1198 :
1199 220 : if ( pNew )
1200 : {
1201 220 : 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 220 : if (!bSuccess || ( USHRT_MAX == m_pSwpHints->GetPos( pNew ) ))
1206 : {
1207 1 : return 0;
1208 : }
1209 : }
1210 :
1211 219 : return pNew;
1212 : }
1213 :
1214 : // take ownership of pAttr; if insertion fails, delete pAttr
1215 11174 : bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode )
1216 : {
1217 11174 : 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 : (nMode & nsSetAttrMode::SETATTR_FORCEHINTEXPAND)
1226 : ? static_cast<IDocumentContentOperations::InsertFlags>(
1227 : IDocumentContentOperations::INS_FORCEHINTEXPAND |
1228 : IDocumentContentOperations::INS_EMPTYEXPAND)
1229 11174 : : IDocumentContentOperations::INS_EMPTYEXPAND;
1230 :
1231 : // need this after TryInsertHint, when pAttr may be deleted
1232 11174 : const xub_StrLen nStart( *pAttr->GetStart() );
1233 11174 : const bool bDummyChar( pAttr->HasDummyChar() );
1234 11174 : if (bDummyChar)
1235 : {
1236 686 : sal_uInt16 nInsMode = nMode;
1237 686 : switch( pAttr->Which() )
1238 : {
1239 : case RES_TXTATR_FLYCNT:
1240 : {
1241 186 : SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr;
1242 186 : SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1243 186 : 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 185 : const SwFmtAnchor* pAnchor = 0;
1252 : pFmt->GetItemState( RES_ANCHOR, sal_False,
1253 185 : (const SfxPoolItem**)&pAnchor );
1254 :
1255 185 : SwIndex aIdx( this, *pAttr->GetStart() );
1256 185 : const rtl::OUString c(GetCharOfTxtAttr(*pAttr));
1257 185 : InsertText( c, aIdx, nInsertFlags );
1258 185 : nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
1259 :
1260 1283 : if (pAnchor &&
1261 185 : (FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
1262 182 : pAnchor->GetCntntAnchor() &&
1263 549 : pAnchor->GetCntntAnchor()->nNode == *this &&
1264 182 : pAnchor->GetCntntAnchor()->nContent == aIdx )
1265 : {
1266 : const_cast<SwIndex&>(
1267 181 : pAnchor->GetCntntAnchor()->nContent)--;
1268 185 : }
1269 : }
1270 186 : pFly->SetAnchor( this );
1271 :
1272 : // Format-Pointer kann sich im SetAnchor geaendert haben!
1273 : // (Kopieren in andere Docs!)
1274 186 : pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1275 186 : SwDoc *pDoc = pFmt->GetDoc();
1276 :
1277 : // OD 26.06.2003 #108784# - allow drawing objects in header/footer.
1278 : // But don't allow control objects in header/footer
1279 204 : if( RES_DRAWFRMFMT == pFmt->Which() &&
1280 18 : pDoc->IsInHeaderFooter( pFmt->GetAnchor().GetCntntAnchor()->nNode ) )
1281 : {
1282 : SwDrawContact* pDrawContact =
1283 0 : static_cast<SwDrawContact*>(pFmt->FindContactObj());
1284 0 : if ( pDrawContact &&
1285 0 : pDrawContact->GetMaster() &&
1286 0 : ::CheckControlLayer( pDrawContact->GetMaster() ) )
1287 : {
1288 : // das soll nicht meoglich sein; hier verhindern
1289 : // Der Dtor des TxtHints loescht nicht das Zeichen.
1290 : // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1291 : // dieses explizit loeschen
1292 0 : if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
1293 : {
1294 : // loesche das Zeichen aus dem String !
1295 : OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
1296 : m_Text.GetChar(*pAttr->GetStart() ) ||
1297 : CH_TXTATR_INWORD ==
1298 : m_Text.GetChar(*pAttr->GetStart())),
1299 : "where is my attribute character?" );
1300 0 : m_Text.Erase( *pAttr->GetStart(), 1 );
1301 : // Indizies Updaten
1302 0 : SwIndex aTmpIdx( this, *pAttr->GetStart() );
1303 0 : Update( aTmpIdx, 1, sal_True );
1304 : }
1305 : // do not record deletion of Format!
1306 0 : ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1307 0 : DestroyAttr( pAttr );
1308 0 : return false;
1309 : }
1310 : }
1311 186 : break;
1312 : }
1313 :
1314 : case RES_TXTATR_FTN :
1315 : {
1316 : // Fussnoten, man kommt an alles irgendwie heran.
1317 : // CntntNode erzeugen und in die Inserts-Section stellen
1318 8 : SwDoc *pDoc = GetDoc();
1319 8 : SwNodes &rNodes = pDoc->GetNodes();
1320 :
1321 : // FussNote in nicht Content-/Redline-Bereich einfuegen ??
1322 8 : if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
1323 : {
1324 : // das soll nicht meoglich sein; hier verhindern
1325 : // Der Dtor des TxtHints loescht nicht das Zeichen.
1326 : // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1327 : // dieses explizit loeschen
1328 0 : if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
1329 : {
1330 : // loesche das Zeichen aus dem String !
1331 : OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
1332 : m_Text.GetChar(*pAttr->GetStart() ) ||
1333 : CH_TXTATR_INWORD ==
1334 : m_Text.GetChar(*pAttr->GetStart())),
1335 : "where is my attribute character?" );
1336 0 : m_Text.Erase( *pAttr->GetStart(), 1 );
1337 : // Indizies Updaten
1338 0 : SwIndex aTmpIdx( this, *pAttr->GetStart() );
1339 0 : Update( aTmpIdx, 1, sal_True );
1340 : }
1341 0 : DestroyAttr( pAttr );
1342 0 : return false;
1343 : }
1344 :
1345 : // wird eine neue Fussnote eingefuegt ??
1346 8 : bool bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode();
1347 8 : if( bNewFtn )
1348 : {
1349 8 : ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() );
1350 8 : SwRegHistory* pHist = GetpSwpHints()
1351 8 : ? GetpSwpHints()->GetHistory() : 0;
1352 8 : if( pHist )
1353 0 : pHist->ChangeNodeIndex( GetIndex() );
1354 : }
1355 0 : else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
1356 : {
1357 : // loesche alle Frames der Section, auf die der StartNode zeigt
1358 : sal_uLong nSttIdx =
1359 0 : ((SwTxtFtn*)pAttr)->GetStartNode()->GetIndex();
1360 0 : sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
1361 : SwCntntNode* pCNd;
1362 0 : for( ; nSttIdx < nEndIdx; ++nSttIdx )
1363 0 : if( 0 != ( pCNd = rNodes[ nSttIdx ]->GetCntntNode() ))
1364 0 : pCNd->DelFrms();
1365 : }
1366 :
1367 8 : if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1368 : {
1369 : // Wir muessen zuerst einfuegen, da sonst gleiche Indizes
1370 : // entstehen koennen und das Attribut im _SortArr_ am
1371 : // Dokument nicht eingetrage wird.
1372 8 : SwIndex aNdIdx( this, *pAttr->GetStart() );
1373 8 : const rtl::OUString c(GetCharOfTxtAttr(*pAttr));
1374 8 : InsertText( c, aNdIdx, nInsertFlags );
1375 8 : nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
1376 : }
1377 :
1378 : // Wir tragen uns am FtnIdx-Array des Docs ein ...
1379 8 : SwTxtFtn* pTxtFtn = 0;
1380 8 : if( !bNewFtn )
1381 : {
1382 : // eine alte Ftn wird umgehaengt (z.B. SplitNode)
1383 0 : for( sal_uInt16 n = 0; n < pDoc->GetFtnIdxs().size(); ++n )
1384 0 : if( pAttr == pDoc->GetFtnIdxs()[n] )
1385 : {
1386 : // neuen Index zuweisen, dafuer aus dem SortArray
1387 : // loeschen und neu eintragen
1388 0 : pTxtFtn = pDoc->GetFtnIdxs()[n];
1389 0 : pDoc->GetFtnIdxs().erase( pDoc->GetFtnIdxs().begin() + n );
1390 0 : break;
1391 : }
1392 : // wenn ueber Undo der StartNode gesetzt wurde, kann
1393 : // der Index noch gar nicht in der Verwaltung stehen !!
1394 : }
1395 8 : if( !pTxtFtn )
1396 8 : pTxtFtn = (SwTxtFtn*)pAttr;
1397 :
1398 : // fuers Update der Nummern und zum Sortieren
1399 : // muss der Node gesetzt sein.
1400 8 : ((SwTxtFtn*)pAttr)->ChgTxtNode( this );
1401 :
1402 : // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen!
1403 8 : if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
1404 : {
1405 8 : const bool bSuccess = pDoc->GetFtnIdxs().insert(pTxtFtn).second;
1406 : OSL_ENSURE( bSuccess, "FtnIdx not inserted." );
1407 : (void) bSuccess; // unused in non-debug
1408 : }
1409 8 : SwNodeIndex aTmpIndex( *this );
1410 8 : pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
1411 8 : ((SwTxtFtn*)pAttr)->SetSeqRefNo();
1412 : }
1413 8 : break;
1414 :
1415 : case RES_TXTATR_FIELD:
1416 : {
1417 : // fuer HiddenParaFields Benachrichtigungsmechanismus
1418 : // anwerfen
1419 491 : if( RES_HIDDENPARAFLD ==
1420 491 : pAttr->GetFld().GetFld()->GetTyp()->Which() )
1421 0 : bHiddenPara = true;
1422 : }
1423 491 : break;
1424 :
1425 : }
1426 : // Fuer SwTxtHints ohne Endindex werden CH_TXTATR_..
1427 : // eingefuegt, aStart muss danach um einen zurueckgesetzt werden.
1428 : // Wenn wir im SwTxtNode::Copy stehen, so wurde das Zeichen bereits
1429 : // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden.
1430 686 : if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1431 : {
1432 492 : SwIndex aIdx( this, *pAttr->GetStart() );
1433 492 : InsertText( rtl::OUString(GetCharOfTxtAttr(*pAttr)), aIdx, nInsertFlags );
1434 :
1435 : // adjust end of hint to account for inserted CH_TXTATR
1436 492 : xub_StrLen * const pEnd(pAttr->GetEnd());
1437 492 : if (pEnd)
1438 : {
1439 0 : *pEnd = *pEnd + 1;
1440 492 : }
1441 : }
1442 : }
1443 :
1444 11174 : GetOrCreateSwpHints();
1445 :
1446 : // 4263: AttrInsert durch TextInsert => kein Adjust
1447 11174 : const bool bRet = m_pSwpHints->TryInsertHint( pAttr, *this, nMode );
1448 :
1449 11174 : if (!bRet && bDummyChar)
1450 : {
1451 : // undo insertion of dummy character
1452 : // N.B. cannot insert the dummy character after inserting the hint,
1453 : // because if the hint has no extent it will be moved in InsertText,
1454 : // resulting in infinite recursion
1455 0 : if ( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) )
1456 : {
1457 : OSL_ENSURE( ( CH_TXTATR_BREAKWORD == m_Text.GetChar(nStart) ||
1458 : CH_TXTATR_INWORD == m_Text.GetChar(nStart) ),
1459 : "where is my attribute character?" );
1460 0 : SwIndex aIdx( this, nStart );
1461 0 : EraseText( aIdx, 1 );
1462 : }
1463 : }
1464 :
1465 11174 : if ( bHiddenPara )
1466 : {
1467 0 : SetCalcHiddenParaField();
1468 : }
1469 :
1470 11174 : return bRet;
1471 : }
1472 :
1473 :
1474 : /*************************************************************************
1475 : * SwTxtNode::DeleteAttribute()
1476 : *************************************************************************/
1477 :
1478 0 : void SwTxtNode::DeleteAttribute( SwTxtAttr * const pAttr )
1479 : {
1480 0 : if ( !HasHints() )
1481 : {
1482 : OSL_FAIL("DeleteAttribute called, but text node without hints?");
1483 0 : return;
1484 : }
1485 :
1486 0 : if ( pAttr->HasDummyChar() )
1487 : {
1488 : // Unbedingt Copy-konstruieren!
1489 0 : const SwIndex aIdx( this, *pAttr->GetStart() );
1490 : // erase the CH_TXTATR, which will also delete pAttr
1491 0 : EraseText( aIdx, 1 );
1492 : }
1493 : else
1494 : {
1495 : // create MsgHint before start/end become invalid
1496 : SwUpdateAttr aHint(
1497 0 : *pAttr->GetStart(), *pAttr->GetEnd(), pAttr->Which() );
1498 0 : m_pSwpHints->Delete( pAttr );
1499 0 : SwTxtAttr::Destroy( pAttr, GetDoc()->GetAttrPool() );
1500 0 : NotifyClients( 0, &aHint );
1501 :
1502 0 : TryDeleteSwpHints();
1503 : }
1504 : }
1505 :
1506 : /*************************************************************************
1507 : * SwTxtNode::DeleteAttributes()
1508 : *************************************************************************/
1509 :
1510 : //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
1511 6 : void SwTxtNode::DeleteAttributes( const sal_uInt16 nWhich,
1512 : const xub_StrLen nStart, const xub_StrLen nEnd )
1513 : {
1514 6 : if ( !HasHints() )
1515 6 : return;
1516 :
1517 13 : for ( sal_uInt16 nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); nPos++ )
1518 : {
1519 7 : SwTxtAttr * const pTxtHt = m_pSwpHints->GetTextHint( nPos );
1520 7 : const xub_StrLen nHintStart = *(pTxtHt->GetStart());
1521 7 : if (nStart < nHintStart)
1522 : {
1523 0 : break; // sorted by start
1524 : }
1525 7 : else if ( (nStart == nHintStart) && (nWhich == pTxtHt->Which()) )
1526 : {
1527 6 : if ( nWhich == RES_CHRATR_HIDDEN )
1528 : {
1529 : OSL_FAIL("hey, that's a CHRATR! how did that get in?");
1530 0 : SetCalcHiddenCharFlags();
1531 : }
1532 6 : else if ( nWhich == RES_TXTATR_CHARFMT )
1533 : {
1534 : // Check if character format contains hidden attribute:
1535 0 : const SwCharFmt* pFmt = pTxtHt->GetCharFmt().GetCharFmt();
1536 : const SfxPoolItem* pItem;
1537 0 : if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
1538 0 : SetCalcHiddenCharFlags();
1539 : }
1540 : // #i75430# Recalc hidden flags if necessary
1541 6 : else if ( nWhich == RES_TXTATR_AUTOFMT )
1542 : {
1543 : // Check if auto style contains hidden attribute:
1544 0 : const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN );
1545 0 : if ( pHiddenItem )
1546 0 : SetCalcHiddenCharFlags();
1547 : }
1548 :
1549 6 : xub_StrLen const * const pEndIdx = pTxtHt->GetEnd();
1550 :
1551 6 : if ( pTxtHt->HasDummyChar() )
1552 : {
1553 : // Unbedingt Copy-konstruieren!
1554 6 : const SwIndex aIdx( this, nStart );
1555 : // erase the CH_TXTATR, which will also delete pTxtHt
1556 6 : EraseText( aIdx, 1 );
1557 : }
1558 0 : else if( *pEndIdx == nEnd )
1559 : {
1560 : // den MsgHint jetzt fuettern, weil gleich sind
1561 : // Start und End weg.
1562 : // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
1563 : // da dies das Feld im Dtor selbst erledigt.
1564 0 : SwUpdateAttr aHint( nStart, *pEndIdx, nWhich );
1565 0 : m_pSwpHints->DeleteAtPos( nPos ); // gefunden, loeschen,
1566 0 : SwTxtAttr::Destroy( pTxtHt, GetDoc()->GetAttrPool() );
1567 0 : NotifyClients( 0, &aHint );
1568 : }
1569 : }
1570 : }
1571 6 : TryDeleteSwpHints();
1572 : }
1573 :
1574 : /*************************************************************************
1575 : * SwTxtNode::DelSoftHyph()
1576 : *************************************************************************/
1577 :
1578 0 : void SwTxtNode::DelSoftHyph( const xub_StrLen nStt, const xub_StrLen nEnd )
1579 : {
1580 0 : xub_StrLen nFndPos = nStt, nEndPos = nEnd;
1581 0 : while( STRING_NOTFOUND !=
1582 0 : ( nFndPos = m_Text.Search( CHAR_SOFTHYPHEN, nFndPos )) &&
1583 : nFndPos < nEndPos )
1584 : {
1585 0 : const SwIndex aIdx( this, nFndPos );
1586 0 : EraseText( aIdx, 1 );
1587 0 : --nEndPos;
1588 0 : }
1589 0 : }
1590 :
1591 : // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
1592 : // dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr)
1593 13199 : sal_Bool SwTxtNode::SetAttr( const SfxItemSet& rSet, xub_StrLen nStt,
1594 : xub_StrLen nEnd, const SetAttrMode nMode )
1595 : {
1596 13199 : if( !rSet.Count() )
1597 0 : return sal_False;
1598 :
1599 : // teil die Sets auf (fuer Selektion in Nodes)
1600 13199 : const SfxItemSet* pSet = &rSet;
1601 13199 : SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
1602 :
1603 : // gesamter Bereich
1604 18036 : if ( !nStt && (nEnd == m_Text.Len()) &&
1605 4837 : !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) )
1606 : {
1607 : // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
1608 : // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
1609 3491 : bool bHasCharFmts = false;
1610 3491 : if ( HasHints() )
1611 : {
1612 507 : for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
1613 : {
1614 276 : if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() )
1615 : {
1616 2 : bHasCharFmts = true;
1617 2 : break;
1618 : }
1619 : }
1620 : }
1621 :
1622 3491 : if( !bHasCharFmts )
1623 : {
1624 3489 : aTxtSet.Put( rSet );
1625 : // If there are any character attributes in rSet,
1626 : // we want to set them at the paragraph:
1627 3489 : if( aTxtSet.Count() != rSet.Count() )
1628 : {
1629 3471 : sal_Bool bRet = SetAttr( rSet );
1630 3471 : if( !aTxtSet.Count() )
1631 3471 : return bRet;
1632 : }
1633 :
1634 : // check for auto style:
1635 : const SfxPoolItem* pItem;
1636 18 : const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, sal_False, &pItem );
1637 18 : if ( bAutoStyle )
1638 : {
1639 5 : boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle();
1640 5 : sal_Bool bRet = SetAttr( *pAutoStyleSet );
1641 5 : if( 1 == aTxtSet.Count() )
1642 5 : return bRet;
1643 : }
1644 :
1645 : // Continue with the text attributes:
1646 13 : pSet = &aTxtSet;
1647 : }
1648 : }
1649 :
1650 9723 : GetOrCreateSwpHints();
1651 :
1652 9723 : SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange );
1653 :
1654 9723 : sal_uInt16 nCount = 0;
1655 9723 : SfxItemIter aIter( *pSet );
1656 9723 : const SfxPoolItem* pItem = aIter.GetCurItem();
1657 :
1658 0 : do
1659 : {
1660 9723 : if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
1661 : {
1662 9723 : const sal_uInt16 nWhich = pItem->Which();
1663 : OSL_ENSURE( isCHRATR(nWhich) || isTXTATR(nWhich),
1664 : "SwTxtNode::SetAttr(): unknown attribute" );
1665 9723 : if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
1666 : {
1667 9735 : if ((RES_TXTATR_CHARFMT == nWhich) &&
1668 12 : (GetDoc()->GetDfltCharFmt() ==
1669 12 : static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt()))
1670 : {
1671 0 : SwIndex aIndex( this, nStt );
1672 0 : RstAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
1673 0 : DontExpandFmt( aIndex );
1674 : }
1675 : else
1676 : {
1677 9723 : if (isCHRATR(nWhich) ||
1678 : (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1679 : {
1680 9201 : aCharSet.Put( *pItem );
1681 : }
1682 : else
1683 : {
1684 :
1685 522 : SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(),
1686 1044 : const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
1687 522 : if ( pNew )
1688 : {
1689 522 : if ( nEnd != nStt && !pNew->GetEnd() )
1690 : {
1691 : OSL_FAIL("Attribut without end, but area marked");
1692 0 : DestroyAttr( pNew ); // do not insert
1693 : }
1694 522 : else if ( InsertHint( pNew, nMode ) )
1695 : {
1696 522 : ++nCount;
1697 : }
1698 : }
1699 : }
1700 : }
1701 : }
1702 : }
1703 9723 : if ( aIter.IsAtEnd() )
1704 9723 : break;
1705 0 : pItem = aIter.NextItem();
1706 : } while( true );
1707 :
1708 9723 : if ( aCharSet.Count() )
1709 : {
1710 9201 : SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd );
1711 9201 : if ( InsertHint( pTmpNew, nMode ) )
1712 : {
1713 9201 : ++nCount;
1714 : }
1715 : }
1716 :
1717 9723 : TryDeleteSwpHints();
1718 :
1719 9723 : return nCount ? sal_True : sal_False;
1720 : }
1721 :
1722 0 : static void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1723 : {
1724 0 : if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
1725 : {
1726 0 : const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1727 0 : if ( !pCFSet )
1728 0 : return;
1729 0 : SfxWhichIter aIter( *pCFSet );
1730 0 : sal_uInt16 nWhich = aIter.FirstWhich();
1731 0 : while( nWhich )
1732 : {
1733 0 : if( ( nWhich < RES_CHRATR_END ||
1734 : RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
1735 0 : ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
1736 0 : rSet.Put( pCFSet->Get( nWhich ) );
1737 0 : nWhich = aIter.NextWhich();
1738 0 : }
1739 : }
1740 : else
1741 0 : rSet.Put( rAttr );
1742 : }
1743 :
1744 3872 : static void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1745 : {
1746 11574 : if( RES_TXTATR_CHARFMT == rAttr.Which() ||
1747 3855 : RES_TXTATR_INETFMT == rAttr.Which() ||
1748 3847 : RES_TXTATR_AUTOFMT == rAttr.Which() )
1749 : {
1750 3872 : const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1751 :
1752 3872 : if ( pCFSet )
1753 : {
1754 3872 : SfxWhichIter aIter( *pCFSet );
1755 3872 : sal_uInt16 nWhich = aIter.FirstWhich();
1756 170343 : while( nWhich )
1757 : {
1758 329045 : if( ( nWhich < RES_CHRATR_END ||
1759 7719 : ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
1760 158727 : ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
1761 17363 : rSet.Put( pCFSet->Get( nWhich ) );
1762 162599 : nWhich = aIter.NextWhich();
1763 3872 : }
1764 : }
1765 : }
1766 :
1767 : // aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
1768 :
1769 : /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
1770 : z.B
1771 : 1234567890123456789
1772 : |------------| Font1
1773 : |------| Font2
1774 : ^ ^
1775 : |--| Abfragebereich: -> Gueltig ist Font2
1776 : */
1777 3872 : rSet.Put( rAttr );
1778 3872 : }
1779 :
1780 : struct SwPoolItemEndPair
1781 : {
1782 : public:
1783 : const SfxPoolItem* mpItem;
1784 : xub_StrLen mnEndPos;
1785 :
1786 600 : SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
1787 : };
1788 :
1789 104 : static void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode,
1790 : SfxItemSet& rSet )
1791 : {
1792 104 : if ( rTxtNode.AreListLevelIndentsApplicable() )
1793 : {
1794 3 : const SwNumRule* pRule = rTxtNode.GetNumRule();
1795 3 : if ( pRule && rTxtNode.GetActualListLevel() >= 0 )
1796 : {
1797 3 : const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()));
1798 3 : if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1799 : {
1800 3 : SvxLRSpaceItem aLR( RES_LR_SPACE );
1801 3 : aLR.SetTxtLeft( rFmt.GetIndentAt() );
1802 3 : aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) );
1803 3 : rSet.Put( aLR );
1804 : }
1805 : }
1806 : }
1807 104 : }
1808 :
1809 : // erfrage die Attribute vom TextNode ueber den Bereich
1810 14442 : sal_Bool SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd,
1811 : sal_Bool bOnlyTxtAttr, sal_Bool bGetFromChrFmt,
1812 : const bool bMergeIndentValuesOfNumRule ) const
1813 : {
1814 14442 : if( HasHints() )
1815 : {
1816 : /* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
1817 : * sind. Dabei gibt es folgende Faelle:
1818 : * UnEindeutig wenn: (wenn != Format-Attribut)
1819 : * - das Attribut liegt vollstaendig im Bereich
1820 : * - das Attributende liegt im Bereich
1821 : * - der Attributanfang liegt im Bereich:
1822 : * Eindeutig (im Set mergen):
1823 : * - das Attrib umfasst den Bereich
1824 : * nichts tun:
1825 : * das Attribut liegt ausserhalb des Bereiches
1826 : */
1827 :
1828 : void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
1829 : = bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt
1830 4281 : : &lcl_MergeAttr;
1831 :
1832 : // dann besorge mal die Auto-(Fmt)Attribute
1833 4281 : SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
1834 4281 : if( !bOnlyTxtAttr )
1835 : {
1836 4276 : SwCntntNode::GetAttr( aFmtSet );
1837 4276 : if ( bMergeIndentValuesOfNumRule )
1838 : {
1839 51 : lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet );
1840 : }
1841 : }
1842 :
1843 4281 : const sal_uInt16 nSize = m_pSwpHints->Count();
1844 :
1845 4281 : if( nStt == nEnd ) // kein Bereich:
1846 : {
1847 117508 : for (sal_uInt16 n = 0; n < nSize; ++n)
1848 : {
1849 115816 : const SwTxtAttr* pHt = (*m_pSwpHints)[n];
1850 115816 : const xub_StrLen nAttrStart = *pHt->GetStart();
1851 115816 : if( nAttrStart > nEnd ) // ueber den Bereich hinaus
1852 30 : break;
1853 :
1854 115786 : const xub_StrLen* pAttrEnd = pHt->GetEnd();
1855 115786 : if ( ! pAttrEnd ) // no attributes without end
1856 114249 : continue;
1857 :
1858 2511 : if( ( nAttrStart < nStt &&
1859 974 : ( pHt->DontExpand() ? nStt < *pAttrEnd
1860 : : nStt <= *pAttrEnd )) ||
1861 : ( nStt == nAttrStart &&
1862 : ( nAttrStart == *pAttrEnd || !nStt )))
1863 1506 : (*fnMergeAttr)( rSet, pHt->GetAttr() );
1864 : }
1865 : }
1866 : else // es ist ein Bereich definiert
1867 : {
1868 : // #i75299#
1869 2559 : ::std::auto_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
1870 :
1871 : const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
1872 2559 : static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
1873 :
1874 6227 : for (sal_uInt16 n = 0; n < nSize; ++n)
1875 : {
1876 3677 : const SwTxtAttr* pHt = (*m_pSwpHints)[n];
1877 3677 : const xub_StrLen nAttrStart = *pHt->GetStart();
1878 3677 : if( nAttrStart > nEnd ) // ueber den Bereich hinaus
1879 9 : break;
1880 :
1881 3668 : const xub_StrLen* pAttrEnd = pHt->GetEnd();
1882 3668 : if ( ! pAttrEnd ) // no attributes without end
1883 154 : continue;
1884 :
1885 3514 : bool bChkInvalid = false;
1886 3514 : if( nAttrStart <= nStt ) // vor oder genau Start
1887 : {
1888 3443 : if( *pAttrEnd <= nStt ) // liegt davor
1889 1071 : continue;
1890 :
1891 2372 : if( nEnd <= *pAttrEnd ) // hinter oder genau Ende
1892 2366 : (*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
1893 : else
1894 : // else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
1895 : // uneindeutig
1896 6 : bChkInvalid = true;
1897 : }
1898 71 : else if( nAttrStart < nEnd // reicht in den Bereich
1899 : )// && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
1900 17 : bChkInvalid = true;
1901 :
1902 2443 : if( bChkInvalid )
1903 : {
1904 : // uneindeutig ?
1905 23 : ::std::auto_ptr< SfxItemIter > pItemIter;
1906 23 : const SfxPoolItem* pItem = 0;
1907 :
1908 23 : if ( RES_TXTATR_AUTOFMT == pHt->Which() )
1909 : {
1910 14 : const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() );
1911 14 : if ( pAutoSet )
1912 : {
1913 14 : pItemIter.reset( new SfxItemIter( *pAutoSet ) );
1914 14 : pItem = pItemIter->GetCurItem();
1915 : }
1916 : }
1917 : else
1918 9 : pItem = &pHt->GetAttr();
1919 :
1920 23 : const sal_uInt16 nHintEnd = *pAttrEnd;
1921 :
1922 77 : while ( pItem )
1923 : {
1924 31 : const sal_uInt16 nHintWhich = pItem->Which();
1925 : OSL_ENSURE(!isUNKNOWNATR(nHintWhich),
1926 : "SwTxtNode::GetAttr(): unknown attribute?");
1927 :
1928 31 : if ( !pAttrArr.get() )
1929 : {
1930 : pAttrArr.reset(
1931 12 : new std::vector< SwPoolItemEndPair >(coArrSz));
1932 : }
1933 :
1934 31 : std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
1935 40 : if (isCHRATR(nHintWhich) ||
1936 9 : isTXTATR_WITHEND(nHintWhich))
1937 : {
1938 31 : pPrev += nHintWhich - RES_CHRATR_BEGIN;
1939 : }
1940 : else
1941 : {
1942 0 : pPrev = pAttrArr->end();
1943 : }
1944 :
1945 31 : if( pPrev != pAttrArr->end() )
1946 : {
1947 31 : if( !pPrev->mpItem )
1948 : {
1949 21 : if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) )
1950 : {
1951 21 : if( nAttrStart > nStt )
1952 : {
1953 13 : rSet.InvalidateItem( nHintWhich );
1954 13 : pPrev->mpItem = (SfxPoolItem*)-1;
1955 : }
1956 : else
1957 : {
1958 8 : pPrev->mpItem = pItem;
1959 8 : pPrev->mnEndPos = nHintEnd;
1960 : }
1961 : }
1962 : }
1963 10 : else if( (SfxPoolItem*)-1 != pPrev->mpItem )
1964 : {
1965 13 : if( pPrev->mnEndPos == nAttrStart &&
1966 5 : *pPrev->mpItem == *pItem )
1967 : {
1968 2 : pPrev->mpItem = pItem;
1969 2 : pPrev->mnEndPos = nHintEnd;
1970 : }
1971 : else
1972 : {
1973 6 : rSet.InvalidateItem( nHintWhich );
1974 6 : pPrev->mpItem = (SfxPoolItem*)-1;
1975 : }
1976 : }
1977 : }
1978 :
1979 53 : pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
1980 53 : ? pItemIter->NextItem() : 0;
1981 23 : } // end while
1982 : }
1983 : }
1984 :
1985 2559 : if ( pAttrArr.get() )
1986 : {
1987 612 : for (sal_uInt16 n = 0; n < coArrSz; ++n)
1988 : {
1989 600 : const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
1990 600 : if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) )
1991 : {
1992 : const sal_uInt16 nWh =
1993 2 : static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
1994 :
1995 2 : if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
1996 : {
1997 0 : if( *rItemPair.mpItem != aFmtSet.Get( nWh ) )
1998 0 : (*fnMergeAttr)( rSet, *rItemPair.mpItem );
1999 : }
2000 : else
2001 : // uneindeutig
2002 2 : rSet.InvalidateItem( nWh );
2003 : }
2004 : }
2005 2559 : }
2006 : }
2007 4281 : if( aFmtSet.Count() )
2008 : {
2009 : // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
2010 1831 : aFmtSet.Differentiate( rSet );
2011 : // jetzt alle zusammen "mergen"
2012 1831 : rSet.Put( aFmtSet );
2013 4281 : }
2014 : }
2015 10161 : else if( !bOnlyTxtAttr )
2016 : {
2017 : // dann besorge mal die Auto-(Fmt)Attribute
2018 10161 : SwCntntNode::GetAttr( rSet );
2019 10161 : if ( bMergeIndentValuesOfNumRule )
2020 : {
2021 53 : lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
2022 : }
2023 : }
2024 :
2025 14442 : return rSet.Count() ? sal_True : sal_False;
2026 : }
2027 :
2028 :
2029 : namespace
2030 : {
2031 :
2032 : typedef std::pair<sal_uInt16, sal_uInt16> AttrSpan_t;
2033 : typedef std::multimap<AttrSpan_t, const SwTxtAttr*> AttrSpanMap_t;
2034 :
2035 :
2036 : struct IsAutoStyle
2037 : {
2038 : bool
2039 0 : operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2040 : const
2041 : {
2042 0 : return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
2043 : }
2044 : };
2045 :
2046 :
2047 : /** Removes from io_rAttrSet all items that are set by style on the
2048 : given span.
2049 : */
2050 : struct RemovePresentAttrs
2051 : {
2052 0 : RemovePresentAttrs(SfxItemSet& io_rAttrSet)
2053 0 : : m_rAttrSet(io_rAttrSet)
2054 : {
2055 0 : }
2056 :
2057 : void
2058 0 : operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2059 : const
2060 : {
2061 0 : if (!i_rAttrSpan.second)
2062 : {
2063 0 : return;
2064 : }
2065 :
2066 0 : const SwTxtAttr* const pAutoStyle(i_rAttrSpan.second);
2067 0 : SfxItemIter aIter(m_rAttrSet);
2068 0 : const SfxPoolItem* pItem(aIter.GetCurItem());
2069 0 : while (pItem)
2070 : {
2071 0 : const sal_uInt16 nWhich(pItem->Which());
2072 0 : if (CharFmt::IsItemIncluded(nWhich, pAutoStyle))
2073 : {
2074 0 : m_rAttrSet.ClearItem(nWhich);
2075 : }
2076 :
2077 0 : if (aIter.IsAtEnd())
2078 : {
2079 0 : break;
2080 : }
2081 0 : pItem = aIter.NextItem();
2082 0 : }
2083 : }
2084 :
2085 : private:
2086 : SfxItemSet& m_rAttrSet;
2087 : };
2088 :
2089 :
2090 : /** Collects all style-covered spans from i_rHints to o_rSpanMap. In
2091 : addition inserts dummy spans with pointer to format equal to 0 for
2092 : all gaps (i.e. spans not covered by any style). This simplifies
2093 : creation of autostyles for all needed spans, but it means all code
2094 : that tries to access the pointer has to check if it's non-null!
2095 : */
2096 : void
2097 0 : lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_uInt16 nLength,
2098 : AttrSpanMap_t& o_rSpanMap)
2099 : {
2100 0 : sal_uInt16 nLastEnd(0);
2101 :
2102 0 : for (sal_uInt16 i(0); i != i_rHints.Count(); ++i)
2103 : {
2104 0 : const SwTxtAttr* const pHint(i_rHints[i]);
2105 0 : const sal_uInt16 nWhich(pHint->Which());
2106 0 : if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
2107 : {
2108 0 : const AttrSpan_t aSpan(*pHint->GetStart(), *pHint->GetEnd());
2109 0 : o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint));
2110 :
2111 : // < not != because there may be multiple CHARFMT at same range
2112 0 : if (nLastEnd < aSpan.first)
2113 : {
2114 : // insert dummy span covering the gap
2115 : o_rSpanMap.insert(AttrSpanMap_t::value_type(
2116 0 : AttrSpan_t(nLastEnd, aSpan.first), (const SwTxtAttr *)0));
2117 : }
2118 :
2119 0 : nLastEnd = aSpan.second;
2120 : }
2121 : }
2122 :
2123 : // no hints at the end (special case: no hints at all in i_rHints)
2124 0 : if (nLastEnd != nLength && nLength != 0)
2125 : {
2126 : o_rSpanMap.insert(
2127 0 : AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), (const SwTxtAttr *)0));
2128 : }
2129 0 : }
2130 :
2131 :
2132 : void
2133 0 : lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
2134 : {
2135 0 : o_rClearIds.reserve(i_rAttrSet.Count());
2136 0 : SfxItemIter aIter(i_rAttrSet);
2137 0 : const SfxPoolItem* pItem(aIter.GetCurItem());
2138 0 : while (pItem)
2139 : {
2140 0 : o_rClearIds.push_back(pItem->Which());
2141 :
2142 0 : if (aIter.IsAtEnd())
2143 : {
2144 0 : break;
2145 : }
2146 0 : pItem = aIter.NextItem();
2147 0 : }
2148 0 : }
2149 :
2150 : struct SfxItemSetClearer
2151 : {
2152 : SfxItemSet & m_rItemSet;
2153 180 : SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
2154 0 : void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
2155 : };
2156 :
2157 : }
2158 :
2159 :
2160 : /** Does the hard work of SwTxtNode::FmtToTxtAttr: the real conversion
2161 : of items to automatic styles.
2162 : */
2163 : void
2164 1496 : SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet)
2165 : {
2166 : typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
2167 1496 : AttrSpanMap_t aAttrSpanMap;
2168 :
2169 1496 : if (i_rAttrSet.Count() == 0)
2170 : {
2171 1496 : return;
2172 : }
2173 :
2174 : // 1. Identify all spans in hints' array
2175 :
2176 0 : lcl_CollectHintSpans(*m_pSwpHints, m_Text.Len(), aAttrSpanMap);
2177 :
2178 : // 2. Go through all spans and insert new attrs
2179 :
2180 0 : AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
2181 0 : const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
2182 0 : while (aCurRange != aEnd)
2183 : {
2184 : typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
2185 : AttrSpanMapRange_t;
2186 0 : AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
2187 :
2188 : // 2a. Collect attributes to insert
2189 :
2190 0 : SfxItemSet aCurSet(i_rAttrSet);
2191 0 : std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
2192 :
2193 : // 2b. Insert automatic style containing the collected attributes
2194 :
2195 0 : if (aCurSet.Count() != 0)
2196 : {
2197 : AttrSpanMap_iterator_t aAutoStyleIt(
2198 0 : std::find_if(aRange.first, aRange.second, IsAutoStyle()));
2199 0 : if (aAutoStyleIt != aRange.second)
2200 : {
2201 : // there already is an automatic style on that span:
2202 : // create new one and remove the original one
2203 0 : SwTxtAttr* const pAutoStyle(const_cast<SwTxtAttr*>(aAutoStyleIt->second));
2204 : const boost::shared_ptr<SfxItemSet> pOldStyle(
2205 : static_cast<const SwFmtAutoFmt&>(
2206 0 : pAutoStyle->GetAttr()).GetStyleHandle());
2207 0 : aCurSet.Put(*pOldStyle);
2208 :
2209 : // remove the old hint
2210 0 : m_pSwpHints->Delete(pAutoStyle);
2211 0 : DestroyAttr(pAutoStyle);
2212 : }
2213 : m_pSwpHints->Insert(
2214 0 : MakeTxtAttr(*GetDoc(), aCurSet,
2215 0 : aCurRange->first.first, aCurRange->first.second));
2216 : }
2217 :
2218 0 : aCurRange = aRange.second;
2219 0 : }
2220 :
2221 : // 3. Clear items from the node
2222 0 : std::vector<sal_uInt16> aClearedIds;
2223 0 : lcl_FillWhichIds(i_rAttrSet, aClearedIds);
2224 0 : ClearItemsFromAttrSet(aClearedIds);
2225 : }
2226 :
2227 1496 : void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
2228 : {
2229 1496 : SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2230 1496 : if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
2231 6 : aThisSet.Put( *GetpSwAttrSet() );
2232 :
2233 1496 : GetOrCreateSwpHints();
2234 :
2235 1496 : if( pNd == this )
2236 : {
2237 1316 : impl_FmtToTxtAttr(aThisSet);
2238 : }
2239 : else
2240 : {
2241 : // There are five possible combinations of items from this and
2242 : // pNd (pNd is the 'main' node):
2243 : //
2244 : // case pNd this action
2245 : // ----------------------------------------------------
2246 : // 1 - - do nothing
2247 : // 2 - a convert item to attr of this
2248 : // 3 a - convert item to attr of pNd
2249 : // 4 a a clear item in this
2250 : // 5 a b convert item to attr of this
2251 :
2252 180 : SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
2253 180 : if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
2254 139 : aNdSet.Put( *pNd->GetpSwAttrSet() );
2255 :
2256 180 : pNd->GetOrCreateSwpHints();
2257 :
2258 180 : std::vector<sal_uInt16> aProcessedIds;
2259 :
2260 180 : if( aThisSet.Count() )
2261 : {
2262 0 : SfxItemIter aIter( aThisSet );
2263 0 : const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0;
2264 0 : SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2265 0 : std::vector<sal_uInt16> aClearWhichIds;
2266 :
2267 0 : while( true )
2268 : {
2269 0 : if( SFX_ITEM_SET == aNdSet.GetItemState( pItem->Which(), sal_False, &pNdItem ) )
2270 : {
2271 0 : if (*pItem == *pNdItem) // 4
2272 : {
2273 0 : aClearWhichIds.push_back( pItem->Which() );
2274 : }
2275 : else // 5
2276 : {
2277 0 : aConvertSet.Put(*pItem);
2278 : }
2279 0 : aProcessedIds.push_back(pItem->Which());
2280 : }
2281 : else // 2
2282 : {
2283 0 : aConvertSet.Put(*pItem);
2284 : }
2285 :
2286 0 : if( aIter.IsAtEnd() )
2287 0 : break;
2288 0 : pItem = aIter.NextItem();
2289 : }
2290 :
2291 : // 4/ clear items of this that are set with the same value on pNd
2292 0 : ClearItemsFromAttrSet( aClearWhichIds );
2293 :
2294 : // 2, 5/ convert all other items to attrs
2295 0 : impl_FmtToTxtAttr(aConvertSet);
2296 : }
2297 :
2298 : {
2299 : std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
2300 180 : SfxItemSetClearer(aNdSet));
2301 :
2302 : // 3/ convert items to attrs
2303 180 : pNd->impl_FmtToTxtAttr(aNdSet);
2304 :
2305 180 : if( aNdSet.Count() )
2306 : {
2307 0 : SwFmtChg aTmp1( pNd->GetFmtColl() );
2308 0 : pNd->NotifyClients( &aTmp1, &aTmp1 );
2309 : }
2310 180 : }
2311 : }
2312 :
2313 1496 : SetCalcHiddenCharFlags();
2314 :
2315 1496 : pNd->TryDeleteSwpHints();
2316 1496 : }
2317 :
2318 : /*************************************************************************
2319 : * SwpHints::CalcFlags()
2320 : *************************************************************************/
2321 :
2322 10078 : void SwpHints::CalcFlags()
2323 : {
2324 10078 : m_bDDEFields = m_bFootnote = false;
2325 10078 : const sal_uInt16 nSize = Count();
2326 : const SwTxtAttr* pAttr;
2327 189403 : for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2328 : {
2329 179325 : switch( ( pAttr = (*this)[ nPos ])->Which() )
2330 : {
2331 : case RES_TXTATR_FTN:
2332 10 : m_bFootnote = true;
2333 10 : if ( m_bDDEFields )
2334 0 : return;
2335 10 : break;
2336 : case RES_TXTATR_FIELD:
2337 : {
2338 122968 : const SwField* pFld = pAttr->GetFld().GetFld();
2339 122968 : if( RES_DDEFLD == pFld->GetTyp()->Which() )
2340 : {
2341 0 : m_bDDEFields = true;
2342 0 : if ( m_bFootnote )
2343 0 : return;
2344 : }
2345 : }
2346 122968 : break;
2347 : }
2348 : }
2349 : }
2350 :
2351 : /*************************************************************************
2352 : * SwpHints::CalcVisibleFlag()
2353 : *************************************************************************/
2354 :
2355 0 : bool SwpHints::CalcHiddenParaField()
2356 : {
2357 0 : m_bCalcHiddenParaField = false;
2358 0 : bool bOldHasHiddenParaField = m_bHasHiddenParaField;
2359 0 : bool bNewHasHiddenParaField = false;
2360 0 : const sal_uInt16 nSize = Count();
2361 : const SwTxtAttr *pTxtHt;
2362 :
2363 0 : for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2364 : {
2365 0 : pTxtHt = (*this)[ nPos ];
2366 0 : const sal_uInt16 nWhich = pTxtHt->Which();
2367 :
2368 0 : if( RES_TXTATR_FIELD == nWhich )
2369 : {
2370 0 : const SwFmtFld& rFld = pTxtHt->GetFld();
2371 0 : if( RES_HIDDENPARAFLD == rFld.GetFld()->GetTyp()->Which() )
2372 : {
2373 0 : if( !((SwHiddenParaField*)rFld.GetFld())->IsHidden() )
2374 : {
2375 0 : SetHiddenParaField(false);
2376 0 : return bOldHasHiddenParaField != bNewHasHiddenParaField;
2377 : }
2378 : else
2379 : {
2380 0 : bNewHasHiddenParaField = true;
2381 : }
2382 : }
2383 : }
2384 : }
2385 0 : SetHiddenParaField( bNewHasHiddenParaField );
2386 0 : return bOldHasHiddenParaField != bNewHasHiddenParaField;
2387 : }
2388 :
2389 :
2390 : /*************************************************************************
2391 : * SwpHints::NoteInHistory()
2392 : *************************************************************************/
2393 :
2394 24057 : void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew )
2395 : {
2396 24057 : if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
2397 24057 : }
2398 :
2399 : /*************************************************************************
2400 : * SwpHints::MergePortions( )
2401 : *************************************************************************/
2402 :
2403 10035 : bool SwpHints::MergePortions( SwTxtNode& rNode )
2404 : {
2405 10035 : if ( !Count() )
2406 0 : return false;
2407 :
2408 : // sort before merging
2409 10035 : SwpHintsArray::Resort();
2410 :
2411 10035 : bool bRet = false;
2412 : typedef std::multimap< int, SwTxtAttr* > PortionMap;
2413 10035 : PortionMap aPortionMap;
2414 10035 : xub_StrLen nLastPorStart = STRING_LEN;
2415 10035 : sal_uInt16 i = 0;
2416 10035 : int nKey = 0;
2417 :
2418 : // get portions by start position:
2419 87422 : for ( i = 0; i < Count(); ++i )
2420 : {
2421 77387 : SwTxtAttr *pHt = GetTextHint( i );
2422 154749 : if ( RES_TXTATR_CHARFMT != pHt->Which() &&
2423 77362 : RES_TXTATR_AUTOFMT != pHt->Which() )
2424 : //&&
2425 : //RES_TXTATR_INETFMT != pHt->Which() )
2426 14658 : continue;
2427 :
2428 62729 : const xub_StrLen nPorStart = *pHt->GetStart();
2429 62729 : if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN )
2430 52656 : ++nKey;
2431 62729 : nLastPorStart = nPorStart;
2432 62729 : aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) );
2433 : }
2434 :
2435 : // check if portion i can be merged with portion i+1:
2436 10035 : i = 0;
2437 10035 : int j = i + 1;
2438 83242 : while ( i <= nKey )
2439 : {
2440 63172 : std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
2441 63172 : std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
2442 63172 : PortionMap::iterator aIter1 = aRange1.first;
2443 63172 : PortionMap::iterator aIter2 = aRange2.first;
2444 :
2445 63172 : bool bMerge = true;
2446 63172 : const sal_uInt16 nAttributesInPor1 = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second ));
2447 63172 : const sal_uInt16 nAttributesInPor2 = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second ));
2448 :
2449 63172 : if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 )
2450 : {
2451 105727 : while ( aIter1 != aRange1.second )
2452 : {
2453 52623 : const SwTxtAttr* p1 = (*aIter1).second;
2454 52623 : const SwTxtAttr* p2 = (*aIter2).second;
2455 52623 : if ( *p1->GetEnd() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) )
2456 : {
2457 52142 : bMerge = false;
2458 52142 : break;
2459 : }
2460 481 : ++aIter1;
2461 481 : ++aIter2;
2462 52623 : }
2463 : }
2464 : else
2465 : {
2466 10549 : bMerge = false;
2467 : }
2468 :
2469 63172 : if ( bMerge )
2470 : {
2471 : // erase all elements with key i + 1
2472 481 : xub_StrLen nNewPortionEnd = 0;
2473 962 : for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
2474 : {
2475 481 : SwTxtAttr* p2 = (*aIter2).second;
2476 481 : nNewPortionEnd = *p2->GetEnd();
2477 :
2478 481 : const sal_uInt16 nCountBeforeDelete = Count();
2479 481 : Delete( p2 );
2480 :
2481 : // robust: check if deletion actually took place before destroying attribute:
2482 481 : if ( Count() < nCountBeforeDelete )
2483 481 : rNode.DestroyAttr( p2 );
2484 : }
2485 481 : aPortionMap.erase( aRange2.first, aRange2.second );
2486 481 : ++j;
2487 :
2488 : // change all attributes with key i
2489 481 : aRange1 = aPortionMap.equal_range( i );
2490 962 : for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
2491 : {
2492 481 : SwTxtAttr* p1 = (*aIter1).second;
2493 481 : NoteInHistory( p1 );
2494 481 : *p1->GetEnd() = nNewPortionEnd;
2495 481 : NoteInHistory( p1, true );
2496 481 : bRet = true;
2497 : }
2498 : }
2499 : else
2500 : {
2501 62691 : ++i;
2502 62691 : j = i + 1;
2503 : }
2504 : }
2505 :
2506 10035 : if ( bRet )
2507 : {
2508 481 : SwpHintsArray::Resort();
2509 : }
2510 :
2511 10035 : return bRet;
2512 : }
2513 :
2514 : // check if there is already a character format and adjust the sort numbers
2515 3 : static void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt )
2516 : {
2517 3 : const xub_StrLen nHtStart = *rNewCharFmt.GetStart();
2518 3 : const xub_StrLen nHtEnd = *rNewCharFmt.GetEnd();
2519 3 : sal_uInt16 nSortNumber = 0;
2520 :
2521 3 : for ( sal_uInt16 i = 0; i < rHints.Count(); ++i )
2522 : {
2523 3 : const SwTxtAttr* pOtherHt = rHints[i];
2524 :
2525 3 : const xub_StrLen nOtherStart = *pOtherHt->GetStart();
2526 :
2527 3 : if ( nOtherStart > nHtStart )
2528 3 : break;
2529 :
2530 0 : if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
2531 : {
2532 0 : const xub_StrLen nOtherEnd = *pOtherHt->GetEnd();
2533 :
2534 0 : if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
2535 : {
2536 0 : const sal_uInt16 nOtherSortNum = static_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber();
2537 0 : nSortNumber = nOtherSortNum + 1;
2538 : }
2539 : }
2540 : }
2541 :
2542 3 : if ( nSortNumber > 0 )
2543 0 : rNewCharFmt.SetSortNumber( nSortNumber );
2544 3 : }
2545 :
2546 : /*************************************************************************
2547 : * SwpHints::Insert()
2548 : *************************************************************************/
2549 :
2550 : /*
2551 : * Try to insert the new hint.
2552 : * Depending on the type of the hint, this either always succeeds, or may fail.
2553 : * Depending on the type of the hint, other hints may be deleted or
2554 : * overwritten.
2555 : * The return value indicates successful insertion.
2556 : */
2557 11174 : bool SwpHints::TryInsertHint( SwTxtAttr* const pHint, SwTxtNode &rNode,
2558 : const SetAttrMode nMode )
2559 : {
2560 11174 : if ( USHRT_MAX == Count() ) // we're sorry, this flight is overbooked...
2561 : {
2562 : OSL_FAIL("hints array full :-(");
2563 0 : return false;
2564 : }
2565 :
2566 : // Felder bilden eine Ausnahme:
2567 : // 1) Sie koennen nie ueberlappen
2568 : // 2) Wenn zwei Felder genau aneinander liegen,
2569 : // sollen sie nicht zu einem verschmolzen werden.
2570 : // Wir koennen also auf die while-Schleife verzichten
2571 :
2572 11174 : xub_StrLen *pHtEnd = pHint->GetEnd();
2573 11174 : sal_uInt16 nWhich = pHint->Which();
2574 :
2575 11174 : switch( nWhich )
2576 : {
2577 : case RES_TXTATR_CHARFMT:
2578 : {
2579 : // Check if character format contains hidden attribute:
2580 15 : const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt();
2581 : const SfxPoolItem* pItem;
2582 15 : if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
2583 0 : rNode.SetCalcHiddenCharFlags();
2584 :
2585 15 : ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode );
2586 : break;
2587 : }
2588 : // #i75430# Recalc hidden flags if necessary
2589 : case RES_TXTATR_AUTOFMT:
2590 : {
2591 : // Check if auto style contains hidden attribute:
2592 10462 : const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
2593 10462 : if ( pHiddenItem )
2594 1 : rNode.SetCalcHiddenCharFlags();
2595 10462 : break;
2596 : }
2597 : case RES_TXTATR_INETFMT:
2598 11 : static_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode);
2599 11 : break;
2600 : case RES_TXTATR_FIELD:
2601 : {
2602 491 : bool bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode();
2603 491 : ((SwTxtFld*)pHint)->ChgTxtNode( &rNode );
2604 491 : SwDoc* pDoc = rNode.GetDoc();
2605 491 : const SwField* pFld = ((SwTxtFld*)pHint)->GetFld().GetFld();
2606 :
2607 491 : if( !pDoc->IsNewFldLst() )
2608 : {
2609 : // was fuer ein Feld ist es denn ??
2610 : // bestimmte Felder mussen am Doc das Calculations-Flag updaten
2611 0 : switch( pFld->GetTyp()->Which() )
2612 : {
2613 : case RES_DBFLD:
2614 : case RES_SETEXPFLD:
2615 : case RES_HIDDENPARAFLD:
2616 : case RES_HIDDENTXTFLD:
2617 : case RES_DBNUMSETFLD:
2618 : case RES_DBNEXTSETFLD:
2619 : {
2620 0 : if( bDelFirst )
2621 0 : pDoc->InsDelFldInFldLst( false, *(SwTxtFld*)pHint );
2622 0 : if( rNode.GetNodes().IsDocNodes() )
2623 0 : pDoc->InsDelFldInFldLst( true, *(SwTxtFld*)pHint );
2624 : }
2625 0 : break;
2626 : case RES_DDEFLD:
2627 0 : if( rNode.GetNodes().IsDocNodes() )
2628 0 : ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2629 0 : break;
2630 : }
2631 : }
2632 :
2633 : // gehts ins normale Nodes-Array?
2634 491 : if( rNode.GetNodes().IsDocNodes() )
2635 : {
2636 491 : sal_Bool bInsFldType = sal_False;
2637 491 : switch( pFld->GetTyp()->Which() )
2638 : {
2639 : case RES_SETEXPFLD:
2640 1 : bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted();
2641 1 : if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() )
2642 : {
2643 : // bevor die ReferenzNummer gesetzt wird, sollte
2644 : // das Feld am richtigen FeldTypen haengen!
2645 : SwSetExpFieldType* pFldType = (SwSetExpFieldType*)
2646 0 : pDoc->InsertFldType( *pFld->GetTyp() );
2647 0 : if( pFldType != pFld->GetTyp() )
2648 : {
2649 : SwFmtFld* pFmtFld = (SwFmtFld*)&((SwTxtFld*)pHint)
2650 0 : ->GetFld();
2651 0 : pFmtFld->RegisterToFieldType( *pFldType );
2652 0 : pFmtFld->GetFld()->ChgTyp( pFldType );
2653 : }
2654 0 : pFldType->SetSeqRefNo( *(SwSetExpField*)pFld );
2655 : }
2656 1 : break;
2657 : case RES_USERFLD:
2658 0 : bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted();
2659 0 : break;
2660 :
2661 : case RES_DDEFLD:
2662 0 : if( pDoc->IsNewFldLst() )
2663 0 : ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2664 0 : bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted();
2665 0 : break;
2666 :
2667 : case RES_POSTITFLD:
2668 9 : if ( pDoc->GetDocShell() )
2669 9 : pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFld(), SWFMTFLD_INSERTED ) );
2670 9 : break;
2671 : }
2672 491 : if( bInsFldType )
2673 0 : pDoc->InsDeletedFldType( *pFld->GetTyp() );
2674 : }
2675 : }
2676 491 : break;
2677 : case RES_TXTATR_FTN :
2678 8 : ((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
2679 8 : break;
2680 : case RES_TXTATR_REFMARK:
2681 1 : ((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode );
2682 1 : if( rNode.GetNodes().IsDocNodes() )
2683 : {
2684 : // search for a reference with the same name
2685 : SwTxtAttr* pTmpHt;
2686 : xub_StrLen *pTmpHtEnd, *pTmpHintEnd;
2687 2 : for( sal_uInt16 n = 0, nEnd = Count(); n < nEnd; ++n )
2688 : {
2689 1 : if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
2690 0 : pHint->GetAttr() == pTmpHt->GetAttr() &&
2691 0 : 0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
2692 0 : 0 != ( pTmpHintEnd = pHint->GetEnd() ) )
2693 : {
2694 : SwComparePosition eCmp = ::ComparePosition(
2695 0 : *pTmpHt->GetStart(), *pTmpHtEnd,
2696 0 : *pHint->GetStart(), *pTmpHintEnd );
2697 0 : bool bDelOld = true, bChgStart = false, bChgEnd = false;
2698 0 : switch( eCmp )
2699 : {
2700 : case POS_BEFORE:
2701 0 : case POS_BEHIND: bDelOld = false; break;
2702 :
2703 0 : case POS_OUTSIDE: bChgStart = bChgEnd = true; break;
2704 :
2705 : case POS_COLLIDE_END:
2706 0 : case POS_OVERLAP_BEFORE: bChgStart = true; break;
2707 : case POS_COLLIDE_START:
2708 0 : case POS_OVERLAP_BEHIND: bChgEnd = true; break;
2709 0 : default: break;
2710 : }
2711 :
2712 0 : if( bChgStart )
2713 0 : *pHint->GetStart() = *pTmpHt->GetStart();
2714 0 : if( bChgEnd )
2715 0 : *pTmpHintEnd = *pTmpHtEnd;
2716 :
2717 0 : if( bDelOld )
2718 : {
2719 0 : NoteInHistory( pTmpHt );
2720 0 : rNode.DestroyAttr( Cut( n-- ) );
2721 0 : --nEnd;
2722 : }
2723 : }
2724 : }
2725 : }
2726 1 : break;
2727 : case RES_TXTATR_TOXMARK:
2728 0 : ((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode );
2729 0 : break;
2730 :
2731 : case RES_TXTATR_CJK_RUBY:
2732 0 : static_cast<SwTxtRuby*>(pHint)->InitRuby(rNode);
2733 0 : break;
2734 :
2735 : case RES_TXTATR_META:
2736 : case RES_TXTATR_METAFIELD:
2737 0 : static_cast<SwTxtMeta *>(pHint)->ChgTxtNode( &rNode );
2738 0 : break;
2739 :
2740 : case RES_CHRATR_HIDDEN:
2741 0 : rNode.SetCalcHiddenCharFlags();
2742 0 : break;
2743 : }
2744 :
2745 11174 : if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode )
2746 0 : pHint->SetDontExpand( sal_True );
2747 :
2748 : // SwTxtAttrs ohne Ende werden sonderbehandelt:
2749 : // Sie werden natuerlich in das Array insertet, aber sie werden nicht
2750 : // in die pPrev/Next/On/Off-Verkettung aufgenommen.
2751 : // Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text !
2752 11174 : xub_StrLen nHtStart = *pHint->GetStart();
2753 11174 : if( !pHtEnd )
2754 : {
2755 686 : SwpHintsArray::Insert( pHint );
2756 686 : CalcFlags();
2757 : #ifdef DBG_UTIL
2758 : if( !rNode.GetDoc()->IsInReading() )
2759 : CHECK;
2760 : #endif
2761 : // ... und die Abhaengigen benachrichtigen
2762 686 : if ( rNode.GetDepends() )
2763 : {
2764 496 : SwUpdateAttr aHint( nHtStart, nHtStart, nWhich );
2765 496 : rNode.ModifyNotification( 0, &aHint );
2766 : }
2767 686 : return true;
2768 : }
2769 :
2770 : // ----------------------------------------------------------------
2771 : // Ab hier gibt es nur noch pHint mit einem EndIdx !!!
2772 :
2773 10488 : if( *pHtEnd < nHtStart )
2774 : {
2775 : OSL_ENSURE( *pHtEnd >= nHtStart,
2776 : "+SwpHints::Insert: invalid hint, end < start" );
2777 :
2778 : // Wir drehen den Quatsch einfach um:
2779 0 : *pHint->GetStart() = *pHtEnd;
2780 0 : *pHtEnd = nHtStart;
2781 0 : nHtStart = *pHint->GetStart();
2782 : }
2783 :
2784 : // I need this value later on for notification but the pointer may become invalid
2785 10488 : const xub_StrLen nHintEnd = *pHtEnd;
2786 10488 : const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode);
2787 :
2788 : // handle nesting attributes: inserting may fail due to overlap!
2789 10488 : if (pHint->IsNesting())
2790 : {
2791 : const bool bRet(
2792 11 : TryInsertNesting(rNode, *static_cast<SwTxtAttrNesting*>(pHint)));
2793 11 : if (!bRet) return false;
2794 : }
2795 : // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
2796 : // These attributes may be inserted directly.
2797 : // Also attributes without length may be inserted directly.
2798 : // SETATTR_NOHINTADJUST is set e.g., during undo.
2799 : // Portion building in not necessary during XML import.
2800 30567 : else if ( !bNoHintAdjustMode &&
2801 10045 : !pHint->IsOverlapAllowedAttr() &&
2802 10045 : !rNode.GetDoc()->IsInXMLImport() &&
2803 : ( RES_TXTATR_AUTOFMT == nWhich ||
2804 : RES_TXTATR_CHARFMT == nWhich ) )
2805 : {
2806 : OSL_ENSURE( nWhich != RES_TXTATR_AUTOFMT ||
2807 : static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
2808 : &rNode.GetDoc()->GetAttrPool(),
2809 : "AUTOSTYLES - Pool mismatch" );
2810 :
2811 10042 : BuildPortions( rNode, *pHint, nMode );
2812 :
2813 10042 : if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
2814 9748 : MergePortions( rNode );
2815 : }
2816 : else
2817 : {
2818 : // There may be more than one character style at the current position.
2819 : // Take care of the sort number.
2820 : // Special case ruby portion: During import, the ruby attribute is set
2821 : // multiple times
2822 : // Special case hyperlink: During import, the ruby attribute is set
2823 : // multiple times
2824 : // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
2825 : // character attributes directly
2826 435 : if ( ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode ) )
2827 : {
2828 0 : BuildPortions( rNode, *pHint, nMode );
2829 : }
2830 : else
2831 : {
2832 : // #i82989# Check sort numbers in NoHintAdjustMode
2833 435 : if ( RES_TXTATR_CHARFMT == nWhich )
2834 3 : lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) );
2835 :
2836 435 : SwpHintsArray::Insert( pHint );
2837 435 : NoteInHistory( pHint, true );
2838 : }
2839 : }
2840 :
2841 : // ... und die Abhaengigen benachrichtigen
2842 10488 : if ( rNode.GetDepends() )
2843 : {
2844 7878 : SwUpdateAttr aHint( nHtStart, nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd, nWhich );
2845 7878 : rNode.ModifyNotification( 0, &aHint );
2846 : }
2847 :
2848 : #ifdef DBG_UTIL
2849 : if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
2850 : CHECK;
2851 : #endif
2852 :
2853 10488 : return true;
2854 : }
2855 :
2856 : /*************************************************************************
2857 : * SwpHints::DeleteAtPos()
2858 : *************************************************************************/
2859 :
2860 9392 : void SwpHints::DeleteAtPos( const sal_uInt16 nPos )
2861 : {
2862 9392 : SwTxtAttr *pHint = GetTextHint(nPos);
2863 : // ChainDelete( pHint );
2864 9392 : NoteInHistory( pHint );
2865 9392 : SwpHintsArray::DeleteAtPos( nPos );
2866 :
2867 9392 : if( RES_TXTATR_FIELD == pHint->Which() )
2868 : {
2869 2 : SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFld().GetFld()->GetTyp();
2870 2 : if( RES_DDEFLD == pFldTyp->Which() )
2871 : {
2872 0 : const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode();
2873 0 : if( pNd && pNd->GetNodes().IsDocNodes() )
2874 0 : ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
2875 0 : ((SwTxtFld*)pHint)->ChgTxtNode( 0 );
2876 : }
2877 2 : else if( RES_POSTITFLD == pFldTyp->Which() )
2878 : {
2879 2 : const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFld(), SWFMTFLD_REMOVED ) );
2880 : }
2881 0 : else if ( m_bHasHiddenParaField &&
2882 0 : RES_HIDDENPARAFLD == pFldTyp->Which() )
2883 : {
2884 0 : m_bCalcHiddenParaField = true;
2885 : }
2886 : }
2887 :
2888 9392 : CalcFlags();
2889 : CHECK;
2890 9392 : }
2891 :
2892 : // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
2893 : // Ist er nicht im Array, so gibt es ein OSL_ENSURE(!!
2894 :
2895 8645 : void SwpHints::Delete( SwTxtAttr* pTxtHt )
2896 : {
2897 : // Attr 2.0: SwpHintsArr::Delete( pTxtHt );
2898 8645 : const sal_uInt16 nPos = GetStartOf( pTxtHt );
2899 : OSL_ENSURE( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" );
2900 8645 : if( USHRT_MAX != nPos )
2901 8645 : DeleteAtPos( nPos );
2902 8645 : }
2903 :
2904 0 : void SwTxtNode::ClearSwpHintsArr( bool bDelFields )
2905 : {
2906 0 : if ( HasHints() )
2907 : {
2908 0 : sal_uInt16 nPos = 0;
2909 0 : while ( nPos < m_pSwpHints->Count() )
2910 : {
2911 0 : SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos );
2912 0 : bool bDel = false;
2913 :
2914 0 : switch( pDel->Which() )
2915 : {
2916 : case RES_TXTATR_FLYCNT:
2917 : case RES_TXTATR_FTN:
2918 0 : break;
2919 :
2920 : case RES_TXTATR_FIELD:
2921 0 : if( bDelFields )
2922 0 : bDel = true;
2923 0 : break;
2924 : default:
2925 0 : bDel = true; break;
2926 : }
2927 :
2928 0 : if( bDel )
2929 : {
2930 0 : m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
2931 0 : DestroyAttr( pDel );
2932 : }
2933 : else
2934 0 : ++nPos;
2935 : }
2936 : }
2937 0 : }
2938 :
2939 5221 : sal_uInt16 SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen,
2940 : sal_uInt16 nScript ) const
2941 : {
2942 5221 : sal_uInt16 nRet = LANGUAGE_DONTKNOW;
2943 :
2944 5221 : if ( ! nScript )
2945 : {
2946 1954 : nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin );
2947 : }
2948 :
2949 : // #i91465# Consider nScript if pSwpHints == 0
2950 5221 : const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
2951 :
2952 5221 : if ( HasHints() )
2953 : {
2954 3522 : const xub_StrLen nEnd = nBegin + nLen;
2955 7889 : for ( sal_uInt16 i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i )
2956 : {
2957 : // ist der Attribut-Anfang schon groesser als der Idx ?
2958 5068 : const SwTxtAttr *pHt = m_pSwpHints->operator[](i);
2959 5068 : const xub_StrLen nAttrStart = *pHt->GetStart();
2960 5068 : if( nEnd < nAttrStart )
2961 701 : break;
2962 :
2963 4367 : const sal_uInt16 nWhich = pHt->Which();
2964 :
2965 11599 : if( nWhichId == nWhich ||
2966 7232 : ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) )
2967 : {
2968 712 : const xub_StrLen *pEndIdx = pHt->GetEnd();
2969 : // Ueberlappt das Attribut den Bereich?
2970 :
2971 796 : if( pEndIdx &&
2972 : nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
2973 : : (( nAttrStart < nBegin &&
2974 84 : ( pHt->DontExpand() ? nBegin < *pEndIdx
2975 : : nBegin <= *pEndIdx )) ||
2976 : ( nBegin == nAttrStart &&
2977 : ( nAttrStart == *pEndIdx || !nBegin ))) )
2978 : {
2979 673 : const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId );
2980 673 : sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
2981 :
2982 : // Umfasst das Attribut den Bereich komplett?
2983 673 : if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
2984 673 : nRet = nLng;
2985 0 : else if( LANGUAGE_DONTKNOW == nRet )
2986 0 : nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
2987 : }
2988 : }
2989 : }
2990 : }
2991 5221 : if( LANGUAGE_DONTKNOW == nRet )
2992 : {
2993 4561 : nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
2994 4561 : if( LANGUAGE_DONTKNOW == nRet )
2995 0 : nRet = static_cast<sal_uInt16>(GetAppLanguage());
2996 : }
2997 5221 : return nRet;
2998 : }
2999 :
3000 :
3001 685 : sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
3002 : {
3003 685 : sal_Unicode cRet = CH_TXTATR_BREAKWORD;
3004 685 : switch ( rAttr.Which() )
3005 : {
3006 : case RES_TXTATR_REFMARK:
3007 : case RES_TXTATR_TOXMARK:
3008 1 : cRet = CH_TXTATR_INWORD;
3009 1 : break;
3010 :
3011 : case RES_TXTATR_FIELD:
3012 : case RES_TXTATR_FLYCNT:
3013 : case RES_TXTATR_FTN:
3014 : case RES_TXTATR_META:
3015 : case RES_TXTATR_METAFIELD:
3016 : {
3017 684 : cRet = CH_TXTATR_BREAKWORD;
3018 :
3019 : // #i78149: PostIt fields should not break words for spell and grammar checking
3020 1175 : if (rAttr.Which() == RES_TXTATR_FIELD &&
3021 491 : RES_POSTITFLD == rAttr.GetFld().GetFld()->GetTyp()->Which())
3022 9 : cRet = CH_TXTATR_INWORD;
3023 : }
3024 684 : break;
3025 :
3026 : default:
3027 : OSL_FAIL("GetCharOfTxtAttr: unknown attr");
3028 0 : break;
3029 : }
3030 685 : return cRet;
3031 : }
3032 :
3033 :
3034 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|