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