bump product version to 6.3.0.0.beta1
[LibreOffice.git] / cui / source / customize / cfg.cxx
blobbf583d4d37a4e2aeb05b4a26aee5226429b6ef74
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 <time.h>
26 #include <typeinfo>
28 #include <vcl/button.hxx>
29 #include <vcl/commandinfoprovider.hxx>
30 #include <vcl/edit.hxx>
31 #include <vcl/event.hxx>
32 #include <vcl/help.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/toolbox.hxx>
35 #include <vcl/weld.hxx>
36 #include <vcl/decoview.hxx>
37 #include <vcl/virdev.hxx>
38 #include <vcl/settings.hxx>
40 #include <sfx2/sfxhelp.hxx>
41 #include <sfx2/app.hxx>
42 #include <sfx2/sfxdlg.hxx>
43 #include <sfx2/viewfrm.hxx>
44 #include <sfx2/viewsh.hxx>
45 #include <sfx2/msg.hxx>
46 #include <sfx2/msgpool.hxx>
47 #include <sfx2/minfitem.hxx>
48 #include <sfx2/objsh.hxx>
49 #include <sfx2/request.hxx>
50 #include <sfx2/filedlghelper.hxx>
51 #include <sfx2/sfxsids.hrc>
52 #include <svl/stritem.hxx>
53 #include <tools/diagnose_ex.h>
54 #include <toolkit/helper/vclunohelper.hxx>
56 #include <algorithm>
57 #include <strings.hrc>
59 #include <acccfg.hxx>
60 #include <cfg.hxx>
61 #include <SvxMenuConfigPage.hxx>
62 #include <SvxToolbarConfigPage.hxx>
63 #include <SvxConfigPageHelper.hxx>
64 #include "eventdlg.hxx"
65 #include <dialmgr.hxx>
67 #include <unotools/configmgr.hxx>
68 #include <com/sun/star/container/XNameContainer.hpp>
69 #include <com/sun/star/embed/ElementModes.hpp>
70 #include <com/sun/star/embed/FileSystemStorageFactory.hpp>
71 #include <com/sun/star/frame/UnknownModuleException.hpp>
72 #include <com/sun/star/frame/XFrames.hpp>
73 #include <com/sun/star/frame/XLayoutManager.hpp>
74 #include <com/sun/star/frame/FrameSearchFlag.hpp>
75 #include <com/sun/star/frame/XController.hpp>
76 #include <com/sun/star/frame/Desktop.hpp>
77 #include <com/sun/star/frame/theUICommandDescription.hpp>
78 #include <com/sun/star/graphic/GraphicProvider.hpp>
79 #include <com/sun/star/io/IOException.hpp>
80 #include <com/sun/star/lang/IllegalAccessException.hpp>
81 #include <com/sun/star/ui/ItemType.hpp>
82 #include <com/sun/star/ui/ItemStyle.hpp>
83 #include <com/sun/star/ui/ImageManager.hpp>
84 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
85 #include <com/sun/star/ui/XUIConfiguration.hpp>
86 #include <com/sun/star/ui/XUIConfigurationListener.hpp>
87 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
88 #include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
89 #include <com/sun/star/ui/XUIConfigurationStorage.hpp>
90 #include <com/sun/star/ui/XModuleUIConfigurationManager.hpp>
91 #include <com/sun/star/ui/XUIElement.hpp>
92 #include <com/sun/star/ui/UIElementType.hpp>
93 #include <com/sun/star/ui/ImageType.hpp>
94 #include <com/sun/star/ui/theWindowStateConfiguration.hpp>
95 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
96 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
97 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
98 #include <com/sun/star/util/thePathSettings.hpp>
99 #include <comphelper/documentinfo.hxx>
100 #include <comphelper/propertysequence.hxx>
101 #include <comphelper/processfactory.hxx>
103 #include <dlgname.hxx>
105 namespace uno = com::sun::star::uno;
106 namespace frame = com::sun::star::frame;
107 namespace lang = com::sun::star::lang;
108 namespace container = com::sun::star::container;
109 namespace beans = com::sun::star::beans;
110 namespace graphic = com::sun::star::graphic;
112 #if OSL_DEBUG_LEVEL > 1
114 void printPropertySet(
115 const OUString& prefix,
116 const uno::Reference< beans::XPropertySet >& xPropSet )
118 uno::Reference< beans::XPropertySetInfo > xPropSetInfo =
119 xPropSet->getPropertySetInfo();
121 uno::Sequence< beans::Property > aPropDetails =
122 xPropSetInfo->getProperties();
124 SAL_WARN("cui", "printPropertySet: " << aPropDetails.getLength() << " properties" );
126 for ( sal_Int32 i = 0; i < aPropDetails.getLength(); ++i )
128 OUString tmp;
129 sal_Int32 ival;
131 uno::Any a = xPropSet->getPropertyValue( aPropDetails[i].Name );
133 if ( a >>= tmp )
135 SAL_WARN("cui", prefix << ": Got property: " << aPropDetails[i].Name << tmp);
137 else if ( ( a >>= ival ) )
139 SAL_WARN("cui", prefix << ": Got property: " << aPropDetails[i].Name << " = " << ival);
141 else
143 SAL_WARN("cui", prefix << ": Got property: " << aPropDetails[i].Name << " of type " << a.getValueTypeName());
148 void printProperties(
149 const OUString& prefix,
150 const uno::Sequence< beans::PropertyValue >& aProp )
152 for ( sal_Int32 i = 0; i < aProp.getLength(); ++i )
154 OUString tmp;
156 aProp[i].Value >>= tmp;
158 SAL_WARN("cui", prefix << ": Got property: " << aProp[i].Name << " = " << tmp);
162 void printEntries(SvxEntries* entries)
164 for (auto const& entry : *entries)
166 SAL_WARN("cui", "printEntries: " << entry->GetName());
170 #endif
172 bool
173 SvxConfigPage::CanConfig( const OUString& aModuleId )
175 return !(aModuleId == "com.sun.star.script.BasicIDE" || aModuleId == "com.sun.star.frame.Bibliography");
178 static VclPtr<SfxTabPage> CreateSvxMenuConfigPage( TabPageParent pParent, const SfxItemSet* rSet )
180 return VclPtr<SvxMenuConfigPage>::Create(pParent, *rSet);
183 static VclPtr<SfxTabPage> CreateSvxContextMenuConfigPage( TabPageParent pParent, const SfxItemSet* rSet )
185 return VclPtr<SvxMenuConfigPage>::Create(pParent, *rSet, false);
188 static VclPtr<SfxTabPage> CreateKeyboardConfigPage( TabPageParent pParent, const SfxItemSet* rSet )
190 return VclPtr<SfxAcceleratorConfigPage>::Create(pParent, *rSet);
193 static VclPtr<SfxTabPage> CreateSvxToolbarConfigPage( TabPageParent pParent, const SfxItemSet* rSet )
195 return VclPtr<SvxToolbarConfigPage>::Create(pParent, *rSet);
198 static VclPtr<SfxTabPage> CreateSvxEventConfigPage( TabPageParent pParent, const SfxItemSet* rSet )
200 return VclPtr<SvxEventConfigPage>::Create(pParent, *rSet, SvxEventConfigPage::EarlyInit());
203 /******************************************************************************
205 * SvxConfigDialog is the configuration dialog which is brought up from the
206 * Tools menu. It includes tabs for customizing menus, toolbars, events and
207 * key bindings.
209 *****************************************************************************/
210 SvxConfigDialog::SvxConfigDialog(weld::Window * pParent, const SfxItemSet* pInSet)
211 : SfxTabDialogController(pParent, "cui/ui/customizedialog.ui", "CustomizeDialog", pInSet)
213 SvxConfigPageHelper::InitImageType();
215 AddTabPage("menus", CreateSvxMenuConfigPage, nullptr);
216 AddTabPage("toolbars", CreateSvxToolbarConfigPage, nullptr);
217 AddTabPage("contextmenus", CreateSvxContextMenuConfigPage, nullptr);
218 AddTabPage("keyboard", CreateKeyboardConfigPage, nullptr);
219 AddTabPage("events", CreateSvxEventConfigPage, nullptr);
221 const SfxPoolItem* pItem =
222 pInSet->GetItem( pInSet->GetPool()->GetWhich( SID_CONFIG ) );
224 if ( pItem )
226 OUString text = static_cast<const SfxStringItem*>(pItem)->GetValue();
228 if (text.startsWith( ITEM_TOOLBAR_URL ) )
230 SetCurPageId("toolbars");
235 void SvxConfigDialog::SetFrame(const css::uno::Reference< css::frame::XFrame >& xFrame)
237 m_xFrame = xFrame;
239 if (!SvxConfigPageHelper::showKeyConfigTabPage( xFrame ))
240 RemoveTabPage("keyboard");
243 void SvxConfigDialog::PageCreated(const OString &rId, SfxTabPage& rPage)
245 if (rId == "menus" || rId == "keyboard" ||
246 rId == "toolbars" || rId == "contextmenus")
248 rPage.SetFrame(m_xFrame);
250 else if (rId == "events")
252 dynamic_cast< SvxEventConfigPage& >( rPage ).LateInit( m_xFrame );
256 /******************************************************************************
258 * The SaveInData class is used to hold data for entries in the Save In
259 * ListBox controls in the menu and toolbar tabs
261 ******************************************************************************/
263 // Initialize static variable which holds default XImageManager
264 uno::Reference< css::ui::XImageManager>* SaveInData::xDefaultImgMgr = nullptr;
266 SaveInData::SaveInData(
267 const uno::Reference< css::ui::XUIConfigurationManager >& xCfgMgr,
268 const uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
269 const OUString& aModuleId,
270 bool isDocConfig )
272 bModified( false ),
273 bDocConfig( isDocConfig ),
274 bReadOnly( false ),
275 m_xCfgMgr( xCfgMgr ),
276 m_xParentCfgMgr( xParentCfgMgr )
278 m_aSeparatorSeq.realloc( 1 );
279 m_aSeparatorSeq[0].Name = ITEM_DESCRIPTOR_TYPE;
280 m_aSeparatorSeq[0].Value <<= css::ui::ItemType::SEPARATOR_LINE;
282 if ( bDocConfig )
284 uno::Reference< css::ui::XUIConfigurationPersistence >
285 xDocPersistence( GetConfigManager(), uno::UNO_QUERY );
287 bReadOnly = xDocPersistence->isReadOnly();
290 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
292 uno::Reference< container::XNameAccess > xNameAccess(
293 css::frame::theUICommandDescription::get(xContext) );
295 xNameAccess->getByName( aModuleId ) >>= m_xCommandToLabelMap;
297 if ( !m_xImgMgr.is() )
299 m_xImgMgr.set( GetConfigManager()->getImageManager(), uno::UNO_QUERY );
302 if ( !IsDocConfig() )
304 // If this is not a document configuration then it is the settings
305 // for the module (writer, calc, impress etc.) Use this as the default
306 // XImageManager instance
307 xDefaultImgMgr = &m_xImgMgr;
309 else
311 // If this is a document configuration then use the module image manager
312 // as default.
313 if ( m_xParentCfgMgr.is() )
315 m_xParentImgMgr.set( m_xParentCfgMgr->getImageManager(), uno::UNO_QUERY );
316 xDefaultImgMgr = &m_xParentImgMgr;
321 uno::Reference<graphic::XGraphic> SaveInData::GetImage(const OUString& rCommandURL)
323 uno::Reference< graphic::XGraphic > xGraphic =
324 SvxConfigPageHelper::GetGraphic( m_xImgMgr, rCommandURL );
326 if (!xGraphic.is() && xDefaultImgMgr != nullptr && (*xDefaultImgMgr).is())
328 xGraphic = SvxConfigPageHelper::GetGraphic( (*xDefaultImgMgr), rCommandURL );
331 return xGraphic;
334 bool SaveInData::PersistChanges(
335 const uno::Reference< uno::XInterface >& xManager )
337 bool result = true;
341 if ( xManager.is() && !IsReadOnly() )
343 uno::Reference< css::ui::XUIConfigurationPersistence >
344 xConfigPersistence( xManager, uno::UNO_QUERY );
346 if ( xConfigPersistence->isModified() )
348 xConfigPersistence->store();
352 catch ( css::io::IOException& )
354 result = false;
357 return result;
360 /******************************************************************************
362 * The MenuSaveInData class extends SaveInData and provides menu specific
363 * load and store functionality.
365 ******************************************************************************/
367 // Initialize static variable which holds default Menu data
368 MenuSaveInData* MenuSaveInData::pDefaultData = nullptr;
370 MenuSaveInData::MenuSaveInData(
371 const uno::Reference< css::ui::XUIConfigurationManager >& cfgmgr,
372 const uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
373 const OUString& aModuleId,
374 bool isDocConfig )
376 SaveInData( cfgmgr, xParentCfgMgr, aModuleId, isDocConfig ),
377 m_aMenuResourceURL(
378 ITEM_MENUBAR_URL ),
379 m_aDescriptorContainer(
380 ITEM_DESCRIPTOR_CONTAINER )
384 OUString url( ITEM_MENUBAR_URL );
385 m_xMenuSettings = GetConfigManager()->getSettings( url, false );
387 catch ( container::NoSuchElementException& )
389 // will use menu settings for the module
392 // If this is not a document configuration then it is the settings
393 // for the module (writer, calc, impress etc.). These settings should
394 // be set as the default to be used for SaveIn locations that do not
395 // have custom settings
396 if ( !IsDocConfig() )
398 SetDefaultData( this );
402 MenuSaveInData::~MenuSaveInData()
406 SvxEntries*
407 MenuSaveInData::GetEntries()
409 if ( pRootEntry == nullptr )
411 pRootEntry.reset( new SvxConfigEntry( "MainMenus", OUString(), true, /*bParentData*/false) );
413 if ( m_xMenuSettings.is() )
415 LoadSubMenus( m_xMenuSettings, OUString(), pRootEntry.get(), false );
417 else if ( GetDefaultData() != nullptr )
419 // If the doc has no config settings use module config settings
420 LoadSubMenus( GetDefaultData()->m_xMenuSettings, OUString(), pRootEntry.get(), false );
424 return pRootEntry->GetEntries();
427 void
428 MenuSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
430 pRootEntry->SetEntries( std::move(pNewEntries) );
433 void SaveInData::LoadSubMenus( const uno::Reference< container::XIndexAccess >& xMenuSettings,
434 const OUString& rBaseTitle, SvxConfigEntry const * pParentData, bool bContextMenu )
436 SvxEntries* pEntries = pParentData->GetEntries();
438 // Don't access non existing menu configuration!
439 if ( !xMenuSettings.is() )
440 return;
442 for ( sal_Int32 nIndex = 0; nIndex < xMenuSettings->getCount(); ++nIndex )
444 uno::Reference< container::XIndexAccess > xSubMenu;
445 OUString aCommandURL;
446 OUString aLabel;
448 sal_uInt16 nType( css::ui::ItemType::DEFAULT );
449 sal_Int32 nStyle(0);
451 bool bItem = SvxConfigPageHelper::GetMenuItemData( xMenuSettings, nIndex,
452 aCommandURL, aLabel, nType, nStyle, xSubMenu );
454 if ( bItem )
456 bool bIsUserDefined = true;
458 if ( nType == css::ui::ItemType::DEFAULT )
460 uno::Any a;
463 a = m_xCommandToLabelMap->getByName( aCommandURL );
464 bIsUserDefined = false;
466 catch ( container::NoSuchElementException& )
468 bIsUserDefined = true;
471 bool bUseDefaultLabel = false;
472 // If custom label not set retrieve it from the command
473 // to info service
474 if ( aLabel.isEmpty() )
476 bUseDefaultLabel = true;
477 uno::Sequence< beans::PropertyValue > aPropSeq;
478 if ( a >>= aPropSeq )
480 OUString aMenuLabel;
481 for ( sal_Int32 i = 0; i < aPropSeq.getLength(); ++i )
483 if ( bContextMenu )
485 if ( aPropSeq[i].Name == "PopupLabel" )
487 aPropSeq[i].Value >>= aLabel;
488 break;
490 else if ( aPropSeq[i].Name == "Label" )
492 aPropSeq[i].Value >>= aMenuLabel;
495 else if ( aPropSeq[i].Name == "Label" )
497 aPropSeq[i].Value >>= aLabel;
498 break;
501 if ( aLabel.isEmpty() )
502 aLabel = aMenuLabel;
506 SvxConfigEntry* pEntry = new SvxConfigEntry(
507 aLabel, aCommandURL, xSubMenu.is(), /*bParentData*/false );
509 pEntry->SetStyle( nStyle );
510 pEntry->SetUserDefined( bIsUserDefined );
511 if ( !bUseDefaultLabel )
512 pEntry->SetName( aLabel );
514 pEntries->push_back( pEntry );
516 if ( xSubMenu.is() )
518 // popup menu
519 OUString subMenuTitle( rBaseTitle );
521 if ( !subMenuTitle.isEmpty() )
523 subMenuTitle += aMenuSeparatorStr;
525 else
527 pEntry->SetMain();
530 subMenuTitle += SvxConfigPageHelper::stripHotKey( aLabel );
532 LoadSubMenus( xSubMenu, subMenuTitle, pEntry, bContextMenu );
535 else
537 SvxConfigEntry* pEntry = new SvxConfigEntry;
538 pEntry->SetUserDefined( bIsUserDefined );
539 pEntries->push_back( pEntry );
545 bool MenuSaveInData::Apply()
547 bool result = false;
549 if ( IsModified() )
551 // Apply new menu bar structure to our settings container
552 m_xMenuSettings.set( GetConfigManager()->createSettings(), uno::UNO_QUERY );
554 uno::Reference< container::XIndexContainer > xIndexContainer (
555 m_xMenuSettings, uno::UNO_QUERY );
557 uno::Reference< lang::XSingleComponentFactory > xFactory (
558 m_xMenuSettings, uno::UNO_QUERY );
560 Apply( xIndexContainer, xFactory );
564 if ( GetConfigManager()->hasSettings( m_aMenuResourceURL ) )
566 GetConfigManager()->replaceSettings(
567 m_aMenuResourceURL, m_xMenuSettings );
569 else
571 GetConfigManager()->insertSettings(
572 m_aMenuResourceURL, m_xMenuSettings );
575 catch ( css::uno::Exception& )
577 css::uno::Any ex( cppu::getCaughtException() );
578 SAL_WARN("cui.customize", "caught some other exception saving settings " << exceptionToString(ex));
581 SetModified( false );
583 result = PersistChanges( GetConfigManager() );
586 return result;
589 void MenuSaveInData::Apply(
590 uno::Reference< container::XIndexContainer > const & rMenuBar,
591 uno::Reference< lang::XSingleComponentFactory >& rFactory )
593 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
595 for (auto const& entryData : *GetEntries())
597 uno::Sequence< beans::PropertyValue > aPropValueSeq =
598 SvxConfigPageHelper::ConvertSvxConfigEntry(entryData);
600 uno::Reference< container::XIndexContainer > xSubMenuBar(
601 rFactory->createInstanceWithContext( xContext ),
602 uno::UNO_QUERY );
604 sal_Int32 nIndex = aPropValueSeq.getLength();
605 aPropValueSeq.realloc( nIndex + 1 );
606 aPropValueSeq[nIndex].Name = m_aDescriptorContainer;
607 aPropValueSeq[nIndex].Value <<= xSubMenuBar;
608 rMenuBar->insertByIndex(
609 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
610 ApplyMenu( xSubMenuBar, rFactory, entryData );
614 void SaveInData::ApplyMenu(
615 uno::Reference< container::XIndexContainer > const & rMenuBar,
616 uno::Reference< lang::XSingleComponentFactory >& rFactory,
617 SvxConfigEntry* pMenuData )
619 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
621 for (auto const& entry : *pMenuData->GetEntries())
623 if (entry->IsPopup())
625 uno::Sequence< beans::PropertyValue > aPropValueSeq =
626 SvxConfigPageHelper::ConvertSvxConfigEntry(entry);
628 uno::Reference< container::XIndexContainer > xSubMenuBar(
629 rFactory->createInstanceWithContext( xContext ),
630 uno::UNO_QUERY );
632 sal_Int32 nIndex = aPropValueSeq.getLength();
633 aPropValueSeq.realloc( nIndex + 1 );
634 aPropValueSeq[nIndex].Name = ITEM_DESCRIPTOR_CONTAINER;
635 aPropValueSeq[nIndex].Value <<= xSubMenuBar;
637 rMenuBar->insertByIndex(
638 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
640 ApplyMenu( xSubMenuBar, rFactory, entry );
641 entry->SetModified( false );
643 else if (entry->IsSeparator())
645 rMenuBar->insertByIndex(
646 rMenuBar->getCount(), uno::Any( m_aSeparatorSeq ));
648 else
650 uno::Sequence< beans::PropertyValue > aPropValueSeq =
651 SvxConfigPageHelper::ConvertSvxConfigEntry(entry);
652 rMenuBar->insertByIndex(
653 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
656 pMenuData->SetModified( false );
659 void
660 MenuSaveInData::Reset()
664 GetConfigManager()->removeSettings( m_aMenuResourceURL );
666 catch ( const css::uno::Exception& )
669 PersistChanges( GetConfigManager() );
671 pRootEntry.reset();
675 m_xMenuSettings = GetConfigManager()->getSettings(
676 m_aMenuResourceURL, false );
678 catch ( container::NoSuchElementException& )
680 // will use default settings
684 ContextMenuSaveInData::ContextMenuSaveInData(
685 const css::uno::Reference< css::ui::XUIConfigurationManager >& xCfgMgr,
686 const css::uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
687 const OUString& aModuleId, bool bIsDocConfig )
688 : SaveInData( xCfgMgr, xParentCfgMgr, aModuleId, bIsDocConfig )
690 css::uno::Reference< css::uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
691 css::uno::Reference< css::container::XNameAccess > xConfig( css::ui::theWindowStateConfiguration::get( xContext ) );
692 xConfig->getByName( aModuleId ) >>= m_xPersistentWindowState;
695 ContextMenuSaveInData::~ContextMenuSaveInData()
699 OUString ContextMenuSaveInData::GetUIName( const OUString& rResourceURL )
701 if ( m_xPersistentWindowState.is() )
703 css::uno::Sequence< css::beans::PropertyValue > aProps;
706 m_xPersistentWindowState->getByName( rResourceURL ) >>= aProps;
708 catch ( const css::uno::Exception& )
711 for ( const auto& aProp : aProps )
713 if ( aProp.Name == ITEM_DESCRIPTOR_UINAME )
715 OUString aResult;
716 aProp.Value >>= aResult;
717 return aResult;
721 return OUString();
724 SvxEntries* ContextMenuSaveInData::GetEntries()
726 if ( !m_pRootEntry )
728 std::unordered_map< OUString, bool > aMenuInfo;
730 m_pRootEntry.reset( new SvxConfigEntry( "ContextMenus", OUString(), true, /*bParentData*/false ) );
731 css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aElementsInfo;
734 aElementsInfo = GetConfigManager()->getUIElementsInfo( css::ui::UIElementType::POPUPMENU );
736 catch ( const css::lang::IllegalArgumentException& )
739 for ( const auto& aElement : aElementsInfo )
741 OUString aUrl;
742 for ( const auto& aElementProp : aElement )
744 if ( aElementProp.Name == ITEM_DESCRIPTOR_RESOURCEURL )
746 aElementProp.Value >>= aUrl;
747 break;
751 css::uno::Reference< css::container::XIndexAccess > xPopupMenu;
754 xPopupMenu = GetConfigManager()->getSettings( aUrl, false );
756 catch ( const css::uno::Exception& )
759 if ( xPopupMenu.is() )
761 // insert into std::unordered_map to filter duplicates from the parent
762 aMenuInfo.emplace( aUrl, true );
764 OUString aUIMenuName = GetUIName( aUrl );
765 if ( aUIMenuName.isEmpty() )
766 // Menus without UI name aren't supposed to be customized.
767 continue;
769 SvxConfigEntry* pEntry = new SvxConfigEntry( aUIMenuName, aUrl, true, /*bParentData*/false );
770 pEntry->SetMain();
771 m_pRootEntry->GetEntries()->push_back( pEntry );
772 LoadSubMenus( xPopupMenu, aUIMenuName, pEntry, true );
776 // Retrieve also the parent menus, to make it possible to configure module menus and save them into the document.
777 css::uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr = GetParentConfigManager();
778 css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aParentElementsInfo;
781 if ( xParentCfgMgr.is() )
782 aParentElementsInfo = xParentCfgMgr->getUIElementsInfo( css::ui::UIElementType::POPUPMENU );
784 catch ( const css::lang::IllegalArgumentException& )
787 for ( const auto& aElement : aParentElementsInfo )
789 OUString aUrl;
790 for ( const auto& aElementProp : aElement )
792 if ( aElementProp.Name == ITEM_DESCRIPTOR_RESOURCEURL )
794 aElementProp.Value >>= aUrl;
795 break;
799 css::uno::Reference< css::container::XIndexAccess > xPopupMenu;
802 if ( aMenuInfo.find( aUrl ) == aMenuInfo.end() )
803 xPopupMenu = xParentCfgMgr->getSettings( aUrl, false );
805 catch ( const css::uno::Exception& )
808 if ( xPopupMenu.is() )
810 OUString aUIMenuName = GetUIName( aUrl );
811 if ( aUIMenuName.isEmpty() )
812 continue;
814 SvxConfigEntry* pEntry = new SvxConfigEntry( aUIMenuName, aUrl, true, true );
815 pEntry->SetMain();
816 m_pRootEntry->GetEntries()->push_back( pEntry );
817 LoadSubMenus( xPopupMenu, aUIMenuName, pEntry, true );
820 std::sort( m_pRootEntry->GetEntries()->begin(), m_pRootEntry->GetEntries()->end(), SvxConfigPageHelper::EntrySort );
822 return m_pRootEntry->GetEntries();
825 void ContextMenuSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
827 m_pRootEntry->SetEntries( std::move(pNewEntries) );
830 bool ContextMenuSaveInData::HasURL( const OUString& rURL )
832 SvxEntries* pEntries = GetEntries();
833 for ( const auto& pEntry : *pEntries )
834 if ( pEntry->GetCommand() == rURL )
835 return true;
837 return false;
840 bool ContextMenuSaveInData::HasSettings()
842 return m_pRootEntry && !m_pRootEntry->GetEntries()->empty();
845 bool ContextMenuSaveInData::Apply()
847 if ( !IsModified() )
848 return false;
850 SvxEntries* pEntries = GetEntries();
851 for ( const auto& pEntry : *pEntries )
853 if ( pEntry->IsModified() || SvxConfigPageHelper::SvxConfigEntryModified( pEntry ) )
855 css::uno::Reference< css::container::XIndexContainer > xIndexContainer( GetConfigManager()->createSettings(), css::uno::UNO_QUERY );
856 css::uno::Reference< css::lang::XSingleComponentFactory > xFactory( xIndexContainer, css::uno::UNO_QUERY );
857 ApplyMenu( xIndexContainer, xFactory, pEntry );
859 const OUString& aUrl = pEntry->GetCommand();
862 if ( GetConfigManager()->hasSettings( aUrl ) )
863 GetConfigManager()->replaceSettings( aUrl, xIndexContainer );
864 else
865 GetConfigManager()->insertSettings( aUrl, xIndexContainer );
867 catch ( const css::uno::Exception& )
871 SetModified( false );
872 return PersistChanges( GetConfigManager() );
875 void ContextMenuSaveInData::Reset()
877 SvxEntries* pEntries = GetEntries();
878 for ( const auto& pEntry : *pEntries )
882 GetConfigManager()->removeSettings( pEntry->GetCommand() );
884 catch ( const css::uno::Exception& e )
886 SAL_WARN("cui.customize", "Exception caught while resetting context menus: " << e);
889 PersistChanges( GetConfigManager() );
890 m_pRootEntry.reset();
893 void ContextMenuSaveInData::ResetContextMenu( const SvxConfigEntry* pEntry )
897 GetConfigManager()->removeSettings( pEntry->GetCommand() );
899 catch ( const css::uno::Exception& e )
901 SAL_WARN("cui.customize", "Exception caught while resetting context menu: " << e);
903 PersistChanges( GetConfigManager() );
904 m_pRootEntry.reset();
907 void SvxMenuEntriesListBox::CreateDropDown()
909 int nWidth = m_xControl->get_text_height() / 2;
910 m_xDropDown->SetOutputSizePixel(Size(nWidth, nWidth));
911 DecorationView aDecoView(m_xDropDown.get());
912 aDecoView.DrawSymbol(tools::Rectangle(Point(0, 0), Size(nWidth, nWidth)),
913 SymbolType::SPIN_RIGHT, m_xDropDown->GetTextColor(),
914 DrawSymbolFlags::NONE);
917 /******************************************************************************
919 * SvxMenuEntriesListBox is the listbox in which the menu items for a
920 * particular menu are shown. We have a custom listbox because we need
921 * to add drag'n'drop support from the Macro Selector and within the
922 * listbox
924 *****************************************************************************/
925 SvxMenuEntriesListBox::SvxMenuEntriesListBox(std::unique_ptr<weld::TreeView> xControl, SvxConfigPage* pPg)
926 : m_xControl(std::move(xControl))
927 , m_xDropDown(m_xControl->create_virtual_device())
928 , pPage(pPg)
930 CreateDropDown();
931 m_xControl->connect_key_press(LINK(this, SvxMenuEntriesListBox, KeyInputHdl));
934 SvxMenuEntriesListBox::~SvxMenuEntriesListBox()
938 IMPL_LINK(SvxMenuEntriesListBox, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
940 vcl::KeyCode keycode = rKeyEvent.GetKeyCode();
942 // support DELETE for removing the current entry
943 if ( keycode == KEY_DELETE )
945 pPage->DeleteSelectedContent();
947 // support CTRL+UP and CTRL+DOWN for moving selected entries
948 else if ( keycode.GetCode() == KEY_UP && keycode.IsMod1() )
950 pPage->MoveEntry( true );
952 else if ( keycode.GetCode() == KEY_DOWN && keycode.IsMod1() )
954 pPage->MoveEntry( false );
956 else
958 return false; // pass on to default handler
960 return true;
963 /******************************************************************************
965 * SvxConfigPage is the abstract base class on which the Menu and Toolbar
966 * configuration tabpages are based. It includes methods which are common to
967 * both tabpages to add, delete, move and rename items etc.
969 *****************************************************************************/
970 SvxConfigPage::SvxConfigPage(TabPageParent pParent, const SfxItemSet& rSet)
971 : SfxTabPage(pParent, "cui/ui/menuassignpage.ui", "MenuAssignPage", &rSet)
972 , m_aUpdateDataTimer("UpdateDataTimer")
973 , bInitialised(false)
974 , pCurrentSaveInData(nullptr)
975 , m_xSearchEdit(m_xBuilder->weld_entry("searchEntry"))
976 , m_xCommandCategoryListBox(new CommandCategoryListBox(m_xBuilder->weld_combo_box("commandcategorylist")))
977 , m_xFunctions(new CuiConfigFunctionListBox(m_xBuilder->weld_tree_view("functions")))
978 , m_xDescriptionFieldLb(m_xBuilder->weld_label("descriptionlabel"))
979 , m_xDescriptionField(m_xBuilder->weld_text_view("desc"))
980 , m_xTopLevelListBox(m_xBuilder->weld_combo_box("toplevellist"))
981 , m_xMoveUpButton(m_xBuilder->weld_button("up"))
982 , m_xMoveDownButton(m_xBuilder->weld_button("down"))
983 , m_xSaveInListBox(m_xBuilder->weld_combo_box("savein"))
984 , m_xInsertBtn(m_xBuilder->weld_menu_button("insert"))
985 , m_xModifyBtn(m_xBuilder->weld_menu_button("modify"))
986 , m_xResetBtn(m_xBuilder->weld_button("defaultsbtn"))
987 , m_xAddCommandButton(m_xBuilder->weld_button("add"))
988 , m_xRemoveCommandButton(m_xBuilder->weld_button("remove"))
990 m_xTopLevelListBox->connect_changed(LINK(this, SvxMenuConfigPage, SelectElementHdl));
992 weld::TreeView& rTreeView = m_xFunctions->get_widget();
993 Size aSize(rTreeView.get_approximate_digit_width() * 40, rTreeView.get_height_rows(8));
994 m_xFunctions->set_size_request(aSize.Width(), aSize.Height());
995 m_xDescriptionField->set_size_request(aSize.Width(), m_xDescriptionField->get_height_rows(3));
997 m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SvxConfigPage, ImplUpdateDataHdl));
998 m_aUpdateDataTimer.SetDebugName( "SvxConfigPage UpdateDataTimer" );
999 m_aUpdateDataTimer.SetTimeout(EDIT_UPDATEDATA_TIMEOUT);
1001 m_xSearchEdit->connect_changed(LINK(this, SvxConfigPage, SearchUpdateHdl));
1002 m_xSearchEdit->connect_focus_out(LINK(this, SvxConfigPage, FocusOut_Impl));
1004 rTreeView.connect_row_activated(LINK(this, SvxConfigPage, FunctionDoubleClickHdl));
1005 rTreeView.connect_changed(LINK(this, SvxConfigPage, SelectFunctionHdl));
1008 IMPL_LINK_NOARG(SvxConfigPage, SelectElementHdl, weld::ComboBox&, void)
1010 SelectElement();
1013 SvxConfigPage::~SvxConfigPage()
1015 disposeOnce();
1018 void SvxConfigPage::Reset( const SfxItemSet* )
1020 // If we haven't initialised our XMultiServiceFactory reference
1021 // then Reset is being called at the opening of the dialog.
1023 // Load menu configuration data for the module of the currently
1024 // selected document, for the currently selected document, and for
1025 // all other open documents of the same module type
1026 if ( !bInitialised )
1028 sal_Int32 nPos = 0;
1029 uno::Reference < css::ui::XUIConfigurationManager > xCfgMgr;
1030 uno::Reference < css::ui::XUIConfigurationManager > xDocCfgMgr;
1032 uno::Reference< uno::XComponentContext > xContext(
1033 ::comphelper::getProcessComponentContext(), uno::UNO_SET_THROW );
1035 m_xFrame = GetFrame();
1036 OUString aModuleId = GetFrameWithDefaultAndIdentify( m_xFrame );
1038 // replace %MODULENAME in the label with the correct module name
1039 uno::Reference< css::frame::XModuleManager2 > xModuleManager(
1040 css::frame::ModuleManager::create( xContext ));
1041 OUString aModuleName = SvxConfigPageHelper::GetUIModuleName( aModuleId, xModuleManager );
1043 uno::Reference< css::ui::XModuleUIConfigurationManagerSupplier >
1044 xModuleCfgSupplier( css::ui::theModuleUIConfigurationManagerSupplier::get(xContext) );
1046 // Set up data for module specific menus
1047 SaveInData* pModuleData = nullptr;
1051 xCfgMgr =
1052 xModuleCfgSupplier->getUIConfigurationManager( aModuleId );
1054 pModuleData = CreateSaveInData( xCfgMgr,
1055 uno::Reference< css::ui::XUIConfigurationManager >(),
1056 aModuleId,
1057 false );
1059 catch ( container::NoSuchElementException& )
1063 if ( pModuleData != nullptr )
1065 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pModuleData)));
1066 m_xSaveInListBox->append(sId, utl::ConfigManager::getProductName() + " " + aModuleName);
1069 // try to retrieve the document based ui configuration manager
1070 OUString aTitle;
1071 uno::Reference< frame::XController > xController =
1072 m_xFrame->getController();
1073 if ( CanConfig( aModuleId ) && xController.is() )
1075 uno::Reference< frame::XModel > xModel( xController->getModel() );
1076 if ( xModel.is() )
1078 uno::Reference< css::ui::XUIConfigurationManagerSupplier >
1079 xCfgSupplier( xModel, uno::UNO_QUERY );
1081 if ( xCfgSupplier.is() )
1083 xDocCfgMgr = xCfgSupplier->getUIConfigurationManager();
1085 aTitle = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
1089 SaveInData* pDocData = nullptr;
1090 if ( xDocCfgMgr.is() )
1092 pDocData = CreateSaveInData( xDocCfgMgr, xCfgMgr, aModuleId, true );
1094 if ( !pDocData->IsReadOnly() )
1096 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pDocData)));
1097 m_xSaveInListBox->append(sId, aTitle);
1101 // if an item to select has been passed in (eg. the ResourceURL for a
1102 // toolbar) then try to select the SaveInData entry that has that item
1103 bool bURLToSelectFound = false;
1104 if ( !m_aURLToSelect.isEmpty() )
1106 if ( pDocData && pDocData->HasURL( m_aURLToSelect ) )
1108 m_xSaveInListBox->set_active(nPos);
1109 pCurrentSaveInData = pDocData;
1110 bURLToSelectFound = true;
1112 else if ( pModuleData && pModuleData->HasURL( m_aURLToSelect ) )
1114 m_xSaveInListBox->set_active(0);
1115 pCurrentSaveInData = pModuleData;
1116 bURLToSelectFound = true;
1120 if ( !bURLToSelectFound )
1122 // if the document has menu configuration settings select it
1123 // it the SaveIn listbox, otherwise select the module data
1124 if ( pDocData != nullptr && pDocData->HasSettings() )
1126 m_xSaveInListBox->set_active(nPos);
1127 pCurrentSaveInData = pDocData;
1129 else
1131 m_xSaveInListBox->set_active(0);
1132 pCurrentSaveInData = pModuleData;
1136 #ifdef DBG_UTIL
1137 DBG_ASSERT( pCurrentSaveInData, "SvxConfigPage::Reset(): no SaveInData" );
1138 #endif
1140 if ( CanConfig( aModuleId ) )
1142 // Load configuration for other open documents which have
1143 // same module type
1144 uno::Sequence< uno::Reference< frame::XFrame > > aFrameList;
1147 uno::Reference< frame::XDesktop2 > xFramesSupplier = frame::Desktop::create(
1148 xContext );
1150 uno::Reference< frame::XFrames > xFrames =
1151 xFramesSupplier->getFrames();
1153 aFrameList = xFrames->queryFrames(
1154 frame::FrameSearchFlag::ALL & ~frame::FrameSearchFlag::SELF );
1157 catch( const uno::Exception& )
1159 DBG_UNHANDLED_EXCEPTION("cui.customize");
1162 for ( sal_Int32 i = 0; i < aFrameList.getLength(); ++i )
1164 uno::Reference < frame::XFrame > xf = aFrameList[i];
1166 if ( xf.is() && xf != m_xFrame )
1168 OUString aCheckId;
1169 try{
1170 aCheckId = xModuleManager->identify( xf );
1171 } catch(const uno::Exception&)
1172 { aCheckId.clear(); }
1174 if ( aModuleId == aCheckId )
1176 // try to get the document based ui configuration manager
1177 OUString aTitle2;
1178 uno::Reference< frame::XController > xController_ =
1179 xf->getController();
1181 if ( xController_.is() )
1183 uno::Reference< frame::XModel > xModel(
1184 xController_->getModel() );
1186 if ( xModel.is() )
1188 uno::Reference<
1189 css::ui::XUIConfigurationManagerSupplier >
1190 xCfgSupplier( xModel, uno::UNO_QUERY );
1192 if ( xCfgSupplier.is() )
1194 xDocCfgMgr =
1195 xCfgSupplier->getUIConfigurationManager();
1197 aTitle2 = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
1201 if ( xDocCfgMgr.is() )
1203 SaveInData* pData = CreateSaveInData( xDocCfgMgr, xCfgMgr, aModuleId, true );
1205 if ( pData && !pData->IsReadOnly() )
1207 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pData)));
1208 m_xSaveInListBox->append(sId, aTitle2);
1216 m_xSaveInListBox->connect_changed(
1217 LINK( this, SvxConfigPage, SelectSaveInLocation ) );
1219 bInitialised = true;
1221 Init();
1223 else
1225 if ( QueryReset() == RET_YES )
1227 // Reset menu configuration for currently selected SaveInData
1228 GetSaveInData()->Reset();
1230 Init();
1235 OUString SvxConfigPage::GetFrameWithDefaultAndIdentify( uno::Reference< frame::XFrame >& _inout_rxFrame )
1237 OUString sModuleID;
1240 uno::Reference< uno::XComponentContext > xContext(
1241 ::comphelper::getProcessComponentContext() );
1243 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(
1244 xContext );
1246 if ( !_inout_rxFrame.is() )
1247 _inout_rxFrame = xDesktop->getActiveFrame();
1249 if ( !_inout_rxFrame.is() )
1251 _inout_rxFrame = xDesktop->getCurrentFrame();
1254 if ( !_inout_rxFrame.is() && SfxViewFrame::Current() )
1255 _inout_rxFrame = SfxViewFrame::Current()->GetFrame().GetFrameInterface();
1257 if ( !_inout_rxFrame.is() )
1259 SAL_WARN( "cui.customize", "SvxConfigPage::GetFrameWithDefaultAndIdentify(): no frame found!" );
1260 return sModuleID;
1263 uno::Reference< css::frame::XModuleManager2 > xModuleManager(
1264 css::frame::ModuleManager::create( xContext ) );
1268 sModuleID = xModuleManager->identify( _inout_rxFrame );
1270 catch ( const frame::UnknownModuleException& )
1275 catch( const uno::Exception& )
1277 DBG_UNHANDLED_EXCEPTION("cui.customize");
1280 return sModuleID;
1283 OUString SvxConfigPage::GetScriptURL() const
1285 OUString result;
1287 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(m_xFunctions->get_selected_id().toInt64());
1288 if (pData)
1290 if ( ( pData->nKind == SfxCfgKind::FUNCTION_SLOT ) ||
1291 ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT ) ||
1292 ( pData->nKind == SfxCfgKind::GROUP_STYLES ) )
1294 result = pData->sCommand;
1298 return result;
1301 OUString SvxConfigPage::GetSelectedDisplayName()
1303 return m_xFunctions->get_selected_text();
1306 bool SvxConfigPage::FillItemSet( SfxItemSet* )
1308 bool result = false;
1310 for (int i = 0, nCount = m_xSaveInListBox->get_count(); i < nCount; ++i)
1312 SaveInData* pData =
1313 reinterpret_cast<SaveInData*>(m_xSaveInListBox->get_id(i).toInt64());
1315 result = pData->Apply();
1317 return result;
1320 IMPL_LINK_NOARG(SvxConfigPage, SelectSaveInLocation, weld::ComboBox&, void)
1322 pCurrentSaveInData = reinterpret_cast<SaveInData*>(m_xSaveInListBox->get_active_id().toInt64());
1323 Init();
1326 void SvxConfigPage::ReloadTopLevelListBox( SvxConfigEntry const * pToSelect )
1328 int nSelectionPos = m_xTopLevelListBox->get_active();
1329 m_xTopLevelListBox->clear();
1331 if ( GetSaveInData() && GetSaveInData()->GetEntries() )
1333 for (auto const& entryData : *GetSaveInData()->GetEntries())
1335 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(entryData)));
1336 m_xTopLevelListBox->append(sId, SvxConfigPageHelper::stripHotKey(entryData->GetName()));
1338 if (entryData == pToSelect)
1339 nSelectionPos = m_xTopLevelListBox->get_count() - 1;
1341 AddSubMenusToUI( SvxConfigPageHelper::stripHotKey( entryData->GetName() ), entryData );
1344 #ifdef DBG_UTIL
1345 else
1347 DBG_ASSERT( GetSaveInData(), "SvxConfigPage::ReloadTopLevelListBox(): no SaveInData" );
1348 DBG_ASSERT( GetSaveInData()->GetEntries() ,
1349 "SvxConfigPage::ReloadTopLevelListBox(): no SaveInData entries" );
1351 #endif
1353 nSelectionPos = (nSelectionPos != -1 && nSelectionPos < m_xTopLevelListBox->get_count()) ?
1354 nSelectionPos : m_xTopLevelListBox->get_count() - 1;
1356 m_xTopLevelListBox->set_active(nSelectionPos);
1357 SelectElement();
1360 void SvxConfigPage::AddSubMenusToUI(
1361 const OUString& rBaseTitle, SvxConfigEntry const * pParentData )
1363 for (auto const& entryData : *pParentData->GetEntries())
1365 if (entryData->IsPopup())
1367 OUString subMenuTitle = rBaseTitle + aMenuSeparatorStr + SvxConfigPageHelper::stripHotKey(entryData->GetName());
1369 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(entryData)));
1370 m_xTopLevelListBox->append(sId, subMenuTitle);
1372 AddSubMenusToUI( subMenuTitle, entryData );
1377 SvxEntries* SvxConfigPage::FindParentForChild(
1378 SvxEntries* pRootEntries, SvxConfigEntry* pChildData )
1380 for (auto const& entryData : *pRootEntries)
1383 if (entryData == pChildData)
1385 return pRootEntries;
1387 else if (entryData->IsPopup())
1389 SvxEntries* result =
1390 FindParentForChild( entryData->GetEntries(), pChildData );
1392 if ( result != nullptr )
1394 return result;
1398 return nullptr;
1401 int SvxConfigPage::AddFunction(int nTarget, bool bFront, bool bAllowDuplicates)
1403 OUString aURL = GetScriptURL();
1404 SvxConfigEntry* pParent = GetTopLevelSelection();
1406 if ( aURL.isEmpty() || pParent == nullptr )
1408 return -1;
1411 OUString aDisplayName;
1412 OUString aModuleId = vcl::CommandInfoProvider::GetModuleIdentifier( m_xFrame );
1414 if ( typeid(*pCurrentSaveInData) == typeid(ContextMenuSaveInData) )
1415 aDisplayName = vcl::CommandInfoProvider::GetPopupLabelForCommand( aURL, aModuleId );
1416 else if ( typeid(*pCurrentSaveInData) == typeid(MenuSaveInData) )
1417 aDisplayName = vcl::CommandInfoProvider::GetMenuLabelForCommand( aURL, aModuleId );
1418 else
1419 aDisplayName = vcl::CommandInfoProvider::GetLabelForCommand( aURL, aModuleId );
1421 SvxConfigEntry* pNewEntryData =
1422 new SvxConfigEntry( aDisplayName, aURL, false, /*bParentData*/false );
1423 pNewEntryData->SetUserDefined();
1425 if ( aDisplayName.isEmpty() )
1426 pNewEntryData->SetName( GetSelectedDisplayName() );
1428 // check that this function is not already in the menu
1429 if ( !bAllowDuplicates )
1431 for (auto const& entry : *pParent->GetEntries())
1433 if ( entry->GetCommand() == pNewEntryData->GetCommand() )
1435 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetDialogFrameWeld(),
1436 VclMessageType::Info, VclButtonsType::Ok, CuiResId(RID_SVXSTR_MNUCFG_ALREADY_INCLUDED)));
1437 xBox->run();
1438 delete pNewEntryData;
1439 return -1;
1444 return InsertEntry(pNewEntryData, nTarget, bFront);
1447 int SvxConfigPage::InsertEntry(
1448 SvxConfigEntry* pNewEntryData,
1449 int nTarget,
1450 bool bFront)
1452 SvxConfigEntry* pTopLevelSelection = GetTopLevelSelection();
1454 if (pTopLevelSelection == nullptr)
1455 return -1;
1457 // Grab the entries list for the currently selected menu
1458 SvxEntries* pEntries = pTopLevelSelection->GetEntries();
1460 int nNewEntry = -1;
1461 int nCurEntry =
1462 nTarget != -1 ? nTarget : m_xContentsListBox->get_selected_index();
1464 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pNewEntryData)));
1466 if (bFront)
1468 pEntries->insert( pEntries->begin(), pNewEntryData );
1469 m_xContentsListBox->insert(0, sId);
1470 nNewEntry = 0;
1472 else if (nCurEntry == -1 || nCurEntry == m_xContentsListBox->n_children() - 1)
1474 pEntries->push_back( pNewEntryData );
1475 m_xContentsListBox->insert(-1, sId);
1476 nNewEntry = m_xContentsListBox->n_children() - 1;
1478 else
1480 SvxConfigEntry* pEntryData =
1481 reinterpret_cast<SvxConfigEntry*>(m_xContentsListBox->get_id(nCurEntry).toInt64());
1483 SvxEntries::iterator iter = pEntries->begin();
1484 SvxEntries::const_iterator end = pEntries->end();
1486 // Advance the iterator to the data for currently selected entry
1487 sal_uInt16 nPos = 0;
1488 while (*iter != pEntryData && ++iter != end)
1490 ++nPos;
1493 // Now step past it to the entry after the currently selected one
1494 ++iter;
1495 ++nPos;
1497 // Now add the new entry to the UI and to the parent's list
1498 if ( iter != end )
1500 pEntries->insert( iter, pNewEntryData );
1501 m_xContentsListBox->insert(nPos, sId);
1502 nNewEntry = nPos;
1506 if (nNewEntry != -1)
1508 m_xContentsListBox->select(nNewEntry);
1509 m_xContentsListBox->scroll_to_row(nNewEntry);
1511 GetSaveInData()->SetModified();
1512 GetTopLevelSelection()->SetModified();
1515 return nNewEntry;
1518 void SvxConfigPage::InsertEntryIntoUI(SvxConfigEntry* pNewEntryData, int nPos, int nStartCol)
1520 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pNewEntryData)));
1522 m_xContentsListBox->set_id(nPos, sId);
1524 if (pNewEntryData->IsSeparator())
1526 m_xContentsListBox->set_text(nPos, "----------------------------------", nStartCol + 1);
1528 else
1530 auto xImage = GetSaveInData()->GetImage(pNewEntryData->GetCommand());
1531 if (xImage.is())
1532 m_xContentsListBox->set_image(nPos, xImage, nStartCol);
1533 OUString aName = SvxConfigPageHelper::stripHotKey( pNewEntryData->GetName() );
1534 m_xContentsListBox->set_text(nPos, aName, nStartCol + 1);
1537 if (nStartCol == 0) // menus
1539 if (pNewEntryData->IsPopup() || pNewEntryData->GetStyle() & css::ui::ItemStyle::DROP_DOWN)
1540 m_xContentsListBox->set_dropdown(nPos, nStartCol + 2);
1541 else
1542 m_xContentsListBox->set_image(nPos, nullptr, nStartCol + 2);
1546 IMPL_LINK(SvxConfigPage, MoveHdl, weld::Button&, rButton, void)
1548 MoveEntry(&rButton == m_xMoveUpButton.get());
1551 IMPL_LINK_NOARG(SvxConfigPage, FunctionDoubleClickHdl, weld::TreeView&, void)
1553 if (m_xAddCommandButton->get_sensitive())
1554 m_xAddCommandButton->clicked();
1557 IMPL_LINK_NOARG(SvxConfigPage, SelectFunctionHdl, weld::TreeView&, void)
1559 // Store the tooltip of the description field at first run
1560 static const OUString sDescTooltip = m_xDescriptionField->get_tooltip_text();
1562 // GetScriptURL() returns a non-empty string if a
1563 // valid command is selected on the left box
1564 bool bIsValidCommand = !GetScriptURL().isEmpty();
1566 // Enable/disable Add and Remove buttons depending on current selection
1567 if (bIsValidCommand)
1569 m_xAddCommandButton->set_sensitive(true);
1570 m_xRemoveCommandButton->set_sensitive(true);
1572 m_xDescriptionField->set_text(m_xFunctions->GetHelpText(false));
1574 else
1577 m_xAddCommandButton->set_sensitive(false);
1578 m_xRemoveCommandButton->set_sensitive(false);
1580 m_xDescriptionField->set_text("");
1583 // Disable the description field and its label if the local help is not installed
1584 // And inform the user via tooltips
1585 if ( !SfxHelp::IsHelpInstalled() )
1587 m_xDescriptionField->set_sensitive(false);
1588 m_xDescriptionFieldLb->set_sensitive(false);
1589 m_xDescriptionField->set_tooltip_text( sDescTooltip );
1590 m_xDescriptionFieldLb->set_tooltip_text( sDescTooltip );
1592 else
1594 m_xDescriptionField->set_sensitive(true);
1595 m_xDescriptionFieldLb->set_sensitive(true);
1596 m_xDescriptionField->set_tooltip_text("");
1597 m_xDescriptionFieldLb->set_tooltip_text("");
1601 IMPL_LINK_NOARG(SvxConfigPage, ImplUpdateDataHdl, Timer*, void)
1603 OUString aSearchTerm(m_xSearchEdit->get_text());
1604 m_xCommandCategoryListBox->categorySelected(m_xFunctions.get(), aSearchTerm, GetSaveInData());
1607 IMPL_LINK_NOARG(SvxConfigPage, SearchUpdateHdl, weld::Entry&, void)
1609 m_aUpdateDataTimer.Start();
1612 IMPL_LINK_NOARG(SvxConfigPage, FocusOut_Impl, weld::Widget&, void)
1614 if (m_aUpdateDataTimer.IsActive())
1616 m_aUpdateDataTimer.Stop();
1617 m_aUpdateDataTimer.Invoke();
1621 void SvxConfigPage::MoveEntry(bool bMoveUp)
1623 weld::TreeView& rTreeView = m_xContentsListBox->get_widget();
1625 int nSourceEntry = rTreeView.get_selected_index();
1626 int nTargetEntry = -1;
1627 int nToSelect = -1;
1629 if (nSourceEntry == -1)
1631 return;
1634 if ( bMoveUp )
1636 // Move Up is just a Move Down with the source and target reversed
1637 nTargetEntry = nSourceEntry;
1638 nSourceEntry = nTargetEntry - 1;
1639 nToSelect = nSourceEntry;
1641 else
1643 nTargetEntry = nSourceEntry + 1;
1644 nToSelect = nTargetEntry;
1647 if (MoveEntryData(nSourceEntry, nTargetEntry))
1649 rTreeView.swap(nSourceEntry, nTargetEntry);
1650 rTreeView.select(nToSelect);
1651 rTreeView.scroll_to_row(nToSelect);
1653 UpdateButtonStates();
1657 bool SvxConfigPage::MoveEntryData(int nSourceEntry, int nTargetEntry)
1659 //#i53677#
1660 if (nSourceEntry == -1 || nTargetEntry == -1)
1662 return false;
1665 // Grab the entries list for the currently selected menu
1666 SvxEntries* pEntries = GetTopLevelSelection()->GetEntries();
1668 SvxConfigEntry* pSourceData =
1669 reinterpret_cast<SvxConfigEntry*>(m_xContentsListBox->get_id(nSourceEntry).toInt64());
1671 SvxConfigEntry* pTargetData =
1672 reinterpret_cast<SvxConfigEntry*>(m_xContentsListBox->get_id(nTargetEntry).toInt64());
1674 if ( pSourceData != nullptr && pTargetData != nullptr )
1676 // remove the source entry from our list
1677 SvxConfigPageHelper::RemoveEntry( pEntries, pSourceData );
1679 SvxEntries::iterator iter = pEntries->begin();
1680 SvxEntries::const_iterator end = pEntries->end();
1682 // advance the iterator to the position of the target entry
1683 while (*iter != pTargetData && ++iter != end) ;
1685 // insert the source entry at the position after the target
1686 pEntries->insert( ++iter, pSourceData );
1688 GetSaveInData()->SetModified();
1689 GetTopLevelSelection()->SetModified();
1691 return true;
1694 return false;
1697 SvxMainMenuOrganizerDialog::SvxMainMenuOrganizerDialog(
1698 weld::Window* pParent, SvxEntries* entries,
1699 SvxConfigEntry const * selection, bool bCreateMenu )
1700 : GenericDialogController(pParent, "cui/ui/movemenu.ui", "MoveMenuDialog")
1701 , m_xMenuBox(m_xBuilder->weld_widget("namebox"))
1702 , m_xMenuNameEdit(m_xBuilder->weld_entry("menuname"))
1703 , m_xMenuListBox(m_xBuilder->weld_tree_view("menulist"))
1704 , m_xMoveUpButton(m_xBuilder->weld_button("up"))
1705 , m_xMoveDownButton(m_xBuilder->weld_button("down"))
1707 m_xMenuListBox->set_size_request(-1, m_xMenuListBox->get_height_rows(12));
1709 // Copy the entries list passed in
1710 if ( entries != nullptr )
1712 mpEntries.reset( new SvxEntries );
1713 for (auto const& entry : *entries)
1715 m_xMenuListBox->append(OUString::number(reinterpret_cast<sal_uInt64>(entry)),
1716 SvxConfigPageHelper::stripHotKey(entry->GetName()));
1717 mpEntries->push_back(entry);
1718 if (entry == selection)
1720 m_xMenuListBox->select(m_xMenuListBox->n_children() - 1);
1725 if ( bCreateMenu )
1727 // Generate custom name for new menu
1728 OUString prefix = CuiResId( RID_SVXSTR_NEW_MENU );
1730 OUString newname = SvxConfigPageHelper::generateCustomName( prefix, entries );
1731 OUString newurl = SvxConfigPageHelper::generateCustomMenuURL( mpEntries.get() );
1733 SvxConfigEntry* pNewEntryData =
1734 new SvxConfigEntry( newname, newurl, true, /*bParentData*/false );
1735 pNewEntryData->SetName( newname );
1736 pNewEntryData->SetUserDefined();
1737 pNewEntryData->SetMain();
1739 m_sNewMenuEntryId = OUString::number(reinterpret_cast<sal_uInt64>(pNewEntryData));
1740 m_xMenuListBox->append(m_sNewMenuEntryId,
1741 SvxConfigPageHelper::stripHotKey(pNewEntryData->GetName()));
1742 m_xMenuListBox->select(m_xMenuListBox->n_children() - 1);
1744 if (mpEntries)
1745 mpEntries->push_back(pNewEntryData);
1747 m_xMenuNameEdit->set_text(newname);
1748 m_xMenuNameEdit->connect_changed(LINK(this, SvxMainMenuOrganizerDialog, ModifyHdl));
1750 else
1752 // hide name label and textfield
1753 m_xMenuBox->hide();
1754 // change the title
1755 m_xDialog->set_title(CuiResId(RID_SVXSTR_MOVE_MENU));
1758 m_xMenuListBox->connect_changed(LINK(this, SvxMainMenuOrganizerDialog, SelectHdl));
1760 m_xMoveUpButton->connect_clicked(LINK( this, SvxMainMenuOrganizerDialog, MoveHdl));
1761 m_xMoveDownButton->connect_clicked(LINK( this, SvxMainMenuOrganizerDialog, MoveHdl));
1763 UpdateButtonStates();
1766 SvxMainMenuOrganizerDialog::~SvxMainMenuOrganizerDialog()
1770 IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog, ModifyHdl, weld::Entry&, void)
1772 // if the Edit control is empty do not change the name
1773 if (m_xMenuNameEdit->get_text().isEmpty())
1775 return;
1778 SvxConfigEntry* pNewEntryData = reinterpret_cast<SvxConfigEntry*>(m_sNewMenuEntryId.toUInt64());
1779 pNewEntryData->SetName(m_xMenuNameEdit->get_text());
1781 const int nNewMenuPos = m_xMenuListBox->find_id(m_sNewMenuEntryId);
1782 const int nOldSelection = m_xMenuListBox->get_selected_index();
1783 m_xMenuListBox->remove(nNewMenuPos);
1784 m_xMenuListBox->insert(nNewMenuPos, pNewEntryData->GetName(), &m_sNewMenuEntryId, nullptr, nullptr);
1785 m_xMenuListBox->select(nOldSelection);
1788 IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog, SelectHdl, weld::TreeView&, void)
1790 UpdateButtonStates();
1793 void SvxMainMenuOrganizerDialog::UpdateButtonStates()
1795 // Disable Up and Down buttons depending on current selection
1796 const int nSelected = m_xMenuListBox->get_selected_index();
1797 m_xMoveUpButton->set_sensitive(nSelected > 0);
1798 m_xMoveDownButton->set_sensitive(nSelected != -1 && nSelected < m_xMenuListBox->n_children() - 1);
1801 IMPL_LINK( SvxMainMenuOrganizerDialog, MoveHdl, weld::Button&, rButton, void )
1803 int nSourceEntry = m_xMenuListBox->get_selected_index();
1804 if (nSourceEntry == -1)
1805 return;
1807 int nTargetEntry;
1809 if (&rButton == m_xMoveDownButton.get())
1811 nTargetEntry = nSourceEntry + 1;
1813 else
1815 // Move Up is just a Move Down with the source and target reversed
1816 nTargetEntry = nSourceEntry - 1;
1819 OUString sId = m_xMenuListBox->get_id(nSourceEntry);
1820 OUString sEntry = m_xMenuListBox->get_text(nSourceEntry);
1821 m_xMenuListBox->remove(nSourceEntry);
1822 m_xMenuListBox->insert(nTargetEntry, sEntry, &sId, nullptr, nullptr);
1823 m_xMenuListBox->select(nTargetEntry);
1825 std::swap(mpEntries->at(nSourceEntry), mpEntries->at(nTargetEntry));
1827 UpdateButtonStates();
1830 SvxConfigEntry* SvxMainMenuOrganizerDialog::GetSelectedEntry()
1832 const int nSelected(m_xMenuListBox->get_selected_index());
1833 if (nSelected == -1)
1834 return nullptr;
1835 return reinterpret_cast<SvxConfigEntry*>(m_xMenuListBox->get_id(nSelected).toUInt64());
1838 SvxConfigEntry::SvxConfigEntry( const OUString& rDisplayName,
1839 const OUString& rCommandURL, bool bPopup, bool bParentData )
1840 : nId( 1 )
1841 , aLabel(rDisplayName)
1842 , aCommand(rCommandURL)
1843 , bPopUp(bPopup)
1844 , bStrEdited( false )
1845 , bIsUserDefined( false )
1846 , bIsMain( false )
1847 , bIsParentData( bParentData )
1848 , bIsModified( false )
1849 , bIsVisible( true )
1850 , nStyle( 0 )
1852 if (bPopUp)
1854 mpEntries.reset( new SvxEntries );
1858 SvxConfigEntry::~SvxConfigEntry()
1860 if (mpEntries)
1862 for (auto const& entry : *mpEntries)
1864 delete entry;
1869 bool SvxConfigEntry::IsMovable()
1871 return !IsPopup() || IsMain();
1874 bool SvxConfigEntry::IsDeletable()
1876 return !IsMain() || IsUserDefined();
1879 bool SvxConfigEntry::IsRenamable()
1881 return !IsMain() || IsUserDefined();
1884 ToolbarSaveInData::ToolbarSaveInData(
1885 const uno::Reference < css::ui::XUIConfigurationManager >& xCfgMgr,
1886 const uno::Reference < css::ui::XUIConfigurationManager >& xParentCfgMgr,
1887 const OUString& aModuleId,
1888 bool docConfig ) :
1890 SaveInData ( xCfgMgr, xParentCfgMgr, aModuleId, docConfig ),
1891 m_aDescriptorContainer ( ITEM_DESCRIPTOR_CONTAINER )
1894 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
1895 // Initialize the m_xPersistentWindowState variable which is used
1896 // to get the default properties of system toolbars such as name
1897 uno::Reference< container::XNameAccess > xPWSS = css::ui::theWindowStateConfiguration::get( xContext );
1899 xPWSS->getByName( aModuleId ) >>= m_xPersistentWindowState;
1902 ToolbarSaveInData::~ToolbarSaveInData()
1906 sal_Int32 ToolbarSaveInData::GetSystemStyle( const OUString& rResourceURL )
1908 sal_Int32 result = 0;
1910 if ( rResourceURL.startsWith( "private" ) &&
1911 m_xPersistentWindowState.is() &&
1912 m_xPersistentWindowState->hasByName( rResourceURL ) )
1916 uno::Sequence< beans::PropertyValue > aProps;
1917 uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
1919 if ( a >>= aProps )
1921 for ( sal_Int32 i = 0; i < aProps.getLength(); ++i )
1923 if ( aProps[ i ].Name == ITEM_DESCRIPTOR_STYLE )
1925 aProps[i].Value >>= result;
1926 break;
1931 catch ( uno::Exception& )
1933 // do nothing, a default value is returned
1937 return result;
1940 void ToolbarSaveInData::SetSystemStyle(
1941 const uno::Reference< frame::XFrame >& xFrame,
1942 const OUString& rResourceURL,
1943 sal_Int32 nStyle )
1945 // change the style using the API
1946 SetSystemStyle( rResourceURL, nStyle );
1948 // this code is a temporary hack as the UI is not updating after
1949 // changing the toolbar style via the API
1950 uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1951 vcl::Window *window = nullptr;
1953 uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
1954 if ( xPropSet.is() )
1956 uno::Any a = xPropSet->getPropertyValue( "LayoutManager" );
1957 a >>= xLayoutManager;
1960 if ( xLayoutManager.is() )
1962 uno::Reference< css::ui::XUIElement > xUIElement =
1963 xLayoutManager->getElement( rResourceURL );
1965 // check reference before we call getRealInterface. The layout manager
1966 // can only provide references for elements that have been created
1967 // before. It's possible that the current element is not available.
1968 uno::Reference< css::awt::XWindow > xWindow;
1969 if ( xUIElement.is() )
1970 xWindow.set( xUIElement->getRealInterface(), uno::UNO_QUERY );
1972 window = VCLUnoHelper::GetWindow( xWindow ).get();
1975 if ( window != nullptr && window->GetType() == WindowType::TOOLBOX )
1977 ToolBox* toolbox = static_cast<ToolBox*>(window);
1979 if ( nStyle == 0 )
1981 toolbox->SetButtonType( ButtonType::SYMBOLONLY );
1983 else if ( nStyle == 1 )
1985 toolbox->SetButtonType( ButtonType::TEXT );
1987 if ( nStyle == 2 )
1989 toolbox->SetButtonType( ButtonType::SYMBOLTEXT );
1994 void ToolbarSaveInData::SetSystemStyle(
1995 const OUString& rResourceURL,
1996 sal_Int32 nStyle )
1998 if ( rResourceURL.startsWith( "private" ) &&
1999 m_xPersistentWindowState.is() &&
2000 m_xPersistentWindowState->hasByName( rResourceURL ) )
2004 uno::Sequence< beans::PropertyValue > aProps;
2006 uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
2008 if ( a >>= aProps )
2010 for ( sal_Int32 i = 0; i < aProps.getLength(); ++i )
2012 if ( aProps[ i ].Name == ITEM_DESCRIPTOR_STYLE )
2014 aProps[ i ].Value <<= nStyle;
2015 break;
2020 uno::Reference< container::XNameReplace >
2021 xNameReplace( m_xPersistentWindowState, uno::UNO_QUERY );
2023 xNameReplace->replaceByName( rResourceURL, uno::Any( aProps ) );
2025 catch ( uno::Exception& )
2027 // do nothing, a default value is returned
2028 SAL_WARN("cui.customize", "Exception setting toolbar style");
2033 OUString ToolbarSaveInData::GetSystemUIName( const OUString& rResourceURL )
2035 OUString result;
2037 if ( rResourceURL.startsWith( "private" ) &&
2038 m_xPersistentWindowState.is() &&
2039 m_xPersistentWindowState->hasByName( rResourceURL ) )
2043 uno::Sequence< beans::PropertyValue > aProps;
2044 uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
2046 if ( a >>= aProps )
2048 for ( sal_Int32 i = 0; i < aProps.getLength(); ++i )
2050 if ( aProps[ i ].Name == ITEM_DESCRIPTOR_UINAME )
2052 aProps[ i ].Value >>= result;
2057 catch ( uno::Exception& )
2059 // do nothing, an empty UIName will be returned
2063 if ( rResourceURL.startsWith( ".uno" ) &&
2064 m_xCommandToLabelMap.is() &&
2065 m_xCommandToLabelMap->hasByName( rResourceURL ) )
2067 uno::Any a;
2070 a = m_xCommandToLabelMap->getByName( rResourceURL );
2072 uno::Sequence< beans::PropertyValue > aPropSeq;
2073 if ( a >>= aPropSeq )
2075 for ( sal_Int32 i = 0; i < aPropSeq.getLength(); ++i )
2077 if ( aPropSeq[i].Name == ITEM_DESCRIPTOR_LABEL )
2079 aPropSeq[i].Value >>= result;
2084 catch ( uno::Exception& )
2086 // not a system command name
2090 return result;
2093 SvxEntries* ToolbarSaveInData::GetEntries()
2095 typedef std::unordered_map<OUString, bool > ToolbarInfo;
2097 ToolbarInfo aToolbarInfo;
2099 if ( pRootEntry == nullptr )
2102 pRootEntry.reset( new SvxConfigEntry( "MainToolbars", OUString(), true, /*bParentData*/false) );
2104 uno::Sequence< uno::Sequence < beans::PropertyValue > > info =
2105 GetConfigManager()->getUIElementsInfo(
2106 css::ui::UIElementType::TOOLBAR );
2108 for ( sal_Int32 i = 0; i < info.getLength(); ++i )
2110 uno::Sequence< beans::PropertyValue > props = info[ i ];
2112 OUString url;
2113 OUString systemname;
2114 OUString uiname;
2116 for ( sal_Int32 j = 0; j < props.getLength(); ++j )
2118 if ( props[ j ].Name == ITEM_DESCRIPTOR_RESOURCEURL )
2120 props[ j ].Value >>= url;
2121 systemname = url.copy( url.lastIndexOf( '/' ) + 1 );
2123 else if ( props[ j ].Name == ITEM_DESCRIPTOR_UINAME )
2125 props[ j ].Value >>= uiname;
2131 uno::Reference< container::XIndexAccess > xToolbarSettings =
2132 GetConfigManager()->getSettings( url, false );
2134 if ( uiname.isEmpty() )
2136 // try to get the name from m_xPersistentWindowState
2137 uiname = GetSystemUIName( url );
2139 if ( uiname.isEmpty() )
2141 uiname = systemname;
2145 SvxConfigEntry* pEntry = new SvxConfigEntry(
2146 uiname, url, true, /*bParentData*/false );
2148 pEntry->SetMain();
2149 pEntry->SetStyle( GetSystemStyle( url ) );
2152 // insert into std::unordered_map to filter duplicates from the parent
2153 aToolbarInfo.emplace( systemname, true );
2155 OUString custom(CUSTOM_TOOLBAR_STR);
2156 if ( systemname.startsWith( custom ) )
2158 pEntry->SetUserDefined();
2160 else
2162 pEntry->SetUserDefined( false );
2165 pRootEntry->GetEntries()->push_back( pEntry );
2167 LoadToolbar( xToolbarSettings, pEntry );
2169 catch ( container::NoSuchElementException& )
2171 // TODO, handle resourceURL with no settings
2175 uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr = GetParentConfigManager();
2176 if ( xParentCfgMgr.is() )
2178 // Retrieve also the parent toolbars to make it possible
2179 // to configure module toolbars and save them into the document
2180 // config manager.
2181 uno::Sequence< uno::Sequence < beans::PropertyValue > > info_ =
2182 xParentCfgMgr->getUIElementsInfo(
2183 css::ui::UIElementType::TOOLBAR );
2185 for ( sal_Int32 i = 0; i < info_.getLength(); ++i )
2187 uno::Sequence< beans::PropertyValue > props = info_[ i ];
2189 OUString url;
2190 OUString systemname;
2191 OUString uiname;
2193 for ( sal_Int32 j = 0; j < props.getLength(); ++j )
2195 if ( props[ j ].Name == ITEM_DESCRIPTOR_RESOURCEURL )
2197 props[ j ].Value >>= url;
2198 systemname = url.copy( url.lastIndexOf( '/' ) + 1 );
2200 else if ( props[ j ].Name == ITEM_DESCRIPTOR_UINAME )
2202 props[ j ].Value >>= uiname;
2206 // custom toolbars of the parent are not visible in the document layer
2207 OUString custom(CUSTOM_TOOLBAR_STR);
2208 if ( systemname.startsWith( custom ) )
2209 continue;
2211 // check if toolbar is already in the document layer
2212 ToolbarInfo::const_iterator pIter = aToolbarInfo.find( systemname );
2213 if ( pIter == aToolbarInfo.end() )
2215 aToolbarInfo.emplace( systemname, true );
2219 uno::Reference< container::XIndexAccess > xToolbarSettings =
2220 xParentCfgMgr->getSettings( url, false );
2222 if ( uiname.isEmpty() )
2224 // try to get the name from m_xPersistentWindowState
2225 uiname = GetSystemUIName( url );
2227 if ( uiname.isEmpty() )
2229 uiname = systemname;
2233 SvxConfigEntry* pEntry = new SvxConfigEntry(
2234 uiname, url, true, true );
2236 pEntry->SetMain();
2237 pEntry->SetStyle( GetSystemStyle( url ) );
2239 if ( systemname.startsWith( custom ) )
2241 pEntry->SetUserDefined();
2243 else
2245 pEntry->SetUserDefined( false );
2248 pRootEntry->GetEntries()->push_back( pEntry );
2250 LoadToolbar( xToolbarSettings, pEntry );
2252 catch ( container::NoSuchElementException& )
2254 // TODO, handle resourceURL with no settings
2260 std::sort( GetEntries()->begin(), GetEntries()->end(), SvxConfigPageHelper::EntrySort );
2263 return pRootEntry->GetEntries();
2266 void
2267 ToolbarSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
2269 pRootEntry->SetEntries( std::move(pNewEntries) );
2272 bool
2273 ToolbarSaveInData::HasURL( const OUString& rURL )
2275 for (auto const& entry : *GetEntries())
2277 if (entry->GetCommand() == rURL)
2279 return !entry->IsParentData();
2282 return false;
2285 bool ToolbarSaveInData::HasSettings()
2287 // return true if there is at least one toolbar entry
2288 return !GetEntries()->empty();
2291 void ToolbarSaveInData::Reset()
2293 // reset each toolbar by calling removeSettings for its toolbar URL
2294 for (auto const& entry : *GetEntries())
2298 const OUString& url = entry->GetCommand();
2299 GetConfigManager()->removeSettings( url );
2301 catch ( uno::Exception& )
2303 // error occurred removing the settings
2304 // TODO - add error dialog in future?
2308 // persist changes to toolbar storage
2309 PersistChanges( GetConfigManager() );
2311 // now delete the root SvxConfigEntry the next call to GetEntries()
2312 // causes it to be reinitialised
2313 pRootEntry.reset();
2315 // reset all icons to default
2318 GetImageManager()->reset();
2319 PersistChanges( GetImageManager() );
2321 catch ( uno::Exception& )
2323 SAL_WARN("cui.customize", "Error resetting all icons when resetting toolbars");
2327 bool ToolbarSaveInData::Apply()
2329 // toolbar changes are instantly applied
2330 return false;
2333 void ToolbarSaveInData::ApplyToolbar(
2334 uno::Reference< container::XIndexContainer > const & rToolbarBar,
2335 uno::Reference< lang::XSingleComponentFactory >& rFactory,
2336 SvxConfigEntry const * pToolbarData )
2338 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
2340 for (auto const& entry : *pToolbarData->GetEntries())
2342 if (entry->IsPopup())
2344 uno::Sequence< beans::PropertyValue > aPropValueSeq =
2345 SvxConfigPageHelper::ConvertToolbarEntry(entry);
2347 uno::Reference< container::XIndexContainer > xSubMenuBar(
2348 rFactory->createInstanceWithContext( xContext ),
2349 uno::UNO_QUERY );
2351 sal_Int32 nIndex = aPropValueSeq.getLength();
2352 aPropValueSeq.realloc( nIndex + 1 );
2353 aPropValueSeq[nIndex].Name = m_aDescriptorContainer;
2354 aPropValueSeq[nIndex].Value <<= xSubMenuBar;
2355 rToolbarBar->insertByIndex(
2356 rToolbarBar->getCount(), uno::Any( aPropValueSeq ));
2358 ApplyToolbar(xSubMenuBar, rFactory, entry);
2360 else if (entry->IsSeparator())
2362 rToolbarBar->insertByIndex(
2363 rToolbarBar->getCount(), uno::Any( m_aSeparatorSeq ));
2365 else
2367 uno::Sequence< beans::PropertyValue > aPropValueSeq =
2368 SvxConfigPageHelper::ConvertToolbarEntry(entry);
2370 rToolbarBar->insertByIndex(
2371 rToolbarBar->getCount(), uno::Any( aPropValueSeq ));
2376 void ToolbarSaveInData::ApplyToolbar( SvxConfigEntry* pToolbar )
2378 // Apply new toolbar structure to our settings container
2379 uno::Reference< container::XIndexAccess > xSettings(
2380 GetConfigManager()->createSettings(), uno::UNO_QUERY );
2382 uno::Reference< container::XIndexContainer > xIndexContainer (
2383 xSettings, uno::UNO_QUERY );
2385 uno::Reference< lang::XSingleComponentFactory > xFactory (
2386 xSettings, uno::UNO_QUERY );
2388 ApplyToolbar( xIndexContainer, xFactory, pToolbar );
2390 uno::Reference< beans::XPropertySet > xProps(
2391 xSettings, uno::UNO_QUERY );
2393 if ( pToolbar->IsUserDefined() )
2395 xProps->setPropertyValue(
2396 ITEM_DESCRIPTOR_UINAME,
2397 uno::Any( pToolbar->GetName() ) );
2402 if ( GetConfigManager()->hasSettings( pToolbar->GetCommand() ) )
2404 GetConfigManager()->replaceSettings(
2405 pToolbar->GetCommand(), xSettings );
2407 else
2409 GetConfigManager()->insertSettings(
2410 pToolbar->GetCommand(), xSettings );
2411 if ( pToolbar->IsParentData() )
2412 pToolbar->SetParentData( false );
2415 catch ( css::uno::Exception const & )
2417 css::uno::Any ex( cppu::getCaughtException() );
2418 SAL_WARN("cui.customize", "caught exception saving settings " << exceptionToString(ex));
2421 PersistChanges( GetConfigManager() );
2424 void ToolbarSaveInData::CreateToolbar( SvxConfigEntry* pToolbar )
2426 // show the new toolbar in the UI also
2427 uno::Reference< container::XIndexAccess >
2428 xSettings( GetConfigManager()->createSettings(), uno::UNO_QUERY );
2430 uno::Reference< beans::XPropertySet >
2431 xPropertySet( xSettings, uno::UNO_QUERY );
2433 xPropertySet->setPropertyValue(
2434 ITEM_DESCRIPTOR_UINAME,
2435 uno::Any( pToolbar->GetName() ) );
2439 GetConfigManager()->insertSettings( pToolbar->GetCommand(), xSettings );
2441 catch ( css::uno::Exception const & )
2443 css::uno::Any ex( cppu::getCaughtException() );
2444 SAL_WARN("cui.customize", "caught exception saving settings " << exceptionToString(ex));
2447 GetEntries()->push_back( pToolbar );
2449 PersistChanges( GetConfigManager() );
2452 void ToolbarSaveInData::RemoveToolbar( SvxConfigEntry* pToolbar )
2456 OUString url = pToolbar->GetCommand();
2457 GetConfigManager()->removeSettings( url );
2458 SvxConfigPageHelper::RemoveEntry( GetEntries(), pToolbar );
2459 delete pToolbar;
2461 PersistChanges( GetConfigManager() );
2463 // remove the persistent window state data
2464 css::uno::Reference< css::container::XNameContainer > xNameContainer(
2465 m_xPersistentWindowState, css::uno::UNO_QUERY_THROW );
2467 xNameContainer->removeByName( url );
2469 catch ( uno::Exception& )
2471 // error occurred removing the settings
2475 void ToolbarSaveInData::RestoreToolbar( SvxConfigEntry* pToolbar )
2477 OUString url = pToolbar->GetCommand();
2479 // Restore of toolbar is done by removing it from
2480 // its configuration manager and then getting it again
2481 bool bParentToolbar = pToolbar->IsParentData();
2483 // Cannot restore parent toolbar
2484 if ( bParentToolbar )
2485 return;
2489 GetConfigManager()->removeSettings( url );
2490 pToolbar->GetEntries()->clear();
2491 PersistChanges( GetConfigManager() );
2493 catch ( uno::Exception& )
2495 // if an error occurs removing the settings then just return
2496 return;
2499 // Now reload the toolbar settings
2502 uno::Reference< container::XIndexAccess > xToolbarSettings;
2503 if ( IsDocConfig() )
2505 xToolbarSettings = GetParentConfigManager()->getSettings( url, false );
2506 pToolbar->SetParentData();
2508 else
2509 xToolbarSettings = GetConfigManager()->getSettings( url, false );
2511 LoadToolbar( xToolbarSettings, pToolbar );
2513 // After reloading, ensure that the icon is reset of each entry
2514 // in the toolbar
2515 uno::Sequence< OUString > aURLSeq( 1 );
2516 for (auto const& entry : *pToolbar->GetEntries())
2518 aURLSeq[ 0 ] = entry->GetCommand();
2522 GetImageManager()->removeImages( SvxConfigPageHelper::GetImageType(), aURLSeq );
2524 catch ( uno::Exception& )
2526 SAL_WARN("cui.customize", "Error restoring icon when resetting toolbar");
2529 PersistChanges( GetImageManager() );
2531 catch ( container::NoSuchElementException& )
2533 // cannot find the resource URL after removing it
2534 // so no entry will appear in the toolbar list
2538 void ToolbarSaveInData::LoadToolbar(
2539 const uno::Reference< container::XIndexAccess >& xToolbarSettings,
2540 SvxConfigEntry const * pParentData )
2542 SvxEntries* pEntries = pParentData->GetEntries();
2544 for ( sal_Int32 nIndex = 0; nIndex < xToolbarSettings->getCount(); ++nIndex )
2546 OUString aCommandURL;
2547 OUString aLabel;
2548 bool bIsVisible;
2549 sal_Int32 nStyle;
2551 sal_uInt16 nType( css::ui::ItemType::DEFAULT );
2553 bool bItem = SvxConfigPageHelper::GetToolbarItemData( xToolbarSettings, nIndex, aCommandURL,
2554 aLabel, nType, bIsVisible, nStyle );
2556 if ( bItem )
2558 bool bIsUserDefined = true;
2560 if ( nType == css::ui::ItemType::DEFAULT )
2562 uno::Any a;
2565 a = m_xCommandToLabelMap->getByName( aCommandURL );
2566 bIsUserDefined = false;
2568 catch ( container::NoSuchElementException& )
2570 bIsUserDefined = true;
2573 bool bUseDefaultLabel = false;
2574 // If custom label not set retrieve it from the command
2575 // to info service
2576 if ( aLabel.isEmpty() )
2578 bUseDefaultLabel = true;
2579 uno::Sequence< beans::PropertyValue > aPropSeq;
2580 if ( a >>= aPropSeq )
2582 for ( sal_Int32 i = 0; i < aPropSeq.getLength(); ++i )
2584 if ( aPropSeq[i].Name == "Name" )
2586 aPropSeq[i].Value >>= aLabel;
2587 break;
2593 SvxConfigEntry* pEntry = new SvxConfigEntry(
2594 aLabel, aCommandURL, false, /*bParentData*/false );
2596 pEntry->SetUserDefined( bIsUserDefined );
2597 pEntry->SetVisible( bIsVisible );
2598 pEntry->SetStyle( nStyle );
2600 if ( !bUseDefaultLabel )
2601 pEntry->SetName( aLabel );
2603 pEntries->push_back( pEntry );
2605 else
2607 SvxConfigEntry* pEntry = new SvxConfigEntry;
2608 pEntry->SetUserDefined( bIsUserDefined );
2609 pEntries->push_back( pEntry );
2615 SvxNewToolbarDialog::SvxNewToolbarDialog(weld::Window* pWindow, const OUString& rName)
2616 : GenericDialogController(pWindow, "cui/ui/newtoolbardialog.ui", "NewToolbarDialog")
2617 , m_xEdtName(m_xBuilder->weld_entry("edit"))
2618 , m_xBtnOK(m_xBuilder->weld_button("ok"))
2619 , m_xSaveInListBox(m_xBuilder->weld_combo_box("savein"))
2621 m_xEdtName->set_text(rName);
2622 m_xEdtName->select_region(0, -1);
2625 SvxNewToolbarDialog::~SvxNewToolbarDialog()
2629 /*******************************************************************************
2631 * The SvxIconSelectorDialog class
2633 *******************************************************************************/
2634 SvxIconSelectorDialog::SvxIconSelectorDialog(weld::Window *pWindow,
2635 const uno::Reference< css::ui::XImageManager >& rXImageManager,
2636 const uno::Reference< css::ui::XImageManager >& rXParentImageManager)
2637 : GenericDialogController(pWindow, "cui/ui/iconselectordialog.ui", "IconSelector")
2638 , m_xImageManager(rXImageManager)
2639 , m_xParentImageManager(rXParentImageManager)
2640 , m_xTbSymbol(new SvtValueSet(m_xBuilder->weld_scrolled_window("symbolswin")))
2641 , m_xTbSymbolWin(new weld::CustomWeld(*m_xBuilder, "symbolsToolbar", *m_xTbSymbol))
2642 , m_xFtNote(m_xBuilder->weld_label("noteLabel"))
2643 , m_xBtnImport(m_xBuilder->weld_button("importButton"))
2644 , m_xBtnDelete(m_xBuilder->weld_button("deleteButton"))
2646 typedef std::unordered_map< OUString, bool > ImageInfo;
2648 m_nExpectedSize = 16;
2649 if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_LARGE)
2650 m_nExpectedSize = 24;
2651 else if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_32)
2652 m_nExpectedSize = 32;
2654 if ( m_nExpectedSize != 16 )
2656 m_xFtNote->set_label(SvxConfigPageHelper::replaceSixteen(m_xFtNote->get_label(), m_nExpectedSize));
2659 m_xTbSymbol->SetStyle(m_xTbSymbol->GetStyle() | WB_ITEMBORDER | WB_VSCROLL);
2660 m_xTbSymbol->SetColCount(11);
2661 m_xTbSymbol->SetLineCount(5);
2662 m_xTbSymbol->SetItemWidth(m_nExpectedSize);
2663 m_xTbSymbol->SetItemHeight(m_nExpectedSize);
2664 m_xTbSymbol->SetExtraSpacing(6);
2665 Size aSize(m_xTbSymbol->CalcWindowSizePixel(Size(m_nExpectedSize, m_nExpectedSize), 11, 5));
2666 m_xTbSymbol->set_size_request(aSize.Width(), aSize.Height());
2668 uno::Reference< uno::XComponentContext > xComponentContext =
2669 ::comphelper::getProcessComponentContext();
2671 m_xGraphProvider.set( graphic::GraphicProvider::create( xComponentContext ) );
2673 uno::Reference< css::util::XPathSettings > xPathSettings =
2674 css::util::thePathSettings::get( xComponentContext );
2677 OUString aDirectory = xPathSettings->getUserConfig();
2679 sal_Int32 aCount = aDirectory.getLength();
2681 if ( aCount > 0 )
2683 sal_Unicode aChar = aDirectory[ aCount-1 ];
2684 if ( aChar != '/')
2686 aDirectory += "/";
2689 else
2691 m_xBtnImport->set_sensitive(false);
2694 aDirectory += "soffice.cfg/import";
2696 uno::Reference< lang::XSingleServiceFactory > xStorageFactory(
2697 css::embed::FileSystemStorageFactory::create( xComponentContext ) );
2699 uno::Sequence< uno::Any > aArgs( 2 );
2700 aArgs[ 0 ] <<= aDirectory;
2701 aArgs[ 1 ] <<= css::embed::ElementModes::READWRITE;
2703 uno::Reference< css::embed::XStorage > xStorage(
2704 xStorageFactory->createInstanceWithArguments( aArgs ), uno::UNO_QUERY );
2706 uno::Sequence<uno::Any> aProp(comphelper::InitAnyPropertySequence(
2708 {"UserConfigStorage", uno::Any(xStorage)},
2709 {"OpenMode", uno::Any(css::embed::ElementModes::READWRITE)}
2710 }));
2711 m_xImportedImageManager = css::ui::ImageManager::create( xComponentContext );
2712 m_xImportedImageManager->initialize(aProp);
2714 ImageInfo aImageInfo1;
2715 uno::Sequence< OUString > names;
2716 if ( m_xImportedImageManager.is() )
2718 names = m_xImportedImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2719 for ( sal_Int32 n = 0; n < names.getLength(); ++n )
2720 aImageInfo1.emplace( names[n], false );
2723 uno::Sequence< OUString > name( 1 );
2724 for (auto const& elem : aImageInfo1)
2726 name[ 0 ] = elem.first;
2727 uno::Sequence< uno::Reference< graphic::XGraphic> > graphics = m_xImportedImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2728 if ( graphics.getLength() > 0 )
2730 m_aGraphics.push_back(graphics[0]);
2731 Image img(graphics[0]);
2732 m_xTbSymbol->InsertItem(m_aGraphics.size(), img, elem.first);
2736 ImageInfo aImageInfo;
2738 if ( m_xParentImageManager.is() )
2740 names = m_xParentImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2741 for ( sal_Int32 n = 0; n < names.getLength(); ++n )
2742 aImageInfo.emplace( names[n], false );
2745 names = m_xImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2746 for ( sal_Int32 n = 0; n < names.getLength(); ++n )
2748 ImageInfo::iterator pIter = aImageInfo.find( names[n] );
2749 if ( pIter != aImageInfo.end() )
2750 pIter->second = true;
2751 else
2752 aImageInfo.emplace( names[n], true );
2755 // large growth factor, expecting many entries
2756 for (auto const& elem : aImageInfo)
2758 name[ 0 ] = elem.first;
2760 uno::Sequence< uno::Reference< graphic::XGraphic> > graphics;
2763 if (elem.second)
2764 graphics = m_xImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2765 else
2766 graphics = m_xParentImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2768 catch ( uno::Exception& )
2770 // can't get sequence for this name so it will not be
2771 // added to the list
2774 if ( graphics.getLength() > 0 )
2776 Image img(graphics[0]);
2777 if (!img.GetBitmapEx().IsEmpty())
2779 m_aGraphics.push_back(graphics[0]);
2780 m_xTbSymbol->InsertItem(m_aGraphics.size(), img, elem.first);
2785 m_xBtnDelete->set_sensitive( false );
2786 m_xTbSymbol->SetSelectHdl( LINK(this, SvxIconSelectorDialog, SelectHdl) );
2787 m_xBtnImport->connect_clicked( LINK(this, SvxIconSelectorDialog, ImportHdl) );
2788 m_xBtnDelete->connect_clicked( LINK(this, SvxIconSelectorDialog, DeleteHdl) );
2791 SvxIconSelectorDialog::~SvxIconSelectorDialog()
2795 uno::Reference< graphic::XGraphic> SvxIconSelectorDialog::GetSelectedIcon()
2797 uno::Reference<graphic::XGraphic> result;
2799 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2801 if (nId)
2803 result = m_aGraphics[nId - 1];
2806 return result;
2809 IMPL_LINK_NOARG(SvxIconSelectorDialog, SelectHdl, SvtValueSet*, void)
2811 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2813 if (!nId)
2815 m_xBtnDelete->set_sensitive(false);
2816 return;
2819 OUString aSelImageText = m_xTbSymbol->GetItemText(nId);
2820 if (m_xImportedImageManager->hasImage(SvxConfigPageHelper::GetImageType(), aSelImageText))
2822 m_xBtnDelete->set_sensitive(true);
2824 else
2826 m_xBtnDelete->set_sensitive(false);
2830 IMPL_LINK_NOARG(SvxIconSelectorDialog, ImportHdl, weld::Button&, void)
2832 sfx2::FileDialogHelper aImportDialog(
2833 css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW,
2834 FileDialogFlags::Graphic | FileDialogFlags::MultiSelection, m_xDialog.get());
2836 // disable the link checkbox in the dialog
2837 uno::Reference< css::ui::dialogs::XFilePickerControlAccess >
2838 xController( aImportDialog.GetFilePicker(), uno::UNO_QUERY);
2839 if ( xController.is() )
2841 xController->enableControl(
2842 css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK,
2843 false);
2846 aImportDialog.SetCurrentFilter(
2847 "PNG - Portable Network Graphic");
2849 if ( ERRCODE_NONE == aImportDialog.Execute() )
2851 uno::Sequence< OUString > paths = aImportDialog.GetMPath();
2852 ImportGraphics ( paths );
2856 IMPL_LINK_NOARG(SvxIconSelectorDialog, DeleteHdl, weld::Button&, void)
2858 OUString message = CuiResId( RID_SVXSTR_DELETE_ICON_CONFIRM );
2860 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xDialog.get(),
2861 VclMessageType::Warning, VclButtonsType::OkCancel,
2862 message));
2863 if (xWarn->run() == RET_OK)
2865 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2867 OUString aSelImageText = m_xTbSymbol->GetItemText( nId );
2868 uno::Sequence< OUString > URLs { aSelImageText };
2869 m_xTbSymbol->RemoveItem(nId);
2870 m_xImportedImageManager->removeImages( SvxConfigPageHelper::GetImageType(), URLs );
2871 uno::Reference< css::ui::XUIConfigurationPersistence >
2872 xConfigPersistence( m_xImportedImageManager, uno::UNO_QUERY );
2873 if ( xConfigPersistence.is() && xConfigPersistence->isModified() )
2875 xConfigPersistence->store();
2880 bool SvxIconSelectorDialog::ReplaceGraphicItem(
2881 const OUString& aURL )
2883 uno::Sequence< OUString > URLs(1);
2884 uno::Sequence< uno::Reference<graphic::XGraphic > > aImportGraph( 1 );
2885 uno::Reference< css::ui::XUIConfigurationPersistence >
2886 xConfigPer( m_xImportedImageManager, uno::UNO_QUERY );
2888 uno::Reference< graphic::XGraphic > xGraphic;
2889 uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
2890 aMediaProps[0].Name = "URL";
2891 aMediaProps[0].Value <<= aURL;
2893 css::awt::Size aSize;
2894 bool bOK = false;
2897 xGraphic = m_xGraphProvider->queryGraphic( aMediaProps );
2899 uno::Reference< beans::XPropertySet > props =
2900 m_xGraphProvider->queryGraphicDescriptor( aMediaProps );
2901 uno::Any a = props->getPropertyValue( "SizePixel" );
2902 a >>= aSize;
2903 if (0 == aSize.Width || 0 == aSize.Height)
2904 return false;
2905 else
2906 bOK = true;
2908 catch ( uno::Exception& )
2910 return false;
2913 bool bResult( false );
2914 size_t nCount = m_xTbSymbol->GetItemCount();
2915 for (size_t n = 0; n < nCount; ++n)
2917 sal_uInt16 nId = m_xTbSymbol->GetItemId( n );
2919 if ( m_xTbSymbol->GetItemText( nId ) == aURL )
2923 // replace/insert image with provided URL
2924 size_t nPos = nId - 1;
2925 assert(nPos == m_xTbSymbol->GetItemPos(nId));
2926 m_xTbSymbol->RemoveItem(nId);
2927 aMediaProps[0].Value <<= aURL;
2929 Image aImage( xGraphic );
2930 if ( bOK && ((aSize.Width != m_nExpectedSize) || (aSize.Height != m_nExpectedSize)) )
2932 BitmapEx aBitmap = aImage.GetBitmapEx();
2933 BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, m_nExpectedSize);
2934 aImage = Image( aBitmapex);
2936 m_xTbSymbol->InsertItem(nId, aImage, aURL, nPos); //modify
2938 m_aGraphics[nPos] = Graphic(aImage.GetBitmapEx()).GetXGraphic();
2940 URLs[0] = aURL;
2941 aImportGraph[ 0 ] = xGraphic;
2942 m_xImportedImageManager->replaceImages( SvxConfigPageHelper::GetImageType(), URLs, aImportGraph );
2943 xConfigPer->store();
2945 bResult = true;
2946 break;
2948 catch ( css::uno::Exception& )
2950 break;
2955 return bResult;
2958 namespace
2960 OUString ReplaceIconName(const OUString& rMessage)
2962 OUString name;
2963 OUString message = CuiResId( RID_SVXSTR_REPLACE_ICON_WARNING );
2964 OUString placeholder("%ICONNAME" );
2965 sal_Int32 pos = message.indexOf( placeholder );
2966 if ( pos != -1 )
2968 name = message.replaceAt(
2969 pos, placeholder.getLength(), rMessage );
2971 return name;
2974 class SvxIconReplacementDialog
2976 private:
2977 std::unique_ptr<weld::MessageDialog> m_xQueryBox;
2978 public:
2979 SvxIconReplacementDialog(weld::Window *pParent, const OUString& rMessage, bool bYestoAll)
2980 : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Warning, VclButtonsType::NONE, ReplaceIconName(rMessage)))
2982 m_xQueryBox->set_title(CuiResId(RID_SVXSTR_REPLACE_ICON_CONFIRM));
2983 m_xQueryBox->add_button(Button::GetStandardText(StandardButtonType::Yes), 2);
2984 if (bYestoAll)
2985 m_xQueryBox->add_button(CuiResId(RID_SVXSTR_YESTOALL), 5);
2986 m_xQueryBox->add_button(Button::GetStandardText(StandardButtonType::No), 4);
2987 m_xQueryBox->add_button(Button::GetStandardText(StandardButtonType::Cancel), 6);
2988 m_xQueryBox->set_default_response(2);
2990 short run() { return m_xQueryBox->run(); }
2994 void SvxIconSelectorDialog::ImportGraphics(
2995 const uno::Sequence< OUString >& rPaths )
2997 uno::Sequence< OUString > rejected( rPaths.getLength() );
2998 sal_Int32 rejectedCount = 0;
3000 sal_uInt16 ret = 0;
3001 sal_Int32 aIndex;
3002 OUString aIconName;
3004 if ( rPaths.getLength() == 1 )
3006 if ( m_xImportedImageManager->hasImage( SvxConfigPageHelper::GetImageType(), rPaths[0] ) )
3008 aIndex = rPaths[0].lastIndexOf( '/' );
3009 aIconName = rPaths[0].copy( aIndex+1 );
3010 SvxIconReplacementDialog aDlg(m_xDialog.get(), aIconName, false);
3011 ret = aDlg.run();
3012 if ( ret == 2 )
3014 ReplaceGraphicItem( rPaths[0] );
3017 else
3019 if ( !ImportGraphic( rPaths[0] ) )
3021 rejected[0] = rPaths[0];
3022 rejectedCount = 1;
3026 else
3028 OUString aSourcePath( rPaths[0] );
3029 if ( rPaths[0].lastIndexOf( '/' ) != rPaths[0].getLength() -1 )
3030 aSourcePath = rPaths[0] + "/";
3032 for ( sal_Int32 i = 1; i < rPaths.getLength(); ++i )
3034 OUString aPath = aSourcePath + rPaths[i];
3035 if ( m_xImportedImageManager->hasImage( SvxConfigPageHelper::GetImageType(), aPath ) )
3037 aIndex = rPaths[i].lastIndexOf( '/' );
3038 aIconName = rPaths[i].copy( aIndex+1 );
3039 SvxIconReplacementDialog aDlg(m_xDialog.get(), aIconName, true);
3040 ret = aDlg.run();
3041 if ( ret == 2 )
3043 ReplaceGraphicItem( aPath );
3045 else if ( ret == 5 )
3047 for ( sal_Int32 k = i; k < rPaths.getLength(); ++k )
3049 aPath = aSourcePath + rPaths[k];
3050 bool bHasReplaced = ReplaceGraphicItem( aPath );
3052 if ( !bHasReplaced )
3054 bool result = ImportGraphic( aPath );
3055 if ( !result )
3057 rejected[ rejectedCount ] = rPaths[i];
3058 ++rejectedCount;
3062 break;
3065 else
3067 bool result = ImportGraphic( aSourcePath + rPaths[i] );
3068 if ( !result )
3070 rejected[ rejectedCount ] = rPaths[i];
3071 ++rejectedCount;
3077 if ( rejectedCount != 0 )
3079 OUStringBuffer message;
3080 OUString fPath;
3081 if (rejectedCount > 1)
3082 fPath = rPaths[0].copy(8) + "/";
3083 for ( sal_Int32 i = 0; i < rejectedCount; ++i )
3085 message.append(fPath).append(rejected[i]).append("\n");
3088 SvxIconChangeDialog aDialog(m_xDialog.get(), message.makeStringAndClear());
3089 aDialog.run();
3093 bool SvxIconSelectorDialog::ImportGraphic( const OUString& aURL )
3095 bool result = false;
3097 uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
3098 aMediaProps[0].Name = "URL";
3100 uno::Reference< graphic::XGraphic > xGraphic;
3101 css::awt::Size aSize;
3102 aMediaProps[0].Value <<= aURL;
3105 uno::Reference< beans::XPropertySet > props =
3106 m_xGraphProvider->queryGraphicDescriptor( aMediaProps );
3108 uno::Any a = props->getPropertyValue("SizePixel");
3110 xGraphic = m_xGraphProvider->queryGraphic( aMediaProps );
3111 if ( xGraphic.is() )
3113 bool bOK = true;
3115 a >>= aSize;
3116 if ( 0 == aSize.Width || 0 == aSize.Height )
3117 bOK = false;
3119 Image aImage( xGraphic );
3121 if ( bOK && ((aSize.Width != m_nExpectedSize) || (aSize.Height != m_nExpectedSize)) )
3123 BitmapEx aBitmap = aImage.GetBitmapEx();
3124 BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, m_nExpectedSize);
3125 aImage = Image( aBitmapex);
3127 if ( bOK && !!aImage )
3129 m_aGraphics.push_back(Graphic(aImage.GetBitmapEx()).GetXGraphic());
3130 m_xTbSymbol->InsertItem(m_aGraphics.size(), aImage, aURL);
3132 uno::Sequence<OUString> aImportURL { aURL };
3133 uno::Sequence< uno::Reference<graphic::XGraphic > > aImportGraph( 1 );
3134 aImportGraph[ 0 ] = xGraphic;
3135 m_xImportedImageManager->insertImages( SvxConfigPageHelper::GetImageType(), aImportURL, aImportGraph );
3136 uno::Reference< css::ui::XUIConfigurationPersistence >
3137 xConfigPersistence( m_xImportedImageManager, uno::UNO_QUERY );
3139 if ( xConfigPersistence.is() && xConfigPersistence->isModified() )
3141 xConfigPersistence->store();
3144 result = true;
3146 else
3148 SAL_WARN("cui.customize", "could not create Image from XGraphic");
3151 else
3153 SAL_WARN("cui.customize", "could not get query XGraphic");
3156 catch( uno::Exception const & )
3158 css::uno::Any ex( cppu::getCaughtException() );
3159 SAL_WARN("cui.customize", "Caught exception importing XGraphic: " << exceptionToString(ex));
3161 return result;
3164 /*******************************************************************************
3166 * The SvxIconChangeDialog class added for issue83555
3168 *******************************************************************************/
3169 SvxIconChangeDialog::SvxIconChangeDialog(weld::Window *pWindow, const OUString& rMessage)
3170 : MessageDialogController(pWindow, "cui/ui/iconchangedialog.ui", "IconChange", "grid")
3171 , m_xLineEditDescription(m_xBuilder->weld_text_view("addrTextview"))
3173 m_xLineEditDescription->set_size_request(m_xLineEditDescription->get_approximate_digit_width() * 48,
3174 m_xLineEditDescription->get_text_height() * 8);
3175 m_xLineEditDescription->set_text(rMessage);
3178 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */