/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_cui.hxx"
#include <vcl/help.hxx>
#include <vcl/msgbox.hxx>
#include <vcl/metric.hxx>
#include "selector.hxx"
#include <dialmgr.hxx>
#include "selector.hrc"
#include <svx/fmresids.hrc> // for RID_SVXIMG_...
#include <svx/dialmgr.hxx>  // for RID_SVXIMG_...
#include <cuires.hrc>
#include <sfx2/app.hxx>
#include <sfx2/msg.hxx>
#include <sfx2/msgpool.hxx>
#include <sfx2/macrconf.hxx>
#include <sfx2/minfitem.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/dispatch.hxx>

#include <comphelper/documentinfo.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/componentcontext.hxx>

#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
#include <com/sun/star/script/provider/XScriptProvider.hpp>
#include <com/sun/star/script/browse/XBrowseNode.hpp>
#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
#include <com/sun/star/script/browse/XBrowseNodeFactory.hpp>
#include <com/sun/star/script/browse/BrowseNodeFactoryViewTypes.hpp>
#include <com/sun/star/frame/XModuleManager.hpp>
#include <com/sun/star/frame/XDesktop.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/container/XEnumeration.hpp>
#include <com/sun/star/document/XEmbeddedScripts.hpp>
#include <com/sun/star/document/XScriptInvocationContext.hpp>
#include <com/sun/star/frame/XDispatchInformationProvider.hpp>
#include <com/sun/star/frame/DispatchInformation.hpp>
#include <com/sun/star/container/XChild.hpp>

using ::rtl::OUString;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::script;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::document;
using namespace ::com::sun::star::container;

#define _SVSTDARR_STRINGSDTOR
#include <svl/svstdarr.hxx>
#include <svtools/imagemgr.hxx>
#include <tools/urlobj.hxx>
#include <tools/diagnose_ex.h>

SV_IMPL_PTRARR(SvxGroupInfoArr_Impl, SvxGroupInfoPtr);

/*
 * The implementations of SvxConfigFunctionListBox_Impl and
 * SvxConfigGroupListBox_Impl are copied from sfx2/source/dialog/cfg.cxx
 */
SvxConfigFunctionListBox_Impl::SvxConfigFunctionListBox_Impl( Window* pParent, const ResId& rResId)
    : SvTreeListBox( pParent, rResId )
    , pCurEntry( 0 )
    , m_pDraggingEntry( 0 )
{
    SetWindowBits( GetStyle() | WB_CLIPCHILDREN | WB_HSCROLL | WB_SORT );
    GetModel()->SetSortMode( SortAscending );

    // Timer f"ur die BallonHelp
    aTimer.SetTimeout( 200 );
    aTimer.SetTimeoutHdl(
        LINK( this, SvxConfigFunctionListBox_Impl, TimerHdl ) );
}

SvxConfigFunctionListBox_Impl::~SvxConfigFunctionListBox_Impl()
{
    ClearAll();
}

SvLBoxEntry* SvxConfigFunctionListBox_Impl::GetLastSelectedEntry()
{
    if ( m_pDraggingEntry != NULL )
    {
        return m_pDraggingEntry;
    }
    else
    {
        return FirstSelected();
    }
}

void SvxConfigFunctionListBox_Impl::MouseMove( const MouseEvent& rMEvt )
{
    Point aMousePos = rMEvt.GetPosPixel();
    pCurEntry = GetCurEntry();

    if ( pCurEntry && GetEntry( aMousePos ) == pCurEntry )
        aTimer.Start();
    else
    {
        Help::ShowBalloon( this, aMousePos, String() );
        aTimer.Stop();
    }
}


IMPL_LINK( SvxConfigFunctionListBox_Impl, TimerHdl, Timer*, EMPTYARG)
{
    aTimer.Stop();
    Point aMousePos = GetPointerPosPixel();
    SvLBoxEntry *pEntry = GetCurEntry();
    if ( pEntry && GetEntry( aMousePos ) == pEntry && pCurEntry == pEntry )
        Help::ShowBalloon( this, OutputToScreenPixel( aMousePos ), GetHelpText( pEntry ) );
    return 0L;
}

void SvxConfigFunctionListBox_Impl::ClearAll()
{
    USHORT nCount = aArr.Count();
    for ( USHORT i=0; i<nCount; i++ )
    {
        SvxGroupInfo_Impl *pData = aArr[i];
        delete pData;
    }

    aArr.Remove( 0, nCount );
    Clear();
}

SvLBoxEntry* SvxConfigFunctionListBox_Impl::GetEntry_Impl( const String& rName )
{
    SvLBoxEntry *pEntry = First();
    while ( pEntry )
    {
        if ( GetEntryText( pEntry ) == rName )
            return pEntry;
        pEntry = Next( pEntry );
    }

    return NULL;
}

SvLBoxEntry* SvxConfigFunctionListBox_Impl::GetEntry_Impl( USHORT nId )
{
    SvLBoxEntry *pEntry = First();
    while ( pEntry )
    {
        SvxGroupInfo_Impl *pData = (SvxGroupInfo_Impl*) pEntry->GetUserData();
        if ( pData && pData->nOrd == nId )
            return pEntry;
        pEntry = Next( pEntry );
    }

    return NULL;
}

