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/toolbarsmenucontroller.hxx> 21 22 #include <algorithm> 23 #include <string_view> 24 25 #include <services.h> 26 #include <strings.hrc> 27 #include <classes/fwkresid.hxx> 28 #include <framework/sfxhelperfunctions.hxx> 29 #include <uiconfiguration/windowstateproperties.hxx> 30 31 #include <com/sun/star/awt/XDevice.hpp> 32 #include <com/sun/star/beans/PropertyValue.hpp> 33 #include <com/sun/star/awt/MenuItemStyle.hpp> 34 #include <com/sun/star/frame/ModuleManager.hpp> 35 #include <com/sun/star/frame/XDispatchProvider.hpp> 36 #include <com/sun/star/util/XURLTransformer.hpp> 37 #include <com/sun/star/container/XNameContainer.hpp> 38 #include <com/sun/star/beans/XPropertySet.hpp> 39 #include <com/sun/star/frame/XLayoutManager.hpp> 40 #include <com/sun/star/ui/XUIElementSettings.hpp> 41 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp> 42 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> 43 #include <com/sun/star/ui/UIElementType.hpp> 44 #include <com/sun/star/ui/theWindowStateConfiguration.hpp> 45 46 #include <vcl/menu.hxx> 47 #include <vcl/svapp.hxx> 48 #include <vcl/i18nhelp.hxx> 49 #include <vcl/image.hxx> 50 #include <vcl/settings.hxx> 51 #include <vcl/commandinfoprovider.hxx> 52 #include <rtl/ustrbuf.hxx> 53 #include <sal/log.hxx> 54 #include <toolkit/helper/vclunohelper.hxx> 55 #include <vcl/window.hxx> 56 #include <svtools/menuoptions.hxx> 57 #include <unotools/cmdoptions.hxx> 58 #include <svtools/miscopt.hxx> 59 #include <unotools/collatorwrapper.hxx> 60 #include <unotools/syslocale.hxx> 61 62 // Defines 63 64 using namespace ::com::sun::star; 65 using namespace ::com::sun::star::uno; 66 using namespace ::com::sun::star::lang; 67 using namespace ::com::sun::star::frame; 68 using namespace ::com::sun::star::beans; 69 using namespace ::com::sun::star::util; 70 using namespace ::com::sun::star::container; 71 using namespace ::com::sun::star::ui; 72 73 static const char CMD_RESTOREVISIBILITY[] = ".cmd:RestoreVisibility"; 74 75 static const char STATIC_CMD_PART[] = ".uno:AvailableToolbars?Toolbar:string="; 76 static const char STATIC_INTERNAL_CMD_PART[] = ".cmd:"; 77 78 namespace framework 79 { 80 81 typedef std::unordered_map< OUString, OUString > ToolbarHashMap; 82 83 struct ToolBarEntry 84 { 85 OUString aUIName; 86 OUString aCommand; 87 bool bVisible; 88 bool bContextSensitive; 89 const CollatorWrapper* pCollatorWrapper; 90 }; 91 92 static bool CompareToolBarEntry( const ToolBarEntry& aOne, const ToolBarEntry& aTwo ) 93 { 94 sal_Int32 nComp = aOne.pCollatorWrapper->compareString( aOne.aUIName, aTwo.aUIName ); 95 96 return nComp < 0; 97 } 98 99 static Reference< XLayoutManager > getLayoutManagerFromFrame( const Reference< XFrame >& rFrame ) 100 { 101 Reference< XPropertySet > xPropSet( rFrame, UNO_QUERY ); 102 Reference< XLayoutManager > xLayoutManager; 103 104 try 105 { 106 xPropSet->getPropertyValue("LayoutManager") >>= xLayoutManager; 107 } 108 catch ( const UnknownPropertyException& ) 109 { 110 } 111 112 return xLayoutManager; 113 } 114 115 struct ToolBarInfo 116 { 117 OUString aToolBarResName; 118 OUString aToolBarUIName; 119 }; 120 121 DEFINE_XSERVICEINFO_MULTISERVICE_2 ( ToolbarsMenuController , 122 OWeakObject , 123 SERVICENAME_POPUPMENUCONTROLLER , 124 IMPLEMENTATIONNAME_TOOLBARSMENUCONTROLLER 125 ) 126 127 DEFINE_INIT_SERVICE ( ToolbarsMenuController, {} ) 128 129 static constexpr OUStringLiteral g_aPropUIName( "UIName" ); 130 static constexpr OUStringLiteral g_aPropResourceURL( "ResourceURL" ); 131 132 ToolbarsMenuController::ToolbarsMenuController( const css::uno::Reference< css::uno::XComponentContext >& xContext ) : 133 svt::PopupMenuControllerBase( xContext ), 134 m_xContext( xContext ), 135 m_bResetActive( false ), 136 m_aIntlWrapper(SvtSysLocale().GetUILanguageTag()) 137 { 138 } 139 140 ToolbarsMenuController::~ToolbarsMenuController() 141 { 142 } 143 144 void ToolbarsMenuController::addCommand( 145 Reference< css::awt::XPopupMenu > const & rPopupMenu, const OUString& rCommandURL, const OUString& rLabel ) 146 { 147 sal_uInt16 nItemId = m_xPopupMenu->getItemCount()+1; 148 149 OUString aLabel; 150 if ( rLabel.isEmpty() ) 151 aLabel = vcl::CommandInfoProvider::GetMenuLabelForCommand( rCommandURL, m_aModuleName ); 152 else 153 aLabel = rLabel; 154 155 rPopupMenu->insertItem( nItemId, aLabel, 0, nItemId ); 156 rPopupMenu->setCommand( nItemId, rCommandURL ); 157 158 bool bInternal = rCommandURL.startsWith( STATIC_INTERNAL_CMD_PART ); 159 if ( !bInternal ) 160 { 161 if ( !getDispatchFromCommandURL( rCommandURL ).is() ) 162 m_xPopupMenu->enableItem( nItemId, false ); 163 } 164 165 SolarMutexGuard aSolarMutexGuard; 166 167 Image aImage; 168 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); 169 170 if ( rSettings.GetUseImagesInMenus() ) 171 aImage = vcl::CommandInfoProvider::GetImageForCommand(rCommandURL, m_xFrame); 172 173 VCLXPopupMenu* pPopupMenu = static_cast<VCLXPopupMenu *>(VCLXPopupMenu::getImplementation( rPopupMenu )); 174 if ( pPopupMenu ) 175 { 176 PopupMenu* pVCLPopupMenu = static_cast<PopupMenu *>(pPopupMenu->GetMenu()); 177 if ( !!aImage ) 178 pVCLPopupMenu->SetItemImage( nItemId, aImage ); 179 } 180 181 m_aCommandVector.push_back( rCommandURL ); 182 } 183 184 Reference< XDispatch > ToolbarsMenuController::getDispatchFromCommandURL( const OUString& rCommandURL ) 185 { 186 URL aTargetURL; 187 Reference< XURLTransformer > xURLTransformer; 188 Reference< XFrame > xFrame; 189 190 { 191 SolarMutexGuard aSolarMutexGuard; 192 xURLTransformer = m_xURLTransformer; 193 xFrame = m_xFrame; 194 } 195 196 aTargetURL.Complete = rCommandURL; 197 xURLTransformer->parseStrict( aTargetURL ); 198 Reference< XDispatchProvider > xDispatchProvider( xFrame, UNO_QUERY ); 199 if ( xDispatchProvider.is() ) 200 return xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); 201 else 202 return Reference< XDispatch >(); 203 } 204 205 static void fillHashMap( const Sequence< Sequence< css::beans::PropertyValue > >& rSeqToolBars, 206 ToolbarHashMap& rHashMap ) 207 { 208 for ( sal_Int32 i = 0; i < rSeqToolBars.getLength(); i++ ) 209 { 210 OUString aResourceURL; 211 OUString aUIName; 212 const PropertyValue* pProperties = rSeqToolBars[i].getConstArray(); 213 for ( sal_Int32 j = 0; j < rSeqToolBars[i].getLength(); j++ ) 214 { 215 if ( pProperties[j].Name == "ResourceURL" ) 216 pProperties[j].Value >>= aResourceURL; 217 else if ( pProperties[j].Name == "UIName" ) 218 pProperties[j].Value >>= aUIName; 219 } 220 221 if ( !aResourceURL.isEmpty() && 222 rHashMap.find( aResourceURL ) == rHashMap.end() ) 223 rHashMap.emplace( aResourceURL, aUIName ); 224 } 225 } 226 227 // private function 228 Sequence< Sequence< css::beans::PropertyValue > > ToolbarsMenuController::getLayoutManagerToolbars( const Reference< css::frame::XLayoutManager >& rLayoutManager ) 229 { 230 std::vector< ToolBarInfo > aToolBarArray; 231 Sequence< Reference< XUIElement > > aUIElements = rLayoutManager->getElements(); 232 for ( sal_Int32 i = 0; i < aUIElements.getLength(); i++ ) 233 { 234 Reference< XUIElement > xUIElement( aUIElements[i] ); 235 Reference< XPropertySet > xPropSet( aUIElements[i], UNO_QUERY ); 236 if ( xPropSet.is() && xUIElement.is() ) 237 { 238 try 239 { 240 OUString aResName; 241 sal_Int16 nType( -1 ); 242 xPropSet->getPropertyValue("Type") >>= nType; 243 xPropSet->getPropertyValue("ResourceURL") >>= aResName; 244 245 if (( nType == css::ui::UIElementType::TOOLBAR ) && 246 !aResName.isEmpty() ) 247 { 248 ToolBarInfo aToolBarInfo; 249 250 aToolBarInfo.aToolBarResName = aResName; 251 252 SolarMutexGuard aGuard; 253 Reference< css::awt::XWindow > xWindow( xUIElement->getRealInterface(), UNO_QUERY ); 254 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); 255 if ( pWindow ) 256 aToolBarInfo.aToolBarUIName = pWindow->GetText(); 257 258 aToolBarArray.push_back( aToolBarInfo ); 259 } 260 } 261 catch ( const Exception& ) 262 { 263 } 264 } 265 } 266 267 Sequence< css::beans::PropertyValue > aTbSeq( 2 ); 268 aTbSeq[0].Name = g_aPropUIName; 269 aTbSeq[1].Name = g_aPropResourceURL; 270 271 Sequence< Sequence< css::beans::PropertyValue > > aSeq( aToolBarArray.size() ); 272 const sal_uInt32 nCount = aToolBarArray.size(); 273 for ( sal_uInt32 i = 0; i < nCount; i++ ) 274 { 275 aTbSeq[0].Value <<= aToolBarArray[i].aToolBarUIName; 276 aTbSeq[1].Value <<= aToolBarArray[i].aToolBarResName; 277 aSeq[i] = aTbSeq; 278 } 279 280 return aSeq; 281 } 282 283 284 void ToolbarsMenuController::fillPopupMenu( Reference< css::awt::XPopupMenu > const & rPopupMenu ) 285 { 286 if( SvtMiscOptions().DisableUICustomization() ) 287 return; 288 289 SolarMutexGuard aSolarMutexGuard; 290 resetPopupMenu( rPopupMenu ); 291 292 m_aCommandVector.clear(); 293 294 // Retrieve layout manager for additional information 295 Reference< XLayoutManager > xLayoutManager( getLayoutManagerFromFrame( m_xFrame )); 296 297 m_bResetActive = false; 298 if ( xLayoutManager.is() ) 299 { 300 ToolbarHashMap aToolbarHashMap; 301 302 if ( m_xDocCfgMgr.is() ) 303 { 304 Sequence< Sequence< css::beans::PropertyValue > > aSeqDocToolBars = 305 m_xDocCfgMgr->getUIElementsInfo( UIElementType::TOOLBAR ); 306 fillHashMap( aSeqDocToolBars, aToolbarHashMap ); 307 } 308 309 if ( m_xModuleCfgMgr.is() ) 310 { 311 Sequence< Sequence< css::beans::PropertyValue > > aSeqToolBars = 312 m_xModuleCfgMgr->getUIElementsInfo( UIElementType::TOOLBAR ); 313 fillHashMap( aSeqToolBars, aToolbarHashMap ); 314 } 315 316 std::vector< ToolBarEntry > aSortedTbs; 317 OUString aStaticCmdPart( STATIC_CMD_PART ); 318 319 Sequence< Sequence< css::beans::PropertyValue > > aSeqFrameToolBars = getLayoutManagerToolbars( xLayoutManager ); 320 fillHashMap( aSeqFrameToolBars, aToolbarHashMap ); 321 322 for (auto const& toolbar : aToolbarHashMap) 323 { 324 OUString aUIName = toolbar.second; 325 bool bHideFromMenu( false ); 326 bool bContextSensitive( false ); 327 if ( aUIName.isEmpty() && 328 m_xPersistentWindowState.is() ) 329 { 330 bool bVisible( false ); 331 332 try 333 { 334 Sequence< PropertyValue > aWindowState; 335 Any a( m_xPersistentWindowState->getByName( toolbar.first )); 336 337 if ( a >>= aWindowState ) 338 { 339 for ( sal_Int32 i = 0; i < aWindowState.getLength(); i++ ) 340 { 341 if ( aWindowState[i].Name == WINDOWSTATE_PROPERTY_UINAME ) 342 aWindowState[i].Value >>= aUIName; 343 else if ( aWindowState[i].Name == WINDOWSTATE_PROPERTY_HIDEFROMENU ) 344 aWindowState[i].Value >>= bHideFromMenu; 345 else if ( aWindowState[i].Name == WINDOWSTATE_PROPERTY_CONTEXT ) 346 aWindowState[i].Value >>= bContextSensitive; 347 else if ( aWindowState[i].Name == WINDOWSTATE_PROPERTY_VISIBLE ) 348 aWindowState[i].Value >>= bVisible; 349 } 350 } 351 } 352 catch ( const Exception& ) 353 { 354 } 355 356 // Check if we have to enable/disable "Reset" menu item 357 if ( bContextSensitive && !bVisible ) 358 m_bResetActive = true; 359 360 } 361 362 if ( !aUIName.isEmpty() && !bHideFromMenu ) 363 { 364 ToolBarEntry aTbEntry; 365 aTbEntry.aUIName = aUIName; 366 aTbEntry.aCommand = toolbar.first; 367 aTbEntry.bVisible = xLayoutManager->isElementVisible( toolbar.first ); 368 aTbEntry.bContextSensitive = bContextSensitive; 369 aTbEntry.pCollatorWrapper = m_aIntlWrapper.getCaseCollator(); 370 aSortedTbs.push_back( aTbEntry ); 371 } 372 } 373 374 // sort toolbars 375 std::sort( aSortedTbs.begin(), aSortedTbs.end(), CompareToolBarEntry ); 376 377 sal_Int16 nIndex( 1 ); 378 const sal_uInt32 nCount = aSortedTbs.size(); 379 for ( sal_uInt32 i = 0; i < nCount; i++ ) 380 { 381 sal_uInt16 nItemCount = m_xPopupMenu->getItemCount(); 382 m_xPopupMenu->insertItem( nIndex, aSortedTbs[i].aUIName, css::awt::MenuItemStyle::CHECKABLE, nItemCount ); 383 if ( aSortedTbs[i].bVisible ) 384 m_xPopupMenu->checkItem( nIndex, true ); 385 386 { 387 SolarMutexGuard aGuard; 388 VCLXPopupMenu* pXPopupMenu = static_cast<VCLXPopupMenu *>(VCLXMenu::getImplementation( m_xPopupMenu )); 389 PopupMenu* pVCLPopupMenu = pXPopupMenu ? static_cast<PopupMenu *>(pXPopupMenu->GetMenu()) : nullptr; 390 assert(pVCLPopupMenu); 391 if (pVCLPopupMenu) 392 pVCLPopupMenu->SetUserValue( nIndex, reinterpret_cast<void*>( aSortedTbs[i].bContextSensitive ? 1 : 0 )); 393 } 394 395 // use VCL popup menu pointer to set vital information that are not part of the awt implementation 396 OUStringBuffer aStrBuf( aStaticCmdPart ); 397 398 sal_Int32 n = aSortedTbs[i].aCommand.lastIndexOf( '/' ); 399 if (( n > 0 ) && (( n+1 ) < aSortedTbs[i].aCommand.getLength() )) 400 aStrBuf.append( std::u16string_view(aSortedTbs[i].aCommand).substr(n+1) ); 401 402 OUString aCmd( aStrBuf.makeStringAndClear() ); 403 404 // Store complete uno-command so it can also be dispatched. This is necessary to support 405 // the test tool! 406 rPopupMenu->setCommand( nIndex, aCmd ); 407 ++nIndex; 408 } 409 410 // Create commands for non-toolbars 411 if ( m_aModuleIdentifier == "com.sun.star.text.TextDocument" || 412 m_aModuleIdentifier == "com.sun.star.text.WebDocument" || 413 m_aModuleIdentifier == "com.sun.star.text.GlobalDocument" || 414 m_aModuleIdentifier == "com.sun.star.drawing.DrawingDocument" || 415 m_aModuleIdentifier == "com.sun.star.presentation.PresentationDocument" || 416 m_aModuleIdentifier == "com.sun.star.sheet.SpreadsheetDocument" ) 417 { 418 if ( m_aModuleIdentifier == "com.sun.star.drawing.DrawingDocument" || 419 m_aModuleIdentifier == "com.sun.star.presentation.PresentationDocument" ) 420 addCommand( m_xPopupMenu, ".uno:ColorControl", "" ); 421 else if ( m_aModuleIdentifier == "com.sun.star.sheet.SpreadsheetDocument" ) 422 addCommand( m_xPopupMenu, ".uno:InputLineVisible", "" ); 423 else 424 addCommand( m_xPopupMenu, ".uno:InsertFormula", "" ); 425 } 426 427 bool bAddCommand( true ); 428 SvtCommandOptions aCmdOptions; 429 430 if ( aCmdOptions.HasEntries( SvtCommandOptions::CMDOPTION_DISABLED )) 431 { 432 if ( aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, 433 "ConfigureDialog")) 434 bAddCommand = false; 435 } 436 437 if ( bAddCommand ) 438 { 439 // Create command for configure 440 if ( m_xPopupMenu->getItemCount() > 0 ) 441 { 442 sal_uInt16 nItemCount = m_xPopupMenu->getItemCount(); 443 m_xPopupMenu->insertSeparator( nItemCount+1 ); 444 } 445 446 addCommand( m_xPopupMenu, ".uno:ConfigureDialog", "" ); 447 } 448 449 // Add separator if no configure has been added 450 if ( !bAddCommand ) 451 { 452 // Create command for configure 453 if ( m_xPopupMenu->getItemCount() > 0 ) 454 { 455 sal_uInt16 nItemCount = m_xPopupMenu->getItemCount(); 456 m_xPopupMenu->insertSeparator( nItemCount+1 ); 457 } 458 } 459 460 OUString aLabelStr(FwkResId(STR_RESTORE_TOOLBARS)); 461 OUString aRestoreCmd( CMD_RESTOREVISIBILITY ); 462 addCommand( m_xPopupMenu, aRestoreCmd, aLabelStr ); 463 } 464 } 465 466 // XEventListener 467 void SAL_CALL ToolbarsMenuController::disposing( const EventObject& ) 468 { 469 Reference< css::awt::XMenuListener > xHolder(static_cast<OWeakObject *>(this), UNO_QUERY ); 470 471 osl::MutexGuard aLock( m_aMutex ); 472 m_xFrame.clear(); 473 m_xDispatch.clear(); 474 m_xDocCfgMgr.clear(); 475 m_xModuleCfgMgr.clear(); 476 m_xContext.clear(); 477 478 if ( m_xPopupMenu.is() ) 479 m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(static_cast<OWeakObject *>(this), UNO_QUERY )); 480 m_xPopupMenu.clear(); 481 } 482 483 // XStatusListener 484 void SAL_CALL ToolbarsMenuController::statusChanged( const FeatureStateEvent& Event ) 485 { 486 OUString aFeatureURL( Event.FeatureURL.Complete ); 487 488 // All other status events will be processed here 489 osl::ClearableMutexGuard aLock( m_aMutex ); 490 Reference< css::awt::XPopupMenu > xPopupMenu( m_xPopupMenu ); 491 aLock.clear(); 492 493 if ( xPopupMenu.is() ) 494 { 495 SolarMutexGuard aGuard; 496 VCLXPopupMenu* pXPopupMenu = static_cast<VCLXPopupMenu *>(VCLXMenu::getImplementation( xPopupMenu )); 497 PopupMenu* pVCLPopupMenu = pXPopupMenu ? static_cast<PopupMenu *>(pXPopupMenu->GetMenu()) : nullptr; 498 499 SAL_WARN_IF(!pVCLPopupMenu, "fwk.uielement", "worrying lack of popup menu"); 500 if (!pVCLPopupMenu) 501 return; 502 503 bool bSetCheckmark = false; 504 bool bCheckmark = false; 505 for ( sal_uInt16 i = 0; i < pVCLPopupMenu->GetItemCount(); i++ ) 506 { 507 sal_uInt16 nId = pVCLPopupMenu->GetItemId( i ); 508 if ( nId == 0 ) 509 continue; 510 511 OUString aCmd = pVCLPopupMenu->GetItemCommand( nId ); 512 if ( aCmd == aFeatureURL ) 513 { 514 // Enable/disable item 515 pVCLPopupMenu->EnableItem( nId, Event.IsEnabled ); 516 517 // Checkmark 518 if ( Event.State >>= bCheckmark ) 519 bSetCheckmark = true; 520 521 if ( bSetCheckmark ) 522 pVCLPopupMenu->CheckItem( nId, bCheckmark ); 523 else 524 { 525 OUString aItemText; 526 527 if ( Event.State >>= aItemText ) 528 pVCLPopupMenu->SetItemText( nId, aItemText ); 529 } 530 } 531 } 532 } 533 } 534 535 // XMenuListener 536 void SAL_CALL ToolbarsMenuController::itemSelected( const css::awt::MenuEvent& rEvent ) 537 { 538 Reference< css::awt::XPopupMenu > xPopupMenu; 539 Reference< XComponentContext > xContext; 540 Reference< XURLTransformer > xURLTransformer; 541 Reference< XFrame > xFrame; 542 Reference< XNameAccess > xPersistentWindowState; 543 544 { 545 osl::MutexGuard aLock(m_aMutex); 546 xPopupMenu = m_xPopupMenu; 547 xContext = m_xContext; 548 xURLTransformer = m_xURLTransformer; 549 xFrame = m_xFrame; 550 xPersistentWindowState = m_xPersistentWindowState; 551 } 552 553 if ( xPopupMenu.is() ) 554 { 555 VCLXPopupMenu* pPopupMenu = static_cast<VCLXPopupMenu *>(VCLXPopupMenu::getImplementation( xPopupMenu )); 556 if ( pPopupMenu ) 557 { 558 SolarMutexGuard aSolarMutexGuard; 559 PopupMenu* pVCLPopupMenu = static_cast<PopupMenu *>(pPopupMenu->GetMenu()); 560 561 OUString aCmd( pVCLPopupMenu->GetItemCommand( rEvent.MenuId )); 562 if ( aCmd.startsWith( STATIC_INTERNAL_CMD_PART ) ) 563 { 564 // Command to restore the visibility of all context sensitive toolbars 565 Reference< XNameReplace > xNameReplace( xPersistentWindowState, UNO_QUERY ); 566 if ( xPersistentWindowState.is() && xNameReplace.is() ) 567 { 568 try 569 { 570 Sequence< OUString > aElementNames = xPersistentWindowState->getElementNames(); 571 sal_Int32 nCount = aElementNames.getLength(); 572 bool bRefreshToolbars( false ); 573 574 for ( sal_Int32 i = 0; i < nCount; i++ ) 575 { 576 try 577 { 578 OUString aElementName = aElementNames[i]; 579 Sequence< PropertyValue > aWindowState; 580 581 if ( xPersistentWindowState->getByName( aElementName ) >>= aWindowState ) 582 { 583 bool bVisible( false ); 584 bool bContextSensitive( false ); 585 sal_Int32 nVisibleIndex( -1 ); 586 for ( sal_Int32 j = 0; j < aWindowState.getLength(); j++ ) 587 { 588 if ( aWindowState[j].Name == WINDOWSTATE_PROPERTY_VISIBLE ) 589 { 590 aWindowState[j].Value >>= bVisible; 591 nVisibleIndex = j; 592 } 593 else if ( aWindowState[j].Name == WINDOWSTATE_PROPERTY_CONTEXT ) 594 aWindowState[j].Value >>= bContextSensitive; 595 } 596 597 if ( !bVisible && bContextSensitive && nVisibleIndex >= 0 ) 598 { 599 // Default is: Every context sensitive toolbar is visible 600 aWindowState[nVisibleIndex].Value <<= true; 601 xNameReplace->replaceByName( aElementName, makeAny( aWindowState )); 602 bRefreshToolbars = true; 603 } 604 } 605 } 606 catch ( const NoSuchElementException& ) 607 { 608 } 609 } 610 611 if ( bRefreshToolbars ) 612 { 613 Reference< XLayoutManager > xLayoutManager( getLayoutManagerFromFrame( xFrame )); 614 if ( xLayoutManager.is() ) 615 { 616 Reference< XPropertySet > xPropSet( xLayoutManager, UNO_QUERY ); 617 if ( xPropSet.is() ) 618 { 619 try 620 { 621 xPropSet->setPropertyValue("RefreshContextToolbarVisibility", makeAny( true )); 622 } 623 catch ( const RuntimeException& ) 624 { 625 } 626 catch ( const Exception& ) 627 { 628 } 629 } 630 } 631 RefreshToolbars( xFrame ); 632 } 633 } 634 catch ( const RuntimeException& ) 635 { 636 throw; 637 } 638 catch ( const Exception& ) 639 { 640 } 641 } 642 } 643 else if ( aCmd.indexOf( STATIC_CMD_PART ) < 0 ) 644 { 645 URL aTargetURL; 646 Sequence<PropertyValue> aArgs; 647 648 aTargetURL.Complete = aCmd; 649 xURLTransformer->parseStrict( aTargetURL ); 650 Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); 651 if ( xDispatchProvider.is() ) 652 { 653 Reference< XDispatch > xDispatch = xDispatchProvider->queryDispatch( 654 aTargetURL, OUString(), 0 ); 655 656 ExecuteInfo* pExecuteInfo = new ExecuteInfo; 657 pExecuteInfo->xDispatch = xDispatch; 658 pExecuteInfo->aTargetURL = aTargetURL; 659 pExecuteInfo->aArgs = aArgs; 660 Application::PostUserEvent( LINK(nullptr, ToolbarsMenuController, ExecuteHdl_Impl), pExecuteInfo ); 661 } 662 } 663 else 664 { 665 Reference< XLayoutManager > xLayoutManager( getLayoutManagerFromFrame( xFrame )); 666 if ( xLayoutManager.is() ) 667 { 668 // Extract toolbar name from the combined uno-command. 669 sal_Int32 nIndex = aCmd.indexOf( '=' ); 670 if (( nIndex > 0 ) && (( nIndex+1 ) < aCmd.getLength() )) 671 { 672 OUStringBuffer aBuf( "private:resource/toolbar/" ); 673 aBuf.append( std::u16string_view(aCmd).substr(nIndex+1) ); 674 675 bool bShow( !pVCLPopupMenu->IsItemChecked( rEvent.MenuId )); 676 OUString aToolBarResName( aBuf.makeStringAndClear() ); 677 if ( bShow ) 678 { 679 xLayoutManager->createElement( aToolBarResName ); 680 xLayoutManager->showElement( aToolBarResName ); 681 } 682 else 683 { 684 // closing means: 685 // hide and destroy element 686 xLayoutManager->hideElement( aToolBarResName ); 687 xLayoutManager->destroyElement( aToolBarResName ); 688 } 689 } 690 } 691 } 692 } 693 } 694 } 695 696 void SAL_CALL ToolbarsMenuController::itemActivated( const css::awt::MenuEvent& ) 697 { 698 std::vector< OUString > aCmdVector; 699 Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY ); 700 Reference< XURLTransformer > xURLTransformer( m_xURLTransformer ); 701 { 702 osl::MutexGuard aLock( m_aMutex ); 703 fillPopupMenu( m_xPopupMenu ); 704 aCmdVector = m_aCommandVector; 705 } 706 707 // Update status for all commands inside our toolbars popup menu 708 const sal_uInt32 nCount = aCmdVector.size(); 709 for ( sal_uInt32 i = 0; i < nCount; i++ ) 710 { 711 bool bInternal = aCmdVector[i].startsWith( STATIC_INTERNAL_CMD_PART ); 712 713 if ( !bInternal ) 714 { 715 URL aTargetURL; 716 aTargetURL.Complete = aCmdVector[i]; 717 xURLTransformer->parseStrict( aTargetURL ); 718 Reference< XDispatch > xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 ); 719 if ( xDispatch.is() ) 720 { 721 xDispatch->addStatusListener( static_cast< XStatusListener* >(this), aTargetURL ); 722 xDispatch->removeStatusListener( static_cast< XStatusListener* >(this), aTargetURL ); 723 } 724 } 725 else if ( aCmdVector[i] == CMD_RESTOREVISIBILITY ) 726 { 727 // Special code to determine the enable/disable state of this command 728 FeatureStateEvent aFeatureStateEvent; 729 aFeatureStateEvent.FeatureURL.Complete = aCmdVector[i]; 730 aFeatureStateEvent.IsEnabled = m_bResetActive; // is context sensitive toolbar non visible 731 statusChanged( aFeatureStateEvent ); 732 } 733 } 734 } 735 736 // XPopupMenuController 737 void SAL_CALL ToolbarsMenuController::setPopupMenu( const Reference< css::awt::XPopupMenu >& xPopupMenu ) 738 { 739 osl::MutexGuard aLock( m_aMutex ); 740 741 throwIfDisposed(); 742 743 if ( m_xFrame.is() && !m_xPopupMenu.is() ) 744 { 745 // Create popup menu on demand 746 SolarMutexGuard aSolarMutexGuard; 747 748 m_xPopupMenu = xPopupMenu; 749 m_xPopupMenu->addMenuListener( Reference< css::awt::XMenuListener >( static_cast<OWeakObject*>(this), UNO_QUERY )); 750 fillPopupMenu( m_xPopupMenu ); 751 } 752 } 753 754 // XInitialization 755 void SAL_CALL ToolbarsMenuController::initialize( const Sequence< Any >& aArguments ) 756 { 757 osl::MutexGuard aLock( m_aMutex ); 758 bool bInitalized( m_bInitialized ); 759 if ( !bInitalized ) 760 { 761 svt::PopupMenuControllerBase::initialize(aArguments); 762 763 if ( m_bInitialized ) 764 { 765 Reference< XModuleManager2 > xModuleManager = ModuleManager::create( m_xContext ); 766 Reference< XNameAccess > xPersistentWindowStateSupplier = css::ui::theWindowStateConfiguration::get( m_xContext ); 767 768 // Retrieve persistent window state reference for our module 769 OUString aModuleIdentifier; 770 try 771 { 772 aModuleIdentifier = xModuleManager->identify( m_xFrame ); 773 xPersistentWindowStateSupplier->getByName( aModuleIdentifier ) >>= m_xPersistentWindowState; 774 775 Reference< XModuleUIConfigurationManagerSupplier > xModuleCfgSupplier = 776 theModuleUIConfigurationManagerSupplier::get( m_xContext ); 777 m_xModuleCfgMgr = xModuleCfgSupplier->getUIConfigurationManager( aModuleIdentifier ); 778 779 Reference< XController > xController = m_xFrame->getController(); 780 Reference< XModel > xModel; 781 if ( xController.is() ) 782 xModel = xController->getModel(); 783 if ( xModel.is() ) 784 { 785 Reference< XUIConfigurationManagerSupplier > xUIConfigurationManagerSupplier( xModel, UNO_QUERY ); 786 if ( xUIConfigurationManagerSupplier.is() ) 787 m_xDocCfgMgr = xUIConfigurationManagerSupplier->getUIConfigurationManager(); 788 } 789 m_aModuleIdentifier = aModuleIdentifier; 790 } 791 catch ( const Exception& ) 792 { 793 } 794 } 795 } 796 } 797 798 IMPL_STATIC_LINK( ToolbarsMenuController, ExecuteHdl_Impl, void*, p, void ) 799 { 800 ExecuteInfo* pExecuteInfo = static_cast<ExecuteInfo*>(p); 801 try 802 { 803 // Asynchronous execution as this can lead to our own destruction! 804 // Framework can recycle our current frame and the layout manager disposes all user interface 805 // elements if a component gets detached from its frame! 806 if ( pExecuteInfo->xDispatch.is() ) 807 { 808 pExecuteInfo->xDispatch->dispatch( pExecuteInfo->aTargetURL, pExecuteInfo->aArgs ); 809 } 810 } 811 catch ( const Exception& ) 812 { 813 } 814 815 delete pExecuteInfo; 816 } 817 818 } 819 820 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 821
