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(SD_RESSTR(STRING_DRAG_AND_DROP_PAGES));
125 : else
126 0 : mpDocument->BegUndo(SD_RESSTR(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 : rtl::Reference<FuPoor> 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, 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<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<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<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 0 : 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 : pTransferable->StartDrag (pActionWindow, DND_ACTION_COPY | DND_ACTION_MOVE);
501 : }
502 : else
503 0 : pTransferable->CopyToClipboard (pActionWindow);
504 0 : }
505 0 : }
506 :
507 :
508 :
509 :
510 0 : ::boost::shared_ptr<SdTransferable::UserData> Clipboard::CreateTransferableUserData (SdTransferable* pTransferable)
511 : {
512 : do
513 : {
514 : SdPageObjsTLB::SdPageObjsTransferable* pTreeListBoxTransferable
515 0 : = dynamic_cast<SdPageObjsTLB::SdPageObjsTransferable*>(pTransferable);
516 0 : if (pTreeListBoxTransferable == NULL)
517 0 : break;
518 :
519 : // Find view shell for the document of the transferable.
520 : ::sd::ViewShell* pViewShell
521 0 : = SdPageObjsTLB::GetViewShellForDocShell(pTreeListBoxTransferable->GetDocShell());
522 0 : if (pViewShell == NULL)
523 0 : break;
524 :
525 : // Find slide sorter for the document of the transferable.
526 : SlideSorterViewShell* pSlideSorterViewShell
527 0 : = SlideSorterViewShell::GetSlideSorter(pViewShell->GetViewShellBase());
528 0 : if (pSlideSorterViewShell == NULL)
529 0 : break;
530 0 : SlideSorter& rSlideSorter (pSlideSorterViewShell->GetSlideSorter());
531 :
532 : // Get bookmark from transferable.
533 0 : TransferableDataHelper aDataHelper (pTransferable);
534 0 : INetBookmark aINetBookmark;
535 0 : if ( ! aDataHelper.GetINetBookmark(SOT_FORMATSTR_ID_NETSCAPE_BOOKMARK, aINetBookmark))
536 0 : break;
537 0 : const OUString sURL (aINetBookmark.GetURL());
538 0 : const sal_Int32 nIndex (sURL.indexOf((sal_Unicode)'#'));
539 0 : if (nIndex == -1)
540 0 : break;
541 0 : OUString sBookmark (sURL.copy(nIndex+1));
542 :
543 : // Make sure that the bookmark points to a page.
544 0 : SdDrawDocument* pTransferableDocument = rSlideSorter.GetModel().GetDocument();
545 0 : if (pTransferableDocument == NULL)
546 0 : break;
547 0 : sal_Bool bIsMasterPage = sal_False;
548 0 : const sal_uInt16 nPageIndex (pTransferableDocument->GetPageByName(sBookmark, bIsMasterPage));
549 0 : if (nPageIndex == SDRPAGE_NOTFOUND)
550 0 : break;
551 :
552 : // Create preview.
553 0 : ::std::vector<TransferableData::Representative> aRepresentatives;
554 0 : aRepresentatives.reserve(1);
555 : ::boost::shared_ptr<cache::PageCache> pPreviewCache (
556 0 : rSlideSorter.GetView().GetPreviewCache());
557 0 : model::SharedPageDescriptor pDescriptor (rSlideSorter.GetModel().GetPageDescriptor((nPageIndex-1)/2));
558 0 : if ( ! pDescriptor || pDescriptor->GetPage()==NULL)
559 0 : break;
560 0 : Bitmap aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false));
561 : aRepresentatives.push_back(TransferableData::Representative(
562 : aPreview,
563 0 : pDescriptor->HasState(model::PageDescriptor::ST_Excluded)));
564 :
565 : // Remember the page in maPagesToRemove so that it can be removed
566 : // when drag and drop action is "move".
567 0 : Clipboard& rOtherClipboard (pSlideSorterViewShell->GetSlideSorter().GetController().GetClipboard());
568 0 : rOtherClipboard.maPagesToRemove.clear();
569 0 : rOtherClipboard.maPagesToRemove.push_back(pDescriptor->GetPage());
570 :
571 : // Create the new transferable.
572 : ::boost::shared_ptr<SdTransferable::UserData> pNewTransferable (
573 : new TransferableData(
574 : pSlideSorterViewShell,
575 0 : aRepresentatives));
576 : pTransferable->SetWorkDocument( dynamic_cast<SdDrawDocument*>(
577 0 : pTreeListBoxTransferable->GetSourceDoc()->AllocModel()));
578 : // pTransferable->SetView(&mrSlideSorter.GetView());
579 :
580 : // Set page bookmark list.
581 0 : std::vector<OUString> aPageBookmarks;
582 0 : aPageBookmarks.push_back(sBookmark);
583 0 : pTransferable->SetPageBookmarks(aPageBookmarks, false);
584 :
585 : // Replace the view referenced by the transferable with the
586 : // corresponding slide sorter view.
587 0 : pTransferable->SetView(&pSlideSorterViewShell->GetSlideSorter().GetView());
588 :
589 0 : return pNewTransferable;
590 : }
591 : while (false);
592 :
593 0 : return ::boost::shared_ptr<SdTransferable::UserData>();
594 : }
595 :
596 :
597 :
598 :
599 0 : void Clipboard::StartDrag (
600 : const Point& rPosition,
601 : ::Window* pWindow)
602 : {
603 0 : maPagesToRemove.clear();
604 0 : maPagesToSelect.clear();
605 0 : mbUpdateSelectionPending = false;
606 0 : CreateSlideTransferable(pWindow, true);
607 :
608 : mrController.GetInsertionIndicatorHandler()->UpdatePosition(
609 : rPosition,
610 0 : InsertionIndicatorHandler::UnknownMode);
611 0 : }
612 :
613 :
614 :
615 :
616 0 : void Clipboard::DragFinished (sal_Int8 nDropAction)
617 : {
618 0 : if (mnDragFinishedUserEventId == 0)
619 : {
620 0 : if ( ! Application::PostUserEvent(
621 : mnDragFinishedUserEventId,
622 : LINK(this, Clipboard, ProcessDragFinished),
623 0 : reinterpret_cast<void*>(nDropAction)))
624 : {
625 0 : mnDragFinishedUserEventId = 0;
626 : }
627 : }
628 0 : }
629 :
630 :
631 :
632 :
633 0 : IMPL_LINK(Clipboard, ProcessDragFinished, void*, pUserData)
634 : {
635 0 : const sal_Int8 nDropAction (static_cast<sal_Int8>(reinterpret_cast<sal_IntPtr>(pUserData)));
636 :
637 0 : mnDragFinishedUserEventId = 0;
638 :
639 : // Hide the substitution display and insertion indicator.
640 0 : ::rtl::Reference<SelectionFunction> pFunction (mrController.GetCurrentSelectionFunction());
641 0 : if (pFunction.is())
642 0 : pFunction->NotifyDragFinished();
643 :
644 0 : PageSelector& rSelector (mrController.GetPageSelector());
645 0 : if ((nDropAction & DND_ACTION_MOVE) != 0
646 0 : && ! maPagesToRemove.empty())
647 : {
648 : // Remove the pages that have been moved to another place (possibly
649 : // in the same document.)
650 0 : rSelector.DeselectAllPages();
651 0 : PageList::iterator aDraggedPage;
652 0 : for (aDraggedPage=maPagesToRemove.begin();
653 0 : aDraggedPage!=maPagesToRemove.end();
654 : ++aDraggedPage)
655 : {
656 0 : rSelector.SelectPage(*aDraggedPage);
657 : }
658 0 : mrController.GetSelectionManager()->DeleteSelectedPages();
659 : }
660 0 : mpUndoContext.reset();
661 0 : mpSelectionObserverContext.reset();
662 :
663 0 : return 1;
664 : }
665 :
666 :
667 :
668 :
669 0 : sal_Int8 Clipboard::AcceptDrop (
670 : const AcceptDropEvent& rEvent,
671 : DropTargetHelper& rTargetHelper,
672 : ::sd::Window* pTargetWindow,
673 : sal_uInt16 nPage,
674 : sal_uInt16 nLayer)
675 : {
676 0 : sal_Int8 nAction (DND_ACTION_NONE);
677 :
678 0 : const Clipboard::DropType eDropType (IsDropAccepted(rTargetHelper));
679 :
680 0 : switch (eDropType)
681 : {
682 : case DT_PAGE:
683 : case DT_PAGE_FROM_NAVIGATOR:
684 : {
685 : // Accept a drop.
686 0 : nAction = rEvent.mnAction;
687 :
688 : // Use the copy action when the drop action is the default, i.e. not
689 : // explicitly set to move or link, and when the source and
690 : // target models are not the same.
691 0 : SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
692 0 : if (pDragTransferable != NULL
693 0 : && pDragTransferable->IsPageTransferable()
694 0 : && ((rEvent.maDragEvent.DropAction
695 0 : & ::com::sun::star::datatransfer::dnd::DNDConstants::ACTION_DEFAULT) != 0)
696 0 : && (mrSlideSorter.GetModel().GetDocument()->GetDocSh()
697 0 : != pDragTransferable->GetPageDocShell()))
698 : {
699 0 : nAction = DND_ACTION_COPY;
700 : }
701 0 : else if (IsInsertionTrivial(pDragTransferable, nAction))
702 : {
703 0 : nAction = DND_ACTION_NONE;
704 : }
705 :
706 : // Show the insertion marker and the substitution for a drop.
707 : SelectionFunction* pSelectionFunction = dynamic_cast<SelectionFunction*>(
708 0 : mrSlideSorter.GetViewShell()->GetCurrentFunction().get());
709 0 : if (pSelectionFunction != NULL)
710 0 : pSelectionFunction->MouseDragged(rEvent, nAction);
711 :
712 : // Scroll the window when the mouse reaches the window border.
713 : // mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel);
714 : }
715 0 : break;
716 :
717 : case DT_SHAPE:
718 : nAction = ExecuteOrAcceptShapeDrop(
719 : DC_ACCEPT,
720 : rEvent.maPosPixel,
721 : &rEvent,
722 : rTargetHelper,
723 : pTargetWindow,
724 : nPage,
725 0 : nLayer);
726 0 : break;
727 :
728 : default:
729 : case DT_NONE:
730 0 : nAction = DND_ACTION_NONE;
731 0 : break;
732 : }
733 :
734 0 : return nAction;
735 : }
736 :
737 :
738 :
739 :
740 0 : sal_Int8 Clipboard::ExecuteDrop (
741 : const ExecuteDropEvent& rEvent,
742 : DropTargetHelper& rTargetHelper,
743 : ::sd::Window* pTargetWindow,
744 : sal_uInt16 nPage,
745 : sal_uInt16 nLayer)
746 : {
747 0 : sal_Int8 nResult = DND_ACTION_NONE;
748 0 : mpUndoContext.reset();
749 0 : const Clipboard::DropType eDropType (IsDropAccepted(rTargetHelper));
750 :
751 0 : switch (eDropType)
752 : {
753 : case DT_PAGE:
754 : case DT_PAGE_FROM_NAVIGATOR:
755 : {
756 0 : SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
757 : const Point aEventModelPosition (
758 0 : pTargetWindow->PixelToLogic (rEvent.maPosPixel));
759 0 : const sal_Int32 nXOffset (labs (pDragTransferable->GetStartPos().X()
760 0 : - aEventModelPosition.X()));
761 0 : const sal_Int32 nYOffset (labs (pDragTransferable->GetStartPos().Y()
762 0 : - aEventModelPosition.Y()));
763 : bool bContinue =
764 0 : ( pDragTransferable->GetView() != &mrSlideSorter.GetView() )
765 0 : || ( nXOffset >= 2 && nYOffset >= 2 );
766 :
767 : ::boost::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler(
768 0 : mrController.GetInsertionIndicatorHandler());
769 : // Get insertion position and then turn off the insertion indicator.
770 0 : pInsertionIndicatorHandler->UpdatePosition(aEventModelPosition, rEvent.mnAction);
771 : // sal_uInt16 nIndex = DetermineInsertPosition(*pDragTransferable);
772 :
773 : // Do not process the insertion when it is trivial,
774 : // i.e. would insert pages at their original place.
775 0 : if (IsInsertionTrivial(pDragTransferable, rEvent.mnAction))
776 0 : bContinue = false;
777 :
778 : // Tell the insertion indicator handler to hide before the model
779 : // is modified. Doing it later may result in page objects whose
780 : // animation state is not properly reset because they are then
781 : // in another run then before the model change.
782 0 : pInsertionIndicatorHandler->End(Animator::AM_Immediate);
783 :
784 0 : if (bContinue)
785 : {
786 0 : SlideSorterController::ModelChangeLock aModelChangeLock (mrController);
787 :
788 : // Handle a general drop operation.
789 : mpUndoContext.reset(new UndoContext (
790 0 : mrSlideSorter.GetModel().GetDocument(),
791 0 : mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell()));
792 0 : mpSelectionObserverContext.reset(new SelectionObserver::Context(mrSlideSorter));
793 :
794 0 : HandlePageDrop(*pDragTransferable);
795 0 : nResult = rEvent.mnAction;
796 :
797 : // We leave the undo context alive for when moving or
798 : // copying inside one view then the actions in
799 : // NotifyDragFinished should be covered as well as
800 : // well as the ones above.
801 : }
802 :
803 : // When the pages originated in another slide sorter then
804 : // only that is notified automatically about the drag
805 : // operation being finished. Because the target slide sorter
806 : // has be notified, too, add a callback for that.
807 : ::boost::shared_ptr<TransferableData> pSlideSorterTransferable (
808 0 : TransferableData::GetFromTransferable(pDragTransferable));
809 : BOOST_ASSERT(pSlideSorterTransferable);
810 0 : if (pSlideSorterTransferable
811 0 : && pSlideSorterTransferable->GetSourceViewShell() != mrSlideSorter.GetViewShell())
812 : {
813 0 : DragFinished(nResult);
814 : }
815 :
816 : // Notify the receiving selection function that drag-and-drop is
817 : // finished and the substitution handler can be released.
818 : ::rtl::Reference<SelectionFunction> pFunction (
819 0 : mrController.GetCurrentSelectionFunction());
820 0 : if (pFunction.is())
821 0 : pFunction->NotifyDragFinished();
822 : }
823 0 : break;
824 :
825 : case DT_SHAPE:
826 : nResult = ExecuteOrAcceptShapeDrop(
827 : DC_EXECUTE,
828 : rEvent.maPosPixel,
829 : &rEvent,
830 : rTargetHelper,
831 : pTargetWindow,
832 : nPage,
833 0 : nLayer);
834 0 : break;
835 :
836 : default:
837 : case DT_NONE:
838 0 : break;
839 : }
840 :
841 0 : return nResult;
842 : }
843 :
844 :
845 :
846 :
847 0 : bool Clipboard::IsInsertionTrivial (
848 : SdTransferable* pTransferable,
849 : const sal_Int8 nDndAction) const
850 : {
851 : ::boost::shared_ptr<TransferableData> pSlideSorterTransferable (
852 0 : TransferableData::GetFromTransferable(pTransferable));
853 0 : if (pSlideSorterTransferable
854 0 : && pSlideSorterTransferable->GetSourceViewShell() != mrSlideSorter.GetViewShell())
855 0 : return false;
856 0 : return mrController.GetInsertionIndicatorHandler()->IsInsertionTrivial(nDndAction);
857 : }
858 :
859 :
860 :
861 :
862 0 : void Clipboard::Abort (void)
863 : {
864 0 : if (mpSelectionObserverContext)
865 : {
866 0 : mpSelectionObserverContext->Abort();
867 0 : mpSelectionObserverContext.reset();
868 : }
869 0 : }
870 :
871 :
872 :
873 :
874 0 : sal_uInt16 Clipboard::DetermineInsertPosition (const SdTransferable& )
875 : {
876 : // Tell the model to move the dragged pages behind the one with the
877 : // index nInsertionIndex which first has to be transformed into an index
878 : // understandable by the document.
879 : const sal_Int32 nInsertionIndex (
880 0 : mrController.GetInsertionIndicatorHandler()->GetInsertionPageIndex());
881 :
882 : // Convert to insertion index to that of an SdModel.
883 0 : if (nInsertionIndex >= 0)
884 0 : return mrSlideSorter.GetModel().GetCoreIndex(nInsertionIndex);
885 : else
886 0 : return 0;
887 : }
888 :
889 :
890 :
891 :
892 0 : sal_uInt16 Clipboard::InsertSlides (
893 : const SdTransferable& rTransferable,
894 : sal_uInt16 nInsertPosition)
895 : {
896 : sal_uInt16 nInsertedPageCount = ViewClipboard::InsertSlides (
897 : rTransferable,
898 0 : nInsertPosition);
899 :
900 : // Remember the inserted pages so that they can be selected when the
901 : // operation is finished.
902 0 : maPagesToSelect.clear();
903 0 : SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
904 0 : if (pDocument != NULL)
905 0 : for (sal_Int32 i=0; i<=nInsertedPageCount; i+=2)
906 : maPagesToSelect.push_back(
907 0 : dynamic_cast<SdPage*>(pDocument->GetPage(nInsertPosition+i)));
908 :
909 0 : mbUpdateSelectionPending |= (nInsertedPageCount>0);
910 :
911 0 : return nInsertedPageCount;
912 : }
913 :
914 :
915 :
916 :
917 0 : Clipboard::DropType Clipboard::IsDropAccepted (DropTargetHelper&) const
918 : {
919 0 : const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag;
920 0 : if (pDragTransferable == NULL)
921 0 : return DT_NONE;
922 :
923 0 : if (pDragTransferable->IsPageTransferable())
924 : {
925 0 : if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE)
926 0 : return DT_PAGE;
927 : else
928 0 : return DT_NONE;
929 : }
930 :
931 : const SdPageObjsTLB::SdPageObjsTransferable* pPageObjsTransferable
932 0 : = dynamic_cast<const SdPageObjsTLB::SdPageObjsTransferable*>(pDragTransferable);
933 0 : if (pPageObjsTransferable != NULL)
934 0 : return DT_PAGE_FROM_NAVIGATOR;
935 :
936 0 : return DT_SHAPE;
937 : }
938 :
939 :
940 :
941 :
942 0 : sal_Int8 Clipboard::ExecuteOrAcceptShapeDrop (
943 : DropCommand eCommand,
944 : const Point& rPosition,
945 : const void* pDropEvent,
946 : DropTargetHelper& rTargetHelper,
947 : ::sd::Window* pTargetWindow,
948 : sal_uInt16 nPage,
949 : sal_uInt16 nLayer)
950 : {
951 0 : sal_Int8 nResult = 0;
952 :
953 : // The dropping of a shape is accepted or executed only when there is
954 : // DrawViewShell available to which we can forward this call. This has
955 : // technical reasons: The actual code to accept or execute a shape drop
956 : // is implemented in the ViewShell class and uses the page view of the
957 : // main edit view. This is not possible without a DrawViewShell.
958 0 : ::boost::shared_ptr<DrawViewShell> pDrawViewShell;
959 0 : if (mrSlideSorter.GetViewShell() != NULL)
960 0 : pDrawViewShell = ::boost::dynamic_pointer_cast<DrawViewShell>(
961 0 : mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell());
962 0 : if (pDrawViewShell.get() != NULL
963 0 : && (pDrawViewShell->GetShellType() == ViewShell::ST_IMPRESS
964 0 : || pDrawViewShell->GetShellType() == ViewShell::ST_DRAW))
965 : {
966 : // The drop is only accepted or executed when it takes place over a
967 : // page object. Therefore we replace a missing page number by the
968 : // number of the page under the mouse.
969 0 : if (nPage == SDRPAGE_NOTFOUND)
970 : {
971 : model::SharedPageDescriptor pDescriptor (
972 0 : mrSlideSorter.GetModel().GetPageDescriptor(
973 0 : mrSlideSorter.GetView().GetPageIndexAtPoint(rPosition)));
974 0 : if (pDescriptor)
975 0 : nPage = pDescriptor->GetPageIndex();
976 : }
977 :
978 : // Now comes the code that is different for the Execute and Accept:
979 : // We simply forward the call to the AcceptDrop() or ExecuteDrop()
980 : // methods of the DrawViewShell in the center pane.
981 0 : if (nPage != SDRPAGE_NOTFOUND)
982 0 : switch (eCommand)
983 : {
984 : case DC_ACCEPT:
985 0 : nResult = pDrawViewShell->AcceptDrop(
986 : *reinterpret_cast<const AcceptDropEvent*>(pDropEvent),
987 : rTargetHelper,
988 : pTargetWindow,
989 : nPage,
990 0 : nLayer);
991 0 : break;
992 :
993 : case DC_EXECUTE:
994 0 : nResult = pDrawViewShell->ExecuteDrop(
995 : *reinterpret_cast<const ExecuteDropEvent*>(pDropEvent),
996 : rTargetHelper,
997 : pTargetWindow,
998 : nPage,
999 0 : nLayer);
1000 0 : break;
1001 : }
1002 : }
1003 :
1004 0 : return nResult;
1005 : }
1006 :
1007 :
1008 :
1009 0 : } } } // end of namespace ::sd::slidesorter::controller
1010 :
1011 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|