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