/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "dp_gui.hrc"
#include "svtools/controldims.hrc"
#include "svtools/svtools.hrc"

#include "dp_gui.h"
#include "dp_gui_dialog2.hxx"
#include "dp_gui_extlistbox.hxx"
#include "dp_gui_shared.hxx"
#include "dp_gui_theextmgr.hxx"
#include "dp_gui_extensioncmdqueue.hxx"
#include "dp_misc.h"
#include "dp_ucb.h"
#include "dp_update.hxx"
#include "dp_identifier.hxx"
#include "dp_descriptioninfoset.hxx"

#include "vcl/ctrl.hxx"
#include "vcl/menu.hxx"
#include "vcl/msgbox.hxx"
#include "vcl/scrbar.hxx"
#include "vcl/svapp.hxx"

#include "osl/mutex.hxx"

#include "svtools/extensionlistbox.hxx"

#include "sfx2/sfxdlg.hxx"

#include "comphelper/anytostring.hxx"
#include "cppuhelper/exc_hlp.hxx"
#include "cppuhelper/bootstrap.hxx"

#include "comphelper/processfactory.hxx"
#include "ucbhelper/content.hxx"
#include "unotools/collatorwrapper.hxx"
#include "unotools/configmgr.hxx"

#include "com/sun/star/beans/StringPair.hpp"

#include "com/sun/star/i18n/CollatorOptions.hpp"

#include "com/sun/star/system/SystemShellExecuteFlags.hpp"
#include "com/sun/star/system/SystemShellExecute.hpp"

#include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp"
#include "com/sun/star/ui/dialogs/TemplateDescription.hpp"
#include "com/sun/star/ui/dialogs/FilePicker.hpp"
#include "com/sun/star/ui/dialogs/XFilterManager.hpp"

#include "com/sun/star/uno/Any.hxx"
#include "com/sun/star/uno/XComponentContext.hpp"

#include <map>
#include <vector>
#include <boost/shared_ptr.hpp>

using namespace ::com::sun::star;
using namespace ::com::sun::star::system;



namespace dp_gui {

#define TOP_OFFSET           5
#define LINE_SIZE            4
#define PROGRESS_WIDTH      60
#define PROGRESS_HEIGHT     14

#define USER_PACKAGE_MANAGER    "user"
#define SHARED_PACKAGE_MANAGER  "shared"
#define BUNDLED_PACKAGE_MANAGER "bundled"


struct StrAllFiles : public rtl::StaticWithInit< OUString, StrAllFiles >
{
    const OUString operator () () {
        const SolarMutexGuard guard;
        ::std::auto_ptr< ResMgr > const resmgr( ResMgr::CreateResMgr( "fps_office" ) );
        OSL_ASSERT( resmgr.get() != 0 );
        return ResId(STR_FILTERNAME_ALL, *resmgr.get()).toString();
    }
};


//                            ExtBoxWithBtns_Impl


enum MENU_COMMAND
{
    CMD_NONE    = 0,
    CMD_REMOVE  = 1,
    CMD_ENABLE,
    CMD_DISABLE,
    CMD_UPDATE,
    CMD_SHOW_LICENSE
};

class ExtBoxWithBtns_Impl : public ExtensionBox_Impl
{
    Size            m_aOutputSize;
    bool            m_bInterfaceLocked;

    PushButton     *m_pOptionsBtn;
    PushButton     *m_pEnableBtn;
    PushButton     *m_pRemoveBtn;

    ExtMgrDialog   *m_pParent;

    void            SetButtonPos( const Rectangle& rRect );
    void            SetButtonStatus( const TEntry_Impl pEntry );
    bool            HandleTabKey( bool bReverse );
    MENU_COMMAND    ShowPopupMenu( const Point &rPos, const long nPos );


    DECL_DLLPRIVATE_LINK( ScrollHdl, ScrollBar * );

    DECL_DLLPRIVATE_LINK( HandleOptionsBtn, void * );
    DECL_DLLPRIVATE_LINK( HandleEnableBtn, void * );
    DECL_DLLPRIVATE_LINK( HandleRemoveBtn, void * );

public:
                    ExtBoxWithBtns_Impl(Window* pParent);
                   virtual ~ExtBoxWithBtns_Impl();

    void InitFromDialog(ExtMgrDialog *pParentDialog);

    virtual void    MouseButtonDown( const MouseEvent& rMEvt ) SAL_OVERRIDE;
    virtual bool    Notify( NotifyEvent& rNEvt ) SAL_OVERRIDE;

    virtual Size    GetOptimalSize() const SAL_OVERRIDE;

    virtual void    RecalcAll() SAL_OVERRIDE;
    virtual void    selectEntry( const long nPos ) SAL_OVERRIDE;

    void            enableButtons( bool bEnable );
};

ExtBoxWithBtns_Impl::ExtBoxWithBtns_Impl(Window* pParent)
    : ExtensionBox_Impl(pParent)
    , m_bInterfaceLocked(false)
    , m_pOptionsBtn(NULL)
    , m_pEnableBtn(NULL)
    , m_pRemoveBtn(NULL)
    , m_pParent(NULL)
{
}

Size ExtBoxWithBtns_Impl::GetOptimalSize() const
{
    return LogicToPixel(Size(250, 150), MAP_APPFONT);
}


void ExtBoxWithBtns_Impl::InitFromDialog(ExtMgrDialog *pParentDialog)
{
    setExtensionManager(pParentDialog->getExtensionManager());

    m_pParent = pParentDialog;

    m_pOptionsBtn = new PushButton( this, WB_TABSTOP );
    m_pEnableBtn = new PushButton( this, WB_TABSTOP );
    m_pRemoveBtn = new PushButton( this, WB_TABSTOP );

    SetHelpId( HID_EXTENSION_MANAGER_LISTBOX );
    m_pOptionsBtn->SetHelpId( HID_EXTENSION_MANAGER_LISTBOX_OPTIONS );
    m_pEnableBtn->SetHelpId( HID_EXTENSION_MANAGER_LISTBOX_DISABLE );
    m_pRemoveBtn->SetHelpId( HID_EXTENSION_MANAGER_LISTBOX_REMOVE );

    m_pOptionsBtn->SetClickHdl( LINK( this, ExtBoxWithBtns_Impl, HandleOptionsBtn ) );
    m_pEnableBtn->SetClickHdl( LINK( this, ExtBoxWithBtns_Impl, HandleEnableBtn ) );
    m_pRemoveBtn->SetClickHdl( LINK( this, ExtBoxWithBtns_Impl, HandleRemoveBtn ) );

    m_pOptionsBtn->SetText( DialogHelper::getResourceString( RID_CTX_ITEM_OPTIONS ) );
    m_pEnableBtn->SetText( DialogHelper::getResourceString( RID_CTX_ITEM_DISABLE ) );
    m_pRemoveBtn->SetText( DialogHelper::getResourceString( RID_CTX_ITEM_REMOVE ) );

    Size aSize = LogicToPixel( Size( RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ),
                               MapMode( MAP_APPFONT ) );
    m_pOptionsBtn->SetSizePixel( aSize );
    m_pEnableBtn->SetSizePixel( aSize );
    m_pRemoveBtn->SetSizePixel( aSize );

    SetExtraSize( aSize.Height() + 2 * TOP_OFFSET );

    SetScrollHdl( LINK( this, ExtBoxWithBtns_Impl, ScrollHdl ) );
}


extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeExtBoxWithBtns(Window *pParent, VclBuilder::stringmap &)
{
    return new ExtBoxWithBtns_Impl(pParent);
}


ExtBoxWithBtns_Impl::~ExtBoxWithBtns_Impl()
{
    delete m_pOptionsBtn;
    delete m_pEnableBtn;
    delete m_pRemoveBtn;
}


void ExtBoxWithBtns_Impl::RecalcAll()
{
    const sal_Int32 nActive = getSelIndex();

    if ( nActive != svt::IExtensionListBox::ENTRY_NOTFOUND )
    {
        SetButtonStatus( GetEntryData( nActive) );
    }
    else
    {
        m_pOptionsBtn->Hide();
        m_pEnableBtn->Hide();
        m_pRemoveBtn->Hide();
    }

    ExtensionBox_Impl::RecalcAll();

    if ( nActive != svt::IExtensionListBox::ENTRY_NOTFOUND )
        SetButtonPos( GetEntryRect( nActive ) );
}



//This function may be called with nPos < 0
void ExtBoxWithBtns_Impl::selectEntry( const long nPos )
{
    if ( HasActive() && ( nPos == getSelIndex() ) )
        return;

    ExtensionBox_Impl::selectEntry( nPos );
}


void ExtBoxWithBtns_Impl::SetButtonPos( const Rectangle& rRect )
{
    Size  aBtnSize( m_pOptionsBtn->GetSizePixel() );
    Point aBtnPos( rRect.Left() + ICON_OFFSET,
                   rRect.Bottom() - TOP_OFFSET - aBtnSize.Height() );

    m_pOptionsBtn->SetPosPixel( aBtnPos );
    aBtnPos.X() = rRect.Right() - TOP_OFFSET - aBtnSize.Width();
    m_pRemoveBtn->SetPosPixel( aBtnPos );
    aBtnPos.X() -= ( TOP_OFFSET + aBtnSize.Width() );
    m_pEnableBtn->SetPosPixel( aBtnPos );
}


void ExtBoxWithBtns_Impl::SetButtonStatus( const TEntry_Impl pEntry )
{
    bool bShowOptionBtn = true;

    pEntry->m_bHasButtons = false;
    if ( ( pEntry->m_eState == REGISTERED ) || ( pEntry->m_eState == NOT_AVAILABLE ) )
    {
        m_pEnableBtn->SetText( DialogHelper::getResourceString( RID_CTX_ITEM_DISABLE ) );
        m_pEnableBtn->SetHelpId( HID_EXTENSION_MANAGER_LISTBOX_DISABLE );
    }
    else
    {
        m_pEnableBtn->SetText( DialogHelper::getResourceString( RID_CTX_ITEM_ENABLE ) );
        m_pEnableBtn->SetHelpId( HID_EXTENSION_MANAGER_LISTBOX_ENABLE );
        bShowOptionBtn = false;
    }

    if ( ( !pEntry->m_bUser || ( pEntry->m_eState == NOT_AVAILABLE ) || pEntry->m_bMissingDeps )
         && !pEntry->m_bMissingLic )
        m_pEnableBtn->Hide();
    else
    {
        m_pEnableBtn->Enable( !pEntry->m_bLocked );
        m_pEnableBtn->Show();
        pEntry->m_bHasButtons = true;
    }

    if ( pEntry->m_bHasOptions && bShowOptionBtn )
    {
        m_pOptionsBtn->Enable( pEntry->m_bHasOptions );
        m_pOptionsBtn->Show();
        pEntry->m_bHasButtons = true;
    }
    else
        m_pOptionsBtn->Hide();

    if ( pEntry->m_bUser || pEntry->m_bShared )
    {
        m_pRemoveBtn->Enable( !pEntry->m_bLocked );
        m_pRemoveBtn->Show();
        pEntry->m_bHasButtons = true;
    }
    else
        m_pRemoveBtn->Hide();
}


bool ExtBoxWithBtns_Impl::HandleTabKey( bool bReverse )
{
    sal_Int32 nIndex = getSelIndex();

    if ( nIndex == svt::IExtensionListBox::ENTRY_NOTFOUND )
        return false;

    PushButton *pNext = NULL;

    if ( m_pOptionsBtn->HasFocus() ) {
        if ( !bReverse && !GetEntryData( nIndex )->m_bLocked )
            pNext = m_pEnableBtn;
    }
    else if ( m_pEnableBtn->HasFocus() ) {
        if ( !bReverse )
            pNext = m_pRemoveBtn;
        else if ( GetEntryData( nIndex )->m_bHasOptions )
            pNext = m_pOptionsBtn;
    }
    else if ( m_pRemoveBtn->HasFocus() ) {
        if ( bReverse )
            pNext = m_pEnableBtn;
    }
    else {
        if ( !bReverse ) {
            if ( GetEntryData( nIndex )->m_bHasOptions )
                pNext = m_pOptionsBtn;
            else if ( ! GetEntryData( nIndex )->m_bLocked )
                pNext = m_pEnableBtn;
        } else {
            if ( ! GetEntryData( nIndex )->m_bLocked )
                pNext = m_pRemoveBtn;
            else if ( GetEntryData( nIndex )->m_bHasOptions )
                pNext = m_pOptionsBtn;
        }
    }

    if ( pNext )
    {
        pNext->GrabFocus();
        return true;
    }
    else
        return false;
}


MENU_COMMAND ExtBoxWithBtns_Impl::ShowPopupMenu( const Point & rPos, const long nPos )
{
    if ( nPos >= (long) getItemCount() )
        return CMD_NONE;

    PopupMenu aPopup;

    aPopup.InsertItem( CMD_UPDATE, DialogHelper::getResourceString( RID_CTX_ITEM_CHECK_UPDATE ) );

    if ( ! GetEntryData( nPos )->m_bLocked )
    {
        if ( GetEntryData( nPos )->m_bUser )
        {
            if ( GetEntryData( nPos )->m_eState == REGISTERED )
                aPopup.InsertItem( CMD_DISABLE, DialogHelper::getResourceString( RID_CTX_ITEM_DISABLE ) );
            else if ( GetEntryData( nPos )->m_eState != NOT_AVAILABLE )
                aPopup.InsertItem( CMD_ENABLE, DialogHelper::getResourceString( RID_CTX_ITEM_ENABLE ) );
        }
        aPopup.InsertItem( CMD_REMOVE, DialogHelper::getResourceString( RID_CTX_ITEM_REMOVE ) );
    }

    if ( !GetEntryData( nPos )->m_sLicenseText.isEmpty() )
        aPopup.InsertItem( CMD_SHOW_LICENSE, DialogHelper::getResourceString( RID_STR_SHOW_LICENSE_CMD ) );

    return (MENU_COMMAND) aPopup.Execute( this, rPos );
}


void ExtBoxWithBtns_Impl::MouseButtonDown( const MouseEvent& rMEvt )
{
    if ( m_bInterfaceLocked )
        return;

    const Point aMousePos( rMEvt.GetPosPixel() );
    const long nPos = PointToPos( aMousePos );

    if ( rMEvt.IsRight() )
    {
        switch( ShowPopupMenu( aMousePos, nPos ) )
        {
            case CMD_NONE:      break;
            case CMD_ENABLE:    m_pParent->enablePackage( GetEntryData( nPos )->m_xPackage, true );
                                break;
            case CMD_DISABLE:   m_pParent->enablePackage( GetEntryData( nPos )->m_xPackage, false );
                                break;
            case CMD_UPDATE:    m_pParent->updatePackage( GetEntryData( nPos )->m_xPackage );
                                break;
            case CMD_REMOVE:    m_pParent->removePackage( GetEntryData( nPos )->m_xPackage );
                                break;
            case CMD_SHOW_LICENSE:
                {
                    ShowLicenseDialog aLicenseDlg( m_pParent, GetEntryData( nPos )->m_xPackage );
                    aLicenseDlg.Execute();
                    break;
                }
        }
    }
    else if ( rMEvt.IsLeft() )
    {
        const SolarMutexGuard aGuard;
        if ( rMEvt.IsMod1() && HasActive() )
            selectEntry( svt::IExtensionListBox::ENTRY_NOTFOUND );
                // selecting a not existing entry will deselect the current one
        else
            selectEntry( nPos );
    }
}


bool ExtBoxWithBtns_Impl::Notify( NotifyEvent& rNEvt )
{
    bool bHandled = false;

    if ( rNEvt.GetType() == EVENT_KEYINPUT )
    {
        const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
        KeyCode         aKeyCode = pKEvt->GetKeyCode();
        sal_uInt16          nKeyCode = aKeyCode.GetCode();

        if ( nKeyCode == KEY_TAB )
            bHandled = HandleTabKey( aKeyCode.IsShift() );
    }

    if ( !bHandled )
        return ExtensionBox_Impl::Notify( rNEvt );
    else
        return true;
}


void ExtBoxWithBtns_Impl::enableButtons( bool bEnable )
{
    m_bInterfaceLocked = ! bEnable;

    if ( bEnable )
    {
        sal_Int32 nIndex = getSelIndex();
        if ( nIndex != svt::IExtensionListBox::ENTRY_NOTFOUND )
            SetButtonStatus( GetEntryData( nIndex ) );
    }
    else
    {
        m_pOptionsBtn->Enable( false );
        m_pRemoveBtn->Enable( false );
        m_pEnableBtn->Enable( false );
    }
}


IMPL_LINK( ExtBoxWithBtns_Impl, ScrollHdl, ScrollBar*, pScrBar )
{
    long nDelta = pScrBar->GetDelta();

    Point aNewOptPt( m_pOptionsBtn->GetPosPixel() - Point( 0, nDelta ) );
    Point aNewRemPt( m_pRemoveBtn->GetPosPixel() - Point( 0, nDelta ) );
    Point aNewEnPt( m_pEnableBtn->GetPosPixel() - Point( 0, nDelta ) );

    DoScroll( nDelta );

    m_pOptionsBtn->SetPosPixel( aNewOptPt );
    m_pRemoveBtn->SetPosPixel( aNewRemPt );
    m_pEnableBtn->SetPosPixel( aNewEnPt );

    return 1;
}


IMPL_LINK_NOARG(ExtBoxWithBtns_Impl, HandleOptionsBtn)
{
    const sal_Int32 nActive = getSelIndex();

    if ( nActive != svt::IExtensionListBox::ENTRY_NOTFOUND )
    {
        SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();

        if ( pFact )
        {
            OUString sExtensionId = GetEntryData( nActive )->m_xPackage->getIdentifier().Value;
            VclAbstractDialog* pDlg = pFact->CreateOptionsDialog( this, sExtensionId, OUString() );

            pDlg->Execute();

            delete pDlg;
        }
    }

    return 1;
}


IMPL_LINK_NOARG(ExtBoxWithBtns_Impl, HandleEnableBtn)
{
    const sal_Int32 nActive = getSelIndex();

    if ( nActive != svt::IExtensionListBox::ENTRY_NOTFOUND )
    {
        TEntry_Impl pEntry = GetEntryData( nActive );

        if ( pEntry->m_bMissingLic )
            m_pParent->acceptLicense( pEntry->m_xPackage );
        else
        {
            const bool bEnable( pEntry->m_eState != REGISTERED );
            m_pParent->enablePackage( pEntry->m_xPackage, bEnable );
        }
    }

    return 1;
}


IMPL_LINK_NOARG(ExtBoxWithBtns_Impl, HandleRemoveBtn)
{
    const sal_Int32 nActive = getSelIndex();

    if ( nActive != svt::IExtensionListBox::ENTRY_NOTFOUND )
    {
        TEntry_Impl pEntry = GetEntryData( nActive );
        m_pParent->removePackage( pEntry->m_xPackage );
    }

    return 1;
}


//                             DialogHelper

DialogHelper::DialogHelper( const uno::Reference< uno::XComponentContext > &xContext,
                            Dialog *pWindow ) :
    m_pVCLWindow( pWindow ),
    m_nEventID(   0 ),
    m_bIsBusy(    false )
{
    m_xContext = xContext;
}


DialogHelper::~DialogHelper()
{
    if ( m_nEventID )
        Application::RemoveUserEvent( m_nEventID );
}


ResId DialogHelper::getResId( sal_uInt16 nId )
{
    const SolarMutexGuard guard;
    return ResId( nId, *DeploymentGuiResMgr::get() );
}


OUString DialogHelper::getResourceString(sal_uInt16 id)
{
    const SolarMutexGuard guard;
    OUString ret(ResId(id, *DeploymentGuiResMgr::get()).toString());
    if (ret.indexOf("%PRODUCTNAME" ) != -1)
    {
        ret = ret.replaceAll("%PRODUCTNAME", utl::ConfigManager::getProductName());
    }
    return ret;
}


bool DialogHelper::IsSharedPkgMgr( const uno::Reference< deployment::XPackage > &xPackage )
{
    if ( xPackage->getRepositoryName() == SHARED_PACKAGE_MANAGER )
        return true;
    else
        return false;
}


bool DialogHelper::continueOnSharedExtension( const uno::Reference< deployment::XPackage > &xPackage,
                                              Window *pParent,
                                              const sal_uInt16 nResID,
                                              bool &bHadWarning )
{
    if ( !bHadWarning && IsSharedPkgMgr( xPackage ) )
    {
        const SolarMutexGuard guard;
        WarningBox aInfoBox( pParent, getResId( nResID ) );
        OUString aMsgText = aInfoBox.GetMessText();
        aMsgText = aMsgText.replaceAll(
            "%PRODUCTNAME", utl::ConfigManager::getProductName());
        aInfoBox.SetMessText( aMsgText );

        bHadWarning = true;

        if ( RET_OK == aInfoBox.Execute() )
            return true;
        else
            return false;
    }
    else
        return true;
}


void DialogHelper::openWebBrowser( const OUString & sURL, const OUString &sTitle ) const
{
    if ( sURL.isEmpty() ) // Nothing to do, when the URL is empty
        return;

    try
    {
        uno::Reference< XSystemShellExecute > xSystemShellExecute(
            SystemShellExecute::create(m_xContext));
        //throws css::lang::IllegalArgumentException, css::system::SystemShellExecuteException
        xSystemShellExecute->execute( sURL, OUString(),  SystemShellExecuteFlags::URIS_ONLY );
    }
    catch ( const uno::Exception& )
    {
        uno::Any exc( ::cppu::getCaughtException() );
        OUString msg( ::comphelper::anyToString( exc ) );
        const SolarMutexGuard guard;
        ErrorBox aErrorBox( NULL, WB_OK, msg );
        aErrorBox.SetText( sTitle );
        aErrorBox.Execute();
    }
}


bool DialogHelper::installExtensionWarn( const OUString &rExtensionName ) const
{
    const SolarMutexGuard guard;
    WarningBox aInfo( m_pVCLWindow, getResId( RID_WARNINGBOX_INSTALL_EXTENSION ) );

    OUString sText(aInfo.GetMessText());
    sText = sText.replaceAll("%NAME", rExtensionName);
    aInfo.SetMessText(sText);

    return ( RET_OK == aInfo.Execute() );
}


bool DialogHelper::installForAllUsers( bool &bInstallForAll ) const
{
    const SolarMutexGuard guard;
    QueryBox aQuery( m_pVCLWindow, getResId( RID_QUERYBOX_INSTALL_FOR_ALL ) );

    OUString sMsgText(aQuery.GetMessText());
    sMsgText = sMsgText.replaceAll(
        "%PRODUCTNAME", utl::ConfigManager::getProductName());
    aQuery.SetMessText(sMsgText);

    sal_uInt16 nYesBtnID = aQuery.GetButtonId( 0 );
    sal_uInt16 nNoBtnID = aQuery.GetButtonId( 1 );

    if ( nYesBtnID != BUTTONDIALOG_BUTTON_NOTFOUND )
        aQuery.SetButtonText( nYesBtnID, getResourceString( RID_STR_INSTALL_FOR_ME ) );
    if ( nNoBtnID != BUTTONDIALOG_BUTTON_NOTFOUND )
        aQuery.SetButtonText( nNoBtnID, getResourceString( RID_STR_INSTALL_FOR_ALL ) );

    short nRet = aQuery.Execute();

    if ( nRet == RET_CANCEL )
        return false;

    bInstallForAll = ( nRet == RET_NO );
    return true;
}


void DialogHelper::PostUserEvent( const Link& rLink, void* pCaller )
{
    if ( m_nEventID )
        Application::RemoveUserEvent( m_nEventID );

    m_nEventID = Application::PostUserEvent( rLink, pCaller );
}


//                             ExtMgrDialog

ExtMgrDialog::ExtMgrDialog(Window *pParent, TheExtensionManager *pManager)
    : ModelessDialog(pParent, "ExtensionManagerDialog", "desktop/ui/extensionmanager.ui")
    , DialogHelper(pManager->getContext(), (Dialog*) this)
    , m_sAddPackages(getResourceString(RID_STR_ADD_PACKAGES))
    , m_bHasProgress(false)
    , m_bProgressChanged(false)
    , m_bStartProgress(false)
    , m_bStopProgress(false)
    , m_bEnableWarning(false)
    , m_bDisableWarning(false)
    , m_bDeleteWarning(false)
    , m_nProgress(0)
    , m_pManager(pManager)
{
    get(m_pExtensionBox, "extensions");
    get(m_pAddBtn, "add");
    get(m_pUpdateBtn, "update");
    get(m_pCloseBtn, "close");
    get(m_pBundledCbx, "bundled");
    get(m_pSharedCbx, "shared");
    get(m_pUserCbx, "user");
    get(m_pGetExtensions, "getextensions");
    get(m_pProgressText, "progressft");
    get(m_pProgressBar, "progressbar");
    get(m_pCancelBtn, "cancel");

    m_pExtensionBox->InitFromDialog(this);
    m_pExtensionBox->SetHyperlinkHdl( LINK( this, ExtMgrDialog, HandleHyperlink ) );

    m_pAddBtn->SetClickHdl( LINK( this, ExtMgrDialog, HandleAddBtn ) );
    m_pCloseBtn->SetClickHdl( LINK( this, ExtMgrDialog, HandleCloseBtn ) );

    m_pUpdateBtn->SetClickHdl( LINK( this, ExtMgrDialog, HandleUpdateBtn ) );
    m_pGetExtensions->SetClickHdl( LINK( this, ExtMgrDialog, HandleHyperlink ) );
    m_pCancelBtn->SetClickHdl( LINK( this, ExtMgrDialog, HandleCancelBtn ) );

    m_pBundledCbx->SetClickHdl( LINK( this, ExtMgrDialog, HandleExtTypeCbx ) );
    m_pSharedCbx->SetClickHdl( LINK( this, ExtMgrDialog, HandleExtTypeCbx ) );
    m_pUserCbx->SetClickHdl( LINK( this, ExtMgrDialog, HandleExtTypeCbx ) );

    m_pBundledCbx->Check( true );
    m_pSharedCbx->Check( true );
    m_pUserCbx->Check( true );

    m_pProgressBar->Hide();

    m_pUpdateBtn->Enable(false);

    m_aTimeoutTimer.SetTimeout( 500 ); // mSec
    m_aTimeoutTimer.SetTimeoutHdl( LINK( this, ExtMgrDialog, TimeOutHdl ) );
}


ExtMgrDialog::~ExtMgrDialog()
{
    m_aTimeoutTimer.Stop();
}


void ExtMgrDialog::setGetExtensionsURL( const OUString &rURL )
{
    m_pGetExtensions->SetURL( rURL );
}


long ExtMgrDialog::addPackageToList( const uno::Reference< deployment::XPackage > &xPackage,
                                     bool bLicenseMissing )
{

    const SolarMutexGuard aGuard;
    m_pUpdateBtn->Enable(true);

    m_pExtensionBox->removeEntry(xPackage);

    if (m_pBundledCbx->IsChecked() && (xPackage->getRepositoryName() == BUNDLED_PACKAGE_MANAGER) )
    {
       return m_pExtensionBox->addEntry( xPackage, bLicenseMissing );
    }
    else if (m_pSharedCbx->IsChecked() && (xPackage->getRepositoryName() == SHARED_PACKAGE_MANAGER) )
    {
        return m_pExtensionBox->addEntry( xPackage, bLicenseMissing );
    }
    else if (m_pUserCbx->IsChecked() && (xPackage->getRepositoryName() == USER_PACKAGE_MANAGER ))
    {
        return m_pExtensionBox->addEntry( xPackage, bLicenseMissing );
    }
    else
    {
    //OSL_FAIL("Package will not be displayed");
        return 0;
    }
}


void ExtMgrDialog::prepareChecking()
{
    m_pExtensionBox->prepareChecking();
}


void ExtMgrDialog::checkEntries()
{
    const SolarMutexGuard guard;
    m_pExtensionBox->checkEntries();
}


bool ExtMgrDialog::removeExtensionWarn( const OUString &rExtensionName ) const
{
    const SolarMutexGuard guard;
    WarningBox aInfo( const_cast< ExtMgrDialog* >(this), getResId( RID_WARNINGBOX_REMOVE_EXTENSION ) );

    OUString sText(aInfo.GetMessText());
    sText = sText.replaceAll("%NAME", rExtensionName);
    aInfo.SetMessText(sText);

    return ( RET_OK == aInfo.Execute() );
}


bool ExtMgrDialog::enablePackage( const uno::Reference< deployment::XPackage > &xPackage,
                                  bool bEnable )
{
    if ( !xPackage.is() )
        return false;

    if ( bEnable )
    {
        if ( ! continueOnSharedExtension( xPackage, this, RID_WARNINGBOX_ENABLE_SHARED_EXTENSION, m_bEnableWarning ) )
            return false;
    }
    else
    {
        if ( ! continueOnSharedExtension( xPackage, this, RID_WARNINGBOX_DISABLE_SHARED_EXTENSION, m_bDisableWarning ) )
            return false;
    }

    m_pManager->getCmdQueue()->enableExtension( xPackage, bEnable );

    return true;
}


bool ExtMgrDialog::removePackage( const uno::Reference< deployment::XPackage > &xPackage )
{
    if ( !xPackage.is() )
        return false;

    if ( !IsSharedPkgMgr( xPackage ) || m_bDeleteWarning )
    {
        if ( ! removeExtensionWarn( xPackage->getDisplayName() ) )
            return false;
    }

    if ( ! continueOnSharedExtension( xPackage, this, RID_WARNINGBOX_REMOVE_SHARED_EXTENSION, m_bDeleteWarning ) )
        return false;

    m_pManager->getCmdQueue()->removeExtension( xPackage );

    return true;
}


bool ExtMgrDialog::updatePackage( const uno::Reference< deployment::XPackage > &xPackage )
{
    if ( !xPackage.is() )
        return false;

    // get the extension with highest version
    uno::Sequence<uno::Reference<deployment::XPackage> > seqExtensions =
    m_pManager->getExtensionManager()->getExtensionsWithSameIdentifier(
        dp_misc::getIdentifier(xPackage), xPackage->getName(), uno::Reference<ucb::XCommandEnvironment>());
    uno::Reference<deployment::XPackage> extension =
        dp_misc::getExtensionWithHighestVersion(seqExtensions);
    OSL_ASSERT(extension.is());
    std::vector< css::uno::Reference< css::deployment::XPackage > > vEntries;
    vEntries.push_back(extension);

    m_pManager->getCmdQueue()->checkForUpdates( vEntries );

    return true;
}


bool ExtMgrDialog::acceptLicense( const uno::Reference< deployment::XPackage > &xPackage )
{
    if ( !xPackage.is() )
        return false;

    m_pManager->getCmdQueue()->acceptLicense( xPackage );

    return true;
}


uno::Sequence< OUString > ExtMgrDialog::raiseAddPicker()
{
    const uno::Reference< uno::XComponentContext > xContext( m_pManager->getContext() );
    const uno::Reference< ui::dialogs::XFilePicker3 > xFilePicker =
        ui::dialogs::FilePicker::createWithMode(xContext, ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE);
    xFilePicker->setTitle( m_sAddPackages );

    if ( !m_sLastFolderURL.isEmpty() )
        xFilePicker->setDisplayDirectory( m_sLastFolderURL );

    // collect and set filter list:
    typedef ::std::map< OUString, OUString > t_string2string;
    t_string2string title2filter;
    OUString sDefaultFilter( StrAllFiles::get() );

    const uno::Sequence< uno::Reference< deployment::XPackageTypeInfo > > packageTypes(
        m_pManager->getExtensionManager()->getSupportedPackageTypes() );

    for ( sal_Int32 pos = 0; pos < packageTypes.getLength(); ++pos )
    {
        uno::Reference< deployment::XPackageTypeInfo > const & xPackageType = packageTypes[ pos ];
        const OUString filter( xPackageType->getFileFilter() );
        if (!filter.isEmpty())
        {
            const OUString title( xPackageType->getShortDescription() );
            const ::std::pair< t_string2string::iterator, bool > insertion(
                title2filter.insert( t_string2string::value_type( title, filter ) ) );
            if ( ! insertion.second )
            { // already existing, append extensions:
                OUStringBuffer buf;
                buf.append( insertion.first->second );
                buf.append( ';' );
                buf.append( filter );
                insertion.first->second = buf.makeStringAndClear();
            }
            if ( xPackageType->getMediaType() == "application/vnd.sun.star.package-bundle" )
                sDefaultFilter = title;
        }
    }

    // All files at top:
    xFilePicker->appendFilter( StrAllFiles::get(), "*.*" );
    // then supported ones:
    t_string2string::const_iterator iPos( title2filter.begin() );
    const t_string2string::const_iterator iEnd( title2filter.end() );
    for ( ; iPos != iEnd; ++iPos ) {
        try {
            xFilePicker->appendFilter( iPos->first, iPos->second );
        }
        catch (const lang::IllegalArgumentException & exc) {
            OSL_FAIL( OUStringToOString(
                            exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
            (void) exc;
        }
    }
    xFilePicker->setCurrentFilter( sDefaultFilter );

    if ( xFilePicker->execute() != ui::dialogs::ExecutableDialogResults::OK )
        return uno::Sequence<OUString>(); // cancelled

    m_sLastFolderURL = xFilePicker->getDisplayDirectory();
    uno::Sequence< OUString > files( xFilePicker->getFiles() );
    OSL_ASSERT( files.getLength() > 0 );
    return files;
}


IMPL_LINK_NOARG(ExtMgrDialog, HandleCancelBtn)
{
    if ( m_xAbortChannel.is() )
    {
        try
        {
            m_xAbortChannel->sendAbort();
        }
        catch ( const uno::RuntimeException & )
        {
            OSL_FAIL( "### unexpected RuntimeException!" );
        }
    }
    return 1;
}

IMPL_LINK_NOARG(ExtMgrDialog, HandleCloseBtn)
{
    Close();
    return 1;
}



IMPL_LINK( ExtMgrDialog, startProgress, void*, _bLockInterface )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    bool bLockInterface = (bool) _bLockInterface;

    if ( m_bStartProgress && !m_bHasProgress )
        m_aTimeoutTimer.Start();

    if ( m_bStopProgress )
    {
        if ( m_pProgressBar->IsVisible() )
            m_pProgressBar->SetValue( 100 );
        m_xAbortChannel.clear();

        OSL_TRACE( " startProgress handler: stop" );
    }
    else
    {
        OSL_TRACE( " startProgress handler: start" );
    }

    m_pCancelBtn->Enable( bLockInterface );
    m_pAddBtn->Enable( !bLockInterface );
    m_pUpdateBtn->Enable( !bLockInterface && m_pExtensionBox->getItemCount() );
    m_pExtensionBox->enableButtons( !bLockInterface );

    clearEventID();

    return 0;
}


void ExtMgrDialog::showProgress( bool _bStart )
{
    ::osl::MutexGuard aGuard( m_aMutex );

    bool bStart = _bStart;

    if ( bStart )
    {
        m_nProgress = 0;
        m_bStartProgress = true;
        OSL_TRACE( "showProgress start" );
    }
    else
    {
        m_nProgress = 100;
        m_bStopProgress = true;
        OSL_TRACE( "showProgress stop!" );
    }

    DialogHelper::PostUserEvent( LINK( this, ExtMgrDialog, startProgress ), (void*) bStart );
}


void ExtMgrDialog::updateProgress( const long nProgress )
{
    ::osl::MutexGuard aGuard( m_aMutex );

    m_nProgress = nProgress;
}


void ExtMgrDialog::updateProgress( const OUString &rText,
                                   const uno::Reference< task::XAbortChannel > &xAbortChannel)
{
    ::osl::MutexGuard aGuard( m_aMutex );

    m_xAbortChannel = xAbortChannel;
    m_sProgressText = rText;
    m_bProgressChanged = true;
}


void ExtMgrDialog::updatePackageInfo( const uno::Reference< deployment::XPackage > &xPackage )
{
    const SolarMutexGuard aGuard;
    m_pExtensionBox->updateEntry( xPackage );
}


IMPL_LINK_NOARG(ExtMgrDialog, HandleAddBtn)
{
    setBusy( true );

    uno::Sequence< OUString > aFileList = raiseAddPicker();

    if ( aFileList.getLength() )
    {
        m_pManager->installPackage( aFileList[0] );
    }

    setBusy( false );
    return 1;
}


IMPL_LINK_NOARG(ExtMgrDialog, HandleExtTypeCbx)
{
    // re-creates the list of packages with addEntry selecting the packages
    m_pManager->createPackageList();
    return 1;
}

IMPL_LINK_NOARG(ExtMgrDialog, HandleUpdateBtn)
{
    m_pManager->checkUpdates( false, true );

    return 1;
}


IMPL_LINK( ExtMgrDialog, HandleHyperlink, FixedHyperlink*, pHyperlink )
{
    openWebBrowser( pHyperlink->GetURL(), GetText() );

    return 1;
}


IMPL_LINK_NOARG(ExtMgrDialog, TimeOutHdl)
{
    if ( m_bStopProgress )
    {
        m_bHasProgress = false;
        m_bStopProgress = false;
        m_pProgressText->Hide();
        m_pProgressBar->Hide();
        m_pCancelBtn->Hide();
    }
    else
    {
        if ( m_bProgressChanged )
        {
            m_bProgressChanged = false;
            m_pProgressText->SetText(m_sProgressText);
        }

        if ( m_bStartProgress )
        {
            m_bStartProgress = false;
            m_bHasProgress = true;
            m_pProgressBar->Show();
            m_pProgressText->Show();
            m_pCancelBtn->Enable();
            m_pCancelBtn->Show();
        }

        if ( m_pProgressBar->IsVisible() )
            m_pProgressBar->SetValue( (sal_uInt16) m_nProgress );

        m_aTimeoutTimer.Start();
    }

    return 1;
}


// VCL::Window / Dialog

bool ExtMgrDialog::Notify( NotifyEvent& rNEvt )
{
    bool bHandled = false;

    if ( rNEvt.GetType() == EVENT_KEYINPUT )
    {
        const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
        KeyCode         aKeyCode = pKEvt->GetKeyCode();
        sal_uInt16          nKeyCode = aKeyCode.GetCode();

        if ( nKeyCode == KEY_TAB )
        {
            if ( aKeyCode.IsShift() ) {
                if ( m_pAddBtn->HasFocus() ) {
                    m_pExtensionBox->GrabFocus();
                    bHandled = true;
                }
            } else {
                if ( m_pGetExtensions->HasFocus() ) {
                    m_pExtensionBox->GrabFocus();
                    bHandled = true;
                }
            }
        }
        if ( aKeyCode.GetGroup() == KEYGROUP_CURSOR )
            bHandled = m_pExtensionBox->Notify( rNEvt );
    }
// VCLEVENT_WINDOW_CLOSE
    if ( !bHandled )
        return ModelessDialog::Notify( rNEvt );
    else
        return true;
}


bool ExtMgrDialog::Close()
{
    bool bRet = m_pManager->queryTermination();
    if ( bRet )
    {
        bRet = ModelessDialog::Close();
        m_pManager->terminateDialog();
    }
    return bRet;
}


//                             UpdateRequiredDialog

UpdateRequiredDialog::UpdateRequiredDialog( Window *pParent, TheExtensionManager *pManager ) :
    ModalDialog( pParent,   getResId( RID_DLG_UPDATE_REQUIRED ) ),
    DialogHelper( pManager->getContext(), (Dialog*) this ),
    m_aUpdateNeeded( this,  getResId( RID_EM_FT_MSG ) ),
    m_aUpdateBtn( this,     getResId( RID_EM_BTN_CHECK_UPDATES ) ),
    m_aCloseBtn( this,      getResId( RID_EM_BTN_CLOSE ) ),
    m_aHelpBtn( this,       getResId( RID_EM_BTN_HELP ) ),
    m_aCancelBtn( this,     getResId( RID_EM_BTN_CANCEL ) ),
    m_aDivider( this ),
    m_aProgressText( this,  getResId( RID_EM_FT_PROGRESS ) ),
    m_aProgressBar( this,   WB_BORDER + WB_3DLOOK ),
    m_sAddPackages(         getResourceString( RID_STR_ADD_PACKAGES ) ),
    m_sCloseText(           getResourceString( RID_STR_CLOSE_BTN ) ),
    m_bHasProgress(         false ),
    m_bProgressChanged(     false ),
    m_bStartProgress(       false ),
    m_bStopProgress(        false ),
    m_bUpdateWarning(       false ),
    m_bDisableWarning(      false ),
    m_bHasLockedEntries(    false ),
    m_nProgress(            0 ),
    m_pManager( pManager )
{
    // free local resources (RID < 256):
    FreeResource();

    m_pExtensionBox = new ExtensionBox_Impl( this, pManager );
    m_pExtensionBox->SetHyperlinkHdl( LINK( this, UpdateRequiredDialog, HandleHyperlink ) );

    m_aUpdateBtn.SetClickHdl( LINK( this, UpdateRequiredDialog, HandleUpdateBtn ) );
    m_aCloseBtn.SetClickHdl( LINK( this, UpdateRequiredDialog, HandleCloseBtn ) );
    m_aCancelBtn.SetClickHdl( LINK( this, UpdateRequiredDialog, HandleCancelBtn ) );

    OUString aText = m_aUpdateNeeded.GetText();
    aText = aText.replaceAll(
        "%PRODUCTNAME", utl::ConfigManager::getProductName());
    m_aUpdateNeeded.SetText(aText);

    // resize update button
    Size aBtnSize = m_aUpdateBtn.GetSizePixel();
    OUString sTitle = m_aUpdateBtn.GetText();
    long nWidth = m_aUpdateBtn.GetCtrlTextWidth( sTitle );
    nWidth += 2 * m_aUpdateBtn.GetTextHeight();
    if ( nWidth > aBtnSize.Width() )
        m_aUpdateBtn.SetSizePixel( Size( nWidth, aBtnSize.Height() ) );

    // resize update button
    aBtnSize = m_aCloseBtn.GetSizePixel();
    sTitle = m_aCloseBtn.GetText();
    nWidth = m_aCloseBtn.GetCtrlTextWidth( sTitle );
    nWidth += 2 * m_aCloseBtn.GetTextHeight();
    if ( nWidth > aBtnSize.Width() )
        m_aCloseBtn.SetSizePixel( Size( nWidth, aBtnSize.Height() ) );

    // minimum size:
    SetMinOutputSizePixel(
        Size( // width:
              (5 * m_aHelpBtn.GetSizePixel().Width()) +
              (5 * RSC_SP_DLG_INNERBORDER_LEFT ),
              // height:
              (1 * m_aHelpBtn.GetSizePixel().Height()) +
              (1 * m_aUpdateNeeded.GetSizePixel().Height()) +
              (1 * m_pExtensionBox->GetMinOutputSizePixel().Height()) +
              (3 * RSC_SP_DLG_INNERBORDER_LEFT) ) );

    m_aDivider.Show();
    m_aProgressBar.Hide();
    m_aUpdateBtn.Enable( false );
    m_aCloseBtn.GrabFocus();

    m_aTimeoutTimer.SetTimeout( 50 ); // mSec
    m_aTimeoutTimer.SetTimeoutHdl( LINK( this, UpdateRequiredDialog, TimeOutHdl ) );
}


UpdateRequiredDialog::~UpdateRequiredDialog()
{
    m_aTimeoutTimer.Stop();

    delete m_pExtensionBox;
}


long UpdateRequiredDialog::addPackageToList( const uno::Reference< deployment::XPackage > &xPackage,
                                             bool bLicenseMissing )
{
    // We will only add entries to the list with unsatisfied dependencies
    if ( !bLicenseMissing && !checkDependencies( xPackage ) )
    {
        m_bHasLockedEntries |= m_pManager->isReadOnly( xPackage );
        const SolarMutexGuard aGuard;
        m_aUpdateBtn.Enable( true );
        return m_pExtensionBox->addEntry( xPackage );
    }
    return 0;
}


void UpdateRequiredDialog::prepareChecking()
{
    m_pExtensionBox->prepareChecking();
}


void UpdateRequiredDialog::checkEntries()
{
    const SolarMutexGuard guard;
    m_pExtensionBox->checkEntries();

    if ( ! hasActiveEntries() )
    {
        m_aCloseBtn.SetText( m_sCloseText );
        m_aCloseBtn.GrabFocus();
    }
}


bool UpdateRequiredDialog::enablePackage( const uno::Reference< deployment::XPackage > &xPackage,
                                          bool bEnable )
{
    m_pManager->getCmdQueue()->enableExtension( xPackage, bEnable );

    return true;
}


IMPL_LINK_NOARG(UpdateRequiredDialog, HandleCancelBtn)
{
    if ( m_xAbortChannel.is() )
    {
        try
        {
            m_xAbortChannel->sendAbort();
        }
        catch ( const uno::RuntimeException & )
        {
            OSL_FAIL( "### unexpected RuntimeException!" );
        }
    }
    return 1;
}


IMPL_LINK( UpdateRequiredDialog, startProgress, void*, _bLockInterface )
{
    ::osl::MutexGuard aGuard( m_aMutex );
    bool bLockInterface = (bool) _bLockInterface;

    if ( m_bStartProgress && !m_bHasProgress )
        m_aTimeoutTimer.Start();

    if ( m_bStopProgress )
    {
        if ( m_aProgressBar.IsVisible() )
            m_aProgressBar.SetValue( 100 );
        m_xAbortChannel.clear();
        OSL_TRACE( " startProgress handler: stop" );
    }
    else
    {
        OSL_TRACE( " startProgress handler: start" );
    }

    m_aCancelBtn.Enable( bLockInterface );
    m_aUpdateBtn.Enable( false );
    clearEventID();

    return 0;
}


void UpdateRequiredDialog::showProgress( bool _bStart )
{
    ::osl::MutexGuard aGuard( m_aMutex );

    bool bStart = _bStart;

    if ( bStart )
    {
        m_nProgress = 0;
        m_bStartProgress = true;
        OSL_TRACE( "showProgress start" );
    }
    else
    {
        m_nProgress = 100;
        m_bStopProgress = true;
        OSL_TRACE( "showProgress stop!" );
    }

    DialogHelper::PostUserEvent( LINK( this, UpdateRequiredDialog, startProgress ), (void*) bStart );
}


void UpdateRequiredDialog::updateProgress( const long nProgress )
{
    ::osl::MutexGuard aGuard( m_aMutex );

    m_nProgress = nProgress;
}


void UpdateRequiredDialog::updateProgress( const OUString &rText,
                                           const uno::Reference< task::XAbortChannel > &xAbortChannel)
{
    ::osl::MutexGuard aGuard( m_aMutex );

    m_xAbortChannel = xAbortChannel;
    m_sProgressText = rText;
    m_bProgressChanged = true;
}


void UpdateRequiredDialog::updatePackageInfo( const uno::Reference< deployment::XPackage > &xPackage )
{
    // We will remove all updated packages with satisfied dependencies, but
    // we will show all disabled entries so the user sees the result
    // of the 'disable all' button
    const SolarMutexGuard aGuard;
    if ( isEnabled( xPackage ) && checkDependencies( xPackage ) )
        m_pExtensionBox->removeEntry( xPackage );
    else
        m_pExtensionBox->updateEntry( xPackage );

    if ( ! hasActiveEntries() )
    {
        m_aCloseBtn.SetText( m_sCloseText );
        m_aCloseBtn.GrabFocus();
    }
}


IMPL_LINK_NOARG(UpdateRequiredDialog, HandleUpdateBtn)
{
    ::osl::ClearableMutexGuard aGuard( m_aMutex );

    std::vector< uno::Reference< deployment::XPackage > > vUpdateEntries;
    sal_Int32 nCount = m_pExtensionBox->GetEntryCount();

    for ( sal_Int32 i = 0; i < nCount; ++i )
    {
        TEntry_Impl pEntry = m_pExtensionBox->GetEntryData( i );
        vUpdateEntries.push_back( pEntry->m_xPackage );
    }

    aGuard.clear();

    m_pManager->getCmdQueue()->checkForUpdates( vUpdateEntries );

    return 1;
}


IMPL_LINK_NOARG(UpdateRequiredDialog, HandleCloseBtn)
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if ( !isBusy() )
    {
        if ( m_bHasLockedEntries )
            EndDialog( -1 );
        else if ( hasActiveEntries() )
            disableAllEntries();
        else
            EndDialog( 0 );
    }

    return 1;
}


IMPL_LINK( UpdateRequiredDialog, HandleHyperlink, FixedHyperlink*, pHyperlink )
{
    openWebBrowser( pHyperlink->GetURL(), GetText() );

    return 1;
}


IMPL_LINK_NOARG(UpdateRequiredDialog, TimeOutHdl)
{
    if ( m_bStopProgress )
    {
        m_bHasProgress = false;
        m_bStopProgress = false;
        m_aProgressText.Hide();
        m_aProgressBar.Hide();
        m_aCancelBtn.Hide();
    }
    else
    {
        if ( m_bProgressChanged )
        {
            m_bProgressChanged = false;
            m_aProgressText.SetText( m_sProgressText );
        }

        if ( m_bStartProgress )
        {
            m_bStartProgress = false;
            m_bHasProgress = true;
            m_aProgressBar.Show();
            m_aProgressText.Show();
            m_aCancelBtn.Enable();
            m_aCancelBtn.Show();
        }

        if ( m_aProgressBar.IsVisible() )
            m_aProgressBar.SetValue( (sal_uInt16) m_nProgress );

        m_aTimeoutTimer.Start();
    }

    return 1;
}


// VCL::Window / Dialog
void UpdateRequiredDialog::Resize()
{
    Size aTotalSize( GetOutputSizePixel() );
    Size aBtnSize( m_aHelpBtn.GetSizePixel() );

    Point aPos( RSC_SP_DLG_INNERBORDER_LEFT,
                aTotalSize.Height() - RSC_SP_DLG_INNERBORDER_BOTTOM - aBtnSize.Height() );

    m_aHelpBtn.SetPosPixel( aPos );

    aPos.X() = aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_RIGHT - m_aCloseBtn.GetSizePixel().Width();
    m_aCloseBtn.SetPosPixel( aPos );

    aPos.X() -= ( RSC_SP_CTRL_X + m_aUpdateBtn.GetSizePixel().Width() );
    m_aUpdateBtn.SetPosPixel( aPos );

    Size aDivSize( aTotalSize.Width(), LINE_SIZE );
    aPos = Point( 0, aPos.Y() - LINE_SIZE - RSC_SP_DLG_INNERBORDER_BOTTOM );
    m_aDivider.SetPosSizePixel( aPos, aDivSize );

    // Calc fixed text size
    aPos = Point( RSC_SP_DLG_INNERBORDER_LEFT, RSC_SP_DLG_INNERBORDER_TOP );
    Size aFTSize = m_aUpdateNeeded.CalcMinimumSize( aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_RIGHT - RSC_SP_DLG_INNERBORDER_LEFT );
    m_aUpdateNeeded.SetPosSizePixel( aPos, aFTSize );

    // Calc list box size
    Size aSize( aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_LEFT - RSC_SP_DLG_INNERBORDER_RIGHT,
                aTotalSize.Height() - 2*aBtnSize.Height() - LINE_SIZE -
                2*RSC_SP_DLG_INNERBORDER_TOP - 3*RSC_SP_DLG_INNERBORDER_BOTTOM - aFTSize.Height() );
    aPos.Y() += aFTSize.Height()+RSC_SP_DLG_INNERBORDER_TOP;

    m_pExtensionBox->SetPosSizePixel( aPos, aSize );

    aPos.X() = aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_RIGHT - aBtnSize.Width();
    aPos.Y() += aSize.Height()+RSC_SP_DLG_INNERBORDER_TOP;
    m_aCancelBtn.SetPosPixel( aPos );

    // Calc progress height
    aFTSize = m_aProgressText.GetSizePixel();
    long nProgressHeight = aFTSize.Height();

    if( IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) )
    {
        ImplControlValue aValue;
        Rectangle aControlRegion( Point( 0, 0 ), m_aProgressBar.GetSizePixel() );
        Rectangle aNativeControlRegion, aNativeContentRegion;
        if( GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion,
                                                 CTRL_STATE_ENABLED, aValue, OUString(),
                                                 aNativeControlRegion, aNativeContentRegion ) )
        {
            nProgressHeight = aNativeControlRegion.GetHeight();
        }
    }

    if ( nProgressHeight < PROGRESS_HEIGHT )
        nProgressHeight = PROGRESS_HEIGHT;

    aPos.X() -= ( RSC_SP_CTRL_GROUP_Y + PROGRESS_WIDTH );
    m_aProgressBar.SetPosSizePixel( Point( aPos.X(), aPos.Y() + ((aBtnSize.Height()-nProgressHeight)/2) ),
                                    Size( PROGRESS_WIDTH, nProgressHeight ) );

    aFTSize.Width() = aPos.X() - 2*RSC_SP_DLG_INNERBORDER_LEFT;
    aPos.X() = RSC_SP_DLG_INNERBORDER_LEFT;
    aPos.Y() += ( aBtnSize.Height() - aFTSize.Height() - 1 ) / 2;
    m_aProgressText.SetPosSizePixel( aPos, aFTSize );
}


// VCL::Dialog
short UpdateRequiredDialog::Execute()
{
    //ToDo
    //I believe m_bHasLockedEntries was used to prevent showing extensions which cannot
    //be disabled because they are in a read only repository. However, disabling extensions
    //is now always possible because the registration data of all repositories
    //are in the user installation.
    //Therfore all extensions could be displayed and all the handling around m_bHasLockedEntries
    //could be removed.
    if ( m_bHasLockedEntries )
    {
        // Set other text, disable update btn, remove not shared entries from list;
        m_aUpdateNeeded.SetText( DialogHelper::getResourceString( RID_STR_NO_ADMIN_PRIVILEGE ) );
        m_aCloseBtn.SetText( DialogHelper::getResourceString( RID_STR_EXIT_BTN ) );
        m_aUpdateBtn.Enable( false );
        m_pExtensionBox->RemoveUnlocked();
        Resize();
    }

    return Dialog::Execute();
}


// VCL::Dialog
bool UpdateRequiredDialog::Close()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    if ( !isBusy() )
    {
        if ( m_bHasLockedEntries )
            EndDialog( -1 );
        else if ( hasActiveEntries() )
            disableAllEntries();
        else
            EndDialog( 0 );
    }

    return false;
}


// Check dependencies of all packages

bool UpdateRequiredDialog::isEnabled( const uno::Reference< deployment::XPackage > &xPackage ) const
{
    bool bRegistered = false;
    try {
        beans::Optional< beans::Ambiguous< sal_Bool > > option( xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
                                                                                        uno::Reference< ucb::XCommandEnvironment >() ) );
        if ( option.IsPresent )
        {
            ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
            if ( reg.IsAmbiguous )
                bRegistered = false;
            else
                bRegistered = reg.Value ? true : false;
        }
        else
            bRegistered = false;
    }
    catch ( const uno::RuntimeException & ) { throw; }
    catch (const uno::Exception & exc) {
        (void) exc;
        OSL_FAIL( OUStringToOString( exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
        bRegistered = false;
    }

    return bRegistered;
}

// Checks the dependencies no matter if the extension is enabled or disabled!
bool UpdateRequiredDialog::checkDependencies( const uno::Reference< deployment::XPackage > &xPackage ) const
{
    bool bDependenciesValid = false;
    try {
        bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
    }
    catch ( const deployment::DeploymentException & ) {}
    return bDependenciesValid;
}


bool UpdateRequiredDialog::hasActiveEntries()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    bool bRet = false;
    long nCount = m_pExtensionBox->GetEntryCount();
    for ( long nIndex = 0; nIndex < nCount; nIndex++ )
    {
        TEntry_Impl pEntry = m_pExtensionBox->GetEntryData( nIndex );

        if ( isEnabled(pEntry->m_xPackage) && !checkDependencies( pEntry->m_xPackage ) )
        {
            bRet = true;
            break;
        }
    }

    return bRet;
}


void UpdateRequiredDialog::disableAllEntries()
{
    ::osl::MutexGuard aGuard( m_aMutex );

    setBusy( true );

    long nCount = m_pExtensionBox->GetEntryCount();
    for ( long nIndex = 0; nIndex < nCount; nIndex++ )
    {
        TEntry_Impl pEntry = m_pExtensionBox->GetEntryData( nIndex );
        enablePackage( pEntry->m_xPackage, false );
    }

    setBusy( false );

    if ( ! hasActiveEntries() )
        m_aCloseBtn.SetText( m_sCloseText );
}


//                             ShowLicenseDialog

ShowLicenseDialog::ShowLicenseDialog( Window * pParent,
                                      const uno::Reference< deployment::XPackage > &xPackage )
    : ModalDialog(pParent, "ShowLicenseDialog", "desktop/ui/showlicensedialog.ui")
{
    get(m_pLicenseText, "textview");
    Size aSize(m_pLicenseText->LogicToPixel(Size(290, 170), MAP_APPFONT));
    m_pLicenseText->set_width_request(aSize.Width());
    m_pLicenseText->set_height_request(aSize.Height());
    m_pLicenseText->SetText(xPackage->getLicenseText());
}


// UpdateRequiredDialogService

UpdateRequiredDialogService::UpdateRequiredDialogService( uno::Sequence< uno::Any > const&,
                                                          uno::Reference< uno::XComponentContext > const& xComponentContext )
    : m_xComponentContext( xComponentContext )
{
}


// XExecutableDialog

void UpdateRequiredDialogService::setTitle( OUString const & ) throw ( uno::RuntimeException, std::exception )
{
}


sal_Int16 UpdateRequiredDialogService::execute() throw ( uno::RuntimeException, std::exception )
{
    ::rtl::Reference< ::dp_gui::TheExtensionManager > xManager( TheExtensionManager::get(
                                                              m_xComponentContext,
                                                              uno::Reference< awt::XWindow >(),
                                                              OUString() ) );
    xManager->createDialog( true );
    sal_Int16 nRet = xManager->execute();

    return nRet;
}


SelectedPackage::~SelectedPackage() {}

} //namespace dp_gui

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