1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: frmcrsr.cxx,v $
10 * $Revision: 1.44.212.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include "ndtxt.hxx" // GetNode()
36 #include "pam.hxx" // SwPosition
37 #include "frmtool.hxx"
38 #include "viewopt.hxx"
40 #include "pagefrm.hxx"
42 #include "txttypes.hxx"
43 #include <sfx2/printer.hxx>
44 #include <svx/lrspitem.hxx>
45 #include <svx/tstpitem.hxx>
46 #include <svx/ulspitem.hxx>
47 #include <svx/lspcitem.hxx>
48 #include <pormulti.hxx> // SwMultiPortion
50 #include <sortedobjs.hxx>
52 #include <unicode/ubidi.h>
55 #include "txtfrm.hxx" // SwTxtFrm
56 #include "inftxt.hxx" // SwTxtSizeInfo
57 #include "itrtxt.hxx" // SwTxtCursor
58 #include "crstate.hxx" // SwTxtCursor
59 #include "viewsh.hxx" // InvalidateWindows
60 #include "swfntcch.hxx" // SwFontAccess
63 #if OSL_DEBUG_LEVEL > 1
64 #include "txtpaint.hxx"
67 #define MIN_OFFSET_STEP 10
69 using namespace ::com::sun::star
;
73 * 1170-SurvivalKit: Wie gelangt man hinter das letzte Zeichen der Zeile.
74 * - RightMargin verzichtet auf den Positionsausgleich mit -1
75 * - GetCharRect liefert bei MV_RIGHTMARGIN ein GetEndCharRect
76 * - GetEndCharRect setzt bRightMargin auf sal_True
77 * - SwTxtCursor::bRightMargin wird per CharCrsrToLine auf sal_False gesetzt
80 /*************************************************************************
82 *************************************************************************/
84 SwTxtFrm
*GetAdjFrmAtPos( SwTxtFrm
*pFrm
, const SwPosition
&rPos
,
85 const sal_Bool bRightMargin
, const sal_Bool bNoScroll
= TRUE
)
87 // 8810: vgl. 1170, RightMargin in der letzten Masterzeile...
88 const xub_StrLen nOffset
= rPos
.nContent
.GetIndex();
89 SwTxtFrm
*pFrmAtPos
= pFrm
;
90 if( !bNoScroll
|| pFrm
->GetFollow() )
92 pFrmAtPos
= pFrm
->GetFrmAtPos( rPos
);
93 if( nOffset
< pFrmAtPos
->GetOfst() &&
94 !pFrmAtPos
->IsFollow() )
96 xub_StrLen nNew
= nOffset
;
97 if( nNew
< MIN_OFFSET_STEP
)
100 nNew
-= MIN_OFFSET_STEP
;
101 lcl_ChangeOffset( pFrmAtPos
, nNew
);
104 while( pFrm
!= pFrmAtPos
)
107 pFrm
->GetFormatted();
108 pFrmAtPos
= (SwTxtFrm
*)pFrm
->GetFrmAtPos( rPos
);
111 if( nOffset
&& bRightMargin
)
113 while( pFrmAtPos
&& pFrmAtPos
->GetOfst() == nOffset
&&
114 pFrmAtPos
->IsFollow() )
116 pFrmAtPos
->GetFormatted();
117 pFrmAtPos
= pFrmAtPos
->FindMaster();
119 ASSERT( pFrmAtPos
, "+GetCharRect: no frame with my rightmargin" );
121 return pFrmAtPos
? pFrmAtPos
: pFrm
;
124 sal_Bool
lcl_ChangeOffset( SwTxtFrm
* pFrm
, xub_StrLen nNew
)
126 // In Bereichen und ausserhalb von Flies wird nicht mehr gescrollt.
127 ASSERT( !pFrm
->IsFollow(), "Illegal Scrolling by Follow!" );
128 if( pFrm
->GetOfst() != nNew
&& !pFrm
->IsInSct() )
130 SwFlyFrm
*pFly
= pFrm
->FindFlyFrm();
131 // Vorsicht, wenn z.B. bei einem spaltigen Rahmen die Groesse noch invalide ist,
132 // duerfen wir nicht mal eben herumscrollen
133 if ( ( pFly
&& pFly
->IsValid() &&
134 !pFly
->GetNextLink() && !pFly
->GetPrevLink() ) ||
135 ( !pFly
&& pFrm
->IsInTab() ) )
137 ViewShell
* pVsh
= pFrm
->GetShell();
140 if( pVsh
->GetNext() != pVsh
||
141 ( pFrm
->GetDrawObjs() && pFrm
->GetDrawObjs()->Count() ) )
143 if( !pFrm
->GetOfst() )
147 pFrm
->SetOfst( nNew
);
149 pFrm
->GetFormatted();
150 if( pFrm
->Frm().HasArea() )
151 pFrm
->GetShell()->InvalidateWindows( pFrm
->Frm() );
159 /*************************************************************************
160 * GetFrmAtOfst(), GetFrmAtPos()
161 *************************************************************************/
163 // OD 07.10.2003 #110978#
164 SwTxtFrm
& SwTxtFrm::GetFrmAtOfst( const xub_StrLen nWhere
)
166 SwTxtFrm
* pRet
= this;
167 while( pRet
->HasFollow() && nWhere
>= pRet
->GetFollow()->GetOfst() )
168 pRet
= pRet
->GetFollow();
172 SwTxtFrm
*SwTxtFrm::GetFrmAtPos( const SwPosition
&rPos
)
174 SwTxtFrm
*pFoll
= (SwTxtFrm
*)this;
175 while( pFoll
->GetFollow() )
177 if( rPos
.nContent
.GetIndex() > pFoll
->GetFollow()->GetOfst() )
178 pFoll
= pFoll
->GetFollow();
181 if( rPos
.nContent
.GetIndex() == pFoll
->GetFollow()->GetOfst()
182 && !SwTxtCursor::IsRightMargin() )
183 pFoll
= pFoll
->GetFollow();
191 /*************************************************************************
192 * SwTxtFrm::GetCharRect()
193 *************************************************************************/
196 * GetCharRect() findet die Characterzelle des Characters, dass
197 * durch aPos beschrieben wird. GetCrsrOfst() findet den
198 * umgekehrten Weg: Von einer Dokumentkoordinate zu einem Pam.
199 * Beide sind virtuell in der Framebasisklasse und werden deshalb
203 sal_Bool
SwTxtFrm::GetCharRect( SwRect
& rOrig
, const SwPosition
&rPos
,
204 SwCrsrMoveState
*pCMS
) const
206 ASSERT( ! IsVertical() || ! IsSwapped(),"SwTxtFrm::GetCharRect with swapped frame" );
208 if( IsLocked() || IsHiddenNow() )
211 //Erstmal den richtigen Frm finden, dabei muss beachtet werden, dass:
212 //- die gecachten Informationen verworfen sein koennen (GetPara() == 0)
213 //- das ein Follow gemeint sein kann
214 //- das die Kette der Follows dynamisch waechst; der in den wir
215 // schliesslich gelangen muss aber Formatiert sein.
217 // opt: reading ahead erspart uns ein GetAdjFrmAtPos
218 const sal_Bool bRightMargin
= pCMS
&& ( MV_RIGHTMARGIN
== pCMS
->eState
);
219 const sal_Bool bNoScroll
= pCMS
&& pCMS
->bNoScroll
;
220 SwTxtFrm
*pFrm
= GetAdjFrmAtPos( (SwTxtFrm
*)this, rPos
, bRightMargin
,
222 pFrm
->GetFormatted();
223 const SwFrm
* pTmpFrm
= (SwFrm
*)pFrm
->GetUpper();
226 const SwTwips nUpperMaxY
= (pTmpFrm
->*fnRect
->fnGetPrtBottom
)();
227 const SwTwips nFrmMaxY
= (pFrm
->*fnRect
->fnGetPrtBottom
)();
229 // nMaxY is an absolute value
230 SwTwips nMaxY
= bVert
?
231 Max( nFrmMaxY
, nUpperMaxY
) :
232 Min( nFrmMaxY
, nUpperMaxY
);
234 sal_Bool bRet
= sal_False
;
236 if ( pFrm
->IsEmpty() || ! (pFrm
->Prt().*fnRect
->fnGetHeight
)() )
238 Point aPnt1
= pFrm
->Frm().Pos() + pFrm
->Prt().Pos();
239 SwTxtNode
* pTxtNd
= ((SwTxtFrm
*)this)->GetTxtNode();
241 pTxtNd
->GetFirstLineOfsWithNum( nFirstOffset
);
246 if( nFirstOffset
> 0 )
247 aPnt1
.Y() += nFirstOffset
;
249 if ( aPnt1
.X() < nMaxY
)
251 aPnt2
.X() = aPnt1
.X() + pFrm
->Prt().Width();
252 aPnt2
.Y() = aPnt1
.Y();
253 if( aPnt2
.X() < nMaxY
)
258 if( nFirstOffset
> 0 )
259 aPnt1
.X() += nFirstOffset
;
261 if( aPnt1
.Y() > nMaxY
)
263 aPnt2
.X() = aPnt1
.X();
264 aPnt2
.Y() = aPnt1
.Y() + pFrm
->Prt().Height();
265 if( aPnt2
.Y() > nMaxY
)
269 rOrig
= SwRect( aPnt1
, aPnt2
);
273 pCMS
->aRealHeight
.X() = 0;
274 pCMS
->aRealHeight
.Y() = bVert
? -rOrig
.Width() : rOrig
.Height();
277 if ( pFrm
->IsRightToLeft() )
278 pFrm
->SwitchLTRtoRTL( rOrig
);
284 if( !pFrm
->HasPara() )
287 SwFrmSwapper
aSwapper( pFrm
, sal_True
);
289 nMaxY
= pFrm
->SwitchVerticalToHorizontal( nMaxY
);
291 sal_Bool bGoOn
= sal_True
;
292 xub_StrLen nOffset
= rPos
.nContent
.GetIndex();
293 xub_StrLen nNextOfst
;
298 SwTxtSizeInfo
aInf( pFrm
);
299 SwTxtCursor
aLine( pFrm
, &aInf
);
300 nNextOfst
= aLine
.GetEnd();
301 // Siehe Kommentar in AdjustFrm
302 // 1170: das letzte Zeichen der Zeile mitnehmen?
303 bRet
= bRightMargin
? aLine
.GetEndCharRect( &rOrig
, nOffset
, pCMS
, nMaxY
)
304 : aLine
.GetCharRect( &rOrig
, nOffset
, pCMS
, nMaxY
);
307 if ( pFrm
->IsRightToLeft() )
308 pFrm
->SwitchLTRtoRTL( rOrig
);
311 pFrm
->SwitchHorizontalToVertical( rOrig
);
313 if( pFrm
->IsUndersized() && pCMS
&& !pFrm
->GetNext() &&
314 (rOrig
.*fnRect
->fnGetBottom
)() == nUpperMaxY
&&
315 pFrm
->GetOfst() < nOffset
&&
316 !pFrm
->IsFollow() && !bNoScroll
&&
317 pFrm
->GetTxtNode()->GetTxt().Len() != nNextOfst
)
318 bGoOn
= lcl_ChangeOffset( pFrm
, nNextOfst
);
325 if ( pFrm
->IsRightToLeft() )
327 if( pCMS
->b2Lines
&& pCMS
->p2Lines
)
329 pFrm
->SwitchLTRtoRTL( pCMS
->p2Lines
->aLine
);
330 pFrm
->SwitchLTRtoRTL( pCMS
->p2Lines
->aPortion
);
336 if ( pCMS
->bRealHeight
)
338 pCMS
->aRealHeight
.Y() = -pCMS
->aRealHeight
.Y();
339 if ( pCMS
->aRealHeight
.Y() < 0 )
341 // writing direction is from top to bottom
342 pCMS
->aRealHeight
.X() = ( rOrig
.Width() -
343 pCMS
->aRealHeight
.X() +
344 pCMS
->aRealHeight
.Y() );
347 if( pCMS
->b2Lines
&& pCMS
->p2Lines
)
349 pFrm
->SwitchHorizontalToVertical( pCMS
->p2Lines
->aLine
);
350 pFrm
->SwitchHorizontalToVertical( pCMS
->p2Lines
->aPortion
);
358 SwPageFrm
*pPage
= pFrm
->FindPageFrm();
359 ASSERT( pPage
, "Text esaped from page?" );
360 const SwTwips nOrigTop
= (rOrig
.*fnRect
->fnGetTop
)();
361 const SwTwips nPageTop
= (pPage
->Frm().*fnRect
->fnGetTop
)();
362 const SwTwips nPageBott
= (pPage
->Frm().*fnRect
->fnGetBottom
)();
364 // Following situation: if the frame is in an invalid sectionframe,
365 // it's possible that the frame is outside the page. If we restrict
366 // the cursor position to the page area, we enforce the formatting
367 // of the page, of the section frame and the frame himself.
368 if( (*fnRect
->fnYDiff
)( nPageTop
, nOrigTop
) > 0 )
369 (rOrig
.*fnRect
->fnSetTop
)( nPageTop
);
371 if ( (*fnRect
->fnYDiff
)( nOrigTop
, nPageBott
) > 0 )
372 (rOrig
.*fnRect
->fnSetTop
)( nPageBott
);
378 /*************************************************************************
379 * SwTxtFrm::GetAutoPos()
380 *************************************************************************/
383 * GetAutoPos() findet die Characterzelle des Characters, dass
384 * durch aPos beschrieben wird und wird von autopositionierten Rahmen genutzt.
387 sal_Bool
SwTxtFrm::GetAutoPos( SwRect
& rOrig
, const SwPosition
&rPos
) const
392 xub_StrLen nOffset
= rPos
.nContent
.GetIndex();
393 SwTxtFrm
* pFrm
= &(const_cast<SwTxtFrm
*>(this)->GetFrmAtOfst( nOffset
));
395 pFrm
->GetFormatted();
396 const SwFrm
* pTmpFrm
= (SwFrm
*)pFrm
->GetUpper();
399 SwTwips nUpperMaxY
= (pTmpFrm
->*fnRect
->fnGetPrtBottom
)();
401 // nMaxY is in absolute value
402 SwTwips nMaxY
= bVert
?
403 Max( (pFrm
->*fnRect
->fnGetPrtBottom
)(), nUpperMaxY
) :
404 Min( (pFrm
->*fnRect
->fnGetPrtBottom
)(), nUpperMaxY
);
406 if ( pFrm
->IsEmpty() || ! (pFrm
->Prt().*fnRect
->fnGetHeight
)() )
408 Point aPnt1
= pFrm
->Frm().Pos() + pFrm
->Prt().Pos();
412 if ( aPnt1
.X() < nMaxY
)
414 aPnt2
.X() = aPnt1
.X() + pFrm
->Prt().Width();
415 aPnt2
.Y() = aPnt1
.Y();
416 if( aPnt2
.X() < nMaxY
)
421 if( aPnt1
.Y() > nMaxY
)
423 aPnt2
.X() = aPnt1
.X();
424 aPnt2
.Y() = aPnt1
.Y() + pFrm
->Prt().Height();
425 if( aPnt2
.Y() > nMaxY
)
428 rOrig
= SwRect( aPnt1
, aPnt2
);
433 if( !pFrm
->HasPara() )
436 SwFrmSwapper
aSwapper( pFrm
, sal_True
);
438 nMaxY
= pFrm
->SwitchVerticalToHorizontal( nMaxY
);
440 SwTxtSizeInfo
aInf( pFrm
);
441 SwTxtCursor
aLine( pFrm
, &aInf
);
442 SwCrsrMoveState
aTmpState( MV_SETONLYTEXT
);
443 aTmpState
.bRealHeight
= TRUE
;
444 if( aLine
.GetCharRect( &rOrig
, nOffset
, &aTmpState
, nMaxY
) )
446 if( aTmpState
.aRealHeight
.X() >= 0 )
448 rOrig
.Pos().Y() += aTmpState
.aRealHeight
.X();
449 rOrig
.Height( aTmpState
.aRealHeight
.Y() );
452 if ( pFrm
->IsRightToLeft() )
453 pFrm
->SwitchLTRtoRTL( rOrig
);
456 pFrm
->SwitchHorizontalToVertical( rOrig
);
464 /** determine top of line for given position in the text frame
466 OD 11.11.2003 #i22341#
467 OD 2004-03-18 #114789# - corrections:
468 - Top of first paragraph line is the top of the printing area of the text frame
469 - If a proportional line spacing is applied use top of anchor character as
474 bool SwTxtFrm::GetTopOfLine( SwTwips
& _onTopOfLine
,
475 const SwPosition
& _rPos
) const
479 // get position offset
480 xub_StrLen nOffset
= _rPos
.nContent
.GetIndex();
482 if ( GetTxt().Len() < nOffset
)
489 if ( IsEmpty() || !(Prt().*fnRect
->fnGetHeight
)() )
491 // OD 2004-03-18 #i11860# - consider upper space amount considered
492 // for previous frame and the page grid.
493 _onTopOfLine
= (this->*fnRect
->fnGetPrtTop
)();
497 // determine formatted text frame that contains the requested position
498 SwTxtFrm
* pFrm
= &(const_cast<SwTxtFrm
*>(this)->GetFrmAtOfst( nOffset
));
499 pFrm
->GetFormatted();
501 // OD 2004-03-18 #114789# - If proportional line spacing is applied
502 // to the text frame, the top of the anchor character is also the
504 // Otherwise the line layout determines the top of the line
505 const SvxLineSpacingItem
& rSpace
= GetAttrSet()->GetLineSpacing();
506 if ( rSpace
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP
)
509 if ( GetAutoPos( aCharRect
, _rPos
) )
511 _onTopOfLine
= (aCharRect
.*fnRect
->fnGetTop
)();
520 // assure that text frame is in a horizontal layout
521 SwFrmSwapper
aSwapper( pFrm
, sal_True
);
522 // determine text line that contains the requested position
523 SwTxtSizeInfo
aInf( pFrm
);
524 SwTxtCursor
aLine( pFrm
, &aInf
);
525 aLine
.CharCrsrToLine( nOffset
);
526 // determine top of line
527 _onTopOfLine
= aLine
.Y();
530 _onTopOfLine
= pFrm
->SwitchHorizontalToVertical( _onTopOfLine
);
539 /*************************************************************************
540 * SwTxtFrm::_GetCrsrOfst()
541 *************************************************************************/
543 // Minimaler Abstand von nichtleeren Zeilen etwas weniger als 2 cm
544 #define FILL_MIN_DIST 1100
549 const SwCrsrMoveState
*pCMS
;
553 sal_Bool bFirstLine
: 1;
555 sal_Bool bColumn
: 1;
557 SwFillData( const SwCrsrMoveState
*pC
, SwPosition
* pP
, const SwRect
& rR
,
558 const Point
& rPt
) : aFrm( rR
), pCMS( pC
), pPos( pP
), rPoint( rPt
),
559 nLineWidth( 0 ), bFirstLine( sal_True
), bInner( sal_False
), bColumn( sal_False
),
561 SwFillMode
Mode() const { return pCMS
->pFill
->eMode
; }
562 long X() const { return rPoint
.X(); }
563 long Y() const { return rPoint
.Y(); }
564 long Left() const { return aFrm
.Left(); }
565 long Right() const { return aFrm
.Right(); }
566 long Bottom() const { return aFrm
.Bottom(); }
567 SwRect
& Frm() { return aFrm
; }
568 SwFillCrsrPos
&Fill() const { return *pCMS
->pFill
; }
569 void SetTab( MSHORT nNew
) { pCMS
->pFill
->nTabCnt
= nNew
; }
570 void SetSpace( MSHORT nNew
) { pCMS
->pFill
->nSpaceCnt
= nNew
; }
571 void SetOrient( const sal_Int16 eNew
){ pCMS
->pFill
->eOrient
= eNew
; }
574 sal_Bool
SwTxtFrm::_GetCrsrOfst(SwPosition
* pPos
, const Point
& rPoint
,
575 const sal_Bool bChgFrm
, SwCrsrMoveState
* pCMS
) const
577 // 8804: _GetCrsrOfst wird vom GetCrsrOfst und GetKeyCrsrOfst gerufen.
578 // In keinem Fall nur ein return sal_False.
580 if( IsLocked() || IsHiddenNow() )
583 ((SwTxtFrm
*)this)->GetFormatted();
585 Point
aOldPoint( rPoint
);
589 SwitchVerticalToHorizontal( (Point
&)rPoint
);
590 ((SwTxtFrm
*)this)->SwapWidthAndHeight();
593 if ( IsRightToLeft() )
594 SwitchRTLtoLTR( (Point
&)rPoint
);
596 SwFillData
*pFillData
= ( pCMS
&& pCMS
->pFill
) ?
597 new SwFillData( pCMS
, pPos
, Frm(), rPoint
) : NULL
;
601 SwTxtNode
* pTxtNd
= ((SwTxtFrm
*)this)->GetTxtNode();
602 pPos
->nNode
= *pTxtNd
;
603 pPos
->nContent
.Assign( pTxtNd
, 0 );
604 if( pCMS
&& pCMS
->bFieldInfo
)
606 SwTwips nDiff
= rPoint
.X() - Frm().Left() - Prt().Left();
607 if( nDiff
> 50 || nDiff
< 0 )
608 ((SwCrsrMoveState
*)pCMS
)->bPosCorr
= sal_True
;
613 SwTxtSizeInfo
aInf( (SwTxtFrm
*)this );
614 SwTxtCursor
aLine( ((SwTxtFrm
*)this), &aInf
);
616 // Siehe Kommentar in AdjustFrm()
617 SwTwips nMaxY
= Frm().Top() + Prt().Top() + Prt().Height();
618 aLine
.TwipsToLine( rPoint
.Y() );
619 while( aLine
.Y() + aLine
.GetLineHeight() > nMaxY
)
626 if( aLine
.GetDropLines() >= aLine
.GetLineNr() && 1 != aLine
.GetLineNr()
627 && rPoint
.X() < aLine
.FirstLeft() + aLine
.GetDropLeft() )
628 while( aLine
.GetLineNr() > 1 )
631 xub_StrLen nOffset
= aLine
.GetCrsrOfst( pPos
, rPoint
, bChgFrm
, pCMS
);
633 if( pCMS
&& pCMS
->eState
== MV_NONE
&& aLine
.GetEnd() == nOffset
)
634 ((SwCrsrMoveState
*)pCMS
)->eState
= MV_RIGHTMARGIN
;
636 // 6776: pPos ist ein reiner IN-Parameter, der nicht ausgewertet werden darf.
637 // Das pIter->GetCrsrOfst returnt aus einer Verschachtelung mit STRING_LEN.
638 // Wenn SwTxtIter::GetCrsrOfst von sich aus weitere GetCrsrOfst
639 // ruft, so aendert sich nNode der Position. In solchen Faellen
640 // darf pPos nicht berechnet werden.
641 if( STRING_LEN
!= nOffset
)
643 SwTxtNode
* pTxtNd
= ((SwTxtFrm
*)this)->GetTxtNode();
644 pPos
->nNode
= *pTxtNd
;
645 pPos
->nContent
.Assign( pTxtNd
, nOffset
);
648 if( pTxtNd
->GetTxt().Len() > nOffset
||
649 rPoint
.Y() < Frm().Top() )
650 pFillData
->bInner
= sal_True
;
651 pFillData
->bFirstLine
= aLine
.GetLineNr() < 2;
652 if( pTxtNd
->GetTxt().Len() )
654 pFillData
->bEmpty
= sal_False
;
655 pFillData
->nLineWidth
= aLine
.GetCurr()->Width();
660 sal_Bool bChgFillData
= sal_False
;
661 if( pFillData
&& FindPageFrm()->Frm().IsInside( aOldPoint
) )
663 FillCrsrPos( *pFillData
);
664 bChgFillData
= sal_True
;
670 SwitchHorizontalToVertical( pFillData
->Fill().aCrsr
.Pos() );
671 ((SwTxtFrm
*)this)->SwapWidthAndHeight();
674 if ( IsRightToLeft() && bChgFillData
)
676 SwitchLTRtoRTL( pFillData
->Fill().aCrsr
.Pos() );
677 const sal_Int16 eOrient
= pFillData
->pCMS
->pFill
->eOrient
;
679 if ( text::HoriOrientation::LEFT
== eOrient
)
680 pFillData
->SetOrient( text::HoriOrientation::RIGHT
);
681 else if ( text::HoriOrientation::RIGHT
== eOrient
)
682 pFillData
->SetOrient( text::HoriOrientation::LEFT
);
685 (Point
&)rPoint
= aOldPoint
;
691 /*************************************************************************
692 * virtual SwTxtFrm::GetCrsrOfst()
693 *************************************************************************/
695 sal_Bool
SwTxtFrm::GetCrsrOfst(SwPosition
* pPos
, Point
& rPoint
,
696 SwCrsrMoveState
* pCMS
) const
701 if( MV_UPDOWN
== pCMS
->eState
)
703 else if( MV_SETONLYTEXT
== pCMS
->eState
||
704 MV_TBLSEL
== pCMS
->eState
)
707 return _GetCrsrOfst( pPos
, rPoint
, nChgFrm
!= 0, pCMS
);
710 /*************************************************************************
711 * SwTxtFrm::LeftMargin()
712 *************************************************************************/
715 * Layout-orientierte Cursorbewegungen
719 * an den Zeilenanfang
722 sal_Bool
SwTxtFrm::LeftMargin(SwPaM
*pPam
) const
724 if( ((const SwNode
*)pPam
->GetNode()) != GetNode() )
725 pPam
->GetPoint()->nNode
= *((SwTxtFrm
*)this)->GetTxtNode();
727 SwTxtFrm
*pFrm
= GetAdjFrmAtPos( (SwTxtFrm
*)this, *pPam
->GetPoint(),
728 SwTxtCursor::IsRightMargin() );
729 pFrm
->GetFormatted();
731 if ( pFrm
->IsEmpty() )
735 SwTxtSizeInfo
aInf( pFrm
);
736 SwTxtCursor
aLine( pFrm
, &aInf
);
738 aLine
.CharCrsrToLine(pPam
->GetPoint()->nContent
.GetIndex());
739 nIndx
= aLine
.GetStart();
740 if( pFrm
->GetOfst() && !pFrm
->IsFollow() && !aLine
.GetPrev() )
742 lcl_ChangeOffset( pFrm
, 0 );
746 pPam
->GetPoint()->nContent
= SwIndex( pFrm
->GetTxtNode(), nIndx
);
747 SwTxtCursor::SetRightMargin( sal_False
);
751 /*************************************************************************
752 * SwTxtFrm::RightMargin()
753 *************************************************************************/
756 * An das Zeilenende:Das ist die Position vor dem letzten
757 * Character in der Zeile. Ausnahme: In der letzten Zeile soll
758 * der Cursor auch hinter dem letzten Character stehen koennen,
759 * um Text anhaengen zu koennen.
763 sal_Bool
SwTxtFrm::RightMargin(SwPaM
*pPam
, sal_Bool bAPI
) const
765 if( ((const SwNode
*)pPam
->GetNode()) != GetNode() )
766 pPam
->GetPoint()->nNode
= *((SwTxtFrm
*)this)->GetTxtNode();
768 SwTxtFrm
*pFrm
= GetAdjFrmAtPos( (SwTxtFrm
*)this, *pPam
->GetPoint(),
769 SwTxtCursor::IsRightMargin() );
770 pFrm
->GetFormatted();
771 xub_StrLen nRightMargin
;
776 SwTxtSizeInfo
aInf( pFrm
);
777 SwTxtCursor
aLine( pFrm
, &aInf
);
779 aLine
.CharCrsrToLine(pPam
->GetPoint()->nContent
.GetIndex());
780 nRightMargin
= aLine
.GetStart() + aLine
.GetCurr()->GetLen();
782 // Harte Zeilenumbrueche lassen wir hinter uns.
783 if( aLine
.GetCurr()->GetLen() &&
784 CH_BREAK
== aInf
.GetTxt().GetChar( nRightMargin
- 1 ) )
786 if( !bAPI
&& (aLine
.GetNext() || pFrm
->GetFollow()) )
788 while( nRightMargin
> aLine
.GetStart() &&
789 ' ' == aInf
.GetTxt().GetChar( nRightMargin
- 1 ) )
793 pPam
->GetPoint()->nContent
= SwIndex( pFrm
->GetTxtNode(), nRightMargin
);
794 SwTxtCursor::SetRightMargin( !bAPI
);
798 /*************************************************************************
799 * SwTxtFrm::_UnitUp()
800 *************************************************************************/
802 //Die beiden folgenden Methoden versuchen zunaechst den Crsr in die
803 //nachste/folgende Zeile zu setzen. Gibt es im Frame keine vorhergehende/
804 //folgende Zeile, so wird der Aufruf an die Basisklasse weitergeleitet.
805 //Die Horizontale Ausrichtung des Crsr wird hinterher von der CrsrShell
808 class SwSetToRightMargin
812 inline SwSetToRightMargin() : bRight( sal_False
) { }
813 inline ~SwSetToRightMargin() { SwTxtCursor::SetRightMargin( bRight
); }
814 inline void SetRight( const sal_Bool bNew
) { bRight
= bNew
; }
817 sal_Bool
SwTxtFrm::_UnitUp( SwPaM
*pPam
, const SwTwips nOffset
,
818 sal_Bool bSetInReadOnly
) const
820 // 8626: Im Notfall den RightMargin setzen.
821 SwSetToRightMargin aSet
;
824 pPam
->GetNode( sal_True
)->StartOfSectionNode() !=
825 pPam
->GetNode( sal_False
)->StartOfSectionNode() )
827 //Wenn der PaM in unterschiedlichen Boxen sitzt, so handelt es sich um
828 //eine Tabellenselektion; diese wird von der Basisklasse abgearbeitet.
829 return SwCntntFrm::UnitUp( pPam
, nOffset
, bSetInReadOnly
);
832 ((SwTxtFrm
*)this)->GetFormatted();
833 const xub_StrLen nPos
= pPam
->GetPoint()->nContent
.GetIndex();
836 if( !IsEmpty() && !IsHiddenNow() )
838 xub_StrLen nFormat
= STRING_LEN
;
841 if( nFormat
!= STRING_LEN
&& !IsFollow() )
842 lcl_ChangeOffset( ((SwTxtFrm
*)this), nFormat
);
844 SwTxtSizeInfo
aInf( (SwTxtFrm
*)this );
845 SwTxtCursor
aLine( ((SwTxtFrm
*)this), &aInf
);
847 // 8116: Flys ohne Umlauf und IsDummy(); hier wegoptimiert
849 aLine
.CharCrsrToLine( nPos
);
853 const SwLineLayout
*pPrevLine
= aLine
.GetPrevLine();
854 const xub_StrLen nStart
= aLine
.GetStart();
855 aLine
.GetCharRect( &aCharBox
, nPos
);
857 sal_Bool bSecondOfDouble
= ( aInf
.IsMulti() && ! aInf
.IsFirstMulti() );
858 sal_Bool bPrevLine
= ( pPrevLine
&& pPrevLine
!= aLine
.GetCurr() );
860 if( !pPrevLine
&& !bSecondOfDouble
&& GetOfst() && !IsFollow() )
863 xub_StrLen nDiff
= aLine
.GetLength();
865 nDiff
= MIN_OFFSET_STEP
;
866 if( nFormat
> nDiff
)
867 nFormat
= nFormat
- nDiff
;
873 // we select the target line for the cursor, in case we are in a
874 // double line portion, prev line = curr line
875 if( bPrevLine
&& !bSecondOfDouble
)
878 while ( aLine
.GetStart() == nStart
&&
879 0 != ( pPrevLine
= aLine
.GetPrevLine() ) &&
880 pPrevLine
!= aLine
.GetCurr() )
884 if ( bPrevLine
|| bSecondOfDouble
)
886 aCharBox
.SSize().Width() /= 2;
887 aCharBox
.Pos().X() = aCharBox
.Pos().X() - 150;
889 // siehe Kommentar in SwTxtFrm::GetCrsrOfst()
891 const ULONG nOldNode
= pPam
->GetPoint()->nNode
.GetIndex();
893 // Der Node soll nicht gewechselt werden
894 xub_StrLen nTmpOfst
= aLine
.GetCrsrOfst( pPam
->GetPoint(),
895 aCharBox
.Pos(), sal_False
);
896 ASSERT( nOldNode
== pPam
->GetPoint()->nNode
.GetIndex(),
897 "SwTxtFrm::UnitUp: illegal node change" )
899 // 7684: Wir stellen sicher, dass wir uns nach oben bewegen.
900 if( nTmpOfst
>= nStart
&& nStart
&& !bSecondOfDouble
)
903 aSet
.SetRight( sal_True
);
905 pPam
->GetPoint()->nContent
=
906 SwIndex( ((SwTxtFrm
*)this)->GetTxtNode(), nTmpOfst
);
912 aLine
.GetCharRect( &aCharBox
, nPos
);
913 aCharBox
.SSize().Width() /= 2;
916 } while ( sal_True
);
918 /* Wenn this ein Follow ist und ein Prev miszlang, so
919 * muessen wir in die letzte Zeile des Master ... und der sind wir.
920 * Oder wir sind ein Follow mit Follow, dann muessen wir uns den
921 * Master extra besorgen...
925 const SwTxtFrm
*pTmpPrev
= FindMaster();
926 xub_StrLen nOffs
= GetOfst();
929 ViewShell
*pSh
= GetShell();
930 sal_Bool bProtectedAllowed
= pSh
&& pSh
->GetViewOptions()->IsCursorInProtectedArea();
931 const SwTxtFrm
*pPrevPrev
= pTmpPrev
;
932 // Hier werden geschuetzte Frames und Frame ohne Inhalt ausgelassen
933 while( pPrevPrev
&& ( pPrevPrev
->GetOfst() == nOffs
||
934 ( !bProtectedAllowed
&& pPrevPrev
->IsProtected() ) ) )
936 pTmpPrev
= pPrevPrev
;
937 nOffs
= pTmpPrev
->GetOfst();
938 if ( pPrevPrev
->IsFollow() )
939 pPrevPrev
= pTmpPrev
->FindMaster();
944 return pTmpPrev
->SwCntntFrm::UnitUp( pPam
, nOffset
, bSetInReadOnly
);
945 aCharBox
.Pos().Y() = pPrevPrev
->Frm().Bottom() - 1;
946 return pPrevPrev
->GetKeyCrsrOfst( pPam
->GetPoint(), aCharBox
.Pos() );
949 return SwCntntFrm::UnitUp( pPam
, nOffset
, bSetInReadOnly
);
953 // Used for Bidi. nPos is the logical position in the string, bLeft indicates
954 // if left arrow or right arrow was pressed. The return values are:
955 // nPos: the new visual position
956 // bLeft: whether the break iterator has to add or subtract from the
958 void lcl_VisualMoveRecursion( const SwLineLayout
& rCurrLine
, xub_StrLen nIdx
,
959 xub_StrLen
& nPos
, sal_Bool
& bRight
,
960 BYTE
& nCrsrLevel
, BYTE nDefaultDir
)
962 const SwLinePortion
* pPor
= rCurrLine
.GetFirstPortion();
963 const SwLinePortion
* pLast
= 0;
965 // what's the current portion
966 while ( pPor
&& nIdx
+ pPor
->GetLen() <= nPos
)
968 nIdx
= nIdx
+ pPor
->GetLen();
970 pPor
= pPor
->GetPortion();
975 sal_Bool bRecurse
= pPor
&& pPor
->IsMultiPortion() &&
976 ((SwMultiPortion
*)pPor
)->IsBidi();
978 // 1. special case: at beginning of bidi portion
979 if ( bRecurse
&& nIdx
== nPos
)
981 nPos
= nPos
+ pPor
->GetLen();
983 // leave bidi portion
984 if ( nCrsrLevel
!= nDefaultDir
)
986 bRecurse
= sal_False
;
990 // buffer: abcXYZ123 in LTR paragraph
992 // cursor is between c and X in the buffer and cursor level = 0
996 // 2. special case: at beginning of portion after bidi portion
997 else if ( pLast
&& pLast
->IsMultiPortion() &&
998 ((SwMultiPortion
*)pLast
)->IsBidi() && nIdx
== nPos
)
1000 // enter bidi portion
1001 if ( nCrsrLevel
!= nDefaultDir
)
1003 bRecurse
= sal_True
;
1004 nIdx
= nIdx
- pLast
->GetLen();
1012 const SwLineLayout
& rLine
= ((SwMultiPortion
*)pPor
)->GetRoot();
1013 xub_StrLen nTmpPos
= nPos
- nIdx
;
1014 sal_Bool bTmpForward
= ! bRight
;
1015 BYTE nTmpCrsrLevel
= nCrsrLevel
;
1016 lcl_VisualMoveRecursion( rLine
, 0, nTmpPos
, bTmpForward
,
1017 nTmpCrsrLevel
, nDefaultDir
+ 1 );
1019 nPos
= nTmpPos
+ nIdx
;
1020 bRight
= bTmpForward
;
1021 nCrsrLevel
= nTmpCrsrLevel
;
1028 nCrsrLevel
= nDefaultDir
;
1034 sal_Bool bRecurse
= pPor
&& pPor
->IsMultiPortion() && ((SwMultiPortion
*)pPor
)->IsBidi();
1036 // 1. special case: at beginning of bidi portion
1037 if ( bRecurse
&& nIdx
== nPos
)
1039 // leave bidi portion
1040 if ( nCrsrLevel
== nDefaultDir
)
1042 bRecurse
= sal_False
;
1046 // 2. special case: at beginning of portion after bidi portion
1047 else if ( pLast
&& pLast
->IsMultiPortion() &&
1048 ((SwMultiPortion
*)pLast
)->IsBidi() && nIdx
== nPos
)
1050 nPos
= nPos
- pLast
->GetLen();
1052 // enter bidi portion
1053 if ( nCrsrLevel
% 2 == nDefaultDir
% 2 )
1055 bRecurse
= sal_True
;
1056 nIdx
= nIdx
- pLast
->GetLen();
1060 // buffer: abcXYZ123 in LTR paragraph
1062 // cursor is behind 3 in the buffer and cursor level = 2
1063 if ( nDefaultDir
+ 2 == nCrsrLevel
)
1064 nPos
= nPos
+ pLast
->GetLen();
1071 const SwLineLayout
& rLine
= ((SwMultiPortion
*)pPor
)->GetRoot();
1072 xub_StrLen nTmpPos
= nPos
- nIdx
;
1073 sal_Bool bTmpForward
= ! bRight
;
1074 BYTE nTmpCrsrLevel
= nCrsrLevel
;
1075 lcl_VisualMoveRecursion( rLine
, 0, nTmpPos
, bTmpForward
,
1076 nTmpCrsrLevel
, nDefaultDir
+ 1 );
1079 // buffer: abcXYZ123 in LTR paragraph
1081 // cursor is between Z and 1 in the buffer and cursor level = 2
1082 if ( nTmpPos
== pPor
->GetLen() && nTmpCrsrLevel
== nDefaultDir
+ 1 )
1084 nTmpPos
= nTmpPos
- pPor
->GetLen();
1085 nTmpCrsrLevel
= nDefaultDir
;
1086 bTmpForward
= ! bTmpForward
;
1089 nPos
= nTmpPos
+ nIdx
;
1090 bRight
= bTmpForward
;
1091 nCrsrLevel
= nTmpCrsrLevel
;
1098 nCrsrLevel
= nDefaultDir
;
1103 void SwTxtFrm::PrepareVisualMove( xub_StrLen
& nPos
, BYTE
& nCrsrLevel
,
1104 sal_Bool
& bForward
, sal_Bool bInsertCrsr
)
1106 if( IsEmpty() || IsHiddenNow() )
1109 ((SwTxtFrm
*)this)->GetFormatted();
1111 SwTxtSizeInfo
aInf( (SwTxtFrm
*)this );
1112 SwTxtCursor
aLine( ((SwTxtFrm
*)this), &aInf
);
1115 aLine
.CharCrsrToLine( nPos
);
1119 const SwLineLayout
* pLine
= aLine
.GetCurr();
1120 const xub_StrLen nStt
= aLine
.GetStart();
1121 const xub_StrLen nLen
= pLine
->GetLen();
1123 // We have to distinguish between an insert and overwrite cursor:
1124 // The insert cursor position depends on the cursor level:
1125 // buffer: abcXYZdef in LTR paragraph
1126 // display: abcZYXdef
1127 // If cursor is between c and X in the buffer and cursor level is 0,
1128 // the cursor blinks between c and Z and -> sets the cursor between Z and Y.
1129 // If the cursor level is 1, the cursor blinks between X and d and
1130 // -> sets the cursor between d and e.
1131 // The overwrite cursor simply travels to the next visual character.
1134 lcl_VisualMoveRecursion( *pLine
, nStt
, nPos
, bForward
,
1135 nCrsrLevel
, IsRightToLeft() ? 1 : 0 );
1139 const BYTE nDefaultDir
= static_cast<BYTE
>(IsRightToLeft() ? UBIDI_RTL
: UBIDI_LTR
);
1140 const sal_Bool bVisualRight
= ( nDefaultDir
== UBIDI_LTR
&& bForward
) ||
1141 ( nDefaultDir
== UBIDI_RTL
&& ! bForward
);
1144 // Bidi functions from icu 2.0
1146 const sal_Unicode
* pLineString
= GetTxtNode()->GetTxt().GetBuffer();
1149 UErrorCode nError
= U_ZERO_ERROR
;
1150 UBiDi
* pBidi
= ubidi_openSized( nLen
, 0, &nError
);
1151 ubidi_setPara( pBidi
, reinterpret_cast<const UChar
*>(pLineString
), nLen
, nDefaultDir
, NULL
, &nError
); // UChar != sal_Unicode in MinGW
1154 sal_Bool bOutOfBounds
= sal_False
;
1156 if ( nPos
< nStt
+ nLen
)
1158 nTmpPos
= (xub_StrLen
)ubidi_getVisualIndex( pBidi
, nPos
, &nError
);
1160 // visual indices are always LTR aligned
1163 if ( nTmpPos
+ 1 < nStt
+ nLen
)
1167 nPos
= nDefaultDir
== UBIDI_RTL
? 0 : nStt
+ nLen
;
1168 bOutOfBounds
= sal_True
;
1177 nPos
= nDefaultDir
== UBIDI_RTL
? nStt
+ nLen
: 0;
1178 bOutOfBounds
= sal_True
;
1184 nTmpPos
= nDefaultDir
== UBIDI_LTR
? nPos
- 1 : 0;
1187 if ( ! bOutOfBounds
)
1189 nPos
= (xub_StrLen
)ubidi_getLogicalIndex( pBidi
, nTmpPos
, &nError
);
1198 bForward
= ! bForward
;
1205 ubidi_close( pBidi
);
1208 /*************************************************************************
1209 * SwTxtFrm::_UnitDown()
1210 *************************************************************************/
1212 sal_Bool
SwTxtFrm::_UnitDown(SwPaM
*pPam
, const SwTwips nOffset
,
1213 sal_Bool bSetInReadOnly
) const
1217 pPam
->GetNode( sal_True
)->StartOfSectionNode() !=
1218 pPam
->GetNode( sal_False
)->StartOfSectionNode() )
1220 //Wenn der PaM in unterschiedlichen Boxen sitzt, so handelt es sich um
1221 //eine Tabellenselektion; diese wird von der Basisklasse abgearbeitet.
1222 return SwCntntFrm::UnitDown( pPam
, nOffset
, bSetInReadOnly
);
1224 ((SwTxtFrm
*)this)->GetFormatted();
1225 const xub_StrLen nPos
= pPam
->GetPoint()->nContent
.GetIndex();
1227 const SwCntntFrm
*pTmpFollow
= 0;
1230 ((SwTxtFrm
*)this)->SwapWidthAndHeight();
1232 if ( !IsEmpty() && !IsHiddenNow() )
1234 xub_StrLen nFormat
= STRING_LEN
;
1237 if( nFormat
!= STRING_LEN
&& !IsFollow() &&
1238 !lcl_ChangeOffset( ((SwTxtFrm
*)this), nFormat
) )
1241 SwTxtSizeInfo
aInf( (SwTxtFrm
*)this );
1242 SwTxtCursor
aLine( ((SwTxtFrm
*)this), &aInf
);
1243 nFormat
= aLine
.GetEnd();
1245 aLine
.CharCrsrToLine( nPos
);
1247 const SwLineLayout
* pNextLine
= aLine
.GetNextLine();
1248 const xub_StrLen nStart
= aLine
.GetStart();
1249 aLine
.GetCharRect( &aCharBox
, nPos
);
1251 sal_Bool bFirstOfDouble
= ( aInf
.IsMulti() && aInf
.IsFirstMulti() );
1253 if( pNextLine
|| bFirstOfDouble
)
1255 aCharBox
.SSize().Width() /= 2;
1257 // siehe Kommentar in SwTxtFrm::GetCrsrOfst()
1258 const ULONG nOldNode
= pPam
->GetPoint()->nNode
.GetIndex();
1260 if ( pNextLine
&& ! bFirstOfDouble
)
1263 xub_StrLen nTmpOfst
= aLine
.GetCrsrOfst( pPam
->GetPoint(),
1264 aCharBox
.Pos(), sal_False
);
1265 ASSERT( nOldNode
== pPam
->GetPoint()->nNode
.GetIndex(),
1266 "SwTxtFrm::UnitDown: illegal node change" )
1268 // 7684: Wir stellen sicher, dass wir uns nach unten bewegen.
1269 if( nTmpOfst
<= nStart
&& ! bFirstOfDouble
)
1270 nTmpOfst
= nStart
+ 1;
1271 pPam
->GetPoint()->nContent
=
1272 SwIndex( ((SwTxtFrm
*)this)->GetTxtNode(), nTmpOfst
);
1275 ((SwTxtFrm
*)this)->SwapWidthAndHeight();
1279 if( 0 != ( pTmpFollow
= GetFollow() ) )
1280 { // geschuetzte Follows auslassen
1281 const SwCntntFrm
* pTmp
= pTmpFollow
;
1282 ViewShell
*pSh
= GetShell();
1283 if( !pSh
|| !pSh
->GetViewOptions()->IsCursorInProtectedArea() )
1285 while( pTmpFollow
&& pTmpFollow
->IsProtected() )
1288 pTmpFollow
= pTmpFollow
->GetFollow();
1291 if( !pTmpFollow
) // nur noch geschuetzte
1294 ((SwTxtFrm
*)this)->SwapWidthAndHeight();
1295 return pTmp
->SwCntntFrm::UnitDown( pPam
, nOffset
, bSetInReadOnly
);
1298 aLine
.GetCharRect( &aCharBox
, nPos
);
1299 aCharBox
.SSize().Width() /= 2;
1301 else if( !IsFollow() )
1303 xub_StrLen nTmpLen
= aInf
.GetTxt().Len();
1304 if( aLine
.GetEnd() < nTmpLen
)
1306 if( nFormat
<= GetOfst() )
1308 nFormat
= Min( xub_StrLen( GetOfst() + MIN_OFFSET_STEP
),
1310 if( nFormat
<= GetOfst() )
1317 } while( sal_True
);
1320 pTmpFollow
= GetFollow();
1323 ((SwTxtFrm
*)this)->SwapWidthAndHeight();
1325 // Bei Follows schlagen wir eine Abkuerzung
1328 aCharBox
.Pos().Y() = pTmpFollow
->Frm().Top() + 1;
1329 return ((SwTxtFrm
*)pTmpFollow
)->GetKeyCrsrOfst( pPam
->GetPoint(),
1332 return SwCntntFrm::UnitDown( pPam
, nOffset
, bSetInReadOnly
);
1335 /*************************************************************************
1336 * virtual SwTxtFrm::UnitUp()
1337 *************************************************************************/
1339 sal_Bool
SwTxtFrm::UnitUp(SwPaM
*pPam
, const SwTwips nOffset
,
1340 sal_Bool bSetInReadOnly
) const
1342 /* Im CrsrSh::Up() wird CntntNode::GetFrm() gerufen.
1343 * Dies liefert _immer_ den Master zurueck.
1344 * Um das Cursortravelling nicht zu belasten, korrigieren wir
1346 * Wir ermittelt UnitUp fuer pFrm, pFrm ist entweder ein Master (=this)
1347 * oder ein Follow (!=this)
1349 const SwTxtFrm
*pFrm
= GetAdjFrmAtPos( (SwTxtFrm
*)this, *(pPam
->GetPoint()),
1350 SwTxtCursor::IsRightMargin() );
1351 const sal_Bool bRet
= pFrm
->_UnitUp( pPam
, nOffset
, bSetInReadOnly
);
1353 // 8626: kein SwTxtCursor::SetRightMargin( sal_False );
1354 // statt dessen steht ein SwSetToRightMargin im _UnitUp
1358 /*************************************************************************
1359 * virtual SwTxtFrm::UnitDown()
1360 *************************************************************************/
1362 sal_Bool
SwTxtFrm::UnitDown(SwPaM
*pPam
, const SwTwips nOffset
,
1363 sal_Bool bSetInReadOnly
) const
1365 const SwTxtFrm
*pFrm
= GetAdjFrmAtPos((SwTxtFrm
*)this, *(pPam
->GetPoint()),
1366 SwTxtCursor::IsRightMargin() );
1367 const sal_Bool bRet
= pFrm
->_UnitDown( pPam
, nOffset
, bSetInReadOnly
);
1368 SwTxtCursor::SetRightMargin( sal_False
);
1372 void SwTxtFrm::FillCrsrPos( SwFillData
& rFill
) const
1374 if( !rFill
.bColumn
&& GetUpper()->IsColBodyFrm() ) // ColumnFrms jetzt mit BodyFrm
1376 const SwColumnFrm
* pTmp
=
1377 (SwColumnFrm
*)GetUpper()->GetUpper()->GetUpper()->Lower(); // die 1. Spalte
1378 // der erste SwFrm im BodyFrm der ersten Spalte
1379 const SwFrm
* pFrm
= ((SwLayoutFrm
*)pTmp
->Lower())->Lower();
1380 MSHORT nNextCol
= 0;
1381 // In welcher Spalte landen wir?
1382 while( rFill
.X() > pTmp
->Frm().Right() && pTmp
->GetNext() )
1384 pTmp
= (SwColumnFrm
*)pTmp
->GetNext();
1385 if( ((SwLayoutFrm
*)pTmp
->Lower())->Lower() ) // ColumnFrms jetzt mit BodyFrm
1387 pFrm
= ((SwLayoutFrm
*)pTmp
->Lower())->Lower();
1391 ++nNextCol
; // leere Spalten erfordern Spaltenumbrueche
1393 if( pTmp
!= GetUpper()->GetUpper() ) // Sind wir in einer anderen Spalte gelandet?
1399 while( pFrm
->GetNext() )
1400 pFrm
= pFrm
->GetNext();
1404 while( pFrm
->GetNext() && pFrm
->Frm().Bottom() < rFill
.Y() )
1405 pFrm
= pFrm
->GetNext();
1407 // Kein Fuellen, wenn als letzter Frame in der anvisierten
1408 // Spalte kein Absatz, sondern z.B. eine Tabelle steht
1409 if( pFrm
->IsTxtFrm() )
1411 rFill
.Fill().nColumnCnt
= nNextCol
;
1412 rFill
.bColumn
= sal_True
;
1415 SwTxtNode
* pTxtNd
= ((SwTxtFrm
*)pFrm
)->GetTxtNode();
1416 rFill
.pPos
->nNode
= *pTxtNd
;
1417 rFill
.pPos
->nContent
.Assign( pTxtNd
, pTxtNd
->GetTxt().Len() );
1421 rFill
.aFrm
= pTmp
->Prt();
1422 rFill
.aFrm
+= pTmp
->Frm().Pos();
1425 rFill
.aFrm
= pFrm
->Frm();
1426 ((SwTxtFrm
*)pFrm
)->FillCrsrPos( rFill
);
1431 sal_Bool bFill
= sal_True
;
1433 SwTxtFmtColl
* pColl
= GetTxtNode()->GetTxtColl();
1434 MSHORT nFirst
= GetTxtNode()->GetSwAttrSet().GetULSpace().GetLower();
1435 SwTwips nDiff
= rFill
.Y() - Frm().Bottom();
1436 if( nDiff
< nFirst
)
1439 pColl
= &pColl
->GetNextTxtFmtColl();
1440 SwAttrSet
aSet( ((SwDoc
*)GetTxtNode()->GetDoc())->GetAttrPool(), aTxtFmtCollSetRange
);
1441 const SwAttrSet
* pSet
= &pColl
->GetAttrSet();
1442 ViewShell
*pSh
= GetShell();
1443 if( GetTxtNode()->HasSwAttrSet() )
1445 aSet
.Put( *GetTxtNode()->GetpSwAttrSet() );
1446 aSet
.SetParent( pSet
);
1448 pFnt
= new SwFont( pSet
, GetNode()->getIDocumentSettingAccess() );
1452 SwFontAccess
aFontAccess( pColl
, pSh
);
1453 pFnt
= new SwFont( *aFontAccess
.Get()->GetFont() );
1454 pFnt
->ChkMagic( pSh
, pFnt
->GetActual() );
1456 OutputDevice
* pOut
= pSh
->GetOut();
1457 if ( !GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE
) ||
1458 ( pSh
->GetViewOptions()->IsPrtFormat() ) )
1459 pOut
= GetTxtNode()->getIDocumentDeviceAccess()->getReferenceDevice( true );
1461 pFnt
->SetFntChg( sal_True
);
1462 pFnt
->ChgPhysFnt( pSh
, *pOut
);
1464 SwTwips nLineHeight
= pFnt
->GetHeight( pSh
, *pOut
);
1468 const SvxULSpaceItem
&rUL
= pSet
->GetULSpace();
1469 SwTwips nDist
= Max( rUL
.GetLower(), rUL
.GetUpper() );
1470 if( rFill
.Fill().nColumnCnt
)
1472 rFill
.aFrm
.Height( nLineHeight
);
1473 nDiff
= rFill
.Y() - rFill
.Bottom();
1476 else if( nDist
< nFirst
)
1477 nFirst
= nFirst
- (USHORT
)nDist
;
1480 nDist
= Max( nDist
, long( GetLineSpace() ) );
1481 nDist
+= nLineHeight
;
1487 rFill
.Fill().nParaCnt
= static_cast<USHORT
>(nDiff
+ 1);
1488 rFill
.nLineWidth
= 0;
1489 rFill
.bInner
= sal_False
;
1490 rFill
.bEmpty
= sal_True
;
1491 rFill
.SetOrient( text::HoriOrientation::LEFT
);
1499 const SvxTabStopItem
&rRuler
= pSet
->GetTabStops();
1500 const SvxLRSpaceItem
&rLRSpace
= pSet
->GetLRSpace();
1502 SwRect
&rRect
= rFill
.Fill().aCrsr
;
1503 rRect
.Top( rFill
.Bottom() + (nDiff
+1) * nDist
- nLineHeight
);
1504 if( nFirst
&& nDiff
> -1 )
1505 rRect
.Top( rRect
.Top() + nFirst
);
1506 rRect
.Height( nLineHeight
);
1507 SwTwips nLeft
= rFill
.Left() + rLRSpace
.GetLeft() +
1508 GetTxtNode()->GetLeftMarginWithNum( sal_False
);
1509 SwTwips nRight
= rFill
.Right() - rLRSpace
.GetRight();
1510 SwTwips nCenter
= ( nLeft
+ nRight
) / 2;
1511 rRect
.Left( nLeft
);
1512 if( FILL_MARGIN
== rFill
.Mode() )
1516 rFill
.SetOrient( text::HoriOrientation::LEFT
);
1517 if( rFill
.X() < nCenter
)
1519 if( rFill
.X() > ( nLeft
+ 2 * nCenter
) / 3 )
1521 rFill
.SetOrient( text::HoriOrientation::CENTER
);
1522 rRect
.Left( nCenter
);
1525 else if( rFill
.X() > ( nRight
+ 2 * nCenter
) / 3 )
1527 rFill
.SetOrient( text::HoriOrientation::RIGHT
);
1528 rRect
.Left( nRight
);
1532 rFill
.SetOrient( text::HoriOrientation::CENTER
);
1533 rRect
.Left( nCenter
);
1542 if( FILL_TAB
!= rFill
.Mode() )
1544 static sal_Char __READONLY_DATA sDoubleSpace
[] = " ";
1545 const XubString
aTmp( sDoubleSpace
, RTL_TEXTENCODING_MS_1252
);
1547 SwDrawTextInfo
aDrawInf( pSh
, *pOut
, 0, aTmp
, 0, 2 );
1548 nSpace
= pFnt
->_GetTxtSize( aDrawInf
).Width()/2;
1550 if( rFill
.X() >= nRight
)
1552 if( FILL_INDENT
!= rFill
.Mode() && ( rFill
.bEmpty
||
1553 rFill
.X() > rFill
.nLineWidth
+ FILL_MIN_DIST
) )
1555 rFill
.SetOrient( text::HoriOrientation::RIGHT
);
1556 rRect
.Left( nRight
);
1561 else if( FILL_INDENT
== rFill
.Mode() )
1563 SwTwips nIndent
= rFill
.X();
1564 if( !rFill
.bEmpty
|| nIndent
> nRight
)
1568 nIndent
-= rFill
.Left();
1569 if( nIndent
>= 0 && nSpace
)
1573 rFill
.SetTab( MSHORT( nIndent
) );
1574 rRect
.Left( nIndent
+ rFill
.Left() );
1580 else if( rFill
.X() > nLeft
)
1582 SwTwips nTxtLeft
= rFill
.Left() + rLRSpace
.GetTxtLeft() +
1583 GetTxtNode()->GetLeftMarginWithNum( sal_True
);
1584 rFill
.nLineWidth
+= rFill
.bFirstLine
? nLeft
: nTxtLeft
;
1585 SwTwips nLeftTab
= nLeft
;
1586 SwTwips nRightTab
= nLeft
;
1587 MSHORT nSpaceCnt
= 0;
1592 nLeftTab
= nRightTab
;
1593 if( nIdx
< rRuler
.Count() )
1595 const SvxTabStop
&rTabStop
= rRuler
.operator[](nIdx
);
1596 nRightTab
= nTxtLeft
+ rTabStop
.GetTabPos();
1597 if( nLeftTab
< nTxtLeft
&& nRightTab
> nTxtLeft
)
1598 nRightTab
= nTxtLeft
;
1601 if( nRightTab
> rFill
.nLineWidth
)
1606 const SvxTabStopItem
& rTab
=
1607 (const SvxTabStopItem
&)pSet
->
1608 GetPool()->GetDefaultItem( RES_PARATR_TABSTOP
);
1609 MSHORT nDefTabDist
= (MSHORT
)rTab
.GetStart()->GetTabPos();
1610 nRightTab
= nLeftTab
- nTxtLeft
;
1611 nRightTab
/= nDefTabDist
;
1612 nRightTab
= nRightTab
* nDefTabDist
+ nTxtLeft
;
1613 while ( nRightTab
<= nLeftTab
)
1614 nRightTab
+= nDefTabDist
;
1615 if( nRightTab
> rFill
.nLineWidth
)
1617 while ( nRightTab
< rFill
.X() )
1619 nRightTab
+= nDefTabDist
;
1620 if( nRightTab
> rFill
.nLineWidth
)
1623 if( nLeftTab
< nRightTab
- nDefTabDist
)
1624 nLeftTab
= nRightTab
- nDefTabDist
;
1626 if( nRightTab
> nRight
)
1629 while( rFill
.X() > nRightTab
);
1631 if( FILL_TAB
!= rFill
.Mode() )
1636 nLeftTab
= rFill
.nLineWidth
;
1637 while( nLeftTab
< rFill
.X() )
1647 if( rFill
.X() - nLeftTab
> nRightTab
- rFill
.X() )
1651 rRect
.Left( nRightTab
);
1655 if( rFill
.X() - nLeftTab
> nSpace
/2 )
1658 rRect
.Left( nLeftTab
+ nSpace
);
1661 rRect
.Left( nLeftTab
);
1664 else if( rFill
.X() - nLeftTab
< nRightTab
- rFill
.X() )
1665 rRect
.Left( nLeftTab
);
1668 if( nRightTab
>= nRight
)
1670 rFill
.SetOrient( text::HoriOrientation::RIGHT
);
1671 rRect
.Left( nRight
);
1677 rRect
.Left( nRightTab
);
1684 if( rFill
.X() - nLeftTab
< nRightTab
- rFill
.X() )
1685 rRect
.Left( nLeftTab
);
1688 if( nRightTab
>= nRight
)
1690 rFill
.SetOrient( text::HoriOrientation::RIGHT
);
1691 rRect
.Left( nRight
);
1697 rRect
.Left( nRightTab
);
1702 rFill
.SetTab( nTabCnt
);
1703 rFill
.SetSpace( nSpaceCnt
);
1706 if( Abs( rFill
.X() - nCenter
) <=
1707 Abs( rFill
.X() - rRect
.Left() ) )
1709 rFill
.SetOrient( text::HoriOrientation::CENTER
);
1711 rFill
.SetSpace( 0 );
1712 rRect
.Left( nCenter
);
1715 rFill
.nLineWidth
+= FILL_MIN_DIST
;
1716 if( rRect
.Left() < rFill
.nLineWidth
)
1721 // Gehen wir ueber die Unterkante der Seite/Spalte etc. hinaus?
1722 const SwFrm
* pUp
= GetUpper();
1723 if( pUp
->IsInSct() )
1725 if( pUp
->IsSctFrm() )
1726 pUp
= pUp
->GetUpper();
1727 else if( pUp
->IsColBodyFrm() &&
1728 pUp
->GetUpper()->GetUpper()->IsSctFrm() )
1729 pUp
= pUp
->GetUpper()->GetUpper()->GetUpper();
1732 SwTwips nLimit
= (pUp
->*fnRect
->fnGetPrtBottom
)();
1733 SwTwips nRectBottom
= rRect
.Bottom();
1735 nRectBottom
= SwitchHorizontalToVertical( nRectBottom
);
1737 if( (*fnRect
->fnYDiff
)( nLimit
, nRectBottom
) < 0 )
1745 ((SwCrsrMoveState
*)rFill
.pCMS
)->bFillRet
= bFill
;