Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / framework / source / uielement / resourcemenucontroller.cxx
blob065a97c63a475302dffc4ee197434b2e517fae22
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/menubarmanager.hxx>
22 #include <cppuhelper/implbase.hxx>
23 #include <svtools/popupmenucontrollerbase.hxx>
24 #include <toolkit/awt/vclxmenu.hxx>
25 #include <toolkit/helper/vclunohelper.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/window.hxx>
28 #include <sal/log.hxx>
30 #include <com/sun/star/embed/VerbAttributes.hpp>
31 #include <com/sun/star/embed/VerbDescriptor.hpp>
32 #include <com/sun/star/frame/Desktop.hpp>
33 #include <com/sun/star/frame/ModuleManager.hpp>
34 #include <com/sun/star/frame/XStorable.hpp>
35 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
36 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
37 #include <com/sun/star/util/URL.hpp>
39 namespace {
41 class ResourceMenuController : public cppu::ImplInheritanceHelper< svt::PopupMenuControllerBase, css::ui::XUIConfigurationListener >
43 public:
44 ResourceMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
45 const css::uno::Sequence< css::uno::Any >& rxArgs, bool bToolbarContainer );
47 // XPopupMenuController
48 virtual void SAL_CALL updatePopupMenu() override;
50 // XStatusListener
51 virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
53 // XEventListener
54 virtual void SAL_CALL disposing( const css::lang::EventObject& rEvent ) override;
56 // XUIConfigurationListener
57 virtual void SAL_CALL elementInserted( const css::ui::ConfigurationEvent& rEvent ) override;
58 virtual void SAL_CALL elementRemoved( const css::ui::ConfigurationEvent& rEvent ) override;
59 virtual void SAL_CALL elementReplaced( const css::ui::ConfigurationEvent& rEvent ) override;
61 // XMenuListener
62 virtual void SAL_CALL itemActivated( const css::awt::MenuEvent& rEvent ) override;
63 virtual void SAL_CALL itemSelected( const css::awt::MenuEvent& rEvent ) override;
65 // XServiceInfo
66 virtual OUString SAL_CALL getImplementationName() override;
67 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
69 private:
70 OUString m_aMenuURL;
71 bool m_bContextMenu;
72 bool m_bInToolbar;
73 bool m_bToolbarContainer;
74 sal_uInt16 m_nNewMenuId;
75 rtl::Reference< framework::MenuBarManager > m_xMenuBarManager;
76 css::uno::Reference< css::frame::XDispatchProvider > m_xDispatchProvider;
77 css::uno::Reference< css::container::XIndexAccess > m_xMenuContainer;
78 css::uno::Reference< css::ui::XUIConfigurationManager > m_xConfigManager, m_xModuleConfigManager;
79 void addVerbs( const css::uno::Sequence< css::embed::VerbDescriptor >& rVerbs );
80 virtual void disposing(std::unique_lock<std::mutex>& rGuard) override;
82 protected:
83 css::uno::Reference< css::uno::XComponentContext > m_xContext;
86 ResourceMenuController::ResourceMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
87 const css::uno::Sequence< css::uno::Any >& rxArgs, bool bToolbarContainer ) :
88 ImplInheritanceHelper( rxContext ),
89 m_bContextMenu( false ),
90 m_bInToolbar( false ),
91 m_bToolbarContainer( bToolbarContainer ),
92 m_nNewMenuId( 1 ),
93 m_xContext( rxContext )
95 for ( const auto& arg: rxArgs )
97 css::beans::PropertyValue aPropValue;
98 if ( arg >>= aPropValue )
100 if ( aPropValue.Name == "Value" )
102 OUString aMenuName;
103 aPropValue.Value >>= aMenuName;
104 if ( aMenuName.isEmpty() )
105 continue;
107 if ( m_bToolbarContainer )
108 m_aMenuURL = "private:resource/toolbar/" + aMenuName;
109 else
110 m_aMenuURL = "private:resource/popupmenu/" + aMenuName;
112 else if ( aPropValue.Name == "ResourceURL" )
113 aPropValue.Value >>= m_aMenuURL;
114 else if ( aPropValue.Name == "Frame" )
115 aPropValue.Value >>= m_xFrame;
116 else if ( aPropValue.Name == "ModuleIdentifier" )
117 aPropValue.Value >>= m_aModuleName;
118 else if ( aPropValue.Name == "DispatchProvider" )
119 aPropValue.Value >>= m_xDispatchProvider;
120 else if ( aPropValue.Name == "IsContextMenu" )
121 aPropValue.Value >>= m_bContextMenu;
122 else if ( aPropValue.Name == "InToolbar" )
123 aPropValue.Value >>= m_bInToolbar;
126 if ( m_xFrame.is() )
127 // No need to initialize again through initialize method.
128 m_bInitialized = true;
131 void ResourceMenuController::updatePopupMenu()
133 if ( ( m_xMenuContainer.is() && !m_bContextMenu ) || m_aMenuURL.isEmpty() )
134 return;
136 if ( m_aModuleName.isEmpty() )
140 css::uno::Reference< css::frame::XModuleManager > xModuleManager( css::frame::ModuleManager::create( m_xContext ) );
141 m_aModuleName = xModuleManager->identify( m_xFrame );
143 catch( const css::uno::Exception& )
147 if ( !m_xConfigManager.is() )
151 css::uno::Reference< css::frame::XController > xController( m_xFrame->getController() );
152 css::uno::Reference< css::frame::XModel > xModel( xController->getModel() );
153 css::uno::Reference< css::ui::XUIConfigurationManagerSupplier > xSupplier( xModel, css::uno::UNO_QUERY_THROW );
154 m_xConfigManager.set( xSupplier->getUIConfigurationManager() );
155 css::uno::Reference< css::ui::XUIConfiguration > xConfig( m_xConfigManager, css::uno::UNO_QUERY_THROW );
156 xConfig->addConfigurationListener( this );
158 catch( const css::uno::RuntimeException& )
162 if ( !m_xModuleConfigManager.is() )
166 css::uno::Reference< css::ui::XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier(
167 css::ui::theModuleUIConfigurationManagerSupplier::get( m_xContext ) );
168 m_xModuleConfigManager.set( xModuleCfgMgrSupplier->getUIConfigurationManager( m_aModuleName ) );
169 css::uno::Reference< css::ui::XUIConfiguration > xConfig( m_xModuleConfigManager, css::uno::UNO_QUERY_THROW );
170 xConfig->addConfigurationListener( this );
172 catch ( const css::container::NoSuchElementException& )
174 SAL_WARN( "fwk.uielement", "Invalid module identifier: " << m_aModuleName );
176 catch( const css::uno::RuntimeException& )
180 if ( !m_xMenuContainer.is() && m_xConfigManager.is() )
184 m_xMenuContainer.set( m_xConfigManager->getSettings( m_aMenuURL, false ) );
186 catch ( const css::container::NoSuchElementException& )
188 // Not an error - element may exist only in the module.
190 catch ( const css::lang::IllegalArgumentException& )
192 SAL_WARN( "fwk.uielement", "The given URL is not valid: " << m_aMenuURL );
193 return;
197 if ( !m_xMenuContainer.is() && m_xModuleConfigManager.is() )
201 m_xMenuContainer.set( m_xModuleConfigManager->getSettings( m_aMenuURL, false ) );
203 catch ( const css::container::NoSuchElementException& )
205 SAL_WARN( "fwk.uielement", "Can not find settings for " << m_aMenuURL );
206 return;
208 catch ( const css::lang::IllegalArgumentException& )
210 SAL_WARN( "fwk.uielement", "The given URL is not valid: " << m_aMenuURL );
211 return;
215 if ( !m_xMenuContainer.is() )
216 return;
218 // Clear previous content.
219 if ( m_xMenuBarManager.is() )
221 m_xMenuBarManager->dispose();
222 m_xMenuBarManager.clear();
224 resetPopupMenu( m_xPopupMenu );
225 m_nNewMenuId = 1;
227 // Now fill the menu with the configuration data.
228 framework::MenuBarManager::FillMenu( m_nNewMenuId, m_xPopupMenu->GetMenu(), m_aModuleName, m_xMenuContainer, m_xDispatchProvider );
230 // For context menus, add object verbs.
231 if ( !m_bContextMenu )
232 return;
234 css::util::URL aObjectMenuURL;
235 aObjectMenuURL.Complete = ".uno:ObjectMenue";
236 m_xURLTransformer->parseStrict( aObjectMenuURL );
237 css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( m_xFrame, css::uno::UNO_QUERY );
238 css::uno::Reference< css::frame::XDispatch > xDispatch( xDispatchProvider->queryDispatch( aObjectMenuURL, OUString(), 0 ) );
239 if ( xDispatch.is() )
241 xDispatch->addStatusListener( this, aObjectMenuURL );
242 xDispatch->removeStatusListener( this, aObjectMenuURL );
246 void ResourceMenuController::statusChanged( const css::frame::FeatureStateEvent& rEvent )
248 css::uno::Sequence< css::embed::VerbDescriptor > aVerbs;
249 if ( rEvent.IsEnabled && ( rEvent.State >>= aVerbs ) )
250 addVerbs( aVerbs );
253 void ResourceMenuController::addVerbs( const css::uno::Sequence< css::embed::VerbDescriptor >& rVerbs )
255 // Check if the document is read-only.
256 css::uno::Reference< css::frame::XController > xController( m_xFrame->getController() );
257 css::uno::Reference< css::frame::XStorable > xStorable;
258 if ( xController.is() )
259 xStorable.set( xController->getModel(), css::uno::UNO_QUERY );
261 bool bReadOnly = xStorable.is() && xStorable->isReadonly();
262 Menu* pVCLMenu = m_xPopupMenu->GetMenu();
264 for ( const auto& rVerb : rVerbs )
266 if ( !( rVerb.VerbAttributes & css::embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU ) ||
267 ( bReadOnly && !( rVerb.VerbAttributes & css::embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES ) ) )
268 continue;
270 pVCLMenu->InsertItem( m_nNewMenuId, rVerb.VerbName );
271 pVCLMenu->SetItemCommand( m_nNewMenuId, ".uno:ObjectMenue?VerbID:short=" + OUString::number( rVerb.VerbID ) );
272 ++m_nNewMenuId;
276 void ResourceMenuController::itemActivated( const css::awt::MenuEvent& /*rEvent*/ )
278 // Must initialize MenuBarManager here, because we want to let the app do context menu interception before.
279 if ( !m_xMenuBarManager.is() )
281 m_xMenuBarManager.set( new framework::MenuBarManager(
282 m_xContext, m_xFrame, m_xURLTransformer, m_xDispatchProvider, m_aModuleName, m_xPopupMenu->GetMenu(), false, !m_bContextMenu && !m_bInToolbar ) );
283 m_xFrame->addFrameActionListener( m_xMenuBarManager );
287 void ResourceMenuController::itemSelected( const css::awt::MenuEvent& /*rEvent*/ )
289 // Must override this, because we are managed by MenuBarManager, so don't want the handler found in the base class.
292 void ResourceMenuController::elementInserted( const css::ui::ConfigurationEvent& rEvent )
294 if ( rEvent.ResourceURL == m_aMenuURL )
295 m_xMenuContainer.clear();
298 void ResourceMenuController::elementRemoved( const css::ui::ConfigurationEvent& rEvent )
300 elementInserted( rEvent );
303 void ResourceMenuController::elementReplaced( const css::ui::ConfigurationEvent& rEvent )
305 elementInserted( rEvent );
308 void ResourceMenuController::disposing( const css::lang::EventObject& rEvent )
310 if ( rEvent.Source == m_xConfigManager )
311 m_xConfigManager.clear();
312 else if ( rEvent.Source == m_xModuleConfigManager )
313 m_xModuleConfigManager.clear();
314 else
316 if ( m_xMenuBarManager.is() )
318 if (m_xFrame.is())
319 m_xFrame->removeFrameActionListener( m_xMenuBarManager );
321 m_xMenuBarManager->dispose();
322 m_xMenuBarManager.clear();
324 svt::PopupMenuControllerBase::disposing( rEvent );
328 void ResourceMenuController::disposing(std::unique_lock<std::mutex>& rGuard)
330 css::uno::Reference< css::ui::XUIConfiguration > xConfig( m_xConfigManager, css::uno::UNO_QUERY );
331 if ( xConfig.is() )
332 xConfig->removeConfigurationListener( this );
334 css::uno::Reference< css::ui::XUIConfiguration > xModuleConfig( m_xModuleConfigManager, css::uno::UNO_QUERY );
335 if ( xModuleConfig.is() )
336 xModuleConfig->removeConfigurationListener( this );
338 m_xConfigManager.clear();
339 m_xModuleConfigManager.clear();
340 m_xMenuContainer.clear();
341 m_xDispatchProvider.clear();
342 if ( m_xMenuBarManager.is() )
344 if (m_xFrame.is())
345 m_xFrame->removeFrameActionListener( m_xMenuBarManager );
347 m_xMenuBarManager->dispose();
348 m_xMenuBarManager.clear();
351 svt::PopupMenuControllerBase::disposing(rGuard);
354 OUString ResourceMenuController::getImplementationName()
356 if ( m_bToolbarContainer )
357 return "com.sun.star.comp.framework.ToolbarAsMenuController";
359 return "com.sun.star.comp.framework.ResourceMenuController";
362 css::uno::Sequence< OUString > ResourceMenuController::getSupportedServiceNames()
364 return { "com.sun.star.frame.PopupMenuController" };
367 class SaveAsMenuController : public ResourceMenuController
369 public:
370 SaveAsMenuController( const css::uno::Reference< css::uno::XComponentContext >& rContext,
371 const css::uno::Sequence< css::uno::Any >& rArgs );
373 // XServiceInfo
374 virtual OUString SAL_CALL getImplementationName() override;
376 private:
377 virtual void impl_setPopupMenu() override;
380 SaveAsMenuController::SaveAsMenuController( const css::uno::Reference< css::uno::XComponentContext >& rContext,
381 const css::uno::Sequence< css::uno::Any >& rArgs )
382 : ResourceMenuController( rContext, rArgs, false )
386 void InsertItem(const css::uno::Reference<css::awt::XPopupMenu>& rPopupMenu,
387 const OUString& rCommand)
389 sal_uInt16 nItemId = rPopupMenu->getItemCount() + 1;
390 rPopupMenu->insertItem(nItemId, OUString(), 0, -1);
391 rPopupMenu->setCommand(nItemId, rCommand);
394 void SaveAsMenuController::impl_setPopupMenu()
396 SolarMutexGuard aGuard;
398 InsertItem(m_xPopupMenu, ".uno:SaveAs");
399 InsertItem(m_xPopupMenu, ".uno:ExportTo");
400 InsertItem(m_xPopupMenu, ".uno:SaveACopy");
401 InsertItem(m_xPopupMenu, ".uno:SaveAsTemplate");
402 m_xPopupMenu->insertSeparator(-1);
403 InsertItem(m_xPopupMenu, ".uno:SaveAsRemote");
406 OUString SaveAsMenuController::getImplementationName()
408 return "com.sun.star.comp.framework.SaveAsMenuController";
411 class WindowListMenuController : public ResourceMenuController
413 public:
414 WindowListMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
415 const css::uno::Sequence< css::uno::Any >& rxArgs )
416 : ResourceMenuController(rxContext, rxArgs, false) {}
418 // XMenuListener
419 void SAL_CALL itemActivated( const css::awt::MenuEvent& rEvent ) override;
420 void SAL_CALL itemSelected( const css::awt::MenuEvent& rEvent ) override;
422 // XServiceInfo
423 OUString SAL_CALL getImplementationName() override;
425 private:
426 void impl_setPopupMenu() override;
429 constexpr sal_uInt16 START_ITEMID_WINDOWLIST = 4600;
430 constexpr sal_uInt16 END_ITEMID_WINDOWLIST = 4699;
432 void WindowListMenuController::itemActivated( const css::awt::MenuEvent& rEvent )
434 ResourceMenuController::itemActivated( rEvent );
436 // update window list
437 ::std::vector< OUString > aNewWindowListVector;
439 css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext );
441 sal_uInt16 nActiveItemId = 0;
442 sal_uInt16 nItemId = START_ITEMID_WINDOWLIST;
444 css::uno::Reference< css::frame::XFrame > xCurrentFrame = xDesktop->getCurrentFrame();
445 css::uno::Reference< css::container::XIndexAccess > xList = xDesktop->getFrames();
446 sal_Int32 nFrameCount = xList->getCount();
447 aNewWindowListVector.reserve(nFrameCount);
448 for (sal_Int32 i=0; i<nFrameCount; ++i )
450 css::uno::Reference< css::frame::XFrame > xFrame;
451 xList->getByIndex(i) >>= xFrame;
453 if (xFrame.is())
455 if ( xFrame == xCurrentFrame )
456 nActiveItemId = nItemId;
458 VclPtr<vcl::Window> pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() );
459 OUString sWindowTitle;
460 if ( pWin && pWin->IsVisible() )
461 sWindowTitle = pWin->GetText();
463 // tdf#101658 In case the frame is embedded somewhere, LO has no control over it.
464 // So we just skip it.
465 if ( sWindowTitle.isEmpty() )
466 continue;
468 aNewWindowListVector.push_back( sWindowTitle );
469 ++nItemId;
474 SolarMutexGuard g;
476 Menu* pVCLMenu = m_xPopupMenu->GetMenu();
477 int nItemCount = pVCLMenu->GetItemCount();
479 if ( nItemCount > 0 )
481 // remove all old window list entries from menu
482 sal_uInt16 nPos = pVCLMenu->GetItemPos( START_ITEMID_WINDOWLIST );
483 for ( sal_uInt16 n = nPos; n < pVCLMenu->GetItemCount(); )
484 pVCLMenu->RemoveItem( n );
486 if ( pVCLMenu->GetItemType( pVCLMenu->GetItemCount()-1 ) == MenuItemType::SEPARATOR )
487 pVCLMenu->RemoveItem( pVCLMenu->GetItemCount()-1 );
490 if ( !aNewWindowListVector.empty() )
492 // append new window list entries to menu
493 pVCLMenu->InsertSeparator();
494 nItemId = START_ITEMID_WINDOWLIST;
495 const sal_uInt32 nCount = aNewWindowListVector.size();
496 for ( sal_uInt32 i = 0; i < nCount; i++ )
498 pVCLMenu->InsertItem( nItemId, aNewWindowListVector.at( i ), MenuItemBits::RADIOCHECK );
499 if ( nItemId == nActiveItemId )
500 pVCLMenu->CheckItem( nItemId );
501 ++nItemId;
507 void WindowListMenuController::itemSelected( const css::awt::MenuEvent& rEvent )
509 if ( rEvent.MenuId < START_ITEMID_WINDOWLIST || rEvent.MenuId > END_ITEMID_WINDOWLIST )
510 return;
512 // window list menu item selected
513 css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext );
515 sal_uInt16 nTaskId = START_ITEMID_WINDOWLIST;
516 css::uno::Reference< css::container::XIndexAccess > xList = xDesktop->getFrames();
517 sal_Int32 nCount = xList->getCount();
518 for ( sal_Int32 i=0; i<nCount; ++i )
520 css::uno::Reference< css::frame::XFrame > xFrame;
521 xList->getByIndex(i) >>= xFrame;
522 if ( xFrame.is() && nTaskId == rEvent.MenuId )
524 VclPtr<vcl::Window> pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() );
525 pWin->GrabFocus();
526 pWin->ToTop( ToTopFlags::RestoreWhenMin );
527 break;
530 nTaskId++;
534 void WindowListMenuController::impl_setPopupMenu()
536 // Make this controller work also with initially empty
537 // menu, which PopupMenu::ImplExecute doesn't allow.
538 if (m_xPopupMenu.is() && !m_xPopupMenu->getItemCount())
539 m_xPopupMenu->insertSeparator(0);
542 OUString WindowListMenuController::getImplementationName()
544 return "com.sun.star.comp.framework.WindowListMenuController";
549 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
550 com_sun_star_comp_framework_ResourceMenuController_get_implementation(
551 css::uno::XComponentContext* context,
552 css::uno::Sequence< css::uno::Any > const & args )
554 return cppu::acquire( new ResourceMenuController( context, args, false ) );
557 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
558 com_sun_star_comp_framework_ToolbarAsMenuController_get_implementation(
559 css::uno::XComponentContext* context,
560 css::uno::Sequence< css::uno::Any > const & args )
562 return cppu::acquire( new ResourceMenuController( context, args, true ) );
565 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
566 com_sun_star_comp_framework_WindowListMenuController_get_implementation(
567 css::uno::XComponentContext* context,
568 css::uno::Sequence< css::uno::Any > const & args )
570 return cppu::acquire( new WindowListMenuController( context, args ) );
573 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
574 com_sun_star_comp_framework_SaveAsMenuController_get_implementation(
575 css::uno::XComponentContext* context,
576 css::uno::Sequence< css::uno::Any > const & args )
578 return cppu::acquire( new SaveAsMenuController( context, args ) );
581 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */