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