sd: keep a non-owning pointer to the OverridingShell
[LibreOffice.git] / cui / source / customize / cfg.cxx
blob0bd6b44ede66dfc888a4946e1eb963be70703116
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 <utility>
28 #include <vcl/stdtext.hxx>
29 #include <vcl/commandinfoprovider.hxx>
30 #include <vcl/event.hxx>
31 #include <vcl/graph.hxx>
32 #include <vcl/graphicfilter.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>
39 #include <sfx2/minfitem.hxx>
40 #include <sfx2/sfxhelp.hxx>
41 #include <sfx2/viewfrm.hxx>
42 #include <sfx2/filedlghelper.hxx>
43 #include <sfx2/sfxsids.hrc>
44 #include <svl/stritem.hxx>
45 #include <rtl/ustrbuf.hxx>
46 #include <tools/debug.hxx>
47 #include <comphelper/diagnose_ex.hxx>
48 #include <toolkit/helper/vclunohelper.hxx>
50 #include <algorithm>
51 #include <strings.hrc>
53 #include <acccfg.hxx>
54 #include <cfg.hxx>
55 #include <CustomNotebookbarGenerator.hxx>
56 #include <SvxMenuConfigPage.hxx>
57 #include <SvxToolbarConfigPage.hxx>
58 #include <SvxNotebookbarConfigPage.hxx>
59 #include <SvxConfigPageHelper.hxx>
60 #include "eventdlg.hxx"
61 #include <dialmgr.hxx>
63 #include <unotools/configmgr.hxx>
64 #include <com/sun/star/container/XNameContainer.hpp>
65 #include <com/sun/star/embed/ElementModes.hpp>
66 #include <com/sun/star/embed/FileSystemStorageFactory.hpp>
67 #include <com/sun/star/frame/ModuleManager.hpp>
68 #include <com/sun/star/frame/XFrames.hpp>
69 #include <com/sun/star/frame/XLayoutManager.hpp>
70 #include <com/sun/star/frame/FrameSearchFlag.hpp>
71 #include <com/sun/star/frame/XController.hpp>
72 #include <com/sun/star/frame/Desktop.hpp>
73 #include <com/sun/star/frame/theUICommandDescription.hpp>
74 #include <com/sun/star/graphic/GraphicProvider.hpp>
75 #include <com/sun/star/io/IOException.hpp>
76 #include <com/sun/star/ui/ItemType.hpp>
77 #include <com/sun/star/ui/ItemStyle.hpp>
78 #include <com/sun/star/ui/ImageManager.hpp>
79 #include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
80 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
81 #include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
82 #include <com/sun/star/ui/XUIElement.hpp>
83 #include <com/sun/star/ui/UIElementType.hpp>
84 #include <com/sun/star/ui/ImageType.hpp>
85 #include <com/sun/star/ui/theWindowStateConfiguration.hpp>
86 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
87 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
88 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
89 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
90 #include <com/sun/star/util/thePathSettings.hpp>
91 #include <comphelper/documentinfo.hxx>
92 #include <comphelper/propertysequence.hxx>
93 #include <comphelper/propertyvalue.hxx>
94 #include <comphelper/processfactory.hxx>
95 #include <config_features.h>
97 namespace uno = css::uno;
98 namespace frame = css::frame;
99 namespace lang = css::lang;
100 namespace container = css::container;
101 namespace beans = css::beans;
102 namespace graphic = css::graphic;
104 #if OSL_DEBUG_LEVEL > 1
106 void printPropertySet(
107 const OUString& prefix,
108 const uno::Reference< beans::XPropertySet >& xPropSet )
110 uno::Reference< beans::XPropertySetInfo > xPropSetInfo =
111 xPropSet->getPropertySetInfo();
113 const uno::Sequence< beans::Property >& aPropDetails =
114 xPropSetInfo->getProperties();
116 SAL_WARN("cui", "printPropertySet: " << aPropDetails.getLength() << " properties" );
118 for ( beans::Property const & aPropDetail : aPropDetails )
120 OUString tmp;
121 sal_Int32 ival;
123 uno::Any a = xPropSet->getPropertyValue( aPropDetail.Name );
125 if ( a >>= tmp )
127 SAL_WARN("cui", prefix << ": Got property: " << aPropDetail.Name << tmp);
129 else if ( ( a >>= ival ) )
131 SAL_WARN("cui", prefix << ": Got property: " << aPropDetail.Name << " = " << ival);
133 else
135 SAL_WARN("cui", prefix << ": Got property: " << aPropDetail.Name << " of type " << a.getValueTypeName());
140 void printProperties(
141 const OUString& prefix,
142 const uno::Sequence< beans::PropertyValue >& aProp )
144 for (beans::PropertyValue const & aPropVal : aProp)
146 OUString tmp;
148 aPropVal.Value >>= tmp;
150 SAL_WARN("cui", prefix << ": Got property: " << aPropVal.Name << " = " << tmp);
154 void printEntries(SvxEntries* entries)
156 for (auto const& entry : *entries)
158 SAL_WARN("cui", "printEntries: " << entry->GetName());
162 #endif
164 bool
165 SvxConfigPage::CanConfig( std::u16string_view aModuleId )
167 return aModuleId != u"com.sun.star.script.BasicIDE" && aModuleId != u"com.sun.star.frame.Bibliography";
170 static std::unique_ptr<SfxTabPage> CreateSvxMenuConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
172 return std::make_unique<SvxMenuConfigPage>(pPage, pController, *rSet);
175 static std::unique_ptr<SfxTabPage> CreateSvxContextMenuConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
177 return std::make_unique<SvxMenuConfigPage>(pPage, pController, *rSet, false);
180 static std::unique_ptr<SfxTabPage> CreateKeyboardConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
182 return std::make_unique<SfxAcceleratorConfigPage>(pPage, pController, *rSet);
185 static std::unique_ptr<SfxTabPage> CreateSvxNotebookbarConfigPage(weld::Container* pPage, weld::DialogController* pController,
186 const SfxItemSet* rSet)
188 return std::make_unique<SvxNotebookbarConfigPage>(pPage, pController, *rSet);
191 static std::unique_ptr<SfxTabPage> CreateSvxToolbarConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
193 return std::make_unique<SvxToolbarConfigPage>(pPage, pController, *rSet);
196 static std::unique_ptr<SfxTabPage> CreateSvxEventConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
198 return std::make_unique<SvxEventConfigPage>(pPage, pController, *rSet, SvxEventConfigPage::EarlyInit());
201 /******************************************************************************
203 * SvxConfigDialog is the configuration dialog which is brought up from the
204 * Tools menu. It includes tabs for customizing menus, toolbars, events and
205 * key bindings.
207 *****************************************************************************/
208 SvxConfigDialog::SvxConfigDialog(weld::Window * pParent, const SfxItemSet* pInSet)
209 : SfxTabDialogController(pParent, u"cui/ui/customizedialog.ui"_ustr, u"CustomizeDialog"_ustr, pInSet)
211 SvxConfigPageHelper::InitImageType();
213 AddTabPage(u"menus"_ustr, CreateSvxMenuConfigPage, nullptr);
214 AddTabPage(u"toolbars"_ustr, CreateSvxToolbarConfigPage, nullptr);
215 AddTabPage(u"notebookbar"_ustr, CreateSvxNotebookbarConfigPage, nullptr);
216 AddTabPage(u"contextmenus"_ustr, CreateSvxContextMenuConfigPage, nullptr);
217 AddTabPage(u"keyboard"_ustr, CreateKeyboardConfigPage, nullptr);
218 AddTabPage(u"events"_ustr, CreateSvxEventConfigPage, nullptr);
220 if (const SfxPoolItem* pItem = pInSet->GetItem(SID_CONFIG))
222 OUString text = static_cast<const SfxStringItem*>(pItem)->GetValue();
223 if (text.startsWith( ITEM_TOOLBAR_URL ) )
224 SetCurPageId(u"toolbars"_ustr);
225 else if (text.startsWith( ITEM_EVENT_URL) )
226 SetCurPageId(u"events"_ustr);
228 #if HAVE_FEATURE_SCRIPTING
229 else if (pInSet->GetItemIfSet(SID_MACROINFO))
231 // for the "assign" button in the Basic Macros chooser automatically switch
232 // to the keyboard tab in which this macro will be pre-selected for assigning
233 // to a keystroke
234 SetCurPageId(u"keyboard"_ustr);
236 #endif
239 void SvxConfigDialog::ActivatePage(const OUString& rPage)
241 SfxTabDialogController::ActivatePage(rPage);
242 GetResetButton()->set_visible(rPage != "keyboard");
245 void SvxConfigDialog::SetFrame(const css::uno::Reference<css::frame::XFrame>& xFrame)
247 m_xFrame = xFrame;
248 OUString aModuleId = SvxConfigPage::GetFrameWithDefaultAndIdentify(m_xFrame);
250 if (aModuleId != "com.sun.star.text.TextDocument" &&
251 aModuleId != "com.sun.star.sheet.SpreadsheetDocument" &&
252 aModuleId != "com.sun.star.presentation.PresentationDocument" &&
253 aModuleId != "com.sun.star.drawing.DrawingDocument")
254 RemoveTabPage(u"notebookbar"_ustr);
256 if (aModuleId == "com.sun.star.frame.StartModule")
257 RemoveTabPage(u"keyboard"_ustr);
260 void SvxConfigDialog::PageCreated(const OUString &rId, SfxTabPage& rPage)
262 if (rId == "menus" || rId == "keyboard" || rId == "notebookbar"
263 || rId == "toolbars" || rId == "contextmenus")
265 rPage.SetFrame(m_xFrame);
267 else if (rId == "events")
269 dynamic_cast< SvxEventConfigPage& >( rPage ).LateInit( m_xFrame );
273 /******************************************************************************
275 * The SaveInData class is used to hold data for entries in the Save In
276 * ListBox controls in the menu and toolbar tabs
278 ******************************************************************************/
280 // Initialize static variable which holds default XImageManager
281 uno::Reference< css::ui::XImageManager>* SaveInData::xDefaultImgMgr = nullptr;
283 SaveInData::SaveInData(
284 uno::Reference< css::ui::XUIConfigurationManager > xCfgMgr,
285 uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr,
286 const OUString& aModuleId,
287 bool isDocConfig )
289 bModified( false ),
290 bDocConfig( isDocConfig ),
291 bReadOnly( false ),
292 m_xCfgMgr(std::move( xCfgMgr )),
293 m_xParentCfgMgr(std::move( xParentCfgMgr )),
294 m_aSeparatorSeq{ comphelper::makePropertyValue(ITEM_DESCRIPTOR_TYPE,
295 css::ui::ItemType::SEPARATOR_LINE) }
297 if ( bDocConfig )
299 uno::Reference< css::ui::XUIConfigurationPersistence >
300 xDocPersistence( GetConfigManager(), uno::UNO_QUERY );
302 bReadOnly = xDocPersistence->isReadOnly();
305 const uno::Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();
307 uno::Reference< container::XNameAccess > xNameAccess(
308 css::frame::theUICommandDescription::get(xContext) );
310 xNameAccess->getByName( aModuleId ) >>= m_xCommandToLabelMap;
312 if ( !m_xImgMgr.is() )
314 m_xImgMgr.set( GetConfigManager()->getImageManager(), uno::UNO_QUERY );
317 if ( !IsDocConfig() )
319 // If this is not a document configuration then it is the settings
320 // for the module (writer, calc, impress etc.) Use this as the default
321 // XImageManager instance
322 xDefaultImgMgr = &m_xImgMgr;
324 else
326 // If this is a document configuration then use the module image manager
327 // as default.
328 if ( m_xParentCfgMgr.is() )
330 m_xParentImgMgr.set( m_xParentCfgMgr->getImageManager(), uno::UNO_QUERY );
331 xDefaultImgMgr = &m_xParentImgMgr;
336 uno::Reference<graphic::XGraphic> SaveInData::GetImage(const OUString& rCommandURL)
338 uno::Reference< graphic::XGraphic > xGraphic =
339 SvxConfigPageHelper::GetGraphic( m_xImgMgr, rCommandURL );
341 if (!xGraphic.is() && xDefaultImgMgr != nullptr && (*xDefaultImgMgr).is())
343 xGraphic = SvxConfigPageHelper::GetGraphic( (*xDefaultImgMgr), rCommandURL );
346 return xGraphic;
349 bool SaveInData::PersistChanges(
350 const uno::Reference< uno::XInterface >& xManager )
352 bool result = true;
356 if ( xManager.is() && !IsReadOnly() )
358 uno::Reference< css::ui::XUIConfigurationPersistence >
359 xConfigPersistence( xManager, uno::UNO_QUERY );
361 if ( xConfigPersistence->isModified() )
363 xConfigPersistence->store();
367 catch ( css::io::IOException& )
369 result = false;
372 return result;
375 /******************************************************************************
377 * The MenuSaveInData class extends SaveInData and provides menu specific
378 * load and store functionality.
380 ******************************************************************************/
382 // Initialize static variable which holds default Menu data
383 MenuSaveInData* MenuSaveInData::pDefaultData = nullptr;
385 MenuSaveInData::MenuSaveInData(
386 const uno::Reference< css::ui::XUIConfigurationManager >& cfgmgr,
387 const uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
388 const OUString& aModuleId,
389 bool isDocConfig )
391 SaveInData( cfgmgr, xParentCfgMgr, aModuleId, isDocConfig ),
392 m_aMenuResourceURL(
393 ITEM_MENUBAR_URL ),
394 m_aDescriptorContainer(
395 ITEM_DESCRIPTOR_CONTAINER )
399 m_xMenuSettings = GetConfigManager()->getSettings( ITEM_MENUBAR_URL, false );
401 catch ( container::NoSuchElementException& )
403 // will use menu settings for the module
406 // If this is not a document configuration then it is the settings
407 // for the module (writer, calc, impress etc.). These settings should
408 // be set as the default to be used for SaveIn locations that do not
409 // have custom settings
410 if ( !IsDocConfig() )
412 SetDefaultData( this );
416 MenuSaveInData::~MenuSaveInData()
420 SvxEntries*
421 MenuSaveInData::GetEntries()
423 if ( pRootEntry == nullptr )
425 pRootEntry.reset( new SvxConfigEntry( u"MainMenus"_ustr, OUString(), true, /*bParentData*/false) );
427 if ( m_xMenuSettings.is() )
429 LoadSubMenus( m_xMenuSettings, OUString(), pRootEntry.get(), false );
431 else if ( GetDefaultData() != nullptr )
433 // If the doc has no config settings use module config settings
434 LoadSubMenus( GetDefaultData()->m_xMenuSettings, OUString(), pRootEntry.get(), false );
438 return pRootEntry->GetEntries();
441 void
442 MenuSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
444 pRootEntry->SetEntries( std::move(pNewEntries) );
447 void SaveInData::LoadSubMenus( const uno::Reference< container::XIndexAccess >& xMenuSettings,
448 const OUString& rBaseTitle, SvxConfigEntry const * pParentData, bool bContextMenu )
450 SvxEntries* pEntries = pParentData->GetEntries();
452 // Don't access non existing menu configuration!
453 if ( !xMenuSettings.is() )
454 return;
456 for ( sal_Int32 nIndex = 0; nIndex < xMenuSettings->getCount(); ++nIndex )
458 uno::Reference< container::XIndexAccess > xSubMenu;
459 OUString aCommandURL;
460 OUString aLabel;
462 sal_uInt16 nType( css::ui::ItemType::DEFAULT );
463 sal_Int32 nStyle(0);
465 bool bItem = SvxConfigPageHelper::GetMenuItemData( xMenuSettings, nIndex,
466 aCommandURL, aLabel, nType, nStyle, xSubMenu );
468 if ( bItem )
470 bool bIsUserDefined = true;
472 if ( nType == css::ui::ItemType::DEFAULT )
474 uno::Any a;
477 a = m_xCommandToLabelMap->getByName( aCommandURL );
478 bIsUserDefined = false;
480 catch ( container::NoSuchElementException& )
482 bIsUserDefined = true;
485 bool bUseDefaultLabel = false;
486 // If custom label not set retrieve it from the command
487 // to info service
488 if ( aLabel.isEmpty() )
490 bUseDefaultLabel = true;
491 uno::Sequence< beans::PropertyValue > aPropSeq;
492 if ( a >>= aPropSeq )
494 OUString aMenuLabel;
495 for (const beans::PropertyValue& prop : aPropSeq)
497 if ( bContextMenu )
499 if ( prop.Name == "PopupLabel" )
501 prop.Value >>= aLabel;
502 break;
504 else if ( prop.Name == "Label" )
506 prop.Value >>= aMenuLabel;
509 else if ( prop.Name == "Label" )
511 prop.Value >>= aLabel;
512 break;
515 if ( aLabel.isEmpty() )
516 aLabel = aMenuLabel;
520 SvxConfigEntry* pEntry = new SvxConfigEntry(
521 aLabel, aCommandURL, xSubMenu.is(), /*bParentData*/false );
523 pEntry->SetStyle( nStyle );
524 pEntry->SetUserDefined( bIsUserDefined );
525 if ( !bUseDefaultLabel )
526 pEntry->SetName( aLabel );
528 pEntries->push_back( pEntry );
530 if ( xSubMenu.is() )
532 // popup menu
533 OUString subMenuTitle( rBaseTitle );
535 if ( !subMenuTitle.isEmpty() )
537 subMenuTitle += aMenuSeparatorStr;
539 else
541 pEntry->SetMain();
544 subMenuTitle += SvxConfigPageHelper::stripHotKey( aLabel );
546 LoadSubMenus( xSubMenu, subMenuTitle, pEntry, bContextMenu );
549 else
551 SvxConfigEntry* pEntry = new SvxConfigEntry;
552 pEntry->SetUserDefined( bIsUserDefined );
553 pEntries->push_back( pEntry );
559 bool MenuSaveInData::Apply()
561 bool result = false;
563 if ( IsModified() )
565 // Apply new menu bar structure to our settings container
566 m_xMenuSettings = GetConfigManager()->createSettings();
568 uno::Reference< container::XIndexContainer > xIndexContainer (
569 m_xMenuSettings, uno::UNO_QUERY );
571 uno::Reference< lang::XSingleComponentFactory > xFactory (
572 m_xMenuSettings, uno::UNO_QUERY );
574 Apply( xIndexContainer, xFactory );
578 if ( GetConfigManager()->hasSettings( m_aMenuResourceURL ) )
580 GetConfigManager()->replaceSettings(
581 m_aMenuResourceURL, m_xMenuSettings );
583 else
585 GetConfigManager()->insertSettings(
586 m_aMenuResourceURL, m_xMenuSettings );
589 catch ( css::uno::Exception& )
591 TOOLS_WARN_EXCEPTION("cui.customize", "caught some other exception saving settings");
594 SetModified( false );
596 result = PersistChanges( GetConfigManager() );
599 return result;
602 void MenuSaveInData::Apply(
603 uno::Reference< container::XIndexContainer > const & rMenuBar,
604 uno::Reference< lang::XSingleComponentFactory >& rFactory )
606 const uno::Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();
608 for (auto const& entryData : *GetEntries())
610 uno::Sequence< beans::PropertyValue > aPropValueSeq =
611 SvxConfigPageHelper::ConvertSvxConfigEntry(entryData);
613 uno::Reference< container::XIndexContainer > xSubMenuBar(
614 rFactory->createInstanceWithContext( xContext ),
615 uno::UNO_QUERY );
617 sal_Int32 nIndex = aPropValueSeq.getLength();
618 aPropValueSeq.realloc( nIndex + 1 );
619 auto pPropValueSeq = aPropValueSeq.getArray();
620 pPropValueSeq[nIndex].Name = m_aDescriptorContainer;
621 pPropValueSeq[nIndex].Value <<= xSubMenuBar;
622 rMenuBar->insertByIndex(
623 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
624 ApplyMenu( xSubMenuBar, rFactory, entryData );
628 void SaveInData::ApplyMenu(
629 uno::Reference< container::XIndexContainer > const & rMenuBar,
630 uno::Reference< lang::XSingleComponentFactory >& rFactory,
631 SvxConfigEntry* pMenuData )
633 const uno::Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();
635 for (auto const& entry : *pMenuData->GetEntries())
637 if (entry->IsPopup())
639 uno::Sequence< beans::PropertyValue > aPropValueSeq =
640 SvxConfigPageHelper::ConvertSvxConfigEntry(entry);
642 uno::Reference< container::XIndexContainer > xSubMenuBar(
643 rFactory->createInstanceWithContext( xContext ),
644 uno::UNO_QUERY );
646 sal_Int32 nIndex = aPropValueSeq.getLength();
647 aPropValueSeq.realloc( nIndex + 1 );
648 auto pPropValueSeq = aPropValueSeq.getArray();
649 pPropValueSeq[nIndex].Name = ITEM_DESCRIPTOR_CONTAINER;
650 pPropValueSeq[nIndex].Value <<= xSubMenuBar;
652 rMenuBar->insertByIndex(
653 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
655 ApplyMenu( xSubMenuBar, rFactory, entry );
656 entry->SetModified( false );
658 else if (entry->IsSeparator())
660 rMenuBar->insertByIndex(
661 rMenuBar->getCount(), uno::Any( m_aSeparatorSeq ));
663 else
665 uno::Sequence< beans::PropertyValue > aPropValueSeq =
666 SvxConfigPageHelper::ConvertSvxConfigEntry(entry);
667 rMenuBar->insertByIndex(
668 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
671 pMenuData->SetModified( false );
674 void
675 MenuSaveInData::Reset()
679 GetConfigManager()->removeSettings( m_aMenuResourceURL );
681 catch ( const css::uno::Exception& )
684 PersistChanges( GetConfigManager() );
686 pRootEntry.reset();
690 m_xMenuSettings = GetConfigManager()->getSettings(
691 m_aMenuResourceURL, false );
693 catch ( container::NoSuchElementException& )
695 // will use default settings
699 ContextMenuSaveInData::ContextMenuSaveInData(
700 const css::uno::Reference< css::ui::XUIConfigurationManager >& xCfgMgr,
701 const css::uno::Reference< css::ui::XUIConfigurationManager >& xParentCfgMgr,
702 const OUString& aModuleId, bool bIsDocConfig )
703 : SaveInData( xCfgMgr, xParentCfgMgr, aModuleId, bIsDocConfig )
705 const css::uno::Reference< css::uno::XComponentContext >& xContext( comphelper::getProcessComponentContext() );
706 css::uno::Reference< css::container::XNameAccess > xConfig( css::ui::theWindowStateConfiguration::get( xContext ) );
707 xConfig->getByName( aModuleId ) >>= m_xPersistentWindowState;
710 ContextMenuSaveInData::~ContextMenuSaveInData()
714 OUString ContextMenuSaveInData::GetUIName( const OUString& rResourceURL )
716 if ( m_xPersistentWindowState.is() )
718 css::uno::Sequence< css::beans::PropertyValue > aProps;
721 m_xPersistentWindowState->getByName( rResourceURL ) >>= aProps;
723 catch ( const css::uno::Exception& )
726 for (const auto& aProp : aProps)
728 if ( aProp.Name == ITEM_DESCRIPTOR_UINAME )
730 OUString aResult;
731 aProp.Value >>= aResult;
732 return aResult;
736 return OUString();
739 SvxEntries* ContextMenuSaveInData::GetEntries()
741 if ( !m_pRootEntry )
743 std::unordered_map< OUString, bool > aMenuInfo;
745 m_pRootEntry.reset( new SvxConfigEntry( u"ContextMenus"_ustr, OUString(), true, /*bParentData*/false ) );
746 css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aElementsInfo;
749 aElementsInfo = GetConfigManager()->getUIElementsInfo( css::ui::UIElementType::POPUPMENU );
751 catch ( const css::lang::IllegalArgumentException& )
754 for (const auto& aElement : aElementsInfo)
756 OUString aUrl;
757 for ( const auto& aElementProp : aElement )
759 if ( aElementProp.Name == ITEM_DESCRIPTOR_RESOURCEURL )
761 aElementProp.Value >>= aUrl;
762 break;
766 css::uno::Reference< css::container::XIndexAccess > xPopupMenu;
769 xPopupMenu = GetConfigManager()->getSettings( aUrl, false );
771 catch ( const css::uno::Exception& )
774 if ( xPopupMenu.is() )
776 // insert into std::unordered_map to filter duplicates from the parent
777 aMenuInfo.emplace( aUrl, true );
779 OUString aUIMenuName = GetUIName( aUrl );
780 if ( aUIMenuName.isEmpty() )
781 // Menus without UI name aren't supposed to be customized.
782 continue;
784 SvxConfigEntry* pEntry = new SvxConfigEntry( aUIMenuName, aUrl, true, /*bParentData*/false );
785 pEntry->SetMain();
786 m_pRootEntry->GetEntries()->push_back( pEntry );
787 LoadSubMenus( xPopupMenu, aUIMenuName, pEntry, true );
791 // Retrieve also the parent menus, to make it possible to configure module menus and save them into the document.
792 css::uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr = GetParentConfigManager();
793 css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aParentElementsInfo;
796 if ( xParentCfgMgr.is() )
797 aParentElementsInfo = xParentCfgMgr->getUIElementsInfo( css::ui::UIElementType::POPUPMENU );
799 catch ( const css::lang::IllegalArgumentException& )
802 for (const auto& aElement : aParentElementsInfo)
804 OUString aUrl;
805 for ( const auto& aElementProp : aElement )
807 if ( aElementProp.Name == ITEM_DESCRIPTOR_RESOURCEURL )
809 aElementProp.Value >>= aUrl;
810 break;
814 css::uno::Reference< css::container::XIndexAccess > xPopupMenu;
817 if ( aMenuInfo.find( aUrl ) == aMenuInfo.end() )
818 xPopupMenu = xParentCfgMgr->getSettings( aUrl, false );
820 catch ( const css::uno::Exception& )
823 if ( xPopupMenu.is() )
825 OUString aUIMenuName = GetUIName( aUrl );
826 if ( aUIMenuName.isEmpty() )
827 continue;
829 SvxConfigEntry* pEntry = new SvxConfigEntry( aUIMenuName, aUrl, true, true );
830 pEntry->SetMain();
831 m_pRootEntry->GetEntries()->push_back( pEntry );
832 LoadSubMenus( xPopupMenu, aUIMenuName, pEntry, true );
835 std::sort( m_pRootEntry->GetEntries()->begin(), m_pRootEntry->GetEntries()->end(), SvxConfigPageHelper::EntrySort );
837 return m_pRootEntry->GetEntries();
840 void ContextMenuSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
842 m_pRootEntry->SetEntries( std::move(pNewEntries) );
845 bool ContextMenuSaveInData::HasURL( const OUString& rURL )
847 SvxEntries* pEntries = GetEntries();
848 for ( const auto& pEntry : *pEntries )
849 if ( pEntry->GetCommand() == rURL )
850 return true;
852 return false;
855 bool ContextMenuSaveInData::HasSettings()
857 return m_pRootEntry && !m_pRootEntry->GetEntries()->empty();
860 bool ContextMenuSaveInData::Apply()
862 if ( !IsModified() )
863 return false;
865 SvxEntries* pEntries = GetEntries();
866 for ( const auto& pEntry : *pEntries )
868 if ( pEntry->IsModified() || SvxConfigPageHelper::SvxConfigEntryModified( pEntry ) )
870 css::uno::Reference< css::container::XIndexContainer > xIndexContainer = GetConfigManager()->createSettings();
871 css::uno::Reference< css::lang::XSingleComponentFactory > xFactory( xIndexContainer, css::uno::UNO_QUERY );
872 ApplyMenu( xIndexContainer, xFactory, pEntry );
874 const OUString& aUrl = pEntry->GetCommand();
877 if ( GetConfigManager()->hasSettings( aUrl ) )
878 GetConfigManager()->replaceSettings( aUrl, xIndexContainer );
879 else
880 GetConfigManager()->insertSettings( aUrl, xIndexContainer );
882 catch ( const css::uno::Exception& )
886 SetModified( false );
887 return PersistChanges( GetConfigManager() );
890 void ContextMenuSaveInData::Reset()
892 SvxEntries* pEntries = GetEntries();
893 for ( const auto& pEntry : *pEntries )
897 GetConfigManager()->removeSettings( pEntry->GetCommand() );
899 catch ( const css::uno::Exception& )
901 TOOLS_WARN_EXCEPTION("cui.customize", "Exception caught while resetting context menus");
904 PersistChanges( GetConfigManager() );
905 m_pRootEntry.reset();
908 void ContextMenuSaveInData::ResetContextMenu( const SvxConfigEntry* pEntry )
912 GetConfigManager()->removeSettings( pEntry->GetCommand() );
914 catch ( const css::uno::Exception& )
916 TOOLS_WARN_EXCEPTION("cui.customize", "Exception caught while resetting context menu");
918 PersistChanges( GetConfigManager() );
919 m_pRootEntry.reset();
922 void SvxMenuEntriesListBox::CreateDropDown()
924 int nWidth = (m_xControl->get_text_height() * 3) / 4;
925 m_xDropDown->SetOutputSizePixel(Size(nWidth, nWidth));
926 DecorationView aDecoView(m_xDropDown.get());
927 aDecoView.DrawSymbol(tools::Rectangle(Point(0, 0), Size(nWidth, nWidth)),
928 SymbolType::SPIN_RIGHT, m_xDropDown->GetTextColor(),
929 DrawSymbolFlags::NONE);
932 /******************************************************************************
934 * SvxMenuEntriesListBox is the listbox in which the menu items for a
935 * particular menu are shown. We have a custom listbox because we need
936 * to add drag'n'drop support from the Macro Selector and within the
937 * listbox
939 *****************************************************************************/
940 SvxMenuEntriesListBox::SvxMenuEntriesListBox(std::unique_ptr<weld::TreeView> xControl, SvxConfigPage* pPg)
941 : m_xControl(std::move(xControl))
942 , m_xDropDown(m_xControl->create_virtual_device())
943 , m_pPage(pPg)
945 m_xControl->enable_toggle_buttons(weld::ColumnToggleType::Check);
946 CreateDropDown();
947 m_xControl->connect_key_press(LINK(this, SvxMenuEntriesListBox, KeyInputHdl));
948 m_xControl->connect_query_tooltip(LINK(this, SvxMenuEntriesListBox, QueryTooltip));
951 SvxMenuEntriesListBox::~SvxMenuEntriesListBox()
955 IMPL_LINK(SvxMenuEntriesListBox, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
957 vcl::KeyCode keycode = rKeyEvent.GetKeyCode();
959 // support DELETE for removing the current entry
960 if ( keycode == KEY_DELETE )
962 m_pPage->DeleteSelectedContent();
964 // support CTRL+UP and CTRL+DOWN for moving selected entries
965 else if ( keycode.GetCode() == KEY_UP && keycode.IsMod1() )
967 m_pPage->MoveEntry( true );
969 else if ( keycode.GetCode() == KEY_DOWN && keycode.IsMod1() )
971 m_pPage->MoveEntry( false );
973 else
975 return false; // pass on to default handler
977 return true;
980 IMPL_LINK(SvxMenuEntriesListBox, QueryTooltip, const weld::TreeIter&, rIter, OUString)
982 SvxConfigEntry *pEntry = weld::fromId<SvxConfigEntry*>(m_xControl->get_id(rIter));
983 if (!pEntry || pEntry->GetCommand().isEmpty())
984 return OUString();
985 const OUString sCommand(pEntry->GetCommand());
986 OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(m_pPage->GetFrame()));
987 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(sCommand, aModuleName);
988 OUString sTooltipLabel = vcl::CommandInfoProvider::GetTooltipForCommand(sCommand, aProperties,
989 m_pPage->GetFrame());
990 return CuiResId(RID_CUISTR_COMMANDLABEL) + ": " + pEntry->GetName().replaceFirst("~", "") + "\n" +
991 CuiResId(RID_CUISTR_COMMANDNAME) + ": " + sCommand + "\n" +
992 CuiResId(RID_CUISTR_COMMANDTIP) + ": " + sTooltipLabel.replaceFirst("~", "");
995 /******************************************************************************
997 * SvxConfigPage is the abstract base class on which the Menu and Toolbar
998 * configuration tabpages are based. It includes methods which are common to
999 * both tabpages to add, delete, move and rename items etc.
1001 *****************************************************************************/
1002 SvxConfigPage::SvxConfigPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
1003 : SfxTabPage(pPage, pController, u"cui/ui/menuassignpage.ui"_ustr, u"MenuAssignPage"_ustr, &rSet)
1004 , m_aUpdateDataTimer( "SvxConfigPage UpdateDataTimer" )
1005 , bInitialised(false)
1006 , pCurrentSaveInData(nullptr)
1007 , m_xCommandCategoryListBox(new CommandCategoryListBox(m_xBuilder->weld_combo_box(u"commandcategorylist"_ustr)))
1008 , m_xFunctions(new CuiConfigFunctionListBox(m_xBuilder->weld_tree_view(u"functions"_ustr)))
1009 , m_xCategoryLabel(m_xBuilder->weld_label(u"categorylabel"_ustr))
1010 , m_xDescriptionFieldLb(m_xBuilder->weld_label(u"descriptionlabel"_ustr))
1011 , m_xDescriptionField(m_xBuilder->weld_text_view(u"desc"_ustr))
1012 , m_xLeftFunctionLabel(m_xBuilder->weld_label(u"leftfunctionlabel"_ustr))
1013 , m_xSearchEdit(m_xBuilder->weld_entry(u"searchEntry"_ustr))
1014 , m_xSearchLabel(m_xBuilder->weld_label(u"searchlabel"_ustr))
1015 , m_xCustomizeLabel(m_xBuilder->weld_label(u"customizelabel"_ustr))
1016 , m_xTopLevelListBox(m_xBuilder->weld_combo_box(u"toplevellist"_ustr))
1017 , m_xMoveUpButton(m_xBuilder->weld_button(u"up"_ustr))
1018 , m_xMoveDownButton(m_xBuilder->weld_button(u"down"_ustr))
1019 , m_xSaveInListBox(m_xBuilder->weld_combo_box(u"savein"_ustr))
1020 , m_xCustomizeBox(m_xBuilder->weld_widget(u"customizebox"_ustr))
1021 , m_xInsertBtn(m_xBuilder->weld_menu_button(u"insert"_ustr))
1022 , m_xModifyBtn(m_xBuilder->weld_menu_button(u"modify"_ustr))
1023 , m_xResetBtn(m_xBuilder->weld_button(u"defaultsbtn"_ustr))
1024 , m_xCommandButtons(m_xBuilder->weld_widget(u"arrowgrid"_ustr))
1025 , m_xAddCommandButton(m_xBuilder->weld_button(u"add"_ustr))
1026 , m_xRemoveCommandButton(m_xBuilder->weld_button(u"remove"_ustr))
1028 CustomNotebookbarGenerator::getFileNameAndAppName(m_sAppName, m_sFileName);
1030 m_xTopLevelListBox->connect_changed(LINK(this, SvxConfigPage, SelectElementHdl));
1032 weld::TreeView& rTreeView = m_xFunctions->get_widget();
1033 Size aSize(rTreeView.get_approximate_digit_width() * 40, rTreeView.get_height_rows(8));
1034 m_xFunctions->set_size_request(aSize.Width(), aSize.Height());
1035 m_xDescriptionField->set_size_request(aSize.Width(), m_xDescriptionField->get_height_rows(3));
1037 m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SvxConfigPage, ImplUpdateDataHdl));
1038 m_aUpdateDataTimer.SetTimeout(EDIT_UPDATEDATA_TIMEOUT);
1040 m_xSearchEdit->connect_changed(LINK(this, SvxConfigPage, SearchUpdateHdl));
1041 m_xSearchEdit->connect_focus_out(LINK(this, SvxConfigPage, FocusOut_Impl));
1043 rTreeView.connect_row_activated(LINK(this, SvxConfigPage, FunctionDoubleClickHdl));
1044 rTreeView.connect_selection_changed(LINK(this, SvxConfigPage, SelectFunctionHdl));
1047 IMPL_LINK_NOARG(SvxConfigPage, SelectElementHdl, weld::ComboBox&, void)
1049 SelectElement();
1052 SvxConfigPage::~SvxConfigPage()
1054 int cnt = m_xSaveInListBox->get_count();
1055 for(int i=0; i < cnt; ++i)
1057 SaveInData *pData = weld::fromId<SaveInData*>(m_xSaveInListBox->get_id(i));
1058 delete pData;
1062 void SvxConfigPage::Reset( const SfxItemSet* )
1064 // If we haven't initialised our XMultiServiceFactory reference
1065 // then Reset is being called at the opening of the dialog.
1067 // Load menu configuration data for the module of the currently
1068 // selected document, for the currently selected document, and for
1069 // all other open documents of the same module type
1070 if ( !bInitialised )
1072 sal_Int32 nPos = 0;
1073 uno::Reference < css::ui::XUIConfigurationManager > xCfgMgr;
1074 uno::Reference < css::ui::XUIConfigurationManager > xDocCfgMgr;
1076 uno::Reference< uno::XComponentContext > xContext(
1077 ::comphelper::getProcessComponentContext(), uno::UNO_SET_THROW );
1079 m_xFrame = GetFrame();
1080 m_aModuleId = GetFrameWithDefaultAndIdentify( m_xFrame );
1082 // replace %MODULENAME in the label with the correct module name
1083 uno::Reference< css::frame::XModuleManager2 > xModuleManager(
1084 css::frame::ModuleManager::create( xContext ));
1085 OUString aModuleName = SvxConfigPageHelper::GetUIModuleName( m_aModuleId, xModuleManager );
1087 uno::Reference< css::ui::XModuleUIConfigurationManagerSupplier >
1088 xModuleCfgSupplier( css::ui::theModuleUIConfigurationManagerSupplier::get(xContext) );
1090 // Set up data for module specific menus
1091 SaveInData* pModuleData = nullptr;
1095 xCfgMgr =
1096 xModuleCfgSupplier->getUIConfigurationManager( m_aModuleId );
1098 pModuleData = CreateSaveInData( xCfgMgr,
1099 uno::Reference< css::ui::XUIConfigurationManager >(),
1100 m_aModuleId,
1101 false );
1103 catch ( container::NoSuchElementException& )
1107 if ( pModuleData != nullptr )
1109 OUString sId(weld::toId(pModuleData));
1110 m_xSaveInListBox->append(sId, utl::ConfigManager::getProductName() + " " + aModuleName);
1113 // try to retrieve the document based ui configuration manager
1114 OUString aTitle;
1115 uno::Reference< frame::XController > xController =
1116 m_xFrame->getController();
1117 if ( CanConfig( m_aModuleId ) && xController.is() )
1119 uno::Reference< frame::XModel > xModel( xController->getModel() );
1120 if ( xModel.is() )
1122 uno::Reference< css::ui::XUIConfigurationManagerSupplier >
1123 xCfgSupplier( xModel, uno::UNO_QUERY );
1125 if ( xCfgSupplier.is() )
1127 xDocCfgMgr = xCfgSupplier->getUIConfigurationManager();
1129 aTitle = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
1133 SaveInData* pDocData = nullptr;
1134 if ( xDocCfgMgr.is() )
1136 pDocData = CreateSaveInData( xDocCfgMgr, xCfgMgr, m_aModuleId, true );
1138 if ( !pDocData->IsReadOnly() )
1140 OUString sId(weld::toId(pDocData));
1141 m_xSaveInListBox->append(sId, aTitle);
1145 // if an item to select has been passed in (eg. the ResourceURL for a
1146 // toolbar) then try to select the SaveInData entry that has that item
1147 bool bURLToSelectFound = false;
1148 if ( !m_aURLToSelect.isEmpty() )
1150 if ( pDocData && pDocData->HasURL( m_aURLToSelect ) )
1152 m_xSaveInListBox->set_active(nPos);
1153 pCurrentSaveInData = pDocData;
1154 bURLToSelectFound = true;
1156 else if ( pModuleData && pModuleData->HasURL( m_aURLToSelect ) )
1158 m_xSaveInListBox->set_active(0);
1159 pCurrentSaveInData = pModuleData;
1160 bURLToSelectFound = true;
1164 if ( !bURLToSelectFound )
1166 // if the document has menu configuration settings select it
1167 // it the SaveIn listbox, otherwise select the module data
1168 if ( pDocData != nullptr && pDocData->HasSettings() )
1170 m_xSaveInListBox->set_active(nPos);
1171 pCurrentSaveInData = pDocData;
1173 else
1175 m_xSaveInListBox->set_active(0);
1176 pCurrentSaveInData = pModuleData;
1180 #ifdef DBG_UTIL
1181 DBG_ASSERT( pCurrentSaveInData, "SvxConfigPage::Reset(): no SaveInData" );
1182 #endif
1184 if ( CanConfig( m_aModuleId ) )
1186 // Load configuration for other open documents which have
1187 // same module type
1188 uno::Sequence< uno::Reference< frame::XFrame > > aFrameList;
1191 uno::Reference< frame::XDesktop2 > xFramesSupplier = frame::Desktop::create(
1192 xContext );
1194 uno::Reference< frame::XFrames > xFrames =
1195 xFramesSupplier->getFrames();
1197 aFrameList = xFrames->queryFrames(
1198 frame::FrameSearchFlag::ALL & ~frame::FrameSearchFlag::SELF );
1201 catch( const uno::Exception& )
1203 DBG_UNHANDLED_EXCEPTION("cui.customize");
1206 for (uno::Reference<frame::XFrame> const& xf : aFrameList)
1208 if ( xf.is() && xf != m_xFrame )
1210 OUString aCheckId;
1211 try{
1212 aCheckId = xModuleManager->identify( xf );
1213 } catch(const uno::Exception&)
1214 { aCheckId.clear(); }
1216 if ( m_aModuleId == aCheckId )
1218 // try to get the document based ui configuration manager
1219 OUString aTitle2;
1220 uno::Reference< frame::XController > xController_ =
1221 xf->getController();
1223 if ( xController_.is() )
1225 uno::Reference< frame::XModel > xModel(
1226 xController_->getModel() );
1228 if ( xModel.is() )
1230 uno::Reference<
1231 css::ui::XUIConfigurationManagerSupplier >
1232 xCfgSupplier( xModel, uno::UNO_QUERY );
1234 if ( xCfgSupplier.is() )
1236 xDocCfgMgr =
1237 xCfgSupplier->getUIConfigurationManager();
1239 aTitle2 = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
1243 if ( xDocCfgMgr.is() )
1245 SaveInData* pData = CreateSaveInData( xDocCfgMgr, xCfgMgr, m_aModuleId, true );
1247 if ( pData && !pData->IsReadOnly() )
1249 OUString sId(weld::toId(pData));
1250 m_xSaveInListBox->append(sId, aTitle2);
1258 m_xSaveInListBox->connect_changed(
1259 LINK( this, SvxConfigPage, SelectSaveInLocation ) );
1261 bInitialised = true;
1263 Init();
1265 else
1267 if ( QueryReset() == RET_YES )
1269 // Reset menu configuration for currently selected SaveInData
1270 GetSaveInData()->Reset();
1272 Init();
1277 OUString SvxConfigPage::GetFrameWithDefaultAndIdentify( uno::Reference< frame::XFrame >& _inout_rxFrame )
1279 OUString sModuleID;
1282 const uno::Reference< uno::XComponentContext >& xContext(
1283 ::comphelper::getProcessComponentContext() );
1285 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(
1286 xContext );
1288 if ( !_inout_rxFrame.is() )
1289 _inout_rxFrame = xDesktop->getActiveFrame();
1291 if ( !_inout_rxFrame.is() )
1293 _inout_rxFrame = xDesktop->getCurrentFrame();
1296 if ( !_inout_rxFrame.is())
1298 if (SfxViewFrame* pViewFrame = SfxViewFrame::Current())
1299 _inout_rxFrame = pViewFrame->GetFrame().GetFrameInterface();
1302 if ( !_inout_rxFrame.is() )
1304 SAL_WARN( "cui.customize", "SvxConfigPage::GetFrameWithDefaultAndIdentify(): no frame found!" );
1305 return sModuleID;
1308 sModuleID = vcl::CommandInfoProvider::GetModuleIdentifier(_inout_rxFrame);
1310 catch( const uno::Exception& )
1312 DBG_UNHANDLED_EXCEPTION("cui.customize");
1315 return sModuleID;
1318 OUString SvxConfigPage::GetScriptURL() const
1320 OUString result;
1322 SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(m_xFunctions->get_selected_id());
1323 if (pData)
1325 if ( ( pData->nKind == SfxCfgKind::FUNCTION_SLOT ) ||
1326 ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT ) ||
1327 ( pData->nKind == SfxCfgKind::GROUP_STYLES ) )
1329 result = pData->sCommand;
1333 return result;
1336 OUString SvxConfigPage::GetSelectedDisplayName() const
1338 return m_xFunctions->get_selected_text();
1341 bool SvxConfigPage::FillItemSet( SfxItemSet* )
1343 bool result = false;
1345 for (int i = 0, nCount = m_xSaveInListBox->get_count(); i < nCount; ++i)
1347 OUString sId = m_xSaveInListBox->get_id(i);
1348 if (sId != notebookbarTabScope)
1350 SaveInData* pData = weld::fromId<SaveInData*>(sId);
1351 result = pData->Apply();
1354 return result;
1357 IMPL_LINK_NOARG(SvxConfigPage, SelectSaveInLocation, weld::ComboBox&, void)
1359 OUString sId = m_xSaveInListBox->get_active_id();
1360 if (sId != notebookbarTabScope)
1361 pCurrentSaveInData = weld::fromId<SaveInData*>(sId);
1362 Init();
1365 void SvxConfigPage::ReloadTopLevelListBox( SvxConfigEntry const * pToSelect )
1367 int nSelectionPos = m_xTopLevelListBox->get_active();
1368 m_xTopLevelListBox->clear();
1370 if ( GetSaveInData() && GetSaveInData()->GetEntries() )
1372 for (auto const& entryData : *GetSaveInData()->GetEntries())
1374 OUString sId(weld::toId(entryData));
1375 m_xTopLevelListBox->append(sId, SvxConfigPageHelper::stripHotKey(entryData->GetName()));
1377 if (entryData == pToSelect)
1378 nSelectionPos = m_xTopLevelListBox->get_count() - 1;
1380 AddSubMenusToUI( SvxConfigPageHelper::stripHotKey( entryData->GetName() ), entryData );
1383 #ifdef DBG_UTIL
1384 else
1386 DBG_ASSERT( GetSaveInData(), "SvxConfigPage::ReloadTopLevelListBox(): no SaveInData" );
1387 DBG_ASSERT( GetSaveInData()->GetEntries() ,
1388 "SvxConfigPage::ReloadTopLevelListBox(): no SaveInData entries" );
1390 #endif
1392 nSelectionPos = (nSelectionPos != -1 && nSelectionPos < m_xTopLevelListBox->get_count()) ?
1393 nSelectionPos : m_xTopLevelListBox->get_count() - 1;
1395 m_xTopLevelListBox->set_active(nSelectionPos);
1396 SelectElement();
1399 void SvxConfigPage::AddSubMenusToUI(
1400 std::u16string_view rBaseTitle, SvxConfigEntry const * pParentData )
1402 for (auto const& entryData : *pParentData->GetEntries())
1404 if (entryData->IsPopup())
1406 OUString subMenuTitle = OUString::Concat(rBaseTitle) + aMenuSeparatorStr + SvxConfigPageHelper::stripHotKey(entryData->GetName());
1408 OUString sId(weld::toId(entryData));
1409 m_xTopLevelListBox->append(sId, subMenuTitle);
1411 AddSubMenusToUI( subMenuTitle, entryData );
1416 SvxEntries* SvxConfigPage::FindParentForChild(
1417 SvxEntries* pRootEntries, SvxConfigEntry* pChildData )
1419 for (auto const& entryData : *pRootEntries)
1422 if (entryData == pChildData)
1424 return pRootEntries;
1426 else if (entryData->IsPopup())
1428 SvxEntries* result =
1429 FindParentForChild( entryData->GetEntries(), pChildData );
1431 if ( result != nullptr )
1433 return result;
1437 return nullptr;
1440 SvxConfigEntry *SvxConfigPage::CreateCommandFromSelection(const OUString &aURL)
1442 OUString aDisplayName;
1444 if ( aURL.isEmpty() ) {
1445 return nullptr;
1448 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aURL, m_aModuleId);
1450 if ( typeid(*pCurrentSaveInData) == typeid(ContextMenuSaveInData) )
1451 aDisplayName = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties);
1452 else if ( typeid(*pCurrentSaveInData) == typeid(MenuSaveInData) )
1453 aDisplayName = vcl::CommandInfoProvider::GetMenuLabelForCommand(aProperties);
1454 else
1455 aDisplayName = vcl::CommandInfoProvider::GetLabelForCommand(aProperties);
1457 SvxConfigEntry* toret =
1458 new SvxConfigEntry( aDisplayName, aURL, false, /*bParentData*/false );
1460 toret->SetUserDefined();
1462 if ( aDisplayName.isEmpty() )
1463 toret->SetName( GetSelectedDisplayName() );
1465 return toret;
1468 bool SvxConfigPage::IsCommandInMenuList(const SvxConfigEntry *pEntryData,
1469 const SvxEntries *pEntries)
1471 bool toret = false;
1473 if ( pEntries != nullptr
1474 && pEntryData != nullptr )
1476 for (auto const& entry : *pEntries)
1478 if ( entry->GetCommand() == pEntryData->GetCommand() )
1480 toret = true;
1481 break;
1486 return toret;
1489 int SvxConfigPage::AddFunction(int nTarget, bool bAllowDuplicates)
1491 int toret = -1;
1492 OUString aURL = GetScriptURL();
1493 SvxConfigEntry* pParent = GetTopLevelSelection();
1495 if ( aURL.isEmpty() || pParent == nullptr )
1497 return -1;
1501 SvxConfigEntry * pNewEntryData = CreateCommandFromSelection( aURL );
1503 // check that this function is not already in the menu
1504 if ( !bAllowDuplicates
1505 && IsCommandInMenuList( pNewEntryData, pParent->GetEntries() )
1508 delete pNewEntryData;
1509 } else {
1510 toret = AppendEntry( pNewEntryData, nTarget );
1513 UpdateButtonStates();
1514 return toret;
1517 int SvxConfigPage::AppendEntry(
1518 SvxConfigEntry* pNewEntryData,
1519 int nTarget)
1521 SvxConfigEntry* pTopLevelSelection = GetTopLevelSelection();
1523 if (pTopLevelSelection == nullptr)
1524 return -1;
1526 // Grab the entries list for the currently selected menu
1527 SvxEntries* pEntries = pTopLevelSelection->GetEntries();
1529 int nNewEntry = -1;
1530 int nCurEntry =
1531 nTarget != -1 ? nTarget : m_xContentsListBox->get_selected_index();
1533 OUString sId(weld::toId(pNewEntryData));
1535 if (nCurEntry == -1 || nCurEntry == m_xContentsListBox->n_children() - 1)
1537 pEntries->push_back( pNewEntryData );
1538 m_xContentsListBox->insert(-1, sId);
1539 nNewEntry = m_xContentsListBox->n_children() - 1;
1541 else
1543 SvxConfigEntry* pEntryData =
1544 weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nCurEntry));
1546 SvxEntries::iterator iter = pEntries->begin();
1547 SvxEntries::const_iterator end = pEntries->end();
1549 // Advance the iterator to the data for currently selected entry
1550 sal_uInt16 nPos = 0;
1551 while (*iter != pEntryData && ++iter != end)
1553 ++nPos;
1556 // Now step past it to the entry after the currently selected one
1557 ++iter;
1558 ++nPos;
1560 // Now add the new entry to the UI and to the parent's list
1561 if ( iter != end )
1563 pEntries->insert( iter, pNewEntryData );
1564 m_xContentsListBox->insert(nPos, sId);
1565 nNewEntry = nPos;
1569 if (nNewEntry != -1)
1571 m_xContentsListBox->select(nNewEntry);
1572 m_xContentsListBox->scroll_to_row(nNewEntry);
1574 GetSaveInData()->SetModified();
1575 GetTopLevelSelection()->SetModified();
1578 return nNewEntry;
1581 namespace
1583 template<typename itertype> void TmplInsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView& rTreeView, itertype& rIter, SaveInData* pSaveInData,
1584 VirtualDevice& rDropDown, bool bMenu)
1586 OUString sId(weld::toId(pNewEntryData));
1588 rTreeView.set_id(rIter, sId);
1590 if (pNewEntryData->IsSeparator())
1592 rTreeView.set_text(rIter, "----------------------------------", 0);
1594 else
1596 auto xImage = pSaveInData->GetImage(pNewEntryData->GetCommand());
1597 if (xImage.is())
1598 rTreeView.set_image(rIter, xImage, -1);
1599 OUString aName = SvxConfigPageHelper::stripHotKey( pNewEntryData->GetName() );
1600 rTreeView.set_text(rIter, aName, 0);
1603 if (bMenu) // menus
1605 if (pNewEntryData->IsPopup() || pNewEntryData->GetStyle() & css::ui::ItemStyle::DROP_DOWN)
1606 rTreeView.set_image(rIter, rDropDown, 1);
1607 else
1608 rTreeView.set_image(rIter, css::uno::Reference<css::graphic::XGraphic>(), 1);
1613 void SvxConfigPage::InsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView& rTreeView, int nPos, bool bMenu)
1615 TmplInsertEntryIntoUI<int>(pNewEntryData, rTreeView, nPos, GetSaveInData(),
1616 m_xContentsListBox->get_dropdown_image(), bMenu);
1619 void SvxConfigPage::InsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView& rTreeView, weld::TreeIter& rIter, bool bMenu)
1621 TmplInsertEntryIntoUI<weld::TreeIter>(pNewEntryData, rTreeView, rIter, GetSaveInData(),
1622 m_xContentsListBox->get_dropdown_image(), bMenu);
1625 IMPL_LINK(SvxConfigPage, MoveHdl, weld::Button&, rButton, void)
1627 MoveEntry(&rButton == m_xMoveUpButton.get());
1630 IMPL_LINK_NOARG(SvxConfigPage, FunctionDoubleClickHdl, weld::TreeView&, bool)
1632 if (m_xAddCommandButton->get_sensitive())
1633 m_xAddCommandButton->clicked();
1634 return true;
1637 IMPL_LINK_NOARG(SvxConfigPage, SelectFunctionHdl, weld::TreeView&, void)
1639 // GetScriptURL() returns a non-empty string if a
1640 // valid command is selected on the left box
1641 OUString aSelectCommand = GetScriptURL();
1642 bool bIsValidCommand = !aSelectCommand.isEmpty();
1644 // Enable/disable Add and Remove buttons depending on current selection
1645 if (bIsValidCommand)
1647 m_xAddCommandButton->set_sensitive(true);
1648 m_xRemoveCommandButton->set_sensitive(true);
1650 if (SfxHelp::IsHelpInstalled())
1652 m_xDescriptionField->set_text(m_xFunctions->GetCommandHelpText());
1654 else
1656 SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(m_xFunctions->get_selected_id());
1657 if (pData)
1659 bool bIsExperimental
1660 = vcl::CommandInfoProvider::IsExperimental(pData->sCommand, m_aModuleId);
1662 OUString aExperimental = "\n" + CuiResId(RID_CUISTR_COMMANDEXPERIMENTAL);
1663 OUString aLabel = CuiResId(RID_CUISTR_COMMANDLABEL) + ": " + pData->sLabel + "\n";
1664 OUString aName = CuiResId(RID_CUISTR_COMMANDNAME) + ": " + pData->sCommand + "\n";
1665 OUString aTip = CuiResId(RID_CUISTR_COMMANDTIP) + ": " + pData->sTooltip;
1666 if (bIsExperimental)
1667 m_xDescriptionField->set_text(aLabel + aName + aTip + aExperimental);
1668 else
1669 m_xDescriptionField->set_text(aLabel + aName + aTip);
1673 else
1676 m_xAddCommandButton->set_sensitive(false);
1677 m_xRemoveCommandButton->set_sensitive(false);
1679 m_xDescriptionField->set_text(u""_ustr);
1682 UpdateButtonStates();
1685 IMPL_LINK_NOARG(SvxConfigPage, ImplUpdateDataHdl, Timer*, void)
1687 OUString aSearchTerm(m_xSearchEdit->get_text());
1688 m_xCommandCategoryListBox->categorySelected(m_xFunctions.get(), aSearchTerm, GetSaveInData());
1689 SelectFunctionHdl(m_xFunctions->get_widget());
1692 IMPL_LINK_NOARG(SvxConfigPage, SearchUpdateHdl, weld::Entry&, void)
1694 m_aUpdateDataTimer.Start();
1697 IMPL_LINK_NOARG(SvxConfigPage, FocusOut_Impl, weld::Widget&, void)
1699 if (m_aUpdateDataTimer.IsActive())
1701 m_aUpdateDataTimer.Stop();
1702 m_aUpdateDataTimer.Invoke();
1706 void SvxConfigPage::MoveEntry(bool bMoveUp)
1708 weld::TreeView& rTreeView = m_xContentsListBox->get_widget();
1710 int nSourceEntry = rTreeView.get_selected_index();
1711 int nTargetEntry = -1;
1712 int nToSelect = -1;
1714 if (nSourceEntry == -1)
1716 return;
1719 if ( bMoveUp )
1721 // Move Up is just a Move Down with the source and target reversed
1722 nTargetEntry = nSourceEntry;
1723 nSourceEntry = nTargetEntry - 1;
1724 nToSelect = nSourceEntry;
1726 else
1728 nTargetEntry = nSourceEntry + 1;
1729 nToSelect = nTargetEntry;
1732 if (MoveEntryData(nSourceEntry, nTargetEntry))
1734 rTreeView.swap(nSourceEntry, nTargetEntry);
1735 rTreeView.select(nToSelect);
1736 rTreeView.scroll_to_row(nToSelect);
1738 UpdateButtonStates();
1742 bool SvxConfigPage::MoveEntryData(int nSourceEntry, int nTargetEntry)
1744 //#i53677#
1745 if (nSourceEntry == -1 || nTargetEntry == -1)
1747 return false;
1750 // Grab the entries list for the currently selected menu
1751 SvxEntries* pEntries = GetTopLevelSelection()->GetEntries();
1753 SvxConfigEntry* pSourceData =
1754 weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nSourceEntry));
1756 SvxConfigEntry* pTargetData =
1757 weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nTargetEntry));
1759 if ( pSourceData == nullptr || pTargetData == nullptr )
1760 return false;
1762 // remove the source entry from our list
1763 SvxConfigPageHelper::RemoveEntry( pEntries, pSourceData );
1765 SvxEntries::iterator iter = pEntries->begin();
1766 SvxEntries::const_iterator end = pEntries->end();
1768 // advance the iterator to the position of the target entry
1769 while (*iter != pTargetData && ++iter != end) ;
1771 // insert the source entry at the position after the target
1772 pEntries->insert( ++iter, pSourceData );
1774 GetSaveInData()->SetModified();
1775 GetTopLevelSelection()->SetModified();
1777 return true;
1780 SvxMainMenuOrganizerDialog::SvxMainMenuOrganizerDialog(
1781 weld::Window* pParent, SvxEntries* entries,
1782 SvxConfigEntry const * selection, bool bCreateMenu )
1783 : GenericDialogController(pParent, u"cui/ui/movemenu.ui"_ustr, u"MoveMenuDialog"_ustr)
1784 , m_xMenuBox(m_xBuilder->weld_widget(u"namebox"_ustr))
1785 , m_xMenuNameEdit(m_xBuilder->weld_entry(u"menuname"_ustr))
1786 , m_xMenuListBox(m_xBuilder->weld_tree_view(u"menulist"_ustr))
1787 , m_xMoveUpButton(m_xBuilder->weld_button(u"up"_ustr))
1788 , m_xMoveDownButton(m_xBuilder->weld_button(u"down"_ustr))
1790 m_xMenuListBox->set_size_request(-1, m_xMenuListBox->get_height_rows(12));
1792 // Copy the entries list passed in
1793 if ( entries != nullptr )
1795 mpEntries.reset( new SvxEntries );
1796 for (auto const& entry : *entries)
1798 m_xMenuListBox->append(weld::toId(entry),
1799 SvxConfigPageHelper::stripHotKey(entry->GetName()));
1800 mpEntries->push_back(entry);
1801 if (entry == selection)
1803 m_xMenuListBox->select(m_xMenuListBox->n_children() - 1);
1808 if ( bCreateMenu )
1810 // Generate custom name for new menu
1811 OUString prefix = CuiResId( RID_CUISTR_NEW_MENU );
1813 OUString newname = SvxConfigPageHelper::generateCustomName( prefix, entries );
1814 OUString newurl = SvxConfigPageHelper::generateCustomMenuURL( mpEntries.get() );
1816 SvxConfigEntry* pNewEntryData =
1817 new SvxConfigEntry( newname, newurl, true, /*bParentData*/false );
1818 pNewEntryData->SetName( newname );
1819 pNewEntryData->SetUserDefined();
1820 pNewEntryData->SetMain();
1822 m_sNewMenuEntryId = weld::toId(pNewEntryData);
1823 m_xMenuListBox->append(m_sNewMenuEntryId,
1824 SvxConfigPageHelper::stripHotKey(pNewEntryData->GetName()));
1825 m_xMenuListBox->select(m_xMenuListBox->n_children() - 1);
1827 if (mpEntries)
1828 mpEntries->push_back(pNewEntryData);
1830 m_xMenuNameEdit->set_text(newname);
1831 m_xMenuNameEdit->connect_changed(LINK(this, SvxMainMenuOrganizerDialog, ModifyHdl));
1833 else
1835 // hide name label and textfield
1836 m_xMenuBox->hide();
1837 // change the title
1838 m_xDialog->set_title(CuiResId(RID_CUISTR_MOVE_MENU));
1841 m_xMenuListBox->connect_selection_changed(LINK(this, SvxMainMenuOrganizerDialog, SelectHdl));
1843 m_xMoveUpButton->connect_clicked(LINK( this, SvxMainMenuOrganizerDialog, MoveHdl));
1844 m_xMoveDownButton->connect_clicked(LINK( this, SvxMainMenuOrganizerDialog, MoveHdl));
1846 UpdateButtonStates();
1849 SvxMainMenuOrganizerDialog::~SvxMainMenuOrganizerDialog()
1853 IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog, ModifyHdl, weld::Entry&, void)
1855 // if the Edit control is empty do not change the name
1856 if (m_xMenuNameEdit->get_text().isEmpty())
1858 return;
1861 SvxConfigEntry* pNewEntryData = weld::fromId<SvxConfigEntry*>(m_sNewMenuEntryId);
1862 pNewEntryData->SetName(m_xMenuNameEdit->get_text());
1864 const int nNewMenuPos = m_xMenuListBox->find_id(m_sNewMenuEntryId);
1865 const int nOldSelection = m_xMenuListBox->get_selected_index();
1866 m_xMenuListBox->remove(nNewMenuPos);
1867 m_xMenuListBox->insert(nNewMenuPos, pNewEntryData->GetName(), &m_sNewMenuEntryId, nullptr, nullptr);
1868 m_xMenuListBox->select(nOldSelection);
1871 IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog, SelectHdl, weld::TreeView&, void)
1873 UpdateButtonStates();
1876 void SvxMainMenuOrganizerDialog::UpdateButtonStates()
1878 // Disable Up and Down buttons depending on current selection
1879 const int nSelected = m_xMenuListBox->get_selected_index();
1880 m_xMoveUpButton->set_sensitive(nSelected > 0);
1881 m_xMoveDownButton->set_sensitive(nSelected != -1 && nSelected < m_xMenuListBox->n_children() - 1);
1884 IMPL_LINK( SvxMainMenuOrganizerDialog, MoveHdl, weld::Button&, rButton, void )
1886 int nSourceEntry = m_xMenuListBox->get_selected_index();
1887 if (nSourceEntry == -1)
1888 return;
1890 int nTargetEntry;
1892 if (&rButton == m_xMoveDownButton.get())
1894 nTargetEntry = nSourceEntry + 1;
1896 else
1898 // Move Up is just a Move Down with the source and target reversed
1899 nTargetEntry = nSourceEntry - 1;
1902 OUString sId = m_xMenuListBox->get_id(nSourceEntry);
1903 OUString sEntry = m_xMenuListBox->get_text(nSourceEntry);
1904 m_xMenuListBox->remove(nSourceEntry);
1905 m_xMenuListBox->insert(nTargetEntry, sEntry, &sId, nullptr, nullptr);
1906 m_xMenuListBox->select(nTargetEntry);
1908 std::swap(mpEntries->at(nSourceEntry), mpEntries->at(nTargetEntry));
1910 UpdateButtonStates();
1913 SvxConfigEntry* SvxMainMenuOrganizerDialog::GetSelectedEntry()
1915 const int nSelected(m_xMenuListBox->get_selected_index());
1916 if (nSelected == -1)
1917 return nullptr;
1918 return weld::fromId<SvxConfigEntry*>(m_xMenuListBox->get_id(nSelected));
1921 SvxConfigEntry::SvxConfigEntry( OUString aDisplayName,
1922 OUString aCommandURL, bool bPopup, bool bParentData )
1923 : nId( 1 )
1924 , aLabel(std::move(aDisplayName))
1925 , aCommand(std::move(aCommandURL))
1926 , bPopUp(bPopup)
1927 , bStrEdited( false )
1928 , bIsUserDefined( false )
1929 , bIsMain( false )
1930 , bIsParentData( bParentData )
1931 , bIsModified( false )
1932 , bIsVisible( true )
1933 , nStyle( 0 )
1935 if (bPopUp)
1937 mpEntries.reset( new SvxEntries );
1941 SvxConfigEntry::~SvxConfigEntry()
1943 if (mpEntries)
1945 for (auto const& entry : *mpEntries)
1947 delete entry;
1952 bool SvxConfigEntry::IsMovable() const
1954 return !IsPopup() || IsMain();
1957 bool SvxConfigEntry::IsDeletable() const
1959 return !IsMain() || IsUserDefined();
1962 bool SvxConfigEntry::IsRenamable() const
1964 return !IsMain() || IsUserDefined();
1967 ToolbarSaveInData::ToolbarSaveInData(
1968 const uno::Reference < css::ui::XUIConfigurationManager >& xCfgMgr,
1969 const uno::Reference < css::ui::XUIConfigurationManager >& xParentCfgMgr,
1970 const OUString& aModuleId,
1971 bool docConfig ) :
1973 SaveInData ( xCfgMgr, xParentCfgMgr, aModuleId, docConfig ),
1974 m_aDescriptorContainer ( ITEM_DESCRIPTOR_CONTAINER )
1977 const uno::Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();
1978 // Initialize the m_xPersistentWindowState variable which is used
1979 // to get the default properties of system toolbars such as name
1980 uno::Reference< container::XNameAccess > xPWSS = css::ui::theWindowStateConfiguration::get( xContext );
1982 xPWSS->getByName( aModuleId ) >>= m_xPersistentWindowState;
1985 ToolbarSaveInData::~ToolbarSaveInData()
1989 sal_Int32 ToolbarSaveInData::GetSystemStyle( const OUString& rResourceURL )
1991 sal_Int32 result = 0;
1993 if ( rResourceURL.startsWith( "private" ) &&
1994 m_xPersistentWindowState.is() &&
1995 m_xPersistentWindowState->hasByName( rResourceURL ) )
1999 uno::Sequence< beans::PropertyValue > aProps;
2000 uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
2002 if ( a >>= aProps )
2004 for (beans::PropertyValue const& prop : aProps)
2006 if ( prop.Name == ITEM_DESCRIPTOR_STYLE )
2008 prop.Value >>= result;
2009 break;
2014 catch ( uno::Exception& )
2016 // do nothing, a default value is returned
2020 return result;
2023 void ToolbarSaveInData::SetSystemStyle(
2024 const uno::Reference< frame::XFrame >& xFrame,
2025 const OUString& rResourceURL,
2026 sal_Int32 nStyle )
2028 // change the style using the API
2029 SetSystemStyle( rResourceURL, nStyle );
2031 // this code is a temporary hack as the UI is not updating after
2032 // changing the toolbar style via the API
2033 uno::Reference< css::frame::XLayoutManager > xLayoutManager;
2034 vcl::Window *window = nullptr;
2036 uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
2037 if ( xPropSet.is() )
2039 uno::Any a = xPropSet->getPropertyValue( u"LayoutManager"_ustr );
2040 a >>= xLayoutManager;
2043 if ( xLayoutManager.is() )
2045 uno::Reference< css::ui::XUIElement > xUIElement =
2046 xLayoutManager->getElement( rResourceURL );
2048 // check reference before we call getRealInterface. The layout manager
2049 // can only provide references for elements that have been created
2050 // before. It's possible that the current element is not available.
2051 uno::Reference< css::awt::XWindow > xWindow;
2052 if ( xUIElement.is() )
2053 xWindow.set( xUIElement->getRealInterface(), uno::UNO_QUERY );
2055 window = VCLUnoHelper::GetWindow( xWindow );
2058 if ( window == nullptr || window->GetType() != WindowType::TOOLBOX )
2059 return;
2061 ToolBox* toolbox = static_cast<ToolBox*>(window);
2063 if ( nStyle == 0 )
2065 toolbox->SetButtonType( ButtonType::SYMBOLONLY );
2067 else if ( nStyle == 1 )
2069 toolbox->SetButtonType( ButtonType::TEXT );
2071 if ( nStyle == 2 )
2073 toolbox->SetButtonType( ButtonType::SYMBOLTEXT );
2077 void ToolbarSaveInData::SetSystemStyle(
2078 const OUString& rResourceURL,
2079 sal_Int32 nStyle )
2081 if ( !(rResourceURL.startsWith( "private" ) &&
2082 m_xPersistentWindowState.is() &&
2083 m_xPersistentWindowState->hasByName( rResourceURL )) )
2084 return;
2088 uno::Sequence< beans::PropertyValue > aProps;
2090 uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
2092 if ( a >>= aProps )
2094 for ( beans::PropertyValue& prop : asNonConstRange(aProps) )
2096 if ( prop.Name == ITEM_DESCRIPTOR_STYLE )
2098 prop.Value <<= nStyle;
2099 break;
2104 uno::Reference< container::XNameReplace >
2105 xNameReplace( m_xPersistentWindowState, uno::UNO_QUERY );
2107 xNameReplace->replaceByName( rResourceURL, uno::Any( aProps ) );
2109 catch ( uno::Exception& )
2111 // do nothing, a default value is returned
2112 TOOLS_WARN_EXCEPTION("cui.customize", "Exception setting toolbar style");
2116 OUString ToolbarSaveInData::GetSystemUIName( const OUString& rResourceURL )
2118 OUString result;
2120 if ( rResourceURL.startsWith( "private" ) &&
2121 m_xPersistentWindowState.is() &&
2122 m_xPersistentWindowState->hasByName( rResourceURL ) )
2126 uno::Sequence< beans::PropertyValue > aProps;
2127 uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
2129 if ( a >>= aProps )
2131 for (beans::PropertyValue const& prop : aProps)
2133 if ( prop.Name == ITEM_DESCRIPTOR_UINAME )
2135 prop.Value >>= result;
2140 catch ( uno::Exception& )
2142 // do nothing, an empty UIName will be returned
2146 if ( rResourceURL.startsWith( ".uno" ) &&
2147 m_xCommandToLabelMap.is() &&
2148 m_xCommandToLabelMap->hasByName( rResourceURL ) )
2150 uno::Any a;
2153 a = m_xCommandToLabelMap->getByName( rResourceURL );
2155 uno::Sequence< beans::PropertyValue > aPropSeq;
2156 if ( a >>= aPropSeq )
2158 for (beans::PropertyValue const& prop : aPropSeq)
2160 if ( prop.Name == ITEM_DESCRIPTOR_LABEL )
2162 prop.Value >>= result;
2167 catch ( uno::Exception& )
2169 // not a system command name
2173 return result;
2176 SvxEntries* ToolbarSaveInData::GetEntries()
2178 typedef std::unordered_map<OUString, bool > ToolbarInfo;
2180 ToolbarInfo aToolbarInfo;
2182 if ( pRootEntry == nullptr )
2185 pRootEntry.reset( new SvxConfigEntry( u"MainToolbars"_ustr, OUString(), true, /*bParentData*/false) );
2187 const uno::Sequence< uno::Sequence < beans::PropertyValue > > info =
2188 GetConfigManager()->getUIElementsInfo(
2189 css::ui::UIElementType::TOOLBAR );
2191 for ( uno::Sequence<beans::PropertyValue> const & props : info )
2193 OUString url;
2194 OUString systemname;
2195 OUString uiname;
2197 for ( const beans::PropertyValue& prop : props )
2199 if ( prop.Name == ITEM_DESCRIPTOR_RESOURCEURL )
2201 prop.Value >>= url;
2202 systemname = url.copy( url.lastIndexOf( '/' ) + 1 );
2204 else if ( prop.Name == ITEM_DESCRIPTOR_UINAME )
2206 prop.Value >>= uiname;
2212 uno::Reference< container::XIndexAccess > xToolbarSettings =
2213 GetConfigManager()->getSettings( url, false );
2215 if ( uiname.isEmpty() )
2217 // try to get the name from m_xPersistentWindowState
2218 uiname = GetSystemUIName( url );
2220 if ( uiname.isEmpty() )
2222 uiname = systemname;
2226 SvxConfigEntry* pEntry = new SvxConfigEntry(
2227 uiname, url, true, /*bParentData*/false );
2229 pEntry->SetMain();
2230 pEntry->SetStyle( GetSystemStyle( url ) );
2233 // insert into std::unordered_map to filter duplicates from the parent
2234 aToolbarInfo.emplace( systemname, true );
2236 if ( systemname.startsWith( CUSTOM_TOOLBAR_STR ) )
2238 pEntry->SetUserDefined();
2240 else
2242 pEntry->SetUserDefined( false );
2245 pRootEntry->GetEntries()->push_back( pEntry );
2247 LoadToolbar( xToolbarSettings, pEntry );
2249 catch ( container::NoSuchElementException& )
2251 // TODO, handle resourceURL with no settings
2255 uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr = GetParentConfigManager();
2256 if ( xParentCfgMgr.is() )
2258 // Retrieve also the parent toolbars to make it possible
2259 // to configure module toolbars and save them into the document
2260 // config manager.
2261 const uno::Sequence< uno::Sequence < beans::PropertyValue > > info_ =
2262 xParentCfgMgr->getUIElementsInfo(
2263 css::ui::UIElementType::TOOLBAR );
2265 for ( uno::Sequence<beans::PropertyValue> const & props : info_ )
2267 OUString url;
2268 OUString systemname;
2269 OUString uiname;
2271 for ( const beans::PropertyValue& prop : props )
2273 if ( prop.Name == ITEM_DESCRIPTOR_RESOURCEURL )
2275 prop.Value >>= url;
2276 systemname = url.copy( url.lastIndexOf( '/' ) + 1 );
2278 else if ( prop.Name == ITEM_DESCRIPTOR_UINAME )
2280 prop.Value >>= uiname;
2284 // custom toolbars of the parent are not visible in the document layer
2285 OUString custom(CUSTOM_TOOLBAR_STR);
2286 if ( systemname.startsWith( custom ) )
2287 continue;
2289 // check if toolbar is already in the document layer
2290 ToolbarInfo::const_iterator pIter = aToolbarInfo.find( systemname );
2291 if ( pIter == aToolbarInfo.end() )
2293 aToolbarInfo.emplace( systemname, true );
2297 uno::Reference< container::XIndexAccess > xToolbarSettings =
2298 xParentCfgMgr->getSettings( url, false );
2300 if ( uiname.isEmpty() )
2302 // try to get the name from m_xPersistentWindowState
2303 uiname = GetSystemUIName( url );
2305 if ( uiname.isEmpty() )
2307 uiname = systemname;
2311 SvxConfigEntry* pEntry = new SvxConfigEntry(
2312 uiname, url, true, true );
2314 pEntry->SetMain();
2315 pEntry->SetStyle( GetSystemStyle( url ) );
2317 if ( systemname.startsWith( custom ) )
2319 pEntry->SetUserDefined();
2321 else
2323 pEntry->SetUserDefined( false );
2326 pRootEntry->GetEntries()->push_back( pEntry );
2328 LoadToolbar( xToolbarSettings, pEntry );
2330 catch ( container::NoSuchElementException& )
2332 // TODO, handle resourceURL with no settings
2338 std::sort( GetEntries()->begin(), GetEntries()->end(), SvxConfigPageHelper::EntrySort );
2341 return pRootEntry->GetEntries();
2344 void
2345 ToolbarSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
2347 pRootEntry->SetEntries( std::move(pNewEntries) );
2350 bool
2351 ToolbarSaveInData::HasURL( const OUString& rURL )
2353 for (auto const& entry : *GetEntries())
2355 if (entry->GetCommand() == rURL)
2357 return !entry->IsParentData();
2360 return false;
2363 bool ToolbarSaveInData::HasSettings()
2365 // return true if there is at least one toolbar entry
2366 return !GetEntries()->empty();
2369 void ToolbarSaveInData::Reset()
2371 // reset each toolbar by calling removeSettings for its toolbar URL
2372 for (auto const& entry : *GetEntries())
2376 const OUString& url = entry->GetCommand();
2377 GetConfigManager()->removeSettings( url );
2379 catch ( uno::Exception& )
2381 // error occurred removing the settings
2382 // TODO - add error dialog in future?
2386 // persist changes to toolbar storage
2387 PersistChanges( GetConfigManager() );
2389 // now delete the root SvxConfigEntry the next call to GetEntries()
2390 // causes it to be reinitialised
2391 pRootEntry.reset();
2393 // reset all icons to default
2396 GetImageManager()->reset();
2397 PersistChanges( GetImageManager() );
2399 catch ( uno::Exception& )
2401 SAL_WARN("cui.customize", "Error resetting all icons when resetting toolbars");
2405 bool ToolbarSaveInData::Apply()
2407 // toolbar changes are instantly applied
2408 return false;
2411 void ToolbarSaveInData::ApplyToolbar(
2412 uno::Reference< container::XIndexContainer > const & rToolbarBar,
2413 uno::Reference< lang::XSingleComponentFactory >& rFactory,
2414 SvxConfigEntry const * pToolbarData )
2416 const uno::Reference<uno::XComponentContext>& xContext = ::comphelper::getProcessComponentContext();
2418 for (auto const& entry : *pToolbarData->GetEntries())
2420 if (entry->IsPopup())
2422 uno::Sequence< beans::PropertyValue > aPropValueSeq =
2423 SvxConfigPageHelper::ConvertToolbarEntry(entry);
2425 uno::Reference< container::XIndexContainer > xSubMenuBar(
2426 rFactory->createInstanceWithContext( xContext ),
2427 uno::UNO_QUERY );
2429 sal_Int32 nIndex = aPropValueSeq.getLength();
2430 aPropValueSeq.realloc( nIndex + 1 );
2431 auto pPropValueSeq = aPropValueSeq.getArray();
2432 pPropValueSeq[nIndex].Name = m_aDescriptorContainer;
2433 pPropValueSeq[nIndex].Value <<= xSubMenuBar;
2434 rToolbarBar->insertByIndex(
2435 rToolbarBar->getCount(), uno::Any( aPropValueSeq ));
2437 ApplyToolbar(xSubMenuBar, rFactory, entry);
2439 else if (entry->IsSeparator())
2441 rToolbarBar->insertByIndex(
2442 rToolbarBar->getCount(), uno::Any( m_aSeparatorSeq ));
2444 else
2446 uno::Sequence< beans::PropertyValue > aPropValueSeq =
2447 SvxConfigPageHelper::ConvertToolbarEntry(entry);
2449 rToolbarBar->insertByIndex(
2450 rToolbarBar->getCount(), uno::Any( aPropValueSeq ));
2455 void ToolbarSaveInData::ApplyToolbar( SvxConfigEntry* pToolbar )
2457 // Apply new toolbar structure to our settings container
2458 uno::Reference< container::XIndexAccess > xSettings =
2459 GetConfigManager()->createSettings();
2461 uno::Reference< container::XIndexContainer > xIndexContainer (
2462 xSettings, uno::UNO_QUERY );
2464 uno::Reference< lang::XSingleComponentFactory > xFactory (
2465 xSettings, uno::UNO_QUERY );
2467 ApplyToolbar( xIndexContainer, xFactory, pToolbar );
2469 uno::Reference< beans::XPropertySet > xProps(
2470 xSettings, uno::UNO_QUERY );
2472 if ( pToolbar->IsUserDefined() )
2474 xProps->setPropertyValue(
2475 ITEM_DESCRIPTOR_UINAME,
2476 uno::Any( pToolbar->GetName() ) );
2481 if ( GetConfigManager()->hasSettings( pToolbar->GetCommand() ) )
2483 GetConfigManager()->replaceSettings(
2484 pToolbar->GetCommand(), xSettings );
2486 else
2488 GetConfigManager()->insertSettings(
2489 pToolbar->GetCommand(), xSettings );
2490 if ( pToolbar->IsParentData() )
2491 pToolbar->SetParentData( false );
2494 catch ( css::uno::Exception const & )
2496 TOOLS_WARN_EXCEPTION("cui.customize", "caught exception saving settings");
2499 PersistChanges( GetConfigManager() );
2502 void ToolbarSaveInData::CreateToolbar( SvxConfigEntry* pToolbar )
2504 // show the new toolbar in the UI also
2505 uno::Reference< container::XIndexAccess >
2506 xSettings = GetConfigManager()->createSettings();
2508 uno::Reference< beans::XPropertySet >
2509 xPropertySet( xSettings, uno::UNO_QUERY );
2511 xPropertySet->setPropertyValue(
2512 ITEM_DESCRIPTOR_UINAME,
2513 uno::Any( pToolbar->GetName() ) );
2517 GetConfigManager()->insertSettings( pToolbar->GetCommand(), xSettings );
2519 catch ( css::uno::Exception const & )
2521 TOOLS_WARN_EXCEPTION("cui.customize", "caught exception saving settings");
2524 GetEntries()->push_back( pToolbar );
2526 PersistChanges( GetConfigManager() );
2529 void ToolbarSaveInData::RemoveToolbar( SvxConfigEntry* pToolbar )
2533 OUString url = pToolbar->GetCommand();
2534 GetConfigManager()->removeSettings( url );
2535 SvxConfigPageHelper::RemoveEntry( GetEntries(), pToolbar );
2536 delete pToolbar;
2538 PersistChanges( GetConfigManager() );
2540 // remove the persistent window state data
2541 css::uno::Reference< css::container::XNameContainer > xNameContainer(
2542 m_xPersistentWindowState, css::uno::UNO_QUERY_THROW );
2544 xNameContainer->removeByName( url );
2546 catch ( uno::Exception& )
2548 // error occurred removing the settings
2552 void ToolbarSaveInData::RestoreToolbar( SvxConfigEntry* pToolbar )
2554 OUString url = pToolbar->GetCommand();
2556 // Restore of toolbar is done by removing it from
2557 // its configuration manager and then getting it again
2558 bool bParentToolbar = pToolbar->IsParentData();
2560 // Cannot restore parent toolbar
2561 if ( bParentToolbar )
2562 return;
2566 GetConfigManager()->removeSettings( url );
2567 pToolbar->GetEntries()->clear();
2568 PersistChanges( GetConfigManager() );
2570 catch ( uno::Exception& )
2572 // if an error occurs removing the settings then just return
2573 return;
2576 // Now reload the toolbar settings
2579 uno::Reference< container::XIndexAccess > xToolbarSettings;
2580 if ( IsDocConfig() )
2582 xToolbarSettings = GetParentConfigManager()->getSettings( url, false );
2583 pToolbar->SetParentData();
2585 else
2586 xToolbarSettings = GetConfigManager()->getSettings( url, false );
2588 LoadToolbar( xToolbarSettings, pToolbar );
2590 // After reloading, ensure that the icon is reset of each entry
2591 // in the toolbar
2592 uno::Sequence< OUString > aURLSeq( 1 );
2593 auto pURLSeq = aURLSeq.getArray();
2594 for (auto const& entry : *pToolbar->GetEntries())
2596 pURLSeq[ 0 ] = entry->GetCommand();
2600 GetImageManager()->removeImages( SvxConfigPageHelper::GetImageType(), aURLSeq );
2602 catch ( uno::Exception& )
2604 SAL_WARN("cui.customize", "Error restoring icon when resetting toolbar");
2607 PersistChanges( GetImageManager() );
2609 catch ( container::NoSuchElementException& )
2611 // cannot find the resource URL after removing it
2612 // so no entry will appear in the toolbar list
2616 void ToolbarSaveInData::LoadToolbar(
2617 const uno::Reference< container::XIndexAccess >& xToolbarSettings,
2618 SvxConfigEntry const * pParentData )
2620 SvxEntries* pEntries = pParentData->GetEntries();
2622 for ( sal_Int32 nIndex = 0; nIndex < xToolbarSettings->getCount(); ++nIndex )
2624 OUString aCommandURL;
2625 OUString aLabel;
2626 bool bIsVisible;
2627 sal_Int32 nStyle;
2629 sal_uInt16 nType( css::ui::ItemType::DEFAULT );
2631 bool bItem = SvxConfigPageHelper::GetToolbarItemData( xToolbarSettings, nIndex, aCommandURL,
2632 aLabel, nType, bIsVisible, nStyle );
2634 if ( bItem )
2636 bool bIsUserDefined = true;
2638 if ( nType == css::ui::ItemType::DEFAULT )
2640 uno::Any a;
2643 a = m_xCommandToLabelMap->getByName( aCommandURL );
2644 bIsUserDefined = false;
2646 catch ( container::NoSuchElementException& )
2648 bIsUserDefined = true;
2651 bool bUseDefaultLabel = false;
2652 // If custom label not set retrieve it from the command
2653 // to info service
2654 if ( aLabel.isEmpty() )
2656 bUseDefaultLabel = true;
2657 uno::Sequence< beans::PropertyValue > aPropSeq;
2658 if ( a >>= aPropSeq )
2660 for (beans::PropertyValue const& prop : aPropSeq)
2662 if ( prop.Name == "Name" )
2664 prop.Value >>= aLabel;
2665 break;
2671 SvxConfigEntry* pEntry = new SvxConfigEntry(
2672 aLabel, aCommandURL, false, /*bParentData*/false );
2674 pEntry->SetUserDefined( bIsUserDefined );
2675 pEntry->SetVisible( bIsVisible );
2676 pEntry->SetStyle( nStyle );
2678 if ( !bUseDefaultLabel )
2679 pEntry->SetName( aLabel );
2681 pEntries->push_back( pEntry );
2683 else
2685 SvxConfigEntry* pEntry = new SvxConfigEntry;
2686 pEntry->SetUserDefined( bIsUserDefined );
2687 pEntries->push_back( pEntry );
2693 SvxNewToolbarDialog::SvxNewToolbarDialog(weld::Window* pWindow, const OUString& rName)
2694 : GenericDialogController(pWindow, u"cui/ui/newtoolbardialog.ui"_ustr, u"NewToolbarDialog"_ustr)
2695 , m_xEdtName(m_xBuilder->weld_entry(u"edit"_ustr))
2696 , m_xSaveInListBox(m_xBuilder->weld_combo_box(u"savein"_ustr))
2698 m_xEdtName->set_text(rName);
2699 m_xEdtName->select_region(0, -1);
2702 SvxNewToolbarDialog::~SvxNewToolbarDialog()
2706 /*******************************************************************************
2708 * The SvxIconSelectorDialog class
2710 *******************************************************************************/
2711 SvxIconSelectorDialog::SvxIconSelectorDialog(weld::Window *pWindow,
2712 uno::Reference< css::ui::XImageManager > xImageManager,
2713 uno::Reference< css::ui::XImageManager > xParentImageManager)
2714 : GenericDialogController(pWindow, u"cui/ui/iconselectordialog.ui"_ustr, u"IconSelector"_ustr)
2715 , m_xImageManager(std::move(xImageManager))
2716 , m_xParentImageManager(std::move(xParentImageManager))
2717 , m_xTbSymbol(new ValueSet(m_xBuilder->weld_scrolled_window(u"symbolswin"_ustr, true)))
2718 , m_xTbSymbolWin(new weld::CustomWeld(*m_xBuilder, u"symbolsToolbar"_ustr, *m_xTbSymbol))
2719 , m_xFtNote(m_xBuilder->weld_label(u"noteLabel"_ustr))
2720 , m_xBtnImport(m_xBuilder->weld_button(u"importButton"_ustr))
2721 , m_xBtnDelete(m_xBuilder->weld_button(u"deleteButton"_ustr))
2723 typedef std::unordered_map< OUString, bool > ImageInfo;
2725 m_nExpectedSize = 16;
2726 if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_LARGE)
2727 m_nExpectedSize = 24;
2728 else if (SvxConfigPageHelper::GetImageType() & css::ui::ImageType::SIZE_32)
2729 m_nExpectedSize = 32;
2731 if ( m_nExpectedSize != 16 )
2733 m_xFtNote->set_label(SvxConfigPageHelper::replaceSixteen(m_xFtNote->get_label(), m_nExpectedSize));
2736 m_xTbSymbol->SetStyle(m_xTbSymbol->GetStyle() | WB_ITEMBORDER | WB_VSCROLL);
2737 m_xTbSymbol->SetColCount(11);
2738 m_xTbSymbol->SetLineCount(5);
2739 m_xTbSymbol->SetItemWidth(m_nExpectedSize);
2740 m_xTbSymbol->SetItemHeight(m_nExpectedSize);
2741 m_xTbSymbol->SetExtraSpacing(6);
2742 m_xTbSymbol->SetMargin(4);
2743 Size aSize(m_xTbSymbol->CalcWindowSizePixel(Size(m_nExpectedSize, m_nExpectedSize), 11, 5));
2744 m_xTbSymbol->set_size_request(aSize.Width(), aSize.Height());
2746 const uno::Reference< uno::XComponentContext >& xComponentContext =
2747 ::comphelper::getProcessComponentContext();
2749 m_xGraphProvider.set( graphic::GraphicProvider::create( xComponentContext ) );
2751 uno::Reference< css::util::XPathSettings > xPathSettings =
2752 css::util::thePathSettings::get( xComponentContext );
2755 OUString aDirectory = xPathSettings->getUserConfig();
2757 sal_Int32 aCount = aDirectory.getLength();
2759 if ( aCount > 0 )
2761 sal_Unicode aChar = aDirectory[ aCount-1 ];
2762 if ( aChar != '/')
2764 aDirectory += "/";
2767 else
2769 m_xBtnImport->set_sensitive(false);
2772 aDirectory += "soffice.cfg/import";
2774 uno::Reference< lang::XSingleServiceFactory > xStorageFactory(
2775 css::embed::FileSystemStorageFactory::create( xComponentContext ) );
2777 uno::Sequence< uno::Any > aArgs{ uno::Any(aDirectory),
2778 uno::Any(css::embed::ElementModes::READWRITE) };
2780 uno::Reference< css::embed::XStorage > xStorage(
2781 xStorageFactory->createInstanceWithArguments( aArgs ), uno::UNO_QUERY );
2783 uno::Sequence<uno::Any> aProp(comphelper::InitAnyPropertySequence(
2785 {"UserConfigStorage", uno::Any(xStorage)},
2786 {"OpenMode", uno::Any(css::embed::ElementModes::READWRITE)}
2787 }));
2788 m_xImportedImageManager = css::ui::ImageManager::create( xComponentContext );
2789 m_xImportedImageManager->initialize(aProp);
2791 ImageInfo aImageInfo1;
2792 if ( m_xImportedImageManager.is() )
2794 const uno::Sequence< OUString > names = m_xImportedImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2795 for (auto const & name : names )
2796 aImageInfo1.emplace( name, false );
2799 uno::Sequence< OUString > name( 1 );
2800 auto pname = name.getArray();
2801 for (auto const& elem : aImageInfo1)
2803 pname[ 0 ] = elem.first;
2804 uno::Sequence< uno::Reference< graphic::XGraphic> > graphics = m_xImportedImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2805 if ( graphics.hasElements() )
2807 m_aGraphics.push_back(graphics[0]);
2808 Image img(graphics[0]);
2809 m_xTbSymbol->InsertItem(m_aGraphics.size(), img, elem.first);
2813 ImageInfo aImageInfo;
2815 if ( m_xParentImageManager.is() )
2817 const uno::Sequence< OUString > names = m_xParentImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2818 for ( auto const & i : names )
2819 aImageInfo.emplace( i, false );
2822 const uno::Sequence< OUString > names = m_xImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2823 for ( auto const & i : names )
2825 ImageInfo::iterator pIter = aImageInfo.find( i );
2826 if ( pIter != aImageInfo.end() )
2827 pIter->second = true;
2828 else
2829 aImageInfo.emplace( i, true );
2832 // large growth factor, expecting many entries
2833 for (auto const& elem : aImageInfo)
2835 pname[ 0 ] = elem.first;
2837 uno::Sequence< uno::Reference< graphic::XGraphic> > graphics;
2840 if (elem.second)
2841 graphics = m_xImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2842 else
2843 graphics = m_xParentImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2845 catch ( uno::Exception& )
2847 // can't get sequence for this name so it will not be
2848 // added to the list
2851 if ( graphics.hasElements() )
2853 Image img(graphics[0]);
2854 if (!img.GetBitmapEx().IsEmpty())
2856 m_aGraphics.push_back(graphics[0]);
2857 m_xTbSymbol->InsertItem(m_aGraphics.size(), img, elem.first);
2862 m_xBtnDelete->set_sensitive( false );
2863 m_xTbSymbol->SetSelectHdl( LINK(this, SvxIconSelectorDialog, SelectHdl) );
2864 m_xBtnImport->connect_clicked( LINK(this, SvxIconSelectorDialog, ImportHdl) );
2865 m_xBtnDelete->connect_clicked( LINK(this, SvxIconSelectorDialog, DeleteHdl) );
2868 SvxIconSelectorDialog::~SvxIconSelectorDialog()
2872 uno::Reference< graphic::XGraphic> SvxIconSelectorDialog::GetSelectedIcon()
2874 uno::Reference<graphic::XGraphic> result;
2876 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2878 if (nId)
2880 result = m_aGraphics[nId - 1];
2883 return result;
2886 IMPL_LINK_NOARG(SvxIconSelectorDialog, SelectHdl, ValueSet*, void)
2888 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2890 if (!nId)
2892 m_xBtnDelete->set_sensitive(false);
2893 return;
2896 OUString aSelImageText = m_xTbSymbol->GetItemText(nId);
2897 if (m_xImportedImageManager->hasImage(SvxConfigPageHelper::GetImageType(), aSelImageText))
2899 m_xBtnDelete->set_sensitive(true);
2901 else
2903 m_xBtnDelete->set_sensitive(false);
2907 IMPL_LINK_NOARG(SvxIconSelectorDialog, ImportHdl, weld::Button&, void)
2909 sfx2::FileDialogHelper aImportDialog(
2910 css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW,
2911 FileDialogFlags::Graphic | FileDialogFlags::MultiSelection, m_xDialog.get());
2912 aImportDialog.SetContext(sfx2::FileDialogHelper::IconImport);
2914 // disable the link checkbox in the dialog
2915 uno::Reference< css::ui::dialogs::XFilePickerControlAccess >
2916 xController( aImportDialog.GetFilePicker(), uno::UNO_QUERY);
2917 if ( xController.is() )
2919 xController->enableControl(
2920 css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK,
2921 false);
2924 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
2925 sal_uInt16 nFilter = rFilter.GetImportFormatNumberForShortName(u"png");
2926 aImportDialog.SetCurrentFilter(rFilter.GetImportFormatName(nFilter));
2928 if ( ERRCODE_NONE == aImportDialog.Execute() )
2930 uno::Sequence< OUString > paths = aImportDialog.GetMPath();
2931 ImportGraphics ( paths );
2935 IMPL_LINK_NOARG(SvxIconSelectorDialog, DeleteHdl, weld::Button&, void)
2937 OUString message = CuiResId( RID_CUISTR_DELETE_ICON_CONFIRM );
2939 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xDialog.get(),
2940 VclMessageType::Warning, VclButtonsType::OkCancel,
2941 message));
2942 if (xWarn->run() != RET_OK)
2943 return;
2945 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2947 uno::Sequence<OUString> URLs { m_xTbSymbol->GetItemText(nId) };
2948 m_xTbSymbol->RemoveItem(nId);
2949 m_xImportedImageManager->removeImages( SvxConfigPageHelper::GetImageType(), URLs );
2950 if ( m_xImportedImageManager->isModified() )
2952 m_xImportedImageManager->store();
2956 bool SvxIconSelectorDialog::ReplaceGraphicItem(
2957 const OUString& aURL )
2959 uno::Reference< graphic::XGraphic > xGraphic;
2960 uno::Sequence< beans::PropertyValue > aMediaProps{ comphelper::makePropertyValue(u"URL"_ustr, aURL) };
2962 css::awt::Size aSize;
2963 bool bOK = false;
2966 xGraphic = m_xGraphProvider->queryGraphic( aMediaProps );
2968 uno::Reference< beans::XPropertySet > props =
2969 m_xGraphProvider->queryGraphicDescriptor( aMediaProps );
2970 uno::Any a = props->getPropertyValue( u"SizePixel"_ustr );
2971 a >>= aSize;
2972 if (0 == aSize.Width || 0 == aSize.Height)
2973 return false;
2974 else
2975 bOK = true;
2977 catch ( uno::Exception& )
2979 return false;
2982 bool bResult( false );
2983 size_t nCount = m_xTbSymbol->GetItemCount();
2984 for (size_t n = 0; n < nCount; ++n)
2986 sal_uInt16 nId = m_xTbSymbol->GetItemId( n );
2987 assert(nId > 0 && "otherwise totally broken");
2989 if ( m_xTbSymbol->GetItemText( nId ) == aURL )
2993 // replace/insert image with provided URL
2994 size_t nPos = nId - 1;
2995 assert(nPos == m_xTbSymbol->GetItemPos(nId));
2996 m_xTbSymbol->RemoveItem(nId);
2998 Image aImage( xGraphic );
2999 if ( bOK && ((aSize.Width != m_nExpectedSize) || (aSize.Height != m_nExpectedSize)) )
3001 BitmapEx aBitmap = aImage.GetBitmapEx();
3002 BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, m_nExpectedSize);
3003 aImage = Image( aBitmapex);
3005 m_xTbSymbol->InsertItem(nId, aImage, aURL, nPos); //modify
3007 m_aGraphics[nPos] = Graphic(aImage.GetBitmapEx()).GetXGraphic();
3009 m_xImportedImageManager->replaceImages( SvxConfigPageHelper::GetImageType(), { aURL }, { xGraphic } );
3010 m_xImportedImageManager->store();
3012 bResult = true;
3013 break;
3015 catch ( css::uno::Exception& )
3017 break;
3022 return bResult;
3025 namespace
3027 OUString ReplaceIconName(std::u16string_view rMessage)
3029 OUString name;
3030 OUString message = CuiResId( RID_CUISTR_REPLACE_ICON_WARNING );
3031 OUString placeholder(u"%ICONNAME"_ustr );
3032 sal_Int32 pos = message.indexOf( placeholder );
3033 if ( pos != -1 )
3035 name = message.replaceAt(
3036 pos, placeholder.getLength(), rMessage );
3038 return name;
3041 class SvxIconReplacementDialog
3043 private:
3044 std::unique_ptr<weld::MessageDialog> m_xQueryBox;
3045 public:
3046 SvxIconReplacementDialog(weld::Window *pParent, std::u16string_view rMessage, bool bYestoAll)
3047 : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Warning, VclButtonsType::NONE, ReplaceIconName(rMessage)))
3049 m_xQueryBox->set_title(CuiResId(RID_CUISTR_REPLACE_ICON_CONFIRM));
3050 m_xQueryBox->add_button(GetStandardText(StandardButtonType::Yes), 2);
3051 if (bYestoAll)
3052 m_xQueryBox->add_button(CuiResId(RID_CUISTR_YESTOALL), 5);
3053 m_xQueryBox->add_button(GetStandardText(StandardButtonType::No), 4);
3054 m_xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), 6);
3055 m_xQueryBox->set_default_response(2);
3057 short run() { return m_xQueryBox->run(); }
3061 void SvxIconSelectorDialog::ImportGraphics(
3062 const uno::Sequence< OUString >& rPaths )
3064 std::vector< OUString > rejected( rPaths.getLength() );
3065 sal_Int32 rejectedCount = 0;
3067 sal_uInt16 ret = 0;
3068 sal_Int32 aIndex;
3069 OUString aIconName;
3071 if ( rPaths.getLength() == 1 )
3073 if ( m_xImportedImageManager->hasImage( SvxConfigPageHelper::GetImageType(), rPaths[0] ) )
3075 aIndex = rPaths[0].lastIndexOf( '/' );
3076 aIconName = rPaths[0].copy( aIndex+1 );
3077 SvxIconReplacementDialog aDlg(m_xDialog.get(), aIconName, false);
3078 ret = aDlg.run();
3079 if ( ret == 2 )
3081 ReplaceGraphicItem( rPaths[0] );
3084 else
3086 if ( !ImportGraphic( rPaths[0] ) )
3088 rejected[0] = rPaths[0];
3089 rejectedCount = 1;
3093 else
3095 OUString aSourcePath( rPaths[0] );
3096 if ( rPaths[0].lastIndexOf( '/' ) != rPaths[0].getLength() -1 )
3097 aSourcePath = rPaths[0] + "/";
3099 for ( sal_Int32 i = 1; i < rPaths.getLength(); ++i )
3101 OUString aPath = aSourcePath + rPaths[i];
3102 if ( m_xImportedImageManager->hasImage( SvxConfigPageHelper::GetImageType(), aPath ) )
3104 aIndex = rPaths[i].lastIndexOf( '/' );
3105 aIconName = rPaths[i].copy( aIndex+1 );
3106 SvxIconReplacementDialog aDlg(m_xDialog.get(), aIconName, true);
3107 ret = aDlg.run();
3108 if ( ret == 2 )
3110 ReplaceGraphicItem( aPath );
3112 else if ( ret == 5 )
3114 for ( sal_Int32 k = i; k < rPaths.getLength(); ++k )
3116 aPath = aSourcePath + rPaths[k];
3117 bool bHasReplaced = ReplaceGraphicItem( aPath );
3119 if ( !bHasReplaced )
3121 bool result = ImportGraphic( aPath );
3122 if ( !result )
3124 rejected[ rejectedCount ] = rPaths[i];
3125 ++rejectedCount;
3129 break;
3132 else
3134 bool result = ImportGraphic( aSourcePath + rPaths[i] );
3135 if ( !result )
3137 rejected[ rejectedCount ] = rPaths[i];
3138 ++rejectedCount;
3144 if ( rejectedCount == 0 )
3145 return;
3147 OUStringBuffer message;
3148 OUString fPath;
3149 if (rejectedCount > 1)
3150 fPath = OUString::Concat(rPaths[0].subView(8)) + "/";
3151 for ( sal_Int32 i = 0; i < rejectedCount; ++i )
3153 message.append(fPath + rejected[i] + "\n");
3156 SvxIconChangeDialog aDialog(m_xDialog.get(), message.makeStringAndClear());
3157 aDialog.run();
3160 bool SvxIconSelectorDialog::ImportGraphic( const OUString& aURL )
3162 bool result = false;
3164 uno::Sequence< beans::PropertyValue > aMediaProps{ comphelper::makePropertyValue(u"URL"_ustr, aURL) };
3168 uno::Reference< beans::XPropertySet > props =
3169 m_xGraphProvider->queryGraphicDescriptor( aMediaProps );
3171 uno::Any a = props->getPropertyValue(u"SizePixel"_ustr);
3173 uno::Reference< graphic::XGraphic > xGraphic = m_xGraphProvider->queryGraphic( aMediaProps );
3174 if ( xGraphic.is() )
3176 bool bOK = true;
3177 css::awt::Size aSize;
3179 a >>= aSize;
3180 if ( 0 == aSize.Width || 0 == aSize.Height )
3181 bOK = false;
3183 Image aImage( xGraphic );
3185 if ( bOK && ((aSize.Width != m_nExpectedSize) || (aSize.Height != m_nExpectedSize)) )
3187 BitmapEx aBitmap = aImage.GetBitmapEx();
3188 BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, m_nExpectedSize);
3189 aImage = Image( aBitmapex);
3191 if ( bOK && !!aImage )
3193 m_aGraphics.push_back(Graphic(aImage.GetBitmapEx()).GetXGraphic());
3194 m_xTbSymbol->InsertItem(m_aGraphics.size(), aImage, aURL);
3196 uno::Sequence<OUString> aImportURL { aURL };
3197 uno::Sequence< uno::Reference<graphic::XGraphic > > aImportGraph{ xGraphic };
3198 m_xImportedImageManager->insertImages( SvxConfigPageHelper::GetImageType(), aImportURL, aImportGraph );
3199 if ( m_xImportedImageManager->isModified() )
3201 m_xImportedImageManager->store();
3204 result = true;
3206 else
3208 SAL_WARN("cui.customize", "could not create Image from XGraphic");
3211 else
3213 SAL_WARN("cui.customize", "could not get query XGraphic");
3216 catch( uno::Exception const & )
3218 TOOLS_WARN_EXCEPTION("cui.customize", "Caught exception importing XGraphic");
3220 return result;
3223 /*******************************************************************************
3225 * The SvxIconChangeDialog class added for issue83555
3227 *******************************************************************************/
3228 SvxIconChangeDialog::SvxIconChangeDialog(weld::Window *pWindow, const OUString& rMessage)
3229 : MessageDialogController(pWindow, u"cui/ui/iconchangedialog.ui"_ustr, u"IconChange"_ustr, u"grid"_ustr)
3230 , m_xLineEditDescription(m_xBuilder->weld_text_view(u"addrTextview"_ustr))
3232 m_xLineEditDescription->set_size_request(m_xLineEditDescription->get_approximate_digit_width() * 48,
3233 m_xLineEditDescription->get_text_height() * 8);
3234 m_xLineEditDescription->set_text(rMessage);
3237 SvxConfigPageFunctionDropTarget::SvxConfigPageFunctionDropTarget(SvxConfigPage&rPage, weld::TreeView& rTreeView)
3238 : weld::ReorderingDropTarget(rTreeView)
3239 , m_rPage(rPage)
3243 sal_Int8 SvxConfigPageFunctionDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
3245 sal_Int8 nRet = weld::ReorderingDropTarget::ExecuteDrop(rEvt);
3246 m_rPage.ListModified();
3247 return nRet;;
3250 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */