Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  cfg.cxx   Sprache: C

 
/* -*- 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 <sal/config.h>
#include <sal/log.hxx>

#include <cassert>
#include <stdlib.h>
#include <typeinfo>

#include <utility>
#include <vcl/stdtext.hxx>
#include <vcl/commandinfoprovider.hxx>
#include <vcl/event.hxx>
#include <vcl/graph.hxx>
#include <vcl/graphicfilter.hxx>
#include <vcl/svapp.hxx>
#include <vcl/toolbox.hxx>
#include <vcl/weld.hxx>
#include <vcl/decoview.hxx>
#include <vcl/virdev.hxx>

#include <sfx2/minfitem.hxx>
#include <sfx2/sfxhelp.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/filedlghelper.hxx>
#include <sfx2/sfxsids.hrc>
#include <svl/stritem.hxx>
#include <rtl/ustrbuf.hxx>
#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <toolkit/helper/vclunohelper.hxx>

#include <algorithm>
#include <strings.hrc>

#include <acccfg.hxx>
#include <cfg.hxx>
#include <CustomNotebookbarGenerator.hxx>
#include <SvxMenuConfigPage.hxx>
#include <SvxToolbarConfigPage.hxx>
#include <SvxNotebookbarConfigPage.hxx>
#include <SvxConfigPageHelper.hxx>
#include "eventdlg.hxx"
#include <dialmgr.hxx>

#include <unotools/configmgr.hxx>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/FileSystemStorageFactory.hpp>
#include <com/sun/star/frame/ModuleManager.hpp>
#include <com/sun/star/frame/XFrames.hpp>
#include <com/sun/star/frame/XLayoutManager.hpp>
#include <com/sun/star/frame/FrameSearchFlag.hpp>
#include <com/sun/star/frame/XController.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/theUICommandDescription.hpp>
#include <com/sun/star/graphic/GraphicProvider.hpp>
#include <com/sun/star/io/IOException.hpp>
#include <com/sun/star/ui/ItemType.hpp>
#include <com/sun/star/ui/ItemStyle.hpp>
#include <com/sun/star/ui/ImageManager.hpp>
#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
#include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
#include <com/sun/star/ui/XUIElement.hpp>
#include <com/sun/star/ui/UIElementType.hpp>
#include <com/sun/star/ui/ImageType.hpp>
#include <com/sun/star/ui/theWindowStateConfiguration.hpp>
#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
#include <com/sun/star/util/thePathSettings.hpp>
#include <comphelper/documentinfo.hxx>
#include <comphelper/propertysequence.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/processfactory.hxx>
#include <config_features.h>

namespace uno = css::uno;
namespace frame = css::frame;
namespace lang = css::lang;
namespace container = css::container;
namespace beans = css::beans;
namespace graphic = css::graphic;

#if OSL_DEBUG_LEVEL > 1

void printPropertySet(
    const OUString& prefix,
    const uno::Reference< beans::XPropertySet >& xPropSet )
{
    uno::Reference< beans::XPropertySetInfo > xPropSetInfo =
        xPropSet->getPropertySetInfo();

    const uno::Sequence< beans::Property >& aPropDetails =
        xPropSetInfo->getProperties();

    SAL_WARN("cui""printPropertySet: " << aPropDetails.getLength() << " properties" );

    for ( beans::Property const & aPropDetail  : aPropDetails )
    {
        OUString tmp;
        sal_Int32 ival;

        uno::Any a = xPropSet->getPropertyValue( aPropDetail.Name );

        if ( a >>= tmp )
        {
            SAL_WARN("cui", prefix << ": Got property: " << aPropDetail.Name << tmp);
        }
        else if ( ( a >>= ival ) )
        {
            SAL_WARN("cui", prefix << ": Got property: " << aPropDetail.Name << " = " << ival);
        }
        else
        {
            SAL_WARN("cui", prefix << ": Got property: " << aPropDetail.Name << " of type " << a.getValueTypeName());
        }
    }
}

void printProperties(
    const OUString& prefix,
    const uno::Sequence< beans::PropertyValue >& aProp )
{
    for (beans::PropertyValue const & aPropVal : aProp)
    {
        OUString tmp;

        aPropVal.Value >>= tmp;

        SAL_WARN("cui", prefix << ": Got property: " << aPropVal.Name << " = " << tmp);
    }
}

void printEntries(SvxEntries* entries)
{
    for (auto const& entry : *entries)
    {
        SAL_WARN("cui""printEntries: " << entry->GetName());
    }
}

#endif

bool
SvxConfigPage::CanConfig( std::u16string_view aModuleId )
{
    return aModuleId != u"com.sun.star.script.BasicIDE" && aModuleId != u"com.sun.star.frame.Bibliography";
}

static std::unique_ptr<SfxTabPage> CreateSvxMenuConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
{
    return std::make_unique<SvxMenuConfigPage>(pPage, pController, *rSet);
}

static std::unique_ptr<SfxTabPage> CreateSvxContextMenuConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
{
    return std::make_unique<SvxMenuConfigPage>(pPage, pController, *rSet, false);
}

static std::unique_ptr<SfxTabPage> CreateKeyboardConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
{
       return std::make_unique<SfxAcceleratorConfigPage>(pPage, pController, *rSet);
}

static std::unique_ptr<SfxTabPage> CreateSvxNotebookbarConfigPage(weld::Container* pPage, weld::DialogController* pController,
                                                         const SfxItemSet* rSet)
{
    return std::make_unique<SvxNotebookbarConfigPage>(pPage, pController, *rSet);
}

static std::unique_ptr<SfxTabPage> CreateSvxToolbarConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
{
    return std::make_unique<SvxToolbarConfigPage>(pPage, pController, *rSet);
}

static std::unique_ptr<SfxTabPage> CreateSvxEventConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
{
    return std::make_unique<SvxEventConfigPage>(pPage, pController, *rSet, SvxEventConfigPage::EarlyInit());
}

/******************************************************************************
 *
 * SvxConfigDialog is the configuration dialog which is brought up from the
 * Tools menu. It includes tabs for customizing menus, toolbars, events and
 * key bindings.
 *
 *****************************************************************************/

SvxConfigDialog::SvxConfigDialog(weld::Window * pParent, const SfxItemSet* pInSet)
    : SfxTabDialogController(pParent, u"cui/ui/customizedialog.ui"_ustr, u"CustomizeDialog"_ustr, pInSet)
{
    SvxConfigPageHelper::InitImageType();

    AddTabPage(u"menus"_ustr, CreateSvxMenuConfigPage, nullptr);
    AddTabPage(u"toolbars"_ustr, CreateSvxToolbarConfigPage, nullptr);
    AddTabPage(u"notebookbar"_ustr, CreateSvxNotebookbarConfigPage, nullptr);
    AddTabPage(u"contextmenus"_ustr, CreateSvxContextMenuConfigPage, nullptr);
    AddTabPage(u"keyboard"_ustr, CreateKeyboardConfigPage, nullptr);
    AddTabPage(u"events"_ustr, CreateSvxEventConfigPage, nullptr);

    if (const SfxPoolItem* pItem = pInSet->GetItem(SID_CONFIG))
    {
        OUString text = static_cast<const SfxStringItem*>(pItem)->GetValue();
        if (text.startsWith( ITEM_TOOLBAR_URL ) )
            SetCurPageId(u"toolbars"_ustr);
        else if (text.startsWith( ITEM_EVENT_URL) )
            SetCurPageId(u"events"_ustr);
    }
#if HAVE_FEATURE_SCRIPTING
    else if (pInSet->GetItemIfSet(SID_MACROINFO))
    {
        // for the "assign" button in the Basic Macros chooser automatically switch
        // to the keyboard tab in which this macro will be pre-selected for assigning
        // to a keystroke
        SetCurPageId(u"keyboard"_ustr);
    }
#endif
}

void SvxConfigDialog::ActivatePage(const OUString& rPage)
{
    SfxTabDialogController::ActivatePage(rPage);
    GetResetButton()->set_visible(rPage != "keyboard");
}

void SvxConfigDialog::SetFrame(const css::uno::Reference<css::frame::XFrame>& xFrame)
{
    m_xFrame = xFrame;
    OUString aModuleId = SvxConfigPage::GetFrameWithDefaultAndIdentify(m_xFrame);

    if (aModuleId != "com.sun.star.text.TextDocument" &&
        aModuleId != "com.sun.star.sheet.SpreadsheetDocument" &&
        aModuleId != "com.sun.star.presentation.PresentationDocument" &&
        aModuleId != "com.sun.star.drawing.DrawingDocument")
        RemoveTabPage(u"notebookbar"_ustr);

    if (aModuleId == "com.sun.star.frame.StartModule")
        RemoveTabPage(u"keyboard"_ustr);
}

void SvxConfigDialog::PageCreated(const OUString &rId, SfxTabPage& rPage)
{
    if (rId == "menus" || rId == "keyboard" || rId == "notebookbar"
        || rId == "toolbars" || rId == "contextmenus")
    {
        rPage.SetFrame(m_xFrame);
    }
    else if (rId == "events")
    {
        dynamic_cast< SvxEventConfigPage& >( rPage ).LateInit( m_xFrame );
    }
}

/******************************************************************************
 *
 * The SaveInData class is used to hold data for entries in the Save In
 * ListBox controls in the menu and toolbar tabs
 *
 ******************************************************************************/


// Initialize static variable which holds default XImageManager
uno::Reference< css::ui::XImageManager>* SaveInData::xDefaultImgMgr = nullptr;

SaveInData::SaveInData(
    uno::Reference< css::ui::XUIConfigurationManager > xCfgMgr,
    uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr,
    const OUString& aModuleId,
    bool isDocConfig )
        :
            bModified( false ),
            bDocConfig( isDocConfig ),
            bReadOnly( false ),
            m_xCfgMgr(std::move( xCfgMgr )),
            m_xParentCfgMgr(std::move( xParentCfgMgr )),
            m_aSeparatorSeq{ comphelper::makePropertyValue(ITEM_DESCRIPTOR_TYPE,
                                                           css::ui::ItemType::SEPARATOR_LINE) }
{
    if ( bDocConfig )
    {
        uno::Reference< css::ui::XUIConfigurationPersistence >
            xDocPersistence( GetConfigManager(), uno::UNO_QUERY );

        bReadOnly = xDocPersistence->isReadOnly();
    }

    const uno::Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();

    uno::Reference< container::XNameAccess > xNameAccess(
        css::frame::theUICommandDescription::get(xContext) );

    xNameAccess->getByName( aModuleId ) >>= m_xCommandToLabelMap;

    if ( !m_xImgMgr.is() )
    {
        m_xImgMgr.set( GetConfigManager()->getImageManager(), uno::UNO_QUERY );
    }

    if ( !IsDocConfig() )
    {
        // If this is not a document configuration then it is the settings
        // for the module (writer, calc, impress etc.) Use this as the default
        // XImageManager instance
        xDefaultImgMgr = &m_xImgMgr;
    }
    else
    {
        // If this is a document configuration then use the module image manager
        // as default.
        if ( m_xParentCfgMgr.is() )
        {
            m_xParentImgMgr.set( m_xParentCfgMgr->getImageManager(), uno::UNO_QUERY );
            xDefaultImgMgr = &m_xParentImgMgr;
        }
    }
}

uno::Reference<graphic::XGraphic> SaveInData::GetImage(const OUString& rCommandURL)
{
    uno::Reference< graphic::XGraphic > xGraphic =
        SvxConfigPageHelper::GetGraphic( m_xImgMgr, rCommandURL );

    if (!xGraphic.is() && xDefaultImgMgr != nullptr && (*xDefaultImgMgr).is())
    {
        xGraphic = SvxConfigPageHelper::GetGraphic( (*xDefaultImgMgr), rCommandURL );
    }

    return xGraphic;
}

bool SaveInData::PersistChanges(
    const uno::Reference< uno::XInterface >& xManager )
{
    bool result = true;

    try
    {
        if ( xManager.is() && !IsReadOnly() )
        {
            uno::Reference< css::ui::XUIConfigurationPersistence >
                xConfigPersistence( xManager, uno::UNO_QUERY );

            if ( xConfigPersistence->isModified() )
            {
                xConfigPersistence->store();
            }
        }
    }
    catch ( css::io::IOException& )
    {
        result = false;
    }

    return result;
}

/******************************************************************************
 *
 * The MenuSaveInData class extends SaveInData and provides menu specific
 * load and store functionality.
 *
 ******************************************************************************/


// Initialize static variable which holds default Menu data
MenuSaveInData* MenuSaveInData::pDefaultData = nullptr;

MenuSaveInData::MenuSaveInData(
    const uno::Reference< css::ui::XUIConfigurationManager >& cfgmgr,
    const uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
    const OUString& aModuleId,
    bool isDocConfig )
    :
        SaveInData( cfgmgr, xParentCfgMgr, aModuleId, isDocConfig ),
        m_aMenuResourceURL(
            ITEM_MENUBAR_URL  ),
        m_aDescriptorContainer(
            ITEM_DESCRIPTOR_CONTAINER  )
{
    try
    {
        m_xMenuSettings = GetConfigManager()->getSettings( ITEM_MENUBAR_URL, false );
    }
    catch ( container::NoSuchElementException& )
    {
        // will use menu settings for the module
    }

    // If this is not a document configuration then it is the settings
    // for the module (writer, calc, impress etc.). These settings should
    // be set as the default to be used for SaveIn locations that do not
    // have custom settings
    if ( !IsDocConfig() )
    {
        SetDefaultData( this );
    }
}

MenuSaveInData::~MenuSaveInData()
{
}

SvxEntries*
MenuSaveInData::GetEntries()
{
    if ( pRootEntry == nullptr )
    {
        pRootEntry.reset( new SvxConfigEntry( u"MainMenus"_ustr, OUString(), true/*bParentData*/false) );

        if ( m_xMenuSettings.is() )
        {
            LoadSubMenus( m_xMenuSettings, OUString(), pRootEntry.get(), false );
        }
        else if ( GetDefaultData() != nullptr )
        {
            // If the doc has no config settings use module config settings
            LoadSubMenus( GetDefaultData()->m_xMenuSettings, OUString(), pRootEntry.get(), false );
        }
    }

    return pRootEntry->GetEntries();
}

void
MenuSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
{
    pRootEntry->SetEntries( std::move(pNewEntries) );
}

void SaveInData::LoadSubMenus( const uno::Reference< container::XIndexAccess >& xMenuSettings,
    const OUString& rBaseTitle, SvxConfigEntry const * pParentData, bool bContextMenu )
{
    SvxEntries* pEntries = pParentData->GetEntries();

    // Don't access non existing menu configuration!
    if ( !xMenuSettings.is() )
        return;

    for ( sal_Int32 nIndex = 0; nIndex < xMenuSettings->getCount(); ++nIndex )
    {
        uno::Reference< container::XIndexAccess >   xSubMenu;
        OUString                aCommandURL;
        OUString                aLabel;

        sal_uInt16 nType( css::ui::ItemType::DEFAULT );
        sal_Int32 nStyle(0);

        bool bItem = SvxConfigPageHelper::GetMenuItemData( xMenuSettings, nIndex,
            aCommandURL, aLabel, nType, nStyle, xSubMenu );

        if ( bItem )
        {
            bool bIsUserDefined = true;

            if ( nType == css::ui::ItemType::DEFAULT )
            {
                uno::Any a;
                try
                {
                    a = m_xCommandToLabelMap->getByName( aCommandURL );
                    bIsUserDefined = false;
                }
                catch ( container::NoSuchElementException& )
                {
                    bIsUserDefined = true;
                }

                bool bUseDefaultLabel = false;
                // If custom label not set retrieve it from the command
                // to info service
                if ( aLabel.isEmpty() )
                {
                    bUseDefaultLabel = true;
                    uno::Sequence< beans::PropertyValue > aPropSeq;
                    if ( a >>= aPropSeq )
                    {
                        OUString aMenuLabel;
                        for (const beans::PropertyValue& prop : aPropSeq)
                        {
                            if ( bContextMenu )
                            {
                                if ( prop.Name == "PopupLabel" )
                                {
                                    prop.Value >>= aLabel;
                                    break;
                                }
                                else if ( prop.Name == "Label" )
                                {
                                    prop.Value >>= aMenuLabel;
                                }
                            }
                            else if ( prop.Name == "Label" )
                            {
                                prop.Value >>= aLabel;
                                break;
                            }
                        }
                        if ( aLabel.isEmpty() )
                            aLabel = aMenuLabel;
                    }
                }

                SvxConfigEntry* pEntry = new SvxConfigEntry(
                    aLabel, aCommandURL, xSubMenu.is(), /*bParentData*/false );

                pEntry->SetStyle( nStyle );
                pEntry->SetUserDefined( bIsUserDefined );
                if ( !bUseDefaultLabel )
                    pEntry->SetName( aLabel );

                pEntries->push_back( pEntry );

                if ( xSubMenu.is() )
                {
                    // popup menu
                    OUString subMenuTitle( rBaseTitle );

                    if ( !subMenuTitle.isEmpty() )
                    {
                        subMenuTitle += aMenuSeparatorStr;
                    }
                    else
                    {
                        pEntry->SetMain();
                    }

                    subMenuTitle += SvxConfigPageHelper::stripHotKey( aLabel );

                    LoadSubMenus( xSubMenu, subMenuTitle, pEntry, bContextMenu );
                }
            }
            else
            {
                SvxConfigEntry* pEntry = new SvxConfigEntry;
                pEntry->SetUserDefined( bIsUserDefined );
                pEntries->push_back( pEntry );
            }
        }
    }
}