USHORT SvxConfigFunctionListBox_Impl::GetId( SvLBoxEntry *pEntry )
{
    SvxGroupInfo_Impl *pData = pEntry ?
        (SvxGroupInfo_Impl*) pEntry->GetUserData() : 0;
    if ( pData )
        return pData->nOrd;
    return 0;
}

String SvxConfigFunctionListBox_Impl::GetHelpText( SvLBoxEntry *pEntry )
{
    // Information zum selektierten Entry aus den Userdaten holen
    SvxGroupInfo_Impl *pInfo =
        pEntry ? (SvxGroupInfo_Impl*) pEntry->GetUserData(): 0;

    if ( pInfo )
    {
        if ( pInfo->nKind == SVX_CFGFUNCTION_SLOT )
        {
            OUString aCmdURL( pInfo->sURL );

            OUString aHelpText = Application::GetHelp()->GetHelpText( aCmdURL, this );

            return aHelpText;
        }
        else if ( pInfo->nKind == SVX_CFGFUNCTION_SCRIPT )
        {
            return pInfo->sHelpText;
        }
    }

    return String();
}

void SvxConfigFunctionListBox_Impl::FunctionSelected()
{
    Help::ShowBalloon( this, Point(), String() );
}

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

void SvxConfigFunctionListBox_Impl::DragFinished( sal_Int8 /*nDropAction*/ )
{
    m_pDraggingEntry = NULL;
}

sal_Int8
SvxConfigFunctionListBox_Impl::AcceptDrop( const AcceptDropEvent& /*rEvt*/ )
{
    return DND_ACTION_NONE;
}

SvxConfigGroupListBox_Impl::SvxConfigGroupListBox_Impl(
    Window* pParent, const ResId& rResId,
    bool _bShowSlots, const Reference< frame::XFrame >& xFrame )
        : SvTreeListBox( pParent, rResId )
        , m_bShowSlots( _bShowSlots ),
    m_hdImage(ResId(IMG_HARDDISK,*rResId.GetResMgr())),
    m_hdImage_hc(ResId(IMG_HARDDISK_HC,*rResId.GetResMgr())),
    m_libImage(ResId(IMG_LIB,*rResId.GetResMgr())),
    m_libImage_hc(ResId(IMG_LIB_HC,*rResId.GetResMgr())),
    m_macImage(ResId(IMG_MACRO,*rResId.GetResMgr())),
    m_macImage_hc(ResId(IMG_MACRO_HC,*rResId.GetResMgr())),
    m_docImage(ResId(IMG_DOC,*rResId.GetResMgr())),
    m_docImage_hc(ResId(IMG_DOC_HC,*rResId.GetResMgr())),
    m_sMyMacros(String(ResId(STR_MYMACROS,*rResId.GetResMgr()))),
    m_sProdMacros(String(ResId(STR_PRODMACROS,*rResId.GetResMgr())))
{
    FreeResource();

    if ( xFrame != NULL )
    {
        m_xFrame.set( xFrame );
    }

    SetWindowBits( GetStyle() | WB_CLIPCHILDREN | WB_HSCROLL | WB_HASBUTTONS | WB_HASLINES | WB_HASLINESATROOT | WB_HASBUTTONSATROOT );

    ImageList aNavigatorImages( SVX_RES( RID_SVXIMGLIST_FMEXPL ) );

    SetNodeBitmaps(
        aNavigatorImages.GetImage( RID_SVXIMG_COLLAPSEDNODE ),
        aNavigatorImages.GetImage( RID_SVXIMG_EXPANDEDNODE ),
        BMP_COLOR_NORMAL );

    SetNodeBitmaps(
        aNavigatorImages.GetImage( RID_SVXIMG_COLLAPSEDNODE ),
        aNavigatorImages.GetImage( RID_SVXIMG_EXPANDEDNODE ),
        BMP_COLOR_HIGHCONTRAST );
}


SvxConfigGroupListBox_Impl::~SvxConfigGroupListBox_Impl()
{
    ClearAll();
}

void SvxConfigGroupListBox_Impl::ClearAll()
{
    USHORT nCount = aArr.Count();
    for ( USHORT i=0; i<nCount; i++ )
    {
        SvxGroupInfo_Impl *pData = aArr[i];
        delete pData;
    }

    aArr.Remove( 0, nCount );
    Clear();
}

//-----------------------------------------------
namespace
{
    //...........................................
    /** examines a component whether it supports XEmbeddedScripts, or provides access to such a
        component by implementing XScriptInvocationContext.
        @return
            the model which supports the embedded scripts, or <NULL/> if it cannot find such a
            model
    */
    static Reference< XModel > lcl_getDocumentWithScripts_throw( const Reference< XInterface >& _rxComponent )
    {
        Reference< XEmbeddedScripts > xScripts( _rxComponent, UNO_QUERY );
        if ( !xScripts.is() )
        {
            Reference< XScriptInvocationContext > xContext( _rxComponent, UNO_QUERY );
            if ( xContext.is() )
                xScripts.set( xContext->getScriptContainer(), UNO_QUERY );
        }

        return Reference< XModel >( xScripts, UNO_QUERY );
    }

