xref: /trunk/main/sw/source/core/txtnode/atrftn.cxx (revision dec99bbd)
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