xref: /core/cui/source/customize/cfgutil.cxx (revision f3ce30ec)
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 <cfgutil.hxx>
21 #include <cfg.hxx>
22 
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/container/XEnumerationAccess.hpp>
25 #include <com/sun/star/container/XEnumeration.hpp>
26 #include <com/sun/star/document/XScriptInvocationContext.hpp>
27 #include <com/sun/star/frame/ModuleManager.hpp>
28 #include <com/sun/star/frame/Desktop.hpp>
29 #include <com/sun/star/frame/theUICommandDescription.hpp>
30 #include <com/sun/star/frame/XDispatchInformationProvider.hpp>
31 #include <com/sun/star/script/browse/XBrowseNode.hpp>
32 #include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
33 #include <com/sun/star/script/browse/theBrowseNodeFactory.hpp>
34 #include <com/sun/star/script/browse/BrowseNodeFactoryViewTypes.hpp>
35 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
36 #include <com/sun/star/uno/RuntimeException.hpp>
37 #include <com/sun/star/ui/theUICategoryDescription.hpp>
38 
39 #include <basic/sbx.hxx>
40 #include <basic/basicmanagerrepository.hxx>
41 #include <basic/sbstar.hxx>
42 #include <basic/sbxmeth.hxx>
43 #include <basic/sbmod.hxx>
44 #include <basic/basmgr.hxx>
45 #include <tools/urlobj.hxx>
46 #include <strings.hrc>
47 #include <bitmaps.hlst>
48 #include <sfx2/app.hxx>
49 #include <sfx2/minfitem.hxx>
50 #include <comphelper/DisableInteractionHelper.hxx>
51 #include <comphelper/documentinfo.hxx>
52 #include <comphelper/processfactory.hxx>
53 #include <comphelper/sequenceashashmap.hxx>
54 #include <comphelper/string.hxx>
55 #include <svtools/imagemgr.hxx>
56 #include <svtools/treelistentry.hxx>
57 #include <rtl/ustrbuf.hxx>
58 #include <sal/log.hxx>
59 #include <unotools/configmgr.hxx>
60 #include <dialmgr.hxx>
61 #include <svl/stritem.hxx>
62 #include <vcl/builderfactory.hxx>
63 #include <vcl/button.hxx>
64 #include <vcl/commandinfoprovider.hxx>
65 #include <vcl/fixed.hxx>
66 #include <vcl/help.hxx>
67 #include <vcl/vclmedit.hxx>
68 #include <o3tl/make_unique.hxx>
69 
70 using namespace ::com::sun::star;
71 using namespace ::com::sun::star::uno;
72 using namespace ::com::sun::star::script;
73 using namespace ::com::sun::star::frame;
74 using namespace ::com::sun::star::document;
75 
76 SfxStylesInfo_Impl::SfxStylesInfo_Impl()
77 {}
78 
79 void SfxStylesInfo_Impl::init(const OUString& rModuleName, const css::uno::Reference< css::frame::XModel >& xModel)
80 {
81     m_aModuleName = rModuleName;
82     m_xDoc = xModel;
83 }
84 
85 static const char CMDURL_STYLEPROT_ONLY[] = ".uno:StyleApply?";
86 static const char CMDURL_SPART_ONLY    [] = "Style:string=";
87 static const char CMDURL_FPART_ONLY    [] = "FamilyName:string=";
88 
89 static const char STYLEPROP_UINAME[] = "DisplayName";
90 
91 OUString SfxStylesInfo_Impl::generateCommand(const OUString& sFamily, const OUString& sStyle)
92 {
93     return ".uno:StyleApply?Style:string="
94            + sStyle
95            + "&FamilyName:string="
96            + sFamily;
97 }
98 
99 bool SfxStylesInfo_Impl::parseStyleCommand(SfxStyleInfo_Impl& aStyle)
100 {
101     static const sal_Int32 LEN_STYLEPROT = strlen(CMDURL_STYLEPROT_ONLY);
102     static const sal_Int32 LEN_SPART     = strlen(CMDURL_SPART_ONLY);
103     static const sal_Int32 LEN_FPART     = strlen(CMDURL_FPART_ONLY);
104 
105     if (!aStyle.sCommand.startsWith(CMDURL_STYLEPROT_ONLY))
106         return false;
107 
108     aStyle.sFamily.clear();
109     aStyle.sStyle.clear();
110 
111     sal_Int32       nCmdLen  = aStyle.sCommand.getLength();
112     OUString sCmdArgs = aStyle.sCommand.copy(LEN_STYLEPROT, nCmdLen-LEN_STYLEPROT);
113     sal_Int32       i        = sCmdArgs.indexOf('&');
114     if (i<0)
115         return false;
116 
117     OUString sArg = sCmdArgs.copy(0, i);
118     if (sArg.startsWith(CMDURL_SPART_ONLY))
119         aStyle.sStyle = sArg.copy(LEN_SPART);
120     else if (sArg.startsWith(CMDURL_FPART_ONLY))
121         aStyle.sFamily = sArg.copy(LEN_FPART);
122 
123     sArg = sCmdArgs.copy(i+1, sCmdArgs.getLength()-i-1);
124     if (sArg.startsWith(CMDURL_SPART_ONLY))
125         aStyle.sStyle = sArg.copy(LEN_SPART);
126     else if (sArg.startsWith(CMDURL_FPART_ONLY))
127         aStyle.sFamily = sArg.copy(LEN_FPART);
128 
129     return !(aStyle.sFamily.isEmpty() || aStyle.sStyle.isEmpty());
130 }
131 
132 void SfxStylesInfo_Impl::getLabel4Style(SfxStyleInfo_Impl& aStyle)
133 {
134     try
135     {
136         css::uno::Reference< css::style::XStyleFamiliesSupplier > xModel(m_xDoc, css::uno::UNO_QUERY);
137 
138         css::uno::Reference< css::container::XNameAccess > xFamilies;
139         if (xModel.is())
140             xFamilies = xModel->getStyleFamilies();
141 
142         css::uno::Reference< css::container::XNameAccess > xStyleSet;
143         if (xFamilies.is())
144             xFamilies->getByName(aStyle.sFamily) >>= xStyleSet;
145 
146         css::uno::Reference< css::beans::XPropertySet > xStyle;
147         if (xStyleSet.is())
148             xStyleSet->getByName(aStyle.sStyle) >>= xStyle;
149 
150         aStyle.sLabel.clear();
151         if (xStyle.is())
152             xStyle->getPropertyValue(STYLEPROP_UINAME) >>= aStyle.sLabel;
153     }
154     catch(const css::uno::RuntimeException&)
155         { throw; }
156     catch(const css::uno::Exception&)
157         { aStyle.sLabel.clear(); }
158 
159     if (aStyle.sLabel.isEmpty())
160     {
161         aStyle.sLabel = aStyle.sCommand;
162     }
163 }
164 
165 std::vector< SfxStyleInfo_Impl > SfxStylesInfo_Impl::getStyleFamilies()
166 {
167     // It's an optional interface!
168     css::uno::Reference< css::style::XStyleFamiliesSupplier > xModel(m_xDoc, css::uno::UNO_QUERY);
169     if (!xModel.is())
170         return std::vector< SfxStyleInfo_Impl >();
171 
172     css::uno::Reference< css::container::XNameAccess > xCont = xModel->getStyleFamilies();
173     css::uno::Sequence< OUString > lFamilyNames = xCont->getElementNames();
174     std::vector< SfxStyleInfo_Impl > lFamilies;
175     for (const auto& aFamily : lFamilyNames)
176     {
177         if ((aFamily == "CellStyles" && m_aModuleName != "com.sun.star.sheet.SpreadsheetDocument") ||
178              aFamily == "cell" || aFamily == "table" || aFamily == "Default")
179             continue;
180 
181         SfxStyleInfo_Impl aFamilyInfo;
182         aFamilyInfo.sFamily = aFamily;
183 
184         try
185         {
186             css::uno::Reference< css::beans::XPropertySet > xFamilyInfo;
187             xCont->getByName(aFamilyInfo.sFamily) >>= xFamilyInfo;
188             if (!xFamilyInfo.is())
189             {
190                 // TODO_AS currently there is no support for an UIName property .. use internal family name instead
191                 aFamilyInfo.sLabel = aFamilyInfo.sFamily;
192             }
193             else
194                 xFamilyInfo->getPropertyValue(STYLEPROP_UINAME) >>= aFamilyInfo.sLabel;
195         }
196         catch(const css::uno::RuntimeException&)
197             { throw; }
198         catch(const css::uno::Exception&)
199             { return std::vector< SfxStyleInfo_Impl >(); }
200 
201         lFamilies.push_back(aFamilyInfo);
202     }
203 
204     return lFamilies;
205 }
206 
207 std::vector< SfxStyleInfo_Impl > SfxStylesInfo_Impl::getStyles(const OUString& sFamily)
208 {
209     css::uno::Sequence< OUString > lStyleNames;
210     css::uno::Reference< css::style::XStyleFamiliesSupplier > xModel(m_xDoc, css::uno::UNO_QUERY_THROW);
211     css::uno::Reference< css::container::XNameAccess > xFamilies = xModel->getStyleFamilies();
212     css::uno::Reference< css::container::XNameAccess > xStyleSet;
213     try
214     {
215         xFamilies->getByName(sFamily) >>= xStyleSet;
216         lStyleNames = xStyleSet->getElementNames();
217     }
218     catch(const css::uno::RuntimeException&)
219         { throw; }
220     catch(const css::uno::Exception&)
221         { return std::vector< SfxStyleInfo_Impl >(); }
222 
223     std::vector< SfxStyleInfo_Impl > lStyles;
224     sal_Int32                          c      = lStyleNames.getLength();
225     sal_Int32                          i      = 0;
226     for (i=0; i<c; ++i)
227     {
228         SfxStyleInfo_Impl aStyleInfo;
229         aStyleInfo.sFamily  = sFamily;
230         aStyleInfo.sStyle   = lStyleNames[i];
231         aStyleInfo.sCommand = SfxStylesInfo_Impl::generateCommand(aStyleInfo.sFamily, aStyleInfo.sStyle);
232 
233         try
234         {
235             css::uno::Reference< css::beans::XPropertySet > xStyle;
236             xStyleSet->getByName(aStyleInfo.sStyle) >>= xStyle;
237             if (!xStyle.is())
238                 continue;
239             xStyle->getPropertyValue("DisplayName") >>= aStyleInfo.sLabel;
240         }
241         catch(const css::uno::RuntimeException&)
242             { throw; }
243         catch(const css::uno::Exception&)
244             { continue; }
245 
246         lStyles.push_back(aStyleInfo);
247     }
248     return lStyles;
249 }
250 
251 SfxConfigFunctionListBox::SfxConfigFunctionListBox(vcl::Window* pParent, WinBits nStyle)
252     : SvTreeListBox( pParent, nStyle )
253 {
254     SetStyle( GetStyle() | WB_CLIPCHILDREN | WB_HSCROLL | WB_SORT );
255     GetModel()->SetSortMode( SortAscending );
256     SetQuickSearch( true );
257 }
258 
259 VCL_BUILDER_FACTORY_CONSTRUCTOR(SfxConfigFunctionListBox, WB_TABSTOP)
260 
261 SfxConfigFunctionListBox::~SfxConfigFunctionListBox()
262 {
263     disposeOnce();
264 }
265 
266 void SfxConfigFunctionListBox::dispose()
267 {
268     ClearAll();
269     SvTreeListBox::dispose();
270 }
271 
272 void SfxConfigFunctionListBox::MouseMove( const MouseEvent& )
273 {
274 }
275 
276 void SfxConfigFunctionListBox::ClearAll()
277 /*  Description
278     Deletes all entries in the FunctionListBox, all UserData and all
279     possibly existing MacroInfo.
280 */
281 {
282     sal_uInt16 nCount = aArr.size();
283     for ( sal_uInt16 i=0; i<nCount; ++i )
284     {
285         SfxGroupInfo_Impl *pData = aArr[i].get();
286 
287         if ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
288         {
289             OUString* pScriptURI = static_cast<OUString*>(pData->pObject);
290             delete pScriptURI;
291         }
292 
293         if ( pData->nKind == SfxCfgKind::GROUP_SCRIPTCONTAINER )
294         {
295             XInterface* xi = static_cast<XInterface *>(pData->pObject);
296             if (xi != nullptr)
297             {
298                 xi->release();
299             }
300         }
301     }
302 
303     aArr.clear();
304     Clear();
305 }
306 
307 OUString SfxConfigFunctionListBox::GetSelectedScriptURI()
308 {
309     SvTreeListEntry *pEntry = FirstSelected();
310     if ( pEntry )
311     {
312         SfxGroupInfo_Impl *pData = static_cast<SfxGroupInfo_Impl*>(pEntry->GetUserData());
313         if ( pData && ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT ) )
314             return *static_cast<OUString*>(pData->pObject);
315     }
316     return OUString();
317 }
318 
319 OUString SfxConfigFunctionListBox::GetHelpText( bool bConsiderParent )
320 {
321     SvTreeListEntry *pEntry = FirstSelected();
322     if ( pEntry )
323     {
324         SfxGroupInfo_Impl *pData = static_cast<SfxGroupInfo_Impl*>(pEntry->GetUserData());
325         if ( pData )
326         {
327             if ( pData->nKind == SfxCfgKind::FUNCTION_SLOT )
328             {
329                 if (bConsiderParent)
330                     return Application::GetHelp()->GetHelpText( pData->sCommand, this );
331                 else
332                     return Application::GetHelp()->GetHelpText( pData->sCommand, nullptr );
333             }
334             else if ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
335             {
336                 return pData->sHelpText;
337             }
338         }
339     }
340     return OUString();
341 }
342 
343 OUString SfxConfigFunctionListBox::GetCurCommand()
344 {
345     SvTreeListEntry *pEntry = FirstSelected();
346     if (!pEntry)
347         return OUString();
348     SfxGroupInfo_Impl *pData = static_cast<SfxGroupInfo_Impl*>(pEntry->GetUserData());
349     if (!pData)
350         return OUString();
351     return pData->sCommand;
352 }
353 
354 OUString SfxConfigFunctionListBox::GetCurLabel()
355 {
356     SvTreeListEntry *pEntry = FirstSelected();
357     if (!pEntry)
358         return OUString();
359     SfxGroupInfo_Impl *pData = static_cast<SfxGroupInfo_Impl*>(pEntry->GetUserData());
360     if (!pData)
361         return OUString();
362     if (!pData->sLabel.isEmpty())
363         return pData->sLabel;
364     return pData->sCommand;
365 }
366 
367 struct SvxConfigGroupBoxResource_Impl
368 {
369     Image m_hdImage;
370     Image m_libImage;
371     Image m_macImage;
372     Image m_docImage;
373     OUString m_sMyMacros;
374     OUString m_sProdMacros;
375     OUString m_sMacros;
376     OUString m_sDlgMacros;
377     OUString m_aStrGroupStyles;
378     Image m_collapsedImage;
379     Image m_expandedImage;
380 
381     SvxConfigGroupBoxResource_Impl();
382 };
383 
384 SvxConfigGroupBoxResource_Impl::SvxConfigGroupBoxResource_Impl() :
385     m_hdImage(BitmapEx(RID_CUIBMP_HARDDISK)),
386     m_libImage(BitmapEx(RID_CUIBMP_LIB)),
387     m_macImage(BitmapEx(RID_CUIBMP_MACRO)),
388     m_docImage(BitmapEx(RID_CUIBMP_DOC)),
389     m_sMyMacros(CuiResId(RID_SVXSTR_MYMACROS)),
390     m_sProdMacros(CuiResId(RID_SVXSTR_PRODMACROS)),
391     m_sMacros(CuiResId(RID_SVXSTR_BASICMACROS)),
392     m_sDlgMacros(CuiResId(RID_SVXSTR_PRODMACROS)),
393     m_aStrGroupStyles(CuiResId(RID_SVXSTR_GROUP_STYLES)),
394     m_collapsedImage(BitmapEx(RID_CUIBMP_COLLAPSED)),
395     m_expandedImage(BitmapEx(RID_CUIBMP_EXPANDED))
396 {
397 }
398 
399 SfxConfigGroupListBox::SfxConfigGroupListBox(vcl::Window* pParent, WinBits nStyle)
400     : SvTreeListBox(pParent, nStyle)
401     , xImp(new SvxConfigGroupBoxResource_Impl())
402     , pFunctionListBox(nullptr)
403     , pStylesInfo(nullptr)
404 {
405     SetStyle( GetStyle() | WB_CLIPCHILDREN | WB_HSCROLL | WB_HASBUTTONS | WB_HASLINES | WB_HASLINESATROOT | WB_HASBUTTONSATROOT );
406     SetNodeBitmaps(xImp->m_collapsedImage, xImp->m_expandedImage);
407 }
408 
409 VCL_BUILDER_FACTORY_CONSTRUCTOR(SfxConfigGroupListBox, WB_TABSTOP)
410 
411 SfxConfigGroupListBox::~SfxConfigGroupListBox()
412 {
413     disposeOnce();
414 }
415 
416 void SfxConfigGroupListBox::dispose()
417 {
418     ClearAll();
419     pFunctionListBox.clear();
420     SvTreeListBox::dispose();
421 }
422 
423 void SfxConfigGroupListBox::ClearAll()
424 {
425     sal_uInt16 nCount = aArr.size();
426     for ( sal_uInt16 i=0; i<nCount; ++i )
427     {
428         SfxGroupInfo_Impl *pData = aArr[i].get();
429         if (pData->nKind == SfxCfgKind::GROUP_SCRIPTCONTAINER)
430         {
431             XInterface* xi = static_cast<XInterface *>(pData->pObject);
432             if (xi != nullptr)
433             {
434                 xi->release();
435             }
436         }
437     }
438 
439     aArr.clear();
440     Clear();
441 }
442 
443 void SfxConfigGroupListBox::SetStylesInfo(SfxStylesInfo_Impl* pStyles)
444 {
445     pStylesInfo = pStyles;
446 }
447 
448 
449 void SfxConfigGroupListBox::InitModule()
450 {
451     try
452     {
453         css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider(m_xFrame, css::uno::UNO_QUERY_THROW);
454         css::uno::Sequence< sal_Int16 > lGroups = xProvider->getSupportedCommandGroups();
455         sal_Int32                       c1      = lGroups.getLength();
456         sal_Int32                       i1      = 0;
457 
458         if ( c1 )
459         {
460             // Add All Commands category
461             SvTreeListEntry* pEntry = InsertEntry( CuiResId(RID_SVXSTR_ALLFUNCTIONS) );
462             aArr.push_back( o3tl::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_ALLFUNCTIONS, 0 ) );
463             pEntry->SetUserData(aArr.back().get());
464         }
465 
466         for (i1=0; i1<c1; ++i1)
467         {
468             sal_Int16&      rGroupID   = lGroups[i1];
469             OUString sGroupID   = OUString::number(rGroupID);
470             OUString sGroupName ;
471 
472             try
473             {
474                 m_xModuleCategoryInfo->getByName(sGroupID) >>= sGroupName;
475                 if (sGroupName.isEmpty())
476                     continue;
477             }
478             catch(const css::container::NoSuchElementException&)
479                 { continue; }
480 
481             SvTreeListEntry*        pEntry = InsertEntry(sGroupName);
482             aArr.push_back( o3tl::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_FUNCTION, rGroupID ) );
483             pEntry->SetUserData(aArr.back().get());
484         }
485     }
486     catch(const css::uno::RuntimeException&)
487         { throw; }
488     catch(const css::uno::Exception&)
489         {}
490 }
491 
492 
493 namespace
494 {
495 
496     /** examines a component whether it supports XEmbeddedScripts, or provides access to such a
497         component by implementing XScriptInvocationContext.
498         @return
499             the model which supports the embedded scripts, or <NULL/> if it cannot find such a
500             model
501     */
502     Reference< XModel > lcl_getDocumentWithScripts_throw( const Reference< XInterface >& _rxComponent )
503     {
504         Reference< XEmbeddedScripts > xScripts( _rxComponent, UNO_QUERY );
505         if ( !xScripts.is() )
506         {
507             Reference< XScriptInvocationContext > xContext( _rxComponent, UNO_QUERY );
508             if ( xContext.is() )
509                 xScripts.set( xContext->getScriptContainer(), UNO_QUERY );
510         }
511 
512         return Reference< XModel >( xScripts, UNO_QUERY );
513     }
514 
515 
516     Reference< XModel > lcl_getScriptableDocument_nothrow( const Reference< XFrame >& _rxFrame )
517     {
518         Reference< XModel > xDocument;
519 
520         // examine our associated frame
521         try
522         {
523             OSL_ENSURE( _rxFrame.is(), "lcl_getScriptableDocument_nothrow: you need to pass a frame to this dialog/tab page!" );
524             if ( _rxFrame.is() )
525             {
526                 // first try the model in the frame
527                 Reference< XController > xController( _rxFrame->getController(), UNO_SET_THROW );
528                 xDocument = lcl_getDocumentWithScripts_throw( xController->getModel() );
529 
530                 if ( !xDocument.is() )
531                 {
532                     // if there is no suitable document in the frame, try the controller
533                     xDocument = lcl_getDocumentWithScripts_throw( _rxFrame->getController() );
534                 }
535             }
536         }
537         catch( const Exception& )
538         {
539         }
540 
541         return xDocument;
542     }
543 }
544 
545 
546 void SfxConfigGroupListBox::FillScriptList(const css::uno::Reference< css::script::browse::XBrowseNode >& xRootNode,
547                                            SvTreeListEntry* pParentEntry, bool bCheapChildrenOnDemand)
548 {
549     try {
550         if ( xRootNode->hasChildNodes() )
551         {
552             // tdf#120362: Don't ask to enable disabled Java when filling script list
553             css::uno::ContextLayer layer(
554                 new comphelper::NoEnableJavaInteractionContext(css::uno::getCurrentContext()));
555 
556             Sequence< Reference< browse::XBrowseNode > > children =
557                 xRootNode->getChildNodes();
558             bool bIsRootNode = false;
559 
560             OUString user("user");
561             OUString share("share");
562             if ( xRootNode->getName() == "Root" )
563             {
564                 bIsRootNode = true;
565             }
566 
567             //To mimic current starbasic behaviour we
568             //need to make sure that only the current document
569             //is displayed in the config tree. Tests below
570             //set the bDisplay flag to FALSE if the current
571             //node is a first level child of the Root and is NOT
572             //either the current document, user or share
573             OUString currentDocTitle;
574             Reference< XModel > xDocument( lcl_getScriptableDocument_nothrow( m_xFrame ) );
575             if ( xDocument.is() )
576             {
577                 currentDocTitle = ::comphelper::DocumentInfo::getDocumentTitle( xDocument );
578             }
579 
580             for ( sal_Int32 n = 0; n < children.getLength(); ++n )
581             {
582                 Reference< browse::XBrowseNode >& theChild = children[n];
583                 bool bDisplay = true;
584                 OUString uiName = theChild->getName();
585                 if ( bIsRootNode )
586                 {
587                     if (  ! (theChild->getName() == user  || theChild->getName() == share ||
588                              theChild->getName() == currentDocTitle ) )
589                     {
590                         bDisplay=false;
591                     }
592                     else
593                     {
594                         if ( uiName == user )
595                         {
596                             uiName = xImp->m_sMyMacros;
597                         }
598                         else if ( uiName == share )
599                         {
600                             uiName = xImp->m_sProdMacros;
601                         }
602                     }
603                 }
604                 if (children[n]->getType() != browse::BrowseNodeTypes::SCRIPT  && bDisplay )
605                 {
606 //                              We call acquire on the XBrowseNode so that it does not
607 //                              get autodestructed and become invalid when accessed later.
608                     theChild->acquire();
609 
610                     Image aImage = GetImage( theChild, m_xContext, bIsRootNode );
611                     SvTreeListEntry* pNewEntry =
612                         InsertEntry( uiName, pParentEntry );
613                     SetExpandedEntryBmp(  pNewEntry, aImage );
614                     SetCollapsedEntryBmp( pNewEntry, aImage );
615 
616                     aArr.push_back( o3tl::make_unique<SfxGroupInfo_Impl>(SfxCfgKind::GROUP_SCRIPTCONTAINER,
617                             0, static_cast<void *>( theChild.get())));
618 
619                     pNewEntry->SetUserData( aArr.back().get() );
620 
621                     if ( !bCheapChildrenOnDemand && children[n]->hasChildNodes() )
622                     {
623                         Sequence< Reference< browse::XBrowseNode > > grandchildren =
624                             children[n]->getChildNodes();
625 
626                         for ( sal_Int32 m = 0; m < grandchildren.getLength(); ++m )
627                         {
628                             if ( grandchildren[m]->getType() == browse::BrowseNodeTypes::CONTAINER )
629                             {
630                                 pNewEntry->EnableChildrenOnDemand();
631                                 m = grandchildren.getLength();
632                             }
633                         }
634                     }
635                     else
636                     {
637                         /* i30923 - Would be nice if there was a better
638                         * way to determine if a basic lib had children
639                         * without having to ask for them (which forces
640                         * the library to be loaded */
641                         pNewEntry->EnableChildrenOnDemand();
642                     }
643                 }
644             }
645         }
646     }
647     catch (RuntimeException&) {
648         // do nothing, the entry will not be displayed in the UI
649     }
650 }
651 
652 void SfxConfigGroupListBox::FillFunctionsList(const css::uno::Sequence<DispatchInformation>& xCommands)
653 {
654     for (const auto & rInfo : xCommands)
655     {
656         OUString sUIName = MapCommand2UIName(rInfo.Command);
657         SvTreeListEntry* pFuncEntry = pFunctionListBox->InsertEntry(sUIName );
658         aArr.push_back( o3tl::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::FUNCTION_SLOT, 0 ) );
659         SfxGroupInfo_Impl* pGrpInfo = aArr.back().get();
660         pGrpInfo->sCommand = rInfo.Command;
661         pGrpInfo->sLabel   = sUIName;
662         pFuncEntry->SetUserData(pGrpInfo);
663     }
664 }
665 
666 void SfxConfigGroupListBox::Init(const css::uno::Reference< css::uno::XComponentContext >& xContext,
667     const css::uno::Reference< css::frame::XFrame >& xFrame,
668     const OUString& sModuleLongName,
669     bool bEventMode)
670 {
671     SetUpdateMode(false);
672     ClearAll(); // Remove all old entries from treelist box
673 
674     m_xContext = xContext;
675     m_xFrame = xFrame;
676     if( bEventMode )
677     {
678         m_sModuleLongName = sModuleLongName;
679         m_xGlobalCategoryInfo = css::ui::theUICategoryDescription::get( m_xContext );
680         m_xModuleCategoryInfo.set(m_xGlobalCategoryInfo->getByName(m_sModuleLongName), css::uno::UNO_QUERY_THROW);
681         m_xUICmdDescription   = css::frame::theUICommandDescription::get( m_xContext );
682 
683         InitModule();
684     }
685 
686     SAL_INFO("cui.customize", "** ** About to initialise SF Scripts");
687     // Add Scripting Framework entries
688     Reference< browse::XBrowseNode > rootNode;
689     try
690     {
691         Reference< browse::XBrowseNodeFactory > xFac = browse::theBrowseNodeFactory::get( m_xContext );
692         rootNode.set( xFac->createView( browse::BrowseNodeFactoryViewTypes::MACROSELECTOR ) );
693     }
694     catch( Exception& e )
695     {
696         SAL_INFO("cui.customize", "Caught some exception whilst retrieving browse nodes from factory... Exception: " << e);
697         // TODO exception handling
698     }
699 
700 
701     if ( rootNode.is() )
702     {
703         if ( bEventMode )
704         {
705                 //We call acquire on the XBrowseNode so that it does not
706                 //get autodestructed and become invalid when accessed later.
707             rootNode->acquire();
708 
709             aArr.push_back( o3tl::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_SCRIPTCONTAINER, 0,
710                     static_cast<void *>(rootNode.get())));
711             OUString aTitle(xImp->m_sDlgMacros);
712             SvTreeListEntry *pNewEntry = InsertEntry( aTitle );
713             pNewEntry->SetUserData( aArr.back().get() );
714             pNewEntry->EnableChildrenOnDemand();
715         }
716         else
717         {
718              //We are only showing scripts not slot APIs so skip
719              //Root node and show location nodes
720             FillScriptList(rootNode, nullptr, false);
721         }
722     }
723 
724     // add styles
725     if ( bEventMode )
726     {
727         OUString sStyle(xImp->m_aStrGroupStyles);
728         SvTreeListEntry *pEntry = InsertEntry( sStyle );
729         aArr.push_back( o3tl::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_STYLES, 0, nullptr ) ); // TODO last parameter should contain user data
730         pEntry->SetUserData( aArr.back().get() );
731         pEntry->EnableChildrenOnDemand();
732     }
733 
734     MakeVisible( GetEntry( nullptr,0 ) );
735     SetUpdateMode( true );
736 }
737 
738 Image SfxConfigGroupListBox::GetImage(
739     const Reference< browse::XBrowseNode >& node,
740     Reference< XComponentContext > const & xCtx,
741     bool bIsRootNode
742 )
743 {
744     Image aImage;
745     if ( bIsRootNode )
746     {
747         if (node->getName() == "user" || node->getName() == "share" )
748         {
749             aImage = xImp->m_hdImage;
750         }
751         else
752         {
753             OUString factoryURL;
754             OUString nodeName = node->getName();
755             Reference<XInterface> xDocumentModel = getDocumentModel(xCtx, nodeName );
756             if ( xDocumentModel.is() )
757             {
758                 Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xCtx) );
759                 // get the long name of the document:
760                 OUString appModule( xModuleManager->identify(
761                                     xDocumentModel ) );
762                 Sequence<beans::PropertyValue> moduleDescr;
763                 Any aAny = xModuleManager->getByName(appModule);
764                 if( !( aAny >>= moduleDescr ) )
765                 {
766                     throw RuntimeException("SFTreeListBox::Init: failed to get PropertyValue");
767                 }
768                 beans::PropertyValue const * pmoduleDescr =
769                     moduleDescr.getConstArray();
770                 for ( sal_Int32 pos = moduleDescr.getLength(); pos--; )
771                 {
772                     if ( pmoduleDescr[ pos ].Name == "ooSetupFactoryEmptyDocumentURL" )
773                     {
774                         pmoduleDescr[ pos ].Value >>= factoryURL;
775                         SAL_INFO("cui.customize", "factory url for doc images is " << factoryURL);
776                         break;
777                     }
778                 }
779             }
780             if( !factoryURL.isEmpty() )
781             {
782                 aImage = SvFileInformationManager::GetFileImage( INetURLObject(factoryURL) );
783             }
784             else
785             {
786                 aImage = xImp->m_docImage;
787             }
788         }
789     }
790     else
791     {
792         if( node->getType() == browse::BrowseNodeTypes::SCRIPT )
793             aImage = xImp->m_macImage;
794         else
795             aImage = xImp->m_libImage;
796     }
797     return aImage;
798 }
799 
800 Reference< XInterface  >
801 SfxConfigGroupListBox::getDocumentModel( Reference< XComponentContext > const & xCtx, OUString const & docName )
802 {
803     Reference< XInterface > xModel;
804     Reference< frame::XDesktop2 > desktop = frame::Desktop::create( xCtx );
805 
806     Reference< container::XEnumerationAccess > componentsAccess =
807         desktop->getComponents();
808     Reference< container::XEnumeration > components =
809         componentsAccess->createEnumeration();
810     while (components->hasMoreElements())
811     {
812         Reference< frame::XModel > model(
813             components->nextElement(), UNO_QUERY );
814         if ( model.is() )
815         {
816             OUString sTdocUrl =
817                 ::comphelper::DocumentInfo::getDocumentTitle( model );
818             if( sTdocUrl == docName )
819             {
820                 xModel = model;
821                 break;
822             }
823         }
824     }
825     return xModel;
826 }
827 
828 
829 OUString SfxConfigGroupListBox::MapCommand2UIName(const OUString& sCommand)
830 {
831     OUString sUIName;
832     try
833     {
834         css::uno::Reference< css::container::XNameAccess > xModuleConf;
835         m_xUICmdDescription->getByName(m_sModuleLongName) >>= xModuleConf;
836         if (xModuleConf.is())
837         {
838             ::comphelper::SequenceAsHashMap lProps(xModuleConf->getByName(sCommand));
839             sUIName = lProps.getUnpackedValueOrDefault("Name", OUString());
840         }
841     }
842     catch(const css::uno::RuntimeException&)
843         { throw; }
844     catch(css::uno::Exception&)
845         { sUIName.clear(); }
846 
847     // fallback for missing UINames !?
848     if (sUIName.isEmpty())
849     {
850         sUIName = sCommand;
851     }
852 
853     return sUIName;
854 }
855 
856 
857 void SfxConfigGroupListBox::GroupSelected()
858 /*  Description
859     A function group or a basic module has been selected.
860     All functions/macros are displayed in the functionlistbox.
861 */
862 {
863     SvTreeListEntry *pEntry = FirstSelected();
864     SfxGroupInfo_Impl *pInfo = static_cast<SfxGroupInfo_Impl*>(pEntry->GetUserData());
865     pFunctionListBox->SetUpdateMode(false);
866     pFunctionListBox->ClearAll();
867 
868     switch ( pInfo->nKind )
869     {
870         case SfxCfgKind::GROUP_ALLFUNCTIONS:
871         {
872             css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider( m_xFrame, UNO_QUERY );
873             SvTreeListEntry *pCurrEntry = First();
874             while( pCurrEntry )
875             {
876                 SfxGroupInfo_Impl *pCurrentInfo = static_cast<SfxGroupInfo_Impl*>(pCurrEntry->GetUserData());
877                 if (pCurrentInfo->nKind == SfxCfgKind::GROUP_FUNCTION)
878                 {
879                     css::uno::Sequence< css::frame::DispatchInformation > lCommands;
880                     try
881                     {
882                         lCommands = xProvider->getConfigurableDispatchInformation( pCurrentInfo->nUniqueID );
883                         FillFunctionsList( lCommands );
884                     }
885                     catch ( container::NoSuchElementException& )
886                     {
887                     }
888                 }
889                 pCurrEntry = Next( pCurrEntry );
890             }
891             break;
892         }
893 
894         case SfxCfgKind::GROUP_FUNCTION :
895         {
896             sal_uInt16                                                          nGroup    = pInfo->nUniqueID;
897             css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider (m_xFrame, css::uno::UNO_QUERY_THROW);
898             css::uno::Sequence< css::frame::DispatchInformation >           lCommands = xProvider->getConfigurableDispatchInformation(nGroup);
899             FillFunctionsList( lCommands );
900             break;
901         }
902 
903         case SfxCfgKind::GROUP_SCRIPTCONTAINER:
904         {
905             if ( !GetChildCount( pEntry ) )
906             {
907                 Reference< browse::XBrowseNode > rootNode(
908                     static_cast< browse::XBrowseNode* >( pInfo->pObject ) ) ;
909 
910                 try {
911                     if ( rootNode->hasChildNodes() )
912                     {
913                         Sequence< Reference< browse::XBrowseNode > > children =
914                             rootNode->getChildNodes();
915 
916                         for ( sal_Int32 n = 0; n < children.getLength(); ++n )
917                         {
918                             if (children[n]->getType() == browse::BrowseNodeTypes::SCRIPT)
919                             {
920                                 OUString uri, description;
921 
922                                 Reference < beans::XPropertySet >xPropSet( children[n], UNO_QUERY );
923                                 if (!xPropSet.is())
924                                 {
925                                     continue;
926                                 }
927 
928                                 Any value =
929                                     xPropSet->getPropertyValue("URI");
930                                 value >>= uri;
931 
932                                 try
933                                 {
934                                     value = xPropSet->getPropertyValue("Description");
935                                     value >>= description;
936                                 }
937                                 catch (Exception &) {
938                                     // do nothing, the description will be empty
939                                 }
940 
941                                 OUString* pScriptURI = new OUString( uri );
942 
943                                 Image aImage = GetImage( children[n], Reference< XComponentContext >(), false );
944                                 SvTreeListEntry* pNewEntry =
945                                     pFunctionListBox->InsertEntry( children[n]->getName() );
946                                 pFunctionListBox->SetExpandedEntryBmp( pNewEntry, aImage );
947                                 pFunctionListBox->SetCollapsedEntryBmp(pNewEntry, aImage );
948 
949                                 pFunctionListBox->aArr.push_back( o3tl::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::FUNCTION_SCRIPT, 0, pScriptURI ));
950                                 pFunctionListBox->aArr.back()->sCommand = uri;
951                                 pFunctionListBox->aArr.back()->sLabel = children[n]->getName();
952                                 pFunctionListBox->aArr.back()->sHelpText = description;
953                                 pNewEntry->SetUserData( pFunctionListBox->aArr.back().get() );
954                             }
955                         }
956                     }
957                 }
958                 catch (RuntimeException&) {
959                     // do nothing, the entry will not be displayed in the UI
960                 }
961             }
962             break;
963         }
964 
965         case SfxCfgKind::GROUP_STYLES :
966         {
967             SfxStyleInfo_Impl* pFamily = static_cast<SfxStyleInfo_Impl*>(pInfo->pObject);
968             if (pFamily)
969             {
970                 const std::vector< SfxStyleInfo_Impl > lStyles = pStylesInfo->getStyles(pFamily->sFamily);
971                 for (auto const& lStyle : lStyles)
972                 {
973                     SfxStyleInfo_Impl* pStyle = new SfxStyleInfo_Impl(lStyle);
974                     SvTreeListEntry* pFuncEntry = pFunctionListBox->InsertEntry( pStyle->sLabel );
975                     pFunctionListBox->aArr.push_back( o3tl::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_STYLES, 0, pStyle ) );
976                     pFunctionListBox->aArr.back()->sCommand = pStyle->sCommand;
977                     pFunctionListBox->aArr.back()->sLabel = pStyle->sLabel;
978                     pFuncEntry->SetUserData( pFunctionListBox->aArr.back().get() );
979                 }
980             }
981             break;
982         }
983 
984         default:
985             // Do nothing, the list box will stay empty
986             SAL_INFO( "cui.customize", "Ignoring unexpected SfxCfgKind: " <<  static_cast<int>(pInfo->nKind) );
987             break;
988     }
989 
990     if ( pFunctionListBox->GetEntryCount() )
991         pFunctionListBox->Select( pFunctionListBox->GetEntry( nullptr, 0 ) );
992 
993     pFunctionListBox->SetUpdateMode(true);
994 }
995 
996 bool SfxConfigGroupListBox::Expand( SvTreeListEntry* pParent )
997 {
998     bool bRet = SvTreeListBox::Expand( pParent );
999     if ( bRet )
1000     {
1001         sal_uLong nEntries = GetOutputSizePixel().Height() / GetEntryHeight();
1002 
1003         sal_uLong nChildCount = GetVisibleChildCount( pParent );
1004 
1005         if ( nChildCount+1 > nEntries )
1006         {
1007             MakeVisible( pParent, true );
1008         }
1009         else
1010         {
1011             SvTreeListEntry *pEntry = GetFirstEntryInView();
1012             sal_uLong nParentPos = 0;
1013             while ( pEntry && pEntry != pParent )
1014             {
1015                 ++nParentPos;
1016                 pEntry = GetNextEntryInView( pEntry );
1017             }
1018 
1019             if ( nParentPos + nChildCount + 1 > nEntries )
1020                 ScrollOutputArea( static_cast<short>( nEntries - ( nParentPos + nChildCount + 1 ) ) );
1021         }
1022     }
1023 
1024     return bRet;
1025 }
1026 
1027 void SfxConfigGroupListBox::RequestingChildren( SvTreeListEntry *pEntry )
1028 /*  Description
1029     A basic or a library is opened.
1030 */
1031 {
1032     SfxGroupInfo_Impl *pInfo = static_cast<SfxGroupInfo_Impl*>(pEntry->GetUserData());
1033     switch ( pInfo->nKind )
1034     {
1035         case SfxCfgKind::GROUP_SCRIPTCONTAINER:
1036         {
1037             if ( !GetChildCount( pEntry ) )
1038             {
1039                 Reference< browse::XBrowseNode > rootNode(
1040                     static_cast< browse::XBrowseNode* >( pInfo->pObject ) ) ;
1041                 FillScriptList(rootNode, pEntry, true /* i30923 */ );
1042             }
1043             break;
1044         }
1045 
1046         case SfxCfgKind::GROUP_STYLES:
1047         {
1048             if ( !GetChildCount( pEntry ) )
1049             {
1050                 const std::vector< SfxStyleInfo_Impl >                 lStyleFamilies = pStylesInfo->getStyleFamilies();
1051                 for (auto const& lStyleFamily : lStyleFamilies)
1052                 {
1053                     SfxStyleInfo_Impl* pFamily = new SfxStyleInfo_Impl(lStyleFamily);
1054                     SvTreeListEntry* pStyleEntry = InsertEntry( pFamily->sLabel, pEntry );
1055                     aArr.push_back( o3tl::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_STYLES, 0, pFamily ));
1056                     pStyleEntry->SetUserData( aArr.back().get() );
1057                     pStyleEntry->EnableChildrenOnDemand( false );
1058                 }
1059             }
1060             break;
1061         }
1062 
1063         default:
1064             OSL_FAIL( "Wrong group type!" );
1065             break;
1066     }
1067 }
1068 
1069 void SfxConfigGroupListBox::SelectMacro( const SfxMacroInfoItem *pItem )
1070 {
1071     SelectMacro( pItem->GetBasicManager()->GetName(),
1072                  pItem->GetQualifiedName() );
1073 }
1074 
1075 void SfxConfigGroupListBox::SelectMacro( const OUString& rBasic,
1076          const OUString& rMacro )
1077 {
1078     const OUString aBasicName(rBasic + " " + xImp->m_sMacros);
1079     const sal_Int32 nCount = comphelper::string::getTokenCount(rMacro, '.');
1080     const OUString aMethod( rMacro.getToken( nCount-1, '.' ) );
1081     OUString aLib;
1082     OUString aModule;
1083     if ( nCount > 2 )
1084     {
1085         aLib = rMacro.getToken( 0, '.' );
1086         aModule = rMacro.getToken( nCount-2, '.' );
1087     }
1088 
1089     SvTreeListEntry *pEntry = FirstChild(nullptr);
1090     while ( pEntry )
1091     {
1092         OUString aEntryBas = GetEntryText( pEntry );
1093         if ( aEntryBas == aBasicName )
1094         {
1095             Expand( pEntry );
1096             SvTreeListEntry *pLib = FirstChild( pEntry );
1097             while ( pLib )
1098             {
1099                 OUString aEntryLib = GetEntryText( pLib );
1100                 if ( aEntryLib == aLib )
1101                 {
1102                     Expand( pLib );
1103                     SvTreeListEntry *pMod = FirstChild( pLib );
1104                     while ( pMod )
1105                     {
1106                         OUString aEntryMod = GetEntryText( pMod );
1107                         if ( aEntryMod == aModule )
1108                         {
1109                             Expand( pMod );
1110                             MakeVisible( pMod );
1111                             Select( pMod );
1112                             SvTreeListEntry *pMethod = pFunctionListBox->First();
1113                             while ( pMethod )
1114                             {
1115                                 OUString aEntryMethod = GetEntryText( pMethod );
1116                                 if ( aEntryMethod == aMethod )
1117                                 {
1118                                     pFunctionListBox->Select( pMethod );
1119                                     pFunctionListBox->MakeVisible( pMethod );
1120                                     return;
1121                                 }
1122                                 pMethod = pFunctionListBox->Next( pMethod );
1123                             }
1124                         }
1125                         pMod = pMod->NextSibling();
1126                     }
1127                 }
1128                 pLib = pLib->NextSibling();
1129             }
1130         }
1131         pEntry = pEntry->NextSibling();
1132     }
1133 }
1134 
1135 /*
1136  * Implementation of SvxScriptSelectorDialog
1137  *
1138  * This dialog is used for selecting Slot API commands
1139  * and Scripting Framework Scripts.
1140  */
1141 
1142 SvxScriptSelectorDialog::SvxScriptSelectorDialog(
1143     vcl::Window* pParent, bool bShowSlots, const css::uno::Reference< css::frame::XFrame >& xFrame)
1144     : ModalDialog(pParent, "MacroSelectorDialog", "cui/ui/macroselectordialog.ui")
1145     , m_bShowSlots(bShowSlots)
1146 {
1147     get<FixedText>("libraryft")->Show(!m_bShowSlots);
1148     get<FixedText>("categoryft")->Show(m_bShowSlots);
1149     get<FixedText>("macronameft")->Show(!m_bShowSlots);
1150     get<FixedText>("commandsft")->Show(m_bShowSlots);
1151     get(m_pDescriptionText, "description");
1152     get(m_pCommands, "commands");
1153     if (m_bShowSlots)
1154     {
1155         // If we are showing Slot API commands update labels in the UI
1156         SetText(CuiResId(RID_SVXSTR_SELECTOR_ADD_COMMANDS));
1157         get(m_pCancelButton, "close");
1158         get(m_pDialogDescription, "helptoolbar");
1159         get(m_pOKButton, "add");
1160     }
1161     else
1162     {
1163         get(m_pCancelButton, "cancel");
1164         get(m_pDialogDescription, "helpmacro");
1165         get(m_pOKButton, "ok");
1166     }
1167     m_pCancelButton->Show();
1168     m_pDialogDescription->Show();
1169     m_pOKButton->Show();
1170 
1171     get(m_pCategories, "categories");
1172     const OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame));
1173     m_pCategories->SetFunctionListBox(m_pCommands);
1174     m_pCategories->Init(comphelper::getProcessComponentContext(), xFrame, aModuleName, bShowSlots);
1175 
1176     m_pCategories->SetSelectHdl(
1177             LINK( this, SvxScriptSelectorDialog, SelectHdl ) );
1178     m_pCommands->SetSelectHdl( LINK( this, SvxScriptSelectorDialog, SelectHdl ) );
1179     m_pCommands->SetDoubleClickHdl( LINK( this, SvxScriptSelectorDialog, FunctionDoubleClickHdl ) );
1180 
1181     m_pOKButton->SetClickHdl( LINK( this, SvxScriptSelectorDialog, ClickHdl ) );
1182     m_pCancelButton->SetClickHdl( LINK( this, SvxScriptSelectorDialog, ClickHdl ) );
1183 
1184     m_sDefaultDesc = m_pDescriptionText->GetText();
1185 
1186     // Support style commands
1187     uno::Reference<frame::XController> xController;
1188     uno::Reference<frame::XModel> xModel;
1189     if (xFrame.is())
1190         xController = xFrame->getController();
1191     if (xController.is())
1192         xModel = xController->getModel();
1193 
1194     m_aStylesInfo.init(aModuleName, xModel);
1195     m_pCategories->SetStylesInfo(&m_aStylesInfo);
1196 
1197     UpdateUI();
1198 }
1199 
1200 SvxScriptSelectorDialog::~SvxScriptSelectorDialog()
1201 {
1202     disposeOnce();
1203 }
1204 
1205 void SvxScriptSelectorDialog::dispose()
1206 {
1207     m_pDialogDescription.clear();
1208     m_pCategories.clear();
1209     m_pCommands.clear();
1210     m_pOKButton.clear();
1211     m_pCancelButton.clear();
1212     m_pDescriptionText.clear();
1213     ModalDialog::dispose();
1214 }
1215 
1216 IMPL_LINK( SvxScriptSelectorDialog, SelectHdl, SvTreeListBox*, pCtrl, void )
1217 {
1218     if (pCtrl == m_pCategories)
1219     {
1220         m_pCategories->GroupSelected();
1221     }
1222     UpdateUI();
1223 }
1224 
1225 IMPL_LINK_NOARG( SvxScriptSelectorDialog, FunctionDoubleClickHdl, SvTreeListBox*, bool )
1226 {
1227     if (m_pOKButton->IsEnabled())
1228         ClickHdl(m_pOKButton);
1229     return false;
1230 }
1231 
1232 // Check if command is selected and enable the OK button accordingly
1233 // Grab the help text for this id if available and update the description field
1234 void
1235 SvxScriptSelectorDialog::UpdateUI()
1236 {
1237     OUString url = GetScriptURL();
1238     if ( !url.isEmpty() )
1239     {
1240         OUString sMessage = m_pCommands->GetHelpText();
1241         m_pDescriptionText->SetText(sMessage.isEmpty() ? m_sDefaultDesc : sMessage);
1242 
1243         m_pOKButton->Enable();
1244     }
1245     else
1246     {
1247         m_pDescriptionText->SetText(m_sDefaultDesc);
1248         m_pOKButton->Enable( false );
1249     }
1250 }
1251 
1252 IMPL_LINK( SvxScriptSelectorDialog, ClickHdl, Button *, pButton, void )
1253 {
1254     if (pButton == m_pCancelButton)
1255     {
1256         EndDialog();
1257     }
1258     else if (pButton == m_pOKButton)
1259     {
1260         // If we are displaying Slot API commands then this the dialog is being
1261         // run from Tools/Configure and we should not close it
1262         if ( !m_bShowSlots )
1263         {
1264             EndDialog( RET_OK );
1265         }
1266         else
1267         {
1268             // Select the next entry in the list if possible
1269             SvTreeListEntry* current = m_pCommands->FirstSelected();
1270             SvTreeListEntry* next = current->NextSibling();
1271 
1272             if ( next != nullptr )
1273             {
1274                 m_pCommands->Select( next );
1275             }
1276         }
1277     }
1278 }
1279 
1280 void
1281 SvxScriptSelectorDialog::SetRunLabel()
1282 {
1283     m_pOKButton->SetText(CuiResId(RID_SVXSTR_SELECTOR_RUN));
1284 }
1285 
1286 OUString
1287 SvxScriptSelectorDialog::GetScriptURL() const
1288 {
1289     OUString result;
1290 
1291     SvTreeListEntry *pEntry = const_cast< SvxScriptSelectorDialog* >( this )->m_pCommands->FirstSelected();
1292     if ( pEntry )
1293     {
1294         SfxGroupInfo_Impl *pData = static_cast<SfxGroupInfo_Impl*>(pEntry->GetUserData());
1295         if  (   ( pData->nKind == SfxCfgKind::FUNCTION_SLOT )
1296             ||  ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
1297             ||  ( pData->nKind == SfxCfgKind::GROUP_STYLES )
1298             )
1299         {
1300             result = pData->sCommand;
1301         }
1302     }
1303 
1304     return result;
1305 }
1306 
1307 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1308