    //...........................................
    static Reference< XModel > lcl_getScriptableDocument_nothrow( const Reference< XFrame >& _rxFrame )
    {
        Reference< XModel > xDocument;

        // examine our associated frame
        try
        {
            OSL_ENSURE( _rxFrame.is(), "lcl_getScriptableDocument_nothrow: you need to pass a frame to this dialog/tab page!" );
            if ( _rxFrame.is() )
            {
                // first try the model in the frame
                Reference< XController > xController( _rxFrame->getController(), UNO_SET_THROW );
                xDocument = lcl_getDocumentWithScripts_throw( xController->getModel() );

                if ( !xDocument.is() )
                {
                    // if there is no suitable document in the frame, try the controller
                    xDocument = lcl_getDocumentWithScripts_throw( _rxFrame->getController() );
                }
            }
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }

        return xDocument;
    }
}

void SvxConfigGroupListBox_Impl::fillScriptList( const Reference< browse::XBrowseNode >& _rxRootNode, SvLBoxEntry* _pParentEntry, bool _bCheapChildsOnDemand )
{
    OSL_PRECOND( _rxRootNode.is(), "SvxConfigGroupListBox_Impl::fillScriptList: invalid root node!" );
    if ( !_rxRootNode.is() )
        return;

    try
    {
        if ( _rxRootNode->hasChildNodes() )
        {
            Sequence< Reference< browse::XBrowseNode > > children =
                _rxRootNode->getChildNodes();

            BOOL bIsRootNode = _rxRootNode->getName().equalsAscii("Root");

            /* To mimic current starbasic behaviour we
            need to make sure that only the current document
            is displayed in the config tree. Tests below
            set the bDisplay flag to FALSE if the current
            node is a first level child of the Root and is NOT
            either the current document, user or share */
            OUString sCurrentDocTitle;
            Reference< XModel > xWorkingDocument = lcl_getScriptableDocument_nothrow( m_xFrame );
            if ( xWorkingDocument.is() )
            {
                sCurrentDocTitle = ::comphelper::DocumentInfo::getDocumentTitle( xWorkingDocument );
            }

            for ( long n = 0; n < children.getLength(); n++ )
            {
                Reference< browse::XBrowseNode >& theChild = children[n];
                //#139111# some crash reports show that it might be unset
                if ( !theChild.is() )
                    continue;
                ::rtl::OUString sUIName = theChild->getName();
                BOOL bDisplay = TRUE;

                if  (   bIsRootNode
                    ||  ( m_bShowSlots && _pParentEntry && ( GetModel()->GetDepth( _pParentEntry ) == 0 ) )
                        // if we show slots (as in the customize dialog)
                        // then the user & share are added at depth=1
                    )
                {
                    if ( sUIName.equalsAscii( "user" ) )
                    {
                        sUIName = m_sMyMacros;
                        bIsRootNode = sal_True;
                    }
                    else if ( sUIName.equalsAscii( "share" ) )
                    {
                        sUIName = m_sProdMacros;
                        bIsRootNode = sal_True;
                    }
                    else if ( !sUIName.equals( sCurrentDocTitle ) )
                    {
                        bDisplay = FALSE;
                    }
                }

                if ( !bDisplay )
                    continue;

                if ( children[n]->getType() == browse::BrowseNodeTypes::SCRIPT )
                    continue;

                SvLBoxEntry* pNewEntry = InsertEntry( sUIName, _pParentEntry );

                ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() );
                Image aImage = GetImage( theChild, aContext.getUNOContext(), bIsRootNode, BMP_COLOR_NORMAL );
                SetExpandedEntryBmp( pNewEntry, aImage, BMP_COLOR_NORMAL );
                SetCollapsedEntryBmp( pNewEntry, aImage, BMP_COLOR_NORMAL );

                aImage = GetImage( theChild, aContext.getUNOContext(), bIsRootNode, BMP_COLOR_HIGHCONTRAST );
                SetExpandedEntryBmp( pNewEntry, aImage, BMP_COLOR_HIGHCONTRAST );
                SetCollapsedEntryBmp( pNewEntry, aImage, BMP_COLOR_HIGHCONTRAST );

                SvxGroupInfo_Impl* pInfo =
                    new SvxGroupInfo_Impl( SVX_CFGGROUP_SCRIPTCONTAINER, 0, theChild );
                pNewEntry->SetUserData( pInfo );
                aArr.Insert( pInfo, aArr.Count() );

                if ( _bCheapChildsOnDemand )
                {
                    /* i30923 - Would be nice if there was a better
                    * way to determine if a basic lib had children
                    * without having to ask for them (which forces
                    * the library to be loaded */
                    pNewEntry->EnableChildsOnDemand( TRUE );
                }
                else
                {
                    // if there are granchildren we're interested in, display the '+' before
                    // the entry, but do not yet expand
                    Sequence< Reference< browse::XBrowseNode > > grandchildren =
                        children[n]->getChildNodes();

                    for ( sal_Int32 m = 0; m < grandchildren.getLength(); m++ )
                    {
                        if ( grandchildren[m]->getType() == browse::BrowseNodeTypes::CONTAINER )
                        {
                            pNewEntry->EnableChildsOnDemand( TRUE );
                            break;
                        }
                    }
                }
            }
        }
    }
    catch (const Exception&)
    {
        DBG_UNHANDLED_EXCEPTION();
    }
}

void SvxConfigGroupListBox_Impl::Init()
{
    SetUpdateMode(FALSE);
    ClearAll();

    Reference< XComponentContext > xContext;
    Reference < beans::XPropertySet > xProps(
        ::comphelper::getProcessServiceFactory(), UNO_QUERY_THROW );

    xContext.set( xProps->getPropertyValue(
        rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))),
        UNO_QUERY );

    // are we showing builtin commands?
    if ( m_bShowSlots && xContext.is() && m_xFrame.is() )
    {
        Reference< lang::XMultiComponentFactory > xMCF =
            xContext->getServiceManager();

        Reference< frame::XDispatchInformationProvider > xDIP(
            m_xFrame, UNO_QUERY );

        Reference< ::com::sun::star::frame::XModuleManager >
            xModuleManager( xMCF->createInstanceWithContext(
                OUString::createFromAscii(
                    "com.sun.star.frame.ModuleManager" ),
                xContext ),
            UNO_QUERY );

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

        Reference< container::XNameAccess > xNameAccess(
            xMCF->createInstanceWithContext(
                OUString::createFromAscii(
                    "com.sun.star.frame.UICommandDescription" ),
                xContext ),
            UNO_QUERY );

        if ( xNameAccess.is() )
        {
            xNameAccess->getByName( aModuleId ) >>= m_xModuleCommands;
        }

        Reference< container::XNameAccess > xAllCategories(
            xMCF->createInstanceWithContext(
                OUString::createFromAscii(
                    "com.sun.star.ui.UICategoryDescription" ),
                xContext ),
            UNO_QUERY );

        Reference< container::XNameAccess > xModuleCategories;
        if ( xAllCategories.is() )
        {
            if ( aModuleId.getLength() != 0 )
            {
                try
                {
                    xModuleCategories = Reference< container::XNameAccess >(
                           xAllCategories->getByName( aModuleId ), UNO_QUERY );
                }
                catch ( container::NoSuchElementException& )
                {
                }
            }

            if ( !xModuleCategories.is() )
            {
                xModuleCategories = xAllCategories;
            }
        }

        if ( xModuleCategories.is() )
        {
            Sequence< sal_Int16 > gids =
                xDIP->getSupportedCommandGroups();

            for ( sal_Int32 i = 0; i < gids.getLength(); i++ )
            {
                Sequence< frame::DispatchInformation > commands;
                try
                {
                    commands =
                        xDIP->getConfigurableDispatchInformation( gids[i] );
                }
                catch ( container::NoSuchElementException& )
                {
                    continue;
                }

                if ( commands.getLength() == 0 )
                {
                    continue;
                }

                sal_Int32 gid = gids[i];
                OUString idx = OUString::valueOf( gid );
                OUString group = idx;
                try
                {
                    xModuleCategories->getByName( idx ) >>= group;
                }
                catch ( container::NoSuchElementException& )
                {
                }

                SvLBoxEntry *pEntry = InsertEntry( group, NULL );

                SvxGroupInfo_Impl *pInfo =
                    new SvxGroupInfo_Impl( SVX_CFGGROUP_FUNCTION, gids[i] );
                aArr.Insert( pInfo, aArr.Count() );

                pEntry->SetUserData( pInfo );
            }
        }
    }

    if ( xContext.is() )
    {
        // Add Scripting Framework entries
        Reference< browse::XBrowseNode > rootNode;
        Reference< XComponentContext> xCtx;

        try
        {
            Reference < beans::XPropertySet > _xProps(
                ::comphelper::getProcessServiceFactory(), UNO_QUERY_THROW );
            xCtx.set( _xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), UNO_QUERY_THROW );
            Reference< browse::XBrowseNodeFactory > xFac( xCtx->getValueByName(
                OUString::createFromAscii( "/singletons/com.sun.star.script.browse.theBrowseNodeFactory") ), UNO_QUERY_THROW );
            rootNode.set( xFac->createView( browse::BrowseNodeFactoryViewTypes::MACROSELECTOR ) );
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }

        if ( rootNode.is() )
        {
            if ( m_bShowSlots )
            {
                SvxGroupInfo_Impl *pInfo =
                    new SvxGroupInfo_Impl( SVX_CFGGROUP_SCRIPTCONTAINER, 0, rootNode );

                String aTitle =
                    String( CUI_RES( STR_SELECTOR_MACROS ) );

                SvLBoxEntry *pNewEntry = InsertEntry( aTitle, NULL );
                pNewEntry->SetUserData( pInfo );
                pNewEntry->EnableChildsOnDemand( TRUE );
                aArr.Insert( pInfo, aArr.Count() );
            }
            else
            {
                fillScriptList( rootNode, NULL, false );
            }
        }
    }
    MakeVisible( GetEntry( 0,0 ) );
    SetUpdateMode( TRUE );
}