bool MenuSaveInData::Apply()
{
    bool result = false;

    if ( IsModified() )
    {
        // Apply new menu bar structure to our settings container
        m_xMenuSettings = GetConfigManager()->createSettings();

        uno::Reference< container::XIndexContainer > xIndexContainer (
            m_xMenuSettings, uno::UNO_QUERY );

        uno::Reference< lang::XSingleComponentFactory > xFactory (
            m_xMenuSettings, uno::UNO_QUERY );

        Apply( xIndexContainer, xFactory );

        try
        {
            if ( GetConfigManager()->hasSettings( m_aMenuResourceURL ) )
            {
                GetConfigManager()->replaceSettings(
                    m_aMenuResourceURL, m_xMenuSettings );
            }
            else
            {
                GetConfigManager()->insertSettings(
                    m_aMenuResourceURL, m_xMenuSettings );
            }
        }
        catch ( css::uno::Exception& )
        {
            TOOLS_WARN_EXCEPTION("cui.customize""caught some other exception saving settings");
        }

        SetModified( false );

        result = PersistChanges( GetConfigManager() );
    }

    return result;
}

void MenuSaveInData::Apply(
    uno::Reference< container::XIndexContainer > const & rMenuBar,
    uno::Reference< lang::XSingleComponentFactory >& rFactory )
{
    const uno::Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();

    for (auto const& entryData : *GetEntries())
    {
        uno::Sequence< beans::PropertyValue > aPropValueSeq =
            SvxConfigPageHelper::ConvertSvxConfigEntry(entryData);

        uno::Reference< container::XIndexContainer > xSubMenuBar(
            rFactory->createInstanceWithContext( xContext ),
            uno::UNO_QUERY );

        sal_Int32 nIndex = aPropValueSeq.getLength();
        aPropValueSeq.realloc( nIndex + 1 );
        auto pPropValueSeq = aPropValueSeq.getArray();
        pPropValueSeq[nIndex].Name = m_aDescriptorContainer;
        pPropValueSeq[nIndex].Value <<= xSubMenuBar;
        rMenuBar->insertByIndex(
            rMenuBar->getCount(), uno::Any( aPropValueSeq ));
        ApplyMenu( xSubMenuBar, rFactory, entryData );
    }
}

void SaveInData::ApplyMenu(
    uno::Reference< container::XIndexContainer > const & rMenuBar,
    uno::Reference< lang::XSingleComponentFactory >& rFactory,
    SvxConfigEntry* pMenuData )
{
    const uno::Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();

    for (auto const& entry : *pMenuData->GetEntries())
    {
        if (entry->IsPopup())
        {
            uno::Sequence< beans::PropertyValue > aPropValueSeq =
                SvxConfigPageHelper::ConvertSvxConfigEntry(entry);

            uno::Reference< container::XIndexContainer > xSubMenuBar(
                rFactory->createInstanceWithContext( xContext ),
                    uno::UNO_QUERY );

            sal_Int32 nIndex = aPropValueSeq.getLength();
            aPropValueSeq.realloc( nIndex + 1 );
            auto pPropValueSeq = aPropValueSeq.getArray();
            pPropValueSeq[nIndex].Name = ITEM_DESCRIPTOR_CONTAINER;
            pPropValueSeq[nIndex].Value <<= xSubMenuBar;

            rMenuBar->insertByIndex(
                rMenuBar->getCount(), uno::Any( aPropValueSeq ));

            ApplyMenu( xSubMenuBar, rFactory, entry );
            entry->SetModified( false );
        }
        else if (entry->IsSeparator())
        {
            rMenuBar->insertByIndex(
                rMenuBar->getCount(), uno::Any( m_aSeparatorSeq ));
        }
        else
        {
            uno::Sequence< beans::PropertyValue > aPropValueSeq =
                SvxConfigPageHelper::ConvertSvxConfigEntry(entry);
            rMenuBar->insertByIndex(
                rMenuBar->getCount(), uno::Any( aPropValueSeq ));
        }
    }
    pMenuData->SetModified( false );
}

void
MenuSaveInData::Reset()
{
    try
    {
        GetConfigManager()->removeSettings( m_aMenuResourceURL );
    }
    catch ( const css::uno::Exception& )
    {}

    PersistChanges( GetConfigManager() );

    pRootEntry.reset();

    try
    {
        m_xMenuSettings = GetConfigManager()->getSettings(
            m_aMenuResourceURL, false );
    }
    catch ( container::NoSuchElementException& )
    {
        // will use default settings
    }
}

ContextMenuSaveInData::ContextMenuSaveInData(
    const css::uno::Reference< css::ui::XUIConfigurationManager >& xCfgMgr,
    const css::uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
    const OUString& aModuleId, bool bIsDocConfig )
    : SaveInData( xCfgMgr, xParentCfgMgr, aModuleId, bIsDocConfig )
{
    const css::uno::Reference< css::uno::XComponentContext >& xContext( comphelper::getProcessComponentContext() );
    css::uno::Reference< css::container::XNameAccess > xConfig( css::ui::theWindowStateConfiguration::get( xContext ) );
    xConfig->getByName( aModuleId ) >>= m_xPersistentWindowState;
}

ContextMenuSaveInData::~ContextMenuSaveInData()
{
}

OUString ContextMenuSaveInData::GetUIName( const OUString& rResourceURL )
{
    if ( m_xPersistentWindowState.is() )
    {
        css::uno::Sequence< css::beans::PropertyValue > aProps;
        try
        {
            m_xPersistentWindowState->getByName( rResourceURL ) >>= aProps;
        }
        catch ( const css::uno::Exception& )
        {}

        for (const auto& aProp : aProps)
        {
            if ( aProp.Name == ITEM_DESCRIPTOR_UINAME )
            {
                OUString aResult;
                aProp.Value >>= aResult;
                return aResult;
            }
        }
    }
    return OUString();
}

