bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / slidesorter / controller / SlsClipboard.cxx
blob89b725d97be0e47882824112f5298d2eabe61567
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <controller/SlsClipboard.hxx>
22 #include <SlideSorterViewShell.hxx>
23 #include <SlideSorter.hxx>
24 #include <model/SlideSorterModel.hxx>
25 #include <model/SlsPageDescriptor.hxx>
26 #include <model/SlsPageEnumerationProvider.hxx>
27 #include <view/SlideSorterView.hxx>
28 #include <view/SlsTheme.hxx>
29 #include <controller/SlideSorterController.hxx>
30 #include <controller/SlsInsertionIndicatorHandler.hxx>
31 #include <controller/SlsPageSelector.hxx>
32 #include <controller/SlsSelectionFunction.hxx>
33 #include <controller/SlsCurrentSlideManager.hxx>
34 #include <controller/SlsScrollBarManager.hxx>
35 #include <controller/SlsFocusManager.hxx>
36 #include <controller/SlsSelectionManager.hxx>
37 #include <controller/SlsTransferableData.hxx>
38 #include <controller/SlsSelectionObserver.hxx>
39 #include <controller/SlsVisibleAreaManager.hxx>
40 #include <cache/SlsPageCache.hxx>
42 #include <ViewShellBase.hxx>
43 #include <View.hxx>
44 #include <DrawViewShell.hxx>
45 #include <Window.hxx>
46 #include <fupoor.hxx>
47 #include <fuzoom.hxx>
48 #include <fucushow.hxx>
49 #include <fusldlg.hxx>
50 #include <fuexpand.hxx>
51 #include <fusumry.hxx>
52 #include <app.hrc>
53 #include <strings.hrc>
54 #include <sdresid.hxx>
55 #include <sdxfer.hxx>
56 #include <sdmod.hxx>
57 #include <ins_paste.hxx>
58 #include <drawdoc.hxx>
59 #include <DrawDocShell.hxx>
60 #include <sdpage.hxx>
61 #include <sdtreelb.hxx>
63 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
64 #include <sfx2/request.hxx>
65 #include <sfx2/viewfrm.hxx>
66 #include <sfx2/bindings.hxx>
67 #include <sfx2/docfile.hxx>
68 #include <svx/svxids.hrc>
69 #include <tools/urlobj.hxx>
70 #include <rtl/ustring.hxx>
71 #include <vcl/svapp.hxx>
73 namespace sd { namespace slidesorter { namespace controller {
75 namespace {
76 /** Temporarily deactivate slide tracking of the VisibleAreaManager.
77 This is used as a workaround to avoid unwanted repositioning of
78 the visible area when the selection of slides is copied to the
79 clipboard (cloning of slides leads to model change notifications
80 for the original model.)
82 class TemporarySlideTrackingDeactivator
84 public:
85 explicit TemporarySlideTrackingDeactivator (SlideSorterController& rController)
86 : mrController(rController),
87 mbIsCurrentSlideTrackingActive (
88 mrController.GetVisibleAreaManager().IsCurrentSlideTrackingActive())
90 if (mbIsCurrentSlideTrackingActive)
91 mrController.GetVisibleAreaManager().DeactivateCurrentSlideTracking();
93 ~TemporarySlideTrackingDeactivator()
95 if (mbIsCurrentSlideTrackingActive)
96 mrController.GetVisibleAreaManager().ActivateCurrentSlideTracking();
99 private:
100 SlideSorterController& mrController;
101 const bool mbIsCurrentSlideTrackingActive;
103 } // end of anonymous namespace
105 class Clipboard::UndoContext
107 public:
108 UndoContext (
109 SdDrawDocument* pDocument,
110 const std::shared_ptr<ViewShell>& rpMainViewShell)
111 : mpDocument(pDocument),
112 mpMainViewShell(rpMainViewShell)
114 if (mpDocument!=nullptr && mpDocument->IsUndoEnabled())
116 if (mpMainViewShell && mpMainViewShell->GetShellType() == ViewShell::ST_DRAW)
117 mpDocument->BegUndo(SdResId(STRING_DRAG_AND_DROP_PAGES));
118 else
119 mpDocument->BegUndo(SdResId(STRING_DRAG_AND_DROP_SLIDES));
123 ~UndoContext()
125 if (mpDocument!=nullptr && mpDocument->IsUndoEnabled())
126 mpDocument->EndUndo();
127 if (mpMainViewShell && mpMainViewShell->GetViewFrame()!=nullptr)
129 SfxBindings& rBindings = mpMainViewShell->GetViewFrame()->GetBindings();
130 rBindings.Invalidate(SID_UNDO);
131 rBindings.Invalidate(SID_REDO);
134 private:
135 SdDrawDocument* mpDocument;
136 std::shared_ptr<ViewShell> mpMainViewShell;
139 Clipboard::Clipboard (SlideSorter& rSlideSorter)
140 : ViewClipboard(rSlideSorter.GetView()),
141 mrSlideSorter(rSlideSorter),
142 mrController(mrSlideSorter.GetController()),
143 maPagesToRemove(),
144 mxUndoContext(),
145 mxSelectionObserverContext(),
146 mnDragFinishedUserEventId(nullptr)
150 Clipboard::~Clipboard()
152 if (mnDragFinishedUserEventId != nullptr)
153 Application::RemoveUserEvent(mnDragFinishedUserEventId);
156 /** With the current implementation the forwarded calls to the current
157 function will come back eventually to call the local Do(Cut|Copy|Paste)
158 methods. A shortcut is possible but would be an unclean hack.
160 void Clipboard::HandleSlotCall (SfxRequest& rRequest)
162 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
163 rtl::Reference<FuPoor> xFunc;
164 if (pViewShell != nullptr)
165 xFunc = pViewShell->GetCurrentFunction();
166 switch (rRequest.GetSlot())
168 case SID_CUT:
169 if (mrSlideSorter.GetModel().GetEditMode() != EditMode::MasterPage)
171 if(xFunc.is())
172 xFunc->DoCut();
173 else
174 DoCut();
176 rRequest.Done();
177 break;
179 case SID_COPY:
180 if (mrSlideSorter.GetModel().GetEditMode() != EditMode::MasterPage)
182 if(xFunc.is())
183 xFunc->DoCopy();
184 else
185 DoCopy();
187 rRequest.Done();
188 break;
190 case SID_PASTE:
191 // Prevent redraws while inserting pages from the clipboard
192 // because the intermediate inconsistent state might lead to
193 // a crash.
194 if (mrSlideSorter.GetModel().GetEditMode() != EditMode::MasterPage)
196 view::SlideSorterView::DrawLock aLock (mrSlideSorter);
197 SelectionObserver::Context aContext (mrSlideSorter);
198 if(xFunc.is())
199 xFunc->DoPaste();
200 else
201 DoPaste();
203 rRequest.Done();
204 break;
206 case SID_DELETE:
207 DoDelete();
208 rRequest.Done();
209 break;
213 void Clipboard::DoCut ()
215 if (mrSlideSorter.GetModel().GetPageCount() > 1)
217 DoCopy();
218 DoDelete();
222 void Clipboard::DoDelete()
224 if (mrSlideSorter.GetModel().GetPageCount() > 1)
226 mrController.GetSelectionManager()->DeleteSelectedPages();
230 void Clipboard::DoCopy ()
232 CreateSlideTransferable( nullptr, false );
235 void Clipboard::DoPaste ()
237 SdTransferable* pClipTransferable = SD_MOD()->pTransferClip;
239 if (pClipTransferable==nullptr || !pClipTransferable->IsPageTransferable())
240 return;
242 sal_Int32 nInsertPosition = GetInsertionPosition();
244 if (nInsertPosition >= 0)
246 // Paste the pages from the clipboard.
247 sal_Int32 nInsertPageCount = PasteTransferable(nInsertPosition);
248 // Select the pasted pages and make the first of them the
249 // current page.
250 mrSlideSorter.GetContentWindow()->GrabFocus();
251 SelectPageRange(nInsertPosition, nInsertPageCount);
255 sal_Int32 Clipboard::GetInsertionPosition ()
257 sal_Int32 nInsertPosition = -1;
259 // Determine the insertion position:
260 // a) When the insertion indicator is visible, then at that position.
261 // b) When the focus indicator is visible, then before or after the
262 // focused page, depending on user input to a dialog.
263 // c) When there is a selection but no focus, then after the
264 // selection.
265 // d) After the last page when there is no selection and no focus.
267 std::shared_ptr<controller::InsertionIndicatorHandler> pInsertionIndicatorHandler (
268 mrController.GetInsertionIndicatorHandler());
269 if (pInsertionIndicatorHandler->IsActive())
271 // Use the insertion index of an active insertion indicator.
272 nInsertPosition = pInsertionIndicatorHandler->GetInsertionPageIndex();
274 else if (mrController.GetSelectionManager()->GetInsertionPosition() >= 0)
276 // Use the insertion index of an insertion indicator that has been
277 // deactivated a short while ago.
278 nInsertPosition = mrController.GetSelectionManager()->GetInsertionPosition();
280 else if (mrController.GetFocusManager().IsFocusShowing())
282 // Use the focus to determine the insertion position.
283 vcl::Window* pWin = mrSlideSorter.GetContentWindow();
284 SdInsertPasteDlg aDialog(pWin ? pWin->GetFrameWeld() : nullptr);
285 if (aDialog.run() == RET_OK)
287 nInsertPosition = mrController.GetFocusManager().GetFocusedPageIndex();
288 if (!aDialog.IsInsertBefore())
289 nInsertPosition ++;
293 return nInsertPosition;
296 sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition)
298 SdTransferable* pClipTransferable = SD_MOD()->pTransferClip;
299 model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
300 bool bMergeMasterPages = !pClipTransferable->HasSourceDoc (rModel.GetDocument());
301 sal_uInt16 nInsertIndex (rModel.GetCoreIndex(nInsertPosition));
302 sal_Int32 nInsertPageCount (0);
303 if (pClipTransferable->HasPageBookmarks())
305 const std::vector<OUString> &rBookmarkList = pClipTransferable->GetPageBookmarks();
306 const SolarMutexGuard aGuard;
308 nInsertPageCount = static_cast<sal_uInt16>(rBookmarkList.size());
309 rModel.GetDocument()->InsertBookmarkAsPage(
310 rBookmarkList,
311 nullptr,
312 false,
313 false,
314 nInsertIndex,
315 false,
316 pClipTransferable->GetPageDocShell(),
317 true,
318 bMergeMasterPages,
319 false);
321 else
323 SfxObjectShell* pShell = pClipTransferable->GetDocShell().get();
324 DrawDocShell* pDataDocSh = static_cast<DrawDocShell*>(pShell);
325 SdDrawDocument* pDataDoc = pDataDocSh->GetDoc();
327 if (pDataDoc!=nullptr
328 && pDataDoc->GetSdPageCount(PageKind::Standard))
330 const SolarMutexGuard aGuard;
332 bMergeMasterPages = (pDataDoc != rModel.GetDocument());
333 nInsertPageCount = pDataDoc->GetSdPageCount( PageKind::Standard );
334 rModel.GetDocument()->InsertBookmarkAsPage(
335 std::vector<OUString>(),
336 nullptr,
337 false,
338 false,
339 nInsertIndex,
340 false,
341 pDataDocSh,
342 true,
343 bMergeMasterPages,
344 false);
347 mrController.HandleModelChange();
348 return nInsertPageCount;
351 void Clipboard::SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount)
353 // Select the newly inserted pages. That are the nInsertPageCount pages
354 // after the nInsertIndex position.
355 PageSelector& rSelector (mrController.GetPageSelector());
356 rSelector.DeselectAllPages();
357 for (sal_Int32 i=0; i<nPageCount; i++)
359 model::SharedPageDescriptor pDescriptor (
360 mrSlideSorter.GetModel().GetPageDescriptor(nFirstIndex + i));
361 if (pDescriptor.get() != nullptr)
363 rSelector.SelectPage(pDescriptor);
364 // The first page of the new selection is made the current page.
365 if (i == 0)
367 mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor);
373 void Clipboard::CreateSlideTransferable (
374 vcl::Window* pWindow,
375 bool bDrag)
377 std::vector<OUString> aBookmarkList;
379 // Insert all selected pages into a bookmark list and remember them in
380 // maPagesToRemove for possible later removal.
381 model::PageEnumeration aSelectedPages
382 (model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
383 mrSlideSorter.GetModel()));
384 SdDrawDocument* const pDocument = mrSlideSorter.GetModel().GetDocument();
385 DrawDocShell* const pDataDocSh = pDocument->GetDocSh();
387 sal_Int32 nUniqueID = 0;
388 while (aSelectedPages.HasMoreElements())
390 model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
392 //ensure that the slides have unique names
393 const OUString sOrigName = pDescriptor->GetPage()->GetName();
394 if ( pDataDocSh && !pDataDocSh->IsPageNameUnique( sOrigName ) )
396 OUString sUniqueName;
397 bool bUnique = false;
398 while ( !bUnique )
400 sUniqueName = sOrigName + "_clipboard" + OUString::number(nUniqueID++);
401 bUnique = pDataDocSh->IsNewPageNameValid( sUniqueName );
402 if ( bUnique )
403 pDescriptor->GetPage()->SetName(sUniqueName);
407 aBookmarkList.push_back(pDescriptor->GetPage()->GetName());
408 maPagesToRemove.push_back (pDescriptor->GetPage());
411 // Create a small set of representatives of the selection for which
412 // previews are included into the transferable so that an insertion
413 // indicator can be rendered.
414 aSelectedPages.Rewind();
415 ::std::vector<TransferableData::Representative> aRepresentatives;
416 aRepresentatives.reserve(3);
417 std::shared_ptr<cache::PageCache> pPreviewCache (
418 mrSlideSorter.GetView().GetPreviewCache());
419 while (aSelectedPages.HasMoreElements())
421 model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
422 if ( ! pDescriptor || pDescriptor->GetPage()==nullptr)
423 continue;
424 BitmapEx aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false));
425 aRepresentatives.emplace_back(
426 aPreview,
427 pDescriptor->HasState(model::PageDescriptor::ST_Excluded));
428 if (aRepresentatives.size() >= 3)
429 break;
432 if (aBookmarkList.empty())
433 return;
435 mrSlideSorter.GetView().BrkAction();
436 SdTransferable* pTransferable = TransferableData::CreateTransferable (
437 pDocument,
438 dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()),
439 aRepresentatives);
441 if (bDrag)
442 SD_MOD()->pTransferDrag = pTransferable;
443 else
444 SD_MOD()->pTransferClip = pTransferable;
446 pDocument->CreatingDataObj (pTransferable);
447 pTransferable->SetWorkDocument(pDocument->AllocSdDrawDocument());
448 std::unique_ptr<TransferableObjectDescriptor> pObjDesc(new TransferableObjectDescriptor);
449 pTransferable->GetWorkDocument()->GetDocSh()
450 ->FillTransferableObjectDescriptor (*pObjDesc);
452 if (pDataDocSh != nullptr)
453 pObjDesc->maDisplayName = pDataDocSh->GetMedium()->GetURLObject().GetURLNoPass();
455 vcl::Window* pActionWindow = pWindow;
456 if (pActionWindow == nullptr)
458 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
459 if (pViewShell != nullptr)
460 pActionWindow = pViewShell->GetActiveWindow();
463 assert(pActionWindow);
465 pTransferable->SetStartPos (pActionWindow->PixelToLogic(
466 pActionWindow->GetPointerPosPixel()));
467 pTransferable->SetObjectDescriptor (std::move(pObjDesc));
470 TemporarySlideTrackingDeactivator aDeactivator (mrController);
471 pTransferable->SetPageBookmarks (aBookmarkList, !bDrag);
474 if (bDrag)
476 pTransferable->SetView (&mrSlideSorter.GetView());
477 pTransferable->StartDrag (pActionWindow, DND_ACTION_COPY | DND_ACTION_MOVE);
479 else
480 pTransferable->CopyToClipboard (pActionWindow);
482 pDocument->CreatingDataObj(nullptr);
485 std::shared_ptr<SdTransferable::UserData> Clipboard::CreateTransferableUserData (SdTransferable* pTransferable)
489 SdPageObjsTLB::SdPageObjsTransferable* pTreeListBoxTransferable
490 = dynamic_cast<SdPageObjsTLB::SdPageObjsTransferable*>(pTransferable);
491 if (pTreeListBoxTransferable == nullptr)
492 break;
494 // Find view shell for the document of the transferable.
495 ::sd::ViewShell* pViewShell
496 = SdPageObjsTLB::GetViewShellForDocShell(pTreeListBoxTransferable->GetDocShell());
497 if (pViewShell == nullptr)
498 break;
500 // Find slide sorter for the document of the transferable.
501 SlideSorterViewShell* pSlideSorterViewShell
502 = SlideSorterViewShell::GetSlideSorter(pViewShell->GetViewShellBase());
503 if (pSlideSorterViewShell == nullptr)
504 break;
505 SlideSorter& rSlideSorter (pSlideSorterViewShell->GetSlideSorter());
507 // Get bookmark from transferable.
508 TransferableDataHelper aDataHelper (pTransferable);
509 INetBookmark aINetBookmark;
510 if ( ! aDataHelper.GetINetBookmark(SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark))
511 break;
512 const OUString sURL (aINetBookmark.GetURL());
513 const sal_Int32 nIndex (sURL.indexOf('#'));
514 if (nIndex == -1)
515 break;
516 OUString sBookmark (sURL.copy(nIndex+1));
518 // Make sure that the bookmark points to a page.
519 SdDrawDocument* pTransferableDocument = rSlideSorter.GetModel().GetDocument();
520 if (pTransferableDocument == nullptr)
521 break;
522 bool bIsMasterPage = false;
523 const sal_uInt16 nPageIndex (pTransferableDocument->GetPageByName(sBookmark, bIsMasterPage));
524 if (nPageIndex == SDRPAGE_NOTFOUND)
525 break;
527 // Create preview.
528 ::std::vector<TransferableData::Representative> aRepresentatives;
529 aRepresentatives.reserve(1);
530 std::shared_ptr<cache::PageCache> pPreviewCache (
531 rSlideSorter.GetView().GetPreviewCache());
532 model::SharedPageDescriptor pDescriptor (rSlideSorter.GetModel().GetPageDescriptor((nPageIndex-1)/2));
533 if ( ! pDescriptor || pDescriptor->GetPage()==nullptr)
534 break;
535 BitmapEx aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false));
536 aRepresentatives.emplace_back(
537 aPreview,
538 pDescriptor->HasState(model::PageDescriptor::ST_Excluded));
540 // Remember the page in maPagesToRemove so that it can be removed
541 // when drag and drop action is "move".
542 Clipboard& rOtherClipboard (pSlideSorterViewShell->GetSlideSorter().GetController().GetClipboard());
543 rOtherClipboard.maPagesToRemove.clear();
544 rOtherClipboard.maPagesToRemove.push_back(pDescriptor->GetPage());
546 // Create the new transferable.
547 std::shared_ptr<SdTransferable::UserData> pNewTransferable (
548 new TransferableData(
549 pSlideSorterViewShell,
550 aRepresentatives));
551 pTransferable->SetWorkDocument(pTreeListBoxTransferable->GetSourceDoc()->AllocSdDrawDocument());
552 // pTransferable->SetView(&mrSlideSorter.GetView());
554 // Set page bookmark list.
555 std::vector<OUString> aPageBookmarks;
556 aPageBookmarks.push_back(sBookmark);
557 pTransferable->SetPageBookmarks(aPageBookmarks, false);
559 // Replace the view referenced by the transferable with the
560 // corresponding slide sorter view.
561 pTransferable->SetView(&pSlideSorterViewShell->GetSlideSorter().GetView());
563 return pNewTransferable;
565 while (false);
567 return std::shared_ptr<SdTransferable::UserData>();
570 void Clipboard::StartDrag (
571 const Point& rPosition,
572 vcl::Window* pWindow)
574 maPagesToRemove.clear();
575 CreateSlideTransferable(pWindow, true);
577 mrController.GetInsertionIndicatorHandler()->UpdatePosition(
578 rPosition,
579 InsertionIndicatorHandler::UnknownMode);
582 void Clipboard::DragFinished (sal_Int8 nDropAction)
584 if (mnDragFinishedUserEventId == nullptr)
586 mnDragFinishedUserEventId = Application::PostUserEvent(
587 LINK(this, Clipboard, ProcessDragFinished),
588 reinterpret_cast<void*>(nDropAction));
592 IMPL_LINK(Clipboard, ProcessDragFinished, void*, pUserData, void)
594 const sal_Int8 nDropAction (static_cast<sal_Int8>(reinterpret_cast<sal_IntPtr>(pUserData)));
596 mnDragFinishedUserEventId = nullptr;
598 // Hide the substitution display and insertion indicator.
599 ::rtl::Reference<SelectionFunction> pFunction (mrController.GetCurrentSelectionFunction());
600 if (pFunction.is())
601 pFunction->NotifyDragFinished();
603 PageSelector& rSelector (mrController.GetPageSelector());
604 if ((nDropAction & DND_ACTION_MOVE) != 0
605 && ! maPagesToRemove.empty())
607 // Remove the pages that have been moved to another place (possibly
608 // in the same document.)
609 rSelector.DeselectAllPages();
610 for (const auto& rpDraggedPage : maPagesToRemove)
612 rSelector.SelectPage(rpDraggedPage);
614 mrController.GetSelectionManager()->DeleteSelectedPages();
616 mxUndoContext.reset();
617 mxSelectionObserverContext.reset();
620 sal_Int8 Clipboard::AcceptDrop (
621 const AcceptDropEvent& rEvent,
622 DropTargetHelper& rTargetHelper,
623 ::sd::Window* pTargetWindow,
624 sal_uInt16 nPage,
625 SdrLayerID nLayer)
627 sal_Int8 nAction (DND_ACTION_NONE);
629 const Clipboard::DropType eDropType (IsDropAccepted());
631 switch (eDropType)
633 case DT_PAGE:
634 case DT_PAGE_FROM_NAVIGATOR:
636 // Accept a drop.
637 nAction = rEvent.mnAction;
639 // Use the copy action when the drop action is the default, i.e. not
640 // explicitly set to move or link, and when the source and
641 // target models are not the same.
642 SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
643 if (pDragTransferable != nullptr
644 && pDragTransferable->IsPageTransferable()
645 && ((rEvent.maDragEvent.DropAction
646 & css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT) != 0)
647 && (mrSlideSorter.GetModel().GetDocument()->GetDocSh()
648 != pDragTransferable->GetPageDocShell()))
650 nAction = DND_ACTION_COPY;
652 else if (IsInsertionTrivial(pDragTransferable, nAction))
654 nAction = DND_ACTION_NONE;
657 // Show the insertion marker and the substitution for a drop.
658 SelectionFunction* pSelectionFunction = dynamic_cast<SelectionFunction*>(
659 mrSlideSorter.GetViewShell()->GetCurrentFunction().get());
660 if (pSelectionFunction != nullptr)
661 pSelectionFunction->MouseDragged(rEvent, nAction);
663 // Scroll the window when the mouse reaches the window border.
664 // mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel);
666 break;
668 case DT_SHAPE:
669 nAction = ExecuteOrAcceptShapeDrop(
670 DC_ACCEPT,
671 rEvent.maPosPixel,
672 &rEvent,
673 rTargetHelper,
674 pTargetWindow,
675 nPage,
676 nLayer);
677 break;
679 default:
680 case DT_NONE:
681 nAction = DND_ACTION_NONE;
682 break;
685 return nAction;
688 sal_Int8 Clipboard::ExecuteDrop (
689 const ExecuteDropEvent& rEvent,
690 DropTargetHelper& rTargetHelper,
691 ::sd::Window* pTargetWindow,
692 sal_uInt16 nPage,
693 SdrLayerID nLayer)
695 sal_Int8 nResult = DND_ACTION_NONE;
696 mxUndoContext.reset();
697 const Clipboard::DropType eDropType (IsDropAccepted());
699 switch (eDropType)
701 case DT_PAGE:
702 case DT_PAGE_FROM_NAVIGATOR:
704 SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
705 const Point aEventModelPosition (
706 pTargetWindow->PixelToLogic (rEvent.maPosPixel));
707 const sal_Int32 nXOffset (labs (pDragTransferable->GetStartPos().X()
708 - aEventModelPosition.X()));
709 const sal_Int32 nYOffset (labs (pDragTransferable->GetStartPos().Y()
710 - aEventModelPosition.Y()));
711 bool bContinue =
712 ( pDragTransferable->GetView() != &mrSlideSorter.GetView() )
713 || ( nXOffset >= 2 && nYOffset >= 2 );
715 std::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler(
716 mrController.GetInsertionIndicatorHandler());
717 // Get insertion position and then turn off the insertion indicator.
718 pInsertionIndicatorHandler->UpdatePosition(aEventModelPosition, rEvent.mnAction);
719 // sal_uInt16 nIndex = DetermineInsertPosition(*pDragTransferable);
721 // Do not process the insertion when it is trivial,
722 // i.e. would insert pages at their original place.
723 if (IsInsertionTrivial(pDragTransferable, rEvent.mnAction))
724 bContinue = false;
726 // Tell the insertion indicator handler to hide before the model
727 // is modified. Doing it later may result in page objects whose
728 // animation state is not properly reset because they are then
729 // in another run then before the model change.
730 pInsertionIndicatorHandler->End(Animator::AM_Immediate);
732 if (bContinue)
734 SlideSorterController::ModelChangeLock aModelChangeLock (mrController);
736 // Handle a general drop operation.
737 mxUndoContext.reset(new UndoContext (
738 mrSlideSorter.GetModel().GetDocument(),
739 mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell()));
740 mxSelectionObserverContext.reset(new SelectionObserver::Context(mrSlideSorter));
742 HandlePageDrop(*pDragTransferable);
743 nResult = rEvent.mnAction;
745 // We leave the undo context alive for when moving or
746 // copying inside one view then the actions in
747 // NotifyDragFinished should be covered as well as
748 // well as the ones above.
751 // When the pages originated in another slide sorter then
752 // only that is notified automatically about the drag
753 // operation being finished. Because the target slide sorter
754 // has be notified, too, add a callback for that.
755 std::shared_ptr<TransferableData> pSlideSorterTransferable (
756 TransferableData::GetFromTransferable(pDragTransferable));
757 BOOST_ASSERT(pSlideSorterTransferable);
758 if (pSlideSorterTransferable
759 && pSlideSorterTransferable->GetSourceViewShell() != mrSlideSorter.GetViewShell())
761 DragFinished(nResult);
764 // Notify the receiving selection function that drag-and-drop is
765 // finished and the substitution handler can be released.
766 ::rtl::Reference<SelectionFunction> pFunction (
767 mrController.GetCurrentSelectionFunction());
768 if (pFunction.is())
769 pFunction->NotifyDragFinished();
771 break;
773 case DT_SHAPE:
774 nResult = ExecuteOrAcceptShapeDrop(
775 DC_EXECUTE,
776 rEvent.maPosPixel,
777 &rEvent,
778 rTargetHelper,
779 pTargetWindow,
780 nPage,
781 nLayer);
782 break;
784 default:
785 case DT_NONE:
786 break;
789 return nResult;
792 bool Clipboard::IsInsertionTrivial (
793 SdTransferable const * pTransferable,
794 const sal_Int8 nDndAction) const
796 std::shared_ptr<TransferableData> pSlideSorterTransferable (
797 TransferableData::GetFromTransferable(pTransferable));
798 if (pSlideSorterTransferable
799 && pSlideSorterTransferable->GetSourceViewShell() != mrSlideSorter.GetViewShell())
800 return false;
801 return mrController.GetInsertionIndicatorHandler()->IsInsertionTrivial(nDndAction);
804 void Clipboard::Abort()
806 if (mxSelectionObserverContext)
808 mxSelectionObserverContext->Abort();
809 mxSelectionObserverContext.reset();
813 sal_uInt16 Clipboard::DetermineInsertPosition (const SdTransferable& )
815 // Tell the model to move the dragged pages behind the one with the
816 // index nInsertionIndex which first has to be transformed into an index
817 // understandable by the document.
818 const sal_Int32 nInsertionIndex (
819 mrController.GetInsertionIndicatorHandler()->GetInsertionPageIndex());
821 // Convert to insertion index to that of an SdModel.
822 if (nInsertionIndex >= 0)
823 return mrSlideSorter.GetModel().GetCoreIndex(nInsertionIndex);
824 else
825 return 0;
828 Clipboard::DropType Clipboard::IsDropAccepted() const
830 const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
831 if (pDragTransferable == nullptr)
832 return DT_NONE;
834 if (pDragTransferable->IsPageTransferable())
836 if (mrSlideSorter.GetModel().GetEditMode() != EditMode::MasterPage)
837 return DT_PAGE;
838 else
839 return DT_NONE;
842 const SdPageObjsTLB::SdPageObjsTransferable* pPageObjsTransferable
843 = dynamic_cast<const SdPageObjsTLB::SdPageObjsTransferable*>(pDragTransferable);
844 if (pPageObjsTransferable != nullptr)
845 return DT_PAGE_FROM_NAVIGATOR;
847 return DT_SHAPE;
850 sal_Int8 Clipboard::ExecuteOrAcceptShapeDrop (
851 DropCommand eCommand,
852 const Point& rPosition,
853 const void* pDropEvent,
854 DropTargetHelper& rTargetHelper,
855 ::sd::Window* pTargetWindow,
856 sal_uInt16 nPage,
857 SdrLayerID nLayer)
859 sal_Int8 nResult = 0;
861 // The dropping of a shape is accepted or executed only when there is
862 // DrawViewShell available to which we can forward this call. This has
863 // technical reasons: The actual code to accept or execute a shape drop
864 // is implemented in the ViewShell class and uses the page view of the
865 // main edit view. This is not possible without a DrawViewShell.
866 std::shared_ptr<DrawViewShell> pDrawViewShell;
867 if (mrSlideSorter.GetViewShell() != nullptr)
868 pDrawViewShell = std::dynamic_pointer_cast<DrawViewShell>(
869 mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell());
870 if (pDrawViewShell != nullptr
871 && (pDrawViewShell->GetShellType() == ViewShell::ST_IMPRESS
872 || pDrawViewShell->GetShellType() == ViewShell::ST_DRAW))
874 // The drop is only accepted or executed when it takes place over a
875 // page object. Therefore we replace a missing page number by the
876 // number of the page under the mouse.
877 if (nPage == SDRPAGE_NOTFOUND)
879 model::SharedPageDescriptor pDescriptor (
880 mrSlideSorter.GetModel().GetPageDescriptor(
881 mrSlideSorter.GetView().GetPageIndexAtPoint(rPosition)));
882 if (pDescriptor)
883 nPage = pDescriptor->GetPageIndex();
886 // Now comes the code that is different for the Execute and Accept:
887 // We simply forward the call to the AcceptDrop() or ExecuteDrop()
888 // methods of the DrawViewShell in the center pane.
889 if (nPage != SDRPAGE_NOTFOUND)
890 switch (eCommand)
892 case DC_ACCEPT:
893 nResult = pDrawViewShell->AcceptDrop(
894 *static_cast<const AcceptDropEvent*>(pDropEvent),
895 rTargetHelper,
896 pTargetWindow,
897 nPage,
898 nLayer);
899 break;
901 case DC_EXECUTE:
902 nResult = pDrawViewShell->ExecuteDrop(
903 *static_cast<const ExecuteDropEvent*>(pDropEvent),
904 rTargetHelper,
905 pTargetWindow,
906 nPage,
907 nLayer);
908 break;
912 return nResult;
915 } } } // end of namespace ::sd::slidesorter::controller
917 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */