android: Update app-specific/MIME type icons
[LibreOffice.git] / cui / source / customize / cfg.cxx
blobd41012850bce9464d0700b6c7c2aef25e931ea45
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 = com::sun::star::uno;
98 namespace frame = com::sun::star::frame;
99 namespace lang = com::sun::star::lang;
100 namespace container = com::sun::star::container;
101 namespace beans = com::sun::star::beans;
102 namespace graphic = com::sun::star::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, "cui/ui/customizedialog.ui", "CustomizeDialog", pInSet)
211 SvxConfigPageHelper::InitImageType();
213 AddTabPage("menus", CreateSvxMenuConfigPage, nullptr);
214 AddTabPage("toolbars", CreateSvxToolbarConfigPage, nullptr);
215 AddTabPage("notebookbar", CreateSvxNotebookbarConfigPage, nullptr);
216 AddTabPage("contextmenus", CreateSvxContextMenuConfigPage, nullptr);
217 AddTabPage("keyboard", CreateKeyboardConfigPage, nullptr);
218 AddTabPage("events", 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("toolbars");
225 else if (text.startsWith( ITEM_EVENT_URL) )
226 SetCurPageId("events");
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("keyboard");
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("notebookbar");
256 if (aModuleId == "com.sun.star.frame.StartModule")
257 RemoveTabPage("keyboard");
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 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( "MainMenus", 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 : std::as_const(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 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 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 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 : std::as_const(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( "ContextMenus", 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 : std::as_const(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 : std::as_const(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, "cui/ui/menuassignpage.ui", "MenuAssignPage", &rSet)
1004 , m_aUpdateDataTimer( "SvxConfigPage UpdateDataTimer" )
1005 , bInitialised(false)
1006 , pCurrentSaveInData(nullptr)
1007 , m_xCommandCategoryListBox(new CommandCategoryListBox(m_xBuilder->weld_combo_box("commandcategorylist")))
1008 , m_xFunctions(new CuiConfigFunctionListBox(m_xBuilder->weld_tree_view("functions")))
1009 , m_xCategoryLabel(m_xBuilder->weld_label("categorylabel"))
1010 , m_xDescriptionFieldLb(m_xBuilder->weld_label("descriptionlabel"))
1011 , m_xDescriptionField(m_xBuilder->weld_text_view("desc"))
1012 , m_xLeftFunctionLabel(m_xBuilder->weld_label("leftfunctionlabel"))
1013 , m_xSearchEdit(m_xBuilder->weld_entry("searchEntry"))
1014 , m_xSearchLabel(m_xBuilder->weld_label("searchlabel"))
1015 , m_xCustomizeLabel(m_xBuilder->weld_label("customizelabel"))
1016 , m_xTopLevelListBox(m_xBuilder->weld_combo_box("toplevellist"))
1017 , m_xMoveUpButton(m_xBuilder->weld_button("up"))
1018 , m_xMoveDownButton(m_xBuilder->weld_button("down"))
1019 , m_xSaveInListBox(m_xBuilder->weld_combo_box("savein"))
1020 , m_xCustomizeBox(m_xBuilder->weld_widget("customizebox"))
1021 , m_xInsertBtn(m_xBuilder->weld_menu_button("insert"))
1022 , m_xModifyBtn(m_xBuilder->weld_menu_button("modify"))
1023 , m_xResetBtn(m_xBuilder->weld_button("defaultsbtn"))
1024 , m_xCommandButtons(m_xBuilder->weld_widget("arrowgrid"))
1025 , m_xAddCommandButton(m_xBuilder->weld_button("add"))
1026 , m_xRemoveCommandButton(m_xBuilder->weld_button("remove"))
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_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 : std::as_const(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 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->GetHelpText(false));
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("");
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, "cui/ui/movemenu.ui", "MoveMenuDialog")
1784 , m_xMenuBox(m_xBuilder->weld_widget("namebox"))
1785 , m_xMenuNameEdit(m_xBuilder->weld_entry("menuname"))
1786 , m_xMenuListBox(m_xBuilder->weld_tree_view("menulist"))
1787 , m_xMoveUpButton(m_xBuilder->weld_button("up"))
1788 , m_xMoveDownButton(m_xBuilder->weld_button("down"))
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_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 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 : std::as_const(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( "LayoutManager" );
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 : std::as_const(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 : std::as_const(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( "MainToolbars", 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 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 : std::as_const(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, "cui/ui/newtoolbardialog.ui", "NewToolbarDialog")
2695 , m_xEdtName(m_xBuilder->weld_entry("edit"))
2696 , m_xSaveInListBox(m_xBuilder->weld_combo_box("savein"))
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, "cui/ui/iconselectordialog.ui", "IconSelector")
2715 , m_xImageManager(std::move(xImageManager))
2716 , m_xParentImageManager(std::move(xParentImageManager))
2717 , m_xTbSymbol(new ValueSet(m_xBuilder->weld_scrolled_window("symbolswin", true)))
2718 , m_xTbSymbolWin(new weld::CustomWeld(*m_xBuilder, "symbolsToolbar", *m_xTbSymbol))
2719 , m_xFtNote(m_xBuilder->weld_label("noteLabel"))
2720 , m_xBtnImport(m_xBuilder->weld_button("importButton"))
2721 , m_xBtnDelete(m_xBuilder->weld_button("deleteButton"))
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 Size aSize(m_xTbSymbol->CalcWindowSizePixel(Size(m_nExpectedSize, m_nExpectedSize), 11, 5));
2743 m_xTbSymbol->set_size_request(aSize.Width(), aSize.Height());
2745 uno::Reference< uno::XComponentContext > xComponentContext =
2746 ::comphelper::getProcessComponentContext();
2748 m_xGraphProvider.set( graphic::GraphicProvider::create( xComponentContext ) );
2750 uno::Reference< css::util::XPathSettings > xPathSettings =
2751 css::util::thePathSettings::get( xComponentContext );
2754 OUString aDirectory = xPathSettings->getUserConfig();
2756 sal_Int32 aCount = aDirectory.getLength();
2758 if ( aCount > 0 )
2760 sal_Unicode aChar = aDirectory[ aCount-1 ];
2761 if ( aChar != '/')
2763 aDirectory += "/";
2766 else
2768 m_xBtnImport->set_sensitive(false);
2771 aDirectory += "soffice.cfg/import";
2773 uno::Reference< lang::XSingleServiceFactory > xStorageFactory(
2774 css::embed::FileSystemStorageFactory::create( xComponentContext ) );
2776 uno::Sequence< uno::Any > aArgs{ uno::Any(aDirectory),
2777 uno::Any(css::embed::ElementModes::READWRITE) };
2779 uno::Reference< css::embed::XStorage > xStorage(
2780 xStorageFactory->createInstanceWithArguments( aArgs ), uno::UNO_QUERY );
2782 uno::Sequence<uno::Any> aProp(comphelper::InitAnyPropertySequence(
2784 {"UserConfigStorage", uno::Any(xStorage)},
2785 {"OpenMode", uno::Any(css::embed::ElementModes::READWRITE)}
2786 }));
2787 m_xImportedImageManager = css::ui::ImageManager::create( xComponentContext );
2788 m_xImportedImageManager->initialize(aProp);
2790 ImageInfo aImageInfo1;
2791 if ( m_xImportedImageManager.is() )
2793 const uno::Sequence< OUString > names = m_xImportedImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2794 for (auto const & name : names )
2795 aImageInfo1.emplace( name, false );
2798 uno::Sequence< OUString > name( 1 );
2799 auto pname = name.getArray();
2800 for (auto const& elem : aImageInfo1)
2802 pname[ 0 ] = elem.first;
2803 uno::Sequence< uno::Reference< graphic::XGraphic> > graphics = m_xImportedImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2804 if ( graphics.hasElements() )
2806 m_aGraphics.push_back(graphics[0]);
2807 Image img(graphics[0]);
2808 m_xTbSymbol->InsertItem(m_aGraphics.size(), img, elem.first);
2812 ImageInfo aImageInfo;
2814 if ( m_xParentImageManager.is() )
2816 const uno::Sequence< OUString > names = m_xParentImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2817 for ( auto const & i : names )
2818 aImageInfo.emplace( i, false );
2821 const uno::Sequence< OUString > names = m_xImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2822 for ( auto const & i : names )
2824 ImageInfo::iterator pIter = aImageInfo.find( i );
2825 if ( pIter != aImageInfo.end() )
2826 pIter->second = true;
2827 else
2828 aImageInfo.emplace( i, true );
2831 // large growth factor, expecting many entries
2832 for (auto const& elem : aImageInfo)
2834 pname[ 0 ] = elem.first;
2836 uno::Sequence< uno::Reference< graphic::XGraphic> > graphics;
2839 if (elem.second)
2840 graphics = m_xImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2841 else
2842 graphics = m_xParentImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2844 catch ( uno::Exception& )
2846 // can't get sequence for this name so it will not be
2847 // added to the list
2850 if ( graphics.hasElements() )
2852 Image img(graphics[0]);
2853 if (!img.GetBitmapEx().IsEmpty())
2855 m_aGraphics.push_back(graphics[0]);
2856 m_xTbSymbol->InsertItem(m_aGraphics.size(), img, elem.first);
2861 m_xBtnDelete->set_sensitive( false );
2862 m_xTbSymbol->SetSelectHdl( LINK(this, SvxIconSelectorDialog, SelectHdl) );
2863 m_xBtnImport->connect_clicked( LINK(this, SvxIconSelectorDialog, ImportHdl) );
2864 m_xBtnDelete->connect_clicked( LINK(this, SvxIconSelectorDialog, DeleteHdl) );
2867 SvxIconSelectorDialog::~SvxIconSelectorDialog()
2871 uno::Reference< graphic::XGraphic> SvxIconSelectorDialog::GetSelectedIcon()
2873 uno::Reference<graphic::XGraphic> result;
2875 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2877 if (nId)
2879 result = m_aGraphics[nId - 1];
2882 return result;
2885 IMPL_LINK_NOARG(SvxIconSelectorDialog, SelectHdl, ValueSet*, void)
2887 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2889 if (!nId)
2891 m_xBtnDelete->set_sensitive(false);
2892 return;
2895 OUString aSelImageText = m_xTbSymbol->GetItemText(nId);
2896 if (m_xImportedImageManager->hasImage(SvxConfigPageHelper::GetImageType(), aSelImageText))
2898 m_xBtnDelete->set_sensitive(true);
2900 else
2902 m_xBtnDelete->set_sensitive(false);
2906 IMPL_LINK_NOARG(SvxIconSelectorDialog, ImportHdl, weld::Button&, void)
2908 sfx2::FileDialogHelper aImportDialog(
2909 css::ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW,
2910 FileDialogFlags::Graphic | FileDialogFlags::MultiSelection, m_xDialog.get());
2911 aImportDialog.SetContext(sfx2::FileDialogHelper::IconImport);
2913 // disable the link checkbox in the dialog
2914 uno::Reference< css::ui::dialogs::XFilePickerControlAccess >
2915 xController( aImportDialog.GetFilePicker(), uno::UNO_QUERY);
2916 if ( xController.is() )
2918 xController->enableControl(
2919 css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK,
2920 false);
2923 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
2924 sal_uInt16 nFilter = rFilter.GetImportFormatNumberForShortName(u"png");
2925 aImportDialog.SetCurrentFilter(rFilter.GetImportFormatName(nFilter));
2927 if ( ERRCODE_NONE == aImportDialog.Execute() )
2929 uno::Sequence< OUString > paths = aImportDialog.GetMPath();
2930 ImportGraphics ( paths );
2934 IMPL_LINK_NOARG(SvxIconSelectorDialog, DeleteHdl, weld::Button&, void)
2936 OUString message = CuiResId( RID_CUISTR_DELETE_ICON_CONFIRM );
2938 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xDialog.get(),
2939 VclMessageType::Warning, VclButtonsType::OkCancel,
2940 message));
2941 if (xWarn->run() != RET_OK)
2942 return;
2944 sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2946 OUString aSelImageText = m_xTbSymbol->GetItemText( nId );
2947 uno::Sequence< OUString > URLs { aSelImageText };
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("URL", 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( "SizePixel" );
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 );
2988 if ( m_xTbSymbol->GetItemText( nId ) == aURL )
2992 // replace/insert image with provided URL
2993 size_t nPos = nId - 1;
2994 assert(nPos == m_xTbSymbol->GetItemPos(nId));
2995 m_xTbSymbol->RemoveItem(nId);
2997 Image aImage( xGraphic );
2998 if ( bOK && ((aSize.Width != m_nExpectedSize) || (aSize.Height != m_nExpectedSize)) )
3000 BitmapEx aBitmap = aImage.GetBitmapEx();
3001 BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, m_nExpectedSize);
3002 aImage = Image( aBitmapex);
3004 m_xTbSymbol->InsertItem(nId, aImage, aURL, nPos); //modify
3006 m_aGraphics[nPos] = Graphic(aImage.GetBitmapEx()).GetXGraphic();
3008 m_xImportedImageManager->replaceImages( SvxConfigPageHelper::GetImageType(), { aURL }, { xGraphic } );
3009 m_xImportedImageManager->store();
3011 bResult = true;
3012 break;
3014 catch ( css::uno::Exception& )
3016 break;
3021 return bResult;
3024 namespace
3026 OUString ReplaceIconName(std::u16string_view rMessage)
3028 OUString name;
3029 OUString message = CuiResId( RID_CUISTR_REPLACE_ICON_WARNING );
3030 OUString placeholder("%ICONNAME" );
3031 sal_Int32 pos = message.indexOf( placeholder );
3032 if ( pos != -1 )
3034 name = message.replaceAt(
3035 pos, placeholder.getLength(), rMessage );
3037 return name;
3040 class SvxIconReplacementDialog
3042 private:
3043 std::unique_ptr<weld::MessageDialog> m_xQueryBox;
3044 public:
3045 SvxIconReplacementDialog(weld::Window *pParent, std::u16string_view rMessage, bool bYestoAll)
3046 : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Warning, VclButtonsType::NONE, ReplaceIconName(rMessage)))
3048 m_xQueryBox->set_title(CuiResId(RID_CUISTR_REPLACE_ICON_CONFIRM));
3049 m_xQueryBox->add_button(GetStandardText(StandardButtonType::Yes), 2);
3050 if (bYestoAll)
3051 m_xQueryBox->add_button(CuiResId(RID_CUISTR_YESTOALL), 5);
3052 m_xQueryBox->add_button(GetStandardText(StandardButtonType::No), 4);
3053 m_xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), 6);
3054 m_xQueryBox->set_default_response(2);
3056 short run() { return m_xQueryBox->run(); }
3060 void SvxIconSelectorDialog::ImportGraphics(
3061 const uno::Sequence< OUString >& rPaths )
3063 std::vector< OUString > rejected( rPaths.getLength() );
3064 sal_Int32 rejectedCount = 0;
3066 sal_uInt16 ret = 0;
3067 sal_Int32 aIndex;
3068 OUString aIconName;
3070 if ( rPaths.getLength() == 1 )
3072 if ( m_xImportedImageManager->hasImage( SvxConfigPageHelper::GetImageType(), rPaths[0] ) )
3074 aIndex = rPaths[0].lastIndexOf( '/' );
3075 aIconName = rPaths[0].copy( aIndex+1 );
3076 SvxIconReplacementDialog aDlg(m_xDialog.get(), aIconName, false);
3077 ret = aDlg.run();
3078 if ( ret == 2 )
3080 ReplaceGraphicItem( rPaths[0] );
3083 else
3085 if ( !ImportGraphic( rPaths[0] ) )
3087 rejected[0] = rPaths[0];
3088 rejectedCount = 1;
3092 else
3094 OUString aSourcePath( rPaths[0] );
3095 if ( rPaths[0].lastIndexOf( '/' ) != rPaths[0].getLength() -1 )
3096 aSourcePath = rPaths[0] + "/";
3098 for ( sal_Int32 i = 1; i < rPaths.getLength(); ++i )
3100 OUString aPath = aSourcePath + rPaths[i];
3101 if ( m_xImportedImageManager->hasImage( SvxConfigPageHelper::GetImageType(), aPath ) )
3103 aIndex = rPaths[i].lastIndexOf( '/' );
3104 aIconName = rPaths[i].copy( aIndex+1 );
3105 SvxIconReplacementDialog aDlg(m_xDialog.get(), aIconName, true);
3106 ret = aDlg.run();
3107 if ( ret == 2 )
3109 ReplaceGraphicItem( aPath );
3111 else if ( ret == 5 )
3113 for ( sal_Int32 k = i; k < rPaths.getLength(); ++k )
3115 aPath = aSourcePath + rPaths[k];
3116 bool bHasReplaced = ReplaceGraphicItem( aPath );
3118 if ( !bHasReplaced )
3120 bool result = ImportGraphic( aPath );
3121 if ( !result )
3123 rejected[ rejectedCount ] = rPaths[i];
3124 ++rejectedCount;
3128 break;
3131 else
3133 bool result = ImportGraphic( aSourcePath + rPaths[i] );
3134 if ( !result )
3136 rejected[ rejectedCount ] = rPaths[i];
3137 ++rejectedCount;
3143 if ( rejectedCount == 0 )
3144 return;
3146 OUStringBuffer message;
3147 OUString fPath;
3148 if (rejectedCount > 1)
3149 fPath = OUString::Concat(rPaths[0].subView(8)) + "/";
3150 for ( sal_Int32 i = 0; i < rejectedCount; ++i )
3152 message.append(fPath + rejected[i] + "\n");
3155 SvxIconChangeDialog aDialog(m_xDialog.get(), message.makeStringAndClear());
3156 aDialog.run();
3159 bool SvxIconSelectorDialog::ImportGraphic( const OUString& aURL )
3161 bool result = false;
3163 uno::Sequence< beans::PropertyValue > aMediaProps{ comphelper::makePropertyValue("URL", aURL) };
3167 uno::Reference< beans::XPropertySet > props =
3168 m_xGraphProvider->queryGraphicDescriptor( aMediaProps );
3170 uno::Any a = props->getPropertyValue("SizePixel");
3172 uno::Reference< graphic::XGraphic > xGraphic = m_xGraphProvider->queryGraphic( aMediaProps );
3173 if ( xGraphic.is() )
3175 bool bOK = true;
3176 css::awt::Size aSize;
3178 a >>= aSize;
3179 if ( 0 == aSize.Width || 0 == aSize.Height )
3180 bOK = false;
3182 Image aImage( xGraphic );
3184 if ( bOK && ((aSize.Width != m_nExpectedSize) || (aSize.Height != m_nExpectedSize)) )
3186 BitmapEx aBitmap = aImage.GetBitmapEx();
3187 BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, m_nExpectedSize);
3188 aImage = Image( aBitmapex);
3190 if ( bOK && !!aImage )
3192 m_aGraphics.push_back(Graphic(aImage.GetBitmapEx()).GetXGraphic());
3193 m_xTbSymbol->InsertItem(m_aGraphics.size(), aImage, aURL);
3195 uno::Sequence<OUString> aImportURL { aURL };
3196 uno::Sequence< uno::Reference<graphic::XGraphic > > aImportGraph{ xGraphic };
3197 m_xImportedImageManager->insertImages( SvxConfigPageHelper::GetImageType(), aImportURL, aImportGraph );
3198 if ( m_xImportedImageManager->isModified() )
3200 m_xImportedImageManager->store();
3203 result = true;
3205 else
3207 SAL_WARN("cui.customize", "could not create Image from XGraphic");
3210 else
3212 SAL_WARN("cui.customize", "could not get query XGraphic");
3215 catch( uno::Exception const & )
3217 TOOLS_WARN_EXCEPTION("cui.customize", "Caught exception importing XGraphic");
3219 return result;
3222 /*******************************************************************************
3224 * The SvxIconChangeDialog class added for issue83555
3226 *******************************************************************************/
3227 SvxIconChangeDialog::SvxIconChangeDialog(weld::Window *pWindow, const OUString& rMessage)
3228 : MessageDialogController(pWindow, "cui/ui/iconchangedialog.ui", "IconChange", "grid")
3229 , m_xLineEditDescription(m_xBuilder->weld_text_view("addrTextview"))
3231 m_xLineEditDescription->set_size_request(m_xLineEditDescription->get_approximate_digit_width() * 48,
3232 m_xLineEditDescription->get_text_height() * 8);
3233 m_xLineEditDescription->set_text(rMessage);
3236 SvxConfigPageFunctionDropTarget::SvxConfigPageFunctionDropTarget(SvxConfigPage&rPage, weld::TreeView& rTreeView)
3237 : weld::ReorderingDropTarget(rTreeView)
3238 , m_rPage(rPage)
3242 sal_Int8 SvxConfigPageFunctionDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
3244 sal_Int8 nRet = weld::ReorderingDropTarget::ExecuteDrop(rEvt);
3245 m_rPage.ListModified();
3246 return nRet;;
3249 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */