merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / txtnode / atrftn.cxx
blob73640e2ba6c127e4c726640332717e8813f3c1ce
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: atrftn.cxx,v $
10 * $Revision: 1.9 $
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>
39 #include <doc.hxx>
40 #include <cntfrm.hxx> // ASSERT in ~SwTxtFtn()
41 #include <pagefrm.hxx> // RemoveFtn()
42 #include <fmtftn.hxx>
43 #include <txtftn.hxx>
44 #include <ftnidx.hxx>
45 #include <ftninfo.hxx>
46 #include <swfont.hxx>
47 #include <ndtxt.hxx>
48 #include <poolfmt.hxx>
49 #include <ftnfrm.hxx>
50 #include <ndindex.hxx>
51 #include <fmtftntx.hxx>
52 #include <section.hxx>
54 /*************************************************************************
56 |* class SwFmtFtn
58 |* Beschreibung
59 |* Ersterstellung JP 09.08.94
60 |* Letzte Aenderung JP 08.08.94
62 *************************************************************************/
65 SwFmtFtn::SwFmtFtn( bool bEndNote )
66 : SfxPoolItem( RES_TXTATR_FTN ),
67 pTxtAttr( 0 ),
68 nNumber( 0 ),
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;
89 return pNew;
92 void SwFmtFtn::SetEndNote( bool b )
94 if ( b != m_bEndNote )
96 if ( GetTxtFtn() )
98 GetTxtFtn()->DelFrms();
100 m_bEndNote = b;
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();
115 if( !pCNd )
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() );
127 if( !sRet.Len() )
129 // dann ist die Nummer von Interesse, also ueber die Info diese
130 // besorgen.
131 BOOL bMakeNum = TRUE;
132 const SwSectionNode* pSectNd = pTxtAttr
133 ? SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtAttr )
134 : 0;
136 if( pSectNd )
138 const SwFmtFtnEndAtTxtEnd& rFtnEnd = (SwFmtFtnEndAtTxtEnd&)
139 pSectNd->GetSection().GetFmt()->GetFmtAttr(
140 IsEndNote() ?
141 static_cast<USHORT>(RES_END_AT_TXTEND) :
142 static_cast<USHORT>(RES_FTN_AT_TXTEND) );
144 if( FTNEND_ATTXTEND_OWNNUMANDFMT == rFtnEnd.GetValue() )
146 bMakeNum = FALSE;
147 sRet = rFtnEnd.GetSwNumType().GetNumStr( GetNumber() );
148 if( bInclStrings )
150 sRet.Insert( rFtnEnd.GetPrefix(), 0 );
151 sRet += rFtnEnd.GetSuffix();
156 if( bMakeNum )
158 const SwEndNoteInfo* pInfo;
159 if( IsEndNote() )
160 pInfo = &rDoc.GetEndNoteInfo();
161 else
162 pInfo = &rDoc.GetFtnInfo();
163 sRet = pInfo->aFmt.GetNumStr( GetNumber() );
164 if( bInclStrings )
166 sRet.Insert( pInfo->GetPrefix(), 0 );
167 sRet += pInfo->GetSuffix();
171 return sRet;
174 /*************************************************************************
175 * class SwTxt/FmtFnt
176 *************************************************************************/
178 SwTxtFtn::SwTxtFtn( SwFmtFtn& rAttr, xub_StrLen nStartPos )
179 : SwTxtAttr( rAttr, nStartPos )
180 , m_pStartNode( 0 )
181 , m_pTxtNode( 0 )
182 , m_nSeqNo( USHRT_MAX )
184 rAttr.pTxtAttr = this;
185 SetHasDummyChar(true);
189 SwTxtFtn::~SwTxtFtn()
191 SetStartNode( 0 );
196 void SwTxtFtn::SetStartNode( const SwNodeIndex *pNewNode, BOOL bDelNode )
198 if( pNewNode )
200 if ( !m_pStartNode )
202 m_pStartNode = new SwNodeIndex( *pNewNode );
204 else
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.
214 SwDoc* pDoc;
215 if ( m_pTxtNode )
217 pDoc = m_pTxtNode->GetDoc();
219 else
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
225 // geloescht werden
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() )
234 if( bDelNode )
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() );
240 else
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!)
244 DelFrms();
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 );
259 break;
265 void SwTxtFtn::SetNumber( const USHORT nNewNum, const XubString* pStr )
267 SwFmtFtn& rFtn = (SwFmtFtn&)GetFtn();
268 if( pStr && pStr->Len() )
269 rFtn.aNumber = *pStr;
270 else
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 );
279 if ( m_pStartNode )
281 // must iterate over all TxtNodes because of footnotes on other pages
282 SwNode* pNd;
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
321 aStart++;
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 )
334 if ( m_pStartNode )
335 return;
337 // Nun verpassen wir dem TxtNode noch die Fussnotenvorlage.
338 SwTxtFmtColl *pFmtColl;
339 const SwEndNoteInfo* pInfo;
340 USHORT nPoolId;
342 if( GetFtn().IsEndNote() )
344 pInfo = &rNodes.GetDoc()->GetEndNoteInfo();
345 nPoolId = RES_POOLCOLL_ENDNOTE;
347 else
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?" );
366 if ( !m_pTxtNode )
367 return;
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();
376 if( pPage )
378 pPage->RemoveFtn( pFnd, this );
379 bFrmFnd = TRUE;
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 );
389 if( pCNd )
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." );
406 while ( pFtn )
408 SwFtnFrm *pFoll = pFtn->GetFollow();
409 pFtn->Cut();
410 delete pFtn;
411 pFtn = pFoll;
414 // #i20556# During hiding of a section, the connection
415 // to the layout is already lost. pPage may be 0:
416 if ( pPage )
417 pPage->UpdateFtnNum();
424 USHORT SwTxtFtn::SetSeqRefNo()
426 if( !m_pTxtNode )
427 return USHRT_MAX;
429 SwDoc* pDoc = m_pTxtNode->GetDoc();
430 if( pDoc->IsInReading() )
431 return USHRT_MAX;
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.
440 SwTxtFtn* pTxtFtn;
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 )
473 if( n != aArr[ n ] )
474 break;
476 return m_nSeqNo = 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
487 SwTxtFtn* pTxtFtn;
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;
508 break;
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()
532 //FEATURE::CONDCOLL
533 if( GetStartNode() )
534 ((SwStartNode&)GetStartNode()->GetNode()).CheckSectionCondColl();
535 //FEATURE::CONDCOLL