Update ooo320-m1
[ooovba.git] / desktop / source / deployment / gui / dp_gui_extlistbox.cxx
blobf4473c2c6fd8779ce09a43138263424fac86c653
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2009 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_desktop.hxx"
31 #include "svtools/controldims.hrc"
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"
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"
45 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
47 using namespace ::com::sun::star;
49 namespace dp_gui {
51 //------------------------------------------------------------------------------
52 // struct Entry_Impl
53 //------------------------------------------------------------------------------
54 Entry_Impl::Entry_Impl( const uno::Reference< deployment::XPackage > &xPackage,
55 const uno::Reference< deployment::XPackageManager > &xPackageManager,
56 PackageState eState ) :
57 m_bActive( false ),
58 m_bLocked( false ),
59 m_bHasOptions( false ),
60 m_bShared( false ),
61 m_bNew( false ),
62 m_bChecked( false ),
63 m_bMissingDeps( false ),
64 m_eState( eState ),
65 m_pPublisher( NULL ),
66 m_xPackage( xPackage ),
67 m_xPackageManager( xPackageManager )
69 m_sTitle = xPackage->getDisplayName();
70 m_sVersion = xPackage->getVersion();
71 m_sDescription = xPackage->getDescription();
73 beans::StringPair aInfo( m_xPackage->getPublisherInfo() );
74 m_sPublisher = aInfo.First;
75 m_sPublisherURL = aInfo.Second;
77 // get the icons for the package if there are any
78 uno::Reference< graphic::XGraphic > xGraphic = xPackage->getIcon( false );
79 if ( xGraphic.is() )
80 m_aIcon = Image( xGraphic );
82 xGraphic = xPackage->getIcon( true );
83 if ( xGraphic.is() )
84 m_aIconHC = Image( xGraphic );
85 else
86 m_aIconHC = m_aIcon;
88 m_bLocked = m_xPackageManager->isReadOnly();
90 if ( eState == AMBIGUOUS )
91 m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_UNKNOWN_STATUS );
92 else if ( eState == NOT_REGISTERED )
93 checkDependencies();
96 //------------------------------------------------------------------------------
97 Entry_Impl::~Entry_Impl()
100 //------------------------------------------------------------------------------
101 StringCompare Entry_Impl::CompareTo( const CollatorWrapper *pCollator, const TEntry_Impl pEntry ) const
103 StringCompare eCompare = (StringCompare) pCollator->compareString( m_sTitle, pEntry->m_sTitle );
104 if ( eCompare == COMPARE_EQUAL )
106 eCompare = m_sVersion.CompareTo( pEntry->m_sVersion );
107 if ( eCompare == COMPARE_EQUAL )
109 if ( m_xPackageManager != pEntry->m_xPackageManager )
111 sal_Int32 nCompare = m_xPackageManager->getContext().compareTo( pEntry->m_xPackageManager->getContext() );
112 if ( nCompare < 0 )
113 eCompare = COMPARE_LESS;
114 else if ( nCompare > 0 )
115 eCompare = COMPARE_GREATER;
119 return eCompare;
122 //------------------------------------------------------------------------------
123 void Entry_Impl::checkDependencies()
125 try {
126 m_xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
128 catch ( deployment::DeploymentException &e )
130 deployment::DependencyException depExc;
131 if ( e.Cause >>= depExc )
133 rtl::OUString aMissingDep( DialogHelper::getResourceString( RID_STR_ERROR_MISSING_DEPENDENCIES ) );
134 for ( sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength(); ++i )
136 aMissingDep += OUSTR("\n");
137 aMissingDep += dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]);
139 aMissingDep += OUSTR("\n");
140 m_sErrorText = aMissingDep;
141 m_bMissingDeps = true;
145 //------------------------------------------------------------------------------
146 // ExtensionRemovedListener
147 //------------------------------------------------------------------------------
148 void ExtensionRemovedListener::disposing( lang::EventObject const & rEvt )
149 throw ( uno::RuntimeException )
151 uno::Reference< deployment::XPackage > xPackage( rEvt.Source, uno::UNO_QUERY );
153 if ( xPackage.is() )
155 m_pParent->removeEntry( xPackage );
159 //------------------------------------------------------------------------------
160 ExtensionRemovedListener::~ExtensionRemovedListener()
164 //------------------------------------------------------------------------------
165 // ExtensionBox_Impl
166 //------------------------------------------------------------------------------
167 ExtensionBox_Impl::ExtensionBox_Impl( Dialog* pParent, TheExtensionManager *pManager ) :
168 IExtensionListBox( pParent, WB_BORDER | WB_TABSTOP | WB_CHILDDLGCTRL ),
169 m_bHasScrollBar( false ),
170 m_bHasActive( false ),
171 m_bNeedsRecalc( true ),
172 m_bHasNew( false ),
173 m_bInCheckMode( false ),
174 m_bAdjustActive( false ),
175 m_bInDelete( false ),
176 m_nActive( 0 ),
177 m_nTopIndex( 0 ),
178 m_nActiveHeight( 0 ),
179 m_nExtraHeight( 2 ),
180 m_aLockedImage( DialogHelper::getResId( RID_IMG_LOCKED ) ),
181 m_aLockedImageHC( DialogHelper::getResId( RID_IMG_LOCKED_HC ) ),
182 m_aWarningImage( DialogHelper::getResId( RID_IMG_WARNING ) ),
183 m_aWarningImageHC( DialogHelper::getResId( RID_IMG_WARNING_HC ) ),
184 m_aDefaultImage( DialogHelper::getResId( RID_IMG_EXTENSION ) ),
185 m_aDefaultImageHC( DialogHelper::getResId( RID_IMG_EXTENSION_HC ) ),
186 m_pScrollBar( NULL ),
187 m_pManager( pManager )
189 SetHelpId( HID_EXTENSION_MANAGER_LISTBOX );
191 m_pScrollBar = new ScrollBar( this, WB_VERT );
192 m_pScrollBar->SetScrollHdl( LINK( this, ExtensionBox_Impl, ScrollHdl ) );
193 m_pScrollBar->EnableDrag();
195 SetPaintTransparent( true );
196 SetPosPixel( Point( RSC_SP_DLG_INNERBORDER_LEFT, RSC_SP_DLG_INNERBORDER_TOP ) );
197 long nIconHeight = 2*TOP_OFFSET + SMALL_ICON_SIZE;
198 long nTitleHeight = 2*TOP_OFFSET + GetTextHeight();
199 if ( nIconHeight < nTitleHeight )
200 m_nStdHeight = nTitleHeight;
201 else
202 m_nStdHeight = nIconHeight;
203 m_nStdHeight += GetTextHeight() + TOP_OFFSET;
205 nIconHeight = ICON_HEIGHT + 2*TOP_OFFSET + 1;
206 if ( m_nStdHeight < nIconHeight )
207 m_nStdHeight = nIconHeight;
209 m_nActiveHeight = m_nStdHeight;
211 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
212 if( IsControlBackground() )
213 SetBackground( GetControlBackground() );
214 else
215 SetBackground( rStyleSettings.GetFieldColor() );
217 m_xRemoveListener = new ExtensionRemovedListener( this );
219 m_pLocale = new lang::Locale( Application::GetSettings().GetLocale() );
220 m_pCollator = new CollatorWrapper( ::comphelper::getProcessServiceFactory() );
221 m_pCollator->loadDefaultCollator( *m_pLocale, i18n::CollatorOptions::CollatorOptions_IGNORE_CASE );
223 Show();
226 //------------------------------------------------------------------------------
227 ExtensionBox_Impl::~ExtensionBox_Impl()
229 if ( ! m_bInDelete )
230 DeleteRemoved();
232 m_bInDelete = true;
234 typedef std::vector< TEntry_Impl >::iterator ITER;
236 for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
238 if ( (*iIndex)->m_pPublisher )
240 delete (*iIndex)->m_pPublisher;
241 (*iIndex)->m_pPublisher = NULL;
243 (*iIndex)->m_xPackage->removeEventListener( uno::Reference< lang::XEventListener > ( m_xRemoveListener, uno::UNO_QUERY ) );
246 m_vEntries.clear();
248 delete m_pScrollBar;
250 m_xRemoveListener.clear();
252 delete m_pLocale;
253 delete m_pCollator;
256 //------------------------------------------------------------------------------
257 sal_Int32 ExtensionBox_Impl::getItemCount() const
259 return static_cast< sal_Int32 >( m_vEntries.size() );
262 //------------------------------------------------------------------------------
263 sal_Int32 ExtensionBox_Impl::getSelIndex() const
265 if ( m_bHasActive )
267 OSL_ASSERT( m_nActive >= -1);
268 return static_cast< sal_Int32 >( m_nActive );
270 else
271 return static_cast< sal_Int32 >( EXTENSION_LISTBOX_ENTRY_NOTFOUND );
274 //------------------------------------------------------------------------------
275 void ExtensionBox_Impl::checkIndex( sal_Int32 nIndex ) const
277 if ( nIndex < 0 )
278 throw lang::IllegalArgumentException( OUSTR("The list index starts with 0"),0, 0 );
279 if ( static_cast< sal_uInt32 >( nIndex ) >= m_vEntries.size())
280 throw lang::IllegalArgumentException( OUSTR("There is no element at the provided position."
281 "The position exceeds the number of available list entries"),0, 0 );
284 //------------------------------------------------------------------------------
285 rtl::OUString ExtensionBox_Impl::getItemName( sal_Int32 nIndex ) const
287 const ::osl::MutexGuard aGuard( m_entriesMutex );
288 checkIndex( nIndex );
289 return m_vEntries[ nIndex ]->m_sTitle;
292 //------------------------------------------------------------------------------
293 rtl::OUString ExtensionBox_Impl::getItemVersion( sal_Int32 nIndex ) const
295 const ::osl::MutexGuard aGuard( m_entriesMutex );
296 checkIndex( nIndex );
297 return m_vEntries[ nIndex ]->m_sVersion;
300 //------------------------------------------------------------------------------
301 rtl::OUString ExtensionBox_Impl::getItemDescription( sal_Int32 nIndex ) const
303 const ::osl::MutexGuard aGuard( m_entriesMutex );
304 checkIndex( nIndex );
305 return m_vEntries[ nIndex ]->m_sDescription;
308 //------------------------------------------------------------------------------
309 rtl::OUString ExtensionBox_Impl::getItemPublisher( sal_Int32 nIndex ) const
311 const ::osl::MutexGuard aGuard( m_entriesMutex );
312 checkIndex( nIndex );
313 return m_vEntries[ nIndex ]->m_sPublisher;
316 //------------------------------------------------------------------------------
317 rtl::OUString ExtensionBox_Impl::getItemPublisherLink( sal_Int32 nIndex ) const
319 const ::osl::MutexGuard aGuard( m_entriesMutex );
320 checkIndex( nIndex );
321 return m_vEntries[ nIndex ]->m_sPublisherURL;
324 //------------------------------------------------------------------------------
325 void ExtensionBox_Impl::select( sal_Int32 nIndex )
327 const ::osl::MutexGuard aGuard( m_entriesMutex );
328 checkIndex( nIndex );
329 selectEntry( nIndex );
332 //------------------------------------------------------------------------------
333 void ExtensionBox_Impl::select( const rtl::OUString & sName )
335 const ::osl::MutexGuard aGuard( m_entriesMutex );
336 typedef ::std::vector< TEntry_Impl >::const_iterator It;
338 for ( It iIter = m_vEntries.begin(); iIter < m_vEntries.end(); iIter++ )
340 if ( sName.equals( (*iIter)->m_sTitle ) )
342 long nPos = iIter - m_vEntries.begin();
343 selectEntry( nPos );
344 break;
349 //------------------------------------------------------------------------------
350 //------------------------------------------------------------------------------
351 // Title + description
352 void ExtensionBox_Impl::CalcActiveHeight( const long nPos )
354 const ::osl::MutexGuard aGuard( m_entriesMutex );
356 // get title height
357 long aTextHeight;
358 long nIconHeight = 2*TOP_OFFSET + SMALL_ICON_SIZE;
359 long nTitleHeight = 2*TOP_OFFSET + GetTextHeight();
360 if ( nIconHeight < nTitleHeight )
361 aTextHeight = nTitleHeight;
362 else
363 aTextHeight = nIconHeight;
365 // calc description height
366 Size aSize = GetOutputSizePixel();
367 if ( m_bHasScrollBar )
368 aSize.Width() -= m_pScrollBar->GetSizePixel().Width();
370 aSize.Width() -= ICON_OFFSET;
371 aSize.Height() = 10000;
373 rtl::OUString aText( m_vEntries[ nPos ]->m_sErrorText );
374 aText += m_vEntries[ nPos ]->m_sDescription;
376 Rectangle aRect = GetTextRect( Rectangle( Point(), aSize ), aText,
377 TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
378 aTextHeight += aRect.GetHeight();
380 if ( aTextHeight < m_nStdHeight )
381 aTextHeight = m_nStdHeight;
383 m_nActiveHeight = aTextHeight + m_nExtraHeight;
386 //------------------------------------------------------------------------------
387 const Size ExtensionBox_Impl::GetMinOutputSizePixel() const
389 return Size( 200, 80 );
392 //------------------------------------------------------------------------------
393 Rectangle ExtensionBox_Impl::GetEntryRect( const long nPos ) const
395 const ::osl::MutexGuard aGuard( m_entriesMutex );
397 Size aSize( GetOutputSizePixel() );
399 if ( m_bHasScrollBar )
400 aSize.Width() -= m_pScrollBar->GetSizePixel().Width();
402 if ( m_vEntries[ nPos ]->m_bActive )
403 aSize.Height() = m_nActiveHeight;
404 else
405 aSize.Height() = m_nStdHeight;
407 Point aPos( 0, -m_nTopIndex + nPos * m_nStdHeight );
408 if ( m_bHasActive && ( nPos < m_nActive ) )
409 aPos.Y() += m_nActiveHeight - m_nStdHeight;
411 return Rectangle( aPos, aSize );
414 //------------------------------------------------------------------------------
415 void ExtensionBox_Impl::DeleteRemoved()
417 const ::osl::MutexGuard aGuard( m_entriesMutex );
419 m_bInDelete = true;
421 if ( ! m_vRemovedEntries.empty() )
423 typedef std::vector< TEntry_Impl >::iterator ITER;
425 for ( ITER iIndex = m_vRemovedEntries.begin(); iIndex < m_vRemovedEntries.end(); ++iIndex )
427 if ( (*iIndex)->m_pPublisher )
429 delete (*iIndex)->m_pPublisher;
430 (*iIndex)->m_pPublisher = NULL;
434 m_vRemovedEntries.clear();
437 m_bInDelete = false;
440 //------------------------------------------------------------------------------
441 //This function may be called with nPos < 0
442 void ExtensionBox_Impl::selectEntry( const long nPos )
444 //ToDo whe should not use the guard at such a big scope here.
445 //Currently it is used to gard m_vEntries and m_nActive. m_nActive will be
446 //modified in this function.
447 //It would be probably best to always use a copy of m_vEntries
448 //and some other state variables from ExtensionBox_Impl for
449 //the whole painting operation. See issue i86993
450 ::osl::ClearableMutexGuard guard(m_entriesMutex);
452 if ( m_bInCheckMode )
453 return;
455 if ( m_bHasActive )
457 if ( nPos == m_nActive )
458 return;
460 m_bHasActive = false;
461 m_vEntries[ m_nActive ]->m_bActive = false;
464 if ( ( nPos >= 0 ) && ( nPos < (long) m_vEntries.size() ) )
466 m_bHasActive = true;
467 m_nActive = nPos;
468 m_vEntries[ nPos ]->m_bActive = true;
470 if ( IsReallyVisible() )
472 m_bNeedsRecalc = true;
473 m_bAdjustActive = true;
477 if ( IsReallyVisible() )
478 Invalidate();
480 guard.clear();
483 // -----------------------------------------------------------------------
484 void ExtensionBox_Impl::DrawRow( const Rectangle& rRect, const TEntry_Impl pEntry )
486 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
488 if ( pEntry->m_bActive )
489 SetTextColor( rStyleSettings.GetHighlightTextColor() );
490 else if ( ( pEntry->m_eState != REGISTERED ) && ( pEntry->m_eState != NOT_AVAILABLE ) )
491 SetTextColor( rStyleSettings.GetDisableColor() );
492 else if ( IsControlForeground() )
493 SetTextColor( GetControlForeground() );
494 else
495 SetTextColor( rStyleSettings.GetFieldTextColor() );
497 if ( pEntry->m_bActive )
499 SetLineColor();
500 SetFillColor( rStyleSettings.GetHighlightColor() );
501 DrawRect( rRect );
503 else
505 if( IsControlBackground() )
506 SetBackground( GetControlBackground() );
507 else
508 SetBackground( rStyleSettings.GetFieldColor() );
510 SetTextFillColor();
511 Erase( rRect );
514 // Draw extension icon
515 Point aPos( rRect.TopLeft() );
516 aPos += Point( TOP_OFFSET, TOP_OFFSET );
517 Image aImage;
518 if ( ! pEntry->m_aIcon )
519 aImage = isHCMode() ? m_aDefaultImageHC : m_aDefaultImage;
520 else
521 aImage = isHCMode() ? pEntry->m_aIconHC : pEntry->m_aIcon;
522 Size aImageSize = aImage.GetSizePixel();
523 if ( ( aImageSize.Width() <= ICON_HEIGHT ) && ( aImageSize.Height() <= ICON_HEIGHT ) )
524 DrawImage( Point( aPos.X()+((ICON_HEIGHT-aImageSize.Width())/2), aPos.Y()+((ICON_HEIGHT-aImageSize.Height())/2) ), aImage );
525 else
526 DrawImage( aPos, Size( ICON_HEIGHT, ICON_HEIGHT ), aImage );
528 // Setup fonts
529 Font aStdFont( GetFont() );
530 Font aBoldFont( aStdFont );
531 aBoldFont.SetWeight( WEIGHT_BOLD );
532 SetFont( aBoldFont );
533 long aTextHeight = GetTextHeight();
535 // Init publisher link here
536 if ( !pEntry->m_pPublisher && pEntry->m_sPublisher.Len() )
538 pEntry->m_pPublisher = new svt::FixedHyperlink( this );
539 pEntry->m_pPublisher->SetBackground();
540 pEntry->m_pPublisher->SetPaintTransparent( true );
541 pEntry->m_pPublisher->SetURL( pEntry->m_sPublisherURL );
542 pEntry->m_pPublisher->SetDescription( pEntry->m_sPublisher );
543 Size aSize = FixedText::CalcMinimumTextSize( pEntry->m_pPublisher );
544 pEntry->m_pPublisher->SetSizePixel( aSize );
546 if ( m_aClickHdl.IsSet() )
547 pEntry->m_pPublisher->SetClickHdl( m_aClickHdl );
550 // Get max title width
551 long nMaxTitleWidth = rRect.GetWidth() - ICON_OFFSET;
552 nMaxTitleWidth -= ( 2 * SMALL_ICON_SIZE ) + ( 4 * SPACE_BETWEEN );
553 if ( pEntry->m_pPublisher )
555 nMaxTitleWidth -= pEntry->m_pPublisher->GetSizePixel().Width() + (2*SPACE_BETWEEN);
558 long aVersionWidth = GetTextWidth( pEntry->m_sVersion );
559 long aTitleWidth = GetTextWidth( pEntry->m_sTitle ) + (aTextHeight / 3);
561 aPos = rRect.TopLeft() + Point( ICON_OFFSET, TOP_OFFSET );
563 if ( aTitleWidth > nMaxTitleWidth - aVersionWidth )
565 aTitleWidth = nMaxTitleWidth - aVersionWidth - (aTextHeight / 3);
566 String aShortTitle = GetEllipsisString( pEntry->m_sTitle, aTitleWidth );
567 DrawText( aPos, aShortTitle );
568 aTitleWidth += (aTextHeight / 3);
570 else
571 DrawText( aPos, pEntry->m_sTitle );
573 SetFont( aStdFont );
574 DrawText( Point( aPos.X() + aTitleWidth, aPos.Y() ), pEntry->m_sVersion );
576 long nIconHeight = TOP_OFFSET + SMALL_ICON_SIZE;
577 long nTitleHeight = TOP_OFFSET + GetTextHeight();
578 if ( nIconHeight < nTitleHeight )
579 aTextHeight = nTitleHeight;
580 else
581 aTextHeight = nIconHeight;
583 // draw description
584 String sDescription;
585 if ( pEntry->m_sErrorText.Len() )
587 if ( pEntry->m_bActive )
588 sDescription = pEntry->m_sErrorText + OUSTR("\n") + pEntry->m_sDescription;
589 else
590 sDescription = pEntry->m_sErrorText;
592 else
593 sDescription = pEntry->m_sDescription;
595 aPos.Y() += aTextHeight;
596 if ( pEntry->m_bActive )
598 DrawText( Rectangle( aPos.X(), aPos.Y(), rRect.Right(), rRect.Bottom() - m_nExtraHeight ),
599 sDescription, TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
601 else
603 const long nWidth = GetTextWidth( sDescription );
604 if ( nWidth > rRect.GetWidth() - aPos.X() )
605 sDescription = GetEllipsisString( sDescription, rRect.GetWidth() - aPos.X() );
606 DrawText( aPos, sDescription );
609 // Draw publisher link
610 if ( pEntry->m_pPublisher )
612 pEntry->m_pPublisher->Show();
613 aPos = rRect.TopLeft() + Point( ICON_OFFSET + nMaxTitleWidth + (2*SPACE_BETWEEN), TOP_OFFSET );
614 pEntry->m_pPublisher->SetPosPixel( aPos );
617 // Draw status icons
618 if ( pEntry->m_bShared )
620 aPos = rRect.TopRight() + Point( -(RIGHT_ICON_OFFSET + SMALL_ICON_SIZE), TOP_OFFSET );
621 DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), isHCMode() ? m_aLockedImageHC : m_aLockedImage );
623 if ( ( pEntry->m_eState == AMBIGUOUS ) || pEntry->m_bMissingDeps )
625 aPos = rRect.TopRight() + Point( -(RIGHT_ICON_OFFSET + SPACE_BETWEEN + 2*SMALL_ICON_SIZE), TOP_OFFSET );
626 DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), isHCMode() ? m_aWarningImageHC : m_aWarningImage );
629 SetLineColor( Color( COL_LIGHTGRAY ) );
630 DrawLine( rRect.BottomLeft(), rRect.BottomRight() );
633 // -----------------------------------------------------------------------
634 void ExtensionBox_Impl::RecalcAll()
636 if ( m_bHasActive )
637 CalcActiveHeight( m_nActive );
639 SetupScrollBar();
641 if ( m_bHasActive )
643 Rectangle aEntryRect = GetEntryRect( m_nActive );
645 if ( m_bAdjustActive )
647 m_bAdjustActive = false;
649 // If the top of the selected entry isn't visible, make it visible
650 if ( aEntryRect.Top() < 0 )
652 m_nTopIndex += aEntryRect.Top();
653 aEntryRect.Move( 0, -aEntryRect.Top() );
656 // If the bottom of the selected entry isn't visible, make it visible even if now the top
657 // isn't visible any longer ( the buttons are more important )
658 Size aOutputSize = GetOutputSizePixel();
659 if ( aEntryRect.Bottom() > aOutputSize.Height() )
661 m_nTopIndex += ( aEntryRect.Bottom() - aOutputSize.Height() );
662 aEntryRect.Move( 0, -( aEntryRect.Bottom() - aOutputSize.Height() ) );
665 // If there is unused space below the last entry but all entries don't fit into the box,
666 // move the content down to use the whole space
667 const long nTotalHeight = GetTotalHeight();
668 if ( m_bHasScrollBar && ( aOutputSize.Height() + m_nTopIndex > nTotalHeight ) )
670 long nOffset = m_nTopIndex;
671 m_nTopIndex = nTotalHeight - aOutputSize.Height();
672 nOffset -= m_nTopIndex;
673 aEntryRect.Move( 0, nOffset );
676 if ( m_bHasScrollBar )
677 m_pScrollBar->SetThumbPos( m_nTopIndex );
681 m_bNeedsRecalc = false;
684 // -----------------------------------------------------------------------
685 bool ExtensionBox_Impl::HandleTabKey( bool )
687 return false;
690 // -----------------------------------------------------------------------
691 bool ExtensionBox_Impl::HandleCursorKey( USHORT nKeyCode )
693 if ( m_vEntries.empty() )
694 return true;
696 long nSelect = 0;
698 if ( m_bHasActive )
700 long nPageSize = GetOutputSizePixel().Height() / m_nStdHeight;
701 if ( nPageSize < 2 )
702 nPageSize = 2;
704 if ( ( nKeyCode == KEY_DOWN ) || ( nKeyCode == KEY_RIGHT ) )
705 nSelect = m_nActive + 1;
706 else if ( ( nKeyCode == KEY_UP ) || ( nKeyCode == KEY_LEFT ) )
707 nSelect = m_nActive - 1;
708 else if ( nKeyCode == KEY_HOME )
709 nSelect = 0;
710 else if ( nKeyCode == KEY_END )
711 nSelect = m_vEntries.size() - 1;
712 else if ( nKeyCode == KEY_PAGEUP )
713 nSelect = m_nActive - nPageSize + 1;
714 else if ( nKeyCode == KEY_PAGEDOWN )
715 nSelect = m_nActive + nPageSize - 1;
717 else // when there is no selected entry, we will select the first or the last.
719 if ( ( nKeyCode == KEY_DOWN ) || ( nKeyCode == KEY_PAGEDOWN ) || ( nKeyCode == KEY_HOME ) )
720 nSelect = 0;
721 else if ( ( nKeyCode == KEY_UP ) || ( nKeyCode == KEY_PAGEUP ) || ( nKeyCode == KEY_END ) )
722 nSelect = m_vEntries.size() - 1;
725 if ( nSelect < 0 )
726 nSelect = 0;
727 if ( nSelect >= (long) m_vEntries.size() )
728 nSelect = m_vEntries.size() - 1;
730 selectEntry( nSelect );
732 return true;
735 // -----------------------------------------------------------------------
736 void ExtensionBox_Impl::Paint( const Rectangle &/*rPaintRect*/ )
738 if ( !m_bInDelete )
739 DeleteRemoved();
741 if ( m_bNeedsRecalc )
742 RecalcAll();
744 Point aStart( 0, -m_nTopIndex );
745 Size aSize( GetOutputSizePixel() );
747 if ( m_bHasScrollBar )
748 aSize.Width() -= m_pScrollBar->GetSizePixel().Width();
750 const ::osl::MutexGuard aGuard( m_entriesMutex );
752 typedef std::vector< TEntry_Impl >::iterator ITER;
753 for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
755 aSize.Height() = (*iIndex)->m_bActive ? m_nActiveHeight : m_nStdHeight;
756 Rectangle aEntryRect( aStart, aSize );
757 DrawRow( aEntryRect, *iIndex );
758 aStart.Y() += aSize.Height();
762 // -----------------------------------------------------------------------
763 long ExtensionBox_Impl::GetTotalHeight() const
765 long nHeight = m_vEntries.size() * m_nStdHeight;
767 if ( m_bHasActive )
769 nHeight += m_nActiveHeight - m_nStdHeight;
772 return nHeight;
775 // -----------------------------------------------------------------------
776 void ExtensionBox_Impl::SetupScrollBar()
778 const Size aSize = GetOutputSizePixel();
779 const long nScrBarSize = GetSettings().GetStyleSettings().GetScrollBarSize();
780 const long nTotalHeight = GetTotalHeight();
781 const bool bNeedsScrollBar = ( nTotalHeight > aSize.Height() );
783 if ( bNeedsScrollBar )
785 if ( m_nTopIndex + aSize.Height() > nTotalHeight )
786 m_nTopIndex = nTotalHeight - aSize.Height();
788 m_pScrollBar->SetPosSizePixel( Point( aSize.Width() - nScrBarSize, 0 ),
789 Size( nScrBarSize, aSize.Height() ) );
790 m_pScrollBar->SetRangeMax( nTotalHeight );
791 m_pScrollBar->SetVisibleSize( aSize.Height() );
792 m_pScrollBar->SetPageSize( ( aSize.Height() * 4 ) / 5 );
793 m_pScrollBar->SetLineSize( m_nStdHeight );
794 m_pScrollBar->SetThumbPos( m_nTopIndex );
796 if ( !m_bHasScrollBar )
797 m_pScrollBar->Show();
799 else if ( m_bHasScrollBar )
801 m_pScrollBar->Hide();
802 m_nTopIndex = 0;
805 m_bHasScrollBar = bNeedsScrollBar;
808 // -----------------------------------------------------------------------
809 void ExtensionBox_Impl::Resize()
811 RecalcAll();
814 //------------------------------------------------------------------------------
815 long ExtensionBox_Impl::PointToPos( const Point& rPos )
817 long nPos = ( rPos.Y() + m_nTopIndex ) / m_nStdHeight;
819 if ( m_bHasActive && ( nPos > m_nActive ) )
821 if ( rPos.Y() + m_nTopIndex <= m_nActive*m_nStdHeight + m_nActiveHeight )
822 nPos = m_nActive;
823 else
824 nPos = ( rPos.Y() + m_nTopIndex - (m_nActiveHeight - m_nStdHeight) ) / m_nStdHeight;
827 return nPos;
830 //------------------------------------------------------------------------------
831 void ExtensionBox_Impl::MouseButtonDown( const MouseEvent& rMEvt )
833 long nPos = PointToPos( rMEvt.GetPosPixel() );
835 if ( rMEvt.IsLeft() )
837 if ( rMEvt.IsMod1() && m_bHasActive )
838 selectEntry( m_vEntries.size() ); // Selecting an not existing entry will deselect the current one
839 else
840 selectEntry( nPos );
844 //------------------------------------------------------------------------------
845 long ExtensionBox_Impl::Notify( NotifyEvent& rNEvt )
847 if ( !m_bInDelete )
848 DeleteRemoved();
850 bool bHandled = false;
852 if ( rNEvt.GetType() == EVENT_KEYINPUT )
854 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
855 KeyCode aKeyCode = pKEvt->GetKeyCode();
856 USHORT nKeyCode = aKeyCode.GetCode();
858 if ( nKeyCode == KEY_TAB )
859 bHandled = HandleTabKey( aKeyCode.IsShift() );
860 else if ( aKeyCode.GetGroup() == KEYGROUP_CURSOR )
861 bHandled = HandleCursorKey( nKeyCode );
864 if ( rNEvt.GetType() == EVENT_COMMAND )
866 if ( m_bHasScrollBar &&
867 ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) )
869 const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
870 if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
872 long nThumbPos = m_pScrollBar->GetThumbPos();
873 if ( pData->GetDelta() < 0 )
874 m_pScrollBar->DoScroll( nThumbPos + m_nStdHeight );
875 else
876 m_pScrollBar->DoScroll( nThumbPos - m_nStdHeight );
877 bHandled = true;
882 if ( !bHandled )
883 return Control::Notify( rNEvt );
884 else
885 return true;
888 //------------------------------------------------------------------------------
889 bool ExtensionBox_Impl::FindEntryPos( const TEntry_Impl pEntry, const long nStart,
890 const long nEnd, long &nPos )
892 nPos = nStart;
893 if ( nStart > nEnd )
894 return false;
896 StringCompare eCompare;
898 if ( nStart == nEnd )
900 eCompare = pEntry->CompareTo( m_pCollator, m_vEntries[ nStart ] );
901 if ( eCompare == COMPARE_LESS )
902 return false;
903 else if ( eCompare == COMPARE_EQUAL )
905 //Workaround. See i86963.
906 if (pEntry->m_xPackage != m_vEntries[nStart]->m_xPackage)
907 return false;
909 if ( m_bInCheckMode )
910 m_vEntries[ nStart ]->m_bChecked = true;
911 return true;
913 else
915 nPos = nStart + 1;
916 return false;
920 const long nMid = nStart + ( ( nEnd - nStart ) / 2 );
921 eCompare = pEntry->CompareTo( m_pCollator, m_vEntries[ nMid ] );
923 if ( eCompare == COMPARE_LESS )
924 return FindEntryPos( pEntry, nStart, nMid-1, nPos );
925 else if ( eCompare == COMPARE_GREATER )
926 return FindEntryPos( pEntry, nMid+1, nEnd, nPos );
927 else
929 //Workaround.See i86963.
930 if (pEntry->m_xPackage != m_vEntries[nMid]->m_xPackage)
931 return false;
933 if ( m_bInCheckMode )
934 m_vEntries[ nMid ]->m_bChecked = true;
935 nPos = nMid;
936 return true;
940 //------------------------------------------------------------------------------
941 long ExtensionBox_Impl::addEntry( const uno::Reference< deployment::XPackage > &xPackage,
942 const uno::Reference< deployment::XPackageManager > &xPackageManager )
944 long nPos = 0;
945 PackageState eState = m_pManager->getPackageState( xPackage );
947 TEntry_Impl pEntry( new Entry_Impl( xPackage, xPackageManager, eState ) );
948 xPackage->addEventListener( uno::Reference< lang::XEventListener > ( m_xRemoveListener, uno::UNO_QUERY ) );
950 ::osl::ClearableMutexGuard guard(m_entriesMutex);
951 if ( m_vEntries.empty() )
953 pEntry->m_bHasOptions = m_pManager->supportsOptions( xPackage );
954 pEntry->m_bShared = ( m_pManager->getSharedPkgMgr() == xPackageManager );
955 pEntry->m_bNew = m_bInCheckMode;
956 m_vEntries.push_back( pEntry );
958 else
960 if ( !FindEntryPos( pEntry, 0, m_vEntries.size()-1, nPos ) )
962 pEntry->m_bHasOptions = m_pManager->supportsOptions( xPackage );
963 pEntry->m_bShared = ( m_pManager->getSharedPkgMgr() == xPackageManager );
964 pEntry->m_bNew = m_bInCheckMode;
965 m_vEntries.insert( m_vEntries.begin()+nPos, pEntry );
967 else if ( !m_bInCheckMode )
969 OSL_ENSURE( 0, "ExtensionBox_Impl::addEntry(): Will not add duplicate entries" );
972 //access to m_nActive must be guarded
973 if ( !m_bInCheckMode && m_bHasActive && ( m_nActive >= nPos ) )
974 m_nActive += 1;
976 guard.clear();
978 if ( IsReallyVisible() )
979 Invalidate();
981 m_bNeedsRecalc = true;
983 return nPos;
986 //------------------------------------------------------------------------------
987 void ExtensionBox_Impl::updateEntry( const uno::Reference< deployment::XPackage > &xPackage )
989 typedef std::vector< TEntry_Impl >::iterator ITER;
990 for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
992 if ( (*iIndex)->m_xPackage == xPackage )
994 PackageState eState = m_pManager->getPackageState( xPackage );
995 (*iIndex)->m_bHasOptions = m_pManager->supportsOptions( xPackage );
996 (*iIndex)->m_eState = eState;
997 (*iIndex)->m_sTitle = xPackage->getDisplayName();
998 (*iIndex)->m_sVersion = xPackage->getVersion();
999 (*iIndex)->m_sDescription = xPackage->getDescription();
1001 if ( eState == AMBIGUOUS )
1002 (*iIndex)->m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_UNKNOWN_STATUS );
1003 else
1004 (*iIndex)->m_sErrorText = String();
1006 if ( IsReallyVisible() )
1007 Invalidate();
1008 break;
1013 //------------------------------------------------------------------------------
1014 void ExtensionBox_Impl::removeEntry( const uno::Reference< deployment::XPackage > &xPackage )
1016 if ( ! m_bInDelete )
1018 ::osl::ClearableMutexGuard aGuard( m_entriesMutex );
1020 typedef std::vector< TEntry_Impl >::iterator ITER;
1022 for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
1024 if ( (*iIndex)->m_xPackage == xPackage )
1026 long nPos = iIndex - m_vEntries.begin();
1028 // Entries mustn't removed here, because they contain a hyperlink control
1029 // which can only be deleted when the thread has the solar mutex. Therefor
1030 // the entry will be moved into the m_vRemovedEntries list which will be
1031 // cleared on the next paint event
1032 m_vRemovedEntries.push_back( *iIndex );
1033 m_vEntries.erase( iIndex );
1035 m_bNeedsRecalc = true;
1037 if ( IsReallyVisible() )
1038 Invalidate();
1040 if ( m_bHasActive )
1042 if ( nPos < m_nActive )
1043 m_nActive -= 1;
1044 else if ( ( nPos == m_nActive ) &&
1045 ( nPos == (long) m_vEntries.size() ) )
1046 m_nActive -= 1;
1048 m_bHasActive = false;
1049 //clear before calling out of this method
1050 aGuard.clear();
1051 selectEntry( m_nActive );
1053 break;
1059 //------------------------------------------------------------------------------
1060 void ExtensionBox_Impl::RemoveUnlocked()
1062 bool bAllRemoved = false;
1064 while ( ! bAllRemoved )
1066 bAllRemoved = true;
1068 ::osl::ClearableMutexGuard aGuard( m_entriesMutex );
1070 typedef std::vector< TEntry_Impl >::iterator ITER;
1072 for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
1074 if ( !(*iIndex)->m_bLocked )
1076 bAllRemoved = false;
1077 uno::Reference< deployment::XPackage> xPackage = (*iIndex)->m_xPackage;
1078 aGuard.clear();
1079 removeEntry( xPackage );
1080 break;
1086 //------------------------------------------------------------------------------
1087 void ExtensionBox_Impl::prepareChecking( const uno::Reference< deployment::XPackageManager > &xPackageMgr )
1089 m_bInCheckMode = true;
1090 typedef std::vector< TEntry_Impl >::iterator ITER;
1091 for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex )
1093 if ( (*iIndex)->m_xPackageManager == xPackageMgr )
1094 (*iIndex)->m_bChecked = false;
1095 else
1096 (*iIndex)->m_bChecked = true;
1097 (*iIndex)->m_bNew = false;
1101 //------------------------------------------------------------------------------
1102 void ExtensionBox_Impl::checkEntries()
1104 long nNewPos = -1;
1105 long nPos = 0;
1106 bool bNeedsUpdate = false;
1108 ::osl::ClearableMutexGuard guard(m_entriesMutex);
1109 typedef std::vector< TEntry_Impl >::iterator ITER;
1110 ITER iIndex = m_vEntries.begin();
1111 while ( iIndex < m_vEntries.end() )
1113 if ( (*iIndex)->m_bChecked == false )
1115 bNeedsUpdate = true;
1116 nPos = iIndex-m_vEntries.begin();
1117 if ( (*iIndex)->m_bNew )
1119 if ( nNewPos == - 1)
1120 nNewPos = nPos;
1121 if ( nPos <= m_nActive )
1122 m_nActive += 1;
1125 iIndex++;
1127 guard.clear();
1129 m_bInCheckMode = false;
1131 if ( nNewPos != - 1)
1132 selectEntry( nNewPos );
1134 if ( bNeedsUpdate )
1136 m_bNeedsRecalc = true;
1137 if ( IsReallyVisible() )
1138 Invalidate();
1141 //------------------------------------------------------------------------------
1142 bool ExtensionBox_Impl::isHCMode()
1144 return (bool)GetDisplayBackground().GetColor().IsDark();
1147 //------------------------------------------------------------------------------
1148 void ExtensionBox_Impl::SetScrollHdl( const Link& rLink )
1150 if ( m_pScrollBar )
1151 m_pScrollBar->SetScrollHdl( rLink );
1154 // -----------------------------------------------------------------------
1155 void ExtensionBox_Impl::DoScroll( long nDelta )
1157 m_nTopIndex += nDelta;
1158 Point aNewSBPt( m_pScrollBar->GetPosPixel() );
1160 Rectangle aScrRect( Point(), GetOutputSizePixel() );
1161 aScrRect.Right() -= m_pScrollBar->GetSizePixel().Width();
1162 Scroll( 0, -nDelta, aScrRect );
1164 m_pScrollBar->SetPosPixel( aNewSBPt );
1167 // -----------------------------------------------------------------------
1168 IMPL_LINK( ExtensionBox_Impl, ScrollHdl, ScrollBar*, pScrBar )
1170 DoScroll( pScrBar->GetDelta() );
1172 return 1;
1175 } //namespace dp_gui