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