    /* -*- 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 <sfx2/app.hxx>

    #include <iconcdlg.hxx>
    #include <cuihyperdlg.hxx>

    #include <sal/log.hxx>
    #include <unotools/viewoptions.hxx>
    #include <svtools/apearcfg.hxx>
    #include <vcl/mnemonic.hxx>
    #include <vcl/i18nhelp.hxx>
    #include <vcl/settings.hxx>
    #include <vcl/builderfactory.hxx>

    using std::vector;

    /**********************************************************************
    |
    | Ctor / Dtor
    |
    \**********************************************************************/

    IconChoicePage::IconChoicePage( vcl::Window *pParent, const OString& rID,
                                    const OUString& rUIXMLDescription,
                                    const SfxItemSet* pItemSet )
    :   TabPage                   ( pParent, rID, rUIXMLDescription ),
        pSet                      ( pItemSet ),
        bHasExchangeSupport       ( false )
    {
        SetStyle ( GetStyle()  | WB_DIALOGCONTROL | WB_HIDE );
    }

    IconChoicePage::~IconChoicePage()
    {
        disposeOnce();
    }

    /**********************************************************************
    |
    | Activate / Deactivate
    |
    \**********************************************************************/

    void IconChoicePage::ActivatePage( const SfxItemSet& )
    {
    }

    DeactivateRC IconChoicePage::DeactivatePage( SfxItemSet* )
    {
        return DeactivateRC::LeavePage;
    }

    bool IconChoicePage::QueryClose()
    {
        return true;
    }

    /**********************************************************************
    |
    | window-methods
    |
    \**********************************************************************/

    void IconChoicePage::ImplInitSettings()
    {
        vcl::Window* pParent = GetParent();
        if ( pParent->IsChildTransparentModeEnabled() && !IsControlBackground() )
        {
            EnableChildTransparentMode();
            SetParentClipMode( ParentClipMode::NoClip );
            SetPaintTransparent( true );
            SetBackground();
        }
        else
        {
            EnableChildTransparentMode( false );
            SetParentClipMode();
            SetPaintTransparent( false );

            if ( IsControlBackground() )
                SetBackground( GetControlBackground() );
            else
                SetBackground( pParent->GetBackground() );
        }
    }

    void IconChoicePage::StateChanged( StateChangedType nType )
    {
        Window::StateChanged( nType );

        if ( nType == StateChangedType::ControlBackground )
        {
            ImplInitSettings();
            Invalidate();
        }
    }

    void IconChoicePage::DataChanged( const DataChangedEvent& rDCEvt )
    {
        Window::DataChanged( rDCEvt );

        if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
             (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
        {
            ImplInitSettings();
            Invalidate();
        }
    }

    // Class IconChoiceDialog

    /**********************************************************************
    |
    | Ctor / Dtor
    |
    \**********************************************************************/

    VCL_BUILDER_FACTORY_ARGS(SvtIconChoiceCtrl,
                             WB_3DLOOK | WB_ICON | WB_BORDER |
                             WB_NOCOLUMNHEADER | WB_HIGHLIGHTFRAME |
                             WB_NODRAGSELECTION | WB_TABSTOP);

    IconChoiceDialog::IconChoiceDialog ( vcl::Window* pParent, const OUString& rID,
                                         const OUString& rUIXMLDescription )
    :   SfxModalDialog         ( pParent, rID, rUIXMLDescription ),
        mnCurrentPageId ( HyperLinkPageType::NONE ),

        pSet            ( nullptr ),
        pExampleSet     ( nullptr )
    {
        get(m_pOKBtn, "ok");
        get(m_pApplyBtn, "apply");
        get(m_pCancelBtn, "cancel");
        get(m_pHelpBtn, "help");
        get(m_pResetBtn, "reset");
        get(m_pIconCtrl, "icon_control");
        get(m_pTabContainer, "tab");

        SetCtrlStyle();
        m_pIconCtrl->SetClickHdl ( LINK ( this, IconChoiceDialog , ChosePageHdl_Impl ) );
        m_pIconCtrl->Show();
        m_pIconCtrl->SetChoiceWithCursor();
        m_pIconCtrl->SetSelectionMode( SelectionMode::Single );

        // ItemSet
        if ( pSet )
        {
            pExampleSet = new SfxItemSet( *pSet );
            pOutSet.reset(new SfxItemSet( *pSet->GetPool(), pSet->GetRanges() ));
        }

        // Buttons
        m_pOKBtn->SetClickHdl   ( LINK( this, IconChoiceDialog, OkHdl ) );
        m_pApplyBtn->SetClickHdl   ( LINK( this, IconChoiceDialog, ApplyHdl ) );
        m_pResetBtn->SetClickHdl( LINK( this, IconChoiceDialog, ResetHdl ) );
        m_pOKBtn->Show();
        m_pApplyBtn->Show();
        m_pCancelBtn->Show();
        m_pHelpBtn->Show();
        m_pResetBtn->Show();
    }

    IconChoiceDialog ::~IconChoiceDialog ()
    {
        disposeOnce();
    }

    void IconChoiceDialog::dispose()
    {
        // save configuration at INI-Manager
        // and remove pages
        //SvtViewOptions aTabDlgOpt( EViewType::TabDialog, rId );
        //aTabDlgOpt.SetWindowState(OStringToOUString(GetWindowState((WindowStateMask::X | WindowStateMask::Y | WindowStateMask::State | WindowStateMask::Minimized)), RTL_TEXTENCODING_ASCII_US));
        //aTabDlgOpt.SetPageID( mnCurrentPageId );

        for (std::unique_ptr<IconChoicePageData> & pData : maPageList)
        {
            if ( pData->pPage )
                pData->pPage.disposeAndClear();
        }
        maPageList.clear();

        pRanges.reset();
        pOutSet.reset();

        m_pIconCtrl.clear();
        m_pOKBtn.clear();
        m_pApplyBtn.clear();
        m_pCancelBtn.clear();
        m_pHelpBtn.clear();
        m_pResetBtn.clear();
        m_pTabContainer.clear();
        SfxModalDialog::dispose();
    }

    /**********************************************************************
    |
    | add new page
    |
    \**********************************************************************/

    SvxIconChoiceCtrlEntry* IconChoiceDialog::AddTabPage(
        HyperLinkPageType nId,
        const OUString&   rIconText,
        const Image&    rChoiceIcon,
        CreatePage      pCreateFunc /* != 0 */
    )
    {
        maPageList.emplace_back( new IconChoicePageData ( nId, pCreateFunc ) );

        SvxIconChoiceCtrlEntry* pEntry = m_pIconCtrl->InsertEntry( rIconText, rChoiceIcon );
        pEntry->SetUserData ( reinterpret_cast<void*>(nId) );
        return pEntry;
    }

    void IconChoiceDialog::SetCtrlStyle()
    {
        WinBits const aWinBits = WB_3DLOOK | WB_ICON | WB_BORDER | WB_NOCOLUMNHEADER | WB_HIGHLIGHTFRAME | WB_NODRAGSELECTION | WB_TABSTOP | WB_CLIPCHILDREN | WB_ALIGN_LEFT | WB_NOHSCROLL;
        m_pIconCtrl->SetStyle(aWinBits);
        m_pIconCtrl->ArrangeIcons();
    }

    /**********************************************************************
    |
    | Show / Hide page or button
    |
    \**********************************************************************/

    void IconChoiceDialog::ShowPageImpl ( IconChoicePageData const * pData )
    {
        if ( pData->pPage )
            pData->pPage->Show();
    }

    void IconChoiceDialog::HidePageImpl ( IconChoicePageData const * pData )
    {
        if ( pData->pPage )
            pData->pPage->Hide();
    }

    void IconChoiceDialog::ShowPage(HyperLinkPageType nId)
    {
        HyperLinkPageType nOldPageId = GetCurPageId();
        bool bInvalidate = nOldPageId != nId;
        if (bInvalidate)
        {
            IconChoicePageData* pOldData = GetPageData(nOldPageId);
            if (pOldData && pOldData->pPage)
            {
                DeActivatePageImpl();
                HidePageImpl(pOldData);
            }

            Invalidate();
        }
        SetCurPageId(nId);
        ActivatePageImpl();
        IconChoicePageData* pNewData = GetPageData(nId);
        if (pNewData && pNewData->pPage)
            ShowPageImpl(pNewData);
    }

    /**********************************************************************
    |
    | select a page
    |
    \**********************************************************************/
    IMPL_LINK_NOARG(IconChoiceDialog , ChosePageHdl_Impl, SvtIconChoiceCtrl*, void)
    {
        SvxIconChoiceCtrlEntry *pEntry = m_pIconCtrl->GetSelectedEntry();
        if ( !pEntry )
            pEntry = m_pIconCtrl->GetCursor( );

        HyperLinkPageType nId = static_cast<HyperLinkPageType>(reinterpret_cast<sal_uIntPtr>(pEntry->GetUserData()));

        if( nId != mnCurrentPageId )
        {
            ShowPage(nId);
        }
    }

    /**********************************************************************
    |
    | Button-handler
    |
    \**********************************************************************/

    IMPL_LINK_NOARG(IconChoiceDialog, OkHdl, Button*, void)
    {
        if ( OK_Impl() )
        {
            Ok();
            Close();
        }
    }

    IMPL_LINK_NOARG(IconChoiceDialog, ApplyHdl, Button*, void)
    {
        if ( OK_Impl() )
        {
            Ok();
            Close();
        }
    }

    IMPL_LINK_NOARG(IconChoiceDialog, ResetHdl, Button*, void)
    {
        ResetPageImpl ();

        IconChoicePageData* pData = GetPageData ( mnCurrentPageId );
        DBG_ASSERT( pData, "ID not known" );

        pData->pPage->Reset( *pSet );
    }

    IMPL_LINK_NOARG(IconChoiceDialog, CancelHdl, Button*, void)
    {
        Close();
    }

    /**********************************************************************
    |
    | call page
    |
    \**********************************************************************/

    void IconChoiceDialog::ActivatePageImpl ()
    {
        DBG_ASSERT( !maPageList.empty(), "no Pages registered" );
        IconChoicePageData* pData = GetPageData ( mnCurrentPageId );
        DBG_ASSERT( pData, "ID not known" );
        if ( pData )
        {
            if ( !pData->pPage )
            {
                pData->pPage = (pData->fnCreatePage)( m_pTabContainer, this, pSet );
                pData->pPage->Reset( *pSet );
                PageCreated( mnCurrentPageId, *pData->pPage );
            }
            else if ( pData->bRefresh )
            {
                pData->pPage->Reset( *pSet );
            }

            pData->bRefresh = false;

            if ( pExampleSet )
                pData->pPage->ActivatePage( *pExampleSet );
            SetHelpId( pData->pPage->GetHelpId() );
        }

        m_pResetBtn->Show();
    }

    void IconChoiceDialog::DeActivatePageImpl ()
    {
        IconChoicePageData *pData = GetPageData ( mnCurrentPageId );

        DeactivateRC nRet = DeactivateRC::LeavePage;

        if ( pData )
        {
            IconChoicePage * pPage = pData->pPage;

            if ( !pExampleSet && pPage->HasExchangeSupport() && pSet )
                pExampleSet = new SfxItemSet( *pSet->GetPool(), pSet->GetRanges() );

            if ( pSet )
            {
                SfxItemSet aTmp( *pSet->GetPool(), pSet->GetRanges() );

                if ( pPage->HasExchangeSupport() )
                    nRet = pPage->DeactivatePage( &aTmp );

                if ( ( DeactivateRC::LeavePage & nRet ) &&
                     aTmp.Count() )
                {
                    if (pExampleSet)
                        pExampleSet->Put(aTmp);
                    pOutSet->Put( aTmp );
                }
            }
            else
            {
                if ( pPage->HasExchangeSupport() ) //!!!
                {
                    if ( !pExampleSet )
                    {
                        SfxItemPool* pPool = pPage->GetItemSet().GetPool();
                        pExampleSet =
                            new SfxItemSet( *pPool, GetInputRanges( *pPool ) );
                    }
                    nRet = pPage->DeactivatePage( pExampleSet );
                }
                else
                    nRet = pPage->DeactivatePage( nullptr );
            }

            if ( nRet & DeactivateRC::RefreshSet )
            {
                // TODO refresh input set
                // flag all pages to be newly initialized
                for (auto & pObj : maPageList)
                {
                    if ( pObj->pPage.get() != pPage )
                        pObj->bRefresh = true;
                    else
                        pObj->bRefresh = false;
                }
            }
        }
    }

    void IconChoiceDialog::ResetPageImpl ()
    {
        IconChoicePageData *pData = GetPageData ( mnCurrentPageId );

        DBG_ASSERT( pData, "ID not known" );

        pData->pPage->Reset( *pSet );
    }

    /**********************************************************************
    |
    | handling itemsets
    |
    \**********************************************************************/

    const sal_uInt16* IconChoiceDialog::GetInputRanges( const SfxItemPool& rPool )
    {
        if ( pSet )
        {
            SAL_WARN( "cui.dialogs", "Set does already exist!" );
            return pSet->GetRanges();
        }

        if ( pRanges )
            return pRanges.get();
        std::vector<sal_uInt16> aUS;

        size_t nCount = maPageList.size();

        // remove double Id's
        {
            nCount = aUS.size();
            for ( size_t i = 0; i < nCount; ++i )
                aUS[i] = rPool.GetWhich( aUS[i] );
        }

        if ( aUS.size() > 1 )
        {
            std::sort( aUS.begin(), aUS.end() );
        }

        pRanges.reset(new sal_uInt16[aUS.size() + 1]);
        std::copy( aUS.begin(), aUS.end(), pRanges.get() );
        pRanges[aUS.size()] = 0;

        return pRanges.get();
    }

    void IconChoiceDialog::SetInputSet( const SfxItemSet* pInSet )
    {
        bool bSet = ( pSet != nullptr );

        pSet = pInSet;

        if ( !bSet && !pExampleSet && !pOutSet )
        {
            pExampleSet = new SfxItemSet( *pSet );
            pOutSet.reset(new SfxItemSet( *pSet->GetPool(), pSet->GetRanges() ));
        }
    }

    void IconChoiceDialog::PageCreated( HyperLinkPageType /*nId*/, IconChoicePage& /*rPage*/ )
    {
        // not interested in
    }

    /**********************************************************************
    |
    | start dialog
    |
    \**********************************************************************/

    short IconChoiceDialog::Execute()
    {
        if ( maPageList.empty() )
            return RET_CANCEL;

        Start_Impl();

        return Dialog::Execute();
    }

    void IconChoiceDialog::Start()
    {
        m_pCancelBtn->SetClickHdl( LINK( this, IconChoiceDialog, CancelHdl ) );

        Start_Impl();
    }

    bool IconChoiceDialog::QueryClose()
    {
        bool bRet = true;
        for (auto & pData : maPageList)
        {
            if ( pData->pPage && !pData->pPage->QueryClose() )
            {
                bRet = false;
                break;
            }
        }
        return bRet;
    }

    void IconChoiceDialog::Start_Impl()
    {
        FocusOnIcon( mnCurrentPageId );
        ActivatePageImpl();
    }

    /**********************************************************************
    |
    | tool-methods
    |
    \**********************************************************************/

    IconChoicePageData* IconChoiceDialog::GetPageData ( HyperLinkPageType nId )
    {
        IconChoicePageData *pRet = nullptr;
        for (auto & pData : maPageList)
        {
            if ( pData->nId == nId )
            {
                pRet = pData.get();
                break;
            }
        }
        return pRet;
    }

    /**********************************************************************
    |
    | OK-Status
    |
    \**********************************************************************/

    bool IconChoiceDialog::OK_Impl()
    {
        IconChoicePage* pPage = GetPageData ( mnCurrentPageId )->pPage;

        bool bEnd = !pPage;
        if ( pPage )
        {
            DeactivateRC nRet = DeactivateRC::LeavePage;
            if ( pSet )
            {
                SfxItemSet aTmp( *pSet->GetPool(), pSet->GetRanges() );

                if ( pPage->HasExchangeSupport() )
                    nRet = pPage->DeactivatePage( &aTmp );

                if ( ( DeactivateRC::LeavePage & nRet )
                     && aTmp.Count() )
                {
                    pExampleSet->Put( aTmp );
                    pOutSet->Put( aTmp );
                }
            }
            else
                nRet = pPage->DeactivatePage( nullptr );
            bEnd = nRet != DeactivateRC::KeepPage;
        }

        return bEnd;
    }

    void IconChoiceDialog::Ok()
    {
        if ( !pOutSet )
        {
            if ( !pExampleSet && pSet )
                pOutSet = pSet->Clone( false ); // without items
            else if ( pExampleSet )
                pOutSet.reset(new SfxItemSet( *pExampleSet ));
        }

        for ( size_t i = 0, nCount = maPageList.size(); i < nCount; ++i )
        {
            IconChoicePageData* pData = GetPageData ( maPageList[i]->nId );

            IconChoicePage* pPage = pData->pPage;

            if ( pPage )
            {
                if ( pSet && !pPage->HasExchangeSupport() )
                {
                    SfxItemSet aTmp( *pSet->GetPool(), pSet->GetRanges() );

                    if ( pPage->FillItemSet( &aTmp ) )
                    {
                        if (pExampleSet)
                            pExampleSet->Put(aTmp);
                        pOutSet->Put( aTmp );
                    }
                }
            }
        }
    }

    void IconChoiceDialog::FocusOnIcon( HyperLinkPageType nId )
    {
        // set focus to icon for the current visible page
        for ( sal_Int32 i=0; i<m_pIconCtrl->GetEntryCount(); i++)
        {
            SvxIconChoiceCtrlEntry* pEntry = m_pIconCtrl->GetEntry ( i );
            HyperLinkPageType nUserData = static_cast<HyperLinkPageType>(reinterpret_cast<sal_uIntPtr>(pEntry->GetUserData()));

            if ( nUserData == nId )
            {
                m_pIconCtrl->SetCursor( pEntry );
                break;
            }
        }
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V654 The condition 'i < nCount' of loop is always false.

↑ V621 Consider inspecting the 'for' operator. It's possible that the loop will be executed incorrectly or won't be executed at all.

↑ V547 Expression 'aUS.size() > 1' is always false.

↑ V1023 A pointer without owner is added to the 'maPageList' container by the 'emplace_back' method. A memory leak will occur in case of an exception.