xref: /AOO41X/main/sw/source/core/txtnode/atrftn.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
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(SwTxtFtn & rDest, SwTxtNode & rDestNode) const
286 {
287     if (m_pStartNode && !rDest.GetStartNode())
288     {
289         // dest missing node section? create it here!
290         // (happens in SwTxtNode::CopyText if pDest == this)
291         rDest.MakeNewTextSection( rDestNode.GetNodes() );
292     }
293     if (m_pStartNode && rDest.GetStartNode())
294     {
295         // footnotes not necessarily in same document!
296         SwDoc *const pDstDoc = rDestNode.GetDoc();
297         SwNodes &rDstNodes = pDstDoc->GetNodes();
298 
299         // copy only the content of the section
300         SwNodeRange aRg( *m_pStartNode, 1,
301                     *m_pStartNode->GetNode().EndOfSectionNode() );
302 
303         // insert at the end of rDest, i.e., the nodes are appended.
304         // nDestLen contains number of CntntNodes in rDest _before_ copy.
305         SwNodeIndex aStart( *(rDest.GetStartNode()) );
306         SwNodeIndex aEnd( *aStart.GetNode().EndOfSectionNode() );
307         sal_uLong  nDestLen = aEnd.GetIndex() - aStart.GetIndex() - 1;
308 
309         m_pTxtNode->GetDoc()->CopyWithFlyInFly( aRg, 0, aEnd, sal_True );
310 
311         // in case the destination section was not empty, delete the old nodes
312         // before:   Src: SxxxE,  Dst: SnE
313         // now:      Src: SxxxE,  Dst: SnxxxE
314         // after:    Src: SxxxE,  Dst: SxxxE
315         aStart++;
316         rDstNodes.Delete( aStart, nDestLen );
317     }
318 
319     // also copy user defined number string
320     if( GetFtn().aNumber.Len() )
321     {
322         const_cast<SwFmtFtn &>(rDest.GetFtn()).aNumber = GetFtn().aNumber;
323     }
324 }
325 
326 
327     // lege eine neue leere TextSection fuer diese Fussnote an
328 void SwTxtFtn::MakeNewTextSection( SwNodes& rNodes )
329 {
330     if ( m_pStartNode )
331         return;
332 
333     // Nun verpassen wir dem TxtNode noch die Fussnotenvorlage.
334     SwTxtFmtColl *pFmtColl;
335     const SwEndNoteInfo* pInfo;
336     sal_uInt16 nPoolId;
337 
338     if( GetFtn().IsEndNote() )
339     {
340         pInfo = &rNodes.GetDoc()->GetEndNoteInfo();
341         nPoolId = RES_POOLCOLL_ENDNOTE;
342     }
343     else
344     {
345         pInfo = &rNodes.GetDoc()->GetFtnInfo();
346         nPoolId = RES_POOLCOLL_FOOTNOTE;
347     }
348 
349     if( 0 == (pFmtColl = pInfo->GetFtnTxtColl() ) )
350         pFmtColl = rNodes.GetDoc()->GetTxtCollFromPool( nPoolId );
351 
352     SwStartNode* pSttNd = rNodes.MakeTextSection( SwNodeIndex( rNodes.GetEndOfInserts() ),
353                                         SwFootnoteStartNode, pFmtColl );
354     m_pStartNode = new SwNodeIndex( *pSttNd );
355 }
356 
357 
358 void SwTxtFtn::DelFrms( const SwFrm* pSib )
359 {
360     // delete the FtnFrames from the pages
361     ASSERT( m_pTxtNode, "SwTxtFtn: where is my TxtNode?" );
362     if ( !m_pTxtNode )
363         return;
364 
365     const SwRootFrm* pRoot = pSib ? pSib->getRootFrm() : 0;
366     sal_Bool bFrmFnd = sal_False;
367     {
368         SwIterator<SwCntntFrm,SwTxtNode> aIter( *m_pTxtNode );
369         for( SwCntntFrm* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
370         {
371             if( pRoot != pFnd->getRootFrm() && pRoot )
372                 continue;
373             SwPageFrm* pPage = pFnd->FindPageFrm();
374             if( pPage )
375             {
376                 pPage->RemoveFtn( pFnd, this );
377                 bFrmFnd = sal_True;
378             }
379         }
380     }
381     //JP 13.05.97: falls das Layout vorm loeschen der Fussnoten entfernt
382     //              wird, sollte man das ueber die Fussnote selbst tun
383     if ( !bFrmFnd && m_pStartNode )
384     {
385         SwNodeIndex aIdx( *m_pStartNode );
386         SwCntntNode* pCNd = m_pTxtNode->GetNodes().GoNext( &aIdx );
387         if( pCNd )
388         {
389             SwIterator<SwCntntFrm,SwCntntNode> aIter( *pCNd );
390             for( SwCntntFrm* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
391             {
392                 if( pRoot != pFnd->getRootFrm() && pRoot )
393                     continue;
394                 SwPageFrm* pPage = pFnd->FindPageFrm();
395 
396                 SwFrm *pFrm = pFnd->GetUpper();
397                 while ( pFrm && !pFrm->IsFtnFrm() )
398                     pFrm = pFrm->GetUpper();
399 
400                 SwFtnFrm *pFtn = (SwFtnFrm*)pFrm;
401                 while ( pFtn && pFtn->GetMaster() )
402                     pFtn = pFtn->GetMaster();
403                 ASSERT( pFtn->GetAttr() == this, "Ftn mismatch error." );
404 
405                 while ( pFtn )
406                 {
407                     SwFtnFrm *pFoll = pFtn->GetFollow();
408                     pFtn->Cut();
409                     delete pFtn;
410                     pFtn = pFoll;
411                 }
412 
413                 // #i20556# During hiding of a section, the connection
414                 // to the layout is already lost. pPage may be 0:
415                 if ( pPage )
416                     pPage->UpdateFtnNum();
417             }
418         }
419     }
420 }
421 
422 
423 sal_uInt16 SwTxtFtn::SetSeqRefNo()
424 {
425     if( !m_pTxtNode )
426         return USHRT_MAX;
427 
428     SwDoc* pDoc = m_pTxtNode->GetDoc();
429     if( pDoc->IsInReading() )
430         return USHRT_MAX;
431 
432     sal_uInt16 n, nFtnCnt = pDoc->GetFtnIdxs().Count();
433 
434     const sal_uInt8 nTmp = 255 < nFtnCnt ? 255 : static_cast<sal_uInt8>(nFtnCnt);
435     SvUShortsSort aArr( nTmp, nTmp );
436 
437     // dann testmal, ob die Nummer schon vergeben ist oder ob eine neue
438     // bestimmt werden muss.
439     SwTxtFtn* pTxtFtn;
440     for( n = 0; n < nFtnCnt; ++n )
441     {
442         pTxtFtn = pDoc->GetFtnIdxs()[ n ];
443         if ( pTxtFtn != this )
444         {
445             aArr.Insert( pTxtFtn->m_nSeqNo );
446         }
447     }
448 
449     // test if number is already in use
450     if ( USHRT_MAX != m_nSeqNo )
451     {
452         for( n = 0; n < aArr.Count(); ++n )
453         {
454             if ( aArr[ n ] > m_nSeqNo )
455             {
456                 return m_nSeqNo;    // free -> use
457             }
458             else if ( aArr[ n ] == m_nSeqNo )
459             {
460                 break;              // used -> create new one
461             }
462         }
463 
464         if ( n == aArr.Count() )
465         {
466             return m_nSeqNo;        // free -> use
467         }
468     }
469 
470     // alle Nummern entsprechend geflag, also bestimme die richtige Nummer
471     for( n = 0; n < aArr.Count(); ++n )
472         if( n != aArr[ n ] )
473             break;
474 
475     return m_nSeqNo = n;
476 }
477 
478 void SwTxtFtn::SetUniqueSeqRefNo( SwDoc& rDoc )
479 {
480     sal_uInt16 n, nStt = 0, nFtnCnt = rDoc.GetFtnIdxs().Count();
481 
482     const sal_uInt8 nTmp = 255 < nFtnCnt ? 255 : static_cast<sal_uInt8>(nFtnCnt);
483     SvUShortsSort aArr( nTmp, nTmp );
484 
485     // dann alle Nummern zusammensammeln die schon existieren
486     SwTxtFtn* pTxtFtn;
487     for( n = 0; n < nFtnCnt; ++n )
488     {
489         pTxtFtn = rDoc.GetFtnIdxs()[ n ];
490         if ( USHRT_MAX != pTxtFtn->m_nSeqNo )
491         {
492             aArr.Insert( pTxtFtn->m_nSeqNo );
493         }
494     }
495 
496 
497     for( n = 0; n < nFtnCnt; ++n )
498     {
499         pTxtFtn = rDoc.GetFtnIdxs()[ n ];
500         if ( USHRT_MAX == pTxtFtn->m_nSeqNo )
501         {
502             for( ; nStt < aArr.Count(); ++nStt )
503             {
504                 if ( nStt != aArr[ nStt ] )
505                 {
506                     pTxtFtn->m_nSeqNo = nStt;
507                     break;
508                 }
509             }
510 
511             if ( USHRT_MAX == pTxtFtn->m_nSeqNo )
512             {
513                 break; // found nothing
514             }
515         }
516     }
517 
518     // alle Nummern schon vergeben, also mit nStt++ weitermachen
519     for( ; n < nFtnCnt; ++n )
520     {
521         pTxtFtn = rDoc.GetFtnIdxs()[ n ];
522         if ( USHRT_MAX == pTxtFtn->m_nSeqNo )
523         {
524             pTxtFtn->m_nSeqNo = nStt++;
525         }
526     }
527 }
528 
529 void SwTxtFtn::CheckCondColl()
530 {
531 //FEATURE::CONDCOLL
532     if( GetStartNode() )
533         ((SwStartNode&)GetStartNode()->GetNode()).CheckSectionCondColl();
534 //FEATURE::CONDCOLL
535 }
536 
537 
538 
539 
540