1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <controller/SlsSelectionManager.hxx>
22 #include <SlideSorter.hxx>
23 #include <controller/SlideSorterController.hxx>
24 #include <controller/SlsCurrentSlideManager.hxx>
25 #include <controller/SlsFocusManager.hxx>
26 #include <controller/SlsPageSelector.hxx>
27 #include <controller/SlsSelectionObserver.hxx>
28 #include <model/SlideSorterModel.hxx>
29 #include <model/SlsPageEnumerationProvider.hxx>
30 #include <model/SlsPageDescriptor.hxx>
31 #include <view/SlideSorterView.hxx>
32 #include <comphelper/diagnose_ex.hxx>
33 #include <drawdoc.hxx>
35 #include <unomodel.hxx>
36 #include <drawview.hxx>
37 #include <DrawViewShell.hxx>
38 #include <ViewShellBase.hxx>
39 #include <svx/svxids.hrc>
40 #include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
41 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
44 #include <sdresid.hxx>
45 #include <strings.hrc>
48 using namespace ::com::sun::star
;
49 using namespace ::com::sun::star::drawing
;
50 using namespace ::com::sun::star::uno
;
51 using namespace ::sd::slidesorter::model
;
52 using namespace ::sd::slidesorter::view
;
53 using namespace ::sd::slidesorter::controller
;
55 namespace sd::slidesorter::controller
{
57 SelectionManager::SelectionManager (SlideSorter
& rSlideSorter
)
58 : mrSlideSorter(rSlideSorter
),
59 mrController(rSlideSorter
.GetController()),
60 mnInsertionPosition(-1),
61 mpSelectionObserver(std::make_shared
<SelectionObserver
>(rSlideSorter
))
65 SelectionManager::~SelectionManager()
69 void SelectionManager::DeleteSelectedPages (const bool bSelectFollowingPage
)
71 // Create some locks to prevent updates of the model, view, selection
72 // state while modifying any of them.
73 SlideSorterController::ModelChangeLock
aLock (mrController
);
74 SlideSorterView::DrawLock
aDrawLock (mrSlideSorter
);
75 PageSelector::UpdateLock
aSelectionLock (mrSlideSorter
);
78 bool bIsFocusShowing
= mrController
.GetFocusManager().IsFocusShowing();
80 mrController
.GetFocusManager().ToggleFocus();
82 // Store pointers to all selected page descriptors. This is necessary
83 // because the pages get deselected when the first one is deleted.
84 model::PageEnumeration
aPageEnumeration (
85 PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter
.GetModel()));
86 ::std::vector
<SdPage
*> aSelectedPages
;
87 sal_Int32
nNewCurrentSlide (-1);
88 while (aPageEnumeration
.HasMoreElements())
90 SharedPageDescriptor
pDescriptor (aPageEnumeration
.GetNextElement());
91 aSelectedPages
.push_back(pDescriptor
->GetPage());
92 if (bSelectFollowingPage
|| nNewCurrentSlide
<0)
93 nNewCurrentSlide
= pDescriptor
->GetPageIndex();
95 if (aSelectedPages
.empty())
98 // Determine the slide to select (and thereby make the current slide)
99 // after the deletion.
100 if (bSelectFollowingPage
)
101 nNewCurrentSlide
-= aSelectedPages
.size() - 1;
105 const auto pViewShell
= mrSlideSorter
.GetViewShell();
106 const auto pDrawViewShell
= pViewShell
? std::dynamic_pointer_cast
<sd::DrawViewShell
>(pViewShell
->GetViewShellBase().GetMainViewShell()) : nullptr;
107 const auto pDrawView
= pDrawViewShell
? pDrawViewShell
->GetDrawView() : nullptr;
110 pDrawView
->BlockPageOrderChangedHint(true);
112 // Proper naming for the undo action
113 OUString
sUndoComment(SdResId(STR_UNDO_DELETEPAGES
));
114 if (mrSlideSorter
.GetView().GetDoc().GetDocumentType() == DocumentType::Draw
)
115 sUndoComment
= SdResId(STR_UNDO_DELETEPAGES_DRAW
);
117 // The actual deletion of the selected pages is done in one of two
118 // helper functions. They are specialized for normal respectively for
120 mrSlideSorter
.GetView().BegUndo (sUndoComment
);
121 if (mrSlideSorter
.GetModel().GetEditMode() == EditMode::Page
)
122 DeleteSelectedNormalPages(aSelectedPages
);
124 DeleteSelectedMasterPages(aSelectedPages
);
125 mrSlideSorter
.GetView().EndUndo ();
127 mrController
.HandleModelChange();
131 assert(pDrawViewShell
);
132 pDrawView
->BlockPageOrderChangedHint(false);
133 pDrawViewShell
->ResetActualPage();
136 // Show focus and move it to next valid location.
138 mrController
.GetFocusManager().ToggleFocus();
140 // Set the new current slide.
141 if (nNewCurrentSlide
< 0)
142 nNewCurrentSlide
= 0;
143 else if (nNewCurrentSlide
>= mrSlideSorter
.GetModel().GetPageCount())
144 nNewCurrentSlide
= mrSlideSorter
.GetModel().GetPageCount()-1;
145 mrController
.GetPageSelector().CountSelectedPages();
146 mrController
.GetPageSelector().SelectPage(nNewCurrentSlide
);
147 mrController
.GetFocusManager().SetFocusedPage(nNewCurrentSlide
);
150 void SelectionManager::DeleteSelectedNormalPages (const ::std::vector
<SdPage
*>& rSelectedPages
)
152 // Prepare the deletion via the UNO API.
153 OSL_ASSERT(mrSlideSorter
.GetModel().GetEditMode() == EditMode::Page
);
157 rtl::Reference
<SdXImpressDocument
> xDrawPagesSupplier( mrSlideSorter
.GetModel().GetDocument()->getUnoModel() );
158 if (!xDrawPagesSupplier
)
160 Reference
<drawing::XDrawPages
> xPages( xDrawPagesSupplier
->getDrawPages(), UNO_SET_THROW
);
162 // Iterate over all pages that were selected when this method was called
163 // and delete the draw page the notes page. The iteration is done in
164 // reverse order so that when one slide is not deleted (to avoid an
165 // empty document) the remaining slide is the first one.
166 ::std::vector
<SdPage
*>::const_reverse_iterator aI
;
167 for (aI
=rSelectedPages
.rbegin(); aI
!=rSelectedPages
.rend(); ++aI
)
169 // Do not delete the last slide in the document.
170 if (xPages
->getCount() <= 1)
173 const sal_uInt16
nPage (model::FromCoreIndex((*aI
)->GetPageNum()));
175 Reference
< XDrawPage
> xPage( xPages
->getByIndex( nPage
), UNO_QUERY_THROW
);
176 xPages
->remove(xPage
);
181 TOOLS_WARN_EXCEPTION( "sd", "SelectionManager::DeleteSelectedNormalPages()");
185 void SelectionManager::DeleteSelectedMasterPages (const ::std::vector
<SdPage
*>& rSelectedPages
)
187 // Prepare the deletion via the UNO API.
188 OSL_ASSERT(mrSlideSorter
.GetModel().GetEditMode() == EditMode::MasterPage
);
192 rtl::Reference
<SdXImpressDocument
> xDrawPagesSupplier( mrSlideSorter
.GetModel().GetDocument()->getUnoModel() );
193 if (!xDrawPagesSupplier
)
195 Reference
<drawing::XDrawPages
> xPages( xDrawPagesSupplier
->getMasterPages(), UNO_SET_THROW
);
197 // Iterate over all pages that were selected when this method was called
198 // and delete the draw page the notes page. The iteration is done in
199 // reverse order so that when one slide is not deleted (to avoid an
200 // empty document) the remaining slide is the first one.
201 ::std::vector
<SdPage
*>::const_reverse_iterator aI
;
202 for (aI
=rSelectedPages
.rbegin(); aI
!=rSelectedPages
.rend(); ++aI
)
204 // Do not delete the last slide in the document.
205 if (xPages
->getCount() <= 1)
208 const sal_uInt16
nPage (model::FromCoreIndex((*aI
)->GetPageNum()));
210 Reference
< XDrawPage
> xPage( xPages
->getByIndex( nPage
), UNO_QUERY_THROW
);
211 xPages
->remove(xPage
);
216 TOOLS_WARN_EXCEPTION( "sd", "SelectionManager::DeleteSelectedMasterPages()");
220 void SelectionManager::SelectionHasChanged ()
222 ViewShell
* pViewShell
= mrSlideSorter
.GetViewShell();
223 if (pViewShell
== nullptr)
226 pViewShell
->Invalidate (SID_EXPAND_PAGE
);
227 pViewShell
->Invalidate (SID_SUMMARY_PAGE
);
228 pViewShell
->Invalidate(SID_SHOW_SLIDE
);
229 pViewShell
->Invalidate(SID_HIDE_SLIDE
);
230 pViewShell
->Invalidate(SID_DELETE_PAGE
);
231 pViewShell
->Invalidate(SID_DELETE_MASTER_PAGE
);
232 pViewShell
->Invalidate(SID_ASSIGN_LAYOUT
);
235 pViewShell
->Invalidate (SID_STATUS_PAGE
);
236 pViewShell
->Invalidate (SID_STATUS_LAYOUT
);
237 pViewShell
->Invalidate (SID_SCALE
);
239 OSL_ASSERT(mrController
.GetCurrentSlideManager());
240 SharedPageDescriptor
pDescriptor(mrController
.GetCurrentSlideManager()->GetCurrentSlide());
242 pViewShell
->UpdatePreview(pDescriptor
->GetPage());
244 // Tell the selection change listeners that the selection has changed.
245 for (const auto& rLink
: maSelectionChangeListeners
)
250 // Reset the insertion position: until set again it is calculated from
251 // the current selection.
252 mnInsertionPosition
= -1;
255 void SelectionManager::AddSelectionChangeListener (const Link
<LinkParamNone
*,void>& rListener
)
258 maSelectionChangeListeners
.begin(),
259 maSelectionChangeListeners
.end(),
260 rListener
) == maSelectionChangeListeners
.end())
262 maSelectionChangeListeners
.push_back (rListener
);
266 void SelectionManager::RemoveSelectionChangeListener(const Link
<LinkParamNone
*,void>& rListener
)
268 maSelectionChangeListeners
.erase (
270 maSelectionChangeListeners
.begin(),
271 maSelectionChangeListeners
.end(),
275 sal_Int32
SelectionManager::GetInsertionPosition() const
277 sal_Int32
nInsertionPosition (mnInsertionPosition
);
278 if (nInsertionPosition
< 0)
280 model::PageEnumeration aSelectedPages
281 (model::PageEnumerationProvider::CreateSelectedPagesEnumeration(
282 mrSlideSorter
.GetModel()));
283 // Initialize (for the case of an empty selection) with the position
284 // at the end of the document.
285 nInsertionPosition
= mrSlideSorter
.GetModel().GetPageCount();
286 while (aSelectedPages
.HasMoreElements())
288 const sal_Int32
nPosition (aSelectedPages
.GetNextElement()->GetPage()->GetPageNum());
289 // Convert *2+1 index to straight index (n-1)/2 after the page
291 nInsertionPosition
= model::FromCoreIndex(nPosition
) + 1;
295 return nInsertionPosition
;
298 void SelectionManager::SetInsertionPosition (const sal_Int32 nInsertionPosition
)
300 if (nInsertionPosition
< 0)
301 mnInsertionPosition
= -1;
302 else if (nInsertionPosition
> mrSlideSorter
.GetModel().GetPageCount())
304 // Assert but then ignore invalid values.
305 OSL_ASSERT(nInsertionPosition
<=mrSlideSorter
.GetModel().GetPageCount());
309 mnInsertionPosition
= nInsertionPosition
;
312 } // end of namespace ::sd::slidesorter::controller
314 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */