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