1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <uielement/menubarmanager.hxx>
21 #include <uielement/styletoolbarcontroller.hxx>
22 #include <framework/menuconfiguration.hxx>
23 #include <framework/addonmenu.hxx>
24 #include <framework/addonsoptions.hxx>
25 #include <classes/fwkresid.hxx>
26 #include <helper/mischelper.hxx>
27 #include <strings.hrc>
28 #include <services.h>
29
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/frame/XDispatch.hpp>
32 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <com/sun/star/lang/DisposedException.hpp>
35 #include <com/sun/star/frame/Desktop.hpp>
36 #include <com/sun/star/container/XEnumeration.hpp>
37 #include <com/sun/star/util/XStringWidth.hpp>
38 #include <com/sun/star/uno/XComponentContext.hpp>
39 #include <com/sun/star/uno/XCurrentContext.hpp>
40 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
41 #include <com/sun/star/frame/XPopupMenuController.hpp>
42 #include <com/sun/star/frame/thePopupMenuControllerFactory.hpp>
43 #include <com/sun/star/lang/SystemDependent.hpp>
44 #include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp>
45 #include <com/sun/star/ui/ItemType.hpp>
46 #include <com/sun/star/ui/ImageType.hpp>
47 #include <com/sun/star/container/XNameAccess.hpp>
48 #include <com/sun/star/frame/ModuleManager.hpp>
49 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
50 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
51 #include <com/sun/star/ui/ItemStyle.hpp>
52 #include <com/sun/star/frame/status/Visibility.hpp>
53 #include <com/sun/star/util/URLTransformer.hpp>
54
55 #include <comphelper/processfactory.hxx>
56 #include <comphelper/propertyvalue.hxx>
57 #include <svtools/menuoptions.hxx>
58 #include <svtools/javainteractionhandler.hxx>
59 #include <uno/current_context.hxx>
60 #include <unotools/historyoptions.hxx>
61 #include <unotools/pathoptions.hxx>
62 #include <unotools/cmdoptions.hxx>
63 #include <unotools/localfilehelper.hxx>
64 #include <toolkit/awt/vclxmenu.hxx>
65 #include <toolkit/helper/vclunohelper.hxx>
66 #include <vcl/svapp.hxx>
67 #include <vcl/sysdata.hxx>
68 #include <vcl/window.hxx>
69 #include <vcl/menu.hxx>
70 #include <vcl/settings.hxx>
71 #include <vcl/commandinfoprovider.hxx>
72 #include <osl/file.hxx>
73 #include <sal/log.hxx>
74 #include <svtools/acceleratorexecute.hxx>
75 #include <svtools/miscopt.hxx>
76 #include <uielement/menubarmerger.hxx>
77 #include <tools/urlobj.hxx>
78
79 using namespace ::cppu;
80 using namespace ::com::sun::star;
81 using namespace ::com::sun::star::uno;
82 using namespace ::com::sun::star::util;
83 using namespace ::com::sun::star::beans;
84 using namespace ::com::sun::star::frame;
85 using namespace ::com::sun::star::container;
86 using namespace ::com::sun::star::lang;
87 using namespace ::com::sun::star::ui;
88
89 const sal_uInt16 ADDONMENU_MERGE_ITEMID_START = 1500;
90
91 namespace framework
92 {
93
94 #define aCmdHelpIndex ".uno:HelpIndex"
95 #define aCmdToolsMenu ".uno:ToolsMenu"
96 #define aCmdHelpMenu ".uno:HelpMenu"
97 #define aSpecialWindowCommand ".uno:WindowList"
98
MenuBarManager(const Reference<XComponentContext> & rxContext,const Reference<XFrame> & rFrame,const Reference<XURLTransformer> & _xURLTransformer,const Reference<XDispatchProvider> & rDispatchProvider,const OUString & rModuleIdentifier,Menu * pMenu,bool bDelete,bool bHasMenuBar)99 MenuBarManager::MenuBarManager(
100 const Reference< XComponentContext >& rxContext,
101 const Reference< XFrame >& rFrame,
102 const Reference< XURLTransformer >& _xURLTransformer,
103 const Reference< XDispatchProvider >& rDispatchProvider,
104 const OUString& rModuleIdentifier,
105 Menu* pMenu, bool bDelete, bool bHasMenuBar ):
106 WeakComponentImplHelper( m_aMutex )
107 , m_bRetrieveImages( false )
108 , m_bAcceleratorCfg( false )
109 , m_bModuleIdentified( false )
110 , m_bHasMenuBar( bHasMenuBar )
111 , m_xContext(rxContext)
112 , m_xURLTransformer(_xURLTransformer)
113 , m_sIconTheme( SvtMiscOptions().GetIconTheme() )
114 {
115 m_aAsyncSettingsTimer.SetDebugName( "framework::MenuBarManager::Deactivate m_aAsyncSettingsTimer" );
116 m_xPopupMenuControllerFactory = frame::thePopupMenuControllerFactory::get(m_xContext);
117 FillMenuManager( pMenu, rFrame, rDispatchProvider, rModuleIdentifier, bDelete );
118 }
119
MenuBarManager(const Reference<XComponentContext> & rxContext,const Reference<XFrame> & rFrame,const Reference<XURLTransformer> & _xURLTransformer,Menu * pAddonMenu,bool popup)120 MenuBarManager::MenuBarManager(
121 const Reference< XComponentContext >& rxContext,
122 const Reference< XFrame >& rFrame,
123 const Reference< XURLTransformer >& _xURLTransformer,
124 Menu* pAddonMenu,
125 bool popup):
126 WeakComponentImplHelper( m_aMutex )
127 , m_bRetrieveImages( true )
128 , m_bAcceleratorCfg( false )
129 , m_bModuleIdentified( false )
130 , m_bHasMenuBar( true )
131 , m_xContext(rxContext)
132 , m_xURLTransformer(_xURLTransformer)
133 , m_sIconTheme( SvtMiscOptions().GetIconTheme() )
134 {
135 m_aAsyncSettingsTimer.SetDebugName( "framework::MenuBarManager::Deactivate m_aAsyncSettingsTimer" );
136 Init(rFrame,pAddonMenu, popup);
137 }
138
getMenuHandle(const Sequence<sal_Int8> &,sal_Int16 SystemType)139 Any SAL_CALL MenuBarManager::getMenuHandle( const Sequence< sal_Int8 >& /*ProcessId*/, sal_Int16 SystemType )
140 {
141 SolarMutexGuard aSolarGuard;
142
143 if ( rBHelper.bDisposed || rBHelper.bInDispose )
144 throw css::lang::DisposedException();
145
146 Any a;
147
148 if ( m_pVCLMenu )
149 {
150 SystemMenuData aSystemMenuData;
151
152 m_pVCLMenu->GetSystemMenuData( &aSystemMenuData );
153 #ifdef _WIN32
154 if( SystemType == SystemDependent::SYSTEM_WIN32 )
155 {
156 a <<= sal_Int64(
157 reinterpret_cast<sal_IntPtr>(aSystemMenuData.hMenu));
158 }
159 #else
160 (void) SystemType;
161 #endif
162 }
163
164 return a;
165 }
166
~MenuBarManager()167 MenuBarManager::~MenuBarManager()
168 {
169 // stop asynchronous settings timer
170 m_xDeferedItemContainer.clear();
171 m_aAsyncSettingsTimer.Stop();
172
173 SAL_WARN_IF( OWeakObject::m_refCount != 0, "fwk.uielement", "Who wants to delete an object with refcount > 0!" );
174 }
175
Destroy()176 void MenuBarManager::Destroy()
177 {
178 SolarMutexGuard aGuard;
179
180 if ( !rBHelper.bDisposed )
181 {
182 // stop asynchronous settings timer and
183 // release deferred item container reference
184 m_aAsyncSettingsTimer.Stop();
185 m_xDeferedItemContainer.clear();
186 RemoveListener();
187
188 m_aMenuItemHandlerVector.clear();
189
190 if ( m_bDeleteMenu )
191 {
192 m_pVCLMenu.disposeAndClear();
193 }
194 }
195 }
196
197 // XComponent
disposing()198 void SAL_CALL MenuBarManager::disposing()
199 {
200 Reference< XComponent > xThis( static_cast< OWeakObject* >(this), UNO_QUERY );
201
202 SolarMutexGuard g;
203 Destroy();
204
205 if ( m_xDocImageManager.is() )
206 {
207 try
208 {
209 m_xDocImageManager->removeConfigurationListener(
210 Reference< XUIConfigurationListener >(
211 static_cast< OWeakObject* >( this ), UNO_QUERY ));
212 }
213 catch ( const Exception& )
214 {
215 }
216 }
217 if ( m_xModuleImageManager.is() )
218 {
219 try
220 {
221 m_xModuleImageManager->removeConfigurationListener(
222 Reference< XUIConfigurationListener >(
223 static_cast< OWeakObject* >( this ), UNO_QUERY ));
224 }
225 catch ( const Exception& )
226 {
227 }
228 }
229 m_xDocImageManager.clear();
230 m_xModuleImageManager.clear();
231 m_xGlobalAcceleratorManager.clear();
232 m_xModuleAcceleratorManager.clear();
233 m_xDocAcceleratorManager.clear();
234 m_xPopupMenuControllerFactory.clear();
235 m_xContext.clear();
236 }
237
elementInserted(const css::ui::ConfigurationEvent & Event)238 void SAL_CALL MenuBarManager::elementInserted( const css::ui::ConfigurationEvent& Event )
239 {
240 SolarMutexGuard g;
241
242 /* SAFE AREA ----------------------------------------------------------------------------------------------- */
243 if ( rBHelper.bDisposed || rBHelper.bInDispose )
244 return;
245
246 sal_Int16 nImageType = sal_Int16();
247 if (( Event.aInfo >>= nImageType ) &&
248 ( nImageType == css::ui::ImageType::SIZE_LARGE ))
249 RequestImages();
250 }
251
elementRemoved(const css::ui::ConfigurationEvent & Event)252 void SAL_CALL MenuBarManager::elementRemoved( const css::ui::ConfigurationEvent& Event )
253 {
254 elementInserted(Event);
255 }
256
elementReplaced(const css::ui::ConfigurationEvent & Event)257 void SAL_CALL MenuBarManager::elementReplaced( const css::ui::ConfigurationEvent& Event )
258 {
259 elementInserted(Event);
260 }
261
262 // XFrameActionListener
frameAction(const FrameActionEvent & Action)263 void SAL_CALL MenuBarManager::frameAction( const FrameActionEvent& Action )
264 {
265 SolarMutexGuard g;
266
267 if ( rBHelper.bDisposed || rBHelper.bInDispose )
268 throw css::lang::DisposedException();
269
270 if ( Action.Action == FrameAction_CONTEXT_CHANGED )
271 {
272 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
273 {
274 // Clear dispatch reference as we will requery it later
275 if ( menuItemHandler->xMenuItemDispatch.is() )
276 {
277 URL aTargetURL;
278 aTargetURL.Complete = menuItemHandler->aMenuItemURL;
279 m_xURLTransformer->parseStrict( aTargetURL );
280
281 menuItemHandler->xMenuItemDispatch->removeStatusListener( this, aTargetURL );
282 }
283 menuItemHandler->xMenuItemDispatch.clear();
284 }
285 }
286 }
287
288 // XStatusListener
statusChanged(const FeatureStateEvent & Event)289 void SAL_CALL MenuBarManager::statusChanged( const FeatureStateEvent& Event )
290 {
291 OUString aFeatureURL = Event.FeatureURL.Complete;
292
293 SolarMutexGuard aSolarGuard;
294 {
295 if ( rBHelper.bDisposed || rBHelper.bInDispose )
296 return;
297
298 // We have to check all menu entries as there can be identical entries in a popup menu.
299 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
300 {
301 if ( menuItemHandler->aParsedItemURL == aFeatureURL )
302 {
303 bool bCheckmark( false );
304 bool bMenuItemEnabled( m_pVCLMenu->IsItemEnabled( menuItemHandler->nItemId ));
305 bool bEnabledItem( Event.IsEnabled );
306 OUString aItemText;
307 status::Visibility aVisibilityStatus;
308
309 #ifdef UNIX
310 //enable some slots hardly, because UNIX clipboard does not notify all changes
311 // Can be removed if follow up task will be fixed directly within applications.
312 // Note: PasteSpecial is handled specifically by calc
313 // Calc also disables Paste under some circumstances, do not override.
314 /* TODO: is this workaround even needed anymore? Was introduced
315 * in 2009 with commit 426ab2c0e8f6e3fe2b766f74f6b8da873d860260
316 * as some "metropatch" and the other places it touched seem to
317 * be gone. */
318 if ( (menuItemHandler->aMenuItemURL == ".uno:Paste" &&
319 m_aModuleIdentifier != "com.sun.star.sheet.SpreadsheetDocument")
320 || menuItemHandler->aMenuItemURL == ".uno:PasteClipboard" ) // special for draw/impress
321 bEnabledItem = true;
322 #endif
323
324 // Enable/disable item
325 if ( bEnabledItem != bMenuItemEnabled )
326 {
327 m_pVCLMenu->EnableItem( menuItemHandler->nItemId, bEnabledItem );
328
329 // Remove "checked" mark for disabled menu items.
330 // Initially disabled but checkable menu items do not receive
331 // checked/unchecked state, so can appear inconsistently after
332 // enabling/disabling. Since we can not pass checked state for disabled
333 // items, we will just reset checked state for them, anyway correct state
334 // will be transferred from controller once item enabled.
335 if ( !bEnabledItem && m_pVCLMenu->IsItemChecked( menuItemHandler->nItemId ) )
336 m_pVCLMenu->CheckItem( menuItemHandler->nItemId, false );
337 }
338
339 if ( Event.State >>= bCheckmark )
340 {
341 // Checkmark or RadioButton
342 m_pVCLMenu->CheckItem( menuItemHandler->nItemId, bCheckmark );
343 // If not already designated RadioButton set as CheckMark
344 MenuItemBits nBits = m_pVCLMenu->GetItemBits( menuItemHandler->nItemId );
345 if (!(nBits & MenuItemBits::RADIOCHECK))
346 m_pVCLMenu->SetItemBits( menuItemHandler->nItemId, nBits | MenuItemBits::CHECKABLE );
347
348 if ( menuItemHandler->bMadeInvisible )
349 m_pVCLMenu->ShowItem( menuItemHandler->nItemId );
350 }
351 else if ( Event.State >>= aItemText )
352 {
353 INetURLObject aURL( aFeatureURL );
354 OUString aEnumPart = aURL.GetURLPath().getToken( 1, '.' );
355 if ( !aEnumPart.isEmpty() && aURL.GetProtocol() == INetProtocol::Uno )
356 {
357 // Checkmark or RadioButton
358 m_pVCLMenu->CheckItem( menuItemHandler->nItemId, aItemText == aEnumPart );
359 // If not already designated RadioButton set as CheckMark
360 MenuItemBits nBits = m_pVCLMenu->GetItemBits( menuItemHandler->nItemId );
361 if (!(nBits & MenuItemBits::RADIOCHECK))
362 m_pVCLMenu->SetItemBits( menuItemHandler->nItemId, nBits | MenuItemBits::CHECKABLE );
363 }
364 else
365 {
366 // Replacement for place holders
367 if ( aItemText.startsWith("($1)") )
368 {
369 aItemText = FwkResId(STR_UPDATEDOC) + " " + aItemText.copy( 4 );
370 }
371 else if ( aItemText.startsWith("($2)") )
372 {
373 aItemText = FwkResId(STR_CLOSEDOC_ANDRETURN) + aItemText.copy( 4 );
374 }
375 else if ( aItemText.startsWith("($3)") )
376 {
377 aItemText = FwkResId(STR_SAVECOPYDOC) + aItemText.copy( 4 );
378 }
379
380 m_pVCLMenu->SetItemText( menuItemHandler->nItemId, aItemText );
381 }
382
383 if ( menuItemHandler->bMadeInvisible )
384 m_pVCLMenu->ShowItem( menuItemHandler->nItemId );
385 }
386 else if ( Event.State >>= aVisibilityStatus )
387 {
388 // Visibility
389 m_pVCLMenu->ShowItem( menuItemHandler->nItemId, aVisibilityStatus.bVisible );
390 menuItemHandler->bMadeInvisible = !aVisibilityStatus.bVisible;
391 }
392 else if ( menuItemHandler->bMadeInvisible )
393 m_pVCLMenu->ShowItem( menuItemHandler->nItemId );
394 }
395
396 if ( Event.Requery )
397 {
398 // Release dispatch object - will be required on the next activate!
399 menuItemHandler->xMenuItemDispatch.clear();
400 }
401 }
402 }
403 }
404
405 // Helper to retrieve own structure from item ID
GetMenuItemHandler(sal_uInt16 nItemId)406 MenuBarManager::MenuItemHandler* MenuBarManager::GetMenuItemHandler( sal_uInt16 nItemId )
407 {
408 SolarMutexGuard g;
409
410 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
411 {
412 if ( menuItemHandler->nItemId == nItemId )
413 return menuItemHandler.get();
414 }
415
416 return nullptr;
417 }
418
419 // Helper to set request images flag
RequestImages()420 void MenuBarManager::RequestImages()
421 {
422
423 m_bRetrieveImages = true;
424 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
425 {
426 if ( menuItemHandler->xSubMenuManager.is() )
427 {
428 MenuBarManager* pMenuBarManager = static_cast<MenuBarManager*>(menuItemHandler->xSubMenuManager.get());
429 pMenuBarManager->RequestImages();
430 }
431 }
432 }
433
434 // Helper to reset objects to prepare shutdown
RemoveListener()435 void MenuBarManager::RemoveListener()
436 {
437 SolarMutexGuard g;
438
439 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
440 {
441 if ( menuItemHandler->xMenuItemDispatch.is() )
442 {
443 URL aTargetURL;
444 aTargetURL.Complete = menuItemHandler->aMenuItemURL;
445 m_xURLTransformer->parseStrict( aTargetURL );
446
447 menuItemHandler->xMenuItemDispatch->removeStatusListener(
448 static_cast< XStatusListener* >( this ), aTargetURL );
449 }
450
451 menuItemHandler->xMenuItemDispatch.clear();
452
453 if ( menuItemHandler->xPopupMenu.is() )
454 {
455 {
456 // Remove popup menu from menu structure
457 m_pVCLMenu->SetPopupMenu( menuItemHandler->nItemId, nullptr );
458 }
459
460 Reference< css::lang::XEventListener > xEventListener( menuItemHandler->xPopupMenuController, UNO_QUERY );
461 if ( xEventListener.is() )
462 {
463 EventObject aEventObject;
464 aEventObject.Source = static_cast<OWeakObject *>(this);
465 xEventListener->disposing( aEventObject );
466 }
467
468 // We now provide a popup menu controller to external code.
469 // Therefore the life-time must be explicitly handled via
470 // dispose!!
471 try
472 {
473 Reference< XComponent > xComponent( menuItemHandler->xPopupMenuController, UNO_QUERY );
474 if ( xComponent.is() )
475 xComponent->dispose();
476 }
477 catch ( const RuntimeException& )
478 {
479 throw;
480 }
481 catch ( const Exception& )
482 {
483 }
484
485 // Release references to controller and popup menu
486 menuItemHandler->xPopupMenuController.clear();
487 menuItemHandler->xPopupMenu.clear();
488 }
489
490 Reference< XComponent > xComponent( menuItemHandler->xSubMenuManager, UNO_QUERY );
491 if ( xComponent.is() )
492 xComponent->dispose();
493 }
494
495 try
496 {
497 if ( m_xFrame.is() )
498 m_xFrame->removeFrameActionListener( Reference< XFrameActionListener >(
499 static_cast< OWeakObject* >( this ), UNO_QUERY ));
500 }
501 catch ( const Exception& )
502 {
503 }
504
505 m_xFrame = nullptr;
506 }
507
disposing(const EventObject & Source)508 void SAL_CALL MenuBarManager::disposing( const EventObject& Source )
509 {
510 MenuItemHandler* pMenuItemDisposing = nullptr;
511
512 SolarMutexGuard g;
513
514 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
515 {
516 if ( menuItemHandler->xMenuItemDispatch.is() &&
517 menuItemHandler->xMenuItemDispatch == Source.Source )
518 {
519 // disposing called from menu item dispatcher, remove listener
520 pMenuItemDisposing = menuItemHandler.get();
521 break;
522 }
523 }
524
525 if ( pMenuItemDisposing )
526 {
527 // Release references to the dispatch object
528 URL aTargetURL;
529 aTargetURL.Complete = pMenuItemDisposing->aMenuItemURL;
530
531 m_xURLTransformer->parseStrict( aTargetURL );
532
533 pMenuItemDisposing->xMenuItemDispatch->removeStatusListener(
534 static_cast< XStatusListener* >( this ), aTargetURL );
535 pMenuItemDisposing->xMenuItemDispatch.clear();
536 if ( pMenuItemDisposing->xPopupMenu.is() )
537 {
538 Reference< css::lang::XEventListener > xEventListener( pMenuItemDisposing->xPopupMenuController, UNO_QUERY );
539 if ( xEventListener.is() )
540 xEventListener->disposing( Source );
541
542 {
543 // Remove popup menu from menu structure as we release our reference to
544 // the controller.
545 m_pVCLMenu->SetPopupMenu( pMenuItemDisposing->nItemId, nullptr );
546 }
547
548 pMenuItemDisposing->xPopupMenuController.clear();
549 pMenuItemDisposing->xPopupMenu.clear();
550 }
551 return;
552 }
553 else if ( Source.Source == m_xFrame )
554 {
555 // Our frame gets disposed. We have to remove all our listeners
556 RemoveListener();
557 }
558 else if ( Source.Source == Reference< XInterface >( m_xDocImageManager, UNO_QUERY ))
559 m_xDocImageManager.clear();
560 else if ( Source.Source == Reference< XInterface >( m_xModuleImageManager, UNO_QUERY ))
561 m_xModuleImageManager.clear();
562 }
563
lcl_CheckForChildren(Menu * pMenu,sal_uInt16 nItemId)564 static void lcl_CheckForChildren(Menu* pMenu, sal_uInt16 nItemId)
565 {
566 if (PopupMenu* pThisPopup = pMenu->GetPopupMenu( nItemId ))
567 pMenu->EnableItem( nItemId, pThisPopup->GetItemCount() != 0 );
568 }
569
570 // vcl handler
571
572 namespace {
573
574 class QuietInteractionContext:
575 public cppu::WeakImplHelper< css::uno::XCurrentContext >
576 {
577 public:
QuietInteractionContext(css::uno::Reference<css::uno::XCurrentContext> const & context)578 explicit QuietInteractionContext(
579 css::uno::Reference< css::uno::XCurrentContext >
580 const & context):
581 context_(context) {}
582 QuietInteractionContext(const QuietInteractionContext&) = delete;
583 QuietInteractionContext& operator=(const QuietInteractionContext&) = delete;
584
585 private:
~QuietInteractionContext()586 virtual ~QuietInteractionContext() override {}
587
getValueByName(OUString const & Name)588 virtual css::uno::Any SAL_CALL getValueByName(
589 OUString const & Name) override
590 {
591 return Name != JAVA_INTERACTION_HANDLER_NAME && context_.is()
592 ? context_->getValueByName(Name)
593 : css::uno::Any();
594 }
595
596 css::uno::Reference< css::uno::XCurrentContext >
597 context_;
598 };
599
600 }
601
IMPL_LINK(MenuBarManager,Activate,Menu *,pMenu,bool)602 IMPL_LINK( MenuBarManager, Activate, Menu *, pMenu, bool )
603 {
604 if ( pMenu == m_pVCLMenu )
605 {
606 css::uno::ContextLayer layer(
607 new QuietInteractionContext(
608 css::uno::getCurrentContext()));
609
610 // set/unset hiding disabled menu entries
611 bool bDontHide = SvtMenuOptions().IsEntryHidingEnabled();
612 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
613 bool bShowMenuImages = rSettings.GetUseImagesInMenus();
614 bool bShowShortcuts = m_bHasMenuBar || rSettings.GetContextMenuShortcuts();
615 bool bHasDisabledEntries = SvtCommandOptions().HasEntries( SvtCommandOptions::CMDOPTION_DISABLED );
616
617 SolarMutexGuard g;
618
619 MenuFlags nFlag = pMenu->GetMenuFlags();
620 if ( bDontHide )
621 nFlag &= ~MenuFlags::HideDisabledEntries;
622 else
623 nFlag |= MenuFlags::HideDisabledEntries;
624 pMenu->SetMenuFlags( nFlag );
625
626 if ( m_bActive )
627 return false;
628
629 m_bActive = true;
630
631 if ( m_aMenuItemCommand == aSpecialWindowCommand )
632 UpdateSpecialWindowMenu( pMenu, m_xContext );
633
634 // Check if some modes have changed so we have to update our menu images
635 OUString sIconTheme = SvtMiscOptions().GetIconTheme();
636
637 if ( m_bRetrieveImages ||
638 bShowMenuImages != m_bShowMenuImages ||
639 sIconTheme != m_sIconTheme )
640 {
641 m_bShowMenuImages = bShowMenuImages;
642 m_bRetrieveImages = false;
643 m_sIconTheme = sIconTheme;
644 FillMenuImages( m_xFrame, pMenu, bShowMenuImages );
645 }
646
647 // Try to map commands to labels
648 for ( sal_uInt16 nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
649 {
650 sal_uInt16 nItemId = pMenu->GetItemId( nPos );
651 if (( pMenu->GetItemType( nPos ) != MenuItemType::SEPARATOR ) &&
652 ( pMenu->GetItemText( nItemId ).isEmpty() ))
653 {
654 OUString aCommand = pMenu->GetItemCommand( nItemId );
655 if ( !aCommand.isEmpty() ) {
656 pMenu->SetItemText( nItemId, RetrieveLabelFromCommand( aCommand ));
657 }
658 }
659 }
660
661 // Try to set accelerator keys
662 {
663 if ( bShowShortcuts )
664 RetrieveShortcuts( m_aMenuItemHandlerVector );
665
666 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
667 {
668 if ( !bShowShortcuts )
669 {
670 pMenu->SetAccelKey( menuItemHandler->nItemId, vcl::KeyCode() );
671 }
672 else if ( menuItemHandler->aMenuItemURL == aCmdHelpIndex )
673 {
674 // Set key code, workaround for hard-coded shortcut F1 mapped to .uno:HelpIndex
675 // Only non-popup menu items can have a short-cut
676 vcl::KeyCode aKeyCode( KEY_F1 );
677 pMenu->SetAccelKey( menuItemHandler->nItemId, aKeyCode );
678 }
679 else if ( pMenu->GetPopupMenu( menuItemHandler->nItemId ) == nullptr )
680 pMenu->SetAccelKey( menuItemHandler->nItemId, menuItemHandler->aKeyCode );
681 }
682 }
683
684 URL aTargetURL;
685
686 // Use provided dispatch provider => fallback to frame as dispatch provider
687 Reference< XDispatchProvider > xDispatchProvider;
688 if ( m_xDispatchProvider.is() )
689 xDispatchProvider = m_xDispatchProvider;
690 else
691 xDispatchProvider.set( m_xFrame, UNO_QUERY );
692
693 if ( xDispatchProvider.is() )
694 {
695 SvtCommandOptions aCmdOptions;
696 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
697 {
698 if (menuItemHandler)
699 {
700 if ( !menuItemHandler->xMenuItemDispatch.is() &&
701 !menuItemHandler->xSubMenuManager.is() )
702 {
703 // There is no dispatch mechanism for the special window list menu items,
704 // because they are handled directly through XFrame->activate!!!
705 // Don't update dispatches for special file menu items.
706 if ( !( menuItemHandler->nItemId >= START_ITEMID_WINDOWLIST &&
707 menuItemHandler->nItemId < END_ITEMID_WINDOWLIST ) )
708 {
709 Reference< XDispatch > xMenuItemDispatch;
710
711 aTargetURL.Complete = menuItemHandler->aMenuItemURL;
712
713 m_xURLTransformer->parseStrict( aTargetURL );
714
715 if ( bHasDisabledEntries )
716 {
717 if ( aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, aTargetURL.Path ))
718 pMenu->HideItem( menuItemHandler->nItemId );
719 }
720
721 if ( aTargetURL.Complete.startsWith( ".uno:StyleApply?" ) )
722 xMenuItemDispatch = new StyleDispatcher( m_xFrame, m_xURLTransformer, aTargetURL );
723 else if ( m_bIsBookmarkMenu )
724 xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, menuItemHandler->aTargetFrame, 0 );
725 else
726 xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
727
728 bool bPopupMenu( false );
729 if ( !menuItemHandler->xPopupMenuController.is() &&
730 m_xPopupMenuControllerFactory->hasController( menuItemHandler->aMenuItemURL, m_aModuleIdentifier ) )
731 {
732 if( xMenuItemDispatch.is() || menuItemHandler->aMenuItemURL != ".uno:RecentFileList" )
733 bPopupMenu = CreatePopupMenuController(menuItemHandler.get());
734 }
735 else if ( menuItemHandler->xPopupMenuController.is() )
736 {
737 // Force update of popup menu
738 menuItemHandler->xPopupMenuController->updatePopupMenu();
739 bPopupMenu = true;
740 if (PopupMenu* pThisPopup = pMenu->GetPopupMenu( menuItemHandler->nItemId ))
741 pMenu->EnableItem( menuItemHandler->nItemId, pThisPopup->GetItemCount() != 0 );
742 }
743 lcl_CheckForChildren(pMenu, menuItemHandler->nItemId);
744
745 if ( xMenuItemDispatch.is() )
746 {
747 menuItemHandler->xMenuItemDispatch = xMenuItemDispatch;
748 menuItemHandler->aParsedItemURL = aTargetURL.Complete;
749
750 if ( !bPopupMenu )
751 {
752 xMenuItemDispatch->addStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
753 // For the menubar, we have to keep status listening to support Ubuntu's HUD.
754 if ( !m_bHasMenuBar )
755 xMenuItemDispatch->removeStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
756 }
757 }
758 else if ( !bPopupMenu )
759 pMenu->EnableItem( menuItemHandler->nItemId, false );
760 }
761 }
762 else if ( menuItemHandler->xPopupMenuController.is() )
763 {
764 // Force update of popup menu
765 menuItemHandler->xPopupMenuController->updatePopupMenu();
766 lcl_CheckForChildren(pMenu, menuItemHandler->nItemId);
767 }
768 else if ( menuItemHandler->xMenuItemDispatch.is() )
769 {
770 // We need an update to reflect the current state
771 try
772 {
773 aTargetURL.Complete = menuItemHandler->aMenuItemURL;
774 m_xURLTransformer->parseStrict( aTargetURL );
775
776 menuItemHandler->xMenuItemDispatch->addStatusListener(
777 static_cast< XStatusListener* >( this ), aTargetURL );
778 menuItemHandler->xMenuItemDispatch->removeStatusListener(
779 static_cast< XStatusListener* >( this ), aTargetURL );
780 }
781 catch ( const Exception& )
782 {
783 }
784 }
785 else if ( menuItemHandler->xSubMenuManager.is() )
786 lcl_CheckForChildren(pMenu, menuItemHandler->nItemId);
787 }
788 }
789 }
790 }
791
792 return true;
793 }
794
IMPL_LINK(MenuBarManager,Deactivate,Menu *,pMenu,bool)795 IMPL_LINK( MenuBarManager, Deactivate, Menu *, pMenu, bool )
796 {
797 if ( pMenu == m_pVCLMenu )
798 {
799 m_bActive = false;
800 if ( pMenu->IsMenuBar() && m_xDeferedItemContainer.is() )
801 {
802 // Start timer to handle settings asynchronous
803 // Changing the menu inside this handler leads to
804 // a crash under X!
805 m_aAsyncSettingsTimer.SetInvokeHandler(LINK(this, MenuBarManager, AsyncSettingsHdl));
806 m_aAsyncSettingsTimer.SetTimeout(10);
807 m_aAsyncSettingsTimer.Start();
808 }
809 }
810
811 return true;
812 }
813
IMPL_LINK_NOARG(MenuBarManager,AsyncSettingsHdl,Timer *,void)814 IMPL_LINK_NOARG( MenuBarManager, AsyncSettingsHdl, Timer*, void)
815 {
816 SolarMutexGuard g;
817 Reference< XInterface > xSelfHold(
818 static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY_THROW );
819
820 m_aAsyncSettingsTimer.Stop();
821 if ( !m_bActive && m_xDeferedItemContainer.is() )
822 {
823 SetItemContainer( m_xDeferedItemContainer );
824 m_xDeferedItemContainer.clear();
825 }
826 }
827
IMPL_LINK(MenuBarManager,Select,Menu *,pMenu,bool)828 IMPL_LINK( MenuBarManager, Select, Menu *, pMenu, bool )
829 {
830 URL aTargetURL;
831 Sequence<PropertyValue> aArgs;
832 Reference< XDispatch > xDispatch;
833
834 {
835 SolarMutexGuard g;
836
837 sal_uInt16 nCurItemId = pMenu->GetCurItemId();
838 sal_uInt16 nCurPos = pMenu->GetItemPos( nCurItemId );
839 if ( pMenu == m_pVCLMenu &&
840 pMenu->GetItemType( nCurPos ) != MenuItemType::SEPARATOR )
841 {
842 if ( nCurItemId >= START_ITEMID_WINDOWLIST &&
843 nCurItemId <= END_ITEMID_WINDOWLIST )
844 {
845 // window list menu item selected
846
847 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( m_xContext );
848
849 sal_uInt16 nTaskId = START_ITEMID_WINDOWLIST;
850 Reference< XIndexAccess > xList = xDesktop->getFrames();
851 sal_Int32 nCount = xList->getCount();
852 for ( sal_Int32 i=0; i<nCount; ++i )
853 {
854 Reference< XFrame > xFrame;
855 xList->getByIndex(i) >>= xFrame;
856 if ( xFrame.is() && nTaskId == nCurItemId )
857 {
858 VclPtr<vcl::Window> pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() );
859 pWin->GrabFocus();
860 pWin->ToTop( ToTopFlags::RestoreWhenMin );
861 break;
862 }
863
864 nTaskId++;
865 }
866 }
867 else
868 {
869 MenuItemHandler* pMenuItemHandler = GetMenuItemHandler( nCurItemId );
870 if ( pMenuItemHandler && pMenuItemHandler->xMenuItemDispatch.is() )
871 {
872 aTargetURL.Complete = pMenuItemHandler->aMenuItemURL;
873 m_xURLTransformer->parseStrict( aTargetURL );
874
875 if ( m_bIsBookmarkMenu )
876 {
877 // bookmark menu item selected
878 aArgs.realloc( 1 );
879 aArgs[0].Name = "Referer";
880 aArgs[0].Value <<= OUString( "private:user" );
881 }
882
883 xDispatch = pMenuItemHandler->xMenuItemDispatch;
884 }
885 }
886 }
887 }
888
889 // tdf#126054 don't let dispatch destroy this until after function completes
890 rtl::Reference<MenuBarManager> xRef(this);
891 if (xDispatch.is())
892 {
893 SolarMutexReleaser aReleaser;
894 xDispatch->dispatch( aTargetURL, aArgs );
895 }
896
897 if ( !m_bHasMenuBar )
898 // Standalone (non-native) popup menu doesn't fire deactivate event
899 // in this case, so we have to reset the active flag here.
900 m_bActive = false;
901
902 return true;
903 }
904
MustBeHidden(PopupMenu * pPopupMenu,const Reference<XURLTransformer> & rTransformer)905 bool MenuBarManager::MustBeHidden( PopupMenu* pPopupMenu, const Reference< XURLTransformer >& rTransformer )
906 {
907 if ( pPopupMenu )
908 {
909 URL aTargetURL;
910 SvtCommandOptions aCmdOptions;
911
912 sal_uInt16 nCount = pPopupMenu->GetItemCount();
913 sal_uInt16 nHideCount( 0 );
914
915 for ( sal_uInt16 i = 0; i < nCount; i++ )
916 {
917 sal_uInt16 nId = pPopupMenu->GetItemId( i );
918 if ( nId > 0 )
919 {
920 PopupMenu* pSubPopupMenu = pPopupMenu->GetPopupMenu( nId );
921 if ( pSubPopupMenu )
922 {
923 if ( MustBeHidden( pSubPopupMenu, rTransformer ))
924 {
925 pPopupMenu->HideItem( nId );
926 ++nHideCount;
927 }
928 }
929 else
930 {
931 aTargetURL.Complete = pPopupMenu->GetItemCommand( nId );
932 rTransformer->parseStrict( aTargetURL );
933
934 if ( aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, aTargetURL.Path ))
935 ++nHideCount;
936 }
937 }
938 else
939 ++nHideCount;
940 }
941
942 return ( nCount == nHideCount );
943 }
944
945 return true;
946 }
947
RetrieveLabelFromCommand(const OUString & rCmdURL)948 OUString MenuBarManager::RetrieveLabelFromCommand(const OUString& rCmdURL)
949 {
950 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rCmdURL, m_aModuleIdentifier);
951 if ( !m_bHasMenuBar )
952 {
953 // This is a context menu, prefer "PopupLabel" over "Label".
954 return vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
955 }
956 return vcl::CommandInfoProvider::GetMenuLabelForCommand(aProperties);
957 }
958
CreatePopupMenuController(MenuItemHandler * pMenuItemHandler)959 bool MenuBarManager::CreatePopupMenuController( MenuItemHandler* pMenuItemHandler )
960 {
961 OUString aItemCommand( pMenuItemHandler->aMenuItemURL );
962
963 // Try instantiate a popup menu controller. It is stored in the menu item handler.
964 if ( !m_xPopupMenuControllerFactory.is() )
965 return false;
966
967 Sequence< Any > aSeq( 3 );
968 aSeq[0] <<= comphelper::makePropertyValue( "ModuleIdentifier", m_aModuleIdentifier );
969 aSeq[1] <<= comphelper::makePropertyValue( "Frame", m_xFrame );
970 aSeq[2] <<= comphelper::makePropertyValue( "InToolbar", !m_bHasMenuBar );
971
972 Reference< XPopupMenuController > xPopupMenuController(
973 m_xPopupMenuControllerFactory->createInstanceWithArgumentsAndContext(
974 aItemCommand,
975 aSeq,
976 m_xContext ),
977 UNO_QUERY );
978
979 if ( xPopupMenuController.is() )
980 {
981 // Provide our awt popup menu to the popup menu controller
982 pMenuItemHandler->xPopupMenuController = xPopupMenuController;
983 xPopupMenuController->setPopupMenu( pMenuItemHandler->xPopupMenu );
984 return true;
985 }
986
987 return false;
988 }
989
FillMenuManager(Menu * pMenu,const Reference<XFrame> & rFrame,const Reference<XDispatchProvider> & rDispatchProvider,const OUString & rModuleIdentifier,bool bDelete)990 void MenuBarManager::FillMenuManager( Menu* pMenu, const Reference< XFrame >& rFrame,
991 const Reference< XDispatchProvider >& rDispatchProvider,
992 const OUString& rModuleIdentifier, bool bDelete )
993 {
994 m_xFrame = rFrame;
995 m_bActive = false;
996 m_bDeleteMenu = bDelete;
997 m_pVCLMenu = pMenu;
998 m_bIsBookmarkMenu = false;
999 m_xDispatchProvider = rDispatchProvider;
1000
1001 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
1002 m_bShowMenuImages = rSettings.GetUseImagesInMenus();
1003 m_bRetrieveImages = false;
1004
1005 // Add root as ui configuration listener
1006 RetrieveImageManagers();
1007
1008 if ( pMenu->IsMenuBar() && rFrame.is() )
1009 {
1010 // First merge all addon popup menus into our structure
1011 sal_uInt16 nPos = 0;
1012 for ( nPos = 0; nPos < pMenu->GetItemCount(); nPos++ )
1013 {
1014 sal_uInt16 nItemId = pMenu->GetItemId( nPos );
1015 OUString aCommand = pMenu->GetItemCommand( nItemId );
1016 if ( aCommand == aSpecialWindowCommand || aCommand == aCmdHelpMenu )
1017 {
1018 // Retrieve addon popup menus and add them to our menu bar
1019 framework::AddonMenuManager::MergeAddonPopupMenus( rFrame, nPos, static_cast<MenuBar *>(pMenu) );
1020 break;
1021 }
1022 }
1023
1024 // Merge the Add-Ons help menu items into the Office help menu
1025 framework::AddonMenuManager::MergeAddonHelpMenu( rFrame, static_cast<MenuBar *>(pMenu) );
1026 }
1027
1028 bool bAccessibilityEnabled( Application::GetSettings().GetMiscSettings().GetEnableATToolSupport() );
1029 sal_uInt16 nItemCount = pMenu->GetItemCount();
1030 OUString aItemCommand;
1031 m_aMenuItemHandlerVector.reserve(nItemCount);
1032 for ( sal_uInt16 i = 0; i < nItemCount; i++ )
1033 {
1034 sal_uInt16 nItemId = FillItemCommand(aItemCommand,pMenu, i );
1035
1036 // Set module identifier when provided from outside
1037 if ( !rModuleIdentifier.isEmpty() )
1038 {
1039 m_aModuleIdentifier = rModuleIdentifier;
1040 m_bModuleIdentified = true;
1041 }
1042
1043 if (( pMenu->IsMenuBar() || bAccessibilityEnabled ) &&
1044 ( pMenu->GetItemText( nItemId ).isEmpty() ))
1045 {
1046 if ( !aItemCommand.isEmpty() )
1047 pMenu->SetItemText( nItemId, RetrieveLabelFromCommand( aItemCommand ));
1048 }
1049
1050 // Command can be just an alias to another command.
1051 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aItemCommand, m_aModuleIdentifier);
1052 OUString aRealCommand = vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties);
1053 if ( !aRealCommand.isEmpty() )
1054 aItemCommand = aRealCommand;
1055
1056 Reference< XDispatch > xDispatch;
1057 Reference< XStatusListener > xStatusListener;
1058 VclPtr<PopupMenu> pPopup = pMenu->GetPopupMenu( nItemId );
1059 // overwrite the show icons on menu option?
1060 MenuItemBits nBits = pMenu->GetItemBits( nItemId ) & ( MenuItemBits::ICON | MenuItemBits::TEXT );
1061 bool bItemShowMenuImages = ( m_bShowMenuImages && nBits != MenuItemBits::TEXT ) || nBits & MenuItemBits::ICON;
1062
1063 if ( pPopup )
1064 {
1065 // Retrieve module identifier from Help Command entry
1066 OUString aModuleIdentifier( rModuleIdentifier );
1067 if (!pMenu->GetHelpCommand(nItemId).isEmpty())
1068 {
1069 aModuleIdentifier = pMenu->GetHelpCommand( nItemId );
1070 pMenu->SetHelpCommand( nItemId, "" );
1071 }
1072
1073 if ( m_xPopupMenuControllerFactory.is() &&
1074 pPopup->GetItemCount() == 0 &&
1075 m_xPopupMenuControllerFactory->hasController( aItemCommand, m_aModuleIdentifier )
1076 )
1077 {
1078 // Check if we have to create a popup menu for a uno based popup menu controller.
1079 // We have to set an empty popup menu into our menu structure so the controller also
1080 // works with inplace OLE. Remove old dummy popup menu!
1081 MenuItemHandler* pItemHandler = new MenuItemHandler( nItemId, xStatusListener, xDispatch );
1082 VCLXPopupMenu* pVCLXPopupMenu = new VCLXPopupMenu;
1083 PopupMenu* pNewPopupMenu = static_cast<PopupMenu *>(pVCLXPopupMenu->GetMenu());
1084 pMenu->SetPopupMenu( nItemId, pNewPopupMenu );
1085 pItemHandler->xPopupMenu = pVCLXPopupMenu;
1086 pItemHandler->aMenuItemURL = aItemCommand;
1087 m_aMenuItemHandlerVector.push_back( std::unique_ptr<MenuItemHandler>(pItemHandler) );
1088 pPopup.disposeAndClear();
1089
1090 if ( bAccessibilityEnabled )
1091 {
1092 if ( CreatePopupMenuController( pItemHandler ))
1093 pItemHandler->xPopupMenuController->updatePopupMenu();
1094 }
1095 lcl_CheckForChildren(pMenu, nItemId);
1096 }
1097 else if ( aItemCommand.startsWith( ADDONSPOPUPMENU_URL_PREFIX_STR ) )
1098 {
1099 // A special addon popup menu, must be created with a different ctor
1100 MenuBarManager* pSubMenuManager = new MenuBarManager( m_xContext, m_xFrame, m_xURLTransformer, pPopup, true );
1101 AddMenu(pSubMenuManager,aItemCommand,nItemId);
1102 }
1103 else
1104 {
1105 Reference< XDispatchProvider > xPopupMenuDispatchProvider( rDispatchProvider );
1106
1107 // Retrieve possible attributes struct
1108 MenuAttributes* pAttributes = static_cast<MenuAttributes *>(pMenu->GetUserValue( nItemId ));
1109 if ( pAttributes )
1110 xPopupMenuDispatchProvider = pAttributes->xDispatchProvider;
1111
1112 // Check if this is the help menu. Add menu item if needed
1113 if ( aItemCommand == aCmdHelpMenu )
1114 {
1115 }
1116 else if ( aItemCommand == aCmdToolsMenu && AddonMenuManager::HasAddonMenuElements() )
1117 {
1118 // Create addon popup menu if there exist elements and this is the tools popup menu
1119 VclPtr<PopupMenu> pSubMenu = AddonMenuManager::CreateAddonMenu(rFrame);
1120 if ( pSubMenu && ( pSubMenu->GetItemCount() > 0 ))
1121 {
1122 if ( pPopup->GetItemType( pPopup->GetItemCount() - 1 ) != MenuItemType::SEPARATOR )
1123 pPopup->InsertSeparator();
1124
1125 pPopup->InsertItem( ITEMID_ADDONLIST, OUString() );
1126 pPopup->SetPopupMenu( ITEMID_ADDONLIST, pSubMenu );
1127 pPopup->SetItemCommand( ITEMID_ADDONLIST, ".uno:Addons" );
1128 }
1129 else
1130 pSubMenu.disposeAndClear();
1131 }
1132
1133 MenuBarManager* pSubMenuManager;
1134 if ( nItemId == ITEMID_ADDONLIST )
1135 pSubMenuManager = new MenuBarManager( m_xContext, m_xFrame, m_xURLTransformer, pPopup, false );
1136 else
1137 pSubMenuManager = new MenuBarManager( m_xContext, rFrame, m_xURLTransformer,
1138 rDispatchProvider, aModuleIdentifier,
1139 pPopup, false, m_bHasMenuBar );
1140
1141 AddMenu(pSubMenuManager, aItemCommand, nItemId);
1142 }
1143 }
1144 else if ( pMenu->GetItemType( i ) != MenuItemType::SEPARATOR )
1145 {
1146 if ( bItemShowMenuImages )
1147 m_bRetrieveImages = true;
1148
1149 std::unique_ptr<MenuItemHandler> pItemHandler(new MenuItemHandler( nItemId, xStatusListener, xDispatch ));
1150 pItemHandler->aMenuItemURL = aItemCommand;
1151
1152 if ( m_xPopupMenuControllerFactory.is() &&
1153 m_xPopupMenuControllerFactory->hasController( aItemCommand, m_aModuleIdentifier ) )
1154 {
1155 // Check if we have to create a popup menu for a uno based popup menu controller.
1156 // We have to set an empty popup menu into our menu structure so the controller also
1157 // works with inplace OLE.
1158 VCLXPopupMenu* pVCLXPopupMenu = new VCLXPopupMenu;
1159 PopupMenu* pPopupMenu = static_cast<PopupMenu *>(pVCLXPopupMenu->GetMenu());
1160 pMenu->SetPopupMenu( pItemHandler->nItemId, pPopupMenu );
1161 pItemHandler->xPopupMenu = pVCLXPopupMenu;
1162
1163 if ( bAccessibilityEnabled && CreatePopupMenuController( pItemHandler.get() ) )
1164 {
1165 pItemHandler->xPopupMenuController->updatePopupMenu();
1166 }
1167
1168 lcl_CheckForChildren(pMenu, pItemHandler->nItemId);
1169 }
1170
1171 m_aMenuItemHandlerVector.push_back( std::move(pItemHandler) );
1172 }
1173 }
1174
1175 if ( m_bHasMenuBar && bAccessibilityEnabled )
1176 {
1177 RetrieveShortcuts( m_aMenuItemHandlerVector );
1178 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
1179 {
1180 // Set key code, workaround for hard-coded shortcut F1 mapped to .uno:HelpIndex
1181 // Only non-popup menu items can have a short-cut
1182 if ( menuItemHandler->aMenuItemURL == aCmdHelpIndex )
1183 {
1184 vcl::KeyCode aKeyCode( KEY_F1 );
1185 pMenu->SetAccelKey( menuItemHandler->nItemId, aKeyCode );
1186 }
1187 else if ( pMenu->GetPopupMenu( menuItemHandler->nItemId ) == nullptr )
1188 pMenu->SetAccelKey( menuItemHandler->nItemId, menuItemHandler->aKeyCode );
1189 }
1190 }
1191
1192 SetHdl();
1193 }
1194
impl_RetrieveShortcutsFromConfiguration(const Reference<XAcceleratorConfiguration> & rAccelCfg,const Sequence<OUString> & rCommands,std::vector<std::unique_ptr<MenuItemHandler>> & aMenuShortCuts)1195 void MenuBarManager::impl_RetrieveShortcutsFromConfiguration(
1196 const Reference< XAcceleratorConfiguration >& rAccelCfg,
1197 const Sequence< OUString >& rCommands,
1198 std::vector< std::unique_ptr<MenuItemHandler> >& aMenuShortCuts )
1199 {
1200 if ( rAccelCfg.is() )
1201 {
1202 try
1203 {
1204 css::awt::KeyEvent aKeyEvent;
1205 Sequence< Any > aSeqKeyCode = rAccelCfg->getPreferredKeyEventsForCommandList( rCommands );
1206 for ( sal_Int32 i = 0; i < aSeqKeyCode.getLength(); i++ )
1207 {
1208 if ( aSeqKeyCode[i] >>= aKeyEvent )
1209 aMenuShortCuts[i]->aKeyCode = svt::AcceleratorExecute::st_AWTKey2VCLKey( aKeyEvent );
1210 }
1211 }
1212 catch ( const IllegalArgumentException& )
1213 {
1214 }
1215 }
1216 }
1217
RetrieveShortcuts(std::vector<std::unique_ptr<MenuItemHandler>> & aMenuShortCuts)1218 void MenuBarManager::RetrieveShortcuts( std::vector< std::unique_ptr<MenuItemHandler> >& aMenuShortCuts )
1219 {
1220 if ( !m_bModuleIdentified )
1221 {
1222 m_bModuleIdentified = true;
1223 Reference< XModuleManager2 > xModuleManager = ModuleManager::create( m_xContext );
1224
1225 try
1226 {
1227 m_aModuleIdentifier = xModuleManager->identify( m_xFrame );
1228 }
1229 catch( const Exception& )
1230 {
1231 }
1232 }
1233
1234 if ( m_bModuleIdentified )
1235 {
1236 Reference< XAcceleratorConfiguration > xDocAccelCfg( m_xDocAcceleratorManager );
1237 Reference< XAcceleratorConfiguration > xModuleAccelCfg( m_xModuleAcceleratorManager );
1238 Reference< XAcceleratorConfiguration > xGlobalAccelCfg( m_xGlobalAcceleratorManager );
1239
1240 if ( !m_bAcceleratorCfg )
1241 {
1242 // Retrieve references on demand
1243 m_bAcceleratorCfg = true;
1244 if ( !xDocAccelCfg.is() )
1245 {
1246 Reference< XController > xController = m_xFrame->getController();
1247 Reference< XModel > xModel;
1248 if ( xController.is() )
1249 {
1250 xModel = xController->getModel();
1251 if ( xModel.is() )
1252 {
1253 Reference< XUIConfigurationManagerSupplier > xSupplier( xModel, UNO_QUERY );
1254 if ( xSupplier.is() )
1255 {
1256 Reference< XUIConfigurationManager > xDocUICfgMgr = xSupplier->getUIConfigurationManager();
1257 if ( xDocUICfgMgr.is() )
1258 {
1259 xDocAccelCfg = xDocUICfgMgr->getShortCutManager();
1260 m_xDocAcceleratorManager = xDocAccelCfg;
1261 }
1262 }
1263 }
1264 }
1265 }
1266
1267 if ( !xModuleAccelCfg.is() )
1268 {
1269 Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier =
1270 theModuleUIConfigurationManagerSupplier::get( m_xContext );
1271 try
1272 {
1273 Reference< XUIConfigurationManager > xUICfgMgr = xModuleCfgMgrSupplier->getUIConfigurationManager( m_aModuleIdentifier );
1274 if ( xUICfgMgr.is() )
1275 {
1276 xModuleAccelCfg = xUICfgMgr->getShortCutManager();
1277 m_xModuleAcceleratorManager = xModuleAccelCfg;
1278 }
1279 }
1280 catch ( const RuntimeException& )
1281 {
1282 throw;
1283 }
1284 catch ( const Exception& )
1285 {
1286 }
1287 }
1288
1289 if ( !xGlobalAccelCfg.is() ) try
1290 {
1291 xGlobalAccelCfg = GlobalAcceleratorConfiguration::create( m_xContext );
1292 m_xGlobalAcceleratorManager = xGlobalAccelCfg;
1293 }
1294 catch ( const css::uno::DeploymentException& )
1295 {
1296 SAL_WARN("fwk.uielement", "GlobalAcceleratorConfiguration"
1297 " not available. This should happen only on mobile platforms.");
1298 }
1299 }
1300
1301 vcl::KeyCode aEmptyKeyCode;
1302 Sequence< OUString > aSeq( aMenuShortCuts.size() );
1303 const sal_uInt32 nCount = aMenuShortCuts.size();
1304 for ( sal_uInt32 i = 0; i < nCount; ++i )
1305 {
1306 OUString aItemURL = aMenuShortCuts[i]->aMenuItemURL;
1307 if( aItemURL.isEmpty() && aMenuShortCuts[i]->xSubMenuManager.is())
1308 aItemURL = "-"; // tdf#99527 prevent throw in case of empty commands
1309 aSeq[i] = aItemURL;
1310 aMenuShortCuts[i]->aKeyCode = aEmptyKeyCode;
1311 }
1312
1313 if ( m_xGlobalAcceleratorManager.is() )
1314 impl_RetrieveShortcutsFromConfiguration( xGlobalAccelCfg, aSeq, aMenuShortCuts );
1315 if ( m_xModuleAcceleratorManager.is() )
1316 impl_RetrieveShortcutsFromConfiguration( xModuleAccelCfg, aSeq, aMenuShortCuts );
1317 if ( m_xDocAcceleratorManager.is() )
1318 impl_RetrieveShortcutsFromConfiguration( xDocAccelCfg, aSeq, aMenuShortCuts );
1319 }
1320 }
1321
RetrieveImageManagers()1322 void MenuBarManager::RetrieveImageManagers()
1323 {
1324 if ( !m_xDocImageManager.is() )
1325 {
1326 Reference< XController > xController = m_xFrame->getController();
1327 Reference< XModel > xModel;
1328 if ( xController.is() )
1329 {
1330 xModel = xController->getModel();
1331 if ( xModel.is() )
1332 {
1333 Reference< XUIConfigurationManagerSupplier > xSupplier( xModel, UNO_QUERY );
1334 if ( xSupplier.is() )
1335 {
1336 Reference< XUIConfigurationManager > xDocUICfgMgr = xSupplier->getUIConfigurationManager();
1337 m_xDocImageManager.set( xDocUICfgMgr->getImageManager(), UNO_QUERY );
1338 m_xDocImageManager->addConfigurationListener(
1339 Reference< XUIConfigurationListener >(
1340 static_cast< OWeakObject* >( this ), UNO_QUERY ));
1341 }
1342 }
1343 }
1344 }
1345
1346 Reference< XModuleManager2 > xModuleManager;
1347 if ( m_aModuleIdentifier.isEmpty() )
1348 xModuleManager.set( ModuleManager::create( m_xContext ) );
1349
1350 try
1351 {
1352 if ( xModuleManager.is() )
1353 m_aModuleIdentifier = xModuleManager->identify( Reference< XInterface >( m_xFrame, UNO_QUERY ) );
1354 }
1355 catch( const Exception& )
1356 {
1357 }
1358
1359 if ( !m_xModuleImageManager.is() )
1360 {
1361 Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgMgrSupplier =
1362 theModuleUIConfigurationManagerSupplier::get( m_xContext );
1363 Reference< XUIConfigurationManager > xUICfgMgr = xModuleCfgMgrSupplier->getUIConfigurationManager( m_aModuleIdentifier );
1364 m_xModuleImageManager.set( xUICfgMgr->getImageManager(), UNO_QUERY );
1365 m_xModuleImageManager->addConfigurationListener( Reference< XUIConfigurationListener >(
1366 static_cast< OWeakObject* >( this ), UNO_QUERY ));
1367 }
1368 }
1369
FillMenuWithConfiguration(sal_uInt16 & nId,Menu * pMenu,const OUString & rModuleIdentifier,const Reference<XIndexAccess> & rItemContainer,const Reference<XURLTransformer> & rTransformer)1370 void MenuBarManager::FillMenuWithConfiguration(
1371 sal_uInt16& nId,
1372 Menu* pMenu,
1373 const OUString& rModuleIdentifier,
1374 const Reference< XIndexAccess >& rItemContainer,
1375 const Reference< XURLTransformer >& rTransformer )
1376 {
1377 Reference< XDispatchProvider > xEmptyDispatchProvider;
1378 MenuBarManager::FillMenu( nId, pMenu, rModuleIdentifier, rItemContainer, xEmptyDispatchProvider );
1379
1380 // Merge add-on menu entries into the menu bar
1381 MenuBarManager::MergeAddonMenus( pMenu,
1382 AddonsOptions().GetMergeMenuInstructions(),
1383 rModuleIdentifier );
1384
1385 bool bHasDisabledEntries = SvtCommandOptions().HasEntries( SvtCommandOptions::CMDOPTION_DISABLED );
1386 if ( bHasDisabledEntries )
1387 {
1388 sal_uInt16 nCount = pMenu->GetItemCount();
1389 for ( sal_uInt16 i = 0; i < nCount; i++ )
1390 {
1391 sal_uInt16 nID = pMenu->GetItemId( i );
1392 if ( nID > 0 )
1393 {
1394 PopupMenu* pPopupMenu = pMenu->GetPopupMenu( nID );
1395 if ( pPopupMenu )
1396 {
1397 if ( MustBeHidden( pPopupMenu, rTransformer ))
1398 pMenu->HideItem( nId );
1399 }
1400 }
1401 }
1402 }
1403 }
1404
FillMenu(sal_uInt16 & nId,Menu * pMenu,const OUString & rModuleIdentifier,const Reference<XIndexAccess> & rItemContainer,const Reference<XDispatchProvider> & rDispatchProvider)1405 void MenuBarManager::FillMenu(
1406 sal_uInt16& nId,
1407 Menu* pMenu,
1408 const OUString& rModuleIdentifier,
1409 const Reference< XIndexAccess >& rItemContainer,
1410 const Reference< XDispatchProvider >& rDispatchProvider )
1411 {
1412 // Fill menu bar with container contents
1413 for ( sal_Int32 n = 0; n < rItemContainer->getCount(); n++ )
1414 {
1415 Sequence< PropertyValue > aProp;
1416 OUString aCommandURL;
1417 OUString aLabel;
1418 OUString aModuleIdentifier( rModuleIdentifier );
1419 sal_uInt16 nType = 0;
1420 Reference< XIndexAccess > xIndexContainer;
1421 Reference< XDispatchProvider > xDispatchProvider( rDispatchProvider );
1422 sal_Int16 nStyle = 0;
1423 try
1424 {
1425 if ( rItemContainer->getByIndex( n ) >>= aProp )
1426 {
1427 bool bShow = true;
1428 bool bEnabled = true;
1429
1430 for ( int i = 0; i < aProp.getLength(); i++ )
1431 {
1432 OUString aPropName = aProp[i].Name;
1433 if ( aPropName == "CommandURL" )
1434 aProp[i].Value >>= aCommandURL;
1435 else if ( aPropName == "ItemDescriptorContainer" )
1436 aProp[i].Value >>= xIndexContainer;
1437 else if ( aPropName == "Label" )
1438 aProp[i].Value >>= aLabel;
1439 else if ( aPropName == "Type" )
1440 aProp[i].Value >>= nType;
1441 else if ( aPropName == "ModuleIdentifier" )
1442 aProp[i].Value >>= aModuleIdentifier;
1443 else if ( aPropName == "DispatchProvider" )
1444 aProp[i].Value >>= xDispatchProvider;
1445 else if ( aPropName == "Style" )
1446 aProp[i].Value >>= nStyle;
1447 else if ( aPropName == "IsVisible" )
1448 aProp[i].Value >>= bShow;
1449 else if ( aPropName == "Enabled" )
1450 aProp[i].Value >>= bEnabled;
1451 }
1452
1453 if (!aCommandURL.isEmpty() && vcl::CommandInfoProvider::IsExperimental(aCommandURL, rModuleIdentifier) &&
1454 !SvtMiscOptions().IsExperimentalMode())
1455 {
1456 continue;
1457 }
1458
1459 if ( nType == css::ui::ItemType::DEFAULT )
1460 {
1461 pMenu->InsertItem( nId, aLabel );
1462 pMenu->SetItemCommand( nId, aCommandURL );
1463
1464 if ( nStyle )
1465 {
1466 MenuItemBits nBits = pMenu->GetItemBits( nId );
1467 if ( nStyle & css::ui::ItemStyle::ICON )
1468 nBits |= MenuItemBits::ICON;
1469 if ( nStyle & css::ui::ItemStyle::TEXT )
1470 nBits |= MenuItemBits::TEXT;
1471 if ( nStyle & css::ui::ItemStyle::RADIO_CHECK )
1472 nBits |= MenuItemBits::RADIOCHECK;
1473 pMenu->SetItemBits( nId, nBits );
1474 }
1475
1476 if ( !bShow )
1477 pMenu->HideItem( nId );
1478
1479 if ( !bEnabled)
1480 pMenu->EnableItem( nId, false );
1481
1482 if ( xIndexContainer.is() )
1483 {
1484 VclPtr<PopupMenu> pNewPopupMenu = VclPtr<PopupMenu>::Create();
1485 pMenu->SetPopupMenu( nId, pNewPopupMenu );
1486
1487 if ( xDispatchProvider.is() )
1488 {
1489 // Use attributes struct to transport special dispatch provider
1490 void* nAttributePtr = MenuAttributes::CreateAttribute(xDispatchProvider);
1491 pMenu->SetUserValue(nId, nAttributePtr, MenuAttributes::ReleaseAttribute);
1492 }
1493
1494 // Use help command to transport module identifier
1495 if ( !aModuleIdentifier.isEmpty() )
1496 pMenu->SetHelpCommand( nId, aModuleIdentifier );
1497
1498 ++nId;
1499 FillMenu( nId, pNewPopupMenu, aModuleIdentifier, xIndexContainer, xDispatchProvider );
1500 }
1501 else
1502 ++nId;
1503 }
1504 else
1505 {
1506 pMenu->InsertSeparator();
1507 ++nId;
1508 }
1509 }
1510 }
1511 catch ( const IndexOutOfBoundsException& )
1512 {
1513 break;
1514 }
1515 }
1516 }
1517
MergeAddonMenus(Menu * pMenuBar,const MergeMenuInstructionContainer & aMergeInstructionContainer,const OUString & rModuleIdentifier)1518 void MenuBarManager::MergeAddonMenus(
1519 Menu* pMenuBar,
1520 const MergeMenuInstructionContainer& aMergeInstructionContainer,
1521 const OUString& rModuleIdentifier )
1522 {
1523 // set start value for the item ID for the new addon menu items
1524 sal_uInt16 nItemId = ADDONMENU_MERGE_ITEMID_START;
1525
1526 const sal_uInt32 nCount = aMergeInstructionContainer.size();
1527 for ( sal_uInt32 i = 0; i < nCount; i++ )
1528 {
1529 const MergeMenuInstruction& rMergeInstruction = aMergeInstructionContainer[i];
1530
1531 if ( MenuBarMerger::IsCorrectContext( rMergeInstruction.aMergeContext, rModuleIdentifier ))
1532 {
1533 ::std::vector< OUString > aMergePath;
1534
1535 // retrieve the merge path from the merge point string
1536 MenuBarMerger::RetrieveReferencePath( rMergeInstruction.aMergePoint, aMergePath );
1537
1538 // convert the sequence/sequence property value to a more convenient vector<>
1539 AddonMenuContainer aMergeMenuItems;
1540 MenuBarMerger::GetSubMenu( rMergeInstruction.aMergeMenu, aMergeMenuItems );
1541
1542 // try to find the reference point for our merge operation
1543 Menu* pMenu = pMenuBar;
1544 ReferencePathInfo aResult = MenuBarMerger::FindReferencePath( aMergePath, pMenu );
1545
1546 if ( aResult.eResult == RP_OK )
1547 {
1548 // normal merge operation
1549 MenuBarMerger::ProcessMergeOperation( aResult.pPopupMenu,
1550 aResult.nPos,
1551 nItemId,
1552 rMergeInstruction.aMergeCommand,
1553 rMergeInstruction.aMergeCommandParameter,
1554 rModuleIdentifier,
1555 aMergeMenuItems );
1556 }
1557 else
1558 {
1559 // fallback
1560 MenuBarMerger::ProcessFallbackOperation( aResult,
1561 nItemId,
1562 rMergeInstruction.aMergeCommand,
1563 rMergeInstruction.aMergeFallback,
1564 aMergePath,
1565 rModuleIdentifier,
1566 aMergeMenuItems );
1567 }
1568 }
1569 }
1570 }
1571
SetItemContainer(const Reference<XIndexAccess> & rItemContainer)1572 void MenuBarManager::SetItemContainer( const Reference< XIndexAccess >& rItemContainer )
1573 {
1574 SolarMutexGuard aSolarMutexGuard;
1575
1576 Reference< XFrame > xFrame = m_xFrame;
1577
1578 if ( !m_bModuleIdentified )
1579 {
1580 m_bModuleIdentified = true;
1581 Reference< XModuleManager2 > xModuleManager = ModuleManager::create( m_xContext );
1582
1583 try
1584 {
1585 m_aModuleIdentifier = xModuleManager->identify( xFrame );
1586 }
1587 catch( const Exception& )
1588 {
1589 }
1590 }
1591
1592 // Clear MenuBarManager structures
1593 {
1594 // Check active state as we cannot change our VCL menu during activation by the user
1595 if ( m_bActive )
1596 {
1597 m_xDeferedItemContainer = rItemContainer;
1598 return;
1599 }
1600
1601 RemoveListener();
1602 m_aMenuItemHandlerVector.clear();
1603 m_pVCLMenu->Clear();
1604
1605 sal_uInt16 nId = 1;
1606
1607 // Fill menu bar with container contents
1608 FillMenuWithConfiguration( nId, m_pVCLMenu, m_aModuleIdentifier, rItemContainer, m_xURLTransformer );
1609
1610 // Refill menu manager again
1611 Reference< XDispatchProvider > xDispatchProvider;
1612 FillMenuManager( m_pVCLMenu, xFrame, xDispatchProvider, m_aModuleIdentifier, false );
1613
1614 // add itself as frame action listener
1615 m_xFrame->addFrameActionListener( Reference< XFrameActionListener >( static_cast< OWeakObject* >( this ), UNO_QUERY ));
1616 }
1617 }
1618
GetPopupController(PopupControllerCache & rPopupController)1619 void MenuBarManager::GetPopupController( PopupControllerCache& rPopupController )
1620 {
1621
1622 SolarMutexGuard aSolarMutexGuard;
1623
1624 for (auto const& menuItemHandler : m_aMenuItemHandlerVector)
1625 {
1626 if ( menuItemHandler->xPopupMenuController.is() )
1627 {
1628 Reference< XDispatchProvider > xDispatchProvider( menuItemHandler->xPopupMenuController, UNO_QUERY );
1629
1630 PopupControllerEntry aPopupControllerEntry;
1631 aPopupControllerEntry.m_xDispatchProvider = xDispatchProvider;
1632
1633 // Just use the main part of the URL for popup menu controllers
1634 sal_Int32 nQueryPart( 0 );
1635 sal_Int32 nSchemePart( 0 );
1636 OUString aMainURL( "vnd.sun.star.popup:" );
1637 OUString aMenuURL( menuItemHandler->aMenuItemURL );
1638
1639 nSchemePart = aMenuURL.indexOf( ':' );
1640 if (( nSchemePart > 0 ) &&
1641 ( aMenuURL.getLength() > ( nSchemePart+1 )))
1642 {
1643 nQueryPart = aMenuURL.indexOf( '?', nSchemePart );
1644 if ( nQueryPart > 0 )
1645 aMainURL += aMenuURL.copy( nSchemePart, nQueryPart-nSchemePart );
1646 else if ( nQueryPart == -1 )
1647 aMainURL += aMenuURL.copy( nSchemePart+1 );
1648
1649 rPopupController.emplace( aMainURL, aPopupControllerEntry );
1650 }
1651 }
1652 if ( menuItemHandler->xSubMenuManager.is() )
1653 {
1654 MenuBarManager* pMenuBarManager = static_cast<MenuBarManager*>(menuItemHandler->xSubMenuManager.get());
1655 if ( pMenuBarManager )
1656 pMenuBarManager->GetPopupController( rPopupController );
1657 }
1658 }
1659 }
1660
AddMenu(MenuBarManager * pSubMenuManager,const OUString & _sItemCommand,sal_uInt16 _nItemId)1661 void MenuBarManager::AddMenu(MenuBarManager* pSubMenuManager,const OUString& _sItemCommand,sal_uInt16 _nItemId)
1662 {
1663 Reference< XStatusListener > xSubMenuManager( static_cast< OWeakObject *>( pSubMenuManager ), UNO_QUERY );
1664 m_xFrame->addFrameActionListener( Reference< XFrameActionListener >( xSubMenuManager, UNO_QUERY ));
1665
1666 // store menu item command as we later have to know which menu is active (see Activate handler)
1667 pSubMenuManager->m_aMenuItemCommand = _sItemCommand;
1668 Reference< XDispatch > xDispatch;
1669 std::unique_ptr<MenuItemHandler> pMenuItemHandler(new MenuItemHandler(
1670 _nItemId,
1671 xSubMenuManager,
1672 xDispatch ));
1673 pMenuItemHandler->aMenuItemURL = _sItemCommand;
1674 m_aMenuItemHandlerVector.push_back( std::move(pMenuItemHandler) );
1675 }
1676
FillItemCommand(OUString & _rItemCommand,Menu * _pMenu,sal_uInt16 _nIndex) const1677 sal_uInt16 MenuBarManager::FillItemCommand(OUString& _rItemCommand, Menu* _pMenu,sal_uInt16 _nIndex) const
1678 {
1679 sal_uInt16 nItemId = _pMenu->GetItemId( _nIndex );
1680
1681 _rItemCommand = _pMenu->GetItemCommand( nItemId );
1682 if ( _rItemCommand.isEmpty() )
1683 {
1684 _rItemCommand = "slot:" + OUString::number( nItemId );
1685 _pMenu->SetItemCommand( nItemId, _rItemCommand );
1686 }
1687 return nItemId;
1688 }
Init(const Reference<XFrame> & rFrame,Menu * pAddonMenu,bool _bHandlePopUp)1689 void MenuBarManager::Init(const Reference< XFrame >& rFrame, Menu* pAddonMenu, bool _bHandlePopUp)
1690 {
1691 m_bActive = false;
1692 m_bDeleteMenu = false;
1693 m_pVCLMenu = pAddonMenu;
1694 m_xFrame = rFrame;
1695 m_bIsBookmarkMenu = true;
1696 m_bShowMenuImages = true;
1697
1698 m_xPopupMenuControllerFactory = frame::thePopupMenuControllerFactory::get(
1699 ::comphelper::getProcessComponentContext());
1700
1701 Reference< XStatusListener > xStatusListener;
1702 Reference< XDispatch > xDispatch;
1703 sal_uInt16 nItemCount = pAddonMenu->GetItemCount();
1704 OUString aItemCommand;
1705 m_aMenuItemHandlerVector.reserve(nItemCount);
1706 for ( sal_uInt16 i = 0; i < nItemCount; i++ )
1707 {
1708 sal_uInt16 nItemId = FillItemCommand(aItemCommand,pAddonMenu, i );
1709
1710 PopupMenu* pPopupMenu = pAddonMenu->GetPopupMenu( nItemId );
1711 if ( pPopupMenu )
1712 {
1713 Reference< XDispatchProvider > xDispatchProvider;
1714 MenuBarManager* pSubMenuManager = new MenuBarManager( m_xContext, rFrame, m_xURLTransformer,
1715 xDispatchProvider, OUString(), pPopupMenu,
1716 false );
1717
1718 Reference< XStatusListener > xSubMenuManager( static_cast< OWeakObject *>( pSubMenuManager ), UNO_QUERY );
1719
1720 // store menu item command as we later have to know which menu is active (see Activate handler)
1721 pSubMenuManager->m_aMenuItemCommand = aItemCommand;
1722
1723 std::unique_ptr<MenuItemHandler> pMenuItemHandler(new MenuItemHandler(
1724 nItemId,
1725 xSubMenuManager,
1726 xDispatch ));
1727 m_aMenuItemHandlerVector.push_back( std::move(pMenuItemHandler) );
1728 }
1729 else
1730 {
1731 if ( pAddonMenu->GetItemType( i ) != MenuItemType::SEPARATOR )
1732 {
1733 MenuAttributes* pAddonAttributes = static_cast<MenuAttributes *>(pAddonMenu->GetUserValue( nItemId ));
1734 std::unique_ptr<MenuItemHandler> pMenuItemHandler(new MenuItemHandler( nItemId, xStatusListener, xDispatch ));
1735
1736 if ( pAddonAttributes )
1737 {
1738 // read additional attributes from attributes struct and AddonMenu implementation
1739 // will delete all attributes itself!!
1740 pMenuItemHandler->aTargetFrame = pAddonAttributes->aTargetFrame;
1741 }
1742
1743 pMenuItemHandler->aMenuItemURL = aItemCommand;
1744 if ( _bHandlePopUp )
1745 {
1746 // Check if we have to create a popup menu for a uno based popup menu controller.
1747 // We have to set an empty popup menu into our menu structure so the controller also
1748 // works with inplace OLE.
1749 if ( m_xPopupMenuControllerFactory.is() &&
1750 m_xPopupMenuControllerFactory->hasController( aItemCommand, m_aModuleIdentifier ) )
1751 {
1752 VCLXPopupMenu* pVCLXPopupMenu = new VCLXPopupMenu;
1753 PopupMenu* pCtlPopupMenu = static_cast<PopupMenu *>(pVCLXPopupMenu->GetMenu());
1754 pAddonMenu->SetPopupMenu( pMenuItemHandler->nItemId, pCtlPopupMenu );
1755 pMenuItemHandler->xPopupMenu = pVCLXPopupMenu;
1756
1757 }
1758 }
1759 m_aMenuItemHandlerVector.push_back( std::move(pMenuItemHandler) );
1760 }
1761 }
1762 }
1763
1764 SetHdl();
1765 }
1766
SetHdl()1767 void MenuBarManager::SetHdl()
1768 {
1769 m_pVCLMenu->SetActivateHdl( LINK( this, MenuBarManager, Activate ));
1770 m_pVCLMenu->SetDeactivateHdl( LINK( this, MenuBarManager, Deactivate ));
1771 m_pVCLMenu->SetSelectHdl( LINK( this, MenuBarManager, Select ));
1772
1773 if ( !m_xURLTransformer.is() && m_xContext.is() )
1774 m_xURLTransformer.set( URLTransformer::create( m_xContext) );
1775 }
1776
UpdateSpecialWindowMenu(Menu * pMenu,const Reference<XComponentContext> & xContext)1777 void MenuBarManager::UpdateSpecialWindowMenu( Menu* pMenu,const Reference< XComponentContext >& xContext )
1778 {
1779 // update window list
1780 ::std::vector< OUString > aNewWindowListVector;
1781
1782 Reference< XDesktop2 > xDesktop = css::frame::Desktop::create( xContext );
1783
1784 sal_uInt16 nActiveItemId = 0;
1785 sal_uInt16 nItemId = START_ITEMID_WINDOWLIST;
1786
1787 Reference< XFrame > xCurrentFrame = xDesktop->getCurrentFrame();
1788 Reference< XIndexAccess > xList = xDesktop->getFrames();
1789 sal_Int32 nFrameCount = xList->getCount();
1790 aNewWindowListVector.reserve(nFrameCount);
1791 for (sal_Int32 i=0; i<nFrameCount; ++i )
1792 {
1793 Reference< XFrame > xFrame;
1794 xList->getByIndex(i) >>= xFrame;
1795
1796 if (xFrame.is())
1797 {
1798 if ( xFrame == xCurrentFrame )
1799 nActiveItemId = nItemId;
1800
1801 VclPtr<vcl::Window> pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() );
1802 OUString sWindowTitle;
1803 if ( pWin && pWin->IsVisible() )
1804 sWindowTitle = pWin->GetText();
1805
1806 // tdf#101658 In case the frame is embedded somewhere, LO has no control over it.
1807 // So we just skip it.
1808 if ( sWindowTitle.isEmpty() )
1809 continue;
1810
1811 aNewWindowListVector.push_back( sWindowTitle );
1812 ++nItemId;
1813 }
1814 }
1815
1816 {
1817 SolarMutexGuard g;
1818
1819 int nItemCount = pMenu->GetItemCount();
1820
1821 if ( nItemCount > 0 )
1822 {
1823 // remove all old window list entries from menu
1824 sal_uInt16 nPos = pMenu->GetItemPos( START_ITEMID_WINDOWLIST );
1825 for ( sal_uInt16 n = nPos; n < pMenu->GetItemCount(); )
1826 pMenu->RemoveItem( n );
1827
1828 if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MenuItemType::SEPARATOR )
1829 pMenu->RemoveItem( pMenu->GetItemCount()-1 );
1830 }
1831
1832 if ( !aNewWindowListVector.empty() )
1833 {
1834 // append new window list entries to menu
1835 pMenu->InsertSeparator();
1836 nItemId = START_ITEMID_WINDOWLIST;
1837 const sal_uInt32 nCount = aNewWindowListVector.size();
1838 for ( sal_uInt32 i = 0; i < nCount; i++ )
1839 {
1840 pMenu->InsertItem( nItemId, aNewWindowListVector.at( i ), MenuItemBits::RADIOCHECK );
1841 if ( nItemId == nActiveItemId )
1842 pMenu->CheckItem( nItemId );
1843 ++nItemId;
1844 }
1845 }
1846 }
1847 }
1848
FillMenuImages(Reference<XFrame> const & _xFrame,Menu * _pMenu,bool bShowMenuImages)1849 void MenuBarManager::FillMenuImages(Reference< XFrame > const & _xFrame, Menu* _pMenu,bool bShowMenuImages)
1850 {
1851 AddonsOptions aAddonOptions;
1852
1853 for ( sal_uInt16 nPos = 0; nPos < _pMenu->GetItemCount(); nPos++ )
1854 {
1855 sal_uInt16 nId = _pMenu->GetItemId( nPos );
1856 if ( _pMenu->GetItemType( nPos ) != MenuItemType::SEPARATOR )
1857 {
1858 // overwrite the show icons on menu option?
1859 MenuItemBits nBits = _pMenu->GetItemBits( nId ) & ( MenuItemBits::ICON | MenuItemBits::TEXT );
1860 bool bTmpShowMenuImages = ( bShowMenuImages && nBits != MenuItemBits::TEXT ) || nBits & MenuItemBits::ICON;
1861
1862 if ( bTmpShowMenuImages )
1863 {
1864 bool bImageSet = false;
1865 OUString aImageId;
1866
1867 ::framework::MenuAttributes* pMenuAttributes =
1868 static_cast< ::framework::MenuAttributes*>(_pMenu->GetUserValue( nId ));
1869
1870 if ( pMenuAttributes )
1871 aImageId = pMenuAttributes->aImageId; // Retrieve image id from menu attributes
1872
1873 if ( !aImageId.isEmpty() )
1874 {
1875 Image aImage = vcl::CommandInfoProvider::GetImageForCommand(aImageId, _xFrame);
1876 if ( !!aImage )
1877 {
1878 bImageSet = true;
1879 _pMenu->SetItemImage( nId, aImage );
1880 }
1881 }
1882
1883 if ( !bImageSet )
1884 {
1885 OUString aMenuItemCommand = _pMenu->GetItemCommand( nId );
1886 Image aImage = vcl::CommandInfoProvider::GetImageForCommand(aMenuItemCommand, _xFrame);
1887 if ( !aImage )
1888 aImage = aAddonOptions.GetImageFromURL( aMenuItemCommand, false );
1889
1890 _pMenu->SetItemImage( nId, aImage );
1891 }
1892 }
1893 else
1894 _pMenu->SetItemImage( nId, Image() );
1895 }
1896 }
1897 }
1898
1899 }
1900
1901 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1902