/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cfg.cxx,v $
 *
 *  $Revision: 1.23 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 20:38:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#pragma hdrstop

#ifndef _HELP_HXX //autogen
#include <vcl/help.hxx>
#endif
#ifndef _MSGBOX_HXX //autogen
#include <vcl/msgbox.hxx>
#endif
#ifndef _SV_DECOVIEW_HXX
#include <vcl/decoview.hxx>
#endif
#ifndef _SV_TOOLBOX_HXX
#include <vcl/toolbox.hxx>
#endif
#ifndef _SV_SCRBAR_HXX
#include <vcl/scrbar.hxx>
#endif

#include <sfx2/app.hxx>
#include <sfx2/sfxdlg.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/msg.hxx>
#include <sfx2/msgpool.hxx>
#include <sfx2/mnumgr.hxx>
#include <sfx2/macrconf.hxx>
#include <sfx2/minfitem.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/request.hxx>
#include <sfx2/filedlghelper.hxx>
#include <svtools/stritem.hxx>
#include <svtools/miscopt.hxx>
#include <toolkit/unohlp.hxx>

#include <algorithm>

#include "dialogs.hrc"
#include "cfg.hrc"
#include "helpid.hrc"

#include "cfg.hxx"
#include "eventdlg.hxx"
#include "dialmgr.hxx"
#include "svxdlg.hxx"

#ifndef _COMPHELPER_PROCESSFACTORY_HXX_
#include <comphelper/processfactory.hxx>
#endif
#ifndef _UNOTOOLS_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif
#ifndef _COM_SUN_STAR_UI_ITEMTYPE_HPP_
#include <com/sun/star/ui/ItemType.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_ITEMSTYLE_HPP_
#include <com/sun/star/ui/ItemStyle.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_XMODULEUICONFIGURATIONMANAGERSUPPLIER_HPP_
#include <com/sun/star/ui/XModuleUIConfigurationManagerSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XCONTROLLER_HPP_
#include <com/sun/star/frame/XController.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XDESKTOP_HPP_
#include <com/sun/star/frame/XDesktop.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_XUICONFIGURATION_HPP_
#include <com/sun/star/ui/XUIConfiguration.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_XUICONFIGURATIONLISTENER_HPP_
#include <com/sun/star/ui/XUIConfigurationListener.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_XUICONFIGURATIONMANAGERSUPPLIER_HPP_
#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_XUICONFIGURATIONPERSISTENCE_HPP_
#include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_XUICONFIGURATIONSTORAGE_HPP_
#include <com/sun/star/ui/XUIConfigurationStorage.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_XMODULEUICONFIGURATIONMANAGER_HPP_
#include <com/sun/star/ui/XModuleUIConfigurationManager.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_XUIELEMENT_HPP_
#include <com/sun/star/ui/XUIElement.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_UIElementType_HPP_
#include <com/sun/star/ui/UIElementType.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_IMAGETYPE_HPP_
#include <com/sun/star/ui/ImageType.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XLAYOUTMANAGER_HPP_
#include <com/sun/star/frame/XLayoutManager.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_DIALOGS_EXTENDEDFILEPICKERELEMENTIDS_HPP_
#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
#endif
#ifndef _COM_SUN_STAR_UI_DIALOGS_XFILEPICKERCONTROLACCESS_HPP_
#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XFRAMESSUPPLIER_HPP_
#include <com/sun/star/frame/XFramesSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XFRAMES_HPP_
#include <com/sun/star/frame/XFrames.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_FRAMESEARCHFLAG_HPP_
#include <com/sun/star/frame/FrameSearchFlag.hpp>
#endif

#define PRTSTR(x) rtl::OUStringToOString(x, RTL_TEXTENCODING_ASCII_US).pData->buffer

#define ENTRY_HEIGHT 16

static const char ITEM_DESCRIPTOR_COMMANDURL[]  = "CommandURL";
static const char ITEM_DESCRIPTOR_HELPURL[]     = "HelpURL";
static const char ITEM_DESCRIPTOR_CONTAINER[]   = "ItemDescriptorContainer";
static const char ITEM_DESCRIPTOR_LABEL[]       = "Label";
static const char ITEM_DESCRIPTOR_TYPE[]        = "Type";
static const char ITEM_DESCRIPTOR_STYLE[]       = "Style";
static const char ITEM_DESCRIPTOR_ISVISIBLE[]   = "IsVisible";
static const char ITEM_DESCRIPTOR_RESOURCEURL[] = "ResourceURL";
static const char ITEM_DESCRIPTOR_UINAME[]      = "UIName";

static const char ITEM_MENUBAR_URL[] = "private:resource/menubar/menubar";
static const char ITEM_TOOLBAR_URL[] = "private:resource/toolbar/";

static const char CUSTOM_TOOLBAR_STR[] = "custom_toolbar_";
static const char CUSTOM_MENU_STR[] = "vnd.openoffice.org:CustomMenu";

static const char __FAR_DATA pSeparatorStr[] =
    "----------------------------------";
static const char __FAR_DATA pMenuSeparatorStr[]    = " | ";

#ifdef MSC
#pragma warning (disable:4355)
#endif

using rtl::OUString;
namespace css = com::sun::star;
namespace uno = com::sun::star::uno;
namespace frame = com::sun::star::frame;
namespace lang = com::sun::star::lang;
namespace container = com::sun::star::container;
namespace beans = com::sun::star::beans;
namespace graphic = com::sun::star::graphic;

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

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

    OSL_TRACE("printPropertySet: %d properties", aPropDetails.getLength());

    for ( sal_Int32 i = 0; i < aPropDetails.getLength(); i++ )
    {
        OUString tmp;
        sal_Int32 ival;

        uno::Any a = xPropSet->getPropertyValue( aPropDetails[i].Name );

        if ( ( a >>= tmp ) /* && tmp.getLength() != 0 */ )
        {
            OSL_TRACE("%s: Got property: %s = %s",
                PRTSTR(prefix), PRTSTR(aPropDetails[i].Name), PRTSTR(tmp));
        }
        else if ( ( a >>= ival ) )
        {
            OSL_TRACE("%s: Got property: %s = %d",
                PRTSTR(prefix), PRTSTR(aPropDetails[i].Name), PRTSTR(tmp));
        }
        else
        {
            OSL_TRACE("%s: Got property: %s of type %s",
                PRTSTR(prefix), PRTSTR(aPropDetails[i].Name), PRTSTR(a.getValueTypeName()));
        }
    }
}

void printProperties(
    const OUString& prefix,
    const uno::Sequence< beans::PropertyValue >& aProp )
{
    for ( sal_Int32 i = 0; i < aProp.getLength(); i++ )
    {
        OUString tmp;

        aProp[i].Value >>= tmp;

        OSL_TRACE("%s: Got property: %s = %s",
            PRTSTR(prefix), PRTSTR(aProp[i].Name), PRTSTR(tmp));
    }
}

void printEntries(SvxEntries* entries)
{
    SvxEntries::const_iterator iter = entries->begin();

    for ( ; iter != entries->end(); iter++ )
    {
        SvxConfigEntry* entry = *iter;

        OSL_TRACE("printEntries: %s", PRTSTR(entry->GetName()));
    }
}

OUString
stripHotKey( const OUString& str )
{
    sal_Int32 index = str.indexOf( '~' );
    if ( index == -1 )
    {
        return str;
    }
    else
    {
        return str.replaceAt( index, 1, OUString() );
    }
}

OUString replaceSaveInName(
    const OUString& rMessage,
    const OUString& rSaveInName )
{
    OUString name;
    OUString placeholder = OUString::createFromAscii( "%SAVE IN SELECTION%" );

    sal_Int32 pos = rMessage.indexOf( placeholder );

    if ( pos != -1 )
    {
        name = rMessage.replaceAt(
            pos, placeholder.getLength(), rSaveInName );
    }
    else
    {
        // don't change the message
    }

    return name;
}

OUString
replaceSixteen( const OUString& str, sal_Int32 nReplacement )
{
    OUString result( str );
    OUString sixteen = OUString::valueOf( (sal_Int32)16 );
    OUString expected = OUString::valueOf( nReplacement );

    sal_Int32 len = sixteen.getLength();
    sal_Int32 index = result.indexOf( sixteen );

    while ( index != -1 )
    {
        result = result.replaceAt( index, len, expected );
        index = result.indexOf( sixteen, index );
    }

    return result;
}

OUString
generateCustomName(
    const OUString& prefix,
    SvxEntries* entries,
    sal_Int32 suffix = 1 )
{
    // find and replace the %n placeholder in the prefix string
    OUString name;
    OUString placeholder = OUString::createFromAscii( "%n" );

    sal_Int32 pos = prefix.indexOf(
        OUString::createFromAscii( "%n" ) );

    if ( pos != -1 )
    {
        name = prefix.replaceAt(
            pos, placeholder.getLength(), OUString::valueOf( suffix ) );
    }
    else
    {
        // no placeholder found so just append the suffix
        name = prefix + OUString::valueOf( suffix );
    }

    // now check is there is an already existing entry with this name
    SvxEntries::const_iterator iter = entries->begin();

    SvxConfigEntry* pEntry;
    while ( iter != entries->end() )
    {
        pEntry = *iter;

        if ( name.equals( pEntry->GetName() ) )
        {
            break;
        }
        iter++;
    }

    if ( iter != entries->end() )
    {
        // name already exists so try the next number up
        return generateCustomName( prefix, entries, ++suffix );
    }

    return name;
}

OUString
generateCustomURL(
    SvxEntries* entries,
    sal_Int32 suffix = 1 )
{
    OUString url = OUString::createFromAscii( ITEM_TOOLBAR_URL );
    url += OUString::createFromAscii( CUSTOM_TOOLBAR_STR );
    url += OUString::valueOf( suffix );

    // now check is there is an already existing entry with this url
    SvxEntries::const_iterator iter = entries->begin();

    SvxConfigEntry* pEntry;
    while ( iter != entries->end() )
    {
        pEntry = *iter;

        if ( url.equals( pEntry->GetCommand() ) )
        {
            break;
        }
        iter++;
    }

    if ( iter != entries->end() )
    {
        // url already exists so try the next number up
        return generateCustomURL( entries, ++suffix );
    }

    return url;
}

OUString
generateCustomMenuURL(
    SvxEntries* entries,
    sal_Int32 suffix = 1 )
{
    OUString url = OUString::createFromAscii( CUSTOM_MENU_STR );
    url += OUString::valueOf( suffix );

    // now check is there is an already existing entry with this url
    SvxEntries::const_iterator iter = entries->begin();

    SvxConfigEntry* pEntry;
    while ( iter != entries->end() )
    {
        pEntry = *iter;

        if ( url.equals( pEntry->GetCommand() ) )
        {
            break;
        }
        iter++;
    }

    if ( iter != entries->end() )
    {
        // url already exists so try the next number up
        return generateCustomMenuURL( entries, ++suffix );
    }

    return url;
}

static sal_Int16 theImageType =
    css::ui::ImageType::COLOR_NORMAL |
    css::ui::ImageType::SIZE_DEFAULT;

void InitImageType()
{
    theImageType =
        css::ui::ImageType::COLOR_NORMAL |
        css::ui::ImageType::SIZE_DEFAULT;

    sal_Int16 eOptSymbolSet = SvtMiscOptions().GetSymbolSet();

    if ( eOptSymbolSet == SFX_SYMBOLS_AUTO )
    {
        // Use system settings, we have to retrieve the toolbar icon size
        // from the Application class
        ULONG nStyleIconSize =
            Application::GetSettings().GetStyleSettings().GetToolbarIconSize();

        if ( nStyleIconSize == STYLE_TOOLBAR_ICONSIZE_LARGE )
            eOptSymbolSet = SFX_SYMBOLS_LARGE;
        else
            eOptSymbolSet = SFX_SYMBOLS_SMALL;
    }

    if ( eOptSymbolSet != SFX_SYMBOLS_SMALL )
    {
        theImageType |= css::ui::ImageType::SIZE_LARGE;
    }

    Window* topwin = Application::GetActiveTopWindow();
    if ( topwin != NULL &&
         topwin->GetDisplayBackground().GetColor().IsDark() )
    {
        theImageType |= css::ui::ImageType::COLOR_HIGHCONTRAST;
    }
}

sal_Int16 GetImageType()
{
    return theImageType;
}

void RemoveEntry( SvxEntries* pEntries, SvxConfigEntry* pChildEntry )
{
    SvxEntries::iterator iter = pEntries->begin();

    while ( iter != pEntries->end() )
    {
        if ( pChildEntry == *iter )
        {
            pEntries->erase( iter );
            break;
        }
        iter++;
    }
}

bool
SvxConfigPage::CanConfig( const OUString& aModuleId )
{
    OSL_TRACE("SupportsDocumentConfig: %s", PRTSTR(aModuleId));

    if ( aModuleId.equals( OUString::createFromAscii(
            "com.sun.star.script.BasicIDE" ) ) ||
         aModuleId.equals( OUString::createFromAscii(
            "com.sun.star.frame.Bibliography" ) ) ||
         aModuleId.equals( OUString::createFromAscii(
            "com.sun.star.sdb.OfficeDatabaseDocument" ) ) )
    {
        return FALSE;
    }
    return TRUE;
}

OUString GetModuleName( const OUString& aModuleId )
{
    if ( aModuleId.equalsAscii( "com.sun.star.text.TextDocument" ) ||
         aModuleId.equalsAscii( "com.sun.star.text.GlobalDocument" ) )
        return OUString::createFromAscii("Writer");
    else if ( aModuleId.equalsAscii( "com.sun.star.text.WebDocument" ) )
        return OUString::createFromAscii("Writer/Web");
    else if ( aModuleId.equalsAscii( "com.sun.star.drawing.DrawingDocument" ) )
        return OUString::createFromAscii("Draw");
    else if ( aModuleId.equalsAscii( "com.sun.star.presentation.PresentationDocument" ) )
        return OUString::createFromAscii("Impress");
    else if ( aModuleId.equalsAscii( "com.sun.star.sheet.SpreadsheetDocument" ) )
        return OUString::createFromAscii("Calc");
    else if ( aModuleId.equalsAscii( "com.sun.star.script.BasicIDE" ) )
        return OUString::createFromAscii("Basic");
    else if ( aModuleId.equalsAscii( "com.sun.star.formula.FormulaProperties" ) )
        return OUString::createFromAscii("Math");
    else if ( aModuleId.equalsAscii( "com.sun.star.sdb.RelationDesign" ) )
        return OUString::createFromAscii("Relation Design");
    else if ( aModuleId.equalsAscii( "com.sun.star.sdb.QueryDesign" ) )
        return OUString::createFromAscii("Query Design");
    else if ( aModuleId.equalsAscii( "com.sun.star.sdb.TableDesign" ) )
        return OUString::createFromAscii("Table Design");
    else if ( aModuleId.equalsAscii( "com.sun.star.sdb.DataSourceBrowser" ) )
        return OUString::createFromAscii("Data Source Browser" );
    else if ( aModuleId.equalsAscii( "com.sun.star.sdb.DatabaseDocument" ) )
        return OUString::createFromAscii("Database" );

    return ::rtl::OUString();
}

OUString GetUIModuleName( const OUString& aModuleId, const uno::Reference< css::frame::XModuleManager >& rModuleManager )
{
    OUString aModuleUIName;

    if ( rModuleManager.is() )
    {
        uno::Reference< css::container::XNameAccess > xNameAccess( rModuleManager, uno::UNO_QUERY );
        if ( xNameAccess.is() )
        {
            try
            {
                uno::Any a = xNameAccess->getByName( aModuleId );
                uno::Sequence< beans::PropertyValue > aSeq;

                if ( a >>= aSeq )
                {
                    OUString aUIName;
                    for ( sal_Int32 i = 0; i < aSeq.getLength(); i++ )
                    {
                        if ( aSeq[i].Name.equalsAscii( "ooSetupFactoryUIName" ))
                        {
                            aSeq[i].Value >>= aModuleUIName;
                            break;
                        }
                    }
                }
            }
            catch ( uno::RuntimeException& e )
            {
                throw e;
            }
            catch ( uno::Exception& )
            {
            }
        }
    }

    if ( aModuleUIName.getLength() == 0 )
        aModuleUIName = GetModuleName( aModuleId );

    return aModuleUIName;
}

bool GetMenuItemData(
    const uno::Reference< container::XIndexAccess >& rItemContainer,
    sal_Int32 nIndex,
    OUString& rCommandURL,
    OUString& rHelpURL,
    OUString& rLabel,
    sal_uInt16& rType,
    uno::Reference< container::XIndexAccess >& rSubMenu )
{
    try
    {
        uno::Sequence< beans::PropertyValue > aProp;
        if ( rItemContainer->getByIndex( nIndex ) >>= aProp )
        {
            for ( sal_Int32 i = 0; i < aProp.getLength(); i++ )
            {
                if ( aProp[i].Name.equalsAscii( ITEM_DESCRIPTOR_COMMANDURL ))
                {
                    aProp[i].Value >>= rCommandURL;
                }
                else if ( aProp[i].Name.equalsAscii( ITEM_DESCRIPTOR_HELPURL ))
                {
                    aProp[i].Value >>= rHelpURL;
                }
                else if ( aProp[i].Name.equalsAscii( ITEM_DESCRIPTOR_CONTAINER ))
                {
                    aProp[i].Value >>= rSubMenu;
                }
                else if ( aProp[i].Name.equalsAscii( ITEM_DESCRIPTOR_LABEL ))
                {
                    aProp[i].Value >>= rLabel;
                }
                else if ( aProp[i].Name.equalsAscii( ITEM_DESCRIPTOR_TYPE ))
                {
                    aProp[i].Value >>= rType;
                }
            }

            return TRUE;
        }
    }
    catch ( ::com::sun::star::lang::IndexOutOfBoundsException& )
    {
    }

    return FALSE;
}

bool GetToolbarItemData(
    const uno::Reference< container::XIndexAccess >& rItemContainer,
    sal_Int32 nIndex,
    OUString& rCommandURL,
    OUString& rHelpURL,
    OUString& rLabel,
    sal_uInt16& rType,
    sal_Bool& rIsVisible,
    sal_Int32& rStyle,
    uno::Reference< container::XIndexAccess >& rSubMenu )
{
    try
    {
        uno::Sequence< beans::PropertyValue > aProp;
        if ( rItemContainer->getByIndex( nIndex ) >>= aProp )
        {
            for ( sal_Int32 i = 0; i < aProp.getLength(); i++ )
            {
                if ( aProp[i].Name.equalsAscii( ITEM_DESCRIPTOR_COMMANDURL ))
                {
                    aProp[i].Value >>= rCommandURL;
                }
                if ( aProp[i].Name.equalsAscii( ITEM_DESCRIPTOR_STYLE ))
                {
                    aProp[i].Value >>= rStyle;
                }
                else if ( aProp[i].Name.equalsAscii( ITEM_DESCRIPTOR_HELPURL ))
                {
                    aProp[i].Value >>= rHelpURL;
                }
                else if (aProp[i].Name.equalsAscii(ITEM_DESCRIPTOR_CONTAINER))
                {
                    aProp[i].Value >>= rSubMenu;
                }
                else if ( aProp[i].Name.equalsAscii( ITEM_DESCRIPTOR_LABEL ))
                {
                    aProp[i].Value >>= rLabel;
                }
                else if ( aProp[i].Name.equalsAscii( ITEM_DESCRIPTOR_TYPE ))
                {
                    aProp[i].Value >>= rType;
                }
                else if (aProp[i].Name.equalsAscii(ITEM_DESCRIPTOR_ISVISIBLE))
                {
                    aProp[i].Value >>= rIsVisible;
                }
            }

            return sal_True;
        }
    }
    catch ( ::com::sun::star::lang::IndexOutOfBoundsException& )
    {
    }

    return sal_False;
}

uno::Sequence< beans::PropertyValue >
ConvertSvxConfigEntry(
    const uno::Reference< container::XNameAccess >& xCommandToLabelMap,
    const SvxConfigEntry* pEntry )
{
    static const OUString aDescriptorCommandURL (
        RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_COMMANDURL ) );

    static const OUString aDescriptorType(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_TYPE ) );

    static const OUString aDescriptorLabel(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_LABEL ) );

    static const OUString aDescriptorHelpURL(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_HELPURL ) );

    static const OUString aDescriptorContainer(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_CONTAINER ) );

    uno::Sequence< beans::PropertyValue > aPropSeq( 4 );

    aPropSeq[0].Name = aDescriptorCommandURL;
    aPropSeq[0].Value <<= rtl::OUString( pEntry->GetCommand() );

    aPropSeq[1].Name = aDescriptorType;
    aPropSeq[1].Value <<= css::ui::ItemType::DEFAULT;

    // If the name has not been changed and the name is the same as
    // in the default command to label map then the label can be stored
    // as an empty string.
    // It will be initialised again later using the command to label map.
    aPropSeq[2].Name = aDescriptorLabel;
    if ( pEntry->HasChangedName() == FALSE && pEntry->GetCommand().getLength() )
    {
        BOOL isDefaultName = FALSE;
        try
        {
            uno::Any a( xCommandToLabelMap->getByName( pEntry->GetCommand() ) );
            uno::Sequence< beans::PropertyValue > tmpPropSeq;
            if ( a >>= tmpPropSeq )
            {
                for ( sal_Int32 i = 0; i < tmpPropSeq.getLength(); i++ )
                {
                    if ( tmpPropSeq[i].Name.equals( aDescriptorLabel ) )
                    {
                        OUString tmpLabel;
                        tmpPropSeq[i].Value >>= tmpLabel;

                        if ( tmpLabel.equals( pEntry->GetName() ) )
                        {
                            isDefaultName = TRUE;
                        }

                        break;
                    }
                }
            }
        }
        catch ( container::NoSuchElementException& )
        {
            // isDefaultName is left as FALSE
        }

        if ( isDefaultName )
        {
            aPropSeq[2].Value <<= rtl::OUString();
        }
        else
        {
            aPropSeq[2].Value <<= rtl::OUString( pEntry->GetName() );
        }
    }
    else
    {
        aPropSeq[2].Value <<= rtl::OUString( pEntry->GetName() );
    }

    aPropSeq[3].Name = aDescriptorHelpURL;
    aPropSeq[3].Value <<= rtl::OUString( pEntry->GetHelpURL() );

    return aPropSeq;
}

