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 .
20 #include <uielement/statusbarmanager.hxx>
21 #include <uielement/genericstatusbarcontroller.hxx>
23 #include <framework/sfxhelperfunctions.hxx>
24 #include <framework/addonsoptions.hxx>
25 #include <uielement/statusbarmerger.hxx>
26 #include <uielement/statusbaritem.hxx>
27 #include <com/sun/star/frame/XLayoutManager.hpp>
28 #include <com/sun/star/frame/theStatusbarControllerFactory.hpp>
29 #include <com/sun/star/ui/ItemStyle.hpp>
30 #include <com/sun/star/ui/ItemType.hpp>
31 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/awt/Command.hpp>
35 #include <com/sun/star/ui/XStatusbarItem.hpp>
36 #include <comphelper/processfactory.hxx>
37 #include <comphelper/propertyvalue.hxx>
38 #include <comphelper/sequence.hxx>
39 #include <toolkit/helper/vclunohelper.hxx>
40 #include <svtools/statusbarcontroller.hxx>
41 #include <tools/debug.hxx>
44 #include <vcl/commandevent.hxx>
45 #include <vcl/event.hxx>
46 #include <vcl/status.hxx>
47 #include <vcl/svapp.hxx>
48 #include <vcl/settings.hxx>
49 #include <vcl/commandinfoprovider.hxx>
53 using namespace ::com::sun::star
;
62 struct lcl_UpdateController
64 void operator()( typename
MAP::value_type
&rElement
) const
68 if ( rElement
.second
.is() )
69 rElement
.second
->update();
71 catch ( uno::Exception
& )
78 struct lcl_RemoveController
80 void operator()( typename
MAP::value_type
&rElement
) const
84 if ( rElement
.second
.is() )
85 rElement
.second
->dispose();
87 catch ( uno::Exception
& )
93 StatusBarItemBits
impl_convertItemStyleToItemBits( sal_Int16 nStyle
)
95 StatusBarItemBits
nItemBits( StatusBarItemBits::NONE
);
97 if (( nStyle
& css::ui::ItemStyle::ALIGN_RIGHT
) == css::ui::ItemStyle::ALIGN_RIGHT
)
98 nItemBits
|= StatusBarItemBits::Right
;
99 else if ( nStyle
& css::ui::ItemStyle::ALIGN_LEFT
)
100 nItemBits
|= StatusBarItemBits::Left
;
102 nItemBits
|= StatusBarItemBits::Center
;
104 if (( nStyle
& css::ui::ItemStyle::DRAW_FLAT
) == css::ui::ItemStyle::DRAW_FLAT
)
105 nItemBits
|= StatusBarItemBits::Flat
;
106 else if ( nStyle
& css::ui::ItemStyle::DRAW_OUT3D
)
107 nItemBits
|= StatusBarItemBits::Out
;
109 nItemBits
|= StatusBarItemBits::In
;
111 if (( nStyle
& css::ui::ItemStyle::AUTO_SIZE
) == css::ui::ItemStyle::AUTO_SIZE
)
112 nItemBits
|= StatusBarItemBits::AutoSize
;
113 if ( nStyle
& css::ui::ItemStyle::OWNER_DRAW
)
114 nItemBits
|= StatusBarItemBits::UserDraw
;
116 if ( nStyle
& css::ui::ItemStyle::MANDATORY
)
117 nItemBits
|= StatusBarItemBits::Mandatory
;
124 StatusBarManager::StatusBarManager(
125 uno::Reference
< uno::XComponentContext
> xContext
,
126 uno::Reference
< frame::XFrame
> rFrame
,
127 StatusBar
* pStatusBar
) :
128 m_bDisposed( false ),
129 m_bFrameActionRegistered( false ),
130 m_bUpdateControllers( false ),
131 m_pStatusBar( pStatusBar
),
132 m_xFrame(std::move( rFrame
)),
133 m_xContext(std::move( xContext
))
136 m_xStatusbarControllerFactory
= frame::theStatusbarControllerFactory::get(
137 ::comphelper::getProcessComponentContext());
139 m_pStatusBar
->AdjustItemWidthsForHiDPI();
140 m_pStatusBar
->SetClickHdl( LINK( this, StatusBarManager
, Click
) );
141 m_pStatusBar
->SetDoubleClickHdl( LINK( this, StatusBarManager
, DoubleClick
) );
144 StatusBarManager::~StatusBarManager()
148 StatusBar
* StatusBarManager::GetStatusBar() const
154 void StatusBarManager::frameAction( const frame::FrameActionEvent
& Action
)
157 if ( Action
.Action
== frame::FrameAction_CONTEXT_CHANGED
)
161 void SAL_CALL
StatusBarManager::disposing( const lang::EventObject
& Source
)
170 if ( Source
.Source
== uno::Reference
< uno::XInterface
>( m_xFrame
, uno::UNO_QUERY
))
177 void SAL_CALL
StatusBarManager::dispose()
179 uno::Reference
< lang::XComponent
> xThis(this );
182 lang::EventObject
aEvent( xThis
);
183 std::unique_lock
aGuard(m_mutex
);
184 m_aListenerContainer
.disposeAndClear( aGuard
, aEvent
);
193 // destroy the item data
194 for ( sal_uInt16 n
= 0; n
< m_pStatusBar
->GetItemCount(); n
++ )
196 AddonStatusbarItemData
*pUserData
= static_cast< AddonStatusbarItemData
*>(
197 m_pStatusBar
->GetItemData( m_pStatusBar
->GetItemId( n
) ) );
201 m_pStatusBar
.disposeAndClear();
203 if ( m_bFrameActionRegistered
&& m_xFrame
.is() )
207 m_xFrame
->removeFrameActionListener( uno::Reference
< frame::XFrameActionListener
>(this) );
209 catch ( const uno::Exception
& )
221 void SAL_CALL
StatusBarManager::addEventListener( const uno::Reference
< lang::XEventListener
>& xListener
)
225 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
227 throw lang::DisposedException();
229 std::unique_lock
aGuard(m_mutex
);
230 m_aListenerContainer
.addInterface( aGuard
, xListener
);
233 void SAL_CALL
StatusBarManager::removeEventListener( const uno::Reference
< lang::XEventListener
>& xListener
)
235 std::unique_lock
aGuard(m_mutex
);
236 m_aListenerContainer
.removeInterface( aGuard
, xListener
);
239 // XUIConfigurationListener
240 void SAL_CALL
StatusBarManager::elementInserted( const css::ui::ConfigurationEvent
& )
248 void SAL_CALL
StatusBarManager::elementRemoved( const css::ui::ConfigurationEvent
& )
256 void SAL_CALL
StatusBarManager::elementReplaced( const css::ui::ConfigurationEvent
& )
264 void StatusBarManager::UpdateControllers()
266 if ( !m_bUpdateControllers
)
268 m_bUpdateControllers
= true;
269 std::for_each( m_aControllerMap
.begin(),
270 m_aControllerMap
.end(),
271 lcl_UpdateController
< StatusBarControllerMap
>() );
273 m_bUpdateControllers
= false;
276 void StatusBarManager::RemoveControllers()
278 DBG_TESTSOLARMUTEX();
279 assert(!m_bDisposed
);
281 std::for_each( m_aControllerMap
.begin(),
282 m_aControllerMap
.end(),
283 lcl_RemoveController
< StatusBarControllerMap
>() );
284 m_aControllerMap
.clear();
287 void StatusBarManager::CreateControllers()
289 uno::Reference
< awt::XWindow
> xStatusbarWindow
= VCLUnoHelper::GetInterface( m_pStatusBar
);
291 for ( sal_uInt16 i
= 0; i
< m_pStatusBar
->GetItemCount(); i
++ )
293 sal_uInt16 nId
= m_pStatusBar
->GetItemId( i
);
297 OUString
aCommandURL( m_pStatusBar
->GetItemCommand( nId
));
299 uno::Reference
< frame::XStatusbarController
> xController
;
300 AddonStatusbarItemData
*pItemData
= static_cast< AddonStatusbarItemData
*>( m_pStatusBar
->GetItemData( nId
) );
301 uno::Reference
< ui::XStatusbarItem
> xStatusbarItem
= new StatusbarItem( m_pStatusBar
, nId
, aCommandURL
);
303 std::vector
< uno::Any
> aPropVector
305 uno::Any(comphelper::makePropertyValue(u
"CommandURL"_ustr
, aCommandURL
)),
306 uno::Any(comphelper::makePropertyValue(u
"ModuleIdentifier"_ustr
, u
""_ustr
)),
307 uno::Any(comphelper::makePropertyValue(u
"Frame"_ustr
, m_xFrame
)),
310 uno::Any(comphelper::makePropertyValue(u
"ServiceManager"_ustr
, uno::Reference
<lang::XMultiServiceFactory
>(m_xContext
->getServiceManager(), uno::UNO_QUERY_THROW
))),
312 uno::Any(comphelper::makePropertyValue(u
"ParentWindow"_ustr
, xStatusbarWindow
)),
313 uno::Any(comphelper::makePropertyValue(u
"Identifier"_ustr
, nId
)),
314 uno::Any(comphelper::makePropertyValue(u
"StatusbarItem"_ustr
, xStatusbarItem
))
317 uno::Sequence
< uno::Any
> aArgs( comphelper::containerToSequence( aPropVector
) );
319 // 1) UNO Statusbar controllers, registered in Controllers.xcu
320 if ( m_xStatusbarControllerFactory
.is() &&
321 m_xStatusbarControllerFactory
->hasController( aCommandURL
, u
""_ustr
))
323 xController
.set(m_xStatusbarControllerFactory
->createInstanceWithArgumentsAndContext(
324 aCommandURL
, aArgs
, m_xContext
),
326 bInit
= false; // Initialization is done through the factory service
329 if ( !xController
.is() )
331 // 2) Old SFX2 Statusbar controllers
332 xController
= CreateStatusBarController( m_xFrame
, m_pStatusBar
, nId
, aCommandURL
);
335 // 3) Is Add-on? Generic statusbar controller
338 xController
= new GenericStatusbarController( m_xContext
,
345 // 4) Default Statusbar controller
346 xController
= new svt::StatusbarController( m_xContext
, m_xFrame
, aCommandURL
, nId
);
351 m_aControllerMap
[nId
] = xController
;
354 xController
->initialize( aArgs
);
358 // add frame action listeners
359 if ( !m_bFrameActionRegistered
&& m_xFrame
.is() )
361 m_bFrameActionRegistered
= true;
362 m_xFrame
->addFrameActionListener( uno::Reference
< frame::XFrameActionListener
>(this) );
366 void StatusBarManager::FillStatusBar( const uno::Reference
< container::XIndexAccess
>& rItemContainer
)
370 if ( m_bDisposed
|| !m_pStatusBar
)
377 // reset and fill command map
378 m_pStatusBar
->Clear();
379 m_aControllerMap
.clear();// TODO already done in RemoveControllers
381 for ( sal_Int32 n
= 0; n
< rItemContainer
->getCount(); n
++ )
383 uno::Sequence
< beans::PropertyValue
> aProps
;
384 OUString aCommandURL
;
385 sal_Int16
nOffset( 0 );
386 sal_Int16
nStyle( 0 );
387 sal_Int16
nWidth( 0 );
388 sal_uInt16
nType( css::ui::ItemType::DEFAULT
);
392 if ( rItemContainer
->getByIndex( n
) >>= aProps
)
394 for (beans::PropertyValue
const& prop
: aProps
)
396 if ( prop
.Name
== "CommandURL" )
398 prop
.Value
>>= aCommandURL
;
400 else if ( prop
.Name
== "Style" )
402 prop
.Value
>>= nStyle
;
404 else if ( prop
.Name
== "Type" )
406 prop
.Value
>>= nType
;
408 else if ( prop
.Name
== "Width" )
410 prop
.Value
>>= nWidth
;
412 else if ( prop
.Name
== "Offset" )
414 prop
.Value
>>= nOffset
;
418 if (( nType
== css::ui::ItemType::DEFAULT
) && !aCommandURL
.isEmpty() )
420 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(aCommandURL
, u
""_ustr
);
421 OUString
aString(vcl::CommandInfoProvider::GetLabelForCommand(aProperties
));
422 StatusBarItemBits
nItemBits( impl_convertItemStyleToItemBits( nStyle
));
424 m_pStatusBar
->InsertItem( nId
, nWidth
, nItemBits
, nOffset
);
425 m_pStatusBar
->SetItemCommand( nId
, aCommandURL
);
426 m_pStatusBar
->SetAccessibleName( nId
, aString
);
431 catch ( const css::lang::IndexOutOfBoundsException
& )
438 constexpr sal_uInt16 STATUSBAR_ITEM_STARTID
= 1000;
439 MergeStatusbarInstructionContainer aMergeInstructions
= AddonsOptions().GetMergeStatusbarInstructions();
440 if ( !aMergeInstructions
.empty() )
442 const sal_uInt32 nCount
= aMergeInstructions
.size();
443 sal_uInt16
nItemId( STATUSBAR_ITEM_STARTID
);
445 for ( sal_uInt32 i
= 0; i
< nCount
; i
++ )
447 MergeStatusbarInstruction
&rInstruction
= aMergeInstructions
[i
];
448 if ( !StatusbarMerger::IsCorrectContext( rInstruction
.aMergeContext
) )
451 AddonStatusbarItemContainer aItems
;
452 StatusbarMerger::ConvertSeqSeqToVector( rInstruction
.aMergeStatusbarItems
, aItems
);
454 sal_uInt16 nRefPos
= StatusbarMerger::FindReferencePos( m_pStatusBar
, rInstruction
.aMergePoint
);
455 if ( nRefPos
!= STATUSBAR_ITEM_NOTFOUND
)
457 StatusbarMerger::ProcessMergeOperation( m_pStatusBar
,
460 rInstruction
.aMergeCommand
,
461 rInstruction
.aMergeCommandParameter
,
466 StatusbarMerger::ProcessMergeFallback( m_pStatusBar
,
468 rInstruction
.aMergeCommand
,
469 rInstruction
.aMergeCommandParameter
,
475 // Create controllers
478 // Notify controllers that they are now correctly initialized and can start listening
482 void StatusBarManager::DataChanged( const DataChangedEvent
& rDCEvt
)
484 SolarMutexClearableGuard aGuard
;
486 if ((( rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) ||
487 ( rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
488 ( rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
489 ( rDCEvt
.GetType() == DataChangedEventType::DISPLAY
)) &&
490 ( rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
492 css::uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
;
493 css::uno::Reference
< css::beans::XPropertySet
> xPropSet( m_xFrame
, css::uno::UNO_QUERY
);
495 xPropSet
->getPropertyValue(u
"LayoutManager"_ustr
) >>= xLayoutManager
;
496 if ( xLayoutManager
.is() )
499 xLayoutManager
->doLayout();
504 void StatusBarManager::UserDraw( const UserDrawEvent
& rUDEvt
)
506 SolarMutexClearableGuard aGuard
;
511 sal_uInt16
nId( rUDEvt
.GetItemId() );
512 StatusBarControllerMap::const_iterator it
= m_aControllerMap
.find( nId
);
513 if (( nId
<= 0 ) || ( it
== m_aControllerMap
.end() ))
516 uno::Reference
< frame::XStatusbarController
> xController( it
->second
);
517 if (xController
.is() && rUDEvt
.GetRenderContext())
519 uno::Reference
< awt::XGraphics
> xGraphics
= rUDEvt
.GetRenderContext()->CreateUnoGraphics();
521 awt::Rectangle
aRect( rUDEvt
.GetRect().Left(),
522 rUDEvt
.GetRect().Top(),
523 rUDEvt
.GetRect().GetWidth(),
524 rUDEvt
.GetRect().GetHeight() );
526 xController
->paint(xGraphics
, aRect
, 0);
530 void StatusBarManager::Command( const CommandEvent
& rEvt
)
537 if ( rEvt
.GetCommand() != CommandEventId::ContextMenu
)
540 sal_uInt16 nId
= m_pStatusBar
->GetItemId( rEvt
.GetMousePosPixel() );
541 StatusBarControllerMap::const_iterator it
= m_aControllerMap
.find( nId
);
542 if (( nId
> 0 ) && ( it
!= m_aControllerMap
.end() ))
544 uno::Reference
< frame::XStatusbarController
> xController( it
->second
);
545 if ( xController
.is() )
548 aPos
.X
= rEvt
.GetMousePosPixel().X();
549 aPos
.Y
= rEvt
.GetMousePosPixel().Y();
550 xController
->command( aPos
, awt::Command::CONTEXTMENU
, true, uno::Any() );
555 void StatusBarManager::MouseMove( const MouseEvent
& rMEvt
)
557 MouseButton(rMEvt
,&frame::XStatusbarController::mouseMove
);
560 void StatusBarManager::MouseButton( const MouseEvent
& rMEvt
,sal_Bool ( SAL_CALL
frame::XStatusbarController::*_pMethod
)(const css::awt::MouseEvent
&))
567 sal_uInt16 nId
= m_pStatusBar
->GetItemId( rMEvt
.GetPosPixel() );
568 StatusBarControllerMap::const_iterator it
= m_aControllerMap
.find( nId
);
569 if (( nId
<= 0 ) || ( it
== m_aControllerMap
.end() ))
572 uno::Reference
< frame::XStatusbarController
> xController( it
->second
);
573 if ( xController
.is() )
575 css::awt::MouseEvent aMouseEvent
;
576 aMouseEvent
.Buttons
= rMEvt
.GetButtons();
577 aMouseEvent
.X
= rMEvt
.GetPosPixel().X();
578 aMouseEvent
.Y
= rMEvt
.GetPosPixel().Y();
579 aMouseEvent
.ClickCount
= rMEvt
.GetClicks();
580 (xController
.get()->*_pMethod
)( aMouseEvent
);
584 void StatusBarManager::MouseButtonDown( const MouseEvent
& rMEvt
)
586 MouseButton(rMEvt
,&frame::XStatusbarController::mouseButtonDown
);
589 void StatusBarManager::MouseButtonUp( const MouseEvent
& rMEvt
)
591 MouseButton(rMEvt
,&frame::XStatusbarController::mouseButtonUp
);
594 IMPL_LINK_NOARG(StatusBarManager
, Click
, StatusBar
*, void)
601 sal_uInt16 nId
= m_pStatusBar
->GetCurItemId();
602 StatusBarControllerMap::const_iterator it
= m_aControllerMap
.find( nId
);
603 if (( nId
> 0 ) && ( it
!= m_aControllerMap
.end() ))
605 uno::Reference
< frame::XStatusbarController
> xController( it
->second
);
606 if ( xController
.is() )
608 const Point aVCLPos
= m_pStatusBar
->GetPointerPosPixel();
609 const awt::Point
aAWTPoint( aVCLPos
.X(), aVCLPos
.Y() );
610 xController
->click( aAWTPoint
);
615 IMPL_LINK_NOARG(StatusBarManager
, DoubleClick
, StatusBar
*, void)
622 sal_uInt16 nId
= m_pStatusBar
->GetCurItemId();
623 StatusBarControllerMap::const_iterator it
= m_aControllerMap
.find( nId
);
624 if (( nId
> 0 ) && ( it
!= m_aControllerMap
.end() ))
626 uno::Reference
< frame::XStatusbarController
> xController( it
->second
);
627 if ( xController
.is() )
629 const Point aVCLPos
= m_pStatusBar
->GetPointerPosPixel();
630 const awt::Point
aAWTPoint( aVCLPos
.X(), aVCLPos
.Y() );
631 xController
->doubleClick( aAWTPoint
);
638 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */