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 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; 109 TxtAttrDeleter( SwDoc & rDoc ) : m_rPool( rDoc.GetAttrPool() ) { } 110 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; 124 TxtAttrContains( const xub_StrLen nPos ) : m_nPos( nPos ) { } 125 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 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 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 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 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 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 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 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 * 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 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 */ 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 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 592 void SwpHints::BuildPortions( SwTxtNode& rNode, SwTxtAttr& rNewHint, 593 const SetAttrMode nMode ) 594 { 595 const sal_uInt16 nWhich = rNewHint.Which(); 596 597 const xub_StrLen nThisStart = *rNewHint.GetStart(); 598 const xub_StrLen nThisEnd = *rNewHint.GetEnd(); 599 const bool bNoLengthAttribute = nThisStart == nThisEnd; 600 601 std::vector<SwTxtAttr*> aInsDelHints; 602 std::vector<SwTxtAttr*>::iterator aIter; 603 604 ASSERT( RES_TXTATR_CHARFMT == rNewHint.Which() || 605 RES_TXTATR_AUTOFMT == rNewHint.Which(), 606 "Expecting CHARFMT or AUTOFMT" ); 607 608 // 609 // 2. Find the hints which cover the start and end position 610 // of the new hint. These hints have to be split into two portions: 611 // 612 if ( !bNoLengthAttribute ) // nothing to do for no length attributes 613 { 614 for ( sal_uInt16 i = 0; i < Count(); ++i ) 615 { 616 SwTxtAttr* pOther = GetTextHint(i); 617 618 if ( RES_TXTATR_CHARFMT != pOther->Which() && 619 RES_TXTATR_AUTOFMT != pOther->Which() ) 620 continue; 621 622 xub_StrLen nOtherStart = *pOther->GetStart(); 623 const xub_StrLen nOtherEnd = *pOther->GetEnd(); 624 625 // Check if start of new attribute overlaps with pOther: 626 // Split pOther if necessary: 627 if ( nOtherStart < nThisStart && nThisStart < nOtherEnd ) 628 { 629 SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(), 630 pOther->GetAttr(), nOtherStart, nThisStart ); 631 if ( RES_TXTATR_CHARFMT == pOther->Which() ) 632 static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() ); 633 aInsDelHints.push_back( pNewAttr ); 634 635 NoteInHistory( pOther ); 636 *pOther->GetStart() = nThisStart; 637 NoteInHistory( pOther, true ); 638 639 nOtherStart = nThisStart; 640 } 641 642 // Check if end of new attribute overlaps with pOther: 643 // Split pOther if necessary: 644 if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd ) 645 { 646 SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(), 647 pOther->GetAttr(), nOtherStart, nThisEnd ); 648 if ( RES_TXTATR_CHARFMT == pOther->Which() ) 649 static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() ); 650 aInsDelHints.push_back( pNewAttr ); 651 652 NoteInHistory( pOther ); 653 *pOther->GetStart() = nThisEnd; 654 NoteInHistory( pOther, true ); 655 } 656 } 657 658 // Insert the newly created attributes: 659 for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter ) 660 { 661 SwpHintsArray::Insert( *aIter ); 662 NoteInHistory( *aIter, true ); 663 } 664 } 665 666 #ifdef DBG_UTIL 667 if( !rNode.GetDoc()->IsInReading() ) 668 CHECK; 669 #endif 670 671 // 672 // 4. Split rNewHint into 1 ... n new hints: 673 // 674 std::set<xub_StrLen> aBounds; 675 aBounds.insert( nThisStart ); 676 aBounds.insert( nThisEnd ); 677 678 if ( !bNoLengthAttribute ) // nothing to do for no length attributes 679 { 680 for ( sal_uInt16 i = 0; i < Count(); ++i ) 681 { 682 const SwTxtAttr* pOther = GetTextHint(i); 683 684 if ( RES_TXTATR_CHARFMT != pOther->Which() && 685 RES_TXTATR_AUTOFMT != pOther->Which() ) 686 continue; 687 688 const xub_StrLen nOtherStart = *pOther->GetStart(); 689 const xub_StrLen nOtherEnd = *pOther->End(); 690 691 aBounds.insert( nOtherStart ); 692 aBounds.insert( nOtherEnd ); 693 } 694 } 695 696 std::set<xub_StrLen>::iterator aStartIter = aBounds.lower_bound( nThisStart ); 697 std::set<xub_StrLen>::iterator aEndIter = aBounds.upper_bound( nThisEnd ); 698 xub_StrLen nPorStart = *aStartIter; 699 ++aStartIter; 700 bool bDestroyHint = true; 701 702 // 703 // Insert the 1...n new parts of the new attribute: 704 // 705 while ( aStartIter != aEndIter || bNoLengthAttribute ) 706 { 707 ASSERT( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" ) 708 709 const xub_StrLen nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter; 710 aInsDelHints.clear(); 711 712 // Get all hints that are in [nPorStart, nPorEnd[: 713 for ( sal_uInt16 i = 0; i < Count(); ++i ) 714 { 715 SwTxtAttr *pOther = GetTextHint(i); 716 717 if ( RES_TXTATR_CHARFMT != pOther->Which() && 718 RES_TXTATR_AUTOFMT != pOther->Which() ) 719 continue; 720 721 const xub_StrLen nOtherStart = *pOther->GetStart(); 722 723 if ( nOtherStart > nPorStart ) 724 break; 725 726 if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart ) 727 { 728 ASSERT( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" ) 729 aInsDelHints.push_back( pOther ); 730 } 731 } 732 733 SwTxtAttr* pNewAttr = 0; 734 if ( RES_TXTATR_CHARFMT == nWhich ) 735 { 736 // pNewHint can be inserted after calculating the sort value. 737 // This should ensure, that pNewHint comes behind the already present 738 // character style 739 sal_uInt16 nCharStyleCount = 0; 740 aIter = aInsDelHints.begin(); 741 while ( aIter != aInsDelHints.end() ) 742 { 743 if ( RES_TXTATR_CHARFMT == (*aIter)->Which() ) 744 { 745 // --> FME 2007-02-16 #i74589# 746 const SwFmtCharFmt& rOtherCharFmt = (*aIter)->GetCharFmt(); 747 const SwFmtCharFmt& rThisCharFmt = rNewHint.GetCharFmt(); 748 const bool bSameCharFmt = rOtherCharFmt.GetCharFmt() == rThisCharFmt.GetCharFmt(); 749 // <-- 750 751 // --> OD 2009-03-24 #i90311# 752 // Do not remove existing character format hint during XML import 753 if ( !rNode.GetDoc()->IsInXMLImport() && 754 ( !( nsSetAttrMode::SETATTR_DONTREPLACE & nMode ) || 755 bNoLengthAttribute || 756 bSameCharFmt ) ) 757 // <-- 758 { 759 // Remove old hint 760 Delete( *aIter ); 761 rNode.DestroyAttr( *aIter ); 762 } 763 else 764 ++nCharStyleCount; 765 } 766 else 767 { 768 // remove all attributes from auto styles, which are explicitely set in 769 // the new character format: 770 ASSERT( RES_TXTATR_AUTOFMT == (*aIter)->Which(), "AUTOSTYLES - Misc trouble" ) 771 SwTxtAttr* pOther = *aIter; 772 boost::shared_ptr<SfxItemSet> pOldStyle = static_cast<const SwFmtAutoFmt&>(pOther->GetAttr()).GetStyleHandle(); 773 774 // For each attribute in the automatic style check if it 775 // is also set the the new character style: 776 SfxItemSet aNewSet( *pOldStyle->GetPool(), 777 aCharAutoFmtSetRange); 778 SfxItemIter aItemIter( *pOldStyle ); 779 const SfxPoolItem* pItem = aItemIter.GetCurItem(); 780 while( sal_True ) 781 { 782 if ( !CharFmt::IsItemIncluded( pItem->Which(), &rNewHint ) ) 783 { 784 aNewSet.Put( *pItem ); 785 } 786 787 if( aItemIter.IsAtEnd() ) 788 break; 789 790 pItem = aItemIter.NextItem(); 791 } 792 793 // Remove old hint 794 Delete( pOther ); 795 rNode.DestroyAttr( pOther ); 796 797 // Create new AutoStyle 798 if ( aNewSet.Count() ) 799 { 800 pNewAttr = MakeTxtAttr( *rNode.GetDoc(), 801 aNewSet, nPorStart, nPorEnd ); 802 SwpHintsArray::Insert( pNewAttr ); 803 NoteInHistory( pNewAttr, true ); 804 } 805 } 806 ++aIter; 807 } 808 809 // If there is no current hint and start and end of rNewHint 810 // is ok, we do not need to create a new txtattr. 811 if ( nPorStart == nThisStart && 812 nPorEnd == nThisEnd && 813 !nCharStyleCount ) 814 { 815 pNewAttr = &rNewHint; 816 bDestroyHint = false; 817 } 818 else 819 { 820 pNewAttr = MakeTxtAttr( *rNode.GetDoc(), rNewHint.GetAttr(), 821 nPorStart, nPorEnd ); 822 static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( nCharStyleCount ); 823 } 824 } 825 else 826 { 827 // Find the current autostyle. Mix attributes if necessary. 828 SwTxtAttr* pCurrentAutoStyle = 0; 829 SwTxtAttr* pCurrentCharFmt = 0; 830 aIter = aInsDelHints.begin(); 831 while ( aIter != aInsDelHints.end() ) 832 { 833 if ( RES_TXTATR_AUTOFMT == (*aIter)->Which() ) 834 pCurrentAutoStyle = *aIter; 835 else if ( RES_TXTATR_CHARFMT == (*aIter)->Which() ) 836 pCurrentCharFmt = *aIter; 837 ++aIter; 838 } 839 840 boost::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFmtAutoFmt&>(rNewHint.GetAttr()).GetStyleHandle(); 841 if ( pCurrentAutoStyle ) 842 { 843 boost::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFmtAutoFmt&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle(); 844 845 // Merge attributes 846 SfxItemSet aNewSet( *pCurrentStyle ); 847 aNewSet.Put( *pNewStyle ); 848 849 // --> FME 2007-4-11 #i75750# Remove attributes already set at whole paragraph 850 // --> FME 2007-09-24 #i81764# This should not be applied for no length attributes!!! <-- 851 if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() ) 852 { 853 SfxItemIter aIter2( aNewSet ); 854 const SfxPoolItem* pItem = aIter2.GetCurItem(); 855 const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet(); 856 857 do 858 { 859 const SfxPoolItem* pTmpItem = 0; 860 if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), sal_False, &pTmpItem ) && 861 pTmpItem == pItem ) 862 { 863 // Do not clear item if the attribute is set in a character format: 864 if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) ) 865 aNewSet.ClearItem( pItem->Which() ); 866 } 867 } 868 while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem())); 869 } 870 // <-- 871 872 // Remove old hint 873 Delete( pCurrentAutoStyle ); 874 rNode.DestroyAttr( pCurrentAutoStyle ); 875 876 // Create new AutoStyle 877 if ( aNewSet.Count() ) 878 pNewAttr = MakeTxtAttr( *rNode.GetDoc(), aNewSet, 879 nPorStart, nPorEnd ); 880 } 881 else 882 { 883 // Remove any attributes which are already set at the whole paragraph: 884 bool bOptimizeAllowed = true; 885 886 SfxItemSet* pNewSet = 0; 887 // --> FME 2007-4-11 #i75750# Remove attributes already set at whole paragraph 888 // --> FME 2007-09-24 #i81764# This should not be applied for no length attributes!!! <-- 889 if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() ) 890 { 891 SfxItemIter aIter2( *pNewStyle ); 892 const SfxPoolItem* pItem = aIter2.GetCurItem(); 893 const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet(); 894 895 do 896 { 897 const SfxPoolItem* pTmpItem = 0; 898 if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), sal_False, &pTmpItem ) && 899 pTmpItem == pItem ) 900 { 901 // Do not clear item if the attribute is set in a character format: 902 if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) ) 903 { 904 if ( !pNewSet ) 905 pNewSet = pNewStyle->Clone( sal_True ); 906 pNewSet->ClearItem( pItem->Which() ); 907 } 908 } 909 } 910 while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem())); 911 912 if ( pNewSet ) 913 { 914 bOptimizeAllowed = false; 915 if ( pNewSet->Count() ) 916 pNewStyle = rNode.getIDocumentStyleAccess().getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR ); 917 else 918 pNewStyle.reset(); 919 920 delete pNewSet; 921 } 922 } 923 // <-- 924 925 // Create new AutoStyle 926 // If there is no current hint and start and end of rNewHint 927 // is ok, we do not need to create a new txtattr. 928 if ( bOptimizeAllowed && 929 nPorStart == nThisStart && 930 nPorEnd == nThisEnd ) 931 { 932 pNewAttr = &rNewHint; 933 bDestroyHint = false; 934 } 935 else if ( pNewStyle.get() ) 936 { 937 pNewAttr = MakeTxtAttr( *rNode.GetDoc(), *pNewStyle, 938 nPorStart, nPorEnd ); 939 } 940 } 941 } 942 943 if ( pNewAttr ) 944 { 945 SwpHintsArray::Insert( pNewAttr ); 946 // if ( bDestroyHint ) 947 NoteInHistory( pNewAttr, true ); 948 } 949 950 if ( !bNoLengthAttribute ) 951 { 952 nPorStart = *aStartIter; 953 ++aStartIter; 954 } 955 else 956 break; 957 } 958 959 if ( bDestroyHint ) 960 rNode.DestroyAttr( &rNewHint ); 961 } 962 963 /************************************************************************* 964 * SwTxtNode::MakeTxtAttr() 965 *************************************************************************/ 966 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 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 = new SwTxtFld( static_cast<SwFmtFld &>(rNew), nStt ); 1053 break; 1054 1055 case RES_TXTATR_ANNOTATION: 1056 { 1057 pNew = new SwTxtAnnotationFld( static_cast<SwFmtFld &>(rNew), nStt ); 1058 if ( bIsCopy == COPY ) 1059 { 1060 // On copy of the annotation field do not keep the annotated text range by removing 1061 // the relation to its annotation mark (relation established via annotation field's name). 1062 // If the annotation mark is also copied, the relation and thus the annotated text range will be reestablished, 1063 // when the annotation mark is created and inserted into the document. 1064 const_cast<SwPostItField*>(dynamic_cast< const SwPostItField* >(pNew->GetFmtFld().GetField()))->SetName( String() ); 1065 } 1066 } 1067 break; 1068 1069 case RES_TXTATR_INPUTFIELD: 1070 pNew = new SwTxtInputFld( static_cast<SwFmtFld &>(rNew), nStt, nEnd ); 1071 break; 1072 1073 case RES_TXTATR_FLYCNT: 1074 { 1075 // erst hier wird das Frame-Format kopiert (mit Inhalt) !! 1076 pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt ); 1077 // Kopie von einem Text-Attribut 1078 if ( static_cast<const SwFmtFlyCnt &>(rAttr).GetTxtFlyCnt() ) 1079 { 1080 // then the format must be copied 1081 static_cast<SwTxtFlyCnt *>(pNew)->CopyFlyFmt( &rDoc ); 1082 } 1083 } 1084 break; 1085 case RES_TXTATR_FTN: 1086 pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt ); 1087 // ggfs. SeqNo kopieren 1088 if( ((SwFmtFtn&)rAttr).GetTxtFtn() ) 1089 ((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() ); 1090 break; 1091 case RES_TXTATR_REFMARK: 1092 pNew = nStt == nEnd 1093 ? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt ) 1094 : new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd ); 1095 break; 1096 case RES_TXTATR_TOXMARK: 1097 pNew = new SwTxtTOXMark( (SwTOXMark&)rNew, nStt, &nEnd ); 1098 break; 1099 case RES_TXTATR_CJK_RUBY: 1100 pNew = new SwTxtRuby( (SwFmtRuby&)rNew, nStt, nEnd ); 1101 break; 1102 case RES_TXTATR_META: 1103 case RES_TXTATR_METAFIELD: 1104 pNew = SwTxtMeta::CreateTxtMeta( rDoc.GetMetaFieldManager(), pTxtNode, 1105 static_cast<SwFmtMeta&>(rNew), nStt, nEnd, bIsCopy ); 1106 break; 1107 default: 1108 ASSERT(RES_TXTATR_AUTOFMT == rNew.Which(), "unknown attribute"); 1109 pNew = new SwTxtAttrEnd( rNew, nStt, nEnd ); 1110 break; 1111 } 1112 1113 return pNew; 1114 } 1115 1116 SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, const SfxItemSet& rSet, 1117 xub_StrLen nStt, xub_StrLen nEnd ) 1118 { 1119 IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess(); 1120 const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR ); 1121 SwFmtAutoFmt aNewAutoFmt; 1122 aNewAutoFmt.SetStyleHandle( pAutoStyle ); 1123 SwTxtAttr* pNew = MakeTxtAttr( rDoc, aNewAutoFmt, nStt, nEnd ); 1124 return pNew; 1125 } 1126 1127 1128 // loesche das Text-Attribut (muss beim Pool abgemeldet werden!) 1129 void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr ) 1130 { 1131 if( pAttr ) 1132 { 1133 // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen 1134 SwDoc* pDoc = GetDoc(); 1135 sal_uInt16 nDelMsg = 0; 1136 switch( pAttr->Which() ) 1137 { 1138 case RES_TXTATR_FLYCNT: 1139 { 1140 // siehe auch die Anmerkung "Loeschen von Formaten 1141 // zeichengebundener Frames" in fesh.cxx, SwFEShell::DelFmt() 1142 SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt(); 1143 if( pFmt ) // vom Undo auf 0 gesetzt ?? 1144 pDoc->DelLayoutFmt( (SwFlyFrmFmt*)pFmt ); 1145 } 1146 break; 1147 1148 case RES_CHRATR_HIDDEN: 1149 SetCalcHiddenCharFlags(); 1150 break; 1151 1152 case RES_TXTATR_FTN: 1153 ((SwTxtFtn*)pAttr)->SetStartNode( 0 ); 1154 nDelMsg = RES_FOOTNOTE_DELETED; 1155 break; 1156 1157 case RES_TXTATR_FIELD: 1158 case RES_TXTATR_ANNOTATION: 1159 case RES_TXTATR_INPUTFIELD: 1160 if( !pDoc->IsInDtor() ) 1161 { 1162 // Wenn wir ein HiddenParaField sind, dann muessen wir 1163 // ggf. fuer eine Neuberechnung des Visible-Flags sorgen. 1164 const SwField* pFld = pAttr->GetFmtFld().GetField(); 1165 1166 //JP 06-08-95: DDE-Felder bilden eine Ausnahme 1167 ASSERT( RES_DDEFLD == pFld->GetTyp()->Which() || 1168 this == ((SwTxtFld*)pAttr)->GetpTxtNode(), 1169 "Wo steht denn dieses Feld?" ) 1170 1171 // bestimmte Felder mussen am Doc das Calculations-Flag updaten 1172 switch( pFld->GetTyp()->Which() ) 1173 { 1174 case RES_HIDDENPARAFLD: 1175 SetCalcHiddenParaField(); 1176 // kein break ! 1177 case RES_DBSETNUMBERFLD: 1178 case RES_GETEXPFLD: 1179 case RES_DBFLD: 1180 case RES_SETEXPFLD: 1181 case RES_HIDDENTXTFLD: 1182 case RES_DBNUMSETFLD: 1183 case RES_DBNEXTSETFLD: 1184 if( !pDoc->IsNewFldLst() && GetNodes().IsDocNodes() ) 1185 pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pAttr ); 1186 break; 1187 case RES_DDEFLD: 1188 if( GetNodes().IsDocNodes() && 1189 ((SwTxtFld*)pAttr)->GetpTxtNode() ) 1190 ((SwDDEFieldType*)pFld->GetTyp())->DecRefCnt(); 1191 break; 1192 case RES_POSTITFLD: 1193 { 1194 const_cast<SwFmtFld&>(pAttr->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pAttr)->GetFmtFld(), SWFMTFLD_REMOVED ) ); 1195 break; 1196 } 1197 } 1198 } 1199 nDelMsg = RES_FIELD_DELETED; 1200 break; 1201 1202 case RES_TXTATR_TOXMARK: 1203 static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark(); 1204 break; 1205 1206 case RES_TXTATR_REFMARK: 1207 nDelMsg = RES_REFMARK_DELETED; 1208 break; 1209 1210 case RES_TXTATR_META: 1211 case RES_TXTATR_METAFIELD: 1212 static_cast<SwTxtMeta*>(pAttr)->ChgTxtNode(0); 1213 break; 1214 1215 default: 1216 break; 1217 } 1218 1219 if( nDelMsg && !pDoc->IsInDtor() && GetNodes().IsDocNodes() ) 1220 { 1221 SwPtrMsgPoolItem aMsgHint( nDelMsg, (void*)&pAttr->GetAttr() ); 1222 pDoc->GetUnoCallBack()->ModifyNotification( &aMsgHint, &aMsgHint ); 1223 } 1224 1225 SwTxtAttr::Destroy( pAttr, pDoc->GetAttrPool() ); 1226 } 1227 } 1228 1229 /************************************************************************* 1230 * SwTxtNode::Insert() 1231 *************************************************************************/ 1232 1233 SwTxtAttr* SwTxtNode::InsertItem( 1234 SfxPoolItem& rAttr, 1235 const xub_StrLen nStart, 1236 const xub_StrLen nEnd, 1237 const SetAttrMode nMode ) 1238 { 1239 // character attributes will be inserted as automatic styles: 1240 ASSERT( !isCHRATR(rAttr.Which()), "AUTOSTYLES - " 1241 "SwTxtNode::InsertItem should not be called with character attributes"); 1242 1243 SwTxtAttr *const pNew = 1244 MakeTxtAttr( 1245 *GetDoc(), 1246 rAttr, 1247 nStart, 1248 nEnd, 1249 (nMode & nsSetAttrMode::SETATTR_IS_COPY) ? COPY : NEW, 1250 this ); 1251 1252 if ( pNew ) 1253 { 1254 const bool bSuccess( InsertHint( pNew, nMode ) ); 1255 // N.B.: also check that the hint is actually in the hints array, 1256 // because hints of certain types may be merged after succesful 1257 // insertion, and thus destroyed! 1258 if (!bSuccess || ( USHRT_MAX == m_pSwpHints->GetPos( pNew ) )) 1259 { 1260 return 0; 1261 } 1262 } 1263 1264 return pNew; 1265 } 1266 1267 // take ownership of pAttr; if insertion fails, delete pAttr 1268 bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode ) 1269 { 1270 bool bHiddenPara = false; 1271 1272 ASSERT( pAttr && *pAttr->GetStart() <= Len(), "StartIdx out of bounds!" ); 1273 ASSERT( !pAttr->GetEnd() || (*pAttr->GetEnd() <= Len()), 1274 "EndIdx out of bounds!" ); 1275 1276 // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR) 1277 const enum IDocumentContentOperations::InsertFlags nInsertFlags = 1278 (nMode & nsSetAttrMode::SETATTR_FORCEHINTEXPAND) 1279 ? static_cast<IDocumentContentOperations::InsertFlags>( 1280 IDocumentContentOperations::INS_FORCEHINTEXPAND | 1281 IDocumentContentOperations::INS_EMPTYEXPAND) 1282 : IDocumentContentOperations::INS_EMPTYEXPAND; 1283 1284 // need this after TryInsertHint, when pAttr may be deleted 1285 const xub_StrLen nStart( *pAttr->GetStart() ); 1286 const bool bDummyChar( pAttr->HasDummyChar() ); 1287 if (bDummyChar) 1288 { 1289 sal_uInt16 nInsMode = nMode; 1290 switch( pAttr->Which() ) 1291 { 1292 case RES_TXTATR_FLYCNT: 1293 { 1294 SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr; 1295 SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt(); 1296 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) ) 1297 { 1298 // Wir muessen zuerst einfuegen, da in SetAnchor() 1299 // dem FlyFrm GetStart() uebermittelt wird. 1300 //JP 11.05.98: falls das Anker-Attribut schon richtig 1301 // gesetzt ist, dann korrigiere dieses nach dem Einfuegen 1302 // des Zeichens. Sonst muesste das immer ausserhalb 1303 // erfolgen (Fehleranfaellig !) 1304 const SwFmtAnchor* pAnchor = 0; 1305 pFmt->GetItemState( RES_ANCHOR, sal_False, 1306 (const SfxPoolItem**)&pAnchor ); 1307 1308 SwIndex aIdx( this, *pAttr->GetStart() ); 1309 const sal_Unicode c = GetCharOfTxtAttr(*pAttr); 1310 InsertText( c, aIdx, nInsertFlags ); 1311 nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR; 1312 1313 if (pAnchor && 1314 (FLY_AS_CHAR == pAnchor->GetAnchorId()) && 1315 pAnchor->GetCntntAnchor() && 1316 pAnchor->GetCntntAnchor()->nNode == *this && 1317 pAnchor->GetCntntAnchor()->nContent == aIdx ) 1318 { 1319 const_cast<SwIndex&>( 1320 pAnchor->GetCntntAnchor()->nContent)--; 1321 } 1322 } 1323 pFly->SetAnchor( this ); 1324 1325 // Format-Pointer kann sich im SetAnchor geaendert haben! 1326 // (Kopieren in andere Docs!) 1327 pFmt = pAttr->GetFlyCnt().GetFrmFmt(); 1328 SwDoc *pDoc = pFmt->GetDoc(); 1329 1330 // OD 26.06.2003 #108784# - allow drawing objects in header/footer. 1331 // But don't allow control objects in header/footer 1332 if( RES_DRAWFRMFMT == pFmt->Which() && 1333 pDoc->IsInHeaderFooter( pFmt->GetAnchor().GetCntntAnchor()->nNode ) ) 1334 { 1335 SwDrawContact* pDrawContact = 1336 static_cast<SwDrawContact*>(pFmt->FindContactObj()); 1337 if ( pDrawContact && 1338 pDrawContact->GetMaster() && 1339 ::CheckControlLayer( pDrawContact->GetMaster() ) ) 1340 { 1341 // das soll nicht meoglich sein; hier verhindern 1342 // Der Dtor des TxtHints loescht nicht das Zeichen. 1343 // Wenn ein CH_TXTATR_.. vorliegt, dann muss man 1344 // dieses explizit loeschen 1345 if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode ) 1346 { 1347 // loesche das Zeichen aus dem String ! 1348 ASSERT( ( CH_TXTATR_BREAKWORD == 1349 m_Text.GetChar(*pAttr->GetStart() ) || 1350 CH_TXTATR_INWORD == 1351 m_Text.GetChar(*pAttr->GetStart())), 1352 "where is my attribute character?" ); 1353 m_Text.Erase( *pAttr->GetStart(), 1 ); 1354 // Indizies Updaten 1355 SwIndex aTmpIdx( this, *pAttr->GetStart() ); 1356 Update( aTmpIdx, 1, sal_True ); 1357 } 1358 // do not record deletion of Format! 1359 ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo()); 1360 DestroyAttr( pAttr ); 1361 return false; 1362 } 1363 } 1364 break; 1365 } 1366 1367 case RES_TXTATR_FTN : 1368 { 1369 // Fussnoten, man kommt an alles irgendwie heran. 1370 // CntntNode erzeugen und in die Inserts-Section stellen 1371 SwDoc *pDoc = GetDoc(); 1372 SwNodes &rNodes = pDoc->GetNodes(); 1373 1374 // FussNote in nicht Content-/Redline-Bereich einfuegen ?? 1375 if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() ) 1376 { 1377 // das soll nicht meoglich sein; hier verhindern 1378 // Der Dtor des TxtHints loescht nicht das Zeichen. 1379 // Wenn ein CH_TXTATR_.. vorliegt, dann muss man 1380 // dieses explizit loeschen 1381 if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode ) 1382 { 1383 // loesche das Zeichen aus dem String ! 1384 ASSERT( ( CH_TXTATR_BREAKWORD == 1385 m_Text.GetChar(*pAttr->GetStart() ) || 1386 CH_TXTATR_INWORD == 1387 m_Text.GetChar(*pAttr->GetStart())), 1388 "where is my attribute character?" ); 1389 m_Text.Erase( *pAttr->GetStart(), 1 ); 1390 // Indizies Updaten 1391 SwIndex aTmpIdx( this, *pAttr->GetStart() ); 1392 Update( aTmpIdx, 1, sal_True ); 1393 } 1394 DestroyAttr( pAttr ); 1395 return false; 1396 } 1397 1398 // wird eine neue Fussnote eingefuegt ?? 1399 sal_Bool bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode(); 1400 if( bNewFtn ) 1401 { 1402 ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() ); 1403 SwRegHistory* pHist = GetpSwpHints() 1404 ? GetpSwpHints()->GetHistory() : 0; 1405 if( pHist ) 1406 pHist->ChangeNodeIndex( GetIndex() ); 1407 } 1408 else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() ) 1409 { 1410 // loesche alle Frames der Section, auf die der StartNode zeigt 1411 sal_uLong nSttIdx = 1412 ((SwTxtFtn*)pAttr)->GetStartNode()->GetIndex(); 1413 sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex(); 1414 SwCntntNode* pCNd; 1415 for( ; nSttIdx < nEndIdx; ++nSttIdx ) 1416 if( 0 != ( pCNd = rNodes[ nSttIdx ]->GetCntntNode() )) 1417 pCNd->DelFrms(); 1418 } 1419 1420 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) ) 1421 { 1422 // Wir muessen zuerst einfuegen, da sonst gleiche Indizes 1423 // entstehen koennen und das Attribut im _SortArr_ am 1424 // Dokument nicht eingetrage wird. 1425 SwIndex aNdIdx( this, *pAttr->GetStart() ); 1426 const sal_Unicode c = GetCharOfTxtAttr(*pAttr); 1427 InsertText( c, aNdIdx, nInsertFlags ); 1428 nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR; 1429 } 1430 1431 // Wir tragen uns am FtnIdx-Array des Docs ein ... 1432 SwTxtFtn* pTxtFtn = 0; 1433 if( !bNewFtn ) 1434 { 1435 // eine alte Ftn wird umgehaengt (z.B. SplitNode) 1436 for( sal_uInt16 n = 0; n < pDoc->GetFtnIdxs().Count(); ++n ) 1437 if( pAttr == pDoc->GetFtnIdxs()[n] ) 1438 { 1439 // neuen Index zuweisen, dafuer aus dem SortArray 1440 // loeschen und neu eintragen 1441 pTxtFtn = pDoc->GetFtnIdxs()[n]; 1442 pDoc->GetFtnIdxs().Remove( n ); 1443 break; 1444 } 1445 // wenn ueber Undo der StartNode gesetzt wurde, kann 1446 // der Index noch gar nicht in der Verwaltung stehen !! 1447 } 1448 if( !pTxtFtn ) 1449 pTxtFtn = (SwTxtFtn*)pAttr; 1450 1451 // fuers Update der Nummern und zum Sortieren 1452 // muss der Node gesetzt sein. 1453 ((SwTxtFtn*)pAttr)->ChgTxtNode( this ); 1454 1455 // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen! 1456 if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() ) 1457 { 1458 #ifdef DBG_UTIL 1459 const sal_Bool bSuccess = 1460 #endif 1461 pDoc->GetFtnIdxs().Insert( pTxtFtn ); 1462 #ifdef DBG_UTIL 1463 ASSERT( bSuccess, "FtnIdx nicht eingetragen." ); 1464 #endif 1465 } 1466 SwNodeIndex aTmpIndex( *this ); 1467 pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex); 1468 ((SwTxtFtn*)pAttr)->SetSeqRefNo(); 1469 } 1470 break; 1471 1472 case RES_TXTATR_FIELD: 1473 { 1474 // fuer HiddenParaFields Benachrichtigungsmechanismus 1475 // anwerfen 1476 if( RES_HIDDENPARAFLD == pAttr->GetFmtFld().GetField()->GetTyp()->Which() ) 1477 { 1478 bHiddenPara = true; 1479 } 1480 } 1481 break; 1482 1483 } 1484 // Fuer SwTxtHints ohne Endindex werden CH_TXTATR_.. 1485 // eingefuegt, aStart muss danach um einen zurueckgesetzt werden. 1486 // Wenn wir im SwTxtNode::Copy stehen, so wurde das Zeichen bereits 1487 // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden. 1488 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) ) 1489 { 1490 SwIndex aIdx( this, *pAttr->GetStart() ); 1491 InsertText( GetCharOfTxtAttr(*pAttr), aIdx, nInsertFlags ); 1492 1493 // adjust end of hint to account for inserted CH_TXTATR 1494 xub_StrLen * const pEnd(pAttr->GetEnd()); 1495 if (pEnd) 1496 { 1497 *pEnd = *pEnd + 1; 1498 } 1499 } 1500 } 1501 1502 // handle attributes which provide content 1503 xub_StrLen nEnd = nStart; 1504 bool bInputFieldStartCharInserted = false; 1505 bool bInputFieldEndCharInserted = false; 1506 const bool bHasContent( pAttr->HasContent() ); 1507 if ( bHasContent ) 1508 { 1509 switch( pAttr->Which() ) 1510 { 1511 case RES_TXTATR_INPUTFIELD: 1512 { 1513 SwTxtInputFld* pTxtInputFld = dynamic_cast<SwTxtInputFld*>(pAttr); 1514 if ( pTxtInputFld ) 1515 { 1516 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) ) 1517 { 1518 SwIndex aIdx( this, *pAttr->GetStart() ); 1519 InsertText( CH_TXT_ATR_INPUTFIELDSTART, aIdx, nInsertFlags ); 1520 const String aContent = pTxtInputFld->GetFieldContent(); 1521 InsertText( aContent, aIdx, nInsertFlags ); 1522 InsertText( CH_TXT_ATR_INPUTFIELDEND, aIdx, nInsertFlags ); 1523 1524 xub_StrLen * const pEnd(pAttr->GetEnd()); 1525 ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" ); 1526 if ( pEnd != NULL ) 1527 { 1528 *pEnd = *pEnd + 2 + aContent.Len(); 1529 nEnd = *pEnd; 1530 } 1531 } 1532 else 1533 { 1534 // assure that CH_TXT_ATR_INPUTFIELDSTART and CH_TXT_ATR_INPUTFIELDEND are inserted. 1535 if ( m_Text.GetChar( *(pAttr->GetStart()) ) != CH_TXT_ATR_INPUTFIELDSTART ) 1536 { 1537 SwIndex aIdx( this, *pAttr->GetStart() ); 1538 InsertText( CH_TXT_ATR_INPUTFIELDSTART, aIdx, nInsertFlags ); 1539 bInputFieldStartCharInserted = true; 1540 xub_StrLen * const pEnd(pAttr->GetEnd()); 1541 ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" ); 1542 if ( pEnd != NULL ) 1543 { 1544 *pEnd = *pEnd + 1; 1545 nEnd = *pEnd; 1546 } 1547 } 1548 1549 xub_StrLen * const pEnd(pAttr->GetEnd()); 1550 ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" ); 1551 if ( pEnd != NULL 1552 && m_Text.GetChar( *(pEnd) - 1 ) != CH_TXT_ATR_INPUTFIELDEND ) 1553 { 1554 SwIndex aIdx( this, *(pEnd) ); 1555 InsertText( CH_TXT_ATR_INPUTFIELDEND, aIdx, nInsertFlags ); 1556 bInputFieldEndCharInserted = true; 1557 *pEnd = *pEnd + 1; 1558 nEnd = *pEnd; 1559 } 1560 } 1561 } 1562 } 1563 break; 1564 default: 1565 break; 1566 } 1567 } 1568 1569 GetOrCreateSwpHints(); 1570 1571 // handle overlap with an existing InputField 1572 bool bInsertHint = true; 1573 { 1574 const SwTxtInputFld* pTxtInputFld = GetOverlappingInputFld( *pAttr ); 1575 if ( pTxtInputFld != NULL ) 1576 { 1577 if ( pAttr->End() == NULL ) 1578 { 1579 bInsertHint = false; 1580 } 1581 else 1582 { 1583 if ( *(pAttr->GetStart()) > *(pTxtInputFld->GetStart()) ) 1584 { 1585 *(pAttr->GetStart()) = *(pTxtInputFld->GetStart()); 1586 } 1587 if ( *(pAttr->End()) < *(pTxtInputFld->End()) ) 1588 { 1589 *(pAttr->GetEnd()) = *(pTxtInputFld->End()); 1590 } 1591 } 1592 } 1593 } 1594 1595 // 4263: AttrInsert durch TextInsert => kein Adjust 1596 const bool bRet = bInsertHint 1597 ? m_pSwpHints->TryInsertHint( pAttr, *this, nMode ) 1598 : false; 1599 1600 if ( !bRet ) 1601 { 1602 if ( bDummyChar 1603 && !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) ) 1604 { 1605 // undo insertion of dummy character 1606 // N.B. cannot insert the dummy character after inserting the hint, 1607 // because if the hint has no extent it will be moved in InsertText, 1608 // resulting in infinite recursion 1609 ASSERT( ( CH_TXTATR_BREAKWORD == m_Text.GetChar(nStart) || 1610 CH_TXTATR_INWORD == m_Text.GetChar(nStart) ), 1611 "where is my attribute character?" ); 1612 SwIndex aIdx( this, nStart ); 1613 EraseText( aIdx, 1 ); 1614 } 1615 1616 if ( bHasContent ) 1617 { 1618 if ( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) 1619 && (nEnd - nStart) > 0 ) 1620 { 1621 SwIndex aIdx( this, nStart ); 1622 EraseText( aIdx, (nEnd - nStart) ); 1623 } 1624 else 1625 { 1626 if ( bInputFieldEndCharInserted 1627 && (nEnd - nStart) > 0 ) 1628 { 1629 SwIndex aIdx( this, nEnd - 1 ); 1630 EraseText( aIdx, 1 ); 1631 } 1632 1633 if ( bInputFieldStartCharInserted ) 1634 { 1635 SwIndex aIdx( this, nStart ); 1636 EraseText( aIdx, 1 ); 1637 } 1638 } 1639 } 1640 } 1641 1642 if ( bHiddenPara ) 1643 { 1644 SetCalcHiddenParaField(); 1645 } 1646 1647 return bRet; 1648 } 1649 1650 1651 /************************************************************************* 1652 * SwTxtNode::DeleteAttribute() 1653 *************************************************************************/ 1654 1655 void SwTxtNode::DeleteAttribute( SwTxtAttr * const pAttr ) 1656 { 1657 if ( !HasHints() ) 1658 { 1659 ASSERT(false, "DeleteAttribute called, but text node without hints?"); 1660 return; 1661 } 1662 1663 if ( pAttr->HasDummyChar() ) 1664 { 1665 // Unbedingt Copy-konstruieren! 1666 const SwIndex aIdx( this, *pAttr->GetStart() ); 1667 // erase the CH_TXTATR, which will also delete pAttr 1668 EraseText( aIdx, 1 ); 1669 } 1670 else if ( pAttr->HasContent() ) 1671 { 1672 const SwIndex aIdx( this, *pAttr->GetStart() ); 1673 ASSERT( pAttr->End() != NULL, "<SwTxtNode::DeleteAttribute(..)> - missing End() at <SwTxtAttr> instance which has content" ); 1674 EraseText( aIdx, *pAttr->End() - *pAttr->GetStart() ); 1675 } 1676 else 1677 { 1678 // create MsgHint before start/end become invalid 1679 SwUpdateAttr aHint( 1680 *pAttr->GetStart(), *pAttr->GetEnd(), pAttr->Which() ); 1681 m_pSwpHints->Delete( pAttr ); 1682 SwTxtAttr::Destroy( pAttr, GetDoc()->GetAttrPool() ); 1683 NotifyClients( 0, &aHint ); 1684 1685 TryDeleteSwpHints(); 1686 } 1687 } 1688 1689 /************************************************************************* 1690 * SwTxtNode::DeleteAttributes() 1691 *************************************************************************/ 1692 1693 //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)! 1694 void SwTxtNode::DeleteAttributes( 1695 const sal_uInt16 nWhich, 1696 const xub_StrLen nStart, 1697 const xub_StrLen nEnd ) 1698 { 1699 if ( !HasHints() ) 1700 return; 1701 1702 for ( sal_uInt16 nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); nPos++ ) 1703 { 1704 SwTxtAttr * const pTxtHt = m_pSwpHints->GetTextHint( nPos ); 1705 const xub_StrLen nHintStart = *(pTxtHt->GetStart()); 1706 if (nStart < nHintStart) 1707 { 1708 break; // sorted by start 1709 } 1710 else if ( (nStart == nHintStart) && (nWhich == pTxtHt->Which()) ) 1711 { 1712 if ( nWhich == RES_CHRATR_HIDDEN ) 1713 { 1714 ASSERT(false, "hey, that's a CHRATR! how did that get in?"); 1715 SetCalcHiddenCharFlags(); 1716 } 1717 else if ( nWhich == RES_TXTATR_CHARFMT ) 1718 { 1719 // Check if character format contains hidden attribute: 1720 const SwCharFmt* pFmt = pTxtHt->GetCharFmt().GetCharFmt(); 1721 const SfxPoolItem* pItem; 1722 if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) ) 1723 SetCalcHiddenCharFlags(); 1724 } 1725 // Recalc hidden flags if necessary 1726 else if ( nWhich == RES_TXTATR_AUTOFMT ) 1727 { 1728 // Check if auto style contains hidden attribute: 1729 const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN ); 1730 if ( pHiddenItem ) 1731 SetCalcHiddenCharFlags(); 1732 } 1733 1734 xub_StrLen const * const pEndIdx = pTxtHt->GetEnd(); 1735 1736 if ( pTxtHt->HasDummyChar() ) 1737 { 1738 // Unbedingt Copy-konstruieren! 1739 const SwIndex aIdx( this, nStart ); 1740 // erase the CH_TXTATR, which will also delete pTxtHt 1741 EraseText( aIdx, 1 ); 1742 } 1743 else if ( pTxtHt->HasContent() ) 1744 { 1745 const SwIndex aIdx( this, nStart ); 1746 ASSERT( pTxtHt->End() != NULL, "<SwTxtNode::DeleteAttributes(..)> - missing End() at <SwTxtAttr> instance which has content" ); 1747 EraseText( aIdx, *pTxtHt->End() - nStart ); 1748 } 1749 else if( *pEndIdx == nEnd ) 1750 { 1751 // den MsgHint jetzt fuettern, weil gleich sind 1752 // Start und End weg. 1753 // Das CalcVisibleFlag bei HiddenParaFields entfaellt, 1754 // da dies das Feld im Dtor selbst erledigt. 1755 SwUpdateAttr aHint( nStart, *pEndIdx, nWhich ); 1756 m_pSwpHints->DeleteAtPos( nPos ); // gefunden, loeschen, 1757 SwTxtAttr::Destroy( pTxtHt, GetDoc()->GetAttrPool() ); 1758 NotifyClients( 0, &aHint ); 1759 } 1760 } 1761 } 1762 TryDeleteSwpHints(); 1763 } 1764 1765 /************************************************************************* 1766 * SwTxtNode::DelSoftHyph() 1767 *************************************************************************/ 1768 1769 void SwTxtNode::DelSoftHyph( const xub_StrLen nStt, const xub_StrLen nEnd ) 1770 { 1771 xub_StrLen nFndPos = nStt, nEndPos = nEnd; 1772 while( STRING_NOTFOUND != 1773 ( nFndPos = m_Text.Search( CHAR_SOFTHYPHEN, nFndPos )) && 1774 nFndPos < nEndPos ) 1775 { 1776 const SwIndex aIdx( this, nFndPos ); 1777 EraseText( aIdx, 1 ); 1778 --nEndPos; 1779 } 1780 } 1781 1782 //Modify here for #119405, by easyfan, 2012-05-24 1783 //In MS Word, the font underline setting of the paragraph end position wont affect the formatting of numbering, so we ignore it 1784 bool lcl_IsIgnoredCharFmtForNumbering(const sal_uInt16 nWhich) 1785 { 1786 return (nWhich == RES_CHRATR_UNDERLINE); 1787 } 1788 1789 //In MS Word, following properties of the paragraph end position wont affect the formatting of bullets, so we ignore them: 1790 //Font underline; 1791 //Font Italic of Western, CJK and CTL; 1792 //Font Bold of Wertern, CJK and CTL; 1793 bool lcl_IsIgnoredCharFmtForBullets(const sal_uInt16 nWhich) 1794 { 1795 return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_POSTURE || nWhich == RES_CHRATR_WEIGHT 1796 || nWhich == RES_CHRATR_CJK_POSTURE || nWhich == RES_CHRATR_CJK_WEIGHT 1797 || nWhich == RES_CHRATR_CTL_POSTURE || nWhich == RES_CHRATR_CTL_WEIGHT); 1798 } 1799 1800 //Condition for expanding char set to character style of specified number rule level: 1801 //The item inside the set should not conflict to any exist and non-default item inside paragraph properties set (SwCntntNode::SwPAttrSet); 1802 //The node should have applied a number rule; 1803 //The node should be counted in a list, if not, make it to be; 1804 //The item should not conflict to any exist and non-default item inside the character of specified number rule level; 1805 //The item should not be ignored depend on the exact number rule type; 1806 bool SwTxtNode::TryCharSetExpandToNum(const SfxItemSet& aCharSet) 1807 { 1808 bool bRet = false; 1809 SfxItemIter aIter( aCharSet ); 1810 const SfxPoolItem* pItem = aIter.FirstItem(); 1811 const sal_uInt16 nWhich = pItem->Which(); 1812 1813 const SfxPoolItem& rInnerItem = GetAttr(nWhich,false); 1814 1815 if (!IsDefaultItem(&rInnerItem) && !IsInvalidItem(&rInnerItem)) 1816 return bRet; 1817 1818 if ( !IsInList() && GetNumRule() && GetListId().Len() > 0 ) 1819 { 1820 return bRet; 1821 } 1822 1823 SwNumRule* pCurrNum = GetNumRule(false); 1824 1825 int nLevel = GetActualListLevel(); 1826 1827 if (nLevel != -1 && pCurrNum) 1828 { 1829 const SwNumFmt* pCurrNumFmt = pCurrNum->GetNumFmt(static_cast<sal_uInt16>(nLevel)); 1830 if (pCurrNumFmt) 1831 { 1832 if (pCurrNumFmt->IsItemize() && lcl_IsIgnoredCharFmtForBullets(nWhich)) 1833 return bRet; 1834 if (pCurrNumFmt->IsEnumeration() && lcl_IsIgnoredCharFmtForNumbering(nWhich)) 1835 return bRet; 1836 SwCharFmt* pCurrCharFmt =pCurrNumFmt->GetCharFmt(); 1837 1838 if (pCurrCharFmt && pCurrCharFmt->GetItemState(nWhich,false) != SFX_ITEM_SET) 1839 { 1840 pCurrCharFmt->SetFmtAttr(*pItem); 1841 SwNumFmt aNewNumFmt(*pCurrNumFmt); 1842 aNewNumFmt.SetCharFmt(pCurrCharFmt); 1843 pCurrNum->Set(nLevel,aNewNumFmt); 1844 bRet = true; 1845 } 1846 } 1847 } 1848 1849 1850 return bRet; 1851 } 1852 //End of modification, by easyfan 1853 1854 // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt, 1855 // dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr) 1856 sal_Bool SwTxtNode::SetAttr( 1857 const SfxItemSet& rSet, 1858 const xub_StrLen nStt, 1859 const xub_StrLen nEnd, 1860 const SetAttrMode nMode ) 1861 { 1862 if( !rSet.Count() ) 1863 return sal_False; 1864 1865 // teil die Sets auf (fuer Selektion in Nodes) 1866 const SfxItemSet* pSet = &rSet; 1867 SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 ); 1868 1869 // gesamter Bereich 1870 if ( !nStt && (nEnd == m_Text.Len()) && 1871 !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) ) 1872 { 1873 // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute 1874 // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden. 1875 int bHasCharFmts = sal_False; 1876 if ( HasHints() ) 1877 { 1878 for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n ) 1879 { 1880 if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() ) 1881 { 1882 bHasCharFmts = sal_True; 1883 break; 1884 } 1885 } 1886 } 1887 1888 if( !bHasCharFmts ) 1889 { 1890 aTxtSet.Put( rSet ); 1891 // If there are any character attributes in rSet, 1892 // we want to set them at the paragraph: 1893 if( aTxtSet.Count() != rSet.Count() ) 1894 { 1895 sal_Bool bRet = SetAttr( rSet ); 1896 if( !aTxtSet.Count() ) 1897 return bRet; 1898 } 1899 1900 // check for auto style: 1901 const SfxPoolItem* pItem; 1902 const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, sal_False, &pItem ); 1903 if ( bAutoStyle ) 1904 { 1905 boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle(); 1906 sal_Bool bRet = SetAttr( *pAutoStyleSet ); 1907 if( 1 == aTxtSet.Count() ) 1908 return bRet; 1909 } 1910 1911 // Continue with the text attributes: 1912 pSet = &aTxtSet; 1913 } 1914 } 1915 1916 GetOrCreateSwpHints(); 1917 1918 SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange ); 1919 1920 sal_uInt16 nCount = 0; 1921 SfxItemIter aIter( *pSet ); 1922 const SfxPoolItem* pItem = aIter.GetCurItem(); 1923 1924 do 1925 { 1926 if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem)) 1927 { 1928 const sal_uInt16 nWhich = pItem->Which(); 1929 ASSERT( isCHRATR(nWhich) || isTXTATR(nWhich), 1930 "SwTxtNode::SetAttr(): unknown attribute" ); 1931 if ( isCHRATR(nWhich) || isTXTATR(nWhich) ) 1932 { 1933 if ((RES_TXTATR_CHARFMT == nWhich) && 1934 (GetDoc()->GetDfltCharFmt() == 1935 static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt())) 1936 { 1937 SwIndex aIndex( this, nStt ); 1938 RstTxtAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 ); 1939 DontExpandFmt( aIndex ); 1940 } 1941 else 1942 { 1943 if (isCHRATR(nWhich) || 1944 (RES_TXTATR_UNKNOWN_CONTAINER == nWhich)) 1945 { 1946 aCharSet.Put( *pItem ); 1947 } 1948 else 1949 { 1950 1951 SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(), 1952 const_cast<SfxPoolItem&>(*pItem), nStt, nEnd ); 1953 if ( pNew ) 1954 { 1955 if ( nEnd != nStt && !pNew->GetEnd() ) 1956 { 1957 ASSERT(false, 1958 "Attribut without end, but area marked"); 1959 DestroyAttr( pNew ); // do not insert 1960 } 1961 else if ( InsertHint( pNew, nMode ) ) 1962 { 1963 ++nCount; 1964 } 1965 } 1966 } 1967 } 1968 } 1969 } 1970 if ( aIter.IsAtEnd() ) 1971 break; 1972 pItem = aIter.NextItem(); 1973 } while( true ); 1974 1975 if ( aCharSet.Count() ) 1976 { 1977 SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd ); 1978 if ( InsertHint( pTmpNew, nMode ) ) 1979 { 1980 ++nCount; 1981 } 1982 } 1983 1984 TryDeleteSwpHints(); 1985 1986 return nCount ? sal_True : sal_False; 1987 } 1988 1989 void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr ) 1990 { 1991 if ( RES_TXTATR_AUTOFMT == rAttr.Which() ) 1992 { 1993 const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr ); 1994 if ( !pCFSet ) 1995 return; 1996 SfxWhichIter aIter( *pCFSet ); 1997 sal_uInt16 nWhich = aIter.FirstWhich(); 1998 while( nWhich ) 1999 { 2000 if( ( nWhich < RES_CHRATR_END || 2001 RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) && 2002 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) ) 2003 rSet.Put( pCFSet->Get( nWhich ) ); 2004 nWhich = aIter.NextWhich(); 2005 } 2006 } 2007 else 2008 rSet.Put( rAttr ); 2009 } 2010 2011 void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr ) 2012 { 2013 if( RES_TXTATR_CHARFMT == rAttr.Which() || 2014 RES_TXTATR_INETFMT == rAttr.Which() || 2015 RES_TXTATR_AUTOFMT == rAttr.Which() ) 2016 { 2017 const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr ); 2018 2019 if ( pCFSet ) 2020 { 2021 SfxWhichIter aIter( *pCFSet ); 2022 sal_uInt16 nWhich = aIter.FirstWhich(); 2023 while( nWhich ) 2024 { 2025 if( ( nWhich < RES_CHRATR_END || 2026 ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) && 2027 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) ) 2028 rSet.Put( pCFSet->Get( nWhich ) ); 2029 nWhich = aIter.NextWhich(); 2030 } 2031 } 2032 } 2033 2034 // aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!) 2035 2036 /* wenn mehrere Attribute ueberlappen gewinnt der letze !! 2037 z.B 2038 1234567890123456789 2039 |------------| Font1 2040 |------| Font2 2041 ^ ^ 2042 |--| Abfragebereich: -> Gueltig ist Font2 2043 */ 2044 rSet.Put( rAttr ); 2045 } 2046 2047 struct SwPoolItemEndPair 2048 { 2049 public: 2050 const SfxPoolItem* mpItem; 2051 xub_StrLen mnEndPos; 2052 2053 SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {}; 2054 }; 2055 2056 // --> OD 2008-01-16 #newlistlevelattrs# 2057 void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode, 2058 SfxItemSet& rSet ) 2059 { 2060 if ( rTxtNode.AreListLevelIndentsApplicable() ) 2061 { 2062 const SwNumRule* pRule = rTxtNode.GetNumRule(); 2063 if ( pRule && rTxtNode.GetActualListLevel() >= 0 ) 2064 { 2065 const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel())); 2066 if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) 2067 { 2068 SvxLRSpaceItem aLR( RES_LR_SPACE ); 2069 aLR.SetTxtLeft( rFmt.GetIndentAt() ); 2070 aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) ); 2071 rSet.Put( aLR ); 2072 } 2073 } 2074 } 2075 } 2076 2077 // erfrage die Attribute vom TextNode ueber den Bereich 2078 // --> OD 2008-01-16 #newlistlevelattrs# 2079 sal_Bool SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd, 2080 sal_Bool bOnlyTxtAttr, sal_Bool bGetFromChrFmt, 2081 const bool bMergeIndentValuesOfNumRule ) const 2082 { 2083 if( HasHints() ) 2084 { 2085 /* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig 2086 * sind. Dabei gibt es folgende Faelle: 2087 * UnEindeutig wenn: (wenn != Format-Attribut) 2088 * - das Attribut liegt vollstaendig im Bereich 2089 * - das Attributende liegt im Bereich 2090 * - der Attributanfang liegt im Bereich: 2091 * Eindeutig (im Set mergen): 2092 * - das Attrib umfasst den Bereich 2093 * nichts tun: 2094 * das Attribut liegt ausserhalb des Bereiches 2095 */ 2096 2097 void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& ) 2098 = bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt 2099 : &lcl_MergeAttr; 2100 2101 // dann besorge mal die Auto-(Fmt)Attribute 2102 SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() ); 2103 if( !bOnlyTxtAttr ) 2104 { 2105 SwCntntNode::GetAttr( aFmtSet ); 2106 // --> OD 2008-01-16 #newlistlevelattrs# 2107 if ( bMergeIndentValuesOfNumRule ) 2108 { 2109 lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet ); 2110 } 2111 // <-- 2112 } 2113 2114 const sal_uInt16 nSize = m_pSwpHints->Count(); 2115 2116 if( nStt == nEnd ) // kein Bereich: 2117 { 2118 for (sal_uInt16 n = 0; n < nSize; ++n) 2119 { 2120 const SwTxtAttr* pHt = (*m_pSwpHints)[n]; 2121 const xub_StrLen nAttrStart = *pHt->GetStart(); 2122 if( nAttrStart > nEnd ) // ueber den Bereich hinaus 2123 break; 2124 2125 const xub_StrLen* pAttrEnd = pHt->End(); 2126 if ( ! pAttrEnd ) // no attributes without end 2127 continue; 2128 2129 if( ( nAttrStart < nStt && 2130 ( pHt->DontExpand() ? nStt < *pAttrEnd 2131 : nStt <= *pAttrEnd )) || 2132 ( nStt == nAttrStart && 2133 ( nAttrStart == *pAttrEnd || !nStt ))) 2134 (*fnMergeAttr)( rSet, pHt->GetAttr() ); 2135 } 2136 } 2137 else // es ist ein Bereich definiert 2138 { 2139 // --> FME 2007-03-13 #i75299# 2140 ::std::auto_ptr< std::vector< SwPoolItemEndPair > > pAttrArr; 2141 // <-- 2142 2143 const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) - 2144 static_cast<sal_uInt16>(RES_CHRATR_BEGIN); 2145 2146 for (sal_uInt16 n = 0; n < nSize; ++n) 2147 { 2148 const SwTxtAttr* pHt = (*m_pSwpHints)[n]; 2149 const xub_StrLen nAttrStart = *pHt->GetStart(); 2150 if( nAttrStart > nEnd ) // ueber den Bereich hinaus 2151 break; 2152 2153 const xub_StrLen* pAttrEnd = pHt->End(); 2154 if ( ! pAttrEnd ) // no attributes without end 2155 continue; 2156 2157 sal_Bool bChkInvalid = sal_False; 2158 if( nAttrStart <= nStt ) // vor oder genau Start 2159 { 2160 if( *pAttrEnd <= nStt ) // liegt davor 2161 continue; 2162 2163 if( nEnd <= *pAttrEnd ) // hinter oder genau Ende 2164 (*fnMergeAttr)( aFmtSet, pHt->GetAttr() ); 2165 else 2166 // else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) ) 2167 // uneindeutig 2168 bChkInvalid = sal_True; 2169 } 2170 else if( nAttrStart < nEnd // reicht in den Bereich 2171 )// && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) ) 2172 bChkInvalid = sal_True; 2173 2174 if( bChkInvalid ) 2175 { 2176 // uneindeutig ? 2177 ::std::auto_ptr< SfxItemIter > pItemIter; 2178 const SfxPoolItem* pItem = 0; 2179 2180 if ( RES_TXTATR_AUTOFMT == pHt->Which() ) 2181 { 2182 const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() ); 2183 if ( pAutoSet ) 2184 { 2185 pItemIter.reset( new SfxItemIter( *pAutoSet ) ); 2186 pItem = pItemIter->GetCurItem(); 2187 } 2188 } 2189 else 2190 pItem = &pHt->GetAttr(); 2191 2192 const sal_uInt16 nHintEnd = *pAttrEnd; 2193 2194 while ( pItem ) 2195 { 2196 const sal_uInt16 nHintWhich = pItem->Which(); 2197 ASSERT(!isUNKNOWNATR(nHintWhich), 2198 "SwTxtNode::GetAttr(): unkonwn attribute?"); 2199 2200 if ( !pAttrArr.get() ) 2201 { 2202 pAttrArr.reset( 2203 new std::vector< SwPoolItemEndPair >(coArrSz)); 2204 } 2205 2206 std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin(); 2207 if (isCHRATR(nHintWhich) || 2208 isTXTATR_WITHEND(nHintWhich)) 2209 { 2210 pPrev += nHintWhich - RES_CHRATR_BEGIN; 2211 } 2212 else 2213 { 2214 pPrev = pAttrArr->end(); 2215 } 2216 2217 #if OSL_DEBUG_LEVEL > 1 2218 SwPoolItemEndPair aTmp = *pPrev; 2219 #endif 2220 2221 if( pPrev != pAttrArr->end() ) 2222 { 2223 if( !pPrev->mpItem ) 2224 { 2225 if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) ) 2226 { 2227 if( nAttrStart > nStt ) 2228 { 2229 rSet.InvalidateItem( nHintWhich ); 2230 pPrev->mpItem = (SfxPoolItem*)-1; 2231 } 2232 else 2233 { 2234 pPrev->mpItem = pItem; 2235 pPrev->mnEndPos = nHintEnd; 2236 } 2237 } 2238 } 2239 else if( (SfxPoolItem*)-1 != pPrev->mpItem ) 2240 { 2241 if( pPrev->mnEndPos == nAttrStart && 2242 *pPrev->mpItem == *pItem ) 2243 { 2244 pPrev->mpItem = pItem; 2245 pPrev->mnEndPos = nHintEnd; 2246 } 2247 else 2248 { 2249 rSet.InvalidateItem( nHintWhich ); 2250 pPrev->mpItem = (SfxPoolItem*)-1; 2251 } 2252 } 2253 } 2254 2255 pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() ) 2256 ? pItemIter->NextItem() : 0; 2257 } // end while 2258 } 2259 } 2260 2261 if ( pAttrArr.get() ) 2262 { 2263 for (sal_uInt16 n = 0; n < coArrSz; ++n) 2264 { 2265 const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ]; 2266 if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) ) 2267 { 2268 const sal_uInt16 nWh = 2269 static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN); 2270 2271 if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende 2272 { 2273 if( *rItemPair.mpItem != aFmtSet.Get( nWh ) ) 2274 (*fnMergeAttr)( rSet, *rItemPair.mpItem ); 2275 } 2276 else 2277 // uneindeutig 2278 rSet.InvalidateItem( nWh ); 2279 } 2280 } 2281 } 2282 } 2283 if( aFmtSet.Count() ) 2284 { 2285 // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind 2286 aFmtSet.Differentiate( rSet ); 2287 // jetzt alle zusammen "mergen" 2288 rSet.Put( aFmtSet ); 2289 } 2290 } 2291 else if( !bOnlyTxtAttr ) 2292 { 2293 // dann besorge mal die Auto-(Fmt)Attribute 2294 SwCntntNode::GetAttr( rSet ); 2295 // --> OD 2008-01-16 #newlistlevelattrs# 2296 if ( bMergeIndentValuesOfNumRule ) 2297 { 2298 lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet ); 2299 } 2300 // <-- 2301 } 2302 2303 return rSet.Count() ? sal_True : sal_False; 2304 } 2305 2306 2307 namespace 2308 { 2309 2310 typedef std::pair<sal_uInt16, sal_uInt16> AttrSpan_t; 2311 typedef std::multimap<AttrSpan_t, const SwTxtAttr*> AttrSpanMap_t; 2312 2313 2314 struct IsAutoStyle 2315 { 2316 bool 2317 operator()(const AttrSpanMap_t::value_type& i_rAttrSpan) 2318 const 2319 { 2320 return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT; 2321 } 2322 }; 2323 2324 2325 /** Removes from io_rAttrSet all items that are set by style on the 2326 given span. 2327 */ 2328 struct RemovePresentAttrs 2329 { 2330 RemovePresentAttrs(SfxItemSet& io_rAttrSet) 2331 : m_rAttrSet(io_rAttrSet) 2332 { 2333 } 2334 2335 void 2336 operator()(const AttrSpanMap_t::value_type& i_rAttrSpan) 2337 const 2338 { 2339 if (!i_rAttrSpan.second) 2340 { 2341 return; 2342 } 2343 2344 const SwTxtAttr* const pAutoStyle(i_rAttrSpan.second); 2345 SfxItemIter aIter(m_rAttrSet); 2346 const SfxPoolItem* pItem(aIter.GetCurItem()); 2347 while (pItem) 2348 { 2349 const sal_uInt16 nWhich(pItem->Which()); 2350 if (CharFmt::IsItemIncluded(nWhich, pAutoStyle)) 2351 { 2352 m_rAttrSet.ClearItem(nWhich); 2353 } 2354 2355 if (aIter.IsAtEnd()) 2356 { 2357 break; 2358 } 2359 pItem = aIter.NextItem(); 2360 } 2361 } 2362 2363 private: 2364 SfxItemSet& m_rAttrSet; 2365 }; 2366 2367 2368 /** Collects all style-covered spans from i_rHints to o_rSpanMap. In 2369 addition inserts dummy spans with pointer to format equal to 0 for 2370 all gaps (i.e. spans not covered by any style). This simplifies 2371 creation of autostyles for all needed spans, but it means all code 2372 that tries to access the pointer has to check if it's non-null! 2373 */ 2374 void 2375 lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_uInt16 nLength, 2376 AttrSpanMap_t& o_rSpanMap) 2377 { 2378 sal_uInt16 nLastEnd(0); 2379 2380 for (sal_uInt16 i(0); i != i_rHints.Count(); ++i) 2381 { 2382 const SwTxtAttr* const pHint(i_rHints[i]); 2383 const sal_uInt16 nWhich(pHint->Which()); 2384 if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT) 2385 { 2386 const AttrSpan_t aSpan(*pHint->GetStart(), *pHint->End()); 2387 o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint)); 2388 2389 // < not != because there may be multiple CHARFMT at same range 2390 if (nLastEnd < aSpan.first) 2391 { 2392 // insert dummy span covering the gap 2393 o_rSpanMap.insert(AttrSpanMap_t::value_type( 2394 AttrSpan_t(nLastEnd, aSpan.first), 0)); 2395 } 2396 2397 nLastEnd = aSpan.second; 2398 } 2399 } 2400 2401 // no hints at the end (special case: no hints at all in i_rHints) 2402 if (nLastEnd != nLength && nLength != 0) 2403 { 2404 o_rSpanMap.insert( 2405 AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), 0)); 2406 } 2407 } 2408 2409 2410 void 2411 lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds) 2412 { 2413 o_rClearIds.reserve(i_rAttrSet.Count()); 2414 SfxItemIter aIter(i_rAttrSet); 2415 const SfxPoolItem* pItem(aIter.GetCurItem()); 2416 while (true) 2417 { 2418 o_rClearIds.push_back(pItem->Which()); 2419 2420 if (aIter.IsAtEnd()) 2421 { 2422 break; 2423 } 2424 pItem = aIter.NextItem(); 2425 } 2426 } 2427 2428 struct SfxItemSetClearer 2429 { 2430 SfxItemSet & m_rItemSet; 2431 SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { } 2432 void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); } 2433 }; 2434 2435 } 2436 2437 2438 /** Does the hard work of SwTxtNode::FmtToTxtAttr: the real conversion 2439 of items to automatic styles. 2440 */ 2441 void 2442 SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet) 2443 { 2444 typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t; 2445 AttrSpanMap_t aAttrSpanMap; 2446 2447 if (i_rAttrSet.Count() == 0) 2448 { 2449 return; 2450 } 2451 2452 // 1. Identify all spans in hints' array 2453 2454 lcl_CollectHintSpans(*m_pSwpHints, m_Text.Len(), aAttrSpanMap); 2455 2456 // 2. Go through all spans and insert new attrs 2457 2458 AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin()); 2459 const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end()); 2460 while (aCurRange != aEnd) 2461 { 2462 typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t> 2463 AttrSpanMapRange_t; 2464 AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first)); 2465 2466 // 2a. Collect attributes to insert 2467 2468 SfxItemSet aCurSet(i_rAttrSet); 2469 std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet)); 2470 2471 // 2b. Insert automatic style containing the collected attributes 2472 2473 if (aCurSet.Count() != 0) 2474 { 2475 AttrSpanMap_iterator_t aAutoStyleIt( 2476 std::find_if(aRange.first, aRange.second, IsAutoStyle())); 2477 if (aAutoStyleIt != aRange.second) 2478 { 2479 // there already is an automatic style on that span: 2480 // create new one and remove the original one 2481 SwTxtAttr* const pAutoStyle(const_cast<SwTxtAttr*>(aAutoStyleIt->second)); 2482 const boost::shared_ptr<SfxItemSet> pOldStyle( 2483 static_cast<const SwFmtAutoFmt&>( 2484 pAutoStyle->GetAttr()).GetStyleHandle()); 2485 aCurSet.Put(*pOldStyle); 2486 2487 // remove the old hint 2488 m_pSwpHints->Delete(pAutoStyle); 2489 DestroyAttr(pAutoStyle); 2490 } 2491 m_pSwpHints->Insert( 2492 MakeTxtAttr(*GetDoc(), aCurSet, 2493 aCurRange->first.first, aCurRange->first.second)); 2494 } 2495 2496 aCurRange = aRange.second; 2497 } 2498 2499 // 3. Clear items from the node 2500 std::vector<sal_uInt16> aClearedIds; 2501 lcl_FillWhichIds(i_rAttrSet, aClearedIds); 2502 ClearItemsFromAttrSet(aClearedIds); 2503 } 2504 2505 void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd ) 2506 { 2507 SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange ); 2508 if( HasSwAttrSet() && GetpSwAttrSet()->Count() ) 2509 aThisSet.Put( *GetpSwAttrSet() ); 2510 2511 GetOrCreateSwpHints(); 2512 2513 if( pNd == this ) 2514 { 2515 impl_FmtToTxtAttr(aThisSet); 2516 } 2517 else 2518 { 2519 // There are five possible combinations of items from this and 2520 // pNd (pNd is the 'main' node): 2521 // 2522 // case pNd this action 2523 // ---------------------------------------------------- 2524 // 1 - - do nothing 2525 // 2 - a convert item to attr of this 2526 // 3 a - convert item to attr of pNd 2527 // 4 a a clear item in this 2528 // 5 a b convert item to attr of this 2529 2530 SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange ); 2531 if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() ) 2532 aNdSet.Put( *pNd->GetpSwAttrSet() ); 2533 2534 pNd->GetOrCreateSwpHints(); 2535 2536 std::vector<sal_uInt16> aProcessedIds; 2537 2538 if( aThisSet.Count() ) 2539 { 2540 SfxItemIter aIter( aThisSet ); 2541 const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0; 2542 SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFmtSetRange ); 2543 std::vector<sal_uInt16> aClearWhichIds; 2544 2545 while( true ) 2546 { 2547 if( SFX_ITEM_SET == aNdSet.GetItemState( pItem->Which(), sal_False, &pNdItem ) ) 2548 { 2549 if (*pItem == *pNdItem) // 4 2550 { 2551 aClearWhichIds.push_back( pItem->Which() ); 2552 } 2553 else // 5 2554 { 2555 aConvertSet.Put(*pItem); 2556 } 2557 aProcessedIds.push_back(pItem->Which()); 2558 } 2559 else // 2 2560 { 2561 aConvertSet.Put(*pItem); 2562 } 2563 2564 if( aIter.IsAtEnd() ) 2565 break; 2566 pItem = aIter.NextItem(); 2567 } 2568 2569 // 4/ clear items of this that are set with the same value on pNd 2570 ClearItemsFromAttrSet( aClearWhichIds ); 2571 2572 // 2, 5/ convert all other items to attrs 2573 impl_FmtToTxtAttr(aConvertSet); 2574 } 2575 2576 { 2577 std::for_each(aProcessedIds.begin(), aProcessedIds.end(), 2578 SfxItemSetClearer(aNdSet)); 2579 2580 // 3/ convert items to attrs 2581 pNd->impl_FmtToTxtAttr(aNdSet); 2582 2583 if( aNdSet.Count() ) 2584 { 2585 SwFmtChg aTmp1( pNd->GetFmtColl() ); 2586 pNd->NotifyClients( &aTmp1, &aTmp1 ); 2587 } 2588 } 2589 } 2590 2591 SetCalcHiddenCharFlags(); 2592 2593 pNd->TryDeleteSwpHints(); 2594 } 2595 2596 /************************************************************************* 2597 * SwpHints::CalcFlags() 2598 *************************************************************************/ 2599 2600 void SwpHints::CalcFlags() 2601 { 2602 m_bDDEFields = m_bFootnote = false; 2603 const sal_uInt16 nSize = Count(); 2604 const SwTxtAttr* pAttr; 2605 for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos ) 2606 { 2607 switch( ( pAttr = (*this)[ nPos ])->Which() ) 2608 { 2609 case RES_TXTATR_FTN: 2610 m_bFootnote = true; 2611 if ( m_bDDEFields ) 2612 return; 2613 break; 2614 case RES_TXTATR_FIELD: 2615 { 2616 const SwField* pFld = pAttr->GetFmtFld().GetField(); 2617 if( RES_DDEFLD == pFld->GetTyp()->Which() ) 2618 { 2619 m_bDDEFields = true; 2620 if ( m_bFootnote ) 2621 return; 2622 } 2623 } 2624 break; 2625 } 2626 } 2627 } 2628 2629 /************************************************************************* 2630 * SwpHints::CalcVisibleFlag() 2631 *************************************************************************/ 2632 2633 bool SwpHints::CalcHiddenParaField() 2634 { 2635 m_bCalcHiddenParaField = false; 2636 bool bOldHasHiddenParaField = m_bHasHiddenParaField; 2637 bool bNewHasHiddenParaField = false; 2638 const sal_uInt16 nSize = Count(); 2639 const SwTxtAttr *pTxtHt; 2640 2641 for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos ) 2642 { 2643 pTxtHt = (*this)[ nPos ]; 2644 const sal_uInt16 nWhich = pTxtHt->Which(); 2645 2646 if( RES_TXTATR_FIELD == nWhich ) 2647 { 2648 const SwFmtFld& rFld = pTxtHt->GetFmtFld(); 2649 if( RES_HIDDENPARAFLD == rFld.GetField()->GetTyp()->Which() ) 2650 { 2651 if( !((SwHiddenParaField*)rFld.GetField())->IsHidden() ) 2652 { 2653 SetHiddenParaField(false); 2654 return bOldHasHiddenParaField != bNewHasHiddenParaField; 2655 } 2656 else 2657 { 2658 bNewHasHiddenParaField = true; 2659 } 2660 } 2661 } 2662 } 2663 SetHiddenParaField( bNewHasHiddenParaField ); 2664 return bOldHasHiddenParaField != bNewHasHiddenParaField; 2665 } 2666 2667 2668 /************************************************************************* 2669 * SwpHints::NoteInHistory() 2670 *************************************************************************/ 2671 2672 void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew ) 2673 { 2674 if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); } 2675 } 2676 2677 /************************************************************************* 2678 * SwpHints::MergePortions( ) 2679 *************************************************************************/ 2680 2681 bool SwpHints::MergePortions( SwTxtNode& rNode ) 2682 { 2683 if ( !Count() ) 2684 return false; 2685 2686 // sort before merging 2687 SwpHintsArray::Resort(); 2688 2689 bool bRet = false; 2690 typedef std::multimap< int, SwTxtAttr* > PortionMap; 2691 PortionMap aPortionMap; 2692 xub_StrLen nLastPorStart = STRING_LEN; 2693 sal_uInt16 i = 0; 2694 int nKey = 0; 2695 2696 // get portions by start position: 2697 for ( i = 0; i < Count(); ++i ) 2698 { 2699 SwTxtAttr *pHt = GetTextHint( i ); 2700 if ( RES_TXTATR_CHARFMT != pHt->Which() && 2701 RES_TXTATR_AUTOFMT != pHt->Which() ) 2702 //&& 2703 //RES_TXTATR_INETFMT != pHt->Which() ) 2704 continue; 2705 2706 const xub_StrLen nPorStart = *pHt->GetStart(); 2707 if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN ) 2708 ++nKey; 2709 nLastPorStart = nPorStart; 2710 aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) ); 2711 } 2712 2713 // check if portion i can be merged with portion i+1: 2714 i = 0; 2715 int j = i + 1; 2716 while ( i <= nKey ) 2717 { 2718 std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i ); 2719 std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j ); 2720 PortionMap::iterator aIter1 = aRange1.first; 2721 PortionMap::iterator aIter2 = aRange2.first; 2722 2723 bool bMerge = true; 2724 const sal_uInt16 nAttributesInPor1 = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second )); 2725 const sal_uInt16 nAttributesInPor2 = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second )); 2726 2727 if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 ) 2728 { 2729 while ( aIter1 != aRange1.second ) 2730 { 2731 const SwTxtAttr* p1 = (*aIter1).second; 2732 const SwTxtAttr* p2 = (*aIter2).second; 2733 if ( *p1->End() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) ) 2734 { 2735 bMerge = false; 2736 break; 2737 } 2738 ++aIter1; 2739 ++aIter2; 2740 } 2741 } 2742 else 2743 { 2744 bMerge = false; 2745 } 2746 2747 if ( bMerge ) 2748 { 2749 // erase all elements with key i + 1 2750 xub_StrLen nNewPortionEnd = 0; 2751 for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 ) 2752 { 2753 SwTxtAttr* p2 = (*aIter2).second; 2754 nNewPortionEnd = *p2->GetEnd(); 2755 2756 const sal_uInt16 nCountBeforeDelete = Count(); 2757 Delete( p2 ); 2758 2759 // robust: check if deletion actually took place before destroying attribute: 2760 if ( Count() < nCountBeforeDelete ) 2761 rNode.DestroyAttr( p2 ); 2762 } 2763 aPortionMap.erase( aRange2.first, aRange2.second ); 2764 ++j; 2765 2766 // change all attributes with key i 2767 aRange1 = aPortionMap.equal_range( i ); 2768 for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 ) 2769 { 2770 SwTxtAttr* p1 = (*aIter1).second; 2771 NoteInHistory( p1 ); 2772 *p1->GetEnd() = nNewPortionEnd; 2773 NoteInHistory( p1, true ); 2774 bRet = true; 2775 } 2776 } 2777 else 2778 { 2779 ++i; 2780 j = i + 1; 2781 } 2782 } 2783 2784 if ( bRet ) 2785 { 2786 SwpHintsArray::Resort(); 2787 } 2788 2789 return bRet; 2790 } 2791 2792 // check if there is already a character format and adjust the sort numbers 2793 void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt ) 2794 { 2795 const xub_StrLen nHtStart = *rNewCharFmt.GetStart(); 2796 const xub_StrLen nHtEnd = *rNewCharFmt.GetEnd(); 2797 sal_uInt16 nSortNumber = 0; 2798 2799 for ( sal_uInt16 i = 0; i < rHints.Count(); ++i ) 2800 { 2801 const SwTxtAttr* pOtherHt = rHints[i]; 2802 2803 const xub_StrLen nOtherStart = *pOtherHt->GetStart(); 2804 2805 if ( nOtherStart > nHtStart ) 2806 break; 2807 2808 if ( RES_TXTATR_CHARFMT == pOtherHt->Which() ) 2809 { 2810 const xub_StrLen nOtherEnd = *pOtherHt->End(); 2811 2812 if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd ) 2813 { 2814 const sal_uInt16 nOtherSortNum = static_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber(); 2815 nSortNumber = nOtherSortNum + 1; 2816 } 2817 } 2818 } 2819 2820 if ( nSortNumber > 0 ) 2821 rNewCharFmt.SetSortNumber( nSortNumber ); 2822 } 2823 2824 /************************************************************************* 2825 * SwpHints::Insert() 2826 *************************************************************************/ 2827 2828 /* 2829 * Try to insert the new hint. 2830 * Depending on the type of the hint, this either always succeeds, or may fail. 2831 * Depending on the type of the hint, other hints may be deleted or 2832 * overwritten. 2833 * The return value indicates successful insertion. 2834 */ 2835 bool SwpHints::TryInsertHint( 2836 SwTxtAttr* const pHint, 2837 SwTxtNode &rNode, 2838 const SetAttrMode nMode ) 2839 { 2840 if ( USHRT_MAX == Count() ) // we're sorry, this flight is overbooked... 2841 { 2842 ASSERT(false, "hints array full :-("); 2843 return false; 2844 } 2845 2846 // Felder bilden eine Ausnahme: 2847 // 1) Sie koennen nie ueberlappen 2848 // 2) Wenn zwei Felder genau aneinander liegen, 2849 // sollen sie nicht zu einem verschmolzen werden. 2850 // Wir koennen also auf die while-Schleife verzichten 2851 2852 xub_StrLen *pHtEnd = pHint->GetEnd(); 2853 sal_uInt16 nWhich = pHint->Which(); 2854 2855 switch( nWhich ) 2856 { 2857 case RES_TXTATR_CHARFMT: 2858 { 2859 // Check if character format contains hidden attribute: 2860 const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt(); 2861 const SfxPoolItem* pItem; 2862 if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) ) 2863 rNode.SetCalcHiddenCharFlags(); 2864 2865 ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode ); 2866 break; 2867 } 2868 // --> FME 2007-03-16 #i75430# Recalc hidden flags if necessary 2869 case RES_TXTATR_AUTOFMT: 2870 { 2871 // Check if auto style contains hidden attribute: 2872 const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN ); 2873 if ( pHiddenItem ) 2874 rNode.SetCalcHiddenCharFlags(); 2875 break; 2876 } 2877 // <-- 2878 2879 case RES_TXTATR_INETFMT: 2880 static_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode); 2881 break; 2882 2883 case RES_TXTATR_FIELD: 2884 case RES_TXTATR_ANNOTATION: 2885 case RES_TXTATR_INPUTFIELD: 2886 { 2887 sal_Bool bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode(); 2888 ((SwTxtFld*)pHint)->ChgTxtNode( &rNode ); 2889 SwDoc* pDoc = rNode.GetDoc(); 2890 const SwField* pFld = ((SwTxtFld*)pHint)->GetFmtFld().GetField(); 2891 2892 if( !pDoc->IsNewFldLst() ) 2893 { 2894 // was fuer ein Feld ist es denn ?? 2895 // bestimmte Felder mussen am Doc das Calculations-Flag updaten 2896 switch( pFld->GetTyp()->Which() ) 2897 { 2898 case RES_DBFLD: 2899 case RES_SETEXPFLD: 2900 case RES_HIDDENPARAFLD: 2901 case RES_HIDDENTXTFLD: 2902 case RES_DBNUMSETFLD: 2903 case RES_DBNEXTSETFLD: 2904 { 2905 if( bDelFirst ) 2906 pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pHint ); 2907 if( rNode.GetNodes().IsDocNodes() ) 2908 pDoc->InsDelFldInFldLst( sal_True, *(SwTxtFld*)pHint ); 2909 } 2910 break; 2911 case RES_DDEFLD: 2912 if( rNode.GetNodes().IsDocNodes() ) 2913 ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt(); 2914 break; 2915 } 2916 } 2917 2918 // gehts ins normale Nodes-Array? 2919 if( rNode.GetNodes().IsDocNodes() ) 2920 { 2921 sal_Bool bInsFldType = sal_False; 2922 switch( pFld->GetTyp()->Which() ) 2923 { 2924 case RES_SETEXPFLD: 2925 bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted(); 2926 if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() ) 2927 { 2928 // bevor die ReferenzNummer gesetzt wird, sollte 2929 // das Feld am richtigen FeldTypen haengen! 2930 SwSetExpFieldType* pFldType = (SwSetExpFieldType*) 2931 pDoc->InsertFldType( *pFld->GetTyp() ); 2932 if( pFldType != pFld->GetTyp() ) 2933 { 2934 SwFmtFld* pFmtFld = (SwFmtFld*)&((SwTxtFld*)pHint)->GetFmtFld(); 2935 pFmtFld->RegisterToFieldType( *pFldType ); 2936 pFmtFld->GetField()->ChgTyp( pFldType ); 2937 } 2938 pFldType->SetSeqRefNo( *(SwSetExpField*)pFld ); 2939 } 2940 break; 2941 case RES_USERFLD: 2942 bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted(); 2943 break; 2944 2945 case RES_DDEFLD: 2946 if( pDoc->IsNewFldLst() ) 2947 ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt(); 2948 bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted(); 2949 break; 2950 2951 case RES_POSTITFLD: 2952 if ( pDoc->GetDocShell() ) 2953 pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_INSERTED ) ); 2954 break; 2955 } 2956 if( bInsFldType ) 2957 pDoc->InsDeletedFldType( *pFld->GetTyp() ); 2958 } 2959 } 2960 break; 2961 case RES_TXTATR_FTN : 2962 ((SwTxtFtn*)pHint)->ChgTxtNode( &rNode ); 2963 break; 2964 case RES_TXTATR_REFMARK: 2965 ((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode ); 2966 if( rNode.GetNodes().IsDocNodes() ) 2967 { 2968 // search for a reference with the same name 2969 SwTxtAttr* pTmpHt; 2970 xub_StrLen *pTmpHtEnd, *pTmpHintEnd; 2971 for( sal_uInt16 n = 0, nEnd = Count(); n < nEnd; ++n ) 2972 { 2973 if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() && 2974 pHint->GetAttr() == pTmpHt->GetAttr() && 2975 0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) && 2976 0 != ( pTmpHintEnd = pHint->GetEnd() ) ) 2977 { 2978 SwComparePosition eCmp = ::ComparePosition( 2979 *pTmpHt->GetStart(), *pTmpHtEnd, 2980 *pHint->GetStart(), *pTmpHintEnd ); 2981 sal_Bool bDelOld = sal_True, bChgStart = sal_False, bChgEnd = sal_False; 2982 switch( eCmp ) 2983 { 2984 case POS_BEFORE: 2985 case POS_BEHIND: bDelOld = sal_False; break; 2986 2987 case POS_OUTSIDE: bChgStart = bChgEnd = sal_True; break; 2988 2989 case POS_COLLIDE_END: 2990 case POS_OVERLAP_BEFORE: bChgStart = sal_True; break; 2991 case POS_COLLIDE_START: 2992 case POS_OVERLAP_BEHIND: bChgEnd = sal_True; break; 2993 default: break; 2994 } 2995 2996 if( bChgStart ) 2997 *pHint->GetStart() = *pTmpHt->GetStart(); 2998 if( bChgEnd ) 2999 *pTmpHintEnd = *pTmpHtEnd; 3000 3001 if( bDelOld ) 3002 { 3003 NoteInHistory( pTmpHt ); 3004 rNode.DestroyAttr( Cut( n-- ) ); 3005 --nEnd; 3006 } 3007 } 3008 } 3009 } 3010 break; 3011 case RES_TXTATR_TOXMARK: 3012 ((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode ); 3013 break; 3014 3015 case RES_TXTATR_CJK_RUBY: 3016 static_cast<SwTxtRuby*>(pHint)->InitRuby(rNode); 3017 break; 3018 3019 case RES_TXTATR_META: 3020 case RES_TXTATR_METAFIELD: 3021 static_cast<SwTxtMeta *>(pHint)->ChgTxtNode( &rNode ); 3022 break; 3023 3024 case RES_CHRATR_HIDDEN: 3025 rNode.SetCalcHiddenCharFlags(); 3026 break; 3027 } 3028 3029 if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode ) 3030 pHint->SetDontExpand( sal_True ); 3031 3032 // SwTxtAttrs ohne Ende werden sonderbehandelt: 3033 // Sie werden natuerlich in das Array insertet, aber sie werden nicht 3034 // in die pPrev/Next/On/Off-Verkettung aufgenommen. 3035 // Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text ! 3036 xub_StrLen nHtStart = *pHint->GetStart(); 3037 if( !pHtEnd ) 3038 { 3039 SwpHintsArray::Insert( pHint ); 3040 CalcFlags(); 3041 #ifdef DBG_UTIL 3042 if( !rNode.GetDoc()->IsInReading() ) 3043 CHECK; 3044 #endif 3045 // ... und die Abhaengigen benachrichtigen 3046 if ( rNode.GetDepends() ) 3047 { 3048 SwUpdateAttr aHint( nHtStart, nHtStart, nWhich ); 3049 rNode.ModifyNotification( 0, &aHint ); 3050 } 3051 return true; 3052 } 3053 3054 // ---------------------------------------------------------------- 3055 // Ab hier gibt es nur noch pHint mit einem EndIdx !!! 3056 3057 if( *pHtEnd < nHtStart ) 3058 { 3059 ASSERT( *pHtEnd >= nHtStart, 3060 "+SwpHints::Insert: invalid hint, end < start" ); 3061 3062 // Wir drehen den Quatsch einfach um: 3063 *pHint->GetStart() = *pHtEnd; 3064 *pHtEnd = nHtStart; 3065 nHtStart = *pHint->GetStart(); 3066 } 3067 3068 // I need this value later on for notification but the pointer may become invalid 3069 const xub_StrLen nHintEnd = *pHtEnd; 3070 const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode); 3071 3072 // handle nesting attributes: inserting may fail due to overlap! 3073 if (pHint->IsNesting()) 3074 { 3075 const bool bRet( 3076 TryInsertNesting(rNode, *static_cast<SwTxtAttrNesting*>(pHint))); 3077 if (!bRet) return false; 3078 } 3079 // Currently REFMARK and TOXMARK have OverlapAllowed set to true. 3080 // These attributes may be inserted directly. 3081 // Also attributes without length may be inserted directly. 3082 // SETATTR_NOHINTADJUST is set e.g., during undo. 3083 // Portion building in not necessary during XML import. 3084 else 3085 if ( !bNoHintAdjustMode && 3086 !pHint->IsOverlapAllowedAttr() && 3087 !rNode.GetDoc()->IsInXMLImport() && 3088 ( RES_TXTATR_AUTOFMT == nWhich || 3089 RES_TXTATR_CHARFMT == nWhich ) ) 3090 { 3091 ASSERT( nWhich != RES_TXTATR_AUTOFMT || 3092 static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() == 3093 &rNode.GetDoc()->GetAttrPool(), 3094 "AUTOSTYLES - Pool mismatch" ) 3095 3096 BuildPortions( rNode, *pHint, nMode ); 3097 3098 if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes 3099 MergePortions( rNode ); 3100 } 3101 else 3102 { 3103 // There may be more than one character style at the current position. 3104 // Take care of the sort number. 3105 // Special case ruby portion: During import, the ruby attribute is set 3106 // multiple times 3107 // Special case hyperlink: During import, the ruby attribute is set 3108 // multiple times 3109 // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert 3110 // character attributes directly 3111 if ( ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode ) ) 3112 { 3113 BuildPortions( rNode, *pHint, nMode ); 3114 } 3115 else 3116 { 3117 // --> FME 2007-11-08 #i82989# Check sort numbers in NoHintAdjustMode 3118 if ( RES_TXTATR_CHARFMT == nWhich ) 3119 lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) ); 3120 // <-- 3121 3122 SwpHintsArray::Insert( pHint ); 3123 NoteInHistory( pHint, true ); 3124 } 3125 } 3126 3127 // ... und die Abhaengigen benachrichtigen 3128 if ( rNode.GetDepends() ) 3129 { 3130 SwUpdateAttr aHint( nHtStart, nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd, nWhich ); 3131 rNode.ModifyNotification( 0, &aHint ); 3132 } 3133 3134 #ifdef DBG_UTIL 3135 if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() ) 3136 CHECK; 3137 #endif 3138 3139 return true; 3140 } 3141 3142 /************************************************************************* 3143 * SwpHints::DeleteAtPos() 3144 *************************************************************************/ 3145 3146 void SwpHints::DeleteAtPos( const sal_uInt16 nPos ) 3147 { 3148 SwTxtAttr *pHint = GetTextHint(nPos); 3149 // ChainDelete( pHint ); 3150 NoteInHistory( pHint ); 3151 SwpHintsArray::DeleteAtPos( nPos ); 3152 3153 if( pHint->Which() == RES_TXTATR_FIELD ) 3154 { 3155 const SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFmtFld().GetField()->GetTyp(); 3156 if( RES_DDEFLD == pFldTyp->Which() ) 3157 { 3158 const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode(); 3159 if( pNd && pNd->GetNodes().IsDocNodes() ) 3160 ((SwDDEFieldType*)pFldTyp)->DecRefCnt(); 3161 ((SwTxtFld*)pHint)->ChgTxtNode( 0 ); 3162 } 3163 else if ( m_bHasHiddenParaField && 3164 RES_HIDDENPARAFLD == pFldTyp->Which() ) 3165 { 3166 m_bCalcHiddenParaField = true; 3167 } 3168 } 3169 else if ( pHint->Which() == RES_TXTATR_ANNOTATION ) 3170 { 3171 const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_REMOVED ) ); 3172 } 3173 3174 CalcFlags(); 3175 CHECK; 3176 } 3177 3178 // Ist der Hint schon bekannt, dann suche die Position und loesche ihn. 3179 // Ist er nicht im Array, so gibt es ein ASSERT !! 3180 3181 void SwpHints::Delete( SwTxtAttr* pTxtHt ) 3182 { 3183 // Attr 2.0: SwpHintsArr::Delete( pTxtHt ); 3184 const sal_uInt16 nPos = GetStartOf( pTxtHt ); 3185 ASSERT( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" ); 3186 if( USHRT_MAX != nPos ) 3187 DeleteAtPos( nPos ); 3188 } 3189 3190 void SwTxtNode::ClearSwpHintsArr( bool bDelFields ) 3191 { 3192 if ( HasHints() ) 3193 { 3194 sal_uInt16 nPos = 0; 3195 while ( nPos < m_pSwpHints->Count() ) 3196 { 3197 SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos ); 3198 bool bDel = false; 3199 3200 switch( pDel->Which() ) 3201 { 3202 case RES_TXTATR_FLYCNT: 3203 case RES_TXTATR_FTN: 3204 break; 3205 3206 case RES_TXTATR_FIELD: 3207 case RES_TXTATR_ANNOTATION: 3208 case RES_TXTATR_INPUTFIELD: 3209 if( bDelFields ) 3210 bDel = true; 3211 break; 3212 default: 3213 bDel = true; break; 3214 } 3215 3216 if( bDel ) 3217 { 3218 m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos ); 3219 DestroyAttr( pDel ); 3220 } 3221 else 3222 ++nPos; 3223 } 3224 } 3225 } 3226 3227 sal_uInt16 SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen, 3228 sal_uInt16 nScript ) const 3229 { 3230 sal_uInt16 nRet = LANGUAGE_DONTKNOW; 3231 3232 if ( ! nScript ) 3233 { 3234 nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin ); 3235 } 3236 3237 // --> FME 2008-09-29 #i91465# hennerdrewes: Consider nScript if pSwpHints == 0 3238 const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript ); 3239 // <-- 3240 3241 if ( HasHints() ) 3242 { 3243 const xub_StrLen nEnd = nBegin + nLen; 3244 for ( sal_uInt16 i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i ) 3245 { 3246 // ist der Attribut-Anfang schon groesser als der Idx ? 3247 const SwTxtAttr *pHt = m_pSwpHints->operator[](i); 3248 const xub_StrLen nAttrStart = *pHt->GetStart(); 3249 if( nEnd < nAttrStart ) 3250 break; 3251 3252 const sal_uInt16 nWhich = pHt->Which(); 3253 3254 if( nWhichId == nWhich || 3255 ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) ) 3256 { 3257 const xub_StrLen *pEndIdx = pHt->End(); 3258 // Ueberlappt das Attribut den Bereich? 3259 3260 if( pEndIdx && 3261 nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx ) 3262 : (( nAttrStart < nBegin && 3263 ( pHt->DontExpand() ? nBegin < *pEndIdx 3264 : nBegin <= *pEndIdx )) || 3265 ( nBegin == nAttrStart && 3266 ( nAttrStart == *pEndIdx || !nBegin ))) ) 3267 { 3268 const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId ); 3269 sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage(); 3270 3271 // Umfasst das Attribut den Bereich komplett? 3272 if( nAttrStart <= nBegin && nEnd <= *pEndIdx ) 3273 nRet = nLng; 3274 else if( LANGUAGE_DONTKNOW == nRet ) 3275 nRet = nLng; // partielle Ueberlappung, der 1. gewinnt 3276 } 3277 } 3278 } 3279 } 3280 if( LANGUAGE_DONTKNOW == nRet ) 3281 { 3282 nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage(); 3283 if( LANGUAGE_DONTKNOW == nRet ) 3284 nRet = static_cast<sal_uInt16>(GetAppLanguage()); 3285 } 3286 return nRet; 3287 } 3288 3289 3290 sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr ) 3291 { 3292 sal_Unicode cRet = CH_TXTATR_BREAKWORD; 3293 switch ( rAttr.Which() ) 3294 { 3295 case RES_TXTATR_FTN: 3296 case RES_TXTATR_REFMARK: 3297 case RES_TXTATR_TOXMARK: 3298 case RES_TXTATR_META: 3299 case RES_TXTATR_METAFIELD: 3300 case RES_TXTATR_ANNOTATION: 3301 cRet = CH_TXTATR_INWORD; 3302 break; 3303 3304 case RES_TXTATR_FIELD: 3305 case RES_TXTATR_FLYCNT: 3306 { 3307 cRet = CH_TXTATR_BREAKWORD; 3308 } 3309 break; 3310 3311 default: 3312 ASSERT(false, "GetCharOfTxtAttr: unknown attr"); 3313 break; 3314 } 3315 return cRet; 3316 } 3317 3318 3319