| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| |
| |
| |
| #define _SVSTDARR_USHORTS |
| #define _SVSTDARR_USHORTSSORT |
| #include <svl/svstdarr.hxx> |
| #include <doc.hxx> |
| #include <cntfrm.hxx> // ASSERT in ~SwTxtFtn() |
| #include <pagefrm.hxx> // RemoveFtn() |
| #include <fmtftn.hxx> |
| #include <txtftn.hxx> |
| #include <ftnidx.hxx> |
| #include <ftninfo.hxx> |
| #include <swfont.hxx> |
| #include <ndtxt.hxx> |
| #include <poolfmt.hxx> |
| #include <ftnfrm.hxx> |
| #include <ndindex.hxx> |
| #include <fmtftntx.hxx> |
| #include <section.hxx> |
| #include <switerator.hxx> |
| |
| /************************************************************************* |
| |* |
| |* class SwFmtFtn |
| |* |
| *************************************************************************/ |
| |
| |
| SwFmtFtn::SwFmtFtn( bool bEndNote ) |
| : SfxPoolItem( RES_TXTATR_FTN ), |
| pTxtAttr( 0 ), |
| nNumber( 0 ), |
| m_bEndNote( bEndNote ) |
| { |
| } |
| |
| |
| int SwFmtFtn::operator==( const SfxPoolItem& rAttr ) const |
| { |
| ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); |
| return nNumber == ((SwFmtFtn&)rAttr).nNumber && |
| aNumber == ((SwFmtFtn&)rAttr).aNumber && |
| m_bEndNote == ((SwFmtFtn&)rAttr).m_bEndNote; |
| } |
| |
| |
| SfxPoolItem* SwFmtFtn::Clone( SfxItemPool* ) const |
| { |
| SwFmtFtn* pNew = new SwFmtFtn; |
| pNew->aNumber = aNumber; |
| pNew->nNumber = nNumber; |
| pNew->m_bEndNote = m_bEndNote; |
| return pNew; |
| } |
| |
| void SwFmtFtn::SetEndNote( bool b ) |
| { |
| if ( b != m_bEndNote ) |
| { |
| if ( GetTxtFtn() ) |
| { |
| GetTxtFtn()->DelFrms(0); |
| } |
| m_bEndNote = b; |
| } |
| } |
| |
| SwFmtFtn::~SwFmtFtn() |
| { |
| } |
| |
| |
| void SwFmtFtn::GetFtnText( XubString& rStr ) const |
| { |
| if( pTxtAttr->GetStartNode() ) |
| { |
| SwNodeIndex aIdx( *pTxtAttr->GetStartNode(), 1 ); |
| SwCntntNode* pCNd = aIdx.GetNode().GetTxtNode(); |
| if( !pCNd ) |
| pCNd = aIdx.GetNodes().GoNext( &aIdx ); |
| |
| if( pCNd->IsTxtNode() ) |
| rStr = ((SwTxtNode*)pCNd)->GetExpandTxt(); |
| } |
| } |
| |
| // returnt den anzuzeigenden String der Fuss-/Endnote |
| XubString SwFmtFtn::GetViewNumStr( const SwDoc& rDoc, sal_Bool bInclStrings ) const |
| { |
| XubString sRet( GetNumStr() ); |
| if( !sRet.Len() ) |
| { |
| // dann ist die Nummer von Interesse, also ueber die Info diese |
| // besorgen. |
| sal_Bool bMakeNum = sal_True; |
| const SwSectionNode* pSectNd = pTxtAttr |
| ? SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtAttr ) |
| : 0; |
| |
| if( pSectNd ) |
| { |
| const SwFmtFtnEndAtTxtEnd& rFtnEnd = (SwFmtFtnEndAtTxtEnd&) |
| pSectNd->GetSection().GetFmt()->GetFmtAttr( |
| IsEndNote() ? |
| static_cast<sal_uInt16>(RES_END_AT_TXTEND) : |
| static_cast<sal_uInt16>(RES_FTN_AT_TXTEND) ); |
| |
| if( FTNEND_ATTXTEND_OWNNUMANDFMT == rFtnEnd.GetValue() ) |
| { |
| bMakeNum = sal_False; |
| sRet = rFtnEnd.GetSwNumType().GetNumStr( GetNumber() ); |
| if( bInclStrings ) |
| { |
| sRet.Insert( rFtnEnd.GetPrefix(), 0 ); |
| sRet += rFtnEnd.GetSuffix(); |
| } |
| } |
| } |
| |
| if( bMakeNum ) |
| { |
| const SwEndNoteInfo* pInfo; |
| if( IsEndNote() ) |
| pInfo = &rDoc.GetEndNoteInfo(); |
| else |
| pInfo = &rDoc.GetFtnInfo(); |
| sRet = pInfo->aFmt.GetNumStr( GetNumber() ); |
| if( bInclStrings ) |
| { |
| sRet.Insert( pInfo->GetPrefix(), 0 ); |
| sRet += pInfo->GetSuffix(); |
| } |
| } |
| } |
| return sRet; |
| } |
| |
| /************************************************************************* |
| * class SwTxt/FmtFnt |
| *************************************************************************/ |
| |
| SwTxtFtn::SwTxtFtn( SwFmtFtn& rAttr, xub_StrLen nStartPos ) |
| : SwTxtAttr( rAttr, nStartPos ) |
| , m_pStartNode( 0 ) |
| , m_pTxtNode( 0 ) |
| , m_nSeqNo( USHRT_MAX ) |
| { |
| rAttr.pTxtAttr = this; |
| SetHasDummyChar(true); |
| } |
| |
| |
| SwTxtFtn::~SwTxtFtn() |
| { |
| SetStartNode( 0 ); |
| } |
| |
| |
| |
| void SwTxtFtn::SetStartNode( const SwNodeIndex *pNewNode, sal_Bool bDelNode ) |
| { |
| if( pNewNode ) |
| { |
| if ( !m_pStartNode ) |
| { |
| m_pStartNode = new SwNodeIndex( *pNewNode ); |
| } |
| else |
| { |
| *m_pStartNode = *pNewNode; |
| } |
| } |
| else if ( m_pStartNode ) |
| { |
| // Zwei Dinge muessen erledigt werden: |
| // 1) Die Fussnoten muessen bei ihren Seiten abgemeldet werden |
| // 2) Die Fussnoten-Sektion in den Inserts muss geloescht werden. |
| SwDoc* pDoc; |
| if ( m_pTxtNode ) |
| { |
| pDoc = m_pTxtNode->GetDoc(); |
| } |
| else |
| { |
| //JP 27.01.97: der sw3-Reader setzt einen StartNode aber das |
| // Attribut ist noch nicht im TextNode verankert. |
| // Wird es geloescht (z.B. bei Datei einfuegen mit |
| // Ftn in einen Rahmen), muss auch der Inhalt |
| // geloescht werden |
| pDoc = m_pStartNode->GetNodes().GetDoc(); |
| } |
| |
| // Wir duerfen die Fussnotennodes nicht loeschen |
| // und brauchen die Fussnotenframes nicht loeschen, wenn |
| // wir im ~SwDoc() stehen. |
| if( !pDoc->IsInDtor() ) |
| { |
| if( bDelNode ) |
| { |
| // 1) Die Section fuer die Fussnote wird beseitigt |
| // Es kann sein, dass die Inserts schon geloescht wurden. |
| pDoc->DeleteSection( &m_pStartNode->GetNode() ); |
| } |
| else |
| // Werden die Nodes nicht geloescht mussen sie bei den Seiten |
| // abmeldet (Frms loeschen) werden, denn sonst bleiben sie |
| // stehen (Undo loescht sie nicht!) |
| DelFrms( 0 ); |
| } |
| DELETEZ( m_pStartNode ); |
| |
| // loesche die Fussnote noch aus dem Array am Dokument |
| for( sal_uInt16 n = 0; n < pDoc->GetFtnIdxs().Count(); ++n ) |
| if( this == pDoc->GetFtnIdxs()[n] ) |
| { |
| pDoc->GetFtnIdxs().Remove( n ); |
| // gibt noch weitere Fussnoten |
| if( !pDoc->IsInDtor() && n < pDoc->GetFtnIdxs().Count() ) |
| { |
| SwNodeIndex aTmp( pDoc->GetFtnIdxs()[n]->GetTxtNode() ); |
| pDoc->GetFtnIdxs().UpdateFtn( aTmp ); |
| } |
| break; |
| } |
| } |
| } |
| |
| |
| void SwTxtFtn::SetNumber( const sal_uInt16 nNewNum, const XubString* pStr ) |
| { |
| SwFmtFtn& rFtn = (SwFmtFtn&)GetFtn(); |
| if( pStr && pStr->Len() ) |
| rFtn.aNumber = *pStr; |
| else |
| { |
| rFtn.nNumber = nNewNum; |
| rFtn.aNumber = aEmptyStr; |
| } |
| |
| ASSERT( m_pTxtNode, "SwTxtFtn: where is my TxtNode?" ); |
| SwNodes &rNodes = m_pTxtNode->GetDoc()->GetNodes(); |
| m_pTxtNode->ModifyNotification( 0, &rFtn ); |
| if ( m_pStartNode ) |
| { |
| // must iterate over all TxtNodes because of footnotes on other pages |
| SwNode* pNd; |
| sal_uLong nSttIdx = m_pStartNode->GetIndex() + 1; |
| sal_uLong nEndIdx = m_pStartNode->GetNode().EndOfSectionIndex(); |
| for( ; nSttIdx < nEndIdx; ++nSttIdx ) |
| { |
| // Es koennen ja auch Grafiken in der Fussnote stehen ... |
| if( ( pNd = rNodes[ nSttIdx ] )->IsTxtNode() ) |
| ((SwTxtNode*)pNd)->ModifyNotification( 0, &rFtn ); |
| } |
| } |
| } |
| |
| // Die Fussnoten duplizieren |
| void SwTxtFtn::CopyFtn( |
| SwTxtFtn & rDest, |
| SwTxtNode & rDestNode ) const |
| { |
| if (m_pStartNode && !rDest.GetStartNode()) |
| { |
| // dest missing node section? create it here! |
| // (happens in SwTxtNode::CopyText if pDest == this) |
| rDest.MakeNewTextSection( rDestNode.GetNodes() ); |
| } |
| if (m_pStartNode && rDest.GetStartNode()) |
| { |
| // footnotes not necessarily in same document! |
| SwDoc *const pDstDoc = rDestNode.GetDoc(); |
| SwNodes &rDstNodes = pDstDoc->GetNodes(); |
| |
| // copy only the content of the section |
| SwNodeRange aRg( *m_pStartNode, 1, |
| *m_pStartNode->GetNode().EndOfSectionNode() ); |
| |
| // insert at the end of rDest, i.e., the nodes are appended. |
| // nDestLen contains number of CntntNodes in rDest _before_ copy. |
| SwNodeIndex aStart( *(rDest.GetStartNode()) ); |
| SwNodeIndex aEnd( *aStart.GetNode().EndOfSectionNode() ); |
| sal_uLong nDestLen = aEnd.GetIndex() - aStart.GetIndex() - 1; |
| |
| m_pTxtNode->GetDoc()->CopyWithFlyInFly( aRg, 0, aEnd, NULL, sal_True ); |
| |
| // in case the destination section was not empty, delete the old nodes |
| // before: Src: SxxxE, Dst: SnE |
| // now: Src: SxxxE, Dst: SnxxxE |
| // after: Src: SxxxE, Dst: SxxxE |
| aStart++; |
| rDstNodes.Delete( aStart, nDestLen ); |
| } |
| |
| // also copy user defined number string |
| if( GetFtn().aNumber.Len() ) |
| { |
| const_cast<SwFmtFtn &>(rDest.GetFtn()).aNumber = GetFtn().aNumber; |
| } |
| } |
| |
| |
| // lege eine neue leere TextSection fuer diese Fussnote an |
| void SwTxtFtn::MakeNewTextSection( SwNodes& rNodes ) |
| { |
| if ( m_pStartNode ) |
| return; |
| |
| // Nun verpassen wir dem TxtNode noch die Fussnotenvorlage. |
| SwTxtFmtColl *pFmtColl; |
| const SwEndNoteInfo* pInfo; |
| sal_uInt16 nPoolId; |
| |
| if( GetFtn().IsEndNote() ) |
| { |
| pInfo = &rNodes.GetDoc()->GetEndNoteInfo(); |
| nPoolId = RES_POOLCOLL_ENDNOTE; |
| } |
| else |
| { |
| pInfo = &rNodes.GetDoc()->GetFtnInfo(); |
| nPoolId = RES_POOLCOLL_FOOTNOTE; |
| } |
| |
| if( 0 == (pFmtColl = pInfo->GetFtnTxtColl() ) ) |
| pFmtColl = rNodes.GetDoc()->GetTxtCollFromPool( nPoolId ); |
| |
| SwStartNode* pSttNd = rNodes.MakeTextSection( SwNodeIndex( rNodes.GetEndOfInserts() ), |
| SwFootnoteStartNode, pFmtColl ); |
| m_pStartNode = new SwNodeIndex( *pSttNd ); |
| } |
| |
| |
| void SwTxtFtn::DelFrms( const SwFrm* pSib ) |
| { |
| // delete the FtnFrames from the pages |
| ASSERT( m_pTxtNode, "SwTxtFtn: where is my TxtNode?" ); |
| if ( !m_pTxtNode ) |
| return; |
| |
| const SwRootFrm* pRoot = pSib ? pSib->getRootFrm() : 0; |
| sal_Bool bFrmFnd = sal_False; |
| { |
| SwIterator<SwCntntFrm,SwTxtNode> aIter( *m_pTxtNode ); |
| for( SwCntntFrm* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() ) |
| { |
| if( pRoot != pFnd->getRootFrm() && pRoot ) |
| continue; |
| SwPageFrm* pPage = pFnd->FindPageFrm(); |
| if( pPage ) |
| { |
| pPage->RemoveFtn( pFnd, this ); |
| bFrmFnd = sal_True; |
| } |
| } |
| } |
| //JP 13.05.97: falls das Layout vorm loeschen der Fussnoten entfernt |
| // wird, sollte man das ueber die Fussnote selbst tun |
| if ( !bFrmFnd && m_pStartNode ) |
| { |
| SwNodeIndex aIdx( *m_pStartNode ); |
| SwCntntNode* pCNd = m_pTxtNode->GetNodes().GoNext( &aIdx ); |
| if( pCNd ) |
| { |
| SwIterator<SwCntntFrm,SwCntntNode> aIter( *pCNd ); |
| for( SwCntntFrm* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() ) |
| { |
| if( pRoot != pFnd->getRootFrm() && pRoot ) |
| continue; |
| SwPageFrm* pPage = pFnd->FindPageFrm(); |
| |
| SwFrm *pFrm = pFnd->GetUpper(); |
| while ( pFrm && !pFrm->IsFtnFrm() ) |
| pFrm = pFrm->GetUpper(); |
| |
| SwFtnFrm *pFtn = (SwFtnFrm*)pFrm; |
| while ( pFtn && pFtn->GetMaster() ) |
| pFtn = pFtn->GetMaster(); |
| ASSERT( pFtn->GetAttr() == this, "Ftn mismatch error." ); |
| |
| while ( pFtn ) |
| { |
| SwFtnFrm *pFoll = pFtn->GetFollow(); |
| pFtn->Cut(); |
| delete pFtn; |
| pFtn = pFoll; |
| } |
| |
| // #i20556# During hiding of a section, the connection |
| // to the layout is already lost. pPage may be 0: |
| if ( pPage ) |
| pPage->UpdateFtnNum(); |
| } |
| } |
| } |
| } |
| |
| |
| sal_uInt16 SwTxtFtn::SetSeqRefNo() |
| { |
| if( !m_pTxtNode ) |
| return USHRT_MAX; |
| |
| SwDoc* pDoc = m_pTxtNode->GetDoc(); |
| if( pDoc->IsInReading() ) |
| return USHRT_MAX; |
| |
| sal_uInt16 n, nFtnCnt = pDoc->GetFtnIdxs().Count(); |
| |
| const sal_uInt8 nTmp = 255 < nFtnCnt ? 255 : static_cast<sal_uInt8>(nFtnCnt); |
| SvUShortsSort aArr( nTmp, nTmp ); |
| |
| // dann testmal, ob die Nummer schon vergeben ist oder ob eine neue |
| // bestimmt werden muss. |
| SwTxtFtn* pTxtFtn; |
| for( n = 0; n < nFtnCnt; ++n ) |
| { |
| pTxtFtn = pDoc->GetFtnIdxs()[ n ]; |
| if ( pTxtFtn != this ) |
| { |
| aArr.Insert( pTxtFtn->m_nSeqNo ); |
| } |
| } |
| |
| // test if number is already in use |
| if ( USHRT_MAX != m_nSeqNo ) |
| { |
| for( n = 0; n < aArr.Count(); ++n ) |
| { |
| if ( aArr[ n ] > m_nSeqNo ) |
| { |
| return m_nSeqNo; // free -> use |
| } |
| else if ( aArr[ n ] == m_nSeqNo ) |
| { |
| break; // used -> create new one |
| } |
| } |
| |
| if ( n == aArr.Count() ) |
| { |
| return m_nSeqNo; // free -> use |
| } |
| } |
| |
| // alle Nummern entsprechend geflag, also bestimme die richtige Nummer |
| for( n = 0; n < aArr.Count(); ++n ) |
| if( n != aArr[ n ] ) |
| break; |
| |
| return m_nSeqNo = n; |
| } |
| |
| void SwTxtFtn::SetUniqueSeqRefNo( SwDoc& rDoc ) |
| { |
| sal_uInt16 n, nStt = 0, nFtnCnt = rDoc.GetFtnIdxs().Count(); |
| |
| const sal_uInt8 nTmp = 255 < nFtnCnt ? 255 : static_cast<sal_uInt8>(nFtnCnt); |
| SvUShortsSort aArr( nTmp, nTmp ); |
| |
| // dann alle Nummern zusammensammeln die schon existieren |
| SwTxtFtn* pTxtFtn; |
| for( n = 0; n < nFtnCnt; ++n ) |
| { |
| pTxtFtn = rDoc.GetFtnIdxs()[ n ]; |
| if ( USHRT_MAX != pTxtFtn->m_nSeqNo ) |
| { |
| aArr.Insert( pTxtFtn->m_nSeqNo ); |
| } |
| } |
| |
| |
| for( n = 0; n < nFtnCnt; ++n ) |
| { |
| pTxtFtn = rDoc.GetFtnIdxs()[ n ]; |
| if ( USHRT_MAX == pTxtFtn->m_nSeqNo ) |
| { |
| for( ; nStt < aArr.Count(); ++nStt ) |
| { |
| if ( nStt != aArr[ nStt ] ) |
| { |
| pTxtFtn->m_nSeqNo = nStt; |
| break; |
| } |
| } |
| |
| if ( USHRT_MAX == pTxtFtn->m_nSeqNo ) |
| { |
| break; // found nothing |
| } |
| } |
| } |
| |
| // alle Nummern schon vergeben, also mit nStt++ weitermachen |
| for( ; n < nFtnCnt; ++n ) |
| { |
| pTxtFtn = rDoc.GetFtnIdxs()[ n ]; |
| if ( USHRT_MAX == pTxtFtn->m_nSeqNo ) |
| { |
| pTxtFtn->m_nSeqNo = nStt++; |
| } |
| } |
| } |
| |
| void SwTxtFtn::CheckCondColl() |
| { |
| //FEATURE::CONDCOLL |
| if( GetStartNode() ) |
| ((SwStartNode&)GetStartNode()->GetNode()).CheckSectionCondColl(); |
| //FEATURE::CONDCOLL |
| } |
| |
| |
| |
| |