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