LibreOffice Module sd (master) 1
MasterPagesSelector.cxx
Go to the documentation of this file.
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 <sal/config.h>
21
22#include <utility>
23
25
27#include "DocumentHelper.hxx"
28#include <pres.hxx>
29#include <drawdoc.hxx>
30#include <sdpage.hxx>
31#include <app.hrc>
32
33#include <DrawController.hxx>
35#include "PreviewValueSet.hxx"
36#include <ViewShellBase.hxx>
37#include <o3tl/safeint.hxx>
38#include <vcl/image.hxx>
39#include <sfx2/dispatch.hxx>
40#include <sfx2/viewfrm.hxx>
42#include <memory>
43
44using namespace ::com::sun::star::text;
45
46namespace sd::sidebar {
47
51constexpr OUStringLiteral gsDefaultClickAction = u"applyselect";
52
54 weld::Widget* pParent,
55 SdDrawDocument& rDocument,
56 ViewShellBase& rBase,
57 std::shared_ptr<MasterPageContainer> pContainer,
58 css::uno::Reference<css::ui::XSidebar> xSidebar,
59 const OUString& rUIFileName,
60 const OUString& rValueSetName)
61 : PanelLayout( pParent, "MasterPagePanel", rUIFileName ),
62 mpContainer(std::move(pContainer)),
63 mxPreviewValueSet(new PreviewValueSet),
64 mxPreviewValueSetWin(new weld::CustomWeld(*m_xBuilder, rValueSetName, *mxPreviewValueSet)),
65 mrDocument(rDocument),
66 mrBase(rBase),
67 mxSidebar(std::move(xSidebar))
68{
69 mxPreviewValueSet->SetSelectHdl (
70 LINK(this, MasterPagesSelector, ClickHandler));
71 mxPreviewValueSet->SetContextMenuHandler (
72 LINK(this, MasterPagesSelector, ContextMenuHandler));
74
75 if (mxPreviewValueSet->GetDrawingArea()->get_ref_device().GetDPIScaleFactor() > 1)
77
78 mxPreviewValueSet->SetPreviewSize(mpContainer->GetPreviewSizePixel());
79 mxPreviewValueSet->Show();
80
82
83 Link<MasterPageContainerChangeEvent&,void> aChangeListener (LINK(this,MasterPagesSelector,ContainerChangeListener));
84 mpContainer->AddChangeListener(aChangeListener);
85}
86
88{
89 Clear();
91
92 Link<MasterPageContainerChangeEvent&,void> aChangeListener (LINK(this,MasterPagesSelector,ContainerChangeListener));
93 mpContainer->RemoveChangeListener(aChangeListener);
94 mpContainer.reset();
96 mxPreviewValueSet.reset();
97}
98
100{
101}
102
103sal_Int32 MasterPagesSelector::GetPreferredHeight (sal_Int32 nWidth)
104{
105 const ::osl::MutexGuard aGuard (maMutex);
106
107 return mxPreviewValueSet->GetPreferredHeight (nWidth);
108}
109
111{
112 ItemList aNewLockList;
113
114 // In here we first lock the master pages in the given list and then
115 // release the locks acquired in a previous call to this method. When
116 // this were done the other way round the lock count of some master
117 // pages might drop temporarily to 0 and would lead to unnecessary
118 // deletion and re-creation of MasterPageDescriptor objects.
119
120 // Lock the master pages in the given list.
121 for (const auto& rItem : rItemList)
122 {
123 mpContainer->AcquireToken(rItem);
124 aNewLockList.push_back(rItem);
125 }
126
127 // Release the previously locked master pages.
128 for (const auto& rPage : maLockedMasterPages)
129 mpContainer->ReleaseToken(rPage);
130
131 maLockedMasterPages.swap(aNewLockList);
132}
133
135{
136 ::std::unique_ptr<ItemList> pItemList (new ItemList);
137
138 Fill(*pItemList);
139
140 UpdateLocks(*pItemList);
141 UpdateItemList(std::move(pItemList));
142}
143
145{
146 return "modules/simpress/ui/mastermenu.ui";
147}
148
150{
151 // We use the framework to assign the clicked-on master page because we
152 // so use the same mechanism as the context menu does (where we do not
153 // have the option to call the assignment method directly.)
154 ExecuteCommand(gsDefaultClickAction);
155}
156
157IMPL_LINK(MasterPagesSelector, ContextMenuHandler, const Point*, pPos, void)
158{
159 if (pPos)
160 {
161 // Here we only prepare the display of the context menu: on right
162 // click the item under the mouse is selected.
163 mxPreviewValueSet->GrabFocus();
164 mxPreviewValueSet->ReleaseMouse();
165
166 sal_uInt16 nIndex = mxPreviewValueSet->GetItemId(*pPos);
167 if (nIndex > 0)
168 mxPreviewValueSet->SelectItem(nIndex);
169 }
170
171 // Now do the actual display of the context menu
172 ShowContextMenu(pPos);
173}
174
176{
177 // Use the currently selected item and show the popup menu in its
178 // center.
179 const sal_uInt16 nIndex = mxPreviewValueSet->GetSelectedItemId();
180 if (nIndex <= 0)
181 return;
182
183 // The position of the upper left corner of the context menu is
184 // taken either from the mouse position (when the command was sent
185 // as reaction to a right click) or in the center of the selected
186 // item (when the command was sent as reaction to Shift+F10.)
187 Point aPosition;
188 if (!pPos)
189 {
190 ::tools::Rectangle aBBox (mxPreviewValueSet->GetItemRect(nIndex));
191 aPosition = aBBox.Center();
192 }
193 else
194 aPosition = *pPos;
195
196 // Setup the menu.
197 weld::Widget* pParent = mxPreviewValueSet->GetDrawingArea();
198 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pParent, GetContextMenuUIFile()));
199 std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
200 ProcessPopupMenu(*xMenu);
201 ::tools::Rectangle aRect(aPosition, Size(1,1));
202 // Show the menu.
203 ExecuteCommand(xMenu->popup_at_rect(pParent, aRect));
204}
205
207{
208 // Disable some entries.
209 if (mpContainer->GetPreviewSize() == MasterPageContainer::SMALL)
210 rMenu.set_sensitive("small", false);
211 else
212 rMenu.set_sensitive("large", false);
213}
214
215void MasterPagesSelector::ExecuteCommand(const OUString &rIdent)
216{
217 if (rIdent == "applyall")
218 {
219 mrBase.SetBusyState (true);
221 mrBase.SetBusyState (false);
222 }
223 else if (rIdent == "applyselect")
224 {
225 mrBase.SetBusyState (true);
227 mrBase.SetBusyState (false);
228 }
229 else if (rIdent == "large")
230 {
231 mrBase.SetBusyState (true);
233 mrBase.SetBusyState (false);
234 if (mxSidebar.is())
235 mxSidebar->requestLayout();
236 }
237 else if (rIdent == "small")
238 {
239 mrBase.SetBusyState (true);
241 mrBase.SetBusyState (false);
242 if (mxSidebar.is())
243 mxSidebar->requestLayout();
244 }
245 else if (rIdent == "edit")
246 {
247 using namespace ::com::sun::star;
248 uno::Reference<drawing::XDrawPage> xSelectedMaster;
249 SdPage* pMasterPage = GetSelectedMasterPage();
250 assert(pMasterPage); //rhbz#902884
251 if (pMasterPage)
252 xSelectedMaster.set(pMasterPage->getUnoPage(), uno::UNO_QUERY);
253 SfxViewFrame& rViewFrame = mrBase.GetViewFrame();
254 if (xSelectedMaster.is())
255 {
256 SfxDispatcher* pDispatcher = rViewFrame.GetDispatcher();
257 if (pDispatcher != nullptr)
258 {
259 sal_uInt16 nIndex = mxPreviewValueSet->GetSelectedItemId();
260 pDispatcher->Execute(SID_MASTERPAGE, SfxCallMode::SYNCHRON);
261 mxPreviewValueSet->SelectItem (nIndex);
262 mrBase.GetDrawController()->setCurrentPage(xSelectedMaster);
263 }
264 }
265 }
266}
267
268IMPL_LINK(MasterPagesSelector, ContainerChangeListener, MasterPageContainerChangeEvent&, rEvent, void)
269{
270 NotifyContainerChangeEvent(rEvent);
271}
272
274{
275 const ::osl::MutexGuard aGuard (maMutex);
276
277 SdPage* pMasterPage = nullptr;
278 sal_uInt16 nIndex = mxPreviewValueSet->GetSelectedItemId();
280 if (pData != nullptr)
281 {
282 pMasterPage = mpContainer->GetPageObjectForToken(pData->second, true);
283 }
284 return pMasterPage;
285}
286
291{
292 if (pMasterPage == nullptr)
293 return;
294
295 sal_uInt16 nPageCount = mrDocument.GetSdPageCount(PageKind::Standard);
296 if (nPageCount == 0)
297 return;
298
299 // Get a list of all pages. As a little optimization we only
300 // include pages that do not already have the given master page
301 // assigned.
302 OUString sFullLayoutName(pMasterPage->GetLayoutName());
304 std::make_shared<::sd::slidesorter::SlideSorterViewShell::PageSelection>();
305 for (sal_uInt16 nPageIndex=0; nPageIndex<nPageCount; nPageIndex++)
306 {
307 SdPage* pPage = mrDocument.GetSdPage (nPageIndex, PageKind::Standard);
308 if (pPage != nullptr && pPage->GetLayoutName() != sFullLayoutName)
309 {
310 pPageList->push_back (pPage);
311 }
312 }
313
314 AssignMasterPageToPageList(pMasterPage, pPageList);
315}
316
321 SdPage* pMasterPage)
322{
323 using namespace ::sd::slidesorter;
324 using namespace ::sd::slidesorter::controller;
325
326 if (pMasterPage == nullptr)
327 return;
328
329 // Find a visible slide sorter.
330 SlideSorterViewShell* pSlideSorter = SlideSorterViewShell::GetSlideSorter(mrBase);
331 if (pSlideSorter == nullptr)
332 return;
333
334 // Get a list of selected pages.
335 SharedPageSelection pPageSelection = pSlideSorter->GetPageSelection();
336 if (pPageSelection->empty())
337 return;
338
339 AssignMasterPageToPageList(pMasterPage, pPageSelection);
340
341 // Restore the previous selection.
342 pSlideSorter->SetPageSelection(pPageSelection);
343}
344
346 SdPage* pMasterPage,
347 const std::shared_ptr<std::vector<SdPage*>>& rPageList)
348{
350}
351
353{
354 const ::osl::MutexGuard aGuard (maMutex);
355
356 switch (rEvent.meEventType)
357 {
359 mxPreviewValueSet->SetPreviewSize(mpContainer->GetPreviewSizePixel());
361 break;
362
364 {
366 if (nIndex >= 0)
367 {
368 mxPreviewValueSet->SetItemImage (
369 static_cast<sal_uInt16>(nIndex),
370 mpContainer->GetPreviewForToken(rEvent.maChildToken));
371 mxPreviewValueSet->Invalidate(mxPreviewValueSet->GetItemRect(static_cast<sal_uInt16>(nIndex)));
372 }
373 }
374 break;
375
377 {
379 Fill();
380 }
381 break;
382
384 {
387 break;
388 }
389
390 default:
391 break;
392 }
393}
394
396{
397 const ::osl::MutexGuard aGuard (maMutex);
398
399 if (nIndex>0 && o3tl::make_unsigned(nIndex)<=mxPreviewValueSet->GetItemCount())
400 return static_cast<UserData*>(mxPreviewValueSet->GetItemData(static_cast<sal_uInt16>(nIndex)));
401 else
402 return nullptr;
403}
404
405void MasterPagesSelector::SetUserData (int nIndex, std::unique_ptr<UserData> pData)
406{
407 const ::osl::MutexGuard aGuard (maMutex);
408
409 delete GetUserData(nIndex);
410 mxPreviewValueSet->SetItemData(static_cast<sal_uInt16>(nIndex), pData.release());
411}
412
414 sal_uInt16 nIndex,
416{
417 const ::osl::MutexGuard aGuard (maMutex);
418
420
421 if (nIndex <= 0)
422 return;
423
424 if (aToken != MasterPageContainer::NIL_TOKEN)
425 {
426 Image aPreview (mpContainer->GetPreviewForToken(aToken));
427 MasterPageContainer::PreviewState eState (mpContainer->GetPreviewState(aToken));
428
429 if (aPreview.GetSizePixel().Width()>0)
430 {
432 {
433 mxPreviewValueSet->SetItemImage(nIndex,aPreview);
434 mxPreviewValueSet->SetItemText(nIndex, mpContainer->GetPageNameForToken(aToken));
435 }
436 else
437 {
438 mxPreviewValueSet->InsertItem (
439 nIndex,
440 aPreview,
441 mpContainer->GetPageNameForToken(aToken),
442 nIndex);
443 }
444 SetUserData(nIndex, std::make_unique<UserData>(nIndex,aToken));
445
447 }
448
450 mpContainer->RequestPreview(aToken);
451 }
452 else
453 {
454 mxPreviewValueSet->RemoveItem(nIndex);
455 }
456
457}
458
460 sal_uInt16 nIndex,
462{
463 const ::osl::MutexGuard aGuard (maMutex);
464
466}
467
469 sal_uInt16 nIndex,
471{
472 const ::osl::MutexGuard aGuard (maMutex);
473
475 if (pData != nullptr)
476 {
477 // Get the token that the index pointed to previously.
478 MasterPageContainer::Token aOldToken (pData->second);
479
480 if (aNewToken != aOldToken
481 && nIndex == GetIndexForToken(aOldToken))
482 {
483 maTokenToValueSetIndex[aOldToken] = 0;
484 }
485 }
486}
487
489{
490 const ::osl::MutexGuard aGuard (maMutex);
491
492 for (size_t nIndex=1; nIndex<=mxPreviewValueSet->GetItemCount(); nIndex++)
493 {
495 if (pData != nullptr)
496 {
497 MasterPageContainer::Token aToken (pData->second);
498 if (pPage == mpContainer->GetPageObjectForToken(aToken,false))
499 {
500 mpContainer->InvalidatePreview(aToken);
501 mpContainer->RequestPreview(aToken);
502 break;
503 }
504 }
505 }
506}
507
509{
510 const ::osl::MutexGuard aGuard (maMutex);
511
512 for (size_t nIndex=1; nIndex<=mxPreviewValueSet->GetItemCount(); nIndex++)
513 {
515 if (pData != nullptr)
516 {
517 MasterPageContainer::Token aToken (pData->second);
518 mxPreviewValueSet->SetItemImage(
519 nIndex,
520 mpContainer->GetPreviewForToken(aToken));
521 if (mpContainer->GetPreviewState(aToken) == MasterPageContainer::PS_CREATABLE)
522 mpContainer->RequestPreview(aToken);
523 }
524 }
525 mxPreviewValueSet->Rearrange();
526}
527
529{
530 const ::osl::MutexGuard aGuard (maMutex);
531
532 for (size_t nIndex=1; nIndex<=mxPreviewValueSet->GetItemCount(); nIndex++)
533 {
535 delete pData;
536 }
537 mxPreviewValueSet->Clear();
538}
539
540void MasterPagesSelector::SetHelpId( const OUString& aId )
541{
542 const ::osl::MutexGuard aGuard (maMutex);
543
544 mxPreviewValueSet->SetHelpId( aId );
545}
546
548{
549 const ::osl::MutexGuard aGuard (maMutex);
550
551 TokenToValueSetIndex::const_iterator iIndex (maTokenToValueSetIndex.find(aToken));
552 if (iIndex != maTokenToValueSetIndex.end())
553 return iIndex->second;
554 else
555 return -1;
556}
557
559{
560 const ::osl::MutexGuard aGuard (maMutex);
561
562 ClearPageSet();
563}
564
566{
567 const ::osl::MutexGuard aGuard (maMutex);
568
569 auto iItem = std::find(maCurrentItemList.begin(), maCurrentItemList.end(), aToken);
570 if (iItem != maCurrentItemList.end())
572}
573
574void MasterPagesSelector::UpdateItemList (::std::unique_ptr<ItemList> && pNewItemList)
575{
576 const ::osl::MutexGuard aGuard (maMutex);
577
578 ItemList::const_iterator iNewItem (pNewItemList->begin());
579 ItemList::const_iterator iCurrentItem (maCurrentItemList.begin());
580 ItemList::const_iterator iNewEnd (pNewItemList->end());
581 ItemList::const_iterator iCurrentEnd (maCurrentItemList.end());
582 sal_uInt16 nIndex (1);
583
584 // Update existing items.
585 for ( ; iNewItem!=iNewEnd && iCurrentItem!=iCurrentEnd; ++iNewItem, ++iCurrentItem,++nIndex)
586 {
587 if (*iNewItem != *iCurrentItem)
588 {
589 SetItem(nIndex,*iNewItem);
590 }
591 }
592
593 // Append new items.
594 for ( ; iNewItem!=iNewEnd; ++iNewItem,++nIndex)
595 {
596 SetItem(nIndex,*iNewItem);
597 }
598
599 // Remove trailing items.
600 for ( ; iCurrentItem!=iCurrentEnd; ++iCurrentItem,++nIndex)
601 {
603 }
604
605 maCurrentItemList.swap(*pNewItemList);
606
607 mxPreviewValueSet->Rearrange();
608 if (mxSidebar.is())
609 mxSidebar->requestLayout();
610}
611
612css::ui::LayoutSize MasterPagesSelector::GetHeightForWidth (const sal_Int32 nWidth)
613{
614 const sal_Int32 nHeight (GetPreferredHeight(nWidth));
615 return css::ui::LayoutSize(nHeight,nHeight,nHeight);
616}
617
618} // end of namespace sd::sidebar
619
620/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static std::unique_ptr< weld::Builder > CreateBuilder(weld::Widget *pParent, const OUString &rUIFile, bool bMobile=false, sal_uInt64 nLOKWindowId=0)
Size GetSizePixel() const
SdPage * GetSdPage(sal_uInt16 nPgNum, PageKind ePgKind) const
Definition: drawdoc2.cxx:207
sal_uInt16 GetSdPageCount(PageKind ePgKind) const
Definition: drawdoc2.cxx:212
virtual OUString GetLayoutName() const override
Definition: sdpage.hxx:255
css::uno::Reference< css::uno::XInterface > const & getUnoPage()
const SfxPoolItem * Execute(sal_uInt16 nSlot, SfxCallMode nCall=SfxCallMode::SLOT, const SfxPoolItem **pArgs=nullptr, sal_uInt16 nModi=0, const SfxPoolItem **pInternalArgs=nullptr)
SfxDispatcher * GetDispatcher()
SfxViewFrame & GetViewFrame() const
constexpr tools::Long Width() const
virtual void SAL_CALL setCurrentPage(const css::uno::Reference< css::drawing::XDrawPage > &xPage) override
SfxViewShell descendant that the stacked Draw/Impress shells are based on.
DrawController * GetDrawController() const
void SetBusyState(bool bBusy)
When <TRUE> is given, then the mouse shape is set to hour glass (or whatever the busy shape looks lik...
static void AssignMasterPageToPageList(SdDrawDocument &rTargetDocument, SdPage *pMasterPage, const std::shared_ptr< std::vector< SdPage * > > &rPageList)
Assign the given master page to the list of pages.
For some changes to the set of master pages in a MasterPageContainer or to the data stored for each m...
enum sd::sidebar::MasterPageContainerChangeEvent::EventType meEventType
Base class of a menu that lets the user select from a list of templates or designs that are loaded fr...
void InvalidateItem(MasterPageContainer::Token aToken)
Invalidate the specified item so that on the next Fill() this item is updated.
void SetItem(sal_uInt16 nIndex, MasterPageContainer::Token aToken)
virtual OUString GetContextMenuUIFile() const
Give derived classes the opportunity to provide their own context menu.
std::unique_ptr< PreviewValueSet > mxPreviewValueSet
virtual css::ui::LayoutSize GetHeightForWidth(const sal_Int32 nWidth) override
css::uno::Reference< css::ui::XSidebar > mxSidebar
::std::pair< int, MasterPageContainer::Token > UserData
void SetUserData(int nIndex, std::unique_ptr< UserData > pData)
virtual void AssignMasterPageToPageList(SdPage *pMasterPage, const std::shared_ptr< std::vector< SdPage * > > &rPageList)
void ShowContextMenu(const Point *pPos)
void RemoveTokenToIndexEntry(sal_uInt16 nIndex, MasterPageContainer::Token aToken)
void AssignMasterPageToSelectedSlides(SdPage *pMasterPage)
Assign the given master page to all slides that are selected in a slide sorter that is displayed in t...
void UpdateItemList(::std::unique_ptr< ItemList > &&pList)
void InvalidatePreview(const SdPage *pPage)
Mark the preview that belongs to the given index as not up-to-date anymore with respect to page conte...
MasterPagesSelector(weld::Widget *pParent, SdDrawDocument &rDocument, ViewShellBase &rBase, std::shared_ptr< MasterPageContainer > pContainer, css::uno::Reference< css::ui::XSidebar > xSidebar, const OUString &rUIFileName, const OUString &rValueSetName)
void AddTokenToIndexEntry(sal_uInt16 nIndex, MasterPageContainer::Token aToken)
void SetHelpId(const OUString &aId)
void ClearPageSet()
Make the selector empty.
virtual void ExecuteCommand(const OUString &rIdent)
virtual void ProcessPopupMenu(weld::Menu &rMenu)
std::unique_ptr< weld::CustomWeld > mxPreviewValueSetWin
void AssignMasterPageToAllSlides(SdPage *pMasterPage)
Assign the given master page to all slides of the document.
std::shared_ptr< MasterPageContainer > mpContainer
sal_Int32 GetIndexForToken(MasterPageContainer::Token aToken) const
void UpdateLocks(const ItemList &rItemList)
Lock master pages in the given list and release locks that were previously acquired.
sal_Int32 GetPreferredHeight(sal_Int32 nWidth)
virtual void NotifyContainerChangeEvent(const MasterPageContainerChangeEvent &rEvent)
::std::vector< MasterPageContainer::Token > ItemList
UserData * GetUserData(int nIndex) const
Adapt the svtools valueset to the needs of the master page controls.
static Color GetColor(const ThemeItem eItem)
constexpr Point Center() const
virtual void set_sensitive(const OUString &rIdent, bool bSensitive)=0
float u
sal_Int32 nIndex
std::unique_ptr< sal_Int32[]> pData
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
IMPL_LINK_NOARG(LayoutMenu, ClickHandler, ValueSet *, void)
Definition: LayoutMenu.cxx:369
IMPL_LINK(CurrentMasterPagesSelector, EventMultiplexerListener, sd::tools::EventMultiplexerEvent &, rEvent, void)
constexpr OUStringLiteral gsDefaultClickAction
menu entry that is executed as default action when the left mouse button is clicked over a master pag...
std::shared_ptr< SlideSorterViewShell::PageSelection > SharedPageSelection
#define VALUESET_ITEM_NOTFOUND
#define WB_NO_DIRECTSELECT