blob: 62618211aff054db51c8b7447141903db1d9af77 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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"
#include "cppuhelper/weakref.hxx"
#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 {
namespace {
struct FindWeakRef
{
const uno::Reference<deployment::XPackage> m_extension;
FindWeakRef( uno::Reference<deployment::XPackage> const & ext): m_extension(ext) {}
bool operator () (uno::WeakReference< deployment::XPackage > const & ref);
};
bool FindWeakRef::operator () (uno::WeakReference< deployment::XPackage > const & ref)
{
const uno::Reference<deployment::XPackage> ext(ref);
if (ext == m_extension)
return true;
return false;
}
} // end namespace
//------------------------------------------------------------------------------
// 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();
m_sLicenseText = xPackage->getLicenseText();
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( sal_uInt16 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();
sal_uInt16 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;
}
}
void ExtensionBox_Impl::cleanVecListenerAdded()
{
typedef ::std::vector<uno::WeakReference<deployment::XPackage> >::iterator IT;
IT i = m_vListenerAdded.begin();
while( i != m_vListenerAdded.end())
{
const uno::Reference<deployment::XPackage> hardRef(*i);
if (!hardRef.is())
i = m_vListenerAdded.erase(i);
else
++i;
}
}
void ExtensionBox_Impl::addEventListenerOnce(
uno::Reference<deployment::XPackage > const & extension)
{
//make sure to only add the listener once
cleanVecListenerAdded();
if ( ::std::find_if(m_vListenerAdded.begin(), m_vListenerAdded.end(),
FindWeakRef(extension))
== m_vListenerAdded.end())
{
extension->addEventListener( uno::Reference< lang::XEventListener > (
m_xRemoveListener, uno::UNO_QUERY ) );
m_vListenerAdded.push_back(extension);
}
}
//------------------------------------------------------------------------------
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;
::osl::ClearableMutexGuard guard(m_entriesMutex);
if ( m_vEntries.empty() )
{
addEventListenerOnce(xPackage);
m_vEntries.push_back( pEntry );
}
else
{
if ( !FindEntryPos( pEntry, 0, m_vEntries.size()-1, nPos ) )
{
addEventListenerOnce(xPackage);
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;
}
}
}
//------------------------------------------------------------------------------
//This function is also called as a result of removing an extension.
//see PackageManagerImpl::removePackage
//The gui is a registered as listener on the package. Removing it will cause the
//listeners to be notified an then this function is called. At this moment xPackage
//is in the disposing state and all calls on it may result in a DisposedException.
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 );
(*iIndex)->m_xPackage->removeEventListener(
uno::Reference<lang::XEventListener>(m_xRemoveListener, uno::UNO_QUERY));
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