/* -*- 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 <glob.hxx>
#include <helpids.h>
#include <pres.hxx>
 
#include <sdpage.hxx>
#include <sdresid.hxx>
#include <bitmaps.hlst>
#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/app.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/objface.hxx>
#include <sfx2/request.hxx>
#include <sfx2/viewfrm.hxx>
#include <svl/languageoptions.hxx>
#include <vcl/image.hxx>
#include <vcl/floatwin.hxx>
#include <xmloff/autolayout.hxx>
 
#include <com/sun/star/drawing/framework/XControllerManager.hpp>
#include <com/sun/star/drawing/framework/XView.hpp>
#include <com/sun/star/drawing/framework/ResourceId.hpp>
 
#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 { namespace sidebar {
 
struct snewfoil_value_info
{
    const char* msBmpResId;
    const char* mpStrResId;
    WritingMode meWritingMode;
    AutoLayout maAutoLayout;
};
 
static const snewfoil_value_info notes[] =
{
    {BMP_FOILN_01, STR_AUTOLAYOUT_NOTES, WritingMode_LR_TB,
     AUTOLAYOUT_NOTES},
    {"", nullptr, WritingMode_LR_TB, AUTOLAYOUT_NONE},
};
 
static const snewfoil_value_info handout[] =
{
    {BMP_FOILH_01, STR_AUTOLAYOUT_HANDOUT1, WritingMode_LR_TB,
     AUTOLAYOUT_HANDOUT1},
    {BMP_FOILH_02, STR_AUTOLAYOUT_HANDOUT2, WritingMode_LR_TB,
     AUTOLAYOUT_HANDOUT2},
    {BMP_FOILH_03, STR_AUTOLAYOUT_HANDOUT3, WritingMode_LR_TB,
     AUTOLAYOUT_HANDOUT3},
    {BMP_FOILH_04, STR_AUTOLAYOUT_HANDOUT4, WritingMode_LR_TB,
     AUTOLAYOUT_HANDOUT4},
    {BMP_FOILH_06, STR_AUTOLAYOUT_HANDOUT6, WritingMode_LR_TB,
     AUTOLAYOUT_HANDOUT6},
    {BMP_FOILH_09, STR_AUTOLAYOUT_HANDOUT9, WritingMode_LR_TB,
     AUTOLAYOUT_HANDOUT9},
    {"", nullptr, WritingMode_LR_TB, AUTOLAYOUT_NONE},
};
 
static const snewfoil_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},
    {"", nullptr, WritingMode_LR_TB, AUTOLAYOUT_NONE}
};
 
LayoutMenu::LayoutMenu (
    vcl::Window* pParent,
    ViewShellBase& rViewShellBase,
    const css::uno::Reference<css::ui::XSidebar>& rxSidebar)
    : ValueSet (pParent, WB_ITEMBORDER),
      DragSourceHelper(this),
      DropTargetHelper(this),
      mrBase(rViewShellBase),
      mbIsMainViewChangePending(false),
      mxSidebar(rxSidebar),
      mbIsDisposed(false)
{
    implConstruct( *mrBase.GetDocument()->GetDocSh() );
    SAL_INFO("sd.ui", "created LayoutMenu at " << this);
 
    SetStyle(GetStyle() | WB_ITEMBORDER | WB_FLATVALUESET | WB_TABSTOP);
 
    SetBackground(sfx2::sidebar::Theme::GetWallpaper(sfx2::sidebar::Theme::Paint_PanelBackground));
    SetColor(sfx2::sidebar::Theme::GetColor(sfx2::sidebar::Theme::Paint_PanelBackground));
 
#ifdef DEBUG
    SetText(OUString("sd:LayoutMenu"));
#endif
}
 
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;
 
    SetStyle (
        ( GetStyle()  & ~(WB_ITEMBORDER) )
        | WB_TABSTOP
        | WB_MENUSTYLEVALUESET
        | WB_NO_DIRECTSELECT
        );
    SetExtraSpacing(2);
    SetSelectHdl (LINK(this, LayoutMenu, ClickHandler));
    InvalidateContent();
 
    Link<::sd::tools::EventMultiplexerEvent&,void> aEventListenerLink (LINK(this,LayoutMenu,EventMultiplexerListener));
    mrBase.GetEventMultiplexer()->AddEventListener(aEventListenerLink);
 
    Window::SetHelpId(HID_SD_TASK_PANE_PREVIEW_LAYOUTS);
    SetAccessibleName(SdResId(STR_TASKPANEL_LAYOUT_MENU_TITLE));
 
    Link<const OUString&,void> aStateChangeLink (LINK(this,LayoutMenu,StateChangeHandler));
    mxListener = new ::sd::tools::SlotStateListener(
        aStateChangeLink,
        Reference<frame::XDispatchProvider>(mrBase.GetController()->getFrame(), UNO_QUERY),
        ".uno:VerticalTextState");
 
    SetSizePixel(GetParent()->GetSizePixel());
    Link<VclWindowEvent&,void> aWindowEventHandlerLink (LINK(this,LayoutMenu,WindowEventHandler));
    GetParent()->AddEventListener(aWindowEventHandlerLink);
}
 
LayoutMenu::~LayoutMenu()
{
    disposeOnce();
}
 
void LayoutMenu::dispose()
{
    SAL_INFO("sd.ui", "destroying LayoutMenu at " << this);
    Dispose();
    DragSourceHelper::dispose();
    DropTargetHelper::dispose();
    ValueSet::dispose();
}
 
void LayoutMenu::Dispose()
{
    if (mbIsDisposed)
        return;
 
    SAL_INFO("sd.ui", "disposing LayoutMenu at " << this);
 
    mbIsDisposed = true;
 
    Reference<lang::XComponent> xComponent (mxListener, UNO_QUERY);
    if (xComponent.is())
        xComponent->dispose();
 
    Clear();
    Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this,LayoutMenu,EventMultiplexerListener));
    mrBase.GetEventMultiplexer()->RemoveEventListener (aLink);
 
    Link<VclWindowEvent&,void> aWindowEventHandlerLink (LINK(this,LayoutMenu,WindowEventHandler));
    GetParent()->RemoveEventListener(aWindowEventHandlerLink);
}
 
AutoLayout LayoutMenu::GetSelectedAutoLayout()
{
    AutoLayout aResult = AUTOLAYOUT_NONE;
 
    if ( ! IsNoSelection() && GetSelectedItemId()!=0)
    {
        AutoLayout* pLayout = static_cast<AutoLayout*>(GetItemData(GetSelectedItemId()));
        if (pLayout != nullptr)
            aResult = *pLayout;
    }
 
    return aResult;
}
 
ui::LayoutSize LayoutMenu::GetHeightForWidth (const sal_Int32 nWidth)
{
    sal_Int32 nPreferredHeight = 200;
    if (GetItemCount()>0)
    {
        Image aImage = GetItemImage(GetItemId(0));
        Size aItemSize = CalcItemSizePixel (aImage.GetSizePixel());
        if (nWidth>0 && aItemSize.Width()>0)
        {
            aItemSize.AdjustWidth(8 );
            aItemSize.AdjustHeight(8 );
            int nColumnCount = nWidth / aItemSize.Width();
            if (nColumnCount <= 0)
                nColumnCount = 1;
            else if (nColumnCount > 4)
                nColumnCount = 4;
            int nRowCount = (GetItemCount() + nColumnCount-1) / nColumnCount;
            nPreferredHeight = nRowCount * aItemSize.Height();
        }
    }
    return ui::LayoutSize(nPreferredHeight,nPreferredHeight,nPreferredHeight);
}
 
void LayoutMenu::Resize()
{
    Size aWindowSize = GetOutputSizePixel();
    if (IsVisible() && aWindowSize.Width() > 0)
    {
        // Calculate the number of rows and columns.
        if (GetItemCount() > 0)
        {
            Image aImage = GetItemImage(GetItemId(0));
            Size aItemSize = CalcItemSizePixel (
                aImage.GetSizePixel());
            aItemSize.AdjustWidth(8 );
            aItemSize.AdjustHeight(8 );
            int nColumnCount = aWindowSize.Width() / aItemSize.Width();
            if (nColumnCount < 1)
                nColumnCount = 1;
            else if (nColumnCount > 4)
                nColumnCount = 4;
 
            int nRowCount = CalculateRowCount (aItemSize, nColumnCount);
 
            SetColCount (static_cast<sal_uInt16>(nColumnCount));
            SetLineCount (static_cast<sal_uInt16>(nRowCount));
        }
    }
 
    ValueSet::Resize ();
}
 
void LayoutMenu::MouseButtonDown (const MouseEvent& rEvent)
{
    // As a preparation for the context menu the item under the mouse is
    // selected.
    if (rEvent.IsRight())
    {
        ReleaseMouse();
        sal_uInt16 nIndex = GetItemId (rEvent.GetPosPixel());
        if (nIndex > 0)
            SelectItem(nIndex);
    }
 
    ValueSet::MouseButtonDown (rEvent);
}
 
void LayoutMenu::InsertPageWithLayout (AutoLayout aLayout)
{
    ViewShell* pViewShell = mrBase.GetMainViewShell().get();
    if (pViewShell == nullptr)
        return;
 
    SfxViewFrame* pViewFrame = mrBase.GetViewFrame();
    if (pViewFrame == nullptr)
        return;
 
    SfxDispatcher* pDispatcher = pViewFrame->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();
}
 
int LayoutMenu::CalculateRowCount (const Size&, int nColumnCount)
{
    int nRowCount = 0;
 
    if (GetItemCount() > 0 && nColumnCount > 0)
    {
        nRowCount = (GetItemCount() + nColumnCount - 1) / nColumnCount;
        //        nRowCount = GetOutputSizePixel().Height() / rItemSize.Height();
        if (nRowCount < 1)
            nRowCount = 1;
    }
 
    return nRowCount;
}
 
IMPL_LINK_NOARG(LayoutMenu, ClickHandler, ValueSet*, void)
{
    AssignLayoutToSelectedSlides( GetSelectedAutoLayout() );
}
 
/** 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 != nullptr)
                    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.get() == nullptr) || pPageSelection->empty() )
        {
            // No valid slide sorter available.  Ask the main view shell for
            // its current page.
            pPageSelection.reset(new ::sd::slidesorter::SlideSorterViewShell::PageSelection);
            pPageSelection->push_back(pMainViewShell->GetActualPage());
        }
 
        if (pPageSelection->empty())
            break;
 
        ::std::vector<SdPage*>::iterator iPage;
        for (iPage=pPageSelection->begin(); iPage!=pPageSelection->end(); ++iPage)
            {
                if ((*iPage) == 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, ((*iPage)->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(
            SdResId(STR_LAYER_BCKGRND)));
        SdrLayerID aBackgroundObject (rLayerAdmin.GetLayerID(
            SdResId(STR_LAYER_BCKGRNDOBJ)));
        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;
}
 
void LayoutMenu::Fill()
{
    SvtLanguageOptions aLanguageOptions;
    bool bVertical = aLanguageOptions.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
    {
        Reference<XControllerManager> xControllerManager (
            Reference<XWeak>(&mrBase.GetDrawController()), UNO_QUERY_THROW);
        Reference<XResourceId> xPaneId (ResourceId::create(
            ::comphelper::getProcessComponentContext(),
            FrameworkHelper::msCenterPaneURL));
        Reference<XView> xView (FrameworkHelper::Instance(mrBase)->GetView(xPaneId));
        if (xView.is())
            sCenterPaneViewName = xView->getResourceId()->getResourceURL();
    }
    catch (RuntimeException&)
    {}
 
    const snewfoil_value_info* pInfo = nullptr;
    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;
    }
    else
    {
        pInfo = nullptr;
    }
 
    Clear();
    for (sal_uInt16 i=1; pInfo!=nullptr && pInfo->mpStrResId != nullptr; i++, pInfo++)
    {
        if ((WritingMode_TB_RL != pInfo->meWritingMode) || bVertical)
        {
            BitmapEx aBmp(OUString::createFromAscii(pInfo->msBmpResId));
 
            if (bRightToLeft && (WritingMode_TB_RL != pInfo->meWritingMode))
                aBmp.Mirror (BmpMirrorFlags::Horizontal);
 
            InsertItem(i, Image(aBmp), SdResId(pInfo->mpStrResId));
            SetItemData (i, new AutoLayout(pInfo->maAutoLayout));
        }
    }
}
 
void LayoutMenu::Clear()
{
    for (size_t nId=1; nId<=GetItemCount(); nId++)
        delete static_cast<AutoLayout*>(GetItemData(nId));
    ValueSet::Clear();
}
 
void LayoutMenu::StartDrag (sal_Int8 , const Point& )
{
}
 
sal_Int8 LayoutMenu::AcceptDrop (const AcceptDropEvent& )
{
    return 0;
}
 
sal_Int8 LayoutMenu::ExecuteDrop (const ExecuteDropEvent& )
{
    return 0;
}
 
void LayoutMenu::Command (const CommandEvent& rEvent)
{
    switch (rEvent.GetCommand())
    {
        case CommandEventId::ContextMenu:
            if ( ! SD_MOD()->GetWaterCan())
            {
                // Determine the position where to show the menu.
                Point aMenuPosition;
                if (rEvent.IsMouseEvent())
                {
                    if (GetItemId(rEvent.GetMousePosPixel()) <= 0)
                        return;
                    aMenuPosition = rEvent.GetMousePosPixel();
                }
                else
                {
                    if (GetSelectedItemId() == sal_uInt16(-1))
                        return;
                    ::tools::Rectangle aBBox (GetItemRect(GetSelectedItemId()));
                    aMenuPosition = aBBox.Center();
                }
 
                // Setup the menu.
                VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/simpress/ui/layoutmenu.ui", "");
                VclPtr<PopupMenu> pMenu(aBuilder.get_menu("menu"));
                FloatingWindow* pMenuWindow = dynamic_cast<FloatingWindow*>(pMenu->GetWindow());
                if (pMenuWindow != nullptr)
                    pMenuWindow->SetPopupModeFlags(
                        pMenuWindow->GetPopupModeFlags() | FloatWinPopupFlags::NoMouseUpClose);
                pMenu->SetSelectHdl(LINK(this, LayoutMenu, OnMenuItemSelected));
 
                // Disable the SID_INSERTPAGE_LAYOUT_MENU item when
                // the document is read-only.
                const SfxPoolItem* pItem = nullptr;
                const SfxItemState aState (
                    mrBase.GetViewFrame()->GetDispatcher()->QueryState(SID_INSERTPAGE, pItem));
                if (aState == SfxItemState::DISABLED)
                    pMenu->EnableItem(SID_INSERTPAGE_LAYOUT_MENU, false);
 
                // Show the menu.
                pMenu->Execute(this, ::tools::Rectangle(aMenuPosition,Size(1,1)), PopupMenuFlags::ExecuteDown);
            }
            break;
 
        default:
            ValueSet::Command(rEvent);
            break;
    }
}
 
IMPL_LINK_NOARG(LayoutMenu, StateChangeHandler, const OUString&, void)
{
    InvalidateContent();
}
 
IMPL_LINK(LayoutMenu, OnMenuItemSelected, Menu*, pMenu, bool)
{
    if (pMenu == nullptr)
    {
        OSL_ENSURE(pMenu!=nullptr, "LayoutMenu::OnMenuItemSelected: illegal menu!");
        return false;
    }
 
    pMenu->Deactivate();
    OString sIdent = pMenu->GetCurItemIdent();
 
    if (sIdent == "apply")
    {
        AssignLayoutToSelectedSlides(GetSelectedAutoLayout());
    }
    else if (sIdent == "insert")
    {
        // Add arguments to this slot and forward it to the main view
        // shell.
        InsertPageWithLayout(GetSelectedAutoLayout());
    }
 
    return false;
}
 
// 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 = GetItemCount();
        for (sal_uInt16 nId=1; nId<=nItemCount; nId++)
        {
            if (*static_cast<AutoLayout*>(GetItemData(nId)) == aLayout)
            {
                // do not set selection twice to the same item
                if (GetSelectedItemId() != nId)
                {
                    SetNoSelection();
                    SelectItem(nId);
                }
 
                bItemSelected = true; // no need to call SetNoSelection()
                break;
            }
        }
    }
    while (false);
 
    if ( ! bItemSelected)
        SetNoSelection();
}
 
IMPL_LINK(LayoutMenu, EventMultiplexerListener, ::sd::tools::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:
            UpdateSelection();
            break;
 
        case EventMultiplexerEventId::CurrentPageChanged:
        case EventMultiplexerEventId::SlideSortedSelection:
            UpdateSelection();
            break;
 
        case EventMultiplexerEventId::MainViewAdded:
            mbIsMainViewChangePending = true;
            break;
 
        case EventMultiplexerEventId::MainViewRemoved:
            HideFocus();
            break;
 
        case EventMultiplexerEventId::ConfigurationUpdated:
            if (mbIsMainViewChangePending)
            {
                mbIsMainViewChangePending = false;
                InvalidateContent();
            }
            break;
 
        default:
            break;
    }
}
 
IMPL_LINK(LayoutMenu, WindowEventHandler, VclWindowEvent&, rEvent, void)
{
    switch (rEvent.GetId())
    {
        case VclEventId::WindowShow:
        case VclEventId::WindowResize:
            SetSizePixel(GetParent()->GetSizePixel());
            break;
 
        default: break;
    }
}
 
void LayoutMenu::DataChanged (const DataChangedEvent& rEvent)
{
    Fill();
    ValueSet::DataChanged(rEvent);
    SetBackground(sfx2::sidebar::Theme::GetWallpaper(sfx2::sidebar::Theme::Paint_PanelBackground));
    SetColor(sfx2::sidebar::Theme::GetColor(sfx2::sidebar::Theme::Paint_PanelBackground));
}
 
} } // end of namespace ::sd::sidebar
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V1016 Expression 'aLayout > AUTOLAYOUT_END' is always false.

V1016 Expression 'aLayout < AUTOLAYOUT_START' is always false.

V547 Expression 'pDrawViewShell != nullptr' is always true.