xref: /trunk/main/sd/source/ui/slidesorter/controller/SlsClipboard.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "precompiled_sd.hxx"
29 
30 #include "controller/SlsClipboard.hxx"
31 
32 #include "SlideSorterViewShell.hxx"
33 #include "SlideSorter.hxx"
34 #include "model/SlideSorterModel.hxx"
35 #include "model/SlsPageDescriptor.hxx"
36 #include "model/SlsPageEnumerationProvider.hxx"
37 #include "view/SlideSorterView.hxx"
38 #include "view/SlsTheme.hxx"
39 #include "controller/SlideSorterController.hxx"
40 #include "controller/SlsInsertionIndicatorHandler.hxx"
41 #include "controller/SlsPageSelector.hxx"
42 #include "controller/SlsSelectionFunction.hxx"
43 #include "controller/SlsCurrentSlideManager.hxx"
44 #include "controller/SlsScrollBarManager.hxx"
45 #include "controller/SlsFocusManager.hxx"
46 #include "controller/SlsSelectionManager.hxx"
47 #include "controller/SlsTransferableData.hxx"
48 #include "controller/SlsSelectionObserver.hxx"
49 #include "cache/SlsPageCache.hxx"
50 
51 #include "ViewShellBase.hxx"
52 #include "View.hxx"
53 #include "DrawViewShell.hxx"
54 #include "Window.hxx"
55 #include "fupoor.hxx"
56 #include "fuslhide.hxx"
57 #include "fuzoom.hxx"
58 #include "fucushow.hxx"
59 #include "fusldlg.hxx"
60 #include "fuexpand.hxx"
61 #include "fusumry.hxx"
62 #include "app.hrc"
63 #include "glob.hrc"
64 #include "strings.hrc"
65 #include "sdresid.hxx"
66 #include "sdxfer.hxx"
67 #include "sdmod.hxx"
68 #include "sddll.hxx"
69 #include "ins_paste.hxx"
70 #include "drawdoc.hxx"
71 #include "DrawDocShell.hxx"
72 #include "sdpage.hxx"
73 #include "sdtreelb.hxx"
74 
75 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
76 #include <sfx2/request.hxx>
77 #include <sfx2/viewfrm.hxx>
78 #include <sfx2/bindings.hxx>
79 #include <sfx2/docfile.hxx>
80 #include <svx/svxids.hrc>
81 #include <svx/svdstr.hrc>
82 #include <vcl/msgbox.hxx>
83 #include <tools/urlobj.hxx>
84 #include <rtl/ustring.hxx>
85 #include <vos/mutex.hxx>
86 #include <vcl/svapp.hxx>
87 #include <boost/bind.hpp>
88 
89 
90 namespace sd { namespace slidesorter { namespace controller {
91 
92 
93 class Clipboard::UndoContext
94 {
95 public:
96     UndoContext (
97         SdDrawDocument* pDocument,
98         const ::boost::shared_ptr<ViewShell>& rpMainViewShell,
99         const ::boost::shared_ptr<view::Theme>& rpTheme)
100         : mpDocument(pDocument),
101           mpMainViewShell(rpMainViewShell)
102     {
103         if (mpDocument!=NULL && mpDocument->IsUndoEnabled())
104         {
105             if (mpMainViewShell && mpMainViewShell->GetShellType() == ViewShell::ST_DRAW)
106                 mpDocument->BegUndo(rpTheme->GetString(view::Theme::String_DragAndDropPages));
107             else
108                 mpDocument->BegUndo(rpTheme->GetString(view::Theme::String_DragAndDropSlides));
109         }
110     }
111 
112     ~UndoContext (void)
113     {
114         if (mpDocument!=NULL && mpDocument->IsUndoEnabled())
115             mpDocument->EndUndo();
116         if (mpMainViewShell && mpMainViewShell->GetViewFrame()!=NULL)
117         {
118             SfxBindings& rBindings = mpMainViewShell->GetViewFrame()->GetBindings();
119             rBindings.Invalidate(SID_UNDO);
120             rBindings.Invalidate(SID_REDO);
121         }
122     }
123 private:
124     SdDrawDocument* mpDocument;
125     ::boost::shared_ptr<ViewShell> mpMainViewShell;
126 };
127 
128 
129 
130 
131 Clipboard::Clipboard (SlideSorter& rSlideSorter)
132     : ViewClipboard(rSlideSorter.GetView()),
133       mrSlideSorter(rSlideSorter),
134       mrController(mrSlideSorter.GetController()),
135       maPagesToRemove(),
136       maPagesToSelect(),
137       mbUpdateSelectionPending(false),
138       mpUndoContext(),
139       mpSelectionObserverContext(),
140       mnDragFinishedUserEventId(0)
141 {
142 }
143 
144 
145 
146 
147 Clipboard::~Clipboard (void)
148 {
149     if (mnDragFinishedUserEventId != 0)
150         Application::RemoveUserEvent(mnDragFinishedUserEventId);
151 }
152 
153 
154 
155 
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.
159 */
160 void Clipboard::HandleSlotCall (SfxRequest& rRequest)
161 {
162     ViewShell* pViewShell = mrSlideSorter.GetViewShell();
163     FunctionReference xFunc;
164     if (pViewShell != NULL)
165         xFunc = pViewShell->GetCurrentFunction();
166     switch (rRequest.GetSlot())
167     {
168         case SID_CUT:
169             if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE)
170             {
171                 if(xFunc.is())
172                     xFunc->DoCut();
173                 else
174                     DoCut();
175             }
176             rRequest.Done();
177             break;
178 
179         case SID_COPY:
180             if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE)
181             {
182                 if(xFunc.is())
183                     xFunc->DoCopy();
184                 else
185                     DoCopy();
186             }
187             rRequest.Done();
188             break;
189 
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() != EM_MASTERPAGE)
195             {
196                 view::SlideSorterView::DrawLock aLock (mrSlideSorter);
197                 SelectionObserver::Context aContext (mrSlideSorter);
198                 if(xFunc.is())
199                     xFunc->DoPaste();
200                 else
201                     DoPaste();
202             }
203             rRequest.Done();
204             break;
205 
206         case SID_DELETE:
207             DoDelete();
208             rRequest.Done();
209             break;
210     }
211 }
212 
213 
214 
215 
216 void Clipboard::DoCut (::Window* pWindow)
217 {
218     if (mrSlideSorter.GetModel().GetPageCount() > 1)
219     {
220         DoCopy(pWindow);
221         DoDelete(pWindow);
222     }
223 }
224 
225 
226 
227 
228 void Clipboard::DoDelete (::Window* )
229 {
230     if (mrSlideSorter.GetModel().GetPageCount() > 1)
231     {
232         mrController.GetSelectionManager()->DeleteSelectedPages();
233     }
234 }
235 
236 
237 
238 
239 void Clipboard::DoCopy (::Window* pWindow )
240 {
241     CreateSlideTransferable( pWindow, sal_False );
242 }
243 
244 
245 
246 
247 void Clipboard::DoPaste (::Window* pWindow)
248 {
249     SdTransferable* pClipTransferable = SD_MOD()->pTransferClip;
250 
251     if (pClipTransferable!=NULL && pClipTransferable->IsPageTransferable())
252     {
253         sal_Int32 nInsertPosition = GetInsertionPosition(pWindow);
254 
255         if (nInsertPosition >= 0)
256         {
257             // Paste the pages from the clipboard.
258             sal_Int32 nInsertPageCount = PasteTransferable(nInsertPosition);
259             // Select the pasted pages and make the first of them the
260             // current page.
261             mrSlideSorter.GetContentWindow()->GrabFocus();
262             SelectPageRange(nInsertPosition, nInsertPageCount);
263         }
264     }
265 }
266 
267 
268 
269 
270 sal_Int32 Clipboard::GetInsertionPosition (::Window* pWindow)
271 {
272     sal_Int32 nInsertPosition = -1;
273 
274     // Determine the insertion position:
275     // a) When the insertion indicator is visible, then at that position.
276     // b) When the focus indicator is visible, then before or after the
277     // focused page, depending on user input to a dialog.
278     // c) When there is a selection but no focus, then after the
279     // selection.
280     // d) After the last page when there is no selection and no focus.
281 
282     ::boost::shared_ptr<controller::InsertionIndicatorHandler> pInsertionIndicatorHandler (
283         mrController.GetInsertionIndicatorHandler());
284     if (pInsertionIndicatorHandler->IsActive())
285     {
286         // Use the insertion index of an active insertion indicator.
287         nInsertPosition = pInsertionIndicatorHandler->GetInsertionPageIndex();
288     }
289     else if (mrController.GetSelectionManager()->GetInsertionPosition() >= 0)
290     {
291         // Use the insertion index of an insertion indicator that has been
292         // deactivated a short while ago.
293         nInsertPosition = mrController.GetSelectionManager()->GetInsertionPosition();
294     }
295     else if (mrController.GetFocusManager().IsFocusShowing())
296     {
297         // Use the focus to determine the insertion position.
298         SdInsertPasteDlg aDialog (pWindow);
299         if (aDialog.Execute() == RET_OK)
300         {
301             nInsertPosition = mrController.GetFocusManager().GetFocusedPageIndex();
302             if ( ! aDialog.IsInsertBefore())
303                 nInsertPosition ++;
304         }
305     }
306 
307     return nInsertPosition;
308 }
309 
310 
311 
312 
313 sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition)
314 {
315     SdTransferable* pClipTransferable = SD_MOD()->pTransferClip;
316     model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
317     bool bMergeMasterPages = !pClipTransferable->HasSourceDoc (rModel.GetDocument());
318     sal_uInt16 nInsertIndex (rModel.GetCoreIndex(nInsertPosition));
319     sal_Int32 nInsertPageCount (0);
320     if (pClipTransferable->HasPageBookmarks())
321     {
322         const List& rBookmarkList = pClipTransferable->GetPageBookmarks();
323         const ::vos::OGuard aGuard (Application::GetSolarMutex());
324 
325         nInsertPageCount = (sal_uInt16) rBookmarkList.Count();
326         rModel.GetDocument()->InsertBookmarkAsPage(
327             const_cast<List*>(&rBookmarkList),
328             NULL,
329             sal_False,
330             sal_False,
331             nInsertIndex,
332             sal_False,
333             pClipTransferable->GetPageDocShell(),
334             sal_True,
335             bMergeMasterPages,
336             sal_False);
337     }
338     else
339     {
340         SfxObjectShell* pShell = pClipTransferable->GetDocShell();
341         DrawDocShell* pDataDocSh = (DrawDocShell*)pShell;
342         SdDrawDocument* pDataDoc = pDataDocSh->GetDoc();
343 
344         if (pDataDoc!=NULL
345             && pDataDoc->GetSdPageCount(PK_STANDARD))
346         {
347             const ::vos::OGuard aGuard (Application::GetSolarMutex());
348 
349             bMergeMasterPages = (pDataDoc != rModel.GetDocument());
350             nInsertPageCount = pDataDoc->GetSdPageCount( PK_STANDARD );
351             rModel.GetDocument()->InsertBookmarkAsPage(
352                 NULL,
353                 NULL,
354                 sal_False,
355                 sal_False,
356                 nInsertIndex,
357                 sal_False,
358                 pDataDocSh,
359                 sal_True,
360                 bMergeMasterPages,
361                 sal_False);
362         }
363     }
364     mrController.HandleModelChange();
365     return nInsertPageCount;
366 }
367 
368 
369 
370 
371 void Clipboard::SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount)
372 {
373     // Select the newly inserted pages.  That are the nInsertPageCount pages
374     // after the nInsertIndex position.
375     PageSelector& rSelector (mrController.GetPageSelector());
376     rSelector.DeselectAllPages();
377     for (sal_uInt16 i=0; i<nPageCount; i++)
378     {
379         model::SharedPageDescriptor pDescriptor (
380             mrSlideSorter.GetModel().GetPageDescriptor(nFirstIndex + i));
381         if (pDescriptor.get() != NULL)
382         {
383             rSelector.SelectPage(pDescriptor);
384             // The first page of the new selection is made the current page.
385             if (i == 0)
386             {
387                 mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor);
388             }
389         }
390     }
391 }
392 
393 
394 
395 
396 void Clipboard::CreateSlideTransferable (
397     ::Window* pWindow,
398     bool bDrag)
399 {
400     List aBookmarkList;
401 
402     // Insert all selected pages into a bookmark list and remember them in
403     // maPagesToRemove for possible later removal.
404     model::PageEnumeration aSelectedPages
405         (model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
406             mrSlideSorter.GetModel()));
407     while (aSelectedPages.HasMoreElements())
408     {
409         model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
410         aBookmarkList.Insert (
411             new String(pDescriptor->GetPage()->GetName()),
412             LIST_APPEND);
413         maPagesToRemove.push_back (pDescriptor->GetPage());
414     }
415 
416     // Create a small set of representatives of the selection for which
417     // previews are included into the transferable so that an insertion
418     // indicator can be rendered.
419     aSelectedPages.Rewind();
420     ::std::vector<TransferableData::Representative> aRepresentatives;
421     aRepresentatives.reserve(3);
422     ::boost::shared_ptr<cache::PageCache> pPreviewCache (
423         mrSlideSorter.GetView().GetPreviewCache());
424     while (aSelectedPages.HasMoreElements())
425     {
426         model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
427         if ( ! pDescriptor || pDescriptor->GetPage()==NULL)
428             continue;
429         Bitmap aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false));
430         aRepresentatives.push_back(TransferableData::Representative(
431             aPreview,
432             pDescriptor->HasState(model::PageDescriptor::ST_Excluded)));
433         if (aRepresentatives.size() >= 3)
434             break;
435     }
436 
437     if (aBookmarkList.Count() > 0)
438     {
439         mrSlideSorter.GetView().BrkAction();
440         SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
441         SdTransferable* pTransferable = TransferableData::CreateTransferable (
442             pDocument,
443             NULL,
444             sal_False,
445             dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()),
446             aRepresentatives);
447 
448         if (bDrag)
449             SD_MOD()->pTransferDrag = pTransferable;
450         else
451             SD_MOD()->pTransferClip = pTransferable;
452 
453         pDocument->CreatingDataObj (pTransferable);
454         pTransferable->SetWorkDocument( dynamic_cast<SdDrawDocument*>(pDocument->AllocModel()) );
455         pDocument->CreatingDataObj (NULL);
456         TransferableObjectDescriptor aObjDesc;
457         pTransferable->GetWorkDocument()->GetDocSh()
458             ->FillTransferableObjectDescriptor (aObjDesc);
459 
460         if (pDocument->GetDocSh() != NULL)
461             aObjDesc.maDisplayName = pDocument->GetDocSh()
462                 ->GetMedium()->GetURLObject().GetURLNoPass();
463 
464         ::Window* pActionWindow = pWindow;
465         if (pActionWindow == NULL)
466         {
467             ViewShell* pViewShell = mrSlideSorter.GetViewShell();
468             if (pViewShell != NULL)
469                 pActionWindow = pViewShell->GetActiveWindow();
470         }
471 
472         pTransferable->SetStartPos (pActionWindow->PixelToLogic(
473             pActionWindow->GetPointerPosPixel()));
474         pTransferable->SetObjectDescriptor (aObjDesc);
475         pTransferable->SetPageBookmarks (aBookmarkList, !bDrag);
476 
477         for (void* p=aBookmarkList.First(); p!=NULL; p=aBookmarkList.Next())
478             delete static_cast<String*>(p);
479 
480         if (bDrag)
481         {
482             pTransferable->SetView (&mrSlideSorter.GetView());
483             sal_Int8 nDragSourceActions (DND_ACTION_COPY);
484             // The move action is available only when not all pages would be
485             // moved.  Otherwise an empty document would remain.  Crash.
486             sal_Int32 nRemainingPages = mrSlideSorter.GetModel().GetPageCount() - aBookmarkList.Count();
487             if (nRemainingPages > 0)
488                 nDragSourceActions |= DND_ACTION_MOVE;
489             pTransferable->StartDrag (pActionWindow, nDragSourceActions);
490         }
491         else
492             pTransferable->CopyToClipboard (pActionWindow);
493     }
494 }
495 
496 
497 
498 
499 ::boost::shared_ptr<SdTransferable::UserData> Clipboard::CreateTransferableUserData (SdTransferable* pTransferable)
500 {
501     do
502     {
503         SdPageObjsTLB::SdPageObjsTransferable* pTreeListBoxTransferable
504             = dynamic_cast<SdPageObjsTLB::SdPageObjsTransferable*>(pTransferable);
505         if (pTreeListBoxTransferable == NULL)
506             break;
507 
508         // Find view shell for the document of the transferable.
509         ::sd::ViewShell* pViewShell
510               = SdPageObjsTLB::GetViewShellForDocShell(pTreeListBoxTransferable->GetDocShell());
511         if (pViewShell == NULL)
512             break;
513 
514         // Find slide sorter for the document of the transferable.
515         SlideSorterViewShell* pSlideSorterViewShell
516             = SlideSorterViewShell::GetSlideSorter(pViewShell->GetViewShellBase());
517         if (pSlideSorterViewShell == NULL)
518             break;
519         SlideSorter& rSlideSorter (pSlideSorterViewShell->GetSlideSorter());
520 
521         // Get bookmark from transferable.
522         TransferableDataHelper  aDataHelper (pTransferable);
523         INetBookmark aINetBookmark;
524         if ( ! aDataHelper.GetINetBookmark(SOT_FORMATSTR_ID_NETSCAPE_BOOKMARK, aINetBookmark))
525             break;
526         const rtl::OUString sURL (aINetBookmark.GetURL());
527         const sal_Int32 nIndex (sURL.indexOf((sal_Unicode)'#'));
528         if (nIndex == -1)
529             break;
530         String sBookmark (sURL.copy(nIndex+1));
531 
532         // Make sure that the bookmark points to a page.
533         SdDrawDocument* pTransferableDocument = rSlideSorter.GetModel().GetDocument();
534         if (pTransferableDocument == NULL)
535             break;
536         sal_Bool bIsMasterPage = sal_False;
537         const sal_uInt16 nPageIndex (pTransferableDocument->GetPageByName(sBookmark, bIsMasterPage));
538         if (nPageIndex == SDRPAGE_NOTFOUND)
539             break;
540 
541         // Create preview.
542         ::std::vector<TransferableData::Representative> aRepresentatives;
543         aRepresentatives.reserve(1);
544         ::boost::shared_ptr<cache::PageCache> pPreviewCache (
545             rSlideSorter.GetView().GetPreviewCache());
546         model::SharedPageDescriptor pDescriptor (rSlideSorter.GetModel().GetPageDescriptor((nPageIndex-1)/2));
547         if ( ! pDescriptor || pDescriptor->GetPage()==NULL)
548             break;
549         Bitmap aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false));
550         aRepresentatives.push_back(TransferableData::Representative(
551                 aPreview,
552                 pDescriptor->HasState(model::PageDescriptor::ST_Excluded)));
553 
554         // Remember the page in maPagesToRemove so that it can be removed
555         // when drag and drop action is "move".
556         Clipboard& rOtherClipboard (pSlideSorterViewShell->GetSlideSorter().GetController().GetClipboard());
557         rOtherClipboard.maPagesToRemove.clear();
558         rOtherClipboard.maPagesToRemove.push_back(pDescriptor->GetPage());
559 
560         // Create the new transferable.
561         ::boost::shared_ptr<SdTransferable::UserData> pNewTransferable (
562             new TransferableData(
563                 pSlideSorterViewShell,
564                 aRepresentatives));
565         pTransferable->SetWorkDocument( dynamic_cast<SdDrawDocument*>(
566                 pTreeListBoxTransferable->GetSourceDoc()->AllocModel()));
567         //        pTransferable->SetView(&mrSlideSorter.GetView());
568 
569         // Set page bookmark list.
570         List aPageBookmarks;
571         aPageBookmarks.Insert(new String(sBookmark));
572         pTransferable->SetPageBookmarks(aPageBookmarks, false);
573 
574         // Replace the view referenced by the transferable with the
575         // corresponding slide sorter view.
576         pTransferable->SetView(&pSlideSorterViewShell->GetSlideSorter().GetView());
577 
578         return pNewTransferable;
579     }
580     while (false);
581 
582     return ::boost::shared_ptr<SdTransferable::UserData>();
583 }
584 
585 
586 
587 
588 void Clipboard::StartDrag (
589     const Point& rPosition,
590     ::Window* pWindow)
591 {
592     maPagesToRemove.clear();
593     maPagesToSelect.clear();
594     mbUpdateSelectionPending = false;
595     CreateSlideTransferable(pWindow, sal_True);
596 
597     mrController.GetInsertionIndicatorHandler()->UpdatePosition(
598         rPosition,
599         InsertionIndicatorHandler::UnknownMode);
600 }
601 
602 
603 
604 
605 void Clipboard::DragFinished (sal_Int8 nDropAction)
606 {
607     // SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
608 
609     if (mnDragFinishedUserEventId == 0)
610     {
611         if ( ! Application::PostUserEvent(
612             mnDragFinishedUserEventId,
613             LINK(this, Clipboard, ProcessDragFinished),
614             reinterpret_cast<void*>(nDropAction)))
615         {
616             mnDragFinishedUserEventId = 0;
617         }
618     }
619 }
620 
621 
622 
623 
624 IMPL_LINK(Clipboard, ProcessDragFinished, void*, pUserData)
625 {
626     const sal_Int8 nDropAction (static_cast<sal_Int8>(reinterpret_cast<sal_IntPtr>(pUserData)));
627 
628     mnDragFinishedUserEventId = 0;
629 
630     // Hide the substitution display and insertion indicator.
631     ::rtl::Reference<SelectionFunction> pFunction (mrController.GetCurrentSelectionFunction());
632     if (pFunction.is())
633         pFunction->NotifyDragFinished();
634 
635     PageSelector& rSelector (mrController.GetPageSelector());
636     if ((nDropAction & DND_ACTION_MOVE) != 0
637         && ! maPagesToRemove.empty())
638     {
639         // Remove the pages that have been moved to another place (possibly
640         // in the same document.)
641         rSelector.DeselectAllPages();
642         PageList::iterator aDraggedPage;
643         for (aDraggedPage=maPagesToRemove.begin();
644              aDraggedPage!=maPagesToRemove.end();
645              aDraggedPage++)
646         {
647             rSelector.SelectPage(*aDraggedPage);
648         }
649         mrController.GetSelectionManager()->DeleteSelectedPages();
650     }
651     mpUndoContext.reset();
652     mpSelectionObserverContext.reset();
653 
654     return 1;
655 }
656 
657 
658 
659 
660 void Clipboard::SelectPages (void)
661 {
662     PageSelector& rSelector (mrController.GetPageSelector());
663 
664     // Select the dropped pages.
665     PageList::iterator iPage;
666     rSelector.DeselectAllPages();
667     for (iPage=maPagesToSelect.begin(); iPage!=maPagesToSelect.end(); ++iPage)
668     {
669         rSelector.SelectPage(*iPage);
670     }
671 }
672 
673 
674 
675 
676 sal_Int8 Clipboard::AcceptDrop (
677     const AcceptDropEvent& rEvent,
678     DropTargetHelper& rTargetHelper,
679     ::sd::Window* pTargetWindow,
680     sal_uInt16 nPage,
681     sal_uInt16 nLayer)
682 {
683     sal_Int8 nAction (DND_ACTION_NONE);
684 
685     const Clipboard::DropType eDropType (IsDropAccepted(rTargetHelper));
686 
687     switch (eDropType)
688     {
689         case DT_PAGE:
690         case DT_PAGE_FROM_NAVIGATOR:
691         {
692             // Accept a drop.
693             nAction = rEvent.mnAction;
694 
695             // Use the copy action when the drop action is the default, i.e. not
696             // explicitly set to move or link, and when the source and
697             // target models are not the same.
698             SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
699             if (pDragTransferable != NULL
700                 && pDragTransferable->IsPageTransferable()
701                 && ((rEvent.maDragEvent.DropAction
702                         & ::com::sun::star::datatransfer::dnd::DNDConstants::ACTION_DEFAULT) != 0)
703                 && (mrSlideSorter.GetModel().GetDocument()->GetDocSh()
704                     != pDragTransferable->GetPageDocShell()))
705             {
706                 nAction = DND_ACTION_COPY;
707             }
708             else if (IsInsertionTrivial(pDragTransferable, nAction))
709             {
710                 nAction = DND_ACTION_NONE;
711             }
712 
713             // Show the insertion marker and the substitution for a drop.
714             SelectionFunction* pSelectionFunction = dynamic_cast<SelectionFunction*>(
715                 mrSlideSorter.GetViewShell()->GetCurrentFunction().get());
716             if (pSelectionFunction != NULL)
717                 pSelectionFunction->MouseDragged(rEvent, nAction);
718 
719             // Scroll the window when the mouse reaches the window border.
720             //            mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel);
721         }
722         break;
723 
724         case DT_SHAPE:
725             nAction = ExecuteOrAcceptShapeDrop(
726                 DC_ACCEPT,
727                 rEvent.maPosPixel,
728                 &rEvent,
729                 rTargetHelper,
730                 pTargetWindow,
731                 nPage,
732                 nLayer);
733             break;
734 
735         default:
736         case DT_NONE:
737             nAction = DND_ACTION_NONE;
738             break;
739     }
740 
741     return nAction;
742 }
743 
744 
745 
746 
747 sal_Int8 Clipboard::ExecuteDrop (
748     const ExecuteDropEvent& rEvent,
749     DropTargetHelper& rTargetHelper,
750     ::sd::Window* pTargetWindow,
751     sal_uInt16 nPage,
752     sal_uInt16 nLayer)
753 {
754     sal_Int8 nResult = DND_ACTION_NONE;
755     mpUndoContext.reset();
756     const Clipboard::DropType eDropType (IsDropAccepted(rTargetHelper));
757 
758     switch (eDropType)
759     {
760         case DT_PAGE:
761         case DT_PAGE_FROM_NAVIGATOR:
762         {
763             SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
764             const Point aEventModelPosition (
765                 pTargetWindow->PixelToLogic (rEvent.maPosPixel));
766             const sal_Int32 nXOffset (labs (pDragTransferable->GetStartPos().X()
767                 - aEventModelPosition.X()));
768             const sal_Int32 nYOffset (labs (pDragTransferable->GetStartPos().Y()
769                 - aEventModelPosition.Y()));
770             bool bContinue =
771                 ( pDragTransferable->GetView() != &mrSlideSorter.GetView() )
772                 || ( nXOffset >= 2 && nYOffset >= 2 );
773 
774             ::boost::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler(
775                         mrController.GetInsertionIndicatorHandler());
776             // Get insertion position and then turn off the insertion indicator.
777             pInsertionIndicatorHandler->UpdatePosition(aEventModelPosition, rEvent.mnAction);
778             //            sal_uInt16 nIndex = DetermineInsertPosition(*pDragTransferable);
779 
780             // Do not process the insertion when it is trivial,
781             // i.e. would insert pages at their original place.
782             if (IsInsertionTrivial(pDragTransferable, rEvent.mnAction))
783                 bContinue = false;
784 
785             // Tell the insertion indicator handler to hide before the model
786             // is modified.  Doing it later may result in page objects whose
787             // animation state is not properly reset because they are then
788             // in another run then before the model change.
789             pInsertionIndicatorHandler->End(Animator::AM_Immediate);
790 
791             if (bContinue)
792             {
793                 SlideSorterController::ModelChangeLock aModelChangeLock (mrController);
794 
795                 // Handle a general drop operation.
796                 mpUndoContext.reset(new UndoContext (
797                     mrSlideSorter.GetModel().GetDocument(),
798                     mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell(),
799                     mrSlideSorter.GetTheme()));
800                 mpSelectionObserverContext.reset(new SelectionObserver::Context(mrSlideSorter));
801 
802                 HandlePageDrop(*pDragTransferable);
803                 nResult = rEvent.mnAction;
804 
805                 // We leave the undo context alive for when moving or
806                 // copying inside one view then the actions in
807                 // NotifyDragFinished should be covered as well as
808                 // well as the ones above.
809             }
810 
811             // When the pages originated in another slide sorter then
812             // only that is notified automatically about the drag
813             // operation being finished.  Because the target slide sorter
814             // has be notified, too, add a callback for that.
815             ::boost::shared_ptr<TransferableData> pSlideSorterTransferable (
816                 TransferableData::GetFromTransferable(pDragTransferable));
817             BOOST_ASSERT(pSlideSorterTransferable);
818             if (pSlideSorterTransferable
819                 && pSlideSorterTransferable->GetSourceViewShell() != mrSlideSorter.GetViewShell())
820             {
821                 DragFinished(nResult);
822             }
823 
824             // Notify the receiving selection function that drag-and-drop is
825             // finished and the substitution handler can be released.
826             ::rtl::Reference<SelectionFunction> pFunction (
827                 mrController.GetCurrentSelectionFunction());
828             if (pFunction.is())
829                 pFunction->NotifyDragFinished();
830         }
831         break;
832 
833         case DT_SHAPE:
834             nResult = ExecuteOrAcceptShapeDrop(
835                 DC_EXECUTE,
836                 rEvent.maPosPixel,
837                 &rEvent,
838                 rTargetHelper,
839                 pTargetWindow,
840                 nPage,
841                 nLayer);
842             break;
843 
844         default:
845         case DT_NONE:
846             break;
847     }
848 
849     return nResult;
850 }
851 
852 
853 
854 
855 bool Clipboard::IsInsertionTrivial (
856     SdTransferable* pTransferable,
857     const sal_Int8 nDndAction) const
858 {
859     ::boost::shared_ptr<TransferableData> pSlideSorterTransferable (
860         TransferableData::GetFromTransferable(pTransferable));
861     if (pSlideSorterTransferable
862         && pSlideSorterTransferable->GetSourceViewShell() != mrSlideSorter.GetViewShell())
863         return false;
864     return mrController.GetInsertionIndicatorHandler()->IsInsertionTrivial(nDndAction);
865 }
866 
867 
868 
869 
870 void Clipboard::Abort (void)
871 {
872     if (mpSelectionObserverContext)
873     {
874         mpSelectionObserverContext->Abort();
875         mpSelectionObserverContext.reset();
876     }
877 }
878 
879 
880 
881 
882 sal_uInt16 Clipboard::DetermineInsertPosition (const SdTransferable& )
883 {
884     // Tell the model to move the dragged pages behind the one with the
885     // index nInsertionIndex which first has to be transformed into an index
886     // understandable by the document.
887     const sal_Int32 nInsertionIndex (
888         mrController.GetInsertionIndicatorHandler()->GetInsertionPageIndex());
889 
890     // Convert to insertion index to that of an SdModel.
891     if (nInsertionIndex >= 0)
892         return mrSlideSorter.GetModel().GetCoreIndex(nInsertionIndex);
893     else
894         return 0;
895 }
896 
897 
898 
899 
900 sal_uInt16 Clipboard::InsertSlides (
901     const SdTransferable& rTransferable,
902     sal_uInt16 nInsertPosition)
903 {
904     sal_uInt16 nInsertedPageCount = ViewClipboard::InsertSlides (
905         rTransferable,
906         nInsertPosition);
907 
908     // Remember the inserted pages so that they can be selected when the
909     // operation is finished.
910     maPagesToSelect.clear();
911     SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
912     if (pDocument != NULL)
913         for (sal_Int32 i=0; i<=nInsertedPageCount; i+=2)
914             maPagesToSelect.push_back(
915                 dynamic_cast<SdPage*>(pDocument->GetPage(nInsertPosition+i)));
916 
917     mbUpdateSelectionPending |= (nInsertedPageCount>0);
918 
919     return nInsertedPageCount;
920 }
921 
922 
923 
924 
925 Clipboard::DropType Clipboard::IsDropAccepted (DropTargetHelper&) const
926 {
927     const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
928     if (pDragTransferable == NULL)
929         return DT_NONE;
930 
931     if (pDragTransferable->IsPageTransferable())
932     {
933         if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE)
934             return DT_PAGE;
935         else
936             return DT_NONE;
937     }
938 
939     const SdPageObjsTLB::SdPageObjsTransferable* pPageObjsTransferable
940         = dynamic_cast<const SdPageObjsTLB::SdPageObjsTransferable*>(pDragTransferable);
941     if (pPageObjsTransferable != NULL)
942         return DT_PAGE_FROM_NAVIGATOR;
943 
944     return DT_SHAPE;
945 }
946 
947 
948 
949 
950 sal_Int8 Clipboard::ExecuteOrAcceptShapeDrop (
951     DropCommand eCommand,
952     const Point& rPosition,
953     const void* pDropEvent,
954     DropTargetHelper& rTargetHelper,
955     ::sd::Window* pTargetWindow,
956     sal_uInt16 nPage,
957     sal_uInt16 nLayer)
958 {
959     sal_Int8 nResult = 0;
960 
961     // The dropping of a shape is accepted or executed only when there is
962     // DrawViewShell available to which we can forward this call.  This has
963     // technical reasons:  The actual code to accept or execute a shape drop
964     // is implemented in the ViewShell class and uses the page view of the
965     // main edit view.  This is not possible without a DrawViewShell.
966     ::boost::shared_ptr<DrawViewShell> pDrawViewShell;
967     if (mrSlideSorter.GetViewShell() != NULL)
968         pDrawViewShell = ::boost::dynamic_pointer_cast<DrawViewShell>(
969             mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell());
970     if (pDrawViewShell.get() != NULL
971         && (pDrawViewShell->GetShellType() == ViewShell::ST_IMPRESS
972             || pDrawViewShell->GetShellType() == ViewShell::ST_DRAW))
973     {
974         // The drop is only accepted or executed when it takes place over a
975         // page object.  Therefore we replace a missing page number by the
976         // number of the page under the mouse.
977         if (nPage == SDRPAGE_NOTFOUND)
978         {
979             model::SharedPageDescriptor pDescriptor (
980                 mrSlideSorter.GetModel().GetPageDescriptor(
981                     mrSlideSorter.GetView().GetPageIndexAtPoint(rPosition)));
982             if (pDescriptor)
983                 nPage = pDescriptor->GetPageIndex();
984         }
985 
986         // Now comes the code that is different for the Execute and Accept:
987         // We simply forward the call to the AcceptDrop() or ExecuteDrop()
988         // methods of the DrawViewShell in the center pane.
989         if (nPage != SDRPAGE_NOTFOUND)
990             switch (eCommand)
991             {
992                 case DC_ACCEPT:
993                     nResult = pDrawViewShell->AcceptDrop(
994                         *reinterpret_cast<const AcceptDropEvent*>(pDropEvent),
995                         rTargetHelper,
996                         pTargetWindow,
997                         nPage,
998                         nLayer);
999                     break;
1000 
1001                 case DC_EXECUTE:
1002                     nResult = pDrawViewShell->ExecuteDrop(
1003                         *reinterpret_cast<const ExecuteDropEvent*>(pDropEvent),
1004                         rTargetHelper,
1005                         pTargetWindow,
1006                         nPage,
1007                         nLayer);
1008                     break;
1009             }
1010     }
1011 
1012     return nResult;
1013 }
1014 
1015 
1016 
1017 } } } // end of namespace ::sd::slidesorter::controller
1018 
1019