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 454 : bool SwTxtFrm::_IsFtnNumFrm() const
59 : {
60 454 : const SwFtnFrm* pFtn = FindFtnFrm()->GetMaster();
61 908 : while( pFtn && !pFtn->ContainsCntnt() )
62 0 : pFtn = pFtn->GetMaster();
63 454 : return !pFtn;
64 : }
65 :
66 : // Sucht innerhalb einer Master-Follow-Kette den richtigen TxtFrm zum SwTxtFtn
67 556 : SwTxtFrm *SwTxtFrm::FindFtnRef( const SwTxtFtn *pFtn )
68 : {
69 556 : SwTxtFrm *pFrm = this;
70 556 : const bool bFwd = pFtn->GetStart() >= GetOfst();
71 1286 : while( pFrm )
72 : {
73 556 : if( SwFtnBossFrm::FindFtn( pFrm, pFtn ) )
74 382 : return pFrm;
75 : pFrm = bFwd ? pFrm->GetFollow() :
76 174 : pFrm->IsFollow() ? pFrm->FindMaster() : 0;
77 : }
78 174 : return pFrm;
79 : }
80 :
81 : #ifdef DBG_UTIL
82 : void SwTxtFrm::CalcFtnFlag( sal_Int32 nStop )// For testing the SplitFrm
83 : #else
84 40216 : void SwTxtFrm::CalcFtnFlag()
85 : #endif
86 : {
87 40216 : bFtn = false;
88 :
89 40216 : const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
90 40216 : if( !pHints )
91 43630 : return;
92 :
93 36802 : const size_t nSize = pHints->Count();
94 :
95 : #ifdef DBG_UTIL
96 : const sal_Int32 nEnd = nStop != COMPLETE_STRING ? nStop
97 : : GetFollow() ? GetFollow()->GetOfst() : COMPLETE_STRING;
98 : #else
99 36802 : const sal_Int32 nEnd = GetFollow() ? GetFollow()->GetOfst() : COMPLETE_STRING;
100 : #endif
101 :
102 118293 : for ( size_t i = 0; i < nSize; ++i )
103 : {
104 81761 : const SwTxtAttr *pHt = (*pHints)[i];
105 81761 : if ( pHt->Which() == RES_TXTATR_FTN )
106 : {
107 270 : const sal_Int32 nIdx = pHt->GetStart();
108 270 : if ( nEnd < nIdx )
109 0 : break;
110 270 : if( GetOfst() <= nIdx )
111 : {
112 270 : bFtn = true;
113 270 : break;
114 : }
115 : }
116 : }
117 : }
118 :
119 32 : bool SwTxtFrm::CalcPrepFtnAdjust()
120 : {
121 : OSL_ENSURE( HasFtn(), "Wer ruft mich da?" );
122 32 : SwFtnBossFrm *pBoss = FindFtnBossFrm( true );
123 32 : const SwFtnFrm *pFtn = pBoss->FindFirstFtn( this );
124 88 : if( pFtn && FTNPOS_CHAPTER != GetNode()->GetDoc()->GetFtnInfo().ePos &&
125 34 : ( !pBoss->GetUpper()->IsSctFrm() ||
126 6 : !((SwSectionFrm*)pBoss->GetUpper())->IsFtnAtEnd() ) )
127 : {
128 28 : const SwFtnContFrm *pCont = pBoss->FindFtnCont();
129 28 : bool bReArrange = true;
130 :
131 28 : SWRECTFN( this )
132 112 : if ( pCont && (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
133 84 : (Frm().*fnRect->fnGetBottom)() ) > 0 )
134 : {
135 56 : pBoss->RearrangeFtns( (Frm().*fnRect->fnGetBottom)(), false,
136 84 : pFtn->GetAttr() );
137 28 : ValidateBodyFrm();
138 28 : ValidateFrm();
139 28 : pFtn = pBoss->FindFirstFtn( this );
140 : }
141 : else
142 0 : bReArrange = false;
143 28 : if( !pCont || !pFtn || bReArrange != (pFtn->FindFtnBossFrm() == pBoss) )
144 : {
145 4 : SwTxtFormatInfo aInf( this );
146 8 : SwTxtFormatter aLine( this, &aInf );
147 4 : aLine.TruncLines();
148 4 : SetPara( 0 ); //Wird ggf. geloescht!
149 4 : ResetPreps();
150 8 : return false;
151 : }
152 : }
153 28 : return true;
154 : }
155 :
156 : // Local helper function. Checks if nLower should be taken as the boundary
157 : // for the footnote.
158 522 : static SwTwips lcl_GetFtnLower( const SwTxtFrm* pFrm, SwTwips nLower )
159 : {
160 : // nLower is an absolute value. It denotes the bottom of the line
161 : // containing the footnote.
162 522 : SWRECTFN( pFrm )
163 :
164 : OSL_ENSURE( !pFrm->IsVertical() || !pFrm->IsSwapped(),
165 : "lcl_GetFtnLower with swapped frame" );
166 :
167 : SwTwips nAdd;
168 522 : SwTwips nRet = nLower;
169 :
170 : // Check if text is inside a table.
171 522 : if ( pFrm->IsInTab() )
172 : {
173 : // If pFrm is inside a table, we have to check if
174 : // a) The table is not allowed to split or
175 : // b) The table row is not allowed to split
176 :
177 : // Inside a table, there are no footnotes,
178 : // see SwFrm::FindFtnBossFrm. So we don't have to check
179 : // the case that pFrm is inside a (footnote collecting) section
180 : // within the table.
181 2 : const SwFrm* pRow = pFrm;
182 8 : while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
183 4 : pRow = pRow->GetUpper();
184 2 : const SwTabFrm* pTabFrm = (SwTabFrm*)pRow->GetUpper();
185 :
186 : OSL_ENSURE( pTabFrm && pRow &&
187 : pRow->GetUpper()->IsTabFrm(), "Upper of row should be tab" );
188 :
189 4 : const bool bDontSplit = !pTabFrm->IsFollow() &&
190 4 : !pTabFrm->IsLayoutSplitAllowed();
191 :
192 2 : SwTwips nMin = 0;
193 2 : if ( bDontSplit )
194 0 : nMin = (pTabFrm->Frm().*fnRect->fnGetBottom)();
195 2 : else if ( !((SwRowFrm*)pRow)->IsRowSplitAllowed() )
196 0 : nMin = (pRow->Frm().*fnRect->fnGetBottom)();
197 :
198 2 : if ( nMin && (*fnRect->fnYDiff)( nMin, nLower ) > 0 )
199 0 : nRet = nMin;
200 :
201 2 : nAdd = (pRow->GetUpper()->*fnRect->fnGetBottomMargin)();
202 : }
203 : else
204 520 : nAdd = (pFrm->*fnRect->fnGetBottomMargin)();
205 :
206 522 : if( nAdd > 0 )
207 : {
208 0 : if ( bVert )
209 0 : nRet -= nAdd;
210 : else
211 0 : nRet += nAdd;
212 : }
213 :
214 : // #i10770#: If there are fly frames anchored at previous paragraphs,
215 : // the deadline should consider their lower borders.
216 522 : const SwFrm* pStartFrm = pFrm->GetUpper()->GetLower();
217 : OSL_ENSURE( pStartFrm, "Upper has no lower" );
218 522 : SwTwips nFlyLower = bVert ? LONG_MAX : 0;
219 1652 : while ( pStartFrm != pFrm )
220 : {
221 : OSL_ENSURE( pStartFrm, "Frame chain is broken" );
222 608 : if ( pStartFrm->GetDrawObjs() )
223 : {
224 0 : const SwSortedObjs &rObjs = *pStartFrm->GetDrawObjs();
225 0 : for ( size_t i = 0; i < rObjs.size(); ++i )
226 : {
227 0 : SwAnchoredObject* pAnchoredObj = rObjs[i];
228 0 : SwRect aRect( pAnchoredObj->GetObjRect() );
229 :
230 0 : if ( !pAnchoredObj->ISA(SwFlyFrm) ||
231 0 : static_cast<SwFlyFrm*>(pAnchoredObj)->IsValid() )
232 : {
233 0 : const SwTwips nBottom = (aRect.*fnRect->fnGetBottom)();
234 0 : if ( (*fnRect->fnYDiff)( nBottom, nFlyLower ) > 0 )
235 0 : nFlyLower = nBottom;
236 : }
237 : }
238 : }
239 :
240 608 : pStartFrm = pStartFrm->GetNext();
241 : }
242 :
243 522 : if ( bVert )
244 0 : nRet = std::min( nRet, nFlyLower );
245 : else
246 522 : nRet = std::max( nRet, nFlyLower );
247 :
248 522 : return nRet;
249 : }
250 :
251 244 : SwTwips SwTxtFrm::GetFtnLine( const SwTxtFtn *pFtn ) const
252 : {
253 : OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
254 : "SwTxtFrm::GetFtnLine with swapped frame" );
255 :
256 244 : SwTxtFrm *pThis = (SwTxtFrm*)this;
257 :
258 244 : if( !HasPara() )
259 : {
260 : // #109071# GetFormatted() does not work here, bacause most probably
261 : // the frame is currently locked. We return the previous value.
262 0 : return pThis->mnFtnLine > 0 ?
263 : pThis->mnFtnLine :
264 0 : IsVertical() ? Frm().Left() : Frm().Bottom();
265 : }
266 :
267 244 : SWAP_IF_NOT_SWAPPED( this )
268 :
269 244 : SwTxtInfo aInf( pThis );
270 244 : SwTxtIter aLine( pThis, &aInf );
271 244 : const sal_Int32 nPos = pFtn->GetStart();
272 244 : aLine.CharToLine( nPos );
273 :
274 244 : SwTwips nRet = aLine.Y() + SwTwips(aLine.GetLineHeight());
275 244 : if( IsVertical() )
276 0 : nRet = SwitchHorizontalToVertical( nRet );
277 :
278 244 : UNDO_SWAP( this )
279 :
280 244 : nRet = lcl_GetFtnLower( pThis, nRet );
281 :
282 244 : pThis->mnFtnLine = nRet;
283 244 : return nRet;
284 : }
285 :
286 : // Ermittelt die max. erreichbare Hoehe des TxtFrm im Ftn-Bereich.
287 : // Sie wird eingeschraenkt durch den unteren Rand der Zeile mit
288 : // der Ftn-Referenz.
289 510 : SwTwips SwTxtFrm::_GetFtnFrmHeight() const
290 : {
291 : OSL_ENSURE( !IsFollow() && IsInFtn(), "SwTxtFrm::SetFtnLine: moon walk" );
292 :
293 510 : const SwFtnFrm *pFtnFrm = FindFtnFrm();
294 510 : const SwTxtFrm *pRef = (const SwTxtFrm *)pFtnFrm->GetRef();
295 510 : const SwFtnBossFrm *pBoss = FindFtnBossFrm();
296 1020 : if( pBoss != pRef->FindFtnBossFrm( !pFtnFrm->GetAttr()->
297 510 : GetFtn().IsEndNote() ) )
298 54 : return 0;
299 :
300 456 : SWAP_IF_SWAPPED( this )
301 :
302 456 : SwTwips nHeight = pRef->IsInFtnConnect() ?
303 456 : 1 : pRef->GetFtnLine( pFtnFrm->GetAttr() );
304 456 : if( nHeight )
305 : {
306 : // So komisch es aussehen mag: Die erste Ftn auf der Seite darf sich
307 : // nicht mit der Ftn-Referenz beruehren, wenn wir im Ftn-Bereich Text
308 : // eingeben.
309 456 : const SwFrm *pCont = pFtnFrm->GetUpper();
310 : //Hoehe innerhalb des Cont, die ich mir 'eh noch genehmigen darf.
311 456 : SWRECTFN( pCont )
312 912 : SwTwips nTmp = (*fnRect->fnYDiff)( (pCont->*fnRect->fnGetPrtBottom)(),
313 1368 : (Frm().*fnRect->fnGetTop)() );
314 :
315 : #if OSL_DEBUG_LEVEL > 0
316 : if( nTmp < 0 )
317 : {
318 : bool bInvalidPos = false;
319 : const SwLayoutFrm* pTmp = GetUpper();
320 : while( !bInvalidPos && pTmp )
321 : {
322 : bInvalidPos = !pTmp->GetValidPosFlag() ||
323 : !pTmp->Lower()->GetValidPosFlag();
324 : if( pTmp == pCont )
325 : break;
326 : pTmp = pTmp->GetUpper();
327 : }
328 : OSL_ENSURE( bInvalidPos, "Hanging below FtnCont" );
329 : }
330 : #endif
331 :
332 456 : if ( (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight) > 0 )
333 : {
334 : //Wachstumspotential den Containers.
335 456 : if ( !pRef->IsInFtnConnect() )
336 : {
337 120 : SwSaveFtnHeight aSave( (SwFtnBossFrm*)pBoss, nHeight );
338 120 : nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, true );
339 : }
340 : else
341 336 : nHeight = ((SwFtnContFrm*)pCont)->Grow( LONG_MAX, true );
342 :
343 456 : nHeight += nTmp;
344 456 : if( nHeight < 0 )
345 0 : nHeight = 0;
346 : }
347 : else
348 : { // The container has to shrink
349 0 : nTmp += (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(), nHeight);
350 0 : if( nTmp > 0 )
351 0 : nHeight = nTmp;
352 : else
353 0 : nHeight = 0;
354 : }
355 : }
356 :
357 456 : UNDO_SWAP( this )
358 :
359 456 : return nHeight;
360 : }
361 :
362 200 : SwTxtFrm *SwTxtFrm::FindQuoVadisFrm()
363 : {
364 : // Erstmal feststellen, ob wir in einem FtnFrm stehen:
365 200 : if( GetIndPrev() || !IsInFtn() )
366 0 : return 0;
367 :
368 : // Zum Vorgaenger-FtnFrm
369 200 : SwFtnFrm *pFtnFrm = FindFtnFrm()->GetMaster();
370 200 : if( !pFtnFrm )
371 200 : return 0;
372 :
373 : // Nun den letzten Cntnt:
374 0 : const SwCntntFrm *pCnt = pFtnFrm->ContainsCntnt();
375 0 : if( !pCnt )
376 0 : return NULL;
377 : const SwCntntFrm *pLast;
378 0 : do
379 0 : { pLast = pCnt;
380 0 : pCnt = pCnt->GetNextCntntFrm();
381 0 : } while( pCnt && pFtnFrm->IsAnLower( pCnt ) );
382 0 : return (SwTxtFrm*)pLast;
383 : }
384 :
385 49520 : void SwTxtFrm::RemoveFtn( const sal_Int32 nStart, const sal_Int32 nLen )
386 : {
387 49520 : if ( !IsFtnAllowed() )
388 13254 : return;
389 :
390 36266 : SwpHints *pHints = GetTxtNode()->GetpSwpHints();
391 36266 : if( !pHints )
392 376 : return;
393 :
394 35890 : bool bRollBack = nLen != COMPLETE_STRING;
395 35890 : const size_t nSize = pHints->Count();
396 : sal_Int32 nEnd;
397 : SwTxtFrm* pSource;
398 35890 : if( bRollBack )
399 : {
400 190 : nEnd = nStart + nLen;
401 190 : pSource = GetFollow();
402 190 : if( !pSource )
403 0 : return;
404 : }
405 : else
406 : {
407 35700 : nEnd = COMPLETE_STRING;
408 35700 : pSource = this;
409 : }
410 :
411 35890 : if( nSize )
412 : {
413 35886 : SwPageFrm* pUpdate = NULL;
414 35886 : bool bRemove = false;
415 35886 : SwFtnBossFrm *pFtnBoss = 0;
416 35886 : SwFtnBossFrm *pEndBoss = 0;
417 : bool bFtnEndDoc
418 35886 : = FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos;
419 151313 : for ( size_t i = nSize; i; )
420 : {
421 79793 : SwTxtAttr *pHt = pHints->GetTextHint(--i);
422 79793 : if ( RES_TXTATR_FTN != pHt->Which() )
423 79541 : continue;
424 :
425 252 : const sal_Int32 nIdx = pHt->GetStart();
426 252 : if( nStart > nIdx )
427 252 : break;
428 :
429 0 : if( nEnd >= nIdx )
430 : {
431 0 : SwTxtFtn *pFtn = (SwTxtFtn*)pHt;
432 0 : const bool bEndn = pFtn->GetFtn().IsEndNote();
433 :
434 0 : if( bEndn )
435 : {
436 0 : if( !pEndBoss )
437 0 : pEndBoss = pSource->FindFtnBossFrm();
438 : }
439 : else
440 : {
441 0 : if( !pFtnBoss )
442 : {
443 0 : pFtnBoss = pSource->FindFtnBossFrm( true );
444 0 : if( pFtnBoss->GetUpper()->IsSctFrm() )
445 : {
446 : SwSectionFrm* pSect = (SwSectionFrm*)
447 0 : pFtnBoss->GetUpper();
448 0 : if( pSect->IsFtnAtEnd() )
449 0 : bFtnEndDoc = false;
450 : }
451 : }
452 : }
453 :
454 : // Wir loeschen nicht, sondern wollen die Ftn verschieben.
455 : // Drei Faelle koennen auftreten:
456 : // 1) Es gibt weder Follow noch PrevFollow
457 : // -> RemoveFtn() (vielleicht sogar ein OSL_ENSURE(wert)
458 : // 2) nStart > GetOfst, ich habe einen Follow
459 : // -> Ftn wandert in den Follow
460 : // 3) nStart < GetOfst, ich bin ein Follow
461 : // -> Ftn wandert in den PrevFollow
462 : // beide muessen auf einer Seite/in einer Spalte stehen.
463 :
464 0 : SwFtnFrm *pFtnFrm = SwFtnBossFrm::FindFtn(pSource, pFtn);
465 :
466 0 : if( pFtnFrm )
467 : {
468 0 : const bool bEndDoc = bEndn || bFtnEndDoc;
469 0 : if( bRollBack )
470 : {
471 0 : while ( pFtnFrm )
472 : {
473 0 : pFtnFrm->SetRef( this );
474 0 : pFtnFrm = pFtnFrm->GetFollow();
475 0 : SetFtn( true );
476 : }
477 : }
478 0 : else if( GetFollow() )
479 : {
480 0 : SwCntntFrm *pDest = GetFollow();
481 0 : while( pDest->GetFollow() && ((SwTxtFrm*)pDest->
482 0 : GetFollow())->GetOfst() <= nIdx )
483 0 : pDest = pDest->GetFollow();
484 : OSL_ENSURE( !SwFtnBossFrm::FindFtn(
485 : pDest,pFtn),"SwTxtFrm::RemoveFtn: footnote exists");
486 :
487 : //Nicht ummelden sondern immer Moven.
488 : // OD 08.11.2002 #104840# - use <SwlayoutFrm::IsBefore(::)>
489 0 : if ( bEndDoc ||
490 0 : !pFtnFrm->FindFtnBossFrm()->IsBefore( pDest->FindFtnBossFrm( !bEndn ) )
491 : )
492 : {
493 0 : SwPageFrm* pTmp = pFtnFrm->FindPageFrm();
494 0 : if( pUpdate && pUpdate != pTmp )
495 0 : pUpdate->UpdateFtnNum();
496 0 : pUpdate = pTmp;
497 0 : while ( pFtnFrm )
498 : {
499 0 : pFtnFrm->SetRef( pDest );
500 0 : pFtnFrm = pFtnFrm->GetFollow();
501 : }
502 : }
503 : else
504 : {
505 0 : pFtnBoss->MoveFtns( this, pDest, pFtn );
506 0 : bRemove = true;
507 : }
508 0 : ((SwTxtFrm*)pDest)->SetFtn( true );
509 :
510 : OSL_ENSURE( SwFtnBossFrm::FindFtn( pDest,
511 : pFtn),"SwTxtFrm::RemoveFtn: footnote ChgRef failed");
512 : }
513 : else
514 : {
515 0 : if( !bEndDoc || ( bEndn && pEndBoss->IsInSct() &&
516 0 : !SwLayouter::Collecting( GetNode()->GetDoc(),
517 0 : pEndBoss->FindSctFrm(), NULL ) ) )
518 : {
519 0 : if( bEndn )
520 0 : pEndBoss->RemoveFtn( this, pFtn );
521 : else
522 0 : pFtnBoss->RemoveFtn( this, pFtn );
523 0 : bRemove = bRemove || !bEndDoc;
524 : OSL_ENSURE( bEndn ? !SwFtnBossFrm::FindFtn( this, pFtn ) :
525 : !SwFtnBossFrm::FindFtn( this, pFtn ),
526 : "SwTxtFrm::RemoveFtn: can't get off that footnote" );
527 : }
528 : }
529 : }
530 : }
531 : }
532 35886 : if( pUpdate )
533 0 : pUpdate->UpdateFtnNum();
534 : // Wir bringen die Oszillation zum stehen:
535 35886 : if( bRemove && !bFtnEndDoc && HasPara() )
536 : {
537 0 : ValidateBodyFrm();
538 0 : ValidateFrm();
539 : }
540 : }
541 : // Folgendes Problem: Aus dem FindBreak heraus wird das RemoveFtn aufgerufen,
542 : // weil die letzte Zeile an den Follow abgegeben werden soll. Der Offset
543 : // des Follows ist aber veraltet, er wird demnaechst gesetzt. CalcFntFlag ist
544 : // auf einen richtigen Follow-Offset angewiesen. Deshalb wird hier kurzfristig
545 : // der Follow-Offset manipuliert.
546 35890 : sal_Int32 nOldOfst = COMPLETE_STRING;
547 35890 : if( HasFollow() && nStart > GetOfst() )
548 : {
549 1472 : nOldOfst = GetFollow()->GetOfst();
550 1472 : GetFollow()->ManipOfst( nStart + ( bRollBack ? nLen : 0 ) );
551 : }
552 35890 : pSource->CalcFtnFlag();
553 35890 : if( nOldOfst < COMPLETE_STRING )
554 1472 : GetFollow()->ManipOfst( nOldOfst );
555 : }
556 :
557 : // false, wenn irgendetwas schief gegangen ist.
558 : // Es gibt eigentlich nur zwei Moeglichkeiten:
559 : // a) Die Ftn ist bereits vorhanden
560 : // => dann wird sie gemoved, wenn ein anderer pSrcFrm gefunden wurde
561 : // b) Die Ftn ist nicht vorhanden
562 : // => dann wird sie fuer uns angelegt.
563 : // Ob die Ftn schliesslich auf unserer Spalte/Seite landet oder nicht,
564 : // spielt in diesem Zusammenhang keine Rolle.
565 : // Optimierungen bei Endnoten.
566 : // Noch ein Problem: wenn die Deadline im Ftn-Bereich liegt, muss die
567 : // Ftn verschoben werden.
568 278 : void SwTxtFrm::ConnectFtn( SwTxtFtn *pFtn, const SwTwips nDeadLine )
569 : {
570 : OSL_ENSURE( !IsVertical() || !IsSwapped(),
571 : "SwTxtFrm::ConnectFtn with swapped frame" );
572 :
573 278 : bFtn = true;
574 278 : bInFtnConnect = true; //Bloss zuruecksetzen!
575 278 : const bool bEnd = pFtn->GetFtn().IsEndNote();
576 :
577 : // We want to store this value, because it is needed as a fallback
578 : // in GetFtnLine(), if there is no paragraph information available
579 278 : mnFtnLine = nDeadLine;
580 :
581 : // Wir brauchen immer einen Boss (Spalte/Seite)
582 : SwSectionFrm *pSect;
583 278 : SwCntntFrm *pCntnt = this;
584 278 : if( bEnd && IsInSct() )
585 : {
586 34 : pSect = FindSctFrm();
587 34 : if( pSect->IsEndnAtEnd() )
588 0 : pCntnt = pSect->FindLastCntnt( FINDMODE_ENDNOTE );
589 34 : if( !pCntnt )
590 0 : pCntnt = this;
591 : }
592 :
593 278 : SwFtnBossFrm *pBoss = pCntnt->FindFtnBossFrm( !bEnd );
594 :
595 : #if OSL_DEBUG_LEVEL > 1
596 : SwTwips nRstHeight = GetRstHeight();
597 : #endif
598 :
599 278 : pSect = pBoss->FindSctFrm();
600 80 : bool bDocEnd = bEnd ? !( pSect && pSect->IsEndnAtEnd() ) :
601 396 : ( !( pSect && pSect->IsFtnAtEnd() ) &&
602 754 : FTNPOS_CHAPTER == GetNode()->GetDoc()->GetFtnInfo().ePos );
603 : //Ftn kann beim Follow angemeldet sein.
604 278 : SwCntntFrm *pSrcFrm = FindFtnRef( pFtn );
605 :
606 278 : if( bDocEnd )
607 : {
608 82 : if( pSect && pSrcFrm )
609 : {
610 18 : SwFtnFrm *pFtnFrm = SwFtnBossFrm::FindFtn( pSrcFrm, pFtn );
611 18 : if( pFtnFrm && pFtnFrm->IsInSct() )
612 : {
613 0 : pBoss->RemoveFtn( pSrcFrm, pFtn );
614 0 : pSrcFrm = 0;
615 : }
616 : }
617 : }
618 196 : else if( bEnd && pSect )
619 : {
620 0 : SwFtnFrm *pFtnFrm = pSrcFrm ? SwFtnBossFrm::FindFtn( pSrcFrm, pFtn ) : NULL;
621 0 : if( pFtnFrm && !pFtnFrm->GetUpper() )
622 0 : pFtnFrm = NULL;
623 0 : SwDoc *pDoc = GetNode()->GetDoc();
624 0 : if( SwLayouter::Collecting( pDoc, pSect, pFtnFrm ) )
625 : {
626 0 : if( !pSrcFrm )
627 : {
628 0 : SwFtnFrm *pNew = new SwFtnFrm(pDoc->GetDfltFrmFmt(),this,this,pFtn);
629 0 : SwNodeIndex aIdx( *pFtn->GetStartNode(), 1 );
630 0 : ::_InsertCnt( pNew, pDoc, aIdx.GetIndex() );
631 0 : GetNode()->getIDocumentLayoutAccess()->GetLayouter()->CollectEndnote( pNew );
632 : }
633 0 : else if( pSrcFrm != this )
634 0 : pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
635 0 : bInFtnConnect = false;
636 0 : return;
637 : }
638 0 : else if( pSrcFrm )
639 : {
640 0 : SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
641 0 : if( !pFtnBoss->IsInSct() ||
642 0 : pFtnBoss->ImplFindSctFrm()->GetSection()!=pSect->GetSection() )
643 : {
644 0 : pBoss->RemoveFtn( pSrcFrm, pFtn );
645 0 : pSrcFrm = 0;
646 : }
647 : }
648 : }
649 :
650 278 : if( bDocEnd || bEnd )
651 : {
652 82 : if( !pSrcFrm )
653 38 : pBoss->AppendFtn( this, pFtn );
654 44 : else if( pSrcFrm != this )
655 0 : pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
656 82 : bInFtnConnect = false;
657 82 : return;
658 : }
659 :
660 196 : SwSaveFtnHeight aHeight( pBoss, nDeadLine );
661 :
662 196 : if( !pSrcFrm ) // Es wurde ueberhaupt keine Ftn gefunden.
663 136 : pBoss->AppendFtn( this, pFtn );
664 : else
665 : {
666 60 : SwFtnFrm *pFtnFrm = SwFtnBossFrm::FindFtn( pSrcFrm, pFtn );
667 60 : SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
668 :
669 60 : bool bBrutal = false;
670 :
671 60 : if( pFtnBoss == pBoss ) // Ref und Ftn sind auf der selben Seite/Spalte.
672 : {
673 56 : SwFrm *pCont = pFtnFrm->GetUpper();
674 :
675 56 : SWRECTFN ( pCont )
676 112 : long nDiff = (*fnRect->fnYDiff)( (pCont->Frm().*fnRect->fnGetTop)(),
677 168 : nDeadLine );
678 :
679 56 : if( nDiff >= 0 )
680 : {
681 : //Wenn die Fussnote bei einem Follow angemeldet ist, so ist
682 : //es jetzt an der Zeit sie umzumelden.
683 56 : if ( pSrcFrm != this )
684 0 : pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
685 : //Es steht Platz zur Verfuegung, also kann die Fussnote evtl.
686 : //wachsen.
687 56 : if ( pFtnFrm->GetFollow() && nDiff > 0 )
688 : {
689 0 : SwTwips nHeight = (pCont->Frm().*fnRect->fnGetHeight)();
690 0 : pBoss->RearrangeFtns( nDeadLine, false, pFtn );
691 0 : ValidateBodyFrm();
692 0 : ValidateFrm();
693 0 : SwViewShell *pSh = getRootFrm()->GetCurrShell();
694 0 : if ( pSh && nHeight == (pCont->Frm().*fnRect->fnGetHeight)() )
695 : //Damit uns nix durch die Lappen geht.
696 0 : pSh->InvalidateWindows( pCont->Frm() );
697 : }
698 56 : bInFtnConnect = false;
699 56 : return;
700 : }
701 : else
702 0 : bBrutal = true;
703 : }
704 : else
705 : {
706 : // Ref und Ftn sind nicht auf einer Seite, Move-Versuch ist noetig.
707 4 : SwFrm* pTmp = this;
708 8 : while( pTmp->GetNext() && pSrcFrm != pTmp )
709 0 : pTmp = pTmp->GetNext();
710 4 : if( pSrcFrm == pTmp )
711 4 : bBrutal = true;
712 : else
713 : { // Wenn unser Boss in einem spaltigen Bereich sitzt, es aber auf
714 : // der Seite schon einen FtnContainer gibt, hilft nur die brutale
715 : // Methode
716 0 : if( pSect && pSect->FindFtnBossFrm( !bEnd )->FindFtnCont() )
717 0 : bBrutal = true;
718 : // OD 08.11.2002 #104840# - use <SwLayoutFrm::IsBefore(..)>
719 0 : else if ( !pFtnFrm->GetPrev() ||
720 0 : pFtnBoss->IsBefore( pBoss )
721 : )
722 : {
723 0 : SwFtnBossFrm *pSrcBoss = pSrcFrm->FindFtnBossFrm( !bEnd );
724 0 : pSrcBoss->MoveFtns( pSrcFrm, this, pFtn );
725 : }
726 : else
727 0 : pBoss->ChangeFtnRef( pSrcFrm, pFtn, this );
728 : }
729 : }
730 :
731 : // Die brutale Loesung: Fussnote entfernen und appenden.
732 : // Es muss SetFtnDeadLine() gerufen werden, weil nach
733 : // RemoveFtn die nMaxFtnHeight evtl. besser auf unsere Wuensche
734 : // eingestellt werden kann.
735 4 : if( bBrutal )
736 : {
737 4 : pBoss->RemoveFtn( pSrcFrm, pFtn, false );
738 : SwSaveFtnHeight *pHeight = bEnd ? NULL :
739 4 : new SwSaveFtnHeight( pBoss, nDeadLine );
740 4 : pBoss->AppendFtn( this, pFtn );
741 4 : delete pHeight;
742 : }
743 : }
744 :
745 : // In spaltigen Bereichen, die noch nicht bis zum Seitenrand gehen,
746 : // ist kein RearrangeFtns sinnvoll, da der Fussnotencontainer noch
747 : // nicht kalkuliert worden ist.
748 140 : if( !pSect || !pSect->Growable() )
749 : {
750 : // Umgebung validieren, um Oszillationen zu verhindern.
751 140 : SwSaveFtnHeight aNochmal( pBoss, nDeadLine );
752 140 : ValidateBodyFrm();
753 140 : pBoss->RearrangeFtns( nDeadLine, true );
754 140 : ValidateFrm();
755 : }
756 0 : else if( pSect->IsFtnAtEnd() )
757 : {
758 0 : ValidateBodyFrm();
759 0 : ValidateFrm();
760 : }
761 :
762 : #if OSL_DEBUG_LEVEL > 1
763 : // pFtnFrm kann sich durch Calc veraendert haben ...
764 : SwFtnFrm *pFtnFrm = pBoss->FindFtn( this, pFtn );
765 : if( pFtnFrm && pBoss != pFtnFrm->FindFtnBossFrm( !bEnd ) )
766 : {
767 : int bla = 5;
768 : (void)bla;
769 : }
770 : nRstHeight = GetRstHeight();
771 : (void)nRstHeight;
772 : #endif
773 140 : bInFtnConnect = false;
774 140 : return;
775 : }
776 :
777 : // Die Portion fuer die Ftn-Referenz im Text
778 278 : SwFtnPortion *SwTxtFormatter::NewFtnPortion( SwTxtFormatInfo &rInf,
779 : SwTxtAttr *pHint )
780 : {
781 : OSL_ENSURE( ! pFrm->IsVertical() || pFrm->IsSwapped(),
782 : "NewFtnPortion with unswapped frame" );
783 :
784 278 : if( !pFrm->IsFtnAllowed() )
785 0 : return 0;
786 :
787 278 : SwTxtFtn *pFtn = (SwTxtFtn*)pHint;
788 278 : SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn();
789 278 : SwDoc *pDoc = pFrm->GetNode()->GetDoc();
790 :
791 278 : if( rInf.IsTest() )
792 0 : return new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ), pFtn );
793 :
794 278 : SWAP_IF_SWAPPED( pFrm )
795 :
796 : sal_uInt16 nReal;
797 : {
798 278 : sal_uInt16 nOldReal = pCurr->GetRealHeight();
799 278 : sal_uInt16 nOldAscent = pCurr->GetAscent();
800 278 : sal_uInt16 nOldHeight = pCurr->Height();
801 278 : ((SwTxtFormatter*)this)->CalcRealHeight();
802 278 : nReal = pCurr->GetRealHeight();
803 278 : if( nReal < nOldReal )
804 0 : nReal = nOldReal;
805 278 : pCurr->SetRealHeight( nOldReal );
806 278 : pCurr->Height( nOldHeight );
807 278 : pCurr->SetAscent( nOldAscent );
808 : }
809 :
810 278 : SwTwips nLower = Y() + nReal;
811 :
812 278 : const bool bVertical = pFrm->IsVertical();
813 278 : if( bVertical )
814 0 : nLower = pFrm->SwitchHorizontalToVertical( nLower );
815 :
816 278 : nLower = lcl_GetFtnLower( pFrm, nLower );
817 :
818 : //6995: Wir frischen nur auf. Das Connect tut fuer diesen Fall nix
819 : //Brauchbares, sondern wuerde stattdessen fuer diesen Fall meist die
820 : //Ftn wegwerfen und neu erzeugen.
821 :
822 278 : if( !rInf.IsQuick() )
823 278 : pFrm->ConnectFtn( pFtn, nLower );
824 :
825 278 : SwTxtFrm *pScrFrm = pFrm->FindFtnRef( pFtn );
826 278 : SwFtnBossFrm *pBoss = pFrm->FindFtnBossFrm( !rFtn.IsEndNote() );
827 278 : SwFtnFrm *pFtnFrm = NULL;
828 278 : if( pScrFrm )
829 278 : pFtnFrm = SwFtnBossFrm::FindFtn( pScrFrm, pFtn );
830 :
831 : // Wir erkundigen uns, ob durch unser Append irgendeine
832 : // Fussnote noch auf der Seite/Spalte steht. Wenn nicht verschwindet
833 : // auch unsere Zeile. Dies fuehrt zu folgendem erwuenschten
834 : // Verhalten: Ftn1 pass noch auf die Seite/Spalte, Ftn2 nicht mehr.
835 : // Also bleibt die Ftn2-Referenz auf der Seite/Spalte stehen. Die
836 : // Fussnote selbst folgt aber erst auf der naechsten Seite/Spalte.
837 : // Ausnahme: Wenn keine weitere Zeile auf diese Seite/Spalte passt,
838 : // so sollte die Ftn2-Referenz auch auf die naechste wandern.
839 278 : if( !rFtn.IsEndNote() )
840 : {
841 198 : SwSectionFrm *pSct = pBoss->FindSctFrm();
842 198 : bool bAtSctEnd = pSct && pSct->IsFtnAtEnd();
843 198 : if( FTNPOS_CHAPTER != pDoc->GetFtnInfo().ePos || bAtSctEnd )
844 : {
845 196 : SwFrm* pFtnCont = pBoss->FindFtnCont();
846 : // Wenn der Boss in einem Bereich liegt, kann es sich nur um eine
847 : // Spalte dieses Bereichs handeln. Wenn dies nicht die erste Spalte
848 : // ist, duerfen wir ausweichen
849 394 : if( !pFrm->IsInTab() && ( GetLineNr() > 1 || pFrm->GetPrev() ||
850 164 : ( !bAtSctEnd && pFrm->GetIndPrev() ) ||
851 4 : ( pSct && pBoss->GetPrev() ) ) )
852 : {
853 116 : if( !pFtnCont )
854 : {
855 0 : rInf.SetStop( true );
856 0 : UNDO_SWAP( pFrm )
857 0 : return 0;
858 : }
859 : else
860 : {
861 : // Es darf keine Fussnotencontainer in spaltigen Bereichen und
862 : // gleichzeitig auf der Seite/Seitenspalte geben
863 116 : if( pSct && !bAtSctEnd ) // liegt unser Container in einem (spaltigen) Bereich?
864 : {
865 10 : SwFtnBossFrm* pTmp = pBoss->FindSctFrm()->FindFtnBossFrm( true );
866 10 : SwFtnContFrm* pFtnC = pTmp->FindFtnCont();
867 10 : if( pFtnC )
868 : {
869 0 : SwFtnFrm* pTmpFrm = (SwFtnFrm*)pFtnC->Lower();
870 0 : if( pTmpFrm && *pTmpFrm < pFtn )
871 : {
872 0 : rInf.SetStop( true );
873 0 : UNDO_SWAP( pFrm )
874 0 : return 0;
875 : }
876 : }
877 : }
878 : // Ist dies die letzte passende Zeile?
879 116 : SwTwips nTmpBot = Y() + nReal * 2;
880 :
881 116 : if( bVertical )
882 0 : nTmpBot = pFrm->SwitchHorizontalToVertical( nTmpBot );
883 :
884 116 : SWRECTFN( pFtnCont )
885 :
886 : const long nDiff = (*fnRect->fnYDiff)(
887 232 : (pFtnCont->Frm().*fnRect->fnGetTop)(),
888 348 : nTmpBot );
889 :
890 116 : if( pScrFrm && nDiff < 0 )
891 : {
892 0 : if( pFtnFrm )
893 : {
894 0 : SwFtnBossFrm *pFtnBoss = pFtnFrm->FindFtnBossFrm();
895 0 : if( pFtnBoss != pBoss )
896 : {
897 : // Wir sind in der letzte Zeile und die Fussnote
898 : // ist auf eine andere Seite gewandert, dann wollen
899 : // wir mit ...
900 0 : rInf.SetStop( true );
901 0 : UNDO_SWAP( pFrm )
902 0 : return 0;
903 : }
904 : }
905 : }
906 : }
907 : }
908 : }
909 : }
910 : // Endlich: FtnPortion anlegen und raus hier...
911 : SwFtnPortion *pRet = new SwFtnPortion( rFtn.GetViewNumStr( *pDoc ),
912 278 : pFtn, nReal );
913 278 : rInf.SetFtnInside( true );
914 :
915 278 : UNDO_SWAP( pFrm )
916 :
917 278 : return pRet;
918 : }
919 :
920 : // Die Portion fuer die Ftn-Nummerierung im Ftn-Bereich
921 236 : SwNumberPortion *SwTxtFormatter::NewFtnNumPortion( SwTxtFormatInfo &rInf ) const
922 : {
923 : OSL_ENSURE( pFrm->IsInFtn() && !pFrm->GetIndPrev() && !rInf.IsFtnDone(),
924 : "This is the wrong place for a ftnnumber" );
925 472 : if( rInf.GetTxtStart() != nStart ||
926 236 : rInf.GetTxtStart() != rInf.GetIdx() )
927 0 : return 0;
928 :
929 236 : const SwFtnFrm* pFtnFrm = pFrm->FindFtnFrm();
930 236 : const SwTxtFtn* pFtn = pFtnFrm->GetAttr();
931 :
932 : // Aha, wir sind also im Fussnotenbereich
933 236 : SwFmtFtn& rFtn = (SwFmtFtn&)pFtn->GetFtn();
934 :
935 236 : SwDoc *pDoc = pFrm->GetNode()->GetDoc();
936 236 : OUString aFtnTxt( rFtn.GetViewNumStr( *pDoc, true ));
937 :
938 : const SwEndNoteInfo* pInfo;
939 236 : if( rFtn.IsEndNote() )
940 36 : pInfo = &pDoc->GetEndNoteInfo();
941 : else
942 200 : pInfo = &pDoc->GetFtnInfo();
943 236 : const SwAttrSet& rSet = pInfo->GetCharFmt(*pDoc)->GetAttrSet();
944 :
945 236 : const SwAttrSet* pParSet = &rInf.GetCharAttr();
946 236 : const IDocumentSettingAccess* pIDSA = pFrm->GetTxtNode()->getIDocumentSettingAccess();
947 236 : SwFont *pNumFnt = new SwFont( pParSet, pIDSA );
948 :
949 : // #i37142#
950 : // Underline style of paragraph font should not be considered
951 : // Overline style of paragraph font should not be considered
952 : // Weight style of paragraph font should not be considered
953 : // Posture style of paragraph font should not be considered
954 : // See also #i18463# and SwTxtFormatter::NewNumberPortion()
955 236 : pNumFnt->SetUnderline( UNDERLINE_NONE );
956 236 : pNumFnt->SetOverline( UNDERLINE_NONE );
957 236 : pNumFnt->SetItalic( ITALIC_NONE, SW_LATIN );
958 236 : pNumFnt->SetItalic( ITALIC_NONE, SW_CJK );
959 236 : pNumFnt->SetItalic( ITALIC_NONE, SW_CTL );
960 236 : pNumFnt->SetWeight( WEIGHT_NORMAL, SW_LATIN );
961 236 : pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CJK );
962 236 : pNumFnt->SetWeight( WEIGHT_NORMAL, SW_CTL );
963 :
964 236 : pNumFnt->SetDiffFnt(&rSet, pIDSA );
965 236 : pNumFnt->SetVertical( pNumFnt->GetOrientation(), pFrm->IsVertical() );
966 :
967 236 : SwFtnNumPortion* pNewPor = new SwFtnNumPortion( aFtnTxt, pNumFnt );
968 236 : pNewPor->SetLeft( !pFrm->IsRightToLeft() );
969 236 : return pNewPor;
970 : }
971 :
972 0 : OUString lcl_GetPageNumber( const SwPageFrm* pPage )
973 : {
974 : OSL_ENSURE( pPage, "GetPageNumber: Homeless TxtFrm" );
975 0 : const sal_uInt16 nVirtNum = pPage->GetVirtPageNum();
976 0 : const SvxNumberType& rNum = pPage->GetPageDesc()->GetNumType();
977 0 : return rNum.GetNumStr( nVirtNum );
978 : }
979 :
980 236 : SwErgoSumPortion *SwTxtFormatter::NewErgoSumPortion( SwTxtFormatInfo &rInf ) const
981 : {
982 : // Wir koennen nicht davon ausgehen, dass wir ein Follow sind
983 : // 7983: GetIdx() nicht nStart
984 944 : if( !pFrm->IsInFtn() || pFrm->GetPrev() ||
985 944 : rInf.IsErgoDone() || rInf.GetIdx() != pFrm->GetOfst() ||
986 236 : pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
987 36 : return 0;
988 :
989 : // Aha, wir sind also im Fussnotenbereich
990 200 : const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
991 200 : SwTxtFrm *pQuoFrm = pFrm->FindQuoVadisFrm();
992 200 : if( !pQuoFrm )
993 200 : return 0;
994 0 : const SwPageFrm* pPage = pFrm->FindPageFrm();
995 0 : const SwPageFrm* pQuoPage = pQuoFrm->FindPageFrm();
996 0 : if( pPage == pQuoFrm->FindPageFrm() )
997 0 : return 0; // Wenn der QuoVadis auf der selben (spaltigen) Seite steht
998 0 : const OUString aPage = lcl_GetPageNumber( pPage );
999 0 : SwParaPortion *pPara = pQuoFrm->GetPara();
1000 0 : if( pPara )
1001 0 : pPara->SetErgoSumNum( aPage );
1002 0 : if( rFtnInfo.aErgoSum.isEmpty() )
1003 0 : return 0;
1004 : SwErgoSumPortion *pErgo = new SwErgoSumPortion( rFtnInfo.aErgoSum,
1005 0 : lcl_GetPageNumber( pQuoPage ) );
1006 0 : return pErgo;
1007 : }
1008 :
1009 440 : sal_Int32 SwTxtFormatter::FormatQuoVadis( const sal_Int32 nOffset )
1010 : {
1011 : OSL_ENSURE( ! pFrm->IsVertical() || ! pFrm->IsSwapped(),
1012 : "SwTxtFormatter::FormatQuoVadis with swapped frame" );
1013 :
1014 440 : if( !pFrm->IsInFtn() || pFrm->ImplFindFtnFrm()->GetAttr()->GetFtn().IsEndNote() )
1015 50 : return nOffset;
1016 :
1017 390 : const SwFrm* pErgoFrm = pFrm->FindFtnFrm()->GetFollow();
1018 390 : if( !pErgoFrm && pFrm->HasFollow() )
1019 0 : pErgoFrm = pFrm->GetFollow();
1020 390 : if( !pErgoFrm )
1021 390 : return nOffset;
1022 :
1023 0 : if( pErgoFrm == pFrm->GetNext() )
1024 : {
1025 0 : SwFrm *pCol = pFrm->FindColFrm();
1026 0 : while( pCol && !pCol->GetNext() )
1027 0 : pCol = pCol->GetUpper()->FindColFrm();
1028 0 : if( pCol )
1029 0 : return nOffset;
1030 : }
1031 : else
1032 : {
1033 0 : const SwPageFrm* pPage = pFrm->FindPageFrm();
1034 0 : const SwPageFrm* pErgoPage = pErgoFrm->FindPageFrm();
1035 0 : if( pPage == pErgoPage )
1036 0 : return nOffset; // Wenn der ErgoSum auf der selben Seite steht
1037 : }
1038 :
1039 0 : SwTxtFormatInfo &rInf = GetInfo();
1040 0 : const SwFtnInfo &rFtnInfo = pFrm->GetNode()->GetDoc()->GetFtnInfo();
1041 0 : if( rFtnInfo.aQuoVadis.isEmpty() )
1042 0 : return nOffset;
1043 :
1044 : // Ein Wort zu QuoVadis/ErgoSum:
1045 : // Fuer diese Texte wird der am Absatz eingestellte Font verwendet.
1046 : // Wir initialisieren uns also:
1047 : // ResetFont();
1048 0 : FeedInf( rInf );
1049 0 : SeekStartAndChg( rInf, true );
1050 0 : if( GetRedln() && pCurr->HasRedline() )
1051 0 : GetRedln()->Seek( *pFnt, nOffset, 0 );
1052 :
1053 : // Ein fieser Sonderfall: Flyfrms reichen in die Zeile und stehen
1054 : // natuerlich da, wo wir unseren Quovadis Text reinsetzen wollen.
1055 : // Erst mal sehen, ob es so schlimm ist:
1056 0 : SwLinePortion *pPor = pCurr->GetFirstPortion();
1057 0 : sal_uInt16 nLastLeft = 0;
1058 0 : while( pPor )
1059 : {
1060 0 : if ( pPor->IsFlyPortion() )
1061 0 : nLastLeft = ( (SwFlyPortion*) pPor)->Fix() +
1062 0 : ( (SwFlyPortion*) pPor)->Width();
1063 0 : pPor = pPor->GetPortion();
1064 : }
1065 : // Das alte Spiel: wir wollen, dass die Zeile an einer bestimmten
1066 : // Stelle umbricht, also beeinflussen wir die Width.
1067 : // nLastLeft ist jetzt quasi der rechte Rand.
1068 0 : const sal_uInt16 nOldRealWidth = rInf.RealWidth();
1069 0 : rInf.RealWidth( nOldRealWidth - nLastLeft );
1070 :
1071 0 : OUString aErgo = lcl_GetPageNumber( pErgoFrm->FindPageFrm() );
1072 0 : SwQuoVadisPortion *pQuo = new SwQuoVadisPortion(rFtnInfo.aQuoVadis, aErgo );
1073 0 : pQuo->SetAscent( rInf.GetAscent() );
1074 0 : pQuo->Height( rInf.GetTxtHeight() );
1075 0 : pQuo->Format( rInf );
1076 0 : sal_uInt16 nQuoWidth = pQuo->Width();
1077 0 : SwLinePortion* pCurrPor = pQuo;
1078 :
1079 0 : while ( rInf.GetRest() )
1080 : {
1081 0 : SwLinePortion* pFollow = rInf.GetRest();
1082 0 : rInf.SetRest( 0 );
1083 0 : pCurrPor->Move( rInf );
1084 :
1085 : OSL_ENSURE( pFollow->IsQuoVadisPortion(),
1086 : "Quo Vadis, rest of QuoVadisPortion" );
1087 :
1088 : // format the rest and append it to the other QuoVadis parts
1089 0 : pFollow->Format( rInf );
1090 0 : nQuoWidth = nQuoWidth + pFollow->Width();
1091 :
1092 0 : pCurrPor->Append( pFollow );
1093 0 : pCurrPor = pFollow;
1094 : }
1095 :
1096 0 : Right( Right() - nQuoWidth );
1097 :
1098 0 : SWAP_IF_NOT_SWAPPED( pFrm )
1099 :
1100 0 : const sal_Int32 nRet = FormatLine( nStart );
1101 :
1102 0 : UNDO_SWAP( pFrm )
1103 :
1104 0 : Right( rInf.Left() + nOldRealWidth - 1 );
1105 :
1106 0 : nLastLeft = nOldRealWidth - pCurr->Width();
1107 0 : FeedInf( rInf );
1108 :
1109 : // Es kann durchaus sein, dass am Ende eine Marginportion steht,
1110 : // die beim erneuten Aufspannen nur Aerger bereiten wuerde.
1111 0 : pPor = pCurr->FindLastPortion();
1112 0 : SwGluePortion *pGlue = pPor->IsMarginPortion() ?
1113 0 : (SwMarginPortion*) pPor : 0;
1114 0 : if( pGlue )
1115 : {
1116 0 : pGlue->Height( 0 );
1117 0 : pGlue->Width( 0 );
1118 0 : pGlue->SetLen( 0 );
1119 0 : pGlue->SetAscent( 0 );
1120 0 : pGlue->SetPortion( NULL );
1121 0 : pGlue->SetFixWidth(0);
1122 : }
1123 :
1124 : // Luxus: Wir sorgen durch das Aufspannen von Glues dafuer,
1125 : // dass der QuoVadis-Text rechts erscheint:
1126 0 : nLastLeft = nLastLeft - nQuoWidth;
1127 0 : if( nLastLeft )
1128 : {
1129 0 : if( nLastLeft > pQuo->GetAscent() ) // Mindestabstand
1130 : {
1131 0 : switch( GetAdjust() )
1132 : {
1133 : case SVX_ADJUST_BLOCK:
1134 : {
1135 0 : if( !pCurr->GetLen() ||
1136 0 : CH_BREAK != GetInfo().GetChar(nStart+pCurr->GetLen()-1))
1137 0 : nLastLeft = pQuo->GetAscent();
1138 0 : nQuoWidth = nQuoWidth + nLastLeft;
1139 0 : break;
1140 : }
1141 : case SVX_ADJUST_RIGHT:
1142 : {
1143 0 : nLastLeft = pQuo->GetAscent();
1144 0 : nQuoWidth = nQuoWidth + nLastLeft;
1145 0 : break;
1146 : }
1147 : case SVX_ADJUST_CENTER:
1148 : {
1149 0 : nQuoWidth = nQuoWidth + pQuo->GetAscent();
1150 0 : long nDiff = nLastLeft - nQuoWidth;
1151 0 : if( nDiff < 0 )
1152 : {
1153 0 : nLastLeft = pQuo->GetAscent();
1154 0 : nQuoWidth = (sal_uInt16)(-nDiff + nLastLeft);
1155 : }
1156 : else
1157 : {
1158 0 : nQuoWidth = 0;
1159 0 : nLastLeft = sal_uInt16(( pQuo->GetAscent() + nDiff ) / 2);
1160 : }
1161 0 : break;
1162 : }
1163 : default:
1164 0 : nQuoWidth = nQuoWidth + nLastLeft;
1165 : }
1166 : }
1167 : else
1168 0 : nQuoWidth = nQuoWidth + nLastLeft;
1169 0 : if( nLastLeft )
1170 : {
1171 0 : pGlue = new SwGluePortion(0);
1172 0 : pGlue->Width( nLastLeft );
1173 0 : pPor->Append( pGlue );
1174 0 : pPor = pPor->GetPortion();
1175 : }
1176 : }
1177 :
1178 : // Jetzt aber: die QuoVadis-Portion wird angedockt:
1179 0 : pCurrPor = pQuo;
1180 0 : while ( pCurrPor )
1181 : {
1182 : // pPor->Append deletes the pPortoin pointer of pPor. Therefore
1183 : // we have to keep a pointer to the next portion
1184 0 : pQuo = (SwQuoVadisPortion*)pCurrPor->GetPortion();
1185 0 : pPor->Append( pCurrPor );
1186 0 : pPor = pPor->GetPortion();
1187 0 : pCurrPor = pQuo;
1188 : }
1189 :
1190 0 : pCurr->Width( pCurr->Width() + nQuoWidth );
1191 :
1192 : // Und noch einmal adjustieren wegen des Adjustment und nicht zu Letzt
1193 : // wegen folgendem Sonderfall: In der Zeile hat der DummUser durchgaengig
1194 : // einen kleineren Font eingestellt als der vom QuoVadis-Text ...
1195 0 : CalcAdjustLine( pCurr );
1196 :
1197 : // Uff...
1198 0 : return nRet;
1199 : }
1200 :
1201 : // MakeDummyLine() erzeugt eine Line, die bis zum unteren Seitenrand
1202 : // reicht. DummyLines bzw. DummyPortions sorgen dafuer, dass Oszillationen
1203 : // zum stehen kommen, weil Rueckflussmoeglichkeiten genommen werden.
1204 : // Sie werden bei absatzgebundenen Frames in Fussnoten und bei Ftn-
1205 : // Oszillationen verwendet.
1206 0 : void SwTxtFormatter::MakeDummyLine()
1207 : {
1208 0 : sal_uInt16 nRstHeight = GetFrmRstHeight();
1209 0 : if( pCurr && nRstHeight > pCurr->Height() )
1210 : {
1211 0 : SwLineLayout *pLay = new SwLineLayout;
1212 0 : nRstHeight = nRstHeight - pCurr->Height();
1213 0 : pLay->Height( nRstHeight );
1214 0 : pLay->SetAscent( nRstHeight );
1215 0 : Insert( pLay );
1216 0 : Next();
1217 : }
1218 0 : }
1219 :
1220 : class SwFtnSave
1221 : {
1222 : SwTxtSizeInfo *pInf;
1223 : SwFont *pFnt;
1224 : SwFont *pOld;
1225 : public:
1226 : SwFtnSave( const SwTxtSizeInfo &rInf,
1227 : const SwTxtFtn *pTxtFtn,
1228 : const bool bApplyGivenScriptType,
1229 : const sal_uInt8 nGivenScriptType );
1230 : ~SwFtnSave();
1231 : };
1232 :
1233 546 : SwFtnSave::SwFtnSave( const SwTxtSizeInfo &rInf,
1234 : const SwTxtFtn* pTxtFtn,
1235 : const bool bApplyGivenScriptType,
1236 : const sal_uInt8 nGivenScriptType )
1237 : : pInf( &((SwTxtSizeInfo&)rInf) )
1238 : , pFnt( 0 )
1239 546 : , pOld( 0 )
1240 : {
1241 546 : if( pTxtFtn && rInf.GetTxtFrm() )
1242 : {
1243 546 : pFnt = ((SwTxtSizeInfo&)rInf).GetFont();
1244 546 : pOld = new SwFont( *pFnt );
1245 546 : pOld->GetTox() = pFnt->GetTox();
1246 546 : pFnt->GetTox() = 0;
1247 546 : SwFmtFtn& rFtn = (SwFmtFtn&)pTxtFtn->GetFtn();
1248 546 : const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
1249 :
1250 : // #i98418#
1251 546 : if ( bApplyGivenScriptType )
1252 : {
1253 546 : pFnt->SetActual( nGivenScriptType );
1254 : }
1255 : else
1256 : {
1257 : // examine text and set script
1258 0 : OUString aTmpStr( rFtn.GetViewNumStr( *pDoc ) );
1259 0 : pFnt->SetActual( SwScriptInfo::WhichFont( 0, &aTmpStr, 0 ) );
1260 : }
1261 :
1262 : const SwEndNoteInfo* pInfo;
1263 546 : if( rFtn.IsEndNote() )
1264 130 : pInfo = &pDoc->GetEndNoteInfo();
1265 : else
1266 416 : pInfo = &pDoc->GetFtnInfo();
1267 546 : const SwAttrSet& rSet = pInfo->GetAnchorCharFmt((SwDoc&)*pDoc)->GetAttrSet();
1268 546 : pFnt->SetDiffFnt( &rSet, rInf.GetTxtFrm()->GetNode()->getIDocumentSettingAccess() );
1269 :
1270 : // we reduce footnote size, if we are inside a double line portion
1271 546 : if ( ! pOld->GetEscapement() && 50 == pOld->GetPropr() )
1272 : {
1273 0 : Size aSize = pFnt->GetSize( pFnt->GetActual() );
1274 0 : pFnt->SetSize( Size( (long)aSize.Width() / 2,
1275 0 : (long)aSize.Height() / 2 ),
1276 0 : pFnt->GetActual() );
1277 : }
1278 :
1279 : // set the correct rotation at the footnote font
1280 : const SfxPoolItem* pItem;
1281 546 : if( SfxItemState::SET == rSet.GetItemState( RES_CHRATR_ROTATE,
1282 546 : true, &pItem ))
1283 0 : pFnt->SetVertical( ((SvxCharRotateItem*)pItem)->GetValue(),
1284 0 : rInf.GetTxtFrm()->IsVertical() );
1285 :
1286 546 : pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
1287 :
1288 546 : if( SfxItemState::SET == rSet.GetItemState( RES_CHRATR_BACKGROUND,
1289 546 : true, &pItem ))
1290 0 : pFnt->SetBackColor( new Color( ((SvxBrushItem*)pItem)->GetColor() ) );
1291 : }
1292 : else
1293 0 : pFnt = NULL;
1294 546 : }
1295 :
1296 546 : SwFtnSave::~SwFtnSave()
1297 : {
1298 546 : if( pFnt )
1299 : {
1300 : // SwFont zurueckstellen
1301 546 : *pFnt = *pOld;
1302 546 : pFnt->GetTox() = pOld->GetTox();
1303 546 : pFnt->ChgPhysFnt( pInf->GetVsh(), *pInf->GetOut() );
1304 546 : delete pOld;
1305 : }
1306 546 : }
1307 :
1308 278 : SwFtnPortion::SwFtnPortion( const OUString &rExpand,
1309 : SwTxtFtn *pFootn, sal_uInt16 nReal )
1310 : : SwFldPortion( rExpand, 0 )
1311 : , pFtn(pFootn)
1312 : , nOrigHeight( nReal )
1313 : // #i98418#
1314 : , mbPreferredScriptTypeSet( false )
1315 278 : , mnPreferredScriptType( SW_LATIN )
1316 : {
1317 278 : SetLen(1);
1318 278 : SetWhichPor( POR_FTN );
1319 278 : }
1320 :
1321 1190 : bool SwFtnPortion::GetExpTxt( const SwTxtSizeInfo &, OUString &rTxt ) const
1322 : {
1323 1190 : rTxt = aExpand;
1324 1190 : return true;
1325 : }
1326 :
1327 278 : bool SwFtnPortion::Format( SwTxtFormatInfo &rInf )
1328 : {
1329 : // #i98418#
1330 : // SwFtnSave aFtnSave( rInf, pFtn );
1331 278 : SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
1332 : // the idx is manipulated in SwExpandPortion::Format
1333 : // this flag indicates, that a footnote is allowed to trigger
1334 : // an underflow during SwTxtGuess::Guess
1335 278 : rInf.SetFakeLineStart( rInf.GetIdx() > rInf.GetLineStart() );
1336 278 : const bool bFull = SwFldPortion::Format( rInf );
1337 278 : rInf.SetFakeLineStart( false );
1338 278 : SetAscent( rInf.GetAscent() );
1339 278 : Height( rInf.GetTxtHeight() );
1340 278 : rInf.SetFtnDone( !bFull );
1341 278 : if( !bFull )
1342 278 : rInf.SetParaFtn();
1343 278 : return bFull;
1344 : }
1345 :
1346 268 : void SwFtnPortion::Paint( const SwTxtPaintInfo &rInf ) const
1347 : {
1348 : // #i98418#
1349 : // SwFtnSave aFtnSave( rInf, pFtn );
1350 268 : SwFtnSave aFtnSave( rInf, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
1351 268 : rInf.DrawViewOpt( *this, POR_FTN );
1352 268 : SwExpandPortion::Paint( rInf );
1353 268 : }
1354 :
1355 0 : SwPosSize SwFtnPortion::GetTxtSize( const SwTxtSizeInfo &rInfo ) const
1356 : {
1357 : // #i98418#
1358 : // SwFtnSave aFtnSave( rInfo, pFtn );
1359 0 : SwFtnSave aFtnSave( rInfo, pFtn, mbPreferredScriptTypeSet, mnPreferredScriptType );
1360 0 : return SwExpandPortion::GetTxtSize( rInfo );
1361 : }
1362 :
1363 : // #i98418#
1364 278 : void SwFtnPortion::SetPreferredScriptType( sal_uInt8 nPreferredScriptType )
1365 : {
1366 278 : mbPreferredScriptTypeSet = true;
1367 278 : mnPreferredScriptType = nPreferredScriptType;
1368 278 : }
1369 :
1370 0 : SwFldPortion *SwQuoVadisPortion::Clone( const OUString &rExpand ) const
1371 : {
1372 0 : return new SwQuoVadisPortion( rExpand, aErgo );
1373 : }
1374 :
1375 0 : SwQuoVadisPortion::SwQuoVadisPortion( const OUString &rExp, const OUString& rStr )
1376 0 : : SwFldPortion( rExp ), aErgo(rStr)
1377 : {
1378 0 : SetLen(0);
1379 0 : SetWhichPor( POR_QUOVADIS );
1380 0 : }
1381 :
1382 0 : bool SwQuoVadisPortion::Format( SwTxtFormatInfo &rInf )
1383 : {
1384 : // erster Versuch, vielleicht passt der Text
1385 0 : CheckScript( rInf );
1386 0 : bool bFull = SwFldPortion::Format( rInf );
1387 0 : SetLen( 0 );
1388 :
1389 0 : if( bFull )
1390 : {
1391 : // zweiter Versuch, wir kuerzen den String:
1392 0 : aExpand = "...";
1393 0 : bFull = SwFldPortion::Format( rInf );
1394 0 : SetLen( 0 );
1395 0 : if( bFull )
1396 : // dritter Versuch, es langt: jetzt wird gestaucht:
1397 0 : Width( sal_uInt16(rInf.Width() - rInf.X()) );
1398 :
1399 : // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum
1400 0 : if( rInf.GetRest() )
1401 : {
1402 0 : delete rInf.GetRest();
1403 0 : rInf.SetRest( 0 );
1404 : }
1405 : }
1406 0 : return bFull;
1407 : }
1408 :
1409 0 : bool SwQuoVadisPortion::GetExpTxt( const SwTxtSizeInfo &, OUString &rTxt ) const
1410 : {
1411 0 : rTxt = aExpand;
1412 : // if this QuoVadisPortion has a follow, the follow is responsible for
1413 : // the ergo text.
1414 0 : if ( ! HasFollow() )
1415 0 : rTxt += aErgo;
1416 0 : return true;
1417 : }
1418 :
1419 0 : void SwQuoVadisPortion::HandlePortion( SwPortionHandler& rPH ) const
1420 : {
1421 0 : rPH.Special( GetLen(), aExpand + aErgo, GetWhichPor() );
1422 0 : }
1423 :
1424 0 : void SwQuoVadisPortion::Paint( const SwTxtPaintInfo &rInf ) const
1425 : {
1426 : // Wir wollen _immer_ per DrawStretchText ausgeben,
1427 : // weil nErgo schnell mal wechseln kann.
1428 0 : if( PrtWidth() )
1429 : {
1430 0 : rInf.DrawViewOpt( *this, POR_QUOVADIS );
1431 0 : SwTxtSlot aDiffTxt( &rInf, this, true, false );
1432 0 : SwFontSave aSave( rInf, pFnt );
1433 0 : rInf.DrawText( *this, rInf.GetLen(), true );
1434 : }
1435 0 : }
1436 :
1437 0 : SwFldPortion *SwErgoSumPortion::Clone( const OUString &rExpand ) const
1438 : {
1439 0 : return new SwErgoSumPortion( rExpand, OUString() );
1440 : }
1441 :
1442 0 : SwErgoSumPortion::SwErgoSumPortion(const OUString &rExp, const OUString& rStr)
1443 0 : : SwFldPortion( rExp )
1444 : {
1445 0 : SetLen(0);
1446 0 : aExpand += rStr;
1447 :
1448 : // 7773: sinnvolle Massnahme: ein Blank Abstand zum Text
1449 0 : aExpand += " ";
1450 0 : SetWhichPor( POR_ERGOSUM );
1451 0 : }
1452 :
1453 0 : sal_Int32 SwErgoSumPortion::GetCrsrOfst( const sal_uInt16 ) const
1454 : {
1455 0 : return 0;
1456 : }
1457 :
1458 0 : bool SwErgoSumPortion::Format( SwTxtFormatInfo &rInf )
1459 : {
1460 0 : const bool bFull = SwFldPortion::Format( rInf );
1461 0 : SetLen( 0 );
1462 0 : rInf.SetErgoDone( true );
1463 :
1464 : // 8317: keine mehrzeiligen Felder bei QuoVadis und ErgoSum
1465 0 : if( bFull && rInf.GetRest() )
1466 : {
1467 0 : delete rInf.GetRest();
1468 0 : rInf.SetRest( 0 );
1469 : }
1470 :
1471 : // We return false in order to get some text into the current line,
1472 : // even if it's full (better than looping)
1473 0 : return false;
1474 : }
1475 :
1476 0 : void SwParaPortion::SetErgoSumNum( const OUString& rErgo )
1477 : {
1478 0 : SwLineLayout *pLay = this;
1479 0 : while( pLay->GetNext() )
1480 : {
1481 0 : pLay = pLay->GetNext();
1482 : }
1483 0 : SwLinePortion *pPor = pLay;
1484 0 : SwQuoVadisPortion *pQuo = 0;
1485 0 : while( pPor && !pQuo )
1486 : {
1487 0 : if ( pPor->IsQuoVadisPortion() )
1488 0 : pQuo = (SwQuoVadisPortion*)pPor;
1489 0 : pPor = pPor->GetPortion();
1490 : }
1491 0 : if( pQuo )
1492 0 : pQuo->SetNumber( rErgo );
1493 0 : }
1494 :
1495 : // Wird im SwTxtFrm::Prepare() gerufen
1496 54 : bool SwParaPortion::UpdateQuoVadis( const OUString &rQuo )
1497 : {
1498 54 : SwLineLayout *pLay = this;
1499 108 : while( pLay->GetNext() )
1500 : {
1501 0 : pLay = pLay->GetNext();
1502 : }
1503 54 : SwLinePortion *pPor = pLay;
1504 54 : SwQuoVadisPortion *pQuo = 0;
1505 224 : while( pPor && !pQuo )
1506 : {
1507 116 : if ( pPor->IsQuoVadisPortion() )
1508 0 : pQuo = (SwQuoVadisPortion*)pPor;
1509 116 : pPor = pPor->GetPortion();
1510 : }
1511 :
1512 54 : if( !pQuo )
1513 54 : return false;
1514 :
1515 0 : return pQuo->GetQuoTxt() == rQuo;
1516 270 : }
1517 :
1518 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|