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 explicitly 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 to 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 successful
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(),
1684 *pAttr->GetEnd(),
1685 pAttr->Which());
1686
1687 m_pSwpHints->Delete( pAttr );
1688 SwTxtAttr::Destroy( pAttr, GetDoc()->GetAttrPool() );
1689 NotifyClients( 0, &aHint );
1690
1691 TryDeleteSwpHints();
1692 }
1693 }
1694
1695 /*************************************************************************
1696 * SwTxtNode::DeleteAttributes()
1697 *************************************************************************/
1698
1699 //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
DeleteAttributes(const sal_uInt16 nWhich,const xub_StrLen nStart,const xub_StrLen nEnd)1700 void SwTxtNode::DeleteAttributes(
1701 const sal_uInt16 nWhich,
1702 const xub_StrLen nStart,
1703 const xub_StrLen nEnd )
1704 {
1705 if ( !HasHints() )
1706 return;
1707
1708 for ( sal_uInt16 nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); nPos++ )
1709 {
1710 SwTxtAttr * const pTxtHt = m_pSwpHints->GetTextHint( nPos );
1711 const xub_StrLen nHintStart = *(pTxtHt->GetStart());
1712 if (nStart < nHintStart)
1713 {
1714 break; // sorted by start
1715 }
1716 else if ( (nStart == nHintStart) && (nWhich == pTxtHt->Which()) )
1717 {
1718 if ( nWhich == RES_CHRATR_HIDDEN )
1719 {
1720 ASSERT(false, "hey, that's a CHRATR! how did that get in?");
1721 SetCalcHiddenCharFlags();
1722 }
1723 else if ( nWhich == RES_TXTATR_CHARFMT )
1724 {
1725 // Check if character format contains hidden attribute:
1726 const SwCharFmt* pFmt = pTxtHt->GetCharFmt().GetCharFmt();
1727 const SfxPoolItem* pItem;
1728 if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
1729 SetCalcHiddenCharFlags();
1730 }
1731 // Recalc hidden flags if necessary
1732 else if ( nWhich == RES_TXTATR_AUTOFMT )
1733 {
1734 // Check if auto style contains hidden attribute:
1735 const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN );
1736 if ( pHiddenItem )
1737 SetCalcHiddenCharFlags();
1738 }
1739
1740 xub_StrLen const * const pEndIdx = pTxtHt->GetEnd();
1741
1742 if ( pTxtHt->HasDummyChar() )
1743 {
1744 // Unbedingt Copy-konstruieren!
1745 const SwIndex aIdx( this, nStart );
1746 // erase the CH_TXTATR, which will also delete pTxtHt
1747 EraseText( aIdx, 1 );
1748 }
1749 else if ( pTxtHt->HasContent() )
1750 {
1751 const SwIndex aIdx( this, nStart );
1752 ASSERT( pTxtHt->End() != NULL, "<SwTxtNode::DeleteAttributes(..)> - missing End() at <SwTxtAttr> instance which has content" );
1753 EraseText( aIdx, *pTxtHt->End() - nStart );
1754 }
1755 else if( *pEndIdx == nEnd )
1756 {
1757 // den MsgHint jetzt fuettern, weil gleich sind
1758 // Start und End weg.
1759 // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
1760 // da dies das Feld im Dtor selbst erledigt.
1761 SwUpdateAttr aHint(
1762 nStart,
1763 *pEndIdx,
1764 nWhich);
1765
1766 m_pSwpHints->DeleteAtPos( nPos ); // gefunden, loeschen,
1767 SwTxtAttr::Destroy( pTxtHt, GetDoc()->GetAttrPool() );
1768 NotifyClients( 0, &aHint );
1769 }
1770 }
1771 }
1772 TryDeleteSwpHints();
1773 }
1774
1775 /*************************************************************************
1776 * SwTxtNode::DelSoftHyph()
1777 *************************************************************************/
1778
DelSoftHyph(const xub_StrLen nStt,const xub_StrLen nEnd)1779 void SwTxtNode::DelSoftHyph( const xub_StrLen nStt, const xub_StrLen nEnd )
1780 {
1781 xub_StrLen nFndPos = nStt, nEndPos = nEnd;
1782 while( STRING_NOTFOUND !=
1783 ( nFndPos = m_Text.Search( CHAR_SOFTHYPHEN, nFndPos )) &&
1784 nFndPos < nEndPos )
1785 {
1786 const SwIndex aIdx( this, nFndPos );
1787 EraseText( aIdx, 1 );
1788 --nEndPos;
1789 }
1790 }
1791
1792 //Modify here for #119405, by easyfan, 2012-05-24
1793 //In MS Word, the font underline setting of the paragraph end position won't affect the formatting of numbering, escapement, etc, so we ignore them
lcl_IsIgnoredCharFmtForNumbering(const sal_uInt16 nWhich)1794 bool lcl_IsIgnoredCharFmtForNumbering(const sal_uInt16 nWhich)
1795 {
1796 return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_ESCAPEMENT);
1797 }
1798
1799 //In MS Word, following properties of the paragraph end position won't affect the formatting of bullets, so we ignore them:
1800 //Font underline;
1801 //Font Italic of Western, CJK and CTL;
1802 //Font Bold of Wertern, CJK and CTL;
lcl_IsIgnoredCharFmtForBullets(const sal_uInt16 nWhich)1803 bool lcl_IsIgnoredCharFmtForBullets(const sal_uInt16 nWhich)
1804 {
1805 return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_POSTURE || nWhich == RES_CHRATR_WEIGHT
1806 || nWhich == RES_CHRATR_CJK_POSTURE || nWhich == RES_CHRATR_CJK_WEIGHT
1807 || nWhich == RES_CHRATR_CTL_POSTURE || nWhich == RES_CHRATR_CTL_WEIGHT);
1808 }
1809
1810 //Condition for expanding char set to character style of specified number rule level:
1811 //The item inside the set should not conflict to any exist and non-default item inside paragraph properties set (SwCntntNode::SwPAttrSet);
1812 //The node should have applied a number rule;
1813 //The node should be counted in a list, if not, make it to be;
1814 //The item should not conflict to any exist and non-default item inside the character of specified number rule level;
1815 //The item should not be ignored depend on the exact number rule type;
TryCharSetExpandToNum(const SfxItemSet & aCharSet)1816 bool SwTxtNode::TryCharSetExpandToNum(const SfxItemSet& aCharSet)
1817 {
1818 bool bRet = false;
1819 SfxItemIter aIter( aCharSet );
1820 const SfxPoolItem* pItem = aIter.FirstItem();
1821 const sal_uInt16 nWhich = pItem->Which();
1822
1823 const SfxPoolItem& rInnerItem = GetAttr(nWhich,false);
1824
1825 if (!IsDefaultItem(&rInnerItem) && !IsInvalidItem(&rInnerItem))
1826 return bRet;
1827
1828 if ( !IsInList() && GetNumRule() && GetListId().Len() > 0 )
1829 {
1830 return bRet;
1831 }
1832
1833 SwNumRule* pCurrNum = GetNumRule(false);
1834
1835 int nLevel = GetActualListLevel();
1836
1837 if (nLevel != -1 && pCurrNum)
1838 {
1839 const SwNumFmt* pCurrNumFmt = pCurrNum->GetNumFmt(static_cast<sal_uInt16>(nLevel));
1840 if (pCurrNumFmt)
1841 {
1842 if (pCurrNumFmt->IsItemize() && lcl_IsIgnoredCharFmtForBullets(nWhich))
1843 return bRet;
1844 if (pCurrNumFmt->IsEnumeration() && lcl_IsIgnoredCharFmtForNumbering(nWhich))
1845 return bRet;
1846 SwCharFmt* pCurrCharFmt =pCurrNumFmt->GetCharFmt();
1847
1848 if (pCurrCharFmt && pCurrCharFmt->GetItemState(nWhich,false) != SFX_ITEM_SET)
1849 {
1850 pCurrCharFmt->SetFmtAttr(*pItem);
1851 SwNumFmt aNewNumFmt(*pCurrNumFmt);
1852 aNewNumFmt.SetCharFmt(pCurrCharFmt);
1853 pCurrNum->Set(nLevel,aNewNumFmt);
1854 bRet = true;
1855 }
1856 }
1857 }
1858
1859
1860 return bRet;
1861 }
1862 //End of modification, by easyfan
1863
1864 // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
1865 // dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr)
SetAttr(const SfxItemSet & rSet,const xub_StrLen nStt,const xub_StrLen nEnd,const SetAttrMode nMode)1866 sal_Bool SwTxtNode::SetAttr(
1867 const SfxItemSet& rSet,
1868 const xub_StrLen nStt,
1869 const xub_StrLen nEnd,
1870 const SetAttrMode nMode )
1871 {
1872 if( !rSet.Count() )
1873 return sal_False;
1874
1875 // teil die Sets auf (fuer Selektion in Nodes)
1876 const SfxItemSet* pSet = &rSet;
1877 SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
1878
1879 // gesamter Bereich
1880 if ( !nStt && (nEnd == m_Text.Len()) &&
1881 !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) )
1882 {
1883 // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
1884 // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
1885 int bHasCharFmts = sal_False;
1886 if ( HasHints() )
1887 {
1888 for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
1889 {
1890 if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() )
1891 {
1892 bHasCharFmts = sal_True;
1893 break;
1894 }
1895 }
1896 }
1897
1898 if( !bHasCharFmts )
1899 {
1900 aTxtSet.Put( rSet );
1901 // If there are any character attributes in rSet,
1902 // we want to set them at the paragraph:
1903 if( aTxtSet.Count() != rSet.Count() )
1904 {
1905 sal_Bool bRet = SetAttr( rSet );
1906 if( !aTxtSet.Count() )
1907 return bRet;
1908 }
1909
1910 // check for auto style:
1911 const SfxPoolItem* pItem;
1912 const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, sal_False, &pItem );
1913 if ( bAutoStyle )
1914 {
1915 boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle();
1916 sal_Bool bRet = SetAttr( *pAutoStyleSet );
1917 if( 1 == aTxtSet.Count() )
1918 return bRet;
1919 }
1920
1921 // Continue with the text attributes:
1922 pSet = &aTxtSet;
1923 }
1924 }
1925
1926 GetOrCreateSwpHints();
1927
1928 SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange );
1929
1930 sal_uInt16 nCount = 0;
1931 SfxItemIter aIter( *pSet );
1932 const SfxPoolItem* pItem = aIter.GetCurItem();
1933
1934 do
1935 {
1936 if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
1937 {
1938 const sal_uInt16 nWhich = pItem->Which();
1939 ASSERT( isCHRATR(nWhich) || isTXTATR(nWhich),
1940 "SwTxtNode::SetAttr(): unknown attribute" );
1941 if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
1942 {
1943 if ((RES_TXTATR_CHARFMT == nWhich) &&
1944 (GetDoc()->GetDfltCharFmt() ==
1945 static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt()))
1946 {
1947 SwIndex aIndex( this, nStt );
1948 RstTxtAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
1949 DontExpandFmt( aIndex );
1950 }
1951 else
1952 {
1953 if (isCHRATR(nWhich) ||
1954 (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1955 {
1956 aCharSet.Put( *pItem );
1957 }
1958 else
1959 {
1960
1961 SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(),
1962 const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
1963 if ( pNew )
1964 {
1965 if ( nEnd != nStt && !pNew->GetEnd() )
1966 {
1967 ASSERT(false,
1968 "Attribut without end, but area marked");
1969 DestroyAttr( pNew ); // do not insert
1970 }
1971 else if ( InsertHint( pNew, nMode ) )
1972 {
1973 ++nCount;
1974 }
1975 }
1976 }
1977 }
1978 }
1979 }
1980 if ( aIter.IsAtEnd() )
1981 break;
1982 pItem = aIter.NextItem();
1983 } while( true );
1984
1985 if ( aCharSet.Count() )
1986 {
1987 SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd );
1988 if ( InsertHint( pTmpNew, nMode ) )
1989 {
1990 ++nCount;
1991 }
1992 }
1993
1994 TryDeleteSwpHints();
1995
1996 return nCount ? sal_True : sal_False;
1997 }
1998
lcl_MergeAttr(SfxItemSet & rSet,const SfxPoolItem & rAttr)1999 void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
2000 {
2001 if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
2002 {
2003 const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
2004 if ( !pCFSet )
2005 return;
2006 SfxWhichIter aIter( *pCFSet );
2007 sal_uInt16 nWhich = aIter.FirstWhich();
2008 while( nWhich )
2009 {
2010 if( ( nWhich < RES_CHRATR_END ||
2011 RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
2012 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
2013 rSet.Put( pCFSet->Get( nWhich ) );
2014 nWhich = aIter.NextWhich();
2015 }
2016 }
2017 else
2018 rSet.Put( rAttr );
2019 }
2020
lcl_MergeAttr_ExpandChrFmt(SfxItemSet & rSet,const SfxPoolItem & rAttr)2021 void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
2022 {
2023 if( RES_TXTATR_CHARFMT == rAttr.Which() ||
2024 RES_TXTATR_INETFMT == rAttr.Which() ||
2025 RES_TXTATR_AUTOFMT == rAttr.Which() )
2026 {
2027 const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
2028
2029 if ( pCFSet )
2030 {
2031 SfxWhichIter aIter( *pCFSet );
2032 sal_uInt16 nWhich = aIter.FirstWhich();
2033 while( nWhich )
2034 {
2035 if( ( nWhich < RES_CHRATR_END ||
2036 ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
2037 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
2038 rSet.Put( pCFSet->Get( nWhich ) );
2039 nWhich = aIter.NextWhich();
2040 }
2041 }
2042 }
2043
2044 // aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
2045
2046 /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
2047 z.B
2048 1234567890123456789
2049 |------------| Font1
2050 |------| Font2
2051 ^ ^
2052 |--| Abfragebereich: -> Gueltig ist Font2
2053 */
2054 rSet.Put( rAttr );
2055 }
2056
2057 struct SwPoolItemEndPair
2058 {
2059 public:
2060 const SfxPoolItem* mpItem;
2061 xub_StrLen mnEndPos;
2062
SwPoolItemEndPairSwPoolItemEndPair2063 SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
2064 };
2065
2066 // --> OD 2008-01-16 #newlistlevelattrs#
lcl_MergeListLevelIndentAsLRSpaceItem(const SwTxtNode & rTxtNode,SfxItemSet & rSet)2067 void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode,
2068 SfxItemSet& rSet )
2069 {
2070 if ( rTxtNode.AreListLevelIndentsApplicable() )
2071 {
2072 const SwNumRule* pRule = rTxtNode.GetNumRule();
2073 if ( pRule && rTxtNode.GetActualListLevel() >= 0 )
2074 {
2075 const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()));
2076 if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
2077 {
2078 SvxLRSpaceItem aLR( RES_LR_SPACE );
2079 aLR.SetTxtLeft( rFmt.GetIndentAt() );
2080 aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) );
2081 rSet.Put( aLR );
2082 }
2083 }
2084 }
2085 }
2086
2087 // erfrage die Attribute vom TextNode ueber den Bereich
2088 // --> OD 2008-01-16 #newlistlevelattrs#
GetAttr(SfxItemSet & rSet,xub_StrLen nStt,xub_StrLen nEnd,sal_Bool bOnlyTxtAttr,sal_Bool bGetFromChrFmt,const bool bMergeIndentValuesOfNumRule) const2089 sal_Bool SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd,
2090 sal_Bool bOnlyTxtAttr, sal_Bool bGetFromChrFmt,
2091 const bool bMergeIndentValuesOfNumRule ) const
2092 {
2093 if( HasHints() )
2094 {
2095 /* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
2096 * sind. Dabei gibt es folgende Faelle:
2097 * UnEindeutig wenn: (wenn != Format-Attribut)
2098 * - das Attribut liegt vollstaendig im Bereich
2099 * - das Attributende liegt im Bereich
2100 * - der Attributanfang liegt im Bereich:
2101 * Eindeutig (im Set mergen):
2102 * - das Attrib umfasst den Bereich
2103 * nichts tun:
2104 * das Attribut liegt ausserhalb des Bereiches
2105 */
2106
2107 void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
2108 = bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt
2109 : &lcl_MergeAttr;
2110
2111 // dann besorge mal die Auto-(Fmt)Attribute
2112 SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
2113 if( !bOnlyTxtAttr )
2114 {
2115 SwCntntNode::GetAttr( aFmtSet );
2116 // --> OD 2008-01-16 #newlistlevelattrs#
2117 if ( bMergeIndentValuesOfNumRule )
2118 {
2119 lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet );
2120 }
2121 // <--
2122 }
2123
2124 const sal_uInt16 nSize = m_pSwpHints->Count();
2125
2126 if( nStt == nEnd ) // kein Bereich:
2127 {
2128 for (sal_uInt16 n = 0; n < nSize; ++n)
2129 {
2130 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
2131 const xub_StrLen nAttrStart = *pHt->GetStart();
2132 if( nAttrStart > nEnd ) // ueber den Bereich hinaus
2133 break;
2134
2135 const xub_StrLen* pAttrEnd = pHt->End();
2136 if ( ! pAttrEnd ) // no attributes without end
2137 continue;
2138
2139 if( ( nAttrStart < nStt &&
2140 ( pHt->DontExpand() ? nStt < *pAttrEnd
2141 : nStt <= *pAttrEnd )) ||
2142 ( nStt == nAttrStart &&
2143 ( nAttrStart == *pAttrEnd || !nStt )))
2144 (*fnMergeAttr)( rSet, pHt->GetAttr() );
2145 }
2146 }
2147 else // es ist ein Bereich definiert
2148 {
2149 // --> FME 2007-03-13 #i75299#
2150 ::std::auto_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
2151 // <--
2152
2153 const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
2154 static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
2155
2156 for (sal_uInt16 n = 0; n < nSize; ++n)
2157 {
2158 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
2159 const xub_StrLen nAttrStart = *pHt->GetStart();
2160 if( nAttrStart > nEnd ) // ueber den Bereich hinaus
2161 break;
2162
2163 const xub_StrLen* pAttrEnd = pHt->End();
2164 if ( ! pAttrEnd ) // no attributes without end
2165 continue;
2166
2167 sal_Bool bChkInvalid = sal_False;
2168 if( nAttrStart <= nStt ) // vor oder genau Start
2169 {
2170 if( *pAttrEnd <= nStt ) // liegt davor
2171 continue;
2172
2173 if( nEnd <= *pAttrEnd ) // hinter oder genau Ende
2174 (*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
2175 else
2176 // else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
2177 // uneindeutig
2178 bChkInvalid = sal_True;
2179 }
2180 else if( nAttrStart < nEnd // reicht in den Bereich
2181 )// && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
2182 bChkInvalid = sal_True;
2183
2184 if( bChkInvalid )
2185 {
2186 // uneindeutig ?
2187 ::std::auto_ptr< SfxItemIter > pItemIter;
2188 const SfxPoolItem* pItem = 0;
2189
2190 if ( RES_TXTATR_AUTOFMT == pHt->Which() )
2191 {
2192 const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() );
2193 if ( pAutoSet )
2194 {
2195 pItemIter.reset( new SfxItemIter( *pAutoSet ) );
2196 pItem = pItemIter->GetCurItem();
2197 }
2198 }
2199 else
2200 pItem = &pHt->GetAttr();
2201
2202 const sal_uInt16 nHintEnd = *pAttrEnd;
2203
2204 while ( pItem )
2205 {
2206 const sal_uInt16 nHintWhich = pItem->Which();
2207 ASSERT(!isUNKNOWNATR(nHintWhich),
2208 "SwTxtNode::GetAttr(): unknown attribute?");
2209
2210 if ( !pAttrArr.get() )
2211 {
2212 pAttrArr.reset(
2213 new std::vector< SwPoolItemEndPair >(coArrSz));
2214 }
2215
2216 std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
2217 if (isCHRATR(nHintWhich) ||
2218 isTXTATR_WITHEND(nHintWhich))
2219 {
2220 pPrev += nHintWhich - RES_CHRATR_BEGIN;
2221 }
2222 else
2223 {
2224 pPrev = pAttrArr->end();
2225 }
2226
2227 #if OSL_DEBUG_LEVEL > 1
2228 SwPoolItemEndPair aTmp = *pPrev;
2229 #endif
2230
2231 if( pPrev != pAttrArr->end() )
2232 {
2233 if( !pPrev->mpItem )
2234 {
2235 if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) )
2236 {
2237 if( nAttrStart > nStt )
2238 {
2239 rSet.InvalidateItem( nHintWhich );
2240 pPrev->mpItem = (SfxPoolItem*)-1;
2241 }
2242 else
2243 {
2244 pPrev->mpItem = pItem;
2245 pPrev->mnEndPos = nHintEnd;
2246 }
2247 }
2248 }
2249 else if( (SfxPoolItem*)-1 != pPrev->mpItem )
2250 {
2251 if( pPrev->mnEndPos == nAttrStart &&
2252 *pPrev->mpItem == *pItem )
2253 {
2254 pPrev->mpItem = pItem;
2255 pPrev->mnEndPos = nHintEnd;
2256 }
2257 else
2258 {
2259 rSet.InvalidateItem( nHintWhich );
2260 pPrev->mpItem = (SfxPoolItem*)-1;
2261 }
2262 }
2263 }
2264
2265 pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
2266 ? pItemIter->NextItem() : 0;
2267 } // end while
2268 }
2269 }
2270
2271 if ( pAttrArr.get() )
2272 {
2273 for (sal_uInt16 n = 0; n < coArrSz; ++n)
2274 {
2275 const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
2276 if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) )
2277 {
2278 const sal_uInt16 nWh =
2279 static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
2280
2281 if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
2282 {
2283 if( *rItemPair.mpItem != aFmtSet.Get( nWh ) )
2284 (*fnMergeAttr)( rSet, *rItemPair.mpItem );
2285 }
2286 else
2287 // uneindeutig
2288 rSet.InvalidateItem( nWh );
2289 }
2290 }
2291 }
2292 }
2293 if( aFmtSet.Count() )
2294 {
2295 // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
2296 aFmtSet.Differentiate( rSet );
2297 // jetzt alle zusammen "mergen"
2298 rSet.Put( aFmtSet );
2299 }
2300 }
2301 else if( !bOnlyTxtAttr )
2302 {
2303 // dann besorge mal die Auto-(Fmt)Attribute
2304 SwCntntNode::GetAttr( rSet );
2305 // --> OD 2008-01-16 #newlistlevelattrs#
2306 if ( bMergeIndentValuesOfNumRule )
2307 {
2308 lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
2309 }
2310 // <--
2311 }
2312
2313 return rSet.Count() ? sal_True : sal_False;
2314 }
2315
2316
2317 namespace
2318 {
2319
2320 typedef std::pair<sal_uInt16, sal_uInt16> AttrSpan_t;
2321 typedef std::multimap<AttrSpan_t, const SwTxtAttr*> AttrSpanMap_t;
2322
2323
2324 struct IsAutoStyle
2325 {
2326 bool
operator ()__anond32bdb4f0111::IsAutoStyle2327 operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2328 const
2329 {
2330 return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
2331 }
2332 };
2333
2334
2335 /** Removes from io_rAttrSet all items that are set by style on the
2336 given span.
2337 */
2338 struct RemovePresentAttrs
2339 {
RemovePresentAttrs__anond32bdb4f0111::RemovePresentAttrs2340 RemovePresentAttrs(SfxItemSet& io_rAttrSet)
2341 : m_rAttrSet(io_rAttrSet)
2342 {
2343 }
2344
2345 void
operator ()__anond32bdb4f0111::RemovePresentAttrs2346 operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2347 const
2348 {
2349 if (!i_rAttrSpan.second)
2350 {
2351 return;
2352 }
2353
2354 const SwTxtAttr* const pAutoStyle(i_rAttrSpan.second);
2355 SfxItemIter aIter(m_rAttrSet);
2356 const SfxPoolItem* pItem(aIter.GetCurItem());
2357 while (pItem)
2358 {
2359 const sal_uInt16 nWhich(pItem->Which());
2360 if (CharFmt::IsItemIncluded(nWhich, pAutoStyle))
2361 {
2362 m_rAttrSet.ClearItem(nWhich);
2363 }
2364
2365 if (aIter.IsAtEnd())
2366 {
2367 break;
2368 }
2369 pItem = aIter.NextItem();
2370 }
2371 }
2372
2373 private:
2374 SfxItemSet& m_rAttrSet;
2375 };
2376
2377
2378 /** Collects all style-covered spans from i_rHints to o_rSpanMap. In
2379 addition inserts dummy spans with pointer to format equal to 0 for
2380 all gaps (i.e. spans not covered by any style). This simplifies
2381 creation of autostyles for all needed spans, but it means all code
2382 that tries to access the pointer has to check if it's non-null!
2383 */
2384 void
lcl_CollectHintSpans(const SwpHints & i_rHints,const sal_uInt16 nLength,AttrSpanMap_t & o_rSpanMap)2385 lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_uInt16 nLength,
2386 AttrSpanMap_t& o_rSpanMap)
2387 {
2388 sal_uInt16 nLastEnd(0);
2389
2390 for (sal_uInt16 i(0); i != i_rHints.Count(); ++i)
2391 {
2392 const SwTxtAttr* const pHint(i_rHints[i]);
2393 const sal_uInt16 nWhich(pHint->Which());
2394 if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
2395 {
2396 const AttrSpan_t aSpan(*pHint->GetStart(), *pHint->End());
2397 o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint));
2398
2399 // < not != because there may be multiple CHARFMT at same range
2400 if (nLastEnd < aSpan.first)
2401 {
2402 // insert dummy span covering the gap
2403 o_rSpanMap.insert(AttrSpanMap_t::value_type(
2404 AttrSpan_t(nLastEnd, aSpan.first), 0));
2405 }
2406
2407 nLastEnd = aSpan.second;
2408 }
2409 }
2410
2411 // no hints at the end (special case: no hints at all in i_rHints)
2412 if (nLastEnd != nLength && nLength != 0)
2413 {
2414 o_rSpanMap.insert(
2415 AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), 0));
2416 }
2417 }
2418
2419
2420 void
lcl_FillWhichIds(const SfxItemSet & i_rAttrSet,std::vector<sal_uInt16> & o_rClearIds)2421 lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
2422 {
2423 o_rClearIds.reserve(i_rAttrSet.Count());
2424 SfxItemIter aIter(i_rAttrSet);
2425 const SfxPoolItem* pItem(aIter.GetCurItem());
2426 while (true)
2427 {
2428 o_rClearIds.push_back(pItem->Which());
2429
2430 if (aIter.IsAtEnd())
2431 {
2432 break;
2433 }
2434 pItem = aIter.NextItem();
2435 }
2436 }
2437
2438 struct SfxItemSetClearer
2439 {
2440 SfxItemSet & m_rItemSet;
SfxItemSetClearer__anond32bdb4f0111::SfxItemSetClearer2441 SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
operator ()__anond32bdb4f0111::SfxItemSetClearer2442 void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
2443 };
2444
2445 }
2446
2447
2448 /** Does the hard work of SwTxtNode::FmtToTxtAttr: the real conversion
2449 of items to automatic styles.
2450 */
2451 void
impl_FmtToTxtAttr(const SfxItemSet & i_rAttrSet)2452 SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet)
2453 {
2454 typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
2455 AttrSpanMap_t aAttrSpanMap;
2456
2457 if (i_rAttrSet.Count() == 0)
2458 {
2459 return;
2460 }
2461
2462 // 1. Identify all spans in hints' array
2463
2464 lcl_CollectHintSpans(*m_pSwpHints, m_Text.Len(), aAttrSpanMap);
2465
2466 // 2. Go through all spans and insert new attrs
2467
2468 AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
2469 const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
2470 while (aCurRange != aEnd)
2471 {
2472 typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
2473 AttrSpanMapRange_t;
2474 AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
2475
2476 // 2a. Collect attributes to insert
2477
2478 SfxItemSet aCurSet(i_rAttrSet);
2479 std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
2480
2481 // 2b. Insert automatic style containing the collected attributes
2482
2483 if (aCurSet.Count() != 0)
2484 {
2485 AttrSpanMap_iterator_t aAutoStyleIt(
2486 std::find_if(aRange.first, aRange.second, IsAutoStyle()));
2487 if (aAutoStyleIt != aRange.second)
2488 {
2489 // there already is an automatic style on that span:
2490 // create new one and remove the original one
2491 SwTxtAttr* const pAutoStyle(const_cast<SwTxtAttr*>(aAutoStyleIt->second));
2492 const boost::shared_ptr<SfxItemSet> pOldStyle(
2493 static_cast<const SwFmtAutoFmt&>(
2494 pAutoStyle->GetAttr()).GetStyleHandle());
2495 aCurSet.Put(*pOldStyle);
2496
2497 // remove the old hint
2498 m_pSwpHints->Delete(pAutoStyle);
2499 DestroyAttr(pAutoStyle);
2500 }
2501 m_pSwpHints->Insert(
2502 MakeTxtAttr(*GetDoc(), aCurSet,
2503 aCurRange->first.first, aCurRange->first.second));
2504 }
2505
2506 aCurRange = aRange.second;
2507 }
2508
2509 // 3. Clear items from the node
2510 std::vector<sal_uInt16> aClearedIds;
2511 lcl_FillWhichIds(i_rAttrSet, aClearedIds);
2512 ClearItemsFromAttrSet(aClearedIds);
2513 }
2514
FmtToTxtAttr(SwTxtNode * pNd)2515 void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
2516 {
2517 SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2518 if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
2519 aThisSet.Put( *GetpSwAttrSet() );
2520
2521 GetOrCreateSwpHints();
2522
2523 if( pNd == this )
2524 {
2525 impl_FmtToTxtAttr(aThisSet);
2526 }
2527 else
2528 {
2529 // There are five possible combinations of items from this and
2530 // pNd (pNd is the 'main' node):
2531 //
2532 // case pNd this action
2533 // ----------------------------------------------------
2534 // 1 - - do nothing
2535 // 2 - a convert item to attr of this
2536 // 3 a - convert item to attr of pNd
2537 // 4 a a clear item in this
2538 // 5 a b convert item to attr of this
2539
2540 SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
2541 if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
2542 aNdSet.Put( *pNd->GetpSwAttrSet() );
2543
2544 pNd->GetOrCreateSwpHints();
2545
2546 std::vector<sal_uInt16> aProcessedIds;
2547
2548 if( aThisSet.Count() )
2549 {
2550 SfxItemIter aIter( aThisSet );
2551 const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0;
2552 SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2553 std::vector<sal_uInt16> aClearWhichIds;
2554
2555 while( true )
2556 {
2557 if( SFX_ITEM_SET == aNdSet.GetItemState( pItem->Which(), sal_False, &pNdItem ) )
2558 {
2559 if (*pItem == *pNdItem) // 4
2560 {
2561 aClearWhichIds.push_back( pItem->Which() );
2562 }
2563 else // 5
2564 {
2565 aConvertSet.Put(*pItem);
2566 }
2567 aProcessedIds.push_back(pItem->Which());
2568 }
2569 else // 2
2570 {
2571 aConvertSet.Put(*pItem);
2572 }
2573
2574 if( aIter.IsAtEnd() )
2575 break;
2576 pItem = aIter.NextItem();
2577 }
2578
2579 // 4/ clear items of this that are set with the same value on pNd
2580 ClearItemsFromAttrSet( aClearWhichIds );
2581
2582 // 2, 5/ convert all other items to attrs
2583 impl_FmtToTxtAttr(aConvertSet);
2584 }
2585
2586 {
2587 std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
2588 SfxItemSetClearer(aNdSet));
2589
2590 // 3/ convert items to attrs
2591 pNd->impl_FmtToTxtAttr(aNdSet);
2592
2593 if( aNdSet.Count() )
2594 {
2595 SwFmtChg aTmp1( pNd->GetFmtColl() );
2596 pNd->NotifyClients( &aTmp1, &aTmp1 );
2597 }
2598 }
2599 }
2600
2601 SetCalcHiddenCharFlags();
2602
2603 pNd->TryDeleteSwpHints();
2604 }
2605
2606 /*************************************************************************
2607 * SwpHints::CalcFlags()
2608 *************************************************************************/
2609
CalcFlags()2610 void SwpHints::CalcFlags()
2611 {
2612 m_bDDEFields = m_bFootnote = false;
2613 const sal_uInt16 nSize = Count();
2614 const SwTxtAttr* pAttr;
2615 for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2616 {
2617 switch( ( pAttr = (*this)[ nPos ])->Which() )
2618 {
2619 case RES_TXTATR_FTN:
2620 m_bFootnote = true;
2621 if ( m_bDDEFields )
2622 return;
2623 break;
2624 case RES_TXTATR_FIELD:
2625 {
2626 const SwField* pFld = pAttr->GetFmtFld().GetField();
2627 if( RES_DDEFLD == pFld->GetTyp()->Which() )
2628 {
2629 m_bDDEFields = true;
2630 if ( m_bFootnote )
2631 return;
2632 }
2633 }
2634 break;
2635 }
2636 }
2637 }
2638
2639 /*************************************************************************
2640 * SwpHints::CalcVisibleFlag()
2641 *************************************************************************/
2642
CalcHiddenParaField()2643 bool SwpHints::CalcHiddenParaField()
2644 {
2645 m_bCalcHiddenParaField = false;
2646 bool bOldHasHiddenParaField = m_bHasHiddenParaField;
2647 bool bNewHasHiddenParaField = false;
2648 const sal_uInt16 nSize = Count();
2649 const SwTxtAttr *pTxtHt;
2650
2651 for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2652 {
2653 pTxtHt = (*this)[ nPos ];
2654 const sal_uInt16 nWhich = pTxtHt->Which();
2655
2656 if( RES_TXTATR_FIELD == nWhich )
2657 {
2658 const SwFmtFld& rFld = pTxtHt->GetFmtFld();
2659 if( RES_HIDDENPARAFLD == rFld.GetField()->GetTyp()->Which() )
2660 {
2661 if( !((SwHiddenParaField*)rFld.GetField())->IsHidden() )
2662 {
2663 SetHiddenParaField(false);
2664 return bOldHasHiddenParaField != bNewHasHiddenParaField;
2665 }
2666 else
2667 {
2668 bNewHasHiddenParaField = true;
2669 }
2670 }
2671 }
2672 }
2673 SetHiddenParaField( bNewHasHiddenParaField );
2674 return bOldHasHiddenParaField != bNewHasHiddenParaField;
2675 }
2676
2677
2678 /*************************************************************************
2679 * SwpHints::NoteInHistory()
2680 *************************************************************************/
2681
NoteInHistory(SwTxtAttr * pAttr,const bool bNew)2682 void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew )
2683 {
2684 if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
2685 }
2686
2687 /*************************************************************************
2688 * SwpHints::MergePortions( )
2689 *************************************************************************/
2690
MergePortions(SwTxtNode & rNode)2691 bool SwpHints::MergePortions( SwTxtNode& rNode )
2692 {
2693 if ( !Count() )
2694 return false;
2695
2696 // sort before merging
2697 SwpHintsArray::Resort();
2698
2699 bool bRet = false;
2700 typedef std::multimap< int, SwTxtAttr* > PortionMap;
2701 PortionMap aPortionMap;
2702 xub_StrLen nLastPorStart = STRING_LEN;
2703 sal_uInt16 i = 0;
2704 int nKey = 0;
2705
2706 // get portions by start position:
2707 for ( i = 0; i < Count(); ++i )
2708 {
2709 SwTxtAttr *pHt = GetTextHint( i );
2710 if ( RES_TXTATR_CHARFMT != pHt->Which() &&
2711 RES_TXTATR_AUTOFMT != pHt->Which() )
2712 //&&
2713 //RES_TXTATR_INETFMT != pHt->Which() )
2714 continue;
2715
2716 const xub_StrLen nPorStart = *pHt->GetStart();
2717 if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN )
2718 ++nKey;
2719 nLastPorStart = nPorStart;
2720 aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) );
2721 }
2722
2723 // check if portion i can be merged with portion i+1:
2724 i = 0;
2725 int j = i + 1;
2726 while ( i <= nKey )
2727 {
2728 std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
2729 std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
2730 PortionMap::iterator aIter1 = aRange1.first;
2731 PortionMap::iterator aIter2 = aRange2.first;
2732
2733 bool bMerge = true;
2734 const sal_uInt16 nAttributesInPor1 = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second ));
2735 const sal_uInt16 nAttributesInPor2 = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second ));
2736
2737 if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 )
2738 {
2739 while ( aIter1 != aRange1.second )
2740 {
2741 const SwTxtAttr* p1 = (*aIter1).second;
2742 const SwTxtAttr* p2 = (*aIter2).second;
2743 if ( *p1->End() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) )
2744 {
2745 bMerge = false;
2746 break;
2747 }
2748 ++aIter1;
2749 ++aIter2;
2750 }
2751 }
2752 else
2753 {
2754 bMerge = false;
2755 }
2756
2757 if ( bMerge )
2758 {
2759 // erase all elements with key i + 1
2760 xub_StrLen nNewPortionEnd = 0;
2761 for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
2762 {
2763 SwTxtAttr* p2 = (*aIter2).second;
2764 nNewPortionEnd = *p2->GetEnd();
2765
2766 const sal_uInt16 nCountBeforeDelete = Count();
2767 Delete( p2 );
2768
2769 // robust: check if deletion actually took place before destroying attribute:
2770 if ( Count() < nCountBeforeDelete )
2771 rNode.DestroyAttr( p2 );
2772 }
2773 aPortionMap.erase( aRange2.first, aRange2.second );
2774 ++j;
2775
2776 // change all attributes with key i
2777 aRange1 = aPortionMap.equal_range( i );
2778 for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
2779 {
2780 SwTxtAttr* p1 = (*aIter1).second;
2781 NoteInHistory( p1 );
2782 *p1->GetEnd() = nNewPortionEnd;
2783 NoteInHistory( p1, true );
2784 bRet = true;
2785 }
2786 }
2787 else
2788 {
2789 ++i;
2790 j = i + 1;
2791 }
2792 }
2793
2794 if ( bRet )
2795 {
2796 SwpHintsArray::Resort();
2797 }
2798
2799 return bRet;
2800 }
2801
2802 // check if there is already a character format and adjust the sort numbers
lcl_CheckSortNumber(const SwpHints & rHints,SwTxtCharFmt & rNewCharFmt)2803 void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt )
2804 {
2805 const xub_StrLen nHtStart = *rNewCharFmt.GetStart();
2806 const xub_StrLen nHtEnd = *rNewCharFmt.GetEnd();
2807 sal_uInt16 nSortNumber = 0;
2808
2809 for ( sal_uInt16 i = 0; i < rHints.Count(); ++i )
2810 {
2811 const SwTxtAttr* pOtherHt = rHints[i];
2812
2813 const xub_StrLen nOtherStart = *pOtherHt->GetStart();
2814
2815 if ( nOtherStart > nHtStart )
2816 break;
2817
2818 if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
2819 {
2820 const xub_StrLen nOtherEnd = *pOtherHt->End();
2821
2822 if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
2823 {
2824 const sal_uInt16 nOtherSortNum = static_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber();
2825 nSortNumber = nOtherSortNum + 1;
2826 }
2827 }
2828 }
2829
2830 if ( nSortNumber > 0 )
2831 rNewCharFmt.SetSortNumber( nSortNumber );
2832 }
2833
2834 /*************************************************************************
2835 * SwpHints::Insert()
2836 *************************************************************************/
2837
2838 /*
2839 * Try to insert the new hint.
2840 * Depending on the type of the hint, this either always succeeds, or may fail.
2841 * Depending on the type of the hint, other hints may be deleted or
2842 * overwritten.
2843 * The return value indicates successful insertion.
2844 */
TryInsertHint(SwTxtAttr * const pHint,SwTxtNode & rNode,const SetAttrMode nMode)2845 bool SwpHints::TryInsertHint(
2846 SwTxtAttr* const pHint,
2847 SwTxtNode &rNode,
2848 const SetAttrMode nMode )
2849 {
2850 if ( USHRT_MAX == Count() ) // we're sorry, this flight is overbooked...
2851 {
2852 ASSERT(false, "hints array full :-(");
2853 return false;
2854 }
2855
2856 // Felder bilden eine Ausnahme:
2857 // 1) Sie koennen nie ueberlappen
2858 // 2) Wenn zwei Felder genau aneinander liegen,
2859 // sollen sie nicht zu einem verschmolzen werden.
2860 // Wir koennen also auf die while-Schleife verzichten
2861
2862 xub_StrLen *pHtEnd = pHint->GetEnd();
2863 sal_uInt16 nWhich = pHint->Which();
2864
2865 switch( nWhich )
2866 {
2867 case RES_TXTATR_CHARFMT:
2868 {
2869 // Check if character format contains hidden attribute:
2870 const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt();
2871 const SfxPoolItem* pItem;
2872 if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
2873 rNode.SetCalcHiddenCharFlags();
2874
2875 ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode );
2876 break;
2877 }
2878 // --> FME 2007-03-16 #i75430# Recalc hidden flags if necessary
2879 case RES_TXTATR_AUTOFMT:
2880 {
2881 // Check if auto style contains hidden attribute:
2882 const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
2883 if ( pHiddenItem )
2884 rNode.SetCalcHiddenCharFlags();
2885 break;
2886 }
2887 // <--
2888
2889 case RES_TXTATR_INETFMT:
2890 static_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode);
2891 break;
2892
2893 case RES_TXTATR_FIELD:
2894 case RES_TXTATR_ANNOTATION:
2895 case RES_TXTATR_INPUTFIELD:
2896 {
2897 sal_Bool bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode();
2898 ((SwTxtFld*)pHint)->ChgTxtNode( &rNode );
2899 SwDoc* pDoc = rNode.GetDoc();
2900 const SwField* pFld = ((SwTxtFld*)pHint)->GetFmtFld().GetField();
2901
2902 if( !pDoc->IsNewFldLst() )
2903 {
2904 // was fuer ein Feld ist es denn ??
2905 // bestimmte Felder mussen am Doc das Calculations-Flag updaten
2906 switch( pFld->GetTyp()->Which() )
2907 {
2908 case RES_DBFLD:
2909 case RES_SETEXPFLD:
2910 case RES_HIDDENPARAFLD:
2911 case RES_HIDDENTXTFLD:
2912 case RES_DBNUMSETFLD:
2913 case RES_DBNEXTSETFLD:
2914 {
2915 if( bDelFirst )
2916 pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pHint );
2917 if( rNode.GetNodes().IsDocNodes() )
2918 pDoc->InsDelFldInFldLst( sal_True, *(SwTxtFld*)pHint );
2919 }
2920 break;
2921 case RES_DDEFLD:
2922 if( rNode.GetNodes().IsDocNodes() )
2923 ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2924 break;
2925 }
2926 }
2927
2928 // gehts ins normale Nodes-Array?
2929 if( rNode.GetNodes().IsDocNodes() )
2930 {
2931 sal_Bool bInsFldType = sal_False;
2932 switch( pFld->GetTyp()->Which() )
2933 {
2934 case RES_SETEXPFLD:
2935 bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted();
2936 if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() )
2937 {
2938 // bevor die ReferenzNummer gesetzt wird, sollte
2939 // das Feld am richtigen FeldTypen haengen!
2940 SwSetExpFieldType* pFldType = (SwSetExpFieldType*)
2941 pDoc->InsertFldType( *pFld->GetTyp() );
2942 if( pFldType != pFld->GetTyp() )
2943 {
2944 SwFmtFld* pFmtFld = (SwFmtFld*)&((SwTxtFld*)pHint)->GetFmtFld();
2945 pFmtFld->RegisterToFieldType( *pFldType );
2946 pFmtFld->GetField()->ChgTyp( pFldType );
2947 }
2948 pFldType->SetSeqRefNo( *(SwSetExpField*)pFld );
2949 }
2950 break;
2951 case RES_USERFLD:
2952 bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted();
2953 break;
2954
2955 case RES_DDEFLD:
2956 if( pDoc->IsNewFldLst() )
2957 ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2958 bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted();
2959 break;
2960
2961 case RES_POSTITFLD:
2962 if ( pDoc->GetDocShell() )
2963 pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_INSERTED ) );
2964 break;
2965 }
2966 if( bInsFldType )
2967 pDoc->InsDeletedFldType( *pFld->GetTyp() );
2968 }
2969 }
2970 break;
2971 case RES_TXTATR_FTN :
2972 ((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
2973 break;
2974 case RES_TXTATR_REFMARK:
2975 ((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode );
2976 if( rNode.GetNodes().IsDocNodes() )
2977 {
2978 // search for a reference with the same name
2979 SwTxtAttr* pTmpHt;
2980 xub_StrLen *pTmpHtEnd, *pTmpHintEnd;
2981 for( sal_uInt16 n = 0, nEnd = Count(); n < nEnd; ++n )
2982 {
2983 if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
2984 pHint->GetAttr() == pTmpHt->GetAttr() &&
2985 0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
2986 0 != ( pTmpHintEnd = pHint->GetEnd() ) )
2987 {
2988 SwComparePosition eCmp = ::ComparePosition(
2989 *pTmpHt->GetStart(), *pTmpHtEnd,
2990 *pHint->GetStart(), *pTmpHintEnd );
2991 sal_Bool bDelOld = sal_True, bChgStart = sal_False, bChgEnd = sal_False;
2992 switch( eCmp )
2993 {
2994 case POS_BEFORE:
2995 case POS_BEHIND: bDelOld = sal_False; break;
2996
2997 case POS_OUTSIDE: bChgStart = bChgEnd = sal_True; break;
2998
2999 case POS_COLLIDE_END:
3000 case POS_OVERLAP_BEFORE: bChgStart = sal_True; break;
3001 case POS_COLLIDE_START:
3002 case POS_OVERLAP_BEHIND: bChgEnd = sal_True; break;
3003 default: break;
3004 }
3005
3006 if( bChgStart )
3007 *pHint->GetStart() = *pTmpHt->GetStart();
3008 if( bChgEnd )
3009 *pTmpHintEnd = *pTmpHtEnd;
3010
3011 if( bDelOld )
3012 {
3013 NoteInHistory( pTmpHt );
3014 rNode.DestroyAttr( Cut( n-- ) );
3015 --nEnd;
3016 }
3017 }
3018 }
3019 }
3020 break;
3021 case RES_TXTATR_TOXMARK:
3022 ((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode );
3023 break;
3024
3025 case RES_TXTATR_CJK_RUBY:
3026 static_cast<SwTxtRuby*>(pHint)->InitRuby(rNode);
3027 break;
3028
3029 case RES_TXTATR_META:
3030 case RES_TXTATR_METAFIELD:
3031 static_cast<SwTxtMeta *>(pHint)->ChgTxtNode( &rNode );
3032 break;
3033
3034 case RES_CHRATR_HIDDEN:
3035 rNode.SetCalcHiddenCharFlags();
3036 break;
3037 }
3038
3039 if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode )
3040 pHint->SetDontExpand( sal_True );
3041
3042 // SwTxtAttrs ohne Ende werden sonderbehandelt:
3043 // Sie werden natuerlich in das Array insertet, aber sie werden nicht
3044 // in die pPrev/Next/On/Off-Verkettung aufgenommen.
3045 // Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text !
3046 xub_StrLen nHtStart = *pHint->GetStart();
3047 if( !pHtEnd )
3048 {
3049 SwpHintsArray::Insert( pHint );
3050 CalcFlags();
3051 #ifdef DBG_UTIL
3052 if( !rNode.GetDoc()->IsInReading() )
3053 CHECK;
3054 #endif
3055 // ... und die Abhaengigen benachrichtigen
3056 if(rNode.GetDepends())
3057 {
3058 SwUpdateAttr aHint(
3059 nHtStart,
3060 nHtStart,
3061 nWhich);
3062
3063 rNode.ModifyNotification(0,&aHint);
3064 }
3065
3066 return true;
3067 }
3068
3069 // ----------------------------------------------------------------
3070 // Ab hier gibt es nur noch pHint mit einem EndIdx !!!
3071
3072 if( *pHtEnd < nHtStart )
3073 {
3074 ASSERT( *pHtEnd >= nHtStart,
3075 "+SwpHints::Insert: invalid hint, end < start" );
3076
3077 // Wir drehen den Quatsch einfach um:
3078 *pHint->GetStart() = *pHtEnd;
3079 *pHtEnd = nHtStart;
3080 nHtStart = *pHint->GetStart();
3081 }
3082
3083 // I need this value later on for notification but the pointer may become invalid
3084 const xub_StrLen nHintEnd = *pHtEnd;
3085 const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode);
3086
3087 // handle nesting attributes: inserting may fail due to overlap!
3088 if (pHint->IsNesting())
3089 {
3090 const bool bRet(
3091 TryInsertNesting(rNode, *static_cast<SwTxtAttrNesting*>(pHint)));
3092 if (!bRet) return false;
3093 }
3094 // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
3095 // These attributes may be inserted directly.
3096 // Also attributes without length may be inserted directly.
3097 // SETATTR_NOHINTADJUST is set e.g., during undo.
3098 // Portion building in not necessary during XML import.
3099 else
3100 if ( !bNoHintAdjustMode &&
3101 !pHint->IsOverlapAllowedAttr() &&
3102 !rNode.GetDoc()->IsInXMLImport() &&
3103 ( RES_TXTATR_AUTOFMT == nWhich ||
3104 RES_TXTATR_CHARFMT == nWhich ) )
3105 {
3106 ASSERT( nWhich != RES_TXTATR_AUTOFMT ||
3107 static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
3108 &rNode.GetDoc()->GetAttrPool(),
3109 "AUTOSTYLES - Pool mismatch" )
3110
3111 BuildPortions( rNode, *pHint, nMode );
3112
3113 if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
3114 MergePortions( rNode );
3115 }
3116 else
3117 {
3118 // There may be more than one character style at the current position.
3119 // Take care of the sort number.
3120 // Special case ruby portion: During import, the ruby attribute is set
3121 // multiple times
3122 // Special case hyperlink: During import, the ruby attribute is set
3123 // multiple times
3124 // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
3125 // character attributes directly
3126 if ( ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode ) )
3127 {
3128 BuildPortions( rNode, *pHint, nMode );
3129 }
3130 else
3131 {
3132 // --> FME 2007-11-08 #i82989# Check sort numbers in NoHintAdjustMode
3133 if ( RES_TXTATR_CHARFMT == nWhich )
3134 lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) );
3135 // <--
3136
3137 SwpHintsArray::Insert( pHint );
3138 NoteInHistory( pHint, true );
3139 }
3140 }
3141
3142 // ... und die Abhaengigen benachrichtigen
3143 if ( rNode.GetDepends() )
3144 {
3145 SwUpdateAttr aHint(
3146 // rNode.GetDoc()->GetAttrPool(),
3147 nHtStart,
3148 nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd,
3149 nWhich);
3150
3151 rNode.ModifyNotification( 0, &aHint );
3152 }
3153
3154 #ifdef DBG_UTIL
3155 if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
3156 CHECK;
3157 #endif
3158
3159 return true;
3160 }
3161
3162 /*************************************************************************
3163 * SwpHints::DeleteAtPos()
3164 *************************************************************************/
3165
DeleteAtPos(const sal_uInt16 nPos)3166 void SwpHints::DeleteAtPos( const sal_uInt16 nPos )
3167 {
3168 SwTxtAttr *pHint = GetTextHint(nPos);
3169 // ChainDelete( pHint );
3170 NoteInHistory( pHint );
3171 SwpHintsArray::DeleteAtPos( nPos );
3172
3173 if( pHint->Which() == RES_TXTATR_FIELD )
3174 {
3175 const SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFmtFld().GetField()->GetTyp();
3176 if( RES_DDEFLD == pFldTyp->Which() )
3177 {
3178 const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode();
3179 if( pNd && pNd->GetNodes().IsDocNodes() )
3180 ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
3181 ((SwTxtFld*)pHint)->ChgTxtNode( 0 );
3182 }
3183 else if ( m_bHasHiddenParaField &&
3184 RES_HIDDENPARAFLD == pFldTyp->Which() )
3185 {
3186 m_bCalcHiddenParaField = true;
3187 }
3188 }
3189 else if ( pHint->Which() == RES_TXTATR_ANNOTATION )
3190 {
3191 const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_REMOVED ) );
3192 }
3193
3194 CalcFlags();
3195 CHECK;
3196 }
3197
3198 // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
3199 // Ist er nicht im Array, so gibt es ein ASSERT !!
3200
Delete(SwTxtAttr * pTxtHt)3201 void SwpHints::Delete( SwTxtAttr* pTxtHt )
3202 {
3203 // Attr 2.0: SwpHintsArr::Delete( pTxtHt );
3204 const sal_uInt16 nPos = GetStartOf( pTxtHt );
3205 ASSERT( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" );
3206 if( USHRT_MAX != nPos )
3207 DeleteAtPos( nPos );
3208 }
3209
ClearSwpHintsArr(bool bDelFields)3210 void SwTxtNode::ClearSwpHintsArr( bool bDelFields )
3211 {
3212 if ( HasHints() )
3213 {
3214 sal_uInt16 nPos = 0;
3215 while ( nPos < m_pSwpHints->Count() )
3216 {
3217 SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos );
3218 bool bDel = false;
3219
3220 switch( pDel->Which() )
3221 {
3222 case RES_TXTATR_FLYCNT:
3223 case RES_TXTATR_FTN:
3224 break;
3225
3226 case RES_TXTATR_FIELD:
3227 case RES_TXTATR_ANNOTATION:
3228 case RES_TXTATR_INPUTFIELD:
3229 if( bDelFields )
3230 bDel = true;
3231 break;
3232 default:
3233 bDel = true; break;
3234 }
3235
3236 if( bDel )
3237 {
3238 m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
3239 DestroyAttr( pDel );
3240 }
3241 else
3242 ++nPos;
3243 }
3244 }
3245 }
3246
GetLang(const xub_StrLen nBegin,const xub_StrLen nLen,sal_uInt16 nScript) const3247 sal_uInt16 SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen,
3248 sal_uInt16 nScript ) const
3249 {
3250 sal_uInt16 nRet = LANGUAGE_DONTKNOW;
3251
3252 if ( ! nScript )
3253 {
3254 nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin );
3255 }
3256
3257 // --> FME 2008-09-29 #i91465# hennerdrewes: Consider nScript if pSwpHints == 0
3258 const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
3259 // <--
3260
3261 if ( HasHints() )
3262 {
3263 const xub_StrLen nEnd = nBegin + nLen;
3264 for ( sal_uInt16 i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i )
3265 {
3266 // ist der Attribut-Anfang schon groesser als der Idx ?
3267 const SwTxtAttr *pHt = m_pSwpHints->operator[](i);
3268 const xub_StrLen nAttrStart = *pHt->GetStart();
3269 if( nEnd < nAttrStart )
3270 break;
3271
3272 const sal_uInt16 nWhich = pHt->Which();
3273
3274 if( nWhichId == nWhich ||
3275 ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) )
3276 {
3277 const xub_StrLen *pEndIdx = pHt->End();
3278 // Ueberlappt das Attribut den Bereich?
3279
3280 if( pEndIdx &&
3281 nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
3282 : (( nAttrStart < nBegin &&
3283 ( pHt->DontExpand() ? nBegin < *pEndIdx
3284 : nBegin <= *pEndIdx )) ||
3285 ( nBegin == nAttrStart &&
3286 ( nAttrStart == *pEndIdx || !nBegin ))) )
3287 {
3288 const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId );
3289 sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
3290
3291 // Umfasst das Attribut den Bereich komplett?
3292 if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
3293 nRet = nLng;
3294 else if( LANGUAGE_DONTKNOW == nRet )
3295 nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
3296 }
3297 }
3298 }
3299 }
3300 if( LANGUAGE_DONTKNOW == nRet )
3301 {
3302 nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
3303 if( LANGUAGE_DONTKNOW == nRet )
3304 nRet = static_cast<sal_uInt16>(GetAppLanguage());
3305 }
3306 return nRet;
3307 }
3308
3309
GetCharOfTxtAttr(const SwTxtAttr & rAttr)3310 sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
3311 {
3312 sal_Unicode cRet = CH_TXTATR_BREAKWORD;
3313 switch ( rAttr.Which() )
3314 {
3315 case RES_TXTATR_FTN:
3316 case RES_TXTATR_REFMARK:
3317 case RES_TXTATR_TOXMARK:
3318 case RES_TXTATR_META:
3319 case RES_TXTATR_METAFIELD:
3320 case RES_TXTATR_ANNOTATION:
3321 cRet = CH_TXTATR_INWORD;
3322 break;
3323
3324 case RES_TXTATR_FIELD:
3325 case RES_TXTATR_FLYCNT:
3326 {
3327 cRet = CH_TXTATR_BREAKWORD;
3328 }
3329 break;
3330
3331 default:
3332 ASSERT(false, "GetCharOfTxtAttr: unknown attr");
3333 break;
3334 }
3335 return cRet;
3336 }
3337
3338
3339