/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "LayoutMenu.hxx"
#include <app.hrc>
#include <drawdoc.hxx>
#include <framework/FrameworkHelper.hxx>
#include <strings.hrc>
#include <helpids.h>
#include <pres.hxx>
#include <sdmod.hxx>
#include <ResourceId.hxx>
#include <sdpage.hxx>
#include <sdresid.hxx>
#include <unokywds.hxx>
#include <bitmaps.hlst>
#include <tools/gen.hxx>
#include <tools/SlotStateListener.hxx>
#include <DrawController.hxx>
#include <DrawDocShell.hxx>
#include <DrawViewShell.hxx>
#include <EventMultiplexer.hxx>
#include <SlideSorterViewShell.hxx>
#include <ViewShellBase.hxx>
#include <sfx2/sidebar/Theme.hxx>
#include <sal/log.hxx>
#include <comphelper/processfactory.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/request.hxx>
#include <sfx2/viewfrm.hxx>
#include <svl/cjkoptions.hxx>
#include <svl/stritem.hxx>
#include <svl/intitem.hxx>
#include <utility>
#include <vcl/commandevent.hxx>
#include <vcl/image.hxx>
#include <xmloff/autolayout.hxx>
#include <comphelper/lok.hxx>
#include <framework/AbstractView.hxx>
#include <string_view>
#include <vector>
using namespace ::com::sun::star;
using namespace ::com::sun::star::text;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::drawing::framework;
using namespace ::sd::slidesorter;
using ::sd::framework::FrameworkHelper;
namespace sd::sidebar {
namespace {
struct snew_slide_value_info
{
OUString msBmpResId;
TranslateId mpStrResId;
WritingMode meWritingMode;
AutoLayout maAutoLayout;
};
}
constexpr snew_slide_value_info notes[] =
{
{BMP_SLIDEN_01, STR_AUTOLAYOUT_NOTES, WritingMode_LR_TB,
AUTOLAYOUT_NOTES},
};
constexpr snew_slide_value_info handout[] =
{
{BMP_SLIDEH_01, STR_AUTOLAYOUT_HANDOUT1, WritingMode_LR_TB,
AUTOLAYOUT_HANDOUT1},
{BMP_SLIDEH_02, STR_AUTOLAYOUT_HANDOUT2, WritingMode_LR_TB,
AUTOLAYOUT_HANDOUT2},
{BMP_SLIDEH_03, STR_AUTOLAYOUT_HANDOUT3, WritingMode_LR_TB,
AUTOLAYOUT_HANDOUT3},
{BMP_SLIDEH_04, STR_AUTOLAYOUT_HANDOUT4, WritingMode_LR_TB,
AUTOLAYOUT_HANDOUT4},
{BMP_SLIDEH_06, STR_AUTOLAYOUT_HANDOUT6, WritingMode_LR_TB,
AUTOLAYOUT_HANDOUT6},
{BMP_SLIDEH_09, STR_AUTOLAYOUT_HANDOUT9, WritingMode_LR_TB,
AUTOLAYOUT_HANDOUT9},
};
constexpr snew_slide_value_info standard[] =
{
{BMP_LAYOUT_EMPTY, STR_AUTOLAYOUT_NONE, WritingMode_LR_TB, AUTOLAYOUT_NONE},
{BMP_LAYOUT_HEAD03, STR_AUTOLAYOUT_TITLE, WritingMode_LR_TB, AUTOLAYOUT_TITLE},
{BMP_LAYOUT_HEAD02, STR_AUTOLAYOUT_CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_CONTENT},
{BMP_LAYOUT_HEAD02A, STR_AUTOLAYOUT_2CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_2CONTENT},
{BMP_LAYOUT_HEAD01, STR_AUTOLAYOUT_ONLY_TITLE, WritingMode_LR_TB, AUTOLAYOUT_TITLE_ONLY},
{BMP_LAYOUT_TEXTONLY, STR_AUTOLAYOUT_ONLY_TEXT, WritingMode_LR_TB, AUTOLAYOUT_ONLY_TEXT},
{BMP_LAYOUT_HEAD03B, STR_AUTOLAYOUT_2CONTENT_CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_2CONTENT_CONTENT},
{BMP_LAYOUT_HEAD03C, STR_AUTOLAYOUT_CONTENT_2CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_CONTENT_2CONTENT},
{BMP_LAYOUT_HEAD03A, STR_AUTOLAYOUT_2CONTENT_OVER_CONTENT,WritingMode_LR_TB, AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT},
{BMP_LAYOUT_HEAD02B, STR_AUTOLAYOUT_CONTENT_OVER_CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT},
{BMP_LAYOUT_HEAD04, STR_AUTOLAYOUT_4CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_4CONTENT},
{BMP_LAYOUT_HEAD06, STR_AUTOLAYOUT_6CONTENT, WritingMode_LR_TB, AUTOLAYOUT_TITLE_6CONTENT},
// vertical
{BMP_LAYOUT_VERTICAL02, STR_AL_VERT_TITLE_TEXT_CHART, WritingMode_TB_RL, AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT},
{BMP_LAYOUT_VERTICAL01, STR_AL_VERT_TITLE_VERT_OUTLINE, WritingMode_TB_RL, AUTOLAYOUT_VTITLE_VCONTENT},
{BMP_LAYOUT_HEAD02, STR_AL_TITLE_VERT_OUTLINE, WritingMode_TB_RL, AUTOLAYOUT_TITLE_VCONTENT},
{BMP_LAYOUT_HEAD02A, STR_AL_TITLE_VERT_OUTLINE_CLIPART, WritingMode_TB_RL, AUTOLAYOUT_TITLE_2VTEXT},
};
LayoutMenu::LayoutMenu (
weld::Widget* pParent,
ViewShellBase& rViewShellBase,
css::uno::Reference<css::ui::XSidebar> xSidebar)
: PanelLayout( pParent, u"LayoutPanel"_ustr, u"modules/simpress/ui/layoutpanel.ui"_ustr ),
mrBase(rViewShellBase),
mxLayoutIconView(m_xBuilder->weld_icon_view(u"layoutpanel_icons"_ustr)),
mbIsMainViewChangePending(false),
mxSidebar(std::move(xSidebar)),
mbIsDisposed(false),
maPreviewSize(0, 0),
bInContextMenuOperation(false)
{
implConstruct( *mrBase.GetDocument()->GetDocSh() );
SAL_INFO("sd.ui", "created LayoutMenu at " << this);
}
void LayoutMenu::implConstruct( DrawDocShell& rDocumentShell )
{
OSL_ENSURE( mrBase.GetDocument()->GetDocSh() == &rDocumentShell,
"LayoutMenu::implConstruct: hmm?" );
// if this fires, then my assumption that the rDocumentShell parameter to our first ctor is superfluous ...
(void) rDocumentShell;
mxLayoutIconView->connect_item_activated(LINK(this, LayoutMenu, LayoutSelected));
mxLayoutIconView->connect_command(LINK(this, LayoutMenu, CommandHdl));
InvalidateContent();
Link<::sdtools::EventMultiplexerEvent&,void> aEventListenerLink (LINK(this,LayoutMenu,EventMultiplexerListener));
mrBase.GetEventMultiplexer()->AddEventListener(aEventListenerLink);
mxLayoutIconView->set_accessible_name(SdResId(STR_TASKPANEL_LAYOUT_MENU_TITLE));
Link<const OUString&,void> aStateChangeLink (LINK(this,LayoutMenu,StateChangeHandler));
mxListener = new ::sdtools::SlotStateListener(
aStateChangeLink,
Reference<frame::XDispatchProvider>(mrBase.GetController()->getFrame(), UNO_QUERY),
u".uno:VerticalTextState"_ustr);
}
LayoutMenu::~LayoutMenu()
{
SAL_INFO("sd.ui", "destroying LayoutMenu at " << this);
Dispose();
mxLayoutIconView.reset();
}
void LayoutMenu::Dispose()
{
if (mbIsDisposed)
return;
SAL_INFO("sd.ui", "disposing LayoutMenu at " << this);
mbIsDisposed = true;
if (mxListener.is())
mxListener->dispose();
Clear();
Link<sdtools::EventMultiplexerEvent&,void> aLink (LINK(this,LayoutMenu,EventMultiplexerListener));
mrBase.GetEventMultiplexer()->RemoveEventListener (aLink);
}
AutoLayout LayoutMenu::GetSelectedAutoLayout() const
{
OUString sId = mxLayoutIconView->get_selected_id();
if (!sId.isEmpty())
return static_cast<AutoLayout>(sId.toInt32());
return AUTOLAYOUT_NONE; // default layout
}
ui::LayoutSize LayoutMenu::GetHeightForWidth (const sal_Int32 nWidth)
{
// there is no way to get margin of item programmatically, we use value provided in ui file.
const int nMargin = 6;
Size aPreviewSize = maPreviewSize;
if (aPreviewSize.Width() == 0 && mxLayoutIconView->n_children() > 0)
{
aPreviewSize.setWidth(mxLayoutIconView->get_item_width());
aPreviewSize.setHeight(mxLayoutIconView->get_preferred_size().getHeight());
}
sal_Int32 nColumnCount = nWidth / (aPreviewSize.Width() + (2 * nMargin));
if (nColumnCount < 1)
nColumnCount = 1;
sal_Int32 nTotalItems = mxLayoutIconView->n_children();
sal_Int32 nRowCount = (nTotalItems + nColumnCount - 1) / nColumnCount;
if (nRowCount < 1)
nRowCount = 1;
sal_Int32 nPreferredHeight = nRowCount * (aPreviewSize.Height() + (2 * nMargin));
return css::ui::LayoutSize(nPreferredHeight, nPreferredHeight, nPreferredHeight);
}
IMPL_LINK(LayoutMenu, CommandHdl, const CommandEvent&, rEvent, bool)
{
if (rEvent.GetCommand() != CommandEventId::ContextMenu)
return false;
Point aPos;
if (rEvent.IsMouseEvent())
{
aPos = rEvent.GetMousePosPixel();
std::unique_ptr<weld::TreeIter> pIter = mxLayoutIconView->get_item_at_pos(aPos);
if (!pIter)
return false;
mxLayoutIconView->select(*pIter);
}
else
{
std::unique_ptr<weld::TreeIter> pSelected = mxLayoutIconView->get_selected();
if (!pSelected)
return false;
aPos = mxLayoutIconView->get_rect(*pSelected).Center();
}
bInContextMenuOperation = true;
ShowContextMenu(aPos);
bInContextMenuOperation = false;
return true;
}
void LayoutMenu::InsertPageWithLayout (AutoLayout aLayout)
{
ViewShell* pViewShell = mrBase.GetMainViewShell().get();
if (pViewShell == nullptr)
return;
SfxViewFrame& rViewFrame = mrBase.GetViewFrame();
SfxDispatcher* pDispatcher = rViewFrame.GetDispatcher();
if (pDispatcher == nullptr)
return;
// Call SID_INSERTPAGE with the right arguments. This is because
// the popup menu can not call this slot with arguments directly.
SfxRequest aRequest (CreateRequest(SID_INSERTPAGE, aLayout));
if (aRequest.GetArgs() != nullptr)
{
pDispatcher->Execute(
SID_INSERTPAGE,
SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
*aRequest.GetArgs());
}
UpdateSelection();
}
void LayoutMenu::InvalidateContent()
{
// Throw away the current set and fill the menu anew according to the
// current settings (this includes the support for vertical writing.)
Fill();
if (mxSidebar.is())
mxSidebar->requestLayout();
// set selection inside the control during Impress start up
UpdateSelection();
}
IMPL_LINK_NOARG(LayoutMenu, LayoutSelected, weld::IconView&, bool)
{
AssignLayoutToSelectedSlides( GetSelectedAutoLayout() );
return true;
}
/** The specified layout is assigned to the current page of the view shell
in the center pane.
*/
void LayoutMenu::AssignLayoutToSelectedSlides (AutoLayout aLayout)
{
using namespace ::sd::slidesorter;
using namespace ::sd::slidesorter::controller;
do
{
// The view shell in the center pane has to be present.
ViewShell* pMainViewShell = mrBase.GetMainViewShell().get();
if (pMainViewShell == nullptr)
break;
// Determine if the current view is in an invalid master page mode.
// The handout view is always in master page mode and therefore not
// invalid.
bool bMasterPageMode (false);
switch (pMainViewShell->GetShellType())
{
case ViewShell::ST_NOTES:
case ViewShell::ST_IMPRESS:
{
DrawViewShell* pDrawViewShell = static_cast<DrawViewShell*>(pMainViewShell);
if (pDrawViewShell->GetEditMode() == EditMode::MasterPage)
bMasterPageMode = true;
break;
}
default:
break;
}
if (bMasterPageMode)
break;
// Get a list of all selected slides and call the SID_MODIFYPAGE
// slot for all of them.
::sd::slidesorter::SharedPageSelection pPageSelection;
// Get a list of selected pages.
// First we try to obtain this list from a slide sorter. This is
// possible only some of the view shells in the center pane. When
// no valid slide sorter is available then ask the main view shell
// for its current page.
SlideSorterViewShell* pSlideSorter = nullptr;
switch (pMainViewShell->GetShellType())
{
case ViewShell::ST_IMPRESS:
case ViewShell::ST_NOTES:
case ViewShell::ST_SLIDE_SORTER:
pSlideSorter = SlideSorterViewShell::GetSlideSorter(mrBase);
break;
default:
break;
}
if (pSlideSorter != nullptr)
{
// There is a slide sorter visible so get the list of selected pages from it.
pPageSelection = pSlideSorter->GetPageSelection();
}
if( (pSlideSorter == nullptr) || !pPageSelection || pPageSelection->empty() )
{
// No valid slide sorter available. Ask the main view shell for
// its current page.
pPageSelection = std::make_shared<::sd::slidesorter::SlideSorterViewShell::PageSelection>();
pPageSelection->push_back(pMainViewShell->GetActualPage());
}
if (pPageSelection->empty())
break;
for (const auto& rpPage : *pPageSelection)
{
if (rpPage == nullptr)
continue;
// Call the SID_ASSIGN_LAYOUT slot with all the necessary parameters.
SfxRequest aRequest(mrBase.GetViewFrame(), SID_ASSIGN_LAYOUT);
aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATPAGE, (rpPage->GetPageNum()-1)/2));
aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATLAYOUT, aLayout));
pMainViewShell->ExecuteSlot (aRequest, false);
}
}
while(false);
}
SfxRequest LayoutMenu::CreateRequest (
sal_uInt16 nSlotId,
AutoLayout aLayout)
{
SfxRequest aRequest(mrBase.GetViewFrame(), nSlotId);
do
{
SdrLayerAdmin& rLayerAdmin (mrBase.GetDocument()->GetLayerAdmin());
SdrLayerID aBackground (rLayerAdmin.GetLayerID(sUNO_LayerName_background));
SdrLayerID aBackgroundObject (rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects));
ViewShell* pViewShell = mrBase.GetMainViewShell().get();
if (pViewShell == nullptr)
break;
SdPage* pPage = pViewShell->GetActualPage();
if (pPage == nullptr)
break;
SdrLayerIDSet aVisibleLayers (pPage->TRG_GetMasterPageVisibleLayers());
aRequest.AppendItem(
SfxStringItem (ID_VAL_PAGENAME, OUString()));//pPage->GetName()));
aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATLAYOUT, aLayout));
aRequest.AppendItem(
SfxBoolItem(ID_VAL_ISPAGEBACK, aVisibleLayers.IsSet(aBackground)));
aRequest.AppendItem(
SfxBoolItem(
ID_VAL_ISPAGEOBJ,
aVisibleLayers.IsSet(aBackgroundObject)));
}
while (false);
return aRequest;
}
VclPtr<VirtualDevice> LayoutMenu::GetVirtualDevice(Image pImage)
{
Bitmap aPreviewBitmap = pImage.GetBitmap();
VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create();
const Point aNull(0, 0);
if (pVDev->GetDPIScaleFactor() > 1)
aPreviewBitmap.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor());
const Size aSize(aPreviewBitmap.GetSizePixel());
pVDev->SetOutputSizePixel(aSize);
pVDev->DrawBitmap(aNull, aPreviewBitmap);
return pVDev;
}
Bitmap LayoutMenu::GetPreviewAsBitmap(const Image& rImage)
{
Bitmap aPreviewBitmap(rImage.GetBitmap());
ScopedVclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create();
if (pVDev->GetDPIScaleFactor() > 1)
aPreviewBitmap.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor());
return aPreviewBitmap;
}
void LayoutMenu::Fill()
{
bool bVertical = SvtCJKOptions::IsVerticalTextEnabled();
SdDrawDocument* pDocument = mrBase.GetDocument();
bool bRightToLeft = (pDocument!=nullptr
&& pDocument->GetDefaultWritingMode() == WritingMode_RL_TB);
// Get URL of the view in the center pane.
OUString sCenterPaneViewName;
try
{
if (mrBase.GetDrawController())
{
rtl::Reference<sd::framework::ResourceId> xPaneId (new sd::framework::ResourceId(
FrameworkHelper::msCenterPaneURL));
rtl::Reference<framework::AbstractView> xView (FrameworkHelper::Instance(mrBase)->GetView(xPaneId));
if (xView.is())
sCenterPaneViewName = xView->getResourceId()->getResourceURL();
}
}
catch (RuntimeException&)
{}
std::span<const snew_slide_value_info> pInfo;
if (sCenterPaneViewName == framework::FrameworkHelper::msNotesViewURL)
{
pInfo = notes;
}
else if (sCenterPaneViewName == framework::FrameworkHelper::msHandoutViewURL)
{
pInfo = handout;
}
else if (sCenterPaneViewName == framework::FrameworkHelper::msImpressViewURL
|| sCenterPaneViewName == framework::FrameworkHelper::msSlideSorterURL)
{
pInfo = standard;
}
Clear();
sal_uInt16 id = 0;
mxLayoutIconView->freeze();
for (const auto& elem : pInfo)
{
if ((WritingMode_TB_RL != elem.meWritingMode) || bVertical)
{
Image aImg(StockImage::Yes, elem.msBmpResId);
if (bRightToLeft && (WritingMode_TB_RL != elem.meWritingMode))
{ // FIXME: avoid interpolating RTL layouts.
Bitmap aRTL = aImg.GetBitmap();
aRTL.Mirror(BmpMirrorFlags::Horizontal);
aImg = Image(aRTL);
}
if (aImg.GetSizePixel().Width() > 0)
{
OUString sId = OUString::number(static_cast<int>(elem.maAutoLayout));
OUString sLayoutName = SdResId(elem.mpStrResId);
if (!mxLayoutIconView->get_id(id).isEmpty())
{
VclPtr<VirtualDevice> pVDev = GetVirtualDevice(aImg);
mxLayoutIconView->set_image(id, *pVDev);
mxLayoutIconView->set_id(id, sId);
mxLayoutIconView->set_text(id, sLayoutName);
pVDev.disposeAndClear();
}
else
{
Bitmap aPreviewBitmap = GetPreviewAsBitmap(aImg);
mxLayoutIconView->insert(id, &sLayoutName, &sId, &aPreviewBitmap, nullptr);
mxLayoutIconView->set_item_accessible_name(id, sLayoutName);
mxLayoutIconView->set_item_tooltip_text(id, sLayoutName);
}
if (maPreviewSize.Width() == 0)
maPreviewSize = aImg.GetSizePixel();
}
++id;
}
}
mxLayoutIconView->thaw();
}
void LayoutMenu::Clear()
{
mxLayoutIconView->clear();
}
void LayoutMenu::ShowContextMenu(const Point& pPos)
{
if (SdModule::get()->GetWaterCan())
return;
// Setup the menu.
::tools::Rectangle aRect(pPos, Size(1, 1));
std::unique_ptr<weld::Builder> xMenuBuilder = Application::CreateBuilder(
mxLayoutIconView.get(), u"modules/simpress/ui/layoutmenu.ui"_ustr);
std::unique_ptr<weld::Menu> xMenu = xMenuBuilder->weld_menu(u"menu"_ustr);
// Disable the SID_INSERTPAGE_LAYOUT_MENU item when
// the document is read-only.
SfxPoolItemHolder aResult;
const SfxItemState aState (
mrBase.GetViewFrame().GetDispatcher()->QueryState(SID_INSERTPAGE, aResult));
if (aState == SfxItemState::DISABLED)
xMenu->set_sensitive(u"insert"_ustr, false);
MenuSelect(xMenu->popup_at_rect(mxLayoutIconView.get(), aRect));
}
void LayoutMenu::MenuSelect(const OUString& rIdent)
{
sLastItemIdent = rIdent;
if (sLastItemIdent.isEmpty())
return;
if (comphelper::LibreOfficeKit::isActive())
HandleMenuSelect(sLastItemIdent);
else
Application::PostUserEvent(LINK(this, LayoutMenu, MenuSelectAsyncHdl));
}
IMPL_LINK_NOARG(LayoutMenu, StateChangeHandler, const OUString&, void)
{
if (bInContextMenuOperation)
return;
InvalidateContent();
}
IMPL_LINK_NOARG(LayoutMenu, MenuSelectAsyncHdl, void*, void)
{
HandleMenuSelect(sLastItemIdent);
}
void LayoutMenu::HandleMenuSelect(std::u16string_view rIdent)
{
if (rIdent == u"apply")
{
AssignLayoutToSelectedSlides(GetSelectedAutoLayout());
}
else if (rIdent == u"insert")
{
// Add arguments to this slot and forward it to the main view
// shell.
InsertPageWithLayout(GetSelectedAutoLayout());
}
}
// Selects an appropriate layout of the slide inside control.
//
// Method may be called several times with the same item-id to be selected -
// only once the actually state of the control will be changed.
//
void LayoutMenu::UpdateSelection()
{
bool bItemSelected = false;
do
{
// Get current page of main view.
ViewShell* pViewShell = mrBase.GetMainViewShell().get();
if (pViewShell == nullptr)
break;
SdPage* pCurrentPage = pViewShell->getCurrentPage();
if (pCurrentPage == nullptr)
break;
// Get layout of current page.
AutoLayout aLayout (pCurrentPage->GetAutoLayout());
if (aLayout<AUTOLAYOUT_START || aLayout>AUTOLAYOUT_END)
break;
// Find the entry of the menu for to the layout.
const sal_uInt16 nItemCount = mxLayoutIconView->n_children();
for (sal_uInt16 nId=0; nId<nItemCount; nId++)
{
OUString sItemId = mxLayoutIconView->get_id(nId);
if (!sItemId.isEmpty() && static_cast<AutoLayout>(sItemId.toInt32()) == aLayout)
{
OUString sCurrentSelectedId = mxLayoutIconView->get_selected_id();
if (sCurrentSelectedId != sItemId)
{
mxLayoutIconView->unselect_all();
mxLayoutIconView->select(nId);
}
bItemSelected = true; // no need to call unselect_all()
break;
}
}
}
while (false);
if (!bItemSelected)
mxLayoutIconView->unselect_all();
}
IMPL_LINK(LayoutMenu, EventMultiplexerListener, ::sdtools::EventMultiplexerEvent&, rEvent, void)
{
switch (rEvent.meEventId)
{
// tdf#89890 During changes of the Layout of the slide when focus is not set inside main area
// we do not receive notification EventMultiplexerEventId::CurrentPageChanged, but we receive the following 3 notification types.
// => let's make UpdateSelection() also when some shape is changed (during Layout changes)
case EventMultiplexerEventId::ShapeChanged:
case EventMultiplexerEventId::ShapeInserted:
case EventMultiplexerEventId::ShapeRemoved:
case EventMultiplexerEventId::CurrentPageChanged:
case EventMultiplexerEventId::SlideSortedSelection:
case EventMultiplexerEventId::MainViewRemoved:
UpdateSelection();
break;
case EventMultiplexerEventId::MainViewAdded:
mbIsMainViewChangePending = true;
break;
case EventMultiplexerEventId::ConfigurationUpdated:
if (mbIsMainViewChangePending)
{
mbIsMainViewChangePending = false;
InvalidateContent();
}
break;
default:
break;
}
}
void LayoutMenu::DataChanged(const DataChangedEvent& rEvent)
{
PanelLayout::DataChanged(rEvent);
Fill();
}
} // end of namespace ::sd::sidebar
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'Execute' is required to be utilized.
↑ V1016 Expression 'aLayout < AUTOLAYOUT_START' is always false.