bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / slidesorter / controller / SlsSlotManager.cxx
blob55b58e197f1c146ec1f9b7e0b2206dc14ec28395
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/beans/PropertyValue.hpp>
22 #include <editeng/outlobj.hxx>
24 #include <controller/SlsSlotManager.hxx>
25 #include <SlideSorter.hxx>
26 #include <SlideSorterViewShell.hxx>
27 #include <controller/SlideSorterController.hxx>
28 #include <controller/SlsClipboard.hxx>
29 #include <controller/SlsCurrentSlideManager.hxx>
30 #include <controller/SlsFocusManager.hxx>
31 #include <controller/SlsInsertionIndicatorHandler.hxx>
32 #include <controller/SlsPageSelector.hxx>
33 #include <controller/SlsSelectionFunction.hxx>
34 #include <controller/SlsSelectionManager.hxx>
35 #include <controller/SlsSelectionObserver.hxx>
36 #include <model/SlideSorterModel.hxx>
37 #include <model/SlsPageEnumerationProvider.hxx>
38 #include <model/SlsPageDescriptor.hxx>
39 #include <view/SlideSorterView.hxx>
40 #include <view/SlsLayouter.hxx>
41 #include <framework/FrameworkHelper.hxx>
42 #include <Window.hxx>
43 #include <fupoor.hxx>
44 #include <fuzoom.hxx>
45 #include <fucushow.hxx>
46 #include <fusldlg.hxx>
47 #include <fuexpand.hxx>
48 #include <fusumry.hxx>
49 #include <fuscale.hxx>
50 #include <slideshow.hxx>
51 #include <app.hrc>
52 #include <strings.hrc>
53 #include <sdresid.hxx>
54 #include <unokywds.hxx>
55 #include <drawdoc.hxx>
56 #include <DrawDocShell.hxx>
57 #include <ViewShellBase.hxx>
58 #include <ViewShellImplementation.hxx>
59 #include <sdattr.hxx>
60 #include <FrameView.hxx>
61 #include <zoomlist.hxx>
62 #include <sdpage.hxx>
63 #include <sdxfer.hxx>
64 #include <helpids.h>
65 #include <unmodpg.hxx>
66 #include <DrawViewShell.hxx>
67 #include <sdabstdlg.hxx>
68 #include <sdmod.hxx>
70 #include <sfx2/request.hxx>
71 #include <sfx2/viewfrm.hxx>
72 #include <sfx2/bindings.hxx>
73 #include <sfx2/dispatch.hxx>
74 #include <sfx2/sidebar/Sidebar.hxx>
75 #include <svx/svxids.hrc>
76 #include <sfx2/zoomitem.hxx>
77 #include <svx/svxdlg.hxx>
78 #include <svx/dialogs.hrc>
79 #include <svl/intitem.hxx>
80 #include <svl/whiter.hxx>
81 #include <svl/itempool.hxx>
82 #include <svl/aeitem.hxx>
83 #include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
84 #include <com/sun/star/drawing/XDrawPages.hpp>
85 #include <vcl/svapp.hxx>
87 #include <memory>
89 using namespace ::com::sun::star;
90 using namespace ::com::sun::star::uno;
91 using namespace ::com::sun::star::beans;
93 namespace sd { namespace slidesorter { namespace controller {
95 namespace {
97 /** The state of a set of slides with respect to being excluded from the
98 slide show.
100 enum SlideExclusionState {UNDEFINED, EXCLUDED, INCLUDED, MIXED};
102 /** Return for the given set of slides whether they included are
103 excluded from the slide show.
105 SlideExclusionState GetSlideExclusionState (model::PageEnumeration& rPageSet);
107 } // end of anonymous namespace
109 SlotManager::SlotManager (SlideSorter& rSlideSorter)
110 : mrSlideSorter(rSlideSorter)
114 SlotManager::~SlotManager()
118 void SlotManager::FuTemporary (SfxRequest& rRequest)
120 SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
122 SlideSorterViewShell* pShell
123 = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
124 if (pShell == nullptr)
125 return;
127 switch (rRequest.GetSlot())
129 case SID_PRESENTATION:
130 case SID_PRESENTATION_CURRENT_SLIDE:
131 case SID_REHEARSE_TIMINGS:
132 slideshowhelp::ShowSlideShow(rRequest, *mrSlideSorter.GetModel().GetDocument());
133 pShell->Cancel();
134 rRequest.Done();
135 break;
137 case SID_HIDE_SLIDE:
138 ChangeSlideExclusionState(model::SharedPageDescriptor(), true);
139 break;
141 case SID_SHOW_SLIDE:
142 ChangeSlideExclusionState(model::SharedPageDescriptor(), false);
143 break;
145 case SID_PAGES_PER_ROW:
146 if (rRequest.GetArgs() != nullptr)
148 const SfxUInt16Item* pPagesPerRow = rRequest.GetArg<SfxUInt16Item>(SID_PAGES_PER_ROW);
149 if (pPagesPerRow != nullptr)
151 sal_Int32 nColumnCount = pPagesPerRow->GetValue();
152 // Force the given number of columns by setting
153 // the minimal and maximal number of columns to
154 // the same value.
155 mrSlideSorter.GetView().GetLayouter().SetColumnCount (
156 nColumnCount, nColumnCount);
157 // Force a repaint and re-layout.
158 pShell->ArrangeGUIElements ();
159 // Rearrange the UI-elements controlled by the
160 // controller and force a rearrangement of the
161 // view.
162 mrSlideSorter.GetController().Rearrange(true);
165 rRequest.Done();
166 break;
168 case SID_SELECTALL:
169 mrSlideSorter.GetController().GetPageSelector().SelectAllPages();
170 rRequest.Done();
171 break;
173 case SID_SLIDE_TRANSITIONS_PANEL:
175 // First make sure that the sidebar is visible
176 pShell->GetViewFrame()->ShowChildWindow(SID_SIDEBAR);
177 ::sfx2::sidebar::Sidebar::ShowPanel(
178 "SdSlideTransitionPanel",
179 pShell->GetViewFrame()->GetFrame().GetFrameInterface());
180 rRequest.Ignore ();
181 break;
184 case SID_PRESENTATION_DLG:
185 FuSlideShowDlg::Create (
186 pShell,
187 mrSlideSorter.GetContentWindow(),
188 &mrSlideSorter.GetView(),
189 pDocument,
190 rRequest);
191 break;
193 case SID_CUSTOMSHOW_DLG:
194 FuCustomShowDlg::Create (
195 pShell,
196 mrSlideSorter.GetContentWindow(),
197 &mrSlideSorter.GetView(),
198 pDocument,
199 rRequest);
200 break;
202 case SID_EXPAND_PAGE:
203 FuExpandPage::Create (
204 pShell,
205 mrSlideSorter.GetContentWindow(),
206 &mrSlideSorter.GetView(),
207 pDocument,
208 rRequest);
209 break;
211 case SID_SUMMARY_PAGE:
212 FuSummaryPage::Create (
213 pShell,
214 mrSlideSorter.GetContentWindow(),
215 &mrSlideSorter.GetView(),
216 pDocument,
217 rRequest);
218 break;
220 case SID_INSERTPAGE:
221 case SID_INSERT_MASTER_PAGE:
222 InsertSlide(rRequest);
223 rRequest.Done();
224 break;
226 case SID_DUPLICATE_PAGE:
227 DuplicateSelectedSlides(rRequest);
228 rRequest.Done();
229 break;
231 case SID_DELETE_PAGE:
232 case SID_DELETE_MASTER_PAGE:
233 case SID_DELETE: // we need SID_CUT to handle the delete key
234 // (DEL -> accelerator -> SID_CUT).
235 if (mrSlideSorter.GetModel().GetPageCount() > 1)
237 mrSlideSorter.GetController().GetSelectionManager()->DeleteSelectedPages();
240 rRequest.Done();
241 break;
243 case SID_RENAMEPAGE:
244 case SID_RENAME_MASTER_PAGE:
245 RenameSlide (rRequest);
246 rRequest.Done ();
247 break;
249 case SID_ASSIGN_LAYOUT:
251 pShell->mpImpl->AssignLayout( rRequest, PageKind::Standard );
252 rRequest.Done ();
254 break;
256 case SID_PHOTOALBUM:
258 SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
259 vcl::Window* pWin = mrSlideSorter.GetContentWindow();
260 ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateSdPhotoAlbumDialog(
261 pWin ? pWin->GetFrameWeld() : nullptr,
262 pDocument));
263 pDlg->Execute();
264 rRequest.Done ();
266 break;
268 case SID_REMOTE_DLG:
270 #ifdef ENABLE_SDREMOTE
271 SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
272 ScopedVclPtr<VclAbstractDialog> pDlg( pFact->CreateRemoteDialog( mrSlideSorter.GetContentWindow() ) );
273 pDlg->Execute();
274 #endif
276 break;
278 default:
279 break;
283 void SlotManager::FuPermanent (SfxRequest& rRequest)
285 ViewShell* pShell = mrSlideSorter.GetViewShell();
286 if (pShell == nullptr)
287 return;
289 if(pShell->GetCurrentFunction().is())
291 rtl::Reference<FuPoor> xEmpty;
292 if (pShell->GetOldFunction() == pShell->GetCurrentFunction())
293 pShell->SetOldFunction(xEmpty);
295 pShell->GetCurrentFunction()->Deactivate();
296 pShell->SetCurrentFunction(xEmpty);
299 switch(rRequest.GetSlot())
301 case SID_OBJECT_SELECT:
302 pShell->SetCurrentFunction( SelectionFunction::Create(mrSlideSorter, rRequest) );
303 rRequest.Done();
304 break;
306 default:
307 break;
310 if(pShell->GetOldFunction().is())
312 pShell->GetOldFunction()->Deactivate();
313 rtl::Reference<FuPoor> xEmpty;
314 pShell->SetOldFunction(xEmpty);
317 if(pShell->GetCurrentFunction().is())
319 pShell->GetCurrentFunction()->Activate();
320 pShell->SetOldFunction(pShell->GetCurrentFunction());
323 //! that's only until ENUM-Slots ?are
324 // Invalidate( SID_OBJECT_SELECT );
327 void SlotManager::FuSupport (SfxRequest& rRequest)
329 switch (rRequest.GetSlot())
331 case SID_STYLE_FAMILY:
332 if (rRequest.GetArgs() != nullptr)
334 SdDrawDocument* pDocument
335 = mrSlideSorter.GetModel().GetDocument();
336 if (pDocument != nullptr)
338 const SfxPoolItem& rItem (
339 rRequest.GetArgs()->Get(SID_STYLE_FAMILY));
340 pDocument->GetDocSh()->SetStyleFamily(
341 static_cast<SfxStyleFamily>(static_cast<const SfxUInt16Item&>(rItem).GetValue()));
344 break;
346 case SID_PASTE:
348 SdTransferable* pTransferClip = SD_MOD()->pTransferClip;
349 if( pTransferClip )
351 SfxObjectShell* pTransferDocShell = pTransferClip->GetDocShell().get();
353 DrawDocShell* pDocShell = dynamic_cast<DrawDocShell*>(pTransferDocShell);
354 if (pDocShell && pDocShell->GetDoc()->GetPageCount() > 1)
356 mrSlideSorter.GetController().GetClipboard().HandleSlotCall(rRequest);
357 break;
360 ViewShellBase* pBase = mrSlideSorter.GetViewShellBase();
361 if (pBase != nullptr)
363 std::shared_ptr<DrawViewShell> pDrawViewShell (
364 std::dynamic_pointer_cast<DrawViewShell>(pBase->GetMainViewShell()));
365 if (pDrawViewShell != nullptr)
366 pDrawViewShell->FuSupport(rRequest);
369 break;
371 case SID_CUT:
372 case SID_COPY:
373 case SID_DELETE:
374 mrSlideSorter.GetController().GetClipboard().HandleSlotCall(rRequest);
375 break;
377 case SID_DRAWINGMODE:
378 case SID_NOTES_MODE:
379 case SID_HANDOUT_MASTER_MODE:
380 case SID_SLIDE_SORTER_MODE:
381 case SID_OUTLINE_MODE:
383 ViewShellBase* pBase = mrSlideSorter.GetViewShellBase();
384 if (pBase != nullptr)
386 framework::FrameworkHelper::Instance(*pBase)->HandleModeChangeSlot(
387 rRequest.GetSlot(), rRequest);
388 rRequest.Done();
390 break;
393 case SID_UNDO:
395 SlideSorterViewShell* pViewShell
396 = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
397 if (pViewShell != nullptr)
399 pViewShell->ImpSidUndo (rRequest);
401 break;
404 case SID_REDO:
406 SlideSorterViewShell* pViewShell
407 = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell());
408 if (pViewShell != nullptr)
410 pViewShell->ImpSidRedo (rRequest);
412 break;
415 default:
416 break;
420 void SlotManager::ExecCtrl (SfxRequest& rRequest)
422 ViewShell* pViewShell = mrSlideSorter.GetViewShell();
423 sal_uInt16 nSlot = rRequest.GetSlot();
424 switch (nSlot)
426 case SID_RELOAD:
428 // empty Undo-Manager
429 mrSlideSorter.GetModel().GetDocument()->GetDocSh()->ClearUndoBuffer();
431 // normal forwarding to ViewFrame for execution
432 if (pViewShell != nullptr)
433 pViewShell->GetViewFrame()->ExecuteSlot(rRequest);
435 // has to be finished right away
436 return;
439 case SID_OUTPUT_QUALITY_COLOR:
440 case SID_OUTPUT_QUALITY_GRAYSCALE:
441 case SID_OUTPUT_QUALITY_BLACKWHITE:
442 case SID_OUTPUT_QUALITY_CONTRAST:
444 // flush page cache
445 if (pViewShell != nullptr)
446 pViewShell->ExecReq (rRequest);
447 break;
450 case SID_MAIL_SCROLLBODY_PAGEDOWN:
452 if (pViewShell != nullptr)
453 pViewShell->ExecReq (rRequest);
454 break;
457 case SID_OPT_LOCALE_CHANGED:
459 mrSlideSorter.GetController().UpdateAllPages();
460 if (pViewShell != nullptr)
461 pViewShell->UpdatePreview (pViewShell->GetActualPage());
462 rRequest.Done();
463 break;
466 case SID_SEARCH_DLG:
467 // We have to handle the SID_SEARCH_DLG slot explicitly because
468 // in some cases (when the slide sorter is displayed in the
469 // center pane) we want to disable the search dialog. Therefore
470 // we have to handle the execution of that slot as well.
471 // We try to do that by forwarding the request to the view frame
472 // of the view shell.
473 if (pViewShell != nullptr)
474 pViewShell->GetViewFrame()->ExecuteSlot(rRequest);
475 break;
477 default:
478 break;
482 void SlotManager::GetAttrState (SfxItemSet& rSet)
484 // Iterate over all items.
485 SfxWhichIter aIter (rSet);
486 sal_uInt16 nWhich = aIter.FirstWhich();
487 while (nWhich)
489 sal_uInt16 nSlotId (nWhich);
490 if (SfxItemPool::IsWhich(nWhich) && mrSlideSorter.GetViewShell()!=nullptr)
491 nSlotId = mrSlideSorter.GetViewShell()->GetPool().GetSlotId(nWhich);
492 switch (nSlotId)
494 case SID_PAGES_PER_ROW:
495 rSet.Put (
496 SfxUInt16Item (
497 nSlotId,
498 static_cast<sal_uInt16>(mrSlideSorter.GetView().GetLayouter().GetColumnCount())
501 break;
503 nWhich = aIter.NextWhich();
507 void SlotManager::GetMenuState (SfxItemSet& rSet)
509 EditMode eEditMode = mrSlideSorter.GetModel().GetEditMode();
510 ViewShell* pShell = mrSlideSorter.GetViewShell();
511 DrawDocShell* pDocShell = mrSlideSorter.GetModel().GetDocument()->GetDocSh();
513 if (pShell!=nullptr && pShell->GetCurrentFunction().is())
515 sal_uInt16 nSId = pShell->GetCurrentFunction()->GetSlotID();
517 rSet.Put( SfxBoolItem( nSId, true ) );
519 rSet.Put( SfxBoolItem( SID_DRAWINGMODE, false ) );
520 rSet.Put( SfxBoolItem( SID_SLIDE_SORTER_MODE, true ) );
521 rSet.Put( SfxBoolItem( SID_OUTLINE_MODE, false ) );
522 rSet.Put( SfxBoolItem( SID_NOTES_MODE, false ) );
523 rSet.Put( SfxBoolItem( SID_HANDOUT_MASTER_MODE, false ) );
525 if (pShell!=nullptr && pShell->IsMainViewShell())
527 rSet.DisableItem(SID_SPELL_DIALOG);
528 rSet.DisableItem(SID_SEARCH_DLG);
531 if (SfxItemState::DEFAULT == rSet.GetItemState(SID_EXPAND_PAGE))
533 bool bDisable = true;
534 if (eEditMode == EditMode::Page)
536 // At least one of the selected pages has to contain an outline
537 // presentation objects in order to enable the expand page menu
538 // entry.
539 model::PageEnumeration aSelectedPages (
540 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
541 mrSlideSorter.GetModel()));
542 while (aSelectedPages.HasMoreElements())
544 SdPage* pPage = aSelectedPages.GetNextElement()->GetPage();
545 SdrObject* pObj = pPage->GetPresObj(PRESOBJ_OUTLINE);
546 if (pObj!=nullptr )
548 if( !pObj->IsEmptyPresObj() )
550 bDisable = false;
552 else
554 // check if the object is in edit, than its temporarily not empty
555 SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObj );
556 if( pTextObj )
558 std::unique_ptr<OutlinerParaObject> pParaObj = pTextObj->GetEditOutlinerParaObject();
559 if( pParaObj )
561 bDisable = false;
569 if (bDisable)
570 rSet.DisableItem (SID_EXPAND_PAGE);
573 if (SfxItemState::DEFAULT == rSet.GetItemState(SID_SUMMARY_PAGE))
575 bool bDisable = true;
576 if (eEditMode == EditMode::Page)
578 // At least one of the selected pages has to contain a title
579 // presentation objects in order to enable the summary page menu
580 // entry.
581 model::PageEnumeration aSelectedPages (
582 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
583 mrSlideSorter.GetModel()));
584 while (aSelectedPages.HasMoreElements())
586 SdPage* pPage = aSelectedPages.GetNextElement()->GetPage();
587 SdrObject* pObj = pPage->GetPresObj(PRESOBJ_TITLE);
589 if (pObj!=nullptr && !pObj->IsEmptyPresObj())
590 bDisable = false;
593 if (bDisable)
594 rSet.DisableItem (SID_SUMMARY_PAGE);
597 // starting of presentation possible?
598 if( SfxItemState::DEFAULT == rSet.GetItemState( SID_PRESENTATION ) ||
599 SfxItemState::DEFAULT == rSet.GetItemState( SID_REHEARSE_TIMINGS ) )
601 bool bDisable = true;
602 model::PageEnumeration aAllPages (
603 model::PageEnumerationProvider::CreateAllPagesEnumeration(mrSlideSorter.GetModel()));
604 while (aAllPages.HasMoreElements())
606 SdPage* pPage = aAllPages.GetNextElement()->GetPage();
608 if( !pPage->IsExcluded() )
609 bDisable = false;
611 if( bDisable || pDocShell->IsPreview())
613 rSet.DisableItem( SID_PRESENTATION );
614 rSet.DisableItem( SID_REHEARSE_TIMINGS );
618 // Disable the rename slots when there are no or more than one slides/master
619 // pages selected; disable the duplicate slot when there are no slides
620 // selected:
621 if (rSet.GetItemState(SID_RENAMEPAGE) == SfxItemState::DEFAULT
622 || rSet.GetItemState(SID_RENAME_MASTER_PAGE) == SfxItemState::DEFAULT
623 || rSet.GetItemState(SID_DUPLICATE_PAGE) == SfxItemState::DEFAULT)
625 int n = mrSlideSorter.GetController().GetPageSelector()
626 .GetSelectedPageCount();
627 if (n != 1)
629 rSet.DisableItem(SID_RENAMEPAGE);
630 rSet.DisableItem(SID_RENAME_MASTER_PAGE);
632 if (n == 0)
634 rSet.DisableItem(SID_DUPLICATE_PAGE);
638 if (rSet.GetItemState(SID_HIDE_SLIDE) == SfxItemState::DEFAULT
639 || rSet.GetItemState(SID_SHOW_SLIDE) == SfxItemState::DEFAULT)
641 model::PageEnumeration aSelectedPages (
642 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
643 mrSlideSorter.GetModel()));
644 const SlideExclusionState eState (GetSlideExclusionState(aSelectedPages));
645 switch (eState)
647 case MIXED:
648 // Show both entries.
649 break;
651 case EXCLUDED:
652 rSet.DisableItem(SID_HIDE_SLIDE);
653 break;
655 case INCLUDED:
656 rSet.DisableItem(SID_SHOW_SLIDE);
657 break;
659 case UNDEFINED:
660 rSet.DisableItem(SID_HIDE_SLIDE);
661 rSet.DisableItem(SID_SHOW_SLIDE);
662 break;
666 if (eEditMode == EditMode::MasterPage)
668 // Disable some slots when in master page mode.
669 rSet.DisableItem(SID_ASSIGN_LAYOUT);
670 rSet.DisableItem(SID_INSERTPAGE);
672 if (rSet.GetItemState(SID_DUPLICATE_PAGE) == SfxItemState::DEFAULT)
673 rSet.DisableItem(SID_DUPLICATE_PAGE);
677 void SlotManager::GetClipboardState ( SfxItemSet& rSet)
679 SdTransferable* pTransferClip = SD_MOD()->pTransferClip;
681 if (rSet.GetItemState(SID_PASTE) == SfxItemState::DEFAULT
682 || rSet.GetItemState(SID_PASTE_SPECIAL) == SfxItemState::DEFAULT)
684 // no own clipboard data?
685 if ( !pTransferClip || !pTransferClip->GetDocShell().is() )
687 rSet.DisableItem(SID_PASTE);
688 rSet.DisableItem(SID_PASTE_SPECIAL);
690 else
692 SfxObjectShell* pTransferDocShell = pTransferClip->GetDocShell().get();
694 if( !pTransferDocShell || static_cast<DrawDocShell*>(pTransferDocShell)->GetDoc()->GetPageCount() <= 1 )
696 bool bIsPastingSupported (false);
698 // No or just one page. Check if there is anything that can be
699 // pasted via a DrawViewShell.
700 ViewShellBase* pBase = mrSlideSorter.GetViewShellBase();
701 if (pBase != nullptr)
703 std::shared_ptr<DrawViewShell> pDrawViewShell (
704 std::dynamic_pointer_cast<DrawViewShell>(pBase->GetMainViewShell()));
705 if (pDrawViewShell != nullptr)
707 TransferableDataHelper aDataHelper (
708 TransferableDataHelper::CreateFromSystemClipboard(
709 pDrawViewShell->GetActiveWindow()));
710 if (aDataHelper.GetFormatCount() > 0)
711 bIsPastingSupported = true;
715 if ( ! bIsPastingSupported)
717 rSet.DisableItem(SID_PASTE);
718 rSet.DisableItem(SID_PASTE_SPECIAL);
724 // Cut, copy and paste of master pages is not yet implemented properly
725 if (rSet.GetItemState(SID_COPY) == SfxItemState::DEFAULT
726 || rSet.GetItemState(SID_PASTE) == SfxItemState::DEFAULT
727 || rSet.GetItemState(SID_PASTE_SPECIAL) == SfxItemState::DEFAULT
728 || rSet.GetItemState(SID_CUT) == SfxItemState::DEFAULT)
730 if (mrSlideSorter.GetModel().GetEditMode() == EditMode::MasterPage)
732 if (rSet.GetItemState(SID_CUT) == SfxItemState::DEFAULT)
733 rSet.DisableItem(SID_CUT);
734 if (rSet.GetItemState(SID_COPY) == SfxItemState::DEFAULT)
735 rSet.DisableItem(SID_COPY);
736 if (rSet.GetItemState(SID_PASTE) == SfxItemState::DEFAULT)
737 rSet.DisableItem(SID_PASTE);
738 if (rSet.GetItemState(SID_PASTE_SPECIAL) == SfxItemState::DEFAULT)
739 rSet.DisableItem(SID_PASTE_SPECIAL);
743 // Cut, copy, and delete page are disabled when there is no selection.
744 if (!(rSet.GetItemState(SID_CUT) == SfxItemState::DEFAULT
745 || rSet.GetItemState(SID_COPY) == SfxItemState::DEFAULT
746 || rSet.GetItemState(SID_DELETE) == SfxItemState::DEFAULT
747 || rSet.GetItemState(SID_DELETE_PAGE) == SfxItemState::DEFAULT
748 || rSet.GetItemState(SID_DELETE_MASTER_PAGE) == SfxItemState::DEFAULT))
749 return;
751 model::PageEnumeration aSelectedPages (
752 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
753 mrSlideSorter.GetModel()));
755 // For copy to work we have to have at least one selected page.
756 if ( ! aSelectedPages.HasMoreElements())
757 rSet.DisableItem(SID_COPY);
759 bool bDisable = false;
760 // The operations that lead to the deletion of a page are valid if
761 // a) there is at least one selected page
762 // b) deleting the selected pages leaves at least one page in the
763 // document
764 // c) selected master pages must not be used by slides.
766 // Test a).
767 if ( ! aSelectedPages.HasMoreElements())
768 bDisable = true;
769 // Test b): Count the number of selected pages. It has to be less
770 // than the number of all pages.
771 else if (mrSlideSorter.GetController().GetPageSelector().GetSelectedPageCount()
772 >= mrSlideSorter.GetController().GetPageSelector().GetPageCount())
773 bDisable = true;
774 // Test c): Iterate over the selected pages and look for a master
775 // page that is used by at least one page.
776 else while (aSelectedPages.HasMoreElements())
778 SdPage* pPage = aSelectedPages.GetNextElement()->GetPage();
779 int nUseCount (mrSlideSorter.GetModel().GetDocument()
780 ->GetMasterPageUserCount(pPage));
781 if (nUseCount > 0)
783 bDisable = true;
784 break;
788 if (bDisable)
790 rSet.DisableItem(SID_CUT);
791 rSet.DisableItem(SID_DELETE_PAGE);
792 rSet.DisableItem(SID_DELETE_MASTER_PAGE);
796 void SlotManager::GetStatusBarState (SfxItemSet& rSet)
798 // page view and layout
799 SdPage* pPage = nullptr;
800 SdPage* pFirstPage = nullptr;
801 sal_uInt16 nFirstPage;
802 sal_Int32 nPageCount;
803 sal_Int32 nActivePageCount;
804 sal_uInt16 nSelectedPages = mrSlideSorter.GetController().GetPageSelector().GetSelectedPageCount();
805 OUString aPageStr;
806 OUString aLayoutStr;
808 //Set number of slides
809 if (nSelectedPages > 0)
811 model::PageEnumeration aSelectedPages (
812 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
813 mrSlideSorter.GetModel()));
814 model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
815 if (pDescriptor)
817 pPage = pDescriptor->GetPage();
818 nFirstPage = (pPage->GetPageNum()/2) + 1;
819 nPageCount = mrSlideSorter.GetModel().GetPageCount();
820 nActivePageCount = static_cast<sal_Int32>(mrSlideSorter.GetModel().GetDocument()->GetActiveSdPageCount());
822 aPageStr = (nPageCount == nActivePageCount) ? SdResId(STR_SD_PAGE_COUNT) : SdResId(STR_SD_PAGE_COUNT_CUSTOM);
824 aPageStr = aPageStr.replaceFirst("%1", OUString::number(nFirstPage));
825 aPageStr = aPageStr.replaceFirst("%2", OUString::number(nPageCount));
826 if(nPageCount != nActivePageCount)
827 aPageStr = aPageStr.replaceFirst("%3", OUString::number(nActivePageCount));
829 rSet.Put( SfxStringItem( SID_STATUS_PAGE, aPageStr ) );
831 //Set layout
832 if (nSelectedPages == 1 && pPage != nullptr)
834 pFirstPage = pPage;
835 aLayoutStr = pFirstPage->GetLayoutName();
836 sal_Int32 nIndex = aLayoutStr.indexOf( SD_LT_SEPARATOR );
837 if( nIndex != -1 )
838 aLayoutStr = aLayoutStr.copy(0, nIndex);
839 rSet.Put( SfxStringItem( SID_STATUS_LAYOUT, aLayoutStr ) );
843 void SlotManager::RenameSlide(const SfxRequest& rRequest)
845 View* pDrView = &mrSlideSorter.GetView();
847 if ( pDrView->IsTextEdit() )
849 pDrView->SdrEndTextEdit();
852 SdPage* pSelectedPage = nullptr;
853 model::PageEnumeration aSelectedPages (
854 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
855 mrSlideSorter.GetModel()));
856 if (aSelectedPages.HasMoreElements())
857 pSelectedPage = aSelectedPages.GetNextElement()->GetPage();
858 if (pSelectedPage == nullptr)
859 return;
861 // tdf#107183 Set different dialog titles when renaming
862 // master slides or normal ones
863 OUString aTitle;
864 if( rRequest.GetSlot() == SID_RENAME_MASTER_PAGE )
865 aTitle = SdResId( STR_TITLE_RENAMEMASTER );
866 else
867 aTitle = SdResId( STR_TITLE_RENAMESLIDE );
869 OUString aDescr( SdResId( STR_DESC_RENAMESLIDE ) );
870 OUString aPageName = pSelectedPage->GetName();
872 if(rRequest.GetArgs())
874 OUString aName = rRequest.GetArgs()->GetItem<const SfxStringItem>(SID_RENAMEPAGE)->GetValue();
876 bool bResult = RenameSlideFromDrawViewShell(pSelectedPage->GetPageNum()/2, aName );
877 DBG_ASSERT( bResult, "Couldn't rename slide" );
879 else
881 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
882 vcl::Window* pWin = mrSlideSorter.GetContentWindow();
883 ScopedVclPtr<AbstractSvxNameDialog> aNameDlg(pFact->CreateSvxNameDialog(
884 pWin ? pWin->GetFrameWeld() : nullptr,
885 aPageName, aDescr));
886 aNameDlg->SetText( aTitle );
887 aNameDlg->SetCheckNameHdl( LINK( this, SlotManager, RenameSlideHdl ), true );
888 aNameDlg->SetEditHelpId( HID_SD_NAMEDIALOG_PAGE );
890 if( aNameDlg->Execute() == RET_OK )
892 OUString aNewName;
893 aNameDlg->GetName( aNewName );
894 if (aNewName != aPageName)
896 bool bResult =
897 RenameSlideFromDrawViewShell(
898 pSelectedPage->GetPageNum()/2, aNewName );
899 DBG_ASSERT( bResult, "Couldn't rename slide" );
902 aNameDlg.disposeAndClear();
904 // Tell the slide sorter about the name change (necessary for
905 // accessibility.)
906 mrSlideSorter.GetController().PageNameHasChanged(
907 (pSelectedPage->GetPageNum()-1)/2, aPageName);
910 IMPL_LINK(SlotManager, RenameSlideHdl, AbstractSvxNameDialog&, rDialog, bool)
912 OUString aNewName;
913 rDialog.GetName( aNewName );
915 model::SharedPageDescriptor pDescriptor (
916 mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide());
917 SdPage* pCurrentPage = nullptr;
918 if (pDescriptor.get() != nullptr)
919 pCurrentPage = pDescriptor->GetPage();
921 return (pCurrentPage!=nullptr && aNewName == pCurrentPage->GetName())
922 || (mrSlideSorter.GetViewShell()
923 && mrSlideSorter.GetViewShell()->GetDocSh()->IsNewPageNameValid( aNewName ) );
926 bool SlotManager::RenameSlideFromDrawViewShell( sal_uInt16 nPageId, const OUString & rName )
928 bool bOutDummy;
929 SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
930 if( pDocument->GetPageByName( rName, bOutDummy ) != SDRPAGE_NOTFOUND )
931 return false;
933 SdPage* pPageToRename = nullptr;
935 SfxUndoManager* pManager = pDocument->GetDocSh()->GetUndoManager();
937 if( mrSlideSorter.GetModel().GetEditMode() == EditMode::Page )
939 model::SharedPageDescriptor pDescriptor (
940 mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide());
941 if (pDescriptor.get() != nullptr)
942 pPageToRename = pDescriptor->GetPage();
944 if (pPageToRename != nullptr)
946 // Undo
947 SdPage* pUndoPage = pPageToRename;
948 SdrLayerAdmin & rLayerAdmin = pDocument->GetLayerAdmin();
949 SdrLayerID nBackground = rLayerAdmin.GetLayerID(sUNO_LayerName_background);
950 SdrLayerID nBgObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects);
951 SdrLayerIDSet aVisibleLayers = pPageToRename->TRG_GetMasterPageVisibleLayers();
953 // (#67720#)
954 pManager->AddUndoAction(
955 std::make_unique<ModifyPageUndoAction>(
956 pDocument, pUndoPage, rName, pUndoPage->GetAutoLayout(),
957 aVisibleLayers.IsSet( nBackground ),
958 aVisibleLayers.IsSet( nBgObj )));
960 // rename
961 pPageToRename->SetName( rName );
963 // also rename notes-page
964 SdPage* pNotesPage = pDocument->GetSdPage( nPageId, PageKind::Notes );
965 if (pNotesPage != nullptr)
966 pNotesPage->SetName (rName);
969 else
971 // rename MasterPage -> rename LayoutTemplate
972 pPageToRename = pDocument->GetMasterSdPage( nPageId, PageKind::Standard );
973 if (pPageToRename != nullptr)
975 const OUString aOldLayoutName( pPageToRename->GetLayoutName() );
976 pManager->AddUndoAction( std::make_unique<RenameLayoutTemplateUndoAction>( pDocument, aOldLayoutName, rName ) );
977 pDocument->RenameLayoutTemplate( aOldLayoutName, rName );
981 bool bSuccess = pPageToRename!=nullptr && ( rName == pPageToRename->GetName() );
983 if( bSuccess )
985 // user edited page names may be changed by the page so update control
986 // aTabControl.SetPageText( nPageId, rName );
988 // set document to modified state
989 pDocument->SetChanged();
991 // inform navigator about change
992 SfxBoolItem aItem( SID_NAVIGATOR_INIT, true );
993 if (mrSlideSorter.GetViewShell() != nullptr)
994 mrSlideSorter.GetViewShell()->GetDispatcher()->ExecuteList(
995 SID_NAVIGATOR_INIT,
996 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
997 { &aItem });
1000 return bSuccess;
1003 /** Insert a slide. The insertion position depends on a) the selection and
1004 b) the mouse position when there is no selection.
1006 When there is a selection then insertion takes place after the last
1007 slide of the selection. For this to work all but the last selected
1008 slide are deselected first.
1010 Otherwise, when there is no selection but the insertion marker is visible
1011 the slide is inserted at that position. The slide before that marker is
1012 selected first.
1014 When both the selection and the insertion marker are not visible--can
1015 that happen?--the new slide is inserted after the last slide.
1017 void SlotManager::InsertSlide (SfxRequest& rRequest)
1019 const sal_Int32 nInsertionIndex (GetInsertionPosition());
1021 PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter);
1023 SdPage* pNewPage = nullptr;
1024 if (mrSlideSorter.GetModel().GetEditMode() == EditMode::Page)
1026 SlideSorterViewShell* pShell = dynamic_cast<SlideSorterViewShell*>(
1027 mrSlideSorter.GetViewShell());
1028 if (pShell != nullptr)
1030 pNewPage = pShell->CreateOrDuplicatePage (
1031 rRequest,
1032 PageKind::Standard,
1033 nInsertionIndex>=0
1034 ? mrSlideSorter.GetModel().GetPageDescriptor(nInsertionIndex)->GetPage()
1035 : nullptr);
1038 else
1040 // Use the API to create a new page.
1041 SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument();
1042 Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier (
1043 pDocument->getUnoModel(), UNO_QUERY);
1044 if (xMasterPagesSupplier.is())
1046 Reference<drawing::XDrawPages> xMasterPages (
1047 xMasterPagesSupplier->getMasterPages());
1048 if (xMasterPages.is())
1050 xMasterPages->insertNewByIndex (nInsertionIndex+1);
1052 // Create shapes for the default layout.
1053 pNewPage = pDocument->GetMasterSdPage(
1054 static_cast<sal_uInt16>(nInsertionIndex+1), PageKind::Standard);
1055 pNewPage->CreateTitleAndLayout (true,true);
1059 if (pNewPage == nullptr)
1060 return;
1062 // When a new page has been inserted then select it, make it the
1063 // current page, and focus it.
1064 view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter);
1065 PageSelector::UpdateLock aUpdateLock (mrSlideSorter);
1066 mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
1067 mrSlideSorter.GetController().GetPageSelector().SelectPage(pNewPage);
1070 void SlotManager::DuplicateSelectedSlides (SfxRequest& rRequest)
1072 // Create a list of the pages that are to be duplicated. The process of
1073 // duplication alters the selection.
1074 sal_Int32 nInsertPosition (0);
1075 ::std::vector<SdPage*> aPagesToDuplicate;
1076 model::PageEnumeration aSelectedPages (
1077 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel()));
1078 while (aSelectedPages.HasMoreElements())
1080 model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
1081 if (pDescriptor && pDescriptor->GetPage())
1083 aPagesToDuplicate.push_back(pDescriptor->GetPage());
1084 nInsertPosition = pDescriptor->GetPage()->GetPageNum()+2;
1088 // Duplicate the pages in aPagesToDuplicate and collect the newly
1089 // created pages in aPagesToSelect.
1090 const bool bUndo (aPagesToDuplicate.size()>1 && mrSlideSorter.GetView().IsUndoEnabled());
1091 if (bUndo)
1092 mrSlideSorter.GetView().BegUndo(SdResId(STR_INSERTPAGE));
1094 ::std::vector<SdPage*> aPagesToSelect;
1095 for(const auto& rpPage : aPagesToDuplicate)
1097 aPagesToSelect.push_back(
1098 mrSlideSorter.GetViewShell()->CreateOrDuplicatePage(
1099 rRequest, PageKind::Standard, rpPage, nInsertPosition));
1100 nInsertPosition += 2;
1102 aPagesToDuplicate.clear();
1104 if (bUndo)
1105 mrSlideSorter.GetView().EndUndo();
1107 // Set the selection to the pages in aPagesToSelect.
1108 PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector());
1109 rSelector.DeselectAllPages();
1110 for (auto const& it: aPagesToSelect)
1112 rSelector.SelectPage(it);
1116 void SlotManager::ChangeSlideExclusionState (
1117 const model::SharedPageDescriptor& rpDescriptor,
1118 const bool bExcludeSlide)
1120 if (rpDescriptor)
1122 mrSlideSorter.GetView().SetState(
1123 rpDescriptor,
1124 model::PageDescriptor::ST_Excluded,
1125 bExcludeSlide);
1127 else
1129 model::PageEnumeration aSelectedPages (
1130 model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
1131 mrSlideSorter.GetModel()));
1132 while (aSelectedPages.HasMoreElements())
1134 model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement());
1135 mrSlideSorter.GetView().SetState(
1136 pDescriptor,
1137 model::PageDescriptor::ST_Excluded,
1138 bExcludeSlide);
1142 SfxBindings& rBindings (mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings());
1143 rBindings.Invalidate(SID_PRESENTATION);
1144 rBindings.Invalidate(SID_REHEARSE_TIMINGS);
1145 rBindings.Invalidate(SID_HIDE_SLIDE);
1146 rBindings.Invalidate(SID_SHOW_SLIDE);
1147 mrSlideSorter.GetModel().GetDocument()->SetChanged();
1150 sal_Int32 SlotManager::GetInsertionPosition()
1152 PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector());
1154 // The insertion indicator is preferred. After all the user explicitly
1155 // used it to define the insertion position.
1156 if (mrSlideSorter.GetController().GetInsertionIndicatorHandler()->IsActive())
1158 // Select the page before the insertion indicator.
1159 return mrSlideSorter.GetController().GetInsertionIndicatorHandler()->GetInsertionPageIndex()
1160 - 1;
1163 // Is there a stored insertion position?
1164 else if (mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() >= 0)
1166 return mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() - 1;
1169 // Use the index of the last selected slide.
1170 else if (rSelector.GetSelectedPageCount() > 0)
1172 for (int nIndex=rSelector.GetPageCount()-1; nIndex>=0; --nIndex)
1173 if (rSelector.IsPageSelected(nIndex))
1174 return nIndex;
1176 // We should never get here.
1177 OSL_ASSERT(false);
1178 return rSelector.GetPageCount() - 1;
1181 // Select the last page when there is at least one page.
1182 else if (rSelector.GetPageCount() > 0)
1184 return rSelector.GetPageCount() - 1;
1187 // Hope for the best that CreateOrDuplicatePage() can cope with an empty
1188 // selection.
1189 else
1191 // We should never get here because there has to be at least one page.
1192 OSL_ASSERT(false);
1193 return -1;
1197 void SlotManager::NotifyEditModeChange()
1199 SfxBindings& rBindings (mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings());
1200 rBindings.Invalidate(SID_PRESENTATION);
1201 rBindings.Invalidate(SID_INSERTPAGE);
1202 rBindings.Invalidate(SID_DUPLICATE_PAGE);
1205 namespace {
1207 SlideExclusionState GetSlideExclusionState (model::PageEnumeration& rPageSet)
1209 SlideExclusionState eState (UNDEFINED);
1211 // Get toggle state of the selected pages.
1212 while (rPageSet.HasMoreElements() && eState!=MIXED)
1214 const bool bState = rPageSet.GetNextElement()->GetPage()->IsExcluded();
1215 switch (eState)
1217 case UNDEFINED:
1218 // Use the first selected page to set the initial value.
1219 eState = bState ? EXCLUDED : INCLUDED;
1220 break;
1222 case EXCLUDED:
1223 // The pages before where all not part of the show,
1224 // this one is.
1225 if ( ! bState)
1226 eState = MIXED;
1227 break;
1229 case INCLUDED:
1230 // The pages before where all part of the show,
1231 // this one is not.
1232 if (bState)
1233 eState = MIXED;
1234 break;
1236 default:
1237 // No need to change anything.
1238 break;
1242 return eState;
1245 } // end of anonymous namespace
1247 } } } // end of namespace ::sd::slidesorter::controller
1249 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */