bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / slidesorter / controller / SlsClipboard.cxx
blob7dfc356a77b11e45ee72e49f29082f55b0280165
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 "glob.hrc"
54 #include "strings.hrc"
55 #include "sdresid.hxx"
56 #include "sdxfer.hxx"
57 #include "sdmod.hxx"
58 #include "ins_paste.hxx"
59 #include "drawdoc.hxx"
60 #include "DrawDocShell.hxx"
61 #include "sdpage.hxx"
62 #include "sdtreelb.hxx"
64 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
65 #include <sfx2/request.hxx>
66 #include <sfx2/viewfrm.hxx>
67 #include <sfx2/bindings.hxx>
68 #include <sfx2/docfile.hxx>
69 #include <svx/svxids.hrc>
70 #include <svx/svdstr.hrc>
71 #include <vcl/msgbox.hxx>
72 #include <tools/urlobj.hxx>
73 #include <rtl/ustring.hxx>
74 #include <osl/mutex.hxx>
75 #include <vcl/svapp.hxx>
76 #include <boost/bind.hpp>
78 namespace sd { namespace slidesorter { namespace controller {
80 namespace {
81 /** Temporarily deactivate slide tracking of the VisibleAreaManager.
82 This is used as a workaround to avoid unwanted repositioning of
83 the visible area when the selection of slides is copied to the
84 clipboard (cloning of slides leads to model change notifications
85 for the original model.)
87 class TemporarySlideTrackingDeactivator
89 public:
90 TemporarySlideTrackingDeactivator (SlideSorterController& rController)
91 : mrController(rController),
92 mbIsCurrentSlideTrackingActive (
93 mrController.GetVisibleAreaManager().IsCurrentSlideTrackingActive())
95 if (mbIsCurrentSlideTrackingActive)
96 mrController.GetVisibleAreaManager().DeactivateCurrentSlideTracking();
98 ~TemporarySlideTrackingDeactivator()
100 if (mbIsCurrentSlideTrackingActive)
101 mrController.GetVisibleAreaManager().ActivateCurrentSlideTracking();
104 private:
105 SlideSorterController& mrController;
106 const bool mbIsCurrentSlideTrackingActive;
108 } // end of anonymous namespace
110 class Clipboard::UndoContext
112 public:
113 UndoContext (
114 SdDrawDocument* pDocument,
115 const ::boost::shared_ptr<ViewShell>& rpMainViewShell)
116 : mpDocument(pDocument),
117 mpMainViewShell(rpMainViewShell)
119 if (mpDocument!=NULL && mpDocument->IsUndoEnabled())
121 if (mpMainViewShell && mpMainViewShell->GetShellType() == ViewShell::ST_DRAW)
122 mpDocument->BegUndo(SD_RESSTR(STRING_DRAG_AND_DROP_PAGES));
123 else
124 mpDocument->BegUndo(SD_RESSTR(STRING_DRAG_AND_DROP_SLIDES));
128 ~UndoContext()
130 if (mpDocument!=NULL && mpDocument->IsUndoEnabled())
131 mpDocument->EndUndo();
132 if (mpMainViewShell && mpMainViewShell->GetViewFrame()!=NULL)
134 SfxBindings& rBindings = mpMainViewShell->GetViewFrame()->GetBindings();
135 rBindings.Invalidate(SID_UNDO);
136 rBindings.Invalidate(SID_REDO);
139 private:
140 SdDrawDocument* mpDocument;
141 ::boost::shared_ptr<ViewShell> mpMainViewShell;
144 Clipboard::Clipboard (SlideSorter& rSlideSorter)
145 : ViewClipboard(rSlideSorter.GetView()),
146 mrSlideSorter(rSlideSorter),
147 mrController(mrSlideSorter.GetController()),
148 maPagesToRemove(),
149 maPagesToSelect(),
150 mbUpdateSelectionPending(false),
151 mxUndoContext(),
152 mxSelectionObserverContext(),
153 mnDragFinishedUserEventId(0)
157 Clipboard::~Clipboard()
159 if (mnDragFinishedUserEventId != 0)
160 Application::RemoveUserEvent(mnDragFinishedUserEventId);
163 /** With the current implementation the forwarded calls to the current
164 function will come back eventually to call the local Do(Cut|Copy|Paste)
165 methods. A shortcut is possible but would be an unclean hack.
167 void Clipboard::HandleSlotCall (SfxRequest& rRequest)
169 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
170 rtl::Reference<FuPoor> xFunc;
171 if (pViewShell != NULL)
172 xFunc = pViewShell->GetCurrentFunction();
173 switch (rRequest.GetSlot())
175 case SID_CUT:
176 if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE)
178 if(xFunc.is())
179 xFunc->DoCut();
180 else
181 DoCut();
183 rRequest.Done();
184 break;
186 case SID_COPY:
187 if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE)
189 if(xFunc.is())
190 xFunc->DoCopy();
191 else
192 DoCopy();
194 rRequest.Done();
195 break;
197 case SID_PASTE:
198 // Prevent redraws while inserting pages from the clipboard
199 // because the intermediate inconsistent state might lead to
200 // a crash.
201 if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE)
203 view::SlideSorterView::DrawLock aLock (mrSlideSorter);
204 SelectionObserver::Context aContext (mrSlideSorter);
205 if(xFunc.is())
206 xFunc->DoPaste();
207 else
208 DoPaste();
210 rRequest.Done();
211 break;
213 case SID_DELETE:
214 DoDelete();
215 rRequest.Done();
216 break;
220 void Clipboard::DoCut (vcl::Window* pWindow)
222 if (mrSlideSorter.GetModel().GetPageCount() > 1)
224 DoCopy(pWindow);
225 DoDelete(pWindow);
229 void Clipboard::DoDelete (vcl::Window* )
231 if (mrSlideSorter.GetModel().GetPageCount() > 1)
233 mrController.GetSelectionManager()->DeleteSelectedPages();
237 void Clipboard::DoCopy (vcl::Window* pWindow )
239 CreateSlideTransferable( pWindow, false );
242 void Clipboard::DoPaste (vcl::Window* pWindow)
244 SdTransferable* pClipTransferable = SD_MOD()->pTransferClip;
246 if (pClipTransferable!=NULL && pClipTransferable->IsPageTransferable())
248 sal_Int32 nInsertPosition = GetInsertionPosition(pWindow);
250 if (nInsertPosition >= 0)
252 // Paste the pages from the clipboard.
253 sal_Int32 nInsertPageCount = PasteTransferable(nInsertPosition);
254 // Select the pasted pages and make the first of them the
255 // current page.
256 mrSlideSorter.GetContentWindow()->GrabFocus();
257 SelectPageRange(nInsertPosition, nInsertPageCount);
262 sal_Int32 Clipboard::GetInsertionPosition (vcl::Window* pWindow)
264 sal_Int32 nInsertPosition = -1;
266 // Determine the insertion position:
267 // a) When the insertion indicator is visible, then at that position.
268 // b) When the focus indicator is visible, then before or after the
269 // focused page, depending on user input to a dialog.
270 // c) When there is a selection but no focus, then after the
271 // selection.
272 // d) After the last page when there is no selection and no focus.
274 ::boost::shared_ptr<controller::InsertionIndicatorHandler> pInsertionIndicatorHandler (
275 mrController.GetInsertionIndicatorHandler());
276 if (pInsertionIndicatorHandler->IsActive())
278 // Use the insertion index of an active insertion indicator.
279 nInsertPosition = pInsertionIndicatorHandler->GetInsertionPageIndex();
281 else if (mrController.GetSelectionManager()->GetInsertionPosition() >= 0)
283 // Use the insertion index of an insertion indicator that has been
284 // deactivated a short while ago.
285 nInsertPosition = mrController.GetSelectionManager()->GetInsertionPosition();
287 else if (mrController.GetFocusManager().IsFocusShowing())
289 // Use the focus to determine the insertion position.
290 ScopedVclPtrInstance< SdInsertPasteDlg > aDialog(pWindow);
291 if (aDialog->Execute() == RET_OK)
293 nInsertPosition = mrController.GetFocusManager().GetFocusedPageIndex();
294 if ( ! aDialog->IsInsertBefore())
295 nInsertPosition ++;
299 return nInsertPosition;
302 sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition)
304 SdTransferable* pClipTransferable = SD_MOD()->pTransferClip;
305 model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
306 bool bMergeMasterPages = !pClipTransferable->HasSourceDoc (rModel.GetDocument());
307 sal_uInt16 nInsertIndex (rModel.GetCoreIndex(nInsertPosition));
308 sal_Int32 nInsertPageCount (0);
309 if (pClipTransferable->HasPageBookmarks())
311 const std::vector<OUString> &rBookmarkList = pClipTransferable->GetPageBookmarks();
312 const SolarMutexGuard aGuard;
314 nInsertPageCount = (sal_uInt16) rBookmarkList.size();
315 rModel.GetDocument()->InsertBookmarkAsPage(
316 rBookmarkList,
317 NULL,
318 false,
319 false,
320 nInsertIndex,
321 false,
322 pClipTransferable->GetPageDocShell(),
323 true,
324 bMergeMasterPages,
325 false);
327 else
329 SfxObjectShell* pShell = pClipTransferable->GetDocShell();
330 DrawDocShell* pDataDocSh = static_cast<DrawDocShell*>(pShell);
331 SdDrawDocument* pDataDoc = pDataDocSh->GetDoc();
333 if (pDataDoc!=NULL
334 && pDataDoc->GetSdPageCount(PK_STANDARD))
336 const SolarMutexGuard aGuard;
338 bMergeMasterPages = (pDataDoc != rModel.GetDocument());
339 nInsertPageCount = pDataDoc->GetSdPageCount( PK_STANDARD );
340 rModel.GetDocument()->InsertBookmarkAsPage(
341 std::vector<OUString>(),
342 NULL,
343 false,
344 false,
345 nInsertIndex,
346 false,
347 pDataDocSh,
348 true,
349 bMergeMasterPages,
350 false);
353 mrController.HandleModelChange();
354 return nInsertPageCount;
357 void Clipboard::SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount)
359 // Select the newly inserted pages. That are the nInsertPageCount pages
360 // after the nInsertIndex position.
361 PageSelector& rSelector (mrController.GetPageSelector());
362 rSelector.DeselectAllPages();
363 for (sal_uInt16 i=0; i<nPageCount; i++)
365 model::SharedPageDescriptor pDescriptor (
366 mrSlideSorter.GetModel().GetPageDescriptor(nFirstIndex + i));
367 if (pDescriptor.get() != NULL)
369 rSelector.SelectPage(pDescriptor);
370 // The first page of the new selection is made the current page.
371 if (i == 0)
373 mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor);
379 void Clipboard::CreateSlideTransferable (
380 vcl::Window* pWindow,
381 bool bDrag)
383 std::vector<OUString> aBookmarkList;
385 // Insert all selected pages into a bookmark list and remember them in
386 // maPagesToRemove for possible later removal.
387 model::PageEnumeration aSelectedPages
388 (model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
389 mrSlideSorter.GetModel()));
390 while (aSelectedPages.HasMoreElements())
392 model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
393 aBookmarkList.push_back(pDescriptor->GetPage()->GetName());
394 maPagesToRemove.push_back (pDescriptor->GetPage());
397 // Create a small set of representatives of the selection for which
398 // previews are included into the transferable so that an insertion
399 // indicator can be rendered.
400 aSelectedPages.Rewind();
401 ::std::vector<TransferableData::Representative> aRepresentatives;
402 aRepresentatives.reserve(3);
403 ::boost::shared_ptr<cache::PageCache> pPreviewCache (
404 mrSlideSorter.GetView().GetPreviewCache());
405 while (aSelectedPages.HasMoreElements())
407 model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
408 if ( ! pDescriptor || pDescriptor->GetPage()==NULL)
409 continue;
410 Bitmap aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false));
411 aRepresentatives.push_back(TransferableData::Representative(
412 aPreview,
413 pDescriptor->HasState(model::PageDescriptor::ST_Excluded)));
414 if (aRepresentatives.size() >= 3)
415 break;
418 if (!aBookmarkList.empty())
420 mrSlideSorter.GetView().BrkAction();
421 SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
422 SdTransferable* pTransferable = TransferableData::CreateTransferable (
423 pDocument,
424 NULL,
425 false,
426 dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()),
427 aRepresentatives);
429 if (bDrag)
430 SD_MOD()->pTransferDrag = pTransferable;
431 else
432 SD_MOD()->pTransferClip = pTransferable;
434 pDocument->CreatingDataObj (pTransferable);
435 pTransferable->SetWorkDocument(pDocument->AllocSdDrawDocument());
436 pDocument->CreatingDataObj (NULL);
437 TransferableObjectDescriptor aObjDesc;
438 pTransferable->GetWorkDocument()->GetDocSh()
439 ->FillTransferableObjectDescriptor (aObjDesc);
441 if (pDocument->GetDocSh() != NULL)
442 aObjDesc.maDisplayName = pDocument->GetDocSh()
443 ->GetMedium()->GetURLObject().GetURLNoPass();
445 vcl::Window* pActionWindow = pWindow;
446 if (pActionWindow == NULL)
448 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
449 if (pViewShell != NULL)
450 pActionWindow = pViewShell->GetActiveWindow();
453 pTransferable->SetStartPos (pActionWindow->PixelToLogic(
454 pActionWindow->GetPointerPosPixel()));
455 pTransferable->SetObjectDescriptor (aObjDesc);
458 TemporarySlideTrackingDeactivator aDeactivator (mrController);
459 pTransferable->SetPageBookmarks (aBookmarkList, !bDrag);
462 if (bDrag)
464 pTransferable->SetView (&mrSlideSorter.GetView());
465 pTransferable->StartDrag (pActionWindow, DND_ACTION_COPY | DND_ACTION_MOVE);
467 else
468 pTransferable->CopyToClipboard (pActionWindow);
472 ::boost::shared_ptr<SdTransferable::UserData> Clipboard::CreateTransferableUserData (SdTransferable* pTransferable)
476 SdPageObjsTLB::SdPageObjsTransferable* pTreeListBoxTransferable
477 = dynamic_cast<SdPageObjsTLB::SdPageObjsTransferable*>(pTransferable);
478 if (pTreeListBoxTransferable == NULL)
479 break;
481 // Find view shell for the document of the transferable.
482 ::sd::ViewShell* pViewShell
483 = SdPageObjsTLB::GetViewShellForDocShell(pTreeListBoxTransferable->GetDocShell());
484 if (pViewShell == NULL)
485 break;
487 // Find slide sorter for the document of the transferable.
488 SlideSorterViewShell* pSlideSorterViewShell
489 = SlideSorterViewShell::GetSlideSorter(pViewShell->GetViewShellBase());
490 if (pSlideSorterViewShell == NULL)
491 break;
492 SlideSorter& rSlideSorter (pSlideSorterViewShell->GetSlideSorter());
494 // Get bookmark from transferable.
495 TransferableDataHelper aDataHelper (pTransferable);
496 INetBookmark aINetBookmark;
497 if ( ! aDataHelper.GetINetBookmark(SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark))
498 break;
499 const OUString sURL (aINetBookmark.GetURL());
500 const sal_Int32 nIndex (sURL.indexOf((sal_Unicode)'#'));
501 if (nIndex == -1)
502 break;
503 OUString sBookmark (sURL.copy(nIndex+1));
505 // Make sure that the bookmark points to a page.
506 SdDrawDocument* pTransferableDocument = rSlideSorter.GetModel().GetDocument();
507 if (pTransferableDocument == NULL)
508 break;
509 bool bIsMasterPage = false;
510 const sal_uInt16 nPageIndex (pTransferableDocument->GetPageByName(sBookmark, bIsMasterPage));
511 if (nPageIndex == SDRPAGE_NOTFOUND)
512 break;
514 // Create preview.
515 ::std::vector<TransferableData::Representative> aRepresentatives;
516 aRepresentatives.reserve(1);
517 ::boost::shared_ptr<cache::PageCache> pPreviewCache (
518 rSlideSorter.GetView().GetPreviewCache());
519 model::SharedPageDescriptor pDescriptor (rSlideSorter.GetModel().GetPageDescriptor((nPageIndex-1)/2));
520 if ( ! pDescriptor || pDescriptor->GetPage()==NULL)
521 break;
522 Bitmap aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false));
523 aRepresentatives.push_back(TransferableData::Representative(
524 aPreview,
525 pDescriptor->HasState(model::PageDescriptor::ST_Excluded)));
527 // Remember the page in maPagesToRemove so that it can be removed
528 // when drag and drop action is "move".
529 Clipboard& rOtherClipboard (pSlideSorterViewShell->GetSlideSorter().GetController().GetClipboard());
530 rOtherClipboard.maPagesToRemove.clear();
531 rOtherClipboard.maPagesToRemove.push_back(pDescriptor->GetPage());
533 // Create the new transferable.
534 ::boost::shared_ptr<SdTransferable::UserData> pNewTransferable (
535 new TransferableData(
536 pSlideSorterViewShell,
537 aRepresentatives));
538 pTransferable->SetWorkDocument(pTreeListBoxTransferable->GetSourceDoc()->AllocSdDrawDocument());
539 // pTransferable->SetView(&mrSlideSorter.GetView());
541 // Set page bookmark list.
542 std::vector<OUString> aPageBookmarks;
543 aPageBookmarks.push_back(sBookmark);
544 pTransferable->SetPageBookmarks(aPageBookmarks, false);
546 // Replace the view referenced by the transferable with the
547 // corresponding slide sorter view.
548 pTransferable->SetView(&pSlideSorterViewShell->GetSlideSorter().GetView());
550 return pNewTransferable;
552 while (false);
554 return ::boost::shared_ptr<SdTransferable::UserData>();
557 void Clipboard::StartDrag (
558 const Point& rPosition,
559 vcl::Window* pWindow)
561 maPagesToRemove.clear();
562 maPagesToSelect.clear();
563 mbUpdateSelectionPending = false;
564 CreateSlideTransferable(pWindow, true);
566 mrController.GetInsertionIndicatorHandler()->UpdatePosition(
567 rPosition,
568 InsertionIndicatorHandler::UnknownMode);
571 void Clipboard::DragFinished (sal_Int8 nDropAction)
573 if (mnDragFinishedUserEventId == 0)
575 mnDragFinishedUserEventId = Application::PostUserEvent(
576 LINK(this, Clipboard, ProcessDragFinished),
577 reinterpret_cast<void*>(nDropAction));
581 IMPL_LINK(Clipboard, ProcessDragFinished, void*, pUserData)
583 const sal_Int8 nDropAction (static_cast<sal_Int8>(reinterpret_cast<sal_IntPtr>(pUserData)));
585 mnDragFinishedUserEventId = 0;
587 // Hide the substitution display and insertion indicator.
588 ::rtl::Reference<SelectionFunction> pFunction (mrController.GetCurrentSelectionFunction());
589 if (pFunction.is())
590 pFunction->NotifyDragFinished();
592 PageSelector& rSelector (mrController.GetPageSelector());
593 if ((nDropAction & DND_ACTION_MOVE) != 0
594 && ! maPagesToRemove.empty())
596 // Remove the pages that have been moved to another place (possibly
597 // in the same document.)
598 rSelector.DeselectAllPages();
599 PageList::iterator aDraggedPage;
600 for (aDraggedPage=maPagesToRemove.begin();
601 aDraggedPage!=maPagesToRemove.end();
602 ++aDraggedPage)
604 rSelector.SelectPage(*aDraggedPage);
606 mrController.GetSelectionManager()->DeleteSelectedPages();
608 mxUndoContext.reset();
609 mxSelectionObserverContext.reset();
611 return 1;
614 sal_Int8 Clipboard::AcceptDrop (
615 const AcceptDropEvent& rEvent,
616 DropTargetHelper& rTargetHelper,
617 ::sd::Window* pTargetWindow,
618 sal_uInt16 nPage,
619 sal_uInt16 nLayer)
621 sal_Int8 nAction (DND_ACTION_NONE);
623 const Clipboard::DropType eDropType (IsDropAccepted(rTargetHelper));
625 switch (eDropType)
627 case DT_PAGE:
628 case DT_PAGE_FROM_NAVIGATOR:
630 // Accept a drop.
631 nAction = rEvent.mnAction;
633 // Use the copy action when the drop action is the default, i.e. not
634 // explicitly set to move or link, and when the source and
635 // target models are not the same.
636 SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
637 if (pDragTransferable != NULL
638 && pDragTransferable->IsPageTransferable()
639 && ((rEvent.maDragEvent.DropAction
640 & ::com::sun::star::datatransfer::dnd::DNDConstants::ACTION_DEFAULT) != 0)
641 && (mrSlideSorter.GetModel().GetDocument()->GetDocSh()
642 != pDragTransferable->GetPageDocShell()))
644 nAction = DND_ACTION_COPY;
646 else if (IsInsertionTrivial(pDragTransferable, nAction))
648 nAction = DND_ACTION_NONE;
651 // Show the insertion marker and the substitution for a drop.
652 SelectionFunction* pSelectionFunction = dynamic_cast<SelectionFunction*>(
653 mrSlideSorter.GetViewShell()->GetCurrentFunction().get());
654 if (pSelectionFunction != NULL)
655 pSelectionFunction->MouseDragged(rEvent, nAction);
657 // Scroll the window when the mouse reaches the window border.
658 // mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel);
660 break;
662 case DT_SHAPE:
663 nAction = ExecuteOrAcceptShapeDrop(
664 DC_ACCEPT,
665 rEvent.maPosPixel,
666 &rEvent,
667 rTargetHelper,
668 pTargetWindow,
669 nPage,
670 nLayer);
671 break;
673 default:
674 case DT_NONE:
675 nAction = DND_ACTION_NONE;
676 break;
679 return nAction;
682 sal_Int8 Clipboard::ExecuteDrop (
683 const ExecuteDropEvent& rEvent,
684 DropTargetHelper& rTargetHelper,
685 ::sd::Window* pTargetWindow,
686 sal_uInt16 nPage,
687 sal_uInt16 nLayer)
689 sal_Int8 nResult = DND_ACTION_NONE;
690 mxUndoContext.reset();
691 const Clipboard::DropType eDropType (IsDropAccepted(rTargetHelper));
693 switch (eDropType)
695 case DT_PAGE:
696 case DT_PAGE_FROM_NAVIGATOR:
698 SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
699 const Point aEventModelPosition (
700 pTargetWindow->PixelToLogic (rEvent.maPosPixel));
701 const sal_Int32 nXOffset (labs (pDragTransferable->GetStartPos().X()
702 - aEventModelPosition.X()));
703 const sal_Int32 nYOffset (labs (pDragTransferable->GetStartPos().Y()
704 - aEventModelPosition.Y()));
705 bool bContinue =
706 ( pDragTransferable->GetView() != &mrSlideSorter.GetView() )
707 || ( nXOffset >= 2 && nYOffset >= 2 );
709 ::boost::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler(
710 mrController.GetInsertionIndicatorHandler());
711 // Get insertion position and then turn off the insertion indicator.
712 pInsertionIndicatorHandler->UpdatePosition(aEventModelPosition, rEvent.mnAction);
713 // sal_uInt16 nIndex = DetermineInsertPosition(*pDragTransferable);
715 // Do not process the insertion when it is trivial,
716 // i.e. would insert pages at their original place.
717 if (IsInsertionTrivial(pDragTransferable, rEvent.mnAction))
718 bContinue = false;
720 // Tell the insertion indicator handler to hide before the model
721 // is modified. Doing it later may result in page objects whose
722 // animation state is not properly reset because they are then
723 // in another run then before the model change.
724 pInsertionIndicatorHandler->End(Animator::AM_Immediate);
726 if (bContinue)
728 SlideSorterController::ModelChangeLock aModelChangeLock (mrController);
730 // Handle a general drop operation.
731 mxUndoContext.reset(new UndoContext (
732 mrSlideSorter.GetModel().GetDocument(),
733 mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell()));
734 mxSelectionObserverContext.reset(new SelectionObserver::Context(mrSlideSorter));
736 HandlePageDrop(*pDragTransferable);
737 nResult = rEvent.mnAction;
739 // We leave the undo context alive for when moving or
740 // copying inside one view then the actions in
741 // NotifyDragFinished should be covered as well as
742 // well as the ones above.
745 // When the pages originated in another slide sorter then
746 // only that is notified automatically about the drag
747 // operation being finished. Because the target slide sorter
748 // has be notified, too, add a callback for that.
749 ::boost::shared_ptr<TransferableData> pSlideSorterTransferable (
750 TransferableData::GetFromTransferable(pDragTransferable));
751 BOOST_ASSERT(pSlideSorterTransferable);
752 if (pSlideSorterTransferable
753 && pSlideSorterTransferable->GetSourceViewShell() != mrSlideSorter.GetViewShell())
755 DragFinished(nResult);
758 // Notify the receiving selection function that drag-and-drop is
759 // finished and the substitution handler can be released.
760 ::rtl::Reference<SelectionFunction> pFunction (
761 mrController.GetCurrentSelectionFunction());
762 if (pFunction.is())
763 pFunction->NotifyDragFinished();
765 break;
767 case DT_SHAPE:
768 nResult = ExecuteOrAcceptShapeDrop(
769 DC_EXECUTE,
770 rEvent.maPosPixel,
771 &rEvent,
772 rTargetHelper,
773 pTargetWindow,
774 nPage,
775 nLayer);
776 break;
778 default:
779 case DT_NONE:
780 break;
783 return nResult;
786 bool Clipboard::IsInsertionTrivial (
787 SdTransferable* pTransferable,
788 const sal_Int8 nDndAction) const
790 ::boost::shared_ptr<TransferableData> pSlideSorterTransferable (
791 TransferableData::GetFromTransferable(pTransferable));
792 if (pSlideSorterTransferable
793 && pSlideSorterTransferable->GetSourceViewShell() != mrSlideSorter.GetViewShell())
794 return false;
795 return mrController.GetInsertionIndicatorHandler()->IsInsertionTrivial(nDndAction);
798 void Clipboard::Abort()
800 if (mxSelectionObserverContext)
802 mxSelectionObserverContext->Abort();
803 mxSelectionObserverContext.reset();
807 sal_uInt16 Clipboard::DetermineInsertPosition (const SdTransferable& )
809 // Tell the model to move the dragged pages behind the one with the
810 // index nInsertionIndex which first has to be transformed into an index
811 // understandable by the document.
812 const sal_Int32 nInsertionIndex (
813 mrController.GetInsertionIndicatorHandler()->GetInsertionPageIndex());
815 // Convert to insertion index to that of an SdModel.
816 if (nInsertionIndex >= 0)
817 return mrSlideSorter.GetModel().GetCoreIndex(nInsertionIndex);
818 else
819 return 0;
822 sal_uInt16 Clipboard::InsertSlides (
823 const SdTransferable& rTransferable,
824 sal_uInt16 nInsertPosition)
826 sal_uInt16 nInsertedPageCount = ViewClipboard::InsertSlides (
827 rTransferable,
828 nInsertPosition);
830 // Remember the inserted pages so that they can be selected when the
831 // operation is finished.
832 maPagesToSelect.clear();
833 SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
834 if (pDocument != NULL)
835 for (sal_Int32 i=0; i<=nInsertedPageCount; i+=2)
836 maPagesToSelect.push_back(
837 dynamic_cast<SdPage*>(pDocument->GetPage(nInsertPosition+i)));
839 mbUpdateSelectionPending |= (nInsertedPageCount>0);
841 return nInsertedPageCount;
844 Clipboard::DropType Clipboard::IsDropAccepted (DropTargetHelper&) const
846 const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
847 if (pDragTransferable == NULL)
848 return DT_NONE;
850 if (pDragTransferable->IsPageTransferable())
852 if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE)
853 return DT_PAGE;
854 else
855 return DT_NONE;
858 const SdPageObjsTLB::SdPageObjsTransferable* pPageObjsTransferable
859 = dynamic_cast<const SdPageObjsTLB::SdPageObjsTransferable*>(pDragTransferable);
860 if (pPageObjsTransferable != NULL)
861 return DT_PAGE_FROM_NAVIGATOR;
863 return DT_SHAPE;
866 sal_Int8 Clipboard::ExecuteOrAcceptShapeDrop (
867 DropCommand eCommand,
868 const Point& rPosition,
869 const void* pDropEvent,
870 DropTargetHelper& rTargetHelper,
871 ::sd::Window* pTargetWindow,
872 sal_uInt16 nPage,
873 sal_uInt16 nLayer)
875 sal_Int8 nResult = 0;
877 // The dropping of a shape is accepted or executed only when there is
878 // DrawViewShell available to which we can forward this call. This has
879 // technical reasons: The actual code to accept or execute a shape drop
880 // is implemented in the ViewShell class and uses the page view of the
881 // main edit view. This is not possible without a DrawViewShell.
882 ::boost::shared_ptr<DrawViewShell> pDrawViewShell;
883 if (mrSlideSorter.GetViewShell() != NULL)
884 pDrawViewShell = ::boost::dynamic_pointer_cast<DrawViewShell>(
885 mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell());
886 if (pDrawViewShell.get() != NULL
887 && (pDrawViewShell->GetShellType() == ViewShell::ST_IMPRESS
888 || pDrawViewShell->GetShellType() == ViewShell::ST_DRAW))
890 // The drop is only accepted or executed when it takes place over a
891 // page object. Therefore we replace a missing page number by the
892 // number of the page under the mouse.
893 if (nPage == SDRPAGE_NOTFOUND)
895 model::SharedPageDescriptor pDescriptor (
896 mrSlideSorter.GetModel().GetPageDescriptor(
897 mrSlideSorter.GetView().GetPageIndexAtPoint(rPosition)));
898 if (pDescriptor)
899 nPage = pDescriptor->GetPageIndex();
902 // Now comes the code that is different for the Execute and Accept:
903 // We simply forward the call to the AcceptDrop() or ExecuteDrop()
904 // methods of the DrawViewShell in the center pane.
905 if (nPage != SDRPAGE_NOTFOUND)
906 switch (eCommand)
908 case DC_ACCEPT:
909 nResult = pDrawViewShell->AcceptDrop(
910 *static_cast<const AcceptDropEvent*>(pDropEvent),
911 rTargetHelper,
912 pTargetWindow,
913 nPage,
914 nLayer);
915 break;
917 case DC_EXECUTE:
918 nResult = pDrawViewShell->ExecuteDrop(
919 *static_cast<const ExecuteDropEvent*>(pDropEvent),
920 rTargetHelper,
921 pTargetWindow,
922 nPage,
923 nLayer);
924 break;
928 return nResult;
931 } } } // end of namespace ::sd::slidesorter::controller
933 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */