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 <sal/config.h>
24 #include "MasterPagesSelector.hxx"
26 #include "MasterPageContainer.hxx"
27 #include "DocumentHelper.hxx"
29 #include <drawdoc.hxx>
30 #include <DrawDocShell.hxx>
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>
60 using namespace ::com::sun::star::text
;
62 namespace sd
{ namespace sidebar
{
64 MasterPagesSelector::MasterPagesSelector (
66 SdDrawDocument
& rDocument
,
68 const std::shared_ptr
<MasterPageContainer
>& rpContainer
,
69 const css::uno::Reference
<css::ui::XSidebar
>& rxSidebar
)
70 : PreviewValueSet(pParent
),
72 mpContainer(rpContainer
),
73 mrDocument(rDocument
),
75 msDefaultClickAction("applyselect"),
77 maTokenToValueSetIndex(),
78 maLockedMasterPages(),
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()
105 void MasterPagesSelector::dispose()
108 UpdateLocks(ItemList());
110 Link
<MasterPageContainerChangeEvent
&,void> aChangeListener (LINK(this,MasterPagesSelector
,ContainerChangeListener
));
111 mpContainer
->RemoveChangeListener(aChangeListener
);
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
);
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());
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
206 const sal_uInt16 nIndex
= PreviewValueSet::GetSelectedItemId();
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();
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
);
232 pMenu
->Execute(this, ::tools::Rectangle(aPosition
,Size(1,1)), PopupMenuFlags::ExecuteDown
);
240 void MasterPagesSelector::ProcessPopupMenu (Menu
& rMenu
)
242 // Disable some entries.
243 if (mpContainer
->GetPreviewSize() == MasterPageContainer::SMALL
)
244 rMenu
.EnableItem(rMenu
.GetItemId("small"), false);
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!");
258 ExecuteCommand(pMenu
->GetCurItemIdent());
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);
282 mxSidebar
->requestLayout();
284 else if (rIdent
== "small")
286 mrBase
.SetBusyState (true);
287 mpContainer
->SetPreviewSize(MasterPageContainer::SMALL
);
288 mrBase
.SetBusyState (false);
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
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);
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)
342 sal_uInt16 nPageCount
= mrDocument
.GetSdPageCount(PageKind::Standard
);
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
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 (
370 using namespace ::sd::slidesorter
;
371 using namespace ::sd::slidesorter::controller
;
373 if (pMasterPage
== nullptr)
376 // Find a visible slide sorter.
377 SlideSorterViewShell
* pSlideSorter
= SlideSorterViewShell::GetSlideSorter(mrBase
);
378 if (pSlideSorter
== nullptr)
381 // Get a list of selected pages.
382 SharedPageSelection pPageSelection
= pSlideSorter
->GetPageSelection();
383 if (pPageSelection
->empty())
386 AssignMasterPageToPageList(pMasterPage
, pPageSelection
);
388 // Restore the previous selection.
389 pSlideSorter
->SetPageSelection(pPageSelection
);
392 void MasterPagesSelector::AssignMasterPageToPageList (
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());
410 case MasterPageContainerChangeEvent::EventType::PREVIEW_CHANGED
:
412 int nIndex (GetIndexForToken(rEvent
.maChildToken
));
415 PreviewValueSet::SetItemImage (
416 static_cast<sal_uInt16
>(nIndex
),
417 mpContainer
->GetPreviewForToken(rEvent
.maChildToken
));
418 PreviewValueSet::Invalidate(PreviewValueSet::GetItemRect(static_cast<sal_uInt16
>(nIndex
)));
423 case MasterPageContainerChangeEvent::EventType::DATA_CHANGED
:
425 InvalidateItem(rEvent
.maChildToken
);
430 case MasterPageContainerChangeEvent::EventType::CHILD_REMOVED
:
432 int nIndex (GetIndexForToken(rEvent
.maChildToken
));
433 SetItem(nIndex
, MasterPageContainer::NIL_TOKEN
);
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
)));
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
)
461 PreviewValueSet::SetItemData(static_cast<sal_uInt16
>(nIndex
), pData
);
465 void MasterPagesSelector::SetItem (
467 MasterPageContainer::Token aToken
)
469 const ::osl::MutexGuard
aGuard (maMutex
);
471 RemoveTokenToIndexEntry(nIndex
,aToken
);
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
));
489 PreviewValueSet::InsertItem (
492 mpContainer
->GetPageNameForToken(aToken
),
495 SetUserData(nIndex
, new UserData(nIndex
,aToken
));
497 AddTokenToIndexEntry(nIndex
,aToken
);
500 if (eState
== MasterPageContainer::PS_CREATABLE
)
501 mpContainer
->RequestPreview(aToken
);
505 PreviewValueSet::RemoveItem(nIndex
);
511 void MasterPagesSelector::AddTokenToIndexEntry (
513 MasterPageContainer::Token aToken
)
515 const ::osl::MutexGuard
aGuard (maMutex
);
517 maTokenToValueSetIndex
[aToken
] = nIndex
;
520 void MasterPagesSelector::RemoveTokenToIndexEntry (
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
);
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(
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
);
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
;
610 void MasterPagesSelector::Clear()
612 const ::osl::MutexGuard
aGuard (maMutex
);
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
;
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
);
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();
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: */