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