bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / sidebar / MasterPagesSelector.cxx
blob0ac4680fbf5d8ddb0bfd2649866c0f68424de59f
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 "glob.hrc"
34 #include "app.hrc"
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 (
68 vcl::Window* pParent,
69 SdDrawDocument& rDocument,
70 ViewShellBase& rBase,
71 const ::boost::shared_ptr<MasterPageContainer>& rpContainer,
72 const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
73 : PreviewValueSet(pParent),
74 maMutex(),
75 mpContainer(rpContainer),
76 mrDocument(rDocument),
77 mbSmallPreviewSize(false),
78 mrBase(rBase),
79 mnDefaultClickAction(SID_TP_APPLY_TO_ALL_SLIDES),
80 maPreviewUpdateQueue(),
81 maCurrentItemList(),
82 maTokenToValueSetIndex(),
83 maLockedMasterPages(),
84 mxSidebar(rxSidebar)
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()
107 disposeOnce();
110 void MasterPagesSelector::dispose()
112 Clear();
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());
162 Fill(*pItemList);
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);
180 return 0;
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());
198 if (nIndex > 0)
199 PreviewValueSet::SelectItem (nIndex);
202 return 0;
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
212 // center.
213 const sal_uInt16 nIndex = PreviewValueSet::GetSelectItemId();
214 if (nIndex > 0)
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();
227 // Setup the menu.
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);
237 // Show the menu.
238 pMenu->Execute(this, Rectangle(aPosition,Size(1,1)), PopupMenuFlags::ExecuteDown);
241 break;
242 default: break;
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);
251 else
252 rMenu.EnableItem(SID_TP_SHOW_LARGE_PREVIEW, false);
255 IMPL_LINK(MasterPagesSelector, OnMenuItemSelected, Menu*, pMenu)
257 if (pMenu == NULL)
259 OSL_ENSURE(pMenu!=NULL, "MasterPagesSelector::OnMenuItemSelected: illegal menu!");
260 return 0;
263 pMenu->Deactivate();
264 ExecuteCommand(pMenu->GetCurItemId());
265 return 0;
268 void MasterPagesSelector::ExecuteCommand (const sal_Int32 nCommandId)
270 switch (nCommandId)
272 case SID_TP_APPLY_TO_ALL_SLIDES:
273 mrBase.SetBusyState (true);
274 AssignMasterPageToAllSlides (GetSelectedMasterPage());
275 mrBase.SetBusyState (false);
276 break;
278 case SID_TP_APPLY_TO_SELECTED_SLIDES:
279 mrBase.SetBusyState (true);
280 AssignMasterPageToSelectedSlides (GetSelectedMasterPage());
281 mrBase.SetBusyState (false);
282 break;
284 case SID_TP_USE_FOR_NEW_PRESENTATIONS:
285 DBG_ASSERT (false,
286 "Using slides as default for new presentations"
287 " is not yet implemented");
288 break;
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);
299 if (mxSidebar.is())
300 mxSidebar->requestLayout();
301 break;
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
310 if (pMasterPage)
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);
324 break;
327 case SID_CUT:
328 case SID_COPY:
329 case SID_PASTE:
330 // Cut, copy, and paste are not supported and thus are ignored.
331 break;
335 IMPL_LINK(MasterPagesSelector, ContainerChangeListener, MasterPageContainerChangeEvent*, pEvent)
337 if (pEvent)
338 NotifyContainerChangeEvent(*pEvent);
339 return 0;
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);
349 if (pData != NULL)
351 pMasterPage = mpContainer->GetPageObjectForToken(pData->second);
353 return pMasterPage;
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)
362 return;
364 sal_uInt16 nPageCount = mrDocument.GetSdPageCount(PK_STANDARD);
365 if (nPageCount == 0)
366 return;
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
370 // assigned.
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 (
390 SdPage* pMasterPage)
392 using namespace ::sd::slidesorter;
393 using namespace ::sd::slidesorter::controller;
395 if (pMasterPage == NULL)
396 return;
398 // Find a visible slide sorter.
399 SlideSorterViewShell* pSlideSorter = SlideSorterViewShell::GetSlideSorter(mrBase);
400 if (pSlideSorter == NULL)
401 return;
403 // Get a list of selected pages.
404 SharedPageSelection pPageSelection = pSlideSorter->GetPageSelection();
405 if (pPageSelection->empty())
406 return;
408 AssignMasterPageToPageList(pMasterPage, pPageSelection);
410 // Restore the previous selection.
411 pSlideSorter->SetPageSelection(pPageSelection);
414 void MasterPagesSelector::AssignMasterPageToPageList (
415 SdPage* pMasterPage,
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());
429 UpdateAllPreviews();
430 break;
432 case MasterPageContainerChangeEvent::PREVIEW_CHANGED:
434 int nIndex (GetIndexForToken(rEvent.maChildToken));
435 if (nIndex >= 0)
437 PreviewValueSet::SetItemImage (
438 (sal_uInt16)nIndex,
439 mpContainer->GetPreviewForToken(rEvent.maChildToken));
440 PreviewValueSet::Invalidate(PreviewValueSet::GetItemRect((sal_uInt16)nIndex));
443 break;
445 case MasterPageContainerChangeEvent::DATA_CHANGED:
447 InvalidateItem(rEvent.maChildToken);
448 Fill();
450 break;
452 case MasterPageContainerChangeEvent::CHILD_REMOVED:
454 int nIndex (GetIndexForToken(rEvent.maChildToken));
455 SetItem(nIndex, MasterPageContainer::NIL_TOKEN);
458 default:
459 break;
463 MasterPagesSelector::UserData* MasterPagesSelector::CreateUserData (
464 int nIndex,
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));
476 else
477 return NULL;
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)
488 delete pOldData;
489 PreviewValueSet::SetItemData((sal_uInt16)nIndex, pData);
493 void MasterPagesSelector::UpdateSelection()
497 void MasterPagesSelector::SetItem (
498 sal_uInt16 nIndex,
499 MasterPageContainer::Token aToken)
501 const ::osl::MutexGuard aGuard (maMutex);
503 RemoveTokenToIndexEntry(nIndex,aToken);
505 if (nIndex > 0)
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));
519 else
521 PreviewValueSet::InsertItem (
522 nIndex,
523 aPreview,
524 mpContainer->GetPageNameForToken(aToken),
525 nIndex);
527 SetUserData(nIndex, CreateUserData(nIndex,aToken));
529 AddTokenToIndexEntry(nIndex,aToken);
532 if (eState == MasterPageContainer::PS_CREATABLE)
533 mpContainer->RequestPreview(aToken);
535 else
537 PreviewValueSet::RemoveItem(nIndex);
543 void MasterPagesSelector::AddTokenToIndexEntry (
544 sal_uInt16 nIndex,
545 MasterPageContainer::Token aToken)
547 const ::osl::MutexGuard aGuard (maMutex);
549 maTokenToValueSetIndex[aToken] = nIndex;
552 void MasterPagesSelector::RemoveTokenToIndexEntry (
553 sal_uInt16 nIndex,
554 MasterPageContainer::Token aNewToken)
556 const ::osl::MutexGuard aGuard (maMutex);
558 UserData* pData = GetUserData(nIndex);
559 if (pData != NULL)
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);
579 if (pData != NULL)
581 MasterPageContainer::Token aToken (pData->second);
582 if (pPage == mpContainer->GetPageObjectForToken(aToken,false))
584 mpContainer->InvalidatePreview(aToken);
585 mpContainer->RequestPreview(aToken);
586 break;
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);
599 if (pData != NULL)
601 MasterPageContainer::Token aToken (pData->second);
602 PreviewValueSet::SetItemImage(
603 nIndex,
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);
619 if (pData != NULL)
620 delete pData;
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;
639 else
640 return -1;
643 void MasterPagesSelector::Clear()
645 const ::osl::MutexGuard aGuard (maMutex);
647 ClearPageSet();
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;
660 break;
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);
684 // Append new items.
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();
699 if (mxSidebar.is())
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: */