diff options
Diffstat (limited to 'desktop/source/deployment/gui/dp_gui_extlistbox.cxx')
-rwxr-xr-x | desktop/source/deployment/gui/dp_gui_extlistbox.cxx | 1220 |
1 files changed, 1220 insertions, 0 deletions
diff --git a/desktop/source/deployment/gui/dp_gui_extlistbox.cxx b/desktop/source/deployment/gui/dp_gui_extlistbox.cxx new file mode 100755 index 000000000000..5f9de3965199 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_extlistbox.cxx @@ -0,0 +1,1220 @@ +/************************************************************************* + * + * 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_desktop.hxx" + +#include "svtools/controldims.hrc" + +#include "dp_gui.h" +#include "dp_gui_extlistbox.hxx" +#include "dp_gui_theextmgr.hxx" +#include "dp_gui_dialog2.hxx" +#include "dp_dependencies.hxx" + +#include "comphelper/processfactory.hxx" +#include "com/sun/star/i18n/CollatorOptions.hpp" +#include "com/sun/star/deployment/DependencyException.hpp" +#include "com/sun/star/deployment/DeploymentException.hpp" + + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + +#define USER_PACKAGE_MANAGER OUSTR("user") +#define SHARED_PACKAGE_MANAGER OUSTR("shared") +#define BUNDLED_PACKAGE_MANAGER OUSTR("bundled") + +using namespace ::com::sun::star; + +namespace dp_gui { + +//------------------------------------------------------------------------------ +// struct Entry_Impl +//------------------------------------------------------------------------------ +Entry_Impl::Entry_Impl( const uno::Reference< deployment::XPackage > &xPackage, + const PackageState eState, const bool bReadOnly ) : + m_bActive( false ), + m_bLocked( bReadOnly ), + m_bHasOptions( false ), + m_bUser( false ), + m_bShared( false ), + m_bNew( false ), + m_bChecked( false ), + m_bMissingDeps( false ), + m_bHasButtons( false ), + m_bMissingLic( false ), + m_eState( eState ), + m_pPublisher( NULL ), + m_xPackage( xPackage ) +{ + try + { + m_sTitle = xPackage->getDisplayName(); + m_sVersion = xPackage->getVersion(); + m_sDescription = xPackage->getDescription(); + + beans::StringPair aInfo( m_xPackage->getPublisherInfo() ); + m_sPublisher = aInfo.First; + m_sPublisherURL = aInfo.Second; + + // get the icons for the package if there are any + uno::Reference< graphic::XGraphic > xGraphic = xPackage->getIcon( false ); + if ( xGraphic.is() ) + m_aIcon = Image( xGraphic ); + + xGraphic = xPackage->getIcon( true ); + if ( xGraphic.is() ) + m_aIconHC = Image( xGraphic ); + else + m_aIconHC = m_aIcon; + + if ( eState == AMBIGUOUS ) + m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_UNKNOWN_STATUS ); + else if ( eState == NOT_REGISTERED ) + checkDependencies(); + } + catch (deployment::ExtensionRemovedException &) {} + catch (uno::RuntimeException &) {} +} + +//------------------------------------------------------------------------------ +Entry_Impl::~Entry_Impl() +{} + +//------------------------------------------------------------------------------ +StringCompare Entry_Impl::CompareTo( const CollatorWrapper *pCollator, const TEntry_Impl pEntry ) const +{ + StringCompare eCompare = (StringCompare) pCollator->compareString( m_sTitle, pEntry->m_sTitle ); + if ( eCompare == COMPARE_EQUAL ) + { + eCompare = m_sVersion.CompareTo( pEntry->m_sVersion ); + if ( eCompare == COMPARE_EQUAL ) + { + sal_Int32 nCompare = m_xPackage->getRepositoryName().compareTo( pEntry->m_xPackage->getRepositoryName() ); + if ( nCompare < 0 ) + eCompare = COMPARE_LESS; + else if ( nCompare > 0 ) + eCompare = COMPARE_GREATER; + } + } + return eCompare; +} + +//------------------------------------------------------------------------------ +void Entry_Impl::checkDependencies() +{ + try { + m_xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() ); + } + catch ( deployment::DeploymentException &e ) + { + deployment::DependencyException depExc; + if ( e.Cause >>= depExc ) + { + rtl::OUString aMissingDep( DialogHelper::getResourceString( RID_STR_ERROR_MISSING_DEPENDENCIES ) ); + for ( sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength(); ++i ) + { + aMissingDep += OUSTR("\n"); + aMissingDep += dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]); + } + aMissingDep += OUSTR("\n"); + m_sErrorText = aMissingDep; + m_bMissingDeps = true; + } + } +} +//------------------------------------------------------------------------------ +// ExtensionRemovedListener +//------------------------------------------------------------------------------ +void ExtensionRemovedListener::disposing( lang::EventObject const & rEvt ) + throw ( uno::RuntimeException ) +{ + uno::Reference< deployment::XPackage > xPackage( rEvt.Source, uno::UNO_QUERY ); + + if ( xPackage.is() ) + { + m_pParent->removeEntry( xPackage ); + } +} + +//------------------------------------------------------------------------------ +ExtensionRemovedListener::~ExtensionRemovedListener() +{ +} + +//------------------------------------------------------------------------------ +// ExtensionBox_Impl +//------------------------------------------------------------------------------ +ExtensionBox_Impl::ExtensionBox_Impl( Dialog* pParent, TheExtensionManager *pManager ) : + IExtensionListBox( pParent, WB_BORDER | WB_TABSTOP | WB_CHILDDLGCTRL ), + m_bHasScrollBar( false ), + m_bHasActive( false ), + m_bNeedsRecalc( true ), + m_bHasNew( false ), + m_bInCheckMode( false ), + m_bAdjustActive( false ), + m_bInDelete( false ), + m_nActive( 0 ), + m_nTopIndex( 0 ), + m_nActiveHeight( 0 ), + m_nExtraHeight( 2 ), + m_aSharedImage( DialogHelper::getResId( RID_IMG_SHARED ) ), + m_aSharedImageHC( DialogHelper::getResId( RID_IMG_SHARED_HC ) ), + m_aLockedImage( DialogHelper::getResId( RID_IMG_LOCKED ) ), + m_aLockedImageHC( DialogHelper::getResId( RID_IMG_LOCKED_HC ) ), + m_aWarningImage( DialogHelper::getResId( RID_IMG_WARNING ) ), + m_aWarningImageHC( DialogHelper::getResId( RID_IMG_WARNING_HC ) ), + m_aDefaultImage( DialogHelper::getResId( RID_IMG_EXTENSION ) ), + m_aDefaultImageHC( DialogHelper::getResId( RID_IMG_EXTENSION_HC ) ), + m_pScrollBar( NULL ), + m_pManager( pManager ) +{ + SetHelpId( HID_EXTENSION_MANAGER_LISTBOX ); + + m_pScrollBar = new ScrollBar( this, WB_VERT ); + m_pScrollBar->SetScrollHdl( LINK( this, ExtensionBox_Impl, ScrollHdl ) ); + m_pScrollBar->EnableDrag(); + + SetPaintTransparent( true ); + SetPosPixel( Point( RSC_SP_DLG_INNERBORDER_LEFT, RSC_SP_DLG_INNERBORDER_TOP ) ); + long nIconHeight = 2*TOP_OFFSET + SMALL_ICON_SIZE; + long nTitleHeight = 2*TOP_OFFSET + GetTextHeight(); + if ( nIconHeight < nTitleHeight ) + m_nStdHeight = nTitleHeight; + else + m_nStdHeight = nIconHeight; + m_nStdHeight += GetTextHeight() + TOP_OFFSET; + + nIconHeight = ICON_HEIGHT + 2*TOP_OFFSET + 1; + if ( m_nStdHeight < nIconHeight ) + m_nStdHeight = nIconHeight; + + m_nActiveHeight = m_nStdHeight; + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + if( IsControlBackground() ) + SetBackground( GetControlBackground() ); + else + SetBackground( rStyleSettings.GetFieldColor() ); + + m_xRemoveListener = new ExtensionRemovedListener( this ); + + m_pLocale = new lang::Locale( Application::GetSettings().GetLocale() ); + m_pCollator = new CollatorWrapper( ::comphelper::getProcessServiceFactory() ); + m_pCollator->loadDefaultCollator( *m_pLocale, i18n::CollatorOptions::CollatorOptions_IGNORE_CASE ); + + Show(); +} + +//------------------------------------------------------------------------------ +ExtensionBox_Impl::~ExtensionBox_Impl() +{ + if ( ! m_bInDelete ) + DeleteRemoved(); + + m_bInDelete = true; + + typedef std::vector< TEntry_Impl >::iterator ITER; + + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + if ( (*iIndex)->m_pPublisher ) + { + delete (*iIndex)->m_pPublisher; + (*iIndex)->m_pPublisher = NULL; + } + (*iIndex)->m_xPackage->removeEventListener( uno::Reference< lang::XEventListener > ( m_xRemoveListener, uno::UNO_QUERY ) ); + } + + m_vEntries.clear(); + + delete m_pScrollBar; + + m_xRemoveListener.clear(); + + delete m_pLocale; + delete m_pCollator; +} + +//------------------------------------------------------------------------------ +sal_Int32 ExtensionBox_Impl::getItemCount() const +{ + return static_cast< sal_Int32 >( m_vEntries.size() ); +} + +//------------------------------------------------------------------------------ +sal_Int32 ExtensionBox_Impl::getSelIndex() const +{ + if ( m_bHasActive ) + { + OSL_ASSERT( m_nActive >= -1); + return static_cast< sal_Int32 >( m_nActive ); + } + else + return static_cast< sal_Int32 >( EXTENSION_LISTBOX_ENTRY_NOTFOUND ); +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::checkIndex( sal_Int32 nIndex ) const +{ + if ( nIndex < 0 ) + throw lang::IllegalArgumentException( OUSTR("The list index starts with 0"),0, 0 ); + if ( static_cast< sal_uInt32 >( nIndex ) >= m_vEntries.size()) + throw lang::IllegalArgumentException( OUSTR("There is no element at the provided position." + "The position exceeds the number of available list entries"),0, 0 ); +} + +//------------------------------------------------------------------------------ +rtl::OUString ExtensionBox_Impl::getItemName( sal_Int32 nIndex ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + return m_vEntries[ nIndex ]->m_sTitle; +} + +//------------------------------------------------------------------------------ +rtl::OUString ExtensionBox_Impl::getItemVersion( sal_Int32 nIndex ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + return m_vEntries[ nIndex ]->m_sVersion; +} + +//------------------------------------------------------------------------------ +rtl::OUString ExtensionBox_Impl::getItemDescription( sal_Int32 nIndex ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + return m_vEntries[ nIndex ]->m_sDescription; +} + +//------------------------------------------------------------------------------ +rtl::OUString ExtensionBox_Impl::getItemPublisher( sal_Int32 nIndex ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + return m_vEntries[ nIndex ]->m_sPublisher; +} + +//------------------------------------------------------------------------------ +rtl::OUString ExtensionBox_Impl::getItemPublisherLink( sal_Int32 nIndex ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + return m_vEntries[ nIndex ]->m_sPublisherURL; +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::select( sal_Int32 nIndex ) +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + selectEntry( nIndex ); +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::select( const rtl::OUString & sName ) +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + typedef ::std::vector< TEntry_Impl >::const_iterator It; + + for ( It iIter = m_vEntries.begin(); iIter < m_vEntries.end(); iIter++ ) + { + if ( sName.equals( (*iIter)->m_sTitle ) ) + { + long nPos = iIter - m_vEntries.begin(); + selectEntry( nPos ); + break; + } + } +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Title + description +void ExtensionBox_Impl::CalcActiveHeight( const long nPos ) +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + + // get title height + long aTextHeight; + long nIconHeight = 2*TOP_OFFSET + SMALL_ICON_SIZE; + long nTitleHeight = 2*TOP_OFFSET + GetTextHeight(); + if ( nIconHeight < nTitleHeight ) + aTextHeight = nTitleHeight; + else + aTextHeight = nIconHeight; + + // calc description height + Size aSize = GetOutputSizePixel(); + if ( m_bHasScrollBar ) + aSize.Width() -= m_pScrollBar->GetSizePixel().Width(); + + aSize.Width() -= ICON_OFFSET; + aSize.Height() = 10000; + + rtl::OUString aText( m_vEntries[ nPos ]->m_sErrorText ); + if ( aText.getLength() ) + aText += OUSTR("\n"); + aText += m_vEntries[ nPos ]->m_sDescription; + + Rectangle aRect = GetTextRect( Rectangle( Point(), aSize ), aText, + TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK ); + aTextHeight += aRect.GetHeight(); + + if ( aTextHeight < m_nStdHeight ) + aTextHeight = m_nStdHeight; + + if ( m_vEntries[ nPos ]->m_bHasButtons ) + m_nActiveHeight = aTextHeight + m_nExtraHeight; + else + m_nActiveHeight = aTextHeight + 2; +} + +//------------------------------------------------------------------------------ +const Size ExtensionBox_Impl::GetMinOutputSizePixel() const +{ + return Size( 200, 80 ); +} + +//------------------------------------------------------------------------------ +Rectangle ExtensionBox_Impl::GetEntryRect( const long nPos ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + + Size aSize( GetOutputSizePixel() ); + + if ( m_bHasScrollBar ) + aSize.Width() -= m_pScrollBar->GetSizePixel().Width(); + + if ( m_vEntries[ nPos ]->m_bActive ) + aSize.Height() = m_nActiveHeight; + else + aSize.Height() = m_nStdHeight; + + Point aPos( 0, -m_nTopIndex + nPos * m_nStdHeight ); + if ( m_bHasActive && ( nPos < m_nActive ) ) + aPos.Y() += m_nActiveHeight - m_nStdHeight; + + return Rectangle( aPos, aSize ); +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::DeleteRemoved() +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + + m_bInDelete = true; + + if ( ! m_vRemovedEntries.empty() ) + { + typedef std::vector< TEntry_Impl >::iterator ITER; + + for ( ITER iIndex = m_vRemovedEntries.begin(); iIndex < m_vRemovedEntries.end(); ++iIndex ) + { + if ( (*iIndex)->m_pPublisher ) + { + delete (*iIndex)->m_pPublisher; + (*iIndex)->m_pPublisher = NULL; + } + } + + m_vRemovedEntries.clear(); + } + + m_bInDelete = false; +} + +//------------------------------------------------------------------------------ +//This function may be called with nPos < 0 +void ExtensionBox_Impl::selectEntry( const long nPos ) +{ + //ToDo whe should not use the guard at such a big scope here. + //Currently it is used to gard m_vEntries and m_nActive. m_nActive will be + //modified in this function. + //It would be probably best to always use a copy of m_vEntries + //and some other state variables from ExtensionBox_Impl for + //the whole painting operation. See issue i86993 + ::osl::ClearableMutexGuard guard(m_entriesMutex); + + if ( m_bInCheckMode ) + return; + + if ( m_bHasActive ) + { + if ( nPos == m_nActive ) + return; + + m_bHasActive = false; + m_vEntries[ m_nActive ]->m_bActive = false; + } + + if ( ( nPos >= 0 ) && ( nPos < (long) m_vEntries.size() ) ) + { + m_bHasActive = true; + m_nActive = nPos; + m_vEntries[ nPos ]->m_bActive = true; + + if ( IsReallyVisible() ) + { + m_bAdjustActive = true; + } + } + + if ( IsReallyVisible() ) + { + m_bNeedsRecalc = true; + Invalidate(); + } + + guard.clear(); +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::DrawRow( const Rectangle& rRect, const TEntry_Impl pEntry ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if ( pEntry->m_bActive ) + SetTextColor( rStyleSettings.GetHighlightTextColor() ); + else if ( ( pEntry->m_eState != REGISTERED ) && ( pEntry->m_eState != NOT_AVAILABLE ) ) + SetTextColor( rStyleSettings.GetDisableColor() ); + else if ( IsControlForeground() ) + SetTextColor( GetControlForeground() ); + else + SetTextColor( rStyleSettings.GetFieldTextColor() ); + + if ( pEntry->m_bActive ) + { + SetLineColor(); + SetFillColor( rStyleSettings.GetHighlightColor() ); + DrawRect( rRect ); + } + else + { + if( IsControlBackground() ) + SetBackground( GetControlBackground() ); + else + SetBackground( rStyleSettings.GetFieldColor() ); + + SetTextFillColor(); + Erase( rRect ); + } + + // Draw extension icon + Point aPos( rRect.TopLeft() ); + aPos += Point( TOP_OFFSET, TOP_OFFSET ); + Image aImage; + if ( ! pEntry->m_aIcon ) + aImage = isHCMode() ? m_aDefaultImageHC : m_aDefaultImage; + else + aImage = isHCMode() ? pEntry->m_aIconHC : pEntry->m_aIcon; + Size aImageSize = aImage.GetSizePixel(); + if ( ( aImageSize.Width() <= ICON_WIDTH ) && ( aImageSize.Height() <= ICON_HEIGHT ) ) + DrawImage( Point( aPos.X()+((ICON_WIDTH-aImageSize.Width())/2), aPos.Y()+((ICON_HEIGHT-aImageSize.Height())/2) ), aImage ); + else + DrawImage( aPos, Size( ICON_WIDTH, ICON_HEIGHT ), aImage ); + + // Setup fonts + Font aStdFont( GetFont() ); + Font aBoldFont( aStdFont ); + aBoldFont.SetWeight( WEIGHT_BOLD ); + SetFont( aBoldFont ); + long aTextHeight = GetTextHeight(); + + // Init publisher link here + if ( !pEntry->m_pPublisher && pEntry->m_sPublisher.Len() ) + { + pEntry->m_pPublisher = new svt::FixedHyperlink( this ); + pEntry->m_pPublisher->SetBackground(); + pEntry->m_pPublisher->SetPaintTransparent( true ); + pEntry->m_pPublisher->SetURL( pEntry->m_sPublisherURL ); + pEntry->m_pPublisher->SetDescription( pEntry->m_sPublisher ); + Size aSize = FixedText::CalcMinimumTextSize( pEntry->m_pPublisher ); + pEntry->m_pPublisher->SetSizePixel( aSize ); + + if ( m_aClickHdl.IsSet() ) + pEntry->m_pPublisher->SetClickHdl( m_aClickHdl ); + } + + // Get max title width + long nMaxTitleWidth = rRect.GetWidth() - ICON_OFFSET; + nMaxTitleWidth -= ( 2 * SMALL_ICON_SIZE ) + ( 4 * SPACE_BETWEEN ); + if ( pEntry->m_pPublisher ) + { + nMaxTitleWidth -= pEntry->m_pPublisher->GetSizePixel().Width() + (2*SPACE_BETWEEN); + } + + long aVersionWidth = GetTextWidth( pEntry->m_sVersion ); + long aTitleWidth = GetTextWidth( pEntry->m_sTitle ) + (aTextHeight / 3); + + aPos = rRect.TopLeft() + Point( ICON_OFFSET, TOP_OFFSET ); + + if ( aTitleWidth > nMaxTitleWidth - aVersionWidth ) + { + aTitleWidth = nMaxTitleWidth - aVersionWidth - (aTextHeight / 3); + String aShortTitle = GetEllipsisString( pEntry->m_sTitle, aTitleWidth ); + DrawText( aPos, aShortTitle ); + aTitleWidth += (aTextHeight / 3); + } + else + DrawText( aPos, pEntry->m_sTitle ); + + SetFont( aStdFont ); + DrawText( Point( aPos.X() + aTitleWidth, aPos.Y() ), pEntry->m_sVersion ); + + long nIconHeight = TOP_OFFSET + SMALL_ICON_SIZE; + long nTitleHeight = TOP_OFFSET + GetTextHeight(); + if ( nIconHeight < nTitleHeight ) + aTextHeight = nTitleHeight; + else + aTextHeight = nIconHeight; + + // draw description + String sDescription; + if ( pEntry->m_sErrorText.Len() ) + { + if ( pEntry->m_bActive ) + sDescription = pEntry->m_sErrorText + OUSTR("\n") + pEntry->m_sDescription; + else + sDescription = pEntry->m_sErrorText; + } + else + sDescription = pEntry->m_sDescription; + + aPos.Y() += aTextHeight; + if ( pEntry->m_bActive ) + { + long nExtraHeight = 0; + + if ( pEntry->m_bHasButtons ) + nExtraHeight = m_nExtraHeight; + + DrawText( Rectangle( aPos.X(), aPos.Y(), rRect.Right(), rRect.Bottom() - nExtraHeight ), + sDescription, TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK ); + } + else + { + const long nWidth = GetTextWidth( sDescription ); + if ( nWidth > rRect.GetWidth() - aPos.X() ) + sDescription = GetEllipsisString( sDescription, rRect.GetWidth() - aPos.X() ); + DrawText( aPos, sDescription ); + } + + // Draw publisher link + if ( pEntry->m_pPublisher ) + { + pEntry->m_pPublisher->Show(); + aPos = rRect.TopLeft() + Point( ICON_OFFSET + nMaxTitleWidth + (2*SPACE_BETWEEN), TOP_OFFSET ); + pEntry->m_pPublisher->SetPosPixel( aPos ); + } + + // Draw status icons + if ( !pEntry->m_bUser ) + { + aPos = rRect.TopRight() + Point( -(RIGHT_ICON_OFFSET + SMALL_ICON_SIZE), TOP_OFFSET ); + if ( pEntry->m_bLocked ) + DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), isHCMode() ? m_aLockedImageHC : m_aLockedImage ); + else + DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), isHCMode() ? m_aSharedImageHC : m_aSharedImage ); + } + if ( ( pEntry->m_eState == AMBIGUOUS ) || pEntry->m_bMissingDeps || pEntry->m_bMissingLic ) + { + aPos = rRect.TopRight() + Point( -(RIGHT_ICON_OFFSET + SPACE_BETWEEN + 2*SMALL_ICON_SIZE), TOP_OFFSET ); + DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), isHCMode() ? m_aWarningImageHC : m_aWarningImage ); + } + + SetLineColor( Color( COL_LIGHTGRAY ) ); + DrawLine( rRect.BottomLeft(), rRect.BottomRight() ); +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::RecalcAll() +{ + if ( m_bHasActive ) + CalcActiveHeight( m_nActive ); + + SetupScrollBar(); + + if ( m_bHasActive ) + { + Rectangle aEntryRect = GetEntryRect( m_nActive ); + + if ( m_bAdjustActive ) + { + m_bAdjustActive = false; + + // If the top of the selected entry isn't visible, make it visible + if ( aEntryRect.Top() < 0 ) + { + m_nTopIndex += aEntryRect.Top(); + aEntryRect.Move( 0, -aEntryRect.Top() ); + } + + // If the bottom of the selected entry isn't visible, make it visible even if now the top + // isn't visible any longer ( the buttons are more important ) + Size aOutputSize = GetOutputSizePixel(); + if ( aEntryRect.Bottom() > aOutputSize.Height() ) + { + m_nTopIndex += ( aEntryRect.Bottom() - aOutputSize.Height() ); + aEntryRect.Move( 0, -( aEntryRect.Bottom() - aOutputSize.Height() ) ); + } + + // If there is unused space below the last entry but all entries don't fit into the box, + // move the content down to use the whole space + const long nTotalHeight = GetTotalHeight(); + if ( m_bHasScrollBar && ( aOutputSize.Height() + m_nTopIndex > nTotalHeight ) ) + { + long nOffset = m_nTopIndex; + m_nTopIndex = nTotalHeight - aOutputSize.Height(); + nOffset -= m_nTopIndex; + aEntryRect.Move( 0, nOffset ); + } + + if ( m_bHasScrollBar ) + m_pScrollBar->SetThumbPos( m_nTopIndex ); + } + } + + m_bNeedsRecalc = false; +} + +// ----------------------------------------------------------------------- +bool ExtensionBox_Impl::HandleTabKey( bool ) +{ + return false; +} + +// ----------------------------------------------------------------------- +bool ExtensionBox_Impl::HandleCursorKey( USHORT nKeyCode ) +{ + if ( m_vEntries.empty() ) + return true; + + long nSelect = 0; + + if ( m_bHasActive ) + { + long nPageSize = GetOutputSizePixel().Height() / m_nStdHeight; + if ( nPageSize < 2 ) + nPageSize = 2; + + if ( ( nKeyCode == KEY_DOWN ) || ( nKeyCode == KEY_RIGHT ) ) + nSelect = m_nActive + 1; + else if ( ( nKeyCode == KEY_UP ) || ( nKeyCode == KEY_LEFT ) ) + nSelect = m_nActive - 1; + else if ( nKeyCode == KEY_HOME ) + nSelect = 0; + else if ( nKeyCode == KEY_END ) + nSelect = m_vEntries.size() - 1; + else if ( nKeyCode == KEY_PAGEUP ) + nSelect = m_nActive - nPageSize + 1; + else if ( nKeyCode == KEY_PAGEDOWN ) + nSelect = m_nActive + nPageSize - 1; + } + else // when there is no selected entry, we will select the first or the last. + { + if ( ( nKeyCode == KEY_DOWN ) || ( nKeyCode == KEY_PAGEDOWN ) || ( nKeyCode == KEY_HOME ) ) + nSelect = 0; + else if ( ( nKeyCode == KEY_UP ) || ( nKeyCode == KEY_PAGEUP ) || ( nKeyCode == KEY_END ) ) + nSelect = m_vEntries.size() - 1; + } + + if ( nSelect < 0 ) + nSelect = 0; + if ( nSelect >= (long) m_vEntries.size() ) + nSelect = m_vEntries.size() - 1; + + selectEntry( nSelect ); + + return true; +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::Paint( const Rectangle &/*rPaintRect*/ ) +{ + if ( !m_bInDelete ) + DeleteRemoved(); + + if ( m_bNeedsRecalc ) + RecalcAll(); + + Point aStart( 0, -m_nTopIndex ); + Size aSize( GetOutputSizePixel() ); + + if ( m_bHasScrollBar ) + aSize.Width() -= m_pScrollBar->GetSizePixel().Width(); + + const ::osl::MutexGuard aGuard( m_entriesMutex ); + + typedef std::vector< TEntry_Impl >::iterator ITER; + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + aSize.Height() = (*iIndex)->m_bActive ? m_nActiveHeight : m_nStdHeight; + Rectangle aEntryRect( aStart, aSize ); + DrawRow( aEntryRect, *iIndex ); + aStart.Y() += aSize.Height(); + } +} + +// ----------------------------------------------------------------------- +long ExtensionBox_Impl::GetTotalHeight() const +{ + long nHeight = m_vEntries.size() * m_nStdHeight; + + if ( m_bHasActive ) + { + nHeight += m_nActiveHeight - m_nStdHeight; + } + + return nHeight; +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::SetupScrollBar() +{ + const Size aSize = GetOutputSizePixel(); + const long nScrBarSize = GetSettings().GetStyleSettings().GetScrollBarSize(); + const long nTotalHeight = GetTotalHeight(); + const bool bNeedsScrollBar = ( nTotalHeight > aSize.Height() ); + + if ( bNeedsScrollBar ) + { + if ( m_nTopIndex + aSize.Height() > nTotalHeight ) + m_nTopIndex = nTotalHeight - aSize.Height(); + + m_pScrollBar->SetPosSizePixel( Point( aSize.Width() - nScrBarSize, 0 ), + Size( nScrBarSize, aSize.Height() ) ); + m_pScrollBar->SetRangeMax( nTotalHeight ); + m_pScrollBar->SetVisibleSize( aSize.Height() ); + m_pScrollBar->SetPageSize( ( aSize.Height() * 4 ) / 5 ); + m_pScrollBar->SetLineSize( m_nStdHeight ); + m_pScrollBar->SetThumbPos( m_nTopIndex ); + + if ( !m_bHasScrollBar ) + m_pScrollBar->Show(); + } + else if ( m_bHasScrollBar ) + { + m_pScrollBar->Hide(); + m_nTopIndex = 0; + } + + m_bHasScrollBar = bNeedsScrollBar; +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::Resize() +{ + RecalcAll(); +} + +//------------------------------------------------------------------------------ +long ExtensionBox_Impl::PointToPos( const Point& rPos ) +{ + long nPos = ( rPos.Y() + m_nTopIndex ) / m_nStdHeight; + + if ( m_bHasActive && ( nPos > m_nActive ) ) + { + if ( rPos.Y() + m_nTopIndex <= m_nActive*m_nStdHeight + m_nActiveHeight ) + nPos = m_nActive; + else + nPos = ( rPos.Y() + m_nTopIndex - (m_nActiveHeight - m_nStdHeight) ) / m_nStdHeight; + } + + return nPos; +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::MouseButtonDown( const MouseEvent& rMEvt ) +{ + long nPos = PointToPos( rMEvt.GetPosPixel() ); + + if ( rMEvt.IsLeft() ) + { + if ( rMEvt.IsMod1() && m_bHasActive ) + selectEntry( m_vEntries.size() ); // Selecting an not existing entry will deselect the current one + else + selectEntry( nPos ); + } +} + +//------------------------------------------------------------------------------ +long ExtensionBox_Impl::Notify( NotifyEvent& rNEvt ) +{ + if ( !m_bInDelete ) + DeleteRemoved(); + + bool bHandled = false; + + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyEvent* pKEvt = rNEvt.GetKeyEvent(); + KeyCode aKeyCode = pKEvt->GetKeyCode(); + USHORT nKeyCode = aKeyCode.GetCode(); + + if ( nKeyCode == KEY_TAB ) + bHandled = HandleTabKey( aKeyCode.IsShift() ); + else if ( aKeyCode.GetGroup() == KEYGROUP_CURSOR ) + bHandled = HandleCursorKey( nKeyCode ); + } + + if ( rNEvt.GetType() == EVENT_COMMAND ) + { + if ( m_bHasScrollBar && + ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) ) + { + const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData(); + if ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) + { + long nThumbPos = m_pScrollBar->GetThumbPos(); + if ( pData->GetDelta() < 0 ) + m_pScrollBar->DoScroll( nThumbPos + m_nStdHeight ); + else + m_pScrollBar->DoScroll( nThumbPos - m_nStdHeight ); + bHandled = true; + } + } + } + + if ( !bHandled ) + return Control::Notify( rNEvt ); + else + return true; +} + +//------------------------------------------------------------------------------ +bool ExtensionBox_Impl::FindEntryPos( const TEntry_Impl pEntry, const long nStart, + const long nEnd, long &nPos ) +{ + nPos = nStart; + if ( nStart > nEnd ) + return false; + + StringCompare eCompare; + + if ( nStart == nEnd ) + { + eCompare = pEntry->CompareTo( m_pCollator, m_vEntries[ nStart ] ); + if ( eCompare == COMPARE_LESS ) + return false; + else if ( eCompare == COMPARE_EQUAL ) + { + //Workaround. See i86963. + if (pEntry->m_xPackage != m_vEntries[nStart]->m_xPackage) + return false; + + if ( m_bInCheckMode ) + m_vEntries[ nStart ]->m_bChecked = true; + return true; + } + else + { + nPos = nStart + 1; + return false; + } + } + + const long nMid = nStart + ( ( nEnd - nStart ) / 2 ); + eCompare = pEntry->CompareTo( m_pCollator, m_vEntries[ nMid ] ); + + if ( eCompare == COMPARE_LESS ) + return FindEntryPos( pEntry, nStart, nMid-1, nPos ); + else if ( eCompare == COMPARE_GREATER ) + return FindEntryPos( pEntry, nMid+1, nEnd, nPos ); + else + { + //Workaround.See i86963. + if (pEntry->m_xPackage != m_vEntries[nMid]->m_xPackage) + return false; + + if ( m_bInCheckMode ) + m_vEntries[ nMid ]->m_bChecked = true; + nPos = nMid; + return true; + } +} + +//------------------------------------------------------------------------------ +long ExtensionBox_Impl::addEntry( const uno::Reference< deployment::XPackage > &xPackage, + bool bLicenseMissing ) +{ + long nPos = 0; + PackageState eState = m_pManager->getPackageState( xPackage ); + bool bLocked = m_pManager->isReadOnly( xPackage ); + + TEntry_Impl pEntry( new Entry_Impl( xPackage, eState, bLocked ) ); + + // Don't add empty entries + if ( ! pEntry->m_sTitle.Len() ) + return 0; + + xPackage->addEventListener( uno::Reference< lang::XEventListener > ( m_xRemoveListener, uno::UNO_QUERY ) ); + + ::osl::ClearableMutexGuard guard(m_entriesMutex); + if ( m_vEntries.empty() ) + { + m_vEntries.push_back( pEntry ); + } + else + { + if ( !FindEntryPos( pEntry, 0, m_vEntries.size()-1, nPos ) ) + { + m_vEntries.insert( m_vEntries.begin()+nPos, pEntry ); + } + else if ( !m_bInCheckMode ) + { + OSL_ENSURE( 0, "ExtensionBox_Impl::addEntry(): Will not add duplicate entries" ); + } + } + + pEntry->m_bHasOptions = m_pManager->supportsOptions( xPackage ); + pEntry->m_bUser = xPackage->getRepositoryName().equals( USER_PACKAGE_MANAGER ); + pEntry->m_bShared = xPackage->getRepositoryName().equals( SHARED_PACKAGE_MANAGER ); + pEntry->m_bNew = m_bInCheckMode; + pEntry->m_bMissingLic = bLicenseMissing; + + if ( bLicenseMissing ) + pEntry->m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_MISSING_LICENSE ); + + //access to m_nActive must be guarded + if ( !m_bInCheckMode && m_bHasActive && ( m_nActive >= nPos ) ) + m_nActive += 1; + + guard.clear(); + + if ( IsReallyVisible() ) + Invalidate(); + + m_bNeedsRecalc = true; + + return nPos; +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::updateEntry( const uno::Reference< deployment::XPackage > &xPackage ) +{ + typedef std::vector< TEntry_Impl >::iterator ITER; + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + if ( (*iIndex)->m_xPackage == xPackage ) + { + PackageState eState = m_pManager->getPackageState( xPackage ); + (*iIndex)->m_bHasOptions = m_pManager->supportsOptions( xPackage ); + (*iIndex)->m_eState = eState; + (*iIndex)->m_sTitle = xPackage->getDisplayName(); + (*iIndex)->m_sVersion = xPackage->getVersion(); + (*iIndex)->m_sDescription = xPackage->getDescription(); + + if ( eState == REGISTERED ) + (*iIndex)->m_bMissingLic = false; + + if ( eState == AMBIGUOUS ) + (*iIndex)->m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_UNKNOWN_STATUS ); + else if ( ! (*iIndex)->m_bMissingLic ) + (*iIndex)->m_sErrorText = String(); + + if ( IsReallyVisible() ) + Invalidate(); + break; + } + } +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::removeEntry( const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( ! m_bInDelete ) + { + ::osl::ClearableMutexGuard aGuard( m_entriesMutex ); + + typedef std::vector< TEntry_Impl >::iterator ITER; + + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + if ( (*iIndex)->m_xPackage == xPackage ) + { + long nPos = iIndex - m_vEntries.begin(); + + // Entries mustn't removed here, because they contain a hyperlink control + // which can only be deleted when the thread has the solar mutex. Therefor + // the entry will be moved into the m_vRemovedEntries list which will be + // cleared on the next paint event + m_vRemovedEntries.push_back( *iIndex ); + m_vEntries.erase( iIndex ); + + m_bNeedsRecalc = true; + + if ( IsReallyVisible() ) + Invalidate(); + + if ( m_bHasActive ) + { + if ( nPos < m_nActive ) + m_nActive -= 1; + else if ( ( nPos == m_nActive ) && + ( nPos == (long) m_vEntries.size() ) ) + m_nActive -= 1; + + m_bHasActive = false; + //clear before calling out of this method + aGuard.clear(); + selectEntry( m_nActive ); + } + break; + } + } + } +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::RemoveUnlocked() +{ + bool bAllRemoved = false; + + while ( ! bAllRemoved ) + { + bAllRemoved = true; + + ::osl::ClearableMutexGuard aGuard( m_entriesMutex ); + + typedef std::vector< TEntry_Impl >::iterator ITER; + + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + if ( !(*iIndex)->m_bLocked ) + { + bAllRemoved = false; + uno::Reference< deployment::XPackage> xPackage = (*iIndex)->m_xPackage; + aGuard.clear(); + removeEntry( xPackage ); + break; + } + } + } +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::prepareChecking() +{ + m_bInCheckMode = true; + typedef std::vector< TEntry_Impl >::iterator ITER; + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + (*iIndex)->m_bChecked = false; + (*iIndex)->m_bNew = false; + } +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::checkEntries() +{ + long nNewPos = -1; + long nPos = 0; + bool bNeedsUpdate = false; + + ::osl::ClearableMutexGuard guard(m_entriesMutex); + typedef std::vector< TEntry_Impl >::iterator ITER; + ITER iIndex = m_vEntries.begin(); + while ( iIndex < m_vEntries.end() ) + { + if ( (*iIndex)->m_bChecked == false ) + { + (*iIndex)->m_bChecked = true; + bNeedsUpdate = true; + nPos = iIndex-m_vEntries.begin(); + if ( (*iIndex)->m_bNew ) + { // add entry to list and correct active pos + if ( nNewPos == - 1) + nNewPos = nPos; + if ( nPos <= m_nActive ) + m_nActive += 1; + iIndex++; + } + else + { // remove entry from list + if ( nPos < m_nActive ) + m_nActive -= 1; + else if ( ( nPos == m_nActive ) && ( nPos == (long) m_vEntries.size() - 1 ) ) + m_nActive -= 1; + m_vRemovedEntries.push_back( *iIndex ); + m_vEntries.erase( iIndex ); + iIndex = m_vEntries.begin() + nPos; + } + } + else + iIndex++; + } + guard.clear(); + + m_bInCheckMode = false; + + if ( nNewPos != - 1) + selectEntry( nNewPos ); + + if ( bNeedsUpdate ) + { + m_bNeedsRecalc = true; + if ( IsReallyVisible() ) + Invalidate(); + } +} +//------------------------------------------------------------------------------ +bool ExtensionBox_Impl::isHCMode() +{ + return (bool)GetSettings().GetStyleSettings().GetHighContrastMode(); +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::SetScrollHdl( const Link& rLink ) +{ + if ( m_pScrollBar ) + m_pScrollBar->SetScrollHdl( rLink ); +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::DoScroll( long nDelta ) +{ + m_nTopIndex += nDelta; + Point aNewSBPt( m_pScrollBar->GetPosPixel() ); + + Rectangle aScrRect( Point(), GetOutputSizePixel() ); + aScrRect.Right() -= m_pScrollBar->GetSizePixel().Width(); + Scroll( 0, -nDelta, aScrRect ); + + m_pScrollBar->SetPosPixel( aNewSBPt ); +} + +// ----------------------------------------------------------------------- +IMPL_LINK( ExtensionBox_Impl, ScrollHdl, ScrollBar*, pScrBar ) +{ + DoScroll( pScrBar->GetDelta() ); + + return 1; +} + +} //namespace dp_gui |