1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sw.hxx" 26 27 28 #include <hintids.hxx> 29 #include <sot/factory.hxx> 30 #include <editeng/xmlcnitm.hxx> 31 #include <svl/whiter.hxx> 32 #include <svl/itemiter.hxx> 33 #include <svl/stylepool.hxx> 34 #include <editeng/fontitem.hxx> 35 #include <editeng/langitem.hxx> 36 #include <editeng/emphitem.hxx> 37 #include <editeng/charscaleitem.hxx> 38 #include <editeng/charrotateitem.hxx> 39 // --> OD 2008-01-16 #newlistlevelattrs# 40 #include <editeng/lrspitem.hxx> 41 // <-- 42 #include <txtinet.hxx> 43 #include <txtflcnt.hxx> 44 #include <fmtfld.hxx> 45 #include <fmtanchr.hxx> 46 #include <fmtinfmt.hxx> 47 #include <txtatr.hxx> 48 #include <fchrfmt.hxx> 49 #include <fmtautofmt.hxx> 50 #include <fmtflcnt.hxx> 51 #include <fmtftn.hxx> 52 #include <txttxmrk.hxx> 53 #include <txtrfmrk.hxx> 54 #include <txtftn.hxx> 55 #include <txtfld.hxx> 56 #include <charatr.hxx> 57 #include <charfmt.hxx> 58 #include <frmfmt.hxx> 59 #include <ftnidx.hxx> 60 #include <fmtruby.hxx> 61 #include <fmtmeta.hxx> 62 #include <breakit.hxx> 63 #include <doc.hxx> 64 #include <IDocumentUndoRedo.hxx> 65 #include <errhdl.hxx> 66 #include <fldbas.hxx> 67 #include <pam.hxx> 68 #include <ndtxt.hxx> 69 #include <txtfrm.hxx> 70 #include <rolbck.hxx> // fuer SwRegHistory 71 #include <ddefld.hxx> 72 #include <docufld.hxx> 73 #include <expfld.hxx> 74 #include <usrfld.hxx> 75 #include <poolfmt.hxx> 76 #include <swfont.hxx> 77 #include <istyleaccess.hxx> 78 // OD 26.06.2003 #108784# 79 #include <dcontact.hxx> 80 #include <docsh.hxx> 81 #include <svl/smplhint.hxx> 82 #include <algorithm> 83 #include <map> 84 85 #ifdef DBG_UTIL 86 #define CHECK Check(); 87 #else 88 #define CHECK 89 #endif 90 91 using namespace ::com::sun::star::i18n; 92 93 94 SwpHints::SwpHints() 95 : m_pHistory(0) 96 , m_bFontChange(true) 97 , m_bInSplitNode(false) 98 , m_bCalcHiddenParaField(false) 99 , m_bHasHiddenParaField(false) 100 , m_bFootnote(false) 101 , m_bDDEFields(false) 102 { 103 } 104 105 struct TxtAttrDeleter 106 { 107 SwAttrPool & m_rPool; 108 TxtAttrDeleter( SwDoc & rDoc ) : m_rPool( rDoc.GetAttrPool() ) { } 109 void operator() (SwTxtAttr * const pAttr) 110 { 111 if (RES_TXTATR_META == pAttr->Which() || 112 RES_TXTATR_METAFIELD == pAttr->Which()) 113 { 114 static_cast<SwTxtMeta *>(pAttr)->ChgTxtNode(0); // prevents ASSERT 115 } 116 SwTxtAttr::Destroy( pAttr, m_rPool ); 117 } 118 }; 119 120 struct TxtAttrContains 121 { 122 xub_StrLen m_nPos; 123 TxtAttrContains( const xub_StrLen nPos ) : m_nPos( nPos ) { } 124 bool operator() (SwTxtAttrEnd * const pAttr) 125 { 126 return (*pAttr->GetStart() < m_nPos) && (m_nPos < *pAttr->End()); 127 } 128 }; 129 130 // a: |-----| 131 // b: 132 // |---| => valid: b before a 133 // |-----| => valid: start == end; b before a 134 // |---------| => invalid: overlap (1) 135 // |-----------| => valid: same end; b around a 136 // |-----------------| => valid: b around a 137 // |---| => valid; same start; b within a 138 // |-----| => valid; same start and end; b around or within a? 139 // |-----------| => valid: same start: b around a 140 // |-| => valid: b within a 141 // |---| => valid: same end; b within a 142 // |---------| => invalid: overlap (2) 143 // |-----| => valid: end == start; b after a 144 // |---| => valid: b after a 145 // ===> 2 invalid overlap cases 146 static 147 bool isOverlap(const xub_StrLen nStart1, const xub_StrLen nEnd1, 148 const xub_StrLen nStart2, const xub_StrLen nEnd2) 149 { 150 return 151 ((nStart1 > nStart2) && (nStart1 < nEnd2) && (nEnd1 > nEnd2)) // (1) 152 || ((nStart1 < nStart2) && (nStart2 < nEnd1) && (nEnd1 < nEnd2)); // (2) 153 } 154 155 /// #i106930#: now asymmetric: empty hint1 is _not_ nested, but empty hint2 is 156 static 157 bool isNestedAny(const xub_StrLen nStart1, const xub_StrLen nEnd1, 158 const xub_StrLen nStart2, const xub_StrLen nEnd2) 159 { 160 return ((nStart1 == nStart2) || (nEnd1 == nEnd2)) 161 // same start/end: nested except if hint1 empty and hint2 not empty 162 ? (nStart1 != nEnd1) || (nStart2 == nEnd2) 163 : ((nStart1 < nStart2) ? (nEnd1 >= nEnd2) : (nEnd1 <= nEnd2)); 164 } 165 166 static 167 bool isSelfNestable(const sal_uInt16 nWhich) 168 { 169 if ((RES_TXTATR_INETFMT == nWhich) || 170 (RES_TXTATR_CJK_RUBY == nWhich) || 171 (RES_TXTATR_INPUTFIELD == nWhich)) 172 return false; 173 ASSERT((RES_TXTATR_META == nWhich) || 174 (RES_TXTATR_METAFIELD == nWhich), "???"); 175 return true; 176 } 177 178 static 179 bool isSplittable(const sal_uInt16 nWhich) 180 { 181 if ((RES_TXTATR_INETFMT == nWhich) || 182 (RES_TXTATR_CJK_RUBY == nWhich)) 183 return true; 184 ASSERT((RES_TXTATR_META == nWhich) || 185 (RES_TXTATR_METAFIELD == nWhich) || 186 (RES_TXTATR_INPUTFIELD == nWhich), "???"); 187 return false; 188 } 189 190 enum Split_t { FAIL, SPLIT_NEW, SPLIT_OTHER }; 191 /** 192 Calculate splitting policy for overlapping hints, based on what kind of 193 hint is inserted, and what kind of existing hint overlaps. 194 */ 195 static Split_t 196 splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther) 197 { 198 if (!isSplittable(nWhichOther)) 199 { 200 if (!isSplittable(nWhichNew)) 201 return FAIL; 202 else 203 return SPLIT_NEW; 204 } 205 else 206 { 207 if ( RES_TXTATR_INPUTFIELD == nWhichNew ) 208 return FAIL; 209 else 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 bNewSelfNestable( isSelfNestable(nNewWhich) ); 370 371 ASSERT( (RES_TXTATR_INETFMT == nNewWhich) || 372 (RES_TXTATR_CJK_RUBY == nNewWhich) || 373 (RES_TXTATR_META == nNewWhich) || 374 (RES_TXTATR_METAFIELD == nNewWhich) || 375 (RES_TXTATR_INPUTFIELD == nNewWhich), 376 "TryInsertNesting: Expecting INETFMT or RUBY or META or METAFIELD or INPUTFIELD" ); 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->End(); 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( 997 SwDoc & rDoc, 998 SfxPoolItem& rAttr, 999 xub_StrLen const nStt, 1000 xub_StrLen const nEnd, 1001 CopyOrNew_t const bIsCopy, 1002 SwTxtNode *const pTxtNode ) 1003 { 1004 if ( isCHRATR(rAttr.Which()) ) 1005 { 1006 // Somebody wants to build a SwTxtAttr for a character attribute. 1007 // Sorry, this is not allowed any longer. 1008 // You'll get a brand new autostyle attribute: 1009 SfxItemSet aItemSet( rDoc.GetAttrPool(), 1010 RES_CHRATR_BEGIN, RES_CHRATR_END ); 1011 aItemSet.Put( rAttr ); 1012 return MakeTxtAttr( rDoc, aItemSet, nStt, nEnd ); 1013 } 1014 else if ( RES_TXTATR_AUTOFMT == rAttr.Which() && 1015 static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle()-> 1016 GetPool() != &rDoc.GetAttrPool() ) 1017 { 1018 // If the attribute is an auto-style which refers to a pool that is 1019 // different from rDoc's pool, we have to correct this: 1020 const StylePool::SfxItemSet_Pointer_t pAutoStyle = static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle(); 1021 ::std::auto_ptr<const SfxItemSet> pNewSet( 1022 pAutoStyle->SfxItemSet::Clone( sal_True, &rDoc.GetAttrPool() )); 1023 SwTxtAttr* pNew = MakeTxtAttr( rDoc, *pNewSet, nStt, nEnd ); 1024 return pNew; 1025 } 1026 1027 // Put new attribute into pool 1028 // FIXME: this const_cast is evil! 1029 SfxPoolItem& rNew = 1030 const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) ); 1031 1032 SwTxtAttr* pNew = 0; 1033 switch( rNew.Which() ) 1034 { 1035 case RES_TXTATR_CHARFMT: 1036 { 1037 SwFmtCharFmt &rFmtCharFmt = (SwFmtCharFmt&) rNew; 1038 if( !rFmtCharFmt.GetCharFmt() ) 1039 { 1040 rFmtCharFmt.SetCharFmt( rDoc.GetDfltCharFmt() ); 1041 } 1042 1043 pNew = new SwTxtCharFmt( rFmtCharFmt, nStt, nEnd ); 1044 } 1045 break; 1046 case RES_TXTATR_INETFMT: 1047 pNew = new SwTxtINetFmt( (SwFmtINetFmt&)rNew, nStt, nEnd ); 1048 break; 1049 case RES_TXTATR_FIELD: 1050 pNew = new SwTxtFld( static_cast<SwFmtFld &>(rNew), nStt ); 1051 break; 1052 case RES_TXTATR_INPUTFIELD: 1053 pNew = new SwTxtInputFld( static_cast<SwFmtFld &>(rNew), nStt, nEnd ); 1054 break; 1055 case RES_TXTATR_FLYCNT: 1056 { 1057 // erst hier wird das Frame-Format kopiert (mit Inhalt) !! 1058 pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt ); 1059 // Kopie von einem Text-Attribut 1060 if ( static_cast<const SwFmtFlyCnt &>(rAttr).GetTxtFlyCnt() ) 1061 { 1062 // then the format must be copied 1063 static_cast<SwTxtFlyCnt *>(pNew)->CopyFlyFmt( &rDoc ); 1064 } 1065 } 1066 break; 1067 case RES_TXTATR_FTN: 1068 pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt ); 1069 // ggfs. SeqNo kopieren 1070 if( ((SwFmtFtn&)rAttr).GetTxtFtn() ) 1071 ((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() ); 1072 break; 1073 case RES_TXTATR_REFMARK: 1074 pNew = nStt == nEnd 1075 ? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt ) 1076 : new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd ); 1077 break; 1078 case RES_TXTATR_TOXMARK: 1079 pNew = new SwTxtTOXMark( (SwTOXMark&)rNew, nStt, &nEnd ); 1080 break; 1081 case RES_TXTATR_CJK_RUBY: 1082 pNew = new SwTxtRuby( (SwFmtRuby&)rNew, nStt, nEnd ); 1083 break; 1084 case RES_TXTATR_META: 1085 case RES_TXTATR_METAFIELD: 1086 pNew = SwTxtMeta::CreateTxtMeta( rDoc.GetMetaFieldManager(), pTxtNode, 1087 static_cast<SwFmtMeta&>(rNew), nStt, nEnd, bIsCopy ); 1088 break; 1089 default: 1090 ASSERT(RES_TXTATR_AUTOFMT == rNew.Which(), "unknown attribute"); 1091 pNew = new SwTxtAttrEnd( rNew, nStt, nEnd ); 1092 break; 1093 } 1094 1095 return pNew; 1096 } 1097 1098 SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, const SfxItemSet& rSet, 1099 xub_StrLen nStt, xub_StrLen nEnd ) 1100 { 1101 IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess(); 1102 const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR ); 1103 SwFmtAutoFmt aNewAutoFmt; 1104 aNewAutoFmt.SetStyleHandle( pAutoStyle ); 1105 SwTxtAttr* pNew = MakeTxtAttr( rDoc, aNewAutoFmt, nStt, nEnd ); 1106 return pNew; 1107 } 1108 1109 1110 // loesche das Text-Attribut (muss beim Pool abgemeldet werden!) 1111 void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr ) 1112 { 1113 if( pAttr ) 1114 { 1115 // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen 1116 SwDoc* pDoc = GetDoc(); 1117 sal_uInt16 nDelMsg = 0; 1118 switch( pAttr->Which() ) 1119 { 1120 case RES_TXTATR_FLYCNT: 1121 { 1122 // siehe auch die Anmerkung "Loeschen von Formaten 1123 // zeichengebundener Frames" in fesh.cxx, SwFEShell::DelFmt() 1124 SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt(); 1125 if( pFmt ) // vom Undo auf 0 gesetzt ?? 1126 pDoc->DelLayoutFmt( (SwFlyFrmFmt*)pFmt ); 1127 } 1128 break; 1129 1130 case RES_CHRATR_HIDDEN: 1131 SetCalcHiddenCharFlags(); 1132 break; 1133 1134 case RES_TXTATR_FTN: 1135 ((SwTxtFtn*)pAttr)->SetStartNode( 0 ); 1136 nDelMsg = RES_FOOTNOTE_DELETED; 1137 break; 1138 1139 case RES_TXTATR_FIELD: 1140 case RES_TXTATR_INPUTFIELD: 1141 if( !pDoc->IsInDtor() ) 1142 { 1143 // Wenn wir ein HiddenParaField sind, dann muessen wir 1144 // ggf. fuer eine Neuberechnung des Visible-Flags sorgen. 1145 const SwField* pFld = pAttr->GetFmtFld().GetField(); 1146 1147 //JP 06-08-95: DDE-Felder bilden eine Ausnahme 1148 ASSERT( RES_DDEFLD == pFld->GetTyp()->Which() || 1149 this == ((SwTxtFld*)pAttr)->GetpTxtNode(), 1150 "Wo steht denn dieses Feld?" ) 1151 1152 // bestimmte Felder mussen am Doc das Calculations-Flag updaten 1153 switch( pFld->GetTyp()->Which() ) 1154 { 1155 case RES_HIDDENPARAFLD: 1156 SetCalcHiddenParaField(); 1157 // kein break ! 1158 case RES_DBSETNUMBERFLD: 1159 case RES_GETEXPFLD: 1160 case RES_DBFLD: 1161 case RES_SETEXPFLD: 1162 case RES_HIDDENTXTFLD: 1163 case RES_DBNUMSETFLD: 1164 case RES_DBNEXTSETFLD: 1165 if( !pDoc->IsNewFldLst() && GetNodes().IsDocNodes() ) 1166 pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pAttr ); 1167 break; 1168 case RES_DDEFLD: 1169 if( GetNodes().IsDocNodes() && 1170 ((SwTxtFld*)pAttr)->GetpTxtNode() ) 1171 ((SwDDEFieldType*)pFld->GetTyp())->DecRefCnt(); 1172 break; 1173 case RES_POSTITFLD: 1174 { 1175 const_cast<SwFmtFld&>(pAttr->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pAttr)->GetFmtFld(), SWFMTFLD_REMOVED ) ); 1176 break; 1177 } 1178 } 1179 } 1180 nDelMsg = RES_FIELD_DELETED; 1181 break; 1182 1183 case RES_TXTATR_TOXMARK: 1184 static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark(); 1185 break; 1186 1187 case RES_TXTATR_REFMARK: 1188 nDelMsg = RES_REFMARK_DELETED; 1189 break; 1190 1191 case RES_TXTATR_META: 1192 case RES_TXTATR_METAFIELD: 1193 static_cast<SwTxtMeta*>(pAttr)->ChgTxtNode(0); 1194 break; 1195 1196 default: 1197 break; 1198 } 1199 1200 if( nDelMsg && !pDoc->IsInDtor() && GetNodes().IsDocNodes() ) 1201 { 1202 SwPtrMsgPoolItem aMsgHint( nDelMsg, (void*)&pAttr->GetAttr() ); 1203 pDoc->GetUnoCallBack()->ModifyNotification( &aMsgHint, &aMsgHint ); 1204 } 1205 1206 SwTxtAttr::Destroy( pAttr, pDoc->GetAttrPool() ); 1207 } 1208 } 1209 1210 /************************************************************************* 1211 * SwTxtNode::Insert() 1212 *************************************************************************/ 1213 1214 SwTxtAttr* 1215 SwTxtNode::InsertItem( SfxPoolItem& rAttr, 1216 const xub_StrLen nStart, const xub_StrLen nEnd, const SetAttrMode nMode ) 1217 { 1218 // character attributes will be inserted as automatic styles: 1219 ASSERT( !isCHRATR(rAttr.Which()), "AUTOSTYLES - " 1220 "SwTxtNode::InsertItem should not be called with character attributes"); 1221 1222 SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(), rAttr, nStart, nEnd, 1223 (nMode & nsSetAttrMode::SETATTR_IS_COPY) ? COPY : NEW, this ); 1224 1225 if ( pNew ) 1226 { 1227 const bool bSuccess( InsertHint( pNew, nMode ) ); 1228 // N.B.: also check that the hint is actually in the hints array, 1229 // because hints of certain types may be merged after succesful 1230 // insertion, and thus destroyed! 1231 if (!bSuccess || ( USHRT_MAX == m_pSwpHints->GetPos( pNew ) )) 1232 { 1233 return 0; 1234 } 1235 } 1236 1237 return pNew; 1238 } 1239 1240 // take ownership of pAttr; if insertion fails, delete pAttr 1241 bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode ) 1242 { 1243 bool bHiddenPara = false; 1244 1245 ASSERT( pAttr && *pAttr->GetStart() <= Len(), "StartIdx out of bounds!" ); 1246 ASSERT( !pAttr->GetEnd() || (*pAttr->GetEnd() <= Len()), 1247 "EndIdx out of bounds!" ); 1248 1249 // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR) 1250 const enum IDocumentContentOperations::InsertFlags nInsertFlags = 1251 (nMode & nsSetAttrMode::SETATTR_FORCEHINTEXPAND) 1252 ? static_cast<IDocumentContentOperations::InsertFlags>( 1253 IDocumentContentOperations::INS_FORCEHINTEXPAND | 1254 IDocumentContentOperations::INS_EMPTYEXPAND) 1255 : IDocumentContentOperations::INS_EMPTYEXPAND; 1256 1257 // need this after TryInsertHint, when pAttr may be deleted 1258 const xub_StrLen nStart( *pAttr->GetStart() ); 1259 const bool bDummyChar( pAttr->HasDummyChar() ); 1260 if (bDummyChar) 1261 { 1262 sal_uInt16 nInsMode = nMode; 1263 switch( pAttr->Which() ) 1264 { 1265 case RES_TXTATR_FLYCNT: 1266 { 1267 SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr; 1268 SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt(); 1269 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) ) 1270 { 1271 // Wir muessen zuerst einfuegen, da in SetAnchor() 1272 // dem FlyFrm GetStart() uebermittelt wird. 1273 //JP 11.05.98: falls das Anker-Attribut schon richtig 1274 // gesetzt ist, dann korrigiere dieses nach dem Einfuegen 1275 // des Zeichens. Sonst muesste das immer ausserhalb 1276 // erfolgen (Fehleranfaellig !) 1277 const SwFmtAnchor* pAnchor = 0; 1278 pFmt->GetItemState( RES_ANCHOR, sal_False, 1279 (const SfxPoolItem**)&pAnchor ); 1280 1281 SwIndex aIdx( this, *pAttr->GetStart() ); 1282 const sal_Unicode c = GetCharOfTxtAttr(*pAttr); 1283 InsertText( c, aIdx, nInsertFlags ); 1284 nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR; 1285 1286 if (pAnchor && 1287 (FLY_AS_CHAR == pAnchor->GetAnchorId()) && 1288 pAnchor->GetCntntAnchor() && 1289 pAnchor->GetCntntAnchor()->nNode == *this && 1290 pAnchor->GetCntntAnchor()->nContent == aIdx ) 1291 { 1292 const_cast<SwIndex&>( 1293 pAnchor->GetCntntAnchor()->nContent)--; 1294 } 1295 } 1296 pFly->SetAnchor( this ); 1297 1298 // Format-Pointer kann sich im SetAnchor geaendert haben! 1299 // (Kopieren in andere Docs!) 1300 pFmt = pAttr->GetFlyCnt().GetFrmFmt(); 1301 SwDoc *pDoc = pFmt->GetDoc(); 1302 1303 // OD 26.06.2003 #108784# - allow drawing objects in header/footer. 1304 // But don't allow control objects in header/footer 1305 if( RES_DRAWFRMFMT == pFmt->Which() && 1306 pDoc->IsInHeaderFooter( pFmt->GetAnchor().GetCntntAnchor()->nNode ) ) 1307 { 1308 SwDrawContact* pDrawContact = 1309 static_cast<SwDrawContact*>(pFmt->FindContactObj()); 1310 if ( pDrawContact && 1311 pDrawContact->GetMaster() && 1312 ::CheckControlLayer( pDrawContact->GetMaster() ) ) 1313 { 1314 // das soll nicht meoglich sein; hier verhindern 1315 // Der Dtor des TxtHints loescht nicht das Zeichen. 1316 // Wenn ein CH_TXTATR_.. vorliegt, dann muss man 1317 // dieses explizit loeschen 1318 if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode ) 1319 { 1320 // loesche das Zeichen aus dem String ! 1321 ASSERT( ( CH_TXTATR_BREAKWORD == 1322 m_Text.GetChar(*pAttr->GetStart() ) || 1323 CH_TXTATR_INWORD == 1324 m_Text.GetChar(*pAttr->GetStart())), 1325 "where is my attribute character?" ); 1326 m_Text.Erase( *pAttr->GetStart(), 1 ); 1327 // Indizies Updaten 1328 SwIndex aTmpIdx( this, *pAttr->GetStart() ); 1329 Update( aTmpIdx, 1, sal_True ); 1330 } 1331 // do not record deletion of Format! 1332 ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo()); 1333 DestroyAttr( pAttr ); 1334 return false; 1335 } 1336 } 1337 break; 1338 } 1339 1340 case RES_TXTATR_FTN : 1341 { 1342 // Fussnoten, man kommt an alles irgendwie heran. 1343 // CntntNode erzeugen und in die Inserts-Section stellen 1344 SwDoc *pDoc = GetDoc(); 1345 SwNodes &rNodes = pDoc->GetNodes(); 1346 1347 // FussNote in nicht Content-/Redline-Bereich einfuegen ?? 1348 if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() ) 1349 { 1350 // das soll nicht meoglich sein; hier verhindern 1351 // Der Dtor des TxtHints loescht nicht das Zeichen. 1352 // Wenn ein CH_TXTATR_.. vorliegt, dann muss man 1353 // dieses explizit loeschen 1354 if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode ) 1355 { 1356 // loesche das Zeichen aus dem String ! 1357 ASSERT( ( CH_TXTATR_BREAKWORD == 1358 m_Text.GetChar(*pAttr->GetStart() ) || 1359 CH_TXTATR_INWORD == 1360 m_Text.GetChar(*pAttr->GetStart())), 1361 "where is my attribute character?" ); 1362 m_Text.Erase( *pAttr->GetStart(), 1 ); 1363 // Indizies Updaten 1364 SwIndex aTmpIdx( this, *pAttr->GetStart() ); 1365 Update( aTmpIdx, 1, sal_True ); 1366 } 1367 DestroyAttr( pAttr ); 1368 return false; 1369 } 1370 1371 // wird eine neue Fussnote eingefuegt ?? 1372 sal_Bool bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode(); 1373 if( bNewFtn ) 1374 { 1375 ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() ); 1376 SwRegHistory* pHist = GetpSwpHints() 1377 ? GetpSwpHints()->GetHistory() : 0; 1378 if( pHist ) 1379 pHist->ChangeNodeIndex( GetIndex() ); 1380 } 1381 else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() ) 1382 { 1383 // loesche alle Frames der Section, auf die der StartNode zeigt 1384 sal_uLong nSttIdx = 1385 ((SwTxtFtn*)pAttr)->GetStartNode()->GetIndex(); 1386 sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex(); 1387 SwCntntNode* pCNd; 1388 for( ; nSttIdx < nEndIdx; ++nSttIdx ) 1389 if( 0 != ( pCNd = rNodes[ nSttIdx ]->GetCntntNode() )) 1390 pCNd->DelFrms(); 1391 } 1392 1393 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) ) 1394 { 1395 // Wir muessen zuerst einfuegen, da sonst gleiche Indizes 1396 // entstehen koennen und das Attribut im _SortArr_ am 1397 // Dokument nicht eingetrage wird. 1398 SwIndex aNdIdx( this, *pAttr->GetStart() ); 1399 const sal_Unicode c = GetCharOfTxtAttr(*pAttr); 1400 InsertText( c, aNdIdx, nInsertFlags ); 1401 nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR; 1402 } 1403 1404 // Wir tragen uns am FtnIdx-Array des Docs ein ... 1405 SwTxtFtn* pTxtFtn = 0; 1406 if( !bNewFtn ) 1407 { 1408 // eine alte Ftn wird umgehaengt (z.B. SplitNode) 1409 for( sal_uInt16 n = 0; n < pDoc->GetFtnIdxs().Count(); ++n ) 1410 if( pAttr == pDoc->GetFtnIdxs()[n] ) 1411 { 1412 // neuen Index zuweisen, dafuer aus dem SortArray 1413 // loeschen und neu eintragen 1414 pTxtFtn = pDoc->GetFtnIdxs()[n]; 1415 pDoc->GetFtnIdxs().Remove( n ); 1416 break; 1417 } 1418 // wenn ueber Undo der StartNode gesetzt wurde, kann 1419 // der Index noch gar nicht in der Verwaltung stehen !! 1420 } 1421 if( !pTxtFtn ) 1422 pTxtFtn = (SwTxtFtn*)pAttr; 1423 1424 // fuers Update der Nummern und zum Sortieren 1425 // muss der Node gesetzt sein. 1426 ((SwTxtFtn*)pAttr)->ChgTxtNode( this ); 1427 1428 // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen! 1429 if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() ) 1430 { 1431 #ifdef DBG_UTIL 1432 const sal_Bool bSuccess = 1433 #endif 1434 pDoc->GetFtnIdxs().Insert( pTxtFtn ); 1435 #ifdef DBG_UTIL 1436 ASSERT( bSuccess, "FtnIdx nicht eingetragen." ); 1437 #endif 1438 } 1439 SwNodeIndex aTmpIndex( *this ); 1440 pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex); 1441 ((SwTxtFtn*)pAttr)->SetSeqRefNo(); 1442 } 1443 break; 1444 1445 case RES_TXTATR_FIELD: 1446 { 1447 // fuer HiddenParaFields Benachrichtigungsmechanismus 1448 // anwerfen 1449 if( RES_HIDDENPARAFLD == pAttr->GetFmtFld().GetField()->GetTyp()->Which() ) 1450 { 1451 bHiddenPara = true; 1452 } 1453 } 1454 break; 1455 1456 } 1457 // Fuer SwTxtHints ohne Endindex werden CH_TXTATR_.. 1458 // eingefuegt, aStart muss danach um einen zurueckgesetzt werden. 1459 // Wenn wir im SwTxtNode::Copy stehen, so wurde das Zeichen bereits 1460 // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden. 1461 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) ) 1462 { 1463 SwIndex aIdx( this, *pAttr->GetStart() ); 1464 InsertText( GetCharOfTxtAttr(*pAttr), aIdx, nInsertFlags ); 1465 1466 // adjust end of hint to account for inserted CH_TXTATR 1467 xub_StrLen * const pEnd(pAttr->GetEnd()); 1468 if (pEnd) 1469 { 1470 *pEnd = *pEnd + 1; 1471 } 1472 } 1473 } 1474 1475 // handle attributes which provide content 1476 xub_StrLen nEnd = nStart; 1477 bool bInputFieldStartCharInserted = false; 1478 bool bInputFieldEndCharInserted = false; 1479 const bool bHasContent( pAttr->HasContent() ); 1480 if ( bHasContent ) 1481 { 1482 switch( pAttr->Which() ) 1483 { 1484 case RES_TXTATR_INPUTFIELD: 1485 { 1486 SwTxtInputFld* pTxtInputFld = dynamic_cast<SwTxtInputFld*>(pAttr); 1487 if ( pTxtInputFld ) 1488 { 1489 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) ) 1490 { 1491 SwIndex aIdx( this, *pAttr->GetStart() ); 1492 InsertText( CH_TXT_ATR_INPUTFIELDSTART, aIdx, nInsertFlags ); 1493 const String aContent = pTxtInputFld->GetFieldContent(); 1494 InsertText( aContent, aIdx, nInsertFlags ); 1495 InsertText( CH_TXT_ATR_INPUTFIELDEND, aIdx, nInsertFlags ); 1496 1497 xub_StrLen * const pEnd(pAttr->GetEnd()); 1498 ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" ); 1499 if ( pEnd != NULL ) 1500 { 1501 *pEnd = *pEnd + 2 + aContent.Len(); 1502 nEnd = *pEnd; 1503 } 1504 } 1505 else 1506 { 1507 // assure that CH_TXT_ATR_INPUTFIELDSTART and CH_TXT_ATR_INPUTFIELDEND are inserted. 1508 if ( m_Text.GetChar( *(pAttr->GetStart()) ) != CH_TXT_ATR_INPUTFIELDSTART ) 1509 { 1510 SwIndex aIdx( this, *pAttr->GetStart() ); 1511 InsertText( CH_TXT_ATR_INPUTFIELDSTART, aIdx, nInsertFlags ); 1512 bInputFieldStartCharInserted = true; 1513 xub_StrLen * const pEnd(pAttr->GetEnd()); 1514 ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" ); 1515 if ( pEnd != NULL ) 1516 { 1517 *pEnd = *pEnd + 1; 1518 nEnd = *pEnd; 1519 } 1520 } 1521 1522 xub_StrLen * const pEnd(pAttr->GetEnd()); 1523 ASSERT( pEnd != NULL, "<SwTxtNode::InsertHint(..)> - missing end of RES_TXTATR_INPUTFIELD!" ); 1524 if ( pEnd != NULL 1525 && m_Text.GetChar( *(pEnd) - 1 ) != CH_TXT_ATR_INPUTFIELDEND ) 1526 { 1527 SwIndex aIdx( this, *(pEnd) ); 1528 InsertText( CH_TXT_ATR_INPUTFIELDEND, aIdx, nInsertFlags ); 1529 bInputFieldEndCharInserted = true; 1530 *pEnd = *pEnd + 1; 1531 nEnd = *pEnd; 1532 } 1533 } 1534 } 1535 } 1536 break; 1537 default: 1538 break; 1539 } 1540 } 1541 1542 GetOrCreateSwpHints(); 1543 1544 // handle overlap with an existing InputField 1545 bool bInsertHint = true; 1546 { 1547 const SwTxtInputFld* pTxtInputFld = GetOverlappingInputFld( *pAttr ); 1548 if ( pTxtInputFld != NULL ) 1549 { 1550 if ( pAttr->End() == NULL ) 1551 { 1552 bInsertHint = false; 1553 } 1554 else 1555 { 1556 if ( *(pAttr->GetStart()) > *(pTxtInputFld->GetStart()) ) 1557 { 1558 *(pAttr->GetStart()) = *(pTxtInputFld->GetStart()); 1559 } 1560 if ( *(pAttr->End()) < *(pTxtInputFld->End()) ) 1561 { 1562 *(pAttr->GetEnd()) = *(pTxtInputFld->End()); 1563 } 1564 } 1565 } 1566 } 1567 1568 // 4263: AttrInsert durch TextInsert => kein Adjust 1569 const bool bRet = bInsertHint 1570 ? m_pSwpHints->TryInsertHint( pAttr, *this, nMode ) 1571 : false; 1572 1573 if ( !bRet ) 1574 { 1575 if ( bDummyChar 1576 && !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) ) 1577 { 1578 // undo insertion of dummy character 1579 // N.B. cannot insert the dummy character after inserting the hint, 1580 // because if the hint has no extent it will be moved in InsertText, 1581 // resulting in infinite recursion 1582 ASSERT( ( CH_TXTATR_BREAKWORD == m_Text.GetChar(nStart) || 1583 CH_TXTATR_INWORD == m_Text.GetChar(nStart) ), 1584 "where is my attribute character?" ); 1585 SwIndex aIdx( this, nStart ); 1586 EraseText( aIdx, 1 ); 1587 } 1588 1589 if ( bHasContent ) 1590 { 1591 if ( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) 1592 && (nEnd - nStart) > 0 ) 1593 { 1594 SwIndex aIdx( this, nStart ); 1595 EraseText( aIdx, (nEnd - nStart) ); 1596 } 1597 else 1598 { 1599 if ( bInputFieldEndCharInserted 1600 && (nEnd - nStart) > 0 ) 1601 { 1602 SwIndex aIdx( this, nEnd - 1 ); 1603 EraseText( aIdx, 1 ); 1604 } 1605 1606 if ( bInputFieldStartCharInserted ) 1607 { 1608 SwIndex aIdx( this, nStart ); 1609 EraseText( aIdx, 1 ); 1610 } 1611 } 1612 } 1613 } 1614 1615 if ( bHiddenPara ) 1616 { 1617 SetCalcHiddenParaField(); 1618 } 1619 1620 return bRet; 1621 } 1622 1623 1624 /************************************************************************* 1625 * SwTxtNode::DeleteAttribute() 1626 *************************************************************************/ 1627 1628 void SwTxtNode::DeleteAttribute( SwTxtAttr * const pAttr ) 1629 { 1630 if ( !HasHints() ) 1631 { 1632 ASSERT(false, "DeleteAttribute called, but text node without hints?"); 1633 return; 1634 } 1635 1636 if ( pAttr->HasDummyChar() ) 1637 { 1638 // Unbedingt Copy-konstruieren! 1639 const SwIndex aIdx( this, *pAttr->GetStart() ); 1640 // erase the CH_TXTATR, which will also delete pAttr 1641 EraseText( aIdx, 1 ); 1642 } 1643 else if ( pAttr->HasContent() ) 1644 { 1645 const SwIndex aIdx( this, *pAttr->GetStart() ); 1646 ASSERT( pAttr->End() != NULL, "<SwTxtNode::DeleteAttribute(..)> - missing End() at <SwTxtAttr> instance which has content" ); 1647 EraseText( aIdx, *pAttr->End() - *pAttr->GetStart() ); 1648 } 1649 else 1650 { 1651 // create MsgHint before start/end become invalid 1652 SwUpdateAttr aHint( 1653 *pAttr->GetStart(), *pAttr->GetEnd(), pAttr->Which() ); 1654 m_pSwpHints->Delete( pAttr ); 1655 SwTxtAttr::Destroy( pAttr, GetDoc()->GetAttrPool() ); 1656 NotifyClients( 0, &aHint ); 1657 1658 TryDeleteSwpHints(); 1659 } 1660 } 1661 1662 /************************************************************************* 1663 * SwTxtNode::DeleteAttributes() 1664 *************************************************************************/ 1665 1666 //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)! 1667 void SwTxtNode::DeleteAttributes( 1668 const sal_uInt16 nWhich, 1669 const xub_StrLen nStart, 1670 const xub_StrLen nEnd ) 1671 { 1672 if ( !HasHints() ) 1673 return; 1674 1675 for ( sal_uInt16 nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); nPos++ ) 1676 { 1677 SwTxtAttr * const pTxtHt = m_pSwpHints->GetTextHint( nPos ); 1678 const xub_StrLen nHintStart = *(pTxtHt->GetStart()); 1679 if (nStart < nHintStart) 1680 { 1681 break; // sorted by start 1682 } 1683 else if ( (nStart == nHintStart) && (nWhich == pTxtHt->Which()) ) 1684 { 1685 if ( nWhich == RES_CHRATR_HIDDEN ) 1686 { 1687 ASSERT(false, "hey, that's a CHRATR! how did that get in?"); 1688 SetCalcHiddenCharFlags(); 1689 } 1690 else if ( nWhich == RES_TXTATR_CHARFMT ) 1691 { 1692 // Check if character format contains hidden attribute: 1693 const SwCharFmt* pFmt = pTxtHt->GetCharFmt().GetCharFmt(); 1694 const SfxPoolItem* pItem; 1695 if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) ) 1696 SetCalcHiddenCharFlags(); 1697 } 1698 // Recalc hidden flags if necessary 1699 else if ( nWhich == RES_TXTATR_AUTOFMT ) 1700 { 1701 // Check if auto style contains hidden attribute: 1702 const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN ); 1703 if ( pHiddenItem ) 1704 SetCalcHiddenCharFlags(); 1705 } 1706 1707 xub_StrLen const * const pEndIdx = pTxtHt->GetEnd(); 1708 1709 if ( pTxtHt->HasDummyChar() ) 1710 { 1711 // Unbedingt Copy-konstruieren! 1712 const SwIndex aIdx( this, nStart ); 1713 // erase the CH_TXTATR, which will also delete pTxtHt 1714 EraseText( aIdx, 1 ); 1715 } 1716 else if ( pTxtHt->HasContent() ) 1717 { 1718 const SwIndex aIdx( this, nStart ); 1719 ASSERT( pTxtHt->End() != NULL, "<SwTxtNode::DeleteAttributes(..)> - missing End() at <SwTxtAttr> instance which has content" ); 1720 EraseText( aIdx, *pTxtHt->End() - nStart ); 1721 } 1722 else if( *pEndIdx == nEnd ) 1723 { 1724 // den MsgHint jetzt fuettern, weil gleich sind 1725 // Start und End weg. 1726 // Das CalcVisibleFlag bei HiddenParaFields entfaellt, 1727 // da dies das Feld im Dtor selbst erledigt. 1728 SwUpdateAttr aHint( nStart, *pEndIdx, nWhich ); 1729 m_pSwpHints->DeleteAtPos( nPos ); // gefunden, loeschen, 1730 SwTxtAttr::Destroy( pTxtHt, GetDoc()->GetAttrPool() ); 1731 NotifyClients( 0, &aHint ); 1732 } 1733 } 1734 } 1735 TryDeleteSwpHints(); 1736 } 1737 1738 /************************************************************************* 1739 * SwTxtNode::DelSoftHyph() 1740 *************************************************************************/ 1741 1742 void SwTxtNode::DelSoftHyph( const xub_StrLen nStt, const xub_StrLen nEnd ) 1743 { 1744 xub_StrLen nFndPos = nStt, nEndPos = nEnd; 1745 while( STRING_NOTFOUND != 1746 ( nFndPos = m_Text.Search( CHAR_SOFTHYPHEN, nFndPos )) && 1747 nFndPos < nEndPos ) 1748 { 1749 const SwIndex aIdx( this, nFndPos ); 1750 EraseText( aIdx, 1 ); 1751 --nEndPos; 1752 } 1753 } 1754 1755 //Modify here for #119405, by easyfan, 2012-05-24 1756 //In MS Word, the font underline setting of the paragraph end position wont affect the formatting of numbering, so we ignore it 1757 bool lcl_IsIgnoredCharFmtForNumbering(const sal_uInt16 nWhich) 1758 { 1759 return (nWhich == RES_CHRATR_UNDERLINE); 1760 } 1761 1762 //In MS Word, following properties of the paragraph end position wont affect the formatting of bullets, so we ignore them: 1763 //Font underline; 1764 //Font Italic of Western, CJK and CTL; 1765 //Font Bold of Wertern, CJK and CTL; 1766 bool lcl_IsIgnoredCharFmtForBullets(const sal_uInt16 nWhich) 1767 { 1768 return (nWhich == RES_CHRATR_UNDERLINE || nWhich == RES_CHRATR_POSTURE || nWhich == RES_CHRATR_WEIGHT 1769 || nWhich == RES_CHRATR_CJK_POSTURE || nWhich == RES_CHRATR_CJK_WEIGHT 1770 || nWhich == RES_CHRATR_CTL_POSTURE || nWhich == RES_CHRATR_CTL_WEIGHT); 1771 } 1772 1773 //Condition for expanding char set to character style of specified number rule level: 1774 //The item inside the set should not conflict to any exist and non-default item inside paragraph properties set (SwCntntNode::SwPAttrSet); 1775 //The node should have applied a number rule; 1776 //The node should be counted in a list, if not, make it to be; 1777 //The item should not conflict to any exist and non-default item inside the character of specified number rule level; 1778 //The item should not be ignored depend on the exact number rule type; 1779 bool SwTxtNode::TryCharSetExpandToNum(const SfxItemSet& aCharSet) 1780 { 1781 bool bRet = false; 1782 SfxItemIter aIter( aCharSet ); 1783 const SfxPoolItem* pItem = aIter.FirstItem(); 1784 const sal_uInt16 nWhich = pItem->Which(); 1785 1786 const SfxPoolItem& rInnerItem = GetAttr(nWhich,false); 1787 1788 if (!IsDefaultItem(&rInnerItem) && !IsInvalidItem(&rInnerItem)) 1789 return bRet; 1790 1791 if ( !IsInList() && GetNumRule() && GetListId().Len() > 0 ) 1792 { 1793 return bRet; 1794 } 1795 1796 SwNumRule* pCurrNum = GetNumRule(false); 1797 1798 int nLevel = GetActualListLevel(); 1799 1800 if (nLevel != -1 && pCurrNum) 1801 { 1802 const SwNumFmt* pCurrNumFmt = pCurrNum->GetNumFmt(static_cast<sal_uInt16>(nLevel)); 1803 if (pCurrNumFmt) 1804 { 1805 if (pCurrNumFmt->IsItemize() && lcl_IsIgnoredCharFmtForBullets(nWhich)) 1806 return bRet; 1807 if (pCurrNumFmt->IsEnumeration() && lcl_IsIgnoredCharFmtForNumbering(nWhich)) 1808 return bRet; 1809 SwCharFmt* pCurrCharFmt =pCurrNumFmt->GetCharFmt(); 1810 1811 if (pCurrCharFmt && pCurrCharFmt->GetItemState(nWhich,false) != SFX_ITEM_SET) 1812 { 1813 pCurrCharFmt->SetFmtAttr(*pItem); 1814 SwNumFmt aNewNumFmt(*pCurrNumFmt); 1815 aNewNumFmt.SetCharFmt(pCurrCharFmt); 1816 pCurrNum->Set(nLevel,aNewNumFmt); 1817 bRet = true; 1818 } 1819 } 1820 } 1821 1822 1823 return bRet; 1824 } 1825 //End of modification, by easyfan 1826 1827 // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt, 1828 // dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr) 1829 sal_Bool SwTxtNode::SetAttr( 1830 const SfxItemSet& rSet, 1831 const xub_StrLen nStt, 1832 const xub_StrLen nEnd, 1833 const SetAttrMode nMode ) 1834 { 1835 if( !rSet.Count() ) 1836 return sal_False; 1837 1838 // teil die Sets auf (fuer Selektion in Nodes) 1839 const SfxItemSet* pSet = &rSet; 1840 SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 ); 1841 1842 // gesamter Bereich 1843 if ( !nStt && (nEnd == m_Text.Len()) && 1844 !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) ) 1845 { 1846 // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute 1847 // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden. 1848 int bHasCharFmts = sal_False; 1849 if ( HasHints() ) 1850 { 1851 for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n ) 1852 { 1853 if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() ) 1854 { 1855 bHasCharFmts = sal_True; 1856 break; 1857 } 1858 } 1859 } 1860 1861 if( !bHasCharFmts ) 1862 { 1863 aTxtSet.Put( rSet ); 1864 // If there are any character attributes in rSet, 1865 // we want to set them at the paragraph: 1866 if( aTxtSet.Count() != rSet.Count() ) 1867 { 1868 sal_Bool bRet = SetAttr( rSet ); 1869 if( !aTxtSet.Count() ) 1870 return bRet; 1871 } 1872 1873 // check for auto style: 1874 const SfxPoolItem* pItem; 1875 const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, sal_False, &pItem ); 1876 if ( bAutoStyle ) 1877 { 1878 boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle(); 1879 sal_Bool bRet = SetAttr( *pAutoStyleSet ); 1880 if( 1 == aTxtSet.Count() ) 1881 return bRet; 1882 } 1883 1884 // Continue with the text attributes: 1885 pSet = &aTxtSet; 1886 } 1887 } 1888 1889 GetOrCreateSwpHints(); 1890 1891 SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange ); 1892 1893 sal_uInt16 nCount = 0; 1894 SfxItemIter aIter( *pSet ); 1895 const SfxPoolItem* pItem = aIter.GetCurItem(); 1896 1897 do 1898 { 1899 if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem)) 1900 { 1901 const sal_uInt16 nWhich = pItem->Which(); 1902 ASSERT( isCHRATR(nWhich) || isTXTATR(nWhich), 1903 "SwTxtNode::SetAttr(): unknown attribute" ); 1904 if ( isCHRATR(nWhich) || isTXTATR(nWhich) ) 1905 { 1906 if ((RES_TXTATR_CHARFMT == nWhich) && 1907 (GetDoc()->GetDfltCharFmt() == 1908 static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt())) 1909 { 1910 SwIndex aIndex( this, nStt ); 1911 RstTxtAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 ); 1912 DontExpandFmt( aIndex ); 1913 } 1914 else 1915 { 1916 if (isCHRATR(nWhich) || 1917 (RES_TXTATR_UNKNOWN_CONTAINER == nWhich)) 1918 { 1919 aCharSet.Put( *pItem ); 1920 } 1921 else 1922 { 1923 1924 SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(), 1925 const_cast<SfxPoolItem&>(*pItem), nStt, nEnd ); 1926 if ( pNew ) 1927 { 1928 if ( nEnd != nStt && !pNew->GetEnd() ) 1929 { 1930 ASSERT(false, 1931 "Attribut without end, but area marked"); 1932 DestroyAttr( pNew ); // do not insert 1933 } 1934 else if ( InsertHint( pNew, nMode ) ) 1935 { 1936 ++nCount; 1937 } 1938 } 1939 } 1940 } 1941 } 1942 } 1943 if ( aIter.IsAtEnd() ) 1944 break; 1945 pItem = aIter.NextItem(); 1946 } while( true ); 1947 1948 if ( aCharSet.Count() ) 1949 { 1950 SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd ); 1951 if ( InsertHint( pTmpNew, nMode ) ) 1952 { 1953 ++nCount; 1954 } 1955 } 1956 1957 TryDeleteSwpHints(); 1958 1959 return nCount ? sal_True : sal_False; 1960 } 1961 1962 void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr ) 1963 { 1964 if ( RES_TXTATR_AUTOFMT == rAttr.Which() ) 1965 { 1966 const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr ); 1967 if ( !pCFSet ) 1968 return; 1969 SfxWhichIter aIter( *pCFSet ); 1970 sal_uInt16 nWhich = aIter.FirstWhich(); 1971 while( nWhich ) 1972 { 1973 if( ( nWhich < RES_CHRATR_END || 1974 RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) && 1975 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) ) 1976 rSet.Put( pCFSet->Get( nWhich ) ); 1977 nWhich = aIter.NextWhich(); 1978 } 1979 } 1980 else 1981 rSet.Put( rAttr ); 1982 } 1983 1984 void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr ) 1985 { 1986 if( RES_TXTATR_CHARFMT == rAttr.Which() || 1987 RES_TXTATR_INETFMT == rAttr.Which() || 1988 RES_TXTATR_AUTOFMT == rAttr.Which() ) 1989 { 1990 const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr ); 1991 1992 if ( pCFSet ) 1993 { 1994 SfxWhichIter aIter( *pCFSet ); 1995 sal_uInt16 nWhich = aIter.FirstWhich(); 1996 while( nWhich ) 1997 { 1998 if( ( nWhich < RES_CHRATR_END || 1999 ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) && 2000 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) ) 2001 rSet.Put( pCFSet->Get( nWhich ) ); 2002 nWhich = aIter.NextWhich(); 2003 } 2004 } 2005 } 2006 2007 // aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!) 2008 2009 /* wenn mehrere Attribute ueberlappen gewinnt der letze !! 2010 z.B 2011 1234567890123456789 2012 |------------| Font1 2013 |------| Font2 2014 ^ ^ 2015 |--| Abfragebereich: -> Gueltig ist Font2 2016 */ 2017 rSet.Put( rAttr ); 2018 } 2019 2020 struct SwPoolItemEndPair 2021 { 2022 public: 2023 const SfxPoolItem* mpItem; 2024 xub_StrLen mnEndPos; 2025 2026 SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {}; 2027 }; 2028 2029 // --> OD 2008-01-16 #newlistlevelattrs# 2030 void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode, 2031 SfxItemSet& rSet ) 2032 { 2033 if ( rTxtNode.AreListLevelIndentsApplicable() ) 2034 { 2035 const SwNumRule* pRule = rTxtNode.GetNumRule(); 2036 if ( pRule && rTxtNode.GetActualListLevel() >= 0 ) 2037 { 2038 const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel())); 2039 if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) 2040 { 2041 SvxLRSpaceItem aLR( RES_LR_SPACE ); 2042 aLR.SetTxtLeft( rFmt.GetIndentAt() ); 2043 aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) ); 2044 rSet.Put( aLR ); 2045 } 2046 } 2047 } 2048 } 2049 2050 // erfrage die Attribute vom TextNode ueber den Bereich 2051 // --> OD 2008-01-16 #newlistlevelattrs# 2052 sal_Bool SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd, 2053 sal_Bool bOnlyTxtAttr, sal_Bool bGetFromChrFmt, 2054 const bool bMergeIndentValuesOfNumRule ) const 2055 { 2056 if( HasHints() ) 2057 { 2058 /* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig 2059 * sind. Dabei gibt es folgende Faelle: 2060 * UnEindeutig wenn: (wenn != Format-Attribut) 2061 * - das Attribut liegt vollstaendig im Bereich 2062 * - das Attributende liegt im Bereich 2063 * - der Attributanfang liegt im Bereich: 2064 * Eindeutig (im Set mergen): 2065 * - das Attrib umfasst den Bereich 2066 * nichts tun: 2067 * das Attribut liegt ausserhalb des Bereiches 2068 */ 2069 2070 void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& ) 2071 = bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt 2072 : &lcl_MergeAttr; 2073 2074 // dann besorge mal die Auto-(Fmt)Attribute 2075 SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() ); 2076 if( !bOnlyTxtAttr ) 2077 { 2078 SwCntntNode::GetAttr( aFmtSet ); 2079 // --> OD 2008-01-16 #newlistlevelattrs# 2080 if ( bMergeIndentValuesOfNumRule ) 2081 { 2082 lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet ); 2083 } 2084 // <-- 2085 } 2086 2087 const sal_uInt16 nSize = m_pSwpHints->Count(); 2088 2089 if( nStt == nEnd ) // kein Bereich: 2090 { 2091 for (sal_uInt16 n = 0; n < nSize; ++n) 2092 { 2093 const SwTxtAttr* pHt = (*m_pSwpHints)[n]; 2094 const xub_StrLen nAttrStart = *pHt->GetStart(); 2095 if( nAttrStart > nEnd ) // ueber den Bereich hinaus 2096 break; 2097 2098 const xub_StrLen* pAttrEnd = pHt->End(); 2099 if ( ! pAttrEnd ) // no attributes without end 2100 continue; 2101 2102 if( ( nAttrStart < nStt && 2103 ( pHt->DontExpand() ? nStt < *pAttrEnd 2104 : nStt <= *pAttrEnd )) || 2105 ( nStt == nAttrStart && 2106 ( nAttrStart == *pAttrEnd || !nStt ))) 2107 (*fnMergeAttr)( rSet, pHt->GetAttr() ); 2108 } 2109 } 2110 else // es ist ein Bereich definiert 2111 { 2112 // --> FME 2007-03-13 #i75299# 2113 ::std::auto_ptr< std::vector< SwPoolItemEndPair > > pAttrArr; 2114 // <-- 2115 2116 const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) - 2117 static_cast<sal_uInt16>(RES_CHRATR_BEGIN); 2118 2119 for (sal_uInt16 n = 0; n < nSize; ++n) 2120 { 2121 const SwTxtAttr* pHt = (*m_pSwpHints)[n]; 2122 const xub_StrLen nAttrStart = *pHt->GetStart(); 2123 if( nAttrStart > nEnd ) // ueber den Bereich hinaus 2124 break; 2125 2126 const xub_StrLen* pAttrEnd = pHt->End(); 2127 if ( ! pAttrEnd ) // no attributes without end 2128 continue; 2129 2130 sal_Bool bChkInvalid = sal_False; 2131 if( nAttrStart <= nStt ) // vor oder genau Start 2132 { 2133 if( *pAttrEnd <= nStt ) // liegt davor 2134 continue; 2135 2136 if( nEnd <= *pAttrEnd ) // hinter oder genau Ende 2137 (*fnMergeAttr)( aFmtSet, pHt->GetAttr() ); 2138 else 2139 // else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) ) 2140 // uneindeutig 2141 bChkInvalid = sal_True; 2142 } 2143 else if( nAttrStart < nEnd // reicht in den Bereich 2144 )// && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) ) 2145 bChkInvalid = sal_True; 2146 2147 if( bChkInvalid ) 2148 { 2149 // uneindeutig ? 2150 ::std::auto_ptr< SfxItemIter > pItemIter; 2151 const SfxPoolItem* pItem = 0; 2152 2153 if ( RES_TXTATR_AUTOFMT == pHt->Which() ) 2154 { 2155 const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() ); 2156 if ( pAutoSet ) 2157 { 2158 pItemIter.reset( new SfxItemIter( *pAutoSet ) ); 2159 pItem = pItemIter->GetCurItem(); 2160 } 2161 } 2162 else 2163 pItem = &pHt->GetAttr(); 2164 2165 const sal_uInt16 nHintEnd = *pAttrEnd; 2166 2167 while ( pItem ) 2168 { 2169 const sal_uInt16 nHintWhich = pItem->Which(); 2170 ASSERT(!isUNKNOWNATR(nHintWhich), 2171 "SwTxtNode::GetAttr(): unkonwn attribute?"); 2172 2173 if ( !pAttrArr.get() ) 2174 { 2175 pAttrArr.reset( 2176 new std::vector< SwPoolItemEndPair >(coArrSz)); 2177 } 2178 2179 std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin(); 2180 if (isCHRATR(nHintWhich) || 2181 isTXTATR_WITHEND(nHintWhich)) 2182 { 2183 pPrev += nHintWhich - RES_CHRATR_BEGIN; 2184 } 2185 else 2186 { 2187 pPrev = pAttrArr->end(); 2188 } 2189 2190 #if OSL_DEBUG_LEVEL > 1 2191 SwPoolItemEndPair aTmp = *pPrev; 2192 #endif 2193 2194 if( pPrev != pAttrArr->end() ) 2195 { 2196 if( !pPrev->mpItem ) 2197 { 2198 if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) ) 2199 { 2200 if( nAttrStart > nStt ) 2201 { 2202 rSet.InvalidateItem( nHintWhich ); 2203 pPrev->mpItem = (SfxPoolItem*)-1; 2204 } 2205 else 2206 { 2207 pPrev->mpItem = pItem; 2208 pPrev->mnEndPos = nHintEnd; 2209 } 2210 } 2211 } 2212 else if( (SfxPoolItem*)-1 != pPrev->mpItem ) 2213 { 2214 if( pPrev->mnEndPos == nAttrStart && 2215 *pPrev->mpItem == *pItem ) 2216 { 2217 pPrev->mpItem = pItem; 2218 pPrev->mnEndPos = nHintEnd; 2219 } 2220 else 2221 { 2222 rSet.InvalidateItem( nHintWhich ); 2223 pPrev->mpItem = (SfxPoolItem*)-1; 2224 } 2225 } 2226 } 2227 2228 pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() ) 2229 ? pItemIter->NextItem() : 0; 2230 } // end while 2231 } 2232 } 2233 2234 if ( pAttrArr.get() ) 2235 { 2236 for (sal_uInt16 n = 0; n < coArrSz; ++n) 2237 { 2238 const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ]; 2239 if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) ) 2240 { 2241 const sal_uInt16 nWh = 2242 static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN); 2243 2244 if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende 2245 { 2246 if( *rItemPair.mpItem != aFmtSet.Get( nWh ) ) 2247 (*fnMergeAttr)( rSet, *rItemPair.mpItem ); 2248 } 2249 else 2250 // uneindeutig 2251 rSet.InvalidateItem( nWh ); 2252 } 2253 } 2254 } 2255 } 2256 if( aFmtSet.Count() ) 2257 { 2258 // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind 2259 aFmtSet.Differentiate( rSet ); 2260 // jetzt alle zusammen "mergen" 2261 rSet.Put( aFmtSet ); 2262 } 2263 } 2264 else if( !bOnlyTxtAttr ) 2265 { 2266 // dann besorge mal die Auto-(Fmt)Attribute 2267 SwCntntNode::GetAttr( rSet ); 2268 // --> OD 2008-01-16 #newlistlevelattrs# 2269 if ( bMergeIndentValuesOfNumRule ) 2270 { 2271 lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet ); 2272 } 2273 // <-- 2274 } 2275 2276 return rSet.Count() ? sal_True : sal_False; 2277 } 2278 2279 2280 namespace 2281 { 2282 2283 typedef std::pair<sal_uInt16, sal_uInt16> AttrSpan_t; 2284 typedef std::multimap<AttrSpan_t, const SwTxtAttr*> AttrSpanMap_t; 2285 2286 2287 struct IsAutoStyle 2288 { 2289 bool 2290 operator()(const AttrSpanMap_t::value_type& i_rAttrSpan) 2291 const 2292 { 2293 return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT; 2294 } 2295 }; 2296 2297 2298 /** Removes from io_rAttrSet all items that are set by style on the 2299 given span. 2300 */ 2301 struct RemovePresentAttrs 2302 { 2303 RemovePresentAttrs(SfxItemSet& io_rAttrSet) 2304 : m_rAttrSet(io_rAttrSet) 2305 { 2306 } 2307 2308 void 2309 operator()(const AttrSpanMap_t::value_type& i_rAttrSpan) 2310 const 2311 { 2312 if (!i_rAttrSpan.second) 2313 { 2314 return; 2315 } 2316 2317 const SwTxtAttr* const pAutoStyle(i_rAttrSpan.second); 2318 SfxItemIter aIter(m_rAttrSet); 2319 const SfxPoolItem* pItem(aIter.GetCurItem()); 2320 while (pItem) 2321 { 2322 const sal_uInt16 nWhich(pItem->Which()); 2323 if (CharFmt::IsItemIncluded(nWhich, pAutoStyle)) 2324 { 2325 m_rAttrSet.ClearItem(nWhich); 2326 } 2327 2328 if (aIter.IsAtEnd()) 2329 { 2330 break; 2331 } 2332 pItem = aIter.NextItem(); 2333 } 2334 } 2335 2336 private: 2337 SfxItemSet& m_rAttrSet; 2338 }; 2339 2340 2341 /** Collects all style-covered spans from i_rHints to o_rSpanMap. In 2342 addition inserts dummy spans with pointer to format equal to 0 for 2343 all gaps (i.e. spans not covered by any style). This simplifies 2344 creation of autostyles for all needed spans, but it means all code 2345 that tries to access the pointer has to check if it's non-null! 2346 */ 2347 void 2348 lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_uInt16 nLength, 2349 AttrSpanMap_t& o_rSpanMap) 2350 { 2351 sal_uInt16 nLastEnd(0); 2352 2353 for (sal_uInt16 i(0); i != i_rHints.Count(); ++i) 2354 { 2355 const SwTxtAttr* const pHint(i_rHints[i]); 2356 const sal_uInt16 nWhich(pHint->Which()); 2357 if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT) 2358 { 2359 const AttrSpan_t aSpan(*pHint->GetStart(), *pHint->End()); 2360 o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint)); 2361 2362 // < not != because there may be multiple CHARFMT at same range 2363 if (nLastEnd < aSpan.first) 2364 { 2365 // insert dummy span covering the gap 2366 o_rSpanMap.insert(AttrSpanMap_t::value_type( 2367 AttrSpan_t(nLastEnd, aSpan.first), 0)); 2368 } 2369 2370 nLastEnd = aSpan.second; 2371 } 2372 } 2373 2374 // no hints at the end (special case: no hints at all in i_rHints) 2375 if (nLastEnd != nLength && nLength != 0) 2376 { 2377 o_rSpanMap.insert( 2378 AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), 0)); 2379 } 2380 } 2381 2382 2383 void 2384 lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds) 2385 { 2386 o_rClearIds.reserve(i_rAttrSet.Count()); 2387 SfxItemIter aIter(i_rAttrSet); 2388 const SfxPoolItem* pItem(aIter.GetCurItem()); 2389 while (true) 2390 { 2391 o_rClearIds.push_back(pItem->Which()); 2392 2393 if (aIter.IsAtEnd()) 2394 { 2395 break; 2396 } 2397 pItem = aIter.NextItem(); 2398 } 2399 } 2400 2401 struct SfxItemSetClearer 2402 { 2403 SfxItemSet & m_rItemSet; 2404 SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { } 2405 void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); } 2406 }; 2407 2408 } 2409 2410 2411 /** Does the hard work of SwTxtNode::FmtToTxtAttr: the real conversion 2412 of items to automatic styles. 2413 */ 2414 void 2415 SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet) 2416 { 2417 typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t; 2418 AttrSpanMap_t aAttrSpanMap; 2419 2420 if (i_rAttrSet.Count() == 0) 2421 { 2422 return; 2423 } 2424 2425 // 1. Identify all spans in hints' array 2426 2427 lcl_CollectHintSpans(*m_pSwpHints, m_Text.Len(), aAttrSpanMap); 2428 2429 // 2. Go through all spans and insert new attrs 2430 2431 AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin()); 2432 const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end()); 2433 while (aCurRange != aEnd) 2434 { 2435 typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t> 2436 AttrSpanMapRange_t; 2437 AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first)); 2438 2439 // 2a. Collect attributes to insert 2440 2441 SfxItemSet aCurSet(i_rAttrSet); 2442 std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet)); 2443 2444 // 2b. Insert automatic style containing the collected attributes 2445 2446 if (aCurSet.Count() != 0) 2447 { 2448 AttrSpanMap_iterator_t aAutoStyleIt( 2449 std::find_if(aRange.first, aRange.second, IsAutoStyle())); 2450 if (aAutoStyleIt != aRange.second) 2451 { 2452 // there already is an automatic style on that span: 2453 // create new one and remove the original one 2454 SwTxtAttr* const pAutoStyle(const_cast<SwTxtAttr*>(aAutoStyleIt->second)); 2455 const boost::shared_ptr<SfxItemSet> pOldStyle( 2456 static_cast<const SwFmtAutoFmt&>( 2457 pAutoStyle->GetAttr()).GetStyleHandle()); 2458 aCurSet.Put(*pOldStyle); 2459 2460 // remove the old hint 2461 m_pSwpHints->Delete(pAutoStyle); 2462 DestroyAttr(pAutoStyle); 2463 } 2464 m_pSwpHints->Insert( 2465 MakeTxtAttr(*GetDoc(), aCurSet, 2466 aCurRange->first.first, aCurRange->first.second)); 2467 } 2468 2469 aCurRange = aRange.second; 2470 } 2471 2472 // 3. Clear items from the node 2473 std::vector<sal_uInt16> aClearedIds; 2474 lcl_FillWhichIds(i_rAttrSet, aClearedIds); 2475 ClearItemsFromAttrSet(aClearedIds); 2476 } 2477 2478 void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd ) 2479 { 2480 SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange ); 2481 if( HasSwAttrSet() && GetpSwAttrSet()->Count() ) 2482 aThisSet.Put( *GetpSwAttrSet() ); 2483 2484 GetOrCreateSwpHints(); 2485 2486 if( pNd == this ) 2487 { 2488 impl_FmtToTxtAttr(aThisSet); 2489 } 2490 else 2491 { 2492 // There are five possible combinations of items from this and 2493 // pNd (pNd is the 'main' node): 2494 // 2495 // case pNd this action 2496 // ---------------------------------------------------- 2497 // 1 - - do nothing 2498 // 2 - a convert item to attr of this 2499 // 3 a - convert item to attr of pNd 2500 // 4 a a clear item in this 2501 // 5 a b convert item to attr of this 2502 2503 SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange ); 2504 if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() ) 2505 aNdSet.Put( *pNd->GetpSwAttrSet() ); 2506 2507 pNd->GetOrCreateSwpHints(); 2508 2509 std::vector<sal_uInt16> aProcessedIds; 2510 2511 if( aThisSet.Count() ) 2512 { 2513 SfxItemIter aIter( aThisSet ); 2514 const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0; 2515 SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFmtSetRange ); 2516 std::vector<sal_uInt16> aClearWhichIds; 2517 2518 while( true ) 2519 { 2520 if( SFX_ITEM_SET == aNdSet.GetItemState( pItem->Which(), sal_False, &pNdItem ) ) 2521 { 2522 if (*pItem == *pNdItem) // 4 2523 { 2524 aClearWhichIds.push_back( pItem->Which() ); 2525 } 2526 else // 5 2527 { 2528 aConvertSet.Put(*pItem); 2529 } 2530 aProcessedIds.push_back(pItem->Which()); 2531 } 2532 else // 2 2533 { 2534 aConvertSet.Put(*pItem); 2535 } 2536 2537 if( aIter.IsAtEnd() ) 2538 break; 2539 pItem = aIter.NextItem(); 2540 } 2541 2542 // 4/ clear items of this that are set with the same value on pNd 2543 ClearItemsFromAttrSet( aClearWhichIds ); 2544 2545 // 2, 5/ convert all other items to attrs 2546 impl_FmtToTxtAttr(aConvertSet); 2547 } 2548 2549 { 2550 std::for_each(aProcessedIds.begin(), aProcessedIds.end(), 2551 SfxItemSetClearer(aNdSet)); 2552 2553 // 3/ convert items to attrs 2554 pNd->impl_FmtToTxtAttr(aNdSet); 2555 2556 if( aNdSet.Count() ) 2557 { 2558 SwFmtChg aTmp1( pNd->GetFmtColl() ); 2559 pNd->NotifyClients( &aTmp1, &aTmp1 ); 2560 } 2561 } 2562 } 2563 2564 SetCalcHiddenCharFlags(); 2565 2566 pNd->TryDeleteSwpHints(); 2567 } 2568 2569 /************************************************************************* 2570 * SwpHints::CalcFlags() 2571 *************************************************************************/ 2572 2573 void SwpHints::CalcFlags() 2574 { 2575 m_bDDEFields = m_bFootnote = false; 2576 const sal_uInt16 nSize = Count(); 2577 const SwTxtAttr* pAttr; 2578 for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos ) 2579 { 2580 switch( ( pAttr = (*this)[ nPos ])->Which() ) 2581 { 2582 case RES_TXTATR_FTN: 2583 m_bFootnote = true; 2584 if ( m_bDDEFields ) 2585 return; 2586 break; 2587 case RES_TXTATR_FIELD: 2588 { 2589 const SwField* pFld = pAttr->GetFmtFld().GetField(); 2590 if( RES_DDEFLD == pFld->GetTyp()->Which() ) 2591 { 2592 m_bDDEFields = true; 2593 if ( m_bFootnote ) 2594 return; 2595 } 2596 } 2597 break; 2598 } 2599 } 2600 } 2601 2602 /************************************************************************* 2603 * SwpHints::CalcVisibleFlag() 2604 *************************************************************************/ 2605 2606 bool SwpHints::CalcHiddenParaField() 2607 { 2608 m_bCalcHiddenParaField = false; 2609 bool bOldHasHiddenParaField = m_bHasHiddenParaField; 2610 bool bNewHasHiddenParaField = false; 2611 const sal_uInt16 nSize = Count(); 2612 const SwTxtAttr *pTxtHt; 2613 2614 for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos ) 2615 { 2616 pTxtHt = (*this)[ nPos ]; 2617 const sal_uInt16 nWhich = pTxtHt->Which(); 2618 2619 if( RES_TXTATR_FIELD == nWhich ) 2620 { 2621 const SwFmtFld& rFld = pTxtHt->GetFmtFld(); 2622 if( RES_HIDDENPARAFLD == rFld.GetField()->GetTyp()->Which() ) 2623 { 2624 if( !((SwHiddenParaField*)rFld.GetField())->IsHidden() ) 2625 { 2626 SetHiddenParaField(false); 2627 return bOldHasHiddenParaField != bNewHasHiddenParaField; 2628 } 2629 else 2630 { 2631 bNewHasHiddenParaField = true; 2632 } 2633 } 2634 } 2635 } 2636 SetHiddenParaField( bNewHasHiddenParaField ); 2637 return bOldHasHiddenParaField != bNewHasHiddenParaField; 2638 } 2639 2640 2641 /************************************************************************* 2642 * SwpHints::NoteInHistory() 2643 *************************************************************************/ 2644 2645 void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew ) 2646 { 2647 if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); } 2648 } 2649 2650 /************************************************************************* 2651 * SwpHints::MergePortions( ) 2652 *************************************************************************/ 2653 2654 bool SwpHints::MergePortions( SwTxtNode& rNode ) 2655 { 2656 if ( !Count() ) 2657 return false; 2658 2659 // sort before merging 2660 SwpHintsArray::Resort(); 2661 2662 bool bRet = false; 2663 typedef std::multimap< int, SwTxtAttr* > PortionMap; 2664 PortionMap aPortionMap; 2665 xub_StrLen nLastPorStart = STRING_LEN; 2666 sal_uInt16 i = 0; 2667 int nKey = 0; 2668 2669 // get portions by start position: 2670 for ( i = 0; i < Count(); ++i ) 2671 { 2672 SwTxtAttr *pHt = GetTextHint( i ); 2673 if ( RES_TXTATR_CHARFMT != pHt->Which() && 2674 RES_TXTATR_AUTOFMT != pHt->Which() ) 2675 //&& 2676 //RES_TXTATR_INETFMT != pHt->Which() ) 2677 continue; 2678 2679 const xub_StrLen nPorStart = *pHt->GetStart(); 2680 if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN ) 2681 ++nKey; 2682 nLastPorStart = nPorStart; 2683 aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) ); 2684 } 2685 2686 // check if portion i can be merged with portion i+1: 2687 i = 0; 2688 int j = i + 1; 2689 while ( i <= nKey ) 2690 { 2691 std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i ); 2692 std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j ); 2693 PortionMap::iterator aIter1 = aRange1.first; 2694 PortionMap::iterator aIter2 = aRange2.first; 2695 2696 bool bMerge = true; 2697 const sal_uInt16 nAttributesInPor1 = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second )); 2698 const sal_uInt16 nAttributesInPor2 = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second )); 2699 2700 if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 ) 2701 { 2702 while ( aIter1 != aRange1.second ) 2703 { 2704 const SwTxtAttr* p1 = (*aIter1).second; 2705 const SwTxtAttr* p2 = (*aIter2).second; 2706 if ( *p1->End() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) ) 2707 { 2708 bMerge = false; 2709 break; 2710 } 2711 ++aIter1; 2712 ++aIter2; 2713 } 2714 } 2715 else 2716 { 2717 bMerge = false; 2718 } 2719 2720 if ( bMerge ) 2721 { 2722 // erase all elements with key i + 1 2723 xub_StrLen nNewPortionEnd = 0; 2724 for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 ) 2725 { 2726 SwTxtAttr* p2 = (*aIter2).second; 2727 nNewPortionEnd = *p2->GetEnd(); 2728 2729 const sal_uInt16 nCountBeforeDelete = Count(); 2730 Delete( p2 ); 2731 2732 // robust: check if deletion actually took place before destroying attribute: 2733 if ( Count() < nCountBeforeDelete ) 2734 rNode.DestroyAttr( p2 ); 2735 } 2736 aPortionMap.erase( aRange2.first, aRange2.second ); 2737 ++j; 2738 2739 // change all attributes with key i 2740 aRange1 = aPortionMap.equal_range( i ); 2741 for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 ) 2742 { 2743 SwTxtAttr* p1 = (*aIter1).second; 2744 NoteInHistory( p1 ); 2745 *p1->GetEnd() = nNewPortionEnd; 2746 NoteInHistory( p1, true ); 2747 bRet = true; 2748 } 2749 } 2750 else 2751 { 2752 ++i; 2753 j = i + 1; 2754 } 2755 } 2756 2757 if ( bRet ) 2758 { 2759 SwpHintsArray::Resort(); 2760 } 2761 2762 return bRet; 2763 } 2764 2765 // check if there is already a character format and adjust the sort numbers 2766 void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt ) 2767 { 2768 const xub_StrLen nHtStart = *rNewCharFmt.GetStart(); 2769 const xub_StrLen nHtEnd = *rNewCharFmt.GetEnd(); 2770 sal_uInt16 nSortNumber = 0; 2771 2772 for ( sal_uInt16 i = 0; i < rHints.Count(); ++i ) 2773 { 2774 const SwTxtAttr* pOtherHt = rHints[i]; 2775 2776 const xub_StrLen nOtherStart = *pOtherHt->GetStart(); 2777 2778 if ( nOtherStart > nHtStart ) 2779 break; 2780 2781 if ( RES_TXTATR_CHARFMT == pOtherHt->Which() ) 2782 { 2783 const xub_StrLen nOtherEnd = *pOtherHt->End(); 2784 2785 if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd ) 2786 { 2787 const sal_uInt16 nOtherSortNum = static_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber(); 2788 nSortNumber = nOtherSortNum + 1; 2789 } 2790 } 2791 } 2792 2793 if ( nSortNumber > 0 ) 2794 rNewCharFmt.SetSortNumber( nSortNumber ); 2795 } 2796 2797 /************************************************************************* 2798 * SwpHints::Insert() 2799 *************************************************************************/ 2800 2801 /* 2802 * Try to insert the new hint. 2803 * Depending on the type of the hint, this either always succeeds, or may fail. 2804 * Depending on the type of the hint, other hints may be deleted or 2805 * overwritten. 2806 * The return value indicates successful insertion. 2807 */ 2808 bool SwpHints::TryInsertHint( SwTxtAttr* const pHint, SwTxtNode &rNode, 2809 const SetAttrMode nMode ) 2810 { 2811 if ( USHRT_MAX == Count() ) // we're sorry, this flight is overbooked... 2812 { 2813 ASSERT(false, "hints array full :-("); 2814 return false; 2815 } 2816 2817 // Felder bilden eine Ausnahme: 2818 // 1) Sie koennen nie ueberlappen 2819 // 2) Wenn zwei Felder genau aneinander liegen, 2820 // sollen sie nicht zu einem verschmolzen werden. 2821 // Wir koennen also auf die while-Schleife verzichten 2822 2823 xub_StrLen *pHtEnd = pHint->GetEnd(); 2824 sal_uInt16 nWhich = pHint->Which(); 2825 2826 switch( nWhich ) 2827 { 2828 case RES_TXTATR_CHARFMT: 2829 { 2830 // Check if character format contains hidden attribute: 2831 const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt(); 2832 const SfxPoolItem* pItem; 2833 if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) ) 2834 rNode.SetCalcHiddenCharFlags(); 2835 2836 ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode ); 2837 break; 2838 } 2839 // --> FME 2007-03-16 #i75430# Recalc hidden flags if necessary 2840 case RES_TXTATR_AUTOFMT: 2841 { 2842 // Check if auto style contains hidden attribute: 2843 const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN ); 2844 if ( pHiddenItem ) 2845 rNode.SetCalcHiddenCharFlags(); 2846 break; 2847 } 2848 // <-- 2849 case RES_TXTATR_INETFMT: 2850 static_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode); 2851 break; 2852 case RES_TXTATR_FIELD: 2853 case RES_TXTATR_INPUTFIELD: 2854 { 2855 sal_Bool bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode(); 2856 ((SwTxtFld*)pHint)->ChgTxtNode( &rNode ); 2857 SwDoc* pDoc = rNode.GetDoc(); 2858 const SwField* pFld = ((SwTxtFld*)pHint)->GetFmtFld().GetField(); 2859 2860 if( !pDoc->IsNewFldLst() ) 2861 { 2862 // was fuer ein Feld ist es denn ?? 2863 // bestimmte Felder mussen am Doc das Calculations-Flag updaten 2864 switch( pFld->GetTyp()->Which() ) 2865 { 2866 case RES_DBFLD: 2867 case RES_SETEXPFLD: 2868 case RES_HIDDENPARAFLD: 2869 case RES_HIDDENTXTFLD: 2870 case RES_DBNUMSETFLD: 2871 case RES_DBNEXTSETFLD: 2872 { 2873 if( bDelFirst ) 2874 pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pHint ); 2875 if( rNode.GetNodes().IsDocNodes() ) 2876 pDoc->InsDelFldInFldLst( sal_True, *(SwTxtFld*)pHint ); 2877 } 2878 break; 2879 case RES_DDEFLD: 2880 if( rNode.GetNodes().IsDocNodes() ) 2881 ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt(); 2882 break; 2883 } 2884 } 2885 2886 // gehts ins normale Nodes-Array? 2887 if( rNode.GetNodes().IsDocNodes() ) 2888 { 2889 sal_Bool bInsFldType = sal_False; 2890 switch( pFld->GetTyp()->Which() ) 2891 { 2892 case RES_SETEXPFLD: 2893 bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted(); 2894 if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() ) 2895 { 2896 // bevor die ReferenzNummer gesetzt wird, sollte 2897 // das Feld am richtigen FeldTypen haengen! 2898 SwSetExpFieldType* pFldType = (SwSetExpFieldType*) 2899 pDoc->InsertFldType( *pFld->GetTyp() ); 2900 if( pFldType != pFld->GetTyp() ) 2901 { 2902 SwFmtFld* pFmtFld = (SwFmtFld*)&((SwTxtFld*)pHint)->GetFmtFld(); 2903 pFmtFld->RegisterToFieldType( *pFldType ); 2904 pFmtFld->GetField()->ChgTyp( pFldType ); 2905 } 2906 pFldType->SetSeqRefNo( *(SwSetExpField*)pFld ); 2907 } 2908 break; 2909 case RES_USERFLD: 2910 bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted(); 2911 break; 2912 2913 case RES_DDEFLD: 2914 if( pDoc->IsNewFldLst() ) 2915 ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt(); 2916 bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted(); 2917 break; 2918 2919 case RES_POSTITFLD: 2920 if ( pDoc->GetDocShell() ) 2921 pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_INSERTED ) ); 2922 break; 2923 } 2924 if( bInsFldType ) 2925 pDoc->InsDeletedFldType( *pFld->GetTyp() ); 2926 } 2927 } 2928 break; 2929 case RES_TXTATR_FTN : 2930 ((SwTxtFtn*)pHint)->ChgTxtNode( &rNode ); 2931 break; 2932 case RES_TXTATR_REFMARK: 2933 ((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode ); 2934 if( rNode.GetNodes().IsDocNodes() ) 2935 { 2936 // search for a reference with the same name 2937 SwTxtAttr* pTmpHt; 2938 xub_StrLen *pTmpHtEnd, *pTmpHintEnd; 2939 for( sal_uInt16 n = 0, nEnd = Count(); n < nEnd; ++n ) 2940 { 2941 if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() && 2942 pHint->GetAttr() == pTmpHt->GetAttr() && 2943 0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) && 2944 0 != ( pTmpHintEnd = pHint->GetEnd() ) ) 2945 { 2946 SwComparePosition eCmp = ::ComparePosition( 2947 *pTmpHt->GetStart(), *pTmpHtEnd, 2948 *pHint->GetStart(), *pTmpHintEnd ); 2949 sal_Bool bDelOld = sal_True, bChgStart = sal_False, bChgEnd = sal_False; 2950 switch( eCmp ) 2951 { 2952 case POS_BEFORE: 2953 case POS_BEHIND: bDelOld = sal_False; break; 2954 2955 case POS_OUTSIDE: bChgStart = bChgEnd = sal_True; break; 2956 2957 case POS_COLLIDE_END: 2958 case POS_OVERLAP_BEFORE: bChgStart = sal_True; break; 2959 case POS_COLLIDE_START: 2960 case POS_OVERLAP_BEHIND: bChgEnd = sal_True; break; 2961 default: break; 2962 } 2963 2964 if( bChgStart ) 2965 *pHint->GetStart() = *pTmpHt->GetStart(); 2966 if( bChgEnd ) 2967 *pTmpHintEnd = *pTmpHtEnd; 2968 2969 if( bDelOld ) 2970 { 2971 NoteInHistory( pTmpHt ); 2972 rNode.DestroyAttr( Cut( n-- ) ); 2973 --nEnd; 2974 } 2975 } 2976 } 2977 } 2978 break; 2979 case RES_TXTATR_TOXMARK: 2980 ((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode ); 2981 break; 2982 2983 case RES_TXTATR_CJK_RUBY: 2984 static_cast<SwTxtRuby*>(pHint)->InitRuby(rNode); 2985 break; 2986 2987 case RES_TXTATR_META: 2988 case RES_TXTATR_METAFIELD: 2989 static_cast<SwTxtMeta *>(pHint)->ChgTxtNode( &rNode ); 2990 break; 2991 2992 case RES_CHRATR_HIDDEN: 2993 rNode.SetCalcHiddenCharFlags(); 2994 break; 2995 } 2996 2997 if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode ) 2998 pHint->SetDontExpand( sal_True ); 2999 3000 // SwTxtAttrs ohne Ende werden sonderbehandelt: 3001 // Sie werden natuerlich in das Array insertet, aber sie werden nicht 3002 // in die pPrev/Next/On/Off-Verkettung aufgenommen. 3003 // Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text ! 3004 xub_StrLen nHtStart = *pHint->GetStart(); 3005 if( !pHtEnd ) 3006 { 3007 SwpHintsArray::Insert( pHint ); 3008 CalcFlags(); 3009 #ifdef DBG_UTIL 3010 if( !rNode.GetDoc()->IsInReading() ) 3011 CHECK; 3012 #endif 3013 // ... und die Abhaengigen benachrichtigen 3014 if ( rNode.GetDepends() ) 3015 { 3016 SwUpdateAttr aHint( nHtStart, nHtStart, nWhich ); 3017 rNode.ModifyNotification( 0, &aHint ); 3018 } 3019 return true; 3020 } 3021 3022 // ---------------------------------------------------------------- 3023 // Ab hier gibt es nur noch pHint mit einem EndIdx !!! 3024 3025 if( *pHtEnd < nHtStart ) 3026 { 3027 ASSERT( *pHtEnd >= nHtStart, 3028 "+SwpHints::Insert: invalid hint, end < start" ); 3029 3030 // Wir drehen den Quatsch einfach um: 3031 *pHint->GetStart() = *pHtEnd; 3032 *pHtEnd = nHtStart; 3033 nHtStart = *pHint->GetStart(); 3034 } 3035 3036 // I need this value later on for notification but the pointer may become invalid 3037 const xub_StrLen nHintEnd = *pHtEnd; 3038 const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode); 3039 3040 // handle nesting attributes: inserting may fail due to overlap! 3041 if (pHint->IsNesting()) 3042 { 3043 const bool bRet( 3044 TryInsertNesting(rNode, *static_cast<SwTxtAttrNesting*>(pHint))); 3045 if (!bRet) return false; 3046 } 3047 // Currently REFMARK and TOXMARK have OverlapAllowed set to true. 3048 // These attributes may be inserted directly. 3049 // Also attributes without length may be inserted directly. 3050 // SETATTR_NOHINTADJUST is set e.g., during undo. 3051 // Portion building in not necessary during XML import. 3052 else 3053 if ( !bNoHintAdjustMode && 3054 !pHint->IsOverlapAllowedAttr() && 3055 !rNode.GetDoc()->IsInXMLImport() && 3056 ( RES_TXTATR_AUTOFMT == nWhich || 3057 RES_TXTATR_CHARFMT == nWhich ) ) 3058 { 3059 ASSERT( nWhich != RES_TXTATR_AUTOFMT || 3060 static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() == 3061 &rNode.GetDoc()->GetAttrPool(), 3062 "AUTOSTYLES - Pool mismatch" ) 3063 3064 BuildPortions( rNode, *pHint, nMode ); 3065 3066 if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes 3067 MergePortions( rNode ); 3068 } 3069 else 3070 { 3071 // There may be more than one character style at the current position. 3072 // Take care of the sort number. 3073 // Special case ruby portion: During import, the ruby attribute is set 3074 // multiple times 3075 // Special case hyperlink: During import, the ruby attribute is set 3076 // multiple times 3077 // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert 3078 // character attributes directly 3079 if ( ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode ) ) 3080 { 3081 BuildPortions( rNode, *pHint, nMode ); 3082 } 3083 else 3084 { 3085 // --> FME 2007-11-08 #i82989# Check sort numbers in NoHintAdjustMode 3086 if ( RES_TXTATR_CHARFMT == nWhich ) 3087 lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) ); 3088 // <-- 3089 3090 SwpHintsArray::Insert( pHint ); 3091 NoteInHistory( pHint, true ); 3092 } 3093 } 3094 3095 // ... und die Abhaengigen benachrichtigen 3096 if ( rNode.GetDepends() ) 3097 { 3098 SwUpdateAttr aHint( nHtStart, nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd, nWhich ); 3099 rNode.ModifyNotification( 0, &aHint ); 3100 } 3101 3102 #ifdef DBG_UTIL 3103 if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() ) 3104 CHECK; 3105 #endif 3106 3107 return true; 3108 } 3109 3110 /************************************************************************* 3111 * SwpHints::DeleteAtPos() 3112 *************************************************************************/ 3113 3114 void SwpHints::DeleteAtPos( const sal_uInt16 nPos ) 3115 { 3116 SwTxtAttr *pHint = GetTextHint(nPos); 3117 // ChainDelete( pHint ); 3118 NoteInHistory( pHint ); 3119 SwpHintsArray::DeleteAtPos( nPos ); 3120 3121 if( RES_TXTATR_FIELD == pHint->Which() ) 3122 { 3123 const SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFmtFld().GetField()->GetTyp(); 3124 if( RES_DDEFLD == pFldTyp->Which() ) 3125 { 3126 const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode(); 3127 if( pNd && pNd->GetNodes().IsDocNodes() ) 3128 ((SwDDEFieldType*)pFldTyp)->DecRefCnt(); 3129 ((SwTxtFld*)pHint)->ChgTxtNode( 0 ); 3130 } 3131 else if( RES_POSTITFLD == pFldTyp->Which() ) 3132 { 3133 const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFmtFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFmtFld(), SWFMTFLD_REMOVED ) ); 3134 } 3135 else if ( m_bHasHiddenParaField && 3136 RES_HIDDENPARAFLD == pFldTyp->Which() ) 3137 { 3138 m_bCalcHiddenParaField = true; 3139 } 3140 } 3141 3142 CalcFlags(); 3143 CHECK; 3144 } 3145 3146 // Ist der Hint schon bekannt, dann suche die Position und loesche ihn. 3147 // Ist er nicht im Array, so gibt es ein ASSERT !! 3148 3149 void SwpHints::Delete( SwTxtAttr* pTxtHt ) 3150 { 3151 // Attr 2.0: SwpHintsArr::Delete( pTxtHt ); 3152 const sal_uInt16 nPos = GetStartOf( pTxtHt ); 3153 ASSERT( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" ); 3154 if( USHRT_MAX != nPos ) 3155 DeleteAtPos( nPos ); 3156 } 3157 3158 void SwTxtNode::ClearSwpHintsArr( bool bDelFields ) 3159 { 3160 if ( HasHints() ) 3161 { 3162 sal_uInt16 nPos = 0; 3163 while ( nPos < m_pSwpHints->Count() ) 3164 { 3165 SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos ); 3166 bool bDel = false; 3167 3168 switch( pDel->Which() ) 3169 { 3170 case RES_TXTATR_FLYCNT: 3171 case RES_TXTATR_FTN: 3172 break; 3173 3174 case RES_TXTATR_FIELD: 3175 case RES_TXTATR_INPUTFIELD: 3176 if( bDelFields ) 3177 bDel = true; 3178 break; 3179 default: 3180 bDel = true; break; 3181 } 3182 3183 if( bDel ) 3184 { 3185 m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos ); 3186 DestroyAttr( pDel ); 3187 } 3188 else 3189 ++nPos; 3190 } 3191 } 3192 } 3193 3194 sal_uInt16 SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen, 3195 sal_uInt16 nScript ) const 3196 { 3197 sal_uInt16 nRet = LANGUAGE_DONTKNOW; 3198 3199 if ( ! nScript ) 3200 { 3201 nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin ); 3202 } 3203 3204 // --> FME 2008-09-29 #i91465# hennerdrewes: Consider nScript if pSwpHints == 0 3205 const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript ); 3206 // <-- 3207 3208 if ( HasHints() ) 3209 { 3210 const xub_StrLen nEnd = nBegin + nLen; 3211 for ( sal_uInt16 i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i ) 3212 { 3213 // ist der Attribut-Anfang schon groesser als der Idx ? 3214 const SwTxtAttr *pHt = m_pSwpHints->operator[](i); 3215 const xub_StrLen nAttrStart = *pHt->GetStart(); 3216 if( nEnd < nAttrStart ) 3217 break; 3218 3219 const sal_uInt16 nWhich = pHt->Which(); 3220 3221 if( nWhichId == nWhich || 3222 ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) ) 3223 { 3224 const xub_StrLen *pEndIdx = pHt->End(); 3225 // Ueberlappt das Attribut den Bereich? 3226 3227 if( pEndIdx && 3228 nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx ) 3229 : (( nAttrStart < nBegin && 3230 ( pHt->DontExpand() ? nBegin < *pEndIdx 3231 : nBegin <= *pEndIdx )) || 3232 ( nBegin == nAttrStart && 3233 ( nAttrStart == *pEndIdx || !nBegin ))) ) 3234 { 3235 const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId ); 3236 sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage(); 3237 3238 // Umfasst das Attribut den Bereich komplett? 3239 if( nAttrStart <= nBegin && nEnd <= *pEndIdx ) 3240 nRet = nLng; 3241 else if( LANGUAGE_DONTKNOW == nRet ) 3242 nRet = nLng; // partielle Ueberlappung, der 1. gewinnt 3243 } 3244 } 3245 } 3246 } 3247 if( LANGUAGE_DONTKNOW == nRet ) 3248 { 3249 nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage(); 3250 if( LANGUAGE_DONTKNOW == nRet ) 3251 nRet = static_cast<sal_uInt16>(GetAppLanguage()); 3252 } 3253 return nRet; 3254 } 3255 3256 3257 sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr ) 3258 { 3259 sal_Unicode cRet = CH_TXTATR_BREAKWORD; 3260 switch ( rAttr.Which() ) 3261 { 3262 case RES_TXTATR_FTN: 3263 case RES_TXTATR_REFMARK: 3264 case RES_TXTATR_TOXMARK: 3265 case RES_TXTATR_META: 3266 case RES_TXTATR_METAFIELD: 3267 cRet = CH_TXTATR_INWORD; 3268 break; 3269 3270 case RES_TXTATR_FIELD: 3271 case RES_TXTATR_FLYCNT: 3272 { 3273 cRet = CH_TXTATR_BREAKWORD; 3274 3275 // #i78149: PostIt fields should not break words for spell and grammar checking 3276 if (rAttr.Which() == RES_TXTATR_FIELD && 3277 RES_POSTITFLD == rAttr.GetFmtFld().GetField()->GetTyp()->Which()) 3278 cRet = CH_TXTATR_INWORD; 3279 } 3280 break; 3281 3282 default: 3283 ASSERT(false, "GetCharOfTxtAttr: unknown attr"); 3284 break; 3285 } 3286 return cRet; 3287 } 3288 3289 3290