Image SvxConfigGroupListBox_Impl::GetImage( Reference< browse::XBrowseNode > node, Reference< XComponentContext > xCtx, bool bIsRootNode, bool bHighContrast )
{
    Image aImage;
    if ( bIsRootNode )
    {
        if ( node->getName().equalsAscii( "user" ) || node->getName().equalsAscii( "share" ) )
        {
            if( bHighContrast == BMP_COLOR_NORMAL )
                aImage = m_hdImage;
            else
                aImage = m_hdImage_hc;
        }
        else
        {
            OUString factoryURL;
            OUString nodeName = node->getName();
            Reference<XInterface> xDocumentModel = getDocumentModel(xCtx, nodeName );
            if ( xDocumentModel.is() )
            {
                Reference< ::com::sun::star::frame::XModuleManager >
                    xModuleManager(
                        xCtx->getServiceManager()
                            ->createInstanceWithContext(
                                OUString::createFromAscii("com.sun.star.frame.ModuleManager"),
                                xCtx ),
                            UNO_QUERY_THROW );
                Reference<container::XNameAccess> xModuleConfig(
                    xModuleManager, UNO_QUERY_THROW );
                // get the long name of the document:
                OUString appModule( xModuleManager->identify(
                                    xDocumentModel ) );
                Sequence<beans::PropertyValue> moduleDescr;
                Any aAny = xModuleConfig->getByName(appModule);
                if( sal_True != ( aAny >>= moduleDescr ) )
                {
                    throw RuntimeException(OUString::createFromAscii("SFTreeListBox::Init: failed to get PropertyValue"), Reference< XInterface >());
                }
                beans::PropertyValue const * pmoduleDescr =
                    moduleDescr.getConstArray();
                for ( sal_Int32 pos = moduleDescr.getLength(); pos--; )
                {
                    if (pmoduleDescr[ pos ].Name.equalsAsciiL(
                            RTL_CONSTASCII_STRINGPARAM(
                                "ooSetupFactoryEmptyDocumentURL") ))
                    {
                        pmoduleDescr[ pos ].Value >>= factoryURL;
                        break;
                    }
                }
            }
            if( factoryURL.getLength() > 0 )
            {
                if( bHighContrast == BMP_COLOR_NORMAL )
                    aImage = SvFileInformationManager::GetFileImage(
                        INetURLObject(factoryURL), false,
                        BMP_COLOR_NORMAL );
                else
                    aImage = SvFileInformationManager::GetFileImage(
                        INetURLObject(factoryURL), false,
                        BMP_COLOR_HIGHCONTRAST );
            }
            else
            {
                if( bHighContrast == BMP_COLOR_NORMAL )
                    aImage = m_docImage;
                else
                    aImage = m_docImage_hc;
            }
        }
    }
    else
    {
        if( node->getType() == browse::BrowseNodeTypes::SCRIPT )
        {
            if( bHighContrast == BMP_COLOR_NORMAL )
                aImage = m_macImage;
            else
                aImage = m_macImage_hc;
        }
        else
        {
            if( bHighContrast == BMP_COLOR_NORMAL )
                aImage = m_libImage;
            else
                aImage = m_libImage_hc;
        }
    }
    return aImage;
}

Reference< XInterface  >
SvxConfigGroupListBox_Impl::getDocumentModel(
    Reference< XComponentContext >& xCtx, OUString& docName )
{
    Reference< XInterface > xModel;
    Reference< lang::XMultiComponentFactory > mcf =
            xCtx->getServiceManager();
    Reference< frame::XDesktop > desktop (
        mcf->createInstanceWithContext(
            OUString::createFromAscii("com.sun.star.frame.Desktop"),                 xCtx ),
            UNO_QUERY );

    Reference< container::XEnumerationAccess > componentsAccess =
        desktop->getComponents();
    Reference< container::XEnumeration > components =
        componentsAccess->createEnumeration();
    while (components->hasMoreElements())
    {
        Reference< frame::XModel > model(
            components->nextElement(), UNO_QUERY );
        if ( model.is() )
        {
            OUString sTdocUrl = ::comphelper::DocumentInfo::getDocumentTitle( model );
            if( sTdocUrl.equals( docName ) )
            {
                xModel = model;
                break;
            }
        }
    }
    return xModel;
}

