1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_desktop.hxx"
30 
31 #include "svtools/controldims.hrc"
32 
33 #include "dp_gui.h"
34 #include "dp_gui_extlistbox.hxx"
35 #include "dp_gui_theextmgr.hxx"
36 #include "dp_gui_dialog2.hxx"
37 #include "dp_dependencies.hxx"
38 
39 #include "comphelper/processfactory.hxx"
40 #include "com/sun/star/i18n/CollatorOptions.hpp"
41 #include "com/sun/star/deployment/DependencyException.hpp"
42 #include "com/sun/star/deployment/DeploymentException.hpp"
43 #include "cppuhelper/weakref.hxx"
44 
45 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
46 
47 #define USER_PACKAGE_MANAGER    OUSTR("user")
48 #define SHARED_PACKAGE_MANAGER  OUSTR("shared")
49 #define BUNDLED_PACKAGE_MANAGER OUSTR("bundled")
50 
51 using namespace ::com::sun::star;
52 
53 namespace dp_gui {
54 
55 namespace {
56 
57 struct FindWeakRef
58 {
59     const uno::Reference<deployment::XPackage> m_extension;
60 
61     FindWeakRef( uno::Reference<deployment::XPackage> const & ext): m_extension(ext) {}
62     bool operator () (uno::WeakReference< deployment::XPackage >  const & ref);
63 };
64 
65 bool FindWeakRef::operator () (uno::WeakReference< deployment::XPackage >  const & ref)
66 {
67     const uno::Reference<deployment::XPackage> ext(ref);
68     if (ext == m_extension)
69         return true;
70     return false;
71 }
72 
73 } // end namespace
74 //------------------------------------------------------------------------------
75 //                          struct Entry_Impl
76 //------------------------------------------------------------------------------
77 Entry_Impl::Entry_Impl( const uno::Reference< deployment::XPackage > &xPackage,
78                         const PackageState eState, const bool bReadOnly ) :
79     m_bActive( false ),
80     m_bLocked( bReadOnly ),
81     m_bHasOptions( false ),
82     m_bUser( false ),
83     m_bShared( false ),
84     m_bNew( false ),
85     m_bChecked( false ),
86     m_bMissingDeps( false ),
87     m_bHasButtons( false ),
88     m_bMissingLic( false ),
89     m_eState( eState ),
90     m_pPublisher( NULL ),
91     m_xPackage( xPackage )
92 {
93     try
94     {
95         m_sTitle = xPackage->getDisplayName();
96         m_sVersion = xPackage->getVersion();
97         m_sDescription = xPackage->getDescription();
98     m_sLicenseText = xPackage->getLicenseText();
99 
100         beans::StringPair aInfo( m_xPackage->getPublisherInfo() );
101         m_sPublisher = aInfo.First;
102         m_sPublisherURL = aInfo.Second;
103 
104         // get the icons for the package if there are any
105         uno::Reference< graphic::XGraphic > xGraphic = xPackage->getIcon( false );
106         if ( xGraphic.is() )
107             m_aIcon = Image( xGraphic );
108 
109         xGraphic = xPackage->getIcon( true );
110         if ( xGraphic.is() )
111             m_aIconHC = Image( xGraphic );
112         else
113             m_aIconHC = m_aIcon;
114 
115         if ( eState == AMBIGUOUS )
116             m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_UNKNOWN_STATUS );
117         else if ( eState == NOT_REGISTERED )
118             checkDependencies();
119     }
120     catch (deployment::ExtensionRemovedException &) {}
121     catch (uno::RuntimeException &) {}
122 }
123 
124 //------------------------------------------------------------------------------
125 Entry_Impl::~Entry_Impl()
126 {}
127 
128 //------------------------------------------------------------------------------
129 StringCompare Entry_Impl::CompareTo( const CollatorWrapper *pCollator, const TEntry_Impl pEntry ) const
130 {
131     StringCompare eCompare = (StringCompare) pCollator->compareString( m_sTitle, pEntry->m_sTitle );
132     if ( eCompare == COMPARE_EQUAL )
133     {
134         eCompare = m_sVersion.CompareTo( pEntry->m_sVersion );
135         if ( eCompare == COMPARE_EQUAL )
136         {
137             sal_Int32 nCompare = m_xPackage->getRepositoryName().compareTo( pEntry->m_xPackage->getRepositoryName() );
138             if ( nCompare < 0 )
139                 eCompare = COMPARE_LESS;
140             else if ( nCompare > 0 )
141                 eCompare = COMPARE_GREATER;
142         }
143     }
144     return eCompare;
145 }
146 
147 //------------------------------------------------------------------------------
148 void Entry_Impl::checkDependencies()
149 {
150     try {
151         m_xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
152     }
153     catch ( deployment::DeploymentException &e )
154     {
155         deployment::DependencyException depExc;
156         if ( e.Cause >>= depExc )
157         {
158             rtl::OUString aMissingDep( DialogHelper::getResourceString( RID_STR_ERROR_MISSING_DEPENDENCIES ) );
159             for ( sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength(); ++i )
160             {
161                 aMissingDep += OUSTR("\n");
162                 aMissingDep += dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]);
163             }
164             aMissingDep += OUSTR("\n");
165             m_sErrorText = aMissingDep;
166             m_bMissingDeps = true;
167         }
168     }
169 }
170 //------------------------------------------------------------------------------
171 // ExtensionRemovedListener
172 //------------------------------------------------------------------------------
173 void ExtensionRemovedListener::disposing( lang::EventObject const & rEvt )
174     throw ( uno::RuntimeException )
175 {
176     uno::Reference< deployment::XPackage > xPackage( rEvt.Source, uno::UNO_QUERY );
177 
178     if ( xPackage.is() )
179     {
180         m_pParent->removeEntry( xPackage );
181     }
182 }
183 
184 //------------------------------------------------------------------------------
185 ExtensionRemovedListener::~ExtensionRemovedListener()
186 {
187 }
188 
189 //------------------------------------------------------------------------------
190 // ExtensionBox_Impl
191 //------------------------------------------------------------------------------
192 ExtensionBox_Impl::ExtensionBox_Impl( Dialog* pParent, TheExtensionManager *pManager ) :
193     IExtensionListBox( pParent, WB_BORDER | WB_TABSTOP | WB_CHILDDLGCTRL ),
194     m_bHasScrollBar( false ),
195     m_bHasActive( false ),
196     m_bNeedsRecalc( true ),
197     m_bHasNew( false ),
198     m_bInCheckMode( false ),
199     m_bAdjustActive( false ),
200     m_bInDelete( false ),
201     m_nActive( 0 ),
202     m_nTopIndex( 0 ),
203     m_nActiveHeight( 0 ),
204     m_nExtraHeight( 2 ),
205     m_aSharedImage( DialogHelper::getResId( RID_IMG_SHARED ) ),
206     m_aSharedImageHC( DialogHelper::getResId( RID_IMG_SHARED_HC ) ),
207     m_aLockedImage( DialogHelper::getResId( RID_IMG_LOCKED ) ),
208     m_aLockedImageHC( DialogHelper::getResId( RID_IMG_LOCKED_HC ) ),
209     m_aWarningImage( DialogHelper::getResId( RID_IMG_WARNING ) ),
210     m_aWarningImageHC( DialogHelper::getResId( RID_IMG_WARNING_HC ) ),
211     m_aDefaultImage( DialogHelper::getResId( RID_IMG_EXTENSION ) ),
212     m_aDefaultImageHC( DialogHelper::getResId( RID_IMG_EXTENSION_HC ) ),
213     m_pScrollBar( NULL ),
214     m_pManager( pManager )
215 {
216     SetHelpId( HID_EXTENSION_MANAGER_LISTBOX );
217 
218     m_pScrollBar = new ScrollBar( this, WB_VERT );
219     m_pScrollBar->SetScrollHdl( LINK( this, ExtensionBox_Impl, ScrollHdl ) );
220     m_pScrollBar->EnableDrag();
221 
222     SetPaintTransparent( true );
223     SetPosPixel( Point( RSC_SP_DLG_INNERBORDER_LEFT, RSC_SP_DLG_INNERBORDER_TOP ) );
224     long nIconHeight = 2*TOP_OFFSET + SMALL_ICON_SIZE;
225     long nTitleHeight = 2*TOP_OFFSET + GetTextHeight();
226     if ( nIconHeight < nTitleHeight )
227         m_nStdHeight = nTitleHeight;
228     else
229         m_nStdHeight = nIconHeight;
230     m_nStdHeight += GetTextHeight() + TOP_OFFSET;
231 
232     nIconHeight = ICON_HEIGHT + 2*TOP_OFFSET + 1;
233     if ( m_nStdHeight < nIconHeight )
234         m_nStdHeight = nIconHeight;
235 
236     m_nActiveHeight = m_nStdHeight;
237 
238     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
239     if( IsControlBackground() )
240         SetBackground( GetControlBackground() );
241     else
242         SetBackground( rStyleSettings.GetFieldColor() );
243 
244     m_xRemoveListener = new ExtensionRemovedListener( this );
245 
246 	m_pLocale = new lang::Locale( Application::GetSettings().GetLocale() );
247 	m_pCollator = new CollatorWrapper( ::comphelper::getProcessServiceFactory() );
248 	m_pCollator->loadDefaultCollator( *m_pLocale, i18n::CollatorOptions::CollatorOptions_IGNORE_CASE );
249 
250     Show();
251 }
252 
253 //------------------------------------------------------------------------------
254 ExtensionBox_Impl::~ExtensionBox_Impl()
255 {
256     if ( ! m_bInDelete )
257         DeleteRemoved();
258 
259     m_bInDelete = true;
260 
261     typedef std::vector< TEntry_Impl >::iterator ITER;
262 
263     for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
264     {
265         if ( (*iIndex)->m_pPublisher )
266         {
267             delete (*iIndex)->m_pPublisher;
268             (*iIndex)->m_pPublisher = NULL;
269         }
270         (*iIndex)->m_xPackage->removeEventListener( uno::Reference< lang::XEventListener > ( m_xRemoveListener, uno::UNO_QUERY ) );
271     }
272 
273     m_vEntries.clear();
274 
275     delete m_pScrollBar;
276 
277     m_xRemoveListener.clear();
278 
279     delete m_pLocale;
280     delete m_pCollator;
281 }
282 
283 //------------------------------------------------------------------------------
284 sal_Int32 ExtensionBox_Impl::getItemCount() const
285 {
286     return static_cast< sal_Int32 >( m_vEntries.size() );
287 }
288 
289 //------------------------------------------------------------------------------
290 sal_Int32 ExtensionBox_Impl::getSelIndex() const
291 {
292     if ( m_bHasActive )
293     {
294         OSL_ASSERT( m_nActive >= -1);
295         return static_cast< sal_Int32 >( m_nActive );
296     }
297     else
298         return static_cast< sal_Int32 >( EXTENSION_LISTBOX_ENTRY_NOTFOUND );
299 }
300 
301 //------------------------------------------------------------------------------
302 void ExtensionBox_Impl::checkIndex( sal_Int32 nIndex ) const
303 {
304     if ( nIndex < 0 )
305         throw lang::IllegalArgumentException( OUSTR("The list index starts with 0"),0, 0 );
306     if ( static_cast< sal_uInt32 >( nIndex ) >= m_vEntries.size())
307         throw lang::IllegalArgumentException( OUSTR("There is no element at the provided position."
308         "The position exceeds the number of available list entries"),0, 0 );
309 }
310 
311 //------------------------------------------------------------------------------
312 rtl::OUString ExtensionBox_Impl::getItemName( sal_Int32 nIndex ) const
313 {
314     const ::osl::MutexGuard aGuard( m_entriesMutex );
315     checkIndex( nIndex );
316     return m_vEntries[ nIndex ]->m_sTitle;
317 }
318 
319 //------------------------------------------------------------------------------
320 rtl::OUString ExtensionBox_Impl::getItemVersion( sal_Int32 nIndex ) const
321 {
322     const ::osl::MutexGuard aGuard( m_entriesMutex );
323     checkIndex( nIndex );
324     return m_vEntries[ nIndex ]->m_sVersion;
325 }
326 
327 //------------------------------------------------------------------------------
328 rtl::OUString ExtensionBox_Impl::getItemDescription( sal_Int32 nIndex ) const
329 {
330     const ::osl::MutexGuard aGuard( m_entriesMutex );
331     checkIndex( nIndex );
332     return m_vEntries[ nIndex ]->m_sDescription;
333 }
334 
335 //------------------------------------------------------------------------------
336 rtl::OUString ExtensionBox_Impl::getItemPublisher( sal_Int32 nIndex ) const
337 {
338     const ::osl::MutexGuard aGuard( m_entriesMutex );
339     checkIndex( nIndex );
340     return m_vEntries[ nIndex ]->m_sPublisher;
341 }
342 
343 //------------------------------------------------------------------------------
344 rtl::OUString ExtensionBox_Impl::getItemPublisherLink( sal_Int32 nIndex ) const
345 {
346     const ::osl::MutexGuard aGuard( m_entriesMutex );
347     checkIndex( nIndex );
348     return m_vEntries[ nIndex ]->m_sPublisherURL;
349 }
350 
351 //------------------------------------------------------------------------------
352 void ExtensionBox_Impl::select( sal_Int32 nIndex )
353 {
354     const ::osl::MutexGuard aGuard( m_entriesMutex );
355     checkIndex( nIndex );
356     selectEntry( nIndex );
357 }
358 
359 //------------------------------------------------------------------------------
360 void ExtensionBox_Impl::select( const rtl::OUString & sName )
361 {
362     const ::osl::MutexGuard aGuard( m_entriesMutex );
363     typedef ::std::vector< TEntry_Impl >::const_iterator It;
364 
365     for ( It iIter = m_vEntries.begin(); iIter < m_vEntries.end(); iIter++ )
366     {
367         if ( sName.equals( (*iIter)->m_sTitle ) )
368         {
369             long nPos = iIter - m_vEntries.begin();
370             selectEntry( nPos );
371             break;
372         }
373     }
374 }
375 
376 //------------------------------------------------------------------------------
377 //------------------------------------------------------------------------------
378 // Title + description
379 void ExtensionBox_Impl::CalcActiveHeight( const long nPos )
380 {
381     const ::osl::MutexGuard aGuard( m_entriesMutex );
382 
383     // get title height
384     long aTextHeight;
385     long nIconHeight = 2*TOP_OFFSET + SMALL_ICON_SIZE;
386     long nTitleHeight = 2*TOP_OFFSET + GetTextHeight();
387     if ( nIconHeight < nTitleHeight )
388         aTextHeight = nTitleHeight;
389     else
390         aTextHeight = nIconHeight;
391 
392     // calc description height
393     Size aSize = GetOutputSizePixel();
394     if ( m_bHasScrollBar )
395         aSize.Width() -= m_pScrollBar->GetSizePixel().Width();
396 
397     aSize.Width() -= ICON_OFFSET;
398     aSize.Height() = 10000;
399 
400     rtl::OUString aText( m_vEntries[ nPos ]->m_sErrorText );
401     if ( aText.getLength() )
402         aText += OUSTR("\n");
403     aText += m_vEntries[ nPos ]->m_sDescription;
404 
405     Rectangle aRect = GetTextRect( Rectangle( Point(), aSize ), aText,
406                                    TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
407     aTextHeight += aRect.GetHeight();
408 
409     if ( aTextHeight < m_nStdHeight )
410         aTextHeight = m_nStdHeight;
411 
412     if ( m_vEntries[ nPos ]->m_bHasButtons )
413         m_nActiveHeight = aTextHeight + m_nExtraHeight;
414     else
415         m_nActiveHeight = aTextHeight + 2;
416 }
417 
418 //------------------------------------------------------------------------------
419 const Size ExtensionBox_Impl::GetMinOutputSizePixel() const
420 {
421     return Size( 200, 80 );
422 }
423 
424 //------------------------------------------------------------------------------
425 Rectangle ExtensionBox_Impl::GetEntryRect( const long nPos ) const
426 {
427     const ::osl::MutexGuard aGuard( m_entriesMutex );
428 
429     Size aSize( GetOutputSizePixel() );
430 
431     if ( m_bHasScrollBar )
432         aSize.Width() -= m_pScrollBar->GetSizePixel().Width();
433 
434     if ( m_vEntries[ nPos ]->m_bActive )
435         aSize.Height() = m_nActiveHeight;
436     else
437         aSize.Height() = m_nStdHeight;
438 
439     Point aPos( 0, -m_nTopIndex + nPos * m_nStdHeight );
440     if ( m_bHasActive && ( nPos < m_nActive ) )
441         aPos.Y() += m_nActiveHeight - m_nStdHeight;
442 
443     return Rectangle( aPos, aSize );
444 }
445 
446 //------------------------------------------------------------------------------
447 void ExtensionBox_Impl::DeleteRemoved()
448 {
449     const ::osl::MutexGuard aGuard( m_entriesMutex );
450 
451     m_bInDelete = true;
452 
453     if ( ! m_vRemovedEntries.empty() )
454     {
455         typedef std::vector< TEntry_Impl >::iterator ITER;
456 
457         for ( ITER iIndex = m_vRemovedEntries.begin(); iIndex < m_vRemovedEntries.end(); ++iIndex )
458         {
459             if ( (*iIndex)->m_pPublisher )
460             {
461                 delete (*iIndex)->m_pPublisher;
462                 (*iIndex)->m_pPublisher = NULL;
463             }
464         }
465 
466         m_vRemovedEntries.clear();
467     }
468 
469     m_bInDelete = false;
470 }
471 
472 //------------------------------------------------------------------------------
473 //This function may be called with nPos < 0
474 void ExtensionBox_Impl::selectEntry( const long nPos )
475 {
476     //ToDo whe should not use the guard at such a big scope here.
477     //Currently it is used to gard m_vEntries and m_nActive. m_nActive will be
478     //modified in this function.
479     //It would be probably best to always use a copy of m_vEntries
480     //and some other state variables from ExtensionBox_Impl for
481     //the whole painting operation. See issue i86993
482     ::osl::ClearableMutexGuard guard(m_entriesMutex);
483 
484 	if ( m_bInCheckMode )
485         return;
486 
487     if ( m_bHasActive )
488     {
489         if ( nPos == m_nActive )
490             return;
491 
492         m_bHasActive = false;
493         m_vEntries[ m_nActive ]->m_bActive = false;
494     }
495 
496     if ( ( nPos >= 0 ) && ( nPos < (long) m_vEntries.size() ) )
497     {
498         m_bHasActive = true;
499         m_nActive = nPos;
500         m_vEntries[ nPos ]->m_bActive = true;
501 
502         if ( IsReallyVisible() )
503         {
504             m_bAdjustActive = true;
505         }
506     }
507 
508     if ( IsReallyVisible() )
509     {
510         m_bNeedsRecalc = true;
511         Invalidate();
512     }
513 
514     guard.clear();
515 }
516 
517 // -----------------------------------------------------------------------
518 void ExtensionBox_Impl::DrawRow( const Rectangle& rRect, const TEntry_Impl pEntry )
519 {
520     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
521 
522     if ( pEntry->m_bActive )
523         SetTextColor( rStyleSettings.GetHighlightTextColor() );
524     else if ( ( pEntry->m_eState != REGISTERED ) && ( pEntry->m_eState != NOT_AVAILABLE ) )
525         SetTextColor( rStyleSettings.GetDisableColor() );
526     else if ( IsControlForeground() )
527         SetTextColor( GetControlForeground() );
528     else
529         SetTextColor( rStyleSettings.GetFieldTextColor() );
530 
531     if ( pEntry->m_bActive )
532     {
533         SetLineColor();
534         SetFillColor( rStyleSettings.GetHighlightColor() );
535         DrawRect( rRect );
536     }
537     else
538     {
539         if( IsControlBackground() )
540 			SetBackground( GetControlBackground() );
541 		else
542 			SetBackground( rStyleSettings.GetFieldColor() );
543 
544         SetTextFillColor();
545         Erase( rRect );
546     }
547 
548     // Draw extension icon
549     Point aPos( rRect.TopLeft() );
550     aPos += Point( TOP_OFFSET, TOP_OFFSET );
551     Image aImage;
552     if ( ! pEntry->m_aIcon )
553         aImage = isHCMode() ? m_aDefaultImageHC : m_aDefaultImage;
554     else
555         aImage = isHCMode() ? pEntry->m_aIconHC : pEntry->m_aIcon;
556     Size aImageSize = aImage.GetSizePixel();
557     if ( ( aImageSize.Width() <= ICON_WIDTH ) && ( aImageSize.Height() <= ICON_HEIGHT ) )
558         DrawImage( Point( aPos.X()+((ICON_WIDTH-aImageSize.Width())/2), aPos.Y()+((ICON_HEIGHT-aImageSize.Height())/2) ), aImage );
559     else
560         DrawImage( aPos, Size( ICON_WIDTH, ICON_HEIGHT ), aImage );
561 
562     // Setup fonts
563     Font aStdFont( GetFont() );
564     Font aBoldFont( aStdFont );
565     aBoldFont.SetWeight( WEIGHT_BOLD );
566     SetFont( aBoldFont );
567     long aTextHeight = GetTextHeight();
568 
569     // Init publisher link here
570     if ( !pEntry->m_pPublisher && pEntry->m_sPublisher.Len() )
571     {
572         pEntry->m_pPublisher = new svt::FixedHyperlink( this );
573         pEntry->m_pPublisher->SetBackground();
574         pEntry->m_pPublisher->SetPaintTransparent( true );
575         pEntry->m_pPublisher->SetURL( pEntry->m_sPublisherURL );
576         pEntry->m_pPublisher->SetDescription( pEntry->m_sPublisher );
577         Size aSize = FixedText::CalcMinimumTextSize( pEntry->m_pPublisher );
578         pEntry->m_pPublisher->SetSizePixel( aSize );
579 
580         if ( m_aClickHdl.IsSet() )
581             pEntry->m_pPublisher->SetClickHdl( m_aClickHdl );
582     }
583 
584     // Get max title width
585     long nMaxTitleWidth = rRect.GetWidth() - ICON_OFFSET;
586     nMaxTitleWidth -= ( 2 * SMALL_ICON_SIZE ) + ( 4 * SPACE_BETWEEN );
587     if ( pEntry->m_pPublisher )
588     {
589         nMaxTitleWidth -= pEntry->m_pPublisher->GetSizePixel().Width() + (2*SPACE_BETWEEN);
590     }
591 
592     long aVersionWidth = GetTextWidth( pEntry->m_sVersion );
593     long aTitleWidth = GetTextWidth( pEntry->m_sTitle ) + (aTextHeight / 3);
594 
595     aPos = rRect.TopLeft() + Point( ICON_OFFSET, TOP_OFFSET );
596 
597     if ( aTitleWidth > nMaxTitleWidth - aVersionWidth )
598     {
599         aTitleWidth = nMaxTitleWidth - aVersionWidth - (aTextHeight / 3);
600         String aShortTitle = GetEllipsisString( pEntry->m_sTitle, aTitleWidth );
601         DrawText( aPos, aShortTitle );
602         aTitleWidth += (aTextHeight / 3);
603     }
604     else
605         DrawText( aPos, pEntry->m_sTitle );
606 
607     SetFont( aStdFont );
608     DrawText( Point( aPos.X() + aTitleWidth, aPos.Y() ), pEntry->m_sVersion );
609 
610     long nIconHeight = TOP_OFFSET + SMALL_ICON_SIZE;
611     long nTitleHeight = TOP_OFFSET + GetTextHeight();
612     if ( nIconHeight < nTitleHeight )
613         aTextHeight = nTitleHeight;
614     else
615         aTextHeight = nIconHeight;
616 
617     // draw description
618     String sDescription;
619     if ( pEntry->m_sErrorText.Len() )
620     {
621         if ( pEntry->m_bActive )
622             sDescription = pEntry->m_sErrorText + OUSTR("\n") + pEntry->m_sDescription;
623         else
624             sDescription = pEntry->m_sErrorText;
625     }
626     else
627         sDescription = pEntry->m_sDescription;
628 
629     aPos.Y() += aTextHeight;
630     if ( pEntry->m_bActive )
631     {
632         long nExtraHeight = 0;
633 
634         if ( pEntry->m_bHasButtons )
635             nExtraHeight = m_nExtraHeight;
636 
637         DrawText( Rectangle( aPos.X(), aPos.Y(), rRect.Right(), rRect.Bottom() - nExtraHeight ),
638                   sDescription, TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
639     }
640     else
641     {
642         const long nWidth = GetTextWidth( sDescription );
643         if ( nWidth > rRect.GetWidth() - aPos.X() )
644             sDescription = GetEllipsisString( sDescription, rRect.GetWidth() - aPos.X() );
645         DrawText( aPos, sDescription );
646     }
647 
648     // Draw publisher link
649     if ( pEntry->m_pPublisher )
650     {
651         pEntry->m_pPublisher->Show();
652         aPos = rRect.TopLeft() + Point( ICON_OFFSET + nMaxTitleWidth + (2*SPACE_BETWEEN), TOP_OFFSET );
653         pEntry->m_pPublisher->SetPosPixel( aPos );
654     }
655 
656     // Draw status icons
657     if ( !pEntry->m_bUser )
658     {
659         aPos = rRect.TopRight() + Point( -(RIGHT_ICON_OFFSET + SMALL_ICON_SIZE), TOP_OFFSET );
660         if ( pEntry->m_bLocked )
661             DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), isHCMode() ? m_aLockedImageHC : m_aLockedImage );
662         else
663             DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), isHCMode() ? m_aSharedImageHC : m_aSharedImage );
664     }
665     if ( ( pEntry->m_eState == AMBIGUOUS ) || pEntry->m_bMissingDeps || pEntry->m_bMissingLic )
666     {
667         aPos = rRect.TopRight() + Point( -(RIGHT_ICON_OFFSET + SPACE_BETWEEN + 2*SMALL_ICON_SIZE), TOP_OFFSET );
668         DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), isHCMode() ? m_aWarningImageHC : m_aWarningImage );
669     }
670 
671     SetLineColor( Color( COL_LIGHTGRAY ) );
672     DrawLine( rRect.BottomLeft(), rRect.BottomRight() );
673 }
674 
675 // -----------------------------------------------------------------------
676 void ExtensionBox_Impl::RecalcAll()
677 {
678     if ( m_bHasActive )
679         CalcActiveHeight( m_nActive );
680 
681     SetupScrollBar();
682 
683     if ( m_bHasActive )
684     {
685         Rectangle aEntryRect = GetEntryRect( m_nActive );
686 
687         if ( m_bAdjustActive )
688         {
689             m_bAdjustActive = false;
690 
691             // If the top of the selected entry isn't visible, make it visible
692             if ( aEntryRect.Top() < 0 )
693             {
694                 m_nTopIndex += aEntryRect.Top();
695                 aEntryRect.Move( 0, -aEntryRect.Top() );
696             }
697 
698             // If the bottom of the selected entry isn't visible, make it visible even if now the top
699             // isn't visible any longer ( the buttons are more important )
700             Size aOutputSize = GetOutputSizePixel();
701             if ( aEntryRect.Bottom() > aOutputSize.Height() )
702             {
703                 m_nTopIndex += ( aEntryRect.Bottom() - aOutputSize.Height() );
704                 aEntryRect.Move( 0, -( aEntryRect.Bottom() - aOutputSize.Height() ) );
705             }
706 
707             // If there is unused space below the last entry but all entries don't fit into the box,
708             // move the content down to use the whole space
709             const long nTotalHeight = GetTotalHeight();
710             if ( m_bHasScrollBar && ( aOutputSize.Height() + m_nTopIndex > nTotalHeight ) )
711             {
712                 long nOffset = m_nTopIndex;
713                 m_nTopIndex = nTotalHeight - aOutputSize.Height();
714                 nOffset -= m_nTopIndex;
715                 aEntryRect.Move( 0, nOffset );
716             }
717 
718             if ( m_bHasScrollBar )
719                 m_pScrollBar->SetThumbPos( m_nTopIndex );
720         }
721     }
722 
723     m_bNeedsRecalc = false;
724 }
725 
726 // -----------------------------------------------------------------------
727 bool ExtensionBox_Impl::HandleTabKey( bool )
728 {
729     return false;
730 }
731 
732 // -----------------------------------------------------------------------
733 bool ExtensionBox_Impl::HandleCursorKey( sal_uInt16 nKeyCode )
734 {
735     if ( m_vEntries.empty() )
736         return true;
737 
738     long nSelect = 0;
739 
740     if ( m_bHasActive )
741     {
742         long nPageSize = GetOutputSizePixel().Height() / m_nStdHeight;
743         if ( nPageSize < 2 )
744             nPageSize = 2;
745 
746         if ( ( nKeyCode == KEY_DOWN ) || ( nKeyCode == KEY_RIGHT ) )
747             nSelect = m_nActive + 1;
748         else if ( ( nKeyCode == KEY_UP ) || ( nKeyCode == KEY_LEFT ) )
749             nSelect = m_nActive - 1;
750         else if ( nKeyCode == KEY_HOME )
751             nSelect = 0;
752         else if ( nKeyCode == KEY_END )
753             nSelect = m_vEntries.size() - 1;
754         else if ( nKeyCode == KEY_PAGEUP )
755             nSelect = m_nActive - nPageSize + 1;
756         else if ( nKeyCode == KEY_PAGEDOWN )
757             nSelect = m_nActive + nPageSize - 1;
758     }
759     else // when there is no selected entry, we will select the first or the last.
760     {
761         if ( ( nKeyCode == KEY_DOWN ) || ( nKeyCode == KEY_PAGEDOWN ) || ( nKeyCode == KEY_HOME ) )
762             nSelect = 0;
763         else if ( ( nKeyCode == KEY_UP ) || ( nKeyCode == KEY_PAGEUP ) || ( nKeyCode == KEY_END ) )
764             nSelect = m_vEntries.size() - 1;
765     }
766 
767     if ( nSelect < 0 )
768         nSelect = 0;
769     if ( nSelect >= (long) m_vEntries.size() )
770         nSelect = m_vEntries.size() - 1;
771 
772     selectEntry( nSelect );
773 
774     return true;
775 }
776 
777 // -----------------------------------------------------------------------
778 void ExtensionBox_Impl::Paint( const Rectangle &/*rPaintRect*/ )
779 {
780     if ( !m_bInDelete )
781         DeleteRemoved();
782 
783     if ( m_bNeedsRecalc )
784         RecalcAll();
785 
786     Point aStart( 0, -m_nTopIndex );
787     Size aSize( GetOutputSizePixel() );
788 
789     if ( m_bHasScrollBar )
790         aSize.Width() -= m_pScrollBar->GetSizePixel().Width();
791 
792     const ::osl::MutexGuard aGuard( m_entriesMutex );
793 
794     typedef std::vector< TEntry_Impl >::iterator ITER;
795     for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
796     {
797         aSize.Height() = (*iIndex)->m_bActive ? m_nActiveHeight : m_nStdHeight;
798         Rectangle aEntryRect( aStart, aSize );
799         DrawRow( aEntryRect, *iIndex );
800         aStart.Y() += aSize.Height();
801     }
802 }
803 
804 // -----------------------------------------------------------------------
805 long ExtensionBox_Impl::GetTotalHeight() const
806 {
807     long nHeight = m_vEntries.size() * m_nStdHeight;
808 
809     if ( m_bHasActive )
810     {
811         nHeight += m_nActiveHeight - m_nStdHeight;
812     }
813 
814     return nHeight;
815 }
816 
817 // -----------------------------------------------------------------------
818 void ExtensionBox_Impl::SetupScrollBar()
819 {
820     const Size aSize = GetOutputSizePixel();
821     const long nScrBarSize = GetSettings().GetStyleSettings().GetScrollBarSize();
822     const long nTotalHeight = GetTotalHeight();
823     const bool bNeedsScrollBar = ( nTotalHeight > aSize.Height() );
824 
825     if ( bNeedsScrollBar )
826     {
827         if ( m_nTopIndex + aSize.Height() > nTotalHeight )
828             m_nTopIndex = nTotalHeight - aSize.Height();
829 
830         m_pScrollBar->SetPosSizePixel( Point( aSize.Width() - nScrBarSize, 0 ),
831                                        Size( nScrBarSize, aSize.Height() ) );
832         m_pScrollBar->SetRangeMax( nTotalHeight );
833         m_pScrollBar->SetVisibleSize( aSize.Height() );
834         m_pScrollBar->SetPageSize( ( aSize.Height() * 4 ) / 5 );
835         m_pScrollBar->SetLineSize( m_nStdHeight );
836         m_pScrollBar->SetThumbPos( m_nTopIndex );
837 
838         if ( !m_bHasScrollBar )
839             m_pScrollBar->Show();
840     }
841     else if ( m_bHasScrollBar )
842     {
843         m_pScrollBar->Hide();
844         m_nTopIndex = 0;
845     }
846 
847     m_bHasScrollBar = bNeedsScrollBar;
848 }
849 
850 // -----------------------------------------------------------------------
851 void ExtensionBox_Impl::Resize()
852 {
853     RecalcAll();
854 }
855 
856 //------------------------------------------------------------------------------
857 long ExtensionBox_Impl::PointToPos( const Point& rPos )
858 {
859     long nPos = ( rPos.Y() + m_nTopIndex ) / m_nStdHeight;
860 
861     if ( m_bHasActive && ( nPos > m_nActive ) )
862     {
863         if ( rPos.Y() + m_nTopIndex <= m_nActive*m_nStdHeight + m_nActiveHeight )
864             nPos = m_nActive;
865         else
866             nPos = ( rPos.Y() + m_nTopIndex - (m_nActiveHeight - m_nStdHeight) ) / m_nStdHeight;
867     }
868 
869     return nPos;
870 }
871 
872 //------------------------------------------------------------------------------
873 void ExtensionBox_Impl::MouseButtonDown( const MouseEvent& rMEvt )
874 {
875     long nPos = PointToPos( rMEvt.GetPosPixel() );
876 
877     if ( rMEvt.IsLeft() )
878     {
879         if ( rMEvt.IsMod1() && m_bHasActive )
880             selectEntry( m_vEntries.size() );   // Selecting an not existing entry will deselect the current one
881         else
882             selectEntry( nPos );
883     }
884 }
885 
886 //------------------------------------------------------------------------------
887 long ExtensionBox_Impl::Notify( NotifyEvent& rNEvt )
888 {
889     if ( !m_bInDelete )
890         DeleteRemoved();
891 
892     bool bHandled = false;
893 
894     if ( rNEvt.GetType() == EVENT_KEYINPUT )
895     {
896         const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
897         KeyCode         aKeyCode = pKEvt->GetKeyCode();
898         sal_uInt16          nKeyCode = aKeyCode.GetCode();
899 
900         if ( nKeyCode == KEY_TAB )
901             bHandled = HandleTabKey( aKeyCode.IsShift() );
902         else if ( aKeyCode.GetGroup() == KEYGROUP_CURSOR )
903             bHandled = HandleCursorKey( nKeyCode );
904     }
905 
906     if ( rNEvt.GetType() == EVENT_COMMAND )
907     {
908         if ( m_bHasScrollBar &&
909              ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) )
910         {
911             const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
912             if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
913             {
914                 long nThumbPos = m_pScrollBar->GetThumbPos();
915                 if ( pData->GetDelta() < 0 )
916                     m_pScrollBar->DoScroll( nThumbPos + m_nStdHeight );
917                 else
918                     m_pScrollBar->DoScroll( nThumbPos - m_nStdHeight );
919                 bHandled = true;
920             }
921         }
922     }
923 
924     if ( !bHandled )
925         return Control::Notify( rNEvt );
926     else
927         return true;
928 }
929 
930 //------------------------------------------------------------------------------
931 bool ExtensionBox_Impl::FindEntryPos( const TEntry_Impl pEntry, const long nStart,
932                                       const long nEnd, long &nPos )
933 {
934     nPos = nStart;
935     if ( nStart > nEnd )
936         return false;
937 
938     StringCompare eCompare;
939 
940     if ( nStart == nEnd )
941     {
942         eCompare = pEntry->CompareTo( m_pCollator, m_vEntries[ nStart ] );
943         if ( eCompare == COMPARE_LESS )
944             return false;
945         else if ( eCompare == COMPARE_EQUAL )
946         {
947             //Workaround. See i86963.
948             if (pEntry->m_xPackage != m_vEntries[nStart]->m_xPackage)
949                 return false;
950 
951             if ( m_bInCheckMode )
952                 m_vEntries[ nStart ]->m_bChecked = true;
953             return true;
954         }
955         else
956         {
957             nPos = nStart + 1;
958             return false;
959         }
960     }
961 
962     const long nMid = nStart + ( ( nEnd - nStart ) / 2 );
963     eCompare = pEntry->CompareTo( m_pCollator, m_vEntries[ nMid ] );
964 
965     if ( eCompare == COMPARE_LESS )
966         return FindEntryPos( pEntry, nStart, nMid-1, nPos );
967     else if ( eCompare == COMPARE_GREATER )
968         return FindEntryPos( pEntry, nMid+1, nEnd, nPos );
969     else
970     {
971         //Workaround.See i86963.
972         if (pEntry->m_xPackage != m_vEntries[nMid]->m_xPackage)
973             return false;
974 
975         if ( m_bInCheckMode )
976             m_vEntries[ nMid ]->m_bChecked = true;
977         nPos = nMid;
978         return true;
979     }
980 }
981 
982 void ExtensionBox_Impl::cleanVecListenerAdded()
983 {
984     typedef ::std::vector<uno::WeakReference<deployment::XPackage> >::iterator IT;
985     IT i = m_vListenerAdded.begin();
986     while( i != m_vListenerAdded.end())
987     {
988         const uno::Reference<deployment::XPackage> hardRef(*i);
989         if (!hardRef.is())
990             i = m_vListenerAdded.erase(i);
991         else
992             ++i;
993     }
994 }
995 
996 void ExtensionBox_Impl::addEventListenerOnce(
997     uno::Reference<deployment::XPackage > const & extension)
998 {
999     //make sure to only add the listener once
1000     cleanVecListenerAdded();
1001     if ( ::std::find_if(m_vListenerAdded.begin(), m_vListenerAdded.end(),
1002                         FindWeakRef(extension))
1003          == m_vListenerAdded.end())
1004     {
1005         extension->addEventListener( uno::Reference< lang::XEventListener > (
1006                                          m_xRemoveListener, uno::UNO_QUERY ) );
1007         m_vListenerAdded.push_back(extension);
1008     }
1009 }
1010 
1011 //------------------------------------------------------------------------------
1012 long ExtensionBox_Impl::addEntry( const uno::Reference< deployment::XPackage > &xPackage,
1013                                   bool bLicenseMissing )
1014 {
1015     long         nPos = 0;
1016     PackageState eState = m_pManager->getPackageState( xPackage );
1017     bool         bLocked = m_pManager->isReadOnly( xPackage );
1018 
1019     TEntry_Impl pEntry( new Entry_Impl( xPackage, eState, bLocked ) );
1020 
1021     // Don't add empty entries
1022     if ( ! pEntry->m_sTitle.Len() )
1023         return 0;
1024 
1025     ::osl::ClearableMutexGuard guard(m_entriesMutex);
1026     if ( m_vEntries.empty() )
1027     {
1028         addEventListenerOnce(xPackage);
1029         m_vEntries.push_back( pEntry );
1030     }
1031     else
1032     {
1033         if ( !FindEntryPos( pEntry, 0, m_vEntries.size()-1, nPos ) )
1034         {
1035             addEventListenerOnce(xPackage);
1036             m_vEntries.insert( m_vEntries.begin()+nPos, pEntry );
1037         }
1038         else if ( !m_bInCheckMode )
1039         {
1040             OSL_ENSURE( 0, "ExtensionBox_Impl::addEntry(): Will not add duplicate entries"  );
1041         }
1042     }
1043 
1044     pEntry->m_bHasOptions = m_pManager->supportsOptions( xPackage );
1045     pEntry->m_bUser       = xPackage->getRepositoryName().equals( USER_PACKAGE_MANAGER );
1046     pEntry->m_bShared     = xPackage->getRepositoryName().equals( SHARED_PACKAGE_MANAGER );
1047     pEntry->m_bNew        = m_bInCheckMode;
1048     pEntry->m_bMissingLic = bLicenseMissing;
1049 
1050     if ( bLicenseMissing )
1051         pEntry->m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_MISSING_LICENSE );
1052 
1053     //access to m_nActive must be guarded
1054     if ( !m_bInCheckMode && m_bHasActive && ( m_nActive >= nPos ) )
1055         m_nActive += 1;
1056 
1057     guard.clear();
1058 
1059     if ( IsReallyVisible() )
1060         Invalidate();
1061 
1062     m_bNeedsRecalc = true;
1063 
1064     return nPos;
1065 }
1066 
1067 //------------------------------------------------------------------------------
1068 void ExtensionBox_Impl::updateEntry( const uno::Reference< deployment::XPackage > &xPackage )
1069 {
1070     typedef std::vector< TEntry_Impl >::iterator ITER;
1071     for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
1072     {
1073         if ( (*iIndex)->m_xPackage == xPackage )
1074         {
1075             PackageState eState = m_pManager->getPackageState( xPackage );
1076             (*iIndex)->m_bHasOptions = m_pManager->supportsOptions( xPackage );
1077             (*iIndex)->m_eState = eState;
1078             (*iIndex)->m_sTitle = xPackage->getDisplayName();
1079             (*iIndex)->m_sVersion = xPackage->getVersion();
1080             (*iIndex)->m_sDescription = xPackage->getDescription();
1081 
1082             if ( eState == REGISTERED )
1083                 (*iIndex)->m_bMissingLic = false;
1084 
1085             if ( eState == AMBIGUOUS )
1086                 (*iIndex)->m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_UNKNOWN_STATUS );
1087             else if ( ! (*iIndex)->m_bMissingLic )
1088                 (*iIndex)->m_sErrorText = String();
1089 
1090             if ( IsReallyVisible() )
1091                 Invalidate();
1092             break;
1093         }
1094     }
1095 }
1096 
1097 //------------------------------------------------------------------------------
1098 //This function is also called as a result of removing an extension.
1099 //see PackageManagerImpl::removePackage
1100 //The gui is a registered as listener on the package. Removing it will cause the
1101 //listeners to be notified an then this function is called. At this moment xPackage
1102 //is in the disposing state and all calls on it may result in a DisposedException.
1103 void ExtensionBox_Impl::removeEntry( const uno::Reference< deployment::XPackage > &xPackage )
1104 {
1105    if ( ! m_bInDelete )
1106     {
1107         ::osl::ClearableMutexGuard aGuard( m_entriesMutex );
1108 
1109         typedef std::vector< TEntry_Impl >::iterator ITER;
1110 
1111         for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
1112         {
1113             if ( (*iIndex)->m_xPackage == xPackage )
1114             {
1115                 long nPos = iIndex - m_vEntries.begin();
1116 
1117                 // Entries mustn't removed here, because they contain a hyperlink control
1118                 // which can only be deleted when the thread has the solar mutex. Therefor
1119                 // the entry will be moved into the m_vRemovedEntries list which will be
1120                 // cleared on the next paint event
1121                 m_vRemovedEntries.push_back( *iIndex );
1122                 (*iIndex)->m_xPackage->removeEventListener(
1123                     uno::Reference<lang::XEventListener>(m_xRemoveListener, uno::UNO_QUERY));
1124                 m_vEntries.erase( iIndex );
1125 
1126                 m_bNeedsRecalc = true;
1127 
1128                 if ( IsReallyVisible() )
1129                     Invalidate();
1130 
1131                 if ( m_bHasActive )
1132                 {
1133                     if ( nPos < m_nActive )
1134                         m_nActive -= 1;
1135                     else if ( ( nPos == m_nActive ) &&
1136                               ( nPos == (long) m_vEntries.size() ) )
1137                         m_nActive -= 1;
1138 
1139                     m_bHasActive = false;
1140                     //clear before calling out of this method
1141                     aGuard.clear();
1142                     selectEntry( m_nActive );
1143                 }
1144                 break;
1145             }
1146         }
1147     }
1148 }
1149 
1150 //------------------------------------------------------------------------------
1151 void ExtensionBox_Impl::RemoveUnlocked()
1152 {
1153     bool bAllRemoved = false;
1154 
1155     while ( ! bAllRemoved )
1156     {
1157         bAllRemoved = true;
1158 
1159         ::osl::ClearableMutexGuard aGuard( m_entriesMutex );
1160 
1161         typedef std::vector< TEntry_Impl >::iterator ITER;
1162 
1163         for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
1164         {
1165             if ( !(*iIndex)->m_bLocked )
1166             {
1167                 bAllRemoved = false;
1168                 uno::Reference< deployment::XPackage> xPackage = (*iIndex)->m_xPackage;
1169                 aGuard.clear();
1170                 removeEntry( xPackage );
1171                 break;
1172             }
1173         }
1174     }
1175 }
1176 
1177 //------------------------------------------------------------------------------
1178 void ExtensionBox_Impl::prepareChecking()
1179 {
1180     m_bInCheckMode = true;
1181     typedef std::vector< TEntry_Impl >::iterator ITER;
1182     for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
1183     {
1184         (*iIndex)->m_bChecked = false;
1185         (*iIndex)->m_bNew = false;
1186     }
1187 }
1188 
1189 //------------------------------------------------------------------------------
1190 void ExtensionBox_Impl::checkEntries()
1191 {
1192     long nNewPos = -1;
1193     long nPos = 0;
1194     bool bNeedsUpdate = false;
1195 
1196     ::osl::ClearableMutexGuard guard(m_entriesMutex);
1197     typedef std::vector< TEntry_Impl >::iterator ITER;
1198     ITER iIndex = m_vEntries.begin();
1199     while ( iIndex < m_vEntries.end() )
1200     {
1201         if ( (*iIndex)->m_bChecked == false )
1202         {
1203             (*iIndex)->m_bChecked = true;
1204             bNeedsUpdate = true;
1205             nPos = iIndex-m_vEntries.begin();
1206             if ( (*iIndex)->m_bNew )
1207             { // add entry to list and correct active pos
1208                 if ( nNewPos == - 1)
1209                     nNewPos = nPos;
1210                 if ( nPos <= m_nActive )
1211                     m_nActive += 1;
1212                 iIndex++;
1213             }
1214             else
1215             {   // remove entry from list
1216                 if ( nPos < m_nActive )
1217                     m_nActive -= 1;
1218                 else if ( ( nPos == m_nActive ) && ( nPos == (long) m_vEntries.size() - 1 ) )
1219                     m_nActive -= 1;
1220                 m_vRemovedEntries.push_back( *iIndex );
1221                 m_vEntries.erase( iIndex );
1222                 iIndex = m_vEntries.begin() + nPos;
1223             }
1224         }
1225         else
1226             iIndex++;
1227     }
1228     guard.clear();
1229 
1230     m_bInCheckMode = false;
1231 
1232     if ( nNewPos != - 1)
1233         selectEntry( nNewPos );
1234 
1235     if ( bNeedsUpdate )
1236     {
1237         m_bNeedsRecalc = true;
1238         if ( IsReallyVisible() )
1239             Invalidate();
1240     }
1241 }
1242 //------------------------------------------------------------------------------
1243 bool ExtensionBox_Impl::isHCMode()
1244 {
1245     return (bool)GetSettings().GetStyleSettings().GetHighContrastMode();
1246 }
1247 
1248 //------------------------------------------------------------------------------
1249 void ExtensionBox_Impl::SetScrollHdl( const Link& rLink )
1250 {
1251     if ( m_pScrollBar )
1252         m_pScrollBar->SetScrollHdl( rLink );
1253 }
1254 
1255 // -----------------------------------------------------------------------
1256 void ExtensionBox_Impl::DoScroll( long nDelta )
1257 {
1258     m_nTopIndex += nDelta;
1259     Point aNewSBPt( m_pScrollBar->GetPosPixel() );
1260 
1261     Rectangle aScrRect( Point(), GetOutputSizePixel() );
1262     aScrRect.Right() -= m_pScrollBar->GetSizePixel().Width();
1263     Scroll( 0, -nDelta, aScrRect );
1264 
1265     m_pScrollBar->SetPosPixel( aNewSBPt );
1266 }
1267 
1268 // -----------------------------------------------------------------------
1269 IMPL_LINK( ExtensionBox_Impl, ScrollHdl, ScrollBar*, pScrBar )
1270 {
1271     DoScroll( pScrBar->GetDelta() );
1272 
1273     return 1;
1274 }
1275 
1276 } //namespace dp_gui
1277