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 #include "precompiled_sd.hxx" 23 24 #include "controller/SlsSelectionFunction.hxx" 25 26 #include "SlideSorter.hxx" 27 #include "SlideSorterViewShell.hxx" 28 #include "SlsDragAndDropContext.hxx" 29 #include "controller/SlsTransferableData.hxx" 30 #include "controller/SlideSorterController.hxx" 31 #include "controller/SlsPageSelector.hxx" 32 #include "controller/SlsFocusManager.hxx" 33 #include "controller/SlsScrollBarManager.hxx" 34 #include "controller/SlsClipboard.hxx" 35 #include "controller/SlsCurrentSlideManager.hxx" 36 #include "controller/SlsInsertionIndicatorHandler.hxx" 37 #include "controller/SlsSelectionManager.hxx" 38 #include "controller/SlsProperties.hxx" 39 #include "controller/SlsProperties.hxx" 40 #include "controller/SlsSlotManager.hxx" 41 #include "controller/SlsVisibleAreaManager.hxx" 42 #include "model/SlideSorterModel.hxx" 43 #include "model/SlsPageDescriptor.hxx" 44 #include "model/SlsPageEnumerationProvider.hxx" 45 #include "view/SlideSorterView.hxx" 46 #include "view/SlsLayouter.hxx" 47 #include "view/SlsPageObjectLayouter.hxx" 48 #include "view/SlsButtonBar.hxx" 49 #include "framework/FrameworkHelper.hxx" 50 #include "ViewShellBase.hxx" 51 #include "DrawController.hxx" 52 #include "Window.hxx" 53 #include "sdpage.hxx" 54 #include "drawdoc.hxx" 55 #include "DrawDocShell.hxx" 56 #include "sdxfer.hxx" 57 #include "ViewShell.hxx" 58 #include "ViewShellBase.hxx" 59 #include "FrameView.hxx" 60 #include "app.hrc" 61 #include "sdresid.hxx" 62 #include "strings.hrc" 63 #include <sfx2/viewfrm.hxx> 64 #include <sfx2/dispatch.hxx> 65 #include <svx/svdpagv.hxx> 66 #include <vcl/msgbox.hxx> 67 #include <svx/svxids.hrc> 68 #include <boost/bind.hpp> 69 #include <boost/optional.hpp> 70 71 namespace { 72 static const sal_uInt32 SINGLE_CLICK (0x00000001); 73 static const sal_uInt32 DOUBLE_CLICK (0x00000002); 74 static const sal_uInt32 LEFT_BUTTON (0x00000010); 75 static const sal_uInt32 RIGHT_BUTTON (0x00000020); 76 static const sal_uInt32 MIDDLE_BUTTON (0x00000040); 77 static const sal_uInt32 BUTTON_DOWN (0x00000100); 78 static const sal_uInt32 BUTTON_UP (0x00000200); 79 static const sal_uInt32 MOUSE_MOTION (0x00000400); 80 static const sal_uInt32 MOUSE_DRAG (0x00000800); 81 // The rest leaves the lower 16 bit untouched so that it can be used with 82 // key codes. 83 static const sal_uInt32 OVER_SELECTED_PAGE (0x00010000); 84 static const sal_uInt32 OVER_UNSELECTED_PAGE (0x00020000); 85 static const sal_uInt32 OVER_FADE_INDICATOR (0x00040000); 86 static const sal_uInt32 OVER_BUTTON_AREA (0x00080000); 87 static const sal_uInt32 OVER_BUTTON (0x00100000); 88 static const sal_uInt32 SHIFT_MODIFIER (0x00200000); 89 static const sal_uInt32 CONTROL_MODIFIER (0x00400000); 90 91 static const sal_uInt32 KEY_EVENT (0x10000000); 92 93 // Some absent events are defined so they can be expressed explicitly. 94 static const sal_uInt32 NO_MODIFIER (0x00000000); 95 static const sal_uInt32 NOT_OVER_PAGE (0x00000000); 96 97 // Masks 98 static const sal_uInt32 MODIFIER_MASK (SHIFT_MODIFIER | CONTROL_MODIFIER); 99 static const sal_uInt32 BUTTON_MASK (LEFT_BUTTON | RIGHT_BUTTON | MIDDLE_BUTTON); 100 101 } // end of anonymous namespace 102 103 // Define some macros to make the following switch statement more readable. 104 #define ANY_MODIFIER(code) \ 105 code|NO_MODIFIER: \ 106 case code|SHIFT_MODIFIER: \ 107 case code|CONTROL_MODIFIER 108 109 namespace sd { namespace slidesorter { namespace controller { 110 111 //===== SelectionFunction::EventDescriptor ==================================== 112 113 class SelectionFunction::EventDescriptor 114 { 115 public: 116 Point maMousePosition; 117 Point maMouseModelPosition; 118 model::SharedPageDescriptor mpHitDescriptor; 119 SdrPage* mpHitPage; 120 sal_uInt32 mnEventCode; 121 bool mbIsOverButton; 122 InsertionIndicatorHandler::Mode meDragMode; 123 bool mbMakeSelectionVisible; 124 bool mbIsLeaving; 125 126 EventDescriptor ( 127 sal_uInt32 nEventType, 128 const MouseEvent& rEvent, 129 SlideSorter& rSlideSorter); 130 EventDescriptor ( 131 sal_uInt32 nEventType, 132 const AcceptDropEvent& rEvent, 133 const sal_Int8 nDragAction, 134 SlideSorter& rSlideSorter); 135 EventDescriptor ( 136 const KeyEvent& rEvent, 137 SlideSorter& rSlideSorter); 138 139 void SetDragMode (const InsertionIndicatorHandler::Mode eMode); 140 141 private: 142 /** Compute a numerical code that describes a mouse event and that can 143 be used for fast look up of the appropriate reaction. 144 */ 145 sal_uInt32 EncodeMouseEvent (const MouseEvent& rEvent) const; 146 147 /** Compute a numerical code that describes a key event and that can 148 be used for fast look up of the appropriate reaction. 149 */ 150 sal_uInt32 EncodeKeyEvent (const KeyEvent& rEvent) const; 151 152 /** Compute a numerical code that describes the current state like 153 whether the selection rectangle is visible or whether the page under 154 the mouse or the one that has the focus is selected. 155 */ 156 sal_uInt32 EncodeState (void) const; 157 }; 158 159 //===== SelectionFunction::ModeHandler ======================================== 160 161 class SelectionFunction::ModeHandler 162 { 163 public: 164 ModeHandler ( 165 SlideSorter& rSlideSorter, 166 SelectionFunction& rSelectionFunction, 167 const bool bIsMouseOverIndicatorAllowed); 168 virtual ~ModeHandler (void); 169 170 virtual Mode GetMode (void) const = 0; 171 virtual void Abort (void) = 0; 172 virtual void ProcessEvent (EventDescriptor& rDescriptor); 173 174 /** Set the selection to exactly the specified page and also set it as 175 the current page. 176 */ 177 void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor); 178 179 /// Deselect all pages. 180 void DeselectAllPages (void); 181 void SelectOnePage (const model::SharedPageDescriptor& rpDescriptor); 182 183 /** When the view on which this selection function is working is the 184 main view then the view is switched to the regular editing view. 185 */ 186 void SwitchView (const model::SharedPageDescriptor& rpDescriptor); 187 188 void StartDrag ( 189 const Point& rMousePosition, 190 const InsertionIndicatorHandler::Mode eMode); 191 192 bool IsMouseOverIndicatorAllowed (void) const; 193 194 protected: 195 SlideSorter& mrSlideSorter; 196 SelectionFunction& mrSelectionFunction; 197 198 virtual bool ProcessButtonDownEvent (EventDescriptor& rDescriptor); 199 virtual bool ProcessButtonUpEvent (EventDescriptor& rDescriptor); 200 virtual bool ProcessMotionEvent (EventDescriptor& rDescriptor); 201 virtual bool ProcessDragEvent (EventDescriptor& rDescriptor); 202 virtual bool HandleUnprocessedEvent (EventDescriptor& rDescriptor); 203 204 void ReprocessEvent (EventDescriptor& rDescriptor); 205 206 private: 207 const bool mbIsMouseOverIndicatorAllowed; 208 }; 209 210 /** This is the default handler for processing events. It activates the 211 multi selection or drag-and-drop when the right conditions are met. 212 */ 213 class NormalModeHandler : public SelectionFunction::ModeHandler 214 { 215 public: 216 NormalModeHandler ( 217 SlideSorter& rSlideSorter, 218 SelectionFunction& rSelectionFunction); 219 virtual ~NormalModeHandler (void); 220 221 virtual SelectionFunction::Mode GetMode (void) const; 222 virtual void Abort (void); 223 224 void ResetButtonDownLocation (void); 225 226 protected: 227 virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor); 228 virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); 229 virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); 230 virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor); 231 232 private: 233 ::boost::optional<Point> maButtonDownLocation; 234 235 /** Select all pages between and including the selection anchor and the 236 specified page. 237 */ 238 void RangeSelect (const model::SharedPageDescriptor& rpDescriptor); 239 }; 240 241 /** Handle events during a multi selection, which typically is started by 242 pressing the left mouse button when not over a page. 243 */ 244 class MultiSelectionModeHandler : public SelectionFunction::ModeHandler 245 { 246 public: 247 /** Start a rectangle selection at the given position. 248 */ 249 MultiSelectionModeHandler ( 250 SlideSorter& rSlideSorter, 251 SelectionFunction& rSelectionFunction, 252 const Point& rMouseModelPosition, 253 const sal_uInt32 nEventCode); 254 virtual ~MultiSelectionModeHandler (void); 255 256 virtual SelectionFunction::Mode GetMode (void) const; 257 virtual void Abort (void); 258 virtual void ProcessEvent (SelectionFunction::EventDescriptor& rDescriptor); 259 260 enum SelectionMode { SM_Normal, SM_Add, SM_Toggle }; 261 262 void SetSelectionMode (const SelectionMode eSelectionMode); 263 void SetSelectionModeFromModifier (const sal_uInt32 nEventCode); 264 265 protected: 266 virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); 267 virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); 268 virtual bool HandleUnprocessedEvent (SelectionFunction::EventDescriptor& rDescriptor); 269 270 private: 271 SelectionMode meSelectionMode; 272 Point maSecondCorner; 273 Pointer maSavedPointer; 274 sal_Int32 mnAnchorIndex; 275 sal_Int32 mnSecondIndex; 276 view::ButtonBar::Lock maButtonBarLock; 277 278 virtual void UpdateModelPosition (const Point& rMouseModelPosition); 279 virtual void UpdateSelection (void); 280 281 /** Update the rectangle selection so that the given position becomes 282 the new second point of the selection rectangle. 283 */ 284 void UpdatePosition ( 285 const Point& rMousePosition, 286 const bool bAllowAutoScroll); 287 288 void UpdateSelectionState ( 289 const model::SharedPageDescriptor& rpDescriptor, 290 const bool bIsInSelection) const; 291 }; 292 293 /** Handle events during drag-and-drop. 294 */ 295 class DragAndDropModeHandler : public SelectionFunction::ModeHandler 296 { 297 public: 298 DragAndDropModeHandler ( 299 SlideSorter& rSlideSorter, 300 SelectionFunction& rSelectionFunction, 301 const Point& rMousePosition, 302 ::Window* pWindow); 303 virtual ~DragAndDropModeHandler (void); 304 305 virtual SelectionFunction::Mode GetMode (void) const; 306 virtual void Abort (void); 307 308 protected: 309 virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); 310 virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor); 311 312 private: 313 ::boost::scoped_ptr<DragAndDropContext> mpDragAndDropContext; 314 }; 315 316 /** Handle events while the left mouse button is pressed over the button 317 bar. 318 */ 319 class ButtonModeHandler : public SelectionFunction::ModeHandler 320 { 321 public: 322 ButtonModeHandler ( 323 SlideSorter& rSlideSorter, 324 SelectionFunction& rSelectionFunction); 325 virtual ~ButtonModeHandler (void); 326 virtual void Abort (void); 327 328 virtual SelectionFunction::Mode GetMode (void) const; 329 330 protected: 331 virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor); 332 virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); 333 virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); 334 }; 335 336 //===== SelectionFunction ===================================================== 337 338 TYPEINIT1(SelectionFunction, FuPoor); 339 340 SelectionFunction::SelectionFunction ( 341 SlideSorter& rSlideSorter, 342 SfxRequest& rRequest) 343 : FuPoor ( 344 rSlideSorter.GetViewShell(), 345 rSlideSorter.GetContentWindow().get(), 346 &rSlideSorter.GetView(), 347 rSlideSorter.GetModel().GetDocument(), 348 rRequest), 349 mrSlideSorter(rSlideSorter), 350 mrController(mrSlideSorter.GetController()), 351 mbDragSelection(false), 352 maInsertionMarkerBox(), 353 mbProcessingMouseButtonDown(false), 354 mnShiftKeySelectionAnchor(-1), 355 mpModeHandler(new NormalModeHandler(rSlideSorter, *this)) 356 { 357 } 358 359 SelectionFunction::~SelectionFunction (void) 360 { 361 mpModeHandler.reset(); 362 } 363 364 FunctionReference SelectionFunction::Create( 365 SlideSorter& rSlideSorter, 366 SfxRequest& rRequest) 367 { 368 FunctionReference xFunc( new SelectionFunction( rSlideSorter, rRequest ) ); 369 return xFunc; 370 } 371 372 sal_Bool SelectionFunction::MouseButtonDown (const MouseEvent& rEvent) 373 { 374 // #95491# remember button state for creation of own MouseEvents 375 SetMouseButtonCode (rEvent.GetButtons()); 376 aMDPos = rEvent.GetPosPixel(); 377 mbProcessingMouseButtonDown = true; 378 379 // mpWindow->CaptureMouse(); 380 381 ProcessMouseEvent(BUTTON_DOWN, rEvent); 382 383 return sal_True; 384 } 385 386 sal_Bool SelectionFunction::MouseMove (const MouseEvent& rEvent) 387 { 388 ProcessMouseEvent(MOUSE_MOTION, rEvent); 389 return sal_True; 390 } 391 392 sal_Bool SelectionFunction::MouseButtonUp (const MouseEvent& rEvent) 393 { 394 mrController.GetScrollBarManager().StopAutoScroll (); 395 396 ProcessMouseEvent(BUTTON_UP, rEvent); 397 398 mbProcessingMouseButtonDown = false; 399 // mpWindow->ReleaseMouse(); 400 401 return sal_True; 402 } 403 404 void SelectionFunction::NotifyDragFinished (void) 405 { 406 SwitchToNormalMode(); 407 } 408 409 sal_Bool SelectionFunction::KeyInput (const KeyEvent& rEvent) 410 { 411 view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); 412 PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter); 413 PageSelector::UpdateLock aLock (mrSlideSorter); 414 FocusManager& rFocusManager (mrController.GetFocusManager()); 415 sal_Bool bResult = sal_False; 416 417 const KeyCode& rCode (rEvent.GetKeyCode()); 418 switch (rCode.GetCode()) 419 { 420 case KEY_RETURN: 421 { 422 model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); 423 ViewShell* pViewShell = mrSlideSorter.GetViewShell(); 424 if (rFocusManager.HasFocus() && pDescriptor && pViewShell!=NULL) 425 { 426 // The Return key triggers different functions depending on 427 // whether the slide sorter is the main view or displayed in 428 // the right pane. 429 if (pViewShell->IsMainViewShell()) 430 { 431 mpModeHandler->SetCurrentPage(pDescriptor); 432 mpModeHandler->SwitchView(pDescriptor); 433 } 434 else 435 { 436 pViewShell->GetDispatcher()->Execute( 437 SID_INSERTPAGE, 438 SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD); 439 } 440 bResult = sal_True; 441 } 442 break; 443 } 444 445 case KEY_TAB: 446 if ( ! rFocusManager.IsFocusShowing()) 447 { 448 rFocusManager.ShowFocus(); 449 bResult = sal_True; 450 } 451 break; 452 453 case KEY_ESCAPE: 454 // When there is an active multiselection or drag-and-drop 455 // operation then stop that. 456 mpModeHandler->Abort(); 457 SwitchToNormalMode(); 458 bResult = sal_True; 459 break; 460 461 case KEY_SPACE: 462 { 463 // Toggle the selection state. 464 model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); 465 if (pDescriptor && rCode.IsMod1()) 466 { 467 if (pDescriptor->HasState(model::PageDescriptor::ST_Selected)) 468 mrController.GetPageSelector().DeselectPage(pDescriptor, false); 469 else 470 mrController.GetPageSelector().SelectPage(pDescriptor); 471 } 472 bResult = sal_True; 473 } 474 break; 475 476 // Move the focus indicator left. 477 case KEY_LEFT: 478 MoveFocus(FocusManager::FMD_LEFT, rCode.IsShift(), rCode.IsMod1()); 479 bResult = sal_True; 480 break; 481 482 // Move the focus indicator right. 483 case KEY_RIGHT: 484 MoveFocus(FocusManager::FMD_RIGHT, rCode.IsShift(), rCode.IsMod1()); 485 bResult = sal_True; 486 break; 487 488 // Move the focus indicator up. 489 case KEY_UP: 490 MoveFocus(FocusManager::FMD_UP, rCode.IsShift(), rCode.IsMod1()); 491 bResult = sal_True; 492 break; 493 494 // Move the focus indicator down. 495 case KEY_DOWN: 496 MoveFocus(FocusManager::FMD_DOWN, rCode.IsShift(), rCode.IsMod1()); 497 bResult = sal_True; 498 break; 499 500 // Go to previous page. No wrap around. 501 case KEY_PAGEUP: 502 GotoNextPage(-1); 503 bResult = sal_True; 504 break; 505 506 // Go to next page. No wrap around.. 507 case KEY_PAGEDOWN: 508 GotoNextPage(+1); 509 bResult = sal_True; 510 break; 511 512 case KEY_HOME: 513 GotoPage(0); 514 bResult = sal_True; 515 break; 516 517 case KEY_END: 518 GotoPage(mrSlideSorter.GetModel().GetPageCount()-1); 519 bResult = sal_True; 520 break; 521 522 case KEY_DELETE: 523 case KEY_BACKSPACE: 524 { 525 if (mrSlideSorter.GetProperties()->IsUIReadOnly()) 526 break; 527 528 mrController.GetSelectionManager()->DeleteSelectedPages(rCode.GetCode()==KEY_DELETE); 529 530 mnShiftKeySelectionAnchor = -1; 531 bResult = sal_True; 532 } 533 break; 534 535 case KEY_F10: 536 if (rCode.IsShift()) 537 { 538 mpModeHandler->SelectOnePage( 539 mrSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); 540 } 541 break; 542 543 default: 544 break; 545 } 546 547 if ( ! bResult) 548 bResult = FuPoor::KeyInput(rEvent); 549 550 return bResult; 551 } 552 553 void SelectionFunction::MoveFocus ( 554 const FocusManager::FocusMoveDirection eDirection, 555 const bool bIsShiftDown, 556 const bool bIsControlDown) 557 { 558 // Remember the anchor of shift key multi selection. 559 if (bIsShiftDown) 560 { 561 if (mnShiftKeySelectionAnchor<0) 562 { 563 model::SharedPageDescriptor pFocusedDescriptor ( 564 mrController.GetFocusManager().GetFocusedPageDescriptor()); 565 mnShiftKeySelectionAnchor = pFocusedDescriptor->GetPageIndex(); 566 } 567 } 568 else if ( ! bIsControlDown) 569 ResetShiftKeySelectionAnchor(); 570 571 mrController.GetFocusManager().MoveFocus(eDirection); 572 573 PageSelector& rSelector (mrController.GetPageSelector()); 574 model::SharedPageDescriptor pFocusedDescriptor ( 575 mrController.GetFocusManager().GetFocusedPageDescriptor()); 576 if (bIsShiftDown) 577 { 578 // When shift is pressed then select all pages in the range between 579 // the currently and the previously focused pages, including them. 580 if (pFocusedDescriptor) 581 { 582 sal_Int32 nPageRangeEnd (pFocusedDescriptor->GetPageIndex()); 583 model::PageEnumeration aPages ( 584 model::PageEnumerationProvider::CreateAllPagesEnumeration( 585 mrSlideSorter.GetModel())); 586 while (aPages.HasMoreElements()) 587 { 588 model::SharedPageDescriptor pDescriptor (aPages.GetNextElement()); 589 if (pDescriptor) 590 { 591 const sal_Int32 nPageIndex(pDescriptor->GetPageIndex()); 592 if ((nPageIndex>=mnShiftKeySelectionAnchor && nPageIndex<=nPageRangeEnd) 593 || (nPageIndex<=mnShiftKeySelectionAnchor && nPageIndex>=nPageRangeEnd)) 594 { 595 rSelector.SelectPage(pDescriptor); 596 } 597 else 598 { 599 rSelector.DeselectPage(pDescriptor); 600 } 601 } 602 } 603 } 604 } 605 else if (bIsControlDown) 606 { 607 // When control is pressed then do not alter the selection or the 608 // current page, just move the focus. 609 } 610 else 611 { 612 // Without shift just select the focused page. 613 mpModeHandler->SelectOnePage(pFocusedDescriptor); 614 } 615 } 616 617 void SelectionFunction::Activate() 618 { 619 FuPoor::Activate(); 620 } 621 622 void SelectionFunction::Deactivate() 623 { 624 FuPoor::Deactivate(); 625 } 626 627 void SelectionFunction::ScrollStart (void) 628 { 629 } 630 631 void SelectionFunction::ScrollEnd (void) 632 { 633 } 634 635 void SelectionFunction::DoCut (void) 636 { 637 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) 638 { 639 mrController.GetClipboard().DoCut(); 640 } 641 } 642 643 void SelectionFunction::DoCopy (void) 644 { 645 mrController.GetClipboard().DoCopy(); 646 } 647 648 void SelectionFunction::DoPaste (void) 649 { 650 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) 651 { 652 mrController.GetClipboard().DoPaste(); 653 } 654 } 655 656 bool SelectionFunction::cancel (void) 657 { 658 mrController.GetFocusManager().ToggleFocus(); 659 return true; 660 } 661 662 void SelectionFunction::GotoNextPage (int nOffset) 663 { 664 model::SharedPageDescriptor pDescriptor 665 = mrController.GetCurrentSlideManager()->GetCurrentSlide(); 666 if (pDescriptor.get() != NULL) 667 { 668 SdPage* pPage = pDescriptor->GetPage(); 669 OSL_ASSERT(pPage!=NULL); 670 sal_Int32 nIndex = (pPage->GetPageNum()-1) / 2; 671 GotoPage(nIndex + nOffset); 672 } 673 ResetShiftKeySelectionAnchor(); 674 } 675 676 void SelectionFunction::GotoPage (int nIndex) 677 { 678 sal_uInt16 nPageCount = (sal_uInt16)mrSlideSorter.GetModel().GetPageCount(); 679 680 if (nIndex >= nPageCount) 681 nIndex = nPageCount - 1; 682 if (nIndex < 0) 683 nIndex = 0; 684 685 mrController.GetFocusManager().SetFocusedPage(nIndex); 686 model::SharedPageDescriptor pNextPageDescriptor ( 687 mrSlideSorter.GetModel().GetPageDescriptor (nIndex)); 688 if (pNextPageDescriptor.get() != NULL) 689 mpModeHandler->SetCurrentPage(pNextPageDescriptor); 690 else 691 { 692 OSL_ASSERT(pNextPageDescriptor.get() != NULL); 693 } 694 ResetShiftKeySelectionAnchor(); 695 } 696 697 void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent) 698 { 699 // #95491# remember button state for creation of own MouseEvents 700 SetMouseButtonCode (rEvent.GetButtons()); 701 702 EventDescriptor aEventDescriptor (nEventType, rEvent, mrSlideSorter); 703 ProcessEvent(aEventDescriptor); 704 } 705 706 void SelectionFunction::MouseDragged ( 707 const AcceptDropEvent& rEvent, 708 const sal_Int8 nDragAction) 709 { 710 EventDescriptor aEventDescriptor (MOUSE_DRAG, rEvent, nDragAction, mrSlideSorter); 711 ProcessEvent(aEventDescriptor); 712 } 713 714 void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent) 715 { 716 EventDescriptor aEventDescriptor (rEvent, mrSlideSorter); 717 ProcessEvent(aEventDescriptor); 718 } 719 720 void SelectionFunction::ProcessEvent (EventDescriptor& rDescriptor) 721 { 722 // The call to ProcessEvent may switch to another mode handler. 723 // Prevent the untimely destruction of the called handler by acquiring a 724 // temporary reference here. 725 ::boost::shared_ptr<ModeHandler> pModeHandler (mpModeHandler); 726 pModeHandler->ProcessEvent(rDescriptor); 727 } 728 729 bool Match ( 730 const sal_uInt32 nEventCode, 731 const sal_uInt32 nPositivePattern) 732 { 733 return (nEventCode & nPositivePattern)==nPositivePattern; 734 } 735 736 void SelectionFunction::SwitchToNormalMode (void) 737 { 738 if (mpModeHandler->GetMode() != NormalMode) 739 SwitchMode(::boost::shared_ptr<ModeHandler>( 740 new NormalModeHandler(mrSlideSorter, *this))); 741 } 742 743 void SelectionFunction::SwitchToDragAndDropMode (const Point aMousePosition) 744 { 745 if (mpModeHandler->GetMode() != DragAndDropMode) 746 { 747 SwitchMode(::boost::shared_ptr<ModeHandler>( 748 new DragAndDropModeHandler(mrSlideSorter, *this, aMousePosition, mpWindow))); 749 } 750 } 751 752 void SelectionFunction::SwitchToMultiSelectionMode ( 753 const Point aMousePosition, 754 const sal_uInt32 nEventCode) 755 { 756 if (mpModeHandler->GetMode() != MultiSelectionMode) 757 SwitchMode(::boost::shared_ptr<ModeHandler>( 758 new MultiSelectionModeHandler(mrSlideSorter, *this, aMousePosition, nEventCode))); 759 } 760 761 bool SelectionFunction::SwitchToButtonMode (void) 762 { 763 // Do not show the buttons for draw pages. 764 ::boost::shared_ptr<ViewShell> pMainViewShell (mrSlideSorter.GetViewShellBase()->GetMainViewShell()); 765 if (pMainViewShell 766 && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW 767 && mpModeHandler->GetMode() != ButtonMode) 768 { 769 SwitchMode(::boost::shared_ptr<ModeHandler>(new ButtonModeHandler(mrSlideSorter, *this))); 770 return true; 771 } 772 else 773 return false; 774 } 775 776 void SelectionFunction::SwitchMode (const ::boost::shared_ptr<ModeHandler>& rpHandler) 777 { 778 // Not all modes allow mouse over indicator. 779 if (mpModeHandler->IsMouseOverIndicatorAllowed() != rpHandler->IsMouseOverIndicatorAllowed()) 780 { 781 if ( ! rpHandler->IsMouseOverIndicatorAllowed()) 782 { 783 mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor()); 784 mrSlideSorter.GetView().GetButtonBar().ResetPage(); 785 } 786 else 787 mrSlideSorter.GetView().UpdatePageUnderMouse(false); 788 } 789 790 mpModeHandler = rpHandler; 791 } 792 793 void SelectionFunction::ResetShiftKeySelectionAnchor (void) 794 { 795 mnShiftKeySelectionAnchor = -1; 796 } 797 798 void SelectionFunction::ResetMouseAnchor (void) 799 { 800 if (mpModeHandler && mpModeHandler->GetMode() == NormalMode) 801 { 802 ::boost::shared_ptr<NormalModeHandler> pHandler ( 803 ::boost::dynamic_pointer_cast<NormalModeHandler>(mpModeHandler)); 804 if (pHandler) 805 pHandler->ResetButtonDownLocation(); 806 } 807 } 808 809 //===== EventDescriptor ======================================================= 810 811 SelectionFunction::EventDescriptor::EventDescriptor ( 812 const sal_uInt32 nEventType, 813 const MouseEvent& rEvent, 814 SlideSorter& rSlideSorter) 815 : maMousePosition(rEvent.GetPosPixel()), 816 maMouseModelPosition(), 817 mpHitDescriptor(), 818 mpHitPage(), 819 mnEventCode(nEventType), 820 mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), 821 meDragMode(InsertionIndicatorHandler::MoveMode), 822 mbMakeSelectionVisible(true), 823 mbIsLeaving(false) 824 { 825 maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition); 826 mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition); 827 if (mpHitDescriptor) 828 { 829 mpHitPage = mpHitDescriptor->GetPage(); 830 } 831 832 mnEventCode |= EncodeMouseEvent(rEvent); 833 mnEventCode |= EncodeState(); 834 835 // Detect the mouse leaving the window. When not button is pressed then 836 // we can call IsLeaveWindow at the event. Otherwise we have to make an 837 // explicit test. 838 mbIsLeaving = rEvent.IsLeaveWindow() 839 || ! Rectangle(Point(0,0), 840 rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition); 841 } 842 843 SelectionFunction::EventDescriptor::EventDescriptor ( 844 const sal_uInt32 nEventType, 845 const AcceptDropEvent& rEvent, 846 const sal_Int8 nDragAction, 847 SlideSorter& rSlideSorter) 848 : maMousePosition(rEvent.maPosPixel), 849 maMouseModelPosition(), 850 mpHitDescriptor(), 851 mpHitPage(), 852 mnEventCode(nEventType), 853 mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), 854 meDragMode(InsertionIndicatorHandler::GetModeFromDndAction(nDragAction)), 855 mbMakeSelectionVisible(true), 856 mbIsLeaving(false) 857 { 858 maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition); 859 mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition); 860 if (mpHitDescriptor) 861 { 862 mpHitPage = mpHitDescriptor->GetPage(); 863 } 864 865 mnEventCode |= EncodeState(); 866 867 // Detect the mouse leaving the window. When not button is pressed then 868 // we can call IsLeaveWindow at the event. Otherwise we have to make an 869 // explicit test. 870 mbIsLeaving = rEvent.mbLeaving 871 || ! Rectangle(Point(0,0), 872 rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition); 873 } 874 875 SelectionFunction::EventDescriptor::EventDescriptor ( 876 const KeyEvent& rEvent, 877 SlideSorter& rSlideSorter) 878 : maMousePosition(), 879 maMouseModelPosition(), 880 mpHitDescriptor(), 881 mpHitPage(), 882 mnEventCode(KEY_EVENT), 883 mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), 884 meDragMode(InsertionIndicatorHandler::MoveMode), 885 mbMakeSelectionVisible(true), 886 mbIsLeaving(false) 887 { 888 model::SharedPageDescriptor pHitDescriptor ( 889 rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); 890 if (pHitDescriptor.get() != NULL) 891 { 892 mpHitPage = pHitDescriptor->GetPage(); 893 mpHitDescriptor = pHitDescriptor; 894 } 895 896 mnEventCode |= EncodeKeyEvent(rEvent) | EncodeState(); 897 } 898 899 void SelectionFunction::EventDescriptor::SetDragMode (const InsertionIndicatorHandler::Mode eMode) 900 { 901 meDragMode = eMode; 902 } 903 904 sal_uInt32 SelectionFunction::EventDescriptor::EncodeMouseEvent ( 905 const MouseEvent& rEvent) const 906 { 907 // Initialize with the type of mouse event. 908 sal_uInt32 nEventCode (mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION)); 909 910 // Detect the affected button. 911 switch (rEvent.GetButtons()) 912 { 913 case MOUSE_LEFT: nEventCode |= LEFT_BUTTON; break; 914 case MOUSE_RIGHT: nEventCode |= RIGHT_BUTTON; break; 915 case MOUSE_MIDDLE: nEventCode |= MIDDLE_BUTTON; break; 916 } 917 918 // Detect the number of clicks. 919 switch (rEvent.GetClicks()) 920 { 921 case 1: nEventCode |= SINGLE_CLICK; break; 922 case 2: nEventCode |= DOUBLE_CLICK; break; 923 } 924 925 // Detect pressed modifier keys. 926 if (rEvent.IsShift()) 927 nEventCode |= SHIFT_MODIFIER; 928 if (rEvent.IsMod1()) 929 nEventCode |= CONTROL_MODIFIER; 930 931 // Detect whether the mouse is over one of the active elements inside a 932 // page object. 933 if (mbIsOverButton) 934 nEventCode |= OVER_BUTTON; 935 936 return nEventCode; 937 } 938 939 sal_uInt32 SelectionFunction::EventDescriptor::EncodeKeyEvent (const KeyEvent& rEvent) const 940 { 941 // The key code in the lower 16 bit. 942 sal_uInt32 nEventCode (rEvent.GetKeyCode().GetCode()); 943 944 // Detect pressed modifier keys. 945 if (rEvent.GetKeyCode().IsShift()) 946 nEventCode |= SHIFT_MODIFIER; 947 if (rEvent.GetKeyCode().IsMod1()) 948 nEventCode |= CONTROL_MODIFIER; 949 950 return nEventCode; 951 } 952 953 sal_uInt32 SelectionFunction::EventDescriptor::EncodeState (void) const 954 { 955 sal_uInt32 nEventCode (0); 956 957 // Detect whether the event has happened over a page object. 958 if (mpHitPage!=NULL && mpHitDescriptor) 959 { 960 if (mpHitDescriptor->HasState(model::PageDescriptor::ST_Selected)) 961 nEventCode |= OVER_SELECTED_PAGE; 962 else 963 nEventCode |= OVER_UNSELECTED_PAGE; 964 965 // Detect whether the mouse is over one of the active elements 966 // inside a page object. 967 if (mbIsOverButton) 968 nEventCode |= OVER_BUTTON; 969 } 970 971 return nEventCode; 972 } 973 974 //===== SelectionFunction::ModeHandler ======================================== 975 976 SelectionFunction::ModeHandler::ModeHandler ( 977 SlideSorter& rSlideSorter, 978 SelectionFunction& rSelectionFunction, 979 const bool bIsMouseOverIndicatorAllowed) 980 : mrSlideSorter(rSlideSorter), 981 mrSelectionFunction(rSelectionFunction), 982 mbIsMouseOverIndicatorAllowed(bIsMouseOverIndicatorAllowed) 983 { 984 } 985 986 SelectionFunction::ModeHandler::~ModeHandler (void) 987 { 988 } 989 990 void SelectionFunction::ModeHandler::ReprocessEvent (EventDescriptor& rDescriptor) 991 { 992 mrSelectionFunction.ProcessEvent(rDescriptor); 993 } 994 995 void SelectionFunction::ModeHandler::ProcessEvent ( 996 SelectionFunction::EventDescriptor& rDescriptor) 997 { 998 PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter); 999 PageSelector::UpdateLock aUpdateLock (mrSlideSorter); 1000 1001 bool bIsProcessed (false); 1002 switch (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION | MOUSE_DRAG)) 1003 { 1004 case BUTTON_DOWN: 1005 bIsProcessed = ProcessButtonDownEvent(rDescriptor); 1006 break; 1007 1008 case BUTTON_UP: 1009 bIsProcessed = ProcessButtonUpEvent(rDescriptor); 1010 break; 1011 1012 case MOUSE_MOTION: 1013 bIsProcessed = ProcessMotionEvent(rDescriptor); 1014 break; 1015 1016 case MOUSE_DRAG: 1017 bIsProcessed = ProcessDragEvent(rDescriptor); 1018 break; 1019 } 1020 1021 if ( ! bIsProcessed) 1022 HandleUnprocessedEvent(rDescriptor); 1023 } 1024 1025 bool SelectionFunction::ModeHandler::ProcessButtonDownEvent (EventDescriptor&) 1026 { 1027 return false; 1028 } 1029 1030 bool SelectionFunction::ModeHandler::ProcessButtonUpEvent (EventDescriptor&) 1031 { 1032 mrSelectionFunction.SwitchToNormalMode(); 1033 return false; 1034 } 1035 1036 bool SelectionFunction::ModeHandler::ProcessMotionEvent (EventDescriptor& rDescriptor) 1037 { 1038 if (mbIsMouseOverIndicatorAllowed) 1039 mrSlideSorter.GetView().UpdatePageUnderMouse( 1040 rDescriptor.maMousePosition, 1041 (rDescriptor.mnEventCode & LEFT_BUTTON) != 0, 1042 true); 1043 1044 if (rDescriptor.mbIsLeaving) 1045 { 1046 mrSelectionFunction.SwitchToNormalMode(); 1047 mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor()); 1048 1049 return true; 1050 } 1051 else 1052 return false; 1053 } 1054 1055 bool SelectionFunction::ModeHandler::ProcessDragEvent (EventDescriptor&) 1056 { 1057 return false; 1058 } 1059 1060 bool SelectionFunction::ModeHandler::HandleUnprocessedEvent (EventDescriptor&) 1061 { 1062 return false; 1063 } 1064 1065 void SelectionFunction::ModeHandler::SetCurrentPage ( 1066 const model::SharedPageDescriptor& rpDescriptor) 1067 { 1068 SelectOnePage(rpDescriptor); 1069 mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor); 1070 } 1071 1072 void SelectionFunction::ModeHandler::DeselectAllPages (void) 1073 { 1074 mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); 1075 mrSelectionFunction.ResetShiftKeySelectionAnchor(); 1076 } 1077 1078 void SelectionFunction::ModeHandler::SelectOnePage ( 1079 const model::SharedPageDescriptor& rpDescriptor) 1080 { 1081 DeselectAllPages(); 1082 mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); 1083 } 1084 1085 void SelectionFunction::ModeHandler::SwitchView (const model::SharedPageDescriptor& rpDescriptor) 1086 { 1087 // Switch to the draw view. This is done only when the current 1088 // view is the main view. 1089 ViewShell* pViewShell = mrSlideSorter.GetViewShell(); 1090 if (pViewShell!=NULL && pViewShell->IsMainViewShell()) 1091 { 1092 if (rpDescriptor.get()!=NULL && rpDescriptor->GetPage()!=NULL) 1093 { 1094 mrSlideSorter.GetModel().GetDocument()->SetSelected(rpDescriptor->GetPage(), sal_True); 1095 pViewShell->GetFrameView()->SetSelectedPage( 1096 (rpDescriptor->GetPage()->GetPageNum()-1)/2); 1097 } 1098 if (mrSlideSorter.GetViewShellBase() != NULL) 1099 framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView( 1100 framework::FrameworkHelper::msImpressViewURL, 1101 framework::FrameworkHelper::msCenterPaneURL); 1102 } 1103 } 1104 1105 void SelectionFunction::ModeHandler::StartDrag ( 1106 const Point& rMousePosition, 1107 const InsertionIndicatorHandler::Mode eMode) 1108 { 1109 (void)eMode; 1110 // Do not start a drag-and-drop operation when one is already active. 1111 // (when dragging pages from one document into another, pressing a 1112 // modifier key can trigger a MouseMotion event in the originating 1113 // window (focus still in there). Together with the mouse button pressed 1114 // (drag-and-drop is active) this triggers the start of drag-and-drop.) 1115 if (SD_MOD()->pTransferDrag != NULL) 1116 return; 1117 1118 if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) 1119 { 1120 mrSelectionFunction.SwitchToDragAndDropMode(rMousePosition); 1121 } 1122 } 1123 1124 bool SelectionFunction::ModeHandler::IsMouseOverIndicatorAllowed (void) const 1125 { 1126 return mbIsMouseOverIndicatorAllowed; 1127 } 1128 1129 //===== NormalModeHandler ===================================================== 1130 1131 NormalModeHandler::NormalModeHandler ( 1132 SlideSorter& rSlideSorter, 1133 SelectionFunction& rSelectionFunction) 1134 : ModeHandler(rSlideSorter, rSelectionFunction, true), 1135 maButtonDownLocation() 1136 { 1137 } 1138 1139 NormalModeHandler::~NormalModeHandler (void) 1140 { 1141 } 1142 1143 SelectionFunction::Mode NormalModeHandler::GetMode (void) const 1144 { 1145 return SelectionFunction::NormalMode; 1146 } 1147 1148 void NormalModeHandler::Abort (void) 1149 { 1150 } 1151 1152 bool NormalModeHandler::ProcessButtonDownEvent ( 1153 SelectionFunction::EventDescriptor& rDescriptor) 1154 { 1155 // Remember the location where the left button is pressed. With 1156 // that we can filter away motion events that are caused by key 1157 // presses. We also can tune the minimal motion distance that 1158 // triggers a drag-and-drop operation. 1159 if ((rDescriptor.mnEventCode & BUTTON_DOWN) != 0) 1160 maButtonDownLocation = rDescriptor.maMousePosition; 1161 1162 switch (rDescriptor.mnEventCode) 1163 { 1164 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE: 1165 SetCurrentPage(rDescriptor.mpHitDescriptor); 1166 break; 1167 1168 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: 1169 break; 1170 1171 case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_SELECTED_PAGE: 1172 case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_UNSELECTED_PAGE: 1173 // A double click always shows the selected slide in the center 1174 // pane in an edit view. 1175 SetCurrentPage(rDescriptor.mpHitDescriptor); 1176 SwitchView(rDescriptor.mpHitDescriptor); 1177 break; 1178 1179 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER: 1180 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER: 1181 // Range selection with the shift modifier. 1182 RangeSelect(rDescriptor.mpHitDescriptor); 1183 break; 1184 1185 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | OVER_BUTTON: 1186 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | OVER_BUTTON: 1187 OSL_ASSERT(mrSlideSorter.GetView().GetButtonBar().IsMouseOverButton()); 1188 1189 // Switch to button mode only when the buttons are visible 1190 // (or being faded in.) 1191 if (mrSlideSorter.GetView().GetButtonBar().IsVisible(rDescriptor.mpHitDescriptor)) 1192 { 1193 if (mrSelectionFunction.SwitchToButtonMode()) 1194 ReprocessEvent(rDescriptor); 1195 } 1196 else 1197 { 1198 // When the buttons are not (yet) visible then behave like 1199 // the left button had been clicked over any other part of 1200 // the slide. 1201 SetCurrentPage(rDescriptor.mpHitDescriptor); 1202 } 1203 break; 1204 1205 // Right button for context menu. 1206 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE: 1207 // Single right click and shift+F10 select as preparation to 1208 // show the context menu. Change the selection only when the 1209 // page under the mouse is not selected. In this case the 1210 // selection is set to this single page. Otherwise the 1211 // selection is not modified. 1212 SetCurrentPage(rDescriptor.mpHitDescriptor); 1213 rDescriptor.mbMakeSelectionVisible = false; 1214 break; 1215 1216 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: 1217 // Do not change the selection. Just adjust the insertion indicator. 1218 rDescriptor.mbMakeSelectionVisible = false; 1219 break; 1220 1221 case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE: 1222 // Remember the current selection so that when a multi selection 1223 // is started, we can restore the previous selection. 1224 mrSlideSorter.GetModel().SaveCurrentSelection(); 1225 DeselectAllPages(); 1226 break; 1227 1228 case ANY_MODIFIER(BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): 1229 // Remember the current selection so that when a multi selection 1230 // is started, we can restore the previous selection. 1231 mrSlideSorter.GetModel().SaveCurrentSelection(); 1232 DeselectAllPages(); 1233 break; 1234 1235 default: 1236 return false; 1237 } 1238 return true; 1239 } 1240 1241 bool NormalModeHandler::ProcessButtonUpEvent ( 1242 SelectionFunction::EventDescriptor& rDescriptor) 1243 { 1244 bool bIsProcessed (true); 1245 switch (rDescriptor.mnEventCode) 1246 { 1247 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: 1248 SetCurrentPage(rDescriptor.mpHitDescriptor); 1249 break; 1250 1251 // Multi selection with the control modifier. 1252 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER: 1253 mrSlideSorter.GetController().GetPageSelector().DeselectPage( 1254 rDescriptor.mpHitDescriptor); 1255 break; 1256 1257 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER: 1258 mrSlideSorter.GetController().GetPageSelector().SelectPage( 1259 rDescriptor.mpHitDescriptor); 1260 mrSlideSorter.GetView().UpdatePageUnderMouse( 1261 rDescriptor.mpHitDescriptor, 1262 rDescriptor.maMousePosition, 1263 false); 1264 break; 1265 case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE: 1266 break; 1267 1268 default: 1269 bIsProcessed = false; 1270 break; 1271 } 1272 mrSelectionFunction.SwitchToNormalMode(); 1273 return bIsProcessed; 1274 } 1275 1276 bool NormalModeHandler::ProcessMotionEvent ( 1277 SelectionFunction::EventDescriptor& rDescriptor) 1278 { 1279 if (ModeHandler::ProcessMotionEvent(rDescriptor)) 1280 return true; 1281 1282 bool bIsProcessed (true); 1283 switch (rDescriptor.mnEventCode) 1284 { 1285 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE): 1286 // SetCurrentPage(rDescriptor.mpHitDescriptor); 1287 // Fallthrough 1288 1289 // A mouse motion without visible substitution starts that. 1290 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE): 1291 { 1292 if (maButtonDownLocation) 1293 { 1294 const sal_Int32 nDistance (maButtonDownLocation 1295 ? ::std::max ( 1296 abs(maButtonDownLocation->X() - rDescriptor.maMousePosition.X()), 1297 abs(maButtonDownLocation->Y() - rDescriptor.maMousePosition.Y())) 1298 : 0); 1299 if (nDistance > 3) 1300 StartDrag( 1301 rDescriptor.maMousePosition, 1302 (rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0 1303 ? InsertionIndicatorHandler::CopyMode 1304 : InsertionIndicatorHandler::MoveMode); 1305 } 1306 } 1307 break; 1308 1309 // A mouse motion not over a page starts a rectangle selection. 1310 case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): 1311 mrSelectionFunction.SwitchToMultiSelectionMode( 1312 rDescriptor.maMouseModelPosition, 1313 rDescriptor.mnEventCode); 1314 break; 1315 1316 default: 1317 bIsProcessed = false; 1318 break; 1319 } 1320 return bIsProcessed; 1321 } 1322 1323 bool NormalModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) 1324 { 1325 mrSelectionFunction.SwitchToDragAndDropMode(rDescriptor.maMousePosition); 1326 ReprocessEvent(rDescriptor); 1327 return true; 1328 } 1329 1330 void NormalModeHandler::RangeSelect (const model::SharedPageDescriptor& rpDescriptor) 1331 { 1332 PageSelector::UpdateLock aLock (mrSlideSorter); 1333 PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); 1334 1335 model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor()); 1336 DeselectAllPages(); 1337 1338 if (pAnchor.get() != NULL) 1339 { 1340 // Select all pages between the anchor and the given one, including 1341 // the two. 1342 const sal_uInt16 nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2); 1343 const sal_uInt16 nOtherIndex ((rpDescriptor->GetPage()->GetPageNum()-1) / 2); 1344 1345 // Iterate over all pages in the range. Start with the anchor 1346 // page. This way the PageSelector will recognize it again as 1347 // anchor (the first selected page after a DeselectAllPages() 1348 // becomes the anchor.) 1349 const sal_uInt16 nStep ((nAnchorIndex < nOtherIndex) ? +1 : -1); 1350 sal_uInt16 nIndex (nAnchorIndex); 1351 while (true) 1352 { 1353 rSelector.SelectPage(nIndex); 1354 if (nIndex == nOtherIndex) 1355 break; 1356 nIndex = nIndex + nStep; 1357 } 1358 } 1359 } 1360 1361 void NormalModeHandler::ResetButtonDownLocation (void) 1362 { 1363 maButtonDownLocation = ::boost::optional<Point>(); 1364 } 1365 1366 //===== MultiSelectionModeHandler ============================================= 1367 1368 MultiSelectionModeHandler::MultiSelectionModeHandler ( 1369 SlideSorter& rSlideSorter, 1370 SelectionFunction& rSelectionFunction, 1371 const Point& rMouseModelPosition, 1372 const sal_uInt32 nEventCode) 1373 : ModeHandler(rSlideSorter, rSelectionFunction, false), 1374 meSelectionMode(SM_Normal), 1375 maSecondCorner(rMouseModelPosition), 1376 maSavedPointer(mrSlideSorter.GetContentWindow()->GetPointer()), 1377 mnAnchorIndex(-1), 1378 mnSecondIndex(-1), 1379 maButtonBarLock(rSlideSorter) 1380 { 1381 const Pointer aSelectionPointer (POINTER_TEXT); 1382 mrSlideSorter.GetContentWindow()->SetPointer(aSelectionPointer); 1383 SetSelectionModeFromModifier(nEventCode); 1384 } 1385 1386 MultiSelectionModeHandler::~MultiSelectionModeHandler (void) 1387 { 1388 mrSlideSorter.GetContentWindow()->SetPointer(maSavedPointer); 1389 } 1390 1391 SelectionFunction::Mode MultiSelectionModeHandler::GetMode (void) const 1392 { 1393 return SelectionFunction::MultiSelectionMode; 1394 } 1395 1396 void MultiSelectionModeHandler::Abort (void) 1397 { 1398 mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection()); 1399 } 1400 1401 void MultiSelectionModeHandler::ProcessEvent ( 1402 SelectionFunction::EventDescriptor& rDescriptor) 1403 { 1404 // During a multi selection we do not want sudden jumps of the 1405 // visible area caused by moving newly selected pages into view. 1406 // Therefore disable that temporarily. The disabler object is 1407 // released at the end of the event processing, after the focus and 1408 // current slide have been updated. 1409 VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); 1410 1411 ModeHandler::ProcessEvent(rDescriptor); 1412 } 1413 1414 bool MultiSelectionModeHandler::ProcessButtonUpEvent ( 1415 SelectionFunction::EventDescriptor& rDescriptor) 1416 { 1417 if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK)) 1418 { 1419 mrSelectionFunction.SwitchToNormalMode(); 1420 return true; 1421 } 1422 else 1423 return false; 1424 } 1425 1426 bool MultiSelectionModeHandler::ProcessMotionEvent ( 1427 SelectionFunction::EventDescriptor& rDescriptor) 1428 { 1429 // The selection rectangle is visible. Handle events accordingly. 1430 if (Match(rDescriptor.mnEventCode, MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK)) 1431 { 1432 SetSelectionModeFromModifier(rDescriptor.mnEventCode); 1433 UpdatePosition(rDescriptor.maMousePosition, true); 1434 rDescriptor.mbMakeSelectionVisible = false; 1435 return true; 1436 } 1437 else 1438 return false; 1439 } 1440 1441 bool MultiSelectionModeHandler::HandleUnprocessedEvent ( 1442 SelectionFunction::EventDescriptor& rDescriptor) 1443 { 1444 if ( ! ModeHandler::HandleUnprocessedEvent(rDescriptor)) 1445 { 1446 // If the event has not been processed then stop multi selection. 1447 mrSelectionFunction.SwitchToNormalMode(); 1448 ReprocessEvent(rDescriptor); 1449 } 1450 return true; 1451 } 1452 1453 void MultiSelectionModeHandler::UpdatePosition ( 1454 const Point& rMousePosition, 1455 const bool bAllowAutoScroll) 1456 { 1457 VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); 1458 1459 // Convert window coordinates into model coordinates (we need the 1460 // window coordinates for auto-scrolling because that remains 1461 // constant while scrolling.) 1462 SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); 1463 const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition)); 1464 1465 if ( ! (bAllowAutoScroll && mrSlideSorter.GetController().GetScrollBarManager().AutoScroll( 1466 rMousePosition, 1467 ::boost::bind( 1468 &MultiSelectionModeHandler::UpdatePosition, 1469 this, 1470 rMousePosition, 1471 false)))) 1472 { 1473 UpdateModelPosition(aMouseModelPosition); 1474 } 1475 } 1476 1477 void MultiSelectionModeHandler::SetSelectionModeFromModifier ( 1478 const sal_uInt32 nEventCode) 1479 { 1480 switch (nEventCode & MODIFIER_MASK) 1481 { 1482 case NO_MODIFIER: 1483 SetSelectionMode(SM_Normal); 1484 break; 1485 1486 case SHIFT_MODIFIER: 1487 SetSelectionMode(SM_Add); 1488 break; 1489 1490 case CONTROL_MODIFIER: 1491 SetSelectionMode(SM_Toggle); 1492 break; 1493 } 1494 } 1495 1496 void MultiSelectionModeHandler::SetSelectionMode (const SelectionMode eSelectionMode) 1497 { 1498 if (meSelectionMode != eSelectionMode) 1499 { 1500 meSelectionMode = eSelectionMode; 1501 UpdateSelection(); 1502 } 1503 } 1504 1505 void MultiSelectionModeHandler::UpdateSelectionState ( 1506 const model::SharedPageDescriptor& rpDescriptor, 1507 const bool bIsInSelection) const 1508 { 1509 // Determine whether the page was selected before the rectangle 1510 // selection was started. 1511 const bool bWasSelected (rpDescriptor->HasState(model::PageDescriptor::ST_WasSelected)); 1512 1513 // Combine the two selection states depending on the selection mode. 1514 bool bSelect (false); 1515 switch(meSelectionMode) 1516 { 1517 case SM_Normal: 1518 bSelect = bIsInSelection; 1519 break; 1520 1521 case SM_Add: 1522 bSelect = bIsInSelection || bWasSelected; 1523 break; 1524 1525 case SM_Toggle: 1526 if (bIsInSelection) 1527 bSelect = !bWasSelected; 1528 else 1529 bSelect = bWasSelected; 1530 break; 1531 } 1532 1533 // Set the new selection state. 1534 if (bSelect) 1535 mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); 1536 else 1537 mrSlideSorter.GetController().GetPageSelector().DeselectPage(rpDescriptor); 1538 } 1539 1540 void MultiSelectionModeHandler::UpdateModelPosition (const Point& rMouseModelPosition) 1541 { 1542 maSecondCorner = rMouseModelPosition; 1543 UpdateSelection(); 1544 } 1545 1546 void MultiSelectionModeHandler::UpdateSelection (void) 1547 { 1548 view::SlideSorterView::DrawLock aLock (mrSlideSorter); 1549 1550 model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); 1551 const sal_Int32 nPageCount (rModel.GetPageCount()); 1552 1553 const sal_Int32 nIndexUnderMouse ( 1554 mrSlideSorter.GetView().GetLayouter().GetIndexAtPoint ( 1555 maSecondCorner, 1556 false, 1557 false)); 1558 if (nIndexUnderMouse>=0 && nIndexUnderMouse<nPageCount) 1559 { 1560 if (mnAnchorIndex < 0) 1561 mnAnchorIndex = nIndexUnderMouse; 1562 mnSecondIndex = nIndexUnderMouse; 1563 1564 Range aRange (mnAnchorIndex, mnSecondIndex); 1565 aRange.Justify(); 1566 1567 for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex) 1568 { 1569 UpdateSelectionState(rModel.GetPageDescriptor(nIndex), aRange.IsInside(nIndex)); 1570 } 1571 } 1572 } 1573 1574 //===== DragAndDropModeHandler ================================================ 1575 1576 DragAndDropModeHandler::DragAndDropModeHandler ( 1577 SlideSorter& rSlideSorter, 1578 SelectionFunction& rSelectionFunction, 1579 const Point& rMousePosition, 1580 ::Window* pWindow) 1581 : ModeHandler(rSlideSorter, rSelectionFunction, false) 1582 { 1583 SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; 1584 if (pDragTransferable==NULL && mrSlideSorter.GetViewShell() != NULL) 1585 { 1586 SlideSorterViewShell* pSlideSorterViewShell 1587 = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); 1588 if (pSlideSorterViewShell != NULL) 1589 pSlideSorterViewShell->StartDrag(rMousePosition, pWindow); 1590 pDragTransferable = SD_MOD()->pTransferDrag; 1591 } 1592 1593 mpDragAndDropContext.reset(new DragAndDropContext(mrSlideSorter)); 1594 mrSlideSorter.GetController().GetInsertionIndicatorHandler()->Start( 1595 pDragTransferable != NULL 1596 && pDragTransferable->GetView()==&mrSlideSorter.GetView()); 1597 } 1598 1599 DragAndDropModeHandler::~DragAndDropModeHandler (void) 1600 { 1601 if (mpDragAndDropContext) 1602 { 1603 // Disconnect the substitution handler from this selection function. 1604 mpDragAndDropContext->SetTargetSlideSorter(); 1605 mpDragAndDropContext.reset(); 1606 } 1607 mrSlideSorter.GetController().GetInsertionIndicatorHandler()->End(Animator::AM_Animated); 1608 } 1609 1610 SelectionFunction::Mode DragAndDropModeHandler::GetMode (void) const 1611 { 1612 return SelectionFunction::DragAndDropMode; 1613 } 1614 1615 void DragAndDropModeHandler::Abort (void) 1616 { 1617 mrSlideSorter.GetController().GetClipboard().Abort(); 1618 if (mpDragAndDropContext) 1619 mpDragAndDropContext->Dispose(); 1620 // mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection()); 1621 } 1622 1623 bool DragAndDropModeHandler::ProcessButtonUpEvent ( 1624 SelectionFunction::EventDescriptor& rDescriptor) 1625 { 1626 if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON)) 1627 { 1628 // The following Process() call may lead to the destruction 1629 // of rDescriptor.mpHitDescriptor so release our reference to it. 1630 rDescriptor.mpHitDescriptor.reset(); 1631 mrSelectionFunction.SwitchToNormalMode(); 1632 return true; 1633 } 1634 else 1635 return false; 1636 } 1637 1638 bool DragAndDropModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) 1639 { 1640 OSL_ASSERT(mpDragAndDropContext); 1641 1642 if (rDescriptor.mbIsLeaving) 1643 { 1644 mrSelectionFunction.SwitchToNormalMode(); 1645 } 1646 else if (mpDragAndDropContext) 1647 { 1648 mpDragAndDropContext->UpdatePosition( 1649 rDescriptor.maMousePosition, 1650 rDescriptor.meDragMode); 1651 } 1652 1653 return true; 1654 } 1655 1656 //===== ButtonModeHandler ===================================================== 1657 1658 ButtonModeHandler::ButtonModeHandler ( 1659 SlideSorter& rSlideSorter, 1660 SelectionFunction& rSelectionFunction) 1661 : ModeHandler(rSlideSorter, rSelectionFunction, true) 1662 { 1663 } 1664 1665 ButtonModeHandler::~ButtonModeHandler (void) 1666 { 1667 } 1668 1669 SelectionFunction::Mode ButtonModeHandler::GetMode (void) const 1670 { 1671 return SelectionFunction::ButtonMode; 1672 } 1673 1674 void ButtonModeHandler::Abort (void) 1675 { 1676 } 1677 1678 bool ButtonModeHandler::ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor) 1679 { 1680 switch (rDescriptor.mnEventCode) 1681 { 1682 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | OVER_BUTTON: 1683 case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | OVER_BUTTON: 1684 // Remember page and button index. When mouse button is released 1685 // over same page and button then invoke action of that button. 1686 mrSlideSorter.GetView().GetButtonBar().ProcessButtonDownEvent( 1687 rDescriptor.mpHitDescriptor, 1688 rDescriptor.maMouseModelPosition); 1689 return true; 1690 1691 default: 1692 return false; 1693 } 1694 } 1695 1696 bool ButtonModeHandler::ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) 1697 { 1698 switch (rDescriptor.mnEventCode & BUTTON_MASK) 1699 { 1700 case LEFT_BUTTON: 1701 mrSlideSorter.GetView().GetButtonBar().ProcessButtonUpEvent( 1702 rDescriptor.mpHitDescriptor, 1703 rDescriptor.maMouseModelPosition); 1704 mrSelectionFunction.SwitchToNormalMode(); 1705 return true; 1706 } 1707 1708 return false; 1709 } 1710 1711 bool ButtonModeHandler::ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor) 1712 { 1713 switch (rDescriptor.mnEventCode & (MOUSE_MOTION | BUTTON_MASK)) 1714 { 1715 case MOUSE_MOTION | LEFT_BUTTON: 1716 mrSlideSorter.GetView().GetButtonBar().ProcessMouseMotionEvent( 1717 rDescriptor.mpHitDescriptor, 1718 rDescriptor.maMouseModelPosition, 1719 true); 1720 return true; 1721 1722 case MOUSE_MOTION: 1723 mrSlideSorter.GetView().GetButtonBar().ProcessMouseMotionEvent( 1724 rDescriptor.mpHitDescriptor, 1725 rDescriptor.maMouseModelPosition, 1726 false); 1727 return true; 1728 } 1729 1730 return false; 1731 } 1732 1733 } } } // end of namespace ::sd::slidesorter::controller 1734 1735 /* vim: set noet sw=4 ts=4: */ 1736