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