Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <hintids.hxx>
21 : #include <hints.hxx>
22 : #include <tools/bigint.hxx>
23 : #include <tools/line.hxx>
24 : #include <editeng/opaqitem.hxx>
25 : #include <editeng/protitem.hxx>
26 : #include <vcl/settings.hxx>
27 : #include <vcl/outdev.hxx>
28 : #include <fmtpdsc.hxx>
29 : #include <fmtsrnd.hxx>
30 : #include <pagedesc.hxx>
31 : #include <pagefrm.hxx>
32 : #include <rootfrm.hxx>
33 : #include <cntfrm.hxx>
34 : #include <ftnfrm.hxx>
35 : #include <flyfrm.hxx>
36 : #include <tabfrm.hxx>
37 : #include <rowfrm.hxx>
38 : #include <cellfrm.hxx>
39 : #include <txtfrm.hxx>
40 : #include <viewsh.hxx>
41 : #include <viewopt.hxx>
42 : #include <doc.hxx>
43 : #include <viscrs.hxx>
44 : #include <frmfmt.hxx>
45 : #include <swtable.hxx>
46 : #include <dflyobj.hxx>
47 : #include <crstate.hxx>
48 : #include <frmtool.hxx>
49 : #include <ndtxt.hxx>
50 : #include <dcontact.hxx>
51 : // OD 2004-05-24 #i28701#
52 : #include <sortedobjs.hxx>
53 : #include <txatbase.hxx>
54 : #include <fmtfld.hxx>
55 : #include <fldbas.hxx>
56 :
57 : // FLT_MAX
58 : #include <cfloat>
59 : #include <swselectionlist.hxx>
60 :
61 : #include <basegfx/numeric/ftools.hxx>
62 :
63 : namespace {
64 0 : bool lcl_GetCrsrOfst_Objects( const SwPageFrm* pPageFrm, bool bSearchBackground,
65 : SwPosition *pPos, Point& rPoint, SwCrsrMoveState* pCMS )
66 : {
67 0 : bool bRet = false;
68 0 : Point aPoint( rPoint );
69 0 : SwOrderIter aIter( pPageFrm );
70 0 : aIter.Top();
71 0 : while ( aIter() )
72 : {
73 : const SwVirtFlyDrawObj* pObj =
74 0 : static_cast<const SwVirtFlyDrawObj*>(aIter());
75 0 : const SwAnchoredObject* pAnchoredObj = GetUserCall( aIter() )->GetAnchoredObj( aIter() );
76 0 : const SwFmtSurround& rSurround = pAnchoredObj->GetFrmFmt().GetSurround();
77 0 : const SvxOpaqueItem& rOpaque = pAnchoredObj->GetFrmFmt().GetOpaque();
78 0 : bool bInBackground = ( rSurround.GetSurround() == SURROUND_THROUGHT ) && !rOpaque.GetValue();
79 :
80 0 : bool bBackgroundMatches = ( bInBackground && bSearchBackground ) ||
81 0 : ( !bInBackground && !bSearchBackground );
82 :
83 0 : const SwFlyFrm* pFly = pObj ? pObj->GetFlyFrm() : 0;
84 0 : if ( pFly && bBackgroundMatches &&
85 0 : ( ( pCMS ? pCMS->bSetInReadOnly : false ) ||
86 0 : !pFly->IsProtected() ) &&
87 0 : pFly->GetCrsrOfst( pPos, aPoint, pCMS ) )
88 : {
89 0 : bRet = true;
90 0 : break;
91 : }
92 :
93 0 : if ( pCMS && pCMS->bStop )
94 0 : return false;
95 0 : aIter.Prev();
96 : }
97 0 : return bRet;
98 : }
99 :
100 0 : double lcl_getDistance( const SwRect& rRect, const Point& rPoint )
101 : {
102 0 : double nDist = 0.0;
103 :
104 : // If the point is inside the rectangle, then distance is 0
105 : // Otherwise, compute the distance to the center of the rectangle.
106 0 : if ( !rRect.IsInside( rPoint ) )
107 : {
108 0 : Line aLine( rPoint, rRect.Center( ) );
109 0 : nDist = aLine.GetLength( );
110 : }
111 :
112 0 : return nDist;
113 : }
114 : }
115 :
116 :
117 : //Fuer SwFlyFrm::GetCrsrOfst
118 : class SwCrsrOszControl
119 : {
120 : public:
121 : // damit schon der Compiler die Klasse initialisieren kann, keinen
122 : // DTOR und member als publics:
123 : const SwFlyFrm *pEntry;
124 : const SwFlyFrm *pStk1;
125 : const SwFlyFrm *pStk2;
126 :
127 : //public:
128 : // SwCrsrOszControl() : pStk1( 0 ), pStk2( 0 ) {}; // ; <- ????
129 :
130 0 : bool ChkOsz( const SwFlyFrm *pFly )
131 : {
132 0 : bool bRet = true;
133 0 : if ( pFly != pStk1 && pFly != pStk2 )
134 : {
135 0 : pStk1 = pStk2;
136 0 : pStk2 = pFly;
137 0 : bRet = false;
138 : }
139 0 : return bRet;
140 : }
141 0 : void Entry( const SwFlyFrm *pFly )
142 : {
143 0 : if ( !pEntry )
144 0 : pEntry = pStk1 = pFly;
145 0 : }
146 0 : void Exit( const SwFlyFrm *pFly )
147 : {
148 0 : if ( pFly == pEntry )
149 0 : pEntry = pStk1 = pStk2 = 0;
150 0 : }
151 : };
152 :
153 : static SwCrsrOszControl aOszCtrl = { 0, 0, 0 };
154 :
155 : /*************************************************************************
156 : |*
157 : |* SwLayoutFrm::GetCrsrOfst()
158 : |*
159 : |* Beschreibung: Sucht denjenigen CntntFrm, innerhalb dessen
160 : |* PrtArea der Point liegt.
161 : |*
162 : |*************************************************************************/
163 469 : sal_Bool SwLayoutFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
164 : SwCrsrMoveState* pCMS, bool ) const
165 : {
166 469 : sal_Bool bRet = sal_False;
167 469 : const SwFrm *pFrm = Lower();
168 1407 : while ( !bRet && pFrm )
169 : {
170 469 : pFrm->Calc();
171 :
172 : // #i43742# New function
173 469 : const bool bCntntCheck = pFrm->IsTxtFrm() && pCMS && pCMS->bCntntCheck;
174 : const SwRect aPaintRect( bCntntCheck ?
175 : pFrm->UnionFrm() :
176 469 : pFrm->PaintArea() );
177 :
178 681 : if ( aPaintRect.IsInside( rPoint ) &&
179 342 : ( bCntntCheck || pFrm->GetCrsrOfst( pPos, rPoint, pCMS ) ) )
180 212 : bRet = sal_True;
181 : else
182 257 : pFrm = pFrm->GetNext();
183 469 : if ( pCMS && pCMS->bStop )
184 0 : return sal_False;
185 : }
186 469 : return bRet;
187 : }
188 :
189 : /*************************************************************************
190 : |*
191 : |* SwPageFrm::GetCrsrOfst()
192 : |*
193 : |* Beschreibung: Sucht die Seite, innerhalb der der gesuchte Point
194 : |* liegt.
195 : |*
196 : |*************************************************************************/
197 :
198 236 : sal_Bool SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
199 : SwCrsrMoveState* pCMS, bool bTestBackground ) const
200 : {
201 236 : sal_Bool bRet = sal_False;
202 236 : Point aPoint( rPoint );
203 :
204 : // check, if we have to adjust the point
205 236 : if ( !Frm().IsInside( aPoint ) )
206 : {
207 1 : aPoint.X() = std::max( aPoint.X(), Frm().Left() );
208 1 : aPoint.X() = std::min( aPoint.X(), Frm().Right() );
209 1 : aPoint.Y() = std::max( aPoint.Y(), Frm().Top() );
210 1 : aPoint.Y() = std::min( aPoint.Y(), Frm().Bottom() );
211 : }
212 :
213 236 : sal_Bool bTextRet, bBackRet = sal_False;
214 :
215 : //Koennte ein Freifliegender gemeint sein?
216 : //Wenn sein Inhalt geschuetzt werden soll, so ist nix mit Crsr
217 : //hineinsetzen, dadurch sollten alle Aenderungen unmoeglich sein.
218 236 : if ( GetSortedObjs() )
219 : {
220 0 : bRet = lcl_GetCrsrOfst_Objects( this, false, pPos, rPoint, pCMS );
221 : }
222 :
223 236 : if ( !bRet )
224 : {
225 236 : SwPosition aBackPos( *pPos );
226 472 : SwPosition aTextPos( *pPos );
227 :
228 : //Wenn kein Cntnt unterhalb der Seite 'antwortet', so korrigieren
229 : //wir den StartPoint und fangen nochmal eine Seite vor der
230 : //aktuellen an. Mit Flys ist es dann allerdings vorbei.
231 236 : if ( SwLayoutFrm::GetCrsrOfst( &aTextPos, aPoint, pCMS ) )
232 : {
233 106 : bTextRet = sal_True;
234 : }
235 : else
236 : {
237 130 : if ( pCMS && (pCMS->bStop || pCMS->bExactOnly) )
238 : {
239 0 : ((SwCrsrMoveState*)pCMS)->bStop = sal_True;
240 0 : return sal_False;
241 : }
242 130 : const SwCntntFrm *pCnt = GetCntntPos( aPoint, sal_False, sal_False, sal_False, pCMS, sal_False );
243 130 : if ( pCMS && pCMS->bStop )
244 0 : return sal_False;
245 :
246 : OSL_ENSURE( pCnt, "Crsr is gone to a Black hole" );
247 130 : if( pCMS && pCMS->pFill && pCnt->IsTxtFrm() )
248 0 : bTextRet = pCnt->GetCrsrOfst( &aTextPos, rPoint, pCMS );
249 : else
250 130 : bTextRet = pCnt->GetCrsrOfst( &aTextPos, aPoint, pCMS );
251 :
252 130 : if ( !bTextRet )
253 : {
254 : // Set point to pCnt, delete mark
255 : // this may happen, if pCnt is hidden
256 9 : aTextPos = SwPosition( *pCnt->GetNode(), SwIndex( (SwTxtNode*)pCnt->GetNode(), 0 ) );
257 9 : bTextRet = sal_True;
258 : }
259 : }
260 :
261 236 : SwCntntNode* pTextNd = aTextPos.nNode.GetNode( ).GetCntntNode( );
262 236 : bool bConsiderBackground = true;
263 : // If the text position is a clickable field, then that should have priority.
264 236 : if (pTextNd && pTextNd->IsTxtNode())
265 : {
266 236 : SwTxtNode* pTxtNd = pTextNd->GetTxtNode();
267 236 : SwTxtAttr* pTxtAttr = pTxtNd->GetTxtAttrForCharAt(aTextPos.nContent.GetIndex(), RES_TXTATR_FIELD);
268 236 : if (pTxtAttr)
269 : {
270 0 : const SwField* pField = pTxtAttr->GetFld().GetFld();
271 0 : if (pField->IsClickable())
272 0 : bConsiderBackground = false;
273 : }
274 : }
275 :
276 : // Check objects in the background if nothing else matched
277 236 : if ( GetSortedObjs() )
278 : {
279 0 : bBackRet = lcl_GetCrsrOfst_Objects( this, true, &aBackPos, rPoint, pCMS );
280 : }
281 :
282 236 : if ( ( bConsiderBackground && bTestBackground && bBackRet ) || !bTextRet )
283 : {
284 0 : bRet = bBackRet;
285 0 : (*pPos) = aBackPos;
286 : }
287 236 : else if (bTextRet && !bBackRet)
288 : {
289 236 : bRet = bTextRet;
290 236 : (*pPos) = aTextPos;
291 : }
292 : else
293 : {
294 : /* In order to provide a selection as accurable as possible when we have both
295 : * text and brackground object, then we compute the distance between both
296 : * would-be positions and the click point. The shortest distance wins.
297 : */
298 0 : double nTextDistance = 0;
299 0 : bool bValidTextDistance = false;
300 0 : if ( pTextNd )
301 : {
302 0 : SwCntntFrm* pTextFrm = pTextNd->getLayoutFrm( getRootFrm( ) );
303 0 : SwRect rTextRect;
304 0 : pTextFrm->GetCharRect( rTextRect, aTextPos );
305 :
306 0 : nTextDistance = lcl_getDistance( rTextRect, rPoint );
307 0 : bValidTextDistance = true;
308 : }
309 :
310 0 : double nBackDistance = 0;
311 0 : bool bValidBackDistance = false;
312 0 : SwCntntNode* pBackNd = aBackPos.nNode.GetNode( ).GetCntntNode( );
313 0 : if ( pBackNd && bConsiderBackground)
314 : {
315 : // FIXME There are still cases were we don't have the proper node here.
316 0 : SwCntntFrm* pBackFrm = pBackNd->getLayoutFrm( getRootFrm( ) );
317 0 : SwRect rBackRect;
318 0 : if (pBackFrm)
319 : {
320 0 : pBackFrm->GetCharRect( rBackRect, aBackPos );
321 :
322 0 : nBackDistance = lcl_getDistance( rBackRect, rPoint );
323 0 : bValidBackDistance = true;
324 : }
325 : }
326 :
327 0 : if ( bValidTextDistance && bValidBackDistance && basegfx::fTools::more( nTextDistance, nBackDistance ) )
328 : {
329 0 : bRet = bBackRet;
330 0 : (*pPos) = aBackPos;
331 : }
332 : else
333 : {
334 0 : bRet = bTextRet;
335 0 : (*pPos) = aTextPos;
336 : }
337 236 : }
338 : }
339 :
340 236 : if ( bRet )
341 236 : rPoint = aPoint;
342 :
343 236 : return bRet;
344 : }
345 :
346 0 : bool SwLayoutFrm::FillSelection( SwSelectionList& rList, const SwRect& rRect ) const
347 : {
348 0 : bool bRet = false;
349 0 : if( rRect.IsOver(PaintArea()) )
350 : {
351 0 : const SwFrm* pFrm = Lower();
352 0 : while( pFrm )
353 : {
354 0 : pFrm->FillSelection( rList, rRect );
355 0 : pFrm = pFrm->GetNext();
356 : }
357 : }
358 0 : return bRet;
359 : }
360 :
361 0 : bool SwPageFrm::FillSelection( SwSelectionList& rList, const SwRect& rRect ) const
362 : {
363 0 : bool bRet = false;
364 0 : if( rRect.IsOver(PaintArea()) )
365 : {
366 0 : bRet = SwLayoutFrm::FillSelection( rList, rRect );
367 0 : if( GetSortedObjs() )
368 : {
369 0 : const SwSortedObjs &rObjs = *GetSortedObjs();
370 0 : for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
371 : {
372 0 : const SwAnchoredObject* pAnchoredObj = rObjs[i];
373 0 : if( !pAnchoredObj->ISA(SwFlyFrm) )
374 0 : continue;
375 0 : const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj);
376 0 : if( pFly->FillSelection( rList, rRect ) )
377 0 : bRet = true;
378 : }
379 : }
380 : }
381 0 : return bRet;
382 : }
383 :
384 0 : bool SwRootFrm::FillSelection( SwSelectionList& aSelList, const SwRect& rRect) const
385 : {
386 0 : const SwFrm *pPage = Lower();
387 0 : const long nBottom = rRect.Bottom();
388 0 : while( pPage )
389 : {
390 0 : if( pPage->Frm().Top() < nBottom )
391 : {
392 0 : if( pPage->Frm().Bottom() > rRect.Top() )
393 0 : pPage->FillSelection( aSelList, rRect );
394 0 : pPage = pPage->GetNext();
395 : }
396 : else
397 0 : pPage = 0;
398 : }
399 0 : return !aSelList.isEmpty();
400 : }
401 :
402 : /*************************************************************************
403 : |*
404 : |* SwRootFrm::GetCrsrOfst()
405 : |*
406 : |* Beschreibung: Reicht Primaer den Aufruf an die erste Seite weiter.
407 : |* Wenn der 'reingereichte Point veraendert wird,
408 : |* so wird sal_False zurueckgegeben.
409 : |*
410 : |*************************************************************************/
411 236 : sal_Bool SwRootFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
412 : SwCrsrMoveState* pCMS, bool bTestBackground ) const
413 : {
414 236 : sal_Bool bOldAction = IsCallbackActionEnabled();
415 236 : ((SwRootFrm*)this)->SetCallbackActionEnabled( sal_False );
416 : OSL_ENSURE( (Lower() && Lower()->IsPageFrm()), "Keinen PageFrm gefunden." );
417 236 : if( pCMS && pCMS->pFill )
418 0 : ((SwCrsrMoveState*)pCMS)->bFillRet = sal_False;
419 236 : Point aOldPoint = rPoint;
420 :
421 : // search for page containing rPoint. The borders around the pages are considerd
422 236 : const SwPageFrm* pPage = GetPageAtPos( rPoint, 0, true );
423 :
424 : // #i95626#
425 : // special handling for <rPoint> beyond root frames area
426 236 : if ( !pPage &&
427 236 : rPoint.X() > Frm().Right() &&
428 0 : rPoint.Y() > Frm().Bottom() )
429 : {
430 0 : pPage = dynamic_cast<const SwPageFrm*>(Lower());
431 0 : while ( pPage && pPage->GetNext() )
432 : {
433 0 : pPage = dynamic_cast<const SwPageFrm*>(pPage->GetNext());
434 : }
435 : }
436 236 : if ( pPage )
437 : {
438 236 : pPage->SwPageFrm::GetCrsrOfst( pPos, rPoint, pCMS, bTestBackground );
439 : }
440 :
441 236 : ((SwRootFrm*)this)->SetCallbackActionEnabled( bOldAction );
442 236 : if( pCMS )
443 : {
444 236 : if( pCMS->bStop )
445 0 : return sal_False;
446 236 : if( pCMS->pFill )
447 0 : return pCMS->bFillRet;
448 : }
449 236 : return aOldPoint == rPoint;
450 : }
451 :
452 : /*************************************************************************
453 : |*
454 : |* SwCellFrm::GetCrsrOfst()
455 : |*
456 : |* Beschreibung Wenn es sich um eine Cntnt-tragende Cell handelt wird
457 : |* der Crsr notfalls mit Gewalt in einen der CntntFrms
458 : |* gesetzt.
459 : |* In geschuetzte Zellen gibt es hier keinen Eingang.
460 : |*
461 : |*************************************************************************/
462 0 : sal_Bool SwCellFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
463 : SwCrsrMoveState* pCMS, bool ) const
464 : {
465 : // cell frame does not necessarily have a lower (split table cell)
466 0 : if ( !Lower() )
467 0 : return sal_False;
468 :
469 0 : if ( !(pCMS?pCMS->bSetInReadOnly:sal_False) &&
470 0 : GetFmt()->GetProtect().IsCntntProtected() )
471 0 : return sal_False;
472 :
473 0 : if ( pCMS && pCMS->eState == MV_TBLSEL )
474 : {
475 0 : const SwTabFrm *pTab = FindTabFrm();
476 0 : if ( pTab->IsFollow() && pTab->IsInHeadline( *this ) )
477 : {
478 0 : ((SwCrsrMoveState*)pCMS)->bStop = sal_True;
479 0 : return sal_False;
480 : }
481 : }
482 :
483 0 : if ( Lower() )
484 : {
485 0 : if ( Lower()->IsLayoutFrm() )
486 0 : return SwLayoutFrm::GetCrsrOfst( pPos, rPoint, pCMS );
487 : else
488 : {
489 0 : Calc();
490 0 : sal_Bool bRet = sal_False;
491 :
492 0 : const SwFrm *pFrm = Lower();
493 0 : while ( pFrm && !bRet )
494 : {
495 0 : pFrm->Calc();
496 0 : if ( pFrm->Frm().IsInside( rPoint ) )
497 : {
498 0 : bRet = pFrm->GetCrsrOfst( pPos, rPoint, pCMS );
499 0 : if ( pCMS && pCMS->bStop )
500 0 : return sal_False;
501 : }
502 0 : pFrm = pFrm->GetNext();
503 : }
504 0 : if ( !bRet )
505 : {
506 0 : Point *pPoint = pCMS && pCMS->pFill ? new Point( rPoint ) : NULL;
507 0 : const SwCntntFrm *pCnt = GetCntntPos( rPoint, sal_True );
508 0 : if( pPoint && pCnt->IsTxtFrm() )
509 : {
510 0 : pCnt->GetCrsrOfst( pPos, *pPoint, pCMS );
511 0 : rPoint = *pPoint;
512 : }
513 : else
514 0 : pCnt->GetCrsrOfst( pPos, rPoint, pCMS );
515 0 : delete pPoint;
516 : }
517 0 : return sal_True;
518 : }
519 : }
520 :
521 0 : return sal_False;
522 : }
523 :
524 : /*************************************************************************
525 : |*
526 : |* SwFlyFrm::GetCrsrOfst()
527 : |*
528 : |*************************************************************************/
529 : //Problem: Wenn zwei Flys genau gleich gross sind und auf derselben
530 : //Position stehen, so liegt jeder innerhalb des anderen.
531 : //Da jeweils geprueft wird, ob der Point nicht zufaellig innerhalb eines
532 : //anderen Flys liegt, der sich vollstaendig innerhalb des aktuellen befindet
533 : //und ggf. ein rekursiver Aufruf erfolgt wuerde o.g. Situation zu einer
534 : //endlosen Rekursion fuehren.
535 : //Mit der Hilfsklasse SwCrsrOszControl unterbinden wir die Rekursion. Das
536 : //GetCrsrOfst entscheidet sich bei einer Rekursion fuer denjenigen der
537 : //am weitesten oben liegt.
538 :
539 0 : sal_Bool SwFlyFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint,
540 : SwCrsrMoveState* pCMS, bool ) const
541 : {
542 0 : aOszCtrl.Entry( this );
543 :
544 : //Wenn der Point innerhalb des Fly sitzt wollen wir energisch
545 : //versuchen den Crsr hineinzusetzen.
546 : //Wenn der Point allerdings in einem Flys sitzt, der sich vollstaendig
547 : //innerhalb des aktuellen befindet, so wird fuer diesen das
548 : //GetCrsrOfst gerufen.
549 0 : Calc();
550 0 : sal_Bool bInside = Frm().IsInside( rPoint ) && Lower(),
551 0 : bRet = sal_False;
552 :
553 : //Wenn der Frm eine Grafik enthaelt, aber nur Text gewuenscht ist, so
554 : //nimmt er den Crsr grundsaetzlich nicht an.
555 0 : if ( bInside && pCMS && pCMS->eState == MV_SETONLYTEXT &&
556 0 : (!Lower() || Lower()->IsNoTxtFrm()) )
557 0 : bInside = sal_False;
558 :
559 0 : const SwPageFrm *pPage = FindPageFrm();
560 0 : if ( bInside && pPage && pPage->GetSortedObjs() )
561 : {
562 0 : SwOrderIter aIter( pPage );
563 0 : aIter.Top();
564 0 : while ( aIter() && !bRet )
565 : {
566 0 : const SwVirtFlyDrawObj* pObj = static_cast<const SwVirtFlyDrawObj*>(aIter());
567 0 : const SwFlyFrm* pFly = pObj ? pObj->GetFlyFrm() : 0;
568 0 : if ( pFly && pFly->Frm().IsInside( rPoint ) &&
569 0 : Frm().IsInside( pFly->Frm() ) )
570 : {
571 0 : if ( aOszCtrl.ChkOsz( pFly ) ||
572 0 : sal_True == (bRet = pFly->GetCrsrOfst( pPos, rPoint, pCMS )))
573 0 : break;
574 0 : if ( pCMS && pCMS->bStop )
575 0 : return sal_False;
576 : }
577 0 : aIter.Next();
578 : }
579 : }
580 :
581 0 : while ( bInside && !bRet )
582 : {
583 0 : const SwFrm *pFrm = Lower();
584 0 : while ( pFrm && !bRet )
585 : {
586 0 : pFrm->Calc();
587 0 : if ( pFrm->Frm().IsInside( rPoint ) )
588 : {
589 0 : bRet = pFrm->GetCrsrOfst( pPos, rPoint, pCMS );
590 0 : if ( pCMS && pCMS->bStop )
591 0 : return sal_False;
592 : }
593 0 : pFrm = pFrm->GetNext();
594 : }
595 0 : if ( !bRet )
596 : {
597 0 : Point *pPoint = pCMS && pCMS->pFill ? new Point( rPoint ) : NULL;
598 : const SwCntntFrm *pCnt = GetCntntPos(
599 0 : rPoint, sal_True, sal_False, sal_False, pCMS );
600 0 : if ( pCMS && pCMS->bStop )
601 0 : return sal_False;
602 0 : if( pPoint && pCnt->IsTxtFrm() )
603 : {
604 0 : pCnt->GetCrsrOfst( pPos, *pPoint, pCMS );
605 0 : rPoint = *pPoint;
606 : }
607 : else
608 0 : pCnt->GetCrsrOfst( pPos, rPoint, pCMS );
609 0 : delete pPoint;
610 0 : bRet = sal_True;
611 : }
612 : }
613 0 : aOszCtrl.Exit( this );
614 0 : return bRet;
615 : }
616 :
617 : /*************************************************************************
618 : |*
619 : |* Beschreibung Layoutabhaengiges Cursortravelling
620 : |*
621 : |*************************************************************************/
622 0 : sal_Bool SwCntntFrm::LeftMargin(SwPaM *pPam) const
623 : {
624 0 : if( pPam->GetNode() != (SwCntntNode*)GetNode() )
625 0 : return sal_False;
626 0 : ((SwCntntNode*)GetNode())->
627 0 : MakeStartIndex((SwIndex *) &pPam->GetPoint()->nContent);
628 0 : return sal_True;
629 : }
630 :
631 0 : sal_Bool SwCntntFrm::RightMargin(SwPaM *pPam, sal_Bool) const
632 : {
633 0 : if( pPam->GetNode() != (SwCntntNode*)GetNode() )
634 0 : return sal_False;
635 0 : ((SwCntntNode*)GetNode())->
636 0 : MakeEndIndex((SwIndex *) &pPam->GetPoint()->nContent);
637 0 : return sal_True;
638 : }
639 :
640 2 : static const SwCntntFrm *lcl_GetNxtCnt( const SwCntntFrm* pCnt )
641 : {
642 2 : return pCnt->GetNextCntntFrm();
643 : }
644 :
645 4 : static const SwCntntFrm *lcl_GetPrvCnt( const SwCntntFrm* pCnt )
646 : {
647 4 : return pCnt->GetPrevCntntFrm();
648 : }
649 :
650 : typedef const SwCntntFrm *(*GetNxtPrvCnt)( const SwCntntFrm* );
651 :
652 : //Frame in wiederholter Headline?
653 6 : static bool lcl_IsInRepeatedHeadline( const SwFrm *pFrm,
654 : const SwTabFrm** ppTFrm = 0 )
655 : {
656 6 : const SwTabFrm *pTab = pFrm->FindTabFrm();
657 6 : if( ppTFrm )
658 0 : *ppTFrm = pTab;
659 6 : return pTab && pTab->IsFollow() && pTab->IsInHeadline( *pFrm );
660 : }
661 :
662 :
663 : //Ueberspringen geschuetzter Tabellenzellen. Optional auch
664 : //Ueberspringen von wiederholten Headlines.
665 : //MA 26. Jan. 98: Chg auch andere Geschuetzte Bereiche ueberspringen.
666 : // FME: Skip follow flow cells
667 137 : static const SwCntntFrm * lcl_MissProtectedFrames( const SwCntntFrm *pCnt,
668 : GetNxtPrvCnt fnNxtPrv,
669 : sal_Bool bMissHeadline,
670 : sal_Bool bInReadOnly,
671 : sal_Bool bMissFollowFlowLine )
672 : {
673 137 : if ( pCnt && pCnt->IsInTab() )
674 : {
675 6 : sal_Bool bProtect = sal_True;
676 18 : while ( pCnt && bProtect )
677 : {
678 6 : const SwLayoutFrm *pCell = pCnt->GetUpper();
679 12 : while ( pCell && !pCell->IsCellFrm() )
680 0 : pCell = pCell->GetUpper();
681 12 : if ( !pCell ||
682 0 : (( ( bInReadOnly || !pCell->GetFmt()->GetProtect().IsCntntProtected() ) &&
683 6 : ( !bMissHeadline || !lcl_IsInRepeatedHeadline( pCell ) ) &&
684 6 : ( !bMissFollowFlowLine || !pCell->IsInFollowFlowRow() ) &&
685 6 : !pCell->IsCoveredCell()) ) )
686 6 : bProtect = sal_False;
687 : else
688 0 : pCnt = (*fnNxtPrv)( pCnt );
689 : }
690 : }
691 131 : else if ( !bInReadOnly )
692 246 : while ( pCnt && pCnt->IsProtected() )
693 0 : pCnt = (*fnNxtPrv)( pCnt );
694 :
695 137 : return pCnt;
696 : }
697 :
698 3 : static sal_Bool lcl_UpDown( SwPaM *pPam, const SwCntntFrm *pStart,
699 : GetNxtPrvCnt fnNxtPrv, sal_Bool bInReadOnly )
700 : {
701 : OSL_ENSURE( pPam->GetNode() == (SwCntntNode*)pStart->GetNode(),
702 : "lcl_UpDown arbeitet nicht fuer andere." );
703 :
704 3 : const SwCntntFrm *pCnt = 0;
705 :
706 : //Wenn gerade eine Tabellenselection laeuft muss ein bischen getricktst
707 : //werden: Beim hochlaufen an den Anfang der Zelle gehen, beim runterlaufen
708 : //an das Ende der Zelle gehen.
709 3 : sal_Bool bTblSel = false;
710 6 : if ( pStart->IsInTab() &&
711 3 : pPam->GetNode( sal_True )->StartOfSectionNode() !=
712 3 : pPam->GetNode( sal_False )->StartOfSectionNode() )
713 : {
714 0 : bTblSel = true;
715 0 : const SwLayoutFrm *pCell = pStart->GetUpper();
716 0 : while ( !pCell->IsCellFrm() )
717 0 : pCell = pCell->GetUpper();
718 :
719 : //
720 : // Check, if cell has a Prev/Follow cell:
721 : //
722 0 : const bool bFwd = ( fnNxtPrv == lcl_GetNxtCnt );
723 : const SwLayoutFrm* pTmpCell = bFwd ?
724 : ((SwCellFrm*)pCell)->GetFollowCell() :
725 0 : ((SwCellFrm*)pCell)->GetPreviousCell();
726 :
727 0 : const SwCntntFrm* pTmpStart = pStart;
728 0 : while ( pTmpCell && 0 != ( pTmpStart = pTmpCell->ContainsCntnt() ) )
729 : {
730 0 : pCell = pTmpCell;
731 : pTmpCell = bFwd ?
732 : ((SwCellFrm*)pCell)->GetFollowCell() :
733 0 : ((SwCellFrm*)pCell)->GetPreviousCell();
734 : }
735 0 : const SwCntntFrm *pNxt = pCnt = pTmpStart;
736 :
737 0 : while ( pCell->IsAnLower( pNxt ) )
738 : {
739 0 : pCnt = pNxt;
740 0 : pNxt = (*fnNxtPrv)( pNxt );
741 : }
742 : }
743 :
744 3 : pCnt = (*fnNxtPrv)( pCnt ? pCnt : pStart );
745 3 : pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel );
746 :
747 :
748 3 : const SwTabFrm *pStTab = pStart->FindTabFrm();
749 3 : const SwTabFrm *pTable = 0;
750 3 : const sal_Bool bTab = pStTab || (pCnt && pCnt->IsInTab()) ? sal_True : sal_False;
751 3 : sal_Bool bEnd = bTab ? sal_False : sal_True;
752 :
753 3 : const SwFrm* pVertRefFrm = pStart;
754 3 : if ( bTblSel && pStTab )
755 0 : pVertRefFrm = pStTab;
756 3 : SWRECTFN( pVertRefFrm )
757 :
758 3 : SwTwips nX = 0;
759 3 : if ( bTab )
760 : {
761 : //
762 : // pStart or pCnt is inside a table. nX will be used for travelling:
763 : //
764 3 : SwRect aRect( pStart->Frm() );
765 3 : pStart->GetCharRect( aRect, *pPam->GetPoint() );
766 3 : Point aCenter = aRect.Center();
767 3 : nX = bVert ? aCenter.Y() : aCenter.X();
768 :
769 3 : pTable = pCnt ? pCnt->FindTabFrm() : 0;
770 3 : if ( !pTable )
771 0 : pTable = pStTab;
772 :
773 6 : if ( pStTab &&
774 6 : !pStTab->GetUpper()->IsInTab() &&
775 3 : !pTable->GetUpper()->IsInTab() )
776 : {
777 3 : const SwFrm *pCell = pStart->GetUpper();
778 6 : while ( pCell && !pCell->IsCellFrm() )
779 0 : pCell = pCell->GetUpper();
780 : OSL_ENSURE( pCell, "Zelle nicht gefunden." );
781 3 : nX = (pCell->Frm().*fnRect->fnGetLeft)() +
782 3 : (pCell->Frm().*fnRect->fnGetWidth)() / 2;
783 :
784 : //Der Fluss fuehrt von einer Tabelle in die nachste. Der X-Wert
785 : //muss ausgehend von der Mitte der Startzelle um die Verschiebung
786 : //der Tabellen korrigiert werden.
787 3 : if ( pStTab != pTable )
788 : {
789 0 : nX += (pTable->Frm().*fnRect->fnGetLeft)() -
790 0 : (pStTab->Frm().*fnRect->fnGetLeft)();
791 : }
792 : }
793 :
794 : //
795 : // Restrict nX to the left and right borders of pTab:
796 : // (is this really necessary?)
797 : //
798 3 : if ( !pTable->GetUpper()->IsInTab() )
799 : {
800 3 : const sal_Bool bRTL = pTable->IsRightToLeft();
801 : const long nPrtLeft = bRTL ?
802 0 : (pTable->*fnRect->fnGetPrtRight)() :
803 3 : (pTable->*fnRect->fnGetPrtLeft)();
804 3 : if ( bRTL != (nX < nPrtLeft) )
805 0 : nX = nPrtLeft;
806 : else
807 : {
808 : const long nPrtRight = bRTL ?
809 0 : (pTable->*fnRect->fnGetPrtLeft)() :
810 3 : (pTable->*fnRect->fnGetPrtRight)();
811 3 : if ( bRTL != (nX > nPrtRight) )
812 0 : nX = nPrtRight;
813 : }
814 : }
815 : }
816 :
817 6 : do
818 : {
819 : //Wenn ich im DokumentBody bin, so will ich da auch bleiben
820 6 : if ( pStart->IsInDocBody() )
821 : {
822 18 : while ( pCnt && (!pCnt->IsInDocBody() ||
823 12 : (pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow())))
824 : {
825 0 : pCnt = (*fnNxtPrv)( pCnt );
826 0 : pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel );
827 : }
828 : }
829 :
830 : //Wenn ich im Fussnotenbereich bin, so versuche ich notfalls den naechsten
831 : //Fussnotenbereich zu erreichen.
832 0 : else if ( pStart->IsInFtn() )
833 : {
834 0 : while ( pCnt && (!pCnt->IsInFtn() ||
835 0 : (pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow())))
836 : {
837 0 : pCnt = (*fnNxtPrv)( pCnt );
838 0 : pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel );
839 : }
840 : }
841 :
842 : //In Flys kann es Blind weitergehen solange ein Cntnt
843 : //gefunden wird.
844 0 : else if ( pStart->IsInFly() )
845 : {
846 0 : if ( pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow() )
847 : {
848 0 : pCnt = (*fnNxtPrv)( pCnt );
849 0 : pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel );
850 : }
851 : }
852 :
853 : //Andernfalls weigere ich mich einfach den derzeitigen Bereich zu
854 : //verlassen.
855 0 : else if ( pCnt )
856 : {
857 0 : const SwFrm *pUp = pStart->GetUpper(); //Head/Foot
858 0 : while ( pUp && pUp->GetUpper() && !(pUp->GetType() & 0x0018 ) )
859 0 : pUp = pUp->GetUpper();
860 0 : sal_Bool bSame = sal_False;
861 0 : const SwFrm *pCntUp = pCnt->GetUpper();
862 0 : while ( pCntUp && !bSame )
863 0 : { if ( pUp == pCntUp )
864 0 : bSame = sal_True;
865 : else
866 0 : pCntUp = pCntUp->GetUpper();
867 : }
868 0 : if ( !bSame )
869 0 : pCnt = 0;
870 0 : else if ( pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow() ) // i73332
871 : {
872 0 : pCnt = (*fnNxtPrv)( pCnt );
873 0 : pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel );
874 : }
875 : }
876 :
877 6 : if ( bTab )
878 : {
879 6 : if ( !pCnt )
880 0 : bEnd = sal_True;
881 : else
882 6 : { const SwTabFrm *pTab = pCnt->FindTabFrm();
883 6 : if( !pTab )
884 0 : bEnd = sal_True;
885 : else
886 : {
887 6 : if ( pTab != pTable )
888 : {
889 : //Der Fluss fuehrt von einer Tabelle in die nachste. Der
890 : //X-Wert muss um die Verschiebung der Tabellen korrigiert
891 : //werden.
892 0 : if ( pTable &&
893 0 : !pTab->GetUpper()->IsInTab() &&
894 0 : !pTable->GetUpper()->IsInTab() )
895 0 : nX += pTab->Frm().Left() - pTable->Frm().Left();
896 0 : pTable = pTab;
897 : }
898 6 : const SwLayoutFrm *pCell = pTable ? pCnt->GetUpper() : 0;
899 12 : while ( pCell && !pCell->IsCellFrm() )
900 0 : pCell = pCell->GetUpper();
901 :
902 6 : Point aInsideCell;
903 6 : Point aInsideCnt;
904 6 : if ( pCell )
905 : {
906 6 : long nTmpTop = (pCell->Frm().*fnRect->fnGetTop)();
907 6 : if ( bVert )
908 : {
909 0 : if ( nTmpTop )
910 0 : --nTmpTop;
911 :
912 0 : aInsideCell = Point( nTmpTop, nX );
913 : }
914 : else
915 6 : aInsideCell = Point( nX, nTmpTop );
916 : }
917 :
918 6 : long nTmpTop = (pCnt->Frm().*fnRect->fnGetTop)();
919 6 : if ( bVert )
920 : {
921 0 : if ( nTmpTop )
922 0 : --nTmpTop;
923 :
924 0 : aInsideCnt = Point( nTmpTop, nX );
925 : }
926 : else
927 6 : aInsideCnt = Point( nX, nTmpTop );
928 :
929 6 : if ( pCell && pCell->Frm().IsInside( aInsideCell ) )
930 : {
931 3 : bEnd = sal_True;
932 : //Jetzt noch schnell den richtigen Cntnt in der Zelle
933 : //greifen.
934 3 : if ( !pCnt->Frm().IsInside( aInsideCnt ) )
935 : {
936 0 : pCnt = pCell->ContainsCntnt();
937 0 : if ( fnNxtPrv == lcl_GetPrvCnt )
938 0 : while ( pCell->IsAnLower(pCnt->GetNextCntntFrm()) )
939 0 : pCnt = pCnt->GetNextCntntFrm();
940 : }
941 : }
942 3 : else if ( pCnt->Frm().IsInside( aInsideCnt ) )
943 0 : bEnd = sal_True;
944 : }
945 : }
946 6 : if ( !bEnd )
947 : {
948 3 : pCnt = (*fnNxtPrv)( pCnt );
949 3 : pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel );
950 : }
951 : }
952 :
953 9 : } while ( !bEnd ||
954 3 : (pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow()));
955 :
956 3 : if( pCnt )
957 : { // setze den Point auf den Content-Node
958 3 : SwCntntNode *pCNd = (SwCntntNode*)pCnt->GetNode();
959 3 : pPam->GetPoint()->nNode = *pCNd;
960 3 : if ( fnNxtPrv == lcl_GetPrvCnt )
961 2 : pCNd->MakeEndIndex( (SwIndex*)&pPam->GetPoint()->nContent );
962 : else
963 1 : pCNd->MakeStartIndex( (SwIndex*)&pPam->GetPoint()->nContent );
964 3 : return sal_True;
965 : }
966 0 : return sal_False;
967 : }
968 :
969 2 : sal_Bool SwCntntFrm::UnitUp( SwPaM* pPam, const SwTwips, sal_Bool bInReadOnly ) const
970 : {
971 2 : return ::lcl_UpDown( pPam, this, lcl_GetPrvCnt, bInReadOnly );
972 : }
973 :
974 1 : sal_Bool SwCntntFrm::UnitDown( SwPaM* pPam, const SwTwips, sal_Bool bInReadOnly ) const
975 : {
976 1 : return ::lcl_UpDown( pPam, this, lcl_GetNxtCnt, bInReadOnly );
977 : }
978 :
979 : /*************************************************************************
980 : |*
981 : |* SwRootFrm::GetCurrPage()
982 : |*
983 : |* Beschreibung: Liefert die Nummer der aktuellen Seite.
984 : |* Wenn die Methode einen PaM bekommt, so ist die aktuelle Seite
985 : |* diejenige in der der PaM sitzt. Anderfalls ist die aktuelle
986 : |* Seite die erste Seite innerhalb der VisibleArea.
987 : |* Es wird nur auf den vorhandenen Seiten gearbeitet!
988 : |*
989 : |*************************************************************************/
990 0 : sal_uInt16 SwRootFrm::GetCurrPage( const SwPaM *pActualCrsr ) const
991 : {
992 : OSL_ENSURE( pActualCrsr, "Welche Seite soll's denn sein?" );
993 0 : SwFrm const*const pActFrm = pActualCrsr->GetPoint()->nNode.GetNode().
994 : GetCntntNode()->getLayoutFrm( this, 0,
995 : pActualCrsr->GetPoint(),
996 0 : sal_False );
997 0 : return pActFrm->FindPageFrm()->GetPhyPageNum();
998 : }
999 :
1000 : /*************************************************************************
1001 : |*
1002 : |* SwRootFrm::SetCurrPage()
1003 : |*
1004 : |* Beschreibung: Liefert einen PaM der am Anfang der gewuenschten
1005 : |* Seite sitzt.
1006 : |* Formatiert wird soweit notwendig
1007 : |* Liefert Null, wenn die Operation nicht moeglich ist.
1008 : |* Der PaM sitzt in der letzten Seite, wenn die Seitenzahl zu gross
1009 : |* gewaehlt wurde.
1010 : |*
1011 : |*************************************************************************/
1012 1 : sal_uInt16 SwRootFrm::SetCurrPage( SwCursor* pToSet, sal_uInt16 nPageNum )
1013 : {
1014 : OSL_ENSURE( Lower() && Lower()->IsPageFrm(), "Keine Seite vorhanden." );
1015 :
1016 1 : SwPageFrm *pPage = (SwPageFrm*)Lower();
1017 1 : sal_Bool bEnd =sal_False;
1018 2 : while ( !bEnd && pPage->GetPhyPageNum() != nPageNum )
1019 0 : { if ( pPage->GetNext() )
1020 0 : pPage = (SwPageFrm*)pPage->GetNext();
1021 : else
1022 : { //Ersten CntntFrm Suchen, und solange Formatieren bis
1023 : //eine neue Seite angefangen wird oder bis die CntntFrm's alle
1024 : //sind.
1025 0 : const SwCntntFrm *pCntnt = pPage->ContainsCntnt();
1026 0 : while ( pCntnt && pPage->IsAnLower( pCntnt ) )
1027 : {
1028 0 : pCntnt->Calc();
1029 0 : pCntnt = pCntnt->GetNextCntntFrm();
1030 : }
1031 : //Jetzt ist entweder eine neue Seite da, oder die letzte Seite
1032 : //ist gefunden.
1033 0 : if ( pPage->GetNext() )
1034 0 : pPage = (SwPageFrm*)pPage->GetNext();
1035 : else
1036 0 : bEnd = sal_True;
1037 : }
1038 : }
1039 : //pPage zeigt jetzt auf die 'gewuenschte' Seite. Jetzt muss noch der
1040 : //PaM auf den Anfang des ersten CntntFrm im Body-Text erzeugt werden.
1041 : //Wenn es sich um eine Fussnotenseite handelt, wird der PaM in die erste
1042 : //Fussnote gesetzt.
1043 1 : const SwCntntFrm *pCntnt = pPage->ContainsCntnt();
1044 1 : if ( pPage->IsFtnPage() )
1045 0 : while ( pCntnt && !pCntnt->IsInFtn() )
1046 0 : pCntnt = pCntnt->GetNextCntntFrm();
1047 : else
1048 2 : while ( pCntnt && !pCntnt->IsInDocBody() )
1049 0 : pCntnt = pCntnt->GetNextCntntFrm();
1050 1 : if ( pCntnt )
1051 : {
1052 1 : SwCntntNode* pCNd = (SwCntntNode*)pCntnt->GetNode();
1053 1 : pToSet->GetPoint()->nNode = *pCNd;
1054 1 : pCNd->MakeStartIndex( (SwIndex*)&pToSet->GetPoint()->nContent );
1055 1 : pToSet->GetPoint()->nContent = ((SwTxtFrm*)pCntnt)->GetOfst();
1056 :
1057 1 : SwShellCrsr* pSCrsr = dynamic_cast<SwShellCrsr*>(pToSet);
1058 1 : if( pSCrsr )
1059 : {
1060 1 : Point &rPt = pSCrsr->GetPtPos();
1061 1 : rPt = pCntnt->Frm().Pos();
1062 1 : rPt += pCntnt->Prt().Pos();
1063 : }
1064 1 : return pPage->GetPhyPageNum();
1065 : }
1066 0 : return 0;
1067 : }
1068 :
1069 : /*************************************************************************
1070 : |*
1071 : |* SwCntntFrm::StartxxPage(), EndxxPage()
1072 : |*
1073 : |* Beschreibung Cursor an Anfang/Ende der aktuellen/vorherigen/
1074 : |* naechsten Seite. Alle sechs Methoden rufen GetFrmInPage() mit der
1075 : |* entsprechenden Parametrisierung.
1076 : |* Zwei Parameter steuern die Richtung: einer bestimmt die Seite, der
1077 : |* andere Anfang/Ende.
1078 : |* Fuer die Bestimmung der Seite und des Cntnt (Anfang/Ende) werden
1079 : |* die im folgenden definierten Funktionen benutzt.
1080 : |*
1081 : |*************************************************************************/
1082 16 : SwCntntFrm *GetFirstSub( const SwLayoutFrm *pLayout )
1083 : {
1084 16 : return ((SwPageFrm*)pLayout)->FindFirstBodyCntnt();
1085 : }
1086 :
1087 2 : SwCntntFrm *GetLastSub( const SwLayoutFrm *pLayout )
1088 : {
1089 2 : return ((SwPageFrm*)pLayout)->FindLastBodyCntnt();
1090 : }
1091 :
1092 1 : SwLayoutFrm *GetNextFrm( const SwLayoutFrm *pFrm )
1093 : {
1094 : SwLayoutFrm *pNext =
1095 2 : (pFrm->GetNext() && pFrm->GetNext()->IsLayoutFrm()) ?
1096 2 : (SwLayoutFrm*)pFrm->GetNext() : 0;
1097 : // #i39402# in case of an empty page
1098 1 : if(pNext && !pNext->ContainsCntnt())
1099 0 : pNext = (pNext->GetNext() && pNext->GetNext()->IsLayoutFrm()) ?
1100 0 : (SwLayoutFrm*)pNext->GetNext() : 0;
1101 1 : return pNext;
1102 : }
1103 :
1104 16 : SwLayoutFrm *GetThisFrm( const SwLayoutFrm *pFrm )
1105 : {
1106 16 : return (SwLayoutFrm*)pFrm;
1107 : }
1108 :
1109 1 : SwLayoutFrm *GetPrevFrm( const SwLayoutFrm *pFrm )
1110 : {
1111 : SwLayoutFrm *pPrev =
1112 2 : (pFrm->GetPrev() && pFrm->GetPrev()->IsLayoutFrm()) ?
1113 2 : (SwLayoutFrm*)pFrm->GetPrev() : 0;
1114 : // #i39402# in case of an empty page
1115 1 : if(pPrev && !pPrev->ContainsCntnt())
1116 0 : pPrev = (pPrev->GetPrev() && pPrev->GetPrev()->IsLayoutFrm()) ?
1117 0 : (SwLayoutFrm*)pPrev->GetPrev() : 0;
1118 1 : return pPrev;
1119 : }
1120 :
1121 : //Jetzt koennen auch die Funktionspointer initalisiert werden;
1122 : //sie sind in cshtyp.hxx declariert.
1123 : SwPosPage fnPageStart = GetFirstSub;
1124 : SwPosPage fnPageEnd = GetLastSub;
1125 : SwWhichPage fnPagePrev = GetPrevFrm;
1126 : SwWhichPage fnPageCurr = GetThisFrm;
1127 : SwWhichPage fnPageNext = GetNextFrm;
1128 :
1129 : //Liefert den ersten/den letzten Contentframe (gesteuert ueber
1130 : //den Parameter fnPosPage) in der
1131 : //aktuellen/vorhergehenden/folgenden Seite (gesteuert durch den
1132 : //Parameter fnWhichPage).
1133 18 : sal_Bool GetFrmInPage( const SwCntntFrm *pCnt, SwWhichPage fnWhichPage,
1134 : SwPosPage fnPosPage, SwPaM *pPam )
1135 : {
1136 : //Erstmal die gewuenschte Seite besorgen, anfangs die aktuelle, dann
1137 : //die die per fnWichPage gewuenscht wurde
1138 18 : const SwLayoutFrm *pLayoutFrm = pCnt->FindPageFrm();
1139 18 : if ( !pLayoutFrm || (0 == (pLayoutFrm = (*fnWhichPage)(pLayoutFrm))) )
1140 0 : return sal_False;
1141 :
1142 : //Jetzt den gewuenschen CntntFrm unterhalb der Seite
1143 18 : if( 0 == (pCnt = (*fnPosPage)(pLayoutFrm)) )
1144 0 : return sal_False;
1145 : else
1146 : {
1147 : // repeated headlines in tables
1148 18 : if ( pCnt->IsInTab() && fnPosPage == GetFirstSub )
1149 : {
1150 1 : const SwTabFrm* pTab = pCnt->FindTabFrm();
1151 1 : if ( pTab->IsFollow() )
1152 : {
1153 1 : if ( pTab->IsInHeadline( *pCnt ) )
1154 : {
1155 0 : SwLayoutFrm* pRow = pTab->GetFirstNonHeadlineRow();
1156 0 : if ( pRow )
1157 : {
1158 : // We are in the first line of a follow table
1159 : // with repeated headings.
1160 : // To actually make a "real" move we take the first content
1161 : // of the next row
1162 0 : pCnt = pRow->ContainsCntnt();
1163 0 : if ( ! pCnt )
1164 0 : return sal_False;
1165 : }
1166 : }
1167 : }
1168 : }
1169 :
1170 18 : SwCntntNode *pCNd = (SwCntntNode*)pCnt->GetNode();
1171 18 : pPam->GetPoint()->nNode = *pCNd;
1172 : xub_StrLen nIdx;
1173 18 : if( fnPosPage == GetFirstSub )
1174 16 : nIdx = ((SwTxtFrm*)pCnt)->GetOfst();
1175 : else
1176 2 : nIdx = pCnt->GetFollow() ?
1177 2 : ((SwTxtFrm*)pCnt)->GetFollow()->GetOfst()-1 : pCNd->Len();
1178 18 : pPam->GetPoint()->nContent.Assign( pCNd, nIdx );
1179 18 : return sal_True;
1180 : }
1181 : }
1182 :
1183 : /*************************************************************************
1184 : |*
1185 : |* SwLayoutFrm::GetCntntPos()
1186 : |*
1187 : |* Beschreibung Es wird der nachstliegende Cntnt zum uebergebenen
1188 : |* gesucht. Betrachtet werden die vorhergehende, die
1189 : |* aktuelle und die folgende Seite.
1190 : |* Wenn kein Inhalt gefunden wird, so wird der Bereich
1191 : * erweitert bis einer gefunden wird.
1192 : |* Zurueckgegeben wird die 'Semantisch richtige' Position
1193 : |* innerhalb der PrtArea des gefundenen CntntFrm
1194 : |*
1195 : |*************************************************************************/
1196 123 : sal_uLong CalcDiff( const Point &rPt1, const Point &rPt2 )
1197 : {
1198 : //Jetzt die Entfernung zwischen den beiden Punkten berechnen.
1199 : //'Delta' X^2 + 'Delta'Y^2 = 'Entfernung'^2
1200 369 : sal_uInt32 dX = std::max( rPt1.X(), rPt2.X() ) -
1201 246 : std::min( rPt1.X(), rPt2.X() ),
1202 369 : dY = std::max( rPt1.Y(), rPt2.Y() ) -
1203 246 : std::min( rPt1.Y(), rPt2.Y() );
1204 123 : BigInt dX1( dX ), dY1( dY );
1205 123 : dX1 *= dX1; dY1 *= dY1;
1206 123 : return ::SqRt( dX1 + dY1 );
1207 : }
1208 :
1209 : // lcl_Inside ueberprueft, ob der Punkt innerhalb des Seitenteils liegt, in dem
1210 : // auch der CntntFrame liegt. Als Seitenteile gelten in diesem Zusammenhang
1211 : // Kopfzeile, Seitenbody, Fusszeile und FussnotenContainer.
1212 : // Dies dient dazu, dass ein CntntFrm, der im "richtigen" Seitenteil liegt,
1213 : // eher akzeptiert wird als ein anderer, der nicht dort liegt, auch wenn
1214 : // dessen Abstand zum Punkt geringer ist.
1215 :
1216 123 : static const SwLayoutFrm* lcl_Inside( const SwCntntFrm *pCnt, Point& rPt )
1217 : {
1218 123 : const SwLayoutFrm* pUp = pCnt->GetUpper();
1219 246 : while( pUp )
1220 : {
1221 123 : if( pUp->IsPageBodyFrm() || pUp->IsFooterFrm() || pUp->IsHeaderFrm() )
1222 : {
1223 123 : if( rPt.Y() >= pUp->Frm().Top() && rPt.Y() <= pUp->Frm().Bottom() )
1224 120 : return pUp;
1225 3 : return NULL;
1226 : }
1227 0 : if( pUp->IsFtnContFrm() )
1228 0 : return pUp->Frm().IsInside( rPt ) ? pUp : NULL;
1229 0 : pUp = pUp->GetUpper();
1230 : }
1231 0 : return NULL;
1232 : }
1233 :
1234 132 : const SwCntntFrm *SwLayoutFrm::GetCntntPos( Point& rPoint,
1235 : const sal_Bool bDontLeave,
1236 : const sal_Bool bBodyOnly,
1237 : const sal_Bool bCalc,
1238 : const SwCrsrMoveState *pCMS,
1239 : const sal_Bool bDefaultExpand ) const
1240 : {
1241 : //Ersten CntntFrm ermitteln.
1242 132 : const SwLayoutFrm *pStart = (!bDontLeave && bDefaultExpand && GetPrev()) ?
1243 132 : (SwLayoutFrm*)GetPrev() : this;
1244 132 : const SwCntntFrm *pCntnt = pStart->ContainsCntnt();
1245 :
1246 132 : if ( !pCntnt && (GetPrev() && !bDontLeave) )
1247 0 : pCntnt = ContainsCntnt();
1248 :
1249 132 : if ( bBodyOnly && pCntnt && !pCntnt->IsInDocBody() )
1250 0 : while ( pCntnt && !pCntnt->IsInDocBody() )
1251 0 : pCntnt = pCntnt->GetNextCntntFrm();
1252 :
1253 132 : const SwCntntFrm *pActual= pCntnt;
1254 132 : const SwLayoutFrm *pInside = NULL;
1255 132 : sal_uInt16 nMaxPage = GetPhyPageNum() + (bDefaultExpand ? 1 : 0);
1256 132 : Point aPoint = rPoint;
1257 132 : sal_uLong nDistance = ULONG_MAX;
1258 :
1259 : while ( true ) //Sicherheitsschleifchen, damit immer einer gefunden wird.
1260 : {
1261 528 : while ( pCntnt &&
1262 132 : ((!bDontLeave || IsAnLower( pCntnt )) &&
1263 132 : (pCntnt->GetPhyPageNum() <= nMaxPage)) )
1264 : {
1265 263 : if ( ( bCalc || pCntnt->Frm().Width() ) &&
1266 1 : ( !bBodyOnly || pCntnt->IsInDocBody() ) )
1267 : {
1268 : //Wenn der Cntnt in einem geschuetzen Bereich (Zelle, Ftn, Section)
1269 : //liegt, wird der nachste Cntnt der nicht geschuetzt ist gesucht.
1270 131 : const SwCntntFrm *pComp = pCntnt;
1271 : pCntnt = ::lcl_MissProtectedFrames( pCntnt, lcl_GetNxtCnt, sal_False,
1272 131 : pCMS ? pCMS->bSetInReadOnly : sal_False, sal_False );
1273 131 : if ( pComp != pCntnt )
1274 0 : continue;
1275 :
1276 131 : if ( !pCntnt->IsTxtFrm() || !((SwTxtFrm*)pCntnt)->IsHiddenNow() )
1277 : {
1278 123 : if ( bCalc )
1279 0 : pCntnt->Calc();
1280 :
1281 123 : SwRect aCntFrm( pCntnt->UnionFrm() );
1282 123 : if ( aCntFrm.IsInside( rPoint ) )
1283 : {
1284 0 : pActual = pCntnt;
1285 0 : aPoint = rPoint;
1286 0 : break;
1287 : }
1288 : //Die Strecke von rPoint zum dichtesten Punkt von pCntnt wird
1289 : //jetzt berechnet.
1290 123 : Point aCntntPoint( rPoint );
1291 :
1292 : //Erst die Vertikale Position einstellen
1293 123 : if ( aCntFrm.Top() > aCntntPoint.Y() )
1294 3 : aCntntPoint.Y() = aCntFrm.Top();
1295 120 : else if ( aCntFrm.Bottom() < aCntntPoint.Y() )
1296 120 : aCntntPoint.Y() = aCntFrm.Bottom();
1297 :
1298 : //Jetzt die Horizontale Position
1299 123 : if ( aCntFrm.Left() > aCntntPoint.X() )
1300 2 : aCntntPoint.X() = aCntFrm.Left();
1301 121 : else if ( aCntFrm.Right() < aCntntPoint.X() )
1302 0 : aCntntPoint.X() = aCntFrm.Right();
1303 :
1304 : // pInside ist ein Seitenbereich, in dem der Punkt liegt,
1305 : // sobald pInside!=0 ist, werden nur noch Frames akzeptiert,
1306 : // die innerhalb liegen.
1307 246 : if( !pInside || ( pInside->IsAnLower( pCntnt ) &&
1308 0 : ( !pCntnt->IsInFtn() || pInside->IsFtnContFrm() ) ) )
1309 : {
1310 123 : const sal_uLong nDiff = ::CalcDiff( aCntntPoint, rPoint );
1311 123 : sal_Bool bBetter = nDiff < nDistance; // Dichter dran
1312 123 : if( !pInside )
1313 : {
1314 123 : pInside = lcl_Inside( pCntnt, rPoint );
1315 123 : if( pInside ) // Im "richtigen" Seitenteil
1316 120 : bBetter = sal_True;
1317 : }
1318 123 : if( bBetter )
1319 : {
1320 123 : aPoint = aCntntPoint;
1321 123 : nDistance = nDiff;
1322 123 : pActual = pCntnt;
1323 : }
1324 : }
1325 : }
1326 : }
1327 132 : pCntnt = pCntnt->GetNextCntntFrm();
1328 132 : if ( bBodyOnly )
1329 2 : while ( pCntnt && !pCntnt->IsInDocBody() )
1330 0 : pCntnt = pCntnt->GetNextCntntFrm();
1331 : }
1332 132 : if ( !pActual )
1333 : { //Wenn noch keiner gefunden wurde muss der Suchbereich erweitert
1334 : //werden, irgenwann muessen wir einen Finden!
1335 : //MA 09. Jan. 97: Opt fuer viele leere Seiten, wenn wir nur im
1336 : //Body suchen, koennen wir den Suchbereich gleich in einem
1337 : //Schritt hinreichend erweitern.
1338 0 : if ( bBodyOnly )
1339 : {
1340 0 : while ( !pCntnt && pStart->GetPrev() )
1341 : {
1342 0 : ++nMaxPage;
1343 0 : if( !pStart->GetPrev()->IsLayoutFrm() )
1344 0 : return 0;
1345 0 : pStart = (SwLayoutFrm*)pStart->GetPrev();
1346 0 : pCntnt = pStart->IsInDocBody()
1347 : ? pStart->ContainsCntnt()
1348 0 : : pStart->FindPageFrm()->FindFirstBodyCntnt();
1349 : }
1350 0 : if ( !pCntnt ) //irgendwann muessen wir mit irgendeinem Anfangen!
1351 : {
1352 0 : pCntnt = pStart->FindPageFrm()->GetUpper()->ContainsCntnt();
1353 0 : while ( pCntnt && !pCntnt->IsInDocBody() )
1354 0 : pCntnt = pCntnt->GetNextCntntFrm();
1355 0 : if ( !pCntnt )
1356 0 : return 0; //Es gibt noch keine Dokumentinhalt!
1357 : }
1358 : }
1359 : else
1360 : {
1361 0 : ++nMaxPage;
1362 0 : if ( pStart->GetPrev() )
1363 : {
1364 0 : if( !pStart->GetPrev()->IsLayoutFrm() )
1365 0 : return 0;
1366 0 : pStart = (SwLayoutFrm*)pStart->GetPrev();
1367 0 : pCntnt = pStart->ContainsCntnt();
1368 : }
1369 : else //irgendwann muessen wir mit irgendeinem Anfangen!
1370 0 : pCntnt = pStart->FindPageFrm()->GetUpper()->ContainsCntnt();
1371 : }
1372 0 : pActual = pCntnt;
1373 : }
1374 : else
1375 132 : break;
1376 : }
1377 :
1378 : OSL_ENSURE( pActual, "no Cntnt found." );
1379 : OSL_ENSURE( !bBodyOnly || pActual->IsInDocBody(), "Cntnt not in Body." );
1380 :
1381 : //Spezialfall fuer das selektieren von Tabellen, nicht in wiederholte
1382 : //TblHedlines.
1383 132 : if ( pActual->IsInTab() && pCMS && pCMS->eState == MV_TBLSEL )
1384 : {
1385 0 : const SwTabFrm *pTab = pActual->FindTabFrm();
1386 0 : if ( pTab->IsFollow() && pTab->IsInHeadline( *pActual ) )
1387 : {
1388 0 : ((SwCrsrMoveState*)pCMS)->bStop = sal_True;
1389 0 : return 0;
1390 : }
1391 : }
1392 :
1393 : //Jetzt noch eine kleine Korrektur beim ersten/letzten
1394 132 : Size aActualSize( pActual->Prt().SSize() );
1395 132 : if ( aActualSize.Height() > pActual->GetUpper()->Prt().Height() )
1396 0 : aActualSize.Height() = pActual->GetUpper()->Prt().Height();
1397 :
1398 132 : SWRECTFN( pActual )
1399 264 : if ( !pActual->GetPrev() &&
1400 264 : (*fnRect->fnYDiff)( (pActual->*fnRect->fnGetPrtTop)(),
1401 396 : bVert ? rPoint.X() : rPoint.Y() ) > 0 )
1402 : {
1403 3 : aPoint.Y() = pActual->Frm().Top() + pActual->Prt().Top();
1404 9 : aPoint.X() = pActual->Frm().Left() +
1405 6 : ( pActual->IsRightToLeft() || bVert ?
1406 0 : pActual->Prt().Right() :
1407 6 : pActual->Prt().Left() );
1408 : }
1409 258 : else if ( !pActual->GetNext() &&
1410 258 : (*fnRect->fnYDiff)( (pActual->*fnRect->fnGetPrtBottom)(),
1411 387 : bVert ? rPoint.X() : rPoint.Y() ) < 0 )
1412 : {
1413 126 : aPoint.Y() = pActual->Frm().Top() + pActual->Prt().Bottom();
1414 378 : aPoint.X() = pActual->Frm().Left() +
1415 252 : ( pActual->IsRightToLeft() || bVert ?
1416 0 : pActual->Prt().Left() :
1417 252 : pActual->Prt().Right() );
1418 : }
1419 :
1420 : //Und den Point in die PrtArea bringen
1421 132 : if ( bCalc )
1422 0 : pActual->Calc();
1423 264 : const SwRect aRect( pActual->Frm().Pos() + pActual->Prt().Pos(),
1424 132 : aActualSize );
1425 132 : if ( aPoint.Y() < aRect.Top() )
1426 0 : aPoint.Y() = aRect.Top();
1427 132 : else if ( aPoint.Y() > aRect.Bottom() )
1428 0 : aPoint.Y() = aRect.Bottom();
1429 132 : if ( aPoint.X() < aRect.Left() )
1430 0 : aPoint.X() = aRect.Left();
1431 132 : else if ( aPoint.X() > aRect.Right() )
1432 0 : aPoint.X() = aRect.Right();
1433 132 : rPoint = aPoint;
1434 132 : return pActual;
1435 : }
1436 :
1437 : /*************************************************************************
1438 : |*
1439 : |* SwPageFrm::GetCntntPosition()
1440 : |*
1441 : |* Beschreibung Analog zu SwLayoutFrm::GetCntntPos().
1442 : |* Spezialisiert fuer Felder in Rahmen.
1443 : |*
1444 : |*************************************************************************/
1445 0 : void SwPageFrm::GetCntntPosition( const Point &rPt, SwPosition &rPos ) const
1446 : {
1447 : //Ersten CntntFrm ermitteln.
1448 0 : const SwCntntFrm *pCntnt = ContainsCntnt();
1449 0 : if ( pCntnt )
1450 : {
1451 : //Einen weiter zurueck schauen (falls moeglich).
1452 0 : const SwCntntFrm *pTmp = pCntnt->GetPrevCntntFrm();
1453 0 : while ( pTmp && !pTmp->IsInDocBody() )
1454 0 : pTmp = pTmp->GetPrevCntntFrm();
1455 0 : if ( pTmp )
1456 0 : pCntnt = pTmp;
1457 : }
1458 : else
1459 0 : pCntnt = GetUpper()->ContainsCntnt();
1460 :
1461 0 : const SwCntntFrm *pAct = pCntnt;
1462 0 : Point aAct = rPt;
1463 0 : sal_uLong nDist = ULONG_MAX;
1464 :
1465 0 : while ( pCntnt )
1466 : {
1467 0 : SwRect aCntFrm( pCntnt->UnionFrm() );
1468 0 : if ( aCntFrm.IsInside( rPt ) )
1469 : {
1470 : //dichter gehts nimmer.
1471 0 : pAct = pCntnt;
1472 0 : break;
1473 : }
1474 :
1475 : //Die Strecke von rPt zum dichtesten Punkt von pCntnt berechnen.
1476 0 : Point aPoint( rPt );
1477 :
1478 : //Erst die vertikale Position einstellen
1479 0 : if ( aCntFrm.Top() > rPt.Y() )
1480 0 : aPoint.Y() = aCntFrm.Top();
1481 0 : else if ( aCntFrm.Bottom() < rPt.Y() )
1482 0 : aPoint.Y() = aCntFrm.Bottom();
1483 :
1484 : //Jetzt die horizontale Position
1485 0 : if ( aCntFrm.Left() > rPt.X() )
1486 0 : aPoint.X() = aCntFrm.Left();
1487 0 : else if ( aCntFrm.Right() < rPt.X() )
1488 0 : aPoint.X() = aCntFrm.Right();
1489 :
1490 0 : const sal_uLong nDiff = ::CalcDiff( aPoint, rPt );
1491 0 : if ( nDiff < nDist )
1492 : {
1493 0 : aAct = aPoint;
1494 0 : nDist = nDiff;
1495 0 : pAct = pCntnt;
1496 : }
1497 0 : else if ( aCntFrm.Top() > Frm().Bottom() )
1498 : //Dichter wirds im Sinne der Felder nicht mehr!
1499 0 : break;
1500 :
1501 0 : pCntnt = pCntnt->GetNextCntntFrm();
1502 0 : while ( pCntnt && !pCntnt->IsInDocBody() )
1503 0 : pCntnt = pCntnt->GetNextCntntFrm();
1504 : }
1505 :
1506 : //Und den Point in die PrtArea bringen
1507 0 : const SwRect aRect( pAct->Frm().Pos() + pAct->Prt().Pos(), pAct->Prt().SSize() );
1508 0 : if ( aAct.Y() < aRect.Top() )
1509 0 : aAct.Y() = aRect.Top();
1510 0 : else if ( aAct.Y() > aRect.Bottom() )
1511 0 : aAct.Y() = aRect.Bottom();
1512 0 : if ( aAct.X() < aRect.Left() )
1513 0 : aAct.X() = aRect.Left();
1514 0 : else if ( aAct.X() > aRect.Right() )
1515 0 : aAct.X() = aRect.Right();
1516 :
1517 0 : if( !pAct->IsValid() )
1518 : {
1519 : // CntntFrm nicht formatiert -> immer auf Node-Anfang
1520 0 : SwCntntNode* pCNd = (SwCntntNode*)pAct->GetNode();
1521 : OSL_ENSURE( pCNd, "Wo ist mein CntntNode?" );
1522 0 : rPos.nNode = *pCNd;
1523 0 : rPos.nContent.Assign( pCNd, 0 );
1524 : }
1525 : else
1526 : {
1527 0 : SwCrsrMoveState aTmpState( MV_SETONLYTEXT );
1528 0 : pAct->GetCrsrOfst( &rPos, aAct, &aTmpState );
1529 : }
1530 0 : }
1531 :
1532 : /*************************************************************************
1533 : |*
1534 : |* SwRootFrm::GetNextPrevCntntPos()
1535 : |*
1536 : |* Beschreibung Es wird der naechstliegende Cntnt zum uebergebenen
1537 : |* Point gesucht. Es wird nur im BodyText gesucht.
1538 : |*
1539 : |*************************************************************************/
1540 :
1541 : // #123110# - helper class to disable creation of an action
1542 : // by a callback event - e.g., change event from a drawing object
1543 : class DisableCallbackAction
1544 : {
1545 : private:
1546 : SwRootFrm& mrRootFrm;
1547 : sal_Bool mbOldCallbackActionState;
1548 :
1549 : public:
1550 0 : DisableCallbackAction( const SwRootFrm& _rRootFrm ) :
1551 : mrRootFrm( const_cast<SwRootFrm&>(_rRootFrm) ),
1552 0 : mbOldCallbackActionState( _rRootFrm.IsCallbackActionEnabled() )
1553 : {
1554 0 : mrRootFrm.SetCallbackActionEnabled( sal_False );
1555 0 : }
1556 :
1557 0 : ~DisableCallbackAction()
1558 : {
1559 0 : mrRootFrm.SetCallbackActionEnabled( mbOldCallbackActionState );
1560 0 : }
1561 : };
1562 :
1563 : //!!!!! Es wird nur der vertikal naechstliegende gesucht.
1564 : //JP 11.10.2001: only in tables we try to find the right column - Bug 72294
1565 0 : Point SwRootFrm::GetNextPrevCntntPos( const Point& rPoint, sal_Bool bNext ) const
1566 : {
1567 : // #123110# - disable creation of an action by a callback
1568 : // event during processing of this method. Needed because formatting is
1569 : // triggered by this method.
1570 0 : DisableCallbackAction aDisableCallbackAction( *this );
1571 : //Ersten CntntFrm und seinen Nachfolger im Body-Bereich suchen
1572 : //Damit wir uns nicht tot suchen (und vor allem nicht zuviel formatieren)
1573 : //gehen wir schon mal von der richtigen Seite aus.
1574 0 : SwLayoutFrm *pPage = (SwLayoutFrm*)Lower();
1575 0 : if( pPage )
1576 0 : while( pPage->GetNext() && pPage->Frm().Bottom() < rPoint.Y() )
1577 0 : pPage = (SwLayoutFrm*)pPage->GetNext();
1578 :
1579 0 : const SwCntntFrm *pCnt = pPage ? pPage->ContainsCntnt() : ContainsCntnt();
1580 0 : while ( pCnt && !pCnt->IsInDocBody() )
1581 0 : pCnt = pCnt->GetNextCntntFrm();
1582 :
1583 0 : if ( !pCnt )
1584 0 : return Point( 0, 0 );
1585 :
1586 0 : pCnt->Calc();
1587 0 : if( !bNext )
1588 : {
1589 : // Solange der Point vor dem ersten CntntFrm liegt und es noch
1590 : // vorhergehende Seiten gibt gehe ich jeweils eine Seite nach vorn.
1591 0 : while ( rPoint.Y() < pCnt->Frm().Top() && pPage->GetPrev() )
1592 : {
1593 0 : pPage = (SwLayoutFrm*)pPage->GetPrev();
1594 0 : pCnt = pPage->ContainsCntnt();
1595 0 : while ( !pCnt )
1596 : {
1597 0 : pPage = (SwLayoutFrm*)pPage->GetPrev();
1598 0 : if ( pPage )
1599 0 : pCnt = pPage->ContainsCntnt();
1600 : else
1601 0 : return ContainsCntnt()->UnionFrm().Pos();
1602 : }
1603 0 : pCnt->Calc();
1604 : }
1605 : }
1606 :
1607 : //Liegt der Point ueber dem ersten CntntFrm?
1608 0 : if ( rPoint.Y() < pCnt->Frm().Top() && !lcl_IsInRepeatedHeadline( pCnt ) )
1609 0 : return pCnt->UnionFrm().Pos();
1610 :
1611 0 : while ( pCnt )
1612 : {
1613 : //Liegt der Point im aktuellen CntntFrm?
1614 0 : SwRect aCntFrm( pCnt->UnionFrm() );
1615 0 : if ( aCntFrm.IsInside( rPoint ) && !lcl_IsInRepeatedHeadline( pCnt ))
1616 0 : return rPoint;
1617 :
1618 : //Ist der aktuelle der letzte CntntFrm? ||
1619 : //Wenn der naechste CntntFrm hinter dem Point liegt, ist der
1620 : //aktuelle der gesuchte.
1621 0 : const SwCntntFrm *pNxt = pCnt->GetNextCntntFrm();
1622 0 : while ( pNxt && !pNxt->IsInDocBody() )
1623 0 : pNxt = pNxt->GetNextCntntFrm();
1624 :
1625 : //Liegt der Point hinter dem letzten CntntFrm?
1626 0 : if ( !pNxt )
1627 0 : return Point( aCntFrm.Right(), aCntFrm.Bottom() );
1628 :
1629 : //Wenn der naechste CntntFrm hinter dem Point liegt ist er der
1630 : //gesuchte.
1631 : const SwTabFrm* pTFrm;
1632 0 : pNxt->Calc();
1633 0 : if( pNxt->Frm().Top() > rPoint.Y() &&
1634 0 : !lcl_IsInRepeatedHeadline( pCnt, &pTFrm ) &&
1635 0 : ( !pTFrm || pNxt->Frm().Left() > rPoint.X() ))
1636 : {
1637 0 : if( bNext )
1638 0 : return pNxt->Frm().Pos();
1639 0 : return Point( aCntFrm.Right(), aCntFrm.Bottom() );
1640 : }
1641 0 : pCnt = pNxt;
1642 : }
1643 0 : return Point( 0, 0 );
1644 : }
1645 :
1646 : /*************************************************************************
1647 : |*
1648 : |* SwRootFrm::GetPagePos()
1649 : |*
1650 : |* Beschreibung: Liefert die absolute Dokumentpositon der gewuenschten
1651 : |* Seite.
1652 : |* Formatiert wird nur soweit notwendig und nur dann wenn bFormat=sal_True
1653 : |* Liefert Null, wenn die Operation nicht moeglich ist.
1654 : |* Die Pos ist die der letzten Seite, wenn die Seitenzahl zu gross
1655 : |* gewaehlt wurde.
1656 : |*
1657 : |*************************************************************************/
1658 0 : Point SwRootFrm::GetPagePos( sal_uInt16 nPageNum ) const
1659 : {
1660 : OSL_ENSURE( Lower() && Lower()->IsPageFrm(), "Keine Seite vorhanden." );
1661 :
1662 0 : const SwPageFrm *pPage = (const SwPageFrm*)Lower();
1663 : while ( true )
1664 : {
1665 0 : if ( pPage->GetPhyPageNum() >= nPageNum || !pPage->GetNext() )
1666 0 : break;
1667 0 : pPage = (const SwPageFrm*)pPage->GetNext();
1668 : }
1669 0 : return pPage->Frm().Pos();
1670 : }
1671 :
1672 : /** get page frame by phyiscal page number
1673 :
1674 : OD 14.01.2003 #103492#
1675 :
1676 : @return pointer to the page frame with the given physical page number
1677 : */
1678 0 : SwPageFrm* SwRootFrm::GetPageByPageNum( sal_uInt16 _nPageNum ) const
1679 : {
1680 0 : const SwPageFrm* pPageFrm = static_cast<const SwPageFrm*>( Lower() );
1681 0 : while ( pPageFrm && pPageFrm->GetPhyPageNum() < _nPageNum )
1682 : {
1683 0 : pPageFrm = static_cast<const SwPageFrm*>( pPageFrm->GetNext() );
1684 : }
1685 :
1686 0 : if ( pPageFrm && pPageFrm->GetPhyPageNum() == _nPageNum )
1687 : {
1688 0 : return const_cast<SwPageFrm*>( pPageFrm );
1689 : }
1690 : else
1691 : {
1692 0 : return 0;
1693 : }
1694 : }
1695 :
1696 : /*************************************************************************
1697 : |*
1698 : |* SwRootFrm::IsDummyPage(sal_uInt16)
1699 : |*
1700 : |* Description: Returns sal_True, when the given physical pagenumber does't exist
1701 : |* or this page is an empty page.
1702 : |*************************************************************************/
1703 0 : sal_Bool SwRootFrm::IsDummyPage( sal_uInt16 nPageNum ) const
1704 : {
1705 0 : if( !Lower() || !nPageNum || nPageNum > GetPageNum() )
1706 0 : return sal_True;
1707 :
1708 0 : const SwPageFrm *pPage = (const SwPageFrm*)Lower();
1709 0 : while( pPage && nPageNum < pPage->GetPhyPageNum() )
1710 0 : pPage = (const SwPageFrm*)pPage->GetNext();
1711 0 : return pPage ? pPage->IsEmptyPage() : sal_True;
1712 : }
1713 :
1714 :
1715 : /*************************************************************************
1716 : |*
1717 : |* SwFrm::IsProtected()
1718 : |*
1719 : |* Beschreibung Ist der Frm bzw. die Section in der er steht
1720 : |* geschuetzt?
1721 : |* Auch Fly in Fly in ... und Fussnoten
1722 : |*
1723 : |*
1724 : |*************************************************************************/
1725 12472 : sal_Bool SwFrm::IsProtected() const
1726 : {
1727 12472 : if (this->IsCntntFrm() && ((SwCntntFrm*)this)->GetNode())
1728 : {
1729 12461 : const SwDoc *pDoc=((SwCntntFrm*)this)->GetNode()->GetDoc();
1730 12461 : bool isFormProtected=pDoc->get(IDocumentSettingAccess::PROTECT_FORM );
1731 12461 : if (isFormProtected)
1732 : {
1733 0 : return sal_False; // TODO a hack for now, well deal with it laster, I we return true here we have a "double" locking
1734 : }
1735 : }
1736 : //Der Frm kann in Rahmen, Zellen oder Bereichen geschuetzt sein.
1737 : //Geht auch FlyFrms rekursiv hoch. Geht auch von Fussnoten zum Anker.
1738 12472 : const SwFrm *pFrm = this;
1739 50620 : do
1740 : {
1741 50620 : if ( pFrm->IsCntntFrm() )
1742 : {
1743 24952 : if ( ((SwCntntFrm*)pFrm)->GetNode() &&
1744 12476 : ((SwCntntFrm*)pFrm)->GetNode()->IsInProtectSect() )
1745 0 : return sal_True;
1746 : }
1747 : else
1748 : {
1749 76288 : if ( ((SwLayoutFrm*)pFrm)->GetFmt() &&
1750 38144 : ((SwLayoutFrm*)pFrm)->GetFmt()->
1751 38144 : GetProtect().IsCntntProtected() )
1752 0 : return sal_True;
1753 38144 : if ( pFrm->IsCoveredCell() )
1754 0 : return sal_True;
1755 : }
1756 50620 : if ( pFrm->IsFlyFrm() )
1757 : {
1758 : //Der Schutz des Inhaltes kann bei Verkettung vom Master der Kette
1759 : //vorgegeben werden.
1760 12 : if ( ((SwFlyFrm*)pFrm)->GetPrevLink() )
1761 : {
1762 0 : SwFlyFrm *pMaster = (SwFlyFrm*)pFrm;
1763 0 : do
1764 0 : { pMaster = pMaster->GetPrevLink();
1765 0 : } while ( pMaster->GetPrevLink() );
1766 0 : if ( pMaster->IsProtected() )
1767 0 : return sal_True;
1768 : }
1769 12 : pFrm = ((SwFlyFrm*)pFrm)->GetAnchorFrm();
1770 : }
1771 50608 : else if ( pFrm->IsFtnFrm() )
1772 5 : pFrm = ((SwFtnFrm*)pFrm)->GetRef();
1773 : else
1774 50603 : pFrm = pFrm->GetUpper();
1775 :
1776 : } while ( pFrm );
1777 :
1778 12472 : return sal_False;
1779 : }
1780 :
1781 : /*************************************************************************
1782 : |*
1783 : |* SwFrm::GetPhyPageNum()
1784 : |* Beschreibung: Liefert die physikalische Seitennummer
1785 : |*
1786 : |*
1787 : |*************************************************************************/
1788 1343 : sal_uInt16 SwFrm::GetPhyPageNum() const
1789 : {
1790 1343 : const SwPageFrm *pPage = FindPageFrm();
1791 1343 : return pPage ? pPage->GetPhyPageNum() : 0;
1792 : }
1793 :
1794 : /*--------------------------------------------------
1795 : * SwFrm::WannaRightPage()
1796 : * decides if the page want to be a rightpage or not.
1797 : * If the first content of the page has a page descriptor,
1798 : * we take the follow of the page descriptor of the last not empty page.
1799 : * If this descriptor allows only right(left) pages and the page
1800 : * isn't an empty page then it wanna be such right(left) page.
1801 : * If the descriptor allows right and left pages, we look for a number offset
1802 : * in the first content. If there is one, odd number results right pages,
1803 : * even number results left pages.
1804 : * If there is no number offset, we take the physical page number instead,
1805 : * but a previous empty page don't count.
1806 : * --------------------------------------------------*/
1807 :
1808 109 : sal_Bool SwFrm::WannaRightPage() const
1809 : {
1810 109 : const SwPageFrm *pPage = FindPageFrm();
1811 109 : if ( !pPage || !pPage->GetUpper() )
1812 0 : return sal_True;
1813 :
1814 109 : const SwFrm *pFlow = pPage->FindFirstBodyCntnt();
1815 109 : const SwPageDesc *pDesc = 0;
1816 109 : sal_uInt16 nPgNum = 0;
1817 109 : if ( pFlow )
1818 : {
1819 104 : if ( pFlow->IsInTab() )
1820 20 : pFlow = pFlow->FindTabFrm();
1821 104 : const SwFlowFrm *pTmp = SwFlowFrm::CastFlowFrm( pFlow );
1822 104 : if ( !pTmp->IsFollow() )
1823 : {
1824 100 : const SwFmtPageDesc& rPgDesc = pFlow->GetAttrSet()->GetPageDesc();
1825 100 : pDesc = rPgDesc.GetPageDesc();
1826 100 : nPgNum = rPgDesc.GetNumOffset();
1827 : }
1828 : }
1829 109 : if ( !pDesc )
1830 : {
1831 78 : SwPageFrm *pPrv = (SwPageFrm*)pPage->GetPrev();
1832 78 : if( pPrv && pPrv->IsEmptyPage() )
1833 0 : pPrv = (SwPageFrm*)pPrv->GetPrev();
1834 78 : if( pPrv )
1835 7 : pDesc = pPrv->GetPageDesc()->GetFollow();
1836 : else
1837 : {
1838 71 : const SwDoc* pDoc = pPage->GetFmt()->GetDoc();
1839 71 : pDesc = &pDoc->GetPageDesc( 0 );
1840 : }
1841 : }
1842 : OSL_ENSURE( pDesc, "No pagedescriptor" );
1843 : sal_Bool bOdd;
1844 109 : if( nPgNum )
1845 1 : bOdd = (nPgNum % 2) ? sal_True : sal_False;
1846 : else
1847 : {
1848 108 : bOdd = pPage->OnRightPage();
1849 108 : if( pPage->GetPrev() && ((SwPageFrm*)pPage->GetPrev())->IsEmptyPage() )
1850 4 : bOdd = !bOdd;
1851 : }
1852 109 : if( !pPage->IsEmptyPage() )
1853 : {
1854 107 : if( !pDesc->GetRightFmt() )
1855 4 : bOdd = sal_False;
1856 103 : else if( !pDesc->GetLeftFmt() )
1857 5 : bOdd = sal_True;
1858 : }
1859 109 : return bOdd;
1860 : }
1861 :
1862 164 : bool SwFrm::OnFirstPage() const
1863 : {
1864 164 : bool bRet = false;
1865 164 : const SwPageFrm *pPage = FindPageFrm();
1866 :
1867 164 : if (pPage)
1868 : {
1869 164 : const SwPageFrm* pPrevFrm = dynamic_cast<const SwPageFrm*>(pPage->GetPrev());
1870 164 : if (pPrevFrm)
1871 : {
1872 67 : const SwPageDesc* pDesc = pPage->GetPageDesc();
1873 67 : bRet = pPrevFrm->GetPageDesc() != pDesc && !pDesc->IsFirstShared();
1874 : }
1875 : else
1876 97 : bRet = true;
1877 : }
1878 164 : return bRet;
1879 : }
1880 :
1881 : /*************************************************************************
1882 : |*
1883 : |* SwFrm::GetVirtPageNum()
1884 : |* Beschreibung: Liefert die virtuelle Seitennummer mit Offset
1885 : |*
1886 : |*************************************************************************/
1887 1023 : sal_uInt16 SwFrm::GetVirtPageNum() const
1888 : {
1889 1023 : const SwPageFrm *pPage = FindPageFrm();
1890 1023 : if ( !pPage || !pPage->GetUpper() )
1891 0 : return 0;
1892 :
1893 1023 : sal_uInt16 nPhyPage = pPage->GetPhyPageNum();
1894 1023 : if ( !((SwRootFrm*)pPage->GetUpper())->IsVirtPageNum() )
1895 1021 : return nPhyPage;
1896 :
1897 : //Den am naechsten stehenden Absatz mit virtueller Seitennummer suchen.
1898 : //Da das rueckwaertsuchen insgesamt sehr viel Zeit verschlingt suchen
1899 : //wir jetzt gezielt ueber die Abhaengigkeiten.
1900 : //von den PageDescs bekommen wir die Attribute, von den Attributen
1901 : //wiederum bekommen wir die Absaetze.
1902 2 : const SwPageFrm *pVirtPage = 0;
1903 2 : const SwFrm *pFrm = 0;
1904 2 : const SfxItemPool &rPool = pPage->GetFmt()->GetDoc()->GetAttrPool();
1905 : const SfxPoolItem* pItem;
1906 2 : sal_uInt32 nMaxItems = rPool.GetItemCount2( RES_PAGEDESC );
1907 26 : for( sal_uInt32 n = 0; n < nMaxItems; ++n )
1908 : {
1909 24 : if( 0 == (pItem = rPool.GetItem2( RES_PAGEDESC, n ) ))
1910 8 : continue;
1911 :
1912 16 : const SwFmtPageDesc *pDesc = (SwFmtPageDesc*)pItem;
1913 16 : if ( pDesc->GetNumOffset() && pDesc->GetDefinedIn() )
1914 : {
1915 0 : const SwModify *pMod = pDesc->GetDefinedIn();
1916 0 : SwVirtPageNumInfo aInfo( pPage );
1917 0 : pMod->GetInfo( aInfo );
1918 0 : if ( aInfo.GetPage() )
1919 : {
1920 0 : if( !pVirtPage || ( pVirtPage && aInfo.GetPage()->
1921 0 : GetPhyPageNum() > pVirtPage->GetPhyPageNum() ) )
1922 : {
1923 0 : pVirtPage = aInfo.GetPage();
1924 0 : pFrm = aInfo.GetFrm();
1925 : }
1926 0 : }
1927 : }
1928 : }
1929 2 : if ( pFrm )
1930 0 : return nPhyPage - pFrm->GetPhyPageNum() +
1931 0 : pFrm->GetAttrSet()->GetPageDesc().GetNumOffset();
1932 2 : return nPhyPage;
1933 : }
1934 :
1935 : /*************************************************************************
1936 : |*
1937 : |* SwRootFrm::MakeTblCrsrs()
1938 : |*
1939 : |*************************************************************************/
1940 : //Ermitteln und einstellen derjenigen Zellen die von der Selektion
1941 : //eingeschlossen sind.
1942 :
1943 345 : bool SwRootFrm::MakeTblCrsrs( SwTableCursor& rTblCrsr )
1944 : {
1945 : //Union-Rects und Tabellen (Follows) der Selektion besorgen.
1946 : OSL_ENSURE( rTblCrsr.GetCntntNode() && rTblCrsr.GetCntntNode( sal_False ),
1947 : "Tabselection nicht auf Cnt." );
1948 :
1949 345 : bool bRet = false;
1950 :
1951 : // For new table models there's no need to ask the layout..
1952 345 : if( rTblCrsr.NewTableSelection() )
1953 345 : return true;
1954 :
1955 0 : Point aPtPt, aMkPt;
1956 : {
1957 0 : SwShellCrsr* pShCrsr = dynamic_cast<SwShellCrsr*>(&rTblCrsr);
1958 :
1959 0 : if( pShCrsr )
1960 : {
1961 0 : aPtPt = pShCrsr->GetPtPos();
1962 0 : aMkPt = pShCrsr->GetMkPos();
1963 : }
1964 : }
1965 :
1966 : // #151012# Made code robust here
1967 0 : const SwCntntNode* pTmpStartNode = rTblCrsr.GetCntntNode();
1968 0 : const SwCntntNode* pTmpEndNode = rTblCrsr.GetCntntNode(sal_False);
1969 :
1970 0 : const SwFrm* pTmpStartFrm = pTmpStartNode ? pTmpStartNode->getLayoutFrm( this, &aPtPt, 0, sal_False ) : 0;
1971 0 : const SwFrm* pTmpEndFrm = pTmpEndNode ? pTmpEndNode->getLayoutFrm( this, &aMkPt, 0, sal_False ) : 0;
1972 :
1973 0 : const SwLayoutFrm* pStart = pTmpStartFrm ? pTmpStartFrm->GetUpper() : 0;
1974 0 : const SwLayoutFrm* pEnd = pTmpEndFrm ? pTmpEndFrm->GetUpper() : 0;
1975 :
1976 : OSL_ENSURE( pStart && pEnd, "MakeTblCrsrs: Good to have the code robust here!" );
1977 :
1978 : /* #109590# Only change table boxes if the frames are
1979 : valid. Needed because otherwise the table cursor after moving
1980 : table cells by dnd resulted in an empty tables cursor. */
1981 0 : if ( pStart && pEnd && pStart->IsValid() && pEnd->IsValid())
1982 : {
1983 0 : SwSelUnions aUnions;
1984 0 : ::MakeSelUnions( aUnions, pStart, pEnd );
1985 :
1986 0 : SwSelBoxes aNew;
1987 :
1988 0 : const sal_Bool bReadOnlyAvailable = rTblCrsr.IsReadOnlyAvailable();
1989 :
1990 0 : for ( sal_uInt16 i = 0; i < aUnions.size(); ++i )
1991 : {
1992 0 : SwSelUnion *pUnion = &aUnions[i];
1993 0 : const SwTabFrm *pTable = pUnion->GetTable();
1994 :
1995 : // Skip any repeated headlines in the follow:
1996 0 : SwLayoutFrm* pRow = pTable->IsFollow() ?
1997 : pTable->GetFirstNonHeadlineRow() :
1998 0 : (SwLayoutFrm*)pTable->Lower();
1999 :
2000 0 : while ( pRow )
2001 : {
2002 0 : if ( pRow->Frm().IsOver( pUnion->GetUnion() ) )
2003 : {
2004 0 : const SwLayoutFrm *pCell = pRow->FirstCell();
2005 :
2006 0 : while ( pCell && pRow->IsAnLower( pCell ) )
2007 : {
2008 : OSL_ENSURE( pCell->IsCellFrm(), "Frame ohne Celle" );
2009 0 : if( IsFrmInTblSel( pUnion->GetUnion(), pCell ) &&
2010 0 : (bReadOnlyAvailable ||
2011 0 : !pCell->GetFmt()->GetProtect().IsCntntProtected()))
2012 : {
2013 : SwTableBox* pInsBox = (SwTableBox*)
2014 0 : ((SwCellFrm*)pCell)->GetTabBox();
2015 0 : aNew.insert( pInsBox );
2016 : }
2017 0 : if ( pCell->GetNext() )
2018 : {
2019 0 : pCell = (const SwLayoutFrm*)pCell->GetNext();
2020 0 : if ( pCell->Lower() && pCell->Lower()->IsRowFrm() )
2021 0 : pCell = pCell->FirstCell();
2022 : }
2023 : else
2024 : {
2025 0 : const SwLayoutFrm* pLastCell = pCell;
2026 0 : do
2027 : {
2028 0 : pCell = pCell->GetNextLayoutLeaf();
2029 0 : } while ( pCell && pLastCell->IsAnLower( pCell ) );
2030 : // Fuer (spaltige) Bereiche...
2031 0 : if( pCell && pCell->IsInTab() )
2032 : {
2033 0 : while( !pCell->IsCellFrm() )
2034 : {
2035 0 : pCell = pCell->GetUpper();
2036 : OSL_ENSURE( pCell, "Where's my cell?" );
2037 : }
2038 : }
2039 : }
2040 : }
2041 : }
2042 0 : pRow = (SwLayoutFrm*)pRow->GetNext();
2043 : }
2044 : }
2045 :
2046 0 : rTblCrsr.ActualizeSelection( aNew );
2047 0 : bRet = true;
2048 : }
2049 :
2050 0 : return bRet;
2051 : }
2052 :
2053 :
2054 : /*************************************************************************
2055 : |*
2056 : |* SwRootFrm::CalcFrmRects
2057 : |*
2058 : |*************************************************************************/
2059 :
2060 : /*
2061 : * nun koennen folgende Situationen auftreten:
2062 : * 1. Start und Ende liegen in einer Bildschirm - Zeile und im
2063 : * gleichen Node
2064 : * -> aus Start und End ein Rectangle, dann Ok
2065 : * 2. Start und Ende liegen in einem Frame (dadurch im gleichen Node!)
2066 : * -> Start nach rechts, End nach links erweitern,
2067 : * und bei mehr als 2 Bildschirm - Zeilen, das dazwischen
2068 : * liegende berechnen
2069 : * 3. Start und Ende liegen in verschiedenen Frames
2070 : * -> Start nach rechts erweitern, bis Frame-Ende Rect berechnen
2071 : * Ende nach links erweitern, bis Frame-Start Rect berechnen
2072 : * und bei mehr als 2 Frames von allen dazwischen liegenden
2073 : * Frames die PrtArea dazu.
2074 : * 4. Wenn es sich um eine Tabellenselektion handelt wird fuer jeden
2075 : * PaM im Ring der CellFrm besorgt, dessen PrtArea wird zu den
2076 : * Rechtecken addiert.
2077 : *
2078 : * Grosser Umbau wg. der FlyFrm; denn diese muessen ausgespart werden.
2079 : * Ausnahmen: - Der Fly in dem die Selektion stattfindet (wenn sie in einem Fly
2080 : * stattfindet).
2081 : * - Die Flys, die vom Text unterlaufen werden.
2082 : * Arbeitsweise: Zuerst wird eine SwRegion mit der Root initialisiert.
2083 : * Aus der Region werden die zu invertierenden Bereiche
2084 : * ausgestantzt. Die Region wird Komprimiert und letztlich
2085 : * invertiert. Damit liegen dann die zu invertierenden
2086 : * Rechtecke vor.
2087 : * Am Ende werden die Flys aus der Region ausgestanzt.
2088 : */
2089 :
2090 349 : inline void Sub( SwRegionRects& rRegion, const SwRect& rRect )
2091 : {
2092 679 : if( rRect.Width() > 1 && rRect.Height() > 1 &&
2093 330 : rRect.IsOver( rRegion.GetOrigin() ))
2094 315 : rRegion -= rRect;
2095 349 : }
2096 :
2097 233 : void SwRootFrm::CalcFrmRects( SwShellCrsr &rCrsr, sal_Bool bIsTblMode )
2098 : {
2099 233 : SwPosition *pStartPos = rCrsr.Start(),
2100 233 : *pEndPos = rCrsr.GetPoint() == pStartPos ? rCrsr.GetMark() : rCrsr.GetPoint();
2101 :
2102 233 : ViewShell *pSh = GetCurrShell();
2103 :
2104 : // #i12836# enhanced pdf
2105 233 : SwRegionRects aRegion( pSh && !pSh->GetViewOptions()->IsPDFExport() ?
2106 : pSh->VisArea() :
2107 466 : Frm() );
2108 699 : if( !pStartPos->nNode.GetNode().IsCntntNode() ||
2109 466 : !pStartPos->nNode.GetNode().GetCntntNode()->getLayoutFrm(this) ||
2110 239 : ( pStartPos->nNode != pEndPos->nNode &&
2111 12 : ( !pEndPos->nNode.GetNode().IsCntntNode() ||
2112 6 : !pEndPos->nNode.GetNode().GetCntntNode()->getLayoutFrm(this) ) ) )
2113 : {
2114 233 : return;
2115 : }
2116 :
2117 : //Erstmal die CntntFrms zum Start und End besorgen, die brauch ich auf
2118 : //jedenfall.
2119 233 : SwCntntFrm const* pStartFrm = pStartPos->nNode.GetNode().
2120 466 : GetCntntNode()->getLayoutFrm( this, &rCrsr.GetSttPos(), pStartPos );
2121 :
2122 233 : SwCntntFrm const* pEndFrm = pEndPos->nNode.GetNode().
2123 466 : GetCntntNode()->getLayoutFrm( this, &rCrsr.GetEndPos(), pEndPos );
2124 :
2125 : OSL_ENSURE( (pStartFrm && pEndFrm), "Keine CntntFrms gefunden." );
2126 :
2127 : //Damit die FlyFrms, in denen selektierte Frames stecken, nicht
2128 : //abgezogen werden
2129 466 : SwSortedObjs aSortObjs;
2130 233 : if ( pStartFrm->IsInFly() )
2131 : {
2132 0 : const SwAnchoredObject* pObj = pStartFrm->FindFlyFrm();
2133 : OSL_ENSURE( pObj, "No Start Object." );
2134 0 : if (pObj) aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj)) );
2135 0 : const SwAnchoredObject* pObj2 = pEndFrm->FindFlyFrm();
2136 : OSL_ENSURE( pObj2, "SwRootFrm::CalcFrmRects(..) - FlyFrame missing - looks like an invalid selection" );
2137 0 : if ( pObj2 != NULL && pObj2 != pObj )
2138 : {
2139 0 : aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj2)) );
2140 : }
2141 : }
2142 :
2143 : //Fall 4: Tabellenselection
2144 233 : if( bIsTblMode )
2145 : {
2146 0 : const SwFrm *pCell = pStartFrm->GetUpper();
2147 0 : while ( !pCell->IsCellFrm() )
2148 0 : pCell = pCell->GetUpper();
2149 0 : SwRect aTmp( pCell->Prt() );
2150 0 : aTmp.Pos() += pCell->Frm().Pos();
2151 0 : aRegion.ChangeOrigin( aTmp );
2152 0 : aRegion.clear();
2153 0 : aRegion.push_back( aTmp);
2154 : }
2155 : else
2156 : {
2157 : // falls eine nicht erlaubte Selection besteht, dann korrigiere das
2158 : // nicht erlaubt ist Header/Footer/TableHeadline ueber 2 Seiten
2159 : do { // middle check loop
2160 233 : const SwLayoutFrm* pSttLFrm = pStartFrm->GetUpper();
2161 233 : const sal_uInt16 cHdFtTblHd = FRM_HEADER | FRM_FOOTER | FRM_TAB;
2162 1864 : while( pSttLFrm &&
2163 699 : ! (cHdFtTblHd & pSttLFrm->GetType() ))
2164 699 : pSttLFrm = pSttLFrm->GetUpper();
2165 233 : if( !pSttLFrm )
2166 233 : break;
2167 0 : const SwLayoutFrm* pEndLFrm = pEndFrm->GetUpper();
2168 0 : while( pEndLFrm &&
2169 0 : ! (cHdFtTblHd & pEndLFrm->GetType() ))
2170 0 : pEndLFrm = pEndLFrm->GetUpper();
2171 0 : if( !pEndLFrm )
2172 0 : break;
2173 :
2174 : OSL_ENSURE( pEndLFrm->GetType() == pSttLFrm->GetType(),
2175 : "Selection ueber unterschiedliche Inhalte" );
2176 0 : switch( pSttLFrm->GetType() )
2177 : {
2178 : case FRM_HEADER:
2179 : case FRM_FOOTER:
2180 : // auf unterschiedlichen Seiten ??
2181 : // dann immer auf die Start-Seite
2182 0 : if( pEndLFrm->FindPageFrm() != pSttLFrm->FindPageFrm() )
2183 : {
2184 : // End- auf den Start-CntntFrame setzen
2185 0 : if( pStartPos == rCrsr.GetPoint() )
2186 0 : pEndFrm = pStartFrm;
2187 : else
2188 0 : pStartFrm = pEndFrm;
2189 : }
2190 0 : break;
2191 : case FRM_TAB:
2192 : // auf unterschiedlichen Seiten ??
2193 : // existiert
2194 : // dann teste auf Tabelle-Headline
2195 : {
2196 0 : const SwTabFrm* pTabFrm = (SwTabFrm*)pSttLFrm;
2197 0 : if( ( pTabFrm->GetFollow() ||
2198 0 : ((SwTabFrm*)pEndLFrm)->GetFollow() ) &&
2199 0 : pTabFrm->GetTable()->GetRowsToRepeat() > 0 &&
2200 0 : pTabFrm->GetLower() != ((SwTabFrm*)pEndLFrm)->GetLower() &&
2201 0 : ( lcl_IsInRepeatedHeadline( pStartFrm ) ||
2202 0 : lcl_IsInRepeatedHeadline( pEndFrm ) ) )
2203 : {
2204 : // End- auf den Start-CntntFrame setzen
2205 0 : if( pStartPos == rCrsr.GetPoint() )
2206 0 : pEndFrm = pStartFrm;
2207 : else
2208 0 : pStartFrm = pEndFrm;
2209 : }
2210 : }
2211 0 : break;
2212 : }
2213 : } while( false );
2214 :
2215 233 : SwCrsrMoveState aTmpState( MV_NONE );
2216 233 : aTmpState.b2Lines = sal_True;
2217 233 : aTmpState.bNoScroll = sal_True;
2218 233 : aTmpState.nCursorBidiLevel = pStartFrm->IsRightToLeft() ? 1 : 0;
2219 :
2220 : //CntntRects zu Start- und EndFrms.
2221 233 : SwRect aStRect, aEndRect;
2222 233 : pStartFrm->GetCharRect( aStRect, *pStartPos, &aTmpState );
2223 233 : Sw2LinesPos *pSt2Pos = aTmpState.p2Lines;
2224 233 : aTmpState.p2Lines = NULL;
2225 233 : aTmpState.nCursorBidiLevel = pEndFrm->IsRightToLeft() ? 1 : 0;
2226 :
2227 233 : pEndFrm->GetCharRect ( aEndRect, *pEndPos, &aTmpState );
2228 233 : Sw2LinesPos *pEnd2Pos = aTmpState.p2Lines;
2229 :
2230 233 : SwRect aStFrm ( pStartFrm->UnionFrm( sal_True ) );
2231 233 : aStFrm.Intersection( pStartFrm->PaintArea() );
2232 233 : SwRect aEndFrm( pStartFrm == pEndFrm ? aStFrm : pEndFrm->UnionFrm( sal_True ) );
2233 233 : if( pStartFrm != pEndFrm )
2234 : {
2235 9 : aEndFrm.Intersection( pEndFrm->PaintArea() );
2236 : }
2237 233 : SWRECTFN( pStartFrm )
2238 233 : const sal_Bool bR2L = pStartFrm->IsRightToLeft();
2239 233 : const sal_Bool bEndR2L = pEndFrm->IsRightToLeft();
2240 :
2241 : // If there's no doubleline portion involved or start and end are both
2242 : // in the same doubleline portion, all works fine, but otherwise
2243 : // we need the following...
2244 233 : if( pSt2Pos != pEnd2Pos && ( !pSt2Pos || !pEnd2Pos ||
2245 0 : pSt2Pos->aPortion != pEnd2Pos->aPortion ) )
2246 : {
2247 : // If we have a start(end) position inside a doubleline portion
2248 : // the surrounded part of the doubleline portion is subtracted
2249 : // from the region and the aStRect(aEndRect) is set to the
2250 : // end(start) of the doubleline portion.
2251 68 : if( pSt2Pos )
2252 : {
2253 0 : SwRect aTmp( aStRect );
2254 :
2255 : // BiDi-Portions are swimming against the current.
2256 0 : const sal_Bool bPorR2L = ( MT_BIDI == pSt2Pos->nMultiType ) ?
2257 0 : ! bR2L :
2258 0 : bR2L;
2259 :
2260 0 : if( MT_BIDI == pSt2Pos->nMultiType &&
2261 0 : (pSt2Pos->aPortion2.*fnRect->fnGetWidth)() )
2262 : {
2263 : // nested bidi portion
2264 0 : long nRightAbs = (pSt2Pos->aPortion.*fnRect->fnGetRight)();
2265 0 : nRightAbs -= (pSt2Pos->aPortion2.*fnRect->fnGetLeft)();
2266 0 : long nLeftAbs = nRightAbs - (pSt2Pos->aPortion2.*fnRect->fnGetWidth)();
2267 :
2268 0 : (aTmp.*fnRect->fnSetRight)( nRightAbs );
2269 :
2270 0 : if ( ! pEnd2Pos || pEnd2Pos->aPortion != pSt2Pos->aPortion )
2271 : {
2272 0 : SwRect aTmp2( pSt2Pos->aPortion );
2273 0 : (aTmp2.*fnRect->fnSetRight)( nLeftAbs );
2274 0 : aTmp2.Intersection( aEndFrm );
2275 0 : Sub( aRegion, aTmp2 );
2276 : }
2277 : }
2278 : else
2279 : {
2280 0 : if( bPorR2L )
2281 : (aTmp.*fnRect->fnSetLeft)(
2282 0 : (pSt2Pos->aPortion.*fnRect->fnGetLeft)() );
2283 : else
2284 : (aTmp.*fnRect->fnSetRight)(
2285 0 : (pSt2Pos->aPortion.*fnRect->fnGetRight)() );
2286 : }
2287 :
2288 0 : if( MT_ROT_90 == pSt2Pos->nMultiType ||
2289 0 : (pSt2Pos->aPortion.*fnRect->fnGetTop)() ==
2290 0 : (aTmp.*fnRect->fnGetTop)() )
2291 : {
2292 : (aTmp.*fnRect->fnSetTop)(
2293 0 : (pSt2Pos->aLine.*fnRect->fnGetTop)() );
2294 : }
2295 :
2296 0 : aTmp.Intersection( aStFrm );
2297 0 : Sub( aRegion, aTmp );
2298 :
2299 0 : SwTwips nTmp = (pSt2Pos->aLine.*fnRect->fnGetBottom)();
2300 0 : if( MT_ROT_90 != pSt2Pos->nMultiType &&
2301 0 : (aStRect.*fnRect->fnBottomDist)( nTmp ) > 0 )
2302 : {
2303 0 : (aTmp.*fnRect->fnSetTop)( (aTmp.*fnRect->fnGetBottom)() );
2304 0 : (aTmp.*fnRect->fnSetBottom)( nTmp );
2305 0 : if( (aStRect.*fnRect->fnBottomDist)(
2306 0 : (pSt2Pos->aPortion.*fnRect->fnGetBottom)() ) > 0 )
2307 : {
2308 0 : if( bPorR2L )
2309 : (aTmp.*fnRect->fnSetRight)(
2310 0 : (pSt2Pos->aPortion.*fnRect->fnGetRight)() );
2311 : else
2312 : (aTmp.*fnRect->fnSetLeft)(
2313 0 : (pSt2Pos->aPortion.*fnRect->fnGetLeft)() );
2314 : }
2315 0 : aTmp.Intersection( aStFrm );
2316 0 : Sub( aRegion, aTmp );
2317 : }
2318 :
2319 0 : aStRect = pSt2Pos->aLine;
2320 : (aStRect.*fnRect->fnSetLeft)( bR2L ?
2321 0 : (pSt2Pos->aPortion.*fnRect->fnGetLeft)() :
2322 0 : (pSt2Pos->aPortion.*fnRect->fnGetRight)() );
2323 0 : (aStRect.*fnRect->fnSetWidth)( 1 );
2324 : }
2325 :
2326 68 : if( pEnd2Pos )
2327 : {
2328 68 : SWRECTFNX( pEndFrm )
2329 68 : SwRect aTmp( aEndRect );
2330 :
2331 : // BiDi-Portions are swimming against the current.
2332 68 : const sal_Bool bPorR2L = ( MT_BIDI == pEnd2Pos->nMultiType ) ?
2333 0 : ! bEndR2L :
2334 68 : bEndR2L;
2335 :
2336 68 : if( MT_BIDI == pEnd2Pos->nMultiType &&
2337 0 : (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)() )
2338 : {
2339 : // nested bidi portion
2340 0 : long nRightAbs = (pEnd2Pos->aPortion.*fnRectX->fnGetRight)();
2341 0 : nRightAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetLeft)();
2342 0 : long nLeftAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)();
2343 :
2344 0 : (aTmp.*fnRectX->fnSetLeft)( nLeftAbs );
2345 :
2346 0 : if ( ! pSt2Pos || pSt2Pos->aPortion != pEnd2Pos->aPortion )
2347 : {
2348 0 : SwRect aTmp2( pEnd2Pos->aPortion );
2349 0 : (aTmp2.*fnRectX->fnSetLeft)( nRightAbs );
2350 0 : aTmp2.Intersection( aEndFrm );
2351 0 : Sub( aRegion, aTmp2 );
2352 : }
2353 : }
2354 : else
2355 : {
2356 68 : if ( bPorR2L )
2357 : (aTmp.*fnRectX->fnSetRight)(
2358 0 : (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() );
2359 : else
2360 : (aTmp.*fnRectX->fnSetLeft)(
2361 68 : (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() );
2362 : }
2363 :
2364 136 : if( MT_ROT_90 == pEnd2Pos->nMultiType ||
2365 68 : (pEnd2Pos->aPortion.*fnRectX->fnGetBottom)() ==
2366 68 : (aEndRect.*fnRectX->fnGetBottom)() )
2367 : {
2368 : (aTmp.*fnRectX->fnSetBottom)(
2369 24 : (pEnd2Pos->aLine.*fnRectX->fnGetBottom)() );
2370 : }
2371 :
2372 68 : aTmp.Intersection( aEndFrm );
2373 68 : Sub( aRegion, aTmp );
2374 :
2375 : // The next statement means neither ruby nor rotate(90):
2376 68 : if( !( MT_RUBY & pEnd2Pos->nMultiType ) )
2377 : {
2378 15 : SwTwips nTmp = (pEnd2Pos->aLine.*fnRectX->fnGetTop)();
2379 15 : if( (aEndRect.*fnRectX->fnGetTop)() != nTmp )
2380 : {
2381 : (aTmp.*fnRectX->fnSetBottom)(
2382 15 : (aTmp.*fnRectX->fnGetTop)() );
2383 15 : (aTmp.*fnRectX->fnSetTop)( nTmp );
2384 30 : if( (aEndRect.*fnRectX->fnGetTop)() !=
2385 15 : (pEnd2Pos->aPortion.*fnRectX->fnGetTop)() )
2386 : {
2387 15 : if( bPorR2L )
2388 : (aTmp.*fnRectX->fnSetLeft)(
2389 0 : (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() );
2390 : else
2391 : (aTmp.*fnRectX->fnSetRight)(
2392 15 : (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() );
2393 : }
2394 15 : aTmp.Intersection( aEndFrm );
2395 15 : Sub( aRegion, aTmp );
2396 : }
2397 : }
2398 :
2399 68 : aEndRect = pEnd2Pos->aLine;
2400 : (aEndRect.*fnRectX->fnSetLeft)( bEndR2L ?
2401 0 : (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() :
2402 68 : (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() );
2403 68 : (aEndRect.*fnRectX->fnSetWidth)( 1 );
2404 : }
2405 : }
2406 165 : else if( pSt2Pos && pEnd2Pos &&
2407 0 : MT_BIDI == pSt2Pos->nMultiType &&
2408 0 : MT_BIDI == pEnd2Pos->nMultiType &&
2409 165 : pSt2Pos->aPortion == pEnd2Pos->aPortion &&
2410 0 : pSt2Pos->aPortion2 != pEnd2Pos->aPortion2 )
2411 : {
2412 : // This is the ugly special case, where the selection starts and
2413 : // ends in the same bidi portion but one start or end is inside a
2414 : // nested bidi portion.
2415 :
2416 0 : if ( (pSt2Pos->aPortion2.*fnRect->fnGetWidth)() )
2417 : {
2418 0 : SwRect aTmp( aStRect );
2419 0 : long nRightAbs = (pSt2Pos->aPortion.*fnRect->fnGetRight)();
2420 0 : nRightAbs -= (pSt2Pos->aPortion2.*fnRect->fnGetLeft)();
2421 0 : long nLeftAbs = nRightAbs - (pSt2Pos->aPortion2.*fnRect->fnGetWidth)();
2422 :
2423 0 : (aTmp.*fnRect->fnSetRight)( nRightAbs );
2424 0 : aTmp.Intersection( aStFrm );
2425 0 : Sub( aRegion, aTmp );
2426 :
2427 0 : aStRect = pSt2Pos->aLine;
2428 0 : (aStRect.*fnRect->fnSetLeft)( bR2L ? nRightAbs : nLeftAbs );
2429 0 : (aStRect.*fnRect->fnSetWidth)( 1 );
2430 : }
2431 :
2432 0 : SWRECTFNX( pEndFrm )
2433 0 : if ( (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)() )
2434 : {
2435 0 : SwRect aTmp( aEndRect );
2436 0 : long nRightAbs = (pEnd2Pos->aPortion.*fnRectX->fnGetRight)();
2437 0 : nRightAbs -= (pEnd2Pos->aPortion2.*fnRectX->fnGetLeft)();
2438 0 : long nLeftAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)();
2439 :
2440 0 : (aTmp.*fnRectX->fnSetLeft)( nLeftAbs );
2441 0 : aTmp.Intersection( aEndFrm );
2442 0 : Sub( aRegion, aTmp );
2443 :
2444 0 : aEndRect = pEnd2Pos->aLine;
2445 0 : (aEndRect.*fnRectX->fnSetLeft)( bEndR2L ? nLeftAbs : nRightAbs );
2446 0 : (aEndRect.*fnRectX->fnSetWidth)( 1 );
2447 : }
2448 : }
2449 :
2450 : // The charrect may be outside the paintarea (for cursortravelling)
2451 : // but the selection has to be restricted to the paintarea
2452 233 : if( aStRect.Left() < aStFrm.Left() )
2453 1 : aStRect.Left( aStFrm.Left() );
2454 232 : else if( aStRect.Left() > aStFrm.Right() )
2455 0 : aStRect.Left( aStFrm.Right() );
2456 233 : SwTwips nTmp = aStRect.Right();
2457 233 : if( nTmp < aStFrm.Left() )
2458 1 : aStRect.Right( aStFrm.Left() );
2459 232 : else if( nTmp > aStFrm.Right() )
2460 0 : aStRect.Right( aStFrm.Right() );
2461 233 : if( aEndRect.Left() < aEndFrm.Left() )
2462 1 : aEndRect.Left( aEndFrm.Left() );
2463 232 : else if( aEndRect.Left() > aEndFrm.Right() )
2464 0 : aEndRect.Left( aEndFrm.Right() );
2465 233 : nTmp = aEndRect.Right();
2466 233 : if( nTmp < aEndFrm.Left() )
2467 1 : aEndRect.Right( aEndFrm.Left() );
2468 232 : else if( nTmp > aEndFrm.Right() )
2469 0 : aEndRect.Right( aEndFrm.Right() );
2470 :
2471 233 : if( pStartFrm == pEndFrm )
2472 : {
2473 0 : sal_Bool bSameRotatedOrBidi = pSt2Pos && pEnd2Pos &&
2474 224 : ( MT_BIDI & pSt2Pos->nMultiType ) &&
2475 224 : pSt2Pos->aPortion == pEnd2Pos->aPortion;
2476 : //case 1: (Same frame and same row)
2477 448 : if( bSameRotatedOrBidi ||
2478 224 : (aStRect.*fnRect->fnGetTop)() == (aEndRect.*fnRect->fnGetTop)() )
2479 : {
2480 219 : Point aTmpSt( aStRect.Pos() );
2481 219 : Point aTmpEnd( aEndRect.Right(), aEndRect.Bottom() );
2482 219 : if( bSameRotatedOrBidi || bR2L )
2483 : {
2484 0 : if( aTmpSt.Y() > aTmpEnd.Y() )
2485 : {
2486 0 : long nTmpY = aTmpEnd.Y();
2487 0 : aTmpEnd.Y() = aTmpSt.Y();
2488 0 : aTmpSt.Y() = nTmpY;
2489 : }
2490 0 : if( aTmpSt.X() > aTmpEnd.X() )
2491 : {
2492 0 : long nTmpX = aTmpEnd.X();
2493 0 : aTmpEnd.X() = aTmpSt.X();
2494 0 : aTmpSt.X() = nTmpX;
2495 : }
2496 : }
2497 :
2498 219 : SwRect aTmp = SwRect( aTmpSt, aTmpEnd );
2499 : // Bug 34888: falls Inhalt selektiert ist, der keinen Platz
2500 : // einnimmt (z.B. PostIts,RefMarks, TOXMarks),
2501 : // dann mindestens die Breite des Crsr setzen.
2502 294 : if( 1 == (aTmp.*fnRect->fnGetWidth)() &&
2503 75 : pStartPos->nContent.GetIndex() !=
2504 75 : pEndPos->nContent.GetIndex() )
2505 : {
2506 69 : OutputDevice* pOut = pSh->GetOut();
2507 69 : long nCrsrWidth = pOut->GetSettings().GetStyleSettings().
2508 69 : GetCursorSize();
2509 : (aTmp.*fnRect->fnSetWidth)( pOut->PixelToLogic(
2510 69 : Size( nCrsrWidth, 0 ) ).Width() );
2511 : }
2512 219 : aTmp.Intersection( aStFrm );
2513 219 : Sub( aRegion, aTmp );
2514 : }
2515 : //case 2: (Same frame, but not the same line)
2516 : else
2517 : {
2518 : SwTwips lLeft, lRight;
2519 5 : if( pSt2Pos && pEnd2Pos && pSt2Pos->aPortion == pEnd2Pos->aPortion )
2520 : {
2521 0 : lLeft = (pSt2Pos->aPortion.*fnRect->fnGetLeft)();
2522 0 : lRight = (pSt2Pos->aPortion.*fnRect->fnGetRight)();
2523 : }
2524 : else
2525 : {
2526 5 : lLeft = (pStartFrm->Frm().*fnRect->fnGetLeft)() +
2527 5 : (pStartFrm->Prt().*fnRect->fnGetLeft)();
2528 5 : lRight = (pStartFrm->Frm().*fnRect->fnGetLeft)() +
2529 5 : (pStartFrm->Prt().*fnRect->fnGetRight)();
2530 : }
2531 5 : if( lLeft < (aStFrm.*fnRect->fnGetLeft)() )
2532 0 : lLeft = (aStFrm.*fnRect->fnGetLeft)();
2533 5 : if( lRight > (aStFrm.*fnRect->fnGetRight)() )
2534 0 : lRight = (aStFrm.*fnRect->fnGetRight)();
2535 5 : SwRect aSubRect( aStRect );
2536 : //First line
2537 5 : if( bR2L )
2538 0 : (aSubRect.*fnRect->fnSetLeft)( lLeft );
2539 : else
2540 5 : (aSubRect.*fnRect->fnSetRight)( lRight );
2541 5 : Sub( aRegion, aSubRect );
2542 :
2543 : //If there's at least a twips between start- and endline,
2544 : //so the whole area between will be added.
2545 5 : SwTwips aTmpBottom = (aStRect.*fnRect->fnGetBottom)();
2546 5 : SwTwips aTmpTop = (aEndRect.*fnRect->fnGetTop)();
2547 5 : if( aTmpBottom != aTmpTop )
2548 : {
2549 5 : (aSubRect.*fnRect->fnSetLeft)( lLeft );
2550 5 : (aSubRect.*fnRect->fnSetRight)( lRight );
2551 5 : (aSubRect.*fnRect->fnSetTop)( aTmpBottom );
2552 5 : (aSubRect.*fnRect->fnSetBottom)( aTmpTop );
2553 5 : Sub( aRegion, aSubRect );
2554 : }
2555 : //and the last line
2556 5 : aSubRect = aEndRect;
2557 5 : if( bR2L )
2558 0 : (aSubRect.*fnRect->fnSetRight)( lRight );
2559 : else
2560 5 : (aSubRect.*fnRect->fnSetLeft)( lLeft );
2561 5 : Sub( aRegion, aSubRect );
2562 : }
2563 : }
2564 : //case 3: (Different frames, maybe with ohther frames between
2565 : else
2566 : {
2567 : //The startframe first...
2568 9 : SwRect aSubRect( aStRect );
2569 9 : if( bR2L )
2570 0 : (aSubRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)());
2571 : else
2572 9 : (aSubRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)());
2573 9 : Sub( aRegion, aSubRect );
2574 9 : SwTwips nTmpTwips = (aStRect.*fnRect->fnGetBottom)();
2575 9 : if( (aStFrm.*fnRect->fnGetBottom)() != nTmpTwips )
2576 : {
2577 7 : aSubRect = aStFrm;
2578 7 : (aSubRect.*fnRect->fnSetTop)( nTmpTwips );
2579 7 : Sub( aRegion, aSubRect );
2580 : }
2581 :
2582 : //Now the frames between, if there are any
2583 9 : bool const bBody = pStartFrm->IsInDocBody();
2584 9 : const SwTableBox* pCellBox = pStartFrm->GetUpper()->IsCellFrm() ?
2585 9 : ((SwCellFrm*)pStartFrm->GetUpper())->GetTabBox() : 0;
2586 9 : const SwCntntFrm *pCntnt = pStartFrm->GetNextCntntFrm();
2587 9 : SwRect aPrvRect;
2588 :
2589 : OSL_ENSURE( pCntnt,
2590 : "<SwRootFrm::CalcFrmRects(..)> - no content frame. This is a serious defect -> please inform OD" );
2591 60 : while ( pCntnt && pCntnt != pEndFrm )
2592 : {
2593 42 : if ( pCntnt->IsInFly() )
2594 : {
2595 0 : const SwAnchoredObject* pObj = pCntnt->FindFlyFrm();
2596 0 : aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj)) );
2597 : }
2598 :
2599 : // Consider only frames which have the same IsInDocBody value like pStartFrm
2600 : // If pStartFrm is inside a SwCellFrm, consider only frames which are inside the
2601 : // same cell frame (or its follow cell)
2602 42 : const SwTableBox* pTmpCellBox = pCntnt->GetUpper()->IsCellFrm() ?
2603 42 : ((SwCellFrm*)pCntnt->GetUpper())->GetTabBox() : 0;
2604 84 : if ( bBody == pCntnt->IsInDocBody() &&
2605 0 : ( !pCellBox || pCellBox == pTmpCellBox ) )
2606 : {
2607 42 : SwRect aCRect( pCntnt->UnionFrm( sal_True ) );
2608 42 : aCRect.Intersection( pCntnt->PaintArea() );
2609 42 : if( aCRect.IsOver( aRegion.GetOrigin() ))
2610 : {
2611 8 : SwRect aTmp( aPrvRect );
2612 8 : aTmp.Union( aCRect );
2613 24 : if ( (aPrvRect.Height() * aPrvRect.Width() +
2614 8 : aCRect.Height() * aCRect.Width()) ==
2615 8 : (aTmp.Height() * aTmp.Width()) )
2616 : {
2617 4 : aPrvRect.Union( aCRect );
2618 : }
2619 : else
2620 : {
2621 4 : if ( aPrvRect.HasArea() )
2622 0 : Sub( aRegion, aPrvRect );
2623 4 : aPrvRect = aCRect;
2624 : }
2625 : }
2626 : }
2627 42 : pCntnt = pCntnt->GetNextCntntFrm();
2628 : OSL_ENSURE( pCntnt,
2629 : "<SwRootFrm::CalcFrmRects(..)> - no content frame. This is a serious defect -> please inform OD" );
2630 : }
2631 9 : if ( aPrvRect.HasArea() )
2632 4 : Sub( aRegion, aPrvRect );
2633 :
2634 : //At least the endframe...
2635 9 : bVert = pEndFrm->IsVertical();
2636 9 : bRev = pEndFrm->IsReverse();
2637 : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
2638 0 : fnRect = bVert ? ( bRev ? fnRectVL2R : ( pEndFrm->IsVertLR() ? fnRectVertL2R : fnRectVert ) ) :
2639 9 : ( bRev ? fnRectB2T : fnRectHori );
2640 9 : nTmpTwips = (aEndRect.*fnRect->fnGetTop)();
2641 9 : if( (aEndFrm.*fnRect->fnGetTop)() != nTmpTwips )
2642 : {
2643 3 : aSubRect = aEndFrm;
2644 3 : (aSubRect.*fnRect->fnSetBottom)( nTmpTwips );
2645 3 : Sub( aRegion, aSubRect );
2646 : }
2647 9 : aSubRect = aEndRect;
2648 9 : if( bEndR2L )
2649 0 : (aSubRect.*fnRect->fnSetRight)((aEndFrm.*fnRect->fnGetRight)());
2650 : else
2651 9 : (aSubRect.*fnRect->fnSetLeft)( (aEndFrm.*fnRect->fnGetLeft)() );
2652 9 : Sub( aRegion, aSubRect );
2653 : }
2654 :
2655 233 : aRegion.Invert();
2656 233 : delete pSt2Pos;
2657 233 : delete pEnd2Pos;
2658 : }
2659 :
2660 : //Flys mit Durchlauf ausstanzen. Nicht ausgestanzt werden Flys:
2661 : //- die Lower des StartFrm/EndFrm sind (FlyInCnt und alle Flys die wiederum
2662 : // darin sitzen)
2663 : //- in der Z-Order ueber denjenigen Flys stehen in denen sich der StartFrm
2664 : // befindet.
2665 233 : const SwPageFrm *pPage = pStartFrm->FindPageFrm();
2666 233 : const SwPageFrm *pEndPage = pEndFrm->FindPageFrm();
2667 :
2668 473 : while ( pPage )
2669 : {
2670 240 : if ( pPage->GetSortedObjs() )
2671 : {
2672 0 : const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
2673 0 : for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
2674 : {
2675 0 : SwAnchoredObject* pAnchoredObj = rObjs[i];
2676 0 : if ( !pAnchoredObj->ISA(SwFlyFrm) )
2677 0 : continue;
2678 0 : const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj);
2679 0 : const SwVirtFlyDrawObj* pObj = pFly->GetVirtDrawObj();
2680 0 : const SwFmtSurround &rSur = pFly->GetFmt()->GetSurround();
2681 0 : if ( !pFly->IsAnLower( pStartFrm ) &&
2682 0 : (rSur.GetSurround() != SURROUND_THROUGHT &&
2683 0 : !rSur.IsContour()) )
2684 : {
2685 0 : if ( aSortObjs.Contains( *pAnchoredObj ) )
2686 0 : continue;
2687 :
2688 0 : sal_Bool bSub = sal_True;
2689 0 : const sal_uInt32 nPos = pObj->GetOrdNum();
2690 0 : for ( sal_uInt16 k = 0; bSub && k < aSortObjs.Count(); ++k )
2691 : {
2692 : OSL_ENSURE( aSortObjs[k]->ISA(SwFlyFrm),
2693 : "<SwRootFrm::CalcFrmRects(..)> - object in <aSortObjs> of unexcepted type" );
2694 0 : const SwFlyFrm* pTmp = static_cast<SwFlyFrm*>(aSortObjs[k]);
2695 0 : do
2696 : {
2697 0 : if ( nPos < pTmp->GetVirtDrawObj()->GetOrdNumDirect() )
2698 : {
2699 0 : bSub = sal_False;
2700 : }
2701 : else
2702 : {
2703 0 : pTmp = pTmp->GetAnchorFrm()->FindFlyFrm();
2704 : }
2705 0 : } while ( bSub && pTmp );
2706 : }
2707 0 : if ( bSub )
2708 0 : Sub( aRegion, pFly->Frm() );
2709 : }
2710 : }
2711 : }
2712 240 : if ( pPage == pEndPage )
2713 233 : break;
2714 : else
2715 7 : pPage = (SwPageFrm*)pPage->GetNext();
2716 : }
2717 :
2718 : //Weil's besser aussieht noch die DropCaps ausschliessen.
2719 233 : SwRect aDropRect;
2720 233 : if ( pStartFrm->IsTxtFrm() )
2721 : {
2722 233 : if ( ((SwTxtFrm*)pStartFrm)->GetDropRect( aDropRect ) )
2723 0 : Sub( aRegion, aDropRect );
2724 : }
2725 233 : if ( pEndFrm != pStartFrm && pEndFrm->IsTxtFrm() )
2726 : {
2727 9 : if ( ((SwTxtFrm*)pEndFrm)->GetDropRect( aDropRect ) )
2728 0 : Sub( aRegion, aDropRect );
2729 : }
2730 :
2731 466 : rCrsr.assign( aRegion.begin(), aRegion.end() );
2732 99 : }
2733 :
2734 :
2735 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|