Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "viewsh.hxx"
21 : #include "doc.hxx"
22 : #include <IDocumentLayoutAccess.hxx>
23 : #include "pagefrm.hxx"
24 : #include "rootfrm.hxx"
25 : #include "ndtxt.hxx"
26 : #include "txtatr.hxx"
27 : #include <SwPortionHandler.hxx>
28 : #include <txtftn.hxx>
29 : #include <flyfrm.hxx>
30 : #include <fmtftn.hxx>
31 : #include <ftninfo.hxx>
32 : #include <charfmt.hxx>
33 : #include <dflyobj.hxx>
34 : #include <rowfrm.hxx>
35 : #include <editeng/brushitem.hxx>
36 : #include <editeng/charrotateitem.hxx>
37 : #include <breakit.hxx>
38 : #include <com/sun/star/i18n/ScriptType.hpp>
39 : #include <tabfrm.hxx>
40 : #include <sortedobjs.hxx>
41 :
42 : #include "swfont.hxx"
43 : #include "porftn.hxx"
44 : #include "porfly.hxx"
45 : #include "porlay.hxx"
46 : #include "txtfrm.hxx"
47 : #include "itrform2.hxx"
48 : #include "ftnfrm.hxx"
49 : #include "pagedesc.hxx"
50 : #include "redlnitr.hxx"
51 : #include "sectfrm.hxx"
52 : #include "layouter.hxx"
53 : #include "frmtool.hxx"
54 : #include "ndindex.hxx"
55 :
56 : using namespace ::com::sun::star;
57 :
58 275 : bool SwTextFrm::_IsFootnoteNumFrm() const
59 : {
60 275 : const SwFootnoteFrm* pFootnote = FindFootnoteFrm()->GetMaster();
61 550 : while( pFootnote && !pFootnote->ContainsContent() )
62 0 : pFootnote = pFootnote->GetMaster();
63 275 : return !pFootnote;
64 : }
65 :
66 : /**
67 : * Looks for the TextFrm matching the SwTextFootnote within a master-follow chain
68 : */
69 290 : SwTextFrm *SwTextFrm::FindFootnoteRef( const SwTextFootnote *pFootnote )
70 : {
71 290 : SwTextFrm *pFrm = this;
72 290 : const bool bFwd = pFootnote->GetStart() >= GetOfst();
73 669 : while( pFrm )
74 : {
75 290 : if( SwFootnoteBossFrm::FindFootnote( pFrm, pFootnote ) )
76 201 : return pFrm;
77 : pFrm = bFwd ? pFrm->GetFollow() :
78 89 : pFrm->IsFollow() ? pFrm->FindMaster() : 0;
79 : }
80 89 : return pFrm;
81 : }
82 :
83 : #ifdef DBG_UTIL
84 : void SwTextFrm::CalcFootnoteFlag( sal_Int32 nStop )// For testing the SplitFrm
85 : #else
86 20955 : void SwTextFrm::CalcFootnoteFlag()
87 : #endif
88 : {
89 20955 : bFootnote = false;
90 :
91 20955 : const SwpHints *pHints = GetTextNode()->GetpSwpHints();
92 20955 : if( !pHints )
93 22911 : return;
94 :
95 18999 : const size_t nSize = pHints->Count();
96 :
97 : #ifdef DBG_UTIL
98 : const sal_Int32 nEnd = nStop != COMPLETE_STRING ? nStop
99 : : GetFollow() ? GetFollow()->GetOfst() : COMPLETE_STRING;
100 : #else
101 18999 : const sal_Int32 nEnd = GetFollow() ? GetFollow()->GetOfst() : COMPLETE_STRING;
102 : #endif
103 :
104 60953 : for ( size_t i = 0; i < nSize; ++i )
105 : {
106 42117 : const SwTextAttr *pHt = (*pHints)[i];
107 42117 : if ( pHt->Which() == RES_TXTATR_FTN )
108 : {
109 299 : const sal_Int32 nIdx = pHt->GetStart();
110 299 : if ( nEnd < nIdx )
111 0 : break;
112 299 : if( GetOfst() <= nIdx )
113 : {
114 163 : bFootnote = true;
115 163 : break;
116 : }
117 : }
118 : }
119 : }
120 :
121 33 : bool SwTextFrm::CalcPrepFootnoteAdjust()
122 : {
123 : OSL_ENSURE( HasFootnote(), "Who´s calling me?" );
124 33 : SwFootnoteBossFrm *pBoss = FindFootnoteBossFrm( true );
125 33 : const SwFootnoteFrm *pFootnote = pBoss->FindFirstFootnote( this );
126 79 : if( pFootnote && FTNPOS_CHAPTER != GetNode()->GetDoc()->GetFootnoteInfo().ePos &&
127 51 : ( !pBoss->GetUpper()->IsSctFrm() ||
128 20 : !static_cast<SwSectionFrm*>(pBoss->GetUpper())->IsFootnoteAtEnd() ) )
129 : {
130 15 : const SwFootnoteContFrm *pCont = pBoss->FindFootnoteCont();
131 15 : bool bReArrange = true;
132 :
133 15 : SWRECTFN( this )
134 60 : if ( pCont && (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
135 45 : (Frm().*fnRect->fnGetBottom)() ) > 0 )
136 : {
137 30 : pBoss->RearrangeFootnotes( (Frm().*fnRect->fnGetBottom)(), false,
138 45 : pFootnote->GetAttr() );
139 15 : ValidateBodyFrm();
140 15 : ValidateFrm();
141 15 : pFootnote = pBoss->FindFirstFootnote( this );
142 : }
143 : else
144 0 : bReArrange = false;
145 15 : if( !pCont || !pFootnote || bReArrange != (pFootnote->FindFootnoteBossFrm() == pBoss) )
146 : {
147 2 : SwTextFormatInfo aInf( this );
148 4 : SwTextFormatter aLine( this, &aInf );
149 2 : aLine.TruncLines();
150 2 : SetPara( 0 ); // May be deleted!
151 2 : ResetPreps();
152 4 : return false;
153 : }
154 : }
155 31 : return true;
156 : }
157 :
158 : /**
159 : * Local helper function. Checks if nLower should be taken as the boundary
160 : * for the footnote.
161 : */
162 363 : static SwTwips lcl_GetFootnoteLower( const SwTextFrm* pFrm, SwTwips nLower )
163 : {
164 : // nLower is an absolute value. It denotes the bottom of the line
165 : // containing the footnote.
166 363 : SWRECTFN( pFrm )
167 :
168 : OSL_ENSURE( !pFrm->IsVertical() || !pFrm->IsSwapped(),
169 : "lcl_GetFootnoteLower with swapped frame" );
170 :
171 : SwTwips nAdd;
172 363 : SwTwips nRet = nLower;
173 :
174 : // Check if text is inside a table.
175 363 : if ( pFrm->IsInTab() )
176 : {
177 : // If pFrm is inside a table, we have to check if
178 : // a) The table is not allowed to split or
179 : // b) The table row is not allowed to split
180 :
181 : // Inside a table, there are no footnotes,
182 : // see SwFrm::FindFootnoteBossFrm. So we don't have to check
183 : // the case that pFrm is inside a (footnote collecting) section
184 : // within the table.
185 1 : const SwFrm* pRow = pFrm;
186 4 : while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
187 2 : pRow = pRow->GetUpper();
188 1 : const SwTabFrm* pTabFrm = static_cast<const SwTabFrm*>(pRow->GetUpper());
189 :
190 : OSL_ENSURE( pTabFrm && pRow &&
191 : pRow->GetUpper()->IsTabFrm(), "Upper of row should be tab" );
192 :
193 2 : const bool bDontSplit = !pTabFrm->IsFollow() &&
194 2 : !pTabFrm->IsLayoutSplitAllowed();
195 :
196 1 : SwTwips nMin = 0;
197 1 : if ( bDontSplit )
198 0 : nMin = (pTabFrm->Frm().*fnRect->fnGetBottom)();
199 1 : else if ( !static_cast<const SwRowFrm*>(pRow)->IsRowSplitAllowed() )
200 0 : nMin = (pRow->Frm().*fnRect->fnGetBottom)();
201 :
202 1 : if ( nMin && (*fnRect->fnYDiff)( nMin, nLower ) > 0 )
203 0 : nRet = nMin;
204 :
205 1 : nAdd = (pRow->GetUpper()->*fnRect->fnGetBottomMargin)();
206 : }
207 : else
208 362 : nAdd = (pFrm->*fnRect->fnGetBottomMargin)();
209 :
210 363 : if( nAdd > 0 )
211 : {
212 0 : if ( bVert )
213 0 : nRet -= nAdd;
214 : else
215 0 : nRet += nAdd;
216 : }
217 :
218 : // #i10770#: If there are fly frames anchored at previous paragraphs,
219 : // the deadline should consider their lower borders.
220 363 : const SwFrm* pStartFrm = pFrm->GetUpper()->GetLower();
221 : OSL_ENSURE( pStartFrm, "Upper has no lower" );
222 363 : SwTwips nFlyLower = bVert ? LONG_MAX : 0;
223 1081 : while ( pStartFrm != pFrm )
224 : {
225 : OSL_ENSURE( pStartFrm, "Frame chain is broken" );
226 355 : if ( pStartFrm->GetDrawObjs() )
227 : {
228 0 : const SwSortedObjs &rObjs = *pStartFrm->GetDrawObjs();
229 0 : for ( size_t i = 0; i < rObjs.size(); ++i )
230 : {
231 0 : SwAnchoredObject* pAnchoredObj = rObjs[i];
232 0 : SwRect aRect( pAnchoredObj->GetObjRect() );
233 :
234 0 : if ( !pAnchoredObj->ISA(SwFlyFrm) ||
235 0 : static_cast<SwFlyFrm*>(pAnchoredObj)->IsValid() )
236 : {
237 0 : const SwTwips nBottom = (aRect.*fnRect->fnGetBottom)();
238 0 : if ( (*fnRect->fnYDiff)( nBottom, nFlyLower ) > 0 )
239 0 : nFlyLower = nBottom;
240 : }
241 : }
242 : }
243 :
244 355 : pStartFrm = pStartFrm->GetNext();
245 : }
246 :
247 363 : if ( bVert )
248 0 : nRet = std::min( nRet, nFlyLower );
249 : else
250 363 : nRet = std::max( nRet, nFlyLower );
251 :
252 363 : return nRet;
253 : }
254 :
255 218 : SwTwips SwTextFrm::GetFootnoteLine( const SwTextFootnote *pFootnote ) const
256 : {
257 : OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
258 : "SwTextFrm::GetFootnoteLine with swapped frame" );
259 :
260 218 : SwTextFrm *pThis = const_cast<SwTextFrm*>(this);
261 :
262 218 : if( !HasPara() )
263 : {
264 : // #109071# GetFormatted() does not work here, bacause most probably
265 : // the frame is currently locked. We return the previous value.
266 0 : return pThis->mnFootnoteLine > 0 ?
267 : pThis->mnFootnoteLine :
268 0 : IsVertical() ? Frm().Left() : Frm().Bottom();
269 : }
270 :
271 : SwTwips nRet;
272 : {
273 218 : SWAP_IF_NOT_SWAPPED swap(const_cast<SwTextFrm *>(this));
274 :
275 218 : SwTextInfo aInf( pThis );
276 436 : SwTextIter aLine( pThis, &aInf );
277 218 : const sal_Int32 nPos = pFootnote->GetStart();
278 218 : aLine.CharToLine( nPos );
279 :
280 218 : nRet = aLine.Y() + SwTwips(aLine.GetLineHeight());
281 218 : if( IsVertical() )
282 218 : nRet = SwitchHorizontalToVertical( nRet );
283 : }
284 :
285 218 : nRet = lcl_GetFootnoteLower( pThis, nRet );
286 :
287 218 : pThis->mnFootnoteLine = nRet;
288 218 : return nRet;
289 : }
290 :
291 : /**
292 : * Calculates the maximum reachable height for the TextFrm in the Footnote Area.
293 : * The cell's bottom margin with the Footnote Reference limit's this height.
294 : */
295 392 : SwTwips SwTextFrm::_GetFootnoteFrmHeight() const
296 : {
297 : OSL_ENSURE( !IsFollow() && IsInFootnote(), "SwTextFrm::SetFootnoteLine: moon walk" );
298 :
299 392 : const SwFootnoteFrm *pFootnoteFrm = FindFootnoteFrm();
300 392 : const SwTextFrm *pRef = static_cast<const SwTextFrm *>(pFootnoteFrm->GetRef());
301 392 : const SwFootnoteBossFrm *pBoss = FindFootnoteBossFrm();
302 784 : if( pBoss != pRef->FindFootnoteBossFrm( !pFootnoteFrm->GetAttr()->
303 392 : GetFootnote().IsEndNote() ) )
304 135 : return 0;
305 :
306 257 : SWAP_IF_SWAPPED swap(const_cast<SwTextFrm *>(this));
307 :
308 257 : SwTwips nHeight = pRef->IsInFootnoteConnect() ?
309 257 : 1 : pRef->GetFootnoteLine( pFootnoteFrm->GetAttr() );
310 257 : if( nHeight )
311 : {
312 : // As odd as it may seem: the first Footnote on the page may not touch the
313 : // Footnote Reference, when entering text in the Footnote Area.
314 257 : const SwFrm *pCont = pFootnoteFrm->GetUpper();
315 :
316 : // Height within the Container which we're allowed to consume anyways
317 257 : SWRECTFN( pCont )
318 514 : SwTwips nTmp = (*fnRect->fnYDiff)( (pCont->*fnRect->fnGetPrtBottom)(),
319 771 : (Frm().*fnRect->fnGetTop)() );
320 :
321 : #if OSL_DEBUG_LEVEL > 0
322 : if( nTmp < 0 )
323 : {
324 : bool bInvalidPos = false;
325 : const SwLayoutFrm* pTmp = GetUpper();
326 : while( !bInvalidPos && pTmp )
327 : {
328 : bInvalidPos = !pTmp->GetValidPosFlag() ||
329 : !pTmp->Lower()->GetValidPosFlag();
330 : if( pTmp == pCont )
331 : break;
332 : pTmp = pTmp->GetUpper();
333 : }
334 : OSL_ENSURE( bInvalidPos, "Hanging below FootnoteCont" );
335 : }
336 : #endif
337 :
338 257 : if ( (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight) > 0 )
339 : {
340 : // Growth potential of the container
341 257 : if ( !pRef->IsInFootnoteConnect() )
342 : {
343 85 : SwSaveFootnoteHeight aSave( const_cast<SwFootnoteBossFrm*>(pBoss), nHeight );
344 85 : nHeight = const_cast<SwFootnoteContFrm*>(static_cast<const SwFootnoteContFrm*>(pCont))->Grow( LONG_MAX, true );
345 : }
346 : else
347 172 : nHeight = const_cast<SwFootnoteContFrm*>(static_cast<const SwFootnoteContFrm*>(pCont))->Grow( LONG_MAX, true );
348 :
349 257 : nHeight += nTmp;
350 257 : if( nHeight < 0 )
351 0 : nHeight = 0;
352 : }
353 : else
354 : { // The container has to shrink
355 0 : nTmp += (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight);
356 0 : if( nTmp > 0 )
357 0 : nHeight = nTmp;
358 : else
359 0 : nHeight = 0;
360 : }
361 : }
362 :
363 257 : return nHeight;
364 : }
365 :
366 116 : SwTextFrm *SwTextFrm::FindQuoVadisFrm()
367 : {
368 : // Check whether we're in a FootnoteFrm
369 116 : if( GetIndPrev() || !IsInFootnote() )
370 0 : return 0;
371 :
372 : // To the preceding FootnoteFrm
373 116 : SwFootnoteFrm *pFootnoteFrm = FindFootnoteFrm()->GetMaster();
374 116 : if( !pFootnoteFrm )
375 116 : return 0;
376 :
377 : // Now the last Content
378 0 : SwContentFrm *pCnt = pFootnoteFrm->ContainsContent();
379 0 : if( !pCnt )
380 0 : return NULL;
381 : SwContentFrm *pLast;
382 0 : do
383 0 : { pLast = pCnt;
384 0 : pCnt = pCnt->GetNextContentFrm();
385 0 : } while( pCnt && pFootnoteFrm->IsAnLower( pCnt ) );
386 0 : return static_cast<SwTextFrm*>(pLast);
387 : }
388 :
389 26160 : void SwTextFrm::RemoveFootnote( const sal_Int32 nStart, const sal_Int32 nLen )
390 : {
391 26160 : if ( !IsFootnoteAllowed() )
392 7413 : return;
393 :
394 18747 : SwpHints *pHints = GetTextNode()->GetpSwpHints();
395 18747 : if( !pHints )
396 165 : return;
397 :
398 18582 : bool bRollBack = nLen != COMPLETE_STRING;
399 18582 : const size_t nSize = pHints->Count();
400 : sal_Int32 nEnd;
401 : SwTextFrm* pSource;
402 18582 : if( bRollBack )
403 : {
404 103 : nEnd = nStart + nLen;
405 103 : pSource = GetFollow();
406 103 : if( !pSource )
407 0 : return;
408 : }
409 : else
410 : {
411 18479 : nEnd = COMPLETE_STRING;
412 18479 : pSource = this;
413 : }
414 :
415 18582 : if( nSize )
416 : {
417 18553 : SwPageFrm* pUpdate = NULL;
418 18553 : bool bRemove = false;
419 18553 : SwFootnoteBossFrm *pFootnoteBoss = 0;
420 18553 : SwFootnoteBossFrm *pEndBoss = 0;
421 : bool bFootnoteEndDoc
422 18553 : = FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFootnoteInfo().ePos;
423 78055 : for ( size_t i = nSize; i; )
424 : {
425 41150 : SwTextAttr *pHt = pHints->GetTextHint(--i);
426 41150 : if ( RES_TXTATR_FTN != pHt->Which() )
427 40949 : continue;
428 :
429 201 : const sal_Int32 nIdx = pHt->GetStart();
430 201 : if( nStart > nIdx )
431 201 : break;
432 :
433 0 : if( nEnd >= nIdx )
434 : {
435 0 : SwTextFootnote *pFootnote = static_cast<SwTextFootnote*>(pHt);
436 0 : const bool bEndn = pFootnote->GetFootnote().IsEndNote();
437 :
438 0 : if( bEndn )
439 : {
440 0 : if( !pEndBoss )
441 0 : pEndBoss = pSource->FindFootnoteBossFrm();
442 : }
443 : else
444 : {
445 0 : if( !pFootnoteBoss )
446 : {
447 0 : pFootnoteBoss = pSource->FindFootnoteBossFrm( true );
448 0 : if( pFootnoteBoss->GetUpper()->IsSctFrm() )
449 : {
450 : SwSectionFrm* pSect = static_cast<SwSectionFrm*>(
451 0 : pFootnoteBoss->GetUpper());
452 0 : if( pSect->IsFootnoteAtEnd() )
453 0 : bFootnoteEndDoc = false;
454 : }
455 : }
456 : }
457 :
458 : // We don't delete, but move instead.
459 : // Three cases are to be considered:
460 : // 1) There's neither Follow nor PrevFollow:
461 : // -> RemoveFootnote() (maybe even a OSL_ENSURE(value))
462 : //
463 : // 2) nStart > GetOfst, I have a Follow
464 : // -> Footnote moves into Follow
465 : //
466 : // 3) nStart < GetOfst, I am a Follow
467 : // -> Footnote moves into the PrevFollow
468 : //
469 : // Both need to be on one Page/in one Column
470 0 : SwFootnoteFrm *pFootnoteFrm = SwFootnoteBossFrm::FindFootnote(pSource, pFootnote);
471 :
472 0 : if( pFootnoteFrm )
473 : {
474 0 : const bool bEndDoc = bEndn || bFootnoteEndDoc;
475 0 : if( bRollBack )
476 : {
477 0 : while ( pFootnoteFrm )
478 : {
479 0 : pFootnoteFrm->SetRef( this );
480 0 : pFootnoteFrm = pFootnoteFrm->GetFollow();
481 0 : SetFootnote( true );
482 : }
483 : }
484 0 : else if( GetFollow() )
485 : {
486 0 : SwContentFrm *pDest = GetFollow();
487 0 : while( pDest->GetFollow() && static_cast<SwTextFrm*>(pDest->
488 0 : GetFollow())->GetOfst() <= nIdx )
489 0 : pDest = pDest->GetFollow();
490 : OSL_ENSURE( !SwFootnoteBossFrm::FindFootnote(
491 : pDest,pFootnote),"SwTextFrm::RemoveFootnote: footnote exists");
492 :
493 : // Never deregister; always move
494 0 : if ( bEndDoc ||
495 0 : !pFootnoteFrm->FindFootnoteBossFrm()->IsBefore( pDest->FindFootnoteBossFrm( !bEndn ) )
496 : )
497 : {
498 0 : SwPageFrm* pTmp = pFootnoteFrm->FindPageFrm();
499 0 : if( pUpdate && pUpdate != pTmp )
500 0 : pUpdate->UpdateFootnoteNum();
501 0 : pUpdate = pTmp;
502 0 : while ( pFootnoteFrm )
503 : {
504 0 : pFootnoteFrm->SetRef( pDest );
505 0 : pFootnoteFrm = pFootnoteFrm->GetFollow();
506 : }
507 : }
508 : else
509 : {
510 0 : pFootnoteBoss->MoveFootnotes( this, pDest, pFootnote );
511 0 : bRemove = true;
512 : }
513 0 : static_cast<SwTextFrm*>(pDest)->SetFootnote( true );
514 :
515 : OSL_ENSURE( SwFootnoteBossFrm::FindFootnote( pDest,
516 : pFootnote),"SwTextFrm::RemoveFootnote: footnote ChgRef failed");
517 : }
518 : else
519 : {
520 0 : if( !bEndDoc || ( bEndn && pEndBoss->IsInSct() &&
521 0 : !SwLayouter::Collecting( GetNode()->GetDoc(),
522 0 : pEndBoss->FindSctFrm(), NULL ) ) )
523 : {
524 0 : if( bEndn )
525 0 : pEndBoss->RemoveFootnote( this, pFootnote );
526 : else
527 0 : pFootnoteBoss->RemoveFootnote( this, pFootnote );
528 0 : bRemove = bRemove || !bEndDoc;
529 : OSL_ENSURE( !SwFootnoteBossFrm::FindFootnote( this, pFootnote ),
530 : "SwTextFrm::RemoveFootnote: can't get off that footnote" );
531 : }
532 : }
533 : }
534 : }
535 : }
536 18553 : if( pUpdate )
537 0 : pUpdate->UpdateFootnoteNum();
538 :
539 : // We brake the oscillation
540 18553 : if( bRemove && !bFootnoteEndDoc && HasPara() )
541 : {
542 0 : ValidateBodyFrm();
543 0 : ValidateFrm();
544 : }
545 : }
546 :
547 : // We call the RemoveFootnote from within the FindBreak, because the last line is
548 : // to be passed to the Follow. The Offset of the Follow is, however, outdated;
549 : // it'll be set soon. CalcFntFlag depends on a correctly set Follow Offset.
550 : // Therefore we temporarily calculate the Follow Offset here
551 18582 : sal_Int32 nOldOfst = COMPLETE_STRING;
552 18582 : if( HasFollow() && nStart > GetOfst() )
553 : {
554 657 : nOldOfst = GetFollow()->GetOfst();
555 657 : GetFollow()->ManipOfst( nStart + ( bRollBack ? nLen : 0 ) );
556 : }
557 18582 : pSource->CalcFootnoteFlag();
558 18582 : if( nOldOfst < COMPLETE_STRING )
559 657 : GetFollow()->ManipOfst( nOldOfst );
560 : }
561 :
562 :
563 : /**
564 : * We basically only have two possibilities:
565 : *
566 : * a) The Footnote is already present
567 : * => we move it, if another pSrcFrm has been found
568 : *
569 : * b) The Footnote is not present
570 : * => we have it created for us
571 : *
572 : * Whether the Footnote ends up on our Page/Column, doesn't matter in this
573 : * context.
574 : *
575 : * Optimization for Endnotes.
576 : *
577 : * Another problem: if the Deadline falls within the Footnote Area, we need
578 : * to move the Footnote.
579 : *
580 : * @returns false on any type of error
581 : */
582 145 : void SwTextFrm::ConnectFootnote( SwTextFootnote *pFootnote, const SwTwips nDeadLine )
583 : {
584 : OSL_ENSURE( !IsVertical() || !IsSwapped(),
585 : "SwTextFrm::ConnectFootnote with swapped frame" );
586 :
587 145 : bFootnote = true;
588 145 : bInFootnoteConnect = true; // Just reset!
589 145 : const bool bEnd = pFootnote->GetFootnote().IsEndNote();
590 :
591 : // We want to store this value, because it is needed as a fallback
592 : // in GetFootnoteLine(), if there is no paragraph information available
593 145 : mnFootnoteLine = nDeadLine;
594 :
595 : // We always need a parent (Page/Column)
596 : SwSectionFrm *pSect;
597 145 : SwContentFrm *pContent = this;
598 145 : if( bEnd && IsInSct() )
599 : {
600 18 : pSect = FindSctFrm();
601 18 : if( pSect->IsEndnAtEnd() )
602 1 : pContent = pSect->FindLastContent( FINDMODE_ENDNOTE );
603 18 : if( !pContent )
604 0 : pContent = this;
605 : }
606 :
607 145 : SwFootnoteBossFrm *pBoss = pContent->FindFootnoteBossFrm( !bEnd );
608 :
609 : #if OSL_DEBUG_LEVEL > 1
610 : SwTwips nRstHeight = GetRstHeight();
611 : #endif
612 :
613 145 : pSect = pBoss->FindSctFrm();
614 31 : bool bDocEnd = bEnd ? !( pSect && pSect->IsEndnAtEnd() ) :
615 227 : ( !( pSect && pSect->IsFootnoteAtEnd() ) &&
616 403 : FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFootnoteInfo().ePos );
617 :
618 : // Footnote can be registered with the Follow
619 145 : SwContentFrm *pSrcFrm = FindFootnoteRef( pFootnote );
620 :
621 145 : if( bDocEnd )
622 : {
623 31 : if( pSect && pSrcFrm )
624 : {
625 9 : SwFootnoteFrm *pFootnoteFrm = SwFootnoteBossFrm::FindFootnote( pSrcFrm, pFootnote );
626 9 : if( pFootnoteFrm && pFootnoteFrm->IsInSct() )
627 : {
628 0 : pBoss->RemoveFootnote( pSrcFrm, pFootnote );
629 0 : pSrcFrm = 0;
630 : }
631 : }
632 : }
633 114 : else if( bEnd && pSect )
634 : {
635 1 : SwFootnoteFrm *pFootnoteFrm = pSrcFrm ? SwFootnoteBossFrm::FindFootnote( pSrcFrm, pFootnote ) : NULL;
636 1 : if( pFootnoteFrm && !pFootnoteFrm->GetUpper() )
637 0 : pFootnoteFrm = NULL;
638 1 : SwDoc *pDoc = GetNode()->GetDoc();
639 1 : if( SwLayouter::Collecting( pDoc, pSect, pFootnoteFrm ) )
640 : {
641 1 : if( !pSrcFrm )
642 : {
643 1 : SwFootnoteFrm *pNew = new SwFootnoteFrm(pDoc->GetDfltFrameFormat(),this,this,pFootnote);
644 1 : SwNodeIndex aIdx( *pFootnote->GetStartNode(), 1 );
645 1 : ::_InsertCnt( pNew, pDoc, aIdx.GetIndex() );
646 1 : GetNode()->getIDocumentLayoutAccess()->GetLayouter()->CollectEndnote( pNew );
647 : }
648 0 : else if( pSrcFrm != this )
649 0 : SwFootnoteBossFrm::ChangeFootnoteRef( pSrcFrm, pFootnote, this );
650 1 : bInFootnoteConnect = false;
651 1 : return;
652 : }
653 0 : else if( pSrcFrm )
654 : {
655 0 : SwFootnoteBossFrm *pFootnoteBoss = pFootnoteFrm->FindFootnoteBossFrm();
656 0 : if( !pFootnoteBoss->IsInSct() ||
657 0 : pFootnoteBoss->ImplFindSctFrm()->GetSection()!=pSect->GetSection() )
658 : {
659 0 : pBoss->RemoveFootnote( pSrcFrm, pFootnote );
660 0 : pSrcFrm = 0;
661 : }
662 : }
663 : }
664 :
665 144 : if( bDocEnd || bEnd )
666 : {
667 31 : if( !pSrcFrm )
668 18 : pBoss->AppendFootnote( this, pFootnote );
669 13 : else if( pSrcFrm != this )
670 0 : SwFootnoteBossFrm::ChangeFootnoteRef( pSrcFrm, pFootnote, this );
671 31 : bInFootnoteConnect = false;
672 31 : return;
673 : }
674 :
675 113 : SwSaveFootnoteHeight aHeight( pBoss, nDeadLine );
676 :
677 113 : if( !pSrcFrm ) // No Footnote was found at all
678 70 : pBoss->AppendFootnote( this, pFootnote );
679 : else
680 : {
681 43 : SwFootnoteFrm *pFootnoteFrm = SwFootnoteBossFrm::FindFootnote( pSrcFrm, pFootnote );
682 43 : SwFootnoteBossFrm *pFootnoteBoss = pFootnoteFrm->FindFootnoteBossFrm();
683 :
684 43 : bool bBrutal = false;
685 :
686 43 : if( pFootnoteBoss == pBoss ) // Ref and Footnote are on the same Page/Column
687 : {
688 41 : SwFrm *pCont = pFootnoteFrm->GetUpper();
689 :
690 41 : SWRECTFN ( pCont )
691 82 : long nDiff = (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
692 123 : nDeadLine );
693 :
694 41 : if( nDiff >= 0 )
695 : {
696 : // If the Footnote has been registered to a Follow, we need to
697 : // rewire it now too
698 41 : if ( pSrcFrm != this )
699 0 : SwFootnoteBossFrm::ChangeFootnoteRef( pSrcFrm, pFootnote, this );
700 :
701 : // We have some room left, so the Footnote can grow
702 41 : if ( pFootnoteFrm->GetFollow() && nDiff > 0 )
703 : {
704 0 : SwTwips nHeight = (pCont->Frm().*fnRect->fnGetHeight)();
705 0 : pBoss->RearrangeFootnotes( nDeadLine, false, pFootnote );
706 0 : ValidateBodyFrm();
707 0 : ValidateFrm();
708 0 : SwViewShell *pSh = getRootFrm()->GetCurrShell();
709 0 : if ( pSh && nHeight == (pCont->Frm().*fnRect->fnGetHeight)() )
710 : // So that we don't miss anything
711 0 : pSh->InvalidateWindows( pCont->Frm() );
712 : }
713 41 : bInFootnoteConnect = false;
714 41 : return;
715 : }
716 : else
717 0 : bBrutal = true;
718 : }
719 : else
720 : {
721 : // Ref and Footnote are not on one Page; attempt to move is necessary
722 2 : SwFrm* pTmp = this;
723 4 : while( pTmp->GetNext() && pSrcFrm != pTmp )
724 0 : pTmp = pTmp->GetNext();
725 2 : if( pSrcFrm == pTmp )
726 2 : bBrutal = true;
727 : else
728 : { // If our Parent is in a column Area, but the Page already has a
729 : // FootnoteContainer, we can only brute force it
730 0 : if( pSect && pSect->FindFootnoteBossFrm( !bEnd )->FindFootnoteCont() )
731 0 : bBrutal = true;
732 :
733 0 : else if ( !pFootnoteFrm->GetPrev() ||
734 0 : pFootnoteBoss->IsBefore( pBoss )
735 : )
736 : {
737 0 : SwFootnoteBossFrm *pSrcBoss = pSrcFrm->FindFootnoteBossFrm( !bEnd );
738 0 : pSrcBoss->MoveFootnotes( pSrcFrm, this, pFootnote );
739 : }
740 : else
741 0 : SwFootnoteBossFrm::ChangeFootnoteRef( pSrcFrm, pFootnote, this );
742 : }
743 : }
744 :
745 : // The brute force method: Remove Footnote and append.
746 : // We need to call SetFootnoteDeadLine(), as we can more easily adapt the
747 : // nMaxFootnoteHeight after RemoveFootnote
748 2 : if( bBrutal )
749 : {
750 2 : pBoss->RemoveFootnote( pSrcFrm, pFootnote, false );
751 2 : SwSaveFootnoteHeight *pHeight = bEnd ? NULL : new SwSaveFootnoteHeight( pBoss, nDeadLine );
752 2 : pBoss->AppendFootnote( this, pFootnote );
753 2 : delete pHeight;
754 : }
755 : }
756 :
757 : // In column Areas, that not yet reach the Page's border a RearrangeFootnotes is not
758 : // useful yet, as the Footnote container has not yet been calculated
759 72 : if( !pSect || !pSect->Growable() )
760 : {
761 : // Validate environment, to avoid oscillation
762 72 : SwSaveFootnoteHeight aNochmal( pBoss, nDeadLine );
763 72 : ValidateBodyFrm();
764 72 : pBoss->RearrangeFootnotes( nDeadLine, true );
765 72 : ValidateFrm();
766 : }
767 0 : else if( pSect->IsFootnoteAtEnd() )
768 : {
769 0 : ValidateBodyFrm();
770 0 : ValidateFrm();
771 : }
772 :
773 : #if OSL_DEBUG_LEVEL > 1
774 : // pFootnoteFrm may have changed due to Calc ...
775 : SwFootnoteFrm *pFootnoteFrm = pBoss->FindFootnote( this, pFootnote );
776 : if( pFootnoteFrm && pBoss != pFootnoteFrm->FindFootnoteBossFrm( !bEnd ) )
777 : {
778 : int bla = 5;
779 : (void)bla;
780 : }
781 : nRstHeight = GetRstHeight();
782 : (void)nRstHeight;
783 : #endif
784 72 : bInFootnoteConnect = false;
785 72 : return;
786 : }
787 :
788 : /**
789 : * The portion for the Footnote Reference in the Text
790 : */
791 145 : SwFootnotePortion *SwTextFormatter::NewFootnotePortion( SwTextFormatInfo &rInf,
792 : SwTextAttr *pHint )
793 : {
794 : OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
795 : "NewFootnotePortion with unswapped frame" );
796 :
797 145 : if( !pFrm->IsFootnoteAllowed() )
798 0 : return 0;
799 :
800 145 : SwTextFootnote *pFootnote = static_cast<SwTextFootnote*>(pHint);
801 145 : const SwFormatFootnote& rFootnote = static_cast<const SwFormatFootnote&>(pFootnote->GetFootnote());
802 145 : SwDoc *pDoc = pFrm->GetNode()->GetDoc();
803 :
804 145 : if( rInf.IsTest() )
805 0 : return new SwFootnotePortion( rFootnote.GetViewNumStr( *pDoc ), pFootnote );
806 :
807 145 : SWAP_IF_SWAPPED swap(pFrm);
808 :
809 : sal_uInt16 nReal;
810 : {
811 145 : sal_uInt16 nOldReal = pCurr->GetRealHeight();
812 145 : sal_uInt16 nOldAscent = pCurr->GetAscent();
813 145 : sal_uInt16 nOldHeight = pCurr->Height();
814 145 : CalcRealHeight();
815 145 : nReal = pCurr->GetRealHeight();
816 145 : if( nReal < nOldReal )
817 0 : nReal = nOldReal;
818 145 : pCurr->SetRealHeight( nOldReal );
819 145 : pCurr->Height( nOldHeight );
820 145 : pCurr->SetAscent( nOldAscent );
821 : }
822 :
823 145 : SwTwips nLower = Y() + nReal;
824 :
825 145 : const bool bVertical = pFrm->IsVertical();
826 145 : if( bVertical )
827 0 : nLower = pFrm->SwitchHorizontalToVertical( nLower );
828 :
829 145 : nLower = lcl_GetFootnoteLower( pFrm, nLower );
830 :
831 : // We just refresh.
832 : // The Connect does not do anything useful in this case, but will
833 : // mostly throw away the Footnote and create it anew.
834 145 : if( !rInf.IsQuick() )
835 145 : pFrm->ConnectFootnote( pFootnote, nLower );
836 :
837 145 : SwTextFrm *pScrFrm = pFrm->FindFootnoteRef( pFootnote );
838 145 : SwFootnoteBossFrm *pBoss = pFrm->FindFootnoteBossFrm( !rFootnote.IsEndNote() );
839 145 : SwFootnoteFrm *pFootnoteFrm = NULL;
840 145 : if( pScrFrm )
841 145 : pFootnoteFrm = SwFootnoteBossFrm::FindFootnote( pScrFrm, pFootnote );
842 :
843 : // We see whether our Append has caused some Footnote to
844 : // still be on the Page/Column. If not, our line disappears too,
845 : // which will lead to the following undesired behaviour:
846 : // Footnote1 still fits onto the Page/Column, but Footnote2 doesn't.
847 : // The Footnote2 Reference remains on the Page/Column. The Footnote itself
848 : // is on the next Page/Column.
849 : //
850 : // Exception: If the Page/Column cannot accomodate another line,
851 : // the Footnote Reference should be moved to the next one.
852 145 : if( !rFootnote.IsEndNote() )
853 : {
854 114 : SwSectionFrm *pSct = pBoss->FindSctFrm();
855 114 : bool bAtSctEnd = pSct && pSct->IsFootnoteAtEnd();
856 114 : if( FTNPOS_CHAPTER != pDoc->GetFootnoteInfo().ePos || bAtSctEnd )
857 : {
858 113 : SwFrm* pFootnoteCont = pBoss->FindFootnoteCont();
859 : // If the Parent is within an Area, it can only be a Column of this
860 : // Area. If this one is not the first Column, we can avoid it.
861 227 : if( !pFrm->IsInTab() && ( GetLineNr() > 1 || pFrm->GetPrev() ||
862 111 : ( !bAtSctEnd && pFrm->GetIndPrev() ) ||
863 3 : ( pSct && pBoss->GetPrev() ) ) )
864 : {
865 58 : if( !pFootnoteCont )
866 : {
867 0 : rInf.SetStop( true );
868 0 : return 0;
869 : }
870 : else
871 : {
872 : // There must not be any Footnote Containers in column Areas and at the same time on the
873 : // Page/Page column
874 58 : if( pSct && !bAtSctEnd ) // Is the Container in a (column) Area?
875 : {
876 5 : SwFootnoteBossFrm* pTmp = pBoss->FindSctFrm()->FindFootnoteBossFrm( true );
877 5 : SwFootnoteContFrm* pFootnoteC = pTmp->FindFootnoteCont();
878 5 : if( pFootnoteC )
879 : {
880 0 : SwFootnoteFrm* pTmpFrm = static_cast<SwFootnoteFrm*>(pFootnoteC->Lower());
881 0 : if( pTmpFrm && *pTmpFrm < pFootnote )
882 : {
883 0 : rInf.SetStop( true );
884 0 : return 0;
885 : }
886 : }
887 : }
888 : // Is this the last Line that fits?
889 58 : SwTwips nTmpBot = Y() + nReal * 2;
890 :
891 58 : if( bVertical )
892 0 : nTmpBot = pFrm->SwitchHorizontalToVertical( nTmpBot );
893 :
894 58 : SWRECTFN( pFootnoteCont )
895 :
896 : const long nDiff = (*fnRect->fnYDiff)(
897 116 : (pFootnoteCont->Frm().*fnRect->fnGetTop)(),
898 174 : nTmpBot );
899 :
900 58 : if( pScrFrm && nDiff < 0 )
901 : {
902 0 : if( pFootnoteFrm )
903 : {
904 0 : SwFootnoteBossFrm *pFootnoteBoss = pFootnoteFrm->FindFootnoteBossFrm();
905 0 : if( pFootnoteBoss != pBoss )
906 : {
907 : // We're in the last Line and the Footnote has moved
908 : // to another Page. We also want to be on that Page!
909 0 : rInf.SetStop( true );
910 0 : return 0;
911 : }
912 : }
913 : }
914 : }
915 : }
916 : }
917 : }
918 : // Finally: Create FootnotePortion and exit ...
919 : SwFootnotePortion *pRet = new SwFootnotePortion( rFootnote.GetViewNumStr( *pDoc ),
920 145 : pFootnote, nReal );
921 145 : rInf.SetFootnoteInside( true );
922 :
923 145 : return pRet;
924 : }
925 :
926 : /**
927 : * The portion for the Footnote Numbering in the Footnote Area
928 : */
929 146 : SwNumberPortion *SwTextFormatter::NewFootnoteNumPortion( SwTextFormatInfo &rInf ) const
930 : {
931 : OSL_ENSURE( pFrm->IsInFootnote() && !pFrm->GetIndPrev() && !rInf.IsFootnoteDone(),
932 : "This is the wrong place for a ftnnumber" );
933 292 : if( rInf.GetTextStart() != nStart ||
934 146 : rInf.GetTextStart() != rInf.GetIdx() )
935 0 : return 0;
936 :
937 146 : const SwFootnoteFrm* pFootnoteFrm = pFrm->FindFootnoteFrm();
938 146 : const SwTextFootnote* pFootnote = pFootnoteFrm->GetAttr();
939 :
940 : // Aha! So we're in the Footnote Area!
941 146 : SwFormatFootnote& rFootnote = (SwFormatFootnote&)pFootnote->GetFootnote();
942 :
943 146 : SwDoc *pDoc = pFrm->GetNode()->GetDoc();
944 146 : OUString aFootnoteText( rFootnote.GetViewNumStr( *pDoc, true ));
945 :
946 : const SwEndNoteInfo* pInfo;
947 146 : if( rFootnote.IsEndNote() )
948 30 : pInfo = &pDoc->GetEndNoteInfo();
949 : else
950 116 : pInfo = &pDoc->GetFootnoteInfo();
951 146 : const SwAttrSet& rSet = pInfo->GetCharFormat(*pDoc)->GetAttrSet();
952 :
953 146 : const SwAttrSet* pParSet = &rInf.GetCharAttr();
954 146 : const IDocumentSettingAccess* pIDSA = pFrm->GetTextNode()->getIDocumentSettingAccess();
955 146 : SwFont *pNumFnt = new SwFont( pParSet, pIDSA );
956 :
957 : // #i37142#
958 : // Underline style of paragraph font should not be considered
959 : // Overline style of paragraph font should not be considered
960 : // Weight style of paragraph font should not be considered
961 : // Posture style of paragraph font should not be considered
962 : // See also #i18463# and SwTextFormatter::NewNumberPortion()
963 146 : pNumFnt->SetUnderline( UNDERLINE_NONE );
964 146 : pNumFnt->SetOverline( UNDERLINE_NONE );
965 146 : pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN );
966 146 : pNumFnt->SetItalic( ITALIC_NONE, SW_CJK );
967 146 : pNumFnt->SetItalic( ITALIC_NONE, SW_CTL );
968 146 : pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN );
969 146 : pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK );
970 146 : pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL );
971 :
972 146 : pNumFnt->SetDiffFnt(&rSet, pIDSA );
973 146 : pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() );
974 :
975 146 : SwFootnoteNumPortion* pNewPor = new SwFootnoteNumPortion( aFootnoteText, pNumFnt );
976 146 : pNewPor->SetLeft( !pFrm->IsRightToLeft() );
977 146 : return pNewPor;
978 : }
979 :
980 0 : OUString lcl_GetPageNumber( const SwPageFrm* pPage )
981 : {
982 : OSL_ENSURE( pPage, "GetPageNumber: Homeless TextFrm" );
983 0 : const sal_uInt16 nVirtNum = pPage->GetVirtPageNum();
984 0 : const SvxNumberType& rNum = pPage->GetPageDesc()->GetNumType();
985 0 : return rNum.GetNumStr( nVirtNum );
986 : }
987 :
988 161 : SwErgoSumPortion *SwTextFormatter::NewErgoSumPortion( SwTextFormatInfo &rInf ) const
989 : {
990 : // We cannot assume we're a Follow
991 644 : if( !pFrm->IsInFootnote() || pFrm->GetPrev() ||
992 644 : rInf.IsErgoDone() || rInf.GetIdx() != pFrm->GetOfst() ||
993 161 : pFrm->ImplFindFootnoteFrm()->GetAttr()->GetFootnote().IsEndNote() )
994 45 : return 0;
995 :
996 : // Aha, wir sind also im Fussnotenbereich
997 116 : const SwFootnoteInfo &rFootnoteInfo = pFrm->GetNode()->GetDoc()->GetFootnoteInfo();
998 116 : SwTextFrm *pQuoFrm = pFrm->FindQuoVadisFrm();
999 116 : if( !pQuoFrm )
1000 116 : return 0;
1001 0 : const SwPageFrm* pPage = pFrm->FindPageFrm();
1002 0 : const SwPageFrm* pQuoPage = pQuoFrm->FindPageFrm();
1003 0 : if( pPage == pQuoFrm->FindPageFrm() )
1004 0 : return 0; // If the QuoVadis is on the same Column/Page
1005 0 : const OUString aPage = lcl_GetPageNumber( pPage );
1006 0 : SwParaPortion *pPara = pQuoFrm->GetPara();
1007 0 : if( pPara )
1008 0 : pPara->SetErgoSumNum( aPage );
1009 0 : if( rFootnoteInfo.aErgoSum.isEmpty() )
1010 0 : return 0;
1011 : SwErgoSumPortion *pErgo = new SwErgoSumPortion( rFootnoteInfo.aErgoSum,
1012 0 : lcl_GetPageNumber( pQuoPage ) );
1013 0 : return pErgo;
1014 : }
1015 :
1016 267 : sal_Int32 SwTextFormatter::FormatQuoVadis( const sal_Int32 nOffset )
1017 : {
1018 : OSL_ENSURE( ! pFrm->IsVertical() || ! pFrm->IsSwapped(),
1019 : "SwTextFormatter::FormatQuoVadis with swapped frame" );
1020 :
1021 267 : if( !pFrm->IsInFootnote() || pFrm->ImplFindFootnoteFrm()->GetAttr()->GetFootnote().IsEndNote() )
1022 52 : return nOffset;
1023 :
1024 215 : const SwFrm* pErgoFrm = pFrm->FindFootnoteFrm()->GetFollow();
1025 215 : if( !pErgoFrm && pFrm->HasFollow() )
1026 0 : pErgoFrm = pFrm->GetFollow();
1027 215 : if( !pErgoFrm )
1028 215 : return nOffset;
1029 :
1030 0 : if( pErgoFrm == pFrm->GetNext() )
1031 : {
1032 0 : SwFrm *pCol = pFrm->FindColFrm();
1033 0 : while( pCol && !pCol->GetNext() )
1034 0 : pCol = pCol->GetUpper()->FindColFrm();
1035 0 : if( pCol )
1036 0 : return nOffset;
1037 : }
1038 : else
1039 : {
1040 0 : const SwPageFrm* pPage = pFrm->FindPageFrm();
1041 0 : const SwPageFrm* pErgoPage = pErgoFrm->FindPageFrm();
1042 0 : if( pPage == pErgoPage )
1043 0 : return nOffset; // If the ErgoSum is on the same Page
1044 : }
1045 :
1046 0 : SwTextFormatInfo &rInf = GetInfo();
1047 0 : const SwFootnoteInfo &rFootnoteInfo = pFrm->GetNode()->GetDoc()->GetFootnoteInfo();
1048 0 : if( rFootnoteInfo.aQuoVadis.isEmpty() )
1049 0 : return nOffset;
1050 :
1051 : // A remark on QuoVadis/ErgoSum:
1052 : // We use the Font set for the Paragraph for these texts.
1053 : // Thus, we initialze:
1054 : // TODO: ResetFont();
1055 0 : FeedInf( rInf );
1056 0 : SeekStartAndChg( rInf, true );
1057 0 : if( GetRedln() && pCurr->HasRedline() )
1058 0 : GetRedln()->Seek( *pFnt, nOffset, 0 );
1059 :
1060 : // A tricky special case: Flyfrms extend into the Line and are at the
1061 : // position we want to insert the Quovadis text
1062 : // Let's see if it is that bad indeed:
1063 0 : SwLinePortion *pPor = pCurr->GetFirstPortion();
1064 0 : sal_uInt16 nLastLeft = 0;
1065 0 : while( pPor )
1066 : {
1067 0 : if ( pPor->IsFlyPortion() )
1068 0 : nLastLeft = static_cast<SwFlyPortion*>(pPor)->Fix() +
1069 0 : static_cast<SwFlyPortion*>(pPor)->Width();
1070 0 : pPor = pPor->GetPortion();
1071 : }
1072 :
1073 : // The old game all over again: we want the Line to wrap around
1074 : // at a certain point, so we adjust the width.
1075 : // nLastLeft is now basically the right margin
1076 0 : const sal_uInt16 nOldRealWidth = rInf.RealWidth();
1077 0 : rInf.RealWidth( nOldRealWidth - nLastLeft );
1078 :
1079 0 : OUString aErgo = lcl_GetPageNumber( pErgoFrm->FindPageFrm() );
1080 0 : SwQuoVadisPortion *pQuo = new SwQuoVadisPortion(rFootnoteInfo.aQuoVadis, aErgo );
1081 0 : pQuo->SetAscent( rInf.GetAscent() );
1082 0 : pQuo->Height( rInf.GetTextHeight() );
1083 0 : pQuo->Format( rInf );
1084 0 : sal_uInt16 nQuoWidth = pQuo->Width();
1085 0 : SwLinePortion* pCurrPor = pQuo;
1086 :
1087 0 : while ( rInf.GetRest() )
1088 : {
1089 0 : SwLinePortion* pFollow = rInf.GetRest();
1090 0 : rInf.SetRest( 0 );
1091 0 : pCurrPor->Move( rInf );
1092 :
1093 : OSL_ENSURE( pFollow->IsQuoVadisPortion(),
1094 : "Quo Vadis, rest of QuoVadisPortion" );
1095 :
1096 : // format the rest and append it to the other QuoVadis parts
1097 0 : pFollow->Format( rInf );
1098 0 : nQuoWidth = nQuoWidth + pFollow->Width();
1099 :
1100 0 : pCurrPor->Append( pFollow );
1101 0 : pCurrPor = pFollow;
1102 : }
1103 :
1104 0 : Right( Right() - nQuoWidth );
1105 :
1106 : sal_Int32 nRet;
1107 : {
1108 0 : SWAP_IF_NOT_SWAPPED swap(pFrm);
1109 :
1110 0 : nRet = FormatLine( nStart );
1111 : }
1112 :
1113 0 : Right( rInf.Left() + nOldRealWidth - 1 );
1114 :
1115 0 : nLastLeft = nOldRealWidth - pCurr->Width();
1116 0 : FeedInf( rInf );
1117 :
1118 : // It's possible that there's a Margin Portion at the end, which would
1119 : // just cause a lot of trouble, when respanning
1120 0 : pPor = pCurr->FindLastPortion();
1121 0 : SwGluePortion *pGlue = pPor->IsMarginPortion() ? static_cast<SwMarginPortion*>(pPor) : 0;
1122 0 : if( pGlue )
1123 : {
1124 0 : pGlue->Height( 0 );
1125 0 : pGlue->Width( 0 );
1126 0 : pGlue->SetLen( 0 );
1127 0 : pGlue->SetAscent( 0 );
1128 0 : pGlue->SetPortion( NULL );
1129 0 : pGlue->SetFixWidth(0);
1130 : }
1131 :
1132 : // Luxury: We make sure the QuoVadis text appears on the right, by
1133 : // using Glues.
1134 0 : nLastLeft = nLastLeft - nQuoWidth;
1135 0 : if( nLastLeft )
1136 : {
1137 0 : if( nLastLeft > pQuo->GetAscent() ) // Minimum distance
1138 : {
1139 0 : switch( GetAdjust() )
1140 : {
1141 : case SVX_ADJUST_BLOCK:
1142 : {
1143 0 : if( !pCurr->GetLen() ||
1144 0 : CH_BREAK != GetInfo().GetChar(nStart+pCurr->GetLen()-1))
1145 0 : nLastLeft = pQuo->GetAscent();
1146 0 : nQuoWidth = nQuoWidth + nLastLeft;
1147 0 : break;
1148 : }
1149 : case SVX_ADJUST_RIGHT:
1150 : {
1151 0 : nLastLeft = pQuo->GetAscent();
1152 0 : nQuoWidth = nQuoWidth + nLastLeft;
1153 0 : break;
1154 : }
1155 : case SVX_ADJUST_CENTER:
1156 : {
1157 0 : nQuoWidth = nQuoWidth + pQuo->GetAscent();
1158 0 : long nDiff = nLastLeft - nQuoWidth;
1159 0 : if( nDiff < 0 )
1160 : {
1161 0 : nLastLeft = pQuo->GetAscent();
1162 0 : nQuoWidth = (sal_uInt16)(-nDiff + nLastLeft);
1163 : }
1164 : else
1165 : {
1166 0 : nQuoWidth = 0;
1167 0 : nLastLeft = sal_uInt16(( pQuo->GetAscent() + nDiff ) / 2);
1168 : }
1169 0 : break;
1170 : }
1171 : default:
1172 0 : nQuoWidth = nQuoWidth + nLastLeft;
1173 : }
1174 : }
1175 : else
1176 0 : nQuoWidth = nQuoWidth + nLastLeft;
1177 0 : if( nLastLeft )
1178 : {
1179 0 : pGlue = new SwGluePortion(0);
1180 0 : pGlue->Width( nLastLeft );
1181 0 : pPor->Append( pGlue );
1182 0 : pPor = pPor->GetPortion();
1183 : }
1184 : }
1185 :
1186 : // Finally: we insert the QuoVadis Portion
1187 0 : pCurrPor = pQuo;
1188 0 : while ( pCurrPor )
1189 : {
1190 : // pPor->Append deletes the pPortion pointer of pPor.
1191 : // Therefore we have to keep a pointer to the next portion
1192 0 : pQuo = static_cast<SwQuoVadisPortion*>(pCurrPor->GetPortion());
1193 0 : pPor->Append( pCurrPor );
1194 0 : pPor = pPor->GetPortion();
1195 0 : pCurrPor = pQuo;
1196 : }
1197 :
1198 0 : pCurr->Width( pCurr->Width() + nQuoWidth );
1199 :
1200 : // And adjust again, due to the adjustment and due to the following special
1201 : // case:
1202 : // The DummyUser has set a smaller Font in the Line than the one used
1203 : // by the QuoVadis text ...
1204 0 : CalcAdjustLine( pCurr );
1205 :
1206 0 : return nRet;
1207 : }
1208 :
1209 : /**
1210 : * This function creates a Line that reaches to the other Page Margin.
1211 : * DummyLines or DummyPortions make sure, that osicllations stop, because
1212 : * there's no way to flow back.
1213 : * They are used for Footnotes in paragraph-bound Frames and for Footnote
1214 : * oscillations
1215 : */
1216 0 : void SwTextFormatter::MakeDummyLine()
1217 : {
1218 0 : sal_uInt16 nRstHeight = GetFrmRstHeight();
1219 0 : if( pCurr && nRstHeight > pCurr->Height() )
1220 : {
1221 0 : SwLineLayout *pLay = new SwLineLayout;
1222 0 : nRstHeight = nRstHeight - pCurr->Height();
1223 0 : pLay->Height( nRstHeight );
1224 0 : pLay->SetAscent( nRstHeight );
1225 0 : Insert( pLay );
1226 0 : Next();
1227 : }
1228 0 : }
1229 :
1230 : class SwFootnoteSave
1231 : {
1232 : SwTextSizeInfo *pInf;
1233 : SwFont *pFnt;
1234 : SwFont *pOld;
1235 : public:
1236 : SwFootnoteSave( const SwTextSizeInfo &rInf,
1237 : const SwTextFootnote *pTextFootnote,
1238 : const bool bApplyGivenScriptType,
1239 : const sal_uInt8 nGivenScriptType );
1240 : ~SwFootnoteSave();
1241 : };
1242 :
1243 294 : SwFootnoteSave::SwFootnoteSave( const SwTextSizeInfo &rInf,
1244 : const SwTextFootnote* pTextFootnote,
1245 : const bool bApplyGivenScriptType,
1246 : const sal_uInt8 nGivenScriptType )
1247 : : pInf( &((SwTextSizeInfo&)rInf) )
1248 : , pFnt( 0 )
1249 294 : , pOld( 0 )
1250 : {
1251 294 : if( pTextFootnote && rInf.GetTextFrm() )
1252 : {
1253 294 : pFnt = ((SwTextSizeInfo&)rInf).GetFont();
1254 294 : pOld = new SwFont( *pFnt );
1255 294 : pOld->GetTox() = pFnt->GetTox();
1256 294 : pFnt->GetTox() = 0;
1257 294 : SwFormatFootnote& rFootnote = (SwFormatFootnote&)pTextFootnote->GetFootnote();
1258 294 : const SwDoc *pDoc = rInf.GetTextFrm()->GetNode()->GetDoc();
1259 :
1260 : // #i98418#
1261 294 : if ( bApplyGivenScriptType )
1262 : {
1263 294 : pFnt->SetActual( nGivenScriptType );
1264 : }
1265 : else
1266 : {
1267 : // examine text and set script
1268 0 : OUString aTmpStr( rFootnote.GetViewNumStr( *pDoc ) );
1269 0 : pFnt->SetActual( SwScriptInfo::WhichFont( 0, &aTmpStr, 0 ) );
1270 : }
1271 :
1272 : const SwEndNoteInfo* pInfo;
1273 294 : if( rFootnote.IsEndNote() )
1274 54 : pInfo = &pDoc->GetEndNoteInfo();
1275 : else
1276 240 : pInfo = &pDoc->GetFootnoteInfo();
1277 294 : const SwAttrSet& rSet = pInfo->GetAnchorCharFormat((SwDoc&)*pDoc)->GetAttrSet();
1278 294 : pFnt->SetDiffFnt( &rSet, rInf.GetTextFrm()->GetNode()->getIDocumentSettingAccess() );
1279 :
1280 : // we reduce footnote size, if we are inside a double line portion
1281 294 : if ( ! pOld->GetEscapement() && 50 == pOld->GetPropr() )
1282 : {
1283 0 : Size aSize = pFnt->GetSize( pFnt->GetActual() );
1284 0 : pFnt->SetSize( Size( (long)aSize.Width() / 2,
1285 0 : (long)aSize.Height() / 2 ),
1286 0 : pFnt->GetActual() );
1287 : }
1288 :
1289 : // set the correct rotation at the footnote font
1290 : const SfxPoolItem* pItem;
1291 294 : if( SfxItemState::SET == rSet.GetItemState( RES_CHRATR_ROTATE,
1292 294 : true, &pItem ))
1293 0 : pFnt->SetVertical( static_cast<const SvxCharRotateItem*>(pItem)->GetValue(),
1294 0 : rInf.GetTextFrm()->IsVertical() );
1295 :
1296 294 : pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
1297 :
1298 294 : if( SfxItemState::SET == rSet.GetItemState( RES_CHRATR_BACKGROUND,
1299 294 : true, &pItem ))
1300 0 : pFnt->SetBackColor( new Color( static_cast<const SvxBrushItem*>(pItem)->GetColor() ) );
1301 : }
1302 : else
1303 0 : pFnt = NULL;
1304 294 : }
1305 :
1306 294 : SwFootnoteSave::~SwFootnoteSave()
1307 : {
1308 294 : if( pFnt )
1309 : {
1310 : // Put back SwFont
1311 294 : *pFnt = *pOld;
1312 294 : pFnt->GetTox() = pOld->GetTox();
1313 294 : pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
1314 294 : delete pOld;
1315 : }
1316 294 : }
1317 :
1318 145 : SwFootnotePortion::SwFootnotePortion( const OUString &rExpand,
1319 : SwTextFootnote *pFootn, sal_uInt16 nReal )
1320 : : SwFieldPortion( rExpand, 0 )
1321 : , pFootnote(pFootn)
1322 : , nOrigHeight( nReal )
1323 : // #i98418#
1324 : , mbPreferredScriptTypeSet( false )
1325 145 : , mnPreferredScriptType( SW_LATIN )
1326 : {
1327 145 : SetLen(1);
1328 145 : SetWhichPor( POR_FTN );
1329 145 : }
1330 :
1331 630 : bool SwFootnotePortion::GetExpText( const SwTextSizeInfo &, OUString &rText ) const
1332 : {
1333 630 : rText = aExpand;
1334 630 : return true;
1335 : }
1336 :
1337 145 : bool SwFootnotePortion::Format( SwTextFormatInfo &rInf )
1338 : {
1339 : // #i98418#
1340 : // SwFootnoteSave aFootnoteSave( rInf, pFootnote );
1341 145 : SwFootnoteSave aFootnoteSave( rInf, pFootnote, mbPreferredScriptTypeSet, mnPreferredScriptType );
1342 : // the idx is manipulated in SwExpandPortion::Format
1343 : // this flag indicates, that a footnote is allowed to trigger
1344 : // an underflow during SwTextGuess::Guess
1345 145 : rInf.SetFakeLineStart( rInf.GetIdx() > rInf.GetLineStart() );
1346 145 : const bool bFull = SwFieldPortion::Format( rInf );
1347 145 : rInf.SetFakeLineStart( false );
1348 145 : SetAscent( rInf.GetAscent() );
1349 145 : Height( rInf.GetTextHeight() );
1350 145 : rInf.SetFootnoteDone( !bFull );
1351 145 : if( !bFull )
1352 145 : rInf.SetParaFootnote();
1353 145 : return bFull;
1354 : }
1355 :
1356 149 : void SwFootnotePortion::Paint( const SwTextPaintInfo &rInf ) const
1357 : {
1358 : // #i98418#
1359 : // SwFootnoteSave aFootnoteSave( rInf, pFootnote );
1360 149 : SwFootnoteSave aFootnoteSave( rInf, pFootnote, mbPreferredScriptTypeSet, mnPreferredScriptType );
1361 149 : rInf.DrawViewOpt( *this, POR_FTN );
1362 149 : SwExpandPortion::Paint( rInf );
1363 149 : }
1364 :
1365 0 : SwPosSize SwFootnotePortion::GetTextSize( const SwTextSizeInfo &rInfo ) const
1366 : {
1367 : // #i98418#
1368 : // SwFootnoteSave aFootnoteSave( rInfo, pFootnote );
1369 0 : SwFootnoteSave aFootnoteSave( rInfo, pFootnote, mbPreferredScriptTypeSet, mnPreferredScriptType );
1370 0 : return SwExpandPortion::GetTextSize( rInfo );
1371 : }
1372 :
1373 : // #i98418#
1374 145 : void SwFootnotePortion::SetPreferredScriptType( sal_uInt8 nPreferredScriptType )
1375 : {
1376 145 : mbPreferredScriptTypeSet = true;
1377 145 : mnPreferredScriptType = nPreferredScriptType;
1378 145 : }
1379 :
1380 0 : SwFieldPortion *SwQuoVadisPortion::Clone( const OUString &rExpand ) const
1381 : {
1382 0 : return new SwQuoVadisPortion( rExpand, aErgo );
1383 : }
1384 :
1385 0 : SwQuoVadisPortion::SwQuoVadisPortion( const OUString &rExp, const OUString& rStr )
1386 0 : : SwFieldPortion( rExp ), aErgo(rStr)
1387 : {
1388 0 : SetLen(0);
1389 0 : SetWhichPor( POR_QUOVADIS );
1390 0 : }
1391 :
1392 0 : bool SwQuoVadisPortion::Format( SwTextFormatInfo &rInf )
1393 : {
1394 : // First try; maybe the Text fits
1395 0 : CheckScript( rInf );
1396 0 : bool bFull = SwFieldPortion::Format( rInf );
1397 0 : SetLen( 0 );
1398 :
1399 0 : if( bFull )
1400 : {
1401 : // Second try; we make the String shorter
1402 0 : aExpand = "...";
1403 0 : bFull = SwFieldPortion::Format( rInf );
1404 0 : SetLen( 0 );
1405 0 : if( bFull )
1406 : // Third try; we're done: we crush
1407 0 : Width( sal_uInt16(rInf.Width() - rInf.X()) );
1408 :
1409 : // No multiline Fields for QuoVadis and ErgoSum
1410 0 : if( rInf.GetRest() )
1411 : {
1412 0 : delete rInf.GetRest();
1413 0 : rInf.SetRest( 0 );
1414 : }
1415 : }
1416 0 : return bFull;
1417 : }
1418 :
1419 0 : bool SwQuoVadisPortion::GetExpText( const SwTextSizeInfo &, OUString &rText ) const
1420 : {
1421 0 : rText = aExpand;
1422 : // if this QuoVadisPortion has a follow, the follow is responsible for
1423 : // the ergo text.
1424 0 : if ( ! HasFollow() )
1425 0 : rText += aErgo;
1426 0 : return true;
1427 : }
1428 :
1429 0 : void SwQuoVadisPortion::HandlePortion( SwPortionHandler& rPH ) const
1430 : {
1431 0 : rPH.Special( GetLen(), aExpand + aErgo, GetWhichPor() );
1432 0 : }
1433 :
1434 0 : void SwQuoVadisPortion::Paint( const SwTextPaintInfo &rInf ) const
1435 : {
1436 : // We _always_ want to ouput per DrawStretchText, because nErgo
1437 : // can quickly switch
1438 0 : if( PrtWidth() )
1439 : {
1440 0 : rInf.DrawViewOpt( *this, POR_QUOVADIS );
1441 0 : SwTextSlot aDiffText( &rInf, this, true, false );
1442 0 : SwFontSave aSave( rInf, pFnt );
1443 0 : rInf.DrawText( *this, rInf.GetLen(), true );
1444 : }
1445 0 : }
1446 :
1447 0 : SwFieldPortion *SwErgoSumPortion::Clone( const OUString &rExpand ) const
1448 : {
1449 0 : return new SwErgoSumPortion( rExpand, OUString() );
1450 : }
1451 :
1452 0 : SwErgoSumPortion::SwErgoSumPortion(const OUString &rExp, const OUString& rStr)
1453 0 : : SwFieldPortion( rExp )
1454 : {
1455 0 : SetLen(0);
1456 0 : aExpand += rStr;
1457 :
1458 : // One blank distance to the text
1459 0 : aExpand += " ";
1460 0 : SetWhichPor( POR_ERGOSUM );
1461 0 : }
1462 :
1463 0 : sal_Int32 SwErgoSumPortion::GetCrsrOfst( const sal_uInt16 ) const
1464 : {
1465 0 : return 0;
1466 : }
1467 :
1468 0 : bool SwErgoSumPortion::Format( SwTextFormatInfo &rInf )
1469 : {
1470 0 : const bool bFull = SwFieldPortion::Format( rInf );
1471 0 : SetLen( 0 );
1472 0 : rInf.SetErgoDone( true );
1473 :
1474 : // No multiline Fields for QuoVadis and ErgoSum
1475 0 : if( bFull && rInf.GetRest() )
1476 : {
1477 0 : delete rInf.GetRest();
1478 0 : rInf.SetRest( 0 );
1479 : }
1480 :
1481 : // We return false in order to get some text into the current line,
1482 : // even if it's full (better than looping)
1483 0 : return false;
1484 : }
1485 :
1486 0 : void SwParaPortion::SetErgoSumNum( const OUString& rErgo )
1487 : {
1488 0 : SwLineLayout *pLay = this;
1489 0 : while( pLay->GetNext() )
1490 : {
1491 0 : pLay = pLay->GetNext();
1492 : }
1493 0 : SwLinePortion *pPor = pLay;
1494 0 : SwQuoVadisPortion *pQuo = 0;
1495 0 : while( pPor && !pQuo )
1496 : {
1497 0 : if ( pPor->IsQuoVadisPortion() )
1498 0 : pQuo = static_cast<SwQuoVadisPortion*>(pPor);
1499 0 : pPor = pPor->GetPortion();
1500 : }
1501 0 : if( pQuo )
1502 0 : pQuo->SetNumber( rErgo );
1503 0 : }
1504 :
1505 : /**
1506 : * Is called in SwTextFrm::Prepare()
1507 : */
1508 27 : bool SwParaPortion::UpdateQuoVadis( const OUString &rQuo )
1509 : {
1510 27 : SwLineLayout *pLay = this;
1511 54 : while( pLay->GetNext() )
1512 : {
1513 0 : pLay = pLay->GetNext();
1514 : }
1515 27 : SwLinePortion *pPor = pLay;
1516 27 : SwQuoVadisPortion *pQuo = 0;
1517 112 : while( pPor && !pQuo )
1518 : {
1519 58 : if ( pPor->IsQuoVadisPortion() )
1520 0 : pQuo = static_cast<SwQuoVadisPortion*>(pPor);
1521 58 : pPor = pPor->GetPortion();
1522 : }
1523 :
1524 27 : if( !pQuo )
1525 27 : return false;
1526 :
1527 0 : return pQuo->GetQuoText() == rQuo;
1528 177 : }
1529 :
1530 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|