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