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;
185 SetHasDummyChar(true);
189 SwTxtFtn::~SwTxtFtn()
196 void SwTxtFtn::SetStartNode( const SwNodeIndex
*pNewNode
, BOOL bDelNode
)
202 m_pStartNode
= new SwNodeIndex( *pNewNode
);
206 *m_pStartNode
= *pNewNode
;
209 else if ( m_pStartNode
)
211 // Zwei Dinge muessen erledigt werden:
212 // 1) Die Fussnoten muessen bei ihren Seiten abgemeldet werden
213 // 2) Die Fussnoten-Sektion in den Inserts muss geloescht werden.
217 pDoc
= m_pTxtNode
->GetDoc();
221 //JP 27.01.97: der sw3-Reader setzt einen StartNode aber das
222 // Attribut ist noch nicht im TextNode verankert.
223 // Wird es geloescht (z.B. bei Datei einfuegen mit
224 // Ftn in einen Rahmen), muss auch der Inhalt
226 pDoc
= m_pStartNode
->GetNodes().GetDoc();
229 // Wir duerfen die Fussnotennodes nicht loeschen
230 // und brauchen die Fussnotenframes nicht loeschen, wenn
231 // wir im ~SwDoc() stehen.
232 if( !pDoc
->IsInDtor() )
236 // 1) Die Section fuer die Fussnote wird beseitigt
237 // Es kann sein, dass die Inserts schon geloescht wurden.
238 pDoc
->DeleteSection( &m_pStartNode
->GetNode() );
241 // Werden die Nodes nicht geloescht mussen sie bei den Seiten
242 // abmeldet (Frms loeschen) werden, denn sonst bleiben sie
243 // stehen (Undo loescht sie nicht!)
246 DELETEZ( m_pStartNode
);
248 // loesche die Fussnote noch aus dem Array am Dokument
249 for( USHORT n
= 0; n
< pDoc
->GetFtnIdxs().Count(); ++n
)
250 if( this == pDoc
->GetFtnIdxs()[n
] )
252 pDoc
->GetFtnIdxs().Remove( n
);
253 // gibt noch weitere Fussnoten
254 if( !pDoc
->IsInDtor() && n
< pDoc
->GetFtnIdxs().Count() )
256 SwNodeIndex
aTmp( pDoc
->GetFtnIdxs()[n
]->GetTxtNode() );
257 pDoc
->GetFtnIdxs().UpdateFtn( aTmp
);
265 void SwTxtFtn::SetNumber( const USHORT nNewNum
, const XubString
* pStr
)
267 SwFmtFtn
& rFtn
= (SwFmtFtn
&)GetFtn();
268 if( pStr
&& pStr
->Len() )
269 rFtn
.aNumber
= *pStr
;
272 rFtn
.nNumber
= nNewNum
;
273 rFtn
.aNumber
= aEmptyStr
;
276 ASSERT( m_pTxtNode
, "SwTxtFtn: where is my TxtNode?" );
277 SwNodes
&rNodes
= m_pTxtNode
->GetDoc()->GetNodes();
278 m_pTxtNode
->Modify( 0, &rFtn
);
281 // must iterate over all TxtNodes because of footnotes on other pages
283 ULONG nSttIdx
= m_pStartNode
->GetIndex() + 1;
284 ULONG nEndIdx
= m_pStartNode
->GetNode().EndOfSectionIndex();
285 for( ; nSttIdx
< nEndIdx
; ++nSttIdx
)
287 // Es koennen ja auch Grafiken in der Fussnote stehen ...
288 if( ( pNd
= rNodes
[ nSttIdx
] )->IsTxtNode() )
289 ((SwTxtNode
*)pNd
)->Modify( 0, &rFtn
);
294 // Die Fussnoten duplizieren
295 void SwTxtFtn::CopyFtn( SwTxtFtn
*pDest
) const
297 if ( m_pStartNode
&& pDest
->GetStartNode() )
299 // die Fussnoten koennen in unterschiedlichen Dokumenten stehen !!
300 SwDoc
* pDstDoc
= pDest
->m_pTxtNode
->GetDoc();
301 SwNodes
&rDstNodes
= pDstDoc
->GetNodes();
303 // Wir kopieren nur den Inhalt der Sektion
304 SwNodeRange
aRg( *m_pStartNode
, 1,
305 *m_pStartNode
->GetNode().EndOfSectionNode() );
307 // Wir fuegen auf dem Ende von pDest ein, d.h. die Nodes
308 // werden angehaengt. nDestLen haelt die Anzahl der CntNodes
309 // in pDest _vor_ dem Kopieren.
310 SwNodeIndex
aStart( *(pDest
->GetStartNode()) );
311 SwNodeIndex
aEnd( *aStart
.GetNode().EndOfSectionNode() );
312 ULONG nDestLen
= aEnd
.GetIndex() - aStart
.GetIndex() - 1;
314 m_pTxtNode
->GetDoc()->CopyWithFlyInFly( aRg
, 0, aEnd
, TRUE
);
316 // Wenn die Dest-Sektion nicht leer war, so muessen die alten
317 // Nodes geloescht werden:
318 // Vorher: Src: SxxxE, Dst: SnE
319 // Nachher: Src: SxxxE, Dst: SnxxxE
320 // und Src: SxxxE, Dst: SxxxE
322 rDstNodes
.Delete( aStart
, nDestLen
);
325 // Der benutzerdefinierte String muss auch uebertragen werden.
326 if( GetFtn().aNumber
.Len() )
327 ((SwFmtFtn
&)pDest
->GetFtn()).aNumber
= GetFtn().aNumber
;
331 // lege eine neue leere TextSection fuer diese Fussnote an
332 void SwTxtFtn::MakeNewTextSection( SwNodes
& rNodes
)
337 // Nun verpassen wir dem TxtNode noch die Fussnotenvorlage.
338 SwTxtFmtColl
*pFmtColl
;
339 const SwEndNoteInfo
* pInfo
;
342 if( GetFtn().IsEndNote() )
344 pInfo
= &rNodes
.GetDoc()->GetEndNoteInfo();
345 nPoolId
= RES_POOLCOLL_ENDNOTE
;
349 pInfo
= &rNodes
.GetDoc()->GetFtnInfo();
350 nPoolId
= RES_POOLCOLL_FOOTNOTE
;
353 if( 0 == (pFmtColl
= pInfo
->GetFtnTxtColl() ) )
354 pFmtColl
= rNodes
.GetDoc()->GetTxtCollFromPool( nPoolId
);
356 SwStartNode
* pSttNd
= rNodes
.MakeTextSection( SwNodeIndex( rNodes
.GetEndOfInserts() ),
357 SwFootnoteStartNode
, pFmtColl
);
358 m_pStartNode
= new SwNodeIndex( *pSttNd
);
362 void SwTxtFtn::DelFrms()
364 // delete the FtnFrames from the pages
365 ASSERT( m_pTxtNode
, "SwTxtFtn: where is my TxtNode?" );
369 BOOL bFrmFnd
= FALSE
;
371 SwClientIter
aIter( *m_pTxtNode
);
372 for( SwCntntFrm
* pFnd
= (SwCntntFrm
*)aIter
.First( TYPE( SwCntntFrm
));
373 pFnd
; pFnd
= (SwCntntFrm
*)aIter
.Next() )
375 SwPageFrm
* pPage
= pFnd
->FindPageFrm();
378 pPage
->RemoveFtn( pFnd
, this );
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
)
387 SwNodeIndex
aIdx( *m_pStartNode
);
388 SwCntntNode
* pCNd
= m_pTxtNode
->GetNodes().GoNext( &aIdx
);
391 SwClientIter
aIter( *pCNd
);
392 for( SwCntntFrm
* pFnd
= (SwCntntFrm
*)aIter
.First( TYPE( SwCntntFrm
));
393 pFnd
; pFnd
= (SwCntntFrm
*)aIter
.Next() )
395 SwPageFrm
* pPage
= pFnd
->FindPageFrm();
397 SwFrm
*pFrm
= pFnd
->GetUpper();
398 while ( pFrm
&& !pFrm
->IsFtnFrm() )
399 pFrm
= pFrm
->GetUpper();
401 SwFtnFrm
*pFtn
= (SwFtnFrm
*)pFrm
;
402 while ( pFtn
&& pFtn
->GetMaster() )
403 pFtn
= pFtn
->GetMaster();
404 ASSERT( pFtn
->GetAttr() == this, "Ftn mismatch error." );
408 SwFtnFrm
*pFoll
= pFtn
->GetFollow();
414 // #i20556# During hiding of a section, the connection
415 // to the layout is already lost. pPage may be 0:
417 pPage
->UpdateFtnNum();
424 USHORT
SwTxtFtn::SetSeqRefNo()
429 SwDoc
* pDoc
= m_pTxtNode
->GetDoc();
430 if( pDoc
->IsInReading() )
433 USHORT n
, nFtnCnt
= pDoc
->GetFtnIdxs().Count();
435 const BYTE nTmp
= 255 < nFtnCnt
? 255 : static_cast<BYTE
>(nFtnCnt
);
436 SvUShortsSort
aArr( nTmp
, nTmp
);
438 // dann testmal, ob die Nummer schon vergeben ist oder ob eine neue
439 // bestimmt werden muss.
441 for( n
= 0; n
< nFtnCnt
; ++n
)
443 pTxtFtn
= pDoc
->GetFtnIdxs()[ n
];
444 if ( pTxtFtn
!= this )
446 aArr
.Insert( pTxtFtn
->m_nSeqNo
);
450 // test if number is already in use
451 if ( USHRT_MAX
!= m_nSeqNo
)
453 for( n
= 0; n
< aArr
.Count(); ++n
)
455 if ( aArr
[ n
] > m_nSeqNo
)
457 return m_nSeqNo
; // free -> use
459 else if ( aArr
[ n
] == m_nSeqNo
)
461 break; // used -> create new one
465 if ( n
== aArr
.Count() )
467 return m_nSeqNo
; // free -> use
471 // alle Nummern entsprechend geflag, also bestimme die richtige Nummer
472 for( n
= 0; n
< aArr
.Count(); ++n
)
479 void SwTxtFtn::SetUniqueSeqRefNo( SwDoc
& rDoc
)
481 USHORT n
, nStt
= 0, nFtnCnt
= rDoc
.GetFtnIdxs().Count();
483 const BYTE nTmp
= 255 < nFtnCnt
? 255 : static_cast<BYTE
>(nFtnCnt
);
484 SvUShortsSort
aArr( nTmp
, nTmp
);
486 // dann alle Nummern zusammensammeln die schon existieren
488 for( n
= 0; n
< nFtnCnt
; ++n
)
490 pTxtFtn
= rDoc
.GetFtnIdxs()[ n
];
491 if ( USHRT_MAX
!= pTxtFtn
->m_nSeqNo
)
493 aArr
.Insert( pTxtFtn
->m_nSeqNo
);
498 for( n
= 0; n
< nFtnCnt
; ++n
)
500 pTxtFtn
= rDoc
.GetFtnIdxs()[ n
];
501 if ( USHRT_MAX
== pTxtFtn
->m_nSeqNo
)
503 for( ; nStt
< aArr
.Count(); ++nStt
)
505 if ( nStt
!= aArr
[ nStt
] )
507 pTxtFtn
->m_nSeqNo
= nStt
;
512 if ( USHRT_MAX
== pTxtFtn
->m_nSeqNo
)
514 break; // found nothing
519 // alle Nummern schon vergeben, also mit nStt++ weitermachen
520 for( ; n
< nFtnCnt
; ++n
)
522 pTxtFtn
= rDoc
.GetFtnIdxs()[ n
];
523 if ( USHRT_MAX
== pTxtFtn
->m_nSeqNo
)
525 pTxtFtn
->m_nSeqNo
= nStt
++;
530 void SwTxtFtn::CheckCondColl()
534 ((SwStartNode
&)GetStartNode()->GetNode()).CheckSectionCondColl();