bump product version to 6.3.0.0.beta1
[LibreOffice.git] / cui / source / customize / cfgutil.cxx
blobc081a5e83394aab5a2df32acffbd1cab728d25ac
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>
21 #include <cfg.hxx>
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>
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 <svtools/imagemgr.hxx>
55 #include <rtl/ustrbuf.hxx>
56 #include <sal/log.hxx>
57 #include <osl/diagnose.h>
58 #include <unotools/configmgr.hxx>
59 #include <dialmgr.hxx>
60 #include <svl/stritem.hxx>
61 #include <vcl/commandinfoprovider.hxx>
62 #include <vcl/help.hxx>
63 #include <vcl/svapp.hxx>
64 #include <uno/current_context.hxx>
66 using namespace ::com::sun::star;
67 using namespace ::com::sun::star::uno;
68 using namespace ::com::sun::star::script;
69 using namespace ::com::sun::star::frame;
70 using namespace ::com::sun::star::document;
72 SfxStylesInfo_Impl::SfxStylesInfo_Impl()
75 void SfxStylesInfo_Impl::init(const OUString& rModuleName, const css::uno::Reference< css::frame::XModel >& xModel)
77 m_aModuleName = rModuleName;
78 m_xDoc = xModel;
81 static const char CMDURL_STYLEPROT_ONLY[] = ".uno:StyleApply?";
82 static const char CMDURL_SPART_ONLY [] = "Style:string=";
83 static const char CMDURL_FPART_ONLY [] = "FamilyName:string=";
85 static const char STYLEPROP_UINAME[] = "DisplayName";
87 OUString SfxStylesInfo_Impl::generateCommand(const OUString& sFamily, const OUString& sStyle)
89 return ".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()
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 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("DisplayName") >>= 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::GetHelpText( bool bConsiderParent )
249 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(get_selected_id().toInt64());
250 if (pData)
252 if ( pData->nKind == SfxCfgKind::FUNCTION_SLOT )
254 if (bConsiderParent)
255 return Application::GetHelp()->GetHelpText(pData->sCommand, m_xTreeView.get());
256 else
257 return Application::GetHelp()->GetHelpText(pData->sCommand, static_cast<weld::Widget*>(nullptr));
259 else if ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
261 return pData->sHelpText;
264 return OUString();
267 OUString CuiConfigFunctionListBox::GetCurCommand()
269 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(get_selected_id().toInt64());
270 if (!pData)
271 return OUString();
272 return pData->sCommand;
275 OUString CuiConfigFunctionListBox::GetCurLabel()
277 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(get_selected_id().toInt64());
278 if (!pData)
279 return OUString();
280 if (!pData->sLabel.isEmpty())
281 return pData->sLabel;
282 return pData->sCommand;
285 CuiConfigFunctionListBox::CuiConfigFunctionListBox(std::unique_ptr<weld::TreeView> xTreeView)
286 : m_xTreeView(std::move(xTreeView))
287 , m_xScratchIter(m_xTreeView->make_iterator())
289 m_xTreeView->make_sorted();
290 m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 35, m_xTreeView->get_height_rows(9));
293 CuiConfigFunctionListBox::~CuiConfigFunctionListBox()
295 ClearAll();
298 void CuiConfigFunctionListBox::ClearAll()
299 /* Description
300 Deletes all entries in the FunctionListBox, all UserData and all
301 possibly existing MacroInfo.
304 sal_uInt16 nCount = aArr.size();
305 for ( sal_uInt16 i=0; i<nCount; ++i )
307 SfxGroupInfo_Impl *pData = aArr[i].get();
309 if ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
311 OUString* pScriptURI = static_cast<OUString*>(pData->pObject);
312 delete pScriptURI;
315 if ( pData->nKind == SfxCfgKind::GROUP_SCRIPTCONTAINER )
317 XInterface* xi = static_cast<XInterface *>(pData->pObject);
318 if (xi != nullptr)
320 xi->release();
325 aArr.clear();
326 m_xTreeView->clear();
329 OUString CuiConfigFunctionListBox::GetSelectedScriptURI()
331 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(get_selected_id().toInt64());
332 if (pData && pData->nKind == SfxCfgKind::FUNCTION_SCRIPT)
333 return *static_cast<OUString*>(pData->pObject);
334 return OUString();
337 struct SvxConfigGroupBoxResource_Impl
339 OUString m_sMyMacros;
340 OUString m_sProdMacros;
341 OUString m_sMacros;
342 OUString m_sDlgMacros;
343 OUString m_aStrGroupStyles;
345 SvxConfigGroupBoxResource_Impl();
348 SvxConfigGroupBoxResource_Impl::SvxConfigGroupBoxResource_Impl() :
349 m_sMyMacros(CuiResId(RID_SVXSTR_MYMACROS)),
350 m_sProdMacros(CuiResId(RID_SVXSTR_PRODMACROS)),
351 m_sMacros(CuiResId(RID_SVXSTR_BASICMACROS)),
352 m_sDlgMacros(CuiResId(RID_SVXSTR_PRODMACROS)),
353 m_aStrGroupStyles(CuiResId(RID_SVXSTR_GROUP_STYLES))
357 void CuiConfigGroupListBox::SetStylesInfo(SfxStylesInfo_Impl* pStyles)
359 m_pStylesInfo = pStyles;
362 namespace
365 /** examines a component whether it supports XEmbeddedScripts, or provides access to such a
366 component by implementing XScriptInvocationContext.
367 @return
368 the model which supports the embedded scripts, or <NULL/> if it cannot find such a
369 model
371 Reference< XModel > lcl_getDocumentWithScripts_throw( const Reference< XInterface >& _rxComponent )
373 Reference< XEmbeddedScripts > xScripts( _rxComponent, UNO_QUERY );
374 if ( !xScripts.is() )
376 Reference< XScriptInvocationContext > xContext( _rxComponent, UNO_QUERY );
377 if ( xContext.is() )
378 xScripts.set( xContext->getScriptContainer(), UNO_QUERY );
381 return Reference< XModel >( xScripts, UNO_QUERY );
385 Reference< XModel > lcl_getScriptableDocument_nothrow( const Reference< XFrame >& _rxFrame )
387 Reference< XModel > xDocument;
389 // examine our associated frame
392 OSL_ENSURE( _rxFrame.is(), "lcl_getScriptableDocument_nothrow: you need to pass a frame to this dialog/tab page!" );
393 if ( _rxFrame.is() )
395 // first try the model in the frame
396 Reference< XController > xController( _rxFrame->getController(), UNO_SET_THROW );
397 xDocument = lcl_getDocumentWithScripts_throw( xController->getModel() );
399 if ( !xDocument.is() )
401 // if there is no suitable document in the frame, try the controller
402 xDocument = lcl_getDocumentWithScripts_throw( _rxFrame->getController() );
406 catch( const Exception& )
410 return xDocument;
414 CuiConfigGroupListBox::CuiConfigGroupListBox(std::unique_ptr<weld::TreeView> xTreeView)
415 : xImp(new SvxConfigGroupBoxResource_Impl())
416 , m_pFunctionListBox(nullptr)
417 , m_pStylesInfo(nullptr)
418 , m_xTreeView(std::move(xTreeView))
420 m_xTreeView->connect_row_activated(LINK(this, CuiConfigGroupListBox, OpenCurrentHdl));
421 m_xTreeView->connect_expanding(LINK(this, CuiConfigGroupListBox, ExpandingHdl));
422 m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 35, m_xTreeView->get_height_rows(9));
425 IMPL_LINK_NOARG(CuiConfigGroupListBox, OpenCurrentHdl, weld::TreeView&, void)
427 std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
428 bool bValidIter = m_xTreeView->get_cursor(xIter.get());
429 if (!bValidIter)
430 return;
431 if (!m_xTreeView->get_row_expanded(*xIter))
432 m_xTreeView->expand_row(*xIter);
433 else
434 m_xTreeView->collapse_row(*xIter);
437 CuiConfigGroupListBox::~CuiConfigGroupListBox()
439 ClearAll();
442 void CuiConfigGroupListBox::ClearAll()
444 sal_uInt16 nCount = aArr.size();
445 for ( sal_uInt16 i=0; i<nCount; ++i )
447 SfxGroupInfo_Impl *pData = aArr[i].get();
448 if (pData->nKind == SfxCfgKind::GROUP_SCRIPTCONTAINER)
450 XInterface* xi = static_cast<XInterface *>(pData->pObject);
451 if (xi != nullptr)
453 xi->release();
458 aArr.clear();
459 m_xTreeView->clear();
462 void CuiConfigGroupListBox::InitModule()
466 css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider(m_xFrame, css::uno::UNO_QUERY_THROW);
467 css::uno::Sequence< sal_Int16 > lGroups = xProvider->getSupportedCommandGroups();
468 sal_Int32 c1 = lGroups.getLength();
469 sal_Int32 i1 = 0;
471 if ( c1 )
473 // Add All Commands category
474 aArr.push_back(std::make_unique<SfxGroupInfo_Impl>(SfxCfgKind::GROUP_ALLFUNCTIONS, 0));
475 m_xTreeView->append(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())),
476 CuiResId(RID_SVXSTR_ALLFUNCTIONS));
479 for (i1=0; i1<c1; ++i1)
481 sal_Int16& rGroupID = lGroups[i1];
482 OUString sGroupID = OUString::number(rGroupID);
483 OUString sGroupName ;
487 m_xModuleCategoryInfo->getByName(sGroupID) >>= sGroupName;
488 if (sGroupName.isEmpty())
489 continue;
491 catch(const css::container::NoSuchElementException&)
492 { continue; }
494 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_FUNCTION, rGroupID ) );
495 m_xTreeView->append(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())),
496 sGroupName);
499 catch(const css::uno::RuntimeException&)
500 { throw; }
501 catch(const css::uno::Exception&)
505 void CuiConfigGroupListBox::FillScriptList(const css::uno::Reference< css::script::browse::XBrowseNode >& xRootNode,
506 const weld::TreeIter* pParentEntry, bool bCheapChildrenOnDemand)
508 try {
509 if ( xRootNode->hasChildNodes() )
511 // tdf#120362: Don't ask to enable disabled Java when filling script list
512 css::uno::ContextLayer layer(
513 new comphelper::NoEnableJavaInteractionContext(css::uno::getCurrentContext()));
515 Sequence< Reference< browse::XBrowseNode > > children =
516 xRootNode->getChildNodes();
517 bool bIsRootNode = false;
519 OUString user("user");
520 OUString share("share");
521 if ( xRootNode->getName() == "Root" )
523 bIsRootNode = true;
526 //To mimic current starbasic behaviour we
527 //need to make sure that only the current document
528 //is displayed in the config tree. Tests below
529 //set the bDisplay flag to FALSE if the current
530 //node is a first level child of the Root and is NOT
531 //either the current document, user or share
532 OUString currentDocTitle;
533 Reference< XModel > xDocument( lcl_getScriptableDocument_nothrow( m_xFrame ) );
534 if ( xDocument.is() )
536 currentDocTitle = ::comphelper::DocumentInfo::getDocumentTitle( xDocument );
539 for ( sal_Int32 n = 0; n < children.getLength(); ++n )
541 Reference< browse::XBrowseNode >& theChild = children[n];
542 bool bDisplay = true;
543 OUString uiName = theChild->getName();
544 if ( bIsRootNode )
546 if ( ! (theChild->getName() == user || theChild->getName() == share ||
547 theChild->getName() == currentDocTitle ) )
549 bDisplay=false;
551 else
553 if ( uiName == user )
555 uiName = xImp->m_sMyMacros;
557 else if ( uiName == share )
559 uiName = xImp->m_sProdMacros;
563 if (children[n]->getType() != browse::BrowseNodeTypes::SCRIPT && bDisplay )
565 // We call acquire on the XBrowseNode so that it does not
566 // get autodestructed and become invalid when accessed later.
567 theChild->acquire();
569 bool bChildOnDemand = false;
570 if ( !bCheapChildrenOnDemand && children[n]->hasChildNodes() )
572 Sequence< Reference< browse::XBrowseNode > > grandchildren =
573 children[n]->getChildNodes();
575 for ( sal_Int32 m = 0; m < grandchildren.getLength(); ++m )
577 if ( grandchildren[m]->getType() == browse::BrowseNodeTypes::CONTAINER )
579 bChildOnDemand = true;
580 m = grandchildren.getLength();
584 else
586 /* i30923 - Would be nice if there was a better
587 * way to determine if a basic lib had children
588 * without having to ask for them (which forces
589 * the library to be loaded */
590 bChildOnDemand = true;
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(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())));
599 m_xTreeView->insert(pParentEntry, -1, &uiName, &sId, nullptr, nullptr, &aImage, bChildOnDemand, nullptr);
604 catch (RuntimeException&) {
605 // do nothing, the entry will not be displayed in the UI
609 void CuiConfigGroupListBox::FillFunctionsList(const css::uno::Sequence<DispatchInformation>& xCommands)
611 m_pFunctionListBox->freeze();
612 for (const auto & rInfo : xCommands)
614 OUString sUIName = MapCommand2UIName(rInfo.Command);
615 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::FUNCTION_SLOT, 0 ) );
616 SfxGroupInfo_Impl* pGrpInfo = aArr.back().get();
617 pGrpInfo->sCommand = rInfo.Command;
618 pGrpInfo->sLabel = sUIName;
619 m_pFunctionListBox->append(OUString::number(reinterpret_cast<sal_Int64>(pGrpInfo)), sUIName);
621 m_pFunctionListBox->thaw();
624 void CuiConfigGroupListBox::Init(const css::uno::Reference< css::uno::XComponentContext >& xContext,
625 const css::uno::Reference< css::frame::XFrame >& xFrame,
626 const OUString& sModuleLongName,
627 bool bEventMode)
629 m_xTreeView->freeze();
630 ClearAll(); // Remove all old entries from treelist box
632 m_xContext = xContext;
633 m_xFrame = xFrame;
634 if( bEventMode )
636 m_sModuleLongName = sModuleLongName;
637 m_xGlobalCategoryInfo = css::ui::theUICategoryDescription::get( m_xContext );
638 m_xModuleCategoryInfo.set(m_xGlobalCategoryInfo->getByName(m_sModuleLongName), css::uno::UNO_QUERY_THROW);
639 m_xUICmdDescription = css::frame::theUICommandDescription::get( m_xContext );
641 InitModule();
644 SAL_INFO("cui.customize", "** ** About to initialise SF Scripts");
645 // Add Scripting Framework entries
646 Reference< browse::XBrowseNode > rootNode;
649 Reference< browse::XBrowseNodeFactory > xFac = browse::theBrowseNodeFactory::get( m_xContext );
650 rootNode.set( xFac->createView( browse::BrowseNodeFactoryViewTypes::MACROSELECTOR ) );
652 catch( Exception& e )
654 SAL_INFO("cui.customize", "Caught some exception whilst retrieving browse nodes from factory... Exception: " << e);
655 // TODO exception handling
659 if ( rootNode.is() )
661 if ( bEventMode )
663 //We call acquire on the XBrowseNode so that it does not
664 //get autodestructed and become invalid when accessed later.
665 rootNode->acquire();
667 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_SCRIPTCONTAINER, 0,
668 static_cast<void *>(rootNode.get())));
669 OUString aTitle(xImp->m_sDlgMacros);
670 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())));
671 m_xTreeView->insert(nullptr, -1, &aTitle, &sId, nullptr, nullptr, nullptr, true, nullptr);
673 else
675 //We are only showing scripts not slot APIs so skip
676 //Root node and show location nodes
677 FillScriptList(rootNode, nullptr, false);
681 // add styles
682 if ( bEventMode )
684 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_STYLES, 0, nullptr ) ); // TODO last parameter should contain user data
685 OUString sStyle(xImp->m_aStrGroupStyles);
686 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())));
687 m_xTreeView->insert(nullptr, -1, &sStyle, &sId, nullptr, nullptr, nullptr, true, nullptr);
690 m_xTreeView->thaw();
691 m_xTreeView->scroll_to_row(0);
692 m_xTreeView->select(0);
695 OUString CuiConfigGroupListBox::GetImage(
696 const Reference< browse::XBrowseNode >& node,
697 Reference< XComponentContext > const & xCtx,
698 bool bIsRootNode)
700 OUString aImage;
701 if ( bIsRootNode )
703 if (node->getName() == "user" || node->getName() == "share" )
705 aImage = RID_CUIBMP_HARDDISK;
707 else
709 OUString factoryURL;
710 OUString nodeName = node->getName();
711 Reference<XInterface> xDocumentModel = getDocumentModel(xCtx, nodeName );
712 if ( xDocumentModel.is() )
714 Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xCtx) );
715 // get the long name of the document:
716 OUString appModule( xModuleManager->identify(
717 xDocumentModel ) );
718 Sequence<beans::PropertyValue> moduleDescr;
719 Any aAny = xModuleManager->getByName(appModule);
720 if( !( aAny >>= moduleDescr ) )
722 throw RuntimeException("SFTreeListBox::Init: failed to get PropertyValue");
724 beans::PropertyValue const * pmoduleDescr =
725 moduleDescr.getConstArray();
726 for ( sal_Int32 pos = moduleDescr.getLength(); pos--; )
728 if ( pmoduleDescr[ pos ].Name == "ooSetupFactoryEmptyDocumentURL" )
730 pmoduleDescr[ pos ].Value >>= factoryURL;
731 SAL_INFO("cui.customize", "factory url for doc images is " << factoryURL);
732 break;
736 if( !factoryURL.isEmpty() )
738 aImage = SvFileInformationManager::GetFileImageId(INetURLObject(factoryURL));
740 else
742 aImage = RID_CUIBMP_DOC;
746 else
748 if( node->getType() == browse::BrowseNodeTypes::SCRIPT )
749 aImage = RID_CUIBMP_MACRO;
750 else
751 aImage = RID_CUIBMP_LIB;
753 return aImage;
756 Reference< XInterface >
757 CuiConfigGroupListBox::getDocumentModel( Reference< XComponentContext > const & xCtx, OUString const & docName )
759 Reference< XInterface > xModel;
760 Reference< frame::XDesktop2 > desktop = frame::Desktop::create( xCtx );
762 Reference< container::XEnumerationAccess > componentsAccess =
763 desktop->getComponents();
764 Reference< container::XEnumeration > components =
765 componentsAccess->createEnumeration();
766 while (components->hasMoreElements())
768 Reference< frame::XModel > model(
769 components->nextElement(), UNO_QUERY );
770 if ( model.is() )
772 OUString sTdocUrl =
773 ::comphelper::DocumentInfo::getDocumentTitle( model );
774 if( sTdocUrl == docName )
776 xModel = model;
777 break;
781 return xModel;
784 OUString CuiConfigGroupListBox::MapCommand2UIName(const OUString& sCommand)
786 OUString sUIName;
789 css::uno::Reference< css::container::XNameAccess > xModuleConf;
790 m_xUICmdDescription->getByName(m_sModuleLongName) >>= xModuleConf;
791 if (xModuleConf.is())
793 ::comphelper::SequenceAsHashMap lProps(xModuleConf->getByName(sCommand));
794 sUIName = lProps.getUnpackedValueOrDefault("Name", OUString());
797 catch(const css::uno::RuntimeException&)
798 { throw; }
799 catch(css::uno::Exception&)
800 { sUIName.clear(); }
802 // fallback for missing UINames !?
803 if (sUIName.isEmpty())
805 sUIName = sCommand;
808 return sUIName;
811 void CuiConfigGroupListBox::GroupSelected()
812 /* Description
813 A function group or a basic module has been selected.
814 All functions/macros are displayed in the functionlistbox.
817 std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
818 if (!m_xTreeView->get_selected(xIter.get()))
819 return;
821 SfxGroupInfo_Impl *pInfo = reinterpret_cast<SfxGroupInfo_Impl*>(m_xTreeView->get_id(*xIter).toInt64());
822 m_pFunctionListBox->freeze();
823 m_pFunctionListBox->ClearAll();
825 switch ( pInfo->nKind )
827 case SfxCfgKind::GROUP_ALLFUNCTIONS:
829 css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider( m_xFrame, UNO_QUERY );
830 bool bValidIter = m_xTreeView->get_iter_first(*xIter);
831 while (bValidIter)
833 SfxGroupInfo_Impl *pCurrentInfo = reinterpret_cast<SfxGroupInfo_Impl*>(m_xTreeView->get_id(*xIter).toInt64());
834 if (pCurrentInfo->nKind == SfxCfgKind::GROUP_FUNCTION)
836 css::uno::Sequence< css::frame::DispatchInformation > lCommands;
839 lCommands = xProvider->getConfigurableDispatchInformation( pCurrentInfo->nUniqueID );
840 FillFunctionsList( lCommands );
842 catch ( container::NoSuchElementException& )
846 bValidIter = m_xTreeView->iter_next(*xIter);
848 break;
851 case SfxCfgKind::GROUP_FUNCTION :
853 sal_uInt16 nGroup = pInfo->nUniqueID;
854 css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider (m_xFrame, css::uno::UNO_QUERY_THROW);
855 css::uno::Sequence< css::frame::DispatchInformation > lCommands = xProvider->getConfigurableDispatchInformation(nGroup);
856 FillFunctionsList( lCommands );
857 break;
860 case SfxCfgKind::GROUP_SCRIPTCONTAINER:
862 if (!m_xTreeView->iter_has_child(*xIter))
864 Reference< browse::XBrowseNode > rootNode(
865 static_cast< browse::XBrowseNode* >( pInfo->pObject ) ) ;
867 try {
868 if ( rootNode->hasChildNodes() )
870 Sequence< Reference< browse::XBrowseNode > > children =
871 rootNode->getChildNodes();
873 for ( sal_Int32 n = 0; n < children.getLength(); ++n )
875 if (children[n]->getType() == browse::BrowseNodeTypes::SCRIPT)
877 OUString uri, description;
879 Reference < beans::XPropertySet >xPropSet( children[n], UNO_QUERY );
880 if (!xPropSet.is())
882 continue;
885 Any value =
886 xPropSet->getPropertyValue("URI");
887 value >>= uri;
891 value = xPropSet->getPropertyValue("Description");
892 value >>= description;
894 catch (Exception &) {
895 // do nothing, the description will be empty
898 OUString* pScriptURI = new OUString( uri );
900 OUString aImage = GetImage(children[n], Reference< XComponentContext >(), false);
901 m_pFunctionListBox->aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::FUNCTION_SCRIPT, 0, pScriptURI ));
902 m_pFunctionListBox->aArr.back()->sCommand = uri;
903 m_pFunctionListBox->aArr.back()->sLabel = children[n]->getName();
904 m_pFunctionListBox->aArr.back()->sHelpText = description;
906 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_pFunctionListBox->aArr.back().get())));
907 m_pFunctionListBox->append(sId, children[n]->getName(), aImage);
912 catch (RuntimeException&) {
913 // do nothing, the entry will not be displayed in the UI
916 break;
919 case SfxCfgKind::GROUP_STYLES :
921 SfxStyleInfo_Impl* pFamily = static_cast<SfxStyleInfo_Impl*>(pInfo->pObject);
922 if (pFamily)
924 const std::vector< SfxStyleInfo_Impl > lStyles = m_pStylesInfo->getStyles(pFamily->sFamily);
925 for (auto const& lStyle : lStyles)
927 SfxStyleInfo_Impl* pStyle = new SfxStyleInfo_Impl(lStyle);
928 m_pFunctionListBox->aArr.push_back(std::make_unique<SfxGroupInfo_Impl>(SfxCfgKind::GROUP_STYLES, 0, pStyle));
929 m_pFunctionListBox->aArr.back()->sCommand = pStyle->sCommand;
930 m_pFunctionListBox->aArr.back()->sLabel = pStyle->sLabel;
931 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_pFunctionListBox->aArr.back().get())));
932 m_pFunctionListBox->append(sId, pStyle->sLabel);
935 break;
938 default:
939 // Do nothing, the list box will stay empty
940 SAL_INFO( "cui.customize", "Ignoring unexpected SfxCfgKind: " << static_cast<int>(pInfo->nKind) );
941 break;
944 m_pFunctionListBox->thaw();
946 if (m_pFunctionListBox->n_children())
947 m_pFunctionListBox->select(0);
950 /* Description
951 A basic or a library is opened.
953 IMPL_LINK(CuiConfigGroupListBox, ExpandingHdl, const weld::TreeIter&, rIter, bool)
955 SfxGroupInfo_Impl *pInfo = reinterpret_cast<SfxGroupInfo_Impl*>(m_xTreeView->get_id(rIter).toInt64());
956 switch ( pInfo->nKind )
958 case SfxCfgKind::GROUP_SCRIPTCONTAINER:
960 if (!m_xTreeView->iter_has_child(rIter))
962 Reference< browse::XBrowseNode > rootNode(
963 static_cast< browse::XBrowseNode* >( pInfo->pObject ) ) ;
964 FillScriptList(rootNode, &rIter, true /* i30923 */ );
966 break;
969 case SfxCfgKind::GROUP_STYLES:
971 if (!m_xTreeView->iter_has_child(rIter))
973 const std::vector<SfxStyleInfo_Impl> lStyleFamilies = m_pStylesInfo->getStyleFamilies();
974 for (auto const& lStyleFamily : lStyleFamilies)
976 SfxStyleInfo_Impl* pFamily = new SfxStyleInfo_Impl(lStyleFamily);
977 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_STYLES, 0, pFamily ));
978 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())));
979 m_xTreeView->insert(&rIter, -1, &pFamily->sLabel, &sId, nullptr, nullptr, nullptr, false, nullptr);
982 break;
985 default:
986 OSL_FAIL( "Wrong group type!" );
987 break;
989 return true;
992 void CuiConfigGroupListBox::SelectMacro( const SfxMacroInfoItem *pItem )
994 SelectMacro( pItem->GetBasicManager()->GetName(),
995 pItem->GetQualifiedName() );
998 void CuiConfigGroupListBox::SelectMacro( const OUString& rBasic,
999 const OUString& rMacro )
1001 const OUString aBasicName(rBasic + " " + xImp->m_sMacros);
1002 sal_Int32 nIdx {rMacro.lastIndexOf('.')};
1003 const OUString aMethod( rMacro.copy(nIdx+1) );
1004 OUString aLib;
1005 OUString aModule;
1006 if ( nIdx>0 )
1008 // string contains at least 2 tokens
1009 nIdx = rMacro.lastIndexOf('.', nIdx);
1010 if (nIdx>=0)
1012 // string contains at least 3 tokens
1013 aLib = rMacro.getToken( 0, '.' );
1014 aModule = rMacro.getToken( 0, '.', ++nIdx );
1018 std::unique_ptr<weld::TreeIter> xIter = m_xTreeView->make_iterator();
1019 if (!m_xTreeView->get_iter_first(*xIter))
1020 return;
1024 OUString aEntryBas = m_xTreeView->get_text(*xIter);
1025 if (aEntryBas == aBasicName)
1027 m_xTreeView->expand_row(*xIter);
1028 std::unique_ptr<weld::TreeIter> xLibIter = m_xTreeView->make_iterator(xIter.get());
1029 if (m_xTreeView->get_iter_first(*xLibIter))
1033 OUString aEntryLib = m_xTreeView->get_text(*xLibIter);
1034 if (aEntryLib == aLib)
1036 m_xTreeView->expand_row(*xLibIter);
1037 std::unique_ptr<weld::TreeIter> xModIter = m_xTreeView->make_iterator(xLibIter.get());
1038 if (m_xTreeView->get_iter_first(*xModIter))
1042 OUString aEntryMod = m_xTreeView->get_text(*xModIter);
1043 if ( aEntryMod == aModule )
1045 m_xTreeView->expand_row(*xModIter);
1046 m_xTreeView->scroll_to_row(*xModIter);
1047 m_xTreeView->select(*xModIter);
1048 for (int i = 0, nCount = m_pFunctionListBox->n_children(); i < nCount; ++i)
1050 OUString aEntryMethod = m_pFunctionListBox->get_text(i);
1051 if (aEntryMethod == aMethod)
1053 m_pFunctionListBox->select(i);
1054 m_pFunctionListBox->scroll_to_row(i);
1055 return;
1059 } while (m_xTreeView->iter_next_sibling(*xModIter));
1062 } while (m_xTreeView->iter_next_sibling(*xLibIter));
1065 } while (m_xTreeView->iter_next_sibling(*xIter));
1069 * Implementation of SvxScriptSelectorDialog
1071 * This dialog is used for selecting Slot API commands
1072 * and Scripting Framework Scripts.
1075 SvxScriptSelectorDialog::SvxScriptSelectorDialog(
1076 weld::Window* pParent, bool bShowSlots, const css::uno::Reference< css::frame::XFrame >& xFrame)
1077 : GenericDialogController(pParent, "cui/ui/macroselectordialog.ui", "MacroSelectorDialog")
1078 , m_bShowSlots(bShowSlots)
1079 , m_xDialogDescription(m_xBuilder->weld_label(bShowSlots ? "helptoolbar" : "helpmacro"))
1080 , m_xCategories(new CuiConfigGroupListBox(m_xBuilder->weld_tree_view("categories")))
1081 , m_xCommands(new CuiConfigFunctionListBox(m_xBuilder->weld_tree_view("commands")))
1082 , m_xLibraryFT(m_xBuilder->weld_label("libraryft"))
1083 , m_xCategoryFT(m_xBuilder->weld_label("categoryft"))
1084 , m_xMacronameFT(m_xBuilder->weld_label("macronameft"))
1085 , m_xCommandsFT(m_xBuilder->weld_label("commandsft"))
1086 , m_xOKButton(m_xBuilder->weld_button(bShowSlots ? "add" : "ok"))
1087 , m_xCancelButton(m_xBuilder->weld_button(bShowSlots ? "close" : "cancel"))
1088 , m_xDescriptionText(m_xBuilder->weld_text_view("description"))
1090 if (m_bShowSlots)
1092 // If we are showing Slot API commands update labels in the UI
1093 m_xDialog->set_title(CuiResId(RID_SVXSTR_SELECTOR_ADD_COMMANDS));
1095 m_xCancelButton->show();
1096 m_xDialogDescription->show();
1097 m_xOKButton->show();
1099 m_xLibraryFT->set_visible(!m_bShowSlots);
1100 m_xCategoryFT->set_visible(m_bShowSlots);
1101 m_xMacronameFT->set_visible(!m_bShowSlots);
1102 m_xCommandsFT->set_visible(m_bShowSlots);
1104 const OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame));
1105 m_xCategories->SetFunctionListBox(m_xCommands.get());
1106 m_xCategories->Init(comphelper::getProcessComponentContext(), xFrame, aModuleName, bShowSlots);
1108 m_xCategories->connect_changed(
1109 LINK( this, SvxScriptSelectorDialog, SelectHdl ) );
1110 m_xCommands->connect_changed( LINK( this, SvxScriptSelectorDialog, SelectHdl ) );
1111 m_xCommands->connect_row_activated( LINK( this, SvxScriptSelectorDialog, FunctionDoubleClickHdl ) );
1113 m_xOKButton->connect_clicked( LINK( this, SvxScriptSelectorDialog, ClickHdl ) );
1114 m_xCancelButton->connect_clicked( LINK( this, SvxScriptSelectorDialog, ClickHdl ) );
1116 m_sDefaultDesc = m_xDescriptionText->get_text();
1118 // Support style commands
1119 uno::Reference<frame::XController> xController;
1120 uno::Reference<frame::XModel> xModel;
1121 if (xFrame.is())
1122 xController = xFrame->getController();
1123 if (xController.is())
1124 xModel = xController->getModel();
1126 m_aStylesInfo.init(aModuleName, xModel);
1127 m_xCategories->SetStylesInfo(&m_aStylesInfo);
1129 UpdateUI();
1132 SvxScriptSelectorDialog::~SvxScriptSelectorDialog()
1136 IMPL_LINK(SvxScriptSelectorDialog, SelectHdl, weld::TreeView&, rCtrl, void)
1138 if (&rCtrl == &m_xCategories->get_widget())
1140 m_xCategories->GroupSelected();
1142 UpdateUI();
1145 IMPL_LINK_NOARG(SvxScriptSelectorDialog, FunctionDoubleClickHdl, weld::TreeView&, void)
1147 if (m_xOKButton->get_sensitive())
1148 ClickHdl(*m_xOKButton);
1151 // Check if command is selected and enable the OK button accordingly
1152 // Grab the help text for this id if available and update the description field
1153 void
1154 SvxScriptSelectorDialog::UpdateUI()
1156 OUString url = GetScriptURL();
1157 if ( !url.isEmpty() )
1159 OUString sMessage = m_xCommands->GetHelpText();
1160 m_xDescriptionText->set_text(sMessage.isEmpty() ? m_sDefaultDesc : sMessage);
1162 m_xOKButton->set_sensitive(true);
1164 else
1166 m_xDescriptionText->set_text(m_sDefaultDesc);
1167 m_xOKButton->set_sensitive(false);
1171 IMPL_LINK(SvxScriptSelectorDialog, ClickHdl, weld::Button&, rButton, void)
1173 if (&rButton == m_xCancelButton.get())
1175 m_xDialog->response(RET_CANCEL);
1177 else if (&rButton == m_xOKButton.get())
1179 // If we are displaying Slot API commands then this the dialog is being
1180 // run from Tools/Configure and we should not close it
1181 if ( !m_bShowSlots )
1183 m_xDialog->response(RET_OK);
1185 else
1187 // Select the next entry in the list if possible
1188 std::unique_ptr<weld::TreeIter> xIter = m_xCommands->make_iterator();
1189 if (m_xCommands->get_selected(xIter.get()) && m_xCommands->iter_next_sibling(*xIter))
1190 m_xCommands->select(*xIter);
1195 void
1196 SvxScriptSelectorDialog::SetRunLabel()
1198 m_xOKButton->set_label(CuiResId(RID_SVXSTR_SELECTOR_RUN));
1201 OUString
1202 SvxScriptSelectorDialog::GetScriptURL() const
1204 OUString result;
1206 std::unique_ptr<weld::TreeIter> xIter = m_xCommands->make_iterator();
1207 if (m_xCommands->get_selected(xIter.get()))
1209 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(m_xCommands->get_id(*xIter).toInt64());
1210 if ( ( pData->nKind == SfxCfgKind::FUNCTION_SLOT )
1211 || ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
1212 || ( pData->nKind == SfxCfgKind::GROUP_STYLES )
1215 result = pData->sCommand;
1219 return result;
1222 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */