1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
23 #include <cppuhelper/implbase.hxx>
24 #include <cppuhelper/implementationentry.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <com/sun/star/lang/XServiceInfo.hpp>
27 #include <com/sun/star/lang/XComponent.hpp>
28 #include <com/sun/star/document/XDocumentEventListener.hpp>
29 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
32 #include <com/sun/star/graphic/GraphicProvider.hpp>
33 #include <com/sun/star/graphic/XGraphicProvider.hpp>
34 #include <com/sun/star/task/XJob.hpp>
35 #include <comphelper/processfactory.hxx>
36 #include <unotools/resmgr.hxx>
37 #include <vcl/window.hxx>
38 #include <vcl/floatwin.hxx>
39 #include <vcl/timer.hxx>
40 #include <vcl/idle.hxx>
41 #include <vcl/menu.hxx>
42 #include <vcl/outdev.hxx>
43 #include <vcl/weld.hxx>
44 #include <vcl/lineinfo.hxx>
45 #include <vcl/button.hxx>
46 #include <vcl/settings.hxx>
47 #include <vcl/svapp.hxx>
48 #include <sfx2/strings.hrc>
49 #include <rtl/ustrbuf.hxx>
51 #include <bitmaps.hlst>
53 #define PROPERTY_TITLE "BubbleHeading"
54 #define PROPERTY_TEXT "BubbleText"
55 #define PROPERTY_IMAGE "BubbleImageURL"
56 #define PROPERTY_SHOW_BUBBLE "BubbleVisible"
57 #define PROPERTY_CLICK_HDL "MenuClickHDL"
58 #define PROPERTY_SHOW_MENUICON "MenuIconVisible"
60 using namespace ::com::sun::star
;
63 static uno::Sequence
< OUString
> getServiceNames()
65 uno::Sequence
< OUString
> aServiceList
{ "com.sun.star.setup.UpdateCheckUI" };
70 static OUString
getImplementationName()
72 return OUString("vnd.sun.UpdateCheckUI");
79 Image
GetMenuBarIcon( MenuBar
const * pMBar
)
82 vcl::Window
*pMBarWin
= pMBar
->GetWindow();
83 sal_uInt32 nMBarHeight
= 20;
86 nMBarHeight
= pMBarWin
->GetOutputSizePixel().getHeight();
88 if (nMBarHeight
>= 35)
89 sResID
= RID_UPDATE_AVAILABLE_26
;
91 sResID
= RID_UPDATE_AVAILABLE_16
;
93 return Image(StockImage::Yes
, sResID
);
96 class BubbleWindow
: public FloatingWindow
100 tools::Polygon maRectPoly
;
101 tools::Polygon maTriPoly
;
102 OUString maBubbleTitle
;
103 OUString maBubbleText
;
106 tools::Rectangle maTitleRect
;
107 tools::Rectangle maTextRect
;
111 void RecalcTextRects();
114 BubbleWindow( vcl::Window
* pParent
, const OUString
& rTitle
,
115 const OUString
& rText
, const Image
& rImage
);
117 virtual void MouseButtonDown( const MouseEvent
& rMEvt
) override
;
118 virtual void Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
) override
;
119 void Resize() override
;
120 void Show( bool bVisible
= true, ShowFlags nFlags
= ShowFlags::NoActivate
);
121 void SetTipPosPixel( const Point
& rTipPos
) { maTipPos
= rTipPos
; }
122 void SetTitleAndText( const OUString
& rTitle
, const OUString
& rText
,
123 const Image
& rImage
);
127 class UpdateCheckUI
: public ::cppu::WeakImplHelper
128 < lang::XServiceInfo
, document::XDocumentEventListener
, beans::XPropertySet
>
130 uno::Reference
< uno::XComponentContext
> m_xContext
;
131 uno::Reference
< task::XJob
> mrJob
;
132 OUString maBubbleTitle
;
133 OUString maBubbleText
;
134 OUString maBubbleImageURL
;
136 VclPtr
<BubbleWindow
> mpBubbleWin
;
137 VclPtr
<SystemWindow
> mpIconSysWin
;
138 VclPtr
<MenuBar
> mpIconMBar
;
139 std::locale maSfxLocale
;
141 Timer maTimeoutTimer
;
142 Link
<VclWindowEvent
&,void> maWindowEventHdl
;
143 Link
<VclSimpleEvent
&,void> maApplicationEventHdl
;
146 bool mbBubbleChanged
;
150 DECL_LINK(ClickHdl
, MenuBar::MenuBarButtonCallbackArg
&, bool);
151 DECL_LINK(HighlightHdl
, MenuBar::MenuBarButtonCallbackArg
&, bool);
152 DECL_LINK(WaitTimeOutHdl
, Timer
*, void);
153 DECL_LINK(TimeOutHdl
, Timer
*, void);
154 DECL_LINK(UserEventHdl
, void *, void);
155 DECL_LINK(WindowEventHdl
, VclWindowEvent
&, void);
156 DECL_LINK(ApplicationEventHdl
, VclSimpleEvent
&, void);
158 VclPtr
<BubbleWindow
> GetBubbleWindow();
159 void RemoveBubbleWindow( bool bRemoveIcon
);
160 void AddMenuBarIcon( SystemWindow
* pSysWin
, bool bAddEventHdl
);
161 Image
GetBubbleImage( OUString
const &rURL
);
164 explicit UpdateCheckUI(const uno::Reference
<uno::XComponentContext
>&);
165 virtual ~UpdateCheckUI() override
;
168 virtual OUString SAL_CALL
getImplementationName() override
;
169 virtual sal_Bool SAL_CALL
supportsService(OUString
const & serviceName
) override
;
170 virtual uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
172 // XDocumentEventListener
173 virtual void SAL_CALL
documentEventOccured(const document::DocumentEvent
& Event
) override
;
174 virtual void SAL_CALL
disposing(const lang::EventObject
& Event
) override
;
177 virtual uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
getPropertySetInfo() override
;
178 virtual void SAL_CALL
setPropertyValue(const OUString
& PropertyName
, const uno::Any
& aValue
) override
;
179 virtual uno::Any SAL_CALL
getPropertyValue(const OUString
& PropertyName
) override
;
180 virtual void SAL_CALL
addPropertyChangeListener(const OUString
& PropertyName
,
181 const uno::Reference
< beans::XPropertyChangeListener
> & aListener
) override
;
182 virtual void SAL_CALL
removePropertyChangeListener(const OUString
& PropertyName
,
183 const uno::Reference
< beans::XPropertyChangeListener
> & aListener
) override
;
184 virtual void SAL_CALL
addVetoableChangeListener(const OUString
& PropertyName
,
185 const uno::Reference
< beans::XVetoableChangeListener
> & aListener
) override
;
186 virtual void SAL_CALL
removeVetoableChangeListener(const OUString
& PropertyName
,
187 const uno::Reference
< beans::XVetoableChangeListener
> & aListener
) override
;
190 UpdateCheckUI::UpdateCheckUI(const uno::Reference
<uno::XComponentContext
>& xContext
) :
192 , mpIconMBar( nullptr )
193 , mbShowBubble( false )
194 , mbShowMenuIcon( false )
195 , mbBubbleChanged( false )
198 maSfxLocale
= Translate::Create("sfx");
200 maBubbleImage
= GetBubbleImage( maBubbleImageURL
);
202 maWaitIdle
.SetPriority( TaskPriority::LOWEST
);
203 maWaitIdle
.SetInvokeHandler( LINK( this, UpdateCheckUI
, WaitTimeOutHdl
) );
205 maTimeoutTimer
.SetTimeout( 10000 );
206 maTimeoutTimer
.SetInvokeHandler( LINK( this, UpdateCheckUI
, TimeOutHdl
) );
208 uno::Reference
< document::XDocumentEventBroadcaster
> xBroadcaster( frame::theGlobalEventBroadcaster::get(m_xContext
) );
209 xBroadcaster
->addDocumentEventListener( this );
211 maWindowEventHdl
= LINK( this, UpdateCheckUI
, WindowEventHdl
);
212 maApplicationEventHdl
= LINK( this, UpdateCheckUI
, ApplicationEventHdl
);
213 Application::AddEventListener( maApplicationEventHdl
);
216 UpdateCheckUI::~UpdateCheckUI()
218 Application::RemoveEventListener( maApplicationEventHdl
);
219 RemoveBubbleWindow( true );
223 UpdateCheckUI::getImplementationName()
225 return ::getImplementationName();
228 uno::Sequence
< OUString
> SAL_CALL
229 UpdateCheckUI::getSupportedServiceNames()
231 return ::getServiceNames();
235 UpdateCheckUI::supportsService( OUString
const & serviceName
)
237 return cppu::supportsService(this, serviceName
);
240 Image
UpdateCheckUI::GetBubbleImage( OUString
const &rURL
)
244 if ( !maBubbleImageURL
.isEmpty() )
246 uno::Reference
< uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
249 throw uno::RuntimeException(
250 "UpdateCheckUI: unable to obtain service manager from component context" );
254 uno::Reference
< graphic::XGraphicProvider
> xGraphProvider(graphic::GraphicProvider::create(xContext
));
255 uno::Sequence
< beans::PropertyValue
> aMediaProps( 1 );
256 aMediaProps
[0].Name
= "URL";
257 aMediaProps
[0].Value
<<= rURL
;
259 uno::Reference
< graphic::XGraphic
> xGraphic
= xGraphProvider
->queryGraphic( aMediaProps
);
262 aImage
= Image( xGraphic
);
265 catch( const uno::Exception
& )
270 if ( aImage
.GetSizePixel().Width() == 0 )
271 aImage
= Image(StockImage::Yes
, SV_RESID_BITMAP_INFOBOX
);
277 void UpdateCheckUI::AddMenuBarIcon( SystemWindow
*pSysWin
, bool bAddEventHdl
)
279 if ( ! mbShowMenuIcon
)
282 SolarMutexGuard aGuard
;
284 MenuBar
*pActiveMBar
= pSysWin
->GetMenuBar();
285 if ( ( pSysWin
!= mpIconSysWin
) || ( pActiveMBar
!= mpIconMBar
) )
287 if ( bAddEventHdl
&& mpIconSysWin
)
288 mpIconSysWin
->RemoveEventListener( maWindowEventHdl
);
290 RemoveBubbleWindow( true );
295 if( !maBubbleTitle
.isEmpty() )
296 aBuf
.append( maBubbleTitle
);
297 if( !maBubbleText
.isEmpty() )
299 if( !maBubbleTitle
.isEmpty() )
300 aBuf
.append( "\n\n" );
301 aBuf
.append( maBubbleText
);
304 Image aImage
= GetMenuBarIcon( pActiveMBar
);
305 mnIconID
= pActiveMBar
->AddMenuBarButton( aImage
,
306 LINK( this, UpdateCheckUI
, ClickHdl
),
307 aBuf
.makeStringAndClear()
309 pActiveMBar
->SetMenuBarButtonHighlightHdl( mnIconID
,
310 LINK( this, UpdateCheckUI
, HighlightHdl
) );
312 mpIconMBar
= pActiveMBar
;
313 mpIconSysWin
= pSysWin
;
314 if ( bAddEventHdl
&& mpIconSysWin
)
315 mpIconSysWin
->AddEventListener( maWindowEventHdl
);
318 if ( mbShowBubble
&& pActiveMBar
)
320 mpBubbleWin
= GetBubbleWindow();
324 maTimeoutTimer
.Start();
326 mbShowBubble
= false;
331 void SAL_CALL
UpdateCheckUI::documentEventOccured(const document::DocumentEvent
& rEvent
)
333 SolarMutexGuard aGuard
;
335 if( rEvent
.EventName
== "OnPrepareViewClosing" )
337 RemoveBubbleWindow( true );
342 void SAL_CALL
UpdateCheckUI::disposing(const lang::EventObject
&)
347 uno::Reference
< beans::XPropertySetInfo
> UpdateCheckUI::getPropertySetInfo()
353 void UpdateCheckUI::setPropertyValue(const OUString
& rPropertyName
,
354 const uno::Any
& rValue
)
356 SolarMutexGuard aGuard
;
360 if( rPropertyName
== PROPERTY_TITLE
) {
362 if ( aString
!= maBubbleTitle
) {
363 maBubbleTitle
= aString
;
364 mbBubbleChanged
= true;
367 else if( rPropertyName
== PROPERTY_TEXT
) {
369 if ( aString
!= maBubbleText
) {
370 maBubbleText
= aString
;
371 mbBubbleChanged
= true;
374 else if( rPropertyName
== PROPERTY_IMAGE
) {
376 if ( aString
!= maBubbleImageURL
) {
377 maBubbleImageURL
= aString
;
378 maBubbleImage
= GetBubbleImage( maBubbleImageURL
);
379 mbBubbleChanged
= true;
382 else if( rPropertyName
== PROPERTY_SHOW_BUBBLE
) {
383 rValue
>>= mbShowBubble
;
385 Application::PostUserEvent( LINK( this, UpdateCheckUI
, UserEventHdl
) );
386 else if ( mpBubbleWin
)
387 mpBubbleWin
->Show( false );
389 else if( rPropertyName
== PROPERTY_CLICK_HDL
) {
390 uno::Reference
< task::XJob
> aJob
;
393 throw lang::IllegalArgumentException();
396 else if (rPropertyName
== PROPERTY_SHOW_MENUICON
) {
397 bool bShowMenuIcon
= false;
398 rValue
>>= bShowMenuIcon
;
399 if ( bShowMenuIcon
!= mbShowMenuIcon
)
401 mbShowMenuIcon
= bShowMenuIcon
;
403 Application::PostUserEvent( LINK( this, UpdateCheckUI
, UserEventHdl
) );
405 RemoveBubbleWindow( true );
409 throw beans::UnknownPropertyException();
411 if ( mbBubbleChanged
&& mpBubbleWin
)
412 mpBubbleWin
->Show( false );
416 uno::Any
UpdateCheckUI::getPropertyValue(const OUString
& rPropertyName
)
418 SolarMutexGuard aGuard
;
422 if( rPropertyName
== PROPERTY_TITLE
)
423 aRet
<<= maBubbleTitle
;
424 else if( rPropertyName
== PROPERTY_TEXT
)
425 aRet
<<= maBubbleText
;
426 else if( rPropertyName
== PROPERTY_SHOW_BUBBLE
)
427 aRet
<<= mbShowBubble
;
428 else if( rPropertyName
== PROPERTY_IMAGE
)
429 aRet
<<= maBubbleImageURL
;
430 else if( rPropertyName
== PROPERTY_CLICK_HDL
)
432 else if( rPropertyName
== PROPERTY_SHOW_MENUICON
)
433 aRet
<<= mbShowMenuIcon
;
435 throw beans::UnknownPropertyException();
441 void UpdateCheckUI::addPropertyChangeListener( const OUString
& /*aPropertyName*/,
442 const uno::Reference
< beans::XPropertyChangeListener
> & /*aListener*/)
444 //no bound properties
448 void UpdateCheckUI::removePropertyChangeListener( const OUString
& /*aPropertyName*/,
449 const uno::Reference
< beans::XPropertyChangeListener
> & /*aListener*/)
451 //no bound properties
455 void UpdateCheckUI::addVetoableChangeListener( const OUString
& /*aPropertyName*/,
456 const uno::Reference
< beans::XVetoableChangeListener
> & /*aListener*/)
458 //no vetoable properties
462 void UpdateCheckUI::removeVetoableChangeListener( const OUString
& /*aPropertyName*/,
463 const uno::Reference
< beans::XVetoableChangeListener
> & /*aListener*/)
465 //no vetoable properties
469 VclPtr
<BubbleWindow
> UpdateCheckUI::GetBubbleWindow()
474 tools::Rectangle aIconRect
= mpIconMBar
->GetMenuBarButtonRectPixel( mnIconID
);
475 if( aIconRect
.IsEmpty() )
478 auto pBubbleWin
= mpBubbleWin
;
481 pBubbleWin
= VclPtr
<BubbleWindow
>::Create( mpIconSysWin
, maBubbleTitle
,
482 maBubbleText
, maBubbleImage
);
483 mbBubbleChanged
= false;
485 else if ( mbBubbleChanged
) {
486 pBubbleWin
->SetTitleAndText( maBubbleTitle
, maBubbleText
,
488 mbBubbleChanged
= false;
491 Point aWinPos
= aIconRect
.BottomCenter();
493 pBubbleWin
->SetTipPosPixel( aWinPos
);
499 void UpdateCheckUI::RemoveBubbleWindow( bool bRemoveIcon
)
501 SolarMutexGuard aGuard
;
504 maTimeoutTimer
.Stop();
508 mpBubbleWin
.disposeAndClear();
514 if ( mpIconMBar
&& ( mnIconID
!= 0 ) )
516 mpIconMBar
->RemoveMenuBarButton( mnIconID
);
517 mpIconMBar
= nullptr;
522 mpIconMBar
= nullptr;
526 mpIconSysWin
= nullptr;
531 IMPL_LINK_NOARG(UpdateCheckUI
, ClickHdl
, MenuBar::MenuBarButtonCallbackArg
&, bool)
533 SolarMutexGuard aGuard
;
537 mpBubbleWin
->Show( false );
542 uno::Sequence
<beans::NamedValue
> aEmpty
;
543 mrJob
->execute( aEmpty
);
545 catch(const uno::Exception
&) {
546 std::unique_ptr
<weld::MessageDialog
> xErrorBox(Application::CreateMessageDialog(nullptr,
547 VclMessageType::Warning
, VclButtonsType::Ok
,
548 Translate::get(STR_NO_WEBBROWSER_FOUND
, maSfxLocale
)));
557 IMPL_LINK( UpdateCheckUI
, HighlightHdl
, MenuBar::MenuBarButtonCallbackArg
&, rData
, bool )
559 if ( rData
.bHighlight
)
562 RemoveBubbleWindow( false );
568 IMPL_LINK_NOARG(UpdateCheckUI
, WaitTimeOutHdl
, Timer
*, void)
570 SolarMutexGuard aGuard
;
572 mpBubbleWin
= GetBubbleWindow();
581 IMPL_LINK_NOARG(UpdateCheckUI
, TimeOutHdl
, Timer
*, void)
583 RemoveBubbleWindow( false );
587 IMPL_LINK_NOARG(UpdateCheckUI
, UserEventHdl
, void*, void)
589 SolarMutexGuard aGuard
;
591 vcl::Window
*pTopWin
= Application::GetFirstTopLevelWindow();
592 vcl::Window
*pActiveWin
= Application::GetActiveTopWindow();
593 SystemWindow
*pActiveSysWin
= nullptr;
595 vcl::Window
*pBubbleWin
= nullptr;
597 pBubbleWin
= mpBubbleWin
;
599 if ( pActiveWin
&& ( pActiveWin
!= pBubbleWin
) && pActiveWin
->IsTopWindow() )
600 pActiveSysWin
= pActiveWin
->GetSystemWindow();
602 if ( pActiveWin
== pBubbleWin
)
603 pActiveSysWin
= nullptr;
605 while ( !pActiveSysWin
&& pTopWin
)
607 if ( ( pTopWin
!= pBubbleWin
) && pTopWin
->IsTopWindow() )
608 pActiveSysWin
= pTopWin
->GetSystemWindow();
609 if ( !pActiveSysWin
)
610 pTopWin
= Application::GetNextTopLevelWindow( pTopWin
);
614 AddMenuBarIcon( pActiveSysWin
, true );
618 IMPL_LINK( UpdateCheckUI
, WindowEventHdl
, VclWindowEvent
&, rEvent
, void )
620 VclEventId nEventID
= rEvent
.GetId();
622 if ( VclEventId::ObjectDying
== nEventID
)
624 SolarMutexGuard aGuard
;
625 if ( mpIconSysWin
== rEvent
.GetWindow() )
627 mpIconSysWin
->RemoveEventListener( maWindowEventHdl
);
628 RemoveBubbleWindow( true );
631 else if ( VclEventId::WindowMenubarAdded
== nEventID
)
633 SolarMutexGuard aGuard
;
634 vcl::Window
*pWindow
= rEvent
.GetWindow();
637 SystemWindow
*pSysWin
= pWindow
->GetSystemWindow();
640 AddMenuBarIcon( pSysWin
, false );
644 else if ( VclEventId::WindowMenubarRemoved
== nEventID
)
646 SolarMutexGuard aGuard
;
647 MenuBar
*pMBar
= static_cast<MenuBar
*>(rEvent
.GetData());
648 if ( pMBar
&& ( pMBar
== mpIconMBar
) )
649 RemoveBubbleWindow( true );
651 else if ( ( nEventID
== VclEventId::WindowMove
) ||
652 ( nEventID
== VclEventId::WindowResize
) )
654 SolarMutexGuard aGuard
;
655 if ( ( mpIconSysWin
== rEvent
.GetWindow() ) &&
656 mpBubbleWin
&& ( mpIconMBar
!= nullptr ) )
658 tools::Rectangle aIconRect
= mpIconMBar
->GetMenuBarButtonRectPixel( mnIconID
);
659 Point aWinPos
= aIconRect
.BottomCenter();
660 mpBubbleWin
->SetTipPosPixel( aWinPos
);
661 if ( mpBubbleWin
->IsVisible() )
662 mpBubbleWin
->Show(); // This will recalc the screen position of the bubble
668 IMPL_LINK( UpdateCheckUI
, ApplicationEventHdl
, VclSimpleEvent
&, rEvent
, void)
670 switch (rEvent
.GetId())
672 case VclEventId::WindowShow
:
673 case VclEventId::WindowActivate
:
674 case VclEventId::WindowGetFocus
: {
675 SolarMutexGuard aGuard
;
677 vcl::Window
*pWindow
= static_cast< VclWindowEvent
* >(&rEvent
)->GetWindow();
678 if ( pWindow
&& pWindow
->IsTopWindow() )
680 SystemWindow
*pSysWin
= pWindow
->GetSystemWindow();
681 MenuBar
*pMBar
= pSysWin
? pSysWin
->GetMenuBar() : nullptr;
684 AddMenuBarIcon( pSysWin
, true );
694 #define TIP_HEIGHT 15
696 #define TIP_RIGHT_OFFSET 18
697 #define BUBBLE_BORDER 10
698 #define TEXT_MAX_WIDTH 300
699 #define TEXT_MAX_HEIGHT 200
702 BubbleWindow::BubbleWindow( vcl::Window
* pParent
, const OUString
& rTitle
,
703 const OUString
& rText
, const Image
& rImage
)
704 : FloatingWindow( pParent
, WB_SYSTEMWINDOW
705 | WB_OWNERDRAWDECORATION
708 , maBubbleTitle( rTitle
)
709 , maBubbleText( rText
)
710 , maBubbleImage( rImage
)
711 , maMaxTextSize( TEXT_MAX_WIDTH
, TEXT_MAX_HEIGHT
)
714 SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetHelpColor() ) );
717 void BubbleWindow::Resize()
719 SolarMutexGuard aGuard
;
721 FloatingWindow::Resize();
723 Size aSize
= GetSizePixel();
725 if ( ( aSize
.Height() < 20 ) || ( aSize
.Width() < 60 ) )
728 tools::Rectangle
aRect( 0, TIP_HEIGHT
, aSize
.Width(), aSize
.Height() - TIP_HEIGHT
);
729 maRectPoly
= tools::Polygon( aRect
, 6, 6 );
730 vcl::Region
aRegion( maRectPoly
);
731 long nTipOffset
= aSize
.Width() - TIP_RIGHT_OFFSET
+ mnTipOffset
;
734 aPointArr
[0] = Point( nTipOffset
, TIP_HEIGHT
);
735 aPointArr
[1] = Point( nTipOffset
, 0 );
736 aPointArr
[2] = Point( nTipOffset
+ TIP_WIDTH
, TIP_HEIGHT
);
737 aPointArr
[3] = Point( nTipOffset
, TIP_HEIGHT
);
738 maTriPoly
= tools::Polygon( 4, aPointArr
);
739 vcl::Region
aTriRegion( maTriPoly
);
741 aRegion
.Union( aTriRegion
);
744 SetWindowRegionPixel( maBounds
);
748 void BubbleWindow::SetTitleAndText( const OUString
& rTitle
,
749 const OUString
& rText
,
750 const Image
& rImage
)
752 maBubbleTitle
= rTitle
;
753 maBubbleText
= rText
;
754 maBubbleImage
= rImage
;
760 void BubbleWindow::Paint(vcl::RenderContext
& /*rRenderContext*/, const tools::Rectangle
& /*rRect*/)
762 SolarMutexGuard aGuard
;
764 LineInfo
aThickLine( LineStyle::Solid
, 2 );
766 DrawPolyLine( maRectPoly
, aThickLine
);
767 DrawPolyLine( maTriPoly
);
769 Color aOldLine
= GetLineColor();
770 Size aSize
= GetSizePixel();
771 long nTipOffset
= aSize
.Width() - TIP_RIGHT_OFFSET
+ mnTipOffset
;
773 SetLineColor( GetSettings().GetStyleSettings().GetHelpColor() );
774 DrawLine( Point( nTipOffset
+2, TIP_HEIGHT
),
775 Point( nTipOffset
+ TIP_WIDTH
-1 , TIP_HEIGHT
),
777 SetLineColor( aOldLine
);
779 Size aImgSize
= maBubbleImage
.GetSizePixel();
781 DrawImage( Point( BUBBLE_BORDER
, BUBBLE_BORDER
+ TIP_HEIGHT
), maBubbleImage
);
783 vcl::Font aOldFont
= GetFont();
784 vcl::Font aBoldFont
= aOldFont
;
785 aBoldFont
.SetWeight( WEIGHT_BOLD
);
787 SetFont( aBoldFont
);
788 tools::Rectangle aTitleRect
= maTitleRect
;
789 aTitleRect
.Move( aImgSize
.Width(), 0 );
790 DrawText( aTitleRect
, maBubbleTitle
, DrawTextFlags::MultiLine
| DrawTextFlags::WordBreak
);
793 tools::Rectangle aTextRect
= maTextRect
;
794 aTextRect
.Move( aImgSize
.Width(), 0 );
795 DrawText( aTextRect
, maBubbleText
, DrawTextFlags::MultiLine
| DrawTextFlags::WordBreak
);
799 void BubbleWindow::MouseButtonDown( const MouseEvent
& )
805 void BubbleWindow::Show( bool bVisible
, ShowFlags nFlags
)
807 SolarMutexGuard aGuard
;
811 FloatingWindow::Show( bVisible
);
815 // don't show bubbles without a text
816 if ( ( maBubbleTitle
.isEmpty() ) && ( maBubbleText
.isEmpty() ) )
819 Size aWindowSize
= GetSizePixel();
821 Size aImgSize
= maBubbleImage
.GetSizePixel();
825 aWindowSize
.setHeight( maTitleRect
.GetHeight() * 7 / 4+ maTextRect
.GetHeight() +
826 3 * BUBBLE_BORDER
+ TIP_HEIGHT
);
828 if ( maTitleRect
.GetWidth() > maTextRect
.GetWidth() )
829 aWindowSize
.setWidth( maTitleRect
.GetWidth() );
831 aWindowSize
.setWidth( maTextRect
.GetWidth() );
833 aWindowSize
.setWidth( aWindowSize
.Width() + 3 * BUBBLE_BORDER
+ aImgSize
.Width() );
835 if ( aWindowSize
.Height() < aImgSize
.Height() + TIP_HEIGHT
+ 2 * BUBBLE_BORDER
)
836 aWindowSize
.setHeight( aImgSize
.Height() + TIP_HEIGHT
+ 2 * BUBBLE_BORDER
);
839 aPos
.setX( maTipPos
.X() - aWindowSize
.Width() + TIP_RIGHT_OFFSET
);
840 aPos
.setY( maTipPos
.Y() );
841 Point aScreenPos
= GetParent()->OutputToAbsoluteScreenPixel( aPos
);
842 if ( aScreenPos
.X() < 0 )
844 mnTipOffset
= aScreenPos
.X();
845 aPos
.AdjustX( -mnTipOffset
);
847 SetPosSizePixel( aPos
, aWindowSize
);
849 FloatingWindow::Show( bVisible
, nFlags
);
853 void BubbleWindow::RecalcTextRects()
856 bool bFinished
= false;
857 vcl::Font aOldFont
= GetFont();
858 vcl::Font aBoldFont
= aOldFont
;
860 aBoldFont
.SetWeight( WEIGHT_BOLD
);
864 SetFont( aBoldFont
);
866 maTitleRect
= GetTextRect( tools::Rectangle( Point( 0, 0 ), maMaxTextSize
),
868 DrawTextFlags::MultiLine
| DrawTextFlags::WordBreak
);
871 maTextRect
= GetTextRect( tools::Rectangle( Point( 0, 0 ), maMaxTextSize
),
873 DrawTextFlags::MultiLine
| DrawTextFlags::WordBreak
);
875 if ( maTextRect
.GetHeight() < 10 )
876 maTextRect
.setHeight( 10 );
878 aTotalSize
.setHeight( maTitleRect
.GetHeight() +
879 aBoldFont
.GetFontHeight() * 3 / 4 +
880 maTextRect
.GetHeight() +
881 3 * BUBBLE_BORDER
+ TIP_HEIGHT
);
882 if ( aTotalSize
.Height() > maMaxTextSize
.Height() )
884 maMaxTextSize
.setWidth( maMaxTextSize
.Width() * 3 / 2 );
885 maMaxTextSize
.setHeight( maMaxTextSize
.Height() * 3 / 2 );
890 maTitleRect
.Move( 2*BUBBLE_BORDER
, BUBBLE_BORDER
+ TIP_HEIGHT
);
891 maTextRect
.Move( 2*BUBBLE_BORDER
, BUBBLE_BORDER
+ TIP_HEIGHT
+ maTitleRect
.GetHeight() + aBoldFont
.GetFontHeight() * 3 / 4 );
895 } // anonymous namespace
898 static uno::Reference
<uno::XInterface
>
899 createInstance(const uno::Reference
<uno::XComponentContext
>& xContext
)
901 SolarMutexGuard aGuard
;
902 return *new UpdateCheckUI(xContext
);
906 static const cppu::ImplementationEntry kImplementations_entries
[] =
910 getImplementationName
,
912 cppu::createSingleComponentFactory
,
916 { nullptr, nullptr, nullptr, nullptr, nullptr, 0 }
920 extern "C" SAL_DLLPUBLIC_EXPORT
void * updchkui_component_getFactory(const sal_Char
*pszImplementationName
, void *pServiceManager
, void *pRegistryKey
)
922 return cppu::component_getFactoryHelper(
923 pszImplementationName
,
926 kImplementations_entries
) ;
929 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */