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