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