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 29 #define _SVSTDARR_USHORTS 30 #define _SVSTDARR_USHORTSSORT 31 #include <svl/svstdarr.hxx> 32 #include <doc.hxx> 33 #include <cntfrm.hxx> // ASSERT in ~SwTxtFtn() 34 #include <pagefrm.hxx> // RemoveFtn() 35 #include <fmtftn.hxx> 36 #include <txtftn.hxx> 37 #include <ftnidx.hxx> 38 #include <ftninfo.hxx> 39 #include <swfont.hxx> 40 #include <ndtxt.hxx> 41 #include <poolfmt.hxx> 42 #include <ftnfrm.hxx> 43 #include <ndindex.hxx> 44 #include <fmtftntx.hxx> 45 #include <section.hxx> 46 #include <switerator.hxx> 47 48 /************************************************************************* 49 |* 50 |* class SwFmtFtn 51 |* 52 *************************************************************************/ 53 54 55 SwFmtFtn::SwFmtFtn( bool bEndNote ) 56 : SfxPoolItem( RES_TXTATR_FTN ), 57 pTxtAttr( 0 ), 58 nNumber( 0 ), 59 m_bEndNote( bEndNote ) 60 { 61 } 62 63 64 int SwFmtFtn::operator==( const SfxPoolItem& rAttr ) const 65 { 66 ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); 67 return nNumber == ((SwFmtFtn&)rAttr).nNumber && 68 aNumber == ((SwFmtFtn&)rAttr).aNumber && 69 m_bEndNote == ((SwFmtFtn&)rAttr).m_bEndNote; 70 } 71 72 73 SfxPoolItem* SwFmtFtn::Clone( SfxItemPool* ) const 74 { 75 SwFmtFtn* pNew = new SwFmtFtn; 76 pNew->aNumber = aNumber; 77 pNew->nNumber = nNumber; 78 pNew->m_bEndNote = m_bEndNote; 79 return pNew; 80 } 81 82 void SwFmtFtn::SetEndNote( bool b ) 83 { 84 if ( b != m_bEndNote ) 85 { 86 if ( GetTxtFtn() ) 87 { 88 GetTxtFtn()->DelFrms(0); 89 } 90 m_bEndNote = b; 91 } 92 } 93 94 SwFmtFtn::~SwFmtFtn() 95 { 96 } 97 98 99 void SwFmtFtn::GetFtnText( XubString& rStr ) const 100 { 101 if( pTxtAttr->GetStartNode() ) 102 { 103 SwNodeIndex aIdx( *pTxtAttr->GetStartNode(), 1 ); 104 SwCntntNode* pCNd = aIdx.GetNode().GetTxtNode(); 105 if( !pCNd ) 106 pCNd = aIdx.GetNodes().GoNext( &aIdx ); 107 108 if( pCNd->IsTxtNode() ) 109 rStr = ((SwTxtNode*)pCNd)->GetExpandTxt(); 110 } 111 } 112 113 // returnt den anzuzeigenden String der Fuss-/Endnote 114 XubString SwFmtFtn::GetViewNumStr( const SwDoc& rDoc, sal_Bool bInclStrings ) const 115 { 116 XubString sRet( GetNumStr() ); 117 if( !sRet.Len() ) 118 { 119 // dann ist die Nummer von Interesse, also ueber die Info diese 120 // besorgen. 121 sal_Bool bMakeNum = sal_True; 122 const SwSectionNode* pSectNd = pTxtAttr 123 ? SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtAttr ) 124 : 0; 125 126 if( pSectNd ) 127 { 128 const SwFmtFtnEndAtTxtEnd& rFtnEnd = (SwFmtFtnEndAtTxtEnd&) 129 pSectNd->GetSection().GetFmt()->GetFmtAttr( 130 IsEndNote() ? 131 static_cast<sal_uInt16>(RES_END_AT_TXTEND) : 132 static_cast<sal_uInt16>(RES_FTN_AT_TXTEND) ); 133 134 if( FTNEND_ATTXTEND_OWNNUMANDFMT == rFtnEnd.GetValue() ) 135 { 136 bMakeNum = sal_False; 137 sRet = rFtnEnd.GetSwNumType().GetNumStr( GetNumber() ); 138 if( bInclStrings ) 139 { 140 sRet.Insert( rFtnEnd.GetPrefix(), 0 ); 141 sRet += rFtnEnd.GetSuffix(); 142 } 143 } 144 } 145 146 if( bMakeNum ) 147 { 148 const SwEndNoteInfo* pInfo; 149 if( IsEndNote() ) 150 pInfo = &rDoc.GetEndNoteInfo(); 151 else 152 pInfo = &rDoc.GetFtnInfo(); 153 sRet = pInfo->aFmt.GetNumStr( GetNumber() ); 154 if( bInclStrings ) 155 { 156 sRet.Insert( pInfo->GetPrefix(), 0 ); 157 sRet += pInfo->GetSuffix(); 158 } 159 } 160 } 161 return sRet; 162 } 163 164 /************************************************************************* 165 * class SwTxt/FmtFnt 166 *************************************************************************/ 167 168 SwTxtFtn::SwTxtFtn( SwFmtFtn& rAttr, xub_StrLen nStartPos ) 169 : SwTxtAttr( rAttr, nStartPos ) 170 , m_pStartNode( 0 ) 171 , m_pTxtNode( 0 ) 172 , m_nSeqNo( USHRT_MAX ) 173 { 174 rAttr.pTxtAttr = this; 175 SetHasDummyChar(true); 176 } 177 178 179 SwTxtFtn::~SwTxtFtn() 180 { 181 SetStartNode( 0 ); 182 } 183 184 185 186 void SwTxtFtn::SetStartNode( const SwNodeIndex *pNewNode, sal_Bool bDelNode ) 187 { 188 if( pNewNode ) 189 { 190 if ( !m_pStartNode ) 191 { 192 m_pStartNode = new SwNodeIndex( *pNewNode ); 193 } 194 else 195 { 196 *m_pStartNode = *pNewNode; 197 } 198 } 199 else if ( m_pStartNode ) 200 { 201 // Zwei Dinge muessen erledigt werden: 202 // 1) Die Fussnoten muessen bei ihren Seiten abgemeldet werden 203 // 2) Die Fussnoten-Sektion in den Inserts muss geloescht werden. 204 SwDoc* pDoc; 205 if ( m_pTxtNode ) 206 { 207 pDoc = m_pTxtNode->GetDoc(); 208 } 209 else 210 { 211 //JP 27.01.97: der sw3-Reader setzt einen StartNode aber das 212 // Attribut ist noch nicht im TextNode verankert. 213 // Wird es geloescht (z.B. bei Datei einfuegen mit 214 // Ftn in einen Rahmen), muss auch der Inhalt 215 // geloescht werden 216 pDoc = m_pStartNode->GetNodes().GetDoc(); 217 } 218 219 // Wir duerfen die Fussnotennodes nicht loeschen 220 // und brauchen die Fussnotenframes nicht loeschen, wenn 221 // wir im ~SwDoc() stehen. 222 if( !pDoc->IsInDtor() ) 223 { 224 if( bDelNode ) 225 { 226 // 1) Die Section fuer die Fussnote wird beseitigt 227 // Es kann sein, dass die Inserts schon geloescht wurden. 228 pDoc->DeleteSection( &m_pStartNode->GetNode() ); 229 } 230 else 231 // Werden die Nodes nicht geloescht mussen sie bei den Seiten 232 // abmeldet (Frms loeschen) werden, denn sonst bleiben sie 233 // stehen (Undo loescht sie nicht!) 234 DelFrms( 0 ); 235 } 236 DELETEZ( m_pStartNode ); 237 238 // loesche die Fussnote noch aus dem Array am Dokument 239 for( sal_uInt16 n = 0; n < pDoc->GetFtnIdxs().Count(); ++n ) 240 if( this == pDoc->GetFtnIdxs()[n] ) 241 { 242 pDoc->GetFtnIdxs().Remove( n ); 243 // gibt noch weitere Fussnoten 244 if( !pDoc->IsInDtor() && n < pDoc->GetFtnIdxs().Count() ) 245 { 246 SwNodeIndex aTmp( pDoc->GetFtnIdxs()[n]->GetTxtNode() ); 247 pDoc->GetFtnIdxs().UpdateFtn( aTmp ); 248 } 249 break; 250 } 251 } 252 } 253 254 255 void SwTxtFtn::SetNumber( const sal_uInt16 nNewNum, const XubString* pStr ) 256 { 257 SwFmtFtn& rFtn = (SwFmtFtn&)GetFtn(); 258 if( pStr && pStr->Len() ) 259 rFtn.aNumber = *pStr; 260 else 261 { 262 rFtn.nNumber = nNewNum; 263 rFtn.aNumber = aEmptyStr; 264 } 265 266 ASSERT( m_pTxtNode, "SwTxtFtn: where is my TxtNode?" ); 267 SwNodes &rNodes = m_pTxtNode->GetDoc()->GetNodes(); 268 m_pTxtNode->ModifyNotification( 0, &rFtn ); 269 if ( m_pStartNode ) 270 { 271 // must iterate over all TxtNodes because of footnotes on other pages 272 SwNode* pNd; 273 sal_uLong nSttIdx = m_pStartNode->GetIndex() + 1; 274 sal_uLong nEndIdx = m_pStartNode->GetNode().EndOfSectionIndex(); 275 for( ; nSttIdx < nEndIdx; ++nSttIdx ) 276 { 277 // Es koennen ja auch Grafiken in der Fussnote stehen ... 278 if( ( pNd = rNodes[ nSttIdx ] )->IsTxtNode() ) 279 ((SwTxtNode*)pNd)->ModifyNotification( 0, &rFtn ); 280 } 281 } 282 } 283 284 // Die Fussnoten duplizieren 285 void SwTxtFtn::CopyFtn( 286 SwTxtFtn & rDest, 287 SwTxtNode & rDestNode ) const 288 { 289 if (m_pStartNode && !rDest.GetStartNode()) 290 { 291 // dest missing node section? create it here! 292 // (happens in SwTxtNode::CopyText if pDest == this) 293 rDest.MakeNewTextSection( rDestNode.GetNodes() ); 294 } 295 if (m_pStartNode && rDest.GetStartNode()) 296 { 297 // footnotes not necessarily in same document! 298 SwDoc *const pDstDoc = rDestNode.GetDoc(); 299 SwNodes &rDstNodes = pDstDoc->GetNodes(); 300 301 // copy only the content of the section 302 SwNodeRange aRg( *m_pStartNode, 1, 303 *m_pStartNode->GetNode().EndOfSectionNode() ); 304 305 // insert at the end of rDest, i.e., the nodes are appended. 306 // nDestLen contains number of CntntNodes in rDest _before_ copy. 307 SwNodeIndex aStart( *(rDest.GetStartNode()) ); 308 SwNodeIndex aEnd( *aStart.GetNode().EndOfSectionNode() ); 309 sal_uLong nDestLen = aEnd.GetIndex() - aStart.GetIndex() - 1; 310 311 m_pTxtNode->GetDoc()->CopyWithFlyInFly( aRg, 0, aEnd, NULL, sal_True ); 312 313 // in case the destination section was not empty, delete the old nodes 314 // before: Src: SxxxE, Dst: SnE 315 // now: Src: SxxxE, Dst: SnxxxE 316 // after: Src: SxxxE, Dst: SxxxE 317 aStart++; 318 rDstNodes.Delete( aStart, nDestLen ); 319 } 320 321 // also copy user defined number string 322 if( GetFtn().aNumber.Len() ) 323 { 324 const_cast<SwFmtFtn &>(rDest.GetFtn()).aNumber = GetFtn().aNumber; 325 } 326 } 327 328 329 // lege eine neue leere TextSection fuer diese Fussnote an 330 void SwTxtFtn::MakeNewTextSection( SwNodes& rNodes ) 331 { 332 if ( m_pStartNode ) 333 return; 334 335 // Nun verpassen wir dem TxtNode noch die Fussnotenvorlage. 336 SwTxtFmtColl *pFmtColl; 337 const SwEndNoteInfo* pInfo; 338 sal_uInt16 nPoolId; 339 340 if( GetFtn().IsEndNote() ) 341 { 342 pInfo = &rNodes.GetDoc()->GetEndNoteInfo(); 343 nPoolId = RES_POOLCOLL_ENDNOTE; 344 } 345 else 346 { 347 pInfo = &rNodes.GetDoc()->GetFtnInfo(); 348 nPoolId = RES_POOLCOLL_FOOTNOTE; 349 } 350 351 if( 0 == (pFmtColl = pInfo->GetFtnTxtColl() ) ) 352 pFmtColl = rNodes.GetDoc()->GetTxtCollFromPool( nPoolId ); 353 354 SwStartNode* pSttNd = rNodes.MakeTextSection( SwNodeIndex( rNodes.GetEndOfInserts() ), 355 SwFootnoteStartNode, pFmtColl ); 356 m_pStartNode = new SwNodeIndex( *pSttNd ); 357 } 358 359 360 void SwTxtFtn::DelFrms( const SwFrm* pSib ) 361 { 362 // delete the FtnFrames from the pages 363 ASSERT( m_pTxtNode, "SwTxtFtn: where is my TxtNode?" ); 364 if ( !m_pTxtNode ) 365 return; 366 367 const SwRootFrm* pRoot = pSib ? pSib->getRootFrm() : 0; 368 sal_Bool bFrmFnd = sal_False; 369 { 370 SwIterator<SwCntntFrm,SwTxtNode> aIter( *m_pTxtNode ); 371 for( SwCntntFrm* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() ) 372 { 373 if( pRoot != pFnd->getRootFrm() && pRoot ) 374 continue; 375 SwPageFrm* pPage = pFnd->FindPageFrm(); 376 if( pPage ) 377 { 378 pPage->RemoveFtn( pFnd, this ); 379 bFrmFnd = sal_True; 380 } 381 } 382 } 383 //JP 13.05.97: falls das Layout vorm loeschen der Fussnoten entfernt 384 // wird, sollte man das ueber die Fussnote selbst tun 385 if ( !bFrmFnd && m_pStartNode ) 386 { 387 SwNodeIndex aIdx( *m_pStartNode ); 388 SwCntntNode* pCNd = m_pTxtNode->GetNodes().GoNext( &aIdx ); 389 if( pCNd ) 390 { 391 SwIterator<SwCntntFrm,SwCntntNode> aIter( *pCNd ); 392 for( SwCntntFrm* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() ) 393 { 394 if( pRoot != pFnd->getRootFrm() && pRoot ) 395 continue; 396 SwPageFrm* pPage = pFnd->FindPageFrm(); 397 398 SwFrm *pFrm = pFnd->GetUpper(); 399 while ( pFrm && !pFrm->IsFtnFrm() ) 400 pFrm = pFrm->GetUpper(); 401 402 SwFtnFrm *pFtn = (SwFtnFrm*)pFrm; 403 while ( pFtn && pFtn->GetMaster() ) 404 pFtn = pFtn->GetMaster(); 405 ASSERT( pFtn->GetAttr() == this, "Ftn mismatch error." ); 406 407 while ( pFtn ) 408 { 409 SwFtnFrm *pFoll = pFtn->GetFollow(); 410 pFtn->Cut(); 411 delete pFtn; 412 pFtn = pFoll; 413 } 414 415 // #i20556# During hiding of a section, the connection 416 // to the layout is already lost. pPage may be 0: 417 if ( pPage ) 418 pPage->UpdateFtnNum(); 419 } 420 } 421 } 422 } 423 424 425 sal_uInt16 SwTxtFtn::SetSeqRefNo() 426 { 427 if( !m_pTxtNode ) 428 return USHRT_MAX; 429 430 SwDoc* pDoc = m_pTxtNode->GetDoc(); 431 if( pDoc->IsInReading() ) 432 return USHRT_MAX; 433 434 sal_uInt16 n, nFtnCnt = pDoc->GetFtnIdxs().Count(); 435 436 const sal_uInt8 nTmp = 255 < nFtnCnt ? 255 : static_cast<sal_uInt8>(nFtnCnt); 437 SvUShortsSort aArr( nTmp, nTmp ); 438 439 // dann testmal, ob die Nummer schon vergeben ist oder ob eine neue 440 // bestimmt werden muss. 441 SwTxtFtn* pTxtFtn; 442 for( n = 0; n < nFtnCnt; ++n ) 443 { 444 pTxtFtn = pDoc->GetFtnIdxs()[ n ]; 445 if ( pTxtFtn != this ) 446 { 447 aArr.Insert( pTxtFtn->m_nSeqNo ); 448 } 449 } 450 451 // test if number is already in use 452 if ( USHRT_MAX != m_nSeqNo ) 453 { 454 for( n = 0; n < aArr.Count(); ++n ) 455 { 456 if ( aArr[ n ] > m_nSeqNo ) 457 { 458 return m_nSeqNo; // free -> use 459 } 460 else if ( aArr[ n ] == m_nSeqNo ) 461 { 462 break; // used -> create new one 463 } 464 } 465 466 if ( n == aArr.Count() ) 467 { 468 return m_nSeqNo; // free -> use 469 } 470 } 471 472 // alle Nummern entsprechend geflag, also bestimme die richtige Nummer 473 for( n = 0; n < aArr.Count(); ++n ) 474 if( n != aArr[ n ] ) 475 break; 476 477 return m_nSeqNo = n; 478 } 479 480 void SwTxtFtn::SetUniqueSeqRefNo( SwDoc& rDoc ) 481 { 482 sal_uInt16 n, nStt = 0, nFtnCnt = rDoc.GetFtnIdxs().Count(); 483 484 const sal_uInt8 nTmp = 255 < nFtnCnt ? 255 : static_cast<sal_uInt8>(nFtnCnt); 485 SvUShortsSort aArr( nTmp, nTmp ); 486 487 // dann alle Nummern zusammensammeln die schon existieren 488 SwTxtFtn* pTxtFtn; 489 for( n = 0; n < nFtnCnt; ++n ) 490 { 491 pTxtFtn = rDoc.GetFtnIdxs()[ n ]; 492 if ( USHRT_MAX != pTxtFtn->m_nSeqNo ) 493 { 494 aArr.Insert( pTxtFtn->m_nSeqNo ); 495 } 496 } 497 498 499 for( n = 0; n < nFtnCnt; ++n ) 500 { 501 pTxtFtn = rDoc.GetFtnIdxs()[ n ]; 502 if ( USHRT_MAX == pTxtFtn->m_nSeqNo ) 503 { 504 for( ; nStt < aArr.Count(); ++nStt ) 505 { 506 if ( nStt != aArr[ nStt ] ) 507 { 508 pTxtFtn->m_nSeqNo = nStt; 509 break; 510 } 511 } 512 513 if ( USHRT_MAX == pTxtFtn->m_nSeqNo ) 514 { 515 break; // found nothing 516 } 517 } 518 } 519 520 // alle Nummern schon vergeben, also mit nStt++ weitermachen 521 for( ; n < nFtnCnt; ++n ) 522 { 523 pTxtFtn = rDoc.GetFtnIdxs()[ n ]; 524 if ( USHRT_MAX == pTxtFtn->m_nSeqNo ) 525 { 526 pTxtFtn->m_nSeqNo = nStt++; 527 } 528 } 529 } 530 531 void SwTxtFtn::CheckCondColl() 532 { 533 //FEATURE::CONDCOLL 534 if( GetStartNode() ) 535 ((SwStartNode&)GetStartNode()->GetNode()).CheckSectionCondColl(); 536 //FEATURE::CONDCOLL 537 } 538 539 540 541 542