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