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 "res_bmp.hrc"
36 #include "strings.hrc"
37 #include "DrawViewShell.hxx"
38 #include "DrawController.hxx"
39 #include "SlideSorterViewShell.hxx"
40 #include "PreviewValueSet.hxx"
41 #include "ViewShellBase.hxx"
42 #include <sfx2/objface.hxx>
43 #include "sdresid.hxx"
44 #include "drawview.hxx"
45 #include <vcl/image.hxx>
46 #include <vcl/floatwin.hxx>
47 #include <svl/languageoptions.hxx>
48 #include <sfx2/app.hxx>
49 #include <sfx2/dispatch.hxx>
50 #include <sfx2/mnumgr.hxx>
51 #include <svl/itemset.hxx>
52 #include <svl/eitem.hxx>
53 #include <svx/dlgutil.hxx>
54 #include <svx/svdpagv.hxx>
55 #include <svx/svxids.hrc>
56 #include "FrameView.hxx"
57 #include "stlpool.hxx"
58 #include "unmovss.hxx"
59 #include <sfx2/request.hxx>
60 #include <svl/itempool.hxx>
61 #include <sfx2/sidebar/Theme.hxx>
63 using namespace ::com::sun::star::text
;
65 namespace sd
{ namespace sidebar
{
67 MasterPagesSelector::MasterPagesSelector (
69 SdDrawDocument
& rDocument
,
71 const ::boost::shared_ptr
<MasterPageContainer
>& rpContainer
,
72 const css::uno::Reference
<css::ui::XSidebar
>& rxSidebar
)
73 : PreviewValueSet(pParent
),
75 mpContainer(rpContainer
),
76 mrDocument(rDocument
),
77 mbSmallPreviewSize(false),
79 mnDefaultClickAction(SID_TP_APPLY_TO_ALL_SLIDES
),
80 maPreviewUpdateQueue(),
82 maTokenToValueSetIndex(),
83 maLockedMasterPages(),
86 PreviewValueSet::SetSelectHdl (
87 LINK(this, MasterPagesSelector
, ClickHandler
));
88 PreviewValueSet::SetRightMouseClickHandler (
89 LINK(this, MasterPagesSelector
, RightClickHandler
));
90 PreviewValueSet::SetStyle(PreviewValueSet::GetStyle() | WB_NO_DIRECTSELECT
);
92 if ( GetDPIScaleFactor() > 1 )
93 mpContainer
->SetPreviewSize(MasterPageContainer::LARGE
);
95 PreviewValueSet::SetPreviewSize(mpContainer
->GetPreviewSizePixel());
96 PreviewValueSet::Show();
98 SetBackground(sfx2::sidebar::Theme::GetWallpaper(sfx2::sidebar::Theme::Paint_PanelBackground
));
99 SetColor(sfx2::sidebar::Theme::GetColor(sfx2::sidebar::Theme::Paint_PanelBackground
));
101 Link
<> aChangeListener (LINK(this,MasterPagesSelector
,ContainerChangeListener
));
102 mpContainer
->AddChangeListener(aChangeListener
);
105 MasterPagesSelector::~MasterPagesSelector()
110 void MasterPagesSelector::dispose()
113 UpdateLocks(ItemList());
115 Link
<> aChangeListener (LINK(this,MasterPagesSelector
,ContainerChangeListener
));
116 mpContainer
->RemoveChangeListener(aChangeListener
);
117 PreviewValueSet::dispose();
120 void MasterPagesSelector::LateInit()
124 sal_Int32
MasterPagesSelector::GetPreferredHeight (sal_Int32 nWidth
)
126 const ::osl::MutexGuard
aGuard (maMutex
);
128 return PreviewValueSet::GetPreferredHeight (nWidth
);
131 void MasterPagesSelector::UpdateLocks (const ItemList
& rItemList
)
133 ItemList aNewLockList
;
135 // In here we first lock the master pages in the given list and then
136 // release the locks acquired in a previous call to this method. When
137 // this were done the other way round the lock count of some master
138 // pages might drop temporarily to 0 and would lead to unnecessary
139 // deletion and re-creation of MasterPageDescriptor objects.
141 // Lock the master pages in the given list.
142 ItemList::const_iterator iItem
;
143 for (iItem
=rItemList
.begin(); iItem
!=rItemList
.end(); ++iItem
)
145 mpContainer
->AcquireToken(*iItem
);
146 aNewLockList
.push_back(*iItem
);
149 // Release the previously locked master pages.
150 ItemList::const_iterator iPage
;
151 ItemList::const_iterator
iEnd (maLockedMasterPages
.end());
152 for (iPage
=maLockedMasterPages
.begin(); iPage
!=iEnd
; ++iPage
)
153 mpContainer
->ReleaseToken(*iPage
);
155 maLockedMasterPages
.swap(aNewLockList
);
158 void MasterPagesSelector::Fill()
160 ::std::unique_ptr
<ItemList
> pItemList (new ItemList());
164 UpdateLocks(*pItemList
);
165 UpdateItemList(std::move(pItemList
));
168 ResId
MasterPagesSelector::GetContextMenuResId() const
170 return SdResId(RID_TASKPANE_MASTERPAGESSELECTOR_POPUP
);
173 IMPL_LINK_NOARG(MasterPagesSelector
, ClickHandler
)
175 // We use the framework to assign the clicked-on master page because we
176 // so use the same mechanism as the context menu does (where we do not
177 // have the option to call the assignment method directly.)
178 ExecuteCommand(mnDefaultClickAction
);
183 IMPL_LINK(MasterPagesSelector
, RightClickHandler
, MouseEvent
*, pEvent
)
185 // Here we only prepare the display of the context menu: the item under
186 // the mouse is selected. The actual display of the context menu is
187 // done in ContextMenuCallback which is called indirectly through
188 // PreviewValueSet::Command().
189 PreviewValueSet::GrabFocus ();
190 PreviewValueSet::ReleaseMouse();
191 SfxViewFrame
* pViewFrame
= mrBase
.GetViewFrame();
192 if (pViewFrame
!= NULL
)
194 SfxDispatcher
* pDispatcher
= pViewFrame
->GetDispatcher();
195 if (pDispatcher
!= NULL
&& pEvent
!= NULL
)
197 sal_uInt16 nIndex
= PreviewValueSet::GetItemId (pEvent
->GetPosPixel());
199 PreviewValueSet::SelectItem (nIndex
);
205 void MasterPagesSelector::Command (const CommandEvent
& rEvent
)
207 switch (rEvent
.GetCommand())
209 case CommandEventId::ContextMenu
:
211 // Use the currently selected item and show the popup menu in its
213 const sal_uInt16 nIndex
= PreviewValueSet::GetSelectItemId();
216 // The position of the upper left corner of the context menu is
217 // taken either from the mouse position (when the command was sent
218 // as reaction to a right click) or in the center of the selected
219 // item (when the command was sent as reaction to Shift+F10.)
220 Point
aPosition (rEvent
.GetMousePosPixel());
221 if ( ! rEvent
.IsMouseEvent())
223 Rectangle
aBBox (PreviewValueSet::GetItemRect(nIndex
));
224 aPosition
= aBBox
.Center();
228 ::boost::scoped_ptr
<PopupMenu
> pMenu (new PopupMenu(GetContextMenuResId()));
229 FloatingWindow
* pMenuWindow
= dynamic_cast<FloatingWindow
*>(pMenu
->GetWindow());
230 if (pMenuWindow
!= NULL
)
231 pMenuWindow
->SetPopupModeFlags(
232 pMenuWindow
->GetPopupModeFlags() | FloatWinPopupFlags::NoMouseUpClose
);
233 pMenu
->SetSelectHdl(LINK(this, MasterPagesSelector
, OnMenuItemSelected
));
235 ProcessPopupMenu(*pMenu
);
238 pMenu
->Execute(this, Rectangle(aPosition
,Size(1,1)), PopupMenuFlags::ExecuteDown
);
246 void MasterPagesSelector::ProcessPopupMenu (Menu
& rMenu
)
248 // Disable some entries.
249 if (mpContainer
->GetPreviewSize() == MasterPageContainer::SMALL
)
250 rMenu
.EnableItem(SID_TP_SHOW_SMALL_PREVIEW
, false);
252 rMenu
.EnableItem(SID_TP_SHOW_LARGE_PREVIEW
, false);
255 IMPL_LINK(MasterPagesSelector
, OnMenuItemSelected
, Menu
*, pMenu
)
259 OSL_ENSURE(pMenu
!=NULL
, "MasterPagesSelector::OnMenuItemSelected: illegal menu!");
264 ExecuteCommand(pMenu
->GetCurItemId());
268 void MasterPagesSelector::ExecuteCommand (const sal_Int32 nCommandId
)
272 case SID_TP_APPLY_TO_ALL_SLIDES
:
273 mrBase
.SetBusyState (true);
274 AssignMasterPageToAllSlides (GetSelectedMasterPage());
275 mrBase
.SetBusyState (false);
278 case SID_TP_APPLY_TO_SELECTED_SLIDES
:
279 mrBase
.SetBusyState (true);
280 AssignMasterPageToSelectedSlides (GetSelectedMasterPage());
281 mrBase
.SetBusyState (false);
284 case SID_TP_USE_FOR_NEW_PRESENTATIONS
:
286 "Using slides as default for new presentations"
287 " is not yet implemented");
290 case SID_TP_SHOW_SMALL_PREVIEW
:
291 case SID_TP_SHOW_LARGE_PREVIEW
:
293 mrBase
.SetBusyState (true);
294 mpContainer
->SetPreviewSize(
295 nCommandId
==SID_TP_SHOW_SMALL_PREVIEW
296 ? MasterPageContainer::SMALL
297 : MasterPageContainer::LARGE
);
298 mrBase
.SetBusyState (false);
300 mxSidebar
->requestLayout();
304 case SID_TP_EDIT_MASTER
:
306 using namespace ::com::sun::star
;
307 uno::Reference
<drawing::XDrawPage
> xSelectedMaster
;
308 SdPage
* pMasterPage
= GetSelectedMasterPage();
309 assert(pMasterPage
); //rhbz#902884
311 xSelectedMaster
= uno::Reference
<drawing::XDrawPage
>(pMasterPage
->getUnoPage(), uno::UNO_QUERY
);
312 SfxViewFrame
* pViewFrame
= mrBase
.GetViewFrame();
313 if (pViewFrame
!= NULL
&& xSelectedMaster
.is())
315 SfxDispatcher
* pDispatcher
= pViewFrame
->GetDispatcher();
316 if (pDispatcher
!= NULL
)
318 sal_uInt16 nIndex
= PreviewValueSet::GetSelectItemId();
319 pDispatcher
->Execute(SID_MASTERPAGE
, SfxCallMode::SYNCHRON
);
320 PreviewValueSet::SelectItem (nIndex
);
321 mrBase
.GetDrawController().setCurrentPage(xSelectedMaster
);
330 // Cut, copy, and paste are not supported and thus are ignored.
335 IMPL_LINK(MasterPagesSelector
, ContainerChangeListener
, MasterPageContainerChangeEvent
*, pEvent
)
338 NotifyContainerChangeEvent(*pEvent
);
342 SdPage
* MasterPagesSelector::GetSelectedMasterPage()
344 const ::osl::MutexGuard
aGuard (maMutex
);
346 SdPage
* pMasterPage
= NULL
;
347 sal_uInt16 nIndex
= PreviewValueSet::GetSelectItemId();
348 UserData
* pData
= GetUserData(nIndex
);
351 pMasterPage
= mpContainer
->GetPageObjectForToken(pData
->second
);
356 /** Assemble a list of all slides of the document and pass it to
357 AssignMasterPageToPageList().
359 void MasterPagesSelector::AssignMasterPageToAllSlides (SdPage
* pMasterPage
)
361 if (pMasterPage
== NULL
)
364 sal_uInt16 nPageCount
= mrDocument
.GetSdPageCount(PK_STANDARD
);
368 // Get a list of all pages. As a little optimization we only
369 // include pages that do not already have the given master page
371 OUString
sFullLayoutName(pMasterPage
->GetLayoutName());
372 ::sd::slidesorter::SharedPageSelection
pPageList (
373 new ::sd::slidesorter::SlideSorterViewShell::PageSelection());
374 for (sal_uInt16 nPageIndex
=0; nPageIndex
<nPageCount
; nPageIndex
++)
376 SdPage
* pPage
= mrDocument
.GetSdPage (nPageIndex
, PK_STANDARD
);
377 if (pPage
!= NULL
&& pPage
->GetLayoutName() != sFullLayoutName
)
379 pPageList
->push_back (pPage
);
383 AssignMasterPageToPageList(pMasterPage
, pPageList
);
386 /** Assemble a list of the currently selected slides (selected in a visible
387 slide sorter) and pass it to AssignMasterPageToPageList().
389 void MasterPagesSelector::AssignMasterPageToSelectedSlides (
392 using namespace ::sd::slidesorter
;
393 using namespace ::sd::slidesorter::controller
;
395 if (pMasterPage
== NULL
)
398 // Find a visible slide sorter.
399 SlideSorterViewShell
* pSlideSorter
= SlideSorterViewShell::GetSlideSorter(mrBase
);
400 if (pSlideSorter
== NULL
)
403 // Get a list of selected pages.
404 SharedPageSelection pPageSelection
= pSlideSorter
->GetPageSelection();
405 if (pPageSelection
->empty())
408 AssignMasterPageToPageList(pMasterPage
, pPageSelection
);
410 // Restore the previous selection.
411 pSlideSorter
->SetPageSelection(pPageSelection
);
414 void MasterPagesSelector::AssignMasterPageToPageList (
416 const ::sd::slidesorter::SharedPageSelection
& rPageList
)
418 DocumentHelper::AssignMasterPageToPageList(mrDocument
, pMasterPage
, rPageList
);
421 void MasterPagesSelector::NotifyContainerChangeEvent (const MasterPageContainerChangeEvent
& rEvent
)
423 const ::osl::MutexGuard
aGuard (maMutex
);
425 switch (rEvent
.meEventType
)
427 case MasterPageContainerChangeEvent::SIZE_CHANGED
:
428 PreviewValueSet::SetPreviewSize(mpContainer
->GetPreviewSizePixel());
432 case MasterPageContainerChangeEvent::PREVIEW_CHANGED
:
434 int nIndex (GetIndexForToken(rEvent
.maChildToken
));
437 PreviewValueSet::SetItemImage (
439 mpContainer
->GetPreviewForToken(rEvent
.maChildToken
));
440 PreviewValueSet::Invalidate(PreviewValueSet::GetItemRect((sal_uInt16
)nIndex
));
445 case MasterPageContainerChangeEvent::DATA_CHANGED
:
447 InvalidateItem(rEvent
.maChildToken
);
452 case MasterPageContainerChangeEvent::CHILD_REMOVED
:
454 int nIndex (GetIndexForToken(rEvent
.maChildToken
));
455 SetItem(nIndex
, MasterPageContainer::NIL_TOKEN
);
463 MasterPagesSelector::UserData
* MasterPagesSelector::CreateUserData (
465 MasterPageContainer::Token aToken
)
467 return new UserData(nIndex
,aToken
);
470 MasterPagesSelector::UserData
* MasterPagesSelector::GetUserData (int nIndex
) const
472 const ::osl::MutexGuard
aGuard (maMutex
);
474 if (nIndex
>0 && static_cast<unsigned int>(nIndex
)<=PreviewValueSet::GetItemCount())
475 return static_cast<UserData
*>(PreviewValueSet::GetItemData((sal_uInt16
)nIndex
));
480 void MasterPagesSelector::SetUserData (int nIndex
, UserData
* pData
)
482 const ::osl::MutexGuard
aGuard (maMutex
);
484 if (nIndex
>0 && static_cast<unsigned int>(nIndex
)<=PreviewValueSet::GetItemCount())
486 UserData
* pOldData
= GetUserData(nIndex
);
487 if (pOldData
!=NULL
&& pOldData
!=pData
)
489 PreviewValueSet::SetItemData((sal_uInt16
)nIndex
, pData
);
493 void MasterPagesSelector::UpdateSelection()
497 void MasterPagesSelector::SetItem (
499 MasterPageContainer::Token aToken
)
501 const ::osl::MutexGuard
aGuard (maMutex
);
503 RemoveTokenToIndexEntry(nIndex
,aToken
);
507 if (aToken
!= MasterPageContainer::NIL_TOKEN
)
509 Image
aPreview (mpContainer
->GetPreviewForToken(aToken
));
510 MasterPageContainer::PreviewState
eState (mpContainer
->GetPreviewState(aToken
));
512 if (aPreview
.GetSizePixel().Width()>0)
514 if (PreviewValueSet::GetItemPos(nIndex
) != VALUESET_ITEM_NOTFOUND
)
516 PreviewValueSet::SetItemImage(nIndex
,aPreview
);
517 PreviewValueSet::SetItemText(nIndex
, mpContainer
->GetPageNameForToken(aToken
));
521 PreviewValueSet::InsertItem (
524 mpContainer
->GetPageNameForToken(aToken
),
527 SetUserData(nIndex
, CreateUserData(nIndex
,aToken
));
529 AddTokenToIndexEntry(nIndex
,aToken
);
532 if (eState
== MasterPageContainer::PS_CREATABLE
)
533 mpContainer
->RequestPreview(aToken
);
537 PreviewValueSet::RemoveItem(nIndex
);
543 void MasterPagesSelector::AddTokenToIndexEntry (
545 MasterPageContainer::Token aToken
)
547 const ::osl::MutexGuard
aGuard (maMutex
);
549 maTokenToValueSetIndex
[aToken
] = nIndex
;
552 void MasterPagesSelector::RemoveTokenToIndexEntry (
554 MasterPageContainer::Token aNewToken
)
556 const ::osl::MutexGuard
aGuard (maMutex
);
558 UserData
* pData
= GetUserData(nIndex
);
561 // Get the token that the index pointed to previously.
562 MasterPageContainer::Token
aOldToken (pData
->second
);
564 if (aNewToken
!= aOldToken
565 && nIndex
== GetIndexForToken(aOldToken
))
567 maTokenToValueSetIndex
[aOldToken
] = 0;
572 void MasterPagesSelector::InvalidatePreview (const SdPage
* pPage
)
574 const ::osl::MutexGuard
aGuard (maMutex
);
576 for (sal_uInt16 nIndex
=1; nIndex
<=PreviewValueSet::GetItemCount(); nIndex
++)
578 UserData
* pData
= GetUserData(nIndex
);
581 MasterPageContainer::Token
aToken (pData
->second
);
582 if (pPage
== mpContainer
->GetPageObjectForToken(aToken
,false))
584 mpContainer
->InvalidatePreview(aToken
);
585 mpContainer
->RequestPreview(aToken
);
592 void MasterPagesSelector::UpdateAllPreviews()
594 const ::osl::MutexGuard
aGuard (maMutex
);
596 for (sal_uInt16 nIndex
=1; nIndex
<=PreviewValueSet::GetItemCount(); nIndex
++)
598 UserData
* pData
= GetUserData(nIndex
);
601 MasterPageContainer::Token
aToken (pData
->second
);
602 PreviewValueSet::SetItemImage(
604 mpContainer
->GetPreviewForToken(aToken
));
605 if (mpContainer
->GetPreviewState(aToken
) == MasterPageContainer::PS_CREATABLE
)
606 mpContainer
->RequestPreview(aToken
);
609 PreviewValueSet::Rearrange(true);
612 void MasterPagesSelector::ClearPageSet()
614 const ::osl::MutexGuard
aGuard (maMutex
);
616 for (sal_uInt16 nIndex
=1; nIndex
<=PreviewValueSet::GetItemCount(); nIndex
++)
618 UserData
* pData
= GetUserData(nIndex
);
622 PreviewValueSet::Clear();
625 void MasterPagesSelector::SetHelpId( const OString
& aId
)
627 const ::osl::MutexGuard
aGuard (maMutex
);
629 PreviewValueSet::SetHelpId( aId
);
632 sal_Int32
MasterPagesSelector::GetIndexForToken (MasterPageContainer::Token aToken
) const
634 const ::osl::MutexGuard
aGuard (maMutex
);
636 TokenToValueSetIndex::const_iterator
iIndex (maTokenToValueSetIndex
.find(aToken
));
637 if (iIndex
!= maTokenToValueSetIndex
.end())
638 return iIndex
->second
;
643 void MasterPagesSelector::Clear()
645 const ::osl::MutexGuard
aGuard (maMutex
);
650 void MasterPagesSelector::InvalidateItem (MasterPageContainer::Token aToken
)
652 const ::osl::MutexGuard
aGuard (maMutex
);
654 ItemList::iterator iItem
;
655 for (iItem
=maCurrentItemList
.begin(); iItem
!=maCurrentItemList
.end(); ++iItem
)
657 if (*iItem
== aToken
)
659 *iItem
= MasterPageContainer::NIL_TOKEN
;
665 void MasterPagesSelector::UpdateItemList (::std::unique_ptr
<ItemList
> && pNewItemList
)
667 const ::osl::MutexGuard
aGuard (maMutex
);
669 ItemList::const_iterator
iNewItem (pNewItemList
->begin());
670 ItemList::const_iterator
iCurrentItem (maCurrentItemList
.begin());
671 ItemList::const_iterator
iNewEnd (pNewItemList
->end());
672 ItemList::const_iterator
iCurrentEnd (maCurrentItemList
.end());
673 sal_uInt16
nIndex (1);
675 // Update existing items.
676 for ( ; iNewItem
!=iNewEnd
&& iCurrentItem
!=iCurrentEnd
; ++iNewItem
, ++iCurrentItem
,++nIndex
)
678 if (*iNewItem
!= *iCurrentItem
)
680 SetItem(nIndex
,*iNewItem
);
685 for ( ; iNewItem
!=iNewEnd
; ++iNewItem
,++nIndex
)
687 SetItem(nIndex
,*iNewItem
);
690 // Remove trailing items.
691 for ( ; iCurrentItem
!=iCurrentEnd
; ++iCurrentItem
,++nIndex
)
693 SetItem(nIndex
,MasterPageContainer::NIL_TOKEN
);
696 maCurrentItemList
.swap(*pNewItemList
);
698 PreviewValueSet::Rearrange();
700 mxSidebar
->requestLayout();
703 css::ui::LayoutSize
MasterPagesSelector::GetHeightForWidth (const sal_Int32 nWidth
)
705 const sal_Int32
nHeight (GetPreferredHeight(nWidth
));
706 return css::ui::LayoutSize(nHeight
,nHeight
,nHeight
);
709 } } // end of namespace sd::sidebar
711 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */