calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / framework / source / uielement / resourcemenucontroller.cxx
blob7a1364b41f4c1a9cb85d9eb70f7dcadb047f6047
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 SAL_CALL disposing() 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, comphelper::getFromUnoTunnel<VCLXMenu>( 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 VCLXMenu* pAwtMenu = comphelper::getFromUnoTunnel<VCLXMenu>( m_xPopupMenu );
263 Menu* pVCLMenu = pAwtMenu->GetMenu();
265 for ( const auto& rVerb : rVerbs )
267 if ( !( rVerb.VerbAttributes & css::embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU ) ||
268 ( bReadOnly && !( rVerb.VerbAttributes & css::embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES ) ) )
269 continue;
271 pVCLMenu->InsertItem( m_nNewMenuId, rVerb.VerbName );
272 pVCLMenu->SetItemCommand( m_nNewMenuId, ".uno:ObjectMenue?VerbID:short=" + OUString::number( rVerb.VerbID ) );
273 ++m_nNewMenuId;
277 void ResourceMenuController::itemActivated( const css::awt::MenuEvent& /*rEvent*/ )
279 // Must initialize MenuBarManager here, because we want to let the app do context menu interception before.
280 if ( !m_xMenuBarManager.is() )
282 VCLXMenu* pAwtMenu = comphelper::getFromUnoTunnel<VCLXMenu>( m_xPopupMenu );
283 m_xMenuBarManager.set( new framework::MenuBarManager(
284 m_xContext, m_xFrame, m_xURLTransformer, m_xDispatchProvider, m_aModuleName, pAwtMenu->GetMenu(), false, !m_bContextMenu && !m_bInToolbar ) );
285 m_xFrame->addFrameActionListener( m_xMenuBarManager );
289 void ResourceMenuController::itemSelected( const css::awt::MenuEvent& /*rEvent*/ )
291 // Must override this, because we are managed by MenuBarManager, so don't want the handler found in the base class.
294 void ResourceMenuController::elementInserted( const css::ui::ConfigurationEvent& rEvent )
296 if ( rEvent.ResourceURL == m_aMenuURL )
297 m_xMenuContainer.clear();
300 void ResourceMenuController::elementRemoved( const css::ui::ConfigurationEvent& rEvent )
302 elementInserted( rEvent );
305 void ResourceMenuController::elementReplaced( const css::ui::ConfigurationEvent& rEvent )
307 elementInserted( rEvent );
310 void ResourceMenuController::disposing( const css::lang::EventObject& rEvent )
312 if ( rEvent.Source == m_xConfigManager )
313 m_xConfigManager.clear();
314 else if ( rEvent.Source == m_xModuleConfigManager )
315 m_xModuleConfigManager.clear();
316 else
318 if ( m_xMenuBarManager.is() )
320 if (m_xFrame.is())
321 m_xFrame->removeFrameActionListener( m_xMenuBarManager );
323 m_xMenuBarManager->dispose();
324 m_xMenuBarManager.clear();
326 svt::PopupMenuControllerBase::disposing( rEvent );
330 void ResourceMenuController::disposing()
332 css::uno::Reference< css::ui::XUIConfiguration > xConfig( m_xConfigManager, css::uno::UNO_QUERY );
333 if ( xConfig.is() )
334 xConfig->removeConfigurationListener( this );
336 css::uno::Reference< css::ui::XUIConfiguration > xModuleConfig( m_xModuleConfigManager, css::uno::UNO_QUERY );
337 if ( xModuleConfig.is() )
338 xModuleConfig->removeConfigurationListener( this );
340 m_xConfigManager.clear();
341 m_xModuleConfigManager.clear();
342 m_xMenuContainer.clear();
343 m_xDispatchProvider.clear();
344 if ( m_xMenuBarManager.is() )
346 if (m_xFrame.is())
347 m_xFrame->removeFrameActionListener( m_xMenuBarManager );
349 m_xMenuBarManager->dispose();
350 m_xMenuBarManager.clear();
353 svt::PopupMenuControllerBase::disposing();
356 OUString ResourceMenuController::getImplementationName()
358 if ( m_bToolbarContainer )
359 return "com.sun.star.comp.framework.ToolbarAsMenuController";
361 return "com.sun.star.comp.framework.ResourceMenuController";
364 css::uno::Sequence< OUString > ResourceMenuController::getSupportedServiceNames()
366 return { "com.sun.star.frame.PopupMenuController" };
369 class SaveAsMenuController : public ResourceMenuController
371 public:
372 SaveAsMenuController( const css::uno::Reference< css::uno::XComponentContext >& rContext,
373 const css::uno::Sequence< css::uno::Any >& rArgs );
375 // XServiceInfo
376 virtual OUString SAL_CALL getImplementationName() override;
378 private:
379 virtual void impl_setPopupMenu() override;
382 SaveAsMenuController::SaveAsMenuController( const css::uno::Reference< css::uno::XComponentContext >& rContext,
383 const css::uno::Sequence< css::uno::Any >& rArgs )
384 : ResourceMenuController( rContext, rArgs, false )
388 void InsertItem(const css::uno::Reference<css::awt::XPopupMenu>& rPopupMenu,
389 const OUString& rCommand)
391 sal_uInt16 nItemId = rPopupMenu->getItemCount() + 1;
392 rPopupMenu->insertItem(nItemId, OUString(), 0, -1);
393 rPopupMenu->setCommand(nItemId, rCommand);
396 void SaveAsMenuController::impl_setPopupMenu()
398 SolarMutexGuard aGuard;
400 InsertItem(m_xPopupMenu, ".uno:SaveAs");
401 InsertItem(m_xPopupMenu, ".uno:ExportTo");
402 InsertItem(m_xPopupMenu, ".uno:SaveACopy");
403 InsertItem(m_xPopupMenu, ".uno:SaveAsTemplate");
404 m_xPopupMenu->insertSeparator(-1);
405 InsertItem(m_xPopupMenu, ".uno:SaveAsRemote");
408 OUString SaveAsMenuController::getImplementationName()
410 return "com.sun.star.comp.framework.SaveAsMenuController";
413 class WindowListMenuController : public ResourceMenuController
415 public:
416 WindowListMenuController( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
417 const css::uno::Sequence< css::uno::Any >& rxArgs )
418 : ResourceMenuController(rxContext, rxArgs, false) {}
420 // XMenuListener
421 void SAL_CALL itemActivated( const css::awt::MenuEvent& rEvent ) override;
422 void SAL_CALL itemSelected( const css::awt::MenuEvent& rEvent ) override;
424 // XServiceInfo
425 OUString SAL_CALL getImplementationName() override;
427 private:
428 void impl_setPopupMenu() override;
431 constexpr sal_uInt16 START_ITEMID_WINDOWLIST = 4600;
432 constexpr sal_uInt16 END_ITEMID_WINDOWLIST = 4699;
434 void WindowListMenuController::itemActivated( const css::awt::MenuEvent& rEvent )
436 ResourceMenuController::itemActivated( rEvent );
438 // update window list
439 ::std::vector< OUString > aNewWindowListVector;
441 css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext );
443 sal_uInt16 nActiveItemId = 0;
444 sal_uInt16 nItemId = START_ITEMID_WINDOWLIST;
446 css::uno::Reference< css::frame::XFrame > xCurrentFrame = xDesktop->getCurrentFrame();
447 css::uno::Reference< css::container::XIndexAccess > xList = xDesktop->getFrames();
448 sal_Int32 nFrameCount = xList->getCount();
449 aNewWindowListVector.reserve(nFrameCount);
450 for (sal_Int32 i=0; i<nFrameCount; ++i )
452 css::uno::Reference< css::frame::XFrame > xFrame;
453 xList->getByIndex(i) >>= xFrame;
455 if (xFrame.is())
457 if ( xFrame == xCurrentFrame )
458 nActiveItemId = nItemId;
460 VclPtr<vcl::Window> pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() );
461 OUString sWindowTitle;
462 if ( pWin && pWin->IsVisible() )
463 sWindowTitle = pWin->GetText();
465 // tdf#101658 In case the frame is embedded somewhere, LO has no control over it.
466 // So we just skip it.
467 if ( sWindowTitle.isEmpty() )
468 continue;
470 aNewWindowListVector.push_back( sWindowTitle );
471 ++nItemId;
476 SolarMutexGuard g;
478 VCLXMenu* pAwtMenu = comphelper::getFromUnoTunnel<VCLXMenu>( m_xPopupMenu );
479 Menu* pVCLMenu = pAwtMenu->GetMenu();
480 int nItemCount = pVCLMenu->GetItemCount();
482 if ( nItemCount > 0 )
484 // remove all old window list entries from menu
485 sal_uInt16 nPos = pVCLMenu->GetItemPos( START_ITEMID_WINDOWLIST );
486 for ( sal_uInt16 n = nPos; n < pVCLMenu->GetItemCount(); )
487 pVCLMenu->RemoveItem( n );
489 if ( pVCLMenu->GetItemType( pVCLMenu->GetItemCount()-1 ) == MenuItemType::SEPARATOR )
490 pVCLMenu->RemoveItem( pVCLMenu->GetItemCount()-1 );
493 if ( !aNewWindowListVector.empty() )
495 // append new window list entries to menu
496 pVCLMenu->InsertSeparator();
497 nItemId = START_ITEMID_WINDOWLIST;
498 const sal_uInt32 nCount = aNewWindowListVector.size();
499 for ( sal_uInt32 i = 0; i < nCount; i++ )
501 pVCLMenu->InsertItem( nItemId, aNewWindowListVector.at( i ), MenuItemBits::RADIOCHECK );
502 if ( nItemId == nActiveItemId )
503 pVCLMenu->CheckItem( nItemId );
504 ++nItemId;
510 void WindowListMenuController::itemSelected( const css::awt::MenuEvent& rEvent )
512 if ( rEvent.MenuId < START_ITEMID_WINDOWLIST || rEvent.MenuId > END_ITEMID_WINDOWLIST )
513 return;
515 // window list menu item selected
516 css::uno::Reference< css::frame::XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext );
518 sal_uInt16 nTaskId = START_ITEMID_WINDOWLIST;
519 css::uno::Reference< css::container::XIndexAccess > xList = xDesktop->getFrames();
520 sal_Int32 nCount = xList->getCount();
521 for ( sal_Int32 i=0; i<nCount; ++i )
523 css::uno::Reference< css::frame::XFrame > xFrame;
524 xList->getByIndex(i) >>= xFrame;
525 if ( xFrame.is() && nTaskId == rEvent.MenuId )
527 VclPtr<vcl::Window> pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() );
528 pWin->GrabFocus();
529 pWin->ToTop( ToTopFlags::RestoreWhenMin );
530 break;
533 nTaskId++;
537 void WindowListMenuController::impl_setPopupMenu()
539 // Make this controller work also with initially empty
540 // menu, which PopupMenu::ImplExecute doesn't allow.
541 if (m_xPopupMenu.is() && !m_xPopupMenu->getItemCount())
542 m_xPopupMenu->insertSeparator(0);
545 OUString WindowListMenuController::getImplementationName()
547 return "com.sun.star.comp.framework.WindowListMenuController";
552 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
553 com_sun_star_comp_framework_ResourceMenuController_get_implementation(
554 css::uno::XComponentContext* context,
555 css::uno::Sequence< css::uno::Any > const & args )
557 return cppu::acquire( new ResourceMenuController( context, args, false ) );
560 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
561 com_sun_star_comp_framework_ToolbarAsMenuController_get_implementation(
562 css::uno::XComponentContext* context,
563 css::uno::Sequence< css::uno::Any > const & args )
565 return cppu::acquire( new ResourceMenuController( context, args, true ) );
568 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
569 com_sun_star_comp_framework_WindowListMenuController_get_implementation(
570 css::uno::XComponentContext* context,
571 css::uno::Sequence< css::uno::Any > const & args )
573 return cppu::acquire( new WindowListMenuController( context, args ) );
576 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
577 com_sun_star_comp_framework_SaveAsMenuController_get_implementation(
578 css::uno::XComponentContext* context,
579 css::uno::Sequence< css::uno::Any > const & args )
581 return cppu::acquire( new SaveAsMenuController( context, args ) );
584 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */