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_extensions.hxx"
30 
31 #include <list>
32 
33 #include <cppuhelper/implbase3.hxx>
34 #include <cppuhelper/implementationentry.hxx>
35 #include <com/sun/star/lang/XServiceInfo.hpp>
36 #include <com/sun/star/lang/XComponent.hpp>
37 #include <com/sun/star/document/XEventListener.hpp>
38 #include <com/sun/star/document/XEventBroadcaster.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/graphic/XGraphicProvider.hpp>
41 #include <com/sun/star/task/XJob.hpp>
42 
43 #include <comphelper/processfactory.hxx>
44 
45 #include <vos/mutex.hxx>
46 #include <osl/mutex.hxx>
47 
48 #include <vcl/window.hxx>
49 #include <vcl/floatwin.hxx>
50 #include <vcl/timer.hxx>
51 #include <vcl/menu.hxx>
52 #include <vcl/outdev.hxx>
53 #include <vcl/msgbox.hxx>
54 #include <vcl/lineinfo.hxx>
55 #include <vcl/button.hxx>
56 #include <vcl/settings.hxx>
57 #include <vcl/svapp.hxx>
58 #include <sfx2/sfx.hrc>
59 #include "rtl/ustrbuf.hxx"
60 
61 #include "updatecheckui.hrc"
62 
63 #define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))
64 
65 #define MSG_ERR_NO_WEBBROWSER_FOUND  (RID_SFX_APP_START + 7)
66 #define DEFAULT_MENUBAR_HEIGHT 24
67 
68 #define PROPERTY_TITLE          RTL_CONSTASCII_STRINGPARAM("BubbleHeading")
69 #define PROPERTY_TEXT           RTL_CONSTASCII_STRINGPARAM("BubbleText")
70 #define PROPERTY_IMAGE          RTL_CONSTASCII_STRINGPARAM("BubbleImageURL")
71 #define PROPERTY_SHOW_BUBBLE    RTL_CONSTASCII_STRINGPARAM("BubbleVisible")
72 #define PROPERTY_CLICK_HDL      RTL_CONSTASCII_STRINGPARAM("MenuClickHDL")
73 #define PROPERTY_SHOW_MENUICON  RTL_CONSTASCII_STRINGPARAM("MenuIconVisible")
74 
75 #define START_TIMER 1
76 
77 using namespace ::com::sun::star;
78 
79 //------------------------------------------------------------------------------
80 
81 static uno::Sequence< rtl::OUString > getServiceNames()
82 {
83     uno::Sequence< rtl::OUString > aServiceList(1);
84     aServiceList[0] = UNISTRING( "com.sun.star.setup.UpdateCheckUI");
85     return aServiceList;
86 }
87 
88 //------------------------------------------------------------------------------
89 
90 static rtl::OUString getImplementationName()
91 {
92     return UNISTRING( "vnd.sun.UpdateCheckUI");
93 }
94 
95 //------------------------------------------------------------------------------
96 
97 namespace
98 {
99 
100 //------------------------------------------------------------------------------
101 class BubbleWindow : public FloatingWindow
102 {
103     Point           maTipPos;
104     Region          maBounds;
105     Polygon         maRectPoly;
106     Polygon         maTriPoly;
107     XubString       maBubbleTitle;
108     XubString       maBubbleText;
109     Image           maBubbleImage;
110     Size            maMaxTextSize;
111     Rectangle       maTitleRect;
112     Rectangle       maTextRect;
113     long            mnTipOffset;
114 
115 private:
116     void            RecalcTextRects();
117 
118 public:
119                     BubbleWindow( Window* pParent, const XubString& rTitle,
120                                   const XubString& rText, const Image& rImage );
121                    ~BubbleWindow();
122 
123     virtual void    MouseButtonDown( const MouseEvent& rMEvt );
124     virtual void    Paint( const Rectangle& rRect );
125     void            Resize();
126     void            Show( sal_Bool bVisible = sal_True, sal_uInt16 nFlags = SHOW_NOACTIVATE );
127     void            SetTipPosPixel( const Point& rTipPos ) { maTipPos = rTipPos; }
128     void            SetTitleAndText( const XubString& rTitle, const XubString& rText,
129                                      const Image& rImage );
130 };
131 
132 //------------------------------------------------------------------------------
133 class UpdateCheckUI : public ::cppu::WeakImplHelper3
134                         < lang::XServiceInfo, document::XEventListener, beans::XPropertySet >
135 {
136     uno::Reference< uno::XComponentContext > m_xContext;
137     uno::Reference< task::XJob > mrJob;
138     rtl::OUString       maBubbleTitle;
139     rtl::OUString       maBubbleText;
140     rtl::OUString       maBubbleImageURL;
141     Image               maBubbleImage;
142     BubbleWindow*       mpBubbleWin;
143     SystemWindow*       mpIconSysWin;
144     MenuBar*            mpIconMBar;
145     ResMgr*             mpUpdResMgr;
146     ResMgr*             mpSfxResMgr;
147     Timer               maWaitTimer;
148     Timer               maTimeoutTimer;
149     Link                maWindowEventHdl;
150     Link                maApplicationEventHdl;
151     bool                mbShowBubble;
152     bool                mbShowMenuIcon;
153     bool                mbBubbleChanged;
154     sal_uInt16              mnIconID;
155 
156 private:
157 				    DECL_LINK( ClickHdl, sal_uInt16* );
158 				    DECL_LINK( HighlightHdl, MenuBar::MenuBarButtonCallbackArg* );
159                     DECL_LINK( WaitTimeOutHdl, Timer* );
160                     DECL_LINK( TimeOutHdl, Timer* );
161                     DECL_LINK( UserEventHdl, UpdateCheckUI* );
162                     DECL_LINK( WindowEventHdl, VclWindowEvent* );
163                     DECL_LINK( ApplicationEventHdl, VclSimpleEvent* );
164 
165     BubbleWindow*   GetBubbleWindow();
166     void            RemoveBubbleWindow( bool bRemoveIcon );
167     Image           GetMenuBarIcon( MenuBar* pMBar );
168     void            AddMenuBarIcon( SystemWindow* pSysWin, bool bAddEventHdl );
169     Image           GetBubbleImage( ::rtl::OUString &rURL );
170 
171     uno::Reference< document::XEventBroadcaster > getGlobalEventBroadcaster() const
172          throw (uno::RuntimeException);
173 
174 public:
175                     UpdateCheckUI(const uno::Reference<uno::XComponentContext>&);
176     virtual        ~UpdateCheckUI();
177 
178     // XServiceInfo
179     virtual rtl::OUString SAL_CALL getImplementationName()
180         throw (uno::RuntimeException);
181     virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & serviceName)
182         throw (uno::RuntimeException);
183     virtual uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames()
184         throw (uno::RuntimeException);
185 
186     // XEventListener
187     virtual void SAL_CALL notifyEvent(const document::EventObject& Event)
188         throw (uno::RuntimeException);
189     virtual void SAL_CALL disposing(const lang::EventObject& Event)
190         throw (uno::RuntimeException);
191 
192 	//XPropertySet
193 	virtual uno::Reference< beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(void)
194         throw ( uno::RuntimeException );
195 	virtual void SAL_CALL setPropertyValue(const rtl::OUString& PropertyName, const uno::Any& aValue)
196         throw( beans::UnknownPropertyException, beans::PropertyVetoException,
197                lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException );
198 	virtual uno::Any SAL_CALL getPropertyValue(const rtl::OUString& PropertyName)
199         throw ( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException );
200 	virtual void SAL_CALL addPropertyChangeListener(const rtl::OUString& PropertyName,
201                                                     const uno::Reference< beans::XPropertyChangeListener > & aListener)
202         throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException );
203 	virtual void SAL_CALL removePropertyChangeListener(const rtl::OUString& PropertyName,
204                                                        const uno::Reference< beans::XPropertyChangeListener > & aListener)
205         throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException );
206 	virtual void SAL_CALL addVetoableChangeListener(const rtl::OUString& PropertyName,
207                                                     const uno::Reference< beans::XVetoableChangeListener > & aListener)
208         throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException );
209 	virtual void SAL_CALL removeVetoableChangeListener(const rtl::OUString& PropertyName,
210                                                        const uno::Reference< beans::XVetoableChangeListener > & aListener)
211         throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException );
212 };
213 
214 //------------------------------------------------------------------------------
215 UpdateCheckUI::UpdateCheckUI(const uno::Reference<uno::XComponentContext>& xContext) :
216       m_xContext(xContext)
217     , mpBubbleWin( NULL )
218     , mpIconSysWin( NULL )
219     , mpIconMBar( NULL )
220     , mbShowBubble( false )
221     , mbShowMenuIcon( false )
222     , mbBubbleChanged( false )
223     , mnIconID( 0 )
224 {
225     mpUpdResMgr = ResMgr::CreateResMgr( "updchk" );
226     mpSfxResMgr = ResMgr::CreateResMgr( "sfx" );
227 
228     maBubbleImage = GetBubbleImage( maBubbleImageURL );
229 
230     maWaitTimer.SetTimeout( 400 );
231     maWaitTimer.SetTimeoutHdl( LINK( this, UpdateCheckUI, WaitTimeOutHdl ) );
232 
233     maTimeoutTimer.SetTimeout( 10000 );
234     maTimeoutTimer.SetTimeoutHdl( LINK( this, UpdateCheckUI, TimeOutHdl ) );
235 
236     uno::Reference< document::XEventBroadcaster > xBroadcaster( getGlobalEventBroadcaster() );
237     xBroadcaster->addEventListener( this );
238 
239     maWindowEventHdl = LINK( this, UpdateCheckUI, WindowEventHdl );
240     maApplicationEventHdl = LINK( this, UpdateCheckUI, ApplicationEventHdl );
241     Application::AddEventListener( maApplicationEventHdl );
242 }
243 
244 //------------------------------------------------------------------------------
245 UpdateCheckUI::~UpdateCheckUI()
246 {
247     Application::RemoveEventListener( maApplicationEventHdl );
248     RemoveBubbleWindow( true );
249     delete mpUpdResMgr;
250     delete mpSfxResMgr;
251 }
252 
253 //------------------------------------------------------------------------------
254 uno::Reference<document::XEventBroadcaster>
255 UpdateCheckUI::getGlobalEventBroadcaster() const throw (uno::RuntimeException)
256 {
257     if( !m_xContext.is() )
258         throw uno::RuntimeException(
259             UNISTRING( "UpdateCheckUI: empty component context" ),
260                 uno::Reference< uno::XInterface >() );
261 
262     uno::Reference< lang::XMultiComponentFactory > xServiceManager(m_xContext->getServiceManager());
263 
264     if( !xServiceManager.is() )
265         throw uno::RuntimeException(
266             UNISTRING( "UpdateCheckUI: unable to obtain service manager from component context" ),
267                 uno::Reference< uno::XInterface >() );
268 
269     return uno::Reference<document::XEventBroadcaster> (
270         xServiceManager->createInstanceWithContext(
271             UNISTRING( "com.sun.star.frame.GlobalEventBroadcaster" ),
272             m_xContext),
273         uno::UNO_QUERY_THROW);
274 }
275 
276 //------------------------------------------------------------------------------
277 rtl::OUString SAL_CALL
278 UpdateCheckUI::getImplementationName() throw (uno::RuntimeException)
279 {
280     return ::getImplementationName();
281 }
282 
283 //------------------------------------------------------------------------------
284 uno::Sequence< rtl::OUString > SAL_CALL
285 UpdateCheckUI::getSupportedServiceNames() throw (uno::RuntimeException)
286 {
287     return ::getServiceNames();
288 }
289 
290 //------------------------------------------------------------------------------
291 sal_Bool SAL_CALL
292 UpdateCheckUI::supportsService( rtl::OUString const & serviceName ) throw (uno::RuntimeException)
293 {
294     uno::Sequence< rtl::OUString > aServiceNameList = ::getServiceNames();
295 
296     for( sal_Int32 n=0; n < aServiceNameList.getLength(); n++ )
297         if( aServiceNameList[n].equals(serviceName) )
298             return sal_True;
299 
300     return sal_False;
301 }
302 
303 //------------------------------------------------------------------------------
304 Image UpdateCheckUI::GetMenuBarIcon( MenuBar* pMBar )
305 {
306     sal_uInt32 nResID;
307     Window *pMBarWin = pMBar->GetWindow();
308     sal_uInt32 nMBarHeight = 20;
309 
310     if ( pMBarWin )
311         nMBarHeight = pMBarWin->GetOutputSizePixel().getHeight();
312 
313     if ( Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) {
314         if ( nMBarHeight >= 35 )
315             nResID = RID_UPDATE_AVAILABLE_26_HC;
316         else
317             nResID = RID_UPDATE_AVAILABLE_16_HC;
318     } else {
319         if ( nMBarHeight >= 35 )
320             nResID = RID_UPDATE_AVAILABLE_26;
321         else
322             nResID = RID_UPDATE_AVAILABLE_16;
323     }
324 
325     return Image( ResId( nResID, *mpUpdResMgr ) );
326 }
327 
328 //------------------------------------------------------------------------------
329 Image UpdateCheckUI::GetBubbleImage( ::rtl::OUString &rURL )
330 {
331     Image aImage;
332 
333     if ( maBubbleImageURL.getLength() != 0 )
334     {
335     	uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
336 
337         if( !xServiceManager.is() )
338             throw uno::RuntimeException(
339                 UNISTRING( "UpdateCheckUI: unable to obtain service manager from component context" ),
340                     uno::Reference< uno::XInterface >() );
341 
342         try
343 		{
344             uno::Reference< graphic::XGraphicProvider > xGraphProvider(
345                     xServiceManager->createInstance(
346                             ::rtl::OUString::createFromAscii( "com.sun.star.graphic.GraphicProvider" ) ),
347                     uno::UNO_QUERY );
348             if ( xGraphProvider.is() )
349             {
350                 uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
351                 aMediaProps[0].Name = ::rtl::OUString::createFromAscii( "URL" );
352                 aMediaProps[0].Value <<= rURL;
353 
354                 uno::Reference< graphic::XGraphic > xGraphic = xGraphProvider->queryGraphic( aMediaProps );
355                 if ( xGraphic.is() )
356                 {
357                     aImage = Image( xGraphic );
358                 }
359             }
360         }
361         catch( uno::Exception& )
362         {
363         }
364     }
365 
366     if ( aImage.GetSizePixel().Width() == 0 )
367         aImage = InfoBox::GetStandardImage();
368 
369     return aImage;
370 }
371 
372 //------------------------------------------------------------------------------
373 void UpdateCheckUI::AddMenuBarIcon( SystemWindow *pSysWin, bool bAddEventHdl )
374 {
375     if ( ! mbShowMenuIcon )
376         return;
377 
378     vos::OGuard aGuard( Application::GetSolarMutex() );
379 
380     MenuBar *pActiveMBar = pSysWin->GetMenuBar();
381     if ( ( pSysWin != mpIconSysWin ) || ( pActiveMBar != mpIconMBar ) )
382     {
383         if ( bAddEventHdl && mpIconSysWin )
384             mpIconSysWin->RemoveEventListener( maWindowEventHdl );
385 
386         RemoveBubbleWindow( true );
387 
388         if ( pActiveMBar )
389         {
390             rtl::OUStringBuffer aBuf;
391             if( maBubbleTitle.getLength() )
392                 aBuf.append( maBubbleTitle );
393             if( maBubbleText.getLength() )
394             {
395                 if( maBubbleTitle.getLength() )
396                     aBuf.appendAscii( "\n\n" );
397                 aBuf.append( maBubbleText );
398             }
399 
400             Image aImage = GetMenuBarIcon( pActiveMBar );
401             mnIconID = pActiveMBar->AddMenuBarButton( aImage,
402                                     LINK( this, UpdateCheckUI, ClickHdl ),
403                                     aBuf.makeStringAndClear()
404                                     );
405             pActiveMBar->SetMenuBarButtonHighlightHdl( mnIconID,
406                                     LINK( this, UpdateCheckUI, HighlightHdl ) );
407         }
408         mpIconMBar = pActiveMBar;
409         mpIconSysWin = pSysWin;
410         if ( bAddEventHdl && mpIconSysWin )
411             mpIconSysWin->AddEventListener( maWindowEventHdl );
412     }
413 
414     if ( mbShowBubble && pActiveMBar )
415     {
416         mpBubbleWin = GetBubbleWindow();
417         if ( mpBubbleWin )
418         {
419             mpBubbleWin->Show( sal_True );
420             maTimeoutTimer.Start();
421         }
422         mbShowBubble = false;
423     }
424 }
425 
426 //------------------------------------------------------------------------------
427 void SAL_CALL UpdateCheckUI::notifyEvent(const document::EventObject& rEvent)
428     throw (uno::RuntimeException)
429 {
430 	vos::OGuard aGuard( Application::GetSolarMutex() );
431 
432 	if( rEvent.EventName.compareToAscii( RTL_CONSTASCII_STRINGPARAM("OnPrepareViewClosing") ) == 0 )
433     {
434         RemoveBubbleWindow( true );
435     }
436 }
437 
438 //------------------------------------------------------------------------------
439 void SAL_CALL UpdateCheckUI::disposing(const lang::EventObject&)
440     throw (uno::RuntimeException)
441 {
442 }
443 
444 //------------------------------------------------------------------------------
445 uno::Reference< beans::XPropertySetInfo > UpdateCheckUI::getPropertySetInfo(void)
446     throw ( uno::RuntimeException )
447 {
448 	return NULL;
449 }
450 
451 //------------------------------------------------------------------------------
452 void UpdateCheckUI::setPropertyValue(const rtl::OUString& rPropertyName,
453 									 const uno::Any& rValue)
454 	throw( beans::UnknownPropertyException, beans::PropertyVetoException,
455 		   lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException)
456 {
457     vos::OGuard aGuard( Application::GetSolarMutex() );
458 
459     rtl::OUString aString;
460 
461 	if( rPropertyName.compareToAscii( PROPERTY_TITLE ) == 0 ) {
462         rValue >>= aString;
463         if ( aString != maBubbleTitle ) {
464             maBubbleTitle = aString;
465             mbBubbleChanged = true;
466         }
467     }
468     else if( rPropertyName.compareToAscii( PROPERTY_TEXT ) == 0 ) {
469         rValue >>= aString;
470         if ( aString != maBubbleText ) {
471             maBubbleText = aString;
472             mbBubbleChanged = true;
473         }
474     }
475     else if( rPropertyName.compareToAscii( PROPERTY_IMAGE ) == 0 ) {
476         rValue >>= aString;
477         if ( aString != maBubbleImageURL ) {
478             maBubbleImageURL = aString;
479             maBubbleImage = GetBubbleImage( maBubbleImageURL );
480             mbBubbleChanged = true;
481         }
482     }
483     else if( rPropertyName.compareToAscii( PROPERTY_SHOW_BUBBLE ) == 0 ) {
484         rValue >>= mbShowBubble;
485 		if ( mbShowBubble )
486             Application::PostUserEvent( LINK( this, UpdateCheckUI, UserEventHdl ) );
487         else if ( mpBubbleWin )
488             mpBubbleWin->Show( sal_False );
489     }
490     else if( rPropertyName.compareToAscii( PROPERTY_CLICK_HDL ) == 0 ) {
491         uno::Reference< task::XJob > aJob;
492         rValue >>= aJob;
493         if ( aJob.is() )
494             mrJob = aJob;
495         else
496             throw lang::IllegalArgumentException();
497     }
498     else if (rPropertyName.compareToAscii( PROPERTY_SHOW_MENUICON ) == 0) {
499         bool bShowMenuIcon = sal_False;
500         rValue >>= bShowMenuIcon;
501         if ( bShowMenuIcon != mbShowMenuIcon )
502         {
503             mbShowMenuIcon = bShowMenuIcon;
504             if ( bShowMenuIcon )
505                 Application::PostUserEvent( LINK( this, UpdateCheckUI, UserEventHdl ) );
506             else
507                 RemoveBubbleWindow( true );
508         }
509     }
510     else
511         throw beans::UnknownPropertyException();
512 
513     if ( mbBubbleChanged && mpBubbleWin )
514         mpBubbleWin->Show( sal_False );
515 }
516 
517 //------------------------------------------------------------------------------
518 uno::Any UpdateCheckUI::getPropertyValue(const rtl::OUString& rPropertyName)
519 	throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException )
520 {
521     vos::OGuard aGuard( Application::GetSolarMutex() );
522 
523 	uno::Any aRet;
524 
525     if( rPropertyName.compareToAscii( PROPERTY_TITLE ) == 0 )
526         aRet = uno::makeAny( maBubbleTitle );
527     else if( rPropertyName.compareToAscii( PROPERTY_TEXT ) == 0 )
528         aRet = uno::makeAny( maBubbleText );
529     else if( rPropertyName.compareToAscii( PROPERTY_SHOW_BUBBLE ) == 0 )
530         aRet = uno::makeAny( mbShowBubble );
531     else if( rPropertyName.compareToAscii( PROPERTY_IMAGE ) == 0 )
532         aRet = uno::makeAny( maBubbleImageURL );
533     else if( rPropertyName.compareToAscii( PROPERTY_CLICK_HDL ) == 0 )
534         aRet = uno::makeAny( mrJob );
535     else if( rPropertyName.compareToAscii( PROPERTY_SHOW_MENUICON ) == 0 )
536         aRet = uno::makeAny( mbShowMenuIcon );
537     else
538         throw beans::UnknownPropertyException();
539 
540 	return aRet;
541 }
542 
543 //------------------------------------------------------------------------------
544 void UpdateCheckUI::addPropertyChangeListener( const rtl::OUString& /*aPropertyName*/,
545                                                const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
546     throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException )
547 {
548 	//no bound properties
549 }
550 
551 //------------------------------------------------------------------------------
552 void UpdateCheckUI::removePropertyChangeListener( const rtl::OUString& /*aPropertyName*/,
553                                                   const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
554     throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException )
555 {
556 	//no bound properties
557 }
558 
559 //------------------------------------------------------------------------------
560 void UpdateCheckUI::addVetoableChangeListener( const rtl::OUString& /*aPropertyName*/,
561                                                const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
562 	throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException )
563 {
564 	//no vetoable properties
565 }
566 
567 //------------------------------------------------------------------------------
568 void UpdateCheckUI::removeVetoableChangeListener( const rtl::OUString& /*aPropertyName*/,
569                                                   const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
570 	throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException )
571 {
572 	//no vetoable properties
573 }
574 
575 
576 //------------------------------------------------------------------------------
577 //------------------------------------------------------------------------------
578 //------------------------------------------------------------------------------
579 BubbleWindow * UpdateCheckUI::GetBubbleWindow()
580 {
581     if ( !mpIconSysWin )
582         return NULL;
583 
584     Rectangle aIconRect = mpIconMBar->GetMenuBarButtonRectPixel( mnIconID );
585     if( aIconRect.IsEmpty() )
586         return NULL;
587 
588     BubbleWindow* pBubbleWin = mpBubbleWin;
589 
590     if ( !pBubbleWin ) {
591         pBubbleWin = new BubbleWindow( mpIconSysWin,
592 		  					           XubString( maBubbleTitle ),
593                                        XubString( maBubbleText ),
594                                        maBubbleImage );
595         mbBubbleChanged = false;
596     }
597     else if ( mbBubbleChanged ) {
598         pBubbleWin->SetTitleAndText( XubString( maBubbleTitle ),
599                                      XubString( maBubbleText ),
600                                      maBubbleImage );
601         mbBubbleChanged = false;
602     }
603 
604     Point aWinPos = aIconRect.BottomCenter();
605 
606     pBubbleWin->SetTipPosPixel( aWinPos );
607 
608     return pBubbleWin;
609 }
610 
611 //------------------------------------------------------------------------------
612 void UpdateCheckUI::RemoveBubbleWindow( bool bRemoveIcon )
613 {
614     vos::OGuard aGuard( Application::GetSolarMutex() );
615 
616     maWaitTimer.Stop();
617     maTimeoutTimer.Stop();
618 
619     if ( mpBubbleWin )
620     {
621         delete mpBubbleWin;
622         mpBubbleWin = NULL;
623     }
624 
625     if ( bRemoveIcon )
626     {
627         try {
628             if ( mpIconMBar && ( mnIconID != 0 ) )
629             {
630                 mpIconMBar->RemoveMenuBarButton( mnIconID );
631                 mpIconMBar = NULL;
632                 mnIconID = 0;
633             }
634         }
635         catch ( ... ) {
636             mpIconMBar = NULL;
637             mnIconID = 0;
638         }
639 
640         mpIconSysWin = NULL;
641     }
642 }
643 
644 // -----------------------------------------------------------------------
645 IMPL_LINK( UpdateCheckUI, ClickHdl, sal_uInt16*, EMPTYARG )
646 {
647     vos::OGuard aGuard( Application::GetSolarMutex() );
648 
649     maWaitTimer.Stop();
650     if ( mpBubbleWin )
651         mpBubbleWin->Show( sal_False );
652 
653     if ( mrJob.is() )
654     {
655         try {
656             uno::Sequence<beans::NamedValue> aEmpty;
657             mrJob->execute( aEmpty );
658         }
659         catch(const uno::Exception&) {
660             ErrorBox( NULL, ResId( MSG_ERR_NO_WEBBROWSER_FOUND, *mpSfxResMgr )).Execute();
661         }
662     }
663 
664     return 0;
665 }
666 
667 // -----------------------------------------------------------------------
668 IMPL_LINK( UpdateCheckUI, HighlightHdl, MenuBar::MenuBarButtonCallbackArg*, pData )
669 {
670 	if ( pData->bHighlight )
671         maWaitTimer.Start();
672     else
673         RemoveBubbleWindow( false );
674 
675 	return 0;
676 }
677 
678 // -----------------------------------------------------------------------
679 IMPL_LINK( UpdateCheckUI, WaitTimeOutHdl, Timer*, EMPTYARG )
680 {
681     vos::OGuard aGuard( Application::GetSolarMutex() );
682 
683     mpBubbleWin = GetBubbleWindow();
684 
685     if ( mpBubbleWin )
686     {
687         mpBubbleWin->Show();
688     }
689 
690 	return 0;
691 }
692 
693 // -----------------------------------------------------------------------
694 IMPL_LINK( UpdateCheckUI, TimeOutHdl, Timer*, EMPTYARG )
695 {
696     RemoveBubbleWindow( false );
697 
698 	return 0;
699 }
700 
701 // -----------------------------------------------------------------------
702 IMPL_LINK( UpdateCheckUI, UserEventHdl, UpdateCheckUI*, EMPTYARG )
703 {
704     vos::OGuard aGuard( Application::GetSolarMutex() );
705 
706     Window *pTopWin = Application::GetFirstTopLevelWindow();
707     Window *pActiveWin = Application::GetActiveTopWindow();
708 	SystemWindow *pActiveSysWin = NULL;
709 
710     Window *pBubbleWin = NULL;
711     if ( mpBubbleWin )
712         pBubbleWin = mpBubbleWin;
713 
714 	if ( pActiveWin && ( pActiveWin != pBubbleWin ) && pActiveWin->IsTopWindow() )
715 		pActiveSysWin = pActiveWin->GetSystemWindow();
716 
717     if ( pActiveWin == pBubbleWin )
718         pActiveSysWin = NULL;
719 
720     while ( !pActiveSysWin && pTopWin )
721     {
722         if ( ( pTopWin != pBubbleWin ) && pTopWin->IsTopWindow() )
723             pActiveSysWin = pTopWin->GetSystemWindow();
724         if ( !pActiveSysWin )
725             pTopWin = Application::GetNextTopLevelWindow( pTopWin );
726     }
727 
728 	if ( pActiveSysWin )
729         AddMenuBarIcon( pActiveSysWin, true );
730 
731     return 0;
732 }
733 
734 // -----------------------------------------------------------------------
735 IMPL_LINK( UpdateCheckUI, WindowEventHdl, VclWindowEvent*, pEvent )
736 {
737     sal_uLong nEventID = pEvent->GetId();
738 
739     if ( VCLEVENT_OBJECT_DYING == nEventID )
740     {
741         vos::OGuard aGuard( Application::GetSolarMutex() );
742         if ( mpIconSysWin == pEvent->GetWindow() )
743         {
744             mpIconSysWin->RemoveEventListener( maWindowEventHdl );
745             RemoveBubbleWindow( true );
746         }
747     }
748     else if ( VCLEVENT_WINDOW_MENUBARADDED == nEventID )
749     {
750         vos::OGuard aGuard( Application::GetSolarMutex() );
751         Window *pWindow = pEvent->GetWindow();
752         if ( pWindow )
753         {
754             SystemWindow *pSysWin = pWindow->GetSystemWindow();
755             if ( pSysWin )
756             {
757                 AddMenuBarIcon( pSysWin, false );
758             }
759         }
760     }
761     else if ( VCLEVENT_WINDOW_MENUBARREMOVED == nEventID )
762     {
763         vos::OGuard aGuard( Application::GetSolarMutex() );
764         MenuBar *pMBar = (MenuBar*) pEvent->GetData();
765         if ( pMBar && ( pMBar == mpIconMBar ) )
766             RemoveBubbleWindow( true );
767     }
768     else if ( ( nEventID == VCLEVENT_WINDOW_MOVE ) ||
769               ( nEventID == VCLEVENT_WINDOW_RESIZE ) )
770     {
771         vos::OGuard aGuard( Application::GetSolarMutex() );
772         if ( ( mpIconSysWin == pEvent->GetWindow() ) &&
773              ( mpBubbleWin != NULL ) && ( mpIconMBar != NULL ) )
774         {
775             Rectangle aIconRect = mpIconMBar->GetMenuBarButtonRectPixel( mnIconID );
776             Point aWinPos = aIconRect.BottomCenter();
777             mpBubbleWin->SetTipPosPixel( aWinPos );
778             if ( mpBubbleWin->IsVisible() )
779                 mpBubbleWin->Show();    // This will recalc the screen positon of the bubble
780         }
781     }
782 
783     return 0;
784 }
785 
786 //------------------------------------------------------------------------------
787 IMPL_LINK( UpdateCheckUI, ApplicationEventHdl, VclSimpleEvent *, pEvent)
788 {
789     switch (pEvent->GetId())
790     {
791         case VCLEVENT_WINDOW_SHOW:
792         case VCLEVENT_WINDOW_ACTIVATE:
793         case VCLEVENT_WINDOW_GETFOCUS: {
794             vos::OGuard aGuard( Application::GetSolarMutex() );
795 
796             Window *pWindow = static_cast< VclWindowEvent * >(pEvent)->GetWindow();
797             if ( pWindow && pWindow->IsTopWindow() )
798             {
799                 SystemWindow *pSysWin = pWindow->GetSystemWindow();
800                 MenuBar      *pMBar   = pSysWin->GetMenuBar();
801                 if ( pSysWin && pMBar )
802                 {
803                     AddMenuBarIcon( pSysWin, true );
804                 }
805             }
806             break;
807         }
808     }
809     return 0;
810 }
811 //------------------------------------------------------------------------------
812 //------------------------------------------------------------------------------
813 //------------------------------------------------------------------------------
814 
815 #define TIP_HEIGHT             15
816 #define TIP_WIDTH               7
817 #define TIP_RIGHT_OFFSET       18
818 #define BUBBLE_BORDER          10
819 #define TEXT_MAX_WIDTH        300
820 #define TEXT_MAX_HEIGHT       200
821 #define INITIAL_SHOW_TIME   10000
822 
823 //------------------------------------------------------------------------------
824 BubbleWindow::BubbleWindow( Window* pParent, const XubString& rTitle,
825                             const XubString& rText, const Image& rImage )
826     : FloatingWindow( pParent, WB_SYSTEMWINDOW
827                                | WB_OWNERDRAWDECORATION
828                                | WB_NOBORDER
829                     )
830     , maBubbleTitle( rTitle )
831     , maBubbleText( rText )
832     , maBubbleImage( rImage )
833     , maMaxTextSize( TEXT_MAX_WIDTH, TEXT_MAX_HEIGHT )
834     , mnTipOffset( 0 )
835 {
836     SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetHelpColor() ) );
837 }
838 
839 //------------------------------------------------------------------------------
840 BubbleWindow::~BubbleWindow()
841 {
842 }
843 
844 //------------------------------------------------------------------------------
845 void BubbleWindow::Resize()
846 {
847     vos::OGuard aGuard( Application::GetSolarMutex() );
848 
849 	FloatingWindow::Resize();
850 
851     Size aSize = GetSizePixel();
852 
853     if ( ( aSize.Height() < 20 ) || ( aSize.Width() < 60 ) )
854         return;
855 
856     Rectangle aRect( 0, TIP_HEIGHT, aSize.Width(), aSize.Height() - TIP_HEIGHT );
857 	maRectPoly = Polygon( aRect, 6, 6 );
858     Region aRegion( maRectPoly );
859     long nTipOffset = aSize.Width() - TIP_RIGHT_OFFSET + mnTipOffset;
860 
861     Point aPointArr[4];
862     aPointArr[0] = Point( nTipOffset, TIP_HEIGHT );
863     aPointArr[1] = Point( nTipOffset, 0 );
864     aPointArr[2] = Point( nTipOffset + TIP_WIDTH , TIP_HEIGHT );
865     aPointArr[3] = Point( nTipOffset, TIP_HEIGHT );
866  	maTriPoly = Polygon( 4, aPointArr );
867     Region aTriRegion( maTriPoly );
868 
869     aRegion.Union( aTriRegion);
870     maBounds = aRegion;
871 
872 	SetWindowRegionPixel( maBounds );
873 }
874 
875 //------------------------------------------------------------------------------
876 void BubbleWindow::SetTitleAndText( const XubString& rTitle,
877                                     const XubString& rText,
878                                     const Image& rImage )
879 {
880     maBubbleTitle = rTitle;
881     maBubbleText = rText;
882     maBubbleImage = rImage;
883 
884     Resize();
885 }
886 
887 //------------------------------------------------------------------------------
888 void BubbleWindow::Paint( const Rectangle& )
889 {
890     vos::OGuard aGuard( Application::GetSolarMutex() );
891 
892     LineInfo aThickLine( LINE_SOLID, 2 );
893 
894     DrawPolyLine( maRectPoly, aThickLine );
895     DrawPolyLine( maTriPoly );
896 
897     Color aOldLine = GetLineColor();
898     Size aSize = GetSizePixel();
899     long nTipOffset = aSize.Width() - TIP_RIGHT_OFFSET + mnTipOffset;
900 
901     SetLineColor( GetSettings().GetStyleSettings().GetHelpColor() );
902     DrawLine( Point( nTipOffset+2, TIP_HEIGHT ),
903               Point( nTipOffset + TIP_WIDTH -1 , TIP_HEIGHT ),
904               aThickLine );
905     SetLineColor( aOldLine );
906 
907 	//Image aImage = InfoBox::GetStandardImage();
908 	Size aImgSize = maBubbleImage.GetSizePixel();
909 
910 	DrawImage( Point( BUBBLE_BORDER, BUBBLE_BORDER + TIP_HEIGHT ), maBubbleImage );
911 
912 	Font aOldFont = GetFont();
913 	Font aBoldFont = aOldFont;
914 	aBoldFont.SetWeight( WEIGHT_BOLD );
915 
916     SetFont( aBoldFont );
917     Rectangle aTitleRect = maTitleRect;
918 	aTitleRect.Move( aImgSize.Width(), 0 );
919     DrawText( aTitleRect, maBubbleTitle, TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
920 
921     SetFont( aOldFont );
922     Rectangle aTextRect = maTextRect;
923 	aTextRect.Move( aImgSize.Width(), 0 );
924     DrawText( aTextRect, maBubbleText, TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
925 }
926 
927 //------------------------------------------------------------------------------
928 void BubbleWindow::MouseButtonDown( const MouseEvent& )
929 {
930     Show( sal_False );
931 }
932 
933 //------------------------------------------------------------------------------
934 void BubbleWindow::Show( sal_Bool bVisible, sal_uInt16 nFlags )
935 {
936     vos::OGuard aGuard( Application::GetSolarMutex() );
937 
938 	if ( !bVisible )
939     {
940         FloatingWindow::Show( bVisible );
941         return;
942     }
943 
944     // don't show bubbles without a text
945     if ( ( maBubbleTitle.Len() == 0 ) && ( maBubbleText.Len() == 0 ) )
946         return;
947 
948 	Size aWindowSize = GetSizePixel();
949 
950 	// Image aImage = InfoBox::GetStandardImage();
951 	Size aImgSize = maBubbleImage.GetSizePixel();
952 
953 	RecalcTextRects();
954 
955 	aWindowSize.setHeight( maTitleRect.GetHeight() * 7 / 4+ maTextRect.GetHeight() +
956 						   3 * BUBBLE_BORDER + TIP_HEIGHT );
957 
958 	if ( maTitleRect.GetWidth() > maTextRect.GetWidth() )
959 		aWindowSize.setWidth( maTitleRect.GetWidth() );
960 	else
961 		aWindowSize.setWidth( maTextRect.GetWidth() );
962 
963 	aWindowSize.setWidth( aWindowSize.Width() + 3 * BUBBLE_BORDER + aImgSize.Width() );
964 
965 	if ( aWindowSize.Height() < aImgSize.Height() + TIP_HEIGHT + 2 * BUBBLE_BORDER )
966 		aWindowSize.setHeight( aImgSize.Height() + TIP_HEIGHT + 2 * BUBBLE_BORDER );
967 
968 	Point aPos;
969 	aPos.X() = maTipPos.X() - aWindowSize.Width() + TIP_RIGHT_OFFSET;
970     aPos.Y() = maTipPos.Y();
971     Point aScreenPos = GetParent()->OutputToAbsoluteScreenPixel( aPos );
972     if ( aScreenPos.X() < 0 )
973     {
974         mnTipOffset = aScreenPos.X();
975         aPos.X() -= mnTipOffset;
976     }
977 	SetPosSizePixel( aPos, aWindowSize );
978 
979 	FloatingWindow::Show( bVisible, nFlags );
980 }
981 
982 //------------------------------------------------------------------------------
983 void BubbleWindow::RecalcTextRects()
984 {
985     Size aTotalSize;
986     sal_Bool bFinished = sal_False;
987 	Font aOldFont = GetFont();
988 	Font aBoldFont = aOldFont;
989 
990 	aBoldFont.SetWeight( WEIGHT_BOLD );
991 
992     while ( !bFinished )
993     {
994         SetFont( aBoldFont );
995 
996         maTitleRect = GetTextRect( Rectangle( Point( 0, 0 ), maMaxTextSize ),
997                                    maBubbleTitle,
998 								   TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
999 
1000         SetFont( aOldFont );
1001         maTextRect = GetTextRect( Rectangle( Point( 0, 0 ), maMaxTextSize ),
1002                                   maBubbleText,
1003                                   TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
1004 
1005         if ( maTextRect.GetHeight() < 10 )
1006             maTextRect.setHeight( 10 );
1007 
1008 	    aTotalSize.setHeight( maTitleRect.GetHeight() +
1009 							  aBoldFont.GetHeight() * 3 / 4 +
1010 							  maTextRect.GetHeight() +
1011 						      3 * BUBBLE_BORDER + TIP_HEIGHT );
1012         if ( aTotalSize.Height() > maMaxTextSize.Height() )
1013         {
1014             maMaxTextSize.Width() = maMaxTextSize.Width() * 3 / 2;
1015             maMaxTextSize.Height() = maMaxTextSize.Height() * 3 / 2;
1016         }
1017         else
1018             bFinished = sal_True;
1019     }
1020     maTitleRect.Move( 2*BUBBLE_BORDER, BUBBLE_BORDER + TIP_HEIGHT );
1021 	maTextRect.Move( 2*BUBBLE_BORDER, BUBBLE_BORDER + TIP_HEIGHT + maTitleRect.GetHeight() + aBoldFont.GetHeight() * 3 / 4 );
1022 }
1023 //------------------------------------------------------------------------------
1024 //------------------------------------------------------------------------------
1025 //------------------------------------------------------------------------------
1026 
1027 } // anonymous namespace
1028 
1029 //------------------------------------------------------------------------------
1030 
1031 static uno::Reference<uno::XInterface> SAL_CALL
1032 createInstance(const uno::Reference<uno::XComponentContext>& xContext)
1033 {
1034     return  *new UpdateCheckUI(xContext);
1035 }
1036 
1037 //------------------------------------------------------------------------------
1038 
1039 static const cppu::ImplementationEntry kImplementations_entries[] =
1040 {
1041     {
1042         createInstance,
1043         getImplementationName,
1044         getServiceNames,
1045         cppu::createSingleComponentFactory,
1046         NULL,
1047         0
1048     },
1049 	{ NULL, NULL, NULL, NULL, NULL, 0 }
1050 } ;
1051 
1052 //------------------------------------------------------------------------------
1053 
1054 extern "C" void SAL_CALL
1055 component_getImplementationEnvironment( const sal_Char **aEnvTypeName, uno_Environment **)
1056 {
1057     *aEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME ;
1058 }
1059 
1060 //------------------------------------------------------------------------------
1061 
1062 extern "C" void *
1063 component_getFactory(const sal_Char *pszImplementationName, void *pServiceManager, void *pRegistryKey)
1064 {
1065     return cppu::component_getFactoryHelper(
1066         pszImplementationName,
1067         pServiceManager,
1068         pRegistryKey,
1069         kImplementations_entries) ;
1070 }
1071 
1072