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