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