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