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