xref: /AOO41X/main/sw/source/core/txtnode/atrftn.cxx (revision dec99bbd1eb6ae693d6ee672c1a69e3a32d917e7)
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 
SwFmtFtn(bool bEndNote)55 SwFmtFtn::SwFmtFtn( bool bEndNote )
56     : SfxPoolItem( RES_TXTATR_FTN ),
57     pTxtAttr( 0 ),
58     nNumber( 0 ),
59     m_bEndNote( bEndNote )
60 {
61 }
62 
63 
operator ==(const SfxPoolItem & rAttr) const64 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 
Clone(SfxItemPool *) const73 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 
SetEndNote(bool b)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 
~SwFmtFtn()94 SwFmtFtn::~SwFmtFtn()
95 {
96 }
97 
98 
GetFtnText(XubString & rStr) const99 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
GetViewNumStr(const SwDoc & rDoc,sal_Bool bInclStrings) const114 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 
SwTxtFtn(SwFmtFtn & rAttr,xub_StrLen nStartPos)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 
~SwTxtFtn()179 SwTxtFtn::~SwTxtFtn()
180 {
181     SetStartNode( 0 );
182 }
183 
184 
185 
SetStartNode(const SwNodeIndex * pNewNode,sal_Bool bDelNode)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 
SetNumber(const sal_uInt16 nNewNum,const XubString * pStr)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
CopyFtn(SwTxtFtn & rDest,SwTxtNode & rDestNode) const285 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
MakeNewTextSection(SwNodes & rNodes)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 
DelFrms(const SwFrm * pSib)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 
SetSeqRefNo()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 
SetUniqueSeqRefNo(SwDoc & rDoc)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 
CheckCondColl()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