uno::Sequence< beans::PropertyValue >
ConvertToolbarEntry(
    const uno::Reference< container::XNameAccess >& xCommandToLabelMap,
    const SvxConfigEntry* pEntry )
{
    static const OUString aDescriptorCommandURL (
        RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_COMMANDURL ) );

    static const OUString aDescriptorType(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_TYPE ) );

    static const OUString aDescriptorLabel(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_LABEL ) );

    static const OUString aDescriptorHelpURL(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_HELPURL ) );

    static const OUString aDescriptorContainer(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_CONTAINER ) );

    static const OUString aIsVisible(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_ISVISIBLE ) );

    uno::Sequence< beans::PropertyValue > aPropSeq( 5 );

    aPropSeq[0].Name = aDescriptorCommandURL;
    aPropSeq[0].Value <<= rtl::OUString( pEntry->GetCommand() );

    aPropSeq[1].Name = aDescriptorType;
    aPropSeq[1].Value <<= css::ui::ItemType::DEFAULT;

    // If the name has not been changed and the name is the same as
    // in the default command to label map then the label can be stored
    // as an empty string.
    // It will be initialised again later using the command to label map.
    aPropSeq[2].Name = aDescriptorLabel;
    if ( pEntry->HasChangedName() == FALSE && pEntry->GetCommand().getLength() )
    {
        BOOL isDefaultName = FALSE;
        try
        {
            uno::Any a( xCommandToLabelMap->getByName( pEntry->GetCommand() ) );
            uno::Sequence< beans::PropertyValue > tmpPropSeq;
            if ( a >>= tmpPropSeq )
            {
                for ( sal_Int32 i = 0; i < tmpPropSeq.getLength(); i++ )
                {
                    if ( tmpPropSeq[i].Name.equals( aDescriptorLabel ) )
                    {
                        OUString tmpLabel;
                        tmpPropSeq[i].Value >>= tmpLabel;

                        if ( tmpLabel.equals( pEntry->GetName() ) )
                        {
                            isDefaultName = TRUE;
                        }

                        break;
                    }
                }
            }
        }
        catch ( container::NoSuchElementException& )
        {
            // isDefaultName is left as FALSE
        }

        if ( isDefaultName )
        {
            aPropSeq[2].Value <<= rtl::OUString();
        }
        else
        {
            aPropSeq[2].Value <<= rtl::OUString( pEntry->GetName() );
        }
    }
    else
    {
        aPropSeq[2].Value <<= rtl::OUString( pEntry->GetName() );
    }

    aPropSeq[3].Name = aDescriptorHelpURL;
    aPropSeq[3].Value <<= rtl::OUString( pEntry->GetHelpURL() );

    aPropSeq[4].Name = aIsVisible;
    aPropSeq[4].Value <<= pEntry->IsVisible();

    return aPropSeq;
}

SfxTabPage *CreateSvxMenuConfigPage( Window *pParent, const SfxItemSet& rSet )
{
    return new SvxMenuConfigPage( pParent, rSet );
}

SfxTabPage *CreateKeyboardConfigPage( Window *pParent, const SfxItemSet& rSet )
{
       return SfxAbstractDialogFactory::CreateSfxAcceleratorConfigPage( pParent, rSet );
}

SfxTabPage *CreateSvxToolbarConfigPage( Window *pParent, const SfxItemSet& rSet )
{
    return new SvxToolbarConfigPage( pParent, rSet );
}

SfxTabPage *CreateSvxEventConfigPage( Window *pParent, const SfxItemSet& rSet )
{
    return new SvxEventConfigPage( pParent, rSet );
}

sal_Bool impl_showKeyConfigTabPage()
{
    static ::rtl::OUString SERVICENAME_MODULEMANAGER = ::rtl::OUString::createFromAscii("com.sun.star.frame.ModuleManager");
    static ::rtl::OUString SERVICENAME_DESKTOP       = ::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop"             );
    static ::rtl::OUString MODULEID_STARTMODULE      = ::rtl::OUString::createFromAscii("com.sun.star.frame.StartModule"         );

    try
    {
        css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR   = ::comphelper::getProcessServiceFactory();
        css::uno::Reference< css::frame::XFramesSupplier >     xDesktop(xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW);
        css::uno::Reference< css::frame::XFrame >              xFrame  = xDesktop->getActiveFrame();
        css::uno::Reference< css::frame::XModuleManager >     xMM     (xSMGR->createInstance(SERVICENAME_MODULEMANAGER), css::uno::UNO_QUERY_THROW);

        if (xMM.is() && xFrame.is())
        {
            ::rtl::OUString sModuleId = xMM->identify(xFrame);
            if (
                ( sModuleId.getLength()                 ) &&
                (!sModuleId.equals(MODULEID_STARTMODULE))
               )
               return sal_True;
        }
    }
    catch(const css::uno::Exception&)
        {}

    return sal_False;
}

/******************************************************************************
 *
 * 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(
    Window * pParent, const SfxItemSet* pSet )
    :
        SfxTabDialog( pParent,
            ResId( RID_SVXDLG_CUSTOMIZE, DIALOG_MGR() ), pSet )
{
    FreeResource();

    InitImageType();

    AddTabPage( RID_SVXPAGE_MENUS, CreateSvxMenuConfigPage, NULL );
    AddTabPage( RID_SVXPAGE_KEYBOARD, CreateKeyboardConfigPage, NULL );
    AddTabPage( RID_SVXPAGE_TOOLBARS, CreateSvxToolbarConfigPage, NULL );
    AddTabPage( RID_SVXPAGE_EVENTS, CreateSvxEventConfigPage, NULL );

    if (!impl_showKeyConfigTabPage())
        RemoveTabPage( RID_SVXPAGE_KEYBOARD );

    const SfxPoolItem* pItem =
        pSet->GetItem( pSet->GetPool()->GetWhich( SID_CONFIG ) );

    if ( pItem )
    {
        OUString text = ((const SfxStringItem*)pItem)->GetValue();

        if (text.indexOf(OUString::createFromAscii(ITEM_TOOLBAR_URL)) == 0)
        {
            SetCurPageId( RID_SVXPAGE_TOOLBARS );
        }
    }
}

SvxConfigDialog::~SvxConfigDialog()
{
}

short SvxConfigDialog::Ok()
{
    return SfxTabDialog::Ok();
}

void SvxConfigDialog::PageCreated( USHORT nId, SfxTabPage& rPage )
{
    switch ( nId )
    {
        case RID_SVXPAGE_MENUS:
            break;
        case RID_SVXPAGE_TOOLBARS:
            break;
        default:
            break;
    }
}

void SvxConfigDialog::ActivateTabPage( USHORT nSlotId )
{
}

/******************************************************************************
 *
 * 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 = NULL;

SaveInData::SaveInData(
    const uno::Reference< css::ui::XUIConfigurationManager >& xCfgMgr,
    const uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
    const OUString& aModuleId,
    bool isDocConfig )
        :
            m_xCfgMgr( xCfgMgr ),
            m_xParentCfgMgr( xParentCfgMgr ),
            bReadOnly( FALSE ),
            bDocConfig( isDocConfig ),
            bModified( FALSE )
{
    uno::Reference< beans::XPropertySet > xProps(
        ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY );

    xProps->getPropertyValue(
        OUString::createFromAscii( "DefaultContext" ))
            >>= m_xComponentContext;

    m_aSeparatorSeq.realloc( 1 );
    m_aSeparatorSeq[0].Name  = OUString(
        RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_TYPE ) );
    m_aSeparatorSeq[0].Value <<= css::ui::ItemType::SEPARATOR_LINE;

    if ( bDocConfig )
    {
        uno::Reference< css::ui::XUIConfigurationPersistence >
            xDocPersistence( GetConfigManager(), uno::UNO_QUERY );

        bReadOnly = xDocPersistence->isReadOnly();
    }

    m_xServiceManager = uno::Reference< lang::XMultiServiceFactory >(
        ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW );

    uno::Reference< container::XNameAccess > xNameAccess(
        m_xServiceManager->createInstance(
            OUString( RTL_CONSTASCII_USTRINGPARAM(
                "com.sun.star.frame.UICommandDescription" ) ) ),
        uno::UNO_QUERY );

    if ( xNameAccess.is() )
        xNameAccess->getByName( aModuleId ) >>= m_xCommandToLabelMap;

    if ( !m_xImgMgr.is() )
    {
        m_xImgMgr = uno::Reference< css::ui::XImageManager >(
            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 = uno::Reference< css::ui::XImageManager >(
                m_xParentCfgMgr->getImageManager(), uno::UNO_QUERY );
            xDefaultImgMgr = &m_xParentImgMgr;
        }
    }
}

uno::Reference< graphic::XGraphic > GetGraphic(
    const uno::Reference< css::ui::XImageManager >& xImageManager,
    const OUString& rCommandURL )
{
    uno::Reference< graphic::XGraphic > result;

    if ( xImageManager.is() )
    {
        // TODO handle large and high contrast graphics
        uno::Sequence< uno::Reference< graphic::XGraphic > > aGraphicSeq;

        uno::Sequence< OUString > aImageCmdSeq( 1 );
        aImageCmdSeq[0] = rCommandURL;

        try
        {
            aGraphicSeq =
                xImageManager->getImages( GetImageType(), aImageCmdSeq );

            if ( aGraphicSeq.getLength() > 0 )
            {
                result =  aGraphicSeq[0];
            }
        }
        catch ( uno::Exception& )
        {
            // will return empty XGraphic
        }
    }

    return result;
}

Image SaveInData::GetImage( const OUString& rCommandURL )
{
    Image aImage;

    uno::Reference< graphic::XGraphic > xGraphic =
        GetGraphic( m_xImgMgr, rCommandURL );

    if ( xGraphic.is() )
    {
        aImage = Image( xGraphic );
    }
    else if ( xDefaultImgMgr != NULL && (*xDefaultImgMgr).is() )
    {
        xGraphic = GetGraphic( (*xDefaultImgMgr), rCommandURL );

        if ( xGraphic.is() )
        {
            aImage = Image( xGraphic );
        }
    }

    return aImage;
}

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 ( com::sun::star::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 = NULL;

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 ),
        pRootEntry( 0 ),
        m_aDescriptorContainer(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_CONTAINER ) ),
        m_aMenuResourceURL(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_MENUBAR_URL ) )
{
    try
    {
        OUString url( RTL_CONSTASCII_USTRINGPARAM( ITEM_MENUBAR_URL ) );
        m_xMenuSettings = GetConfigManager()->getSettings( url, sal_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()
{
    if ( pRootEntry != NULL )
    {
        delete pRootEntry;
    }
}

SvxEntries*
MenuSaveInData::GetEntries()
{
    if ( pRootEntry == NULL )
    {
        pRootEntry = new SvxConfigEntry(
            String::CreateFromAscii("MainMenus"), String(), TRUE );

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

    return pRootEntry->GetEntries();
}

void
MenuSaveInData::SetEntries( SvxEntries* pNewEntries )
{
    // delete old menu hierarchy first
    if ( pRootEntry != NULL )
    {
        delete pRootEntry->GetEntries();
    }

    // now set new menu hierarchy
    pRootEntry->SetEntries( pNewEntries );
}

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

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

        sal_uInt16 nType( css::ui::ItemType::DEFAULT );

        bool bItem = GetMenuItemData( xMenuSettings, nIndex,
            aCommandURL, aHelpURL, aLabel, nType, xSubMenu );

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

                // If custom label not set retrieve it from the command
                // to info service
                if ( aLabel.equals( OUString() ) )
                {
                    uno::Sequence< beans::PropertyValue > aPropSeq;
                    if ( a >>= aPropSeq )
                    {
                        for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
                        {
                            if ( aPropSeq[i].Name.equalsAscii( ITEM_DESCRIPTOR_LABEL ) )
                            {
                                aPropSeq[i].Value >>= aLabel;
                                break;
                            }
                        }
                    }
                }

                if ( xSubMenu.is() )
                {
                    // popup menu
                    SvxConfigEntry* pEntry = new SvxConfigEntry(
                        aLabel, aCommandURL, TRUE );

                    pEntry->SetUserDefined( bIsUserDefined );
                    pEntry->SetHelpURL( aHelpURL );

                    pEntries->push_back( pEntry );

                    OUString subMenuTitle( rBaseTitle );

                    if ( subMenuTitle.getLength() != 0 )
                    {
                        subMenuTitle +=
                            OUString::createFromAscii(pMenuSeparatorStr);
                    }
                    else
                    {
                        pEntry->SetMain( TRUE );
                    }

                    subMenuTitle += stripHotKey( aLabel );

                    LoadSubMenus( xSubMenu, subMenuTitle, pEntry );
                }
                else
                {
                    SvxConfigEntry* pEntry = new SvxConfigEntry(
                        aLabel, aCommandURL, FALSE );
                    pEntry->SetUserDefined( bIsUserDefined );
                    pEntry->SetHelpURL( aHelpURL );
                    pEntries->push_back( pEntry );
                }
            }
            else
            {
                SvxConfigEntry* pEntry = new SvxConfigEntry;
                pEntry->SetUserDefined( bIsUserDefined );
                pEntries->push_back( pEntry );
            }
        }
    }
    return true;
}

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

    if ( IsModified() )
    {
        // Apply new menu bar structure to our settings container
        m_xMenuSettings = uno::Reference< container::XIndexAccess >(
            GetConfigManager()->createSettings(), uno::UNO_QUERY );

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

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

        Apply( pRootEntry, xIndexContainer, xFactory, NULL );

        try
        {
            if ( GetConfigManager()->hasSettings( m_aMenuResourceURL ) )
            {
                GetConfigManager()->replaceSettings(
                    m_aMenuResourceURL, m_xMenuSettings );
            }
            else
            {
                GetConfigManager()->insertSettings(
                    m_aMenuResourceURL, m_xMenuSettings );
            }
        }
        catch ( container::NoSuchElementException& )
        {
            OSL_TRACE("caught container::NoSuchElementException saving settings");
        }
        catch ( com::sun::star::io::IOException& )
        {
            OSL_TRACE("caught IOException saving settings");
        }
        catch ( com::sun::star::uno::Exception& )
        {
            OSL_TRACE("caught some other exception saving settings");
        }

        SetModified( FALSE );

        result = PersistChanges( GetConfigManager() );
    }

    return result;
}

void MenuSaveInData::Apply(
    SvxConfigEntry* pRootEntry,
    uno::Reference< container::XIndexContainer >& rMenuBar,
    uno::Reference< lang::XSingleComponentFactory >& rFactory,
    SvLBoxEntry *pParentEntry )
{
    SvxEntries::const_iterator iter = GetEntries()->begin();
    SvxEntries::const_iterator end = GetEntries()->end();

    for ( ; iter != end; iter++ )
    {
        SvxConfigEntry* pEntryData = *iter;

        uno::Sequence< beans::PropertyValue > aPropValueSeq =
            ConvertSvxConfigEntry( m_xCommandToLabelMap, pEntryData );

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

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

void MenuSaveInData::ApplyMenu(
    uno::Reference< container::XIndexContainer >& rMenuBar,
    uno::Reference< lang::XSingleComponentFactory >& rFactory,
    SvxConfigEntry* pMenuData )
{
    SvxEntries::const_iterator iter = pMenuData->GetEntries()->begin();
    SvxEntries::const_iterator end = pMenuData->GetEntries()->end();

    for ( ; iter != end; iter++ )
    {
        SvxConfigEntry* pEntry = *iter;

        if ( pEntry->IsPopup() )
        {
            uno::Sequence< beans::PropertyValue > aPropValueSeq =
                ConvertSvxConfigEntry( m_xCommandToLabelMap, pEntry );

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

            sal_Int32 nIndex = aPropValueSeq.getLength();
            aPropValueSeq.realloc( nIndex + 1 );
            aPropValueSeq[nIndex].Name = m_aDescriptorContainer;
            aPropValueSeq[nIndex].Value <<= xSubMenuBar;

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

            ApplyMenu( xSubMenuBar, rFactory, pEntry );
        }
        else if ( pEntry->IsSeparator() )
        {
            rMenuBar->insertByIndex(
                rMenuBar->getCount(), uno::makeAny( m_aSeparatorSeq ));
        }
        else
        {
            uno::Sequence< beans::PropertyValue > aPropValueSeq =
                ConvertSvxConfigEntry( m_xCommandToLabelMap, pEntry );

            if ( pEntry->GetCommand().equalsAscii( ".uno:FormatMenu" ))
            {
                // Special popup menu "Format". It must be an empty popup menu!
                uno::Reference< lang::XSingleComponentFactory >
                    xFactory( rMenuBar, uno::UNO_QUERY );

                uno::Reference< container::XIndexContainer >
                    xSubMenuBar( xFactory->createInstanceWithContext(
                        m_xComponentContext ), uno::UNO_QUERY );

                sal_Int32 nIndex = aPropValueSeq.getLength();
                aPropValueSeq.realloc( nIndex + 1 );
                aPropValueSeq[nIndex].Name = m_aDescriptorContainer;
                aPropValueSeq[nIndex].Value <<= xSubMenuBar;
            }

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

void
MenuSaveInData::Reset()
{
    GetConfigManager()->reset();

    delete pRootEntry;
    pRootEntry = NULL;

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

class PopupPainter : public SvLBoxString
{
public:
    PopupPainter( SvLBoxEntry* pEntry, const String& rStr )
        : SvLBoxString( pEntry, 0, rStr )
    { }

    ~PopupPainter() { }

    void Paint( const Point& rPos, SvLBox& rOutDev,
        USHORT nViewDataEntryFlags, SvLBoxEntry* pEntry )
    {
        SvLBoxString::Paint( rPos, rOutDev, nViewDataEntryFlags, pEntry );

        Color aOldFillColor = rOutDev.GetFillColor();

        SvTreeListBox* pTreeBox = static_cast< SvTreeListBox* >( &rOutDev );
        long nX = pTreeBox->GetSizePixel().Width();

        ScrollBar* pVScroll = pTreeBox->GetVScroll();
        if ( pVScroll->IsVisible() )
        {
            nX -= pVScroll->GetSizePixel().Width();
        }

        SvViewDataItem* pItem = rOutDev.GetViewDataItem( pEntry, this );
        nX -= pItem->aSize.Height();

        long nSize = pItem->aSize.Height() / 2;
        long nHalfSize = nSize / 2;
        long nY = rPos.Y() + nHalfSize;

        if ( aOldFillColor == COL_WHITE )
        {
            rOutDev.SetFillColor( Color( COL_BLACK ) );
        }
        else
        {
            rOutDev.SetFillColor( Color( COL_WHITE ) );
        }

        long n = 0;
        while ( n <= nHalfSize )
        {
            rOutDev.DrawRect( Rectangle( nX+n, nY+n, nX+n, nY+nSize-n ) );
            n++;
        }

        rOutDev.SetFillColor( aOldFillColor );
    }
};

/******************************************************************************
 *
 * 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(
    Window* pParent, const ResId& rResId)
    : SvTreeListBox( pParent, rResId )
    , pPage( (SvxMenuConfigPage*) pParent )
    , m_bIsInternalDrag( FALSE )
{
    SetWindowBits(
        GetStyle() | WB_CLIPCHILDREN | WB_HSCROLL | WB_HIDESELECTION );

    SetSpaceBetweenEntries( 3 );
    SetEntryHeight( ENTRY_HEIGHT );

    SetHighlightRange();
    SetSelectionMode(SINGLE_SELECTION);

    SetDragDropMode( SV_DRAGDROP_CTRL_MOVE  |
                     SV_DRAGDROP_APP_COPY   |
                     SV_DRAGDROP_ENABLE_TOP |
                     SV_DRAGDROP_APP_DROP);
}

SvxMenuEntriesListBox::~SvxMenuEntriesListBox()
{
    // do nothing
}

// drag and drop support
DragDropMode SvxMenuEntriesListBox::NotifyStartDrag(
    TransferDataContainer& aTransferDataContainer, SvLBoxEntry* pEntry )
{
    m_bIsInternalDrag = TRUE;
    return GetDragDropMode();
}

void SvxMenuEntriesListBox::DragFinished( sal_Int8 nDropAction )
{
    m_bIsInternalDrag = FALSE;
}

sal_Int8 SvxMenuEntriesListBox::AcceptDrop( const AcceptDropEvent& rEvt )
{
    if ( m_bIsInternalDrag )
    {
        // internal copy isn't allowed!
        if ( rEvt.mnAction == DND_ACTION_COPY )
            return DND_ACTION_NONE;
        else
            return SvTreeListBox::AcceptDrop( rEvt );
    }

    // Always do COPY instead of MOVE if D&D comes from outside!
    AcceptDropEvent aNewAcceptDropEvent( rEvt );
    aNewAcceptDropEvent.mnAction = DND_ACTION_COPY;
    return SvTreeListBox::AcceptDrop( aNewAcceptDropEvent );
}

BOOL SvxMenuEntriesListBox::NotifyAcceptDrop( SvLBoxEntry* )
{
    return TRUE;
}

BOOL SvxMenuEntriesListBox::NotifyMoving(
    SvLBoxEntry* pTarget, SvLBoxEntry* pSource,
    SvLBoxEntry*& rpNewParent, ULONG& rNewChildPos)
{
    // only try to do a move if we are dragging within the list box
    if ( m_bIsInternalDrag )
    {
        if ( pPage->MoveEntryData( pSource, pTarget ) == TRUE )
        {
            SvTreeListBox::NotifyMoving(
                pTarget, pSource, rpNewParent, rNewChildPos );
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    }
    else
    {
        return NotifyCopying( pTarget, pSource, rpNewParent, rNewChildPos );
    }
}

BOOL SvxMenuEntriesListBox::NotifyCopying(
    SvLBoxEntry* pTarget, SvLBoxEntry* pSource,
    SvLBoxEntry*& rpNewParent, ULONG& rNewChildPos)
{
    if ( !m_bIsInternalDrag )
    {
        // if the target is NULL then add function to the start of the list
        pPage->AddFunction( pTarget, pTarget == NULL );

        // AddFunction already adds the listbox entry so return FALSE
        // to stop another listbox entry being added
        return FALSE;
    }

    // Copying is only allowed from external controls, not within the listbox
    return FALSE;
}

void SvxMenuEntriesListBox::KeyInput( const KeyEvent& rKeyEvent )
{
    KeyCode keycode = rKeyEvent.GetKeyCode();

    // support DELETE for removing the current entry
    if ( keycode == KEY_DELETE )
    {
        pPage->DeleteSelectedContent();
    }
    // support CTRL+UP and CTRL+DOWN for moving selected entries
    else if ( keycode.GetCode() == KEY_UP && keycode.IsMod1() )
    {
        pPage->MoveEntry( TRUE );
    }
    else if ( keycode.GetCode() == KEY_DOWN && keycode.IsMod1() )
    {
        pPage->MoveEntry( FALSE );
    }
    else
    {
        // pass on to superclass
        SvTreeListBox::KeyInput( rKeyEvent );
    }
}

/******************************************************************************
 *
 * 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(
    Window *pParent, const SfxItemSet& rSet )
    :
    SfxTabPage( pParent, ResId( RID_SVXPAGE_MENUS, DIALOG_MGR()), rSet ),
    aTopLevelSeparator( this, ResId( GRP_MENUS ) ),
    aTopLevelLabel( this, ResId( FT_MENUS ) ),
    aTopLevelListBox( this, ResId( LB_MENUS ) ),
    aNewTopLevelButton( this, ResId( BTN_NEW ) ),
    aModifyTopLevelButton( this, ResId( BTN_CHANGE ) ),
    aContentsSeparator( this, ResId( GRP_MENU_SEPARATOR ) ),
    aContentsLabel( this, ResId( GRP_MENU_ENTRIES ) ),
    aContentsListBox( 0 ),
    aAddCommandsButton( this, ResId( BTN_ADD_COMMANDS ) ),
    aModifyCommandButton( this, ResId( BTN_CHANGE_ENTRY ) ),
    aMoveUpButton( this, ResId( BTN_UP ) ),
    aMoveDownButton( this, ResId( BTN_DOWN ) ),
    aSaveInText( this, ResId( TXT_SAVEIN ) ),
    aSaveInListBox( this, ResId( LB_SAVEIN ) ),
    aDescriptionLine( this, ResId( GRP_DESCRIPTION ) ),
    aDescriptionText( this, ResId( TXT_DESCRIPTION ) ),
    pCurrentSaveInData( 0 ),
    pSelectorDlg( 0 ),
    bInitialised( FALSE )
{
}

SvxConfigPage::~SvxConfigPage()
{
}

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 )
    {
        USHORT nPos = 0;
        uno::Reference < css::ui::XUIConfigurationManager > xCfgMgr;
        uno::Reference < css::ui::XUIConfigurationManager > xDocCfgMgr;

        uno::Reference< lang::XMultiServiceFactory > xServiceManager(
            ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW );

        uno::Reference< frame::XFramesSupplier > xFramesSupplier(
            xServiceManager->createInstance(
                OUString( RTL_CONSTASCII_USTRINGPARAM(
                    "com.sun.star.frame.Desktop" ) ) ),
            uno::UNO_QUERY );

        m_xFrame = xFramesSupplier->getActiveFrame();
        if ( !m_xFrame.is() )
        {
            uno::Reference< frame::XDesktop > xDesktop( xFramesSupplier, uno::UNO_QUERY );
            m_xFrame = xDesktop->getCurrentFrame();
            if ( !m_xFrame.is() )
                m_xFrame = SfxViewFrame::Current()->GetFrame()->GetFrameInterface();
        }

        uno::Reference< css::frame::XModuleManager > xModuleManager(
            xServiceManager->createInstance(
                OUString( RTL_CONSTASCII_USTRINGPARAM(
                    "com.sun.star.frame.ModuleManager" ) ) ),
            uno::UNO_QUERY );

        OUString aModuleId;
        try
        {
            aModuleId = xModuleManager->identify( m_xFrame );
        }
        catch ( const uno::Exception& )
        {
            aModuleId = ::rtl::OUString();
        }

        // replace %MODULENAME in the label with the correct module name
        OUString aModuleName = GetUIModuleName( aModuleId, xModuleManager );

        OUString title = aTopLevelSeparator.GetText();
        OUString aSearchString = OUString::createFromAscii( "%MODULENAME" );
        sal_Int32 index = title.indexOf( aSearchString );

        if ( index != -1 )
        {
            title = title.replaceAt(
                index, aSearchString.getLength(), aModuleName );
            aTopLevelSeparator.SetText( title );
        }

        if ( !m_xFrame.is() )
        {
            DBG_ERRORFILE( "SvxConfigPage::Reset(): no active frame" );
            return;
        }

        uno::Reference< css::ui::XModuleUIConfigurationManagerSupplier >
            xModuleCfgSupplier( xServiceManager->createInstance(
                OUString( RTL_CONSTASCII_USTRINGPARAM(
            "com.sun.star.ui.ModuleUIConfigurationManagerSupplier" ))),
            uno::UNO_QUERY );

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

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

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

        if ( pModuleData != NULL )
        {
            OUString label;
            utl::ConfigManager::GetDirectConfigProperty(
                utl::ConfigManager::PRODUCTNAME ) >>= label;
            label += OUString::createFromAscii( " " );
            label += aModuleName;

            nPos = aSaveInListBox.InsertEntry( label );
            aSaveInListBox.SetEntryData( nPos, pModuleData );
        }

        // try to retrieve the document based ui configuration manager
        OUString aTitle;
        uno::Reference< frame::XController > xController =
            m_xFrame->getController();
        if ( CanConfig( 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();
                }
                SvxScriptSelectorDialog::GetDocTitle( xModel, aTitle );
            }
        }

        SaveInData* pDocData = NULL;
        if ( xDocCfgMgr.is() )
        {
            pDocData = CreateSaveInData( xDocCfgMgr, xCfgMgr, aModuleId, TRUE );

            if ( !pDocData->IsReadOnly() )
            {
                nPos = aSaveInListBox.InsertEntry( aTitle );
                aSaveInListBox.SetEntryData( nPos, pDocData );
            }
        }

        // 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.getLength() != 0 )
        {
            if ( pDocData != NULL && pDocData->HasURL( m_aURLToSelect ) )
            {
                aSaveInListBox.SelectEntryPos( nPos, TRUE );
                pCurrentSaveInData = pDocData;
                bURLToSelectFound = TRUE;
            }
            else if ( pModuleData->HasURL( m_aURLToSelect ) )
            {
                aSaveInListBox.SelectEntryPos( 0, TRUE );
                pCurrentSaveInData = pModuleData;
                bURLToSelectFound = TRUE;
            }
        }

        if ( bURLToSelectFound == FALSE )
        {
            // if the document has menu configuration settings select it
            // it the SaveIn listbox, otherwise select the module data
            if ( pDocData != NULL && pDocData->HasSettings() )
            {
                aSaveInListBox.SelectEntryPos( nPos, TRUE );
                pCurrentSaveInData = pDocData;
            }
            else
            {
                aSaveInListBox.SelectEntryPos( 0, TRUE );
                pCurrentSaveInData = pModuleData;
            }
        }

        if ( CanConfig( aModuleId ) )
        {
            // Load configuration for other open documents which have
            // same module type
            uno::Reference< frame::XFrames > xFrames =
                xFramesSupplier->getFrames();

            uno::Sequence< uno::Reference< frame::XFrame > >
                xFrameList = xFrames->queryFrames(
                    frame::FrameSearchFlag::ALL & ~frame::FrameSearchFlag::SELF );

            for ( sal_Int32 i = 0; i < xFrameList.getLength(); i++ )
            {
                SaveInData* pData = NULL;
                uno::Reference < frame::XFrame > xf = xFrameList[i];

                if ( xf.is() && xf != m_xFrame )
                {
                    OUString aCheckId;
                    try{
                        aCheckId = xModuleManager->identify( xf );
                    } catch(const uno::Exception&)
                        { aCheckId = ::rtl::OUString(); }

                    if ( aModuleId.equals( 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();
                                }
                                SvxScriptSelectorDialog::GetDocTitle(
                                    xModel, aTitle2 );
                            }
                        }

                        if ( xDocCfgMgr.is() )
                        {
                            pData = CreateSaveInData( xDocCfgMgr, xCfgMgr, aModuleId, TRUE );

                            if ( pData && !pData->IsReadOnly() )
                            {
                                nPos = aSaveInListBox.InsertEntry( aTitle2 );
                                aSaveInListBox.SetEntryData( nPos, pData );
                            }
                        }
                    }
                }
            }
        }

        aSaveInListBox.SetSelectHdl(
            LINK( this, SvxConfigPage, SelectSaveInLocation ) );

        bInitialised = TRUE;

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

            Init();
        }
    }
}

BOOL SvxConfigPage::FillItemSet( SfxItemSet& )
{
    bool result = FALSE;

    for ( USHORT i = 0 ; i < aSaveInListBox.GetEntryCount(); i++ )
    {
        SaveInData* pData =
            (SaveInData*) aSaveInListBox.GetEntryData( i );

        result = pData->Apply();
    }
    return result;
}

void SvxConfigPage::PositionContentsListBox()
{
    if ( aContentsListBox == NULL )
    {
        return;
    }

    Point p, newp;
    Size s, news;
    long x, y, width, height;

    // x and width is same as aTopLevelListBox
    x = aTopLevelListBox.GetPosPixel().X();
    width = aTopLevelListBox.GetSizePixel().Width();

    // y is same as aAddCommandsButton
    y = aAddCommandsButton.GetPosPixel().Y();

    // get gap between aAddCommandsButton and aContentsSeparator
    p = aContentsSeparator.GetPosPixel();
    s = aContentsSeparator.GetSizePixel();
    long gap = y - ( p.Y() + s.Height() );

    height = aSaveInListBox.GetPosPixel().Y() - y - gap;

    aContentsListBox->SetPosPixel( Point( x, y ) );
    aContentsListBox->SetSizePixel( Size( width, height ) );
}

IMPL_LINK( SvxConfigPage, SelectSaveInLocation, ListBox *, pBox )
{
    pCurrentSaveInData = (SaveInData*) aSaveInListBox.GetEntryData(
            aSaveInListBox.GetSelectEntryPos());

    Init();
    return 1;
}

void SvxConfigPage::ReloadTopLevelListBox( SvxConfigEntry* pToSelect )
{
    USHORT nSelectionPos = aTopLevelListBox.GetSelectEntryPos();
    aTopLevelListBox.Clear();

    SvxEntries::const_iterator iter =
        GetSaveInData()->GetEntries()->begin();

    SvxEntries::const_iterator end =
        GetSaveInData()->GetEntries()->end();

    for ( ; iter != end; iter++ )
    {
        SvxConfigEntry* pEntryData = *iter;

        USHORT nPos = aTopLevelListBox.InsertEntry(
            stripHotKey( pEntryData->GetName() ) );

        aTopLevelListBox.SetEntryData( nPos, pEntryData );

        if ( pEntryData == pToSelect )
        {
            nSelectionPos = nPos;
        }

        AddSubMenusToUI( stripHotKey( pEntryData->GetName() ), pEntryData );
    }

    nSelectionPos = nSelectionPos < aTopLevelListBox.GetEntryCount() ?
        nSelectionPos : aTopLevelListBox.GetEntryCount() - 1;

    aTopLevelListBox.SelectEntryPos( nSelectionPos, TRUE );
    aTopLevelListBox.GetSelectHdl().Call( this );
}

void SvxConfigPage::AddSubMenusToUI(
    const String& rBaseTitle, SvxConfigEntry* pParentData )
{
    SvxEntries::const_iterator iter = pParentData->GetEntries()->begin();
    SvxEntries::const_iterator end = pParentData->GetEntries()->end();

    for ( ; iter != end; iter++ )
    {
        SvxConfigEntry* pEntryData = *iter;

        if ( pEntryData->IsPopup() )
        {
            OUString subMenuTitle( rBaseTitle );
            subMenuTitle += OUString::createFromAscii( pMenuSeparatorStr );
            subMenuTitle += stripHotKey( pEntryData->GetName() );

            USHORT nPos = aTopLevelListBox.InsertEntry( subMenuTitle );
            aTopLevelListBox.SetEntryData( nPos, pEntryData );

            AddSubMenusToUI( subMenuTitle, pEntryData );
        }
    }
}

SvxEntries* SvxConfigPage::FindParentForChild(
    SvxEntries* pRootEntries, SvxConfigEntry* pChildData )
{
    SvxEntries::const_iterator iter = pRootEntries->begin();
    SvxEntries::const_iterator end = pRootEntries->end();

    for ( ; iter != end; iter++ )
    {
        SvxConfigEntry* pEntryData = *iter;

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

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

SvLBoxEntry* SvxConfigPage::AddFunction(
    SvLBoxEntry* pTarget, bool bFront, bool bAllowDuplicates )
{
    String aDisplayName = pSelectorDlg->GetSelectedDisplayName();
    String aHelpText = pSelectorDlg->GetSelectedHelpText();
    String aURL = pSelectorDlg->GetScriptURL();

    if ( !aURL.Len() )
    {
        return NULL;
    }

    SvxConfigEntry* pNewEntryData =
        new SvxConfigEntry( aDisplayName, aURL, FALSE );
    pNewEntryData->SetUserDefined( TRUE );
    pNewEntryData->SetHelpURL( aURL );

    // check that this function is not already in the menu
    SvxConfigEntry* pParent = GetTopLevelSelection();

    SvxEntries::const_iterator iter = pParent->GetEntries()->begin();
    SvxEntries::const_iterator end = pParent->GetEntries()->end();

    if ( !bAllowDuplicates )
    {
        while ( iter != end )
        {
            SvxConfigEntry *pCurEntry = *iter;

            if ( pCurEntry->GetCommand() == pNewEntryData->GetCommand() )
            {
                // asynchronous error message, because of MsgBoxes
                PostUserEvent(
                    LINK( this, SvxConfigPage, AsyncInfoMsg ) );
                return NULL;
            }

            iter++;
        }
    }

    return InsertEntry( pNewEntryData, pTarget, bFront );
}

SvLBoxEntry* SvxConfigPage::InsertEntry(
    SvxConfigEntry* pNewEntryData,
    SvLBoxEntry* pTarget,
    bool bFront )
{
    // Grab the entries list for the currently selected menu
    SvxEntries* pEntries = GetTopLevelSelection()->GetEntries();

    SvLBoxEntry* pNewEntry = NULL;
    SvLBoxEntry* pCurEntry =
        pTarget != NULL ? pTarget : aContentsListBox->GetCurEntry();

    if ( bFront )
    {
        pEntries->insert( pEntries->begin(), pNewEntryData );
        pNewEntry = InsertEntryIntoUI( pNewEntryData, 0 );
    }
    else if ( pCurEntry == NULL || pCurEntry == aContentsListBox->Last() )
    {
        pEntries->push_back( pNewEntryData );
        pNewEntry = InsertEntryIntoUI( pNewEntryData );
    }
    else
    {
        SvxConfigEntry* pEntryData =
            (SvxConfigEntry*) pCurEntry->GetUserData();

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

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

        // 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 );
            pNewEntry = InsertEntryIntoUI( pNewEntryData, nPos );
        }
    }

    if ( pNewEntry != NULL )
    {
        aContentsListBox->Select( pNewEntry );
        aContentsListBox->MakeVisible( pNewEntry );

        GetSaveInData()->SetModified( TRUE );
    }

    return pNewEntry;
}

SvLBoxEntry* SvxConfigPage::InsertEntryIntoUI(
    SvxConfigEntry* pNewEntryData, ULONG nPos )
{
    SvLBoxEntry* pNewEntry = NULL;

    if (pNewEntryData->IsSeparator())
    {
        pNewEntry = aContentsListBox->InsertEntry(
            String::CreateFromAscii( pSeparatorStr ),
                0, FALSE, nPos, pNewEntryData );
    }
    else
    {
        OUString aName = stripHotKey( pNewEntryData->GetName() );

        Image aImage = GetSaveInData()->GetImage(
            pNewEntryData->GetCommand());

        if ( !!aImage )
        {
            pNewEntry = aContentsListBox->InsertEntry(
                aName, aImage, aImage, 0, FALSE, nPos, pNewEntryData );
        }
        else
        {
            pNewEntry = aContentsListBox->InsertEntry(
                aName, 0, FALSE, nPos, pNewEntryData );
        }

        if ( pNewEntryData->IsPopup() ||
             pNewEntryData->GetStyle() & css::ui::ItemStyle::DROP_DOWN )
        {
            // add new popup painter, it gets destructed by the entry
            pNewEntry->ReplaceItem(
                new PopupPainter( pNewEntry, aName ),
                pNewEntry->ItemCount() - 1 );
        }
    }

    return pNewEntry;
}

IMPL_LINK( SvxConfigPage, AsyncInfoMsg, String*, pMsg )
{
    // Asynchronous msg because of D&D
    InfoBox( this, ResId(
        IBX_MNUCFG_ALREADY_INCLUDED, DIALOG_MGR() ) ).Execute();

    return 0;
}

IMPL_LINK( SvxConfigPage, MoveHdl, Button *, pButton )
{
    MoveEntry( pButton == &aMoveUpButton );
    return 0;
}

void SvxConfigPage::MoveEntry( bool bMoveUp )
{
    SvLBoxEntry *pSourceEntry = aContentsListBox->FirstSelected();
    SvLBoxEntry *pTargetEntry = NULL;
    SvLBoxEntry *pToSelect = NULL;

    if ( !pSourceEntry )
    {
        return;
    }

    if ( bMoveUp )
    {
        // Move Up is just a Move Down with the source and target reversed
        pTargetEntry = pSourceEntry;
        pSourceEntry = aContentsListBox->PrevSibling( pTargetEntry );
        pToSelect = pTargetEntry;
    }
    else
    {
        pTargetEntry = aContentsListBox->NextSibling( pSourceEntry );
        pToSelect = pSourceEntry;
    }

    if ( MoveEntryData( pSourceEntry, pTargetEntry ) )
    {
        aContentsListBox->GetModel()->Move( pSourceEntry, pTargetEntry );
        aContentsListBox->Select( pToSelect );
        aContentsListBox->MakeVisible( pToSelect );

        UpdateButtonStates();
    }
}

bool SvxConfigPage::MoveEntryData(
    SvLBoxEntry* pSourceEntry, SvLBoxEntry* pTargetEntry )
{
    if ( pSourceEntry == NULL )
    {
        return FALSE;
    }

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

    SvxConfigEntry* pSourceData =
        (SvxConfigEntry*) pSourceEntry->GetUserData();

    if ( pTargetEntry == NULL )
    {
        RemoveEntry( pEntries, pSourceData );
        pEntries->insert(
            pEntries->begin(), pSourceData );

        GetSaveInData()->SetModified( TRUE );

        return TRUE;
    }
    else
    {
        SvxConfigEntry* pTargetData =
            (SvxConfigEntry*) pTargetEntry->GetUserData();

        if ( pSourceData != NULL && pTargetData != NULL )
        {
            // remove the source entry from our list
            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( TRUE );

            return TRUE;
        }
    }

    return FALSE;
}

SvxMenuConfigPage::SvxMenuConfigPage(
    Window *pParent, const SfxItemSet& rSet )
    :
    SvxConfigPage( pParent, rSet )
{
    aContentsListBox = new SvxMenuEntriesListBox( this, ResId( BOX_ENTRIES ) );
    FreeResource();

    PositionContentsListBox();
    aContentsListBox->SetZOrder( &aAddCommandsButton, WINDOW_ZORDER_BEFOR );

    aTopLevelListBox.SetSelectHdl(
        LINK( this, SvxMenuConfigPage, SelectMenu ) );

    aContentsListBox->SetSelectHdl(
        LINK( this, SvxMenuConfigPage, SelectMenuEntry ) );

    aMoveUpButton.SetClickHdl ( LINK( this, SvxConfigPage, MoveHdl) );
    aMoveDownButton.SetClickHdl ( LINK( this, SvxConfigPage, MoveHdl) );

    aNewTopLevelButton.SetClickHdl  (
        LINK( this, SvxMenuConfigPage, NewMenuHdl ) );

    aAddCommandsButton.SetClickHdl  (
        LINK( this, SvxMenuConfigPage, AddCommandsHdl ) );

    PopupMenu* pMenu = new PopupMenu( ResId( MODIFY_MENU, DIALOG_MGR() ) );
    pMenu->SetMenuFlags(
        pMenu->GetMenuFlags() | MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES );

    aModifyTopLevelButton.SetPopupMenu( pMenu );
    aModifyTopLevelButton.SetSelectHdl(
        LINK( this, SvxMenuConfigPage, MenuSelectHdl ) );

    PopupMenu* pEntry = new PopupMenu( ResId( MODIFY_ENTRY, DIALOG_MGR() ) );
    pEntry->SetMenuFlags(
        pEntry->GetMenuFlags() | MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES );

    aModifyCommandButton.SetPopupMenu( pEntry );
    aModifyCommandButton.SetSelectHdl(
        LINK( this, SvxMenuConfigPage, EntrySelectHdl ) );
}

// Populates the Menu combo box
void SvxMenuConfigPage::Init()
{
    // ensure that the UI is cleared before populating it
    aTopLevelListBox.Clear();
    aContentsListBox->Clear();

    ReloadTopLevelListBox();

    aTopLevelListBox.SelectEntryPos(0, TRUE);
    aTopLevelListBox.GetSelectHdl().Call(this);
}

SvxMenuConfigPage::~SvxMenuConfigPage()
{
    for ( USHORT i = 0 ; i < aSaveInListBox.GetEntryCount(); i++ )
    {
        MenuSaveInData* pData =
            (MenuSaveInData*) aSaveInListBox.GetEntryData( i );

        delete pData;
    }

    if ( pSelectorDlg != NULL )
    {
        delete pSelectorDlg;
    }

    delete aContentsListBox;
}

IMPL_LINK( SvxMenuConfigPage, SelectMenuEntry, Control *, pBox )
{
    UpdateButtonStates();

    return 1;
}

void SvxMenuConfigPage::UpdateButtonStates()
{
    PopupMenu* pPopup = aModifyCommandButton.GetPopupMenu();

    // Disable Up and Down buttons depending on current selection
    SvLBoxEntry* selection = aContentsListBox->GetCurEntry();

    if ( aContentsListBox->GetEntryCount() == 0 || selection == NULL )
    {
        aMoveUpButton.Enable( FALSE );
        aMoveDownButton.Enable( FALSE );

        pPopup->EnableItem( ID_BEGIN_GROUP, TRUE );
        pPopup->EnableItem( ID_RENAME, FALSE );
        pPopup->EnableItem( ID_DELETE, FALSE );

        aDescriptionText.SetText( String() );

        return;
    }

    SvLBoxEntry* first = aContentsListBox->First();
    SvLBoxEntry* last = aContentsListBox->Last();

    aMoveUpButton.Enable( selection != first );
    aMoveDownButton.Enable( selection != last );

    SvxConfigEntry* pEntryData =
        (SvxConfigEntry*) selection->GetUserData();

    if ( pEntryData->IsSeparator() )
    {
        pPopup->EnableItem( ID_DELETE, TRUE );
        pPopup->EnableItem( ID_BEGIN_GROUP, FALSE );
        pPopup->EnableItem( ID_RENAME, FALSE );

        aDescriptionText.SetText( String() );
    }
    else
    {
        pPopup->EnableItem( ID_BEGIN_GROUP, TRUE );
        pPopup->EnableItem( ID_DELETE, TRUE );
        pPopup->EnableItem( ID_RENAME, TRUE );

        aDescriptionText.SetText( pEntryData->GetHelpText() );
    }
}

void SvxMenuConfigPage::DeleteSelectedTopLevel()
{
    SvxConfigEntry* pMenuData = GetTopLevelSelection();

    SvxEntries* pParentEntries =
        FindParentForChild( GetSaveInData()->GetEntries(), pMenuData );

    RemoveEntry( pParentEntries, pMenuData );
    delete pMenuData;

    ReloadTopLevelListBox();

    GetSaveInData()->SetModified( TRUE );
}

bool SvxMenuConfigPage::DeleteSelectedContent()
{
    SvLBoxEntry *pActEntry = aContentsListBox->FirstSelected();

    if ( pActEntry != NULL )
    {
        // get currently selected menu entry
        SvxConfigEntry* pMenuEntry =
            (SvxConfigEntry*) pActEntry->GetUserData();

        // get currently selected menu
        SvxConfigEntry* pMenu = GetTopLevelSelection();

        // remove menu entry from the list for this menu
        RemoveEntry( pMenu->GetEntries(), pMenuEntry );

        // remove menu entry from UI
        aContentsListBox->GetModel()->Remove( pActEntry );

        // if this is a submenu entry, redraw the menus list box
        if ( pMenuEntry->IsPopup() )
        {
            ReloadTopLevelListBox();
        }

        // delete data for menu entry
        delete pMenuEntry;

        GetSaveInData()->SetModified( TRUE );

        return TRUE;
    }
    return FALSE;
}

short SvxMenuConfigPage::QueryReset()
{
    String msg =
        String( ResId( RID_SVXSTR_CONFIRM_MENU_RESET, DIALOG_MGR() ) );

    String saveInName = aSaveInListBox.GetEntry(
        aSaveInListBox.GetSelectEntryPos() );

    OUString label = replaceSaveInName( msg, saveInName );

    QueryBox qbox( this, WB_YES_NO, label );

    return qbox.Execute();
}

IMPL_LINK( SvxMenuConfigPage, SelectMenu, ListBox *, pBox )
{
    aContentsListBox->Clear();

    SvxConfigEntry* pMenuData = GetTopLevelSelection();

    PopupMenu* pPopup = aModifyTopLevelButton.GetPopupMenu();
    pPopup->EnableItem( ID_DELETE, pMenuData->IsDeletable() );
    pPopup->EnableItem( ID_RENAME, pMenuData->IsRenamable() );
    pPopup->EnableItem( ID_MOVE, pMenuData->IsMovable() );

    SvxEntries* pEntries = pMenuData->GetEntries();
    SvxEntries::const_iterator iter = pEntries->begin();

    for ( ; iter != pEntries->end(); iter++ )
    {
        SvxConfigEntry* pEntry = *iter;
        InsertEntryIntoUI( pEntry );
    }

    UpdateButtonStates();

    return 0;
}

IMPL_LINK( SvxMenuConfigPage, MenuSelectHdl, MenuButton *, pButton )
{
    switch( pButton->GetCurItemId() )
    {
        case ID_DELETE:
        {
            DeleteSelectedTopLevel();
            break;
        }
        case ID_RENAME:
        {
            SvxConfigEntry* pMenuData = GetTopLevelSelection();

            String aNewName( stripHotKey( pMenuData->GetName() ) );
            String aDesc( RTL_CONSTASCII_USTRINGPARAM( "Enter New Name" ) );

            SvxAbstractDialogFactory* pFact =
                SvxAbstractDialogFactory::Create();

            AbstractSvxNameDialog* pNameDialog =
                pFact->CreateSvxNameDialog(
                    0, aNewName, aDesc, ResId(RID_SVXDLG_NAME) );

            pNameDialog->SetHelpId( HID_SVX_CONFIG_RENAME_MENU );

            bool ret = pNameDialog->Execute();

            if ( ret == RET_OK ) {
                pNameDialog->GetName( aNewName );
                pMenuData->SetName( aNewName );

                ReloadTopLevelListBox();

                GetSaveInData()->SetModified( TRUE );
            }

            break;
        }
        case ID_MOVE:
        {
            SvxConfigEntry* pMenuData = GetTopLevelSelection();

            SvxMainMenuOrganizerDialog* pDialog =
                new SvxMainMenuOrganizerDialog( this,
                    GetSaveInData()->GetEntries(), pMenuData );

            bool ret = pDialog->Execute();

            if ( ret == RET_OK )
            {
                GetSaveInData()->SetEntries( pDialog->GetEntries() );

                ReloadTopLevelListBox( pDialog->GetSelectedEntry() );

                GetSaveInData()->SetModified( TRUE );
            }

            delete pDialog;

            break;
        }
        default:
            return FALSE;
    }
    return TRUE;
}

IMPL_LINK( SvxMenuConfigPage, EntrySelectHdl, MenuButton *, pButton )
{
    switch( pButton->GetCurItemId() )
    {
        case ID_ADD_SUBMENU:
        {
            String aNewName( RTL_CONSTASCII_USTRINGPARAM( "" ) );
            String aDesc( RTL_CONSTASCII_USTRINGPARAM( "Enter New Name" ) );

            SvxAbstractDialogFactory* pFact =
                SvxAbstractDialogFactory::Create();

            AbstractSvxNameDialog* pNameDialog =
                pFact->CreateSvxNameDialog(
                    0, aNewName, aDesc, ResId(RID_SVXDLG_NAME) );

            pNameDialog->SetHelpId( HID_SVX_CONFIG_NAME_SUBMENU );

            bool ret = pNameDialog->Execute();

            if ( ret == RET_OK ) {
                pNameDialog->GetName(aNewName);

                SvxConfigEntry* pNewEntryData =
                    new SvxConfigEntry( aNewName, aNewName, TRUE );
                pNewEntryData->SetUserDefined( TRUE );

                InsertEntry( pNewEntryData );

                ReloadTopLevelListBox();

                GetSaveInData()->SetModified( TRUE );
            }

            delete pNameDialog;

            break;
        }
        case ID_BEGIN_GROUP:
        {
            SvxConfigEntry* pNewEntryData = new SvxConfigEntry;
            pNewEntryData->SetUserDefined( TRUE );
            InsertEntry( pNewEntryData );

            break;
        }
        case ID_DELETE:
        {
            DeleteSelectedContent();
            break;
        }
        case ID_RENAME:
        {
            SvLBoxEntry* pActEntry = aContentsListBox->GetCurEntry();
            SvxConfigEntry* pEntry =
                (SvxConfigEntry*) pActEntry->GetUserData();

            String aNewName( stripHotKey( pEntry->GetName() ) );
            String aDesc( RTL_CONSTASCII_USTRINGPARAM( "Enter New Name" ) );

            SvxAbstractDialogFactory* pFact =
                SvxAbstractDialogFactory::Create();

            AbstractSvxNameDialog* pNameDialog =
                pFact->CreateSvxNameDialog(
                    0, aNewName, aDesc, ResId(RID_SVXDLG_NAME) );

            pNameDialog->SetHelpId( HID_SVX_CONFIG_RENAME_MENU_ITEM );

            bool ret = pNameDialog->Execute();

            if ( ret == RET_OK ) {
                pNameDialog->GetName(aNewName);

                pEntry->SetName( aNewName );
                aContentsListBox->SetEntryText( pActEntry, aNewName );

                GetSaveInData()->SetModified( TRUE );
            }

            delete pNameDialog;

            break;
        }
        default:
        {
            return FALSE;
        }
    }

    if ( GetSaveInData()->IsModified() )
    {
        UpdateButtonStates();
    }

    return TRUE;
}

IMPL_LINK( SvxMenuConfigPage, AddFunctionHdl,
    SvxScriptSelectorDialog *, pDialog )
{
    AddFunction();

    return 0;
}

IMPL_LINK( SvxMenuConfigPage, NewMenuHdl, Button *, pButton )
{
    SvxMainMenuOrganizerDialog* pDialog =
        new SvxMainMenuOrganizerDialog( 0,
            GetSaveInData()->GetEntries(), NULL, TRUE );

    bool ret = pDialog->Execute();

    if ( ret == RET_OK )
    {
        GetSaveInData()->SetEntries( pDialog->GetEntries() );
        ReloadTopLevelListBox( pDialog->GetSelectedEntry() );
        GetSaveInData()->SetModified( TRUE );
    }

    delete pDialog;

    return 0;
}

IMPL_LINK( SvxMenuConfigPage, AddCommandsHdl, Button *, pButton )
{
    if ( pSelectorDlg == NULL )
    {
        // Create Script Selector which also shows builtin commands
        pSelectorDlg = new SvxScriptSelectorDialog( this, TRUE, m_xFrame );

        pSelectorDlg->SetAddHdl(
            LINK( this, SvxMenuConfigPage, AddFunctionHdl ) );

        pSelectorDlg->SetDialogDescription( String(
            ResId( RID_SVXSTR_MENU_ADDCOMMANDS_DESCRIPTION, DIALOG_MGR() ) ) );
    }

    // Position the Script Selector over the Add button so it is
    // beside the menu contents list and does not obscure it
    pSelectorDlg->SetPosPixel( aAddCommandsButton.GetPosPixel() );

    pSelectorDlg->SetImageProvider(
        static_cast< ImageProvider* >( GetSaveInData() ) );

    pSelectorDlg->Show();
    return 1;
}

SaveInData* SvxMenuConfigPage::CreateSaveInData(
    const uno::Reference< css::ui::XUIConfigurationManager >& xCfgMgr,
    const uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
    const OUString& aModuleId,
    bool bDocConfig )
{
    return static_cast< SaveInData* >(
        new MenuSaveInData( xCfgMgr, xParentCfgMgr, aModuleId, bDocConfig ));
}

SvxMainMenuOrganizerDialog::SvxMainMenuOrganizerDialog(
    Window* pParent, SvxEntries* entries,
    SvxConfigEntry* selection, bool bCreateMenu )
    :
    ModalDialog( pParent, ResId( MD_MENU_ORGANISER, DIALOG_MGR() ) ),
    aMenuNameText( this, ResId( TXT_MENU_NAME ) ),
    aMenuNameEdit( this, ResId( EDIT_MENU_NAME ) ),
    aMenuListText( this, ResId( TXT_MENU ) ),
    aMenuListBox( this, ResId( BOX_MAIN_MENUS ) ),
    aMoveUpButton( this, ResId( BTN_MENU_UP ) ),
    aMoveDownButton( this, ResId( BTN_MENU_DOWN ) ),
    aOKButton( this, ResId( BTN_MENU_ADD ) ),
    aCloseButton( this, ResId( BTN_MENU_CLOSE ) ),
    aHelpButton( this, ResId( BTN_MENU_HELP ) ),
    bModified( FALSE )
{
    FreeResource();

    // Copy the entries list passed in
    if ( entries != NULL )
    {
        SvxConfigEntry* pEntry;
        SvLBoxEntry* pLBEntry;

        pEntries = new SvxEntries();
        SvxEntries::const_iterator iter = entries->begin();

        while ( iter != entries->end() )
        {
            pEntry = *iter;
            pLBEntry =
                aMenuListBox.InsertEntry( stripHotKey( pEntry->GetName() ) );
            pLBEntry->SetUserData( pEntry );
            pEntries->push_back( pEntry );

            if ( pEntry == selection )
            {
                aMenuListBox.Select( pLBEntry );
            }
            iter++;
        }
    }

    if ( bCreateMenu )
    {
        // Generate custom name for new menu
        String prefix =
            String( ResId ( RID_SVXSTR_NEW_MENU, DIALOG_MGR() ) );

        OUString newname = generateCustomName( prefix, entries );
        OUString newurl = generateCustomMenuURL( pEntries );

        SvxConfigEntry* pNewEntryData =
            new SvxConfigEntry( newname, newurl, TRUE );
        pNewEntryData->SetUserDefined( TRUE );
        pNewEntryData->SetMain( TRUE );

        pNewMenuEntry =
            aMenuListBox.InsertEntry( stripHotKey( pNewEntryData->GetName() ) );
        aMenuListBox.Select( pNewMenuEntry );

        pNewMenuEntry->SetUserData( pNewEntryData );

        pEntries->push_back( pNewEntryData );

        aMenuNameEdit.SetText( newname );
        aMenuNameEdit.SetModifyHdl(
            LINK( this, SvxMainMenuOrganizerDialog, ModifyHdl ) );
    }
    else
    {
        Point p, newp;
        Size s, news;

        // get offset to bottom of name textfield from top of dialog
        p = aMenuNameEdit.GetPosPixel();
        s = aMenuNameEdit.GetSizePixel();
        long offset = p.Y() + s.Height();

        // reposition menu list and label
        aMenuListText.SetPosPixel( aMenuNameText.GetPosPixel() );
        aMenuListBox.SetPosPixel( aMenuNameEdit.GetPosPixel() );

        // reposition up and down buttons
        p = aMoveUpButton.GetPosPixel();
        newp = Point( p.X(), p.Y() - offset );
        aMoveUpButton.SetPosPixel( newp );

        p = aMoveDownButton.GetPosPixel();
        newp = Point( p.X(), p.Y() - offset );
        aMoveDownButton.SetPosPixel( newp );

        // change size of dialog
        s = GetSizePixel();
        news = Size( s.Width(), s.Height() - offset );
        SetSizePixel( news );

        // hide name label and textfield
        aMenuNameText.Hide();
        aMenuNameEdit.Hide();

        // change the title
        SetText( ResId( RID_SVXSTR_MOVE_MENU, DIALOG_MGR() ) );
    }

    aMenuListBox.SetSelectHdl(
        LINK( this, SvxMainMenuOrganizerDialog, SelectHdl ) );

    aMoveUpButton.SetClickHdl (
        LINK( this, SvxMainMenuOrganizerDialog, MoveHdl) );
    aMoveDownButton.SetClickHdl (
        LINK( this, SvxMainMenuOrganizerDialog, MoveHdl) );
}

IMPL_LINK(SvxMainMenuOrganizerDialog, ModifyHdl, Edit*, pEdit)
{
    // if the Edit control is empty do not change the name
    if ( aMenuNameEdit.GetText().Equals( String() ) )
    {
        return 0;
    }

    SvxConfigEntry* pNewEntryData =
        (SvxConfigEntry*) pNewMenuEntry->GetUserData();

    pNewEntryData->SetName( aMenuNameEdit.GetText() );

    aMenuListBox.SetEntryText( pNewMenuEntry, pNewEntryData->GetName() );

    return 0;
}

SvxMainMenuOrganizerDialog::~SvxMainMenuOrganizerDialog()
{
}

IMPL_LINK( SvxMainMenuOrganizerDialog, SelectHdl, Control*, pCtrl )
{
    UpdateButtonStates();
    return 1;
}

void SvxMainMenuOrganizerDialog::UpdateButtonStates()
{
    // Disable Up and Down buttons depending on current selection
    SvLBoxEntry* selection = aMenuListBox.GetCurEntry();
    SvLBoxEntry* first = aMenuListBox.First();
    SvLBoxEntry* last = aMenuListBox.Last();

    aMoveUpButton.Enable( selection != first );
    aMoveDownButton.Enable( selection != last );
}

IMPL_LINK( SvxMainMenuOrganizerDialog, MoveHdl, Button *, pButton )
{
    SvLBoxEntry *pSourceEntry = aMenuListBox.FirstSelected();
    SvLBoxEntry *pTargetEntry = NULL;

    if ( !pSourceEntry )
    {
        return 0;
    }

    if ( pButton == &aMoveDownButton )
    {
        pTargetEntry = aMenuListBox.NextSibling( pSourceEntry );
    }
    else if ( pButton == &aMoveUpButton )
    {
        // Move Up is just a Move Down with the source and target reversed
        pTargetEntry = pSourceEntry;
        pSourceEntry = aMenuListBox.PrevSibling( pTargetEntry );
    }

    if ( pSourceEntry != NULL && pTargetEntry != NULL )
    {
        SvxConfigEntry* pSourceData =
            (SvxConfigEntry*) pSourceEntry->GetUserData();
        SvxConfigEntry* pTargetData =
            (SvxConfigEntry*) pTargetEntry->GetUserData();

        SvxEntries::iterator iter1 = GetEntries()->begin();
        SvxEntries::iterator iter2 = GetEntries()->begin();
        SvxEntries::const_iterator end = GetEntries()->end();

        // Advance the iterators to the positions of the source and target
        while (*iter1 != pSourceData && ++iter1 != end);
        while (*iter2 != pTargetData && ++iter2 != end);

        // Now swap the entries in the menu list and in the UI
        if ( iter1 != end && iter2 != end )
        {
            std::swap( *iter1, *iter2 );
            aMenuListBox.GetModel()->Move( pSourceEntry, pTargetEntry );
            aMenuListBox.MakeVisible( pSourceEntry );

            bModified = TRUE;
        }
    }

    if ( bModified )
    {
        UpdateButtonStates();
    }

    return 0;
}

SvxEntries* SvxMainMenuOrganizerDialog::GetEntries()
{
    return pEntries;
}

SvxConfigEntry* SvxMainMenuOrganizerDialog::GetSelectedEntry()
{
    return (SvxConfigEntry*)aMenuListBox.FirstSelected()->GetUserData();
}

SvxConfigEntry::SvxConfigEntry(
    const uno::Sequence< beans::PropertyValue >& rProperties,
    const uno::Reference< container::XNameAccess >& rCommandToLabelMap )
    :
        nId( 1 ),
        bPopUp( FALSE ),
        bIsUserDefined( FALSE ),
        bIsMain( FALSE ),
        bStrEdited( FALSE ),
        bIsVisible( TRUE ),
        nStyle( 0 ),
        pEntries( 0 ),
        bIsParentData( FALSE )
{
    sal_uInt16 nType( css::ui::ItemType::DEFAULT );
    OUString aHelpURL;

    for ( sal_Int32 i = 0; i < rProperties.getLength(); i++ )
    {
        if ( rProperties[i].Name.equalsAscii( ITEM_DESCRIPTOR_COMMANDURL ))
        {
            rProperties[i].Value >>= aCommand;
        }
        else if ( rProperties[i].Name.equalsAscii( ITEM_DESCRIPTOR_HELPURL ))
        {
            rProperties[i].Value >>= aHelpURL;
        }
        else if ( rProperties[i].Name.equalsAscii( ITEM_DESCRIPTOR_LABEL ))
        {
            rProperties[i].Value >>= aLabel;
        }
        else if ( rProperties[i].Name.equalsAscii( ITEM_DESCRIPTOR_TYPE ))
        {
            rProperties[i].Value >>= nType;
        }
    }

    if ( nType == css::ui::ItemType::DEFAULT )
    {
        uno::Any a;
        try
        {
            a = rCommandToLabelMap->getByName( aCommand );
            bIsUserDefined = FALSE;
        }
        catch ( container::NoSuchElementException& )
        {
            bIsUserDefined = TRUE;
        }

        // If custom label not set retrieve it from the command to info service
        if ( aLabel.equals( OUString() ) )
        {
            uno::Sequence< beans::PropertyValue > aPropSeq;
            if ( a >>= aPropSeq )
            {
                for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
                {
                    if ( aPropSeq[i].Name.equalsAscii( ITEM_DESCRIPTOR_LABEL ) )
                    {
                        aPropSeq[i].Value >>= aLabel;
                        break;
                    }
                }
            }
        }
    }
}

const OUString&
SvxConfigEntry::GetHelpText()
{
    if ( aHelpText.getLength() == 0 )
    {
        OUString helpid = OUString::createFromAscii( "helpid:" );
        if ( aHelpURL.indexOf( helpid ) != -1 )
        {
            aHelpURL = aHelpURL.copy( helpid.getLength() );
        }

        Help* pHelp = Application::GetHelp();
        if ( aHelpURL.toInt32() != 0 )
        {
            aHelpText = pHelp->GetHelpText( aHelpURL.toInt32(), NULL );
        }

        if ( aHelpText.getLength() == 0 && aCommand.getLength() != 0 )
        {
            aHelpText = pHelp->GetHelpText( aCommand, NULL );
        }
    }

    return aHelpText;
}

uno::Sequence< beans::PropertyValue >
SvxConfigEntry::GetProperties(
    const uno::Reference< container::XNameAccess >& rCommandToLabelMap )
{
    if ( IsSeparator() )
    {
        uno::Sequence< beans::PropertyValue > aPropSeq( 1 );

        aPropSeq[0].Name  = OUString(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_TYPE ) );
        aPropSeq[0].Value <<= css::ui::ItemType::SEPARATOR_LINE;

        return aPropSeq;
    }

    static const OUString aDescriptorCommandURL (
        RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_COMMANDURL ) );

    static const OUString aDescriptorType(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_TYPE ) );

    static const OUString aDescriptorLabel(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_LABEL ) );

    static const OUString aDescriptorHelpURL(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_HELPURL ) );

    uno::Sequence< beans::PropertyValue > aPropSeq( 4 );

    aPropSeq[0].Name = aDescriptorCommandURL;
    aPropSeq[0].Value <<= rtl::OUString( GetCommand() );

    aPropSeq[1].Name = aDescriptorType;
    aPropSeq[1].Value <<= css::ui::ItemType::DEFAULT;

    // If the name has not been changed and the name is the same as
    // in the default command to label map then the label can be stored
    // as an empty string.
    // It will be initialised again later using the command to label map.
    aPropSeq[2].Name = aDescriptorLabel;
    if ( HasChangedName() == FALSE && GetCommand().getLength() )
    {
        BOOL isDefaultName = FALSE;
        try
        {
            uno::Any a( rCommandToLabelMap->getByName( GetCommand() ) );
            uno::Sequence< beans::PropertyValue > tmpPropSeq;
            if ( a >>= tmpPropSeq )
            {
                for ( sal_Int32 i = 0; i < tmpPropSeq.getLength(); i++ )
                {
                    if ( tmpPropSeq[i].Name.equals( aDescriptorLabel ) )
                    {
                        OUString tmpLabel;
                        tmpPropSeq[i].Value >>= tmpLabel;

                        if ( tmpLabel.equals( GetName() ) )
                        {
                            isDefaultName = TRUE;
                        }

                        break;
                    }
                }
            }
        }
        catch ( container::NoSuchElementException& )
        {
            // isDefaultName is left as FALSE
        }

        if ( isDefaultName )
        {
            aPropSeq[2].Value <<= rtl::OUString();
        }
        else
        {
            aPropSeq[2].Value <<= rtl::OUString( GetName() );
        }
    }
    else
    {
        aPropSeq[2].Value <<= rtl::OUString( GetName() );
    }

    aPropSeq[3].Name = aDescriptorHelpURL;
    aPropSeq[3].Value <<= rtl::OUString( GetHelpURL() );

    return aPropSeq;
}

/*
SvxMenuConfigEntry::SvxMenuConfigEntry(
    const uno::Sequence< beans::PropertyValue >& rProperties,
    const uno::Reference< container::XNameAccess >& rCommandToLabelMap )
    :
        SvxConfigEntry( rProperties, rCommandToLabelMap )
{
    uno::Reference< container::XIndexAccess > aChildren;

    for ( sal_Int32 i = 0; i < rProperties.getLength(); i++ )
    {
        if ( rProperties[i].Name.equalsAscii( ITEM_DESCRIPTOR_CONTAINER ))
        {
            rProperties[i].Value >>= aChildren;
        }
    }

    if ( aChildren.is() )
    {
        SetPopup( TRUE );
        SetEntries( new SvxEntries() );

           uno::Sequence< beans::PropertyValue > aProps;
        for ( sal_Int32 i = 0; i < aChildren->getCount(); i++ )
        {
               if ( aChildren->getByIndex( i ) >>= aProps )
            {
                SvxConfigEntry* pEntry =
                    new SvxMenuConfigEntry( aProps, rCommandToLabelMap );
                GetEntries()->push_back( pEntry );
            }
        }
    }
}
*/

SvxConfigEntry::SvxConfigEntry( const OUString& rDisplayName,
                                const OUString& rCommandURL, bool bPopup, bool bParentData )
    : nId( 1 )
    , bPopUp(bPopup)
    , aCommand(rCommandURL)
    , aLabel(rDisplayName)
    , bIsUserDefined( FALSE )
    , bIsMain( FALSE )
    , bStrEdited( FALSE )
    , bIsVisible( TRUE )
    , nStyle( 0 )
    , pEntries( 0 )
    , bIsParentData( bParentData )
{
    if (bPopUp)
    {
        pEntries = new SvxEntries();
    }
}

SvxConfigEntry::~SvxConfigEntry()
{
    if ( pEntries != NULL )
    {
        SvxEntries::const_iterator iter = pEntries->begin();

        for ( ; iter != pEntries->end(); iter++ )
        {
            delete *iter;
        }
        delete pEntries;
    }
}

bool SvxConfigEntry::IsMovable()
{
    if ( IsPopup() && !IsMain() )
    {
        return FALSE;
    }
    return TRUE;
}

bool SvxConfigEntry::IsDeletable()
{
    if ( IsMain() && !IsUserDefined() )
    {
        return FALSE;
    }
    return TRUE;
}

bool SvxConfigEntry::IsRenamable()
{
    if ( IsMain() && !IsUserDefined() )
    {
        return FALSE;
    }
    return TRUE;
}

SvxToolbarConfigPage::SvxToolbarConfigPage(
    Window *pParent, const SfxItemSet& rSet )
    :
    SvxConfigPage( pParent, rSet )
{
    SetHelpId( HID_SVX_CONFIG_TOOLBAR );

    aContentsListBox = new SvxToolbarEntriesListBox(this, ResId(BOX_ENTRIES));
    FreeResource();
    PositionContentsListBox();
    aContentsListBox->SetZOrder( &aAddCommandsButton, WINDOW_ZORDER_BEFOR );

    aContentsListBox->SetHelpId( HID_SVX_CONFIG_TOOLBAR_CONTENTS );
    aNewTopLevelButton.SetHelpId( HID_SVX_NEW_TOOLBAR );
    aModifyTopLevelButton.SetHelpId( HID_SVX_MODIFY_TOOLBAR );
    aAddCommandsButton.SetHelpId( HID_SVX_NEW_TOOLBAR_ITEM );
    aModifyCommandButton.SetHelpId( HID_SVX_MODIFY_TOOLBAR_ITEM );
    aSaveInListBox.SetHelpId( HID_SVX_SAVE_IN );

    aTopLevelSeparator.SetText(
        ResId ( RID_SVXSTR_PRODUCTNAME_TOOLBARS, DIALOG_MGR() ) );

    aTopLevelLabel.SetText( ResId ( RID_SVXSTR_TOOLBAR, DIALOG_MGR() ) );
    aModifyTopLevelButton.SetText( ResId ( RID_SVXSTR_TOOLBAR, DIALOG_MGR() ) );
    aContentsSeparator.SetText( ResId ( RID_SVXSTR_TOOLBAR_CONTENT, DIALOG_MGR() ) );
    aContentsLabel.SetText( ResId ( RID_SVXSTR_COMMANDS, DIALOG_MGR() ) );

    aTopLevelListBox.SetSelectHdl(
        LINK( this, SvxToolbarConfigPage, SelectToolbar ) );
    aContentsListBox->SetSelectHdl(
        LINK( this, SvxToolbarConfigPage, SelectToolbarEntry ) );

    aNewTopLevelButton.SetClickHdl  (
        LINK( this, SvxToolbarConfigPage, NewToolbarHdl ) );

    aAddCommandsButton.SetClickHdl  (
        LINK( this, SvxToolbarConfigPage, AddCommandsHdl ) );

    aMoveUpButton.SetClickHdl ( LINK( this, SvxToolbarConfigPage, MoveHdl) );
    aMoveDownButton.SetClickHdl ( LINK( this, SvxToolbarConfigPage, MoveHdl) );

    PopupMenu* pMenu = new PopupMenu( ResId( MODIFY_TOOLBAR, DIALOG_MGR() ) );
    pMenu->SetMenuFlags(
        pMenu->GetMenuFlags() | MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES );

    aModifyTopLevelButton.SetPopupMenu( pMenu );
    aModifyTopLevelButton.SetSelectHdl(
        LINK( this, SvxToolbarConfigPage, ToolbarSelectHdl ) );

    PopupMenu* pEntry = new PopupMenu(
        ResId( MODIFY_TOOLBAR_CONTENT, DIALOG_MGR() ) );
    pEntry->SetMenuFlags(
        pEntry->GetMenuFlags() | MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES );

    aModifyCommandButton.SetPopupMenu( pEntry );
    aModifyCommandButton.SetSelectHdl(
        LINK( this, SvxToolbarConfigPage, EntrySelectHdl ) );

    // default toolbar to select is standardbar unless a different one
    // has been passed in
    m_aURLToSelect = OUString::createFromAscii( ITEM_TOOLBAR_URL );
    m_aURLToSelect += OUString::createFromAscii( "standardbar" );

    const SfxPoolItem* pItem =
        rSet.GetItem( rSet.GetPool()->GetWhich( SID_CONFIG ) );

    if ( pItem )
    {
        OUString text = ((const SfxStringItem*)pItem)->GetValue();
        if (text.indexOf(OUString::createFromAscii(ITEM_TOOLBAR_URL)) == 0)
        {
            m_aURLToSelect = text.copy( 0 );
        }
    }

    long nTxtW = aTopLevelLabel.GetCtrlTextWidth( aTopLevelLabel.GetText() );
    long nCtrlW = aTopLevelLabel.GetSizePixel().Width();
    if ( nTxtW >= nCtrlW )
    {
        long nDelta = Max( (long)10, nTxtW - nCtrlW );
        Size aNewSz = aTopLevelLabel.GetSizePixel();
        aNewSz.Width() += nDelta;
        aTopLevelLabel.SetSizePixel( aNewSz );
        aNewSz = aTopLevelListBox.GetSizePixel();
        aNewSz.Width() -= nDelta;
        Point aNewPt = aTopLevelListBox.GetPosPixel();
        aNewPt.X() += nDelta;
        aTopLevelListBox.SetPosSizePixel( aNewPt, aNewSz );
    }
}

SvxToolbarConfigPage::~SvxToolbarConfigPage()
{
    for ( USHORT i = 0 ; i < aSaveInListBox.GetEntryCount(); i++ )
    {
        ToolbarSaveInData* pData =
            (ToolbarSaveInData*) aSaveInListBox.GetEntryData( i );

        delete pData;
    }

    if ( pSelectorDlg != NULL )
    {
        delete pSelectorDlg;
    }


    delete aContentsListBox;
}

void SvxToolbarConfigPage::DeleteSelectedTopLevel()
{
    USHORT nSelectionPos = aTopLevelListBox.GetSelectEntryPos();
    ToolbarSaveInData* pSaveInData = (ToolbarSaveInData*) GetSaveInData();
    pSaveInData->RemoveToolbar( GetTopLevelSelection() );

    if ( aTopLevelListBox.GetEntryCount() > 1 )
    {
        // select next entry after the one being deleted
        // selection position is indexed from 0 so need to
        // subtract one from the entry count
        if ( nSelectionPos != aTopLevelListBox.GetEntryCount() - 1 )
        {
            aTopLevelListBox.SelectEntryPos( nSelectionPos + 1, TRUE );
        }
        else
        {
            aTopLevelListBox.SelectEntryPos( nSelectionPos - 1, TRUE );
        }
        aTopLevelListBox.GetSelectHdl().Call( this );

        // and now remove the entry
        aTopLevelListBox.RemoveEntry( nSelectionPos );
    }
    else
    {
        ReloadTopLevelListBox();
    }
}

bool SvxToolbarConfigPage::DeleteSelectedContent()
{
    SvLBoxEntry *pActEntry = aContentsListBox->FirstSelected();

    if ( pActEntry != NULL )
    {
        // get currently selected entry
        SvxConfigEntry* pEntry =
            (SvxConfigEntry*) pActEntry->GetUserData();

        SvxConfigEntry* pToolbar = GetTopLevelSelection();

        // remove entry from the list for this toolbar
        RemoveEntry( pToolbar->GetEntries(), pEntry );

        // remove toolbar entry from UI
        aContentsListBox->GetModel()->Remove( pActEntry );

        // delete data for toolbar entry
        delete pEntry;

        (( ToolbarSaveInData* ) GetSaveInData())->ApplyToolbar( pToolbar );
        UpdateButtonStates();

        // if this is the last entry in the toolbar and it is a user
        // defined toolbar pop up a dialog asking the user if they
        // want to delete the toolbar
        if ( aContentsListBox->GetEntryCount() == 0 &&
             GetTopLevelSelection()->IsDeletable() )
        {
            QueryBox qbox( this,
                ResId( QBX_CONFIRM_DELETE_TOOLBAR, DIALOG_MGR() ) );

            if ( qbox.Execute() == RET_YES )
            {
                DeleteSelectedTopLevel();
            }
        }

        return TRUE;
    }

    return FALSE;
}

IMPL_LINK( SvxToolbarConfigPage, MoveHdl, Button *, pButton )
{
    MoveEntry( pButton == &aMoveUpButton );
    return 0;
}

void SvxToolbarConfigPage::MoveEntry( bool bMoveUp )
{
    SvxConfigPage::MoveEntry( bMoveUp );

    // Apply change to currently selected toolbar
    SvxConfigEntry* pToolbar = GetTopLevelSelection();
    ((ToolbarSaveInData*)GetSaveInData())->ApplyToolbar( pToolbar );
}

IMPL_LINK( SvxToolbarConfigPage, ToolbarSelectHdl, MenuButton *, pButton )
{
    USHORT nSelectionPos = aTopLevelListBox.GetSelectEntryPos();

    SvxConfigEntry* pToolbar =
        (SvxConfigEntry*)aTopLevelListBox.GetEntryData( nSelectionPos );

    ToolbarSaveInData* pSaveInData = (ToolbarSaveInData*) GetSaveInData();

    switch( pButton->GetCurItemId() )
    {
        case ID_DELETE:
        {
            DeleteSelectedTopLevel();
            break;
        }
        case ID_RENAME:
        {
            String aNewName( stripHotKey( pToolbar->GetName() ) );
            String aDesc( RTL_CONSTASCII_USTRINGPARAM( "Enter New Name" ) );

            SvxAbstractDialogFactory* pFact =
                SvxAbstractDialogFactory::Create();

            AbstractSvxNameDialog* pNameDialog =
                pFact->CreateSvxNameDialog(
                    0, aNewName, aDesc, ResId(RID_SVXDLG_NAME) );

            pNameDialog->SetHelpId( HID_SVX_CONFIG_RENAME_TOOLBAR );

            bool ret = pNameDialog->Execute();

            if ( ret == RET_OK )
            {
                pNameDialog->GetName(aNewName);

                pToolbar->SetName( aNewName );
                pSaveInData->ApplyToolbar( pToolbar );

                // have to use remove and insert to change the name
                aTopLevelListBox.RemoveEntry( nSelectionPos );
                nSelectionPos =
                    aTopLevelListBox.InsertEntry( aNewName, nSelectionPos );
                aTopLevelListBox.SetEntryData( nSelectionPos, pToolbar );
                aTopLevelListBox.SelectEntryPos( nSelectionPos );
            }

            delete pNameDialog;

            break;
        }
        case ID_DEFAULT_STYLE:
        {
            QueryBox qbox( this,
                ResId( QBX_CONFIRM_RESTORE_DEFAULT, DIALOG_MGR() ) );

            if ( qbox.Execute() == RET_YES )
            {
                ToolbarSaveInData* pSaveInData =
                    (ToolbarSaveInData*) GetSaveInData();

                pSaveInData->RestoreToolbar( pToolbar );

                aTopLevelListBox.GetSelectHdl().Call( this );
            }

            break;
        }
        case ID_ICONS_ONLY:
        {
            pToolbar->SetStyle( 0 );
            pSaveInData->SetSystemStyle( m_xFrame, pToolbar->GetCommand(), 0 );

            aTopLevelListBox.GetSelectHdl().Call( this );

            break;
        }
        case ID_TEXT_ONLY:
        {
            pToolbar->SetStyle( 1 );
            pSaveInData->SetSystemStyle( m_xFrame, pToolbar->GetCommand(), 1 );

            aTopLevelListBox.GetSelectHdl().Call( this );

            break;
        }
        case ID_ICONS_AND_TEXT:
        {
            pToolbar->SetStyle( 2 );
            pSaveInData->SetSystemStyle( m_xFrame, pToolbar->GetCommand(), 2 );

            aTopLevelListBox.GetSelectHdl().Call( this );

            break;
        }
    }
    return 1;
}

IMPL_LINK( SvxToolbarConfigPage, EntrySelectHdl, MenuButton *, pButton )
{
    bool bNeedsApply = FALSE;

    // get currently selected toolbar
    SvxConfigEntry* pToolbar = GetTopLevelSelection();

    switch( pButton->GetCurItemId() )
    {
        case ID_RENAME:
        {
            SvLBoxEntry* pActEntry = aContentsListBox->GetCurEntry();
            SvxConfigEntry* pEntry =
                (SvxConfigEntry*) pActEntry->GetUserData();

            String aNewName( stripHotKey( pEntry->GetName() ) );
            String aDesc( RTL_CONSTASCII_USTRINGPARAM( "Enter New Name" ) );

            SvxAbstractDialogFactory* pFact =
                SvxAbstractDialogFactory::Create();

            AbstractSvxNameDialog* pNameDialog =
                pFact->CreateSvxNameDialog(
                    0, aNewName, aDesc, ResId(RID_SVXDLG_NAME) );

            pNameDialog->SetHelpId( HID_SVX_CONFIG_RENAME_TOOLBAR_ITEM );

            bool ret = pNameDialog->Execute();

            if ( ret == RET_OK ) {
                pNameDialog->GetName(aNewName);

                pEntry->SetName( aNewName );
                aContentsListBox->SetEntryText( pActEntry, aNewName );

                bNeedsApply = TRUE;
            }

            delete pNameDialog;
            break;
        }
        case ID_DEFAULT_COMMAND:
        {
            SvLBoxEntry* pActEntry = aContentsListBox->GetCurEntry();
            SvxConfigEntry* pEntry =
                (SvxConfigEntry*) pActEntry->GetUserData();

            USHORT nSelectionPos = 0;

            // find position of entry within the list
            for ( USHORT i = 0; i < aContentsListBox->GetEntryCount(); i++ )
            {
                if ( aContentsListBox->GetEntry( 0, i ) == pActEntry )
                {
                    nSelectionPos = i;
                    break;
                }
            }

            ToolbarSaveInData* pSaveInData =
                (ToolbarSaveInData*) GetSaveInData();

            OUString aSystemName =
                pSaveInData->GetSystemUIName( pEntry->GetCommand() );

            if ( !pEntry->GetName().equals( aSystemName ) )
            {
                pEntry->SetName( aSystemName );
                aContentsListBox->SetEntryText(
                    pActEntry, stripHotKey( aSystemName ) );
                bNeedsApply = TRUE;
            }

            uno::Sequence< OUString > aURLSeq( 1 );
            aURLSeq[ 0 ] = pEntry->GetCommand();

            try
            {
                GetSaveInData()->GetImageManager()->removeImages(
                    GetImageType(), aURLSeq );

                // reset backup in entry
                pEntry->SetBackupGraphic(
                    uno::Reference< graphic::XGraphic >() );

                GetSaveInData()->PersistChanges(
                    GetSaveInData()->GetImageManager() );

                aContentsListBox->GetModel()->Remove( pActEntry );

                SvLBoxEntry* pNewLBEntry =
                    InsertEntryIntoUI( pEntry, nSelectionPos );

                aContentsListBox->SetCheckButtonState( pNewLBEntry,
                    pEntry->IsVisible() ?
                        SV_BUTTON_CHECKED : SV_BUTTON_UNCHECKED );

                aContentsListBox->Select( pNewLBEntry );
                aContentsListBox->MakeVisible( pNewLBEntry );

                bNeedsApply = TRUE;
            }
               catch ( uno::Exception& )
               {
                OSL_TRACE("Error restoring image");
               }
            break;
        }
        case ID_BEGIN_GROUP:
        {
            SvxConfigEntry* pNewEntryData = new SvxConfigEntry;
            pNewEntryData->SetUserDefined( TRUE );

            SvLBoxEntry* pNewLBEntry = InsertEntry( pNewEntryData );

            aContentsListBox->SetCheckButtonState(
                pNewLBEntry, SV_BUTTON_TRISTATE );

            bNeedsApply = TRUE;
            break;
        }
        case ID_DELETE:
        {
            DeleteSelectedContent();
            break;
        }
        case ID_ICON_ONLY:
        {
            break;
        }
        case ID_TEXT_ONLY:
        {
            break;
        }
        case ID_ICON_AND_TEXT:
        {
            break;
        }
        case ID_CHANGE_SYMBOL:
        {
            SvLBoxEntry* pActEntry = aContentsListBox->GetCurEntry();
            SvxConfigEntry* pEntry =
                (SvxConfigEntry*) pActEntry->GetUserData();

            USHORT nSelectionPos = 0;

            // find position of entry within the list
            for ( USHORT i = 0; i < aContentsListBox->GetEntryCount(); i++ )
            {
                if ( aContentsListBox->GetEntry( 0, i ) == pActEntry )
                {
                    nSelectionPos = i;
                    break;
                }
            }

            SvxIconSelectorDialog* pIconDialog =
                new SvxIconSelectorDialog( 0,
                    GetSaveInData()->GetImageManager(),
                    GetSaveInData()->GetParentImageManager() );

            bool ret = pIconDialog->Execute();

            if ( ret == RET_OK )
            {
                uno::Reference< graphic::XGraphic > newgraphic =
                    pIconDialog->GetSelectedIcon();

                if ( newgraphic.is() )
                {
                    uno::Sequence< uno::Reference< graphic::XGraphic > >
                        aGraphicSeq( 1 );

                    uno::Sequence< OUString > aURLSeq( 1 );
                    aURLSeq[ 0 ] = pEntry->GetCommand();

                    if ( !pEntry->GetBackupGraphic().is() )
                    {
                        uno::Reference< graphic::XGraphic > backup;
                        backup = GetGraphic(
                            GetSaveInData()->GetImageManager(), aURLSeq[ 0 ] );

                        if ( backup.is() )
                        {
                            pEntry->SetBackupGraphic( backup );
                        }
                    }

                    aGraphicSeq[ 0 ] = newgraphic;
                    try
                    {
                        GetSaveInData()->GetImageManager()->replaceImages(
                            GetImageType(), aURLSeq, aGraphicSeq );

                        Image aImage( newgraphic );

                        aContentsListBox->GetModel()->Remove( pActEntry );
                        SvLBoxEntry* pNewLBEntry =
                            InsertEntryIntoUI( pEntry, nSelectionPos );

                        aContentsListBox->SetCheckButtonState( pNewLBEntry,
                            pEntry->IsVisible() ?
                                SV_BUTTON_CHECKED : SV_BUTTON_UNCHECKED );

                        aContentsListBox->Select( pNewLBEntry );
                        aContentsListBox->MakeVisible( pNewLBEntry );

                        GetSaveInData()->PersistChanges(
                            GetSaveInData()->GetImageManager() );
                    }
                    catch ( uno::Exception& )
                    {
                        OSL_TRACE("Error replacing image");
                    }
                }
            }

            delete pIconDialog;

            break;
        }
        case ID_RESET_SYMBOL:
        {
            SvLBoxEntry* pActEntry = aContentsListBox->GetCurEntry();
            SvxConfigEntry* pEntry =
                (SvxConfigEntry*) pActEntry->GetUserData();

            USHORT nSelectionPos = 0;

            // find position of entry within the list
            for ( USHORT i = 0; i < aContentsListBox->GetEntryCount(); i++ )
            {
                if ( aContentsListBox->GetEntry( 0, i ) == pActEntry )
                {
                    nSelectionPos = i;
                    break;
                }
            }

            uno::Reference< graphic::XGraphic > backup =
                pEntry->GetBackupGraphic();

            uno::Sequence< uno::Reference< graphic::XGraphic > >
                aGraphicSeq( 1 );
            aGraphicSeq[ 0 ] = backup;

            uno::Sequence< OUString > aURLSeq( 1 );
            aURLSeq[ 0 ] = pEntry->GetCommand();

            try
            {
                GetSaveInData()->GetImageManager()->replaceImages(
                    GetImageType(), aURLSeq, aGraphicSeq );

                Image aImage( backup );
                aContentsListBox->GetModel()->Remove( pActEntry );

                SvLBoxEntry* pNewLBEntry =
                    InsertEntryIntoUI( pEntry, nSelectionPos );

                aContentsListBox->SetCheckButtonState( pNewLBEntry,
                    pEntry->IsVisible() ?
                        SV_BUTTON_CHECKED : SV_BUTTON_UNCHECKED );

                aContentsListBox->Select( pNewLBEntry );
                aContentsListBox->MakeVisible( pNewLBEntry );

                // reset backup in entry
                pEntry->SetBackupGraphic(
                    uno::Reference< graphic::XGraphic >() );

                GetSaveInData()->PersistChanges(
                    GetSaveInData()->GetImageManager() );
            }
            catch ( uno::Exception& )
            {
                OSL_TRACE("Error resetting image");
            }
            break;
        }
    }

    if ( bNeedsApply == TRUE )
    {
        (( ToolbarSaveInData* ) GetSaveInData())->ApplyToolbar( pToolbar );
        UpdateButtonStates();
    }

    return 1;
}

void SvxToolbarConfigPage::Init()
{
    // ensure that the UI is cleared before populating it
    aTopLevelListBox.Clear();
    aContentsListBox->Clear();

    ReloadTopLevelListBox();

    USHORT nPos = 0;
    if ( m_aURLToSelect.getLength() != 0 )
    {
        for ( USHORT i = 0 ; i < aTopLevelListBox.GetEntryCount(); i++ )
        {
            SvxConfigEntry* pData =
                (SvxConfigEntry*) aTopLevelListBox.GetEntryData( i );

            if ( pData->GetCommand().equals( m_aURLToSelect ) )
            {
                nPos = i;
                break;
            }
        }

        // in future select the default toolbar: Standard
        m_aURLToSelect = OUString::createFromAscii( ITEM_TOOLBAR_URL );
        m_aURLToSelect += OUString::createFromAscii( "standardbar" );
    }

    aTopLevelListBox.SelectEntryPos(nPos, TRUE);
    aTopLevelListBox.GetSelectHdl().Call(this);
}

SaveInData* SvxToolbarConfigPage::CreateSaveInData(
    const uno::Reference< css::ui::XUIConfigurationManager >& xCfgMgr,
    const uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
    const OUString& aModuleId,
    bool bDocConfig )
{
    return static_cast< SaveInData* >(
        new ToolbarSaveInData( xCfgMgr, xParentCfgMgr, aModuleId, bDocConfig ));
}

ToolbarSaveInData::ToolbarSaveInData(
    const uno::Reference <
        css::ui::XUIConfigurationManager >& xCfgMgr,
    const uno::Reference <
        css::ui::XUIConfigurationManager >& xParentCfgMgr,
    const OUString& aModuleId,
    bool docConfig )
    :
        SaveInData ( xCfgMgr, xParentCfgMgr, aModuleId, docConfig ),
        m_aDescriptorContainer(
            RTL_CONSTASCII_USTRINGPARAM( ITEM_DESCRIPTOR_CONTAINER ) ),
        pRootEntry( 0 )
{
    // Initialize the m_xPersistentWindowState variable which is used
    // to get the default properties of system toolbars such as name
    uno::Reference< container::XNameAccess > xPWSS(
        m_xServiceManager->createInstance(
            OUString( RTL_CONSTASCII_USTRINGPARAM(
                "com.sun.star.ui.WindowStateConfiguration" ) ) ),
        uno::UNO_QUERY );

    if ( xPWSS.is() )
        xPWSS->getByName( aModuleId ) >>= m_xPersistentWindowState;
}

ToolbarSaveInData::~ToolbarSaveInData()
{
    if ( pRootEntry != NULL )
    {
        delete pRootEntry;
    }
}

void ToolbarSaveInData::SetSystemStyle(
    uno::Reference< frame::XFrame > xFrame,
    const OUString& rResourceURL,
    sal_Int32 nStyle )
{
    // change the style using the API
    SetSystemStyle( rResourceURL, nStyle );

    // this code is a temporary hack as the UI is not updating after
    // changing the toolbar style via the API
    uno::Reference< css::frame::XLayoutManager > xLayoutManager;
    Window *window = NULL;

    uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
    if ( xPropSet.is() )
    {
        uno::Any a = xPropSet->getPropertyValue(
            OUString( RTL_CONSTASCII_USTRINGPARAM( "LayoutManager" ) ) );
        a >>= xLayoutManager;
    }

    if ( xLayoutManager.is() )
    {
        uno::Reference< css::ui::XUIElement > xUIElement =
            xLayoutManager->getElement( rResourceURL );

        // check reference before we call getRealInterface. The layout manager
        // can only provide references for elements that have been created
        // before. It's possible that the current element is not available.
        uno::Reference< com::sun::star::awt::XWindow > xWindow;
        if ( xUIElement.is() )
            xWindow = uno::Reference< com::sun::star::awt::XWindow >(
                        xUIElement->getRealInterface(), uno::UNO_QUERY );

        window = VCLUnoHelper::GetWindow( xWindow );
    }

    if ( window != NULL && window->GetType() == WINDOW_TOOLBOX )
    {
        ToolBox* toolbox = (ToolBox*)window;

        if ( nStyle == 0 )
        {
            toolbox->SetButtonType( BUTTON_SYMBOL );
        }
        else if ( nStyle == 1 )
        {
            toolbox->SetButtonType( BUTTON_TEXT );
        }
        if ( nStyle == 2 )
        {
            toolbox->SetButtonType( BUTTON_SYMBOLTEXT );
        }
    }
}

void ToolbarSaveInData::SetSystemStyle(
    const OUString& rResourceURL,
    sal_Int32 nStyle )
{
    if ( rResourceURL.indexOf( OUString::createFromAscii( "private" ) ) == 0 &&
         m_xPersistentWindowState.is() &&
         m_xPersistentWindowState->hasByName( rResourceURL ) )
    {
        try
        {
            uno::Sequence< beans::PropertyValue > aProps;

            uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );

            if ( a >>= aProps )
            {
                for ( sal_Int32 i = 0; i < aProps.getLength(); i++ )
                {
                    if ( aProps[ i ].Name.equalsAscii( ITEM_DESCRIPTOR_STYLE) )
                    {
                        aProps[ i ].Value = uno::makeAny( nStyle );
                        break;
                    }
                }
            }

            uno::Reference< container::XNameReplace >
                xNameReplace( m_xPersistentWindowState, uno::UNO_QUERY );

            xNameReplace->replaceByName( rResourceURL, uno::makeAny( aProps ) );
        }
        catch ( uno::Exception& )
        {
            // do nothing, a default value is returned
            OSL_TRACE("Exception setting toolbar style");
        }
    }
}

sal_Int32 ToolbarSaveInData::GetSystemStyle( const OUString& rResourceURL )
{
    sal_Int32 result = 0;

    if ( rResourceURL.indexOf( OUString::createFromAscii( "private" ) ) == 0 &&
         m_xPersistentWindowState.is() &&
         m_xPersistentWindowState->hasByName( rResourceURL ) )
    {
        try
        {
            uno::Sequence< beans::PropertyValue > aProps;
            uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );

            if ( a >>= aProps )
            {
                for ( sal_Int32 i = 0; i < aProps.getLength(); i++ )
                {
                    if ( aProps[ i ].Name.equalsAscii( ITEM_DESCRIPTOR_STYLE) )
                    {
                        aProps[i].Value >>= result;
                        break;
                    }
                }
            }
        }
        catch ( uno::Exception& )
        {
            // do nothing, a default value is returned
        }
    }

    return result;
}

OUString ToolbarSaveInData::GetSystemUIName( const OUString& rResourceURL )
{
    OUString result;

    if ( rResourceURL.indexOf( OUString::createFromAscii( "private" ) ) == 0 &&
         m_xPersistentWindowState.is() &&
         m_xPersistentWindowState->hasByName( rResourceURL ) )
    {
        try
        {
            uno::Sequence< beans::PropertyValue > aProps;
            uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );

            if ( a >>= aProps )
            {
                for ( sal_Int32 i = 0; i < aProps.getLength(); i++ )
                {
                    if ( aProps[ i ].Name.equalsAscii( ITEM_DESCRIPTOR_UINAME) )
                    {
                        aProps[ i ].Value >>= result;
                    }
                }
            }
        }
        catch ( uno::Exception& )
        {
            // do nothing, an empty UIName will be returned
        }
    }

    if ( rResourceURL.indexOf( OUString::createFromAscii( ".uno" ) ) == 0 &&
         m_xCommandToLabelMap.is() &&
         m_xCommandToLabelMap->hasByName( rResourceURL ) )
    {
        uno::Any a;
        try
        {
            a = m_xCommandToLabelMap->getByName( rResourceURL );

            uno::Sequence< beans::PropertyValue > aPropSeq;
            if ( a >>= aPropSeq )
            {
                for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
                {
                    if ( aPropSeq[i].Name.equalsAscii( ITEM_DESCRIPTOR_LABEL ) )
                    {
                        aPropSeq[i].Value >>= result;
                    }
                }
            }
        }
        catch ( uno::Exception& )
        {
            // not a system command name
        }
    }

    return result;
}

bool EntrySort( SvxConfigEntry* a, SvxConfigEntry* b )
{
    return a->GetName().compareTo( b->GetName() ) < 0;
}

SvxEntries* ToolbarSaveInData::GetEntries()
{
    typedef ::std::hash_map< ::rtl::OUString,
                             bool,
                             ::rtl::OUStringHash,
                             ::std::equal_to< ::rtl::OUString > > ToolbarInfo;

    ToolbarInfo aToolbarInfo;

    if ( pRootEntry == NULL )
    {

        pRootEntry = new SvxConfigEntry(
            String::CreateFromAscii("MainToolbars"), String(), TRUE );

        uno::Sequence< uno::Sequence < beans::PropertyValue > > info =
            GetConfigManager()->getUIElementsInfo(
                css::ui::UIElementType::TOOLBAR );

        for ( sal_Int32 i = 0; i < info.getLength(); i++ )
        {
            uno::Sequence< beans::PropertyValue > props = info[ i ];

            OUString url;
            OUString systemname;
            OUString uiname;

            for ( sal_Int32 j = 0; j < props.getLength(); j++ )
            {
                if ( props[ j ].Name.equalsAscii( ITEM_DESCRIPTOR_RESOURCEURL) )
                {
                    props[ j ].Value >>= url;
                    systemname = url.copy( url.lastIndexOf( '/' ) + 1 );
                }
                else if ( props[ j ].Name.equalsAscii( ITEM_DESCRIPTOR_UINAME) )
                {
                    props[ j ].Value >>= uiname;
                }
            }

            try
            {
                uno::Reference< container::XIndexAccess > xToolbarSettings =
                    GetConfigManager()->getSettings( url, sal_False );

                uno::Reference< beans::XPropertySet > props(
                    xToolbarSettings, uno::UNO_QUERY );

                if ( uiname.getLength() == 0 )
                {
                    // try to get the name from m_xPersistentWindowState
                    uiname = GetSystemUIName( url );

                    if ( uiname.getLength() == 0 )
                    {
                        uiname = systemname;
                    }
                }

                SvxConfigEntry* pEntry = new SvxConfigEntry(
                    uiname, url, TRUE );

                pEntry->SetMain( TRUE );
                pEntry->SetStyle( GetSystemStyle( url ) );


                // insert into hash_map to filter duplicates from the parent
                aToolbarInfo.insert( ToolbarInfo::value_type( systemname, true ));

                OUString custom = OUString::createFromAscii(CUSTOM_TOOLBAR_STR);
                if ( systemname.indexOf( custom ) == 0 )
                {
                    pEntry->SetUserDefined( TRUE );
                }
                else
                {
                    pEntry->SetUserDefined( FALSE );
                }

                pRootEntry->GetEntries()->push_back( pEntry );

                LoadToolbar( xToolbarSettings, pEntry );
            }
            catch ( container::NoSuchElementException& )
            {
                // TODO, handle resourceURL with no settings
            }
        }

        uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr = GetParentConfigManager();
        if ( xParentCfgMgr.is() )
        {
            // Retrieve also the parent toolbars to make it possible
            // to configure module toolbars and save them into the document
            // config manager.
            uno::Sequence< uno::Sequence < beans::PropertyValue > > info =
                xParentCfgMgr->getUIElementsInfo(
                    css::ui::UIElementType::TOOLBAR );

            for ( sal_Int32 i = 0; i < info.getLength(); i++ )
            {
                uno::Sequence< beans::PropertyValue > props = info[ i ];

                OUString url;
                OUString systemname;
                OUString uiname;

                for ( sal_Int32 j = 0; j < props.getLength(); j++ )
                {
                    if ( props[ j ].Name.equalsAscii( ITEM_DESCRIPTOR_RESOURCEURL) )
                    {
                        props[ j ].Value >>= url;
                        systemname = url.copy( url.lastIndexOf( '/' ) + 1 );
                    }
                    else if ( props[ j ].Name.equalsAscii( ITEM_DESCRIPTOR_UINAME) )
                    {
                        props[ j ].Value >>= uiname;
                    }
                }

                // custom toolbars of the parent are not visible in the document layer
                OUString custom = OUString::createFromAscii(CUSTOM_TOOLBAR_STR);
                if ( systemname.indexOf( custom ) == 0 )
                    continue;

                // check if toolbar is already in the document layer
                ToolbarInfo::const_iterator pIter = aToolbarInfo.find( systemname );
                if ( pIter == aToolbarInfo.end() )
                {
                    aToolbarInfo.insert( ToolbarInfo::value_type( systemname, true ));

                    try
                    {
                        uno::Reference< container::XIndexAccess > xToolbarSettings =
                            xParentCfgMgr->getSettings( url, sal_False );

                        uno::Reference< beans::XPropertySet > props(
                            xToolbarSettings, uno::UNO_QUERY );

                        if ( uiname.getLength() == 0 )
                        {
                            // try to get the name from m_xPersistentWindowState
                            uiname = GetSystemUIName( url );

                            if ( uiname.getLength() == 0 )
                            {
                                uiname = systemname;
                            }
                        }

                        SvxConfigEntry* pEntry = new SvxConfigEntry(
                            uiname, url, TRUE, TRUE );

                        pEntry->SetMain( TRUE );
                        pEntry->SetStyle( GetSystemStyle( url ) );

                        OUString custom = OUString::createFromAscii(CUSTOM_TOOLBAR_STR);
                        if ( systemname.indexOf( custom ) == 0 )
                        {
                            pEntry->SetUserDefined( TRUE );
                        }
                        else
                        {
                            pEntry->SetUserDefined( FALSE );
                        }

                        pRootEntry->GetEntries()->push_back( pEntry );

                        LoadToolbar( xToolbarSettings, pEntry );
                    }
                    catch ( container::NoSuchElementException& )
                    {
                        // TODO, handle resourceURL with no settings
                    }
                }
            }
        }

        std::sort( GetEntries()->begin(), GetEntries()->end(), EntrySort );
    }

    return pRootEntry->GetEntries();
}

