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