void SvxConfigGroupListBox_Impl::GroupSelected()
{
    SvLBoxEntry *pEntry = FirstSelected();
    SvxGroupInfo_Impl *pInfo = (SvxGroupInfo_Impl*) pEntry->GetUserData();
    pFunctionListBox->SetUpdateMode(FALSE);
    pFunctionListBox->ClearAll();
    if ( pInfo->nKind != SVX_CFGGROUP_FUNCTION &&
             pInfo->nKind != SVX_CFGGROUP_SCRIPTCONTAINER )
    {
        pFunctionListBox->SetUpdateMode(TRUE);
        return;
    }

    switch ( pInfo->nKind )
    {
        case SVX_CFGGROUP_FUNCTION :
        {
            SvLBoxEntry *_pEntry = FirstSelected();
            if ( _pEntry != NULL )
            {
                SvxGroupInfo_Impl *_pInfo =
                    (SvxGroupInfo_Impl*) _pEntry->GetUserData();

                Reference< frame::XDispatchInformationProvider > xDIP(
                    m_xFrame, UNO_QUERY );

                Sequence< frame::DispatchInformation > commands;
                try
                {
                    commands = xDIP->getConfigurableDispatchInformation(
                        _pInfo->nOrd );
                }
                catch ( container::NoSuchElementException& )
                {
                }

                for ( sal_Int32 i = 0; i < commands.getLength(); i++ )
                {
                    if ( commands[i].Command.getLength() == 0 )
                    {
                        continue;
                    }

                    Image aImage;

                    OUString aCmdURL( commands[i].Command );

                    if ( m_pImageProvider )
                    {
                        aImage = m_pImageProvider->GetImage( aCmdURL );
                    }

                    OUString aLabel;
                    try
                    {
                        Any a = m_xModuleCommands->getByName( aCmdURL );
                        Sequence< beans::PropertyValue > aPropSeq;

                        if ( a >>= aPropSeq )
                        {
                            for ( sal_Int32 k = 0; k < aPropSeq.getLength(); k++ )
                            {
                                if ( aPropSeq[k].Name.equalsAscii( "Name" ) )
                                {
                                    aPropSeq[k].Value >>= aLabel;
                                    break;
                                }
                            }
                        }
                    }
                    catch ( container::NoSuchElementException& )
                    {
                    }

                    if ( aLabel.getLength() == 0 )
                    {
                        aLabel = commands[i].Command;
                    }

                    SvLBoxEntry* pFuncEntry = NULL;
                    if ( !!aImage )
                    {
                        pFuncEntry = pFunctionListBox->InsertEntry(
                            aLabel, aImage, aImage );
                    }
                    else
                    {
                        pFuncEntry = pFunctionListBox->InsertEntry(
                            aLabel, NULL );
                    }

                    SvxGroupInfo_Impl *_pGroupInfo = new SvxGroupInfo_Impl(
                        SVX_CFGFUNCTION_SLOT, 123, aCmdURL, ::rtl::OUString() );

                    pFunctionListBox->aArr.Insert(
                        _pGroupInfo, pFunctionListBox->aArr.Count() );

                    pFuncEntry->SetUserData( _pGroupInfo );
                }
            }
            break;
        }

        case SVX_CFGGROUP_SCRIPTCONTAINER:
        {
            Reference< browse::XBrowseNode > rootNode( pInfo->xBrowseNode );

            try {
                if ( rootNode->hasChildNodes() )
                {
                    Sequence< Reference< browse::XBrowseNode > > children =
                        rootNode->getChildNodes();

                    for ( long n = 0; n < children.getLength(); n++ )
                    {
                        if (!children[n].is())
                            continue;
                        if (children[n]->getType() == browse::BrowseNodeTypes::SCRIPT)
                        {
                            OUString uri;
                            OUString description;

                            Reference < beans::XPropertySet >xPropSet( children[n], UNO_QUERY );
                            if (!xPropSet.is())
                            {
                                continue;
                            }

                            Any value =
                                xPropSet->getPropertyValue( String::CreateFromAscii( "URI" ) );
                            value >>= uri;

                            try
                            {
                                value = xPropSet->getPropertyValue(
                                    String::CreateFromAscii( "Description" ) );
                                value >>= description;
                            }
                            catch (Exception &) {
                                // do nothing, the description will be empty
                            }

                            SvxGroupInfo_Impl* _pGroupInfo =
                                new SvxGroupInfo_Impl(
                                    SVX_CFGFUNCTION_SCRIPT, 123, uri, description );

                            Image aImage = GetImage( children[n], Reference< XComponentContext >(), sal_False, BMP_COLOR_NORMAL );
                            SvLBoxEntry* pNewEntry =
                                pFunctionListBox->InsertEntry( children[n]->getName(), NULL );
                            pFunctionListBox->SetExpandedEntryBmp(pNewEntry, aImage, BMP_COLOR_NORMAL);
                            pFunctionListBox->SetCollapsedEntryBmp(pNewEntry, aImage, BMP_COLOR_NORMAL);
                            aImage = GetImage( children[n], Reference< XComponentContext >(), sal_False, BMP_COLOR_HIGHCONTRAST );
                            pFunctionListBox->SetExpandedEntryBmp(pNewEntry, aImage, BMP_COLOR_HIGHCONTRAST);
                            pFunctionListBox->SetCollapsedEntryBmp(pNewEntry, aImage, BMP_COLOR_HIGHCONTRAST);

                            pNewEntry->SetUserData( _pGroupInfo );

                            pFunctionListBox->aArr.Insert(
                                _pGroupInfo, pFunctionListBox->aArr.Count() );

                        }
                    }
                }
            }
            catch (const Exception&)
            {
                DBG_UNHANDLED_EXCEPTION();
            }
            break;
        }

        default:
        {
            return;
        }
    }

    if ( pFunctionListBox->GetEntryCount() )
        pFunctionListBox->Select( pFunctionListBox->GetEntry( 0, 0 ) );

    pFunctionListBox->SetUpdateMode(TRUE);
}

BOOL SvxConfigGroupListBox_Impl::Expand( SvLBoxEntry* pParent )
{
    BOOL bRet = SvTreeListBox::Expand( pParent );
    if ( bRet )
    {
        // Wieviele Entries k"onnen angezeigt werden ?
        ULONG nEntries = GetOutputSizePixel().Height() / GetEntryHeight();

        // Wieviele Kinder sollen angezeigt werden ?
        ULONG nChildCount = GetVisibleChildCount( pParent );

        // Passen alle Kinder und der parent gleichzeitig in die View ?
        if ( nChildCount+1 > nEntries )
        {
            // Wenn nicht, wenigstens parent ganz nach oben schieben
            MakeVisible( pParent, TRUE );
        }
        else
        {
            // An welcher relativen ViewPosition steht der aufzuklappende parent
            SvLBoxEntry *pEntry = GetFirstEntryInView();
            ULONG nParentPos = 0;
            while ( pEntry && pEntry != pParent )
            {
                nParentPos++;
                pEntry = GetNextEntryInView( pEntry );
            }

            // Ist unter dem parent noch genug Platz f"ur alle Kinder ?
            if ( nParentPos + nChildCount + 1 > nEntries )
                ScrollOutputArea( (short)( nEntries - ( nParentPos + nChildCount + 1 ) ) );
        }
    }

    return bRet;
}

void SvxConfigGroupListBox_Impl::RequestingChilds( SvLBoxEntry *pEntry )
{
    SvxGroupInfo_Impl *pInfo = (SvxGroupInfo_Impl*) pEntry->GetUserData();
    pInfo->bWasOpened = TRUE;
    switch ( pInfo->nKind )
    {
        case SVX_CFGGROUP_SCRIPTCONTAINER:
        {
            if ( !GetChildCount( pEntry ) )
            {
                Reference< browse::XBrowseNode > rootNode( pInfo->xBrowseNode ) ;
                fillScriptList( rootNode, pEntry, true /* i30923 */ );
            }
            break;
        }

        default:
            DBG_ERROR( "Falscher Gruppentyp!" );
            break;
    }
}

/*
 * Implementation of SvxScriptSelectorDialog
 *
 * This dialog is used for selecting Slot API commands
 * and Scripting Framework Scripts.
 */

SvxScriptSelectorDialog::SvxScriptSelectorDialog(
  Window* pParent, BOOL bShowSlots, const Reference< frame::XFrame >& xFrame )
    :
    ModelessDialog( pParent, CUI_RES( RID_DLG_SCRIPTSELECTOR ) ),
    aDialogDescription( this, CUI_RES( TXT_SELECTOR_DIALOG_DESCRIPTION ) ),
    aGroupText( this, CUI_RES( TXT_SELECTOR_CATEGORIES ) ),
    aCategories( this, CUI_RES( BOX_SELECTOR_CATEGORIES ), bShowSlots, xFrame ),
    aFunctionText( this, CUI_RES( TXT_SELECTOR_COMMANDS ) ),
    aCommands( this, CUI_RES( BOX_SELECTOR_COMMANDS ) ),
    aOKButton( this, CUI_RES( BTN_SELECTOR_OK ) ),
    aCancelButton( this, CUI_RES( BTN_SELECTOR_CANCEL ) ),
    aHelpButton( this, CUI_RES( BTN_SELECTOR_HELP ) ),
    aDescription( this, CUI_RES( GRP_SELECTOR_DESCRIPTION ) ),
    aDescriptionText( this, CUI_RES( TXT_SELECTOR_DESCRIPTION ) ),
    m_bShowSlots( bShowSlots )
{

    ResMgr& rMgr = CUI_MGR();

    // If we are showing Slot API commands update labels in the UI, and
    // enable drag'n'drop
    if ( m_bShowSlots )
    {
        aGroupText.SetText( String( ResId( STR_SELECTOR_CATEGORIES, rMgr ) ) );
        aOKButton.SetText( String( ResId( STR_SELECTOR_ADD, rMgr ) ) );
        aCancelButton.SetText( String( ResId( STR_SELECTOR_CLOSE, rMgr ) ) );
        aFunctionText.SetText( String( ResId( STR_SELECTOR_COMMANDS, rMgr ) ) );
        SetDialogDescription(
            String( ResId( STR_SELECTOR_ADD_COMMANDS_DESCRIPTION, rMgr ) ) );
        SetText( String( ResId( STR_SELECTOR_ADD_COMMANDS, rMgr ) ) );

        aCommands.SetDragDropMode( SV_DRAGDROP_APP_COPY );
    }

    ResizeControls();

    aCategories.SetFunctionListBox( &aCommands );
    aCategories.Init();
    // aCategories.Select( aCategories.GetEntry( 0, 0 ) );

    aCategories.SetSelectHdl(
            LINK( this, SvxScriptSelectorDialog, SelectHdl ) );
    aCommands.SetSelectHdl( LINK( this, SvxScriptSelectorDialog, SelectHdl ) );
    aCommands.SetDoubleClickHdl( LINK( this, SvxScriptSelectorDialog, FunctionDoubleClickHdl ) );

    aOKButton.SetClickHdl( LINK( this, SvxScriptSelectorDialog, ClickHdl ) );
    aCancelButton.SetClickHdl( LINK( this, SvxScriptSelectorDialog, ClickHdl ) );

    UpdateUI();
    FreeResource();
}

