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