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