void SvxScriptSelectorDialog::ResizeControls()
{
    Point p, newp;
    Size s, news;
    long gap;

    USHORT style = TEXT_DRAW_MULTILINE | TEXT_DRAW_TOP |
                   TEXT_DRAW_LEFT | TEXT_DRAW_WORDBREAK;

    // get dimensions of dialog instructions control
    p = aDialogDescription.GetPosPixel();
    s = aDialogDescription.GetSizePixel();

    // get dimensions occupied by text in the control
    Rectangle rect =
        GetTextRect( Rectangle( p, s ), aDialogDescription.GetText(), style );
    news = rect.GetSize();

    // the gap is the difference between the control height and its text height
    gap = s.Height() - news.Height();

    // resize the dialog instructions control
    news = Size( s.Width(), s.Height() - gap );
    aDialogDescription.SetSizePixel( news );

    // resize other controls to fill the gap
    p = aGroupText.GetPosPixel();
    newp = Point( p.X(), p.Y() - gap );
    aGroupText.SetPosPixel( newp );

    p = aCategories.GetPosPixel();
    newp = Point( p.X(), p.Y() - gap );
    aCategories.SetPosPixel( newp );
    s = aCategories.GetSizePixel();
    news = Size( s.Width(), s.Height() + gap );
    aCategories.SetSizePixel( news );

    p = aFunctionText.GetPosPixel();
    newp = Point( p.X(), p.Y() - gap );
    aFunctionText.SetPosPixel( newp );

    p = aCommands.GetPosPixel();
    newp = Point( p.X(), p.Y() - gap );
    aCommands.SetPosPixel( newp );
    s = aCommands.GetSizePixel();
    news = Size( s.Width(), s.Height() + gap );
    aCommands.SetSizePixel( news );

    p = aOKButton.GetPosPixel();
    newp = Point( p.X(), p.Y() - gap );
    aOKButton.SetPosPixel( newp );

    p = aCancelButton.GetPosPixel();
    newp = Point( p.X(), p.Y() - gap );
    aCancelButton.SetPosPixel( newp );

    p = aHelpButton.GetPosPixel();
    newp = Point( p.X(), p.Y() - gap );
    aHelpButton.SetPosPixel( newp );
}

SvxScriptSelectorDialog::~SvxScriptSelectorDialog()
{
}

IMPL_LINK( SvxScriptSelectorDialog, SelectHdl, Control*, pCtrl )
{
    if ( pCtrl == &aCategories )
    {
        aCategories.GroupSelected();
    }
    else if ( pCtrl == &aCommands )
    {
        aCommands.FunctionSelected();
    }
    UpdateUI();
    return 0;
}

IMPL_LINK( SvxScriptSelectorDialog, FunctionDoubleClickHdl, Control*, pCtrl )
{
    (void)pCtrl;
    if ( aOKButton.IsEnabled() )
        return ClickHdl( &aOKButton );
    return 0;
}

// Check if command is selected and enable the OK button accordingly
// Grab the help text for this id if available and update the description field
void
SvxScriptSelectorDialog::UpdateUI()
{
    OUString url = GetScriptURL();
    if ( url != NULL && url.getLength() != 0 )
    {
        String rMessage =
            aCommands.GetHelpText( aCommands.FirstSelected() );
        aDescriptionText.SetText( rMessage );

        aOKButton.Enable( TRUE );
    }
    else
    {
        aDescriptionText.SetText( String() );
        aOKButton.Enable( FALSE );
    }
}

IMPL_LINK( SvxScriptSelectorDialog, ClickHdl, Button *, pButton )
{
    if ( pButton == &aCancelButton )
    {
        // If we are displaying Slot API commands then the dialog is being
        // run from Tools/Configure and we should not close it, just hide it
        if ( m_bShowSlots == FALSE )
        {
            EndDialog( RET_CANCEL );
        }
        else
        {
            Hide();
        }
    }
    else if ( pButton == &aOKButton )
    {
        GetAddHdl().Call( this );

        // If we are displaying Slot API commands then this the dialog is being
        // run from Tools/Configure and we should not close it
        if ( m_bShowSlots == FALSE )
        {
            EndDialog( RET_OK );
        }
        else
        {
            // Select the next entry in the list if possible
            SvLBoxEntry* current = aCommands.FirstSelected();
            SvLBoxEntry* next = aCommands.NextSibling( current );

            if ( next != NULL )
            {
                aCommands.Select( next );
            }
        }
    }

    return 0;
}

void
SvxScriptSelectorDialog::SetRunLabel()
{
    aOKButton.SetText( String( CUI_RES( STR_SELECTOR_RUN ) ) );
}

void
SvxScriptSelectorDialog::SetDialogDescription( const String& rDescription )
{
    aDialogDescription.SetText( rDescription );
}

USHORT
SvxScriptSelectorDialog::GetSelectedId()
{
    return aCommands.GetId( aCommands.GetLastSelectedEntry() );
}

String
SvxScriptSelectorDialog::GetScriptURL() const
{
    OUString result;

    SvLBoxEntry *pEntry = const_cast< SvxScriptSelectorDialog* >( this )->aCommands.GetLastSelectedEntry();
    if ( pEntry )
    {
        SvxGroupInfo_Impl *pData = (SvxGroupInfo_Impl*) pEntry->GetUserData();
        if  (   ( pData->nKind == SVX_CFGFUNCTION_SLOT )
            ||  ( pData->nKind == SVX_CFGFUNCTION_SCRIPT )
            )
        {
            result = pData->sURL;
        }
    }

    return result;
}

String
SvxScriptSelectorDialog::GetSelectedDisplayName()
{
    return aCommands.GetEntryText( aCommands.GetLastSelectedEntry() );
}

String
SvxScriptSelectorDialog::GetSelectedHelpText()
{
    return aCommands.GetHelpText( aCommands.GetLastSelectedEntry() );
}
