1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <sal/config.h>
24 #include <controller/SlsClipboard.hxx>
26 #include <SlideSorterViewShell.hxx>
27 #include <SlideSorter.hxx>
28 #include <model/SlideSorterModel.hxx>
29 #include <model/SlsPageDescriptor.hxx>
30 #include <model/SlsPageEnumerationProvider.hxx>
32 #include <view/SlideSorterView.hxx>
33 #include <controller/SlideSorterController.hxx>
34 #include <controller/SlsInsertionIndicatorHandler.hxx>
35 #include <controller/SlsPageSelector.hxx>
36 #include <controller/SlsSelectionFunction.hxx>
37 #include <controller/SlsCurrentSlideManager.hxx>
38 #include <controller/SlsFocusManager.hxx>
39 #include <controller/SlsSelectionManager.hxx>
40 #include <controller/SlsTransferableData.hxx>
41 #include <controller/SlsSelectionObserver.hxx>
42 #include <controller/SlsVisibleAreaManager.hxx>
43 #include <cache/SlsPageCache.hxx>
45 #include <ViewShellBase.hxx>
46 #include <DrawViewShell.hxx>
49 #include <strings.hrc>
50 #include <sdresid.hxx>
53 #include <ins_paste.hxx>
54 #include <drawdoc.hxx>
55 #include <DrawDocShell.hxx>
57 #include <sdtreelb.hxx>
59 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
60 #include <sfx2/request.hxx>
61 #include <sfx2/viewfrm.hxx>
62 #include <sfx2/bindings.hxx>
63 #include <sfx2/docfile.hxx>
64 #include <svx/svxids.hrc>
65 #include <tools/urlobj.hxx>
66 #include <rtl/ustring.hxx>
67 #include <vcl/svapp.hxx>
69 namespace sd::slidesorter::controller
{
72 /** Temporarily deactivate slide tracking of the VisibleAreaManager.
73 This is used as a workaround to avoid unwanted repositioning of
74 the visible area when the selection of slides is copied to the
75 clipboard (cloning of slides leads to model change notifications
76 for the original model.)
78 class TemporarySlideTrackingDeactivator
81 explicit TemporarySlideTrackingDeactivator (SlideSorterController
& rController
)
82 : mrController(rController
),
83 mbIsCurrentSlideTrackingActive (
84 mrController
.GetVisibleAreaManager().IsCurrentSlideTrackingActive())
86 if (mbIsCurrentSlideTrackingActive
)
87 mrController
.GetVisibleAreaManager().DeactivateCurrentSlideTracking();
89 ~TemporarySlideTrackingDeactivator()
91 if (mbIsCurrentSlideTrackingActive
)
92 mrController
.GetVisibleAreaManager().ActivateCurrentSlideTracking();
96 SlideSorterController
& mrController
;
97 const bool mbIsCurrentSlideTrackingActive
;
99 } // end of anonymous namespace
101 class Clipboard::UndoContext
105 SdDrawDocument
* pDocument
,
106 std::shared_ptr
<ViewShell
> pMainViewShell
)
107 : mpDocument(pDocument
),
108 mpMainViewShell(std::move(pMainViewShell
))
110 if (mpDocument
!=nullptr && mpDocument
->IsUndoEnabled())
112 if (mpMainViewShell
&& mpMainViewShell
->GetShellType() == ViewShell::ST_DRAW
)
113 mpDocument
->BegUndo(SdResId(STRING_DRAG_AND_DROP_PAGES
));
115 mpDocument
->BegUndo(SdResId(STRING_DRAG_AND_DROP_SLIDES
));
121 if (mpDocument
!=nullptr && mpDocument
->IsUndoEnabled())
122 mpDocument
->EndUndo();
123 if (mpMainViewShell
&& mpMainViewShell
->GetViewFrame()!=nullptr)
125 SfxBindings
& rBindings
= mpMainViewShell
->GetViewFrame()->GetBindings();
126 rBindings
.Invalidate(SID_UNDO
);
127 rBindings
.Invalidate(SID_REDO
);
131 SdDrawDocument
* mpDocument
;
132 std::shared_ptr
<ViewShell
> mpMainViewShell
;
135 Clipboard::Clipboard (SlideSorter
& rSlideSorter
)
136 : ViewClipboard(rSlideSorter
.GetView()),
137 mrSlideSorter(rSlideSorter
),
138 mrController(mrSlideSorter
.GetController()),
139 mnDragFinishedUserEventId(nullptr)
143 Clipboard::~Clipboard()
145 if (mnDragFinishedUserEventId
!= nullptr)
146 Application::RemoveUserEvent(mnDragFinishedUserEventId
);
149 /** With the current implementation the forwarded calls to the current
150 function will come back eventually to call the local Do(Cut|Copy|Paste)
151 methods. A shortcut is possible but would be an unclean hack.
153 void Clipboard::HandleSlotCall (SfxRequest
& rRequest
)
155 ViewShell
* pViewShell
= mrSlideSorter
.GetViewShell();
156 rtl::Reference
<FuPoor
> xFunc
;
157 if (pViewShell
!= nullptr)
158 xFunc
= pViewShell
->GetCurrentFunction();
159 switch (rRequest
.GetSlot())
162 if (mrSlideSorter
.GetModel().GetEditMode() != EditMode::MasterPage
)
173 if (mrSlideSorter
.GetModel().GetEditMode() != EditMode::MasterPage
)
184 // Prevent redraws while inserting pages from the clipboard
185 // because the intermediate inconsistent state might lead to
187 if (mrSlideSorter
.GetModel().GetEditMode() != EditMode::MasterPage
)
189 view::SlideSorterView::DrawLock
aLock (mrSlideSorter
);
190 SelectionObserver::Context
aContext (mrSlideSorter
);
206 void Clipboard::DoCut ()
208 if (mrSlideSorter
.GetModel().GetPageCount() > 1)
215 void Clipboard::DoDelete()
217 if (mrSlideSorter
.GetModel().GetPageCount() > 1)
219 mrController
.GetSelectionManager()->DeleteSelectedPages();
223 void Clipboard::DoCopy ()
225 CreateSlideTransferable( nullptr, false );
228 void Clipboard::DoPaste ()
230 SdTransferable
* pClipTransferable
= SdModule::get()->pTransferClip
;
232 if (pClipTransferable
==nullptr || !pClipTransferable
->IsPageTransferable())
235 sal_Int32 nInsertPosition
= GetInsertionPosition();
237 if (nInsertPosition
>= 0)
239 // Paste the pages from the clipboard.
240 sal_Int32 nInsertPageCount
= PasteTransferable(nInsertPosition
);
241 // Select the pasted pages and make the first of them the
243 mrSlideSorter
.GetContentWindow()->GrabFocus();
244 SelectPageRange(nInsertPosition
, nInsertPageCount
);
248 sal_Int32
Clipboard::GetInsertionPosition ()
250 sal_Int32 nInsertPosition
= -1;
252 // Determine the insertion position:
253 // a) When the insertion indicator is visible, then at that position.
254 // b) When the focus indicator is visible, then before or after the
255 // focused page, depending on user input to a dialog.
256 // c) When there is a selection but no focus, then after the
258 // d) After the last page when there is no selection and no focus.
260 std::shared_ptr
<controller::InsertionIndicatorHandler
> pInsertionIndicatorHandler (
261 mrController
.GetInsertionIndicatorHandler());
262 if (pInsertionIndicatorHandler
->IsActive())
264 // Use the insertion index of an active insertion indicator.
265 nInsertPosition
= pInsertionIndicatorHandler
->GetInsertionPageIndex();
267 else if (mrController
.GetSelectionManager()->GetInsertionPosition() >= 0)
269 // Use the insertion index of an insertion indicator that has been
270 // deactivated a short while ago.
271 nInsertPosition
= mrController
.GetSelectionManager()->GetInsertionPosition();
273 else if (mrController
.GetFocusManager().IsFocusShowing())
275 // Use the focus to determine the insertion position.
276 vcl::Window
* pWin
= mrSlideSorter
.GetContentWindow();
277 SdInsertPasteDlg
aDialog(pWin
? pWin
->GetFrameWeld() : nullptr);
278 if (aDialog
.run() == RET_OK
)
280 nInsertPosition
= mrController
.GetFocusManager().GetFocusedPageIndex();
281 if (!aDialog
.IsInsertBefore())
286 return nInsertPosition
;
289 sal_Int32
Clipboard::PasteTransferable (sal_Int32 nInsertPosition
)
291 SdTransferable
* pClipTransferable
= SdModule::get()->pTransferClip
;
292 model::SlideSorterModel
& rModel (mrSlideSorter
.GetModel());
293 bool bMergeMasterPages
= !pClipTransferable
->HasSourceDoc (rModel
.GetDocument());
294 sal_uInt16
nInsertIndex (rModel
.GetCoreIndex(nInsertPosition
));
295 sal_Int32
nInsertPageCount (0);
296 if (pClipTransferable
->HasPageBookmarks())
298 const std::vector
<OUString
> &rBookmarkList
= pClipTransferable
->GetPageBookmarks();
299 const SolarMutexGuard aGuard
;
301 nInsertPageCount
= static_cast<sal_uInt16
>(rBookmarkList
.size());
302 rModel
.GetDocument()->InsertBookmarkAsPage(
309 pClipTransferable
->GetPageDocShell(),
316 SfxObjectShell
* pShell
= pClipTransferable
->GetDocShell().get();
317 DrawDocShell
* pDataDocSh
= static_cast<DrawDocShell
*>(pShell
);
318 SdDrawDocument
* pDataDoc
= pDataDocSh
->GetDoc();
320 if (pDataDoc
!=nullptr
321 && pDataDoc
->GetSdPageCount(PageKind::Standard
))
323 const SolarMutexGuard aGuard
;
325 bMergeMasterPages
= (pDataDoc
!= rModel
.GetDocument());
326 nInsertPageCount
= pDataDoc
->GetSdPageCount( PageKind::Standard
);
327 rModel
.GetDocument()->InsertBookmarkAsPage(
328 std::vector
<OUString
>(),
340 mrController
.HandleModelChange();
341 return nInsertPageCount
;
344 void Clipboard::SelectPageRange (sal_Int32 nFirstIndex
, sal_Int32 nPageCount
)
346 // Select the newly inserted pages. That are the nInsertPageCount pages
347 // after the nInsertIndex position.
348 PageSelector
& rSelector (mrController
.GetPageSelector());
349 rSelector
.DeselectAllPages();
350 for (sal_Int32 i
=0; i
<nPageCount
; i
++)
352 model::SharedPageDescriptor
pDescriptor (
353 mrSlideSorter
.GetModel().GetPageDescriptor(nFirstIndex
+ i
));
356 rSelector
.SelectPage(pDescriptor
);
357 // The first page of the new selection is made the current page.
360 mrController
.GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor
);
366 void Clipboard::CreateSlideTransferable (
367 vcl::Window
* pWindow
,
370 std::vector
<OUString
> aBookmarkList
;
372 // Insert all selected pages into a bookmark list and remember them in
373 // maPagesToRemove for possible later removal.
374 model::PageEnumeration aSelectedPages
375 (model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
376 mrSlideSorter
.GetModel()));
377 SdDrawDocument
* const pDocument
= mrSlideSorter
.GetModel().GetDocument();
378 DrawDocShell
* const pDataDocSh
= pDocument
->GetDocSh();
380 sal_Int32 nUniqueID
= 0;
381 while (aSelectedPages
.HasMoreElements())
383 model::SharedPageDescriptor
pDescriptor (aSelectedPages
.GetNextElement());
385 //ensure that the slides have unique names
386 const OUString sOrigName
= pDescriptor
->GetPage()->GetName();
387 if ( pDataDocSh
&& !pDataDocSh
->IsPageNameUnique( sOrigName
) )
389 OUString sUniqueName
;
390 bool bUnique
= false;
393 sUniqueName
= sOrigName
+ "_clipboard" + OUString::number(nUniqueID
++);
394 bUnique
= pDataDocSh
->IsNewPageNameValid( sUniqueName
);
396 pDescriptor
->GetPage()->SetName(sUniqueName
);
400 aBookmarkList
.push_back(pDescriptor
->GetPage()->GetName());
401 maPagesToRemove
.push_back (pDescriptor
->GetPage());
404 // Create a small set of representatives of the selection for which
405 // previews are included into the transferable so that an insertion
406 // indicator can be rendered.
407 aSelectedPages
.Rewind();
408 ::std::vector
<TransferableData::Representative
> aRepresentatives
;
409 aRepresentatives
.reserve(3);
410 std::shared_ptr
<cache::PageCache
> pPreviewCache (
411 mrSlideSorter
.GetView().GetPreviewCache());
412 while (aSelectedPages
.HasMoreElements())
414 model::SharedPageDescriptor
pDescriptor (aSelectedPages
.GetNextElement());
415 if ( ! pDescriptor
|| pDescriptor
->GetPage()==nullptr)
417 BitmapEx
aPreview (pPreviewCache
->GetPreviewBitmap(pDescriptor
->GetPage(), false));
418 aRepresentatives
.emplace_back(
420 pDescriptor
->HasState(model::PageDescriptor::ST_Excluded
));
421 if (aRepresentatives
.size() >= 3)
425 if (aBookmarkList
.empty())
428 mrSlideSorter
.GetView().BrkAction();
429 rtl::Reference
<SdTransferable
> pTransferable
= TransferableData::CreateTransferable (
431 dynamic_cast<SlideSorterViewShell
*>(mrSlideSorter
.GetViewShell()),
432 std::move(aRepresentatives
));
435 SdModule::get()->pTransferDrag
= pTransferable
.get();
437 SdModule::get()->pTransferClip
= pTransferable
.get();
439 pDocument
->CreatingDataObj (pTransferable
.get());
440 pTransferable
->SetWorkDocument(pDocument
->AllocSdDrawDocument());
441 std::unique_ptr
<TransferableObjectDescriptor
> pObjDesc(new TransferableObjectDescriptor
);
442 pTransferable
->GetWorkDocument()->GetDocSh()
443 ->FillTransferableObjectDescriptor (*pObjDesc
);
445 if (pDataDocSh
!= nullptr)
446 pObjDesc
->maDisplayName
= pDataDocSh
->GetMedium()->GetURLObject().GetURLNoPass();
448 vcl::Window
* pActionWindow
= pWindow
;
449 if (pActionWindow
== nullptr)
451 ViewShell
* pViewShell
= mrSlideSorter
.GetViewShell();
452 if (pViewShell
!= nullptr)
453 pActionWindow
= pViewShell
->GetActiveWindow();
456 assert(pActionWindow
);
458 pTransferable
->SetStartPos (pActionWindow
->PixelToLogic(
459 pActionWindow
->GetPointerPosPixel()));
460 pTransferable
->SetObjectDescriptor (std::move(pObjDesc
));
463 TemporarySlideTrackingDeactivator
aDeactivator (mrController
);
464 pTransferable
->SetPageBookmarks (std::move(aBookmarkList
), !bDrag
);
469 pTransferable
->SetView (&mrSlideSorter
.GetView());
470 pTransferable
->StartDrag (pActionWindow
, DND_ACTION_COPY
| DND_ACTION_MOVE
);
473 pTransferable
->CopyToClipboard (pActionWindow
);
475 pDocument
->CreatingDataObj(nullptr);
478 std::shared_ptr
<SdTransferable::UserData
> Clipboard::CreateTransferableUserData (SdTransferable
* pTransferable
)
482 SdPageObjsTLV::SdPageObjsTransferable
* pTreeListBoxTransferable
483 = dynamic_cast<SdPageObjsTLV::SdPageObjsTransferable
*>(pTransferable
);
484 if (pTreeListBoxTransferable
== nullptr)
487 // Find view shell for the document of the transferable.
488 ::sd::ViewShell
* pViewShell
489 = SdPageObjsTLV::GetViewShellForDocShell(pTreeListBoxTransferable
->GetDocShell());
490 if (pViewShell
== nullptr)
493 // Find slide sorter for the document of the transferable.
494 SlideSorterViewShell
* pSlideSorterViewShell
495 = SlideSorterViewShell::GetSlideSorter(pViewShell
->GetViewShellBase());
496 if (pSlideSorterViewShell
== nullptr)
498 SlideSorter
& rSlideSorter (pSlideSorterViewShell
->GetSlideSorter());
500 // Get bookmark from transferable.
501 TransferableDataHelper
aDataHelper (pTransferable
);
502 INetBookmark aINetBookmark
;
503 if ( ! aDataHelper
.GetINetBookmark(SotClipboardFormatId::NETSCAPE_BOOKMARK
, aINetBookmark
))
505 const OUString
sURL (aINetBookmark
.GetURL());
506 const sal_Int32
nIndex (sURL
.indexOf('#'));
509 OUString
sBookmark (sURL
.copy(nIndex
+1));
511 // Make sure that the bookmark points to a page.
512 SdDrawDocument
* pTransferableDocument
= rSlideSorter
.GetModel().GetDocument();
513 if (pTransferableDocument
== nullptr)
515 bool bIsMasterPage
= false;
516 const sal_uInt16
nPageIndex (pTransferableDocument
->GetPageByName(sBookmark
, bIsMasterPage
));
517 if (nPageIndex
== SDRPAGE_NOTFOUND
)
521 ::std::vector
<TransferableData::Representative
> aRepresentatives
;
522 aRepresentatives
.reserve(1);
523 std::shared_ptr
<cache::PageCache
> pPreviewCache (
524 rSlideSorter
.GetView().GetPreviewCache());
525 model::SharedPageDescriptor
pDescriptor (rSlideSorter
.GetModel().GetPageDescriptor((nPageIndex
-1)/2));
526 if ( ! pDescriptor
|| pDescriptor
->GetPage()==nullptr)
528 BitmapEx
aPreview (pPreviewCache
->GetPreviewBitmap(pDescriptor
->GetPage(), false));
529 aRepresentatives
.emplace_back(
531 pDescriptor
->HasState(model::PageDescriptor::ST_Excluded
));
533 // Remember the page in maPagesToRemove so that it can be removed
534 // when drag and drop action is "move".
535 Clipboard
& rOtherClipboard (pSlideSorterViewShell
->GetSlideSorter().GetController().GetClipboard());
536 rOtherClipboard
.maPagesToRemove
.clear();
537 rOtherClipboard
.maPagesToRemove
.push_back(pDescriptor
->GetPage());
539 // Create the new transferable.
540 std::shared_ptr
<SdTransferable::UserData
> pNewTransferable
=
541 std::make_shared
<TransferableData
>(
542 pSlideSorterViewShell
,
543 std::move(aRepresentatives
));
544 pTransferable
->SetWorkDocument(pTreeListBoxTransferable
->GetSourceDoc()->AllocSdDrawDocument());
545 // pTransferable->SetView(&mrSlideSorter.GetView());
547 // Set page bookmark list.
548 std::vector
<OUString
> aPageBookmarks
{ sBookmark
};
549 pTransferable
->SetPageBookmarks(std::move(aPageBookmarks
), false);
551 // Replace the view referenced by the transferable with the
552 // corresponding slide sorter view.
553 pTransferable
->SetView(&pSlideSorterViewShell
->GetSlideSorter().GetView());
555 return pNewTransferable
;
559 return std::shared_ptr
<SdTransferable::UserData
>();
562 void Clipboard::StartDrag (
563 const Point
& rPosition
,
564 vcl::Window
* pWindow
)
566 maPagesToRemove
.clear();
567 CreateSlideTransferable(pWindow
, true);
569 mrController
.GetInsertionIndicatorHandler()->UpdatePosition(
571 InsertionIndicatorHandler::UnknownMode
);
574 void Clipboard::DragFinished (sal_Int8 nDropAction
)
576 if (mnDragFinishedUserEventId
== nullptr)
578 mnDragFinishedUserEventId
= Application::PostUserEvent(
579 LINK(this, Clipboard
, ProcessDragFinished
),
580 reinterpret_cast<void*>(nDropAction
));
584 IMPL_LINK(Clipboard
, ProcessDragFinished
, void*, pUserData
, void)
586 const sal_Int8
nDropAction (static_cast<sal_Int8
>(reinterpret_cast<sal_IntPtr
>(pUserData
)));
588 mnDragFinishedUserEventId
= nullptr;
590 // Hide the substitution display and insertion indicator.
591 ::rtl::Reference
<SelectionFunction
> pFunction (mrController
.GetCurrentSelectionFunction());
593 pFunction
->NotifyDragFinished();
595 PageSelector
& rSelector (mrController
.GetPageSelector());
596 if ((nDropAction
& DND_ACTION_MOVE
) != 0
597 && ! maPagesToRemove
.empty())
599 // Remove the pages that have been moved to another place (possibly
600 // in the same document.)
601 rSelector
.DeselectAllPages();
602 for (const auto& rpDraggedPage
: maPagesToRemove
)
604 rSelector
.SelectPage(rpDraggedPage
);
606 mrController
.GetSelectionManager()->DeleteSelectedPages();
608 mxUndoContext
.reset();
609 mxSelectionObserverContext
.reset();
612 sal_Int8
Clipboard::AcceptDrop (
613 const AcceptDropEvent
& rEvent
,
614 DropTargetHelper
& rTargetHelper
,
615 ::sd::Window
* pTargetWindow
,
619 sal_Int8
nAction (DND_ACTION_NONE
);
621 const Clipboard::DropType
eDropType (IsDropAccepted());
626 case DT_PAGE_FROM_NAVIGATOR
:
629 nAction
= rEvent
.mnAction
;
631 // Use the copy action when the drop action is the default, i.e. not
632 // explicitly set to move or link, and when the source and
633 // target models are not the same.
634 SdTransferable
* pDragTransferable
= SdModule::get()->pTransferDrag
;
635 if (pDragTransferable
!= nullptr
636 && pDragTransferable
->IsPageTransferable()
637 && ((rEvent
.maDragEvent
.DropAction
638 & css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT
) != 0)
639 && (mrSlideSorter
.GetModel().GetDocument()->GetDocSh()
640 != pDragTransferable
->GetPageDocShell()))
642 nAction
= DND_ACTION_COPY
;
644 else if (IsInsertionTrivial(pDragTransferable
, nAction
))
646 nAction
= DND_ACTION_NONE
;
649 // Show the insertion marker and the substitution for a drop.
650 SelectionFunction
* pSelectionFunction
= dynamic_cast<SelectionFunction
*>(
651 mrSlideSorter
.GetViewShell()->GetCurrentFunction().get());
652 if (pSelectionFunction
!= nullptr)
653 pSelectionFunction
->MouseDragged(rEvent
, nAction
);
655 // Scroll the window when the mouse reaches the window border.
656 // mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel);
661 nAction
= ExecuteOrAcceptShapeDrop(
673 nAction
= DND_ACTION_NONE
;
680 sal_Int8
Clipboard::ExecuteDrop (
681 const ExecuteDropEvent
& rEvent
,
682 DropTargetHelper
& rTargetHelper
,
683 ::sd::Window
* pTargetWindow
,
687 sal_Int8 nResult
= DND_ACTION_NONE
;
688 mxUndoContext
.reset();
689 const Clipboard::DropType
eDropType (IsDropAccepted());
694 case DT_PAGE_FROM_NAVIGATOR
:
696 SdTransferable
* pDragTransferable
= SdModule::get()->pTransferDrag
;
697 const Point
aEventModelPosition (
698 pTargetWindow
->PixelToLogic (rEvent
.maPosPixel
));
699 const sal_Int32
nXOffset (std::abs (pDragTransferable
->GetStartPos().X()
700 - aEventModelPosition
.X()));
701 const sal_Int32
nYOffset (std::abs (pDragTransferable
->GetStartPos().Y()
702 - aEventModelPosition
.Y()));
704 ( pDragTransferable
->GetView() != &mrSlideSorter
.GetView() )
705 || ( nXOffset
>= 2 && nYOffset
>= 2 );
707 std::shared_ptr
<InsertionIndicatorHandler
> pInsertionIndicatorHandler(
708 mrController
.GetInsertionIndicatorHandler());
709 // Get insertion position and then turn off the insertion indicator.
710 pInsertionIndicatorHandler
->UpdatePosition(aEventModelPosition
, rEvent
.mnAction
);
711 // sal_uInt16 nIndex = DetermineInsertPosition(*pDragTransferable);
713 // Do not process the insertion when it is trivial,
714 // i.e. would insert pages at their original place.
715 if (IsInsertionTrivial(pDragTransferable
, rEvent
.mnAction
))
718 // Tell the insertion indicator handler to hide before the model
719 // is modified. Doing it later may result in page objects whose
720 // animation state is not properly reset because they are then
721 // in another run then before the model change.
722 pInsertionIndicatorHandler
->End(Animator::AM_Immediate
);
726 SlideSorterController::ModelChangeLock
aModelChangeLock (mrController
);
728 // Handle a general drop operation.
729 mxUndoContext
.reset(new UndoContext (
730 mrSlideSorter
.GetModel().GetDocument(),
731 mrSlideSorter
.GetViewShell()->GetViewShellBase().GetMainViewShell()));
732 mxSelectionObserverContext
.reset(new SelectionObserver::Context(mrSlideSorter
));
734 if (rEvent
.mnAction
== DND_ACTION_MOVE
)
736 SdDrawDocument
* pDoc
= mrSlideSorter
.GetModel().GetDocument();
737 const bool bDoesMakePageObjectsNamesUnique
= pDoc
->DoesMakePageObjectsNamesUnique();
738 pDoc
->DoMakePageObjectsNamesUnique(false);
739 HandlePageDrop(*pDragTransferable
);
740 pDoc
->DoMakePageObjectsNamesUnique(bDoesMakePageObjectsNamesUnique
);
743 HandlePageDrop(*pDragTransferable
);
745 nResult
= rEvent
.mnAction
;
747 // We leave the undo context alive for when moving or
748 // copying inside one view then the actions in
749 // NotifyDragFinished should be covered as well as
750 // well as the ones above.
753 // When the pages originated in another slide sorter then
754 // only that is notified automatically about the drag
755 // operation being finished. Because the target slide sorter
756 // has be notified, too, add a callback for that.
757 std::shared_ptr
<TransferableData
> pSlideSorterTransferable (
758 TransferableData::GetFromTransferable(pDragTransferable
));
759 assert(pSlideSorterTransferable
);
760 if (pSlideSorterTransferable
761 && pSlideSorterTransferable
->GetSourceViewShell() != mrSlideSorter
.GetViewShell())
763 DragFinished(nResult
);
766 // Notify the receiving selection function that drag-and-drop is
767 // finished and the substitution handler can be released.
768 ::rtl::Reference
<SelectionFunction
> pFunction (
769 mrController
.GetCurrentSelectionFunction());
771 pFunction
->NotifyDragFinished();
776 nResult
= ExecuteOrAcceptShapeDrop(
794 bool Clipboard::IsInsertionTrivial (
795 SdTransferable
const * pTransferable
,
796 const sal_Int8 nDndAction
) const
798 std::shared_ptr
<TransferableData
> pSlideSorterTransferable (
799 TransferableData::GetFromTransferable(pTransferable
));
800 if (pSlideSorterTransferable
801 && pSlideSorterTransferable
->GetSourceViewShell() != mrSlideSorter
.GetViewShell())
803 return mrController
.GetInsertionIndicatorHandler()->IsInsertionTrivial(nDndAction
);
806 void Clipboard::Abort()
808 if (mxSelectionObserverContext
)
810 mxSelectionObserverContext
->Abort();
811 mxSelectionObserverContext
.reset();
815 sal_uInt16
Clipboard::DetermineInsertPosition ()
817 // Tell the model to move the dragged pages behind the one with the
818 // index nInsertionIndex which first has to be transformed into an index
819 // understandable by the document.
820 const sal_Int32
nInsertionIndex (
821 mrController
.GetInsertionIndicatorHandler()->GetInsertionPageIndex());
823 // Convert to insertion index to that of an SdModel.
824 if (nInsertionIndex
>= 0)
825 return mrSlideSorter
.GetModel().GetCoreIndex(nInsertionIndex
);
830 Clipboard::DropType
Clipboard::IsDropAccepted() const
832 const SdTransferable
* pDragTransferable
= SdModule::get()->pTransferDrag
;
833 if (pDragTransferable
== nullptr)
836 if (pDragTransferable
->IsPageTransferable())
838 if (mrSlideSorter
.GetModel().GetEditMode() != EditMode::MasterPage
)
844 const SdPageObjsTLV::SdPageObjsTransferable
* pPageObjsTransferable
845 = dynamic_cast<const SdPageObjsTLV::SdPageObjsTransferable
*>(pDragTransferable
);
846 if (pPageObjsTransferable
!= nullptr)
847 return DT_PAGE_FROM_NAVIGATOR
;
852 sal_Int8
Clipboard::ExecuteOrAcceptShapeDrop (
853 DropCommand eCommand
,
854 const Point
& rPosition
,
855 const void* pDropEvent
,
856 DropTargetHelper
& rTargetHelper
,
857 ::sd::Window
* pTargetWindow
,
861 sal_Int8 nResult
= 0;
863 // The dropping of a shape is accepted or executed only when there is
864 // DrawViewShell available to which we can forward this call. This has
865 // technical reasons: The actual code to accept or execute a shape drop
866 // is implemented in the ViewShell class and uses the page view of the
867 // main edit view. This is not possible without a DrawViewShell.
868 std::shared_ptr
<DrawViewShell
> pDrawViewShell
;
869 if (mrSlideSorter
.GetViewShell() != nullptr)
870 pDrawViewShell
= std::dynamic_pointer_cast
<DrawViewShell
>(
871 mrSlideSorter
.GetViewShell()->GetViewShellBase().GetMainViewShell());
872 if (pDrawViewShell
!= nullptr
873 && (pDrawViewShell
->GetShellType() == ViewShell::ST_IMPRESS
874 || pDrawViewShell
->GetShellType() == ViewShell::ST_DRAW
))
876 // The drop is only accepted or executed when it takes place over a
877 // page object. Therefore we replace a missing page number by the
878 // number of the page under the mouse.
879 if (nPage
== SDRPAGE_NOTFOUND
)
881 model::SharedPageDescriptor
pDescriptor (
882 mrSlideSorter
.GetModel().GetPageDescriptor(
883 mrSlideSorter
.GetView().GetPageIndexAtPoint(rPosition
)));
885 nPage
= pDescriptor
->GetPageIndex();
888 // Now comes the code that is different for the Execute and Accept:
889 // We simply forward the call to the AcceptDrop() or ExecuteDrop()
890 // methods of the DrawViewShell in the center pane.
891 if (nPage
!= SDRPAGE_NOTFOUND
)
895 nResult
= pDrawViewShell
->AcceptDrop(
896 *static_cast<const AcceptDropEvent
*>(pDropEvent
),
904 nResult
= pDrawViewShell
->ExecuteDrop(
905 *static_cast<const ExecuteDropEvent
*>(pDropEvent
),
917 } // end of namespace ::sd::slidesorter::controller
919 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */