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