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