Get the style color and number just once
[LibreOffice.git] / sd / source / ui / sidebar / LayoutMenu.cxx
blob4f0545fbf83e86d1bd1184d429a360367f544572
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 "LayoutMenu.hxx"
22 #include <app.hrc>
23 #include <drawdoc.hxx>
24 #include <framework/FrameworkHelper.hxx>
25 #include <strings.hrc>
26 #include <helpids.h>
27 #include <pres.hxx>
28 #include <sdmod.hxx>
30 #include <sdpage.hxx>
31 #include <sdresid.hxx>
32 #include <unokywds.hxx>
33 #include <bitmaps.hlst>
34 #include <tools/gen.hxx>
35 #include <tools/SlotStateListener.hxx>
36 #include <DrawController.hxx>
37 #include <DrawDocShell.hxx>
38 #include <DrawViewShell.hxx>
39 #include <EventMultiplexer.hxx>
40 #include <SlideSorterViewShell.hxx>
41 #include <ViewShellBase.hxx>
42 #include <sfx2/sidebar/Theme.hxx>
43 #include <sal/log.hxx>
45 #include <comphelper/processfactory.hxx>
46 #include <sfx2/dispatch.hxx>
47 #include <sfx2/request.hxx>
48 #include <sfx2/viewfrm.hxx>
49 #include <svl/cjkoptions.hxx>
50 #include <svl/stritem.hxx>
51 #include <svl/intitem.hxx>
52 #include <utility>
53 #include <vcl/commandevent.hxx>
54 #include <vcl/image.hxx>
55 #include <xmloff/autolayout.hxx>
57 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
58 #include <com/sun/star/drawing/framework/XView.hpp>
59 #include <com/sun/star/drawing/framework/ResourceId.hpp>
61 #include <string_view>
62 #include <vector>
64 using namespace ::com::sun::star;
65 using namespace ::com::sun::star::text;
66 using namespace ::com::sun::star::uno;
67 using namespace ::com::sun::star::drawing::framework;
68 using namespace ::sd::slidesorter;
69 using ::sd::framework::FrameworkHelper;
71 namespace sd::sidebar {
73 namespace {
75 struct snew_slide_value_info
77 OUString msBmpResId;
78 TranslateId mpStrResId;
79 WritingMode meWritingMode;
80 AutoLayout maAutoLayout;
85 constexpr snew_slide_value_info notes[] =
87 {BMP_SLIDEN_01, STR_AUTOLAYOUT_NOTES, WritingMode_LR_TB,
88 AUTOLAYOUT_NOTES},
91 constexpr snew_slide_value_info handout[] =
93 {BMP_SLIDEH_01, STR_AUTOLAYOUT_HANDOUT1, WritingMode_LR_TB,
94 AUTOLAYOUT_HANDOUT1},
95 {BMP_SLIDEH_02, STR_AUTOLAYOUT_HANDOUT2, WritingMode_LR_TB,
96 AUTOLAYOUT_HANDOUT2},
97 {BMP_SLIDEH_03, STR_AUTOLAYOUT_HANDOUT3, WritingMode_LR_TB,
98 AUTOLAYOUT_HANDOUT3},
99 {BMP_SLIDEH_04, STR_AUTOLAYOUT_HANDOUT4, WritingMode_LR_TB,
100 AUTOLAYOUT_HANDOUT4},
101 {BMP_SLIDEH_06, STR_AUTOLAYOUT_HANDOUT6, WritingMode_LR_TB,
102 AUTOLAYOUT_HANDOUT6},
103 {BMP_SLIDEH_09, STR_AUTOLAYOUT_HANDOUT9, WritingMode_LR_TB,
104 AUTOLAYOUT_HANDOUT9},
107 constexpr snew_slide_value_info standard[] =
109 {BMP_LAYOUT_EMPTY, STR_AUTOLAYOUT_NONE, WritingMode_LR_TB, AUTOLAYOUT_NONE},
110 {BMP_LAYOUT_HEAD03, STR_AUTOLAYOUT_TITLE, WritingMode_LR_TB, AUTOLAYOUT_TITLE},
111 {BMP_LAYOUT_HEAD02, STR_AUTOLAYOUT_CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_CONTENT},
112 {BMP_LAYOUT_HEAD02A, STR_AUTOLAYOUT_2CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_2CONTENT},
113 {BMP_LAYOUT_HEAD01, STR_AUTOLAYOUT_ONLY_TITLE, WritingMode_LR_TB, AUTOLAYOUT_TITLE_ONLY},
114 {BMP_LAYOUT_TEXTONLY, STR_AUTOLAYOUT_ONLY_TEXT, WritingMode_LR_TB, AUTOLAYOUT_ONLY_TEXT},
115 {BMP_LAYOUT_HEAD03B, STR_AUTOLAYOUT_2CONTENT_CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_2CONTENT_CONTENT},
116 {BMP_LAYOUT_HEAD03C, STR_AUTOLAYOUT_CONTENT_2CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_CONTENT_2CONTENT},
117 {BMP_LAYOUT_HEAD03A, STR_AUTOLAYOUT_2CONTENT_OVER_CONTENT,WritingMode_LR_TB, AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT},
118 {BMP_LAYOUT_HEAD02B, STR_AUTOLAYOUT_CONTENT_OVER_CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT},
119 {BMP_LAYOUT_HEAD04, STR_AUTOLAYOUT_4CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_4CONTENT},
120 {BMP_LAYOUT_HEAD06, STR_AUTOLAYOUT_6CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_6CONTENT},
122 // vertical
123 {BMP_LAYOUT_VERTICAL02, STR_AL_VERT_TITLE_TEXT_CHART, WritingMode_TB_RL, AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT},
124 {BMP_LAYOUT_VERTICAL01, STR_AL_VERT_TITLE_VERT_OUTLINE, WritingMode_TB_RL, AUTOLAYOUT_VTITLE_VCONTENT},
125 {BMP_LAYOUT_HEAD02, STR_AL_TITLE_VERT_OUTLINE, WritingMode_TB_RL, AUTOLAYOUT_TITLE_VCONTENT},
126 {BMP_LAYOUT_HEAD02A, STR_AL_TITLE_VERT_OUTLINE_CLIPART, WritingMode_TB_RL, AUTOLAYOUT_TITLE_2VTEXT},
129 class LayoutValueSet : public ValueSet
131 private:
132 LayoutMenu& mrMenu;
134 /** Calculate the number of displayed rows. This depends on the given
135 item size, the given number of columns, and the size of the
136 control. Note that this is not the number of rows managed by the
137 valueset. This number may be larger. In that case a vertical
138 scroll bar is displayed.
140 int CalculateRowCount(const Size& rItemSize, int nColumnCount);
142 public:
143 LayoutValueSet(LayoutMenu& rMenu)
144 : ValueSet(nullptr)
145 , mrMenu(rMenu)
149 virtual void Resize() override;
151 virtual bool Command(const CommandEvent& rEvent) override;
154 LayoutMenu::LayoutMenu (
155 weld::Widget* pParent,
156 ViewShellBase& rViewShellBase,
157 css::uno::Reference<css::ui::XSidebar> xSidebar)
158 : PanelLayout( pParent, u"LayoutPanel"_ustr, u"modules/simpress/ui/layoutpanel.ui"_ustr ),
159 mrBase(rViewShellBase),
160 mxLayoutValueSet(new LayoutValueSet(*this)),
161 mxLayoutValueSetWin(new weld::CustomWeld(*m_xBuilder, u"layoutvalueset"_ustr, *mxLayoutValueSet)),
162 mbIsMainViewChangePending(false),
163 mxSidebar(std::move(xSidebar)),
164 mbIsDisposed(false)
166 implConstruct( *mrBase.GetDocument()->GetDocSh() );
167 SAL_INFO("sd.ui", "created LayoutMenu at " << this);
169 mxLayoutValueSet->SetStyle(mxLayoutValueSet->GetStyle() | WB_ITEMBORDER | WB_FLATVALUESET | WB_TABSTOP);
171 mxLayoutValueSet->SetColor(sfx2::sidebar::Theme::GetColor(sfx2::sidebar::Theme::Color_PanelBackground));
174 void LayoutMenu::implConstruct( DrawDocShell& rDocumentShell )
176 OSL_ENSURE( mrBase.GetDocument()->GetDocSh() == &rDocumentShell,
177 "LayoutMenu::implConstruct: hmm?" );
178 // if this fires, then my assumption that the rDocumentShell parameter to our first ctor is superfluous ...
179 (void) rDocumentShell;
181 mxLayoutValueSet->SetStyle (
182 ( mxLayoutValueSet->GetStyle() & ~(WB_ITEMBORDER) )
183 | WB_TABSTOP
184 | WB_MENUSTYLEVALUESET
185 | WB_NO_DIRECTSELECT
187 mxLayoutValueSet->SetExtraSpacing(2);
188 mxLayoutValueSet->SetSelectHdl (LINK(this, LayoutMenu, ClickHandler));
189 InvalidateContent();
191 Link<::sd::tools::EventMultiplexerEvent&,void> aEventListenerLink (LINK(this,LayoutMenu,EventMultiplexerListener));
192 mrBase.GetEventMultiplexer()->AddEventListener(aEventListenerLink);
194 mxLayoutValueSet->SetHelpId(HID_SD_TASK_PANE_PREVIEW_LAYOUTS);
195 mxLayoutValueSet->SetAccessibleName(SdResId(STR_TASKPANEL_LAYOUT_MENU_TITLE));
197 Link<const OUString&,void> aStateChangeLink (LINK(this,LayoutMenu,StateChangeHandler));
198 mxListener = new ::sd::tools::SlotStateListener(
199 aStateChangeLink,
200 Reference<frame::XDispatchProvider>(mrBase.GetController()->getFrame(), UNO_QUERY),
201 u".uno:VerticalTextState"_ustr);
204 LayoutMenu::~LayoutMenu()
206 SAL_INFO("sd.ui", "destroying LayoutMenu at " << this);
207 Dispose();
208 mxLayoutValueSetWin.reset();
209 mxLayoutValueSet.reset();
212 void LayoutMenu::Dispose()
214 if (mbIsDisposed)
215 return;
217 SAL_INFO("sd.ui", "disposing LayoutMenu at " << this);
219 mbIsDisposed = true;
221 if (mxListener.is())
222 mxListener->dispose();
224 Clear();
225 Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this,LayoutMenu,EventMultiplexerListener));
226 mrBase.GetEventMultiplexer()->RemoveEventListener (aLink);
229 AutoLayout LayoutMenu::GetSelectedAutoLayout() const
231 AutoLayout aResult = AUTOLAYOUT_NONE;
233 if (!mxLayoutValueSet->IsNoSelection() && mxLayoutValueSet->GetSelectedItemId()!=0)
235 AutoLayout* pLayout = static_cast<AutoLayout*>(mxLayoutValueSet->GetItemData(mxLayoutValueSet->GetSelectedItemId()));
236 if (pLayout != nullptr)
237 aResult = *pLayout;
240 return aResult;
243 ui::LayoutSize LayoutMenu::GetHeightForWidth (const sal_Int32 nWidth)
245 sal_Int32 nPreferredHeight = 200;
246 if (mxLayoutValueSet->GetItemCount()>0)
248 Image aImage = mxLayoutValueSet->GetItemImage(mxLayoutValueSet->GetItemId(0));
249 Size aItemSize = mxLayoutValueSet->CalcItemSizePixel(aImage.GetSizePixel());
250 if (nWidth>0 && aItemSize.Width()>0)
252 aItemSize.AdjustWidth(8 );
253 aItemSize.AdjustHeight(8 );
254 int nColumnCount = nWidth / aItemSize.Width();
255 if (nColumnCount <= 0)
256 nColumnCount = 1;
257 else if (nColumnCount > 4)
258 nColumnCount = 4;
259 int nRowCount = (mxLayoutValueSet->GetItemCount() + nColumnCount-1) / nColumnCount;
260 nPreferredHeight = nRowCount * aItemSize.Height();
263 return ui::LayoutSize(nPreferredHeight,nPreferredHeight,nPreferredHeight);
266 void LayoutValueSet::Resize()
268 Size aWindowSize = GetOutputSizePixel();
269 if (IsVisible() && aWindowSize.Width() > 0)
271 // Calculate the number of rows and columns.
272 if (GetItemCount() > 0)
274 Image aImage = GetItemImage(GetItemId(0));
275 Size aItemSize = CalcItemSizePixel (
276 aImage.GetSizePixel());
277 aItemSize.AdjustWidth(8 );
278 aItemSize.AdjustHeight(8 );
279 int nColumnCount = aWindowSize.Width() / aItemSize.Width();
280 if (nColumnCount < 1)
281 nColumnCount = 1;
282 else if (nColumnCount > 4)
283 nColumnCount = 4;
285 int nRowCount = CalculateRowCount (aItemSize, nColumnCount);
287 SetColCount(nColumnCount);
288 SetLineCount(nRowCount);
292 ValueSet::Resize();
295 bool LayoutValueSet::Command(const CommandEvent& rEvent)
297 if (rEvent.GetCommand() != CommandEventId::ContextMenu)
298 return false;
300 // As a preparation for the context menu the item under the mouse is
301 // selected.
302 if (rEvent.IsMouseEvent())
304 sal_uInt16 nIndex = GetItemId(rEvent.GetMousePosPixel());
305 if (nIndex > 0)
306 SelectItem(nIndex);
309 mrMenu.ShowContextMenu(rEvent.IsMouseEvent() ? &rEvent.GetMousePosPixel() : nullptr);
310 return true;
313 void LayoutMenu::InsertPageWithLayout (AutoLayout aLayout)
315 ViewShell* pViewShell = mrBase.GetMainViewShell().get();
316 if (pViewShell == nullptr)
317 return;
319 SfxViewFrame& rViewFrame = mrBase.GetViewFrame();
320 SfxDispatcher* pDispatcher = rViewFrame.GetDispatcher();
321 if (pDispatcher == nullptr)
322 return;
324 // Call SID_INSERTPAGE with the right arguments. This is because
325 // the popup menu can not call this slot with arguments directly.
326 SfxRequest aRequest (CreateRequest(SID_INSERTPAGE, aLayout));
327 if (aRequest.GetArgs() != nullptr)
329 pDispatcher->Execute(
330 SID_INSERTPAGE,
331 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
332 *aRequest.GetArgs());
334 UpdateSelection();
337 void LayoutMenu::InvalidateContent()
339 // Throw away the current set and fill the menu anew according to the
340 // current settings (this includes the support for vertical writing.)
341 Fill();
343 if (mxSidebar.is())
344 mxSidebar->requestLayout();
346 // set selection inside the control during Impress start up
347 UpdateSelection();
350 int LayoutValueSet::CalculateRowCount (const Size&, int nColumnCount)
352 int nRowCount = 0;
354 if (GetItemCount() > 0 && nColumnCount > 0)
356 nRowCount = (GetItemCount() + nColumnCount - 1) / nColumnCount;
357 if (nRowCount < 1)
358 nRowCount = 1;
361 return nRowCount;
364 IMPL_LINK_NOARG(LayoutMenu, ClickHandler, ValueSet*, void)
366 AssignLayoutToSelectedSlides( GetSelectedAutoLayout() );
369 /** The specified layout is assigned to the current page of the view shell
370 in the center pane.
372 void LayoutMenu::AssignLayoutToSelectedSlides (AutoLayout aLayout)
374 using namespace ::sd::slidesorter;
375 using namespace ::sd::slidesorter::controller;
379 // The view shell in the center pane has to be present.
380 ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
381 if (pMainViewShell == nullptr)
382 break;
384 // Determine if the current view is in an invalid master page mode.
385 // The handout view is always in master page mode and therefore not
386 // invalid.
387 bool bMasterPageMode (false);
388 switch (pMainViewShell->GetShellType())
390 case ViewShell::ST_NOTES:
391 case ViewShell::ST_IMPRESS:
393 DrawViewShell* pDrawViewShell = static_cast<DrawViewShell*>(pMainViewShell);
394 if (pDrawViewShell->GetEditMode() == EditMode::MasterPage)
395 bMasterPageMode = true;
396 break;
398 default:
399 break;
401 if (bMasterPageMode)
402 break;
404 // Get a list of all selected slides and call the SID_MODIFYPAGE
405 // slot for all of them.
406 ::sd::slidesorter::SharedPageSelection pPageSelection;
408 // Get a list of selected pages.
409 // First we try to obtain this list from a slide sorter. This is
410 // possible only some of the view shells in the center pane. When
411 // no valid slide sorter is available then ask the main view shell
412 // for its current page.
413 SlideSorterViewShell* pSlideSorter = nullptr;
414 switch (pMainViewShell->GetShellType())
416 case ViewShell::ST_IMPRESS:
417 case ViewShell::ST_NOTES:
418 case ViewShell::ST_SLIDE_SORTER:
419 pSlideSorter = SlideSorterViewShell::GetSlideSorter(mrBase);
420 break;
421 default:
422 break;
424 if (pSlideSorter != nullptr)
426 // There is a slide sorter visible so get the list of selected pages from it.
427 pPageSelection = pSlideSorter->GetPageSelection();
430 if( (pSlideSorter == nullptr) || !pPageSelection || pPageSelection->empty() )
432 // No valid slide sorter available. Ask the main view shell for
433 // its current page.
434 pPageSelection = std::make_shared<::sd::slidesorter::SlideSorterViewShell::PageSelection>();
435 pPageSelection->push_back(pMainViewShell->GetActualPage());
438 if (pPageSelection->empty())
439 break;
441 for (const auto& rpPage : *pPageSelection)
443 if (rpPage == nullptr)
444 continue;
446 // Call the SID_ASSIGN_LAYOUT slot with all the necessary parameters.
447 SfxRequest aRequest(mrBase.GetViewFrame(), SID_ASSIGN_LAYOUT);
448 aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATPAGE, (rpPage->GetPageNum()-1)/2));
449 aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATLAYOUT, aLayout));
450 pMainViewShell->ExecuteSlot (aRequest, false);
453 while(false);
456 SfxRequest LayoutMenu::CreateRequest (
457 sal_uInt16 nSlotId,
458 AutoLayout aLayout)
460 SfxRequest aRequest(mrBase.GetViewFrame(), nSlotId);
464 SdrLayerAdmin& rLayerAdmin (mrBase.GetDocument()->GetLayerAdmin());
465 SdrLayerID aBackground (rLayerAdmin.GetLayerID(sUNO_LayerName_background));
466 SdrLayerID aBackgroundObject (rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects));
467 ViewShell* pViewShell = mrBase.GetMainViewShell().get();
468 if (pViewShell == nullptr)
469 break;
470 SdPage* pPage = pViewShell->GetActualPage();
471 if (pPage == nullptr)
472 break;
474 SdrLayerIDSet aVisibleLayers (pPage->TRG_GetMasterPageVisibleLayers());
476 aRequest.AppendItem(
477 SfxStringItem (ID_VAL_PAGENAME, OUString()));//pPage->GetName()));
478 aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATLAYOUT, aLayout));
479 aRequest.AppendItem(
480 SfxBoolItem(ID_VAL_ISPAGEBACK, aVisibleLayers.IsSet(aBackground)));
481 aRequest.AppendItem(
482 SfxBoolItem(
483 ID_VAL_ISPAGEOBJ,
484 aVisibleLayers.IsSet(aBackgroundObject)));
486 while (false);
488 return aRequest;
491 void LayoutMenu::Fill()
493 bool bVertical = SvtCJKOptions::IsVerticalTextEnabled();
494 SdDrawDocument* pDocument = mrBase.GetDocument();
495 bool bRightToLeft = (pDocument!=nullptr
496 && pDocument->GetDefaultWritingMode() == WritingMode_RL_TB);
498 // Get URL of the view in the center pane.
499 OUString sCenterPaneViewName;
502 if (mrBase.GetDrawController())
504 Reference<XResourceId> xPaneId (ResourceId::create(
505 ::comphelper::getProcessComponentContext(),
506 FrameworkHelper::msCenterPaneURL));
507 Reference<XView> xView (FrameworkHelper::Instance(mrBase)->GetView(xPaneId));
508 if (xView.is())
509 sCenterPaneViewName = xView->getResourceId()->getResourceURL();
512 catch (RuntimeException&)
515 std::span<const snew_slide_value_info> pInfo;
516 if (sCenterPaneViewName == framework::FrameworkHelper::msNotesViewURL)
518 pInfo = notes;
520 else if (sCenterPaneViewName == framework::FrameworkHelper::msHandoutViewURL)
522 pInfo = handout;
524 else if (sCenterPaneViewName == framework::FrameworkHelper::msImpressViewURL
525 || sCenterPaneViewName == framework::FrameworkHelper::msSlideSorterURL)
527 pInfo = standard;
530 Clear();
531 sal_uInt16 id = 1;
532 for (const auto& elem : pInfo)
534 if ((WritingMode_TB_RL != elem.meWritingMode) || bVertical)
536 Image aImg(OUString::Concat("private:graphicrepository/") + elem.msBmpResId);
538 if (bRightToLeft && (WritingMode_TB_RL != elem.meWritingMode))
539 { // FIXME: avoid interpolating RTL layouts.
540 BitmapEx aRTL = aImg.GetBitmapEx();
541 aRTL.Mirror(BmpMirrorFlags::Horizontal);
542 aImg = Image(aRTL);
545 mxLayoutValueSet->InsertItem(id, aImg, SdResId(elem.mpStrResId));
546 mxLayoutValueSet->SetItemData(id, new AutoLayout(elem.maAutoLayout));
547 ++id;
552 void LayoutMenu::Clear()
554 for (size_t nId=1; nId<=mxLayoutValueSet->GetItemCount(); nId++)
555 delete static_cast<AutoLayout*>(mxLayoutValueSet->GetItemData(nId));
556 mxLayoutValueSet->Clear();
559 void LayoutMenu::ShowContextMenu(const Point* pPos)
561 if (SdModule::get()->GetWaterCan())
562 return;
564 // Determine the position where to show the menu.
565 Point aMenuPosition;
566 if (pPos)
568 auto nItemId = mxLayoutValueSet->GetItemId(*pPos);
569 if (nItemId <= 0)
570 return;
571 mxLayoutValueSet->SelectItem(nItemId);
572 aMenuPosition = *pPos;
574 else
576 if (mxLayoutValueSet->GetSelectedItemId() == sal_uInt16(-1))
577 return;
578 ::tools::Rectangle aBBox(mxLayoutValueSet->GetItemRect(mxLayoutValueSet->GetSelectedItemId()));
579 aMenuPosition = aBBox.Center();
582 // Setup the menu.
583 ::tools::Rectangle aRect(aMenuPosition, Size(1, 1));
584 weld::Widget* pPopupParent = mxLayoutValueSet->GetDrawingArea();
585 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, u"modules/simpress/ui/layoutmenu.ui"_ustr));
586 std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu(u"menu"_ustr));
588 // Disable the SID_INSERTPAGE_LAYOUT_MENU item when
589 // the document is read-only.
590 SfxPoolItemHolder aResult;
591 const SfxItemState aState (
592 mrBase.GetViewFrame().GetDispatcher()->QueryState(SID_INSERTPAGE, aResult));
593 if (aState == SfxItemState::DISABLED)
594 xMenu->set_sensitive(u"insert"_ustr, false);
596 // Show the menu.
597 OnMenuItemSelected(xMenu->popup_at_rect(pPopupParent, aRect));
600 IMPL_LINK_NOARG(LayoutMenu, StateChangeHandler, const OUString&, void)
602 InvalidateContent();
605 void LayoutMenu::OnMenuItemSelected(std::u16string_view ident)
607 if (ident.empty())
608 return;
610 if (ident == u"apply")
612 AssignLayoutToSelectedSlides(GetSelectedAutoLayout());
614 else if (ident == u"insert")
616 // Add arguments to this slot and forward it to the main view
617 // shell.
618 InsertPageWithLayout(GetSelectedAutoLayout());
622 // Selects an appropriate layout of the slide inside control.
624 // Method may be called several times with the same item-id to be selected -
625 // only once the actually state of the control will be changed.
627 void LayoutMenu::UpdateSelection()
629 bool bItemSelected = false;
633 // Get current page of main view.
634 ViewShell* pViewShell = mrBase.GetMainViewShell().get();
635 if (pViewShell == nullptr)
636 break;
638 SdPage* pCurrentPage = pViewShell->getCurrentPage();
639 if (pCurrentPage == nullptr)
640 break;
642 // Get layout of current page.
643 AutoLayout aLayout (pCurrentPage->GetAutoLayout());
644 if (aLayout<AUTOLAYOUT_START || aLayout>AUTOLAYOUT_END)
645 break;
647 // Find the entry of the menu for to the layout.
648 const sal_uInt16 nItemCount = mxLayoutValueSet->GetItemCount();
649 for (sal_uInt16 nId=1; nId<=nItemCount; nId++)
651 if (*static_cast<AutoLayout*>(mxLayoutValueSet->GetItemData(nId)) == aLayout)
653 // do not set selection twice to the same item
654 if (mxLayoutValueSet->GetSelectedItemId() != nId)
656 mxLayoutValueSet->SetNoSelection();
657 mxLayoutValueSet->SelectItem(nId);
660 bItemSelected = true; // no need to call SetNoSelection()
661 break;
665 while (false);
667 if (!bItemSelected)
668 mxLayoutValueSet->SetNoSelection();
671 IMPL_LINK(LayoutMenu, EventMultiplexerListener, ::sd::tools::EventMultiplexerEvent&, rEvent, void)
673 switch (rEvent.meEventId)
675 // tdf#89890 During changes of the Layout of the slide when focus is not set inside main area
676 // we do not receive notification EventMultiplexerEventId::CurrentPageChanged, but we receive the following 3 notification types.
677 // => let's make UpdateSelection() also when some shape is changed (during Layout changes)
678 case EventMultiplexerEventId::ShapeChanged:
679 case EventMultiplexerEventId::ShapeInserted:
680 case EventMultiplexerEventId::ShapeRemoved:
681 case EventMultiplexerEventId::CurrentPageChanged:
682 case EventMultiplexerEventId::SlideSortedSelection:
683 UpdateSelection();
684 break;
686 case EventMultiplexerEventId::MainViewAdded:
687 mbIsMainViewChangePending = true;
688 break;
690 case EventMultiplexerEventId::MainViewRemoved:
691 mxLayoutValueSet->Invalidate(); // redraw without focus
692 break;
694 case EventMultiplexerEventId::ConfigurationUpdated:
695 if (mbIsMainViewChangePending)
697 mbIsMainViewChangePending = false;
698 InvalidateContent();
700 break;
702 default:
703 break;
707 void LayoutMenu::DataChanged(const DataChangedEvent& rEvent)
709 PanelLayout::DataChanged(rEvent);
710 Fill();
711 mxLayoutValueSet->StyleUpdated();
712 mxLayoutValueSet->SetColor(sfx2::sidebar::Theme::GetColor(sfx2::sidebar::Theme::Color_PanelBackground));
715 } // end of namespace ::sd::sidebar
717 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */