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