bump product version to 6.4.0.3
[LibreOffice.git] / cui / source / customize / cfg.cxx
blob8daf8409ed680b3d7ef39159bd63f751958a5768
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <cassert>
24 #include <stdlib.h>
25 #include <typeinfo>
27 #include <vcl/stdtext.hxx>
28 #include <vcl/commandinfoprovider.hxx>
29 #include <vcl/event.hxx>
30 #include <vcl/graph.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/toolbox.hxx>
33 #include <vcl/weld.hxx>
34 #include <vcl/decoview.hxx>
35 #include <vcl/virdev.hxx>
37 #include <sfx2/sfxhelp.hxx>
38 #include <sfx2/viewfrm.hxx>
39 #include <sfx2/filedlghelper.hxx>
40 #include <sfx2/sfxsids.hrc>
41 #include <svl/stritem.hxx>
42 #include <tools/debug.hxx>
43 #include <tools/diagnose_ex.h>
44 #include <toolkit/helper/vclunohelper.hxx>
46 #include <algorithm>
47 #include <strings.hrc>
49 #include <acccfg.hxx>
50 #include <cfg.hxx>
51 #include <CustomNotebookbarGenerator.hxx>
52 #include <SvxMenuConfigPage.hxx>
53 #include <SvxToolbarConfigPage.hxx>
54 #include <SvxNotebookbarConfigPage.hxx>
55 #include <SvxConfigPageHelper.hxx>
56 #include "eventdlg.hxx"
57 #include <dialmgr.hxx>
59 #include <unotools/configmgr.hxx>
60 #include <com/sun/star/container/XNameContainer.hpp>
61 #include <com/sun/star/embed/ElementModes.hpp>
62 #include <com/sun/star/embed/FileSystemStorageFactory.hpp>
63 #include <com/sun/star/frame/ModuleManager.hpp>
64 #include <com/sun/star/frame/UnknownModuleException.hpp>
65 #include <com/sun/star/frame/XFrames.hpp>
66 #include <com/sun/star/frame/XLayoutManager.hpp>
67 #include <com/sun/star/frame/FrameSearchFlag.hpp>
68 #include <com/sun/star/frame/XController.hpp>
69 #include <com/sun/star/frame/Desktop.hpp>
70 #include <com/sun/star/frame/theUICommandDescription.hpp>
71 #include <com/sun/star/graphic/GraphicProvider.hpp>
72 #include <com/sun/star/io/IOException.hpp>
73 #include <com/sun/star/ui/ItemType.hpp>
74 #include <com/sun/star/ui/ItemStyle.hpp>
75 #include <com/sun/star/ui/ImageManager.hpp>
76 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
77 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
78 #include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
79 #include <com/sun/star/ui/XUIElement.hpp>
80 #include <com/sun/star/ui/UIElementType.hpp>
81 #include <com/sun/star/ui/ImageType.hpp>
82 #include <com/sun/star/ui/theWindowStateConfiguration.hpp>
83 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
84 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
85 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
86 #include <com/sun/star/util/thePathSettings.hpp>
87 #include <comphelper/documentinfo.hxx>
88 #include <comphelper/propertysequence.hxx>
89 #include <comphelper/processfactory.hxx>
91 namespace uno = com::sun::star::uno;
92 namespace frame = com::sun::star::frame;
93 namespace lang = com::sun::star::lang;
94 namespace container = com::sun::star::container;
95 namespace beans = com::sun::star::beans;
96 namespace graphic = com::sun::star::graphic;
98 #if OSL_DEBUG_LEVEL > 1
100 void printPropertySet(
101 const OUString& prefix,
102 const uno::Reference< beans::XPropertySet >& xPropSet )
104 uno::Reference< beans::XPropertySetInfo > xPropSetInfo =
105 xPropSet->getPropertySetInfo();
107 uno::Sequence< beans::Property > aPropDetails =
108 xPropSetInfo->getProperties();
110 SAL_WARN("cui", "printPropertySet: " << aPropDetails.getLength() << " properties" );
112 for ( sal_Int32 i = 0; i < aPropDetails.getLength(); ++i )
114 OUString tmp;
115 sal_Int32 ival;
117 uno::Any a = xPropSet->getPropertyValue( aPropDetails[i].Name );
119 if ( a >>= tmp )
121 SAL_WARN("cui", prefix << ": Got property: " << aPropDetails[i].Name << tmp);
123 else if ( ( a >>= ival ) )
125 SAL_WARN("cui", prefix << ": Got property: " << aPropDetails[i].Name << " = " << ival);
127 else
129 SAL_WARN("cui", prefix << ": Got property: " << aPropDetails[i].Name << " of type " << a.getValueTypeName());
134 void printProperties(
135 const OUString& prefix,
136 const uno::Sequence< beans::PropertyValue >& aProp )
138 for ( sal_Int32 i = 0; i < aProp.getLength(); ++i )
140 OUString tmp;
142 aProp[i].Value >>= tmp;
144 SAL_WARN("cui", prefix << ": Got property: " << aProp[i].Name << " = " << tmp);
148 void printEntries(SvxEntries* entries)
150 for (auto const& entry : *entries)
152 SAL_WARN("cui", "printEntries: " << entry->GetName());
156 #endif
158 bool
159 SvxConfigPage::CanConfig( const OUString& aModuleId )
161 return !(aModuleId == "com.sun.star.script.BasicIDE" || aModuleId == "com.sun.star.frame.Bibliography");
164 static std::unique_ptr<SfxTabPage> CreateSvxMenuConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
166 return std::make_unique<SvxMenuConfigPage>(pPage, pController, *rSet);
169 static std::unique_ptr<SfxTabPage> CreateSvxContextMenuConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
171 return std::make_unique<SvxMenuConfigPage>(pPage, pController, *rSet, false);
174 static std::unique_ptr<SfxTabPage> CreateKeyboardConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
176 return std::make_unique<SfxAcceleratorConfigPage>(pPage, pController, *rSet);
179 static std::unique_ptr<SfxTabPage> CreateSvxNotebookbarConfigPage(weld::Container* pPage, weld::DialogController* pController,
180 const SfxItemSet* rSet)
182 return std::make_unique<SvxNotebookbarConfigPage>(pPage, pController, *rSet);
185 static std::unique_ptr<SfxTabPage> CreateSvxToolbarConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
187 return std::make_unique<SvxToolbarConfigPage>(pPage, pController, *rSet);
190 static std::unique_ptr<SfxTabPage> CreateSvxEventConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
192 return std::make_unique<SvxEventConfigPage>(pPage, pController, *rSet, SvxEventConfigPage::EarlyInit());
195 /******************************************************************************
197 * SvxConfigDialog is the configuration dialog which is brought up from the
198 * Tools menu. It includes tabs for customizing menus, toolbars, events and
199 * key bindings.
201 *****************************************************************************/
202 SvxConfigDialog::SvxConfigDialog(weld::Window * pParent, const SfxItemSet* pInSet)
203 : SfxTabDialogController(pParent, "cui/ui/customizedialog.ui", "CustomizeDialog", pInSet)
205 SvxConfigPageHelper::InitImageType();
207 AddTabPage("menus", CreateSvxMenuConfigPage, nullptr);
208 AddTabPage("toolbars", CreateSvxToolbarConfigPage, nullptr);
209 AddTabPage("notebookbar", CreateSvxNotebookbarConfigPage, nullptr);
210 AddTabPage("contextmenus", CreateSvxContextMenuConfigPage, nullptr);
211 AddTabPage("keyboard", CreateKeyboardConfigPage, nullptr);
212 AddTabPage("events", CreateSvxEventConfigPage, nullptr);
214 const SfxPoolItem* pItem =
215 pInSet->GetItem( pInSet->GetPool()->GetWhich( SID_CONFIG ) );
217 if ( pItem )
219 OUString text = static_cast<const SfxStringItem*>(pItem)->GetValue();
221 if (text.startsWith( ITEM_TOOLBAR_URL ) )
223 SetCurPageId("toolbars");
228 void SvxConfigDialog::SetFrame(const css::uno::Reference<css::frame::XFrame>& xFrame)
230 m_xFrame = xFrame;
231 uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext(),
232 uno::UNO_SET_THROW);
234 OUString aModuleId = SvxConfigPage::GetFrameWithDefaultAndIdentify(m_xFrame);
235 uno::Reference<css::frame::XModuleManager2> xModuleManager(
236 css::frame::ModuleManager::create(xContext));
237 OUString aModuleName = SvxConfigPageHelper::GetUIModuleName(aModuleId, xModuleManager);
238 if (aModuleName != "Writer" && aModuleName != "Calc" && aModuleName != "Impress"
239 && aModuleName != "Draw")
240 RemoveTabPage("notebookbar");
242 if (!SvxConfigPageHelper::showKeyConfigTabPage(xFrame))
243 RemoveTabPage("keyboard");
246 void SvxConfigDialog::PageCreated(const OString &rId, SfxTabPage& rPage)
248 if (rId == "menus" || rId == "keyboard" || rId == "notebookbar"
249 || rId == "toolbars" || rId == "contextmenus")
251 rPage.SetFrame(m_xFrame);
253 else if (rId == "events")
255 dynamic_cast< SvxEventConfigPage& >( rPage ).LateInit( m_xFrame );
259 /******************************************************************************
261 * The SaveInData class is used to hold data for entries in the Save In
262 * ListBox controls in the menu and toolbar tabs
264 ******************************************************************************/
266 // Initialize static variable which holds default XImageManager
267 uno::Reference< css::ui::XImageManager>* SaveInData::xDefaultImgMgr = nullptr;
269 SaveInData::SaveInData(
270 const uno::Reference< css::ui::XUIConfigurationManager >& xCfgMgr,
271 const uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
272 const OUString& aModuleId,
273 bool isDocConfig )
275 bModified( false ),
276 bDocConfig( isDocConfig ),
277 bReadOnly( false ),
278 m_xCfgMgr( xCfgMgr ),
279 m_xParentCfgMgr( xParentCfgMgr )
281 m_aSeparatorSeq.realloc( 1 );
282 m_aSeparatorSeq[0].Name = ITEM_DESCRIPTOR_TYPE;
283 m_aSeparatorSeq[0].Value <<= css::ui::ItemType::SEPARATOR_LINE;
285 if ( bDocConfig )
287 uno::Reference< css::ui::XUIConfigurationPersistence >
288 xDocPersistence( GetConfigManager(), uno::UNO_QUERY );
290 bReadOnly = xDocPersistence->isReadOnly();
293 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
295 uno::Reference< container::XNameAccess > xNameAccess(
296 css::frame::theUICommandDescription::get(xContext) );
298 xNameAccess->getByName( aModuleId ) >>= m_xCommandToLabelMap;
300 if ( !m_xImgMgr.is() )
302 m_xImgMgr.set( GetConfigManager()->getImageManager(), uno::UNO_QUERY );
305 if ( !IsDocConfig() )
307 // If this is not a document configuration then it is the settings
308 // for the module (writer, calc, impress etc.) Use this as the default
309 // XImageManager instance
310 xDefaultImgMgr = &m_xImgMgr;
312 else
314 // If this is a document configuration then use the module image manager
315 // as default.
316 if ( m_xParentCfgMgr.is() )
318 m_xParentImgMgr.set( m_xParentCfgMgr->getImageManager(), uno::UNO_QUERY );
319 xDefaultImgMgr = &m_xParentImgMgr;
324 uno::Reference<graphic::XGraphic> SaveInData::GetImage(const OUString& rCommandURL)
326 uno::Reference< graphic::XGraphic > xGraphic =
327 SvxConfigPageHelper::GetGraphic( m_xImgMgr, rCommandURL );
329 if (!xGraphic.is() && xDefaultImgMgr != nullptr && (*xDefaultImgMgr).is())
331 xGraphic = SvxConfigPageHelper::GetGraphic( (*xDefaultImgMgr), rCommandURL );
334 return xGraphic;
337 bool SaveInData::PersistChanges(
338 const uno::Reference< uno::XInterface >& xManager )
340 bool result = true;
344 if ( xManager.is() && !IsReadOnly() )
346 uno::Reference< css::ui::XUIConfigurationPersistence >
347 xConfigPersistence( xManager, uno::UNO_QUERY );
349 if ( xConfigPersistence->isModified() )
351 xConfigPersistence->store();
355 catch ( css::io::IOException& )
357 result = false;
360 return result;
363 /******************************************************************************
365 * The MenuSaveInData class extends SaveInData and provides menu specific
366 * load and store functionality.
368 ******************************************************************************/
370 // Initialize static variable which holds default Menu data
371 MenuSaveInData* MenuSaveInData::pDefaultData = nullptr;
373 MenuSaveInData::MenuSaveInData(
374 const uno::Reference< css::ui::XUIConfigurationManager >& cfgmgr,
375 const uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
376 const OUString& aModuleId,
377 bool isDocConfig )
379 SaveInData( cfgmgr, xParentCfgMgr, aModuleId, isDocConfig ),
380 m_aMenuResourceURL(
381 ITEM_MENUBAR_URL ),
382 m_aDescriptorContainer(
383 ITEM_DESCRIPTOR_CONTAINER )
387 OUString url( ITEM_MENUBAR_URL );
388 m_xMenuSettings = GetConfigManager()->getSettings( url, false );
390 catch ( container::NoSuchElementException& )
392 // will use menu settings for the module
395 // If this is not a document configuration then it is the settings
396 // for the module (writer, calc, impress etc.). These settings should
397 // be set as the default to be used for SaveIn locations that do not
398 // have custom settings
399 if ( !IsDocConfig() )
401 SetDefaultData( this );
405 MenuSaveInData::~MenuSaveInData()
409 SvxEntries*
410 MenuSaveInData::GetEntries()
412 if ( pRootEntry == nullptr )
414 pRootEntry.reset( new SvxConfigEntry( "MainMenus", OUString(), true, /*bParentData*/false) );
416 if ( m_xMenuSettings.is() )
418 LoadSubMenus( m_xMenuSettings, OUString(), pRootEntry.get(), false );
420 else if ( GetDefaultData() != nullptr )
422 // If the doc has no config settings use module config settings
423 LoadSubMenus( GetDefaultData()->m_xMenuSettings, OUString(), pRootEntry.get(), false );
427 return pRootEntry->GetEntries();
430 void
431 MenuSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
433 pRootEntry->SetEntries( std::move(pNewEntries) );
436 void SaveInData::LoadSubMenus( const uno::Reference< container::XIndexAccess >& xMenuSettings,
437 const OUString& rBaseTitle, SvxConfigEntry const * pParentData, bool bContextMenu )
439 SvxEntries* pEntries = pParentData->GetEntries();
441 // Don't access non existing menu configuration!
442 if ( !xMenuSettings.is() )
443 return;
445 for ( sal_Int32 nIndex = 0; nIndex < xMenuSettings->getCount(); ++nIndex )
447 uno::Reference< container::XIndexAccess > xSubMenu;
448 OUString aCommandURL;
449 OUString aLabel;
451 sal_uInt16 nType( css::ui::ItemType::DEFAULT );
452 sal_Int32 nStyle(0);
454 bool bItem = SvxConfigPageHelper::GetMenuItemData( xMenuSettings, nIndex,
455 aCommandURL, aLabel, nType, nStyle, xSubMenu );
457 if ( bItem )
459 bool bIsUserDefined = true;
461 if ( nType == css::ui::ItemType::DEFAULT )
463 uno::Any a;
466 a = m_xCommandToLabelMap->getByName( aCommandURL );
467 bIsUserDefined = false;
469 catch ( container::NoSuchElementException& )
471 bIsUserDefined = true;
474 bool bUseDefaultLabel = false;
475 // If custom label not set retrieve it from the command
476 // to info service
477 if ( aLabel.isEmpty() )
479 bUseDefaultLabel = true;
480 uno::Sequence< beans::PropertyValue > aPropSeq;
481 if ( a >>= aPropSeq )
483 OUString aMenuLabel;
484 for ( sal_Int32 i = 0; i < aPropSeq.getLength(); ++i )
486 if ( bContextMenu )
488 if ( aPropSeq[i].Name == "PopupLabel" )
490 aPropSeq[i].Value >>= aLabel;
491 break;
493 else if ( aPropSeq[i].Name == "Label" )
495 aPropSeq[i].Value >>= aMenuLabel;
498 else if ( aPropSeq[i].Name == "Label" )
500 aPropSeq[i].Value >>= aLabel;
501 break;
504 if ( aLabel.isEmpty() )
505 aLabel = aMenuLabel;
509 SvxConfigEntry* pEntry = new SvxConfigEntry(
510 aLabel, aCommandURL, xSubMenu.is(), /*bParentData*/false );
512 pEntry->SetStyle( nStyle );
513 pEntry->SetUserDefined( bIsUserDefined );
514 if ( !bUseDefaultLabel )
515 pEntry->SetName( aLabel );
517 pEntries->push_back( pEntry );
519 if ( xSubMenu.is() )
521 // popup menu
522 OUString subMenuTitle( rBaseTitle );
524 if ( !subMenuTitle.isEmpty() )
526 subMenuTitle += aMenuSeparatorStr;
528 else
530 pEntry->SetMain();
533 subMenuTitle += SvxConfigPageHelper::stripHotKey( aLabel );
535 LoadSubMenus( xSubMenu, subMenuTitle, pEntry, bContextMenu );
538 else
540 SvxConfigEntry* pEntry = new SvxConfigEntry;
541 pEntry->SetUserDefined( bIsUserDefined );
542 pEntries->push_back( pEntry );
548 bool MenuSaveInData::Apply()
550 bool result = false;
552 if ( IsModified() )
554 // Apply new menu bar structure to our settings container
555 m_xMenuSettings = GetConfigManager()->createSettings();
557 uno::Reference< container::XIndexContainer > xIndexContainer (
558 m_xMenuSettings, uno::UNO_QUERY );
560 uno::Reference< lang::XSingleComponentFactory > xFactory (
561 m_xMenuSettings, uno::UNO_QUERY );
563 Apply( xIndexContainer, xFactory );
567 if ( GetConfigManager()->hasSettings( m_aMenuResourceURL ) )
569 GetConfigManager()->replaceSettings(
570 m_aMenuResourceURL, m_xMenuSettings );
572 else
574 GetConfigManager()->insertSettings(
575 m_aMenuResourceURL, m_xMenuSettings );
578 catch ( css::uno::Exception& )
580 TOOLS_WARN_EXCEPTION("cui.customize", "caught some other exception saving settings");
583 SetModified( false );
585 result = PersistChanges( GetConfigManager() );
588 return result;
591 void MenuSaveInData::Apply(
592 uno::Reference< container::XIndexContainer > const & rMenuBar,
593 uno::Reference< lang::XSingleComponentFactory >& rFactory )
595 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
597 for (auto const& entryData : *GetEntries())
599 uno::Sequence< beans::PropertyValue > aPropValueSeq =
600 SvxConfigPageHelper::ConvertSvxConfigEntry(entryData);
602 uno::Reference< container::XIndexContainer > xSubMenuBar(
603 rFactory->createInstanceWithContext( xContext ),
604 uno::UNO_QUERY );
606 sal_Int32 nIndex = aPropValueSeq.getLength();
607 aPropValueSeq.realloc( nIndex + 1 );
608 aPropValueSeq[nIndex].Name = m_aDescriptorContainer;
609 aPropValueSeq[nIndex].Value <<= xSubMenuBar;
610 rMenuBar->insertByIndex(
611 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
612 ApplyMenu( xSubMenuBar, rFactory, entryData );
616 void SaveInData::ApplyMenu(
617 uno::Reference< container::XIndexContainer > const & rMenuBar,
618 uno::Reference< lang::XSingleComponentFactory >& rFactory,
619 SvxConfigEntry* pMenuData )
621 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
623 for (auto const& entry : *pMenuData->GetEntries())
625 if (entry->IsPopup())
627 uno::Sequence< beans::PropertyValue > aPropValueSeq =
628 SvxConfigPageHelper::ConvertSvxConfigEntry(entry);
630 uno::Reference< container::XIndexContainer > xSubMenuBar(
631 rFactory->createInstanceWithContext( xContext ),
632 uno::UNO_QUERY );
634 sal_Int32 nIndex = aPropValueSeq.getLength();
635 aPropValueSeq.realloc( nIndex + 1 );
636 aPropValueSeq[nIndex].Name = ITEM_DESCRIPTOR_CONTAINER;
637 aPropValueSeq[nIndex].Value <<= xSubMenuBar;
639 rMenuBar->insertByIndex(
640 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
642 ApplyMenu( xSubMenuBar, rFactory, entry );
643 entry->SetModified( false );
645 else if (entry->IsSeparator())
647 rMenuBar->insertByIndex(
648 rMenuBar->getCount(), uno::Any( m_aSeparatorSeq ));
650 else
652 uno::Sequence< beans::PropertyValue > aPropValueSeq =
653 SvxConfigPageHelper::ConvertSvxConfigEntry(entry);
654 rMenuBar->insertByIndex(
655 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
658 pMenuData->SetModified( false );
661 void
662 MenuSaveInData::Reset()
666 GetConfigManager()->removeSettings( m_aMenuResourceURL );
668 catch ( const css::uno::Exception& )
671 PersistChanges( GetConfigManager() );
673 pRootEntry.reset();
677 m_xMenuSettings = GetConfigManager()->getSettings(
678 m_aMenuResourceURL, false );
680 catch ( container::NoSuchElementException& )
682 // will use default settings
686 ContextMenuSaveInData::ContextMenuSaveInData(
687 const css::uno::Reference< css::ui::XUIConfigurationManager >& xCfgMgr,
688 const css::uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
689 const OUString& aModuleId, bool bIsDocConfig )
690 : SaveInData( xCfgMgr, xParentCfgMgr, aModuleId, bIsDocConfig )
692 css::uno::Reference< css::uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
693 css::uno::Reference< css::container::XNameAccess > xConfig( css::ui::theWindowStateConfiguration::get( xContext ) );
694 xConfig->getByName( aModuleId ) >>= m_xPersistentWindowState;
697 ContextMenuSaveInData::~ContextMenuSaveInData()
701 OUString ContextMenuSaveInData::GetUIName( const OUString& rResourceURL )
703 if ( m_xPersistentWindowState.is() )
705 css::uno::Sequence< css::beans::PropertyValue > aProps;
708 m_xPersistentWindowState->getByName( rResourceURL ) >>= aProps;
710 catch ( const css::uno::Exception& )
713 for ( const auto& aProp : std::as_const(aProps) )
715 if ( aProp.Name == ITEM_DESCRIPTOR_UINAME )
717 OUString aResult;
718 aProp.Value >>= aResult;
719 return aResult;
723 return OUString();
726 SvxEntries* ContextMenuSaveInData::GetEntries()
728 if ( !m_pRootEntry )
730 std::unordered_map< OUString, bool > aMenuInfo;
732 m_pRootEntry.reset( new SvxConfigEntry( "ContextMenus", OUString(), true, /*bParentData*/false ) );
733 css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aElementsInfo;
736 aElementsInfo = GetConfigManager()->getUIElementsInfo( css::ui::UIElementType::POPUPMENU );
738 catch ( const css::lang::IllegalArgumentException& )
741 for ( const auto& aElement : std::as_const(aElementsInfo) )
743 OUString aUrl;
744 for ( const auto& aElementProp : aElement )
746 if ( aElementProp.Name == ITEM_DESCRIPTOR_RESOURCEURL )
748 aElementProp.Value >>= aUrl;
749 break;
753 css::uno::Reference< css::container::XIndexAccess > xPopupMenu;
756 xPopupMenu = GetConfigManager()->getSettings( aUrl, false );
758 catch ( const css::uno::Exception& )
761 if ( xPopupMenu.is() )
763 // insert into std::unordered_map to filter duplicates from the parent
764 aMenuInfo.emplace( aUrl, true );
766 OUString aUIMenuName = GetUIName( aUrl );
767 if ( aUIMenuName.isEmpty() )
768 // Menus without UI name aren't supposed to be customized.
769 continue;
771 SvxConfigEntry* pEntry = new SvxConfigEntry( aUIMenuName, aUrl, true, /*bParentData*/false );
772 pEntry->SetMain();
773 m_pRootEntry->GetEntries()->push_back( pEntry );
774 LoadSubMenus( xPopupMenu, aUIMenuName, pEntry, true );
778 // Retrieve also the parent menus, to make it possible to configure module menus and save them into the document.
779 css::uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr = GetParentConfigManager();
780 css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aParentElementsInfo;
783 if ( xParentCfgMgr.is() )
784 aParentElementsInfo = xParentCfgMgr->getUIElementsInfo( css::ui::UIElementType::POPUPMENU );
786 catch ( const css::lang::IllegalArgumentException& )
789 for ( const auto& aElement : std::as_const(aParentElementsInfo) )
791 OUString aUrl;
792 for ( const auto& aElementProp : aElement )
794 if ( aElementProp.Name == ITEM_DESCRIPTOR_RESOURCEURL )
796 aElementProp.Value >>= aUrl;
797 break;
801 css::uno::Reference< css::container::XIndexAccess > xPopupMenu;
804 if ( aMenuInfo.find( aUrl ) == aMenuInfo.end() )
805 xPopupMenu = xParentCfgMgr->getSettings( aUrl, false );
807 catch ( const css::uno::Exception& )
810 if ( xPopupMenu.is() )
812 OUString aUIMenuName = GetUIName( aUrl );
813 if ( aUIMenuName.isEmpty() )
814 continue;
816 SvxConfigEntry* pEntry = new SvxConfigEntry( aUIMenuName, aUrl, true, true );
817 pEntry->SetMain();
818 m_pRootEntry->GetEntries()->push_back( pEntry );
819 LoadSubMenus( xPopupMenu, aUIMenuName, pEntry, true );
822 std::sort( m_pRootEntry->GetEntries()->begin(), m_pRootEntry->GetEntries()->end(), SvxConfigPageHelper::EntrySort );
824 return m_pRootEntry->GetEntries();
827 void ContextMenuSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
829 m_pRootEntry->SetEntries( std::move(pNewEntries) );
832 bool ContextMenuSaveInData::HasURL( const OUString& rURL )
834 SvxEntries* pEntries = GetEntries();
835 for ( const auto& pEntry : *pEntries )
836 if ( pEntry->GetCommand() == rURL )
837 return true;
839 return false;
842 bool ContextMenuSaveInData::HasSettings()
844 return m_pRootEntry && !m_pRootEntry->GetEntries()->empty();
847 bool ContextMenuSaveInData::Apply()
849 if ( !IsModified() )
850 return false;
852 SvxEntries* pEntries = GetEntries();
853 for ( const auto& pEntry : *pEntries )
855 if ( pEntry->IsModified() || SvxConfigPageHelper::SvxConfigEntryModified( pEntry ) )
857 css::uno::Reference< css::container::XIndexContainer > xIndexContainer = GetConfigManager()->createSettings();
858 css::uno::Reference< css::lang::XSingleComponentFactory > xFactory( xIndexContainer, css::uno::UNO_QUERY );
859 ApplyMenu( xIndexContainer, xFactory, pEntry );
861 const OUString& aUrl = pEntry->GetCommand();
864 if ( GetConfigManager()->hasSettings( aUrl ) )
865 GetConfigManager()->replaceSettings( aUrl, xIndexContainer );
866 else
867 GetConfigManager()->insertSettings( aUrl, xIndexContainer );
869 catch ( const css::uno::Exception& )
873 SetModified( false );
874 return PersistChanges( GetConfigManager() );
877 void ContextMenuSaveInData::Reset()
879 SvxEntries* pEntries = GetEntries();
880 for ( const auto& pEntry : *pEntries )
884 GetConfigManager()->removeSettings( pEntry->GetCommand() );
886 catch ( const css::uno::Exception& )
888 TOOLS_WARN_EXCEPTION("cui.customize", "Exception caught while resetting context menus");
891 PersistChanges( GetConfigManager() );
892 m_pRootEntry.reset();
895 void ContextMenuSaveInData::ResetContextMenu( const SvxConfigEntry* pEntry )
899 GetConfigManager()->removeSettings( pEntry->GetCommand() );
901 catch ( const css::uno::Exception& )
903 TOOLS_WARN_EXCEPTION("cui.customize", "Exception caught while resetting context menu");
905 PersistChanges( GetConfigManager() );
906 m_pRootEntry.reset();
909 void SvxMenuEntriesListBox::CreateDropDown()
911 int nWidth = m_xControl->get_text_height() / 2;
912 m_xDropDown->SetOutputSizePixel(Size(nWidth, nWidth));
913 DecorationView aDecoView(m_xDropDown.get());
914 aDecoView.DrawSymbol(tools::Rectangle(Point(0, 0), Size(nWidth, nWidth)),
915 SymbolType::SPIN_RIGHT, m_xDropDown->GetTextColor(),
916 DrawSymbolFlags::NONE);
919 /******************************************************************************
921 * SvxMenuEntriesListBox is the listbox in which the menu items for a
922 * particular menu are shown. We have a custom listbox because we need
923 * to add drag'n'drop support from the Macro Selector and within the
924 * listbox
926 *****************************************************************************/
927 SvxMenuEntriesListBox::SvxMenuEntriesListBox(std::unique_ptr<weld::TreeView> xControl, SvxConfigPage* pPg)
928 : m_xControl(std::move(xControl))
929 , m_xDropDown(m_xControl->create_virtual_device())
930 , m_pPage(pPg)
932 CreateDropDown();
933 m_xControl->connect_key_press(LINK(this, SvxMenuEntriesListBox, KeyInputHdl));
936 SvxMenuEntriesListBox::~SvxMenuEntriesListBox()
940 IMPL_LINK(SvxMenuEntriesListBox, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
942 vcl::KeyCode keycode = rKeyEvent.GetKeyCode();
944 // support DELETE for removing the current entry
945 if ( keycode == KEY_DELETE )
947 m_pPage->DeleteSelectedContent();
949 // support CTRL+UP and CTRL+DOWN for moving selected entries
950 else if ( keycode.GetCode() == KEY_UP && keycode.IsMod1() )
952 m_pPage->MoveEntry( true );
954 else if ( keycode.GetCode() == KEY_DOWN && keycode.IsMod1() )
956 m_pPage->MoveEntry( false );
958 else
960 return false; // pass on to default handler
962 return true;
965 /******************************************************************************
967 * SvxConfigPage is the abstract base class on which the Menu and Toolbar
968 * configuration tabpages are based. It includes methods which are common to
969 * both tabpages to add, delete, move and rename items etc.
971 *****************************************************************************/
972 SvxConfigPage::SvxConfigPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
973 : SfxTabPage(pPage, pController, "cui/ui/menuassignpage.ui", "MenuAssignPage", &rSet)
974 , m_aUpdateDataTimer("UpdateDataTimer")
975 , bInitialised(false)
976 , pCurrentSaveInData(nullptr)
977 , m_xCommandCategoryListBox(new CommandCategoryListBox(m_xBuilder->weld_combo_box("commandcategorylist")))
978 , m_xFunctions(new CuiConfigFunctionListBox(m_xBuilder->weld_tree_view("functions")))
979 , m_xCategoryLabel(m_xBuilder->weld_label("categorylabel"))
980 , m_xDescriptionFieldLb(m_xBuilder->weld_label("descriptionlabel"))
981 , m_xDescriptionField(m_xBuilder->weld_text_view("desc"))
982 , m_xLeftFunctionLabel(m_xBuilder->weld_label("leftfunctionlabel"))
983 , m_xSearchEdit(m_xBuilder->weld_entry("searchEntry"))
984 , m_xSearchLabel(m_xBuilder->weld_label("searchlabel"))
985 , m_xCustomizeLabel(m_xBuilder->weld_label("customizelabel"))
986 , m_xTopLevelListBox(m_xBuilder->weld_combo_box("toplevellist"))
987 , m_xMoveUpButton(m_xBuilder->weld_button("up"))
988 , m_xMoveDownButton(m_xBuilder->weld_button("down"))
989 , m_xSaveInListBox(m_xBuilder->weld_combo_box("savein"))
990 , m_xInsertBtn(m_xBuilder->weld_menu_button("insert"))
991 , m_xModifyBtn(m_xBuilder->weld_menu_button("modify"))
992 , m_xResetBtn(m_xBuilder->weld_button("defaultsbtn"))
993 , m_xAddCommandButton(m_xBuilder->weld_button("add"))
994 , m_xRemoveCommandButton(m_xBuilder->weld_button("remove"))
996 CustomNotebookbarGenerator::getFileNameAndAppName(m_sAppName, m_sFileName);
998 m_xTopLevelListBox->connect_changed(LINK(this, SvxConfigPage, SelectElementHdl));
1000 weld::TreeView& rTreeView = m_xFunctions->get_widget();
1001 Size aSize(rTreeView.get_approximate_digit_width() * 40, rTreeView.get_height_rows(8));
1002 m_xFunctions->set_size_request(aSize.Width(), aSize.Height());
1003 m_xDescriptionField->set_size_request(aSize.Width(), m_xDescriptionField->get_height_rows(3));
1005 m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SvxConfigPage, ImplUpdateDataHdl));
1006 m_aUpdateDataTimer.SetDebugName( "SvxConfigPage UpdateDataTimer" );
1007 m_aUpdateDataTimer.SetTimeout(EDIT_UPDATEDATA_TIMEOUT);
1009 m_xSearchEdit->connect_changed(LINK(this, SvxConfigPage, SearchUpdateHdl));
1010 m_xSearchEdit->connect_focus_out(LINK(this, SvxConfigPage, FocusOut_Impl));
1012 rTreeView.connect_row_activated(LINK(this, SvxConfigPage, FunctionDoubleClickHdl));
1013 rTreeView.connect_changed(LINK(this, SvxConfigPage, SelectFunctionHdl));
1016 IMPL_LINK_NOARG(SvxConfigPage, SelectElementHdl, weld::ComboBox&, void)
1018 SelectElement();
1021 SvxConfigPage::~SvxConfigPage()
1025 void SvxConfigPage::Reset( const SfxItemSet* )
1027 // If we haven't initialised our XMultiServiceFactory reference
1028 // then Reset is being called at the opening of the dialog.
1030 // Load menu configuration data for the module of the currently
1031 // selected document, for the currently selected document, and for
1032 // all other open documents of the same module type
1033 if ( !bInitialised )
1035 sal_Int32 nPos = 0;
1036 uno::Reference < css::ui::XUIConfigurationManager > xCfgMgr;
1037 uno::Reference < css::ui::XUIConfigurationManager > xDocCfgMgr;
1039 uno::Reference< uno::XComponentContext > xContext(
1040 ::comphelper::getProcessComponentContext(), uno::UNO_SET_THROW );
1042 m_xFrame = GetFrame();
1043 m_aModuleId = GetFrameWithDefaultAndIdentify( m_xFrame );
1045 // replace %MODULENAME in the label with the correct module name
1046 uno::Reference< css::frame::XModuleManager2 > xModuleManager(
1047 css::frame::ModuleManager::create( xContext ));
1048 OUString aModuleName = SvxConfigPageHelper::GetUIModuleName( m_aModuleId, xModuleManager );
1050 uno::Reference< css::ui::XModuleUIConfigurationManagerSupplier >
1051 xModuleCfgSupplier( css::ui::theModuleUIConfigurationManagerSupplier::get(xContext) );
1053 // Set up data for module specific menus
1054 SaveInData* pModuleData = nullptr;
1058 xCfgMgr =
1059 xModuleCfgSupplier->getUIConfigurationManager( m_aModuleId );
1061 pModuleData = CreateSaveInData( xCfgMgr,
1062 uno::Reference< css::ui::XUIConfigurationManager >(),
1063 m_aModuleId,
1064 false );
1066 catch ( container::NoSuchElementException& )
1070 if ( pModuleData != nullptr )
1072 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pModuleData)));
1073 m_xSaveInListBox->append(sId, utl::ConfigManager::getProductName() + " " + aModuleName);
1076 // try to retrieve the document based ui configuration manager
1077 OUString aTitle;
1078 uno::Reference< frame::XController > xController =
1079 m_xFrame->getController();
1080 if ( CanConfig( m_aModuleId ) && xController.is() )
1082 uno::Reference< frame::XModel > xModel( xController->getModel() );
1083 if ( xModel.is() )
1085 uno::Reference< css::ui::XUIConfigurationManagerSupplier >
1086 xCfgSupplier( xModel, uno::UNO_QUERY );
1088 if ( xCfgSupplier.is() )
1090 xDocCfgMgr = xCfgSupplier->getUIConfigurationManager();
1092 aTitle = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
1096 SaveInData* pDocData = nullptr;
1097 if ( xDocCfgMgr.is() )
1099 pDocData = CreateSaveInData( xDocCfgMgr, xCfgMgr, m_aModuleId, true );
1101 if ( !pDocData->IsReadOnly() )
1103 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pDocData)));
1104 m_xSaveInListBox->append(sId, aTitle);
1108 // if an item to select has been passed in (eg. the ResourceURL for a
1109 // toolbar) then try to select the SaveInData entry that has that item
1110 bool bURLToSelectFound = false;
1111 if ( !m_aURLToSelect.isEmpty() )
1113 if ( pDocData && pDocData->HasURL( m_aURLToSelect ) )
1115 m_xSaveInListBox->set_active(nPos);
1116 pCurrentSaveInData = pDocData;
1117 bURLToSelectFound = true;
1119 else if ( pModuleData && pModuleData->HasURL( m_aURLToSelect ) )
1121 m_xSaveInListBox->set_active(0);
1122 pCurrentSaveInData = pModuleData;
1123 bURLToSelectFound = true;
1127 if ( !bURLToSelectFound )
1129 // if the document has menu configuration settings select it
1130 // it the SaveIn listbox, otherwise select the module data
1131 if ( pDocData != nullptr && pDocData->HasSettings() )
1133 m_xSaveInListBox->set_active(nPos);
1134 pCurrentSaveInData = pDocData;
1136 else
1138 m_xSaveInListBox->set_active(0);
1139 pCurrentSaveInData = pModuleData;
1143 #ifdef DBG_UTIL
1144 DBG_ASSERT( pCurrentSaveInData, "SvxConfigPage::Reset(): no SaveInData" );
1145 #endif
1147 if ( CanConfig( m_aModuleId ) )
1149 // Load configuration for other open documents which have
1150 // same module type
1151 uno::Sequence< uno::Reference< frame::XFrame > > aFrameList;
1154 uno::Reference< frame::XDesktop2 > xFramesSupplier = frame::Desktop::create(
1155 xContext );
1157 uno::Reference< frame::XFrames > xFrames =
1158 xFramesSupplier->getFrames();
1160 aFrameList = xFrames->queryFrames(
1161 frame::FrameSearchFlag::ALL & ~frame::FrameSearchFlag::SELF );
1164 catch( const uno::Exception& )
1166 DBG_UNHANDLED_EXCEPTION("cui.customize");
1169 for ( sal_Int32 i = 0; i < aFrameList.getLength(); ++i )
1171 uno::Reference < frame::XFrame > xf = aFrameList[i];
1173 if ( xf.is() && xf != m_xFrame )
1175 OUString aCheckId;
1176 try{
1177 aCheckId = xModuleManager->identify( xf );
1178 } catch(const uno::Exception&)
1179 { aCheckId.clear(); }
1181 if ( m_aModuleId == aCheckId )
1183 // try to get the document based ui configuration manager
1184 OUString aTitle2;
1185 uno::Reference< frame::XController > xController_ =
1186 xf->getController();
1188 if ( xController_.is() )
1190 uno::Reference< frame::XModel > xModel(
1191 xController_->getModel() );
1193 if ( xModel.is() )
1195 uno::Reference<
1196 css::ui::XUIConfigurationManagerSupplier >
1197 xCfgSupplier( xModel, uno::UNO_QUERY );
1199 if ( xCfgSupplier.is() )
1201 xDocCfgMgr =
1202 xCfgSupplier->getUIConfigurationManager();
1204 aTitle2 = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
1208 if ( xDocCfgMgr.is() )
1210 SaveInData* pData = CreateSaveInData( xDocCfgMgr, xCfgMgr, m_aModuleId, true );
1212 if ( pData && !pData->IsReadOnly() )
1214 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pData)));
1215 m_xSaveInListBox->append(sId, aTitle2);
1223 m_xSaveInListBox->connect_changed(
1224 LINK( this, SvxConfigPage, SelectSaveInLocation ) );
1226 bInitialised = true;
1228 Init();
1230 else
1232 if ( QueryReset() == RET_YES )
1234 // Reset menu configuration for currently selected SaveInData
1235 GetSaveInData()->Reset();
1237 Init();
1242 OUString SvxConfigPage::GetFrameWithDefaultAndIdentify( uno::Reference< frame::XFrame >& _inout_rxFrame )
1244 OUString sModuleID;
1247 uno::Reference< uno::XComponentContext > xContext(
1248 ::comphelper::getProcessComponentContext() );
1250 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(
1251 xContext );
1253 if ( !_inout_rxFrame.is() )
1254 _inout_rxFrame = xDesktop->getActiveFrame();
1256 if ( !_inout_rxFrame.is() )
1258 _inout_rxFrame = xDesktop->getCurrentFrame();
1261 if ( !_inout_rxFrame.is() && SfxViewFrame::Current() )
1262 _inout_rxFrame = SfxViewFrame::Current()->GetFrame().GetFrameInterface();
1264 if ( !_inout_rxFrame.is() )
1266 SAL_WARN( "cui.customize", "SvxConfigPage::GetFrameWithDefaultAndIdentify(): no frame found!" );
1267 return sModuleID;
1270 sModuleID = vcl::CommandInfoProvider::GetModuleIdentifier(_inout_rxFrame);
1272 catch( const uno::Exception& )
1274 DBG_UNHANDLED_EXCEPTION("cui.customize");
1277 return sModuleID;
1280 OUString SvxConfigPage::GetScriptURL() const
1282 OUString result;
1284 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(m_xFunctions->get_selected_id().toInt64());
1285 if (pData)
1287 if ( ( pData->nKind == SfxCfgKind::FUNCTION_SLOT ) ||
1288 ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT ) ||
1289 ( pData->nKind == SfxCfgKind::GROUP_STYLES ) )
1291 result = pData->sCommand;
1295 return result;
1298 OUString SvxConfigPage::GetSelectedDisplayName() const
1300 return m_xFunctions->get_selected_text();
1303 bool SvxConfigPage::FillItemSet( SfxItemSet* )
1305 bool result = false;
1307 for (int i = 0, nCount = m_xSaveInListBox->get_count(); i < nCount; ++i)
1309 SaveInData* pData =
1310 reinterpret_cast<SaveInData*>(m_xSaveInListBox->get_id(i).toInt64());
1311 if(m_xSaveInListBox->get_id(i) != notebookbarTabScope)
1312 result = pData->Apply();
1314 return result;
1317 IMPL_LINK_NOARG(SvxConfigPage, SelectSaveInLocation, weld::ComboBox&, void)
1319 pCurrentSaveInData = reinterpret_cast<SaveInData*>(m_xSaveInListBox->get_active_id().toInt64());
1320 Init();
1323 void SvxConfigPage::ReloadTopLevelListBox( SvxConfigEntry const * pToSelect )
1325 int nSelectionPos = m_xTopLevelListBox->get_active();
1326 m_xTopLevelListBox->clear();
1328 if ( GetSaveInData() && GetSaveInData()->GetEntries() )
1330 for (auto const& entryData : *GetSaveInData()->GetEntries())
1332 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(entryData)));
1333 m_xTopLevelListBox->append(sId, SvxConfigPageHelper::stripHotKey(entryData->GetName()));
1335 if (entryData == pToSelect)
1336 nSelectionPos = m_xTopLevelListBox->get_count() - 1;
1338 AddSubMenusToUI( SvxConfigPageHelper::stripHotKey( entryData->GetName() ), entryData );
1341 #ifdef DBG_UTIL
1342 else
1344 DBG_ASSERT( GetSaveInData(), "SvxConfigPage::ReloadTopLevelListBox(): no SaveInData" );
1345 DBG_ASSERT( GetSaveInData()->GetEntries() ,
1346 "SvxConfigPage::ReloadTopLevelListBox(): no SaveInData entries" );
1348 #endif
1350 nSelectionPos = (nSelectionPos != -1 && nSelectionPos < m_xTopLevelListBox->get_count()) ?
1351 nSelectionPos : m_xTopLevelListBox->get_count() - 1;
1353 m_xTopLevelListBox->set_active(nSelectionPos);
1354 SelectElement();
1357 void SvxConfigPage::AddSubMenusToUI(
1358 const OUString& rBaseTitle, SvxConfigEntry const * pParentData )
1360 for (auto const& entryData : *pParentData->GetEntries())
1362 if (entryData->IsPopup())
1364 OUString subMenuTitle = rBaseTitle + aMenuSeparatorStr + SvxConfigPageHelper::stripHotKey(entryData->GetName());
1366 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(entryData)));
1367 m_xTopLevelListBox->append(sId, subMenuTitle);
1369 AddSubMenusToUI( subMenuTitle, entryData );
1374 SvxEntries* SvxConfigPage::FindParentForChild(
1375 SvxEntries* pRootEntries, SvxConfigEntry* pChildData )
1377 for (auto const& entryData : *pRootEntries)
1380 if (entryData == pChildData)
1382 return pRootEntries;
1384 else if (entryData->IsPopup())
1386 SvxEntries* result =
1387 FindParentForChild( entryData->GetEntries(), pChildData );
1389 if ( result != nullptr )
1391 return result;
1395 return nullptr;
1398 int SvxConfigPage::AddFunction(int nTarget, bool bAllowDuplicates)
1400 OUString aURL = GetScriptURL();
1401 SvxConfigEntry* pParent = GetTopLevelSelection();
1403 if ( aURL.isEmpty() || pParent == nullptr )
1405 return -1;
1408 OUString aDisplayName;
1410 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aURL, m_aModuleId);
1412 if ( typeid(*pCurrentSaveInData) == typeid(ContextMenuSaveInData) )
1413 aDisplayName = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
1414 else if ( typeid(*pCurrentSaveInData) == typeid(MenuSaveInData) )
1415 aDisplayName = vcl::CommandInfoProvider::GetMenuLabelForCommand(aProperties);
1416 else
1417 aDisplayName = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
1419 SvxConfigEntry* pNewEntryData =
1420 new SvxConfigEntry( aDisplayName, aURL, false, /*bParentData*/false );
1421 pNewEntryData->SetUserDefined();
1423 if ( aDisplayName.isEmpty() )
1424 pNewEntryData->SetName( GetSelectedDisplayName() );
1426 // check that this function is not already in the menu
1427 if ( !bAllowDuplicates )
1429 for (auto const& entry : *pParent->GetEntries())
1431 if ( entry->GetCommand() == pNewEntryData->GetCommand() )
1433 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
1434 VclMessageType::Info, VclButtonsType::Ok, CuiResId(RID_SVXSTR_MNUCFG_ALREADY_INCLUDED)));
1435 xBox->run();
1436 delete pNewEntryData;
1437 return -1;
1442 return AppendEntry(pNewEntryData, nTarget);
1445 int SvxConfigPage::AppendEntry(
1446 SvxConfigEntry* pNewEntryData,
1447 int nTarget)
1449 SvxConfigEntry* pTopLevelSelection = GetTopLevelSelection();
1451 if (pTopLevelSelection == nullptr)
1452 return -1;
1454 // Grab the entries list for the currently selected menu
1455 SvxEntries* pEntries = pTopLevelSelection->GetEntries();
1457 int nNewEntry = -1;
1458 int nCurEntry =
1459 nTarget != -1 ? nTarget : m_xContentsListBox->get_selected_index();
1461 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pNewEntryData)));
1463 if (nCurEntry == -1 || nCurEntry == m_xContentsListBox->n_children() - 1)
1465 pEntries->push_back( pNewEntryData );
1466 m_xContentsListBox->insert(-1, sId);
1467 nNewEntry = m_xContentsListBox->n_children() - 1;
1469 else
1471 SvxConfigEntry* pEntryData =
1472 reinterpret_cast<SvxConfigEntry*>(m_xContentsListBox->get_id(nCurEntry).toInt64());
1474 SvxEntries::iterator iter = pEntries->begin();
1475 SvxEntries::const_iterator end = pEntries->end();
1477 // Advance the iterator to the data for currently selected entry
1478 sal_uInt16 nPos = 0;
1479 while (*iter != pEntryData && ++iter != end)
1481 ++nPos;
1484 // Now step past it to the entry after the currently selected one
1485 ++iter;
1486 ++nPos;
1488 // Now add the new entry to the UI and to the parent's list
1489 if ( iter != end )
1491 pEntries->insert( iter, pNewEntryData );
1492 m_xContentsListBox->insert(nPos, sId);
1493 nNewEntry = nPos;
1497 if (nNewEntry != -1)
1499 m_xContentsListBox->select(nNewEntry);
1500 m_xContentsListBox->scroll_to_row(nNewEntry);
1502 GetSaveInData()->SetModified();
1503 GetTopLevelSelection()->SetModified();
1506 return nNewEntry;
1509 namespace
1511 template<typename itertype> void TmplInsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView& rTreeView, itertype& rIter, int nStartCol, SaveInData* pSaveInData, VirtualDevice& rDropDown)
1513 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pNewEntryData)));
1515 rTreeView.set_id(rIter, sId);
1517 if (pNewEntryData->IsSeparator())
1519 rTreeView.set_text(rIter, "----------------------------------", nStartCol + 1);
1521 else
1523 auto xImage = pSaveInData->GetImage(pNewEntryData->GetCommand());
1524 if (xImage.is())
1525 rTreeView.set_image(rIter, xImage, nStartCol);
1526 OUString aName = SvxConfigPageHelper::stripHotKey( pNewEntryData->GetName() );
1527 rTreeView.set_text(rIter, aName, nStartCol + 1);
1530 if (nStartCol == 0) // menus
1532 if (pNewEntryData->IsPopup() || pNewEntryData->GetStyle() & css::ui::ItemStyle::DROP_DOWN)
1533 rTreeView.set_image(rIter, rDropDown, nStartCol + 2);
1534 else
1535 rTreeView.set_image(rIter, css::uno::Reference<css::graphic::XGraphic>(), nStartCol + 2);
1540 void SvxConfigPage::InsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView& rTreeView, int nPos, int nStartCol)
1542 TmplInsertEntryIntoUI<int>(pNewEntryData, rTreeView, nPos, nStartCol,
1543 GetSaveInData(), m_xContentsListBox->get_dropdown_image());
1546 void SvxConfigPage::InsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView& rTreeView, weld::TreeIter& rIter, int nStartCol)
1548 TmplInsertEntryIntoUI<weld::TreeIter>(pNewEntryData, rTreeView, rIter, nStartCol,
1549 GetSaveInData(), m_xContentsListBox->get_dropdown_image());
1552 IMPL_LINK(SvxConfigPage, MoveHdl, weld::Button&, rButton, void)
1554 MoveEntry(&rButton == m_xMoveUpButton.get());
1557 IMPL_LINK_NOARG(SvxConfigPage, FunctionDoubleClickHdl, weld::TreeView&, bool)
1559 if (m_xAddCommandButton->get_sensitive())
1560 m_xAddCommandButton->clicked();
1561 return true;
1564 IMPL_LINK_NOARG(SvxConfigPage, SelectFunctionHdl, weld::TreeView&, void)
1566 // Store the tooltip of the description field at first run
1567 static const OUString sDescTooltip = m_xDescriptionField->get_tooltip_text();
1569 // GetScriptURL() returns a non-empty string if a
1570 // valid command is selected on the left box
1571 bool bIsValidCommand = !GetScriptURL().isEmpty();
1573 // Enable/disable Add and Remove buttons depending on current selection
1574 if (bIsValidCommand)
1576 m_xAddCommandButton->set_sensitive(true);
1577 m_xRemoveCommandButton->set_sensitive(true);
1579 m_xDescriptionField->set_text(m_xFunctions->GetHelpText(false));
1581 else
1584 m_xAddCommandButton->set_sensitive(false);
1585 m_xRemoveCommandButton->set_sensitive(false);
1587 m_xDescriptionField->set_text("");
1590 // Disable the description field and its label if the local help is not installed
1591 // And inform the user via tooltips
1592 if ( !SfxHelp::IsHelpInstalled() )
1594 m_xDescriptionField->set_sensitive(false);
1595 m_xDescriptionFieldLb->set_sensitive(false);
1596 m_xDescriptionField->set_tooltip_text( sDescTooltip );
1597 m_xDescriptionFieldLb->set_tooltip_text( sDescTooltip );
1599 else
1601 m_xDescriptionField->set_sensitive(true);
1602 m_xDescriptionFieldLb->set_sensitive(true);
1603 m_xDescriptionField->set_tooltip_text("");
1604 m_xDescriptionFieldLb->set_tooltip_text("");
1608 IMPL_LINK_NOARG(SvxConfigPage, ImplUpdateDataHdl, Timer*, void)
1610 OUString aSearchTerm(m_xSearchEdit->get_text());
1611 m_xCommandCategoryListBox->categorySelected(m_xFunctions.get(), aSearchTerm, GetSaveInData());
1614 IMPL_LINK_NOARG(SvxConfigPage, SearchUpdateHdl, weld::Entry&, void)
1616 m_aUpdateDataTimer.Start();
1619 IMPL_LINK_NOARG(SvxConfigPage, FocusOut_Impl, weld::Widget&, void)
1621 if (m_aUpdateDataTimer.IsActive())
1623 m_aUpdateDataTimer.Stop();
1624 m_aUpdateDataTimer.Invoke();
1628 void SvxConfigPage::MoveEntry(bool bMoveUp)
1630 weld::TreeView& rTreeView = m_xContentsListBox->get_widget();
1632 int nSourceEntry = rTreeView.get_selected_index();
1633 int nTargetEntry = -1;
1634 int nToSelect = -1;
1636 if (nSourceEntry == -1)
1638 return;
1641 if ( bMoveUp )
1643 // Move Up is just a Move Down with the source and target reversed
1644 nTargetEntry = nSourceEntry;
1645 nSourceEntry = nTargetEntry - 1;
1646 nToSelect = nSourceEntry;
1648 else
1650 nTargetEntry = nSourceEntry + 1;
1651 nToSelect = nTargetEntry;
1654 if (MoveEntryData(nSourceEntry, nTargetEntry))
1656 rTreeView.swap(nSourceEntry, nTargetEntry);
1657 rTreeView.select(nToSelect);
1658 rTreeView.scroll_to_row(nToSelect);
1660 UpdateButtonStates();
1664 bool SvxConfigPage::MoveEntryData(int nSourceEntry, int nTargetEntry)
1666 //#i53677#
1667 if (nSourceEntry == -1 || nTargetEntry == -1)
1669 return false;
1672 // Grab the entries list for the currently selected menu
1673 SvxEntries* pEntries = GetTopLevelSelection()->GetEntries();
1675 SvxConfigEntry* pSourceData =
1676 reinterpret_cast<SvxConfigEntry*>(m_xContentsListBox->get_id(nSourceEntry).toInt64());
1678 SvxConfigEntry* pTargetData =
1679 reinterpret_cast<SvxConfigEntry*>(m_xContentsListBox->get_id(nTargetEntry).toInt64());
1681 if ( pSourceData != nullptr && pTargetData != nullptr )
1683 // remove the source entry from our list
1684 SvxConfigPageHelper::RemoveEntry( pEntries, pSourceData );
1686 SvxEntries::iterator iter = pEntries->begin();
1687 SvxEntries::const_iterator end = pEntries->end();
1689 // advance the iterator to the position of the target entry
1690 while (*iter != pTargetData && ++iter != end) ;
1692 // insert the source entry at the position after the target
1693 pEntries->insert( ++iter, pSourceData );
1695 GetSaveInData()->SetModified();
1696 GetTopLevelSelection()->SetModified();
1698 return true;
1701 return false;
1704 SvxMainMenuOrganizerDialog::SvxMainMenuOrganizerDialog(
1705 weld::Window* pParent, SvxEntries* entries,
1706 SvxConfigEntry const * selection, bool bCreateMenu )
1707 : GenericDialogController(pParent, "cui/ui/movemenu.ui", "MoveMenuDialog")
1708 , m_xMenuBox(m_xBuilder->weld_widget("namebox"))
1709 , m_xMenuNameEdit(m_xBuilder->weld_entry("menuname"))
1710 , m_xMenuListBox(m_xBuilder->weld_tree_view("menulist"))
1711 , m_xMoveUpButton(m_xBuilder->weld_button("up"))
1712 , m_xMoveDownButton(m_xBuilder->weld_button("down"))
1714 m_xMenuListBox->set_size_request(-1, m_xMenuListBox->get_height_rows(12));
1716 // Copy the entries list passed in
1717 if ( entries != nullptr )
1719 mpEntries.reset( new SvxEntries );
1720 for (auto const& entry : *entries)
1722 m_xMenuListBox->append(OUString::number(reinterpret_cast<sal_uInt64>(entry)),
1723 SvxConfigPageHelper::stripHotKey(entry->GetName()));
1724 mpEntries->push_back(entry);
1725 if (entry == selection)
1727 m_xMenuListBox->select(m_xMenuListBox->n_children() - 1);
1732 if ( bCreateMenu )
1734 // Generate custom name for new menu
1735 OUString prefix = CuiResId( RID_SVXSTR_NEW_MENU );
1737 OUString newname = SvxConfigPageHelper::generateCustomName( prefix, entries );
1738 OUString newurl = SvxConfigPageHelper::generateCustomMenuURL( mpEntries.get() );
1740 SvxConfigEntry* pNewEntryData =
1741 new SvxConfigEntry( newname, newurl, true, /*bParentData*/false );
1742 pNewEntryData->SetName( newname );
1743 pNewEntryData->SetUserDefined();
1744 pNewEntryData->SetMain();
1746 m_sNewMenuEntryId = OUString::number(reinterpret_cast<sal_uInt64>(pNewEntryData));
1747 m_xMenuListBox->append(m_sNewMenuEntryId,
1748 SvxConfigPageHelper::stripHotKey(pNewEntryData->GetName()));
1749 m_xMenuListBox->select(m_xMenuListBox->n_children() - 1);
1751 if (mpEntries)
1752 mpEntries->push_back(pNewEntryData);
1754 m_xMenuNameEdit->set_text(newname);
1755 m_xMenuNameEdit->connect_changed(LINK(this, SvxMainMenuOrganizerDialog, ModifyHdl));
1757 else
1759 // hide name label and textfield
1760 m_xMenuBox->hide();
1761 // change the title
1762 m_xDialog->set_title(CuiResId(RID_SVXSTR_MOVE_MENU));
1765 m_xMenuListBox->connect_changed(LINK(this, SvxMainMenuOrganizerDialog, SelectHdl));
1767 m_xMoveUpButton->connect_clicked(LINK( this, SvxMainMenuOrganizerDialog, MoveHdl));
1768 m_xMoveDownButton->connect_clicked(LINK( this, SvxMainMenuOrganizerDialog, MoveHdl));
1770 UpdateButtonStates();
1773 SvxMainMenuOrganizerDialog::~SvxMainMenuOrganizerDialog()
1777 IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog, ModifyHdl, weld::Entry&, void)
1779 // if the Edit control is empty do not change the name
1780 if (m_xMenuNameEdit->get_text().isEmpty())
1782 return;
1785 SvxConfigEntry* pNewEntryData = reinterpret_cast<SvxConfigEntry*>(m_sNewMenuEntryId.toUInt64());
1786 pNewEntryData->SetName(m_xMenuNameEdit->get_text());
1788 const int nNewMenuPos = m_xMenuListBox->find_id(m_sNewMenuEntryId);
1789 const int nOldSelection = m_xMenuListBox->get_selected_index();
1790 m_xMenuListBox->remove(nNewMenuPos);
1791 m_xMenuListBox->insert(nNewMenuPos, pNewEntryData->GetName(), &m_sNewMenuEntryId, nullptr, nullptr);
1792 m_xMenuListBox->select(nOldSelection);
1795 IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog, SelectHdl, weld::TreeView&, void)
1797 UpdateButtonStates();
1800 void SvxMainMenuOrganizerDialog::UpdateButtonStates()
1802 // Disable Up and Down buttons depending on current selection
1803 const int nSelected = m_xMenuListBox->get_selected_index();
1804 m_xMoveUpButton->set_sensitive(nSelected > 0);
1805 m_xMoveDownButton->set_sensitive(nSelected != -1 && nSelected < m_xMenuListBox->n_children() - 1);
1808 IMPL_LINK( SvxMainMenuOrganizerDialog, MoveHdl, weld::Button&, rButton, void )
1810 int nSourceEntry = m_xMenuListBox->get_selected_index();
1811 if (nSourceEntry == -1)
1812 return;
1814 int nTargetEntry;
1816 if (&rButton == m_xMoveDownButton.get())
1818 nTargetEntry = nSourceEntry + 1;
1820 else
1822 // Move Up is just a Move Down with the source and target reversed
1823 nTargetEntry = nSourceEntry - 1;
1826 OUString sId = m_xMenuListBox->get_id(nSourceEntry);
1827 OUString sEntry = m_xMenuListBox->get_text(nSourceEntry);
1828 m_xMenuListBox->remove(nSourceEntry);
1829 m_xMenuListBox->insert(nTargetEntry, sEntry, &sId, nullptr, nullptr);
1830 m_xMenuListBox->select(nTargetEntry);
1832 std::swap(mpEntries->at(nSourceEntry), mpEntries->at(nTargetEntry));
1834 UpdateButtonStates();
1837 SvxConfigEntry* SvxMainMenuOrganizerDialog::GetSelectedEntry()
1839 const int nSelected(m_xMenuListBox->get_selected_index());
1840 if (nSelected == -1)
1841 return nullptr;
1842 return reinterpret_cast<SvxConfigEntry*>(m_xMenuListBox->get_id(nSelected).toUInt64());
1845 SvxConfigEntry::SvxConfigEntry( const OUString& rDisplayName,
1846 const OUString& rCommandURL, bool bPopup, bool bParentData )
1847 : nId( 1 )
1848 , aLabel(rDisplayName)
1849 , aCommand(rCommandURL)
1850 , bPopUp(bPopup)
1851 , bStrEdited( false )
1852 , bIsUserDefined( false )
1853 , bIsMain( false )
1854 , bIsParentData( bParentData )
1855 , bIsModified( false )
1856 , bIsVisible( true )
1857 , nStyle( 0 )
1859 if (bPopUp)
1861 mpEntries.reset( new SvxEntries );
1865 SvxConfigEntry::~SvxConfigEntry()
1867 if (mpEntries)
1869 for (auto const& entry : *mpEntries)
1871 delete entry;
1876 bool SvxConfigEntry::IsMovable() const
1878 return !IsPopup() || IsMain();
1881 bool SvxConfigEntry::IsDeletable() const
1883 return !IsMain() || IsUserDefined();
1886 bool SvxConfigEntry::IsRenamable() const
1888 return !IsMain() || IsUserDefined();
1891 ToolbarSaveInData::ToolbarSaveInData(
1892 const uno::Reference < css::ui::XUIConfigurationManager >& xCfgMgr,
1893 const uno::Reference < css::ui::XUIConfigurationManager >& xParentCfgMgr,
1894 const OUString& aModuleId,
1895 bool docConfig ) :
1897 SaveInData ( xCfgMgr, xParentCfgMgr, aModuleId, docConfig ),
1898 m_aDescriptorContainer ( ITEM_DESCRIPTOR_CONTAINER )
1901 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
1902 // Initialize the m_xPersistentWindowState variable which is used
1903 // to get the default properties of system toolbars such as name
1904 uno::Reference< container::XNameAccess > xPWSS = css::ui::theWindowStateConfiguration::get( xContext );
1906 xPWSS->getByName( aModuleId ) >>= m_xPersistentWindowState;
1909 ToolbarSaveInData::~ToolbarSaveInData()
1913 sal_Int32 ToolbarSaveInData::GetSystemStyle( const OUString& rResourceURL )
1915 sal_Int32 result = 0;
1917 if ( rResourceURL.startsWith( "private" ) &&
1918 m_xPersistentWindowState.is() &&
1919 m_xPersistentWindowState->hasByName( rResourceURL ) )
1923 uno::Sequence< beans::PropertyValue > aProps;
1924 uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
1926 if ( a >>= aProps )
1928 for ( sal_Int32 i = 0; i < aProps.getLength(); ++i )
1930 if ( aProps[ i ].Name == ITEM_DESCRIPTOR_STYLE )
1932 aProps[i].Value >>= result;
1933 break;
1938 catch ( uno::Exception& )
1940 // do nothing, a default value is returned
1944 return result;
1947 void ToolbarSaveInData::SetSystemStyle(
1948 const uno::Reference< frame::XFrame >& xFrame,
1949 const OUString& rResourceURL,
1950 sal_Int32 nStyle )
1952 // change the style using the API
1953 SetSystemStyle( rResourceURL, nStyle );
1955 // this code is a temporary hack as the UI is not updating after
1956 // changing the toolbar style via the API
1957 uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1958 vcl::Window *window = nullptr;
1960 uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
1961 if ( xPropSet.is() )
1963 uno::Any a = xPropSet->getPropertyValue( "LayoutManager" );
1964 a >>= xLayoutManager;
1967 if ( xLayoutManager.is() )
1969 uno::Reference< css::ui::XUIElement > xUIElement =
1970 xLayoutManager->getElement( rResourceURL );
1972 // check reference before we call getRealInterface. The layout manager
1973 // can only provide references for elements that have been created
1974 // before. It's possible that the current element is not available.
1975 uno::Reference< css::awt::XWindow > xWindow;
1976 if ( xUIElement.is() )
1977 xWindow.set( xUIElement->getRealInterface(), uno::UNO_QUERY );
1979 window = VCLUnoHelper::GetWindow( xWindow ).get();
1982 if ( window != nullptr && window->GetType() == WindowType::TOOLBOX )
1984 ToolBox* toolbox = static_cast<ToolBox*>(window);
1986 if ( nStyle == 0 )
1988 toolbox->SetButtonType( ButtonType::SYMBOLONLY );
1990 else if ( nStyle == 1 )
1992 toolbox->SetButtonType( ButtonType::TEXT );
1994 if ( nStyle == 2 )
1996 toolbox->SetButtonType( ButtonType::SYMBOLTEXT );
2001 void ToolbarSaveInData::SetSystemStyle(
2002 const OUString& rResourceURL,
2003 sal_Int32 nStyle )
2005 if ( rResourceURL.startsWith( "private" ) &&
2006 m_xPersistentWindowState.is() &&
2007 m_xPersistentWindowState->hasByName( rResourceURL ) )
2011 uno::Sequence< beans::PropertyValue > aProps;
2013 uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
2015 if ( a >>= aProps )
2017 for ( sal_Int32 i = 0; i < aProps.getLength(); ++i )
2019 if ( aProps[ i ].Name == ITEM_DESCRIPTOR_STYLE )
2021 aProps[ i ].Value <<= nStyle;
2022 break;
2027 uno::Reference< container::XNameReplace >
2028 xNameReplace( m_xPersistentWindowState, uno::UNO_QUERY );
2030 xNameReplace->replaceByName( rResourceURL, uno::Any( aProps ) );
2032 catch ( uno::Exception& )
2034 // do nothing, a default value is returned
2035 SAL_WARN("cui.customize", "Exception setting toolbar style");
2040 OUString ToolbarSaveInData::GetSystemUIName( const OUString& rResourceURL )
2042 OUString result;
2044 if ( rResourceURL.startsWith( "private" ) &&
2045 m_xPersistentWindowState.is() &&
2046 m_xPersistentWindowState->hasByName( rResourceURL ) )
2050 uno::Sequence< beans::PropertyValue > aProps;
2051 uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
2053 if ( a >>= aProps )
2055 for ( sal_Int32 i = 0; i < aProps.getLength(); ++i )
2057 if ( aProps[ i ].Name == ITEM_DESCRIPTOR_UINAME )
2059 aProps[ i ].Value >>= result;
2064 catch ( uno::Exception& )
2066 // do nothing, an empty UIName will be returned
2070 if ( rResourceURL.startsWith( ".uno" ) &&
2071 m_xCommandToLabelMap.is() &&
2072 m_xCommandToLabelMap->hasByName( rResourceURL ) )
2074 uno::Any a;
2077 a = m_xCommandToLabelMap->getByName( rResourceURL );
2079 uno::Sequence< beans::PropertyValue > aPropSeq;
2080 if ( a >>= aPropSeq )
2082 for ( sal_Int32 i = 0; i < aPropSeq.getLength(); ++i )
2084 if ( aPropSeq[i].Name == ITEM_DESCRIPTOR_LABEL )
2086 aPropSeq[i].Value >>= result;
2091 catch ( uno::Exception& )
2093 // not a system command name
2097 return result;
2100 SvxEntries* ToolbarSaveInData::GetEntries()
2102 typedef std::unordered_map<OUString, bool > ToolbarInfo;
2104 ToolbarInfo aToolbarInfo;
2106 if ( pRootEntry == nullptr )
2109 pRootEntry.reset( new SvxConfigEntry( "MainToolbars", OUString(), true, /*bParentData*/false) );
2111 uno::Sequence< uno::Sequence < beans::PropertyValue > > info =
2112 GetConfigManager()->getUIElementsInfo(
2113 css::ui::UIElementType::TOOLBAR );
2115 for ( sal_Int32 i = 0; i < info.getLength(); ++i )
2117 uno::Sequence< beans::PropertyValue > props = info[ i ];
2119 OUString url;
2120 OUString systemname;
2121 OUString uiname;
2123 for ( sal_Int32 j = 0; j < props.getLength(); ++j )
2125 if ( props[ j ].Name == ITEM_DESCRIPTOR_RESOURCEURL )
2127 props[ j ].Value >>= url;
2128 systemname = url.copy( url.lastIndexOf( '/' ) + 1 );
2130 else if ( props[ j ].Name == ITEM_DESCRIPTOR_UINAME )
2132 props[ j ].Value >>= uiname;
2138 uno::Reference< container::XIndexAccess > xToolbarSettings =
2139 GetConfigManager()->getSettings( url, false );
2141 if ( uiname.isEmpty() )
2143 // try to get the name from m_xPersistentWindowState
2144 uiname = GetSystemUIName( url );
2146 if ( uiname.isEmpty() )
2148 uiname = systemname;
2152 SvxConfigEntry* pEntry = new SvxConfigEntry(
2153 uiname, url, true, /*bParentData*/false );
2155 pEntry->SetMain();
2156 pEntry->SetStyle( GetSystemStyle( url ) );
2159 // insert into std::unordered_map to filter duplicates from the parent
2160 aToolbarInfo.emplace( systemname, true );
2162 OUString custom(CUSTOM_TOOLBAR_STR);
2163 if ( systemname.startsWith( custom ) )
2165 pEntry->SetUserDefined();
2167 else
2169 pEntry->SetUserDefined( false );
2172 pRootEntry->GetEntries()->push_back( pEntry );
2174 LoadToolbar( xToolbarSettings, pEntry );
2176 catch ( container::NoSuchElementException& )
2178 // TODO, handle resourceURL with no settings
2182 uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr = GetParentConfigManager();
2183 if ( xParentCfgMgr.is() )
2185 // Retrieve also the parent toolbars to make it possible
2186 // to configure module toolbars and save them into the document
2187 // config manager.
2188 uno::Sequence< uno::Sequence < beans::PropertyValue > > info_ =
2189 xParentCfgMgr->getUIElementsInfo(
2190 css::ui::UIElementType::TOOLBAR );
2192 for ( sal_Int32 i = 0; i < info_.getLength(); ++i )
2194 uno::Sequence< beans::PropertyValue > props = info_[ i ];
2196 OUString url;
2197 OUString systemname;
2198 OUString uiname;
2200 for ( sal_Int32 j = 0; j < props.getLength(); ++j )
2202 if ( props[ j ].Name == ITEM_DESCRIPTOR_RESOURCEURL )
2204 props[ j ].Value >>= url;
2205 systemname = url.copy( url.lastIndexOf( '/' ) + 1 );
2207 else if ( props[ j ].Name == ITEM_DESCRIPTOR_UINAME )
2209 props[ j ].Value >>= uiname;
2213 // custom toolbars of the parent are not visible in the document layer
2214 OUString custom(CUSTOM_TOOLBAR_STR);
2215 if ( systemname.startsWith( custom ) )
2216 continue;
2218 // check if toolbar is already in the document layer
2219 ToolbarInfo::const_iterator pIter = aToolbarInfo.find( systemname );
2220 if ( pIter == aToolbarInfo.end() )
2222 aToolbarInfo.emplace( systemname, true );
2226 uno::Reference< container::XIndexAccess > xToolbarSettings =
2227 xParentCfgMgr->getSettings( url, false );
2229 if ( uiname.isEmpty() )
2231 // try to get the name from m_xPersistentWindowState
2232 uiname = GetSystemUIName( url );
2234 if ( uiname.isEmpty() )
2236 uiname = systemname;
2240 SvxConfigEntry* pEntry = new SvxConfigEntry(
2241 uiname, url, true, true );
2243 pEntry->SetMain();
2244 pEntry->SetStyle( GetSystemStyle( url ) );
2246 if ( systemname.startsWith( custom ) )
2248 pEntry->SetUserDefined();
2250 else
2252 pEntry->SetUserDefined( false );
2255 pRootEntry->GetEntries()->push_back( pEntry );
2257 LoadToolbar( xToolbarSettings, pEntry );
2259 catch ( container::NoSuchElementException& )
2261 // TODO, handle resourceURL with no settings
2267 std::sort( GetEntries()->begin(), GetEntries()->end(), SvxConfigPageHelper::EntrySort );
2270 return pRootEntry->GetEntries();
2273 void
2274 ToolbarSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
2276 pRootEntry->SetEntries( std::move(pNewEntries) );
2279 bool
2280 ToolbarSaveInData::HasURL( const OUString& rURL )
2282 for (auto const& entry : *GetEntries())
2284 if (entry->GetCommand() == rURL)
2286 return !entry->IsParentData();
2289 return false;
2292 bool ToolbarSaveInData::HasSettings()
2294 // return true if there is at least one toolbar entry
2295 return !GetEntries()->empty();
2298 void ToolbarSaveInData::Reset()
2300 // reset each toolbar by calling removeSettings for its toolbar URL
2301 for (auto const& entry : *GetEntries())
2305 const OUString& url = entry->GetCommand();
2306 GetConfigManager()->removeSettings( url );
2308 catch ( uno::Exception& )
2310 // error occurred removing the settings
2311 // TODO - add error dialog in future?
2315 // persist changes to toolbar storage
2316 PersistChanges( GetConfigManager() );
2318 // now delete the root SvxConfigEntry the next call to GetEntries()
2319 // causes it to be reinitialised
2320 pRootEntry.reset();
2322 // reset all icons to default
2325 GetImageManager()->reset();
2326 PersistChanges( GetImageManager() );
2328 catch ( uno::Exception& )
2330 SAL_WARN("cui.customize", "Error resetting all icons when resetting toolbars");
2334 bool ToolbarSaveInData::Apply()
2336 // toolbar changes are instantly applied
2337 return false;
2340 void ToolbarSaveInData::ApplyToolbar(
2341 uno::Reference< container::XIndexContainer > const & rToolbarBar,
2342 uno::Reference< lang::XSingleComponentFactory >& rFactory,
2343 SvxConfigEntry const * pToolbarData )
2345 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
2347 for (auto const& entry : *pToolbarData->GetEntries())
2349 if (entry->IsPopup())
2351 uno::Sequence< beans::PropertyValue > aPropValueSeq =
2352 SvxConfigPageHelper::ConvertToolbarEntry(entry);
2354 uno::Reference< container::XIndexContainer > xSubMenuBar(
2355 rFactory->createInstanceWithContext( xContext ),
2356 uno::UNO_QUERY );
2358 sal_Int32 nIndex = aPropValueSeq.getLength();
2359 aPropValueSeq.realloc( nIndex + 1 );
2360 aPropValueSeq[nIndex].Name = m_aDescriptorContainer;
2361 aPropValueSeq[nIndex].Value <<= xSubMenuBar;
2362 rToolbarBar->insertByIndex(
2363 rToolbarBar->getCount(), uno::Any( aPropValueSeq ));
2365 ApplyToolbar(xSubMenuBar, rFactory, entry);
2367 else if (entry->IsSeparator())
2369 rToolbarBar->insertByIndex(
2370 rToolbarBar->getCount(), uno::Any( m_aSeparatorSeq ));
2372 else
2374 uno::Sequence< beans::PropertyValue > aPropValueSeq =
2375 SvxConfigPageHelper::ConvertToolbarEntry(entry);
2377 rToolbarBar->insertByIndex(
2378 rToolbarBar->getCount(), uno::Any( aPropValueSeq ));
2383 void ToolbarSaveInData::ApplyToolbar( SvxConfigEntry* pToolbar )
2385 // Apply new toolbar structure to our settings container
2386 uno::Reference< container::XIndexAccess > xSettings =
2387 GetConfigManager()->createSettings();
2389 uno::Reference< container::XIndexContainer > xIndexContainer (
2390 xSettings, uno::UNO_QUERY );
2392 uno::Reference< lang::XSingleComponentFactory > xFactory (
2393 xSettings, uno::UNO_QUERY );
2395 ApplyToolbar( xIndexContainer, xFactory, pToolbar );
2397 uno::Reference< beans::XPropertySet > xProps(
2398 xSettings, uno::UNO_QUERY );
2400 if ( pToolbar->IsUserDefined() )
2402 xProps->setPropertyValue(
2403 ITEM_DESCRIPTOR_UINAME,
2404 uno::Any( pToolbar->GetName() ) );
2409 if ( GetConfigManager()->hasSettings( pToolbar->GetCommand() ) )
2411 GetConfigManager()->replaceSettings(
2412 pToolbar->GetCommand(), xSettings );
2414 else
2416 GetConfigManager()->insertSettings(
2417 pToolbar->GetCommand(), xSettings );
2418 if ( pToolbar->IsParentData() )
2419 pToolbar->SetParentData( false );
2422 catch ( css::uno::Exception const & )
2424 TOOLS_WARN_EXCEPTION("cui.customize", "caught exception saving settings");
2427 PersistChanges( GetConfigManager() );
2430 void ToolbarSaveInData::CreateToolbar( SvxConfigEntry* pToolbar )
2432 // show the new toolbar in the UI also
2433 uno::Reference< container::XIndexAccess >
2434 xSettings = GetConfigManager()->createSettings();
2436 uno::Reference< beans::XPropertySet >
2437 xPropertySet( xSettings, uno::UNO_QUERY );
2439 xPropertySet->setPropertyValue(
2440 ITEM_DESCRIPTOR_UINAME,
2441 uno::Any( pToolbar->GetName() ) );
2445 GetConfigManager()->insertSettings( pToolbar->GetCommand(), xSettings );
2447 catch ( css::uno::Exception const & )
2449 TOOLS_WARN_EXCEPTION("cui.customize", "caught exception saving settings");
2452 GetEntries()->push_back( pToolbar );
2454 PersistChanges( GetConfigManager() );
2457 void ToolbarSaveInData::RemoveToolbar( SvxConfigEntry* pToolbar )
2461 OUString url = pToolbar->GetCommand();
2462 GetConfigManager()->removeSettings( url );
2463 SvxConfigPageHelper::RemoveEntry( GetEntries(), pToolbar );
2464 delete pToolbar;
2466 PersistChanges( GetConfigManager() );
2468 // remove the persistent window state data
2469 css::uno::Reference< css::container::XNameContainer > xNameContainer(
2470 m_xPersistentWindowState, css::uno::UNO_QUERY_THROW );
2472 xNameContainer->removeByName( url );
2474 catch ( uno::Exception& )
2476 // error occurred removing the settings
2480 void ToolbarSaveInData::RestoreToolbar( SvxConfigEntry* pToolbar )
2482 OUString url = pToolbar->GetCommand();
2484 // Restore of toolbar is done by removing it from
2485 // its configuration manager and then getting it again
2486 bool bParentToolbar = pToolbar->IsParentData();
2488 // Cannot restore parent toolbar
2489 if ( bParentToolbar )
2490 return;
2494 GetConfigManager()->removeSettings( url );
2495 pToolbar->GetEntries()->clear();
2496 PersistChanges( GetConfigManager() );
2498 catch ( uno::Exception& )
2500 // if an error occurs removing the settings then just return
2501 return;
2504 // Now reload the toolbar settings
2507 uno::Reference< container::XIndexAccess > xToolbarSettings;
2508 if ( IsDocConfig() )
2510 xToolbarSettings = GetParentConfigManager()->getSettings( url, false );
2511 pToolbar->SetParentData();
2513 else
2514 xToolbarSettings = GetConfigManager()->getSettings( url, false );
2516 LoadToolbar( xToolbarSettings, pToolbar );
2518 // After reloading, ensure that the icon is reset of each entry
2519 // in the toolbar
2520 uno::Sequence< OUString > aURLSeq( 1 );
2521 for (auto const& entry : *pToolbar->GetEntries())
2523 aURLSeq[ 0 ] = entry->GetCommand();
2527 GetImageManager()->removeImages( SvxConfigPageHelper::GetImageType(), aURLSeq );
2529 catch ( uno::Exception& )
2531 SAL_WARN("cui.customize", "Error restoring icon when resetting toolbar");
2534 PersistChanges( GetImageManager() );
2536 catch ( container::NoSuchElementException& )
2538 // cannot find the resource URL after removing it
2539 // so no entry will appear in the toolbar list
2543 void ToolbarSaveInData::LoadToolbar(
2544 const uno::Reference< container::XIndexAccess >& xToolbarSettings,
2545 SvxConfigEntry const * pParentData )
2547 SvxEntries* pEntries = pParentData->GetEntries();
2549 for ( sal_Int32 nIndex = 0; nIndex < xToolbarSettings->getCount(); ++nIndex )
2551 OUString aCommandURL;
2552 OUString aLabel;
2553 bool bIsVisible;
2554 sal_Int32 nStyle;
2556 sal_uInt16 nType( css::ui::ItemType::DEFAULT );
2558 bool bItem = SvxConfigPageHelper::GetToolbarItemData( xToolbarSettings, nIndex, aCommandURL,
2559 aLabel, nType, bIsVisible, nStyle );
2561 if ( bItem )
2563 bool bIsUserDefined = true;
2565 if ( nType == css::ui::ItemType::DEFAULT )
2567 uno::Any a;
2570 a = m_xCommandToLabelMap->getByName( aCommandURL );
2571 bIsUserDefined = false;
2573 catch ( container::NoSuchElementException& )
2575 bIsUserDefined = true;
2578 bool bUseDefaultLabel = false;
2579 // If custom label not set retrieve it from the command
2580 // to info service
2581 if ( aLabel.isEmpty() )
2583 bUseDefaultLabel = true;
2584 uno::Sequence< beans::PropertyValue > aPropSeq;
2585 if ( a >>= aPropSeq )
2587 for ( sal_Int32 i = 0; i < aPropSeq.getLength(); ++i )
2589 if ( aPropSeq[i].Name == "Name" )
2591 aPropSeq[i].Value >>= aLabel;
2592 break;
2598 SvxConfigEntry* pEntry = new SvxConfigEntry(
2599 aLabel, aCommandURL, false, /*bParentData*/false );
2601 pEntry->SetUserDefined( bIsUserDefined );
2602 pEntry->SetVisible( bIsVisible );
2603 pEntry->SetStyle( nStyle );
2605 if ( !bUseDefaultLabel )
2606 pEntry->SetName( aLabel );
2608 pEntries->push_back( pEntry );
2610 else
2612 SvxConfigEntry* pEntry = new SvxConfigEntry;
2613 pEntry->SetUserDefined( bIsUserDefined );
2614 pEntries->push_back( pEntry );
2620 SvxNewToolbarDialog::SvxNewToolbarDialog(weld::Window* pWindow, const OUString& rName)
2621 : GenericDialogController(pWindow, "cui/ui/newtoolbardialog.ui", "NewToolbarDialog")
2622 , m_xEdtName(m_xBuilder->weld_entry("edit"))
2623 , m_xBtnOK(m_xBuilder->weld_button("ok"))
2624 , m_xSaveInListBox(m_xBuilder->weld_combo_box("savein"))
2626 m_xEdtName->set_text(rName);
2627 m_xEdtName->select_region(0, -1);
2630 SvxNewToolbarDialog::~SvxNewToolbarDialog()
2634 /*******************************************************************************
2636 * The SvxIconSelectorDialog class
2638 *******************************************************************************/
2639 SvxIconSelectorDialog::SvxIconSelectorDialog(weld::Window *pWindow,
2640 const uno::Reference< css::ui::XImageManager >& rXImageManager,
2641 const uno::Reference< css::ui::XImageManager >& rXParentImageManager)
2642 : GenericDialogController(pWindow, "cui/ui/iconselectordialog.ui", "IconSelector")
2643 , m_xImageManager(rXImageManager)
2644 , m_xParentImageManager(rXParentImageManager)
2645 , m_xTbSymbol(new SvtValueSet(m_xBuilder->weld_scrolled_window("symbolswin")))
2646 , m_xTbSymbolWin(new weld::CustomWeld(*m_xBuilder, "symbolsToolbar", *m_xTbSymbol))
2647 , m_xFtNote(m_xBuilder->weld_label("noteLabel"))
2648 , m_xBtnImport(m_xBuilder->weld_button("importButton"))
2649 , m_xBtnDelete(m_xBuilder->weld_button("deleteButton"))
2651 typedef std::unordered_map< OUString, bool > ImageInfo;
2653 m_nExpectedSize = 16;
2654 if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_LARGE)
2655 m_nExpectedSize = 24;
2656 else if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_32)
2657 m_nExpectedSize = 32;
2659 if ( m_nExpectedSize != 16 )
2661 m_xFtNote->set_label(SvxConfigPageHelper::replaceSixteen(m_xFtNote->get_label(), m_nExpectedSize));
2664 m_xTbSymbol->SetStyle(m_xTbSymbol->GetStyle() | WB_ITEMBORDER | WB_VSCROLL);
2665 m_xTbSymbol->SetColCount(11);
2666 m_xTbSymbol->SetLineCount(5);
2667 m_xTbSymbol->SetItemWidth(m_nExpectedSize);
2668 m_xTbSymbol->SetItemHeight(m_nExpectedSize);
2669 m_xTbSymbol->SetExtraSpacing(6);
2670 Size aSize(m_xTbSymbol->CalcWindowSizePixel(Size(m_nExpectedSize, m_nExpectedSize), 11, 5));
2671 m_xTbSymbol->set_size_request(aSize.Width(), aSize.Height());
2673 uno::Reference< uno::XComponentContext > xComponentContext =
2674 ::comphelper::getProcessComponentContext();
2676 m_xGraphProvider.set( graphic::GraphicProvider::create( xComponentContext ) );
2678 uno::Reference< css::util::XPathSettings > xPathSettings =
2679 css::util::thePathSettings::get( xComponentContext );
2682 OUString aDirectory = xPathSettings->getUserConfig();
2684 sal_Int32 aCount = aDirectory.getLength();
2686 if ( aCount > 0 )
2688 sal_Unicode aChar = aDirectory[ aCount-1 ];
2689 if ( aChar != '/')
2691 aDirectory += "/";
2694 else
2696 m_xBtnImport->set_sensitive(false);
2699 aDirectory += "soffice.cfg/import";
2701 uno::Reference< lang::XSingleServiceFactory > xStorageFactory(
2702 css::embed::FileSystemStorageFactory::create( xComponentContext ) );
2704 uno::Sequence< uno::Any > aArgs( 2 );
2705 aArgs[ 0 ] <<= aDirectory;
2706 aArgs[ 1 ] <<= css::embed::ElementModes::READWRITE;
2708 uno::Reference< css::embed::XStorage > xStorage(
2709 xStorageFactory->createInstanceWithArguments( aArgs ), uno::UNO_QUERY );
2711 uno::Sequence<uno::Any> aProp(comphelper::InitAnyPropertySequence(
2713 {"UserConfigStorage", uno::Any(xStorage)},
2714 {"OpenMode", uno::Any(css::embed::ElementModes::READWRITE)}
2715 }));
2716 m_xImportedImageManager = css::ui::ImageManager::create( xComponentContext );
2717 m_xImportedImageManager->initialize(aProp);
2719 ImageInfo aImageInfo1;
2720 uno::Sequence< OUString > names;
2721 if ( m_xImportedImageManager.is() )
2723 names = m_xImportedImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2724 for ( sal_Int32 n = 0; n < names.getLength(); ++n )
2725 aImageInfo1.emplace( names[n], false );
2728 uno::Sequence< OUString > name( 1 );
2729 for (auto const& elem : aImageInfo1)
2731 name[ 0 ] = elem.first;
2732 uno::Sequence< uno::Reference< graphic::XGraphic> > graphics = m_xImportedImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2733 if ( graphics.hasElements() )
2735 m_aGraphics.push_back(graphics[0]);
2736 Image img(graphics[0]);
2737 m_xTbSymbol->InsertItem(m_aGraphics.size(), img, elem.first);
2741 ImageInfo aImageInfo;
2743 if ( m_xParentImageManager.is() )
2745 names = m_xParentImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2746 for ( sal_Int32 n = 0; n < names.getLength(); ++n )
2747 aImageInfo.emplace( names[n], false );
2750 names = m_xImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2751 for ( sal_Int32 n = 0; n < names.getLength(); ++n )
2753 ImageInfo::iterator pIter = aImageInfo.find( names[n] );
2754 if ( pIter != aImageInfo.end() )
2755 pIter->second = true;
2756 else
2757 aImageInfo.emplace( names[n], true );
2760 // large growth factor, expecting many entries
2761 for (auto const& elem : aImageInfo)
2763 name[ 0 ] = elem.first;
2765 uno::Sequence< uno::Reference< graphic::XGraphic> > graphics;
2768 if (elem.second)
2769 graphics = m_xImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2770 else
2771 graphics = m_xParentImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2773 catch ( uno::Exception& )
2775 // can't get sequence for this name so it will not be
2776 // added to the list
2779 if ( graphics.hasElements() )
2781 Image img(graphics[0]);
2782 if (!img.GetBitmapEx().IsEmpty())
2784 m_aGraphics.push_back(graphics[0]);
2785 m_xTbSymbol->InsertItem(m_aGraphics.size(), img, elem.first);
2790 m_xBtnDelete->set_sensitive( false );
2791 m_xTbSymbol->SetSelectHdl( LINK(this, SvxIconSelectorDialog, SelectHdl) );
2792 m_xBtnImport->connect_clicked( LINK(this, SvxIconSelectorDialog, ImportHdl) );
2793 m_xBtnDelete->connect_clicked( LINK(this, SvxIconSelectorDialog, DeleteHdl) );
2796 SvxIconSelectorDialog::~SvxIconSelectorDialog()
2800 uno::Reference< graphic::XGraphic> SvxIconSelectorDialog::GetSelectedIcon()
2802 uno::Reference<graphic::XGraphic> result;
2804 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2806 if (nId)
2808 result = m_aGraphics[nId - 1];
2811 return result;
2814 IMPL_LINK_NOARG(SvxIconSelectorDialog, SelectHdl, SvtValueSet*, void)
2816 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2818 if (!nId)
2820 m_xBtnDelete->set_sensitive(false);
2821 return;
2824 OUString aSelImageText = m_xTbSymbol->GetItemText(nId);
2825 if (m_xImportedImageManager->hasImage(SvxConfigPageHelper::GetImageType(), aSelImageText))
2827 m_xBtnDelete->set_sensitive(true);
2829 else
2831 m_xBtnDelete->set_sensitive(false);
2835 IMPL_LINK_NOARG(SvxIconSelectorDialog, ImportHdl, weld::Button&, void)
2837 sfx2::FileDialogHelper aImportDialog(
2838 css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW,
2839 FileDialogFlags::Graphic | FileDialogFlags::MultiSelection, m_xDialog.get());
2841 // disable the link checkbox in the dialog
2842 uno::Reference< css::ui::dialogs::XFilePickerControlAccess >
2843 xController( aImportDialog.GetFilePicker(), uno::UNO_QUERY);
2844 if ( xController.is() )
2846 xController->enableControl(
2847 css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK,
2848 false);
2851 aImportDialog.SetCurrentFilter(
2852 "PNG - Portable Network Graphic");
2854 if ( ERRCODE_NONE == aImportDialog.Execute() )
2856 uno::Sequence< OUString > paths = aImportDialog.GetMPath();
2857 ImportGraphics ( paths );
2861 IMPL_LINK_NOARG(SvxIconSelectorDialog, DeleteHdl, weld::Button&, void)
2863 OUString message = CuiResId( RID_SVXSTR_DELETE_ICON_CONFIRM );
2865 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xDialog.get(),
2866 VclMessageType::Warning, VclButtonsType::OkCancel,
2867 message));
2868 if (xWarn->run() == RET_OK)
2870 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2872 OUString aSelImageText = m_xTbSymbol->GetItemText( nId );
2873 uno::Sequence< OUString > URLs { aSelImageText };
2874 m_xTbSymbol->RemoveItem(nId);
2875 m_xImportedImageManager->removeImages( SvxConfigPageHelper::GetImageType(), URLs );
2876 if ( m_xImportedImageManager->isModified() )
2878 m_xImportedImageManager->store();
2883 bool SvxIconSelectorDialog::ReplaceGraphicItem(
2884 const OUString& aURL )
2886 uno::Sequence< OUString > URLs(1);
2887 uno::Sequence< uno::Reference<graphic::XGraphic > > aImportGraph( 1 );
2889 uno::Reference< graphic::XGraphic > xGraphic;
2890 uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
2891 aMediaProps[0].Name = "URL";
2892 aMediaProps[0].Value <<= aURL;
2894 css::awt::Size aSize;
2895 bool bOK = false;
2898 xGraphic = m_xGraphProvider->queryGraphic( aMediaProps );
2900 uno::Reference< beans::XPropertySet > props =
2901 m_xGraphProvider->queryGraphicDescriptor( aMediaProps );
2902 uno::Any a = props->getPropertyValue( "SizePixel" );
2903 a >>= aSize;
2904 if (0 == aSize.Width || 0 == aSize.Height)
2905 return false;
2906 else
2907 bOK = true;
2909 catch ( uno::Exception& )
2911 return false;
2914 bool bResult( false );
2915 size_t nCount = m_xTbSymbol->GetItemCount();
2916 for (size_t n = 0; n < nCount; ++n)
2918 sal_uInt16 nId = m_xTbSymbol->GetItemId( n );
2920 if ( m_xTbSymbol->GetItemText( nId ) == aURL )
2924 // replace/insert image with provided URL
2925 size_t nPos = nId - 1;
2926 assert(nPos == m_xTbSymbol->GetItemPos(nId));
2927 m_xTbSymbol->RemoveItem(nId);
2928 aMediaProps[0].Value <<= aURL;
2930 Image aImage( xGraphic );
2931 if ( bOK && ((aSize.Width != m_nExpectedSize) || (aSize.Height != m_nExpectedSize)) )
2933 BitmapEx aBitmap = aImage.GetBitmapEx();
2934 BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, m_nExpectedSize);
2935 aImage = Image( aBitmapex);
2937 m_xTbSymbol->InsertItem(nId, aImage, aURL, nPos); //modify
2939 m_aGraphics[nPos] = Graphic(aImage.GetBitmapEx()).GetXGraphic();
2941 URLs[0] = aURL;
2942 aImportGraph[ 0 ] = xGraphic;
2943 m_xImportedImageManager->replaceImages( SvxConfigPageHelper::GetImageType(), URLs, aImportGraph );
2944 m_xImportedImageManager->store();
2946 bResult = true;
2947 break;
2949 catch ( css::uno::Exception& )
2951 break;
2956 return bResult;
2959 namespace
2961 OUString ReplaceIconName(const OUString& rMessage)
2963 OUString name;
2964 OUString message = CuiResId( RID_SVXSTR_REPLACE_ICON_WARNING );
2965 OUString placeholder("%ICONNAME" );
2966 sal_Int32 pos = message.indexOf( placeholder );
2967 if ( pos != -1 )
2969 name = message.replaceAt(
2970 pos, placeholder.getLength(), rMessage );
2972 return name;
2975 class SvxIconReplacementDialog
2977 private:
2978 std::unique_ptr<weld::MessageDialog> m_xQueryBox;
2979 public:
2980 SvxIconReplacementDialog(weld::Window *pParent, const OUString& rMessage, bool bYestoAll)
2981 : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Warning, VclButtonsType::NONE, ReplaceIconName(rMessage)))
2983 m_xQueryBox->set_title(CuiResId(RID_SVXSTR_REPLACE_ICON_CONFIRM));
2984 m_xQueryBox->add_button(GetStandardText(StandardButtonType::Yes), 2);
2985 if (bYestoAll)
2986 m_xQueryBox->add_button(CuiResId(RID_SVXSTR_YESTOALL), 5);
2987 m_xQueryBox->add_button(GetStandardText(StandardButtonType::No), 4);
2988 m_xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), 6);
2989 m_xQueryBox->set_default_response(2);
2991 short run() { return m_xQueryBox->run(); }
2995 void SvxIconSelectorDialog::ImportGraphics(
2996 const uno::Sequence< OUString >& rPaths )
2998 uno::Sequence< OUString > rejected( rPaths.getLength() );
2999 sal_Int32 rejectedCount = 0;
3001 sal_uInt16 ret = 0;
3002 sal_Int32 aIndex;
3003 OUString aIconName;
3005 if ( rPaths.getLength() == 1 )
3007 if ( m_xImportedImageManager->hasImage( SvxConfigPageHelper::GetImageType(), rPaths[0] ) )
3009 aIndex = rPaths[0].lastIndexOf( '/' );
3010 aIconName = rPaths[0].copy( aIndex+1 );
3011 SvxIconReplacementDialog aDlg(m_xDialog.get(), aIconName, false);
3012 ret = aDlg.run();
3013 if ( ret == 2 )
3015 ReplaceGraphicItem( rPaths[0] );
3018 else
3020 if ( !ImportGraphic( rPaths[0] ) )
3022 rejected[0] = rPaths[0];
3023 rejectedCount = 1;
3027 else
3029 OUString aSourcePath( rPaths[0] );
3030 if ( rPaths[0].lastIndexOf( '/' ) != rPaths[0].getLength() -1 )
3031 aSourcePath = rPaths[0] + "/";
3033 for ( sal_Int32 i = 1; i < rPaths.getLength(); ++i )
3035 OUString aPath = aSourcePath + rPaths[i];
3036 if ( m_xImportedImageManager->hasImage( SvxConfigPageHelper::GetImageType(), aPath ) )
3038 aIndex = rPaths[i].lastIndexOf( '/' );
3039 aIconName = rPaths[i].copy( aIndex+1 );
3040 SvxIconReplacementDialog aDlg(m_xDialog.get(), aIconName, true);
3041 ret = aDlg.run();
3042 if ( ret == 2 )
3044 ReplaceGraphicItem( aPath );
3046 else if ( ret == 5 )
3048 for ( sal_Int32 k = i; k < rPaths.getLength(); ++k )
3050 aPath = aSourcePath + rPaths[k];
3051 bool bHasReplaced = ReplaceGraphicItem( aPath );
3053 if ( !bHasReplaced )
3055 bool result = ImportGraphic( aPath );
3056 if ( !result )
3058 rejected[ rejectedCount ] = rPaths[i];
3059 ++rejectedCount;
3063 break;
3066 else
3068 bool result = ImportGraphic( aSourcePath + rPaths[i] );
3069 if ( !result )
3071 rejected[ rejectedCount ] = rPaths[i];
3072 ++rejectedCount;
3078 if ( rejectedCount != 0 )
3080 OUStringBuffer message;
3081 OUString fPath;
3082 if (rejectedCount > 1)
3083 fPath = rPaths[0].copy(8) + "/";
3084 for ( sal_Int32 i = 0; i < rejectedCount; ++i )
3086 message.append(fPath).append(rejected[i]).append("\n");
3089 SvxIconChangeDialog aDialog(m_xDialog.get(), message.makeStringAndClear());
3090 aDialog.run();
3094 bool SvxIconSelectorDialog::ImportGraphic( const OUString& aURL )
3096 bool result = false;
3098 uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
3099 aMediaProps[0].Name = "URL";
3101 uno::Reference< graphic::XGraphic > xGraphic;
3102 css::awt::Size aSize;
3103 aMediaProps[0].Value <<= aURL;
3106 uno::Reference< beans::XPropertySet > props =
3107 m_xGraphProvider->queryGraphicDescriptor( aMediaProps );
3109 uno::Any a = props->getPropertyValue("SizePixel");
3111 xGraphic = m_xGraphProvider->queryGraphic( aMediaProps );
3112 if ( xGraphic.is() )
3114 bool bOK = true;
3116 a >>= aSize;
3117 if ( 0 == aSize.Width || 0 == aSize.Height )
3118 bOK = false;
3120 Image aImage( xGraphic );
3122 if ( bOK && ((aSize.Width != m_nExpectedSize) || (aSize.Height != m_nExpectedSize)) )
3124 BitmapEx aBitmap = aImage.GetBitmapEx();
3125 BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, m_nExpectedSize);
3126 aImage = Image( aBitmapex);
3128 if ( bOK && !!aImage )
3130 m_aGraphics.push_back(Graphic(aImage.GetBitmapEx()).GetXGraphic());
3131 m_xTbSymbol->InsertItem(m_aGraphics.size(), aImage, aURL);
3133 uno::Sequence<OUString> aImportURL { aURL };
3134 uno::Sequence< uno::Reference<graphic::XGraphic > > aImportGraph( 1 );
3135 aImportGraph[ 0 ] = xGraphic;
3136 m_xImportedImageManager->insertImages( SvxConfigPageHelper::GetImageType(), aImportURL, aImportGraph );
3137 if ( m_xImportedImageManager->isModified() )
3139 m_xImportedImageManager->store();
3142 result = true;
3144 else
3146 SAL_WARN("cui.customize", "could not create Image from XGraphic");
3149 else
3151 SAL_WARN("cui.customize", "could not get query XGraphic");
3154 catch( uno::Exception const & )
3156 TOOLS_WARN_EXCEPTION("cui.customize", "Caught exception importing XGraphic");
3158 return result;
3161 /*******************************************************************************
3163 * The SvxIconChangeDialog class added for issue83555
3165 *******************************************************************************/
3166 SvxIconChangeDialog::SvxIconChangeDialog(weld::Window *pWindow, const OUString& rMessage)
3167 : MessageDialogController(pWindow, "cui/ui/iconchangedialog.ui", "IconChange", "grid")
3168 , m_xLineEditDescription(m_xBuilder->weld_text_view("addrTextview"))
3170 m_xLineEditDescription->set_size_request(m_xLineEditDescription->get_approximate_digit_width() * 48,
3171 m_xLineEditDescription->get_text_height() * 8);
3172 m_xLineEditDescription->set_text(rMessage);
3175 SvxConfigPageFunctionDropTarget::SvxConfigPageFunctionDropTarget(SvxConfigPage&rPage, weld::TreeView& rTreeView)
3176 : DropTargetHelper(rTreeView.get_drop_target())
3177 , m_rPage(rPage)
3178 , m_rTreeView(rTreeView)
3182 sal_Int8 SvxConfigPageFunctionDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
3184 // to enable the autoscroll when we're close to the edges
3185 m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, nullptr);
3186 return DND_ACTION_MOVE;
3189 sal_Int8 SvxConfigPageFunctionDropTarget::ExecuteDrop( const ExecuteDropEvent& rEvt )
3191 weld::TreeView* pSource = m_rTreeView.get_drag_source();
3192 // only draging within the same widget allowed
3193 if (!pSource || pSource != &m_rTreeView)
3194 return DND_ACTION_NONE;
3196 std::unique_ptr<weld::TreeIter> xSource(m_rTreeView.make_iterator());
3197 if (!m_rTreeView.get_selected(xSource.get()))
3198 return DND_ACTION_NONE;
3200 std::unique_ptr<weld::TreeIter> xTarget(m_rTreeView.make_iterator());
3201 int nTargetPos = -1;
3202 if (m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get()))
3203 nTargetPos = m_rTreeView.get_iter_index_in_parent(*xTarget);
3204 m_rTreeView.move_subtree(*xSource, nullptr, nTargetPos);
3206 m_rPage.ListModified();
3208 return DND_ACTION_NONE;
3211 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */