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