xref: /trunk/main/sw/source/ui/wrtsh/move.cxx (revision 083d9fe7b3d2dda5c3695550b2c36f86003acbfa)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_sw.hxx"
24 
25 #include <sfx2/bindings.hxx>
26 #include <wrtsh.hxx>
27 #ifndef _VIEW_HXX
28 #include <view.hxx>
29 #endif
30 #include <viewopt.hxx>
31 #include <crsskip.hxx>
32 
33 /*  Immer:
34     -   Zurücksetzen des Cursorstacks
35     -   Timer nachtriggern
36     -   gfs. GCAttr
37 
38     bei Selektion
39     -   SttSelect()
40 
41     sonst
42     -   EndSelect()
43  */
44 
45 const long nReadOnlyScrollOfst = 10;
46 
47 class ShellMoveCrsr
48 {
49     SwWrtShell* pSh;
50     sal_Bool bAct;
51 public:
52     inline ShellMoveCrsr( SwWrtShell* pWrtSh, sal_Bool bSel )
53     {
54         bAct = !pWrtSh->ActionPend() && (pWrtSh->GetFrmType(0,sal_False) & FRMTYPE_FLY_ANY);
55         ( pSh = pWrtSh )->MoveCrsr( sal_Bool(bSel) );
56         pWrtSh->GetView().GetViewFrame()->GetBindings().Invalidate(SID_HYPERLINK_GETLINK);
57     }
58     inline ~ShellMoveCrsr()
59     {
60         if( bAct )
61         {
62             //Die Action wird für das Scrollen in "einabsaetzigen" Rahmen mit
63             //fester Höhe gebraucht.
64             pSh->StartAllAction();
65             pSh->EndAllAction();
66         }
67     }
68 };
69 
70 void SwWrtShell::MoveCrsr( sal_Bool bWithSelect )
71 {
72     ResetCursorStack();
73     if ( IsGCAttr() )
74     {
75         GCAttr();
76         ClearGCAttr();
77     }
78     if ( bWithSelect )
79         SttSelect();
80     else
81     {
82         EndSelect();
83         (this->*fnKillSel)( 0, sal_False );
84     }
85 }
86 
87 sal_Bool SwWrtShell::SimpleMove( FNSimpleMove FnSimpleMove, sal_Bool bSelect )
88 {
89     sal_Bool nRet;
90     if( bSelect )
91     {
92         SttCrsrMove();
93         MoveCrsr( sal_True );
94         nRet = (this->*FnSimpleMove)();
95         EndCrsrMove();
96     }
97     else if( 0 != ( nRet = (this->*FnSimpleMove)() ) )
98         MoveCrsr( sal_False );
99     return nRet;
100 }
101 
102 
103 sal_Bool SwWrtShell::Left( sal_uInt16 nMode, sal_Bool bSelect,
104                             sal_uInt16 nCount, sal_Bool bBasicCall, sal_Bool bVisual )
105 {
106     if ( !bSelect && !bBasicCall && IsCrsrReadonly()  && !GetViewOptions()->IsSelectionInReadonly())
107     {
108         Point aTmp( VisArea().Pos() );
109         aTmp.X() -= VisArea().Width() * nReadOnlyScrollOfst / 100;
110         rView.SetVisArea( aTmp );
111         return sal_True;
112     }
113     else
114     {
115         ShellMoveCrsr aTmp( this, bSelect );
116         return SwCrsrShell::Left( nCount, nMode, bVisual );
117     }
118 }
119 
120 
121 
122 sal_Bool SwWrtShell::Right( sal_uInt16 nMode, sal_Bool bSelect,
123                             sal_uInt16 nCount, sal_Bool bBasicCall, sal_Bool bVisual )
124 {
125     if ( !bSelect && !bBasicCall && IsCrsrReadonly() && !GetViewOptions()->IsSelectionInReadonly() )
126     {
127         Point aTmp( VisArea().Pos() );
128         aTmp.X() += VisArea().Width() * nReadOnlyScrollOfst / 100;
129         aTmp.X() = rView.SetHScrollMax( aTmp.X() );
130         rView.SetVisArea( aTmp );
131         return sal_True;
132     }
133     else
134     {
135         ShellMoveCrsr aTmp( this, bSelect );
136         return SwCrsrShell::Right( nCount, nMode, bVisual );
137     }
138 }
139 
140 
141 
142 sal_Bool SwWrtShell::Up( sal_Bool bSelect, sal_uInt16 nCount, sal_Bool bBasicCall )
143 {
144     if ( !bSelect && !bBasicCall && IsCrsrReadonly()  && !GetViewOptions()->IsSelectionInReadonly())
145     {
146         Point aTmp( VisArea().Pos() );
147         aTmp.Y() -= VisArea().Height() * nReadOnlyScrollOfst / 100;
148         rView.SetVisArea( aTmp );
149         return sal_True;
150     }
151     else
152     {
153         ShellMoveCrsr aTmp( this, bSelect );
154         return SwCrsrShell::Up( nCount );
155     }
156 }
157 
158 
159 
160 sal_Bool SwWrtShell::Down( sal_Bool bSelect, sal_uInt16 nCount, sal_Bool bBasicCall )
161 {
162     if ( !bSelect && !bBasicCall && IsCrsrReadonly() && !GetViewOptions()->IsSelectionInReadonly())
163     {
164         Point aTmp( VisArea().Pos() );
165         aTmp.Y() += VisArea().Height() * nReadOnlyScrollOfst / 100;
166         aTmp.Y() = rView.SetVScrollMax( aTmp.Y() );
167         rView.SetVisArea( aTmp );
168         return sal_True;
169     }
170     else
171     {
172         ShellMoveCrsr aTmp( this, bSelect );
173         return SwCrsrShell::Down( nCount );
174     }
175 }
176 
177 
178 
179 sal_Bool SwWrtShell::LeftMargin( sal_Bool bSelect, sal_Bool bBasicCall )
180 {
181     if ( !bSelect && !bBasicCall && IsCrsrReadonly() )
182     {
183         Point aTmp( VisArea().Pos() );
184         aTmp.X() = DOCUMENTBORDER;
185         rView.SetVisArea( aTmp );
186         return sal_True;
187     }
188     else
189     {
190         ShellMoveCrsr aTmp( this, bSelect );
191         return SwCrsrShell::LeftMargin();
192     }
193 }
194 
195 
196 
197 sal_Bool SwWrtShell::RightMargin( sal_Bool bSelect, sal_Bool bBasicCall  )
198 {
199     if ( !bSelect && !bBasicCall && IsCrsrReadonly() )
200     {
201         Point aTmp( VisArea().Pos() );
202         aTmp.X() = GetDocSize().Width() - VisArea().Width() + DOCUMENTBORDER;
203         if( DOCUMENTBORDER > aTmp.X() )
204             aTmp.X() = DOCUMENTBORDER;
205         rView.SetVisArea( aTmp );
206         return sal_True;
207     }
208     else
209     {
210         ShellMoveCrsr aTmp( this, bSelect );
211         return SwCrsrShell::RightMargin(bBasicCall);
212     }
213 }
214 
215 
216 
217 sal_Bool SwWrtShell::GoStart( sal_Bool bKeepArea, sal_Bool *pMoveTable,
218                             sal_Bool bSelect, sal_Bool bDontMoveRegion )
219 {
220     if ( IsCrsrInTbl() )
221     {
222         const sal_Bool bBoxSelection = HasBoxSelection();
223         if( !bBlockMode )
224         {
225             if ( !bSelect )
226                 EnterStdMode();
227             else
228                 SttSelect();
229         }
230             // Tabellenzelle?
231         if ( !bBoxSelection && (MoveSection( fnSectionCurr, fnSectionStart)
232                 || bDontMoveRegion))
233         {
234             if ( pMoveTable )
235                 *pMoveTable = sal_False;
236             return sal_True;
237         }
238         if( MoveTable( fnTableCurr, fnTableStart ) || bDontMoveRegion )
239         {
240             if ( pMoveTable )
241                 *pMoveTable = sal_True;
242             return sal_True;
243         }
244         else if( bBoxSelection && pMoveTable )
245         {
246             // JP 09.01.96: wir haben eine Boxselektion (oder leere Zelle)
247             //              und wollen selektieren (pMoveTable wird im
248             //              SelAll gesetzt). Dann darf die Tabelle nicht
249             //              verlassen werden; sonst ist keine Selektion der
250             //              gesamten Tabelle moeglich!
251             *pMoveTable = sal_True;
252             return sal_True;
253         }
254     }
255 
256     if( !bBlockMode )
257     {
258         if ( !bSelect )
259             EnterStdMode();
260         else
261             SttSelect();
262     }
263     const sal_uInt16 nFrmType = GetFrmType(0,sal_False);
264     if ( FRMTYPE_FLY_ANY & nFrmType )
265     {
266         if( MoveSection( fnSectionCurr, fnSectionStart ) )
267             return sal_True;
268         else if ( FRMTYPE_FLY_FREE & nFrmType || bDontMoveRegion )
269             return sal_False;
270     }
271     if(( FRMTYPE_HEADER | FRMTYPE_FOOTER | FRMTYPE_FOOTNOTE ) & nFrmType )
272     {
273         if ( MoveSection( fnSectionCurr, fnSectionStart ) )
274             return sal_True;
275         else if ( bKeepArea )
276             return sal_True;
277     }
278     // Bereiche ???
279     return SwCrsrShell::MoveRegion( fnRegionCurrAndSkip, fnRegionStart ) ||
280            SwCrsrShell::SttEndDoc(sal_True);
281 }
282 
283 
284 
285 sal_Bool SwWrtShell::GoEnd(sal_Bool bKeepArea, sal_Bool *pMoveTable)
286 {
287     if ( pMoveTable && *pMoveTable )
288         return MoveTable( fnTableCurr, fnTableEnd );
289 
290     if ( IsCrsrInTbl() )
291     {
292         if ( MoveSection( fnSectionCurr, fnSectionEnd ) ||
293              MoveTable( fnTableCurr, fnTableEnd ) )
294             return sal_True;
295     }
296     else
297     {
298         const sal_uInt16 nFrmType = GetFrmType(0,sal_False);
299         if ( FRMTYPE_FLY_ANY & nFrmType )
300         {
301             if ( MoveSection( fnSectionCurr, fnSectionEnd ) )
302                 return sal_True;
303             else if ( FRMTYPE_FLY_FREE & nFrmType )
304                 return sal_False;
305         }
306         if(( FRMTYPE_HEADER | FRMTYPE_FOOTER | FRMTYPE_FOOTNOTE ) & nFrmType )
307         {
308             if ( MoveSection( fnSectionCurr, fnSectionEnd) )
309                 return sal_True;
310             else if ( bKeepArea )
311                 return sal_True;
312         }
313     }
314     // Bereiche ???
315     return SwCrsrShell::MoveRegion( fnRegionCurrAndSkip, fnRegionEnd ) ||
316            SwCrsrShell::SttEndDoc(sal_False);
317 }
318 
319 
320 
321 sal_Bool SwWrtShell::SttDoc( sal_Bool bSelect )
322 {
323     ShellMoveCrsr aTmp( this, bSelect );
324     return GoStart(sal_False, 0, bSelect );
325 }
326 
327 
328 
329 sal_Bool SwWrtShell::EndDoc( sal_Bool bSelect)
330 {
331     ShellMoveCrsr aTmp( this, bSelect );
332     return GoEnd();
333 }
334 
335 
336 sal_Bool SwWrtShell::SttNxtPg( sal_Bool bSelect )
337 {
338     ShellMoveCrsr aTmp( this, bSelect );
339     return MovePage( fnPageNext, fnPageStart );
340 }
341 
342 
343 
344 sal_Bool SwWrtShell::SttPrvPg( sal_Bool bSelect )
345 {
346     ShellMoveCrsr aTmp( this, bSelect );
347     return MovePage( fnPagePrev, fnPageStart );
348 }
349 
350 
351 
352 sal_Bool SwWrtShell::EndNxtPg( sal_Bool bSelect )
353 {
354     ShellMoveCrsr aTmp( this, bSelect );
355     return MovePage( fnPageNext, fnPageEnd );
356 }
357 
358 
359 
360 sal_Bool SwWrtShell::EndPrvPg( sal_Bool bSelect )
361 {
362     ShellMoveCrsr aTmp( this, bSelect );
363     return MovePage( fnPagePrev, fnPageEnd );
364 }
365 
366 
367 
368 sal_Bool SwWrtShell::SttPg( sal_Bool bSelect )
369 {
370     ShellMoveCrsr aTmp( this, bSelect );
371     return MovePage( fnPageCurr, fnPageStart );
372 }
373 
374 
375 
376 sal_Bool SwWrtShell::EndPg( sal_Bool bSelect )
377 {
378     ShellMoveCrsr aTmp( this, bSelect );
379     return MovePage( fnPageCurr, fnPageEnd );
380 }
381 
382 
383 
384 sal_Bool SwWrtShell::SttPara( sal_Bool bSelect )
385 {
386     ShellMoveCrsr aTmp( this, bSelect );
387     return MovePara( fnParaCurr, fnParaStart );
388 }
389 
390 
391 
392 sal_Bool SwWrtShell::EndPara( sal_Bool bSelect )
393 {
394     ShellMoveCrsr aTmp( this, bSelect );
395     return MovePara(fnParaCurr,fnParaEnd);
396 }
397 
398 
399 /*------------------------------------------------------------------------
400  Beschreibung:  Spaltenweises Springen
401  Parameter:     mit oder ohne SSelection
402  Return:        Erfolg oder Misserfolg
403 ------------------------------------------------------------------------*/
404 
405 
406 
407 sal_Bool SwWrtShell::StartOfColumn( sal_Bool bSelect )
408 {
409     ShellMoveCrsr aTmp( this, bSelect);
410     return MoveColumn(fnColumnCurr, fnColumnStart);
411 }
412 
413 
414 
415 sal_Bool SwWrtShell::EndOfColumn( sal_Bool bSelect )
416 {
417     ShellMoveCrsr aTmp( this, bSelect);
418     return MoveColumn(fnColumnCurr, fnColumnEnd);
419 }
420 
421 
422 
423 sal_Bool SwWrtShell::StartOfNextColumn( sal_Bool bSelect )
424 {
425     ShellMoveCrsr aTmp( this, bSelect);
426     return MoveColumn( fnColumnNext, fnColumnStart);
427 }
428 
429 
430 
431 sal_Bool SwWrtShell::EndOfNextColumn( sal_Bool bSelect )
432 {
433     ShellMoveCrsr aTmp( this, bSelect);
434     return MoveColumn(fnColumnNext, fnColumnEnd);
435 }
436 
437 
438 
439 sal_Bool SwWrtShell::StartOfPrevColumn( sal_Bool bSelect )
440 {
441     ShellMoveCrsr aTmp( this, bSelect);
442     return MoveColumn(fnColumnPrev, fnColumnStart);
443 }
444 
445 
446 
447 sal_Bool SwWrtShell::EndOfPrevColumn( sal_Bool bSelect )
448 {
449     ShellMoveCrsr aTmp( this, bSelect);
450     return MoveColumn(fnColumnPrev, fnColumnEnd);
451 }
452 
453 
454 
455 sal_Bool SwWrtShell::PushCrsr(SwTwips lOffset, sal_Bool bSelect)
456 {
457     sal_Bool bDiff = sal_False;
458     SwRect aOldRect( GetCharRect() ), aTmpArea( VisArea() );
459 
460     //bDestOnStack besagt, ob ich den Cursor nicht an die aktuelle Position
461     //setzen konnte, da in diesem Bereich kein Inhalt vorhanden ist.
462     if( !bDestOnStack )
463     {
464         Point aPt( aOldRect.Center() );
465 
466         if( !IsCrsrVisible() )
467             // set CrsrPos to top-/bottom left pos. So the pagescroll is not
468             // be dependent on the current cursor, but on the visarea.
469             aPt.Y() = aTmpArea.Top() + aTmpArea.Height() / 2;
470 
471         aPt.Y() += lOffset;
472         aDest = GetCntntPos(aPt,lOffset > 0);
473         aDest.X() = aPt.X();
474         bDestOnStack = sal_True;
475     }
476 
477     //falls wir eine Rahmenselektion hatten, muss diese nach dem
478     //fnSetCrsr entfernt werden und damit wir da wieder hinkommen
479     //auf dem Stack gemerkt werden.
480     sal_Bool bIsFrmSel = sal_False;
481 
482     sal_Bool bIsObjSel = sal_False;
483 
484     //Zielposition liegt jetzt innerhalb des sichtbaren Bereiches -->
485     //Cursor an die Zielposition setzen; merken, dass keine Ziel-
486     //position mehr auf dem Stack steht.
487     //Der neue sichtbare Bereich wird zuvor ermittelt.
488     aTmpArea.Pos().Y() += lOffset;
489     if( aTmpArea.IsInside(aDest) )
490     {
491         if( bSelect )
492             SttSelect();
493         else
494             EndSelect();
495 
496         bIsFrmSel = IsFrmSelected();
497         bIsObjSel = 0 != IsObjSelected();
498 
499         // Rahmenselektion aufheben
500         if( bIsFrmSel || bIsObjSel )
501         {
502             UnSelectFrm();
503             LeaveSelFrmMode();
504             if ( bIsObjSel )
505             {
506                 GetView().SetDrawFuncPtr( NULL );
507                 GetView().LeaveDrawCreate();
508             }
509 
510             CallChgLnk();
511         }
512 
513         (this->*fnSetCrsr)( &aDest, sal_True );
514 
515         bDiff = aOldRect != GetCharRect();
516 
517         if( bIsFrmSel )
518         {
519 //          CallChgLnk();
520             // bei Frames immer nur die obere Ecke nehmen, damit dieser
521             // wieder selektiert werden kann
522             aOldRect.SSize( 5, 5 );
523         }
524 
525             // Zuruecksetzen des Dest. SPoint Flags
526         bDestOnStack = sal_False;
527     }
528 
529     // Position auf den Stack; bDiff besagt, ob ein Unterschied zwischen
530     // der alten und der neuen Cursorposition besteht.
531     pCrsrStack = new CrsrStack( bDiff, bIsFrmSel, aOldRect.Center(),
532                                 lOffset, pCrsrStack );
533     return !bDestOnStack && bDiff;
534 }
535 
536 
537 
538 sal_Bool SwWrtShell::PopCrsr(sal_Bool bUpdate, sal_Bool bSelect)
539 {
540     if( 0 == pCrsrStack)
541         return sal_False;
542 
543     const sal_Bool bValidPos = pCrsrStack->bValidCurPos;
544     if( bUpdate && bValidPos )
545     {
546             // falls ein Vorgänger auf dem Stack steht, dessen Flag für eine
547             // gültige Position verwenden.
548         SwRect aTmpArea(VisArea());
549         aTmpArea.Pos().Y() -= pCrsrStack->lOffset;
550         if( aTmpArea.IsInside( pCrsrStack->aDocPos ) )
551         {
552             if( bSelect )
553                 SttSelect();
554             else
555                 EndSelect();
556 
557             (this->*fnSetCrsr)(&pCrsrStack->aDocPos, !pCrsrStack->bIsFrmSel);
558             if( pCrsrStack->bIsFrmSel && IsObjSelectable(pCrsrStack->aDocPos))
559             {
560                 HideCrsr();
561                 SelectObj( pCrsrStack->aDocPos );
562                 EnterSelFrmMode( &pCrsrStack->aDocPos );
563             }
564         }
565             // Falls eine Verschiebung zwischen dem sichtbaren Bereich
566             // und der gemerkten Cursorpositionen auftritt, werden
567             // alle gemerkten Positionen weggeschmissen
568         else
569         {
570             _ResetCursorStack();
571             return sal_False;
572         }
573     }
574     CrsrStack *pTmp = pCrsrStack;
575     pCrsrStack = pCrsrStack->pNext;
576     delete pTmp;
577     if( 0 == pCrsrStack )
578     {
579         ePageMove = MV_NO;
580         bDestOnStack = sal_False;
581     }
582     return bValidPos;
583 }
584 
585 /*
586  * Zuruecksetzen aller gepushten Cursorpositionen; dieser werden nicht
587  * zur Anzeige gebracht ( --> Kein Start-/EndAction!!)
588  */
589 
590 
591 
592 void SwWrtShell::_ResetCursorStack()
593 {
594     CrsrStack *pTmp = pCrsrStack;
595     while(pCrsrStack)
596     {
597         pTmp = pCrsrStack->pNext;
598         delete pCrsrStack;
599         pCrsrStack = pTmp;
600     }
601     ePageMove = MV_NO;
602     bDestOnStack = sal_False;
603 }
604 /**************
605 
606     falls kein Stack existiert --> Selektionen aufheben
607     falls Stack && Richtungswechsel
608         --> Cursor poppen und return
609     sonst
610         --> Cursor pushen
611              Cursor umsetzen
612 
613 ***************/
614 
615 
616 
617 sal_Bool SwWrtShell::PageCrsr(SwTwips lOffset, sal_Bool bSelect)
618 {
619     // nichts tun, wenn ein Offset von 0 angegeben wurde
620     if(!lOffset) return sal_False;
621         // Diente mal dazu, eine Neuformatierung fuer das Layout
622         // zu erzwingen.
623         // Hat so nicht funktioniert, da der Cursor nicht gesetzt
624         // wurde, da dies innerhalb einer Start- / EndActionklammerung
625         // nicht geschieht.
626         // Da am Ende nur ViewShell::EndAction() gerufen wird,
627         // findet auch hier keine Aktualisierung der Anzeige
628         // der Cursorposition statt.
629         // Die CrsrShell- Actionklammerung kann nicht verwendet werden,
630         // da sie immer zu einer Anzeige des Cursors fuehrt, also auch,
631         // wenn nach dem Blaettern in einen Bereich ohne gueltige Position
632         // geblaettert wurde.
633         //  ViewShell::StartAction();
634     PageMove eDir = lOffset > 0? MV_PAGE_DOWN: MV_PAGE_UP;
635         // Richtungswechsel und Stack vorhanden
636     if( eDir != ePageMove && ePageMove != MV_NO && PopCrsr( sal_True, bSelect ))
637         return sal_True;
638 
639     const sal_Bool bRet = PushCrsr(lOffset, bSelect);
640     ePageMove = eDir;
641     return bRet;
642 }
643 
644 
645 
646 sal_Bool SwWrtShell::GotoPage(sal_uInt16 nPage, sal_Bool bRecord)
647 {
648     ShellMoveCrsr aTmp( this, sal_False);
649     if( SwCrsrShell::GotoPage(nPage) && bRecord)
650     {
651         if(IsSelFrmMode())
652         {
653             UnSelectFrm();
654             LeaveSelFrmMode();
655         }
656         return sal_True;
657     }
658     return sal_False;
659 }
660 
661 
662 
663 sal_Bool SwWrtShell::GotoMark( const ::sw::mark::IMark* const pMark, sal_Bool bSelect, sal_Bool bStart )
664 {
665     ShellMoveCrsr aTmp( this, bSelect );
666     return SwCrsrShell::GotoMark( pMark, bStart );
667 }
668 
669 
670 
671 sal_Bool SwWrtShell::SelectTxtAttr( sal_uInt16 nWhich, const SwTxtAttr* pAttr )
672 {
673     sal_Bool bRet;
674     {
675         MV_CONTEXT(this);
676         SttSelect();
677         bRet = SwCrsrShell::SelectTxtAttr( nWhich, sal_False, pAttr );
678     }
679     EndSelect();
680     return bRet;
681 }
682 
683 /* vim: set noet sw=4 ts=4: */
684