SvxEntries* ContextMenuSaveInData::GetEntries()
{
    if ( !m_pRootEntry )
    {
        std::unordered_map< OUString, bool > aMenuInfo;

        m_pRootEntry.reset( new SvxConfigEntry( u"ContextMenus"_ustr, OUString(), true/*bParentData*/false ) );
        css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aElementsInfo;
        try
        {
            aElementsInfo = GetConfigManager()->getUIElementsInfo( css::ui::UIElementType::POPUPMENU );
        }
        catch ( const css::lang::IllegalArgumentException& )
        {}

        for (const auto& aElement : aElementsInfo)
        {
            OUString aUrl;
            for ( const auto& aElementProp : aElement )
            {
                if ( aElementProp.Name == ITEM_DESCRIPTOR_RESOURCEURL )
                {
                    aElementProp.Value >>= aUrl;
                    break;
                }
            }

            css::uno::Reference< css::container::XIndexAccess > xPopupMenu;
            try
            {
                xPopupMenu = GetConfigManager()->getSettings( aUrl, false );
            }
            catch ( const css::uno::Exception& )
            {}

            if ( xPopupMenu.is() )
            {
                // insert into std::unordered_map to filter duplicates from the parent
                aMenuInfo.emplace(  aUrl, true );

                OUString aUIMenuName = GetUIName( aUrl );
                if ( aUIMenuName.isEmpty() )
                    // Menus without UI name aren't supposed to be customized.
                    continue;

                SvxConfigEntry* pEntry = new SvxConfigEntry( aUIMenuName, aUrl, true/*bParentData*/false );
                pEntry->SetMain();
                m_pRootEntry->GetEntries()->push_back( pEntry );
                LoadSubMenus( xPopupMenu, aUIMenuName, pEntry, true );
            }
        }

        // Retrieve also the parent menus, to make it possible to configure module menus and save them into the document.
        css::uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr = GetParentConfigManager();
        css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aParentElementsInfo;
        try
        {
            if ( xParentCfgMgr.is() )
                aParentElementsInfo = xParentCfgMgr->getUIElementsInfo( css::ui::UIElementType::POPUPMENU );
        }
        catch ( const css::lang::IllegalArgumentException& )
        {}

        for (const auto& aElement : aParentElementsInfo)
        {
            OUString aUrl;
            for ( const auto& aElementProp : aElement )
            {
                if ( aElementProp.Name == ITEM_DESCRIPTOR_RESOURCEURL )
                {
                    aElementProp.Value >>= aUrl;
                    break;
                }
            }

            css::uno::Reference< css::container::XIndexAccess > xPopupMenu;
            try
            {
                if ( aMenuInfo.find( aUrl ) == aMenuInfo.end() )
                    xPopupMenu = xParentCfgMgr->getSettings( aUrl, false );
            }
            catch ( const css::uno::Exception& )
            {}

            if ( xPopupMenu.is() )
            {
                OUString aUIMenuName = GetUIName( aUrl );
                if ( aUIMenuName.isEmpty() )
                    continue;

                SvxConfigEntry* pEntry = new SvxConfigEntry( aUIMenuName, aUrl, truetrue );
                pEntry->SetMain();
                m_pRootEntry->GetEntries()->push_back( pEntry );
                LoadSubMenus( xPopupMenu, aUIMenuName, pEntry, true );
            }
        }
        std::sort( m_pRootEntry->GetEntries()->begin(), m_pRootEntry->GetEntries()->end(), SvxConfigPageHelper::EntrySort );
    }
    return m_pRootEntry->GetEntries();
}

void ContextMenuSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
{
    m_pRootEntry->SetEntries( std::move(pNewEntries) );
}

bool ContextMenuSaveInData::HasURL( const OUString& rURL )
{
    SvxEntries* pEntries = GetEntries();
    for ( const auto& pEntry : *pEntries )
        if ( pEntry->GetCommand() == rURL )
            return true;

    return false;
}

bool ContextMenuSaveInData::HasSettings()
{
    return m_pRootEntry && !m_pRootEntry->GetEntries()->empty();
}

bool ContextMenuSaveInData::Apply()
{
    if ( !IsModified() )
        return false;

    SvxEntries* pEntries = GetEntries();
    for ( const auto& pEntry : *pEntries )
    {
        if ( pEntry->IsModified() || SvxConfigPageHelper::SvxConfigEntryModified( pEntry ) )
        {
            css::uno::Reference< css::container::XIndexContainer > xIndexContainer = GetConfigManager()->createSettings();
            css::uno::Reference< css::lang::XSingleComponentFactory > xFactory( xIndexContainer, css::uno::UNO_QUERY );
            ApplyMenu( xIndexContainer, xFactory, pEntry );

            const OUString& aUrl = pEntry->GetCommand();
            try
            {
                if ( GetConfigManager()->hasSettings( aUrl ) )
                    GetConfigManager()->replaceSettings( aUrl, xIndexContainer );
                else
                    GetConfigManager()->insertSettings( aUrl, xIndexContainer );
            }
            catch ( const css::uno::Exception& )
            {}
        }
    }
    SetModified( false );
    return PersistChanges( GetConfigManager() );
}

void ContextMenuSaveInData::Reset()
{
    SvxEntries* pEntries = GetEntries();
    for ( const auto& pEntry : *pEntries )
    {
        try
        {
            GetConfigManager()->removeSettings( pEntry->GetCommand() );
        }
        catch ( const css::uno::Exception& )
        {
            TOOLS_WARN_EXCEPTION("cui.customize""Exception caught while resetting context menus");
        }
    }
    PersistChanges( GetConfigManager() );
    m_pRootEntry.reset();
}

void ContextMenuSaveInData::ResetContextMenu( const SvxConfigEntry* pEntry )
{
    try
    {
        GetConfigManager()->removeSettings( pEntry->GetCommand() );
    }
    catch ( const css::uno::Exception& )
    {
        TOOLS_WARN_EXCEPTION("cui.customize""Exception caught while resetting context menu");
    }
    PersistChanges( GetConfigManager() );
    m_pRootEntry.reset();
}

void SvxMenuEntriesListBox::CreateDropDown()
{
    int nWidth = (m_xControl->get_text_height() * 3) / 4;
    m_xDropDown->SetOutputSizePixel(Size(nWidth, nWidth));
    DecorationView aDecoView(m_xDropDown.get());
    aDecoView.DrawSymbol(tools::Rectangle(Point(0, 0), Size(nWidth, nWidth)),
                         SymbolType::SPIN_RIGHT, m_xDropDown->GetTextColor(),
                         DrawSymbolFlags::NONE);
}

/******************************************************************************
 *
 * SvxMenuEntriesListBox is the listbox in which the menu items for a
 * particular menu are shown. We have a custom listbox because we need
 * to add drag'n'drop support from the Macro Selector and within the
 * listbox
 *
 *****************************************************************************/

SvxMenuEntriesListBox::SvxMenuEntriesListBox(std::unique_ptr<weld::TreeView> xControl, SvxConfigPage* pPg)
    : m_xControl(std::move(xControl))
    , m_xDropDown(m_xControl->create_virtual_device())
    , m_pPage(pPg)
{
    m_xControl->enable_toggle_buttons(weld::ColumnToggleType::Check);
    CreateDropDown();
    m_xControl->connect_key_press(LINK(this, SvxMenuEntriesListBox, KeyInputHdl));
    m_xControl->connect_query_tooltip(LINK(this, SvxMenuEntriesListBox, QueryTooltip));
}

SvxMenuEntriesListBox::~SvxMenuEntriesListBox()
{
}

IMPL_LINK(SvxMenuEntriesListBox, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
{
    vcl::KeyCode keycode = rKeyEvent.GetKeyCode();

    // support DELETE for removing the current entry
    if ( keycode == KEY_DELETE )
    {
        m_pPage->DeleteSelectedContent();
    }
    // support CTRL+UP and CTRL+DOWN for moving selected entries
    else if ( keycode.GetCode() == KEY_UP && keycode.IsMod1() )
    {
        m_pPage->MoveEntry( true );
    }
    else if ( keycode.GetCode() == KEY_DOWN && keycode.IsMod1() )
    {
        m_pPage->MoveEntry( false );
    }
    else
    {
        return false// pass on to default handler
    }
    return true;
}

IMPL_LINK(SvxMenuEntriesListBox, QueryTooltip, const weld::TreeIter&, rIter, OUString)
{
    SvxConfigEntry *pEntry = weld::fromId<SvxConfigEntry*>(m_xControl->get_id(rIter));
    if (!pEntry || pEntry->GetCommand().isEmpty())
        return OUString();
    const OUString sCommand(pEntry->GetCommand());
    OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(m_pPage->GetFrame()));
    auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(sCommand, aModuleName);
    OUString sTooltipLabel = vcl::CommandInfoProvider::GetTooltipForCommand(sCommand, aProperties,
                                                                            m_pPage->GetFrame());
    return CuiResId(RID_CUISTR_COMMANDLABEL) + ": " + pEntry->GetName().replaceFirst("~""") + "\n" +
            CuiResId(RID_CUISTR_COMMANDNAME) + ": " + sCommand + "\n" +
            CuiResId(RID_CUISTR_COMMANDTIP) + ": " + sTooltipLabel.replaceFirst("~""");
}

/******************************************************************************
 *
 * SvxConfigPage is the abstract base class on which the Menu and Toolbar
 * configuration tabpages are based. It includes methods which are common to
 * both tabpages to add, delete, move and rename items etc.
 *
 *****************************************************************************/

SvxConfigPage::SvxConfigPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
    : SfxTabPage(pPage, pController, u"cui/ui/menuassignpage.ui"_ustr, u"MenuAssignPage"_ustr, &rSet)
    , m_aUpdateDataTimer( "SvxConfigPage UpdateDataTimer" )
    , bInitialised(false)
    , pCurrentSaveInData(nullptr)
    , m_xCommandCategoryListBox(new CommandCategoryListBox(m_xBuilder->weld_combo_box(u"commandcategorylist"_ustr)))
    , m_xFunctions(new CuiConfigFunctionListBox(m_xBuilder->weld_tree_view(u"functions"_ustr)))
    , m_xCategoryLabel(m_xBuilder->weld_label(u"categorylabel"_ustr))
    , m_xDescriptionFieldLb(m_xBuilder->weld_label(u"descriptionlabel"_ustr))
    , m_xDescriptionField(m_xBuilder->weld_text_view(u"desc"_ustr))
    , m_xLeftFunctionLabel(m_xBuilder->weld_label(u"leftfunctionlabel"_ustr))
    , m_xSearchEdit(m_xBuilder->weld_entry(u"searchEntry"_ustr))
    , m_xSearchLabel(m_xBuilder->weld_label(u"searchlabel"_ustr))
    , m_xCustomizeLabel(m_xBuilder->weld_label(u"customizelabel"_ustr))
    , m_xTopLevelListBox(m_xBuilder->weld_combo_box(u"toplevellist"_ustr))
    , m_xMoveUpButton(m_xBuilder->weld_button(u"up"_ustr))
    , m_xMoveDownButton(m_xBuilder->weld_button(u"down"_ustr))
    , m_xSaveInListBox(m_xBuilder->weld_combo_box(u"savein"_ustr))
    , m_xCustomizeBox(m_xBuilder->weld_widget(u"customizebox"_ustr))
    , m_xInsertBtn(m_xBuilder->weld_menu_button(u"insert"_ustr))
    , m_xModifyBtn(m_xBuilder->weld_menu_button(u"modify"_ustr))
    , m_xResetBtn(m_xBuilder->weld_button(u"defaultsbtn"_ustr))
    , m_xCommandButtons(m_xBuilder->weld_widget(u"arrowgrid"_ustr))
    , m_xAddCommandButton(m_xBuilder->weld_button(u"add"_ustr))
    , m_xRemoveCommandButton(m_xBuilder->weld_button(u"remove"_ustr))
{
    CustomNotebookbarGenerator::getFileNameAndAppName(m_sAppName, m_sFileName);

    m_xTopLevelListBox->connect_changed(LINK(this, SvxConfigPage, SelectElementHdl));

    weld::TreeView& rTreeView = m_xFunctions->get_widget();
    Size aSize(rTreeView.get_approximate_digit_width() * 40, rTreeView.get_height_rows(8));
    m_xFunctions->set_size_request(aSize.Width(), aSize.Height());
    m_xDescriptionField->set_size_request(aSize.Width(), m_xDescriptionField->get_height_rows(3));

    m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SvxConfigPage, ImplUpdateDataHdl));
    m_aUpdateDataTimer.SetTimeout(EDIT_UPDATEDATA_TIMEOUT);

    m_xSearchEdit->connect_changed(LINK(this, SvxConfigPage, SearchUpdateHdl));
    m_xSearchEdit->connect_focus_out(LINK(this, SvxConfigPage, FocusOut_Impl));

    rTreeView.connect_row_activated(LINK(this, SvxConfigPage, FunctionDoubleClickHdl));
    rTreeView.connect_selection_changed(LINK(this, SvxConfigPage, SelectFunctionHdl));
}

IMPL_LINK_NOARG(SvxConfigPage, SelectElementHdl, weld::ComboBox&, void)
{
    SelectElement();
}

SvxConfigPage::~SvxConfigPage()
{
    int cnt = m_xSaveInListBox->get_count();
    for(int i=0; i < cnt; ++i)
    {
        SaveInData *pData = weld::fromId<SaveInData*>(m_xSaveInListBox->get_id(i));
        delete pData;
    }
}

void SvxConfigPage::Reset( const SfxItemSet* )
{
    // If we haven't initialised our XMultiServiceFactory reference
    // then Reset is being called at the opening of the dialog.

    // Load menu configuration data for the module of the currently
    // selected document, for the currently selected document, and for
    // all other open documents of the same module type
    if ( !bInitialised )
    {
        sal_Int32 nPos = 0;
        uno::Reference < css::ui::XUIConfigurationManager > xCfgMgr;
        uno::Reference < css::ui::XUIConfigurationManager > xDocCfgMgr;

        uno::Reference< uno::XComponentContext > xContext(
            ::comphelper::getProcessComponentContext(), uno::UNO_SET_THROW );

        m_xFrame = GetFrame();
        m_aModuleId = GetFrameWithDefaultAndIdentify( m_xFrame );

        // replace %MODULENAME in the label with the correct module name
        uno::Reference< css::frame::XModuleManager2 > xModuleManager(
            css::frame::ModuleManager::create( xContext ));
        OUString aModuleName = SvxConfigPageHelper::GetUIModuleName( m_aModuleId, xModuleManager );

        uno::Reference< css::ui::XModuleUIConfigurationManagerSupplier >
            xModuleCfgSupplier( css::ui::theModuleUIConfigurationManagerSupplier::get(xContext) );

        // Set up data for module specific menus
        SaveInData* pModuleData = nullptr;

        try
        {
            xCfgMgr =
                xModuleCfgSupplier->getUIConfigurationManager( m_aModuleId );

            pModuleData = CreateSaveInData( xCfgMgr,
                                            uno::Reference< css::ui::XUIConfigurationManager >(),
                                            m_aModuleId,
                                            false );
        }
        catch ( container::NoSuchElementException& )
        {
        }

        if ( pModuleData != nullptr )
        {
            OUString sId(weld::toId(pModuleData));
            m_xSaveInListBox->append(sId, utl::ConfigManager::getProductName() + " " + aModuleName);
        }

        // try to retrieve the document based ui configuration manager
        OUString aTitle;
        uno::Reference< frame::XController > xController =
            m_xFrame->getController();
        if ( CanConfig( m_aModuleId ) && xController.is() )
        {
            uno::Reference< frame::XModel > xModel( xController->getModel() );
            if ( xModel.is() )
            {
                uno::Reference< css::ui::XUIConfigurationManagerSupplier >
                    xCfgSupplier( xModel, uno::UNO_QUERY );

                if ( xCfgSupplier.is() )
                {
                    xDocCfgMgr = xCfgSupplier->getUIConfigurationManager();
                }
                aTitle = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
            }
        }

        SaveInData* pDocData = nullptr;
        if ( xDocCfgMgr.is() )
        {
            pDocData = CreateSaveInData( xDocCfgMgr, xCfgMgr, m_aModuleId, true );

            if ( !pDocData->IsReadOnly() )
            {
                OUString sId(weld::toId(pDocData));
                m_xSaveInListBox->append(sId, aTitle);
                nPos = m_xSaveInListBox->get_count() - 1;
            }
        }

        // if an item to select has been passed in (eg. the ResourceURL for a
        // toolbar) then try to select the SaveInData entry that has that item
        bool bURLToSelectFound = false;
        if ( !m_aURLToSelect.isEmpty() )
        {
            if ( pDocData && pDocData->HasURL( m_aURLToSelect ) )
            {
                m_xSaveInListBox->set_active(nPos);
                pCurrentSaveInData = pDocData;
                bURLToSelectFound = true;
            }
            else if ( pModuleData && pModuleData->HasURL( m_aURLToSelect ) )
            {
                m_xSaveInListBox->set_active(0);
                pCurrentSaveInData = pModuleData;
                bURLToSelectFound = true;
            }
        }

        if ( !bURLToSelectFound )
        {
            // if the document has menu configuration settings select it
            // it the SaveIn listbox, otherwise select the module data
            if ( pDocData != nullptr && pDocData->HasSettings() )
            {
                m_xSaveInListBox->set_active(nPos);
                pCurrentSaveInData = pDocData;
            }
            else
            {
                m_xSaveInListBox->set_active(0);
                pCurrentSaveInData = pModuleData;
            }
        }

#ifdef DBG_UTIL
        DBG_ASSERT( pCurrentSaveInData, "SvxConfigPage::Reset(): no SaveInData" );
#endif

        if ( CanConfig( m_aModuleId ) )
        {
            // Load configuration for other open documents which have
            // same module type
            uno::Sequence< uno::Reference< frame::XFrame > > aFrameList;
            try
            {
                uno::Reference< frame::XDesktop2 > xFramesSupplier = frame::Desktop::create(
                    xContext );

                uno::Reference< frame::XFrames > xFrames =
                    xFramesSupplier->getFrames();

                aFrameList = xFrames->queryFrames(
                    frame::FrameSearchFlag::ALL & ~frame::FrameSearchFlag::SELF );

            }
            catchconst uno::Exception& )
            {
                DBG_UNHANDLED_EXCEPTION("cui.customize");
            }

            for (uno::Reference<frame::XFrame> const& xf : aFrameList)
            {
                if ( xf.is() && xf != m_xFrame )
                {
                    OUString aCheckId;
                    try{
                        aCheckId = xModuleManager->identify( xf );
                    } catch(const uno::Exception&)
                        { aCheckId.clear(); }

                    if ( m_aModuleId == aCheckId )
                    {
                        // try to get the document based ui configuration manager
                        OUString aTitle2;
                        uno::Reference< frame::XController > xController_ =
                            xf->getController();

                        if ( xController_.is() )
                        {
                            uno::Reference< frame::XModel > xModel(
                                xController_->getModel() );

                            if ( xModel.is() )
                            {
                                uno::Reference<
                                    css::ui::XUIConfigurationManagerSupplier >
                                        xCfgSupplier( xModel, uno::UNO_QUERY );

                                if ( xCfgSupplier.is() )
                                {
                                    xDocCfgMgr =
                                        xCfgSupplier->getUIConfigurationManager();
                                }
                                aTitle2 = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
                            }
                        }

                        if ( xDocCfgMgr.is() )
                        {
                            SaveInData* pData = CreateSaveInData( xDocCfgMgr, xCfgMgr, m_aModuleId, true );

                            if ( pData && !pData->IsReadOnly() )
                            {
                                OUString sId(weld::toId(pData));
                                m_xSaveInListBox->append(sId, aTitle2);
                            }
                        }
                    }
                }
            }
        }

        m_xSaveInListBox->connect_changed(
            LINK( this, SvxConfigPage, SelectSaveInLocation ) );

        bInitialised = true;

        Init();
    }
    else
    {
        if ( QueryReset() == RET_YES )
        {
            // Reset menu configuration for currently selected SaveInData
            GetSaveInData()->Reset();

            Init();
        }
    }
}

