xref: /trunk/main/sw/source/core/txtnode/atrftn.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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