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