OUString SvxConfigPage::GetFrameWithDefaultAndIdentify( uno::Reference< frame::XFrame >& _inout_rxFrame )
{
    OUString sModuleID;
    try
    {
        const uno::Reference< uno::XComponentContext >& xContext(
            ::comphelper::getProcessComponentContext() );

        uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(
            xContext );

        if ( !_inout_rxFrame.is() )
            _inout_rxFrame = xDesktop->getActiveFrame();

        if ( !_inout_rxFrame.is() )
        {
            _inout_rxFrame = xDesktop->getCurrentFrame();
        }

        if ( !_inout_rxFrame.is())
        {
            if (SfxViewFrame* pViewFrame = SfxViewFrame::Current())
                _inout_rxFrame = pViewFrame->GetFrame().GetFrameInterface();
        }

        if ( !_inout_rxFrame.is() )
        {
            SAL_WARN( "cui.customize""SvxConfigPage::GetFrameWithDefaultAndIdentify(): no frame found!" );
            return sModuleID;
        }

        sModuleID = vcl::CommandInfoProvider::GetModuleIdentifier(_inout_rxFrame);
    }
    catchconst uno::Exception& )
    {
        DBG_UNHANDLED_EXCEPTION("cui.customize");
    }

    return sModuleID;
}

OUString SvxConfigPage::GetScriptURL() const
{
    OUString result;

    SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(m_xFunctions->get_selected_id());
    if (pData)
    {
        if  (   ( pData->nKind == SfxCfgKind::FUNCTION_SLOT ) ||
                ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT ) ||
                ( pData->nKind == SfxCfgKind::GROUP_STYLES )    )
        {
            result = pData->sCommand;
        }
    }

    return result;
}

OUString SvxConfigPage::GetSelectedDisplayName() const
{
    return m_xFunctions->get_selected_text();
}

bool SvxConfigPage::FillItemSet( SfxItemSet* )
{
    bool result = false;

    for (int i = 0, nCount = m_xSaveInListBox->get_count(); i < nCount; ++i)
    {
        OUString sId = m_xSaveInListBox->get_id(i);
        if (sId != notebookbarTabScope)
        {
            SaveInData* pData = weld::fromId<SaveInData*>(sId);
            result = pData->Apply();
        }
    }
    return result;
}

IMPL_LINK_NOARG(SvxConfigPage, SelectSaveInLocation, weld::ComboBox&, void)
{
    OUString sId = m_xSaveInListBox->get_active_id();
    if (sId != notebookbarTabScope)
        pCurrentSaveInData = weld::fromId<SaveInData*>(sId);
    Init();
}

void SvxConfigPage::ReloadTopLevelListBox( SvxConfigEntry const * pToSelect )
{
    int nSelectionPos = m_xTopLevelListBox->get_active();
    m_xTopLevelListBox->clear();

    if ( GetSaveInData() && GetSaveInData()->GetEntries() )
    {
        for (auto const& entryData : *GetSaveInData()->GetEntries())
        {
            OUString sId(weld::toId(entryData));
            m_xTopLevelListBox->append(sId, SvxConfigPageHelper::stripHotKey(entryData->GetName()));

            if (entryData == pToSelect)
                nSelectionPos = m_xTopLevelListBox->get_count() - 1;

            AddSubMenusToUI( SvxConfigPageHelper::stripHotKey( entryData->GetName() ), entryData );
        }
    }
#ifdef DBG_UTIL
    else
    {
        DBG_ASSERT( GetSaveInData(), "SvxConfigPage::ReloadTopLevelListBox(): no SaveInData" );
        DBG_ASSERT( GetSaveInData()->GetEntries() ,
            "SvxConfigPage::ReloadTopLevelListBox(): no SaveInData entries" );
    }
#endif

    nSelectionPos = (nSelectionPos != -1 && nSelectionPos < m_xTopLevelListBox->get_count()) ?
        nSelectionPos : m_xTopLevelListBox->get_count() - 1;

    m_xTopLevelListBox->set_active(nSelectionPos);
    SelectElement();
}

void SvxConfigPage::AddSubMenusToUI(
    std::u16string_view rBaseTitle, SvxConfigEntry const * pParentData )
{
    for (auto const& entryData : *pParentData->GetEntries())
    {
        if (entryData->IsPopup())
        {
            OUString subMenuTitle = OUString::Concat(rBaseTitle) + aMenuSeparatorStr + SvxConfigPageHelper::stripHotKey(entryData->GetName());

            OUString sId(weld::toId(entryData));
            m_xTopLevelListBox->append(sId, subMenuTitle);

            AddSubMenusToUI( subMenuTitle, entryData );
        }
    }
}

SvxEntries* SvxConfigPage::FindParentForChild(
    SvxEntries* pRootEntries, SvxConfigEntry* pChildData )
{
    for (auto const& entryData : *pRootEntries)
    {

        if (entryData == pChildData)
        {
            return pRootEntries;
        }
        else if (entryData->IsPopup())
        {
            SvxEntries* result =
                FindParentForChild( entryData->GetEntries(), pChildData );

            if ( result != nullptr )
            {
                return result;
            }
        }
    }
    return nullptr;
}