void
ToolbarSaveInData::SetEntries( SvxEntries* pNewEntries )
{
    // delete old menu hierarchy first
    if ( pRootEntry != NULL && pRootEntry->GetEntries() != NULL )
    {
        delete pRootEntry->GetEntries();
    }

    // now set new menu hierarchy
    pRootEntry->SetEntries( pNewEntries );
}

bool
ToolbarSaveInData::HasURL( const OUString& rURL )
{
    SvxEntries::const_iterator iter = GetEntries()->begin();
    SvxEntries::const_iterator end = GetEntries()->end();

    while ( iter != end )
    {
        SvxConfigEntry* pEntry = *iter;

        if ( pEntry->GetCommand().equals( rURL ) )
        {
            if ( pEntry->IsParentData() )
                return FALSE;
            else
                return TRUE;
        }

        iter++;
    }
    return FALSE;
}

bool ToolbarSaveInData::HasSettings()
{
    // return true if there is at least one toolbar entry
    if ( GetEntries()->size() > 0 )
    {
        return TRUE;
    }
    return FALSE;
}

void ToolbarSaveInData::Reset()
{
    SvxEntries::const_iterator toolbars = GetEntries()->begin();
    SvxEntries::const_iterator end = GetEntries()->end();

    // reset each toolbar by calling removeSettings for it's toolbar URL
    for ( ; toolbars != end; toolbars++ )
    {
        SvxConfigEntry* pToolbar = *toolbars;

        try
        {
            OUString url = pToolbar->GetCommand();
            GetConfigManager()->removeSettings( url );
        }
        catch ( uno::Exception& )
        {
            // error occured removing the settings
            // TODO - add error dialog in future?
        }
    }

    // persist changes to toolbar storage
    PersistChanges( GetConfigManager() );

    // now delete the root SvxConfigEntry the next call to GetEntries()
    // causes it to be reinitialised
    delete pRootEntry;
    pRootEntry = NULL;

    // reset all icons to default
    try
    {
        GetImageManager()->reset();
        PersistChanges( GetImageManager() );
    }
    catch ( uno::Exception& )
    {
        OSL_TRACE("Error resetting all icons when resetting toolbars");
    }
}

bool ToolbarSaveInData::Apply()
{
    // toolbar changes are instantly applied
    return FALSE;
}

void ToolbarSaveInData::ApplyToolbar(
    uno::Reference< container::XIndexContainer >& rToolbarBar,
    uno::Reference< lang::XSingleComponentFactory >& rFactory,
    SvxConfigEntry* pToolbarData )
{
    SvxEntries::const_iterator iter = pToolbarData->GetEntries()->begin();
    SvxEntries::const_iterator end = pToolbarData->GetEntries()->end();

    for ( ; iter != end; iter++ )
    {
        SvxConfigEntry* pEntry = *iter;

        if ( pEntry->IsPopup() )
        {
            uno::Sequence< beans::PropertyValue > aPropValueSeq =
                ConvertToolbarEntry( m_xCommandToLabelMap, pEntry );

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

            sal_Int32 nIndex = aPropValueSeq.getLength();
            aPropValueSeq.realloc( nIndex + 1 );
            aPropValueSeq[nIndex].Name = m_aDescriptorContainer;
            aPropValueSeq[nIndex].Value <<= xSubMenuBar;
            rToolbarBar->insertByIndex(
                rToolbarBar->getCount(), uno::makeAny( aPropValueSeq ));

            ApplyToolbar( xSubMenuBar, rFactory, pEntry );
        }
        else if ( pEntry->IsSeparator() )
        {
            rToolbarBar->insertByIndex(
                rToolbarBar->getCount(), uno::makeAny( m_aSeparatorSeq ));
        }
        else
        {
            uno::Sequence< beans::PropertyValue > aPropValueSeq =
                ConvertToolbarEntry( m_xCommandToLabelMap, pEntry );

            rToolbarBar->insertByIndex(
                rToolbarBar->getCount(), uno::makeAny( aPropValueSeq ));
        }
    }
}

void ToolbarSaveInData::ApplyToolbar( SvxConfigEntry* pToolbar )
{
    // Apply new toolbar structure to our settings container
    uno::Reference< container::XIndexAccess > xSettings(
        GetConfigManager()->createSettings(), uno::UNO_QUERY );

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

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

    ApplyToolbar( xIndexContainer, xFactory, pToolbar );

    uno::Reference< beans::XPropertySet > xProps(
        xSettings, uno::UNO_QUERY );

    if ( pToolbar->IsUserDefined() )
    {
        xProps->setPropertyValue(
            OUString::createFromAscii( ITEM_DESCRIPTOR_UINAME ),
            uno::makeAny( OUString( pToolbar->GetName() ) ) );
    }

    try
    {
        if ( GetConfigManager()->hasSettings( pToolbar->GetCommand() ) )
        {
            GetConfigManager()->replaceSettings(
                pToolbar->GetCommand(), xSettings );
        }
        else
        {
            GetConfigManager()->insertSettings(
                pToolbar->GetCommand(), xSettings );
            if ( pToolbar->IsParentData() )
                pToolbar->SetParentData( false );
        }
    }
    catch ( container::NoSuchElementException& )
    {
        OSL_TRACE("caught container::NoSuchElementException saving settings");
    }
    catch ( com::sun::star::io::IOException& )
    {
        OSL_TRACE("caught IOException saving settings");
    }
    catch ( com::sun::star::uno::Exception& )
    {
        OSL_TRACE("caught some other exception saving settings");
    }

    PersistChanges( GetConfigManager() );
}

void ToolbarSaveInData::CreateToolbar( SvxConfigEntry* pToolbar )
{
    // show the new toolbar in the UI also
    uno::Reference< container::XIndexAccess >
        xSettings( GetConfigManager()->createSettings(), uno::UNO_QUERY );

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

    uno::Reference< beans::XPropertySet >
        xPropertySet( xSettings, uno::UNO_QUERY );

    xPropertySet->setPropertyValue(
        OUString::createFromAscii( ITEM_DESCRIPTOR_UINAME ),
            uno::makeAny( pToolbar->GetName() ) );

    try
    {
        GetConfigManager()->insertSettings( pToolbar->GetCommand(), xSettings );
    }
    catch ( container::ElementExistException& )
    {
        OSL_TRACE("caught ElementExistsException saving settings");
    }
    catch ( com::sun::star::lang::IllegalArgumentException& )
    {
        OSL_TRACE("caught IOException saving settings");
    }
    catch ( com::sun::star::lang::IllegalAccessException& )
    {
        OSL_TRACE("caught IOException saving settings");
    }
    catch ( com::sun::star::uno::Exception& )
    {
        OSL_TRACE("caught some other exception saving settings");
    }

    GetEntries()->push_back( pToolbar );

    PersistChanges( GetConfigManager() );
}

void ToolbarSaveInData::RemoveToolbar( SvxConfigEntry* pToolbar )
{
    try
    {
        bool bIsModuleToolbar = pToolbar->IsParentData();

        OUString url = pToolbar->GetCommand();
        GetConfigManager()->removeSettings( url );
        RemoveEntry( GetEntries(), pToolbar );
        delete pToolbar;

        PersistChanges( GetConfigManager() );
    }
    catch ( uno::Exception& )
    {
        // error occured removing the settings
    }
}

void ToolbarSaveInData::RestoreToolbar( SvxConfigEntry* pToolbar )
{
    OUString url = pToolbar->GetCommand();

    // Restore of toolbar is done by removing it from
    // it's configuration manager and then getting it again
    bool bParentToolbar = pToolbar->IsParentData();

    // Cannot restore parent toolbar
    if ( bParentToolbar )
        return;

    try
    {
        GetConfigManager()->removeSettings( url );
        pToolbar->GetEntries()->clear();
        PersistChanges( GetConfigManager() );
    }
    catch ( uno::Exception& )
    {
        // if an error occurs removing the settings then just return
        return;
    }

    // Now reload the toolbar settings
    try
    {
        uno::Reference< container::XIndexAccess > xToolbarSettings;
        if ( IsDocConfig() )
        {
            xToolbarSettings = GetParentConfigManager()->getSettings( url, sal_False );
            pToolbar->SetParentData( true );
        }
        else
            xToolbarSettings = GetConfigManager()->getSettings( url, sal_False );

        LoadToolbar( xToolbarSettings, pToolbar );

        // After reloading, ensure that the icon is reset of each entry
        // in the toolbar
        SvxEntries::const_iterator iter = pToolbar->GetEntries()->begin();
        uno::Sequence< OUString > aURLSeq( 1 );
        for ( ; iter != pToolbar->GetEntries()->end(); iter++ )
        {
            SvxConfigEntry* pEntry = *iter;
            aURLSeq[ 0 ] = pEntry->GetCommand();

            try
            {
                GetImageManager()->removeImages( GetImageType(), aURLSeq );
            }
               catch ( uno::Exception& )
               {
                OSL_TRACE("Error restoring icon when resetting toolbar");
               }
        }
        PersistChanges( GetImageManager() );
    }
    catch ( container::NoSuchElementException& )
    {
        // cannot find the resource URL after removing it
        // so no entry will appear in the toolbar list
    }
}

void ToolbarSaveInData::ReloadToolbar( const OUString& rResourceURL )
{
    SvxEntries::const_iterator iter = GetEntries()->begin();
    SvxConfigEntry* pToolbar = NULL;

    for ( ; iter != GetEntries()->end(); iter++ )
    {
        SvxConfigEntry* pEntry = *iter;

        if ( pEntry->GetCommand().equals( rResourceURL ) )
        {
            pToolbar = pEntry;
            break;
        }
    }

    if ( pToolbar != NULL )
    {
        delete pToolbar->GetEntries();

        try
        {
            uno::Reference< container::XIndexAccess > xToolbarSettings;

            if ( pToolbar->IsParentData() )
            {
                xToolbarSettings = GetParentConfigManager()->getSettings(
                    pToolbar->GetCommand(), sal_False);
            }
            else
            {
                xToolbarSettings = GetConfigManager()->getSettings(
                    pToolbar->GetCommand(), sal_False);
            }

            LoadToolbar( xToolbarSettings, pToolbar );
        }
        catch ( container::NoSuchElementException& )
        {
            // toolbar not found for some reason
            // it will not appear in the toolbar list
        }
    }
}

bool ToolbarSaveInData::LoadToolbar(
    const uno::Reference< container::XIndexAccess >& xToolbarSettings,
    SvxConfigEntry* pParentData )
{
    SvxEntries*         pEntries            = pParentData->GetEntries();

    for ( sal_Int32 nIndex = 0; nIndex < xToolbarSettings->getCount(); nIndex++ )
    {
        uno::Reference< container::XIndexAccess >   xSubMenu;
        OUString                aCommandURL;
        OUString                aHelpURL;
        OUString                aLabel;
        bool                    bIsUserDefined = TRUE;
        sal_Bool                bIsVisible;
        sal_Int32               nStyle;

        sal_uInt16 nType( css::ui::ItemType::DEFAULT );

        bool bItem = GetToolbarItemData( xToolbarSettings, nIndex, aCommandURL,
            aHelpURL, aLabel, nType, bIsVisible, nStyle, xSubMenu );

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

                // If custom label not set retrieve it from the command
                // to info service
                if ( aLabel.equals( OUString() ) )
                {
                    uno::Sequence< beans::PropertyValue > aPropSeq;
                    if ( a >>= aPropSeq )
                    {
                        for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
                        {
                            if ( aPropSeq[i].Name.equalsAscii( ITEM_DESCRIPTOR_LABEL ) )
                            {
                                aPropSeq[i].Value >>= aLabel;
                                break;
                            }
                        }
                    }
                }

                if ( xSubMenu.is() )
                {
                    SvxConfigEntry* pEntry = new SvxConfigEntry(
                        aLabel, aCommandURL, TRUE );

                    pEntry->SetUserDefined( bIsUserDefined );
                    pEntry->SetHelpURL( aHelpURL );
                    pEntry->SetVisible( bIsVisible );

                    pEntries->push_back( pEntry );

                    LoadToolbar( xSubMenu, pEntry );
                }
                else
                {
                    SvxConfigEntry* pEntry = new SvxConfigEntry(
                        aLabel, aCommandURL, FALSE );
                    pEntry->SetUserDefined( bIsUserDefined );
                    pEntry->SetHelpURL( aHelpURL );
                    pEntry->SetVisible( bIsVisible );
                    pEntry->SetStyle( nStyle );
                    pEntries->push_back( pEntry );
                }
            }
            else
            {
                SvxConfigEntry* pEntry = new SvxConfigEntry;
                pEntry->SetUserDefined( bIsUserDefined );
                pEntries->push_back( pEntry );
            }
        }
    }

    return true;
}

IMPL_LINK( SvxToolbarConfigPage, SelectToolbarEntry, Control *, pBox )
{
    UpdateButtonStates();
    return 1;
}

void SvxToolbarConfigPage::UpdateButtonStates()
{
    PopupMenu* pPopup = aModifyCommandButton.GetPopupMenu();

    // disable all buttons first and then re-enable buttons as needed
    aMoveUpButton.Enable( FALSE );
    aMoveDownButton.Enable( FALSE );

    pPopup->EnableItem( ID_RENAME, FALSE );
    pPopup->EnableItem( ID_DELETE, FALSE );
    pPopup->EnableItem( ID_BEGIN_GROUP, FALSE );
    pPopup->EnableItem( ID_DEFAULT_COMMAND, FALSE );
    pPopup->EnableItem( ID_ICON_ONLY, FALSE );
    pPopup->EnableItem( ID_ICON_AND_TEXT, FALSE );
    pPopup->EnableItem( ID_TEXT_ONLY, FALSE );
    pPopup->EnableItem( ID_CHANGE_SYMBOL, FALSE );
    pPopup->EnableItem( ID_RESET_SYMBOL, FALSE );

    aDescriptionText.SetText( String() );

    SvLBoxEntry* selection = aContentsListBox->GetCurEntry();
    if ( aContentsListBox->GetEntryCount() == 0 || selection == NULL )
    {
        return;
    }

    SvLBoxEntry* first = aContentsListBox->First();
    SvLBoxEntry* last = aContentsListBox->Last();

    aMoveUpButton.Enable( selection != first );
    aMoveDownButton.Enable( selection != last );

    SvxConfigEntry* pEntryData =
        (SvxConfigEntry*) selection->GetUserData();

    if ( pEntryData->IsSeparator() )
    {
        pPopup->EnableItem( ID_DELETE, TRUE );
        pPopup->EnableItem( ID_BEGIN_GROUP, FALSE );
        pPopup->EnableItem( ID_RENAME, FALSE );
    }
    else
    {
        pPopup->EnableItem( ID_BEGIN_GROUP, TRUE );
        pPopup->EnableItem( ID_DELETE, TRUE );
        pPopup->EnableItem( ID_RENAME, TRUE );
        pPopup->EnableItem( ID_ICON_ONLY, TRUE );
        pPopup->EnableItem( ID_ICON_AND_TEXT, TRUE );
        pPopup->EnableItem( ID_TEXT_ONLY, TRUE );
        pPopup->EnableItem( ID_CHANGE_SYMBOL, TRUE );

        if ( !pEntryData->IsUserDefined() )
        {
            pPopup->EnableItem( ID_DEFAULT_COMMAND, TRUE );
        }

        if ( pEntryData->IsIconModified() )
        {
            pPopup->EnableItem( ID_RESET_SYMBOL, TRUE );
        }

        aDescriptionText.SetText( pEntryData->GetHelpText() );
    }
}

short SvxToolbarConfigPage::QueryReset()
{
    String msg =
        String( ResId( RID_SVXSTR_CONFIRM_TOOLBAR_RESET, DIALOG_MGR() ) );

    String saveInName = aSaveInListBox.GetEntry(
        aSaveInListBox.GetSelectEntryPos() );

    OUString label = replaceSaveInName( msg, saveInName );

    QueryBox qbox( this, WB_YES_NO, label );

    return qbox.Execute();
}

IMPL_LINK( SvxToolbarConfigPage, SelectToolbar, ListBox *, pBox )
{
    aContentsListBox->Clear();

    SvxConfigEntry* pToolbar = GetTopLevelSelection();
    if ( pToolbar == NULL )
    {
        aModifyTopLevelButton.Enable( FALSE );
        aModifyCommandButton.Enable( FALSE );
        aAddCommandsButton.Enable( FALSE );

        return 0;
    }

    aModifyTopLevelButton.Enable( TRUE );
    aModifyCommandButton.Enable( TRUE );
    aAddCommandsButton.Enable( TRUE );

    PopupMenu* pPopup = aModifyTopLevelButton.GetPopupMenu();

    pPopup->EnableItem( ID_DELETE, pToolbar->IsDeletable() );
    pPopup->EnableItem( ID_RENAME, pToolbar->IsRenamable() );
    pPopup->EnableItem( ID_DEFAULT_STYLE, !pToolbar->IsRenamable() );

    switch( pToolbar->GetStyle() )
    {
        case 0:
        {
            pPopup->CheckItem( ID_ICONS_ONLY );
            break;
        }
        case 1:
        {
            pPopup->CheckItem( ID_TEXT_ONLY );
            break;
        }
        case 2:
        {
            pPopup->CheckItem( ID_ICONS_AND_TEXT );
            break;
        }
    }

    SvxEntries* pEntries = pToolbar->GetEntries();
    SvxEntries::const_iterator iter = pEntries->begin();

    for ( ; iter != pEntries->end(); iter++ )
    {
        SvxConfigEntry* pEntry = *iter;

        SvLBoxEntry* pNewLBEntry = InsertEntryIntoUI( pEntry );

        if (pEntry->IsBinding())
        {
            aContentsListBox->SetCheckButtonState( pNewLBEntry,
                pEntry->IsVisible() ? SV_BUTTON_CHECKED : SV_BUTTON_UNCHECKED );
        }
        else
        {
            aContentsListBox->SetCheckButtonState(
                pNewLBEntry, SV_BUTTON_TRISTATE );
        }
    }

    UpdateButtonStates();

    return 0;
}

IMPL_LINK( SvxToolbarConfigPage, NewToolbarHdl, Button *, pButton )
{
    String prefix =
        String( ResId( RID_SVXSTR_NEW_TOOLBAR, DIALOG_MGR() ) );

    OUString aNewName =
        generateCustomName( prefix, GetSaveInData()->GetEntries() );

    OUString aNewURL =
        generateCustomURL( GetSaveInData()->GetEntries() );

    SvxNewToolbarDialog* pNameDialog = new SvxNewToolbarDialog( 0, aNewName );

    USHORT nInsertPos;
    for ( USHORT i = 0 ; i < aSaveInListBox.GetEntryCount(); i++ )
    {
        SaveInData* pData =
            (SaveInData*) aSaveInListBox.GetEntryData( i );

        nInsertPos = pNameDialog->aSaveInListBox.InsertEntry(
            aSaveInListBox.GetEntry( i ) );

        pNameDialog->aSaveInListBox.SetEntryData( nInsertPos, pData );
    }

    pNameDialog->aSaveInListBox.SelectEntryPos(
        aSaveInListBox.GetSelectEntryPos(), TRUE );

    bool ret = pNameDialog->Execute();
    if ( ret == RET_OK )
    {
        pNameDialog->GetName( aNewName );

        nInsertPos = pNameDialog->aSaveInListBox.GetSelectEntryPos();

        ToolbarSaveInData* pData = (ToolbarSaveInData*)
            pNameDialog->aSaveInListBox.GetEntryData( nInsertPos );

        SvxConfigEntry* pToolbar =
            new SvxConfigEntry( aNewName, aNewURL, TRUE );

        pToolbar->SetUserDefined( TRUE );
        pToolbar->SetMain( TRUE );

        pData->CreateToolbar( pToolbar );

        if ( GetSaveInData() != pData )
        {
            aSaveInListBox.SelectEntryPos( nInsertPos, TRUE );
            aSaveInListBox.GetSelectHdl().Call(this);
        }

        nInsertPos = aTopLevelListBox.InsertEntry( pToolbar->GetName() );
        aTopLevelListBox.SetEntryData( nInsertPos, pToolbar );
        aTopLevelListBox.SelectEntryPos( nInsertPos, TRUE );
        aTopLevelListBox.GetSelectHdl().Call(this);

        pData->SetModified( TRUE );
    }

    delete pNameDialog;

    return 0;
}

