bump product version to 5.0.4.1
[LibreOffice.git] / extensions / source / update / ui / updatecheckui.cxx
blob565a33e5282593bcb8bede51466708e1d5e0e1fc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <list>
23 #include <cppuhelper/implbase3.hxx>
24 #include <cppuhelper/implementationentry.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <com/sun/star/lang/XServiceInfo.hpp>
27 #include <com/sun/star/lang/XComponent.hpp>
28 #include <com/sun/star/document/XDocumentEventListener.hpp>
29 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
32 #include <com/sun/star/graphic/GraphicProvider.hpp>
33 #include <com/sun/star/graphic/XGraphicProvider.hpp>
34 #include <com/sun/star/task/XJob.hpp>
36 #include <comphelper/processfactory.hxx>
38 #include <osl/mutex.hxx>
40 #include <vcl/window.hxx>
41 #include <vcl/floatwin.hxx>
42 #include <vcl/timer.hxx>
43 #include <vcl/idle.hxx>
44 #include <vcl/menu.hxx>
45 #include <vcl/outdev.hxx>
46 #include <vcl/layout.hxx>
47 #include <vcl/msgbox.hxx>
48 #include <vcl/lineinfo.hxx>
49 #include <vcl/button.hxx>
50 #include <vcl/settings.hxx>
51 #include <vcl/svapp.hxx>
52 #include <sfx2/sfx.hrc>
53 #include "rtl/ustrbuf.hxx"
55 #include "updatecheckui.hrc"
57 #define STR_NO_WEBBROWSER_FOUND (RID_SFX_APP_START + 7)
59 #define PROPERTY_TITLE "BubbleHeading"
60 #define PROPERTY_TEXT "BubbleText"
61 #define PROPERTY_IMAGE "BubbleImageURL"
62 #define PROPERTY_SHOW_BUBBLE "BubbleVisible"
63 #define PROPERTY_CLICK_HDL "MenuClickHDL"
64 #define PROPERTY_SHOW_MENUICON "MenuIconVisible"
66 using namespace ::com::sun::star;
70 static uno::Sequence< OUString > getServiceNames()
72 uno::Sequence< OUString > aServiceList(1);
73 aServiceList[0] = "com.sun.star.setup.UpdateCheckUI";
74 return aServiceList;
79 static OUString getImplementationName()
81 return OUString("vnd.sun.UpdateCheckUI");
86 namespace
90 class BubbleWindow : public FloatingWindow
92 Point maTipPos;
93 vcl::Region maBounds;
94 Polygon maRectPoly;
95 Polygon maTriPoly;
96 OUString maBubbleTitle;
97 OUString maBubbleText;
98 Image maBubbleImage;
99 Size maMaxTextSize;
100 Rectangle maTitleRect;
101 Rectangle maTextRect;
102 long mnTipOffset;
104 private:
105 void RecalcTextRects();
107 public:
108 BubbleWindow( vcl::Window* pParent, const OUString& rTitle,
109 const OUString& rText, const Image& rImage );
110 virtual ~BubbleWindow();
112 virtual void MouseButtonDown( const MouseEvent& rMEvt ) SAL_OVERRIDE;
113 virtual void Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect) SAL_OVERRIDE;
114 void Resize() SAL_OVERRIDE;
115 void Show( bool bVisible = true, sal_uInt16 nFlags = SHOW_NOACTIVATE );
116 void SetTipPosPixel( const Point& rTipPos ) { maTipPos = rTipPos; }
117 void SetTitleAndText( const OUString& rTitle, const OUString& rText,
118 const Image& rImage );
122 class UpdateCheckUI : public ::cppu::WeakImplHelper3
123 < lang::XServiceInfo, document::XDocumentEventListener, beans::XPropertySet >
125 uno::Reference< uno::XComponentContext > m_xContext;
126 uno::Reference< task::XJob > mrJob;
127 OUString maBubbleTitle;
128 OUString maBubbleText;
129 OUString maBubbleImageURL;
130 Image maBubbleImage;
131 VclPtr<BubbleWindow> mpBubbleWin;
132 VclPtr<SystemWindow> mpIconSysWin;
133 MenuBar* mpIconMBar;
134 ResMgr* mpUpdResMgr;
135 ResMgr* mpSfxResMgr;
136 Idle maWaitIdle;
137 Timer maTimeoutTimer;
138 Link<> maWindowEventHdl;
139 Link<> maApplicationEventHdl;
140 bool mbShowBubble;
141 bool mbShowMenuIcon;
142 bool mbBubbleChanged;
143 sal_uInt16 mnIconID;
145 private:
146 DECL_LINK(ClickHdl, void *);
147 DECL_LINK( HighlightHdl, MenuBar::MenuBarButtonCallbackArg* );
148 DECL_LINK_TYPED(WaitTimeOutHdl, Idle *, void);
149 DECL_LINK_TYPED(TimeOutHdl, Timer *, void);
150 DECL_LINK(UserEventHdl, void *);
151 DECL_LINK( WindowEventHdl, VclWindowEvent* );
152 DECL_LINK( ApplicationEventHdl, VclSimpleEvent* );
154 BubbleWindow* GetBubbleWindow();
155 void RemoveBubbleWindow( bool bRemoveIcon );
156 Image GetMenuBarIcon( MenuBar* pMBar );
157 void AddMenuBarIcon( SystemWindow* pSysWin, bool bAddEventHdl );
158 Image GetBubbleImage( OUString &rURL );
160 public:
161 UpdateCheckUI(const uno::Reference<uno::XComponentContext>&);
162 virtual ~UpdateCheckUI();
164 // XServiceInfo
165 virtual OUString SAL_CALL getImplementationName()
166 throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
167 virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName)
168 throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
169 virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames()
170 throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
172 // XDocumentEventListener
173 virtual void SAL_CALL documentEventOccured(const document::DocumentEvent& Event)
174 throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
175 virtual void SAL_CALL disposing(const lang::EventObject& Event)
176 throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
178 //XPropertySet
179 virtual uno::Reference< beans::XPropertySetInfo > SAL_CALL getPropertySetInfo()
180 throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
181 virtual void SAL_CALL setPropertyValue(const OUString& PropertyName, const uno::Any& aValue)
182 throw( beans::UnknownPropertyException, beans::PropertyVetoException,
183 lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException, std::exception ) SAL_OVERRIDE;
184 virtual uno::Any SAL_CALL getPropertyValue(const OUString& PropertyName)
185 throw ( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException, std::exception ) SAL_OVERRIDE;
186 virtual void SAL_CALL addPropertyChangeListener(const OUString& PropertyName,
187 const uno::Reference< beans::XPropertyChangeListener > & aListener)
188 throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException, std::exception ) SAL_OVERRIDE;
189 virtual void SAL_CALL removePropertyChangeListener(const OUString& PropertyName,
190 const uno::Reference< beans::XPropertyChangeListener > & aListener)
191 throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException, std::exception ) SAL_OVERRIDE;
192 virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName,
193 const uno::Reference< beans::XVetoableChangeListener > & aListener)
194 throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException, std::exception ) SAL_OVERRIDE;
195 virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName,
196 const uno::Reference< beans::XVetoableChangeListener > & aListener)
197 throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException, std::exception ) SAL_OVERRIDE;
201 UpdateCheckUI::UpdateCheckUI(const uno::Reference<uno::XComponentContext>& xContext) :
202 m_xContext(xContext)
203 , mpIconMBar( NULL )
204 , mbShowBubble( false )
205 , mbShowMenuIcon( false )
206 , mbBubbleChanged( false )
207 , mnIconID( 0 )
209 mpUpdResMgr = ResMgr::CreateResMgr( "updchk" );
210 mpSfxResMgr = ResMgr::CreateResMgr( "sfx" );
212 maBubbleImage = GetBubbleImage( maBubbleImageURL );
214 maWaitIdle.SetPriority( SchedulerPriority::LOWEST );
215 maWaitIdle.SetIdleHdl( LINK( this, UpdateCheckUI, WaitTimeOutHdl ) );
217 maTimeoutTimer.SetTimeout( 10000 );
218 maTimeoutTimer.SetTimeoutHdl( LINK( this, UpdateCheckUI, TimeOutHdl ) );
220 uno::Reference< document::XDocumentEventBroadcaster > xBroadcaster( frame::theGlobalEventBroadcaster::get(m_xContext) );
221 xBroadcaster->addDocumentEventListener( this );
223 maWindowEventHdl = LINK( this, UpdateCheckUI, WindowEventHdl );
224 maApplicationEventHdl = LINK( this, UpdateCheckUI, ApplicationEventHdl );
225 Application::AddEventListener( maApplicationEventHdl );
229 UpdateCheckUI::~UpdateCheckUI()
231 Application::RemoveEventListener( maApplicationEventHdl );
232 RemoveBubbleWindow( true );
233 delete mpUpdResMgr;
234 delete mpSfxResMgr;
238 OUString SAL_CALL
239 UpdateCheckUI::getImplementationName() throw (uno::RuntimeException, std::exception)
241 return ::getImplementationName();
245 uno::Sequence< OUString > SAL_CALL
246 UpdateCheckUI::getSupportedServiceNames() throw (uno::RuntimeException, std::exception)
248 return ::getServiceNames();
251 sal_Bool SAL_CALL
252 UpdateCheckUI::supportsService( OUString const & serviceName ) throw (uno::RuntimeException, std::exception)
254 return cppu::supportsService(this, serviceName);
258 Image UpdateCheckUI::GetMenuBarIcon( MenuBar* pMBar )
260 sal_uInt32 nResID;
261 vcl::Window *pMBarWin = pMBar->GetWindow();
262 sal_uInt32 nMBarHeight = 20;
264 if ( pMBarWin )
265 nMBarHeight = pMBarWin->GetOutputSizePixel().getHeight();
267 if ( nMBarHeight >= 35 )
268 nResID = RID_UPDATE_AVAILABLE_26;
269 else
270 nResID = RID_UPDATE_AVAILABLE_16;
272 return Image( ResId( nResID, *mpUpdResMgr ) );
276 Image UpdateCheckUI::GetBubbleImage( OUString &rURL )
278 Image aImage;
280 if ( !maBubbleImageURL.isEmpty() )
282 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
284 if( !xContext.is() )
285 throw uno::RuntimeException(
286 "UpdateCheckUI: unable to obtain service manager from component context" );
290 uno::Reference< graphic::XGraphicProvider > xGraphProvider(graphic::GraphicProvider::create(xContext));
291 uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
292 aMediaProps[0].Name = "URL";
293 aMediaProps[0].Value <<= rURL;
295 uno::Reference< graphic::XGraphic > xGraphic = xGraphProvider->queryGraphic( aMediaProps );
296 if ( xGraphic.is() )
298 aImage = Image( xGraphic );
301 catch( const uno::Exception& )
306 if ( aImage.GetSizePixel().Width() == 0 )
307 aImage = InfoBox::GetStandardImage();
309 return aImage;
313 void UpdateCheckUI::AddMenuBarIcon( SystemWindow *pSysWin, bool bAddEventHdl )
315 if ( ! mbShowMenuIcon )
316 return;
318 SolarMutexGuard aGuard;
320 MenuBar *pActiveMBar = pSysWin->GetMenuBar();
321 if ( ( pSysWin != mpIconSysWin ) || ( pActiveMBar != mpIconMBar ) )
323 if ( bAddEventHdl && mpIconSysWin )
324 mpIconSysWin->RemoveEventListener( maWindowEventHdl );
326 RemoveBubbleWindow( true );
328 if ( pActiveMBar )
330 OUStringBuffer aBuf;
331 if( !maBubbleTitle.isEmpty() )
332 aBuf.append( maBubbleTitle );
333 if( !maBubbleText.isEmpty() )
335 if( !maBubbleTitle.isEmpty() )
336 aBuf.appendAscii( "\n\n" );
337 aBuf.append( maBubbleText );
340 Image aImage = GetMenuBarIcon( pActiveMBar );
341 mnIconID = pActiveMBar->AddMenuBarButton( aImage,
342 LINK( this, UpdateCheckUI, ClickHdl ),
343 aBuf.makeStringAndClear()
345 pActiveMBar->SetMenuBarButtonHighlightHdl( mnIconID,
346 LINK( this, UpdateCheckUI, HighlightHdl ) );
348 mpIconMBar = pActiveMBar;
349 mpIconSysWin = pSysWin;
350 if ( bAddEventHdl && mpIconSysWin )
351 mpIconSysWin->AddEventListener( maWindowEventHdl );
354 if ( mbShowBubble && pActiveMBar )
356 mpBubbleWin = GetBubbleWindow();
357 if ( mpBubbleWin )
359 mpBubbleWin->Show( true );
360 maTimeoutTimer.Start();
362 mbShowBubble = false;
367 void SAL_CALL UpdateCheckUI::documentEventOccured(const document::DocumentEvent& rEvent)
368 throw (uno::RuntimeException, std::exception)
370 SolarMutexGuard aGuard;
372 if( rEvent.EventName == "OnPrepareViewClosing" )
374 RemoveBubbleWindow( true );
379 void SAL_CALL UpdateCheckUI::disposing(const lang::EventObject&)
380 throw (uno::RuntimeException, std::exception)
385 uno::Reference< beans::XPropertySetInfo > UpdateCheckUI::getPropertySetInfo()
386 throw ( uno::RuntimeException, std::exception )
388 return NULL;
392 void UpdateCheckUI::setPropertyValue(const OUString& rPropertyName,
393 const uno::Any& rValue)
394 throw( beans::UnknownPropertyException, beans::PropertyVetoException,
395 lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException, std::exception)
397 SolarMutexGuard aGuard;
399 OUString aString;
401 if( rPropertyName == PROPERTY_TITLE ) {
402 rValue >>= aString;
403 if ( aString != maBubbleTitle ) {
404 maBubbleTitle = aString;
405 mbBubbleChanged = true;
408 else if( rPropertyName == PROPERTY_TEXT ) {
409 rValue >>= aString;
410 if ( aString != maBubbleText ) {
411 maBubbleText = aString;
412 mbBubbleChanged = true;
415 else if( rPropertyName == PROPERTY_IMAGE ) {
416 rValue >>= aString;
417 if ( aString != maBubbleImageURL ) {
418 maBubbleImageURL = aString;
419 maBubbleImage = GetBubbleImage( maBubbleImageURL );
420 mbBubbleChanged = true;
423 else if( rPropertyName == PROPERTY_SHOW_BUBBLE ) {
424 rValue >>= mbShowBubble;
425 if ( mbShowBubble )
426 Application::PostUserEvent( LINK( this, UpdateCheckUI, UserEventHdl ) );
427 else if ( mpBubbleWin )
428 mpBubbleWin->Show( false );
430 else if( rPropertyName == PROPERTY_CLICK_HDL ) {
431 uno::Reference< task::XJob > aJob;
432 rValue >>= aJob;
433 if ( aJob.is() )
434 mrJob = aJob;
435 else
436 throw lang::IllegalArgumentException();
438 else if (rPropertyName == PROPERTY_SHOW_MENUICON ) {
439 bool bShowMenuIcon = false;
440 rValue >>= bShowMenuIcon;
441 if ( bShowMenuIcon != mbShowMenuIcon )
443 mbShowMenuIcon = bShowMenuIcon;
444 if ( bShowMenuIcon )
445 Application::PostUserEvent( LINK( this, UpdateCheckUI, UserEventHdl ) );
446 else
447 RemoveBubbleWindow( true );
450 else
451 throw beans::UnknownPropertyException();
453 if ( mbBubbleChanged && mpBubbleWin )
454 mpBubbleWin->Show( false );
458 uno::Any UpdateCheckUI::getPropertyValue(const OUString& rPropertyName)
459 throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException, std::exception )
461 SolarMutexGuard aGuard;
463 uno::Any aRet;
465 if( rPropertyName == PROPERTY_TITLE )
466 aRet = uno::makeAny( maBubbleTitle );
467 else if( rPropertyName == PROPERTY_TEXT )
468 aRet = uno::makeAny( maBubbleText );
469 else if( rPropertyName == PROPERTY_SHOW_BUBBLE )
470 aRet = uno::makeAny( mbShowBubble );
471 else if( rPropertyName == PROPERTY_IMAGE )
472 aRet = uno::makeAny( maBubbleImageURL );
473 else if( rPropertyName == PROPERTY_CLICK_HDL )
474 aRet = uno::makeAny( mrJob );
475 else if( rPropertyName == PROPERTY_SHOW_MENUICON )
476 aRet = uno::makeAny( mbShowMenuIcon );
477 else
478 throw beans::UnknownPropertyException();
480 return aRet;
484 void UpdateCheckUI::addPropertyChangeListener( const OUString& /*aPropertyName*/,
485 const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
486 throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException, std::exception )
488 //no bound properties
492 void UpdateCheckUI::removePropertyChangeListener( const OUString& /*aPropertyName*/,
493 const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
494 throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException, std::exception )
496 //no bound properties
500 void UpdateCheckUI::addVetoableChangeListener( const OUString& /*aPropertyName*/,
501 const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
502 throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException, std::exception )
504 //no vetoable properties
508 void UpdateCheckUI::removeVetoableChangeListener( const OUString& /*aPropertyName*/,
509 const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
510 throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException, std::exception )
512 //no vetoable properties
519 BubbleWindow * UpdateCheckUI::GetBubbleWindow()
521 if ( !mpIconSysWin )
522 return NULL;
524 Rectangle aIconRect = mpIconMBar->GetMenuBarButtonRectPixel( mnIconID );
525 if( aIconRect.IsEmpty() )
526 return NULL;
528 BubbleWindow* pBubbleWin = mpBubbleWin;
530 if ( !pBubbleWin ) {
531 pBubbleWin = new BubbleWindow( mpIconSysWin, maBubbleTitle,
532 maBubbleText, maBubbleImage );
533 mbBubbleChanged = false;
535 else if ( mbBubbleChanged ) {
536 pBubbleWin->SetTitleAndText( maBubbleTitle, maBubbleText,
537 maBubbleImage );
538 mbBubbleChanged = false;
541 Point aWinPos = aIconRect.BottomCenter();
543 pBubbleWin->SetTipPosPixel( aWinPos );
545 return pBubbleWin;
549 void UpdateCheckUI::RemoveBubbleWindow( bool bRemoveIcon )
551 SolarMutexGuard aGuard;
553 maWaitIdle.Stop();
554 maTimeoutTimer.Stop();
556 if ( mpBubbleWin )
558 mpBubbleWin.disposeAndClear();
561 if ( bRemoveIcon )
563 try {
564 if ( mpIconMBar && ( mnIconID != 0 ) )
566 mpIconMBar->RemoveMenuBarButton( mnIconID );
567 mpIconMBar = NULL;
568 mnIconID = 0;
571 catch ( ... ) {
572 mpIconMBar = NULL;
573 mnIconID = 0;
576 mpIconSysWin = NULL;
581 IMPL_LINK_NOARG(UpdateCheckUI, ClickHdl)
583 SolarMutexGuard aGuard;
585 maWaitIdle.Stop();
586 if ( mpBubbleWin )
587 mpBubbleWin->Show( false );
589 if ( mrJob.is() )
591 try {
592 uno::Sequence<beans::NamedValue> aEmpty;
593 mrJob->execute( aEmpty );
595 catch(const uno::Exception&) {
596 ScopedVclPtrInstance<MessageDialog>::Create( nullptr, ResId( STR_NO_WEBBROWSER_FOUND, *mpSfxResMgr ))->Execute();
600 return 0;
604 IMPL_LINK( UpdateCheckUI, HighlightHdl, MenuBar::MenuBarButtonCallbackArg*, pData )
606 if ( pData->bHighlight )
607 maWaitIdle.Start();
608 else
609 RemoveBubbleWindow( false );
611 return 0;
615 IMPL_LINK_NOARG_TYPED(UpdateCheckUI, WaitTimeOutHdl, Idle *, void)
617 SolarMutexGuard aGuard;
619 mpBubbleWin = GetBubbleWindow();
621 if ( mpBubbleWin )
623 mpBubbleWin->Show();
628 IMPL_LINK_NOARG_TYPED(UpdateCheckUI, TimeOutHdl, Timer *, void)
630 RemoveBubbleWindow( false );
634 IMPL_LINK_NOARG(UpdateCheckUI, UserEventHdl)
636 SolarMutexGuard aGuard;
638 vcl::Window *pTopWin = Application::GetFirstTopLevelWindow();
639 vcl::Window *pActiveWin = Application::GetActiveTopWindow();
640 SystemWindow *pActiveSysWin = NULL;
642 vcl::Window *pBubbleWin = NULL;
643 if ( mpBubbleWin )
644 pBubbleWin = mpBubbleWin;
646 if ( pActiveWin && ( pActiveWin != pBubbleWin ) && pActiveWin->IsTopWindow() )
647 pActiveSysWin = pActiveWin->GetSystemWindow();
649 if ( pActiveWin == pBubbleWin )
650 pActiveSysWin = NULL;
652 while ( !pActiveSysWin && pTopWin )
654 if ( ( pTopWin != pBubbleWin ) && pTopWin->IsTopWindow() )
655 pActiveSysWin = pTopWin->GetSystemWindow();
656 if ( !pActiveSysWin )
657 pTopWin = Application::GetNextTopLevelWindow( pTopWin );
660 if ( pActiveSysWin )
661 AddMenuBarIcon( pActiveSysWin, true );
663 return 0;
667 IMPL_LINK( UpdateCheckUI, WindowEventHdl, VclWindowEvent*, pEvent )
669 sal_uLong nEventID = pEvent->GetId();
671 if ( VCLEVENT_OBJECT_DYING == nEventID )
673 SolarMutexGuard aGuard;
674 if ( mpIconSysWin == pEvent->GetWindow() )
676 mpIconSysWin->RemoveEventListener( maWindowEventHdl );
677 RemoveBubbleWindow( true );
680 else if ( VCLEVENT_WINDOW_MENUBARADDED == nEventID )
682 SolarMutexGuard aGuard;
683 vcl::Window *pWindow = pEvent->GetWindow();
684 if ( pWindow )
686 SystemWindow *pSysWin = pWindow->GetSystemWindow();
687 if ( pSysWin )
689 AddMenuBarIcon( pSysWin, false );
693 else if ( VCLEVENT_WINDOW_MENUBARREMOVED == nEventID )
695 SolarMutexGuard aGuard;
696 MenuBar *pMBar = static_cast<MenuBar*>(pEvent->GetData());
697 if ( pMBar && ( pMBar == mpIconMBar ) )
698 RemoveBubbleWindow( true );
700 else if ( ( nEventID == VCLEVENT_WINDOW_MOVE ) ||
701 ( nEventID == VCLEVENT_WINDOW_RESIZE ) )
703 SolarMutexGuard aGuard;
704 if ( ( mpIconSysWin == pEvent->GetWindow() ) &&
705 mpBubbleWin && ( mpIconMBar != NULL ) )
707 Rectangle aIconRect = mpIconMBar->GetMenuBarButtonRectPixel( mnIconID );
708 Point aWinPos = aIconRect.BottomCenter();
709 mpBubbleWin->SetTipPosPixel( aWinPos );
710 if ( mpBubbleWin->IsVisible() )
711 mpBubbleWin->Show(); // This will recalc the screen position of the bubble
715 return 0;
719 IMPL_LINK( UpdateCheckUI, ApplicationEventHdl, VclSimpleEvent *, pEvent)
721 switch (pEvent->GetId())
723 case VCLEVENT_WINDOW_SHOW:
724 case VCLEVENT_WINDOW_ACTIVATE:
725 case VCLEVENT_WINDOW_GETFOCUS: {
726 SolarMutexGuard aGuard;
728 vcl::Window *pWindow = static_cast< VclWindowEvent * >(pEvent)->GetWindow();
729 if ( pWindow && pWindow->IsTopWindow() )
731 SystemWindow *pSysWin = pWindow->GetSystemWindow();
732 MenuBar *pMBar = pSysWin ? pSysWin->GetMenuBar() : NULL;
733 if (pMBar)
735 AddMenuBarIcon( pSysWin, true );
738 break;
741 return 0;
747 #define TIP_HEIGHT 15
748 #define TIP_WIDTH 7
749 #define TIP_RIGHT_OFFSET 18
750 #define BUBBLE_BORDER 10
751 #define TEXT_MAX_WIDTH 300
752 #define TEXT_MAX_HEIGHT 200
755 BubbleWindow::BubbleWindow( vcl::Window* pParent, const OUString& rTitle,
756 const OUString& rText, const Image& rImage )
757 : FloatingWindow( pParent, WB_SYSTEMWINDOW
758 | WB_OWNERDRAWDECORATION
759 | WB_NOBORDER
761 , maBubbleTitle( rTitle )
762 , maBubbleText( rText )
763 , maBubbleImage( rImage )
764 , maMaxTextSize( TEXT_MAX_WIDTH, TEXT_MAX_HEIGHT )
765 , mnTipOffset( 0 )
767 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetHelpColor() ) );
771 BubbleWindow::~BubbleWindow()
776 void BubbleWindow::Resize()
778 SolarMutexGuard aGuard;
780 FloatingWindow::Resize();
782 Size aSize = GetSizePixel();
784 if ( ( aSize.Height() < 20 ) || ( aSize.Width() < 60 ) )
785 return;
787 Rectangle aRect( 0, TIP_HEIGHT, aSize.Width(), aSize.Height() - TIP_HEIGHT );
788 maRectPoly = Polygon( aRect, 6, 6 );
789 vcl::Region aRegion( maRectPoly );
790 long nTipOffset = aSize.Width() - TIP_RIGHT_OFFSET + mnTipOffset;
792 Point aPointArr[4];
793 aPointArr[0] = Point( nTipOffset, TIP_HEIGHT );
794 aPointArr[1] = Point( nTipOffset, 0 );
795 aPointArr[2] = Point( nTipOffset + TIP_WIDTH , TIP_HEIGHT );
796 aPointArr[3] = Point( nTipOffset, TIP_HEIGHT );
797 maTriPoly = Polygon( 4, aPointArr );
798 vcl::Region aTriRegion( maTriPoly );
800 aRegion.Union( aTriRegion);
801 maBounds = aRegion;
803 SetWindowRegionPixel( maBounds );
807 void BubbleWindow::SetTitleAndText( const OUString& rTitle,
808 const OUString& rText,
809 const Image& rImage )
811 maBubbleTitle = rTitle;
812 maBubbleText = rText;
813 maBubbleImage = rImage;
815 Resize();
819 void BubbleWindow::Paint(vcl::RenderContext& /*rRenderContext*/, const Rectangle& /*rRect*/)
821 SolarMutexGuard aGuard;
823 LineInfo aThickLine( LINE_SOLID, 2 );
825 DrawPolyLine( maRectPoly, aThickLine );
826 DrawPolyLine( maTriPoly );
828 Color aOldLine = GetLineColor();
829 Size aSize = GetSizePixel();
830 long nTipOffset = aSize.Width() - TIP_RIGHT_OFFSET + mnTipOffset;
832 SetLineColor( GetSettings().GetStyleSettings().GetHelpColor() );
833 DrawLine( Point( nTipOffset+2, TIP_HEIGHT ),
834 Point( nTipOffset + TIP_WIDTH -1 , TIP_HEIGHT ),
835 aThickLine );
836 SetLineColor( aOldLine );
838 //Image aImage = InfoBox::GetStandardImage();
839 Size aImgSize = maBubbleImage.GetSizePixel();
841 DrawImage( Point( BUBBLE_BORDER, BUBBLE_BORDER + TIP_HEIGHT ), maBubbleImage );
843 vcl::Font aOldFont = GetFont();
844 vcl::Font aBoldFont = aOldFont;
845 aBoldFont.SetWeight( WEIGHT_BOLD );
847 SetFont( aBoldFont );
848 Rectangle aTitleRect = maTitleRect;
849 aTitleRect.Move( aImgSize.Width(), 0 );
850 DrawText( aTitleRect, maBubbleTitle, DrawTextFlags::MultiLine | DrawTextFlags::WordBreak );
852 SetFont( aOldFont );
853 Rectangle aTextRect = maTextRect;
854 aTextRect.Move( aImgSize.Width(), 0 );
855 DrawText( aTextRect, maBubbleText, DrawTextFlags::MultiLine | DrawTextFlags::WordBreak );
859 void BubbleWindow::MouseButtonDown( const MouseEvent& )
861 Show( false );
865 void BubbleWindow::Show( bool bVisible, sal_uInt16 nFlags )
867 SolarMutexGuard aGuard;
869 if ( !bVisible )
871 FloatingWindow::Show( bVisible );
872 return;
875 // don't show bubbles without a text
876 if ( ( maBubbleTitle.isEmpty() ) && ( maBubbleText.isEmpty() ) )
877 return;
879 Size aWindowSize = GetSizePixel();
881 // Image aImage = InfoBox::GetStandardImage();
882 Size aImgSize = maBubbleImage.GetSizePixel();
884 RecalcTextRects();
886 aWindowSize.setHeight( maTitleRect.GetHeight() * 7 / 4+ maTextRect.GetHeight() +
887 3 * BUBBLE_BORDER + TIP_HEIGHT );
889 if ( maTitleRect.GetWidth() > maTextRect.GetWidth() )
890 aWindowSize.setWidth( maTitleRect.GetWidth() );
891 else
892 aWindowSize.setWidth( maTextRect.GetWidth() );
894 aWindowSize.setWidth( aWindowSize.Width() + 3 * BUBBLE_BORDER + aImgSize.Width() );
896 if ( aWindowSize.Height() < aImgSize.Height() + TIP_HEIGHT + 2 * BUBBLE_BORDER )
897 aWindowSize.setHeight( aImgSize.Height() + TIP_HEIGHT + 2 * BUBBLE_BORDER );
899 Point aPos;
900 aPos.X() = maTipPos.X() - aWindowSize.Width() + TIP_RIGHT_OFFSET;
901 aPos.Y() = maTipPos.Y();
902 Point aScreenPos = GetParent()->OutputToAbsoluteScreenPixel( aPos );
903 if ( aScreenPos.X() < 0 )
905 mnTipOffset = aScreenPos.X();
906 aPos.X() -= mnTipOffset;
908 SetPosSizePixel( aPos, aWindowSize );
910 FloatingWindow::Show( bVisible, nFlags );
914 void BubbleWindow::RecalcTextRects()
916 Size aTotalSize;
917 bool bFinished = false;
918 vcl::Font aOldFont = GetFont();
919 vcl::Font aBoldFont = aOldFont;
921 aBoldFont.SetWeight( WEIGHT_BOLD );
923 while ( !bFinished )
925 SetFont( aBoldFont );
927 maTitleRect = GetTextRect( Rectangle( Point( 0, 0 ), maMaxTextSize ),
928 maBubbleTitle,
929 DrawTextFlags::MultiLine | DrawTextFlags::WordBreak );
931 SetFont( aOldFont );
932 maTextRect = GetTextRect( Rectangle( Point( 0, 0 ), maMaxTextSize ),
933 maBubbleText,
934 DrawTextFlags::MultiLine | DrawTextFlags::WordBreak );
936 if ( maTextRect.GetHeight() < 10 )
937 maTextRect.setHeight( 10 );
939 aTotalSize.setHeight( maTitleRect.GetHeight() +
940 aBoldFont.GetHeight() * 3 / 4 +
941 maTextRect.GetHeight() +
942 3 * BUBBLE_BORDER + TIP_HEIGHT );
943 if ( aTotalSize.Height() > maMaxTextSize.Height() )
945 maMaxTextSize.Width() = maMaxTextSize.Width() * 3 / 2;
946 maMaxTextSize.Height() = maMaxTextSize.Height() * 3 / 2;
948 else
949 bFinished = true;
951 maTitleRect.Move( 2*BUBBLE_BORDER, BUBBLE_BORDER + TIP_HEIGHT );
952 maTextRect.Move( 2*BUBBLE_BORDER, BUBBLE_BORDER + TIP_HEIGHT + maTitleRect.GetHeight() + aBoldFont.GetHeight() * 3 / 4 );
958 } // anonymous namespace
962 static uno::Reference<uno::XInterface> SAL_CALL
963 createInstance(const uno::Reference<uno::XComponentContext>& xContext)
965 return *new UpdateCheckUI(xContext);
970 static const cppu::ImplementationEntry kImplementations_entries[] =
973 createInstance,
974 getImplementationName,
975 getServiceNames,
976 cppu::createSingleComponentFactory,
977 NULL,
980 { NULL, NULL, NULL, NULL, NULL, 0 }
985 extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL updchkui_component_getFactory(const sal_Char *pszImplementationName, void *pServiceManager, void *pRegistryKey)
987 return cppu::component_getFactoryHelper(
988 pszImplementationName,
989 pServiceManager,
990 pRegistryKey,
991 kImplementations_entries) ;
994 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */