sd: keep a non-owning pointer to the OverridingShell
[LibreOffice.git] / cui / source / customize / cfgutil.cxx
blob5b1a9c9ced706fbabaabb6580b52c790e5d42f6d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <cfgutil.hxx>
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/container/XEnumerationAccess.hpp>
24 #include <com/sun/star/container/XEnumeration.hpp>
25 #include <com/sun/star/document/XScriptInvocationContext.hpp>
26 #include <com/sun/star/frame/ModuleManager.hpp>
27 #include <com/sun/star/frame/Desktop.hpp>
28 #include <com/sun/star/frame/theUICommandDescription.hpp>
29 #include <com/sun/star/frame/XDispatchInformationProvider.hpp>
30 #include <com/sun/star/script/browse/XBrowseNode.hpp>
31 #include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
32 #include <com/sun/star/script/browse/theBrowseNodeFactory.hpp>
33 #include <com/sun/star/script/browse/BrowseNodeFactoryViewTypes.hpp>
34 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
35 #include <com/sun/star/uno/RuntimeException.hpp>
36 #include <com/sun/star/ui/theUICategoryDescription.hpp>
38 #include <basic/basmgr.hxx>
39 #include <tools/urlobj.hxx>
40 #include <strings.hrc>
41 #include <bitmaps.hlst>
42 #include <sfx2/minfitem.hxx>
43 #include <comphelper/SetFlagContextHelper.hxx>
44 #include <comphelper/documentinfo.hxx>
45 #include <comphelper/lok.hxx>
46 #include <comphelper/processfactory.hxx>
47 #include <comphelper/sequenceashashmap.hxx>
48 #include <svtools/imagemgr.hxx>
49 #include <sal/log.hxx>
50 #include <osl/diagnose.h>
51 #include <dialmgr.hxx>
52 #include <comphelper/diagnose_ex.hxx>
53 #include <vcl/commandevent.hxx>
54 #include <vcl/commandinfoprovider.hxx>
55 #include <vcl/help.hxx>
56 #include <vcl/svapp.hxx>
57 #include <o3tl/string_view.hxx>
59 #include <sfx2/sidebar/ResourceManager.hxx>
60 #include <sfx2/sidebar/Context.hxx>
61 #include <unotools/viewoptions.hxx>
63 using namespace ::com::sun::star;
64 using namespace ::com::sun::star::uno;
65 using namespace ::com::sun::star::script;
66 using namespace ::com::sun::star::frame;
67 using namespace ::com::sun::star::document;
69 SfxStylesInfo_Impl::SfxStylesInfo_Impl()
72 void SfxStylesInfo_Impl::init(const OUString& rModuleName, const css::uno::Reference< css::frame::XModel >& xModel)
74 m_aModuleName = rModuleName;
75 m_xDoc = xModel;
78 const char CMDURL_STYLEPROT_ONLY[] = ".uno:StyleApply?";
79 const char CMDURL_SPART_ONLY [] = "Style:string=";
80 const char CMDURL_FPART_ONLY [] = "FamilyName:string=";
82 constexpr OUString STYLEPROP_UINAME = u"DisplayName"_ustr;
83 constexpr OUString MACRO_SELECTOR_CONFIGNAME = u"MacroSelectorDialog"_ustr;
84 constexpr OUString LAST_RUN_MACRO_INFO = u"LastRunMacro"_ustr;
86 OUString SfxStylesInfo_Impl::generateCommand(
87 std::u16string_view sFamily, std::u16string_view sStyle)
89 return OUString::Concat(".uno:StyleApply?Style:string=")
90 + sStyle
91 + "&FamilyName:string="
92 + sFamily;
95 bool SfxStylesInfo_Impl::parseStyleCommand(SfxStyleInfo_Impl& aStyle)
97 static const sal_Int32 LEN_STYLEPROT = strlen(CMDURL_STYLEPROT_ONLY);
98 static const sal_Int32 LEN_SPART = strlen(CMDURL_SPART_ONLY);
99 static const sal_Int32 LEN_FPART = strlen(CMDURL_FPART_ONLY);
101 if (!aStyle.sCommand.startsWith(CMDURL_STYLEPROT_ONLY))
102 return false;
104 aStyle.sFamily.clear();
105 aStyle.sStyle.clear();
107 sal_Int32 nCmdLen = aStyle.sCommand.getLength();
108 OUString sCmdArgs = aStyle.sCommand.copy(LEN_STYLEPROT, nCmdLen-LEN_STYLEPROT);
109 sal_Int32 i = sCmdArgs.indexOf('&');
110 if (i<0)
111 return false;
113 OUString sArg = sCmdArgs.copy(0, i);
114 if (sArg.startsWith(CMDURL_SPART_ONLY))
115 aStyle.sStyle = sArg.copy(LEN_SPART);
116 else if (sArg.startsWith(CMDURL_FPART_ONLY))
117 aStyle.sFamily = sArg.copy(LEN_FPART);
119 sArg = sCmdArgs.copy(i+1, sCmdArgs.getLength()-i-1);
120 if (sArg.startsWith(CMDURL_SPART_ONLY))
121 aStyle.sStyle = sArg.copy(LEN_SPART);
122 else if (sArg.startsWith(CMDURL_FPART_ONLY))
123 aStyle.sFamily = sArg.copy(LEN_FPART);
125 return !(aStyle.sFamily.isEmpty() || aStyle.sStyle.isEmpty());
128 void SfxStylesInfo_Impl::getLabel4Style(SfxStyleInfo_Impl& aStyle)
132 css::uno::Reference< css::style::XStyleFamiliesSupplier > xModel(m_xDoc, css::uno::UNO_QUERY);
134 css::uno::Reference< css::container::XNameAccess > xFamilies;
135 if (xModel.is())
136 xFamilies = xModel->getStyleFamilies();
138 css::uno::Reference< css::container::XNameAccess > xStyleSet;
139 if (xFamilies.is())
140 xFamilies->getByName(aStyle.sFamily) >>= xStyleSet;
142 css::uno::Reference< css::beans::XPropertySet > xStyle;
143 if (xStyleSet.is())
144 xStyleSet->getByName(aStyle.sStyle) >>= xStyle;
146 aStyle.sLabel.clear();
147 if (xStyle.is())
148 xStyle->getPropertyValue(STYLEPROP_UINAME) >>= aStyle.sLabel;
150 catch(const css::uno::RuntimeException&)
151 { throw; }
152 catch(const css::uno::Exception&)
153 { aStyle.sLabel.clear(); }
155 if (aStyle.sLabel.isEmpty())
157 aStyle.sLabel = aStyle.sCommand;
161 std::vector< SfxStyleInfo_Impl > SfxStylesInfo_Impl::getStyleFamilies() const
163 // It's an optional interface!
164 css::uno::Reference< css::style::XStyleFamiliesSupplier > xModel(m_xDoc, css::uno::UNO_QUERY);
165 if (!xModel.is())
166 return std::vector< SfxStyleInfo_Impl >();
168 css::uno::Reference< css::container::XNameAccess > xCont = xModel->getStyleFamilies();
169 const css::uno::Sequence< OUString > lFamilyNames = xCont->getElementNames();
170 std::vector< SfxStyleInfo_Impl > lFamilies;
171 for (const auto& aFamily : lFamilyNames)
173 if ((aFamily == "CellStyles" && m_aModuleName != "com.sun.star.sheet.SpreadsheetDocument") ||
174 aFamily == "cell" || aFamily == "table" || aFamily == "Default")
175 continue;
177 SfxStyleInfo_Impl aFamilyInfo;
178 aFamilyInfo.sFamily = aFamily;
182 css::uno::Reference< css::beans::XPropertySet > xFamilyInfo;
183 xCont->getByName(aFamilyInfo.sFamily) >>= xFamilyInfo;
184 if (!xFamilyInfo.is())
186 // TODO_AS currently there is no support for an UIName property .. use internal family name instead
187 aFamilyInfo.sLabel = aFamilyInfo.sFamily;
189 else
190 xFamilyInfo->getPropertyValue(STYLEPROP_UINAME) >>= aFamilyInfo.sLabel;
192 catch(const css::uno::RuntimeException&)
193 { throw; }
194 catch(const css::uno::Exception&)
195 { return std::vector< SfxStyleInfo_Impl >(); }
197 lFamilies.push_back(aFamilyInfo);
200 return lFamilies;
203 std::vector< SfxStyleInfo_Impl > SfxStylesInfo_Impl::getStyles(const OUString& sFamily)
205 css::uno::Sequence< OUString > lStyleNames;
206 css::uno::Reference< css::style::XStyleFamiliesSupplier > xModel(m_xDoc, css::uno::UNO_QUERY_THROW);
207 css::uno::Reference< css::container::XNameAccess > xFamilies = xModel->getStyleFamilies();
208 css::uno::Reference< css::container::XNameAccess > xStyleSet;
211 xFamilies->getByName(sFamily) >>= xStyleSet;
212 lStyleNames = xStyleSet->getElementNames();
214 catch(const css::uno::RuntimeException&)
215 { throw; }
216 catch(const css::uno::Exception&)
217 { return std::vector< SfxStyleInfo_Impl >(); }
219 std::vector< SfxStyleInfo_Impl > lStyles;
220 sal_Int32 c = lStyleNames.getLength();
221 sal_Int32 i = 0;
222 for (i=0; i<c; ++i)
224 SfxStyleInfo_Impl aStyleInfo;
225 aStyleInfo.sFamily = sFamily;
226 aStyleInfo.sStyle = lStyleNames[i];
227 aStyleInfo.sCommand = SfxStylesInfo_Impl::generateCommand(aStyleInfo.sFamily, aStyleInfo.sStyle);
231 css::uno::Reference< css::beans::XPropertySet > xStyle;
232 xStyleSet->getByName(aStyleInfo.sStyle) >>= xStyle;
233 if (!xStyle.is())
234 continue;
235 xStyle->getPropertyValue(u"DisplayName"_ustr) >>= aStyleInfo.sLabel;
237 catch(const css::uno::RuntimeException&)
238 { throw; }
239 catch(const css::uno::Exception&)
240 { continue; }
242 lStyles.push_back(aStyleInfo);
244 return lStyles;
247 OUString CuiConfigFunctionListBox::GetCommandHelpText()
249 SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(get_selected_id());
250 if (pData)
252 if ( pData->nKind == SfxCfgKind::FUNCTION_SLOT )
254 return Application::GetHelp()->GetHelpText(pData->sCommand);
256 else if ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
258 return pData->sHelpText;
261 return OUString();
264 OUString CuiConfigFunctionListBox::GetCurCommand() const
266 SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(get_selected_id());
267 if (!pData)
268 return OUString();
269 return pData->sCommand;
272 OUString CuiConfigFunctionListBox::GetCurLabel() const
274 SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(get_selected_id());
275 if (!pData)
276 return OUString();
277 if (!pData->sLabel.isEmpty())
278 return pData->sLabel;
279 return pData->sCommand;
282 CuiConfigFunctionListBox::CuiConfigFunctionListBox(std::unique_ptr<weld::TreeView> xTreeView)
283 : m_xTreeView(std::move(xTreeView))
284 , m_xScratchIter(m_xTreeView->make_iterator())
286 m_xTreeView->make_sorted();
287 m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 35, m_xTreeView->get_height_rows(9));
288 m_xTreeView->connect_query_tooltip(LINK(this, CuiConfigFunctionListBox, QueryTooltip));
291 CuiConfigFunctionListBox::~CuiConfigFunctionListBox()
293 ClearAll();
296 IMPL_LINK(CuiConfigFunctionListBox, QueryTooltip, const weld::TreeIter&, rIter, OUString)
298 SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(m_xTreeView->get_id(rIter));
299 if (!pData)
300 return OUString();
301 OUString aLabel = CuiResId(RID_CUISTR_COMMANDLABEL) + ": ";
302 OUString aName = CuiResId(RID_CUISTR_COMMANDNAME) + ": ";
303 OUString aTip = CuiResId(RID_CUISTR_COMMANDTIP) + ": ";
304 return aLabel + pData->sLabel + "\n" + aName + pData->sCommand+ "\n" + aTip + pData->sTooltip;
307 void CuiConfigFunctionListBox::ClearAll()
308 /* Description
309 Deletes all entries in the FunctionListBox, all UserData and all
310 possibly existing MacroInfo.
313 sal_uInt16 nCount = aArr.size();
314 for ( sal_uInt16 i=0; i<nCount; ++i )
316 SfxGroupInfo_Impl *pData = aArr[i].get();
318 if ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
320 OUString* pScriptURI = static_cast<OUString*>(pData->pObject);
321 delete pScriptURI;
324 if ( pData->nKind == SfxCfgKind::GROUP_SCRIPTCONTAINER )
326 XInterface* xi = static_cast<XInterface *>(pData->pObject);
327 if (xi != nullptr)
329 xi->release();
334 aArr.clear();
335 m_xTreeView->clear();
338 OUString CuiConfigFunctionListBox::GetSelectedScriptURI() const
340 SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(get_selected_id());
341 if (pData && pData->nKind == SfxCfgKind::FUNCTION_SCRIPT)
342 return *static_cast<OUString*>(pData->pObject);
343 return OUString();
346 struct SvxConfigGroupBoxResource_Impl
348 OUString m_sMyMacros;
349 OUString m_sProdMacros;
350 OUString m_sDlgMacros;
351 OUString m_aStrGroupStyles;
352 OUString m_aStrGroupSidebarDecks;
354 SvxConfigGroupBoxResource_Impl();
357 SvxConfigGroupBoxResource_Impl::SvxConfigGroupBoxResource_Impl() :
358 m_sMyMacros(CuiResId(RID_CUISTR_MYMACROS)),
359 m_sProdMacros(CuiResId(RID_CUISTR_PRODMACROS)),
360 m_sDlgMacros(CuiResId(RID_CUISTR_PRODMACROS)),
361 m_aStrGroupStyles(CuiResId(RID_CUISTR_GROUP_STYLES)),
362 m_aStrGroupSidebarDecks(CuiResId(RID_CUISTR_GROUP_SIDEBARDECKS))
366 void CuiConfigGroupListBox::SetStylesInfo(SfxStylesInfo_Impl* pStyles)
368 m_pStylesInfo = pStyles;
371 namespace
374 /** examines a component whether it supports XEmbeddedScripts, or provides access to such a
375 component by implementing XScriptInvocationContext.
376 @return
377 the model which supports the embedded scripts, or <NULL/> if it cannot find such a
378 model
380 Reference< XModel > lcl_getDocumentWithScripts_throw( const Reference< XInterface >& _rxComponent )
382 Reference< XEmbeddedScripts > xScripts( _rxComponent, UNO_QUERY );
383 if ( !xScripts.is() )
385 Reference< XScriptInvocationContext > xContext( _rxComponent, UNO_QUERY );
386 if ( xContext.is() )
387 xScripts = xContext->getScriptContainer();
390 return Reference< XModel >( xScripts, UNO_QUERY );
394 Reference< XModel > lcl_getScriptableDocument_nothrow( const Reference< XFrame >& _rxFrame )
396 Reference< XModel > xDocument;
398 // examine our associated frame
401 OSL_ENSURE( _rxFrame.is(), "lcl_getScriptableDocument_nothrow: you need to pass a frame to this dialog/tab page!" );
402 if ( _rxFrame.is() )
404 // first try the model in the frame
405 Reference< XController > xController( _rxFrame->getController(), UNO_SET_THROW );
406 xDocument = lcl_getDocumentWithScripts_throw( xController->getModel() );
408 if ( !xDocument.is() )
410 // if there is no suitable document in the frame, try the controller
411 xDocument = lcl_getDocumentWithScripts_throw( _rxFrame->getController() );
415 catch( const Exception& )
419 return xDocument;
423 CuiConfigGroupListBox::CuiConfigGroupListBox(std::unique_ptr<weld::TreeView> xTreeView)
424 : xImp(new SvxConfigGroupBoxResource_Impl())
425 , m_pFunctionListBox(nullptr)
426 , m_pStylesInfo(nullptr)
427 , m_xTreeView(std::move(xTreeView))
428 , m_xScratchIter(m_xTreeView->make_iterator())
430 m_xTreeView->connect_expanding(LINK(this, CuiConfigGroupListBox, ExpandingHdl));
431 m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 35, m_xTreeView->get_height_rows(9));
434 CuiConfigGroupListBox::~CuiConfigGroupListBox()
436 ClearAll();
439 void CuiConfigGroupListBox::ClearAll()
441 sal_uInt16 nCount = aArr.size();
442 for ( sal_uInt16 i=0; i<nCount; ++i )
444 SfxGroupInfo_Impl *pData = aArr[i].get();
445 if (pData->nKind == SfxCfgKind::GROUP_STYLES && pData->pObject)
447 SfxStyleInfo_Impl* pStyle = static_cast<SfxStyleInfo_Impl*>(pData->pObject);
448 delete pStyle;
450 else if (pData->nKind == SfxCfgKind::FUNCTION_SCRIPT && pData->pObject )
452 OUString* pScriptURI = static_cast<OUString*>(pData->pObject);
453 delete pScriptURI;
455 else if (pData->nKind == SfxCfgKind::GROUP_SCRIPTCONTAINER)
457 XInterface* xi = static_cast<XInterface *>(pData->pObject);
458 if (xi != nullptr)
460 xi->release();
465 aArr.clear();
466 m_xTreeView->clear();
469 sal_Int32 CuiConfigGroupListBox::InitModule()
473 // return the number of added groups
474 css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider(m_xFrame, css::uno::UNO_QUERY_THROW);
475 css::uno::Sequence< sal_Int16 > lGroups = xProvider->getSupportedCommandGroups();
476 sal_Int32 c1 = lGroups.getLength();
477 sal_Int32 i1 = 0;
478 sal_Int32 nAddedGroups = 0;
480 for (i1=0; i1<c1; ++i1)
482 sal_Int16 nGroupID = lGroups[i1];
483 OUString sGroupID = OUString::number(nGroupID);
484 OUString sGroupName ;
488 m_xModuleCategoryInfo->getByName(sGroupID) >>= sGroupName;
489 if (sGroupName.isEmpty())
490 continue;
492 catch(const css::container::NoSuchElementException&)
493 { continue; }
495 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_FUNCTION, nGroupID ) );
496 m_xTreeView->append(weld::toId(aArr.back().get()), sGroupName);
497 nAddedGroups++;
499 return nAddedGroups;
501 catch(const css::uno::RuntimeException&)
502 { throw; }
503 catch(const css::uno::Exception&)
505 return 0;
508 void CuiConfigGroupListBox::FillScriptList(const css::uno::Reference< css::script::browse::XBrowseNode >& xRootNode,
509 const weld::TreeIter* pParentEntry)
511 try {
512 if ( xRootNode->hasChildNodes() )
514 // tdf#120362: Don't ask to enable disabled Java when filling script list
515 css::uno::ContextLayer layer(comphelper::NoEnableJavaInteractionContext());
517 const Sequence< Reference< browse::XBrowseNode > > children =
518 xRootNode->getChildNodes();
519 bool bIsRootNode = false;
521 OUString user(u"user"_ustr);
522 OUString share(u"share"_ustr);
523 if ( xRootNode->getName() == "Root" )
525 bIsRootNode = true;
528 //To mimic current starbasic behaviour we
529 //need to make sure that only the current document
530 //is displayed in the config tree. Tests below
531 //set the bDisplay flag to FALSE if the current
532 //node is a first level child of the Root and is NOT
533 //either the current document, user or share
534 OUString currentDocTitle;
535 Reference< XModel > xDocument( lcl_getScriptableDocument_nothrow( m_xFrame ) );
536 if ( xDocument.is() )
538 currentDocTitle = ::comphelper::DocumentInfo::getDocumentTitle( xDocument );
541 for ( Reference< browse::XBrowseNode > const & theChild : children )
543 if (!theChild.is())
544 continue;
546 bool bDisplay = true;
547 OUString uiName = theChild->getName();
548 if ( bIsRootNode )
550 if ( ! (uiName == user || uiName == share ||
551 uiName == currentDocTitle ) )
553 bDisplay=false;
555 else
557 if ( uiName == user )
559 uiName = xImp->m_sMyMacros;
561 else if ( uiName == share )
563 uiName = xImp->m_sProdMacros;
567 if (theChild->getType() != browse::BrowseNodeTypes::SCRIPT && bDisplay )
569 // We call acquire on the XBrowseNode so that it does not
570 // get autodestructed and become invalid when accessed later.
571 theChild->acquire();
573 bool bChildOnDemand = false;
575 if ( theChild->hasChildNodes() )
577 const Sequence< Reference< browse::XBrowseNode > > grandchildren =
578 theChild->getChildNodes();
580 for ( const auto& rxNode : grandchildren )
582 if (!rxNode.is())
583 continue;
585 if ( rxNode->getType() == browse::BrowseNodeTypes::CONTAINER )
587 bChildOnDemand = true;
588 break;
593 OUString aImage = GetImage(theChild, m_xContext, bIsRootNode);
595 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>(SfxCfgKind::GROUP_SCRIPTCONTAINER,
596 0, static_cast<void *>( theChild.get())));
598 OUString sId(weld::toId(aArr.back().get()));
599 m_xTreeView->insert(pParentEntry, -1, &uiName, &sId, nullptr, nullptr, bChildOnDemand, m_xScratchIter.get());
600 m_xTreeView->set_image(*m_xScratchIter, aImage);
605 catch (RuntimeException&) {
606 // do nothing, the entry will not be displayed in the UI
610 void CuiConfigGroupListBox::FillFunctionsList(const css::uno::Sequence<DispatchInformation>& xCommands)
612 m_pFunctionListBox->freeze();
613 for (const auto & rInfo : xCommands)
615 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rInfo.Command, m_sModuleLongName);
617 OUString sUIName = MapCommand2UIName(rInfo.Command);
618 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::FUNCTION_SLOT, 0 ) );
619 SfxGroupInfo_Impl* pGrpInfo = aArr.back().get();
620 pGrpInfo->sCommand = rInfo.Command;
621 pGrpInfo->sLabel = sUIName;
622 pGrpInfo->sTooltip = vcl::CommandInfoProvider::GetTooltipForCommand(rInfo.Command, aProperties, m_xFrame);
623 m_pFunctionListBox->append(weld::toId(pGrpInfo), sUIName);
625 m_pFunctionListBox->thaw();
628 void CuiConfigGroupListBox::Init(const css::uno::Reference< css::uno::XComponentContext >& xContext,
629 const css::uno::Reference< css::frame::XFrame >& xFrame,
630 const OUString& sModuleLongName,
631 bool bEventMode)
633 m_xTreeView->freeze();
634 ClearAll(); // Remove all old entries from treelist box
636 m_xContext = xContext;
637 m_xFrame = xFrame;
638 sal_Int32 nAddedGroups = 0;
639 if( bEventMode )
641 m_sModuleLongName = sModuleLongName;
642 m_xGlobalCategoryInfo = css::ui::theUICategoryDescription::get( m_xContext );
643 m_xModuleCategoryInfo.set(m_xGlobalCategoryInfo->getByName(m_sModuleLongName), css::uno::UNO_QUERY_THROW);
644 m_xUICmdDescription = css::frame::theUICommandDescription::get( m_xContext );
646 nAddedGroups = InitModule();
649 SAL_INFO("cui.customize", "** ** About to initialise SF Scripts");
650 // Add Scripting Framework entries
651 Reference< browse::XBrowseNode > rootNode;
654 Reference< browse::XBrowseNodeFactory > xFac = browse::theBrowseNodeFactory::get( m_xContext );
655 rootNode.set( xFac->createView( browse::BrowseNodeFactoryViewTypes::MACROSELECTOR ) );
657 catch( const Exception& )
659 TOOLS_WARN_EXCEPTION("cui.customize", "Caught some exception whilst retrieving browse nodes from factory");
660 // TODO exception handling
663 m_xTreeView->thaw();
664 m_xTreeView->make_sorted();
665 m_xTreeView->make_unsorted();
666 m_xTreeView->freeze();
668 // add All Commands to the top
669 if ( bEventMode && nAddedGroups )
671 aArr.insert(aArr.begin(), std::make_unique<SfxGroupInfo_Impl>(SfxCfgKind::GROUP_ALLFUNCTIONS, 0));
672 OUString sId(weld::toId(aArr.front().get()));
673 OUString s(CuiResId(RID_CUISTR_ALLFUNCTIONS));
674 m_xTreeView->insert(nullptr, 0, &s, &sId, nullptr, nullptr, false, nullptr);
677 // add application macros to the end
678 if ( rootNode.is() )
680 if ( bEventMode )
682 //We call acquire on the XBrowseNode so that it does not
683 //get autodestructed and become invalid when accessed later.
684 rootNode->acquire();
686 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_SCRIPTCONTAINER, 0,
687 static_cast<void *>(rootNode.get())));
688 OUString aTitle(xImp->m_sDlgMacros);
689 OUString sId(weld::toId(aArr.back().get()));
690 m_xTreeView->insert(nullptr, -1, &aTitle, &sId, nullptr, nullptr, true, nullptr);
692 else
694 //We are only showing scripts not slot APIs so skip
695 //Root node and show location nodes
696 FillScriptList(rootNode, nullptr);
700 // add styles and sidebar decks to the end
701 if ( bEventMode )
703 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_STYLES, 0, nullptr ) ); // TODO last parameter should contain user data
704 OUString sStyle(xImp->m_aStrGroupStyles);
705 OUString sId(weld::toId(aArr.back().get()));
706 m_xTreeView->insert(nullptr, -1, &sStyle, &sId, nullptr, nullptr, true, nullptr);
708 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>(SfxCfgKind::GROUP_SIDEBARDECKS, 0));
709 OUString sSidebarDecks(xImp->m_aStrGroupSidebarDecks);
710 sId = weld::toId(aArr.back().get());
711 m_xTreeView->insert(nullptr, -1, &sSidebarDecks, &sId, nullptr, nullptr, false, nullptr);
714 m_xTreeView->thaw();
715 m_xTreeView->scroll_to_row(0);
716 m_xTreeView->select(0);
719 OUString CuiConfigGroupListBox::GetImage(
720 const Reference< browse::XBrowseNode >& node,
721 Reference< XComponentContext > const & xCtx,
722 bool bIsRootNode)
724 OUString aImage;
725 if ( bIsRootNode )
727 if (node->getName() == "user" || node->getName() == "share" )
729 aImage = RID_CUIBMP_HARDDISK;
731 else
733 OUString factoryURL;
734 OUString nodeName = node->getName();
735 Reference<XInterface> xDocumentModel = getDocumentModel(xCtx, nodeName );
736 if ( xDocumentModel.is() )
738 Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xCtx) );
739 // get the long name of the document:
740 OUString appModule( xModuleManager->identify(
741 xDocumentModel ) );
742 Sequence<beans::PropertyValue> moduleDescr;
743 Any aAny = xModuleManager->getByName(appModule);
744 if( !( aAny >>= moduleDescr ) )
746 throw RuntimeException(u"SFTreeListBox::Init: failed to get PropertyValue"_ustr);
748 for ( sal_Int32 pos = moduleDescr.getLength(); pos--; )
750 if (moduleDescr[pos].Name == "ooSetupFactoryEmptyDocumentURL")
752 moduleDescr[pos].Value >>= factoryURL;
753 SAL_INFO("cui.customize", "factory url for doc images is " << factoryURL);
754 break;
758 if( !factoryURL.isEmpty() )
760 aImage = SvFileInformationManager::GetFileImageId(INetURLObject(factoryURL));
762 else
764 aImage = RID_CUIBMP_DOC;
768 else
770 if( node->getType() == browse::BrowseNodeTypes::SCRIPT )
771 aImage = RID_CUIBMP_MACRO;
772 else
773 aImage = RID_CUIBMP_LIB;
775 return aImage;
778 Reference< XInterface >
779 CuiConfigGroupListBox::getDocumentModel( Reference< XComponentContext > const & xCtx, std::u16string_view docName )
781 Reference< XInterface > xModel;
782 Reference< frame::XDesktop2 > desktop = frame::Desktop::create( xCtx );
784 Reference< container::XEnumerationAccess > componentsAccess =
785 desktop->getComponents();
786 Reference< container::XEnumeration > components =
787 componentsAccess->createEnumeration();
788 while (components->hasMoreElements())
790 Reference< frame::XModel > model(
791 components->nextElement(), UNO_QUERY );
792 if ( model.is() )
794 OUString sTdocUrl =
795 ::comphelper::DocumentInfo::getDocumentTitle( model );
796 if( sTdocUrl == docName )
798 xModel = model;
799 break;
803 return xModel;
806 OUString CuiConfigGroupListBox::MapCommand2UIName(const OUString& sCommand)
808 OUString sUIName;
811 css::uno::Reference< css::container::XNameAccess > xModuleConf;
812 m_xUICmdDescription->getByName(m_sModuleLongName) >>= xModuleConf;
813 if (xModuleConf.is())
815 ::comphelper::SequenceAsHashMap lProps(xModuleConf->getByName(sCommand));
816 sUIName = lProps.getUnpackedValueOrDefault(u"Name"_ustr, OUString());
819 catch(const css::uno::RuntimeException&)
820 { throw; }
821 catch(css::uno::Exception&)
822 { sUIName.clear(); }
824 // fallback for missing UINames !?
825 if (sUIName.isEmpty())
827 sUIName = sCommand;
830 return sUIName;
833 void CuiConfigGroupListBox::GroupSelected()
834 /* Description
835 A function group or a basic module has been selected.
836 All functions/macros are displayed in the functionlistbox.
839 std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
840 if (!m_xTreeView->get_selected(xIter.get()))
841 return;
843 SfxGroupInfo_Impl *pInfo = weld::fromId<SfxGroupInfo_Impl*>(m_xTreeView->get_id(*xIter));
844 m_pFunctionListBox->freeze();
845 m_pFunctionListBox->ClearAll();
847 switch ( pInfo->nKind )
849 case SfxCfgKind::GROUP_ALLFUNCTIONS:
851 css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider( m_xFrame, UNO_QUERY );
852 bool bValidIter = m_xTreeView->get_iter_first(*xIter);
853 while (bValidIter)
855 SfxGroupInfo_Impl *pCurrentInfo = weld::fromId<SfxGroupInfo_Impl*>(m_xTreeView->get_id(*xIter));
856 if (pCurrentInfo->nKind == SfxCfgKind::GROUP_FUNCTION)
858 css::uno::Sequence< css::frame::DispatchInformation > lCommands;
861 lCommands = xProvider->getConfigurableDispatchInformation( pCurrentInfo->nUniqueID );
862 FillFunctionsList( lCommands );
864 catch ( container::NoSuchElementException& )
868 bValidIter = m_xTreeView->iter_next(*xIter);
870 break;
873 case SfxCfgKind::GROUP_FUNCTION :
875 sal_uInt16 nGroup = pInfo->nUniqueID;
876 css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider (m_xFrame, css::uno::UNO_QUERY_THROW);
877 css::uno::Sequence< css::frame::DispatchInformation > lCommands = xProvider->getConfigurableDispatchInformation(nGroup);
878 FillFunctionsList( lCommands );
879 break;
882 case SfxCfgKind::GROUP_SCRIPTCONTAINER:
884 Reference< browse::XBrowseNode > rootNode(
885 static_cast< browse::XBrowseNode* >( pInfo->pObject ) ) ;
887 try {
888 if ( rootNode->hasChildNodes() )
890 const Sequence< Reference< browse::XBrowseNode > > children =
891 rootNode->getChildNodes();
893 for ( const Reference< browse::XBrowseNode >& childNode : children )
895 if (!childNode.is())
896 continue;
898 if (childNode->getType() == browse::BrowseNodeTypes::SCRIPT)
900 OUString uri, description;
902 Reference < beans::XPropertySet >xPropSet( childNode, UNO_QUERY );
903 if (!xPropSet.is())
905 continue;
908 Any value =
909 xPropSet->getPropertyValue(u"URI"_ustr);
910 value >>= uri;
914 value = xPropSet->getPropertyValue(u"Description"_ustr);
915 value >>= description;
917 catch (Exception &) {
918 // do nothing, the description will be empty
921 OUString* pScriptURI = new OUString( uri );
923 OUString aImage = GetImage(childNode, Reference< XComponentContext >(), false);
924 m_pFunctionListBox->aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::FUNCTION_SCRIPT, 0, pScriptURI ));
925 m_pFunctionListBox->aArr.back()->sCommand = uri;
926 m_pFunctionListBox->aArr.back()->sLabel = childNode->getName();
927 m_pFunctionListBox->aArr.back()->sHelpText = description;
929 OUString sId(weld::toId(m_pFunctionListBox->aArr.back().get()));
930 m_pFunctionListBox->append(sId, childNode->getName(), aImage);
935 catch (RuntimeException&) {
936 // do nothing, the entry will not be displayed in the UI
938 break;
941 case SfxCfgKind::GROUP_STYLES :
943 SfxStyleInfo_Impl* pFamily = static_cast<SfxStyleInfo_Impl*>(pInfo->pObject);
944 if (pFamily)
946 const std::vector< SfxStyleInfo_Impl > lStyles = m_pStylesInfo->getStyles(pFamily->sFamily);
947 for (auto const& lStyle : lStyles)
949 SfxStyleInfo_Impl* pStyle = new SfxStyleInfo_Impl(lStyle);
950 m_pFunctionListBox->aArr.push_back(std::make_unique<SfxGroupInfo_Impl>(SfxCfgKind::GROUP_STYLES, 0, pStyle));
951 m_pFunctionListBox->aArr.back()->sCommand = pStyle->sCommand;
952 m_pFunctionListBox->aArr.back()->sLabel = pStyle->sLabel;
953 OUString sId(weld::toId(m_pFunctionListBox->aArr.back().get()));
954 m_pFunctionListBox->append(sId, pStyle->sLabel);
957 break;
960 case SfxCfgKind::GROUP_SIDEBARDECKS:
962 sfx2::sidebar::ResourceManager aResourceManager;
963 sfx2::sidebar::Context aContext(m_sModuleLongName, OUString());
964 sfx2::sidebar::ResourceManager::DeckContextDescriptorContainer aDecks;
965 aResourceManager.GetMatchingDecks(aDecks, aContext, false, m_xFrame->getController());
967 for (auto const& rDeck : aDecks)
969 const OUString sCommand = ".uno:SidebarDeck." + rDeck.msId;
970 m_pFunctionListBox->aArr.push_back(std::make_unique<SfxGroupInfo_Impl>(
971 SfxCfgKind::GROUP_SIDEBARDECKS, 0,
972 nullptr));
973 m_pFunctionListBox->aArr.back()->sCommand = sCommand;
974 m_pFunctionListBox->aArr.back()->sLabel = rDeck.msId;
975 m_pFunctionListBox->aArr.back()->sTooltip =
976 vcl::CommandInfoProvider::GetCommandShortcut(sCommand, m_xFrame);
977 m_pFunctionListBox->append(weld::toId(m_pFunctionListBox->aArr.back().get()),
978 rDeck.msId);
981 break;
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;
990 m_pFunctionListBox->thaw();
992 if (m_pFunctionListBox->n_children())
993 m_pFunctionListBox->select(0);
996 /* Description
997 A basic or a library is opened.
999 IMPL_LINK(CuiConfigGroupListBox, ExpandingHdl, const weld::TreeIter&, rIter, bool)
1001 SfxGroupInfo_Impl *pInfo = weld::fromId<SfxGroupInfo_Impl*>(m_xTreeView->get_id(rIter));
1002 switch ( pInfo->nKind )
1004 case SfxCfgKind::GROUP_SCRIPTCONTAINER:
1006 if (!m_xTreeView->iter_has_child(rIter))
1008 Reference< browse::XBrowseNode > rootNode(
1009 static_cast< browse::XBrowseNode* >( pInfo->pObject ) ) ;
1010 FillScriptList(rootNode, &rIter);
1012 break;
1015 case SfxCfgKind::GROUP_STYLES:
1017 if (!m_xTreeView->iter_has_child(rIter))
1019 const std::vector<SfxStyleInfo_Impl> lStyleFamilies = m_pStylesInfo->getStyleFamilies();
1020 for (auto const& lStyleFamily : lStyleFamilies)
1022 SfxStyleInfo_Impl* pFamily = new SfxStyleInfo_Impl(lStyleFamily);
1023 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_STYLES, 0, pFamily ));
1024 OUString sId(weld::toId(aArr.back().get()));
1025 m_xTreeView->insert(&rIter, -1, &pFamily->sLabel, &sId, nullptr, nullptr, false, nullptr);
1028 break;
1031 default:
1032 OSL_FAIL( "Wrong group type!" );
1033 break;
1035 return true;
1038 #if HAVE_FEATURE_SCRIPTING
1039 void CuiConfigGroupListBox::SelectMacro( const SfxMacroInfoItem *pItem )
1041 const std::u16string_view aLocation = pItem->GetLocation();
1042 const std::u16string_view aLib = pItem->GetLib();
1043 const std::u16string_view aModule = pItem->GetModule();
1044 const std::u16string_view aMethod = pItem->GetMethod();
1046 std::unique_ptr<weld::TreeIter> xIter = m_xTreeView->make_iterator();
1047 if (!m_xTreeView->get_iter_first(*xIter))
1048 return;
1052 OUString aEntryBas = m_xTreeView->get_text(*xIter);
1053 if (aEntryBas == xImp->m_sDlgMacros)
1055 m_xTreeView->expand_row(*xIter);
1056 std::unique_ptr<weld::TreeIter> xLocationIter = m_xTreeView->make_iterator(xIter.get());
1057 if (m_xTreeView->iter_children(*xLocationIter))
1061 if (aLocation != m_xTreeView->get_text(*xLocationIter))
1062 continue;
1063 m_xTreeView->expand_row(*xLocationIter);
1064 std::unique_ptr<weld::TreeIter> xLibIter = m_xTreeView->make_iterator(xLocationIter.get());
1065 if (m_xTreeView->iter_children(*xLibIter))
1069 OUString aEntryLib = m_xTreeView->get_text(*xLibIter);
1070 if (aEntryLib == aLib)
1072 if (aModule.empty())
1074 m_xTreeView->scroll_to_row(*xLibIter);
1075 m_xTreeView->select(*xLibIter);
1076 GroupSelected();
1077 weld::TreeView& rFunctionListBoxTreeView
1078 = m_pFunctionListBox->get_widget();
1079 std::unique_ptr<weld::TreeIter> xFunctionListBoxIter
1080 = rFunctionListBoxTreeView.make_iterator();
1081 if (!rFunctionListBoxTreeView.get_iter_first(
1082 *xFunctionListBoxIter))
1083 return;
1086 OUString aEntryMethod = rFunctionListBoxTreeView.get_text(
1087 *xFunctionListBoxIter);
1088 if (aEntryMethod == aMethod)
1090 rFunctionListBoxTreeView.scroll_to_row(
1091 *xFunctionListBoxIter);
1092 rFunctionListBoxTreeView.select(*xFunctionListBoxIter);
1093 return;
1095 } while (
1096 rFunctionListBoxTreeView.iter_next(*xFunctionListBoxIter));
1097 return;
1100 m_xTreeView->expand_row(*xLibIter);
1101 std::unique_ptr<weld::TreeIter> xModIter = m_xTreeView->make_iterator(xLibIter.get());
1102 if (m_xTreeView->iter_children(*xModIter))
1106 OUString aEntryMod = m_xTreeView->get_text(*xModIter);
1107 if ( aEntryMod == aModule )
1109 m_xTreeView->expand_row(*xModIter);
1110 m_xTreeView->scroll_to_row(*xModIter);
1111 m_xTreeView->select(*xModIter);
1112 GroupSelected();
1113 for (int i = 0, nCount = m_pFunctionListBox->n_children(); i < nCount; ++i)
1115 OUString aEntryMethod = m_pFunctionListBox->get_text(i);
1116 if (aEntryMethod == aMethod)
1118 m_pFunctionListBox->select(i);
1119 m_pFunctionListBox->scroll_to_row(i);
1120 return;
1123 m_xTreeView->collapse_row(*xModIter);
1125 } while (m_xTreeView->iter_next_sibling(*xModIter));
1127 m_xTreeView->collapse_row(*xLibIter);
1129 } while (m_xTreeView->iter_next_sibling(*xLibIter));
1131 m_xTreeView->collapse_row(*xLocationIter);
1132 } while (m_xTreeView->iter_next_sibling(*xLocationIter));
1134 // If the macro can't be located, preselect the "Application Macros" category:
1135 m_xTreeView->scroll_to_row(*xIter);
1136 m_xTreeView->select(*xIter);
1137 return;
1139 } while (m_xTreeView->iter_next_sibling(*xIter));
1141 #endif
1144 * Implementation of SvxScriptSelectorDialog
1146 * This dialog is used for selecting Slot API commands
1147 * and Scripting Framework Scripts.
1150 SvxScriptSelectorDialog::SvxScriptSelectorDialog(
1151 weld::Window* pParent, const css::uno::Reference< css::frame::XFrame >& xFrame)
1152 : GenericDialogController(pParent, u"cui/ui/macroselectordialog.ui"_ustr, u"MacroSelectorDialog"_ustr)
1153 , m_xDialogDescription(m_xBuilder->weld_label(u"helpmacro"_ustr))
1154 , m_xCategories(new CuiConfigGroupListBox(m_xBuilder->weld_tree_view(u"categories"_ustr)))
1155 , m_xCommands(new CuiConfigFunctionListBox(m_xBuilder->weld_tree_view(u"commands"_ustr)))
1156 , m_xLibraryFT(m_xBuilder->weld_label(u"libraryft"_ustr))
1157 , m_xMacronameFT(m_xBuilder->weld_label(u"macronameft"_ustr))
1158 , m_xOKButton(m_xBuilder->weld_button(u"ok"_ustr))
1159 , m_xCancelButton(m_xBuilder->weld_button(u"cancel"_ustr))
1160 , m_xDescriptionText(m_xBuilder->weld_text_view(u"description"_ustr))
1161 , m_xDescriptionFrame(m_xBuilder->weld_frame(u"descriptionframe"_ustr))
1163 m_xCancelButton->show();
1164 m_xDialogDescription->show();
1165 m_xOKButton->show();
1167 m_xLibraryFT->set_visible(true);
1168 m_xMacronameFT->set_visible(true);
1170 const OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame));
1171 m_xCategories->SetFunctionListBox(m_xCommands.get());
1172 m_xCategories->Init(comphelper::getProcessComponentContext(), xFrame, aModuleName, /*bShowSlots*/false);
1174 m_xCategories->connect_changed(
1175 LINK( this, SvxScriptSelectorDialog, SelectHdl ) );
1176 m_xCommands->connect_changed( LINK( this, SvxScriptSelectorDialog, SelectHdl ) );
1177 m_xCommands->connect_row_activated( LINK( this, SvxScriptSelectorDialog, FunctionDoubleClickHdl ) );
1178 m_xCommands->connect_popup_menu( LINK( this, SvxScriptSelectorDialog, ContextMenuHdl ) );
1180 m_xOKButton->connect_clicked( LINK( this, SvxScriptSelectorDialog, ClickHdl ) );
1181 m_xCancelButton->connect_clicked( LINK( this, SvxScriptSelectorDialog, ClickHdl ) );
1183 m_sDefaultDesc = m_xDescriptionText->get_text();
1185 // Support style commands
1186 uno::Reference<frame::XController> xController;
1187 uno::Reference<frame::XModel> xModel;
1188 if (xFrame.is())
1189 xController = xFrame->getController();
1190 if (xController.is())
1191 xModel = xController->getModel();
1193 m_aStylesInfo.init(aModuleName, xModel);
1194 m_xCategories->SetStylesInfo(&m_aStylesInfo);
1196 // The following call is a workaround to make scroll_to_row work as expected in kf5/x11
1197 m_xDialog->resize_to_request();
1199 LoadLastUsedMacro();
1200 UpdateUI();
1202 if (comphelper::LibreOfficeKit::isActive())
1203 m_xDescriptionFrame->hide();
1206 SvxScriptSelectorDialog::~SvxScriptSelectorDialog()
1210 IMPL_LINK(SvxScriptSelectorDialog, SelectHdl, weld::TreeView&, rCtrl, void)
1212 if (&rCtrl == &m_xCategories->get_widget())
1214 m_xCategories->GroupSelected();
1216 UpdateUI();
1219 IMPL_LINK_NOARG(SvxScriptSelectorDialog, FunctionDoubleClickHdl, weld::TreeView&, bool)
1221 if (m_xOKButton->get_sensitive())
1222 ClickHdl(*m_xOKButton);
1223 return true;
1226 IMPL_LINK(SvxScriptSelectorDialog, ContextMenuHdl, const CommandEvent&, rCEvt, bool)
1228 weld::TreeView& xTreeView = m_xCommands->get_widget();
1229 if (rCEvt.GetCommand() != CommandEventId::ContextMenu || !xTreeView.n_children())
1230 return false;
1232 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(&xTreeView, u"modules/BasicIDE/ui/sortmenu.ui"_ustr));
1233 std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu(u"sortmenu"_ustr));
1234 std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu(u"sortsubmenu"_ustr));
1235 xDropMenu->set_active(u"alphabetically"_ustr, xTreeView.get_sort_order());
1236 xDropMenu->set_active(u"properorder"_ustr, !xTreeView.get_sort_order());
1238 OUString sCommand(xPopup->popup_at_rect(&xTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
1239 if (sCommand == "alphabetically")
1241 xTreeView.make_sorted();
1243 else if (sCommand == "properorder")
1245 xTreeView.make_unsorted();
1246 m_xCategories->GroupSelected();
1248 else if (!sCommand.isEmpty())
1250 SAL_WARN("cui.customize", "Unknown context menu action: " << sCommand );
1253 return true;
1256 // Check if command is selected and enable the OK button accordingly
1257 // Grab the help text for this id if available and update the description field
1258 void
1259 SvxScriptSelectorDialog::UpdateUI()
1261 OUString url = GetScriptURL();
1262 if ( !url.isEmpty() )
1264 OUString sMessage = m_xCommands->GetCommandHelpText();
1265 m_xDescriptionText->set_text(sMessage.isEmpty() ? m_sDefaultDesc : sMessage);
1266 m_xOKButton->set_sensitive(true);
1268 else
1270 m_xDescriptionText->set_text(m_sDefaultDesc);
1271 m_xOKButton->set_sensitive(false);
1275 IMPL_LINK(SvxScriptSelectorDialog, ClickHdl, weld::Button&, rButton, void)
1277 if (&rButton == m_xCancelButton.get())
1279 m_xDialog->response(RET_CANCEL);
1281 else if (&rButton == m_xOKButton.get())
1283 SaveLastUsedMacro();
1284 m_xDialog->response(RET_OK);
1288 void
1289 SvxScriptSelectorDialog::SetRunLabel()
1291 m_xOKButton->set_label(CuiResId(RID_CUISTR_SELECTOR_RUN));
1294 OUString
1295 SvxScriptSelectorDialog::GetScriptURL() const
1297 OUString result;
1299 std::unique_ptr<weld::TreeIter> xIter = m_xCommands->make_iterator();
1300 if (m_xCommands->get_selected(xIter.get()))
1302 SfxGroupInfo_Impl *pData = weld::fromId<SfxGroupInfo_Impl*>(m_xCommands->get_id(*xIter));
1303 if ( ( pData->nKind == SfxCfgKind::FUNCTION_SLOT )
1304 || ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
1305 || ( pData->nKind == SfxCfgKind::GROUP_STYLES )
1308 result = pData->sCommand;
1312 return result;
1315 void
1316 SvxScriptSelectorDialog::SaveLastUsedMacro()
1318 // Gets the current selection in the dialog as a series of selected entries
1319 OUString sMacroInfo;
1320 sMacroInfo = m_xCommands->get_selected_text();
1321 weld::TreeView& xCategories = m_xCategories->get_widget();
1322 std::unique_ptr<weld::TreeIter> xIter = xCategories.make_iterator();
1324 if (!xCategories.get_selected(xIter.get()))
1325 return;
1329 sMacroInfo = xCategories.get_text(*xIter) + "|" + sMacroInfo;
1330 } while (xCategories.iter_parent(*xIter));
1332 SvtViewOptions( EViewType::Dialog, MACRO_SELECTOR_CONFIGNAME ).SetUserItem(
1333 LAST_RUN_MACRO_INFO, Any(sMacroInfo));
1336 void
1337 SvxScriptSelectorDialog::LoadLastUsedMacro()
1339 SvtViewOptions aDlgOpt( EViewType::Dialog, MACRO_SELECTOR_CONFIGNAME );
1340 if (!aDlgOpt.Exists())
1341 return;
1343 OUString sMacroInfo;
1344 aDlgOpt.GetUserItem(LAST_RUN_MACRO_INFO) >>= sMacroInfo;
1345 if (sMacroInfo.isEmpty())
1346 return;
1348 // Counts how many entries exist in the macro info string
1349 sal_Int16 nInfoParts = 0;
1350 sal_Int16 nLastIndex = sMacroInfo.indexOf('|');
1351 if (nLastIndex > -1)
1353 nInfoParts = 1;
1354 while ( nLastIndex != -1 )
1356 nInfoParts++;
1357 nLastIndex = sMacroInfo.indexOf('|', nLastIndex + 1);
1361 weld::TreeView& xCategories = m_xCategories->get_widget();
1362 std::unique_ptr<weld::TreeIter> xIter = xCategories.make_iterator();
1363 if (!xCategories.get_iter_first(*xIter))
1364 return;
1366 // Expand the nodes in the category tree
1367 OUString sNodeToExpand;
1368 bool bIsIterValid;
1369 sal_Int16 nOpenedNodes = 0;
1370 for (sal_Int16 i=0; i<nInfoParts - 1; i++)
1372 sNodeToExpand = sMacroInfo.getToken(i, '|');
1373 bIsIterValid = true;
1374 while (bIsIterValid && xCategories.get_text(*xIter) != sNodeToExpand)
1375 bIsIterValid = xCategories.iter_next_sibling(*xIter);
1377 if (bIsIterValid)
1379 xCategories.expand_row(*xIter);
1380 nOpenedNodes++;
1382 if (xCategories.iter_has_child(*xIter))
1383 (void)xCategories.iter_children(*xIter);
1384 else if (nOpenedNodes < nInfoParts - 1)
1385 // If the number of levels in the tree is smaller than the
1386 // number of parts in the macro info string, then return
1387 return;
1389 xCategories.select(*xIter);
1390 xCategories.scroll_to_row(*xIter);
1391 m_xCategories->GroupSelected();
1393 // Select the macro in the command tree
1394 weld::TreeView& xCommands = m_xCommands->get_widget();
1395 xIter = xCommands.make_iterator();
1396 if (!xCommands.get_iter_first(*xIter))
1397 return;
1399 OUString sMacroName = sMacroInfo.getToken(nInfoParts - 1, '|');
1400 bIsIterValid = true;
1401 while (bIsIterValid && xCommands.get_text(*xIter) != sMacroName)
1402 bIsIterValid = xCommands.iter_next_sibling(*xIter);
1404 if (bIsIterValid)
1406 xCommands.scroll_to_row(*xIter);
1407 xCommands.select(*xIter);
1411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */