Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / sd / source / ui / sidebar / MasterPagesSelector.cxx
bloba5b8479dee45ceaa7ab21c9b074e5a32ba7af502
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 <sal/config.h>
22 #include <utility>
24 #include "MasterPagesSelector.hxx"
26 #include "MasterPageContainer.hxx"
27 #include "DocumentHelper.hxx"
28 #include <pres.hxx>
29 #include <drawdoc.hxx>
30 #include <DrawDocShell.hxx>
31 #include <sdpage.hxx>
32 #include <glob.hxx>
33 #include <app.hrc>
35 #include <DrawViewShell.hxx>
36 #include <DrawController.hxx>
37 #include <SlideSorterViewShell.hxx>
38 #include "PreviewValueSet.hxx"
39 #include <ViewShellBase.hxx>
40 #include <sfx2/objface.hxx>
41 #include <drawview.hxx>
42 #include <vcl/image.hxx>
43 #include <vcl/floatwin.hxx>
44 #include <svl/languageoptions.hxx>
45 #include <sfx2/app.hxx>
46 #include <sfx2/dispatch.hxx>
47 #include <svl/itemset.hxx>
48 #include <svl/eitem.hxx>
49 #include <svx/dlgutil.hxx>
50 #include <svx/svdpagv.hxx>
51 #include <svx/svxids.hrc>
52 #include <FrameView.hxx>
53 #include <stlpool.hxx>
54 #include <unmovss.hxx>
55 #include <sfx2/request.hxx>
56 #include <svl/itempool.hxx>
57 #include <sfx2/sidebar/Theme.hxx>
58 #include <memory>
60 using namespace ::com::sun::star::text;
62 namespace sd { namespace sidebar {
64 MasterPagesSelector::MasterPagesSelector (
65 vcl::Window* pParent,
66 SdDrawDocument& rDocument,
67 ViewShellBase& rBase,
68 const std::shared_ptr<MasterPageContainer>& rpContainer,
69 const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
70 : PreviewValueSet(pParent),
71 maMutex(),
72 mpContainer(rpContainer),
73 mrDocument(rDocument),
74 mrBase(rBase),
75 msDefaultClickAction("applyselect"),
76 maCurrentItemList(),
77 maTokenToValueSetIndex(),
78 maLockedMasterPages(),
79 mxSidebar(rxSidebar)
81 PreviewValueSet::SetSelectHdl (
82 LINK(this, MasterPagesSelector, ClickHandler));
83 PreviewValueSet::SetRightMouseClickHandler (
84 LINK(this, MasterPagesSelector, RightClickHandler));
85 PreviewValueSet::SetStyle(PreviewValueSet::GetStyle() | WB_NO_DIRECTSELECT);
87 if ( GetDPIScaleFactor() > 1 )
88 mpContainer->SetPreviewSize(MasterPageContainer::LARGE);
90 PreviewValueSet::SetPreviewSize(mpContainer->GetPreviewSizePixel());
91 PreviewValueSet::Show();
93 SetBackground(sfx2::sidebar::Theme::GetWallpaper(sfx2::sidebar::Theme::Paint_PanelBackground));
94 SetColor(sfx2::sidebar::Theme::GetColor(sfx2::sidebar::Theme::Paint_PanelBackground));
96 Link<MasterPageContainerChangeEvent&,void> aChangeListener (LINK(this,MasterPagesSelector,ContainerChangeListener));
97 mpContainer->AddChangeListener(aChangeListener);
100 MasterPagesSelector::~MasterPagesSelector()
102 disposeOnce();
105 void MasterPagesSelector::dispose()
107 Clear();
108 UpdateLocks(ItemList());
110 Link<MasterPageContainerChangeEvent&,void> aChangeListener (LINK(this,MasterPagesSelector,ContainerChangeListener));
111 mpContainer->RemoveChangeListener(aChangeListener);
112 mpContainer.reset();
113 PreviewValueSet::dispose();
116 void MasterPagesSelector::LateInit()
120 sal_Int32 MasterPagesSelector::GetPreferredHeight (sal_Int32 nWidth)
122 const ::osl::MutexGuard aGuard (maMutex);
124 return PreviewValueSet::GetPreferredHeight (nWidth);
127 void MasterPagesSelector::UpdateLocks (const ItemList& rItemList)
129 ItemList aNewLockList;
131 // In here we first lock the master pages in the given list and then
132 // release the locks acquired in a previous call to this method. When
133 // this were done the other way round the lock count of some master
134 // pages might drop temporarily to 0 and would lead to unnecessary
135 // deletion and re-creation of MasterPageDescriptor objects.
137 // Lock the master pages in the given list.
138 ItemList::const_iterator iItem;
139 for (iItem=rItemList.begin(); iItem!=rItemList.end(); ++iItem)
141 mpContainer->AcquireToken(*iItem);
142 aNewLockList.push_back(*iItem);
145 // Release the previously locked master pages.
146 ItemList::const_iterator iPage;
147 ItemList::const_iterator iEnd (maLockedMasterPages.end());
148 for (iPage=maLockedMasterPages.begin(); iPage!=iEnd; ++iPage)
149 mpContainer->ReleaseToken(*iPage);
151 maLockedMasterPages.swap(aNewLockList);
154 void MasterPagesSelector::Fill()
156 ::std::unique_ptr<ItemList> pItemList (new ItemList);
158 Fill(*pItemList);
160 UpdateLocks(*pItemList);
161 UpdateItemList(std::move(pItemList));
164 OUString MasterPagesSelector::GetContextMenuUIFile() const
166 return OUString("modules/simpress/ui/mastermenu.ui");
169 IMPL_LINK_NOARG(MasterPagesSelector, ClickHandler, ValueSet*, void)
171 // We use the framework to assign the clicked-on master page because we
172 // so use the same mechanism as the context menu does (where we do not
173 // have the option to call the assignment method directly.)
174 ExecuteCommand(msDefaultClickAction);
177 IMPL_LINK(MasterPagesSelector, RightClickHandler, const MouseEvent&, rEvent, void)
179 // Here we only prepare the display of the context menu: the item under
180 // the mouse is selected. The actual display of the context menu is
181 // done in ContextMenuCallback which is called indirectly through
182 // PreviewValueSet::Command().
183 PreviewValueSet::GrabFocus ();
184 PreviewValueSet::ReleaseMouse();
185 SfxViewFrame* pViewFrame = mrBase.GetViewFrame();
186 if (pViewFrame != nullptr)
188 SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher();
189 if (pDispatcher != nullptr)
191 sal_uInt16 nIndex = PreviewValueSet::GetItemId (rEvent.GetPosPixel());
192 if (nIndex > 0)
193 PreviewValueSet::SelectItem (nIndex);
198 void MasterPagesSelector::Command (const CommandEvent& rEvent)
200 switch (rEvent.GetCommand())
202 case CommandEventId::ContextMenu:
204 // Use the currently selected item and show the popup menu in its
205 // center.
206 const sal_uInt16 nIndex = PreviewValueSet::GetSelectedItemId();
207 if (nIndex > 0)
209 // The position of the upper left corner of the context menu is
210 // taken either from the mouse position (when the command was sent
211 // as reaction to a right click) or in the center of the selected
212 // item (when the command was sent as reaction to Shift+F10.)
213 Point aPosition (rEvent.GetMousePosPixel());
214 if ( ! rEvent.IsMouseEvent())
216 ::tools::Rectangle aBBox (PreviewValueSet::GetItemRect(nIndex));
217 aPosition = aBBox.Center();
220 // Setup the menu.
221 VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), GetContextMenuUIFile(), "");
222 VclPtr<PopupMenu> pMenu(aBuilder.get_menu("menu"));
223 FloatingWindow* pMenuWindow = dynamic_cast<FloatingWindow*>(pMenu->GetWindow());
224 if (pMenuWindow != nullptr)
225 pMenuWindow->SetPopupModeFlags(
226 pMenuWindow->GetPopupModeFlags() | FloatWinPopupFlags::NoMouseUpClose);
227 pMenu->SetSelectHdl(LINK(this, MasterPagesSelector, OnMenuItemSelected));
229 ProcessPopupMenu(*pMenu);
231 // Show the menu.
232 pMenu->Execute(this, ::tools::Rectangle(aPosition,Size(1,1)), PopupMenuFlags::ExecuteDown);
235 break;
236 default: break;
240 void MasterPagesSelector::ProcessPopupMenu (Menu& rMenu)
242 // Disable some entries.
243 if (mpContainer->GetPreviewSize() == MasterPageContainer::SMALL)
244 rMenu.EnableItem(rMenu.GetItemId("small"), false);
245 else
246 rMenu.EnableItem(rMenu.GetItemId("large"), false);
249 IMPL_LINK(MasterPagesSelector, OnMenuItemSelected, Menu*, pMenu, bool)
251 if (pMenu == nullptr)
253 OSL_ENSURE(pMenu!=nullptr, "MasterPagesSelector::OnMenuItemSelected: illegal menu!");
254 return false;
257 pMenu->Deactivate();
258 ExecuteCommand(pMenu->GetCurItemIdent());
259 return false;
262 void MasterPagesSelector::ExecuteCommand(const OString &rIdent)
264 if (rIdent == "applyall")
266 mrBase.SetBusyState (true);
267 AssignMasterPageToAllSlides (GetSelectedMasterPage());
268 mrBase.SetBusyState (false);
270 else if (rIdent == "applyselect")
272 mrBase.SetBusyState (true);
273 AssignMasterPageToSelectedSlides (GetSelectedMasterPage());
274 mrBase.SetBusyState (false);
276 else if (rIdent == "large")
278 mrBase.SetBusyState (true);
279 mpContainer->SetPreviewSize(MasterPageContainer::LARGE);
280 mrBase.SetBusyState (false);
281 if (mxSidebar.is())
282 mxSidebar->requestLayout();
284 else if (rIdent == "small")
286 mrBase.SetBusyState (true);
287 mpContainer->SetPreviewSize(MasterPageContainer::SMALL);
288 mrBase.SetBusyState (false);
289 if (mxSidebar.is())
290 mxSidebar->requestLayout();
292 else if (rIdent == "edit")
294 using namespace ::com::sun::star;
295 uno::Reference<drawing::XDrawPage> xSelectedMaster;
296 SdPage* pMasterPage = GetSelectedMasterPage();
297 assert(pMasterPage); //rhbz#902884
298 if (pMasterPage)
299 xSelectedMaster.set(pMasterPage->getUnoPage(), uno::UNO_QUERY);
300 SfxViewFrame* pViewFrame = mrBase.GetViewFrame();
301 if (pViewFrame != nullptr && xSelectedMaster.is())
303 SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher();
304 if (pDispatcher != nullptr)
306 sal_uInt16 nIndex = PreviewValueSet::GetSelectedItemId();
307 pDispatcher->Execute(SID_MASTERPAGE, SfxCallMode::SYNCHRON);
308 PreviewValueSet::SelectItem (nIndex);
309 mrBase.GetDrawController().setCurrentPage(xSelectedMaster);
315 IMPL_LINK(MasterPagesSelector, ContainerChangeListener, MasterPageContainerChangeEvent&, rEvent, void)
317 NotifyContainerChangeEvent(rEvent);
320 SdPage* MasterPagesSelector::GetSelectedMasterPage()
322 const ::osl::MutexGuard aGuard (maMutex);
324 SdPage* pMasterPage = nullptr;
325 sal_uInt16 nIndex = PreviewValueSet::GetSelectedItemId();
326 UserData* pData = GetUserData(nIndex);
327 if (pData != nullptr)
329 pMasterPage = mpContainer->GetPageObjectForToken(pData->second, true);
331 return pMasterPage;
334 /** Assemble a list of all slides of the document and pass it to
335 AssignMasterPageToPageList().
337 void MasterPagesSelector::AssignMasterPageToAllSlides (SdPage* pMasterPage)
339 if (pMasterPage == nullptr)
340 return;
342 sal_uInt16 nPageCount = mrDocument.GetSdPageCount(PageKind::Standard);
343 if (nPageCount == 0)
344 return;
346 // Get a list of all pages. As a little optimization we only
347 // include pages that do not already have the given master page
348 // assigned.
349 OUString sFullLayoutName(pMasterPage->GetLayoutName());
350 ::sd::slidesorter::SharedPageSelection pPageList (
351 new ::sd::slidesorter::SlideSorterViewShell::PageSelection);
352 for (sal_uInt16 nPageIndex=0; nPageIndex<nPageCount; nPageIndex++)
354 SdPage* pPage = mrDocument.GetSdPage (nPageIndex, PageKind::Standard);
355 if (pPage != nullptr && pPage->GetLayoutName() != sFullLayoutName)
357 pPageList->push_back (pPage);
361 AssignMasterPageToPageList(pMasterPage, pPageList);
364 /** Assemble a list of the currently selected slides (selected in a visible
365 slide sorter) and pass it to AssignMasterPageToPageList().
367 void MasterPagesSelector::AssignMasterPageToSelectedSlides (
368 SdPage* pMasterPage)
370 using namespace ::sd::slidesorter;
371 using namespace ::sd::slidesorter::controller;
373 if (pMasterPage == nullptr)
374 return;
376 // Find a visible slide sorter.
377 SlideSorterViewShell* pSlideSorter = SlideSorterViewShell::GetSlideSorter(mrBase);
378 if (pSlideSorter == nullptr)
379 return;
381 // Get a list of selected pages.
382 SharedPageSelection pPageSelection = pSlideSorter->GetPageSelection();
383 if (pPageSelection->empty())
384 return;
386 AssignMasterPageToPageList(pMasterPage, pPageSelection);
388 // Restore the previous selection.
389 pSlideSorter->SetPageSelection(pPageSelection);
392 void MasterPagesSelector::AssignMasterPageToPageList (
393 SdPage* pMasterPage,
394 const ::sd::slidesorter::SharedPageSelection& rPageList)
396 DocumentHelper::AssignMasterPageToPageList(mrDocument, pMasterPage, rPageList);
399 void MasterPagesSelector::NotifyContainerChangeEvent (const MasterPageContainerChangeEvent& rEvent)
401 const ::osl::MutexGuard aGuard (maMutex);
403 switch (rEvent.meEventType)
405 case MasterPageContainerChangeEvent::EventType::SIZE_CHANGED:
406 PreviewValueSet::SetPreviewSize(mpContainer->GetPreviewSizePixel());
407 UpdateAllPreviews();
408 break;
410 case MasterPageContainerChangeEvent::EventType::PREVIEW_CHANGED:
412 int nIndex (GetIndexForToken(rEvent.maChildToken));
413 if (nIndex >= 0)
415 PreviewValueSet::SetItemImage (
416 static_cast<sal_uInt16>(nIndex),
417 mpContainer->GetPreviewForToken(rEvent.maChildToken));
418 PreviewValueSet::Invalidate(PreviewValueSet::GetItemRect(static_cast<sal_uInt16>(nIndex)));
421 break;
423 case MasterPageContainerChangeEvent::EventType::DATA_CHANGED:
425 InvalidateItem(rEvent.maChildToken);
426 Fill();
428 break;
430 case MasterPageContainerChangeEvent::EventType::CHILD_REMOVED:
432 int nIndex (GetIndexForToken(rEvent.maChildToken));
433 SetItem(nIndex, MasterPageContainer::NIL_TOKEN);
434 break;
437 default:
438 break;
442 MasterPagesSelector::UserData* MasterPagesSelector::GetUserData (int nIndex) const
444 const ::osl::MutexGuard aGuard (maMutex);
446 if (nIndex>0 && static_cast<unsigned int>(nIndex)<=PreviewValueSet::GetItemCount())
447 return static_cast<UserData*>(PreviewValueSet::GetItemData(static_cast<sal_uInt16>(nIndex)));
448 else
449 return nullptr;
452 void MasterPagesSelector::SetUserData (int nIndex, UserData* pData)
454 const ::osl::MutexGuard aGuard (maMutex);
456 if (nIndex>0 && static_cast<unsigned int>(nIndex)<=PreviewValueSet::GetItemCount())
458 UserData* pOldData = GetUserData(nIndex);
459 if (pOldData!=nullptr && pOldData!=pData)
460 delete pOldData;
461 PreviewValueSet::SetItemData(static_cast<sal_uInt16>(nIndex), pData);
465 void MasterPagesSelector::SetItem (
466 sal_uInt16 nIndex,
467 MasterPageContainer::Token aToken)
469 const ::osl::MutexGuard aGuard (maMutex);
471 RemoveTokenToIndexEntry(nIndex,aToken);
473 if (nIndex > 0)
475 if (aToken != MasterPageContainer::NIL_TOKEN)
477 Image aPreview (mpContainer->GetPreviewForToken(aToken));
478 MasterPageContainer::PreviewState eState (mpContainer->GetPreviewState(aToken));
480 if (aPreview.GetSizePixel().Width()>0)
482 if (PreviewValueSet::GetItemPos(nIndex) != VALUESET_ITEM_NOTFOUND)
484 PreviewValueSet::SetItemImage(nIndex,aPreview);
485 PreviewValueSet::SetItemText(nIndex, mpContainer->GetPageNameForToken(aToken));
487 else
489 PreviewValueSet::InsertItem (
490 nIndex,
491 aPreview,
492 mpContainer->GetPageNameForToken(aToken),
493 nIndex);
495 SetUserData(nIndex, new UserData(nIndex,aToken));
497 AddTokenToIndexEntry(nIndex,aToken);
500 if (eState == MasterPageContainer::PS_CREATABLE)
501 mpContainer->RequestPreview(aToken);
503 else
505 PreviewValueSet::RemoveItem(nIndex);
511 void MasterPagesSelector::AddTokenToIndexEntry (
512 sal_uInt16 nIndex,
513 MasterPageContainer::Token aToken)
515 const ::osl::MutexGuard aGuard (maMutex);
517 maTokenToValueSetIndex[aToken] = nIndex;
520 void MasterPagesSelector::RemoveTokenToIndexEntry (
521 sal_uInt16 nIndex,
522 MasterPageContainer::Token aNewToken)
524 const ::osl::MutexGuard aGuard (maMutex);
526 UserData* pData = GetUserData(nIndex);
527 if (pData != nullptr)
529 // Get the token that the index pointed to previously.
530 MasterPageContainer::Token aOldToken (pData->second);
532 if (aNewToken != aOldToken
533 && nIndex == GetIndexForToken(aOldToken))
535 maTokenToValueSetIndex[aOldToken] = 0;
540 void MasterPagesSelector::InvalidatePreview (const SdPage* pPage)
542 const ::osl::MutexGuard aGuard (maMutex);
544 for (size_t nIndex=1; nIndex<=PreviewValueSet::GetItemCount(); nIndex++)
546 UserData* pData = GetUserData(nIndex);
547 if (pData != nullptr)
549 MasterPageContainer::Token aToken (pData->second);
550 if (pPage == mpContainer->GetPageObjectForToken(aToken,false))
552 mpContainer->InvalidatePreview(aToken);
553 mpContainer->RequestPreview(aToken);
554 break;
560 void MasterPagesSelector::UpdateAllPreviews()
562 const ::osl::MutexGuard aGuard (maMutex);
564 for (size_t nIndex=1; nIndex<=PreviewValueSet::GetItemCount(); nIndex++)
566 UserData* pData = GetUserData(nIndex);
567 if (pData != nullptr)
569 MasterPageContainer::Token aToken (pData->second);
570 PreviewValueSet::SetItemImage(
571 nIndex,
572 mpContainer->GetPreviewForToken(aToken));
573 if (mpContainer->GetPreviewState(aToken) == MasterPageContainer::PS_CREATABLE)
574 mpContainer->RequestPreview(aToken);
577 PreviewValueSet::Rearrange();
580 void MasterPagesSelector::ClearPageSet()
582 const ::osl::MutexGuard aGuard (maMutex);
584 for (size_t nIndex=1; nIndex<=PreviewValueSet::GetItemCount(); nIndex++)
586 UserData* pData = GetUserData(nIndex);
587 delete pData;
589 PreviewValueSet::Clear();
592 void MasterPagesSelector::SetHelpId( const OString& aId )
594 const ::osl::MutexGuard aGuard (maMutex);
596 PreviewValueSet::SetHelpId( aId );
599 sal_Int32 MasterPagesSelector::GetIndexForToken (MasterPageContainer::Token aToken) const
601 const ::osl::MutexGuard aGuard (maMutex);
603 TokenToValueSetIndex::const_iterator iIndex (maTokenToValueSetIndex.find(aToken));
604 if (iIndex != maTokenToValueSetIndex.end())
605 return iIndex->second;
606 else
607 return -1;
610 void MasterPagesSelector::Clear()
612 const ::osl::MutexGuard aGuard (maMutex);
614 ClearPageSet();
617 void MasterPagesSelector::InvalidateItem (MasterPageContainer::Token aToken)
619 const ::osl::MutexGuard aGuard (maMutex);
621 ItemList::iterator iItem;
622 for (iItem=maCurrentItemList.begin(); iItem!=maCurrentItemList.end(); ++iItem)
624 if (*iItem == aToken)
626 *iItem = MasterPageContainer::NIL_TOKEN;
627 break;
632 void MasterPagesSelector::UpdateItemList (::std::unique_ptr<ItemList> && pNewItemList)
634 const ::osl::MutexGuard aGuard (maMutex);
636 ItemList::const_iterator iNewItem (pNewItemList->begin());
637 ItemList::const_iterator iCurrentItem (maCurrentItemList.begin());
638 ItemList::const_iterator iNewEnd (pNewItemList->end());
639 ItemList::const_iterator iCurrentEnd (maCurrentItemList.end());
640 sal_uInt16 nIndex (1);
642 // Update existing items.
643 for ( ; iNewItem!=iNewEnd && iCurrentItem!=iCurrentEnd; ++iNewItem, ++iCurrentItem,++nIndex)
645 if (*iNewItem != *iCurrentItem)
647 SetItem(nIndex,*iNewItem);
651 // Append new items.
652 for ( ; iNewItem!=iNewEnd; ++iNewItem,++nIndex)
654 SetItem(nIndex,*iNewItem);
657 // Remove trailing items.
658 for ( ; iCurrentItem!=iCurrentEnd; ++iCurrentItem,++nIndex)
660 SetItem(nIndex,MasterPageContainer::NIL_TOKEN);
663 maCurrentItemList.swap(*pNewItemList);
665 PreviewValueSet::Rearrange();
666 if (mxSidebar.is())
667 mxSidebar->requestLayout();
670 css::ui::LayoutSize MasterPagesSelector::GetHeightForWidth (const sal_Int32 nWidth)
672 const sal_Int32 nHeight (GetPreferredHeight(nWidth));
673 return css::ui::LayoutSize(nHeight,nHeight,nHeight);
676 } } // end of namespace sd::sidebar
678 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */