xref: /core/cui/source/customize/cfg.cxx (revision 69ebf098)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <cassert>
24 #include <stdlib.h>
25 #include <typeinfo>
26 
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>
38 
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>
49 
50 #include <algorithm>
51 #include <strings.hrc>
52 
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>
62 
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>
96 
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;
103 
104 #if OSL_DEBUG_LEVEL > 1
105 
printPropertySet(const OUString & prefix,const uno::Reference<beans::XPropertySet> & xPropSet)106 void printPropertySet(
107     const OUString& prefix,
108     const uno::Reference< beans::XPropertySet >& xPropSet )
109 {
110     uno::Reference< beans::XPropertySetInfo > xPropSetInfo =
111         xPropSet->getPropertySetInfo();
112 
113     const uno::Sequence< beans::Property >& aPropDetails =
114         xPropSetInfo->getProperties();
115 
116     SAL_WARN("cui", "printPropertySet: " << aPropDetails.getLength() << " properties" );
117 
118     for ( beans::Property const & aPropDetail  : aPropDetails )
119     {
120         OUString tmp;
121         sal_Int32 ival;
122 
123         uno::Any a = xPropSet->getPropertyValue( aPropDetail.Name );
124 
125         if ( a >>= tmp )
126         {
127             SAL_WARN("cui", prefix << ": Got property: " << aPropDetail.Name << tmp);
128         }
129         else if ( ( a >>= ival ) )
130         {
131             SAL_WARN("cui", prefix << ": Got property: " << aPropDetail.Name << " = " << ival);
132         }
133         else
134         {
135             SAL_WARN("cui", prefix << ": Got property: " << aPropDetail.Name << " of type " << a.getValueTypeName());
136         }
137     }
138 }
139 
printProperties(const OUString & prefix,const uno::Sequence<beans::PropertyValue> & aProp)140 void printProperties(
141     const OUString& prefix,
142     const uno::Sequence< beans::PropertyValue >& aProp )
143 {
144     for (beans::PropertyValue const & aPropVal : aProp)
145     {
146         OUString tmp;
147 
148         aPropVal.Value >>= tmp;
149 
150         SAL_WARN("cui", prefix << ": Got property: " << aPropVal.Name << " = " << tmp);
151     }
152 }
153 
printEntries(SvxEntries * entries)154 void printEntries(SvxEntries* entries)
155 {
156     for (auto const& entry : *entries)
157     {
158         SAL_WARN("cui", "printEntries: " << entry->GetName());
159     }
160 }
161 
162 #endif
163 
164 bool
CanConfig(std::u16string_view aModuleId)165 SvxConfigPage::CanConfig( std::u16string_view aModuleId )
166 {
167     return aModuleId != u"com.sun.star.script.BasicIDE" && aModuleId != u"com.sun.star.frame.Bibliography";
168 }
169 
CreateSvxMenuConfigPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)170 static std::unique_ptr<SfxTabPage> CreateSvxMenuConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
171 {
172     return std::make_unique<SvxMenuConfigPage>(pPage, pController, *rSet);
173 }
174 
CreateSvxContextMenuConfigPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)175 static std::unique_ptr<SfxTabPage> CreateSvxContextMenuConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
176 {
177     return std::make_unique<SvxMenuConfigPage>(pPage, pController, *rSet, false);
178 }
179 
CreateKeyboardConfigPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)180 static std::unique_ptr<SfxTabPage> CreateKeyboardConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
181 {
182        return std::make_unique<SfxAcceleratorConfigPage>(pPage, pController, *rSet);
183 }
184 
CreateSvxNotebookbarConfigPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)185 static std::unique_ptr<SfxTabPage> CreateSvxNotebookbarConfigPage(weld::Container* pPage, weld::DialogController* pController,
186                                                          const SfxItemSet* rSet)
187 {
188     return std::make_unique<SvxNotebookbarConfigPage>(pPage, pController, *rSet);
189 }
190 
CreateSvxToolbarConfigPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)191 static std::unique_ptr<SfxTabPage> CreateSvxToolbarConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
192 {
193     return std::make_unique<SvxToolbarConfigPage>(pPage, pController, *rSet);
194 }
195 
CreateSvxEventConfigPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rSet)196 static std::unique_ptr<SfxTabPage> CreateSvxEventConfigPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
197 {
198     return std::make_unique<SvxEventConfigPage>(pPage, pController, *rSet, SvxEventConfigPage::EarlyInit());
199 }
200 
201 /******************************************************************************
202  *
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.
206  *
207  *****************************************************************************/
SvxConfigDialog(weld::Window * pParent,const SfxItemSet * pInSet)208 SvxConfigDialog::SvxConfigDialog(weld::Window * pParent, const SfxItemSet* pInSet)
209     : SfxTabDialogController(pParent, u"cui/ui/customizedialog.ui"_ustr, u"CustomizeDialog"_ustr, pInSet)
210 {
211     SvxConfigPageHelper::InitImageType();
212 
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);
219 
220     if (const SfxPoolItem* pItem = pInSet->GetItem(SID_CONFIG))
221     {
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);
227     }
228 #if HAVE_FEATURE_SCRIPTING
229     else if (pInSet->GetItemIfSet(SID_MACROINFO))
230     {
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);
235     }
236 #endif
237 }
238 
ActivatePage(const OUString & rPage)239 void SvxConfigDialog::ActivatePage(const OUString& rPage)
240 {
241     SfxTabDialogController::ActivatePage(rPage);
242     GetResetButton()->set_visible(rPage != "keyboard");
243 }
244 
SetFrame(const css::uno::Reference<css::frame::XFrame> & xFrame)245 void SvxConfigDialog::SetFrame(const css::uno::Reference<css::frame::XFrame>& xFrame)
246 {
247     m_xFrame = xFrame;
248     OUString aModuleId = SvxConfigPage::GetFrameWithDefaultAndIdentify(m_xFrame);
249 
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);
255 
256     if (aModuleId == "com.sun.star.frame.StartModule")
257         RemoveTabPage(u"keyboard"_ustr);
258 }
259 
PageCreated(const OUString & rId,SfxTabPage & rPage)260 void SvxConfigDialog::PageCreated(const OUString &rId, SfxTabPage& rPage)
261 {
262     if (rId == "menus" || rId == "keyboard" || rId == "notebookbar"
263         || rId == "toolbars" || rId == "contextmenus")
264     {
265         rPage.SetFrame(m_xFrame);
266     }
267     else if (rId == "events")
268     {
269         dynamic_cast< SvxEventConfigPage& >( rPage ).LateInit( m_xFrame );
270     }
271 }
272 
273 /******************************************************************************
274  *
275  * The SaveInData class is used to hold data for entries in the Save In
276  * ListBox controls in the menu and toolbar tabs
277  *
278  ******************************************************************************/
279 
280 // Initialize static variable which holds default XImageManager
281 uno::Reference< css::ui::XImageManager>* SaveInData::xDefaultImgMgr = nullptr;
282 
SaveInData(uno::Reference<css::ui::XUIConfigurationManager> xCfgMgr,uno::Reference<css::ui::XUIConfigurationManager> xParentCfgMgr,const OUString & aModuleId,bool isDocConfig)283 SaveInData::SaveInData(
284     uno::Reference< css::ui::XUIConfigurationManager > xCfgMgr,
285     uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr,
286     const OUString& aModuleId,
287     bool isDocConfig )
288         :
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) }
296 {
297     if ( bDocConfig )
298     {
299         uno::Reference< css::ui::XUIConfigurationPersistence >
300             xDocPersistence( GetConfigManager(), uno::UNO_QUERY );
301 
302         bReadOnly = xDocPersistence->isReadOnly();
303     }
304 
305     uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
306 
307     uno::Reference< container::XNameAccess > xNameAccess(
308         css::frame::theUICommandDescription::get(xContext) );
309 
310     xNameAccess->getByName( aModuleId ) >>= m_xCommandToLabelMap;
311 
312     if ( !m_xImgMgr.is() )
313     {
314         m_xImgMgr.set( GetConfigManager()->getImageManager(), uno::UNO_QUERY );
315     }
316 
317     if ( !IsDocConfig() )
318     {
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;
323     }
324     else
325     {
326         // If this is a document configuration then use the module image manager
327         // as default.
328         if ( m_xParentCfgMgr.is() )
329         {
330             m_xParentImgMgr.set( m_xParentCfgMgr->getImageManager(), uno::UNO_QUERY );
331             xDefaultImgMgr = &m_xParentImgMgr;
332         }
333     }
334 }
335 
GetImage(const OUString & rCommandURL)336 uno::Reference<graphic::XGraphic> SaveInData::GetImage(const OUString& rCommandURL)
337 {
338     uno::Reference< graphic::XGraphic > xGraphic =
339         SvxConfigPageHelper::GetGraphic( m_xImgMgr, rCommandURL );
340 
341     if (!xGraphic.is() && xDefaultImgMgr != nullptr && (*xDefaultImgMgr).is())
342     {
343         xGraphic = SvxConfigPageHelper::GetGraphic( (*xDefaultImgMgr), rCommandURL );
344     }
345 
346     return xGraphic;
347 }
348 
PersistChanges(const uno::Reference<uno::XInterface> & xManager)349 bool SaveInData::PersistChanges(
350     const uno::Reference< uno::XInterface >& xManager )
351 {
352     bool result = true;
353 
354     try
355     {
356         if ( xManager.is() && !IsReadOnly() )
357         {
358             uno::Reference< css::ui::XUIConfigurationPersistence >
359                 xConfigPersistence( xManager, uno::UNO_QUERY );
360 
361             if ( xConfigPersistence->isModified() )
362             {
363                 xConfigPersistence->store();
364             }
365         }
366     }
367     catch ( css::io::IOException& )
368     {
369         result = false;
370     }
371 
372     return result;
373 }
374 
375 /******************************************************************************
376  *
377  * The MenuSaveInData class extends SaveInData and provides menu specific
378  * load and store functionality.
379  *
380  ******************************************************************************/
381 
382 // Initialize static variable which holds default Menu data
383 MenuSaveInData* MenuSaveInData::pDefaultData = nullptr;
384 
MenuSaveInData(const uno::Reference<css::ui::XUIConfigurationManager> & cfgmgr,const uno::Reference<css::ui::XUIConfigurationManager> & xParentCfgMgr,const OUString & aModuleId,bool isDocConfig)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 )
390     :
391         SaveInData( cfgmgr, xParentCfgMgr, aModuleId, isDocConfig ),
392         m_aMenuResourceURL(
393             ITEM_MENUBAR_URL  ),
394         m_aDescriptorContainer(
395             ITEM_DESCRIPTOR_CONTAINER  )
396 {
397     try
398     {
399         m_xMenuSettings = GetConfigManager()->getSettings( ITEM_MENUBAR_URL, false );
400     }
401     catch ( container::NoSuchElementException& )
402     {
403         // will use menu settings for the module
404     }
405 
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() )
411     {
412         SetDefaultData( this );
413     }
414 }
415 
~MenuSaveInData()416 MenuSaveInData::~MenuSaveInData()
417 {
418 }
419 
420 SvxEntries*
GetEntries()421 MenuSaveInData::GetEntries()
422 {
423     if ( pRootEntry == nullptr )
424     {
425         pRootEntry.reset( new SvxConfigEntry( u"MainMenus"_ustr, OUString(), true, /*bParentData*/false) );
426 
427         if ( m_xMenuSettings.is() )
428         {
429             LoadSubMenus( m_xMenuSettings, OUString(), pRootEntry.get(), false );
430         }
431         else if ( GetDefaultData() != nullptr )
432         {
433             // If the doc has no config settings use module config settings
434             LoadSubMenus( GetDefaultData()->m_xMenuSettings, OUString(), pRootEntry.get(), false );
435         }
436     }
437 
438     return pRootEntry->GetEntries();
439 }
440 
441 void
SetEntries(std::unique_ptr<SvxEntries> pNewEntries)442 MenuSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
443 {
444     pRootEntry->SetEntries( std::move(pNewEntries) );
445 }
446 
LoadSubMenus(const uno::Reference<container::XIndexAccess> & xMenuSettings,const OUString & rBaseTitle,SvxConfigEntry const * pParentData,bool bContextMenu)447 void SaveInData::LoadSubMenus( const uno::Reference< container::XIndexAccess >& xMenuSettings,
448     const OUString& rBaseTitle, SvxConfigEntry const * pParentData, bool bContextMenu )
449 {
450     SvxEntries* pEntries = pParentData->GetEntries();
451 
452     // Don't access non existing menu configuration!
453     if ( !xMenuSettings.is() )
454         return;
455 
456     for ( sal_Int32 nIndex = 0; nIndex < xMenuSettings->getCount(); ++nIndex )
457     {
458         uno::Reference< container::XIndexAccess >   xSubMenu;
459         OUString                aCommandURL;
460         OUString                aLabel;
461 
462         sal_uInt16 nType( css::ui::ItemType::DEFAULT );
463         sal_Int32 nStyle(0);
464 
465         bool bItem = SvxConfigPageHelper::GetMenuItemData( xMenuSettings, nIndex,
466             aCommandURL, aLabel, nType, nStyle, xSubMenu );
467 
468         if ( bItem )
469         {
470             bool bIsUserDefined = true;
471 
472             if ( nType == css::ui::ItemType::DEFAULT )
473             {
474                 uno::Any a;
475                 try
476                 {
477                     a = m_xCommandToLabelMap->getByName( aCommandURL );
478                     bIsUserDefined = false;
479                 }
480                 catch ( container::NoSuchElementException& )
481                 {
482                     bIsUserDefined = true;
483                 }
484 
485                 bool bUseDefaultLabel = false;
486                 // If custom label not set retrieve it from the command
487                 // to info service
488                 if ( aLabel.isEmpty() )
489                 {
490                     bUseDefaultLabel = true;
491                     uno::Sequence< beans::PropertyValue > aPropSeq;
492                     if ( a >>= aPropSeq )
493                     {
494                         OUString aMenuLabel;
495                         for (const beans::PropertyValue& prop : aPropSeq)
496                         {
497                             if ( bContextMenu )
498                             {
499                                 if ( prop.Name == "PopupLabel" )
500                                 {
501                                     prop.Value >>= aLabel;
502                                     break;
503                                 }
504                                 else if ( prop.Name == "Label" )
505                                 {
506                                     prop.Value >>= aMenuLabel;
507                                 }
508                             }
509                             else if ( prop.Name == "Label" )
510                             {
511                                 prop.Value >>= aLabel;
512                                 break;
513                             }
514                         }
515                         if ( aLabel.isEmpty() )
516                             aLabel = aMenuLabel;
517                     }
518                 }
519 
520                 SvxConfigEntry* pEntry = new SvxConfigEntry(
521                     aLabel, aCommandURL, xSubMenu.is(), /*bParentData*/false );
522 
523                 pEntry->SetStyle( nStyle );
524                 pEntry->SetUserDefined( bIsUserDefined );
525                 if ( !bUseDefaultLabel )
526                     pEntry->SetName( aLabel );
527 
528                 pEntries->push_back( pEntry );
529 
530                 if ( xSubMenu.is() )
531                 {
532                     // popup menu
533                     OUString subMenuTitle( rBaseTitle );
534 
535                     if ( !subMenuTitle.isEmpty() )
536                     {
537                         subMenuTitle += aMenuSeparatorStr;
538                     }
539                     else
540                     {
541                         pEntry->SetMain();
542                     }
543 
544                     subMenuTitle += SvxConfigPageHelper::stripHotKey( aLabel );
545 
546                     LoadSubMenus( xSubMenu, subMenuTitle, pEntry, bContextMenu );
547                 }
548             }
549             else
550             {
551                 SvxConfigEntry* pEntry = new SvxConfigEntry;
552                 pEntry->SetUserDefined( bIsUserDefined );
553                 pEntries->push_back( pEntry );
554             }
555         }
556     }
557 }
558 
Apply()559 bool MenuSaveInData::Apply()
560 {
561     bool result = false;
562 
563     if ( IsModified() )
564     {
565         // Apply new menu bar structure to our settings container
566         m_xMenuSettings = GetConfigManager()->createSettings();
567 
568         uno::Reference< container::XIndexContainer > xIndexContainer (
569             m_xMenuSettings, uno::UNO_QUERY );
570 
571         uno::Reference< lang::XSingleComponentFactory > xFactory (
572             m_xMenuSettings, uno::UNO_QUERY );
573 
574         Apply( xIndexContainer, xFactory );
575 
576         try
577         {
578             if ( GetConfigManager()->hasSettings( m_aMenuResourceURL ) )
579             {
580                 GetConfigManager()->replaceSettings(
581                     m_aMenuResourceURL, m_xMenuSettings );
582             }
583             else
584             {
585                 GetConfigManager()->insertSettings(
586                     m_aMenuResourceURL, m_xMenuSettings );
587             }
588         }
589         catch ( css::uno::Exception& )
590         {
591             TOOLS_WARN_EXCEPTION("cui.customize", "caught some other exception saving settings");
592         }
593 
594         SetModified( false );
595 
596         result = PersistChanges( GetConfigManager() );
597     }
598 
599     return result;
600 }
601 
Apply(uno::Reference<container::XIndexContainer> const & rMenuBar,uno::Reference<lang::XSingleComponentFactory> & rFactory)602 void MenuSaveInData::Apply(
603     uno::Reference< container::XIndexContainer > const & rMenuBar,
604     uno::Reference< lang::XSingleComponentFactory >& rFactory )
605 {
606     uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
607 
608     for (auto const& entryData : *GetEntries())
609     {
610         uno::Sequence< beans::PropertyValue > aPropValueSeq =
611             SvxConfigPageHelper::ConvertSvxConfigEntry(entryData);
612 
613         uno::Reference< container::XIndexContainer > xSubMenuBar(
614             rFactory->createInstanceWithContext( xContext ),
615             uno::UNO_QUERY );
616 
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 );
625     }
626 }
627 
ApplyMenu(uno::Reference<container::XIndexContainer> const & rMenuBar,uno::Reference<lang::XSingleComponentFactory> & rFactory,SvxConfigEntry * pMenuData)628 void SaveInData::ApplyMenu(
629     uno::Reference< container::XIndexContainer > const & rMenuBar,
630     uno::Reference< lang::XSingleComponentFactory >& rFactory,
631     SvxConfigEntry* pMenuData )
632 {
633     uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
634 
635     for (auto const& entry : *pMenuData->GetEntries())
636     {
637         if (entry->IsPopup())
638         {
639             uno::Sequence< beans::PropertyValue > aPropValueSeq =
640                 SvxConfigPageHelper::ConvertSvxConfigEntry(entry);
641 
642             uno::Reference< container::XIndexContainer > xSubMenuBar(
643                 rFactory->createInstanceWithContext( xContext ),
644                     uno::UNO_QUERY );
645 
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;
651 
652             rMenuBar->insertByIndex(
653                 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
654 
655             ApplyMenu( xSubMenuBar, rFactory, entry );
656             entry->SetModified( false );
657         }
658         else if (entry->IsSeparator())
659         {
660             rMenuBar->insertByIndex(
661                 rMenuBar->getCount(), uno::Any( m_aSeparatorSeq ));
662         }
663         else
664         {
665             uno::Sequence< beans::PropertyValue > aPropValueSeq =
666                 SvxConfigPageHelper::ConvertSvxConfigEntry(entry);
667             rMenuBar->insertByIndex(
668                 rMenuBar->getCount(), uno::Any( aPropValueSeq ));
669         }
670     }
671     pMenuData->SetModified( false );
672 }
673 
674 void
Reset()675 MenuSaveInData::Reset()
676 {
677     try
678     {
679         GetConfigManager()->removeSettings( m_aMenuResourceURL );
680     }
681     catch ( const css::uno::Exception& )
682     {}
683 
684     PersistChanges( GetConfigManager() );
685 
686     pRootEntry.reset();
687 
688     try
689     {
690         m_xMenuSettings = GetConfigManager()->getSettings(
691             m_aMenuResourceURL, false );
692     }
693     catch ( container::NoSuchElementException& )
694     {
695         // will use default settings
696     }
697 }
698 
ContextMenuSaveInData(const css::uno::Reference<css::ui::XUIConfigurationManager> & xCfgMgr,const css::uno::Reference<css::ui::XUIConfigurationManager> & xParentCfgMgr,const OUString & aModuleId,bool bIsDocConfig)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 )
704 {
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;
708 }
709 
~ContextMenuSaveInData()710 ContextMenuSaveInData::~ContextMenuSaveInData()
711 {
712 }
713 
GetUIName(const OUString & rResourceURL)714 OUString ContextMenuSaveInData::GetUIName( const OUString& rResourceURL )
715 {
716     if ( m_xPersistentWindowState.is() )
717     {
718         css::uno::Sequence< css::beans::PropertyValue > aProps;
719         try
720         {
721             m_xPersistentWindowState->getByName( rResourceURL ) >>= aProps;
722         }
723         catch ( const css::uno::Exception& )
724         {}
725 
726         for (const auto& aProp : aProps)
727         {
728             if ( aProp.Name == ITEM_DESCRIPTOR_UINAME )
729             {
730                 OUString aResult;
731                 aProp.Value >>= aResult;
732                 return aResult;
733             }
734         }
735     }
736     return OUString();
737 }
738 
GetEntries()739 SvxEntries* ContextMenuSaveInData::GetEntries()
740 {
741     if ( !m_pRootEntry )
742     {
743         std::unordered_map< OUString, bool > aMenuInfo;
744 
745         m_pRootEntry.reset( new SvxConfigEntry( u"ContextMenus"_ustr, OUString(), true, /*bParentData*/false ) );
746         css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > aElementsInfo;
747         try
748         {
749             aElementsInfo = GetConfigManager()->getUIElementsInfo( css::ui::UIElementType::POPUPMENU );
750         }
751         catch ( const css::lang::IllegalArgumentException& )
752         {}
753 
754         for (const auto& aElement : aElementsInfo)
755         {
756             OUString aUrl;
757             for ( const auto& aElementProp : aElement )
758             {
759                 if ( aElementProp.Name == ITEM_DESCRIPTOR_RESOURCEURL )
760                 {
761                     aElementProp.Value >>= aUrl;
762                     break;
763                 }
764             }
765 
766             css::uno::Reference< css::container::XIndexAccess > xPopupMenu;
767             try
768             {
769                 xPopupMenu = GetConfigManager()->getSettings( aUrl, false );
770             }
771             catch ( const css::uno::Exception& )
772             {}
773 
774             if ( xPopupMenu.is() )
775             {
776                 // insert into std::unordered_map to filter duplicates from the parent
777                 aMenuInfo.emplace(  aUrl, true );
778 
779                 OUString aUIMenuName = GetUIName( aUrl );
780                 if ( aUIMenuName.isEmpty() )
781                     // Menus without UI name aren't supposed to be customized.
782                     continue;
783 
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 );
788             }
789         }
790 
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;
794         try
795         {
796             if ( xParentCfgMgr.is() )
797                 aParentElementsInfo = xParentCfgMgr->getUIElementsInfo( css::ui::UIElementType::POPUPMENU );
798         }
799         catch ( const css::lang::IllegalArgumentException& )
800         {}
801 
802         for (const auto& aElement : aParentElementsInfo)
803         {
804             OUString aUrl;
805             for ( const auto& aElementProp : aElement )
806             {
807                 if ( aElementProp.Name == ITEM_DESCRIPTOR_RESOURCEURL )
808                 {
809                     aElementProp.Value >>= aUrl;
810                     break;
811                 }
812             }
813 
814             css::uno::Reference< css::container::XIndexAccess > xPopupMenu;
815             try
816             {
817                 if ( aMenuInfo.find( aUrl ) == aMenuInfo.end() )
818                     xPopupMenu = xParentCfgMgr->getSettings( aUrl, false );
819             }
820             catch ( const css::uno::Exception& )
821             {}
822 
823             if ( xPopupMenu.is() )
824             {
825                 OUString aUIMenuName = GetUIName( aUrl );
826                 if ( aUIMenuName.isEmpty() )
827                     continue;
828 
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 );
833             }
834         }
835         std::sort( m_pRootEntry->GetEntries()->begin(), m_pRootEntry->GetEntries()->end(), SvxConfigPageHelper::EntrySort );
836     }
837     return m_pRootEntry->GetEntries();
838 }
839 
SetEntries(std::unique_ptr<SvxEntries> pNewEntries)840 void ContextMenuSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
841 {
842     m_pRootEntry->SetEntries( std::move(pNewEntries) );
843 }
844 
HasURL(const OUString & rURL)845 bool ContextMenuSaveInData::HasURL( const OUString& rURL )
846 {
847     SvxEntries* pEntries = GetEntries();
848     for ( const auto& pEntry : *pEntries )
849         if ( pEntry->GetCommand() == rURL )
850             return true;
851 
852     return false;
853 }
854 
HasSettings()855 bool ContextMenuSaveInData::HasSettings()
856 {
857     return m_pRootEntry && !m_pRootEntry->GetEntries()->empty();
858 }
859 
Apply()860 bool ContextMenuSaveInData::Apply()
861 {
862     if ( !IsModified() )
863         return false;
864 
865     SvxEntries* pEntries = GetEntries();
866     for ( const auto& pEntry : *pEntries )
867     {
868         if ( pEntry->IsModified() || SvxConfigPageHelper::SvxConfigEntryModified( pEntry ) )
869         {
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 );
873 
874             const OUString& aUrl = pEntry->GetCommand();
875             try
876             {
877                 if ( GetConfigManager()->hasSettings( aUrl ) )
878                     GetConfigManager()->replaceSettings( aUrl, xIndexContainer );
879                 else
880                     GetConfigManager()->insertSettings( aUrl, xIndexContainer );
881             }
882             catch ( const css::uno::Exception& )
883             {}
884         }
885     }
886     SetModified( false );
887     return PersistChanges( GetConfigManager() );
888 }
889 
Reset()890 void ContextMenuSaveInData::Reset()
891 {
892     SvxEntries* pEntries = GetEntries();
893     for ( const auto& pEntry : *pEntries )
894     {
895         try
896         {
897             GetConfigManager()->removeSettings( pEntry->GetCommand() );
898         }
899         catch ( const css::uno::Exception& )
900         {
901             TOOLS_WARN_EXCEPTION("cui.customize", "Exception caught while resetting context menus");
902         }
903     }
904     PersistChanges( GetConfigManager() );
905     m_pRootEntry.reset();
906 }
907 
ResetContextMenu(const SvxConfigEntry * pEntry)908 void ContextMenuSaveInData::ResetContextMenu( const SvxConfigEntry* pEntry )
909 {
910     try
911     {
912         GetConfigManager()->removeSettings( pEntry->GetCommand() );
913     }
914     catch ( const css::uno::Exception& )
915     {
916         TOOLS_WARN_EXCEPTION("cui.customize", "Exception caught while resetting context menu");
917     }
918     PersistChanges( GetConfigManager() );
919     m_pRootEntry.reset();
920 }
921 
CreateDropDown()922 void SvxMenuEntriesListBox::CreateDropDown()
923 {
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);
930 }
931 
932 /******************************************************************************
933  *
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
938  *
939  *****************************************************************************/
SvxMenuEntriesListBox(std::unique_ptr<weld::TreeView> xControl,SvxConfigPage * pPg)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)
944 {
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));
949 }
950 
~SvxMenuEntriesListBox()951 SvxMenuEntriesListBox::~SvxMenuEntriesListBox()
952 {
953 }
954 
IMPL_LINK(SvxMenuEntriesListBox,KeyInputHdl,const KeyEvent &,rKeyEvent,bool)955 IMPL_LINK(SvxMenuEntriesListBox, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
956 {
957     vcl::KeyCode keycode = rKeyEvent.GetKeyCode();
958 
959     // support DELETE for removing the current entry
960     if ( keycode == KEY_DELETE )
961     {
962         m_pPage->DeleteSelectedContent();
963     }
964     // support CTRL+UP and CTRL+DOWN for moving selected entries
965     else if ( keycode.GetCode() == KEY_UP && keycode.IsMod1() )
966     {
967         m_pPage->MoveEntry( true );
968     }
969     else if ( keycode.GetCode() == KEY_DOWN && keycode.IsMod1() )
970     {
971         m_pPage->MoveEntry( false );
972     }
973     else
974     {
975         return false; // pass on to default handler
976     }
977     return true;
978 }
979 
IMPL_LINK(SvxMenuEntriesListBox,QueryTooltip,const weld::TreeIter &,rIter,OUString)980 IMPL_LINK(SvxMenuEntriesListBox, QueryTooltip, const weld::TreeIter&, rIter, OUString)
981 {
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("~", "");
993 }
994 
995 /******************************************************************************
996  *
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.
1000  *
1001  *****************************************************************************/
SvxConfigPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rSet)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))
1027 {
1028     CustomNotebookbarGenerator::getFileNameAndAppName(m_sAppName, m_sFileName);
1029 
1030     m_xTopLevelListBox->connect_changed(LINK(this, SvxConfigPage, SelectElementHdl));
1031 
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));
1036 
1037     m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SvxConfigPage, ImplUpdateDataHdl));
1038     m_aUpdateDataTimer.SetTimeout(EDIT_UPDATEDATA_TIMEOUT);
1039 
1040     m_xSearchEdit->connect_changed(LINK(this, SvxConfigPage, SearchUpdateHdl));
1041     m_xSearchEdit->connect_focus_out(LINK(this, SvxConfigPage, FocusOut_Impl));
1042 
1043     rTreeView.connect_row_activated(LINK(this, SvxConfigPage, FunctionDoubleClickHdl));
1044     rTreeView.connect_changed(LINK(this, SvxConfigPage, SelectFunctionHdl));
1045 }
1046 
IMPL_LINK_NOARG(SvxConfigPage,SelectElementHdl,weld::ComboBox &,void)1047 IMPL_LINK_NOARG(SvxConfigPage, SelectElementHdl, weld::ComboBox&, void)
1048 {
1049     SelectElement();
1050 }
1051 
~SvxConfigPage()1052 SvxConfigPage::~SvxConfigPage()
1053 {
1054     int cnt = m_xSaveInListBox->get_count();
1055     for(int i=0; i < cnt; ++i)
1056     {
1057         SaveInData *pData = weld::fromId<SaveInData*>(m_xSaveInListBox->get_id(i));
1058         delete pData;
1059     }
1060 }
1061 
Reset(const SfxItemSet *)1062 void SvxConfigPage::Reset( const SfxItemSet* )
1063 {
1064     // If we haven't initialised our XMultiServiceFactory reference
1065     // then Reset is being called at the opening of the dialog.
1066 
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 )
1071     {
1072         sal_Int32 nPos = 0;
1073         uno::Reference < css::ui::XUIConfigurationManager > xCfgMgr;
1074         uno::Reference < css::ui::XUIConfigurationManager > xDocCfgMgr;
1075 
1076         uno::Reference< uno::XComponentContext > xContext(
1077             ::comphelper::getProcessComponentContext(), uno::UNO_SET_THROW );
1078 
1079         m_xFrame = GetFrame();
1080         m_aModuleId = GetFrameWithDefaultAndIdentify( m_xFrame );
1081 
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 );
1086 
1087         uno::Reference< css::ui::XModuleUIConfigurationManagerSupplier >
1088             xModuleCfgSupplier( css::ui::theModuleUIConfigurationManagerSupplier::get(xContext) );
1089 
1090         // Set up data for module specific menus
1091         SaveInData* pModuleData = nullptr;
1092 
1093         try
1094         {
1095             xCfgMgr =
1096                 xModuleCfgSupplier->getUIConfigurationManager( m_aModuleId );
1097 
1098             pModuleData = CreateSaveInData( xCfgMgr,
1099                                             uno::Reference< css::ui::XUIConfigurationManager >(),
1100                                             m_aModuleId,
1101                                             false );
1102         }
1103         catch ( container::NoSuchElementException& )
1104         {
1105         }
1106 
1107         if ( pModuleData != nullptr )
1108         {
1109             OUString sId(weld::toId(pModuleData));
1110             m_xSaveInListBox->append(sId, utl::ConfigManager::getProductName() + " " + aModuleName);
1111         }
1112 
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() )
1118         {
1119             uno::Reference< frame::XModel > xModel( xController->getModel() );
1120             if ( xModel.is() )
1121             {
1122                 uno::Reference< css::ui::XUIConfigurationManagerSupplier >
1123                     xCfgSupplier( xModel, uno::UNO_QUERY );
1124 
1125                 if ( xCfgSupplier.is() )
1126                 {
1127                     xDocCfgMgr = xCfgSupplier->getUIConfigurationManager();
1128                 }
1129                 aTitle = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
1130             }
1131         }
1132 
1133         SaveInData* pDocData = nullptr;
1134         if ( xDocCfgMgr.is() )
1135         {
1136             pDocData = CreateSaveInData( xDocCfgMgr, xCfgMgr, m_aModuleId, true );
1137 
1138             if ( !pDocData->IsReadOnly() )
1139             {
1140                 OUString sId(weld::toId(pDocData));
1141                 m_xSaveInListBox->append(sId, aTitle);
1142             }
1143         }
1144 
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() )
1149         {
1150             if ( pDocData && pDocData->HasURL( m_aURLToSelect ) )
1151             {
1152                 m_xSaveInListBox->set_active(nPos);
1153                 pCurrentSaveInData = pDocData;
1154                 bURLToSelectFound = true;
1155             }
1156             else if ( pModuleData && pModuleData->HasURL( m_aURLToSelect ) )
1157             {
1158                 m_xSaveInListBox->set_active(0);
1159                 pCurrentSaveInData = pModuleData;
1160                 bURLToSelectFound = true;
1161             }
1162         }
1163 
1164         if ( !bURLToSelectFound )
1165         {
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() )
1169             {
1170                 m_xSaveInListBox->set_active(nPos);
1171                 pCurrentSaveInData = pDocData;
1172             }
1173             else
1174             {
1175                 m_xSaveInListBox->set_active(0);
1176                 pCurrentSaveInData = pModuleData;
1177             }
1178         }
1179 
1180 #ifdef DBG_UTIL
1181         DBG_ASSERT( pCurrentSaveInData, "SvxConfigPage::Reset(): no SaveInData" );
1182 #endif
1183 
1184         if ( CanConfig( m_aModuleId ) )
1185         {
1186             // Load configuration for other open documents which have
1187             // same module type
1188             uno::Sequence< uno::Reference< frame::XFrame > > aFrameList;
1189             try
1190             {
1191                 uno::Reference< frame::XDesktop2 > xFramesSupplier = frame::Desktop::create(
1192                     xContext );
1193 
1194                 uno::Reference< frame::XFrames > xFrames =
1195                     xFramesSupplier->getFrames();
1196 
1197                 aFrameList = xFrames->queryFrames(
1198                     frame::FrameSearchFlag::ALL & ~frame::FrameSearchFlag::SELF );
1199 
1200             }
1201             catch( const uno::Exception& )
1202             {
1203                 DBG_UNHANDLED_EXCEPTION("cui.customize");
1204             }
1205 
1206             for (uno::Reference<frame::XFrame> const& xf : aFrameList)
1207             {
1208                 if ( xf.is() && xf != m_xFrame )
1209                 {
1210                     OUString aCheckId;
1211                     try{
1212                         aCheckId = xModuleManager->identify( xf );
1213                     } catch(const uno::Exception&)
1214                         { aCheckId.clear(); }
1215 
1216                     if ( m_aModuleId == aCheckId )
1217                     {
1218                         // try to get the document based ui configuration manager
1219                         OUString aTitle2;
1220                         uno::Reference< frame::XController > xController_ =
1221                             xf->getController();
1222 
1223                         if ( xController_.is() )
1224                         {
1225                             uno::Reference< frame::XModel > xModel(
1226                                 xController_->getModel() );
1227 
1228                             if ( xModel.is() )
1229                             {
1230                                 uno::Reference<
1231                                     css::ui::XUIConfigurationManagerSupplier >
1232                                         xCfgSupplier( xModel, uno::UNO_QUERY );
1233 
1234                                 if ( xCfgSupplier.is() )
1235                                 {
1236                                     xDocCfgMgr =
1237                                         xCfgSupplier->getUIConfigurationManager();
1238                                 }
1239                                 aTitle2 = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
1240                             }
1241                         }
1242 
1243                         if ( xDocCfgMgr.is() )
1244                         {
1245                             SaveInData* pData = CreateSaveInData( xDocCfgMgr, xCfgMgr, m_aModuleId, true );
1246 
1247                             if ( pData && !pData->IsReadOnly() )
1248                             {
1249                                 OUString sId(weld::toId(pData));
1250                                 m_xSaveInListBox->append(sId, aTitle2);
1251                             }
1252                         }
1253                     }
1254                 }
1255             }
1256         }
1257 
1258         m_xSaveInListBox->connect_changed(
1259             LINK( this, SvxConfigPage, SelectSaveInLocation ) );
1260 
1261         bInitialised = true;
1262 
1263         Init();
1264     }
1265     else
1266     {
1267         if ( QueryReset() == RET_YES )
1268         {
1269             // Reset menu configuration for currently selected SaveInData
1270             GetSaveInData()->Reset();
1271 
1272             Init();
1273         }
1274     }
1275 }
1276 
GetFrameWithDefaultAndIdentify(uno::Reference<frame::XFrame> & _inout_rxFrame)1277 OUString SvxConfigPage::GetFrameWithDefaultAndIdentify( uno::Reference< frame::XFrame >& _inout_rxFrame )
1278 {
1279     OUString sModuleID;
1280     try
1281     {
1282         uno::Reference< uno::XComponentContext > xContext(
1283             ::comphelper::getProcessComponentContext() );
1284 
1285         uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(
1286             xContext );
1287 
1288         if ( !_inout_rxFrame.is() )
1289             _inout_rxFrame = xDesktop->getActiveFrame();
1290 
1291         if ( !_inout_rxFrame.is() )
1292         {
1293             _inout_rxFrame = xDesktop->getCurrentFrame();
1294         }
1295 
1296         if ( !_inout_rxFrame.is())
1297         {
1298             if (SfxViewFrame* pViewFrame = SfxViewFrame::Current())
1299                 _inout_rxFrame = pViewFrame->GetFrame().GetFrameInterface();
1300         }
1301 
1302         if ( !_inout_rxFrame.is() )
1303         {
1304             SAL_WARN( "cui.customize", "SvxConfigPage::GetFrameWithDefaultAndIdentify(): no frame found!" );
1305             return sModuleID;
1306         }
1307 
1308         sModuleID = vcl::CommandInfoProvider::GetModuleIdentifier(_inout_rxFrame);
1309     }
1310     catch( const uno::Exception& )
1311     {
1312         DBG_UNHANDLED_EXCEPTION("cui.customize");
1313     }
1314 
1315     return sModuleID;
1316 }
1317 
GetScriptURL() const1318 OUString SvxConfigPage::GetScriptURL() const
1319 {
1320     OUString result;
1321 
1322     SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(m_xFunctions->get_selected_id());
1323     if (pData)
1324     {
1325         if  (   ( pData->nKind == SfxCfgKind::FUNCTION_SLOT ) ||
1326                 ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT ) ||
1327                 ( pData->nKind == SfxCfgKind::GROUP_STYLES )    )
1328         {
1329             result = pData->sCommand;
1330         }
1331     }
1332 
1333     return result;
1334 }
1335 
GetSelectedDisplayName() const1336 OUString SvxConfigPage::GetSelectedDisplayName() const
1337 {
1338     return m_xFunctions->get_selected_text();
1339 }
1340 
FillItemSet(SfxItemSet *)1341 bool SvxConfigPage::FillItemSet( SfxItemSet* )
1342 {
1343     bool result = false;
1344 
1345     for (int i = 0, nCount = m_xSaveInListBox->get_count(); i < nCount; ++i)
1346     {
1347         OUString sId = m_xSaveInListBox->get_id(i);
1348         if (sId != notebookbarTabScope)
1349         {
1350             SaveInData* pData = weld::fromId<SaveInData*>(sId);
1351             result = pData->Apply();
1352         }
1353     }
1354     return result;
1355 }
1356 
IMPL_LINK_NOARG(SvxConfigPage,SelectSaveInLocation,weld::ComboBox &,void)1357 IMPL_LINK_NOARG(SvxConfigPage, SelectSaveInLocation, weld::ComboBox&, void)
1358 {
1359     OUString sId = m_xSaveInListBox->get_active_id();
1360     if (sId != notebookbarTabScope)
1361         pCurrentSaveInData = weld::fromId<SaveInData*>(sId);
1362     Init();
1363 }
1364 
ReloadTopLevelListBox(SvxConfigEntry const * pToSelect)1365 void SvxConfigPage::ReloadTopLevelListBox( SvxConfigEntry const * pToSelect )
1366 {
1367     int nSelectionPos = m_xTopLevelListBox->get_active();
1368     m_xTopLevelListBox->clear();
1369 
1370     if ( GetSaveInData() && GetSaveInData()->GetEntries() )
1371     {
1372         for (auto const& entryData : *GetSaveInData()->GetEntries())
1373         {
1374             OUString sId(weld::toId(entryData));
1375             m_xTopLevelListBox->append(sId, SvxConfigPageHelper::stripHotKey(entryData->GetName()));
1376 
1377             if (entryData == pToSelect)
1378                 nSelectionPos = m_xTopLevelListBox->get_count() - 1;
1379 
1380             AddSubMenusToUI( SvxConfigPageHelper::stripHotKey( entryData->GetName() ), entryData );
1381         }
1382     }
1383 #ifdef DBG_UTIL
1384     else
1385     {
1386         DBG_ASSERT( GetSaveInData(), "SvxConfigPage::ReloadTopLevelListBox(): no SaveInData" );
1387         DBG_ASSERT( GetSaveInData()->GetEntries() ,
1388             "SvxConfigPage::ReloadTopLevelListBox(): no SaveInData entries" );
1389     }
1390 #endif
1391 
1392     nSelectionPos = (nSelectionPos != -1 && nSelectionPos < m_xTopLevelListBox->get_count()) ?
1393         nSelectionPos : m_xTopLevelListBox->get_count() - 1;
1394 
1395     m_xTopLevelListBox->set_active(nSelectionPos);
1396     SelectElement();
1397 }
1398 
AddSubMenusToUI(std::u16string_view rBaseTitle,SvxConfigEntry const * pParentData)1399 void SvxConfigPage::AddSubMenusToUI(
1400     std::u16string_view rBaseTitle, SvxConfigEntry const * pParentData )
1401 {
1402     for (auto const& entryData : *pParentData->GetEntries())
1403     {
1404         if (entryData->IsPopup())
1405         {
1406             OUString subMenuTitle = OUString::Concat(rBaseTitle) + aMenuSeparatorStr + SvxConfigPageHelper::stripHotKey(entryData->GetName());
1407 
1408             OUString sId(weld::toId(entryData));
1409             m_xTopLevelListBox->append(sId, subMenuTitle);
1410 
1411             AddSubMenusToUI( subMenuTitle, entryData );
1412         }
1413     }
1414 }
1415 
FindParentForChild(SvxEntries * pRootEntries,SvxConfigEntry * pChildData)1416 SvxEntries* SvxConfigPage::FindParentForChild(
1417     SvxEntries* pRootEntries, SvxConfigEntry* pChildData )
1418 {
1419     for (auto const& entryData : *pRootEntries)
1420     {
1421 
1422         if (entryData == pChildData)
1423         {
1424             return pRootEntries;
1425         }
1426         else if (entryData->IsPopup())
1427         {
1428             SvxEntries* result =
1429                 FindParentForChild( entryData->GetEntries(), pChildData );
1430 
1431             if ( result != nullptr )
1432             {
1433                 return result;
1434             }
1435         }
1436     }
1437     return nullptr;
1438 }
1439 
CreateCommandFromSelection(const OUString & aURL)1440 SvxConfigEntry *SvxConfigPage::CreateCommandFromSelection(const OUString &aURL)
1441 {
1442     OUString aDisplayName;
1443 
1444     if ( aURL.isEmpty() ) {
1445         return nullptr;
1446     }
1447 
1448     auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aURL, m_aModuleId);
1449 
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);
1456 
1457     SvxConfigEntry* toret =
1458         new SvxConfigEntry( aDisplayName, aURL, false, /*bParentData*/false );
1459 
1460     toret->SetUserDefined();
1461 
1462     if ( aDisplayName.isEmpty() )
1463         toret->SetName( GetSelectedDisplayName() );
1464 
1465     return toret;
1466 }
1467 
IsCommandInMenuList(const SvxConfigEntry * pEntryData,const SvxEntries * pEntries)1468 bool SvxConfigPage::IsCommandInMenuList(const SvxConfigEntry *pEntryData,
1469                                         const SvxEntries *pEntries)
1470 {
1471     bool toret = false;
1472 
1473     if ( pEntries != nullptr
1474       && pEntryData != nullptr )
1475     {
1476         for (auto const& entry : *pEntries)
1477         {
1478                 if ( entry->GetCommand() == pEntryData->GetCommand() )
1479                 {
1480                     toret = true;
1481                     break;
1482                 }
1483         }
1484     }
1485 
1486     return toret;
1487 }
1488 
AddFunction(int nTarget,bool bAllowDuplicates)1489 int SvxConfigPage::AddFunction(int nTarget, bool bAllowDuplicates)
1490 {
1491     int toret = -1;
1492     OUString aURL = GetScriptURL();
1493     SvxConfigEntry* pParent = GetTopLevelSelection();
1494 
1495     if ( aURL.isEmpty() || pParent == nullptr )
1496     {
1497         return -1;
1498     }
1499 
1500 
1501     SvxConfigEntry * pNewEntryData = CreateCommandFromSelection( aURL );
1502 
1503     // check that this function is not already in the menu
1504     if ( !bAllowDuplicates
1505       && IsCommandInMenuList( pNewEntryData, pParent->GetEntries() )
1506     )
1507     {
1508         delete pNewEntryData;
1509     } else {
1510         toret = AppendEntry( pNewEntryData, nTarget );
1511     }
1512 
1513     UpdateButtonStates();
1514     return toret;
1515 }
1516 
AppendEntry(SvxConfigEntry * pNewEntryData,int nTarget)1517 int SvxConfigPage::AppendEntry(
1518     SvxConfigEntry* pNewEntryData,
1519     int nTarget)
1520 {
1521     SvxConfigEntry* pTopLevelSelection = GetTopLevelSelection();
1522 
1523     if (pTopLevelSelection == nullptr)
1524         return -1;
1525 
1526     // Grab the entries list for the currently selected menu
1527     SvxEntries* pEntries = pTopLevelSelection->GetEntries();
1528 
1529     int nNewEntry = -1;
1530     int nCurEntry =
1531         nTarget != -1 ? nTarget : m_xContentsListBox->get_selected_index();
1532 
1533     OUString sId(weld::toId(pNewEntryData));
1534 
1535     if (nCurEntry == -1 || nCurEntry == m_xContentsListBox->n_children() - 1)
1536     {
1537         pEntries->push_back( pNewEntryData );
1538         m_xContentsListBox->insert(-1, sId);
1539         nNewEntry = m_xContentsListBox->n_children() - 1;
1540     }
1541     else
1542     {
1543         SvxConfigEntry* pEntryData =
1544             weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nCurEntry));
1545 
1546         SvxEntries::iterator iter = pEntries->begin();
1547         SvxEntries::const_iterator end = pEntries->end();
1548 
1549         // Advance the iterator to the data for currently selected entry
1550         sal_uInt16 nPos = 0;
1551         while (*iter != pEntryData && ++iter != end)
1552         {
1553             ++nPos;
1554         }
1555 
1556         // Now step past it to the entry after the currently selected one
1557         ++iter;
1558         ++nPos;
1559 
1560         // Now add the new entry to the UI and to the parent's list
1561         if ( iter != end )
1562         {
1563             pEntries->insert( iter, pNewEntryData );
1564             m_xContentsListBox->insert(nPos, sId);
1565             nNewEntry = nPos;
1566         }
1567     }
1568 
1569     if (nNewEntry != -1)
1570     {
1571         m_xContentsListBox->select(nNewEntry);
1572         m_xContentsListBox->scroll_to_row(nNewEntry);
1573 
1574         GetSaveInData()->SetModified();
1575         GetTopLevelSelection()->SetModified();
1576     }
1577 
1578     return nNewEntry;
1579 }
1580 
1581 namespace
1582 {
TmplInsertEntryIntoUI(SvxConfigEntry * pNewEntryData,weld::TreeView & rTreeView,itertype & rIter,SaveInData * pSaveInData,VirtualDevice & rDropDown,bool bMenu)1583     template<typename itertype> void TmplInsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView& rTreeView, itertype& rIter, SaveInData* pSaveInData,
1584                                                            VirtualDevice& rDropDown, bool bMenu)
1585     {
1586         OUString sId(weld::toId(pNewEntryData));
1587 
1588         rTreeView.set_id(rIter, sId);
1589 
1590         if (pNewEntryData->IsSeparator())
1591         {
1592             rTreeView.set_text(rIter, "----------------------------------", 0);
1593         }
1594         else
1595         {
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);
1601         }
1602 
1603         if (bMenu)  // menus
1604         {
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);
1609         }
1610     }
1611 }
1612 
InsertEntryIntoUI(SvxConfigEntry * pNewEntryData,weld::TreeView & rTreeView,int nPos,bool bMenu)1613 void SvxConfigPage::InsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView& rTreeView, int nPos, bool bMenu)
1614 {
1615     TmplInsertEntryIntoUI<int>(pNewEntryData, rTreeView, nPos, GetSaveInData(),
1616                                m_xContentsListBox->get_dropdown_image(), bMenu);
1617 }
1618 
InsertEntryIntoUI(SvxConfigEntry * pNewEntryData,weld::TreeView & rTreeView,weld::TreeIter & rIter,bool bMenu)1619 void SvxConfigPage::InsertEntryIntoUI(SvxConfigEntry* pNewEntryData, weld::TreeView& rTreeView, weld::TreeIter& rIter, bool bMenu)
1620 {
1621     TmplInsertEntryIntoUI<weld::TreeIter>(pNewEntryData, rTreeView, rIter, GetSaveInData(),
1622                                           m_xContentsListBox->get_dropdown_image(), bMenu);
1623 }
1624 
IMPL_LINK(SvxConfigPage,MoveHdl,weld::Button &,rButton,void)1625 IMPL_LINK(SvxConfigPage, MoveHdl, weld::Button&, rButton, void)
1626 {
1627     MoveEntry(&rButton == m_xMoveUpButton.get());
1628 }
1629 
IMPL_LINK_NOARG(SvxConfigPage,FunctionDoubleClickHdl,weld::TreeView &,bool)1630 IMPL_LINK_NOARG(SvxConfigPage, FunctionDoubleClickHdl, weld::TreeView&, bool)
1631 {
1632     if (m_xAddCommandButton->get_sensitive())
1633         m_xAddCommandButton->clicked();
1634     return true;
1635 }
1636 
IMPL_LINK_NOARG(SvxConfigPage,SelectFunctionHdl,weld::TreeView &,void)1637 IMPL_LINK_NOARG(SvxConfigPage, SelectFunctionHdl, weld::TreeView&, void)
1638 {
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();
1643 
1644     // Enable/disable Add and Remove buttons depending on current selection
1645     if (bIsValidCommand)
1646     {
1647         m_xAddCommandButton->set_sensitive(true);
1648         m_xRemoveCommandButton->set_sensitive(true);
1649 
1650         if (SfxHelp::IsHelpInstalled())
1651         {
1652             m_xDescriptionField->set_text(m_xFunctions->GetCommandHelpText());
1653         }
1654         else
1655         {
1656             SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(m_xFunctions->get_selected_id());
1657             if (pData)
1658             {
1659                 bool bIsExperimental
1660                     = vcl::CommandInfoProvider::IsExperimental(pData->sCommand, m_aModuleId);
1661 
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);
1670             }
1671         }
1672     }
1673     else
1674     {
1675 
1676         m_xAddCommandButton->set_sensitive(false);
1677         m_xRemoveCommandButton->set_sensitive(false);
1678 
1679         m_xDescriptionField->set_text(u""_ustr);
1680     }
1681 
1682     UpdateButtonStates();
1683 }
1684 
IMPL_LINK_NOARG(SvxConfigPage,ImplUpdateDataHdl,Timer *,void)1685 IMPL_LINK_NOARG(SvxConfigPage, ImplUpdateDataHdl, Timer*, void)
1686 {
1687     OUString aSearchTerm(m_xSearchEdit->get_text());
1688     m_xCommandCategoryListBox->categorySelected(m_xFunctions.get(), aSearchTerm, GetSaveInData());
1689     SelectFunctionHdl(m_xFunctions->get_widget());
1690 }
1691 
IMPL_LINK_NOARG(SvxConfigPage,SearchUpdateHdl,weld::Entry &,void)1692 IMPL_LINK_NOARG(SvxConfigPage, SearchUpdateHdl, weld::Entry&, void)
1693 {
1694     m_aUpdateDataTimer.Start();
1695 }
1696 
IMPL_LINK_NOARG(SvxConfigPage,FocusOut_Impl,weld::Widget &,void)1697 IMPL_LINK_NOARG(SvxConfigPage, FocusOut_Impl, weld::Widget&, void)
1698 {
1699     if (m_aUpdateDataTimer.IsActive())
1700     {
1701         m_aUpdateDataTimer.Stop();
1702         m_aUpdateDataTimer.Invoke();
1703     }
1704 }
1705 
MoveEntry(bool bMoveUp)1706 void SvxConfigPage::MoveEntry(bool bMoveUp)
1707 {
1708     weld::TreeView& rTreeView = m_xContentsListBox->get_widget();
1709 
1710     int nSourceEntry = rTreeView.get_selected_index();
1711     int nTargetEntry = -1;
1712     int nToSelect = -1;
1713 
1714     if (nSourceEntry == -1)
1715     {
1716         return;
1717     }
1718 
1719     if ( bMoveUp )
1720     {
1721         // Move Up is just a Move Down with the source and target reversed
1722         nTargetEntry = nSourceEntry;
1723         nSourceEntry = nTargetEntry - 1;
1724         nToSelect = nSourceEntry;
1725     }
1726     else
1727     {
1728         nTargetEntry = nSourceEntry + 1;
1729         nToSelect = nTargetEntry;
1730     }
1731 
1732     if (MoveEntryData(nSourceEntry, nTargetEntry))
1733     {
1734         rTreeView.swap(nSourceEntry, nTargetEntry);
1735         rTreeView.select(nToSelect);
1736         rTreeView.scroll_to_row(nToSelect);
1737 
1738         UpdateButtonStates();
1739     }
1740 }
1741 
MoveEntryData(int nSourceEntry,int nTargetEntry)1742 bool SvxConfigPage::MoveEntryData(int nSourceEntry, int nTargetEntry)
1743 {
1744     //#i53677#
1745     if (nSourceEntry == -1 || nTargetEntry == -1)
1746     {
1747         return false;
1748     }
1749 
1750     // Grab the entries list for the currently selected menu
1751     SvxEntries* pEntries = GetTopLevelSelection()->GetEntries();
1752 
1753     SvxConfigEntry* pSourceData =
1754         weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nSourceEntry));
1755 
1756     SvxConfigEntry* pTargetData =
1757         weld::fromId<SvxConfigEntry*>(m_xContentsListBox->get_id(nTargetEntry));
1758 
1759     if ( pSourceData == nullptr || pTargetData == nullptr )
1760         return false;
1761 
1762     // remove the source entry from our list
1763     SvxConfigPageHelper::RemoveEntry( pEntries, pSourceData );
1764 
1765     SvxEntries::iterator iter = pEntries->begin();
1766     SvxEntries::const_iterator end = pEntries->end();
1767 
1768     // advance the iterator to the position of the target entry
1769     while (*iter != pTargetData && ++iter != end) ;
1770 
1771     // insert the source entry at the position after the target
1772     pEntries->insert( ++iter, pSourceData );
1773 
1774     GetSaveInData()->SetModified();
1775     GetTopLevelSelection()->SetModified();
1776 
1777     return true;
1778 }
1779 
SvxMainMenuOrganizerDialog(weld::Window * pParent,SvxEntries * entries,SvxConfigEntry const * selection,bool bCreateMenu)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))
1789 {
1790     m_xMenuListBox->set_size_request(-1, m_xMenuListBox->get_height_rows(12));
1791 
1792     // Copy the entries list passed in
1793     if ( entries != nullptr )
1794     {
1795         mpEntries.reset( new SvxEntries );
1796         for (auto const& entry : *entries)
1797         {
1798             m_xMenuListBox->append(weld::toId(entry),
1799                                    SvxConfigPageHelper::stripHotKey(entry->GetName()));
1800             mpEntries->push_back(entry);
1801             if (entry == selection)
1802             {
1803                 m_xMenuListBox->select(m_xMenuListBox->n_children() - 1);
1804             }
1805         }
1806     }
1807 
1808     if ( bCreateMenu )
1809     {
1810         // Generate custom name for new menu
1811         OUString prefix = CuiResId( RID_CUISTR_NEW_MENU );
1812 
1813         OUString newname = SvxConfigPageHelper::generateCustomName( prefix, entries );
1814         OUString newurl = SvxConfigPageHelper::generateCustomMenuURL( mpEntries.get() );
1815 
1816         SvxConfigEntry* pNewEntryData =
1817             new SvxConfigEntry( newname, newurl, true, /*bParentData*/false );
1818         pNewEntryData->SetName( newname );
1819         pNewEntryData->SetUserDefined();
1820         pNewEntryData->SetMain();
1821 
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);
1826 
1827         if (mpEntries)
1828             mpEntries->push_back(pNewEntryData);
1829 
1830         m_xMenuNameEdit->set_text(newname);
1831         m_xMenuNameEdit->connect_changed(LINK(this, SvxMainMenuOrganizerDialog, ModifyHdl));
1832     }
1833     else
1834     {
1835         // hide name label and textfield
1836         m_xMenuBox->hide();
1837         // change the title
1838         m_xDialog->set_title(CuiResId(RID_CUISTR_MOVE_MENU));
1839     }
1840 
1841     m_xMenuListBox->connect_changed(LINK(this, SvxMainMenuOrganizerDialog, SelectHdl));
1842 
1843     m_xMoveUpButton->connect_clicked(LINK( this, SvxMainMenuOrganizerDialog, MoveHdl));
1844     m_xMoveDownButton->connect_clicked(LINK( this, SvxMainMenuOrganizerDialog, MoveHdl));
1845 
1846     UpdateButtonStates();
1847 }
1848 
~SvxMainMenuOrganizerDialog()1849 SvxMainMenuOrganizerDialog::~SvxMainMenuOrganizerDialog()
1850 {
1851 }
1852 
IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog,ModifyHdl,weld::Entry &,void)1853 IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog, ModifyHdl, weld::Entry&, void)
1854 {
1855     // if the Edit control is empty do not change the name
1856     if (m_xMenuNameEdit->get_text().isEmpty())
1857     {
1858         return;
1859     }
1860 
1861     SvxConfigEntry* pNewEntryData = weld::fromId<SvxConfigEntry*>(m_sNewMenuEntryId);
1862     pNewEntryData->SetName(m_xMenuNameEdit->get_text());
1863 
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);
1869 }
1870 
IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog,SelectHdl,weld::TreeView &,void)1871 IMPL_LINK_NOARG(SvxMainMenuOrganizerDialog, SelectHdl, weld::TreeView&, void)
1872 {
1873     UpdateButtonStates();
1874 }
1875 
UpdateButtonStates()1876 void SvxMainMenuOrganizerDialog::UpdateButtonStates()
1877 {
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);
1882 }
1883 
IMPL_LINK(SvxMainMenuOrganizerDialog,MoveHdl,weld::Button &,rButton,void)1884 IMPL_LINK( SvxMainMenuOrganizerDialog, MoveHdl, weld::Button&, rButton, void )
1885 {
1886     int nSourceEntry = m_xMenuListBox->get_selected_index();
1887     if (nSourceEntry == -1)
1888         return;
1889 
1890     int nTargetEntry;
1891 
1892     if (&rButton == m_xMoveDownButton.get())
1893     {
1894         nTargetEntry = nSourceEntry + 1;
1895     }
1896     else
1897     {
1898         // Move Up is just a Move Down with the source and target reversed
1899         nTargetEntry = nSourceEntry - 1;
1900     }
1901 
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);
1907 
1908     std::swap(mpEntries->at(nSourceEntry), mpEntries->at(nTargetEntry));
1909 
1910     UpdateButtonStates();
1911 }
1912 
GetSelectedEntry()1913 SvxConfigEntry* SvxMainMenuOrganizerDialog::GetSelectedEntry()
1914 {
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));
1919 }
1920 
SvxConfigEntry(OUString aDisplayName,OUString aCommandURL,bool bPopup,bool bParentData)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 )
1934 {
1935     if (bPopUp)
1936     {
1937         mpEntries.reset( new SvxEntries );
1938     }
1939 }
1940 
~SvxConfigEntry()1941 SvxConfigEntry::~SvxConfigEntry()
1942 {
1943     if (mpEntries)
1944     {
1945         for (auto const& entry : *mpEntries)
1946         {
1947             delete entry;
1948         }
1949     }
1950 }
1951 
IsMovable() const1952 bool SvxConfigEntry::IsMovable() const
1953 {
1954     return !IsPopup() || IsMain();
1955 }
1956 
IsDeletable() const1957 bool SvxConfigEntry::IsDeletable() const
1958 {
1959     return !IsMain() || IsUserDefined();
1960 }
1961 
IsRenamable() const1962 bool SvxConfigEntry::IsRenamable() const
1963 {
1964     return !IsMain() || IsUserDefined();
1965 }
1966 
ToolbarSaveInData(const uno::Reference<css::ui::XUIConfigurationManager> & xCfgMgr,const uno::Reference<css::ui::XUIConfigurationManager> & xParentCfgMgr,const OUString & aModuleId,bool docConfig)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 ) :
1972 
1973     SaveInData              ( xCfgMgr, xParentCfgMgr, aModuleId, docConfig ),
1974     m_aDescriptorContainer  ( ITEM_DESCRIPTOR_CONTAINER  )
1975 
1976 {
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 );
1981 
1982     xPWSS->getByName( aModuleId ) >>= m_xPersistentWindowState;
1983 }
1984 
~ToolbarSaveInData()1985 ToolbarSaveInData::~ToolbarSaveInData()
1986 {
1987 }
1988 
GetSystemStyle(const OUString & rResourceURL)1989 sal_Int32 ToolbarSaveInData::GetSystemStyle( const OUString& rResourceURL )
1990 {
1991     sal_Int32 result = 0;
1992 
1993     if ( rResourceURL.startsWith( "private" ) &&
1994          m_xPersistentWindowState.is() &&
1995          m_xPersistentWindowState->hasByName( rResourceURL ) )
1996     {
1997         try
1998         {
1999             uno::Sequence< beans::PropertyValue > aProps;
2000             uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
2001 
2002             if ( a >>= aProps )
2003             {
2004                 for (beans::PropertyValue const& prop : aProps)
2005                 {
2006                     if ( prop.Name == ITEM_DESCRIPTOR_STYLE )
2007                     {
2008                         prop.Value >>= result;
2009                         break;
2010                     }
2011                 }
2012             }
2013         }
2014         catch ( uno::Exception& )
2015         {
2016             // do nothing, a default value is returned
2017         }
2018     }
2019 
2020     return result;
2021 }
2022 
SetSystemStyle(const uno::Reference<frame::XFrame> & xFrame,const OUString & rResourceURL,sal_Int32 nStyle)2023 void ToolbarSaveInData::SetSystemStyle(
2024     const uno::Reference< frame::XFrame >& xFrame,
2025     const OUString& rResourceURL,
2026     sal_Int32 nStyle )
2027 {
2028     // change the style using the API
2029     SetSystemStyle( rResourceURL, nStyle );
2030 
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;
2035 
2036     uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
2037     if ( xPropSet.is() )
2038     {
2039         uno::Any a = xPropSet->getPropertyValue( u"LayoutManager"_ustr );
2040         a >>= xLayoutManager;
2041     }
2042 
2043     if ( xLayoutManager.is() )
2044     {
2045         uno::Reference< css::ui::XUIElement > xUIElement =
2046             xLayoutManager->getElement( rResourceURL );
2047 
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 );
2054 
2055         window = VCLUnoHelper::GetWindow( xWindow );
2056     }
2057 
2058     if ( window == nullptr || window->GetType() != WindowType::TOOLBOX )
2059         return;
2060 
2061     ToolBox* toolbox = static_cast<ToolBox*>(window);
2062 
2063     if ( nStyle == 0 )
2064     {
2065         toolbox->SetButtonType( ButtonType::SYMBOLONLY );
2066     }
2067     else if ( nStyle == 1 )
2068     {
2069         toolbox->SetButtonType( ButtonType::TEXT );
2070     }
2071     if ( nStyle == 2 )
2072     {
2073         toolbox->SetButtonType( ButtonType::SYMBOLTEXT );
2074     }
2075 }
2076 
SetSystemStyle(const OUString & rResourceURL,sal_Int32 nStyle)2077 void ToolbarSaveInData::SetSystemStyle(
2078     const OUString& rResourceURL,
2079     sal_Int32 nStyle )
2080 {
2081     if ( !(rResourceURL.startsWith( "private" ) &&
2082          m_xPersistentWindowState.is() &&
2083          m_xPersistentWindowState->hasByName( rResourceURL )) )
2084         return;
2085 
2086     try
2087     {
2088         uno::Sequence< beans::PropertyValue > aProps;
2089 
2090         uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
2091 
2092         if ( a >>= aProps )
2093         {
2094             for ( beans::PropertyValue& prop : asNonConstRange(aProps) )
2095             {
2096                 if ( prop.Name == ITEM_DESCRIPTOR_STYLE )
2097                 {
2098                     prop.Value <<= nStyle;
2099                     break;
2100                 }
2101             }
2102         }
2103 
2104         uno::Reference< container::XNameReplace >
2105             xNameReplace( m_xPersistentWindowState, uno::UNO_QUERY );
2106 
2107         xNameReplace->replaceByName( rResourceURL, uno::Any( aProps ) );
2108     }
2109     catch ( uno::Exception& )
2110     {
2111         // do nothing, a default value is returned
2112         TOOLS_WARN_EXCEPTION("cui.customize", "Exception setting toolbar style");
2113     }
2114 }
2115 
GetSystemUIName(const OUString & rResourceURL)2116 OUString ToolbarSaveInData::GetSystemUIName( const OUString& rResourceURL )
2117 {
2118     OUString result;
2119 
2120     if ( rResourceURL.startsWith( "private" ) &&
2121          m_xPersistentWindowState.is() &&
2122          m_xPersistentWindowState->hasByName( rResourceURL ) )
2123     {
2124         try
2125         {
2126             uno::Sequence< beans::PropertyValue > aProps;
2127             uno::Any a( m_xPersistentWindowState->getByName( rResourceURL ) );
2128 
2129             if ( a >>= aProps )
2130             {
2131                 for (beans::PropertyValue const& prop : aProps)
2132                 {
2133                     if ( prop.Name == ITEM_DESCRIPTOR_UINAME )
2134                     {
2135                         prop.Value >>= result;
2136                     }
2137                 }
2138             }
2139         }
2140         catch ( uno::Exception& )
2141         {
2142             // do nothing, an empty UIName will be returned
2143         }
2144     }
2145 
2146     if ( rResourceURL.startsWith( ".uno" ) &&
2147          m_xCommandToLabelMap.is() &&
2148          m_xCommandToLabelMap->hasByName( rResourceURL ) )
2149     {
2150         uno::Any a;
2151         try
2152         {
2153             a = m_xCommandToLabelMap->getByName( rResourceURL );
2154 
2155             uno::Sequence< beans::PropertyValue > aPropSeq;
2156             if ( a >>= aPropSeq )
2157             {
2158                 for (beans::PropertyValue const& prop : aPropSeq)
2159                 {
2160                     if ( prop.Name == ITEM_DESCRIPTOR_LABEL )
2161                     {
2162                         prop.Value >>= result;
2163                     }
2164                 }
2165             }
2166         }
2167         catch ( uno::Exception& )
2168         {
2169             // not a system command name
2170         }
2171     }
2172 
2173     return result;
2174 }
2175 
GetEntries()2176 SvxEntries* ToolbarSaveInData::GetEntries()
2177 {
2178     typedef std::unordered_map<OUString, bool > ToolbarInfo;
2179 
2180     ToolbarInfo aToolbarInfo;
2181 
2182     if ( pRootEntry == nullptr )
2183     {
2184 
2185         pRootEntry.reset( new SvxConfigEntry( u"MainToolbars"_ustr, OUString(), true, /*bParentData*/false) );
2186 
2187         const uno::Sequence< uno::Sequence < beans::PropertyValue > > info =
2188             GetConfigManager()->getUIElementsInfo(
2189                 css::ui::UIElementType::TOOLBAR );
2190 
2191         for ( uno::Sequence<beans::PropertyValue> const & props : info )
2192         {
2193             OUString url;
2194             OUString systemname;
2195             OUString uiname;
2196 
2197             for ( const beans::PropertyValue& prop : props )
2198             {
2199                 if ( prop.Name == ITEM_DESCRIPTOR_RESOURCEURL )
2200                 {
2201                     prop.Value >>= url;
2202                     systemname = url.copy( url.lastIndexOf( '/' ) + 1 );
2203                 }
2204                 else if ( prop.Name == ITEM_DESCRIPTOR_UINAME )
2205                 {
2206                     prop.Value >>= uiname;
2207                 }
2208             }
2209 
2210             try
2211             {
2212                 uno::Reference< container::XIndexAccess > xToolbarSettings =
2213                     GetConfigManager()->getSettings( url, false );
2214 
2215                 if ( uiname.isEmpty() )
2216                 {
2217                     // try to get the name from m_xPersistentWindowState
2218                     uiname = GetSystemUIName( url );
2219 
2220                     if ( uiname.isEmpty() )
2221                     {
2222                         uiname = systemname;
2223                     }
2224                 }
2225 
2226                 SvxConfigEntry* pEntry = new SvxConfigEntry(
2227                     uiname, url, true, /*bParentData*/false );
2228 
2229                 pEntry->SetMain();
2230                 pEntry->SetStyle( GetSystemStyle( url ) );
2231 
2232 
2233                 // insert into std::unordered_map to filter duplicates from the parent
2234                 aToolbarInfo.emplace( systemname, true );
2235 
2236                 if ( systemname.startsWith( CUSTOM_TOOLBAR_STR ) )
2237                 {
2238                     pEntry->SetUserDefined();
2239                 }
2240                 else
2241                 {
2242                     pEntry->SetUserDefined( false );
2243                 }
2244 
2245                 pRootEntry->GetEntries()->push_back( pEntry );
2246 
2247                 LoadToolbar( xToolbarSettings, pEntry );
2248             }
2249             catch ( container::NoSuchElementException& )
2250             {
2251                 // TODO, handle resourceURL with no settings
2252             }
2253         }
2254 
2255         uno::Reference< css::ui::XUIConfigurationManager > xParentCfgMgr = GetParentConfigManager();
2256         if ( xParentCfgMgr.is() )
2257         {
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 );
2264 
2265             for ( uno::Sequence<beans::PropertyValue> const & props : info_ )
2266             {
2267                 OUString url;
2268                 OUString systemname;
2269                 OUString uiname;
2270 
2271                 for ( const beans::PropertyValue& prop : props )
2272                 {
2273                     if ( prop.Name == ITEM_DESCRIPTOR_RESOURCEURL )
2274                     {
2275                         prop.Value >>= url;
2276                         systemname = url.copy( url.lastIndexOf( '/' ) + 1 );
2277                     }
2278                     else if ( prop.Name == ITEM_DESCRIPTOR_UINAME )
2279                     {
2280                         prop.Value >>= uiname;
2281                     }
2282                 }
2283 
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;
2288 
2289                 // check if toolbar is already in the document layer
2290                 ToolbarInfo::const_iterator pIter = aToolbarInfo.find( systemname );
2291                 if ( pIter == aToolbarInfo.end() )
2292                 {
2293                     aToolbarInfo.emplace( systemname, true );
2294 
2295                     try
2296                     {
2297                         uno::Reference< container::XIndexAccess > xToolbarSettings =
2298                             xParentCfgMgr->getSettings( url, false );
2299 
2300                         if ( uiname.isEmpty() )
2301                         {
2302                             // try to get the name from m_xPersistentWindowState
2303                             uiname = GetSystemUIName( url );
2304 
2305                             if ( uiname.isEmpty() )
2306                             {
2307                                 uiname = systemname;
2308                             }
2309                         }
2310 
2311                         SvxConfigEntry* pEntry = new SvxConfigEntry(
2312                             uiname, url, true, true );
2313 
2314                         pEntry->SetMain();
2315                         pEntry->SetStyle( GetSystemStyle( url ) );
2316 
2317                         if ( systemname.startsWith( custom ) )
2318                         {
2319                             pEntry->SetUserDefined();
2320                         }
2321                         else
2322                         {
2323                             pEntry->SetUserDefined( false );
2324                         }
2325 
2326                         pRootEntry->GetEntries()->push_back( pEntry );
2327 
2328                         LoadToolbar( xToolbarSettings, pEntry );
2329                     }
2330                     catch ( container::NoSuchElementException& )
2331                     {
2332                         // TODO, handle resourceURL with no settings
2333                     }
2334                 }
2335             }
2336         }
2337 
2338         std::sort( GetEntries()->begin(), GetEntries()->end(), SvxConfigPageHelper::EntrySort );
2339     }
2340 
2341     return pRootEntry->GetEntries();
2342 }
2343 
2344 void
SetEntries(std::unique_ptr<SvxEntries> pNewEntries)2345 ToolbarSaveInData::SetEntries( std::unique_ptr<SvxEntries> pNewEntries )
2346 {
2347     pRootEntry->SetEntries( std::move(pNewEntries) );
2348 }
2349 
2350 bool
HasURL(const OUString & rURL)2351 ToolbarSaveInData::HasURL( const OUString& rURL )
2352 {
2353     for (auto const& entry : *GetEntries())
2354     {
2355         if (entry->GetCommand() == rURL)
2356         {
2357             return !entry->IsParentData();
2358         }
2359     }
2360     return false;
2361 }
2362 
HasSettings()2363 bool ToolbarSaveInData::HasSettings()
2364 {
2365     // return true if there is at least one toolbar entry
2366     return !GetEntries()->empty();
2367 }
2368 
Reset()2369 void ToolbarSaveInData::Reset()
2370 {
2371     // reset each toolbar by calling removeSettings for its toolbar URL
2372     for (auto const& entry : *GetEntries())
2373     {
2374         try
2375         {
2376             const OUString& url = entry->GetCommand();
2377             GetConfigManager()->removeSettings( url );
2378         }
2379         catch ( uno::Exception& )
2380         {
2381             // error occurred removing the settings
2382             // TODO - add error dialog in future?
2383         }
2384     }
2385 
2386     // persist changes to toolbar storage
2387     PersistChanges( GetConfigManager() );
2388 
2389     // now delete the root SvxConfigEntry the next call to GetEntries()
2390     // causes it to be reinitialised
2391     pRootEntry.reset();
2392 
2393     // reset all icons to default
2394     try
2395     {
2396         GetImageManager()->reset();
2397         PersistChanges( GetImageManager() );
2398     }
2399     catch ( uno::Exception& )
2400     {
2401         SAL_WARN("cui.customize", "Error resetting all icons when resetting toolbars");
2402     }
2403 }
2404 
Apply()2405 bool ToolbarSaveInData::Apply()
2406 {
2407     // toolbar changes are instantly applied
2408     return false;
2409 }
2410 
ApplyToolbar(uno::Reference<container::XIndexContainer> const & rToolbarBar,uno::Reference<lang::XSingleComponentFactory> & rFactory,SvxConfigEntry const * pToolbarData)2411 void ToolbarSaveInData::ApplyToolbar(
2412     uno::Reference< container::XIndexContainer > const & rToolbarBar,
2413     uno::Reference< lang::XSingleComponentFactory >& rFactory,
2414     SvxConfigEntry const * pToolbarData )
2415 {
2416     uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
2417 
2418     for (auto const& entry : *pToolbarData->GetEntries())
2419     {
2420         if (entry->IsPopup())
2421         {
2422             uno::Sequence< beans::PropertyValue > aPropValueSeq =
2423                 SvxConfigPageHelper::ConvertToolbarEntry(entry);
2424 
2425             uno::Reference< container::XIndexContainer > xSubMenuBar(
2426                 rFactory->createInstanceWithContext( xContext ),
2427                     uno::UNO_QUERY );
2428 
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 ));
2436 
2437             ApplyToolbar(xSubMenuBar, rFactory, entry);
2438         }
2439         else if (entry->IsSeparator())
2440         {
2441             rToolbarBar->insertByIndex(
2442                 rToolbarBar->getCount(), uno::Any( m_aSeparatorSeq ));
2443         }
2444         else
2445         {
2446             uno::Sequence< beans::PropertyValue > aPropValueSeq =
2447                 SvxConfigPageHelper::ConvertToolbarEntry(entry);
2448 
2449             rToolbarBar->insertByIndex(
2450                 rToolbarBar->getCount(), uno::Any( aPropValueSeq ));
2451         }
2452     }
2453 }
2454 
ApplyToolbar(SvxConfigEntry * pToolbar)2455 void ToolbarSaveInData::ApplyToolbar( SvxConfigEntry* pToolbar )
2456 {
2457     // Apply new toolbar structure to our settings container
2458     uno::Reference< container::XIndexAccess > xSettings =
2459         GetConfigManager()->createSettings();
2460 
2461     uno::Reference< container::XIndexContainer > xIndexContainer (
2462         xSettings, uno::UNO_QUERY );
2463 
2464     uno::Reference< lang::XSingleComponentFactory > xFactory (
2465         xSettings, uno::UNO_QUERY );
2466 
2467     ApplyToolbar( xIndexContainer, xFactory, pToolbar );
2468 
2469     uno::Reference< beans::XPropertySet > xProps(
2470         xSettings, uno::UNO_QUERY );
2471 
2472     if ( pToolbar->IsUserDefined() )
2473     {
2474         xProps->setPropertyValue(
2475             ITEM_DESCRIPTOR_UINAME,
2476             uno::Any( pToolbar->GetName() ) );
2477     }
2478 
2479     try
2480     {
2481         if ( GetConfigManager()->hasSettings( pToolbar->GetCommand() ) )
2482         {
2483             GetConfigManager()->replaceSettings(
2484                 pToolbar->GetCommand(), xSettings );
2485         }
2486         else
2487         {
2488             GetConfigManager()->insertSettings(
2489                 pToolbar->GetCommand(), xSettings );
2490             if ( pToolbar->IsParentData() )
2491                 pToolbar->SetParentData( false );
2492         }
2493     }
2494     catch ( css::uno::Exception const & )
2495     {
2496         TOOLS_WARN_EXCEPTION("cui.customize", "caught exception saving settings");
2497     }
2498 
2499     PersistChanges( GetConfigManager() );
2500 }
2501 
CreateToolbar(SvxConfigEntry * pToolbar)2502 void ToolbarSaveInData::CreateToolbar( SvxConfigEntry* pToolbar )
2503 {
2504     // show the new toolbar in the UI also
2505     uno::Reference< container::XIndexAccess >
2506         xSettings = GetConfigManager()->createSettings();
2507 
2508     uno::Reference< beans::XPropertySet >
2509         xPropertySet( xSettings, uno::UNO_QUERY );
2510 
2511     xPropertySet->setPropertyValue(
2512             ITEM_DESCRIPTOR_UINAME,
2513             uno::Any( pToolbar->GetName() ) );
2514 
2515     try
2516     {
2517         GetConfigManager()->insertSettings( pToolbar->GetCommand(), xSettings );
2518     }
2519     catch ( css::uno::Exception const & )
2520     {
2521         TOOLS_WARN_EXCEPTION("cui.customize", "caught exception saving settings");
2522     }
2523 
2524     GetEntries()->push_back( pToolbar );
2525 
2526     PersistChanges( GetConfigManager() );
2527 }
2528 
RemoveToolbar(SvxConfigEntry * pToolbar)2529 void ToolbarSaveInData::RemoveToolbar( SvxConfigEntry* pToolbar )
2530 {
2531     try
2532     {
2533         OUString url = pToolbar->GetCommand();
2534         GetConfigManager()->removeSettings( url );
2535         SvxConfigPageHelper::RemoveEntry( GetEntries(), pToolbar );
2536         delete pToolbar;
2537 
2538         PersistChanges( GetConfigManager() );
2539 
2540         // remove the persistent window state data
2541         css::uno::Reference< css::container::XNameContainer > xNameContainer(
2542             m_xPersistentWindowState, css::uno::UNO_QUERY_THROW );
2543 
2544         xNameContainer->removeByName( url );
2545     }
2546     catch ( uno::Exception& )
2547     {
2548         // error occurred removing the settings
2549     }
2550 }
2551 
RestoreToolbar(SvxConfigEntry * pToolbar)2552 void ToolbarSaveInData::RestoreToolbar( SvxConfigEntry* pToolbar )
2553 {
2554     OUString url = pToolbar->GetCommand();
2555 
2556     // Restore of toolbar is done by removing it from
2557     // its configuration manager and then getting it again
2558     bool bParentToolbar = pToolbar->IsParentData();
2559 
2560     // Cannot restore parent toolbar
2561     if ( bParentToolbar )
2562         return;
2563 
2564     try
2565     {
2566         GetConfigManager()->removeSettings( url );
2567         pToolbar->GetEntries()->clear();
2568         PersistChanges( GetConfigManager() );
2569     }
2570     catch ( uno::Exception& )
2571     {
2572         // if an error occurs removing the settings then just return
2573         return;
2574     }
2575 
2576     // Now reload the toolbar settings
2577     try
2578     {
2579         uno::Reference< container::XIndexAccess > xToolbarSettings;
2580         if ( IsDocConfig() )
2581         {
2582             xToolbarSettings = GetParentConfigManager()->getSettings( url, false );
2583             pToolbar->SetParentData();
2584         }
2585         else
2586             xToolbarSettings = GetConfigManager()->getSettings( url, false );
2587 
2588         LoadToolbar( xToolbarSettings, pToolbar );
2589 
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())
2595         {
2596             pURLSeq[ 0 ] = entry->GetCommand();
2597 
2598             try
2599             {
2600                 GetImageManager()->removeImages( SvxConfigPageHelper::GetImageType(), aURLSeq );
2601             }
2602             catch ( uno::Exception& )
2603             {
2604                 SAL_WARN("cui.customize", "Error restoring icon when resetting toolbar");
2605             }
2606         }
2607         PersistChanges( GetImageManager() );
2608     }
2609     catch ( container::NoSuchElementException& )
2610     {
2611         // cannot find the resource URL after removing it
2612         // so no entry will appear in the toolbar list
2613     }
2614 }
2615 
LoadToolbar(const uno::Reference<container::XIndexAccess> & xToolbarSettings,SvxConfigEntry const * pParentData)2616 void ToolbarSaveInData::LoadToolbar(
2617     const uno::Reference< container::XIndexAccess >& xToolbarSettings,
2618     SvxConfigEntry const * pParentData )
2619 {
2620     SvxEntries*         pEntries            = pParentData->GetEntries();
2621 
2622     for ( sal_Int32 nIndex = 0; nIndex < xToolbarSettings->getCount(); ++nIndex )
2623     {
2624         OUString                aCommandURL;
2625         OUString                aLabel;
2626         bool                bIsVisible;
2627         sal_Int32               nStyle;
2628 
2629         sal_uInt16 nType( css::ui::ItemType::DEFAULT );
2630 
2631         bool bItem = SvxConfigPageHelper::GetToolbarItemData( xToolbarSettings, nIndex, aCommandURL,
2632             aLabel, nType, bIsVisible, nStyle );
2633 
2634         if ( bItem )
2635         {
2636             bool bIsUserDefined = true;
2637 
2638             if ( nType == css::ui::ItemType::DEFAULT )
2639             {
2640                 uno::Any a;
2641                 try
2642                 {
2643                     a = m_xCommandToLabelMap->getByName( aCommandURL );
2644                     bIsUserDefined = false;
2645                 }
2646                 catch ( container::NoSuchElementException& )
2647                 {
2648                     bIsUserDefined = true;
2649                 }
2650 
2651                 bool bUseDefaultLabel = false;
2652                 // If custom label not set retrieve it from the command
2653                 // to info service
2654                 if ( aLabel.isEmpty() )
2655                 {
2656                     bUseDefaultLabel = true;
2657                     uno::Sequence< beans::PropertyValue > aPropSeq;
2658                     if ( a >>= aPropSeq )
2659                     {
2660                         for (beans::PropertyValue const& prop : aPropSeq)
2661                         {
2662                             if ( prop.Name == "Name" )
2663                             {
2664                                 prop.Value >>= aLabel;
2665                                 break;
2666                             }
2667                         }
2668                     }
2669                 }
2670 
2671                 SvxConfigEntry* pEntry = new SvxConfigEntry(
2672                     aLabel, aCommandURL, false, /*bParentData*/false );
2673 
2674                 pEntry->SetUserDefined( bIsUserDefined );
2675                 pEntry->SetVisible( bIsVisible );
2676                 pEntry->SetStyle( nStyle );
2677 
2678                 if ( !bUseDefaultLabel )
2679                     pEntry->SetName( aLabel );
2680 
2681                 pEntries->push_back( pEntry );
2682             }
2683             else
2684             {
2685                 SvxConfigEntry* pEntry = new SvxConfigEntry;
2686                 pEntry->SetUserDefined( bIsUserDefined );
2687                 pEntries->push_back( pEntry );
2688             }
2689         }
2690     }
2691 }
2692 
SvxNewToolbarDialog(weld::Window * pWindow,const OUString & rName)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))
2697 {
2698     m_xEdtName->set_text(rName);
2699     m_xEdtName->select_region(0, -1);
2700 }
2701 
~SvxNewToolbarDialog()2702 SvxNewToolbarDialog::~SvxNewToolbarDialog()
2703 {
2704 }
2705 
2706 /*******************************************************************************
2707 *
2708 * The SvxIconSelectorDialog class
2709 *
2710 *******************************************************************************/
SvxIconSelectorDialog(weld::Window * pWindow,uno::Reference<css::ui::XImageManager> xImageManager,uno::Reference<css::ui::XImageManager> xParentImageManager)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))
2722 {
2723     typedef std::unordered_map< OUString, bool > ImageInfo;
2724 
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;
2730 
2731     if ( m_nExpectedSize != 16 )
2732     {
2733         m_xFtNote->set_label(SvxConfigPageHelper::replaceSixteen(m_xFtNote->get_label(), m_nExpectedSize));
2734     }
2735 
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());
2744 
2745     uno::Reference< uno::XComponentContext > xComponentContext =
2746         ::comphelper::getProcessComponentContext();
2747 
2748     m_xGraphProvider.set( graphic::GraphicProvider::create( xComponentContext ) );
2749 
2750     uno::Reference< css::util::XPathSettings > xPathSettings =
2751         css::util::thePathSettings::get( xComponentContext );
2752 
2753 
2754     OUString aDirectory = xPathSettings->getUserConfig();
2755 
2756     sal_Int32 aCount = aDirectory.getLength();
2757 
2758     if ( aCount > 0 )
2759     {
2760         sal_Unicode aChar = aDirectory[ aCount-1 ];
2761         if ( aChar != '/')
2762         {
2763             aDirectory += "/";
2764         }
2765     }
2766     else
2767     {
2768         m_xBtnImport->set_sensitive(false);
2769     }
2770 
2771     aDirectory += "soffice.cfg/import";
2772 
2773     uno::Reference< lang::XSingleServiceFactory > xStorageFactory(
2774           css::embed::FileSystemStorageFactory::create( xComponentContext ) );
2775 
2776     uno::Sequence< uno::Any > aArgs{ uno::Any(aDirectory),
2777                                      uno::Any(css::embed::ElementModes::READWRITE) };
2778 
2779     uno::Reference< css::embed::XStorage > xStorage(
2780         xStorageFactory->createInstanceWithArguments( aArgs ), uno::UNO_QUERY );
2781 
2782     uno::Sequence<uno::Any> aProp(comphelper::InitAnyPropertySequence(
2783     {
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);
2789 
2790     ImageInfo aImageInfo1;
2791     if ( m_xImportedImageManager.is() )
2792     {
2793         const uno::Sequence< OUString > names = m_xImportedImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2794         for (auto const & name : names )
2795             aImageInfo1.emplace( name, false );
2796     }
2797 
2798     uno::Sequence< OUString > name( 1 );
2799     auto pname = name.getArray();
2800     for (auto const& elem : aImageInfo1)
2801     {
2802         pname[ 0 ] = elem.first;
2803         uno::Sequence< uno::Reference< graphic::XGraphic> > graphics = m_xImportedImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2804         if ( graphics.hasElements() )
2805         {
2806             m_aGraphics.push_back(graphics[0]);
2807             Image img(graphics[0]);
2808             m_xTbSymbol->InsertItem(m_aGraphics.size(), img, elem.first);
2809         }
2810     }
2811 
2812     ImageInfo                 aImageInfo;
2813 
2814     if ( m_xParentImageManager.is() )
2815     {
2816         const uno::Sequence< OUString > names = m_xParentImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2817         for ( auto const & i : names )
2818             aImageInfo.emplace( i, false );
2819     }
2820 
2821     const uno::Sequence< OUString > names = m_xImageManager->getAllImageNames( SvxConfigPageHelper::GetImageType() );
2822     for ( auto const & i : names )
2823     {
2824         ImageInfo::iterator pIter = aImageInfo.find( i );
2825         if ( pIter != aImageInfo.end() )
2826             pIter->second = true;
2827         else
2828             aImageInfo.emplace( i, true );
2829     }
2830 
2831     // large growth factor, expecting many entries
2832     for (auto const& elem : aImageInfo)
2833     {
2834         pname[ 0 ] = elem.first;
2835 
2836         uno::Sequence< uno::Reference< graphic::XGraphic> > graphics;
2837         try
2838         {
2839             if (elem.second)
2840                 graphics = m_xImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2841             else
2842                 graphics = m_xParentImageManager->getImages( SvxConfigPageHelper::GetImageType(), name );
2843         }
2844         catch ( uno::Exception& )
2845         {
2846             // can't get sequence for this name so it will not be
2847             // added to the list
2848         }
2849 
2850         if ( graphics.hasElements() )
2851         {
2852             Image img(graphics[0]);
2853             if (!img.GetBitmapEx().IsEmpty())
2854             {
2855                 m_aGraphics.push_back(graphics[0]);
2856                 m_xTbSymbol->InsertItem(m_aGraphics.size(), img, elem.first);
2857             }
2858         }
2859     }
2860 
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) );
2865 }
2866 
~SvxIconSelectorDialog()2867 SvxIconSelectorDialog::~SvxIconSelectorDialog()
2868 {
2869 }
2870 
GetSelectedIcon()2871 uno::Reference< graphic::XGraphic> SvxIconSelectorDialog::GetSelectedIcon()
2872 {
2873     uno::Reference<graphic::XGraphic> result;
2874 
2875     sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2876 
2877     if (nId)
2878     {
2879         result = m_aGraphics[nId - 1];
2880     }
2881 
2882     return result;
2883 }
2884 
IMPL_LINK_NOARG(SvxIconSelectorDialog,SelectHdl,ValueSet *,void)2885 IMPL_LINK_NOARG(SvxIconSelectorDialog, SelectHdl, ValueSet*, void)
2886 {
2887     sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2888 
2889     if (!nId)
2890     {
2891         m_xBtnDelete->set_sensitive(false);
2892         return;
2893     }
2894 
2895     OUString aSelImageText = m_xTbSymbol->GetItemText(nId);
2896     if (m_xImportedImageManager->hasImage(SvxConfigPageHelper::GetImageType(), aSelImageText))
2897     {
2898         m_xBtnDelete->set_sensitive(true);
2899     }
2900     else
2901     {
2902         m_xBtnDelete->set_sensitive(false);
2903     }
2904 }
2905 
IMPL_LINK_NOARG(SvxIconSelectorDialog,ImportHdl,weld::Button &,void)2906 IMPL_LINK_NOARG(SvxIconSelectorDialog, ImportHdl, weld::Button&, void)
2907 {
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);
2912 
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() )
2917     {
2918         xController->enableControl(
2919             css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK,
2920             false);
2921     }
2922 
2923     GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
2924     sal_uInt16 nFilter = rFilter.GetImportFormatNumberForShortName(u"png");
2925     aImportDialog.SetCurrentFilter(rFilter.GetImportFormatName(nFilter));
2926 
2927     if ( ERRCODE_NONE == aImportDialog.Execute() )
2928     {
2929         uno::Sequence< OUString > paths = aImportDialog.GetMPath();
2930         ImportGraphics ( paths );
2931     }
2932 }
2933 
IMPL_LINK_NOARG(SvxIconSelectorDialog,DeleteHdl,weld::Button &,void)2934 IMPL_LINK_NOARG(SvxIconSelectorDialog, DeleteHdl, weld::Button&, void)
2935 {
2936     OUString message = CuiResId( RID_CUISTR_DELETE_ICON_CONFIRM );
2937 
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;
2943 
2944     sal_uInt16 nId = m_xTbSymbol->GetSelectedItemId();
2945 
2946     uno::Sequence<OUString> URLs { m_xTbSymbol->GetItemText(nId) };
2947     m_xTbSymbol->RemoveItem(nId);
2948     m_xImportedImageManager->removeImages( SvxConfigPageHelper::GetImageType(), URLs );
2949     if ( m_xImportedImageManager->isModified() )
2950     {
2951         m_xImportedImageManager->store();
2952     }
2953 }
2954 
ReplaceGraphicItem(const OUString & aURL)2955 bool SvxIconSelectorDialog::ReplaceGraphicItem(
2956     const OUString& aURL )
2957 {
2958     uno::Reference< graphic::XGraphic > xGraphic;
2959     uno::Sequence< beans::PropertyValue > aMediaProps{ comphelper::makePropertyValue(u"URL"_ustr, aURL) };
2960 
2961     css::awt::Size aSize;
2962     bool bOK = false;
2963     try
2964     {
2965         xGraphic = m_xGraphProvider->queryGraphic( aMediaProps );
2966 
2967         uno::Reference< beans::XPropertySet > props =
2968             m_xGraphProvider->queryGraphicDescriptor( aMediaProps );
2969         uno::Any a = props->getPropertyValue( u"SizePixel"_ustr );
2970         a >>= aSize;
2971         if (0 == aSize.Width || 0 == aSize.Height)
2972             return false;
2973         else
2974             bOK = true;
2975     }
2976     catch ( uno::Exception& )
2977     {
2978         return false;
2979     }
2980 
2981     bool   bResult( false );
2982     size_t nCount = m_xTbSymbol->GetItemCount();
2983     for (size_t n = 0; n < nCount; ++n)
2984     {
2985         sal_uInt16 nId = m_xTbSymbol->GetItemId( n );
2986 
2987         if ( m_xTbSymbol->GetItemText( nId ) == aURL )
2988         {
2989             try
2990             {
2991                 // replace/insert image with provided URL
2992                 size_t nPos = nId - 1;
2993                 assert(nPos == m_xTbSymbol->GetItemPos(nId));
2994                 m_xTbSymbol->RemoveItem(nId);
2995 
2996                 Image aImage( xGraphic );
2997                 if ( bOK && ((aSize.Width != m_nExpectedSize) || (aSize.Height != m_nExpectedSize)) )
2998                 {
2999                     BitmapEx aBitmap = aImage.GetBitmapEx();
3000                     BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, m_nExpectedSize);
3001                     aImage = Image( aBitmapex);
3002                 }
3003                 m_xTbSymbol->InsertItem(nId, aImage, aURL, nPos); //modify
3004 
3005                 m_aGraphics[nPos] = Graphic(aImage.GetBitmapEx()).GetXGraphic();
3006 
3007                 m_xImportedImageManager->replaceImages( SvxConfigPageHelper::GetImageType(), { aURL }, { xGraphic } );
3008                 m_xImportedImageManager->store();
3009 
3010                 bResult = true;
3011                 break;
3012             }
3013             catch ( css::uno::Exception& )
3014             {
3015                 break;
3016             }
3017         }
3018     }
3019 
3020     return bResult;
3021 }
3022 
3023 namespace
3024 {
ReplaceIconName(std::u16string_view rMessage)3025     OUString ReplaceIconName(std::u16string_view rMessage)
3026     {
3027         OUString name;
3028         OUString message = CuiResId( RID_CUISTR_REPLACE_ICON_WARNING );
3029         OUString placeholder(u"%ICONNAME"_ustr );
3030         sal_Int32 pos = message.indexOf( placeholder );
3031         if ( pos != -1 )
3032         {
3033             name = message.replaceAt(
3034                 pos, placeholder.getLength(), rMessage );
3035         }
3036         return name;
3037     }
3038 
3039     class SvxIconReplacementDialog
3040     {
3041     private:
3042         std::unique_ptr<weld::MessageDialog> m_xQueryBox;
3043     public:
SvxIconReplacementDialog(weld::Window * pParent,std::u16string_view rMessage,bool bYestoAll)3044         SvxIconReplacementDialog(weld::Window *pParent, std::u16string_view rMessage, bool bYestoAll)
3045             : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Warning, VclButtonsType::NONE, ReplaceIconName(rMessage)))
3046         {
3047             m_xQueryBox->set_title(CuiResId(RID_CUISTR_REPLACE_ICON_CONFIRM));
3048             m_xQueryBox->add_button(GetStandardText(StandardButtonType::Yes), 2);
3049             if (bYestoAll)
3050                 m_xQueryBox->add_button(CuiResId(RID_CUISTR_YESTOALL), 5);
3051             m_xQueryBox->add_button(GetStandardText(StandardButtonType::No), 4);
3052             m_xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), 6);
3053             m_xQueryBox->set_default_response(2);
3054         }
run()3055         short run() { return m_xQueryBox->run(); }
3056     };
3057 }
3058 
ImportGraphics(const uno::Sequence<OUString> & rPaths)3059 void SvxIconSelectorDialog::ImportGraphics(
3060     const uno::Sequence< OUString >& rPaths )
3061 {
3062     std::vector< OUString > rejected( rPaths.getLength() );
3063     sal_Int32 rejectedCount = 0;
3064 
3065     sal_uInt16 ret = 0;
3066     sal_Int32 aIndex;
3067     OUString aIconName;
3068 
3069     if ( rPaths.getLength() == 1 )
3070     {
3071         if ( m_xImportedImageManager->hasImage( SvxConfigPageHelper::GetImageType(), rPaths[0] ) )
3072         {
3073             aIndex = rPaths[0].lastIndexOf( '/' );
3074             aIconName = rPaths[0].copy( aIndex+1 );
3075             SvxIconReplacementDialog aDlg(m_xDialog.get(), aIconName, false);
3076             ret = aDlg.run();
3077             if ( ret == 2 )
3078             {
3079                 ReplaceGraphicItem( rPaths[0] );
3080             }
3081         }
3082         else
3083         {
3084             if ( !ImportGraphic( rPaths[0] ) )
3085             {
3086                 rejected[0] = rPaths[0];
3087                 rejectedCount = 1;
3088             }
3089         }
3090     }
3091     else
3092     {
3093         OUString aSourcePath( rPaths[0] );
3094         if ( rPaths[0].lastIndexOf( '/' ) != rPaths[0].getLength() -1 )
3095             aSourcePath = rPaths[0] + "/";
3096 
3097         for ( sal_Int32 i = 1; i < rPaths.getLength(); ++i )
3098         {
3099             OUString aPath = aSourcePath + rPaths[i];
3100             if ( m_xImportedImageManager->hasImage( SvxConfigPageHelper::GetImageType(), aPath ) )
3101             {
3102                 aIndex = rPaths[i].lastIndexOf( '/' );
3103                 aIconName = rPaths[i].copy( aIndex+1 );
3104                 SvxIconReplacementDialog aDlg(m_xDialog.get(), aIconName, true);
3105                 ret = aDlg.run();
3106                 if ( ret == 2 )
3107                 {
3108                     ReplaceGraphicItem( aPath );
3109                 }
3110                 else if ( ret == 5 )
3111                 {
3112                     for ( sal_Int32 k = i; k < rPaths.getLength(); ++k )
3113                     {
3114                         aPath = aSourcePath + rPaths[k];
3115                         bool bHasReplaced = ReplaceGraphicItem( aPath );
3116 
3117                         if ( !bHasReplaced )
3118                         {
3119                             bool result = ImportGraphic( aPath );
3120                             if ( !result )
3121                             {
3122                                 rejected[ rejectedCount ] = rPaths[i];
3123                                 ++rejectedCount;
3124                             }
3125                         }
3126                     }
3127                     break;
3128                 }
3129             }
3130             else
3131             {
3132                 bool result = ImportGraphic( aSourcePath + rPaths[i] );
3133                 if ( !result )
3134                 {
3135                     rejected[ rejectedCount ] = rPaths[i];
3136                     ++rejectedCount;
3137                 }
3138             }
3139         }
3140     }
3141 
3142     if ( rejectedCount == 0 )
3143         return;
3144 
3145     OUStringBuffer message;
3146     OUString fPath;
3147     if (rejectedCount > 1)
3148           fPath = OUString::Concat(rPaths[0].subView(8)) + "/";
3149     for ( sal_Int32 i = 0; i < rejectedCount; ++i )
3150     {
3151         message.append(fPath + rejected[i] + "\n");
3152     }
3153 
3154     SvxIconChangeDialog aDialog(m_xDialog.get(), message.makeStringAndClear());
3155     aDialog.run();
3156 }
3157 
ImportGraphic(const OUString & aURL)3158 bool SvxIconSelectorDialog::ImportGraphic( const OUString& aURL )
3159 {
3160     bool result = false;
3161 
3162     uno::Sequence< beans::PropertyValue > aMediaProps{ comphelper::makePropertyValue(u"URL"_ustr, aURL) };
3163 
3164     try
3165     {
3166         uno::Reference< beans::XPropertySet > props =
3167             m_xGraphProvider->queryGraphicDescriptor( aMediaProps );
3168 
3169         uno::Any a = props->getPropertyValue(u"SizePixel"_ustr);
3170 
3171         uno::Reference< graphic::XGraphic > xGraphic = m_xGraphProvider->queryGraphic( aMediaProps );
3172         if ( xGraphic.is() )
3173         {
3174             bool bOK = true;
3175             css::awt::Size aSize;
3176 
3177             a >>= aSize;
3178             if ( 0 == aSize.Width || 0 == aSize.Height )
3179                 bOK = false;
3180 
3181             Image aImage( xGraphic );
3182 
3183             if ( bOK && ((aSize.Width != m_nExpectedSize) || (aSize.Height != m_nExpectedSize)) )
3184             {
3185                 BitmapEx aBitmap = aImage.GetBitmapEx();
3186                 BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, m_nExpectedSize);
3187                 aImage = Image( aBitmapex);
3188             }
3189             if ( bOK && !!aImage )
3190             {
3191                 m_aGraphics.push_back(Graphic(aImage.GetBitmapEx()).GetXGraphic());
3192                 m_xTbSymbol->InsertItem(m_aGraphics.size(), aImage, aURL);
3193 
3194                 uno::Sequence<OUString> aImportURL { aURL };
3195                 uno::Sequence< uno::Reference<graphic::XGraphic > > aImportGraph{ xGraphic };
3196                 m_xImportedImageManager->insertImages( SvxConfigPageHelper::GetImageType(), aImportURL, aImportGraph );
3197                 if ( m_xImportedImageManager->isModified() )
3198                 {
3199                     m_xImportedImageManager->store();
3200                 }
3201 
3202                 result = true;
3203             }
3204             else
3205             {
3206                 SAL_WARN("cui.customize", "could not create Image from XGraphic");
3207             }
3208         }
3209         else
3210         {
3211                 SAL_WARN("cui.customize", "could not get query XGraphic");
3212         }
3213     }
3214     catch( uno::Exception const & )
3215     {
3216         TOOLS_WARN_EXCEPTION("cui.customize", "Caught exception importing XGraphic");
3217     }
3218     return result;
3219 }
3220 
3221 /*******************************************************************************
3222 *
3223 * The SvxIconChangeDialog class added for issue83555
3224 *
3225 *******************************************************************************/
SvxIconChangeDialog(weld::Window * pWindow,const OUString & rMessage)3226 SvxIconChangeDialog::SvxIconChangeDialog(weld::Window *pWindow, const OUString& rMessage)
3227     : MessageDialogController(pWindow, u"cui/ui/iconchangedialog.ui"_ustr, u"IconChange"_ustr, u"grid"_ustr)
3228     , m_xLineEditDescription(m_xBuilder->weld_text_view(u"addrTextview"_ustr))
3229 {
3230     m_xLineEditDescription->set_size_request(m_xLineEditDescription->get_approximate_digit_width() * 48,
3231                                              m_xLineEditDescription->get_text_height() * 8);
3232     m_xLineEditDescription->set_text(rMessage);
3233 }
3234 
SvxConfigPageFunctionDropTarget(SvxConfigPage & rPage,weld::TreeView & rTreeView)3235 SvxConfigPageFunctionDropTarget::SvxConfigPageFunctionDropTarget(SvxConfigPage&rPage, weld::TreeView& rTreeView)
3236     : weld::ReorderingDropTarget(rTreeView)
3237     , m_rPage(rPage)
3238 {
3239 }
3240 
ExecuteDrop(const ExecuteDropEvent & rEvt)3241 sal_Int8 SvxConfigPageFunctionDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
3242 {
3243     sal_Int8 nRet = weld::ReorderingDropTarget::ExecuteDrop(rEvt);
3244     m_rPage.ListModified();
3245     return nRet;;
3246 }
3247 
3248 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3249