SvxConfigEntry *SvxConfigPage::CreateCommandFromSelection(const OUString &aURL)
{
    OUString aDisplayName;

    if ( aURL.isEmpty() ) {
        return nullptr;
    }

    auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aURL, m_aModuleId);

    if ( typeid(*pCurrentSaveInData) == typeid(ContextMenuSaveInData) )
        aDisplayName = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
    else if ( typeid(*pCurrentSaveInData) == typeid(MenuSaveInData) )
        aDisplayName = vcl::CommandInfoProvider::GetMenuLabelForCommand(aProperties);
    else
        aDisplayName = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);

    SvxConfigEntry* toret =
        new SvxConfigEntry( aDisplayName, aURL, false/*bParentData*/false );

    toret->SetUserDefined();

    if ( aDisplayName.isEmpty() )
        toret->SetName( GetSelectedDisplayName() );

    return toret;
}

bool SvxConfigPage::IsCommandInMenuList(const SvxConfigEntry *pEntryData,
                                        const SvxEntries *pEntries)
{
    bool toret = false;

    if ( pEntries != nullptr
      && pEntryData != nullptr )
    {
        for (auto const& entry : *pEntries)
        {
                if ( entry->GetCommand() == pEntryData->GetCommand() )
                {
                    toret = true;
                    break;
                }
        }
    }

    return toret;
}

int SvxConfigPage::AddFunction(int nTarget, bool bAllowDuplicates, bool bAfter)
{
    int toret = -1;
    OUString aURL = GetScriptURL();
    SvxConfigEntry* pParent = GetTopLevelSelection();

    if ( aURL.isEmpty() || pParent == nullptr )
    {
        return -1;
    }


    SvxConfigEntry * pNewEntryData = CreateCommandFromSelection( aURL );

    // check that this function is not already in the menu
    if ( !bAllowDuplicates
      && IsCommandInMenuList( pNewEntryData, pParent->GetEntries() )
    )
    {
        delete pNewEntryData;
    } else {
        toret = AppendEntry( pNewEntryData, nTarget, bAfter );
    }

    UpdateButtonStates();
    return toret;
}

int SvxConfigPage::AppendEntry(
    SvxConfigEntry* pNewEntryData,
    int nTarget, bool bAfter)
{
    SvxConfigEntry* pTopLevelSelection = GetTopLevelSelection();

    if (pTopLevelSelection == nullptr)
        return -1;

    // Grab the entries list for the currently selected menu
    SvxEntries* pEntries = pTopLevelSelection->GetEntries();

    int nNewEntry = -1;
    int nCurEntry =
        nTarget != -1 ? nTarget : m_xContentsListBox->get_selected_index();

    OUString sId(weld::toId(pNewEntryData));

    if (nCurEntry == -1 || nCurEntry == m_xContentsListBox->n_children() - 1)
    {
        pEntries->push_back( pNewEntryData );
        m_xContentsListBox->insert(-1, sId);
        nNewEntry = m_xContentsListBox->n_children() - 1;
    }
    else
    {
        SvxConfigEntry* pEntryData =
            weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nCurEntry));

        SvxEntries::iterator iter = pEntries->begin();
        SvxEntries::const_iterator end = pEntries->end();

        // Advance the iterator to the data for currently selected entry
        sal_uInt16 nPos = 0;
        while (*iter != pEntryData && ++iter != end)
        {
            ++nPos;
        }

        if (bAfter)
        {
            // Now step past it to the entry after the currently selected one
            ++iter;
            ++nPos;
        }

        // Now add the new entry to the UI and to the parent's list
        if ( iter != end )
        {
            pEntries->insert( iter, pNewEntryData );
            m_xContentsListBox->insert(nPos, sId);
            nNewEntry = nPos;
        }
    }

    if (nNewEntry != -1)
    {
        m_xContentsListBox->select(nNewEntry);
        m_xContentsListBox->scroll_to_row(nNewEntry);

        GetSaveInData()->SetModified();
        GetTopLevelSelection()->SetModified();
    }

    return nNewEntry;
}

namespace
{
    template<typename itertype> void TmplInsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView& rTreeView, itertype& rIter, SaveInData* pSaveInData,
                                                           VirtualDevice& rDropDown, bool bMenu)
    {
        OUString sId(weld::toId(pNewEntryData));

        rTreeView.set_id(rIter, sId);

        if (pNewEntryData->IsSeparator())
        {
            rTreeView.set_text(rIter, "----------------------------------", 0);
        }
        else
        {
            auto xImage = pSaveInData->GetImage(pNewEntryData->GetCommand());
            if (xImage.is())
                rTreeView.set_image(rIter, xImage, -1);
            OUString aName = SvxConfigPageHelper::stripHotKey( pNewEntryData->GetName() );
            rTreeView.set_text(rIter, aName, 0);
        }

        if (bMenu)  // menus
        {
            if (pNewEntryData->IsPopup() || pNewEntryData->GetStyle() & css::ui::ItemStyle::DROP_DOWN)
                rTreeView.set_image(rIter, rDropDown, 1);
            else
                rTreeView.set_image(rIter, css::uno::Reference<css::graphic::XGraphic>(), 1);
        }
    }
}

void SvxConfigPage::InsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView&&nbsp;rTreeView, int nPos, bool bMenu)
{
    TmplInsertEntryIntoUI<int>(pNewEntryData, rTreeView, nPos, GetSaveInData(),
                               m_xContentsListBox->get_dropdown_image(), bMenu);
}

void SvxConfigPage::InsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView&&nbsp;rTreeView, weld::TreeIter& rIter, bool bMenu)
{
    TmplInsertEntryIntoUI<weld::TreeIter>(pNewEntryData, rTreeView, rIter, GetSaveInData(),
                                          m_xContentsListBox->get_dropdown_image(), bMenu);
}

IMPL_LINK(SvxConfigPage, MoveHdl, weld::Button&, rButton, void)
{
    MoveEntry(&rButton == m_xMoveUpButton.get());
}

IMPL_LINK_NOARG(SvxConfigPage, FunctionDoubleClickHdl, weld::TreeView&, bool)
{
    if (m_xAddCommandButton->get_sensitive())
        m_xAddCommandButton->clicked();
    return true;
}

IMPL_LINK_NOARG(SvxConfigPage, SelectFunctionHdl, weld::TreeView&, void)
{
    // GetScriptURL() returns a non-empty string if a
    // valid command is selected on the left box
    OUString aSelectCommand = GetScriptURL();
    bool bIsValidCommand = !aSelectCommand.isEmpty();

    // Enable/disable Add and Remove buttons depending on current selection
    if (bIsValidCommand)
    {
        m_xAddCommandButton->set_sensitive(true);
        m_xRemoveCommandButton->set_sensitive(true);

        if (SfxHelp::IsHelpInstalled())
        {
            m_xDescriptionField->set_text(m_xFunctions->GetCommandHelpText());
        }
        else
        {
            SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(m_xFunctions->get_selected_id());
            if (pData)
            {
                bool bIsExperimental
                    = vcl::CommandInfoProvider::IsExperimental(pData->sCommand, m_aModuleId);

                OUString aExperimental = "\n" + CuiResId(RID_CUISTR_COMMANDEXPERIMENTAL);
                OUString aLabel = CuiResId(RID_CUISTR_COMMANDLABEL) + ": " + pData->sLabel + "\n";
                OUString aName = CuiResId(RID_CUISTR_COMMANDNAME) + ": " + pData->sCommand + "\n";
                OUString aTip = CuiResId(RID_CUISTR_COMMANDTIP) + ": " + pData->sTooltip;
                if (bIsExperimental)
                    m_xDescriptionField->set_text(aLabel + aName + aTip + aExperimental);
                else
                    m_xDescriptionField->set_text(aLabel + aName + aTip);
            }
        }
    }
    else
    {

        m_xAddCommandButton->set_sensitive(false);
        m_xRemoveCommandButton->set_sensitive(false);

        m_xDescriptionField->set_text(u""_ustr);
    }

    UpdateButtonStates();
}

IMPL_LINK_NOARG(SvxConfigPage, ImplUpdateDataHdl, Timer*, void)
{
    OUString aSearchTerm(m_xSearchEdit->get_text());
    m_xCommandCategoryListBox->categorySelected(m_xFunctions.get(), aSearchTerm, GetSaveInData());
    SelectFunctionHdl(m_xFunctions->get_widget());
}

IMPL_LINK_NOARG(SvxConfigPage, SearchUpdateHdl, weld::Entry&, void)
{
    m_aUpdateDataTimer.Start();
}

IMPL_LINK_NOARG(SvxConfigPage, FocusOut_Impl, weld::Widget&, void)
{
    if (m_aUpdateDataTimer.IsActive())
    {
        m_aUpdateDataTimer.Stop();
        m_aUpdateDataTimer.Invoke();
    }
}