IMPL_LINK( SvxToolbarConfigPage, AddCommandsHdl, Button *, pButton )
{
    if ( pSelectorDlg == NULL )
    {
        // Create Script Selector which shows slot commands
        pSelectorDlg = new SvxScriptSelectorDialog( this, TRUE, m_xFrame );

        // Position the Script Selector over the Add button so it is
        // beside the menu contents list and does not obscure it
        pSelectorDlg->SetPosPixel( aAddCommandsButton.GetPosPixel() );

        pSelectorDlg->SetAddHdl(
            LINK( this, SvxToolbarConfigPage, AddFunctionHdl ) );
    }

    pSelectorDlg->SetImageProvider(
        static_cast< ImageProvider* >( GetSaveInData() ) );

    pSelectorDlg->Show();
    return 1;
}

IMPL_LINK( SvxToolbarConfigPage, AddFunctionHdl,
    SvxScriptSelectorDialog *, pDialog )
{
    AddFunction();

    return 0;
}

SvLBoxEntry* SvxToolbarConfigPage::AddFunction(
    SvLBoxEntry* pTarget, bool bFront, bool bAllowDuplicates )
{
    SvLBoxEntry* pNewLBEntry =
        SvxConfigPage::AddFunction( pTarget, bFront, bAllowDuplicates );

    SvxConfigEntry* pEntry = (SvxConfigEntry*) pNewLBEntry->GetUserData();

    if ( pEntry->IsBinding() )
    {
        pEntry->SetVisible( TRUE );
        aContentsListBox->SetCheckButtonState(
            pNewLBEntry, SV_BUTTON_CHECKED );
    }
    else
    {
        aContentsListBox->SetCheckButtonState(
            pNewLBEntry, SV_BUTTON_TRISTATE );
    }

    // get currently selected toolbar and apply change
    SvxConfigEntry* pToolbar = GetTopLevelSelection();

    if ( pToolbar != NULL )
    {
        ( ( ToolbarSaveInData* ) GetSaveInData() )->ApplyToolbar( pToolbar );
    }

    return pNewLBEntry;
}

// -----------------------------------------------------------------------

SvxToolbarEntriesListBox::SvxToolbarEntriesListBox(
    Window* pParent, const ResId& aResId )
    :
        SvxMenuEntriesListBox( pParent, aResId ),
        pPage( ( SvxToolbarConfigPage* ) pParent )
{
    m_pButtonData = new SvLBoxButtonData( this );
    BuildCheckBoxButtonImages( m_pButtonData );
    EnableCheckButton( m_pButtonData );

    m_bHiContrastMode = GetDisplayBackground().GetColor().IsDark();
}

// --------------------------------------------------------

SvxToolbarEntriesListBox::~SvxToolbarEntriesListBox()
{
    delete m_pButtonData;
}

// --------------------------------------------------------

void SvxToolbarEntriesListBox::BuildCheckBoxButtonImages( SvLBoxButtonData* pData )
{
    // Build checkbox images according to the current application
    // settings. This is necessary to be able to have correct colors
    // in all color modes, like high contrast.
    const AllSettings& rSettings = Application::GetSettings();

    VirtualDevice   aDev;
    Size            aSize( 26, 20 );

    aDev.SetOutputSizePixel( aSize );

    Image aImage = GetSizedImage( aDev, aSize,
        CheckBox::GetCheckImage( rSettings, BUTTON_DRAW_DEFAULT ));

    // Fill button data struct with new images
    pData->aBmps[SV_BMP_UNCHECKED]      = aImage;
    pData->aBmps[SV_BMP_CHECKED]        = GetSizedImage( aDev, aSize, CheckBox::GetCheckImage( rSettings, BUTTON_DRAW_CHECKED ));
    pData->aBmps[SV_BMP_HICHECKED]      = GetSizedImage( aDev, aSize, CheckBox::GetCheckImage( rSettings, BUTTON_DRAW_CHECKED | BUTTON_DRAW_PRESSED ));
    pData->aBmps[SV_BMP_HIUNCHECKED]    = GetSizedImage( aDev, aSize, CheckBox::GetCheckImage( rSettings, BUTTON_DRAW_DEFAULT | BUTTON_DRAW_PRESSED));
    pData->aBmps[SV_BMP_TRISTATE]       = GetSizedImage( aDev, aSize, Image() ); // Use tristate bitmaps to have no checkbox for separator entries
    pData->aBmps[SV_BMP_HITRISTATE]     = GetSizedImage( aDev, aSize, Image() );

    // Get image size
    m_aCheckBoxImageSizePixel = aImage.GetSizePixel();
}

Image SvxToolbarEntriesListBox::GetSizedImage(
    VirtualDevice& aDev, const Size& aNewSize, const Image& aImage )
{
    // Create new checkbox images for treelistbox. They must have a
    // decent width to have a clear column for the visibility checkbox.

    // Standard transparent color is light magenta as is won't be
    // used for other things
    Color   aFillColor( COL_LIGHTMAGENTA );

    // Position image at the center of (width-2),(height) rectangle.
    // We need 2 pixels to have a bigger border to the next button image
    USHORT  nPosX = std::max( (USHORT) (((( aNewSize.Width() - 2 ) - aImage.GetSizePixel().Width() ) / 2 ) - 1), (USHORT) 0 );
    USHORT  nPosY = std::max( (USHORT) (((( aNewSize.Height() - 2 ) - aImage.GetSizePixel().Height() ) / 2 ) + 1), (USHORT) 0 );
    Point   aPos( nPosX > 0 ? nPosX : 0, nPosY > 0 ? nPosY : 0 );
    aDev.SetFillColor( aFillColor );
    aDev.SetLineColor( aFillColor );
    aDev.DrawRect( Rectangle( Point(), aNewSize ));
    aDev.DrawImage( aPos, aImage );

    // Draw separator line 2 pixels left from the right border
    Color aLineColor = GetDisplayBackground().GetColor().IsDark() ? Color( COL_WHITE ) : Color( COL_BLACK );
    aDev.SetLineColor( aLineColor );
    aDev.DrawLine( Point( aNewSize.Width()-3, 0 ), Point( aNewSize.Width()-3, aNewSize.Height()-1 ));

    // Create new image that uses the fillcolor as transparent
    return Image( aDev.GetBitmap( Point(), aNewSize ), aFillColor );
}

void SvxToolbarEntriesListBox::DataChanged( const DataChangedEvent& rDCEvt )
{
    SvTreeListBox::DataChanged( rDCEvt );

    if (( rDCEvt.GetType() == DATACHANGED_SETTINGS ) &&
        ( rDCEvt.GetFlags() & SETTINGS_STYLE ))
    {
        if ( m_bHiContrastMode != GetDisplayBackground().GetColor().IsDark() )
        {
            // We have to reset all images because we change to/from high contrast mode
            m_bHiContrastMode = GetDisplayBackground().GetColor().IsDark();
        }

        BuildCheckBoxButtonImages( m_pButtonData );
        Invalidate();
    }
}

// --------------------------------------------------------

void SvxToolbarEntriesListBox::ChangeVisibility( SvLBoxEntry* pEntry )
{
    if ( pEntry != NULL )
    {
        SvxConfigEntry* pEntryData =
            (SvxConfigEntry*) pEntry->GetUserData();

        if ( pEntryData->IsBinding() )
        {
            pEntryData->SetVisible( !pEntryData->IsVisible() );

            SvxConfigEntry* pToolbar = pPage->GetTopLevelSelection();

            ToolbarSaveInData* pToolbarSaveInData = ( ToolbarSaveInData* )
                pPage->GetSaveInData();

               pToolbarSaveInData->ApplyToolbar( pToolbar );

            SetCheckButtonState( pEntry, pEntryData->IsVisible() ?
                SV_BUTTON_CHECKED : SV_BUTTON_UNCHECKED );
        }
    }
}

void SvxToolbarEntriesListBox::CheckButtonHdl()
{
    ChangeVisibility( GetHdlEntry() );
}

void SvxToolbarEntriesListBox::KeyInput( const KeyEvent& rKeyEvent )
{
    // space key will change visibility of toolbar items
    if ( rKeyEvent.GetKeyCode() == KEY_SPACE )
    {
        ChangeVisibility( GetCurEntry() );
    }
    else
    {
        // pass on to superclass
        SvxMenuEntriesListBox::KeyInput( rKeyEvent );
    }
}

BOOL SvxToolbarEntriesListBox::NotifyMoving(
    SvLBoxEntry* pTarget, SvLBoxEntry* pSource,
    SvLBoxEntry*& rpNewParent, ULONG& rNewChildPos)
{
    bool result = SvxMenuEntriesListBox::NotifyMoving(
        pTarget, pSource, rpNewParent, rNewChildPos );

    if ( result == TRUE )
    {
        // Instant Apply changes to UI
        SvxConfigEntry* pToolbar = pPage->GetTopLevelSelection();
        if ( pToolbar != NULL )
        {
            ToolbarSaveInData* pSaveInData =
                ( ToolbarSaveInData*) pPage->GetSaveInData();
            pSaveInData->ApplyToolbar( pToolbar );
        }
    }

    return result;
}

BOOL SvxToolbarEntriesListBox::NotifyCopying(
    SvLBoxEntry*  pTarget,
    SvLBoxEntry*  pSource,
    SvLBoxEntry*& rpNewParent,
    ULONG&      rNewChildPos)
{
    if ( !m_bIsInternalDrag )
    {
        ULONG target = pTarget == NULL ? 0 : GetModel()->GetAbsPos( pTarget );

        // if the target is NULL then add function to the start of the list
        ((SvxToolbarConfigPage*)pPage)->AddFunction( pTarget, pTarget == NULL );

        // Instant Apply changes to UI
        SvxConfigEntry* pToolbar = pPage->GetTopLevelSelection();
        if ( pToolbar != NULL )
        {
            ToolbarSaveInData* pSaveInData =
                ( ToolbarSaveInData*) pPage->GetSaveInData();
            pSaveInData->ApplyToolbar( pToolbar );
        }

        // AddFunction already adds the listbox entry so return FALSE
        // to stop another listbox entry being added
        return FALSE;
    }

    // Copying is only allowed from external controls, not within the listbox
    return FALSE;
}

SvxNewToolbarDialog::SvxNewToolbarDialog(
    Window* pWindow, const String& rName )
    :
    ModalDialog     ( pWindow, ResId( MD_NEW_TOOLBAR, DIALOG_MGR() ) ),
    aFtDescription  ( this, ResId( FT_DESCRIPTION ) ),
    aEdtName        ( this, ResId( EDT_STRING ) ),
    aSaveInText     ( this, ResId( TXT_SAVEIN ) ),
    aSaveInListBox  ( this, ResId( LB_SAVEIN ) ),
    aBtnOK          ( this, ResId( BTN_OK ) ),
    aBtnCancel      ( this, ResId( BTN_CANCEL ) ),
    aBtnHelp        ( this, ResId( BTN_HELP ) )
{
    FreeResource();

    aEdtName.SetText( rName );
    aEdtName.SetSelection(Selection(SELECTION_MIN, SELECTION_MAX));
    ModifyHdl(&aEdtName);
    aEdtName.SetModifyHdl(LINK(this, SvxNewToolbarDialog, ModifyHdl));
}

IMPL_LINK(SvxNewToolbarDialog, ModifyHdl, Edit*, pEdit)
{
    if(aCheckNameHdl.IsSet())
        aBtnOK.Enable(aCheckNameHdl.Call(this) > 0);

    return 0;
}

/*******************************************************************************
*
* The SvxIconSelectorDialog class
*
*******************************************************************************/
SvxIconSelectorDialog::SvxIconSelectorDialog( Window *pWindow,
    const uno::Reference< css::ui::XImageManager >& rXImageManager,
    const uno::Reference< css::ui::XImageManager >& rXParentImageManager )
    :
    ModalDialog          ( pWindow, ResId( MD_ICONSELECTOR, DIALOG_MGR() ) ),
    aFtDescription       ( this, ResId( FT_SYMBOLS ) ),
    aTbSymbol            ( this, ResId( TB_SYMBOLS ) ),
    aFtNote              ( this, ResId( FT_NOTE ) ),
    aBtnOK               ( this, ResId( BTN_OK ) ),
    aBtnCancel           ( this, ResId( BTN_CANCEL ) ),
    aBtnHelp             ( this, ResId( BTN_HELP ) ),
    aBtnImport           ( this, ResId( BTN_IMPORT ) ),
    m_xImageManager      ( rXImageManager ),
    m_xParentImageManager( rXParentImageManager )
{
    FreeResource();

    typedef ::std::hash_map< ::rtl::OUString,
                             bool,
                             ::rtl::OUStringHash,
                             ::std::equal_to< ::rtl::OUString > > ImageInfo;

    aTbSymbol.SetPageScroll( TRUE );

    bool bLargeIcons = GetImageType() & css::ui::ImageType::SIZE_LARGE;
    m_nExpectedSize = bLargeIcons ? 26 : 16;

    if ( m_nExpectedSize != 16 )
    {
        aFtNote.SetText( replaceSixteen( aFtNote.GetText(), m_nExpectedSize ) );
    }

    uno::Reference< lang::XMultiServiceFactory > xServiceManager =
        ::comphelper::getProcessServiceFactory();

    if ( xServiceManager.is() )
    {
        m_xGraphProvider = uno::Reference< graphic::XGraphicProvider >(
            xServiceManager->createInstance(
                ::rtl::OUString::createFromAscii(
                    "com.sun.star.graphic.GraphicProvider" ) ),
            uno::UNO_QUERY );
    }

    if ( !m_xGraphProvider.is() )
    {
        aBtnImport.Enable( FALSE );
    }

    uno::Sequence< OUString > names;
    ImageInfo                 aImageInfo;

    if ( m_xParentImageManager.is() )
    {
        names = m_xParentImageManager->getAllImageNames( GetImageType() );
        for ( sal_Int32 n = 0; n < names.getLength(); n++ )
            aImageInfo.insert( ImageInfo::value_type( names[n], false ));
    }

    names = m_xImageManager->getAllImageNames( GetImageType() );
    for ( sal_Int32 n = 0; n < names.getLength(); n++ )
    {
        ImageInfo::iterator pIter = aImageInfo.find( names[n] );
        if ( pIter != aImageInfo.end() )
            pIter->second = true;
        else
            aImageInfo.insert( ImageInfo::value_type( names[n], true ));
    }

    // large growth factor, expecting many entries
    USHORT nId = 1;
    uno::Sequence< OUString > name( 1 );
    ImageInfo::const_iterator pConstIter = aImageInfo.begin();
    while ( pConstIter != aImageInfo.end() )
    {
        name[ 0 ] = pConstIter->first;

        uno::Sequence< uno::Reference< graphic::XGraphic> > graphics;
        try
        {
            if ( pConstIter->second )
                graphics = m_xImageManager->getImages( GetImageType(), name );
            else
                graphics = m_xParentImageManager->getImages( GetImageType(), name );
        }
        catch ( uno::Exception& )
        {
            // can't get sequence for this name so it will not be
            // added to the list
        }

        if ( graphics.getLength() > 0 )
        {
            Image img = Image( graphics[ 0 ] );
            aTbSymbol.InsertItem( nId, img, pConstIter->first );

            graphics[ 0 ]->acquire();

            aTbSymbol.SetItemData(
                nId, static_cast< void * > ( graphics[ 0 ].get() ) );

            ++nId;
        }

        ++pConstIter;
    }

    aTbSymbol.SetSelectHdl( LINK(this, SvxIconSelectorDialog, SelectHdl) );
    aBtnImport.SetClickHdl( LINK(this, SvxIconSelectorDialog, ImportHdl) );
}

SvxIconSelectorDialog::~SvxIconSelectorDialog()
{
    USHORT nCount = aTbSymbol.GetItemCount();

    for (USHORT n = 0; n < nCount; n++ )
    {
        USHORT nId = aTbSymbol.GetItemId(n);

        uno::XInterface* xi = static_cast< uno::XInterface* >(
            aTbSymbol.GetItemData( aTbSymbol.GetItemId( n ) ) );

        if ( xi != NULL )
        {
            xi->release();
        }
    }
}

uno::Reference< graphic::XGraphic> SvxIconSelectorDialog::GetSelectedIcon()
{
    uno::Reference< graphic::XGraphic > result;

    USHORT nId;
    for ( USHORT n = 0; n < aTbSymbol.GetItemCount(); n++ )
    {
        nId = aTbSymbol.GetItemId( n );
        if ( aTbSymbol.IsItemChecked( nId ) )
        {
            result = uno::Reference< graphic::XGraphic >(
                reinterpret_cast< graphic::XGraphic* >(
                    aTbSymbol.GetItemData( nId ) ) );
        }
    }

    return result;
}

IMPL_LINK( SvxIconSelectorDialog, SelectHdl, ToolBox *, pToolBox )
{
    USHORT nCount = aTbSymbol.GetItemCount();

    for (USHORT n = 0; n < nCount; n++ )
    {
        USHORT nId = aTbSymbol.GetItemId( n );

        if ( aTbSymbol.IsItemChecked( nId ) )
        {
            aTbSymbol.CheckItem( nId, FALSE );
        }
    }

    USHORT nId = aTbSymbol.GetCurItemId();
    aTbSymbol.CheckItem( nId );

    return 0;
}

IMPL_LINK( SvxIconSelectorDialog, ImportHdl, PushButton *, pButton )
{
    sfx2::FileDialogHelper aImportDialog(
        ::sfx2::FILEOPEN_LINK_PREVIEW, SFXWB_GRAPHIC | SFXWB_MULTISELECTION );

    // disable the link checkbox in the dialog
    uno::Reference< css::ui::dialogs::XFilePickerControlAccess >
        xController( aImportDialog.GetFilePicker(), uno::UNO_QUERY);
    if ( xController.is() )
    {
        xController->enableControl(
            css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK,
            sal_False);
    }

    aImportDialog.SetCurrentFilter(
        String::CreateFromAscii( "PNG - Portable Network Graphic" ) );

    if ( ERRCODE_NONE == aImportDialog.Execute() )
    {
        uno::Sequence< OUString > paths = aImportDialog.GetMPath();
        ImportGraphics ( paths );
    }

    return 0;
}

void SvxIconSelectorDialog::ImportGraphics(
    const uno::Sequence< OUString >& rPaths )
{
    uno::Sequence< OUString > rejected( rPaths.getLength() );
    sal_Int32 rejectedCount = 0;

    if ( rPaths.getLength() == 1 )
    {
        if ( ImportGraphic( rPaths[0] ) == FALSE )
        {
            rejected[0] = rPaths[0];
            rejectedCount = 1;
        }
    }
    else
    {
        for ( sal_Int32 i = 1; i < rPaths.getLength(); i++ )
        {
            bool result = ImportGraphic( rPaths[0] + OUString::createFromAscii("/") + rPaths[i] );
            if ( result == FALSE )
            {
                rejected[ rejectedCount ] = rPaths[i];
                rejectedCount++;
            }
        }
    }

    if ( rejectedCount != 0 )
    {
        OUString message = String( ResId( RID_SVXSTR_IMPORT_ICON_ERROR, DIALOG_MGR() ) );
        if ( m_nExpectedSize != 16 )
        {
            message = replaceSixteen( message, m_nExpectedSize );
        }

        OUString newLine = OUString::createFromAscii("\n");
        message += newLine;
        message += newLine;

        for ( sal_Int32 i = 0; i < rejectedCount; i++ )
        {
            message += rejected[i];
            message += newLine;
        }

        InfoBox( this, message ).Execute();
    }
}

bool SvxIconSelectorDialog::ImportGraphic( const OUString& aURL )
{
    bool result = FALSE;

    USHORT nId = aTbSymbol.GetItemId(aTbSymbol.GetItemCount() -1);
    nId++;

    uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
    aMediaProps[0].Name = ::rtl::OUString::createFromAscii("URL");

    uno::Reference< graphic::XGraphic > xGraphic;
    com::sun::star::awt::Size aSize;

    aMediaProps[0].Value <<= aURL;

    try
    {
        uno::Reference< beans::XPropertySet > props =
            m_xGraphProvider->queryGraphicDescriptor( aMediaProps );

        uno::Any a = props->getPropertyValue(
            OUString::createFromAscii("SizePixel") );

        if ( ( a >>= aSize ) && aSize.Width == m_nExpectedSize &&
                aSize.Height == m_nExpectedSize )
        {
            xGraphic = m_xGraphProvider->queryGraphic( aMediaProps );

            if ( xGraphic.is() )
            {
                Image aImage( xGraphic );

                if ( !!aImage )
                {
                    aTbSymbol.InsertItem( nId, aImage, aURL );

                    xGraphic->acquire();

                    aTbSymbol.SetItemData(
                        nId, static_cast< void * > ( xGraphic.get() ) );

                    result = TRUE;
                }
                else
                {
                    OSL_TRACE("could not create Image from XGraphic");
                }
            }
            else
            {
                OSL_TRACE("could not get query XGraphic");
            }
        }
    }
    catch( uno::Exception& e )
    {
        OSL_TRACE("Caught exception importing XGraphic: %s", PRTSTR(e.Message));
    }
    return result;
}