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