void SvxConfigPage::MoveEntry(bool bMoveUp)
{
    weld::TreeView& rTreeView = m_xContentsListBox->get_widget();

    int nSourceEntry = rTreeView.get_selected_index();
    int nTargetEntry = -1;
    int nToSelect = -1;

    if (nSourceEntry == -1)
    {
        return;
    }

    if ( bMoveUp )
    {
        // Move Up is just a Move Down with the source and target reversed
        nTargetEntry = nSourceEntry;
        nSourceEntry = nTargetEntry - 1;
        nToSelect = nSourceEntry;
    }
    else
    {
        nTargetEntry = nSourceEntry + 1;
        nToSelect = nTargetEntry;
    }

    if (MoveEntryData(nSourceEntry, nTargetEntry))
    {
        rTreeView.swap(nSourceEntry, nTargetEntry);
        rTreeView.select(nToSelect);
        rTreeView.scroll_to_row(nToSelect);

        UpdateButtonStates();
    }
}

bool SvxConfigPage::MoveEntryData(int nSourceEntry, int nTargetEntry)
{
    //#i53677#
    if (nSourceEntry == -1 || nTargetEntry == -1)
    {
        return false;
    }

    // Grab the entries list for the currently selected menu
    SvxEntries* pEntries = GetTopLevelSelection()->GetEntries();

    SvxConfigEntry* pSourceData =
        weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nSourceEntry));

    SvxConfigEntry* pTargetData =
        weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nTargetEntry));

    if ( pSourceData == nullptr || pTargetData == nullptr )
        return false;

    // remove the source entry from our list
    SvxConfigPageHelper::RemoveEntry( pEntries, pSourceData );

    SvxEntries::iterator iter = pEntries->begin();
    SvxEntries::const_iterator end = pEntries->end();

    // advance the iterator to the position of the target entry
    while (*iter != pTargetData && ++iter != end) ;

    // insert the source entry at the position after the target
    pEntries->insert( ++iter, pSourceData );

    GetSaveInData()->SetModified();
    GetTopLevelSelection()->SetModified();

    return true;
}

SvxMainMenuOrganizerDialog::SvxMainMenuOrganizerDialog(
    weld::Window* pParent, SvxEntries* entries,
    SvxConfigEntry const * selection, bool bCreateMenu )
    : GenericDialogController(pParent, u"cui/ui/movemenu.ui"_ustr, u"MoveMenuDialog"_ustr)
    , m_xMenuBox(m_xBuilder->weld_widget(u"namebox"_ustr))
    , m_xMenuNameEdit(m_xBuilder->weld_entry(u"menuname"_ustr))
    , m_xMenuListBox(m_xBuilder->weld_tree_view(u"menulist"_ustr))
    , m_xMoveUpButton(m_xBuilder->weld_button(u"up"_ustr))
    , m_xMoveDownButton(m_xBuilder->weld_button(u"down"_ustr))
{
    m_xMenuListBox->set_size_request(-1, m_xMenuListBox->get_height_rows(12));

    // Copy the entries list passed in
    if ( entries != nullptr )
    {
        mpEntries.reset( new SvxEntries );
        for (auto const& entry : *entries)
        {
            m_xMenuListBox->append(weld::toId(entry),
                                   SvxConfigPageHelper::stripHotKey(entry->GetName()));
            mpEntries->push_back(entry);
            if (entry == selection)
            {
                m_xMenuListBox->select(m_xMenuListBox->n_children() - 1);
            }
        }
    }

    if ( bCreateMenu )
    {
        // Generate custom name for new menu
        OUString prefix = CuiResId( RID_CUISTR_NEW_MENU );

        OUString newname = SvxConfigPageHelper::generateCustomName( prefix, entries );
        OUString newurl = SvxConfigPageHelper::generateCustomMenuURL( mpEntries.get() );

        SvxConfigEntry* pNewEntryData =
            new SvxConfigEntry( newname, newurl, true/*bParentData*/false );
        pNewEntryData->SetName( newname );
        pNewEntryData->SetUserDefined();
        pNewEntryData->SetMain();

        m_sNewMenuEntryId = weld::toId(pNewEntryData);
        m_xMenuListBox->append(m_sNewMenuEntryId,
                               SvxConfigPageHelper::stripHotKey(pNewEntryData->GetName()));
        m_xMenuListBox->select(m_xMenuListBox->n_children() - 1);

        if (mpEntries)
            mpEntries->push_back(pNewEntryData);

        m_xMenuNameEdit->set_text(newname);
        m_xMenuNameEdit->connect_changed(LINK(this, SvxMainMenuOrganizerDialog, ModifyHdl));
    }
    else
    {
        // hide name label and textfield
        m_xMenuBox->hide();
        // change the title
        m_xDialog->set_title(CuiResId(RID_CUISTR_MOVE_MENU));
    }

    m_xMenuListBox->connect_selection_changed(LINK(this, SvxMainMenuOrganizerDialog, SelectHdl));

    m_xMoveUpButton->connect_clicked(LINK( this, SvxMainMenuOrganizerDialog, MoveHdl));
    m_xMoveDownButton->connect_clicked(LINK( this, SvxMainMenuOrganizerDialog, MoveHdl));

    UpdateButtonStates();
}

SvxMainMenuOrganizerDialog::~SvxMainMenuOrganizerDialog()
{
}

IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog, ModifyHdl, weld::Entry&, void)
{
    // if the Edit control is empty do not change the name
    if (m_xMenuNameEdit->get_text().isEmpty())
    {
        return;
    }

    SvxConfigEntry* pNewEntryData = weld::fromId<SvxConfigEntry*>(m_sNewMenuEntryId);
    pNewEntryData->SetName(m_xMenuNameEdit->get_text());

    const int nNewMenuPos = m_xMenuListBox->find_id(m_sNewMenuEntryId);
    const int nOldSelection = m_xMenuListBox->get_selected_index();
    m_xMenuListBox->remove(nNewMenuPos);
    m_xMenuListBox->insert(nNewMenuPos, pNewEntryData->GetName(), &m_sNewMenuEntryId, nullptr, nullptr);
    m_xMenuListBox->select(nOldSelection);
}

IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog, SelectHdl, weld::TreeView&, void)
{
    UpdateButtonStates();
}

void SvxMainMenuOrganizerDialog::UpdateButtonStates()
{
    // Disable Up and Down buttons depending on current selection
    const int nSelected = m_xMenuListBox->get_selected_index();
    m_xMoveUpButton->set_sensitive(nSelected > 0);
    m_xMoveDownButton->set_sensitive(nSelected != -1 && nSelected < m_xMenuListBox->n_children() - 1);
}

IMPL_LINK( SvxMainMenuOrganizerDialog, MoveHdl, weld::Button&, rButton, void )
{
    int nSourceEntry = m_xMenuListBox->get_selected_index();
    if (nSourceEntry == -1)
        return;

    int nTargetEntry;

    if (&rButton == m_xMoveDownButton.get())
    {
        nTargetEntry = nSourceEntry + 1;
    }
    else
    {
        // Move Up is just a Move Down with the source and target reversed
        nTargetEntry = nSourceEntry - 1;
    }

    OUString sId = m_xMenuListBox->get_id(nSourceEntry);
    OUString sEntry = m_xMenuListBox->get_text(nSourceEntry);
    m_xMenuListBox->remove(nSourceEntry);
    m_xMenuListBox->insert(nTargetEntry, sEntry, &sId, nullptr, nullptr);
    m_xMenuListBox->select(nTargetEntry);

    std::swap(mpEntries->at(nSourceEntry), mpEntries->at(nTargetEntry));

    UpdateButtonStates();
}

SvxConfigEntry* SvxMainMenuOrganizerDialog::GetSelectedEntry()
{
    const int nSelected(m_xMenuListBox->get_selected_index());
    if (nSelected == -1)
        return nullptr;
    return weld::fromId<SvxConfigEntry*>(m_xMenuListBox->get_id(nSelected));
}

SvxConfigEntry::SvxConfigEntry( OUString aDisplayName,
                                OUString aCommandURL, bool bPopup, bool bParentData )
    : nId( 1 )
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=91 G=93

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge