1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: atrftn.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
36 #define _SVSTDARR_USHORTS
37 #define _SVSTDARR_USHORTSSORT
38 #include <svtools/svstdarr.hxx>
40 #include <cntfrm.hxx> // ASSERT in ~SwTxtFtn()
41 #include <pagefrm.hxx> // RemoveFtn()
45 #include <ftninfo.hxx>
48 #include <poolfmt.hxx>
50 #include <ndindex.hxx>
51 #include <fmtftntx.hxx>
52 #include <section.hxx>
54 /*************************************************************************
59 |* Ersterstellung JP 09.08.94
60 |* Letzte Aenderung JP 08.08.94
62 *************************************************************************/
65 SwFmtFtn::SwFmtFtn( bool bEndNote
)
66 : SfxPoolItem( RES_TXTATR_FTN
),
69 m_bEndNote( bEndNote
)
74 int SwFmtFtn::operator==( const SfxPoolItem
& rAttr
) const
76 ASSERT( SfxPoolItem::operator==( rAttr
), "keine gleichen Attribute" );
77 return nNumber
== ((SwFmtFtn
&)rAttr
).nNumber
&&
78 aNumber
== ((SwFmtFtn
&)rAttr
).aNumber
&&
79 m_bEndNote
== ((SwFmtFtn
&)rAttr
).m_bEndNote
;
83 SfxPoolItem
* SwFmtFtn::Clone( SfxItemPool
* ) const
85 SwFmtFtn
* pNew
= new SwFmtFtn
;
86 pNew
->aNumber
= aNumber
;
87 pNew
->nNumber
= nNumber
;
88 pNew
->m_bEndNote
= m_bEndNote
;
92 void SwFmtFtn::SetEndNote( bool b
)
94 if ( b
!= m_bEndNote
)
98 GetTxtFtn()->DelFrms();
104 SwFmtFtn::~SwFmtFtn()
109 void SwFmtFtn::GetFtnText( XubString
& rStr
) const
111 if( pTxtAttr
->GetStartNode() )
113 SwNodeIndex
aIdx( *pTxtAttr
->GetStartNode(), 1 );
114 SwCntntNode
* pCNd
= aIdx
.GetNode().GetTxtNode();
116 pCNd
= aIdx
.GetNodes().GoNext( &aIdx
);
118 if( pCNd
->IsTxtNode() )
119 rStr
= ((SwTxtNode
*)pCNd
)->GetExpandTxt();
123 // returnt den anzuzeigenden String der Fuss-/Endnote
124 XubString
SwFmtFtn::GetViewNumStr( const SwDoc
& rDoc
, BOOL bInclStrings
) const
126 XubString
sRet( GetNumStr() );
129 // dann ist die Nummer von Interesse, also ueber die Info diese
131 BOOL bMakeNum
= TRUE
;
132 const SwSectionNode
* pSectNd
= pTxtAttr
133 ? SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtAttr
)
138 const SwFmtFtnEndAtTxtEnd
& rFtnEnd
= (SwFmtFtnEndAtTxtEnd
&)
139 pSectNd
->GetSection().GetFmt()->GetFmtAttr(
141 static_cast<USHORT
>(RES_END_AT_TXTEND
) :
142 static_cast<USHORT
>(RES_FTN_AT_TXTEND
) );
144 if( FTNEND_ATTXTEND_OWNNUMANDFMT
== rFtnEnd
.GetValue() )
147 sRet
= rFtnEnd
.GetSwNumType().GetNumStr( GetNumber() );
150 sRet
.Insert( rFtnEnd
.GetPrefix(), 0 );
151 sRet
+= rFtnEnd
.GetSuffix();
158 const SwEndNoteInfo
* pInfo
;
160 pInfo
= &rDoc
.GetEndNoteInfo();
162 pInfo
= &rDoc
.GetFtnInfo();
163 sRet
= pInfo
->aFmt
.GetNumStr( GetNumber() );
166 sRet
.Insert( pInfo
->GetPrefix(), 0 );
167 sRet
+= pInfo
->GetSuffix();
174 /*************************************************************************
176 *************************************************************************/
178 SwTxtFtn::SwTxtFtn( SwFmtFtn
& rAttr
, xub_StrLen nStartPos
)
179 : SwTxtAttr( rAttr
, nStartPos
)
182 , m_nSeqNo( USHRT_MAX
)
184 rAttr
.pTxtAttr
= this;
188 SwTxtFtn::~SwTxtFtn()
195 void SwTxtFtn::SetStartNode( const SwNodeIndex
*pNewNode
, BOOL bDelNode
)
201 m_pStartNode
= new SwNodeIndex( *pNewNode
);
205 *m_pStartNode
= *pNewNode
;
208 else if ( m_pStartNode
)
210 // Zwei Dinge muessen erledigt werden:
211 // 1) Die Fussnoten muessen bei ihren Seiten abgemeldet werden
212 // 2) Die Fussnoten-Sektion in den Inserts muss geloescht werden.
216 pDoc
= m_pTxtNode
->GetDoc();
220 //JP 27.01.97: der sw3-Reader setzt einen StartNode aber das
221 // Attribut ist noch nicht im TextNode verankert.
222 // Wird es geloescht (z.B. bei Datei einfuegen mit
223 // Ftn in einen Rahmen), muss auch der Inhalt
225 pDoc
= m_pStartNode
->GetNodes().GetDoc();
228 // Wir duerfen die Fussnotennodes nicht loeschen
229 // und brauchen die Fussnotenframes nicht loeschen, wenn
230 // wir im ~SwDoc() stehen.
231 if( !pDoc
->IsInDtor() )
235 // 1) Die Section fuer die Fussnote wird beseitigt
236 // Es kann sein, dass die Inserts schon geloescht wurden.
237 pDoc
->DeleteSection( &m_pStartNode
->GetNode() );
240 // Werden die Nodes nicht geloescht mussen sie bei den Seiten
241 // abmeldet (Frms loeschen) werden, denn sonst bleiben sie
242 // stehen (Undo loescht sie nicht!)
245 DELETEZ( m_pStartNode
);
247 // loesche die Fussnote noch aus dem Array am Dokument
248 for( USHORT n
= 0; n
< pDoc
->GetFtnIdxs().Count(); ++n
)
249 if( this == pDoc
->GetFtnIdxs()[n
] )
251 pDoc
->GetFtnIdxs().Remove( n
);
252 // gibt noch weitere Fussnoten
253 if( !pDoc
->IsInDtor() && n
< pDoc
->GetFtnIdxs().Count() )
255 SwNodeIndex
aTmp( pDoc
->GetFtnIdxs()[n
]->GetTxtNode() );
256 pDoc
->GetFtnIdxs().UpdateFtn( aTmp
);
264 void SwTxtFtn::SetNumber( const USHORT nNewNum
, const XubString
* pStr
)
266 SwFmtFtn
& rFtn
= (SwFmtFtn
&)GetFtn();
267 if( pStr
&& pStr
->Len() )
268 rFtn
.aNumber
= *pStr
;
271 rFtn
.nNumber
= nNewNum
;
272 rFtn
.aNumber
= aEmptyStr
;
275 ASSERT( m_pTxtNode
, "SwTxtFtn: where is my TxtNode?" );
276 SwNodes
&rNodes
= m_pTxtNode
->GetDoc()->GetNodes();
277 m_pTxtNode
->Modify( 0, &rFtn
);
280 // must iterate over all TxtNodes because of footnotes on other pages
282 ULONG nSttIdx
= m_pStartNode
->GetIndex() + 1;
283 ULONG nEndIdx
= m_pStartNode
->GetNode().EndOfSectionIndex();
284 for( ; nSttIdx
< nEndIdx
; ++nSttIdx
)
286 // Es koennen ja auch Grafiken in der Fussnote stehen ...
287 if( ( pNd
= rNodes
[ nSttIdx
] )->IsTxtNode() )
288 ((SwTxtNode
*)pNd
)->Modify( 0, &rFtn
);
293 // Die Fussnoten duplizieren
294 void SwTxtFtn::CopyFtn( SwTxtFtn
*pDest
)
296 if ( m_pStartNode
&& pDest
->GetStartNode() )
298 // die Fussnoten koennen in unterschiedlichen Dokumenten stehen !!
299 SwDoc
* pDstDoc
= pDest
->m_pTxtNode
->GetDoc();
300 SwNodes
&rDstNodes
= pDstDoc
->GetNodes();
302 // Wir kopieren nur den Inhalt der Sektion
303 SwNodeRange
aRg( *m_pStartNode
, 1,
304 *m_pStartNode
->GetNode().EndOfSectionNode() );
306 // Wir fuegen auf dem Ende von pDest ein, d.h. die Nodes
307 // werden angehaengt. nDestLen haelt die Anzahl der CntNodes
308 // in pDest _vor_ dem Kopieren.
309 SwNodeIndex
aStart( *(pDest
->GetStartNode()) );
310 SwNodeIndex
aEnd( *aStart
.GetNode().EndOfSectionNode() );
311 ULONG nDestLen
= aEnd
.GetIndex() - aStart
.GetIndex() - 1;
313 m_pTxtNode
->GetDoc()->CopyWithFlyInFly( aRg
, 0, aEnd
, TRUE
);
315 // Wenn die Dest-Sektion nicht leer war, so muessen die alten
316 // Nodes geloescht werden:
317 // Vorher: Src: SxxxE, Dst: SnE
318 // Nachher: Src: SxxxE, Dst: SnxxxE
319 // und Src: SxxxE, Dst: SxxxE
321 rDstNodes
.Delete( aStart
, nDestLen
);
324 // Der benutzerdefinierte String muss auch uebertragen werden.
325 if( GetFtn().aNumber
.Len() )
326 ((SwFmtFtn
&)pDest
->GetFtn()).aNumber
= GetFtn().aNumber
;
330 // lege eine neue leere TextSection fuer diese Fussnote an
331 void SwTxtFtn::MakeNewTextSection( SwNodes
& rNodes
)
336 // Nun verpassen wir dem TxtNode noch die Fussnotenvorlage.
337 SwTxtFmtColl
*pFmtColl
;
338 const SwEndNoteInfo
* pInfo
;
341 if( GetFtn().IsEndNote() )
343 pInfo
= &rNodes
.GetDoc()->GetEndNoteInfo();
344 nPoolId
= RES_POOLCOLL_ENDNOTE
;
348 pInfo
= &rNodes
.GetDoc()->GetFtnInfo();
349 nPoolId
= RES_POOLCOLL_FOOTNOTE
;
352 if( 0 == (pFmtColl
= pInfo
->GetFtnTxtColl() ) )
353 pFmtColl
= rNodes
.GetDoc()->GetTxtCollFromPool( nPoolId
);
355 SwStartNode
* pSttNd
= rNodes
.MakeTextSection( SwNodeIndex( rNodes
.GetEndOfInserts() ),
356 SwFootnoteStartNode
, pFmtColl
);
357 m_pStartNode
= new SwNodeIndex( *pSttNd
);
361 void SwTxtFtn::DelFrms()
363 // delete the FtnFrames from the pages
364 ASSERT( m_pTxtNode
, "SwTxtFtn: where is my TxtNode?" );
368 BOOL bFrmFnd
= FALSE
;
370 SwClientIter
aIter( *m_pTxtNode
);
371 for( SwCntntFrm
* pFnd
= (SwCntntFrm
*)aIter
.First( TYPE( SwCntntFrm
));
372 pFnd
; pFnd
= (SwCntntFrm
*)aIter
.Next() )
374 SwPageFrm
* pPage
= pFnd
->FindPageFrm();
377 pPage
->RemoveFtn( pFnd
, this );
382 //JP 13.05.97: falls das Layout vorm loeschen der Fussnoten entfernt
383 // wird, sollte man das ueber die Fussnote selbst tun
384 if ( !bFrmFnd
&& m_pStartNode
)
386 SwNodeIndex
aIdx( *m_pStartNode
);
387 SwCntntNode
* pCNd
= m_pTxtNode
->GetNodes().GoNext( &aIdx
);
390 SwClientIter
aIter( *pCNd
);
391 for( SwCntntFrm
* pFnd
= (SwCntntFrm
*)aIter
.First( TYPE( SwCntntFrm
));
392 pFnd
; pFnd
= (SwCntntFrm
*)aIter
.Next() )
394 SwPageFrm
* pPage
= pFnd
->FindPageFrm();
396 SwFrm
*pFrm
= pFnd
->GetUpper();
397 while ( pFrm
&& !pFrm
->IsFtnFrm() )
398 pFrm
= pFrm
->GetUpper();
400 SwFtnFrm
*pFtn
= (SwFtnFrm
*)pFrm
;
401 while ( pFtn
&& pFtn
->GetMaster() )
402 pFtn
= pFtn
->GetMaster();
403 ASSERT( pFtn
->GetAttr() == this, "Ftn mismatch error." );
407 SwFtnFrm
*pFoll
= pFtn
->GetFollow();
413 // #i20556# During hiding of a section, the connection
414 // to the layout is already lost. pPage may be 0:
416 pPage
->UpdateFtnNum();
423 USHORT
SwTxtFtn::SetSeqRefNo()
428 SwDoc
* pDoc
= m_pTxtNode
->GetDoc();
429 if( pDoc
->IsInReading() )
432 USHORT n
, nFtnCnt
= pDoc
->GetFtnIdxs().Count();
434 const BYTE nTmp
= 255 < nFtnCnt
? 255 : static_cast<BYTE
>(nFtnCnt
);
435 SvUShortsSort
aArr( nTmp
, nTmp
);
437 // dann testmal, ob die Nummer schon vergeben ist oder ob eine neue
438 // bestimmt werden muss.
440 for( n
= 0; n
< nFtnCnt
; ++n
)
442 pTxtFtn
= pDoc
->GetFtnIdxs()[ n
];
443 if ( pTxtFtn
!= this )
445 aArr
.Insert( pTxtFtn
->m_nSeqNo
);
449 // test if number is already in use
450 if ( USHRT_MAX
!= m_nSeqNo
)
452 for( n
= 0; n
< aArr
.Count(); ++n
)
454 if ( aArr
[ n
] > m_nSeqNo
)
456 return m_nSeqNo
; // free -> use
458 else if ( aArr
[ n
] == m_nSeqNo
)
460 break; // used -> create new one
464 if ( n
== aArr
.Count() )
466 return m_nSeqNo
; // free -> use
470 // alle Nummern entsprechend geflag, also bestimme die richtige Nummer
471 for( n
= 0; n
< aArr
.Count(); ++n
)
478 void SwTxtFtn::SetUniqueSeqRefNo( SwDoc
& rDoc
)
480 USHORT n
, nStt
= 0, nFtnCnt
= rDoc
.GetFtnIdxs().Count();
482 const BYTE nTmp
= 255 < nFtnCnt
? 255 : static_cast<BYTE
>(nFtnCnt
);
483 SvUShortsSort
aArr( nTmp
, nTmp
);
485 // dann alle Nummern zusammensammeln die schon existieren
487 for( n
= 0; n
< nFtnCnt
; ++n
)
489 pTxtFtn
= rDoc
.GetFtnIdxs()[ n
];
490 if ( USHRT_MAX
!= pTxtFtn
->m_nSeqNo
)
492 aArr
.Insert( pTxtFtn
->m_nSeqNo
);
497 for( n
= 0; n
< nFtnCnt
; ++n
)
499 pTxtFtn
= rDoc
.GetFtnIdxs()[ n
];
500 if ( USHRT_MAX
== pTxtFtn
->m_nSeqNo
)
502 for( ; nStt
< aArr
.Count(); ++nStt
)
504 if ( nStt
!= aArr
[ nStt
] )
506 pTxtFtn
->m_nSeqNo
= nStt
;
511 if ( USHRT_MAX
== pTxtFtn
->m_nSeqNo
)
513 break; // found nothing
518 // alle Nummern schon vergeben, also mit nStt++ weitermachen
519 for( ; n
< nFtnCnt
; ++n
)
521 pTxtFtn
= rDoc
.GetFtnIdxs()[ n
];
522 if ( USHRT_MAX
== pTxtFtn
->m_nSeqNo
)
524 pTxtFtn
->m_nSeqNo
= nStt
++;
529 void SwTxtFtn::CheckCondColl()
533 ((SwStartNode
&)GetStartNode()->GetNode()).CheckSectionCondColl();