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