Bump version to 6.4.7.2.M8
[LibreOffice.git] / cui / source / customize / cfgutil.cxx
blob1d94255e73eb14528049c4094a1f0de88b85686e
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/processfactory.hxx>
46 #include <comphelper/sequenceashashmap.hxx>
47 #include <svtools/imagemgr.hxx>
48 #include <sal/log.hxx>
49 #include <osl/diagnose.h>
50 #include <dialmgr.hxx>
51 #include <tools/diagnose_ex.h>
52 #include <vcl/commandinfoprovider.hxx>
53 #include <vcl/help.hxx>
54 #include <vcl/svapp.hxx>
56 using namespace ::com::sun::star;
57 using namespace ::com::sun::star::uno;
58 using namespace ::com::sun::star::script;
59 using namespace ::com::sun::star::frame;
60 using namespace ::com::sun::star::document;
62 SfxStylesInfo_Impl::SfxStylesInfo_Impl()
65 void SfxStylesInfo_Impl::init(const OUString& rModuleName, const css::uno::Reference< css::frame::XModel >& xModel)
67 m_aModuleName = rModuleName;
68 m_xDoc = xModel;
71 static const char CMDURL_STYLEPROT_ONLY[] = ".uno:StyleApply?";
72 static const char CMDURL_SPART_ONLY [] = "Style:string=";
73 static const char CMDURL_FPART_ONLY [] = "FamilyName:string=";
75 static const char STYLEPROP_UINAME[] = "DisplayName";
77 OUString SfxStylesInfo_Impl::generateCommand(const OUString& sFamily, const OUString& sStyle)
79 return ".uno:StyleApply?Style:string="
80 + sStyle
81 + "&FamilyName:string="
82 + sFamily;
85 bool SfxStylesInfo_Impl::parseStyleCommand(SfxStyleInfo_Impl& aStyle)
87 static const sal_Int32 LEN_STYLEPROT = strlen(CMDURL_STYLEPROT_ONLY);
88 static const sal_Int32 LEN_SPART = strlen(CMDURL_SPART_ONLY);
89 static const sal_Int32 LEN_FPART = strlen(CMDURL_FPART_ONLY);
91 if (!aStyle.sCommand.startsWith(CMDURL_STYLEPROT_ONLY))
92 return false;
94 aStyle.sFamily.clear();
95 aStyle.sStyle.clear();
97 sal_Int32 nCmdLen = aStyle.sCommand.getLength();
98 OUString sCmdArgs = aStyle.sCommand.copy(LEN_STYLEPROT, nCmdLen-LEN_STYLEPROT);
99 sal_Int32 i = sCmdArgs.indexOf('&');
100 if (i<0)
101 return false;
103 OUString sArg = sCmdArgs.copy(0, i);
104 if (sArg.startsWith(CMDURL_SPART_ONLY))
105 aStyle.sStyle = sArg.copy(LEN_SPART);
106 else if (sArg.startsWith(CMDURL_FPART_ONLY))
107 aStyle.sFamily = sArg.copy(LEN_FPART);
109 sArg = sCmdArgs.copy(i+1, sCmdArgs.getLength()-i-1);
110 if (sArg.startsWith(CMDURL_SPART_ONLY))
111 aStyle.sStyle = sArg.copy(LEN_SPART);
112 else if (sArg.startsWith(CMDURL_FPART_ONLY))
113 aStyle.sFamily = sArg.copy(LEN_FPART);
115 return !(aStyle.sFamily.isEmpty() || aStyle.sStyle.isEmpty());
118 void SfxStylesInfo_Impl::getLabel4Style(SfxStyleInfo_Impl& aStyle)
122 css::uno::Reference< css::style::XStyleFamiliesSupplier > xModel(m_xDoc, css::uno::UNO_QUERY);
124 css::uno::Reference< css::container::XNameAccess > xFamilies;
125 if (xModel.is())
126 xFamilies = xModel->getStyleFamilies();
128 css::uno::Reference< css::container::XNameAccess > xStyleSet;
129 if (xFamilies.is())
130 xFamilies->getByName(aStyle.sFamily) >>= xStyleSet;
132 css::uno::Reference< css::beans::XPropertySet > xStyle;
133 if (xStyleSet.is())
134 xStyleSet->getByName(aStyle.sStyle) >>= xStyle;
136 aStyle.sLabel.clear();
137 if (xStyle.is())
138 xStyle->getPropertyValue(STYLEPROP_UINAME) >>= aStyle.sLabel;
140 catch(const css::uno::RuntimeException&)
141 { throw; }
142 catch(const css::uno::Exception&)
143 { aStyle.sLabel.clear(); }
145 if (aStyle.sLabel.isEmpty())
147 aStyle.sLabel = aStyle.sCommand;
151 std::vector< SfxStyleInfo_Impl > SfxStylesInfo_Impl::getStyleFamilies() const
153 // It's an optional interface!
154 css::uno::Reference< css::style::XStyleFamiliesSupplier > xModel(m_xDoc, css::uno::UNO_QUERY);
155 if (!xModel.is())
156 return std::vector< SfxStyleInfo_Impl >();
158 css::uno::Reference< css::container::XNameAccess > xCont = xModel->getStyleFamilies();
159 const css::uno::Sequence< OUString > lFamilyNames = xCont->getElementNames();
160 std::vector< SfxStyleInfo_Impl > lFamilies;
161 for (const auto& aFamily : lFamilyNames)
163 if ((aFamily == "CellStyles" && m_aModuleName != "com.sun.star.sheet.SpreadsheetDocument") ||
164 aFamily == "cell" || aFamily == "table" || aFamily == "Default")
165 continue;
167 SfxStyleInfo_Impl aFamilyInfo;
168 aFamilyInfo.sFamily = aFamily;
172 css::uno::Reference< css::beans::XPropertySet > xFamilyInfo;
173 xCont->getByName(aFamilyInfo.sFamily) >>= xFamilyInfo;
174 if (!xFamilyInfo.is())
176 // TODO_AS currently there is no support for an UIName property .. use internal family name instead
177 aFamilyInfo.sLabel = aFamilyInfo.sFamily;
179 else
180 xFamilyInfo->getPropertyValue(STYLEPROP_UINAME) >>= aFamilyInfo.sLabel;
182 catch(const css::uno::RuntimeException&)
183 { throw; }
184 catch(const css::uno::Exception&)
185 { return std::vector< SfxStyleInfo_Impl >(); }
187 lFamilies.push_back(aFamilyInfo);
190 return lFamilies;
193 std::vector< SfxStyleInfo_Impl > SfxStylesInfo_Impl::getStyles(const OUString& sFamily)
195 css::uno::Sequence< OUString > lStyleNames;
196 css::uno::Reference< css::style::XStyleFamiliesSupplier > xModel(m_xDoc, css::uno::UNO_QUERY_THROW);
197 css::uno::Reference< css::container::XNameAccess > xFamilies = xModel->getStyleFamilies();
198 css::uno::Reference< css::container::XNameAccess > xStyleSet;
201 xFamilies->getByName(sFamily) >>= xStyleSet;
202 lStyleNames = xStyleSet->getElementNames();
204 catch(const css::uno::RuntimeException&)
205 { throw; }
206 catch(const css::uno::Exception&)
207 { return std::vector< SfxStyleInfo_Impl >(); }
209 std::vector< SfxStyleInfo_Impl > lStyles;
210 sal_Int32 c = lStyleNames.getLength();
211 sal_Int32 i = 0;
212 for (i=0; i<c; ++i)
214 SfxStyleInfo_Impl aStyleInfo;
215 aStyleInfo.sFamily = sFamily;
216 aStyleInfo.sStyle = lStyleNames[i];
217 aStyleInfo.sCommand = SfxStylesInfo_Impl::generateCommand(aStyleInfo.sFamily, aStyleInfo.sStyle);
221 css::uno::Reference< css::beans::XPropertySet > xStyle;
222 xStyleSet->getByName(aStyleInfo.sStyle) >>= xStyle;
223 if (!xStyle.is())
224 continue;
225 xStyle->getPropertyValue("DisplayName") >>= aStyleInfo.sLabel;
227 catch(const css::uno::RuntimeException&)
228 { throw; }
229 catch(const css::uno::Exception&)
230 { continue; }
232 lStyles.push_back(aStyleInfo);
234 return lStyles;
237 OUString CuiConfigFunctionListBox::GetHelpText( bool bConsiderParent )
239 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(get_selected_id().toInt64());
240 if (pData)
242 if ( pData->nKind == SfxCfgKind::FUNCTION_SLOT )
244 if (bConsiderParent)
245 return Application::GetHelp()->GetHelpText(pData->sCommand, m_xTreeView.get());
246 else
247 return Application::GetHelp()->GetHelpText(pData->sCommand, static_cast<weld::Widget*>(nullptr));
249 else if ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
251 return pData->sHelpText;
254 return OUString();
257 OUString CuiConfigFunctionListBox::GetCurCommand() const
259 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(get_selected_id().toInt64());
260 if (!pData)
261 return OUString();
262 return pData->sCommand;
265 OUString CuiConfigFunctionListBox::GetCurLabel() const
267 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(get_selected_id().toInt64());
268 if (!pData)
269 return OUString();
270 if (!pData->sLabel.isEmpty())
271 return pData->sLabel;
272 return pData->sCommand;
275 CuiConfigFunctionListBox::CuiConfigFunctionListBox(std::unique_ptr<weld::TreeView> xTreeView)
276 : m_xTreeView(std::move(xTreeView))
277 , m_xScratchIter(m_xTreeView->make_iterator())
279 m_xTreeView->make_sorted();
280 m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 35, m_xTreeView->get_height_rows(9));
283 CuiConfigFunctionListBox::~CuiConfigFunctionListBox()
285 ClearAll();
288 void CuiConfigFunctionListBox::ClearAll()
289 /* Description
290 Deletes all entries in the FunctionListBox, all UserData and all
291 possibly existing MacroInfo.
294 sal_uInt16 nCount = aArr.size();
295 for ( sal_uInt16 i=0; i<nCount; ++i )
297 SfxGroupInfo_Impl *pData = aArr[i].get();
299 if ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
301 OUString* pScriptURI = static_cast<OUString*>(pData->pObject);
302 delete pScriptURI;
305 if ( pData->nKind == SfxCfgKind::GROUP_SCRIPTCONTAINER )
307 XInterface* xi = static_cast<XInterface *>(pData->pObject);
308 if (xi != nullptr)
310 xi->release();
315 aArr.clear();
316 m_xTreeView->clear();
319 OUString CuiConfigFunctionListBox::GetSelectedScriptURI() const
321 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(get_selected_id().toInt64());
322 if (pData && pData->nKind == SfxCfgKind::FUNCTION_SCRIPT)
323 return *static_cast<OUString*>(pData->pObject);
324 return OUString();
327 struct SvxConfigGroupBoxResource_Impl
329 OUString m_sMyMacros;
330 OUString m_sProdMacros;
331 OUString m_sMacros;
332 OUString m_sDlgMacros;
333 OUString m_aStrGroupStyles;
335 SvxConfigGroupBoxResource_Impl();
338 SvxConfigGroupBoxResource_Impl::SvxConfigGroupBoxResource_Impl() :
339 m_sMyMacros(CuiResId(RID_SVXSTR_MYMACROS)),
340 m_sProdMacros(CuiResId(RID_SVXSTR_PRODMACROS)),
341 m_sMacros(CuiResId(RID_SVXSTR_BASICMACROS)),
342 m_sDlgMacros(CuiResId(RID_SVXSTR_PRODMACROS)),
343 m_aStrGroupStyles(CuiResId(RID_SVXSTR_GROUP_STYLES))
347 void CuiConfigGroupListBox::SetStylesInfo(SfxStylesInfo_Impl* pStyles)
349 m_pStylesInfo = pStyles;
352 namespace
355 /** examines a component whether it supports XEmbeddedScripts, or provides access to such a
356 component by implementing XScriptInvocationContext.
357 @return
358 the model which supports the embedded scripts, or <NULL/> if it cannot find such a
359 model
361 Reference< XModel > lcl_getDocumentWithScripts_throw( const Reference< XInterface >& _rxComponent )
363 Reference< XEmbeddedScripts > xScripts( _rxComponent, UNO_QUERY );
364 if ( !xScripts.is() )
366 Reference< XScriptInvocationContext > xContext( _rxComponent, UNO_QUERY );
367 if ( xContext.is() )
368 xScripts = xContext->getScriptContainer();
371 return Reference< XModel >( xScripts, UNO_QUERY );
375 Reference< XModel > lcl_getScriptableDocument_nothrow( const Reference< XFrame >& _rxFrame )
377 Reference< XModel > xDocument;
379 // examine our associated frame
382 OSL_ENSURE( _rxFrame.is(), "lcl_getScriptableDocument_nothrow: you need to pass a frame to this dialog/tab page!" );
383 if ( _rxFrame.is() )
385 // first try the model in the frame
386 Reference< XController > xController( _rxFrame->getController(), UNO_SET_THROW );
387 xDocument = lcl_getDocumentWithScripts_throw( xController->getModel() );
389 if ( !xDocument.is() )
391 // if there is no suitable document in the frame, try the controller
392 xDocument = lcl_getDocumentWithScripts_throw( _rxFrame->getController() );
396 catch( const Exception& )
400 return xDocument;
404 CuiConfigGroupListBox::CuiConfigGroupListBox(std::unique_ptr<weld::TreeView> xTreeView)
405 : xImp(new SvxConfigGroupBoxResource_Impl())
406 , m_pFunctionListBox(nullptr)
407 , m_pStylesInfo(nullptr)
408 , m_xTreeView(std::move(xTreeView))
410 m_xTreeView->connect_expanding(LINK(this, CuiConfigGroupListBox, ExpandingHdl));
411 m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 35, m_xTreeView->get_height_rows(9));
414 CuiConfigGroupListBox::~CuiConfigGroupListBox()
416 ClearAll();
419 void CuiConfigGroupListBox::ClearAll()
421 sal_uInt16 nCount = aArr.size();
422 for ( sal_uInt16 i=0; i<nCount; ++i )
424 SfxGroupInfo_Impl *pData = aArr[i].get();
425 if (pData->nKind == SfxCfgKind::GROUP_SCRIPTCONTAINER)
427 XInterface* xi = static_cast<XInterface *>(pData->pObject);
428 if (xi != nullptr)
430 xi->release();
435 aArr.clear();
436 m_xTreeView->clear();
439 void CuiConfigGroupListBox::InitModule()
443 css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider(m_xFrame, css::uno::UNO_QUERY_THROW);
444 css::uno::Sequence< sal_Int16 > lGroups = xProvider->getSupportedCommandGroups();
445 sal_Int32 c1 = lGroups.getLength();
446 sal_Int32 i1 = 0;
448 if ( c1 )
450 // Add All Commands category
451 aArr.push_back(std::make_unique<SfxGroupInfo_Impl>(SfxCfgKind::GROUP_ALLFUNCTIONS, 0));
452 m_xTreeView->append(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())),
453 CuiResId(RID_SVXSTR_ALLFUNCTIONS));
456 for (i1=0; i1<c1; ++i1)
458 sal_Int16& rGroupID = lGroups[i1];
459 OUString sGroupID = OUString::number(rGroupID);
460 OUString sGroupName ;
464 m_xModuleCategoryInfo->getByName(sGroupID) >>= sGroupName;
465 if (sGroupName.isEmpty())
466 continue;
468 catch(const css::container::NoSuchElementException&)
469 { continue; }
471 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_FUNCTION, rGroupID ) );
472 m_xTreeView->append(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())),
473 sGroupName);
476 catch(const css::uno::RuntimeException&)
477 { throw; }
478 catch(const css::uno::Exception&)
482 void CuiConfigGroupListBox::FillScriptList(const css::uno::Reference< css::script::browse::XBrowseNode >& xRootNode,
483 const weld::TreeIter* pParentEntry, bool bCheapChildrenOnDemand)
485 try {
486 if ( xRootNode->hasChildNodes() )
488 // tdf#120362: Don't ask to enable disabled Java when filling script list
489 css::uno::ContextLayer layer(comphelper::NoEnableJavaInteractionContext());
491 Sequence< Reference< browse::XBrowseNode > > children =
492 xRootNode->getChildNodes();
493 bool bIsRootNode = false;
495 OUString user("user");
496 OUString share("share");
497 if ( xRootNode->getName() == "Root" )
499 bIsRootNode = true;
502 //To mimic current starbasic behaviour we
503 //need to make sure that only the current document
504 //is displayed in the config tree. Tests below
505 //set the bDisplay flag to FALSE if the current
506 //node is a first level child of the Root and is NOT
507 //either the current document, user or share
508 OUString currentDocTitle;
509 Reference< XModel > xDocument( lcl_getScriptableDocument_nothrow( m_xFrame ) );
510 if ( xDocument.is() )
512 currentDocTitle = ::comphelper::DocumentInfo::getDocumentTitle( xDocument );
515 for ( sal_Int32 n = 0; n < children.getLength(); ++n )
517 Reference< browse::XBrowseNode >& theChild = children[n];
518 bool bDisplay = true;
519 OUString uiName = theChild->getName();
520 if ( bIsRootNode )
522 if ( ! (theChild->getName() == user || theChild->getName() == share ||
523 theChild->getName() == currentDocTitle ) )
525 bDisplay=false;
527 else
529 if ( uiName == user )
531 uiName = xImp->m_sMyMacros;
533 else if ( uiName == share )
535 uiName = xImp->m_sProdMacros;
539 if (children[n]->getType() != browse::BrowseNodeTypes::SCRIPT && bDisplay )
541 // We call acquire on the XBrowseNode so that it does not
542 // get autodestructed and become invalid when accessed later.
543 theChild->acquire();
545 bool bChildOnDemand = false;
546 if ( !bCheapChildrenOnDemand && children[n]->hasChildNodes() )
548 Sequence< Reference< browse::XBrowseNode > > grandchildren =
549 children[n]->getChildNodes();
551 for ( sal_Int32 m = 0; m < grandchildren.getLength(); ++m )
553 if ( grandchildren[m]->getType() == browse::BrowseNodeTypes::CONTAINER )
555 bChildOnDemand = true;
556 m = grandchildren.getLength();
560 else
562 /* i30923 - Would be nice if there was a better
563 * way to determine if a basic lib had children
564 * without having to ask for them (which forces
565 * the library to be loaded */
566 bChildOnDemand = true;
569 OUString aImage = GetImage(theChild, m_xContext, bIsRootNode);
571 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>(SfxCfgKind::GROUP_SCRIPTCONTAINER,
572 0, static_cast<void *>( theChild.get())));
574 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())));
575 m_xTreeView->insert(pParentEntry, -1, &uiName, &sId, nullptr, nullptr, &aImage, bChildOnDemand, nullptr);
580 catch (RuntimeException&) {
581 // do nothing, the entry will not be displayed in the UI
585 void CuiConfigGroupListBox::FillFunctionsList(const css::uno::Sequence<DispatchInformation>& xCommands)
587 m_pFunctionListBox->freeze();
588 for (const auto & rInfo : xCommands)
590 OUString sUIName = MapCommand2UIName(rInfo.Command);
591 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::FUNCTION_SLOT, 0 ) );
592 SfxGroupInfo_Impl* pGrpInfo = aArr.back().get();
593 pGrpInfo->sCommand = rInfo.Command;
594 pGrpInfo->sLabel = sUIName;
595 m_pFunctionListBox->append(OUString::number(reinterpret_cast<sal_Int64>(pGrpInfo)), sUIName);
597 m_pFunctionListBox->thaw();
600 void CuiConfigGroupListBox::Init(const css::uno::Reference< css::uno::XComponentContext >& xContext,
601 const css::uno::Reference< css::frame::XFrame >& xFrame,
602 const OUString& sModuleLongName,
603 bool bEventMode)
605 m_xTreeView->freeze();
606 ClearAll(); // Remove all old entries from treelist box
608 m_xContext = xContext;
609 m_xFrame = xFrame;
610 if( bEventMode )
612 m_sModuleLongName = sModuleLongName;
613 m_xGlobalCategoryInfo = css::ui::theUICategoryDescription::get( m_xContext );
614 m_xModuleCategoryInfo.set(m_xGlobalCategoryInfo->getByName(m_sModuleLongName), css::uno::UNO_QUERY_THROW);
615 m_xUICmdDescription = css::frame::theUICommandDescription::get( m_xContext );
617 InitModule();
620 SAL_INFO("cui.customize", "** ** About to initialise SF Scripts");
621 // Add Scripting Framework entries
622 Reference< browse::XBrowseNode > rootNode;
625 Reference< browse::XBrowseNodeFactory > xFac = browse::theBrowseNodeFactory::get( m_xContext );
626 rootNode.set( xFac->createView( browse::BrowseNodeFactoryViewTypes::MACROSELECTOR ) );
628 catch( const Exception& )
630 TOOLS_WARN_EXCEPTION("cui.customize", "Caught some exception whilst retrieving browse nodes from factory");
631 // TODO exception handling
635 if ( rootNode.is() )
637 if ( bEventMode )
639 //We call acquire on the XBrowseNode so that it does not
640 //get autodestructed and become invalid when accessed later.
641 rootNode->acquire();
643 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_SCRIPTCONTAINER, 0,
644 static_cast<void *>(rootNode.get())));
645 OUString aTitle(xImp->m_sDlgMacros);
646 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())));
647 m_xTreeView->insert(nullptr, -1, &aTitle, &sId, nullptr, nullptr, nullptr, true, nullptr);
649 else
651 //We are only showing scripts not slot APIs so skip
652 //Root node and show location nodes
653 FillScriptList(rootNode, nullptr, false);
657 // add styles
658 if ( bEventMode )
660 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_STYLES, 0, nullptr ) ); // TODO last parameter should contain user data
661 OUString sStyle(xImp->m_aStrGroupStyles);
662 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())));
663 m_xTreeView->insert(nullptr, -1, &sStyle, &sId, nullptr, nullptr, nullptr, true, nullptr);
666 m_xTreeView->thaw();
667 m_xTreeView->scroll_to_row(0);
668 m_xTreeView->select(0);
671 OUString CuiConfigGroupListBox::GetImage(
672 const Reference< browse::XBrowseNode >& node,
673 Reference< XComponentContext > const & xCtx,
674 bool bIsRootNode)
676 OUString aImage;
677 if ( bIsRootNode )
679 if (node->getName() == "user" || node->getName() == "share" )
681 aImage = RID_CUIBMP_HARDDISK;
683 else
685 OUString factoryURL;
686 OUString nodeName = node->getName();
687 Reference<XInterface> xDocumentModel = getDocumentModel(xCtx, nodeName );
688 if ( xDocumentModel.is() )
690 Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xCtx) );
691 // get the long name of the document:
692 OUString appModule( xModuleManager->identify(
693 xDocumentModel ) );
694 Sequence<beans::PropertyValue> moduleDescr;
695 Any aAny = xModuleManager->getByName(appModule);
696 if( !( aAny >>= moduleDescr ) )
698 throw RuntimeException("SFTreeListBox::Init: failed to get PropertyValue");
700 beans::PropertyValue const * pmoduleDescr =
701 moduleDescr.getConstArray();
702 for ( sal_Int32 pos = moduleDescr.getLength(); pos--; )
704 if ( pmoduleDescr[ pos ].Name == "ooSetupFactoryEmptyDocumentURL" )
706 pmoduleDescr[ pos ].Value >>= factoryURL;
707 SAL_INFO("cui.customize", "factory url for doc images is " << factoryURL);
708 break;
712 if( !factoryURL.isEmpty() )
714 aImage = SvFileInformationManager::GetFileImageId(INetURLObject(factoryURL));
716 else
718 aImage = RID_CUIBMP_DOC;
722 else
724 if( node->getType() == browse::BrowseNodeTypes::SCRIPT )
725 aImage = RID_CUIBMP_MACRO;
726 else
727 aImage = RID_CUIBMP_LIB;
729 return aImage;
732 Reference< XInterface >
733 CuiConfigGroupListBox::getDocumentModel( Reference< XComponentContext > const & xCtx, OUString const & docName )
735 Reference< XInterface > xModel;
736 Reference< frame::XDesktop2 > desktop = frame::Desktop::create( xCtx );
738 Reference< container::XEnumerationAccess > componentsAccess =
739 desktop->getComponents();
740 Reference< container::XEnumeration > components =
741 componentsAccess->createEnumeration();
742 while (components->hasMoreElements())
744 Reference< frame::XModel > model(
745 components->nextElement(), UNO_QUERY );
746 if ( model.is() )
748 OUString sTdocUrl =
749 ::comphelper::DocumentInfo::getDocumentTitle( model );
750 if( sTdocUrl == docName )
752 xModel = model;
753 break;
757 return xModel;
760 OUString CuiConfigGroupListBox::MapCommand2UIName(const OUString& sCommand)
762 OUString sUIName;
765 css::uno::Reference< css::container::XNameAccess > xModuleConf;
766 m_xUICmdDescription->getByName(m_sModuleLongName) >>= xModuleConf;
767 if (xModuleConf.is())
769 ::comphelper::SequenceAsHashMap lProps(xModuleConf->getByName(sCommand));
770 sUIName = lProps.getUnpackedValueOrDefault("Name", OUString());
773 catch(const css::uno::RuntimeException&)
774 { throw; }
775 catch(css::uno::Exception&)
776 { sUIName.clear(); }
778 // fallback for missing UINames !?
779 if (sUIName.isEmpty())
781 sUIName = sCommand;
784 return sUIName;
787 void CuiConfigGroupListBox::GroupSelected()
788 /* Description
789 A function group or a basic module has been selected.
790 All functions/macros are displayed in the functionlistbox.
793 std::unique_ptr<weld::TreeIter> xIter(m_xTreeView->make_iterator());
794 if (!m_xTreeView->get_selected(xIter.get()))
795 return;
797 SfxGroupInfo_Impl *pInfo = reinterpret_cast<SfxGroupInfo_Impl*>(m_xTreeView->get_id(*xIter).toInt64());
798 m_pFunctionListBox->freeze();
799 m_pFunctionListBox->ClearAll();
801 switch ( pInfo->nKind )
803 case SfxCfgKind::GROUP_ALLFUNCTIONS:
805 css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider( m_xFrame, UNO_QUERY );
806 bool bValidIter = m_xTreeView->get_iter_first(*xIter);
807 while (bValidIter)
809 SfxGroupInfo_Impl *pCurrentInfo = reinterpret_cast<SfxGroupInfo_Impl*>(m_xTreeView->get_id(*xIter).toInt64());
810 if (pCurrentInfo->nKind == SfxCfgKind::GROUP_FUNCTION)
812 css::uno::Sequence< css::frame::DispatchInformation > lCommands;
815 lCommands = xProvider->getConfigurableDispatchInformation( pCurrentInfo->nUniqueID );
816 FillFunctionsList( lCommands );
818 catch ( container::NoSuchElementException& )
822 bValidIter = m_xTreeView->iter_next(*xIter);
824 break;
827 case SfxCfgKind::GROUP_FUNCTION :
829 sal_uInt16 nGroup = pInfo->nUniqueID;
830 css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider (m_xFrame, css::uno::UNO_QUERY_THROW);
831 css::uno::Sequence< css::frame::DispatchInformation > lCommands = xProvider->getConfigurableDispatchInformation(nGroup);
832 FillFunctionsList( lCommands );
833 break;
836 case SfxCfgKind::GROUP_SCRIPTCONTAINER:
838 if (!m_xTreeView->iter_has_child(*xIter))
840 Reference< browse::XBrowseNode > rootNode(
841 static_cast< browse::XBrowseNode* >( pInfo->pObject ) ) ;
843 try {
844 if ( rootNode->hasChildNodes() )
846 Sequence< Reference< browse::XBrowseNode > > children =
847 rootNode->getChildNodes();
849 for ( sal_Int32 n = 0; n < children.getLength(); ++n )
851 if (children[n]->getType() == browse::BrowseNodeTypes::SCRIPT)
853 OUString uri, description;
855 Reference < beans::XPropertySet >xPropSet( children[n], UNO_QUERY );
856 if (!xPropSet.is())
858 continue;
861 Any value =
862 xPropSet->getPropertyValue("URI");
863 value >>= uri;
867 value = xPropSet->getPropertyValue("Description");
868 value >>= description;
870 catch (Exception &) {
871 // do nothing, the description will be empty
874 OUString* pScriptURI = new OUString( uri );
876 OUString aImage = GetImage(children[n], Reference< XComponentContext >(), false);
877 m_pFunctionListBox->aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::FUNCTION_SCRIPT, 0, pScriptURI ));
878 m_pFunctionListBox->aArr.back()->sCommand = uri;
879 m_pFunctionListBox->aArr.back()->sLabel = children[n]->getName();
880 m_pFunctionListBox->aArr.back()->sHelpText = description;
882 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_pFunctionListBox->aArr.back().get())));
883 m_pFunctionListBox->append(sId, children[n]->getName(), aImage);
888 catch (RuntimeException&) {
889 // do nothing, the entry will not be displayed in the UI
892 break;
895 case SfxCfgKind::GROUP_STYLES :
897 SfxStyleInfo_Impl* pFamily = static_cast<SfxStyleInfo_Impl*>(pInfo->pObject);
898 if (pFamily)
900 const std::vector< SfxStyleInfo_Impl > lStyles = m_pStylesInfo->getStyles(pFamily->sFamily);
901 for (auto const& lStyle : lStyles)
903 SfxStyleInfo_Impl* pStyle = new SfxStyleInfo_Impl(lStyle);
904 m_pFunctionListBox->aArr.push_back(std::make_unique<SfxGroupInfo_Impl>(SfxCfgKind::GROUP_STYLES, 0, pStyle));
905 m_pFunctionListBox->aArr.back()->sCommand = pStyle->sCommand;
906 m_pFunctionListBox->aArr.back()->sLabel = pStyle->sLabel;
907 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_pFunctionListBox->aArr.back().get())));
908 m_pFunctionListBox->append(sId, pStyle->sLabel);
911 break;
914 default:
915 // Do nothing, the list box will stay empty
916 SAL_INFO( "cui.customize", "Ignoring unexpected SfxCfgKind: " << static_cast<int>(pInfo->nKind) );
917 break;
920 m_pFunctionListBox->thaw();
922 if (m_pFunctionListBox->n_children())
923 m_pFunctionListBox->select(0);
926 /* Description
927 A basic or a library is opened.
929 IMPL_LINK(CuiConfigGroupListBox, ExpandingHdl, const weld::TreeIter&, rIter, bool)
931 SfxGroupInfo_Impl *pInfo = reinterpret_cast<SfxGroupInfo_Impl*>(m_xTreeView->get_id(rIter).toInt64());
932 switch ( pInfo->nKind )
934 case SfxCfgKind::GROUP_SCRIPTCONTAINER:
936 if (!m_xTreeView->iter_has_child(rIter))
938 Reference< browse::XBrowseNode > rootNode(
939 static_cast< browse::XBrowseNode* >( pInfo->pObject ) ) ;
940 FillScriptList(rootNode, &rIter, true /* i30923 */ );
942 break;
945 case SfxCfgKind::GROUP_STYLES:
947 if (!m_xTreeView->iter_has_child(rIter))
949 const std::vector<SfxStyleInfo_Impl> lStyleFamilies = m_pStylesInfo->getStyleFamilies();
950 for (auto const& lStyleFamily : lStyleFamilies)
952 SfxStyleInfo_Impl* pFamily = new SfxStyleInfo_Impl(lStyleFamily);
953 aArr.push_back( std::make_unique<SfxGroupInfo_Impl>( SfxCfgKind::GROUP_STYLES, 0, pFamily ));
954 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(aArr.back().get())));
955 m_xTreeView->insert(&rIter, -1, &pFamily->sLabel, &sId, nullptr, nullptr, nullptr, false, nullptr);
958 break;
961 default:
962 OSL_FAIL( "Wrong group type!" );
963 break;
965 return true;
968 void CuiConfigGroupListBox::SelectMacro( const SfxMacroInfoItem *pItem )
970 SelectMacro( pItem->GetBasicManager()->GetName(),
971 pItem->GetQualifiedName() );
974 void CuiConfigGroupListBox::SelectMacro( const OUString& rBasic,
975 const OUString& rMacro )
977 const OUString aBasicName(rBasic + " " + xImp->m_sMacros);
978 sal_Int32 nIdx {rMacro.lastIndexOf('.')};
979 const OUString aMethod( rMacro.copy(nIdx+1) );
980 OUString aLib;
981 OUString aModule;
982 if ( nIdx>0 )
984 // string contains at least 2 tokens
985 nIdx = rMacro.lastIndexOf('.', nIdx);
986 if (nIdx>=0)
988 // string contains at least 3 tokens
989 aLib = rMacro.getToken( 0, '.' );
990 aModule = rMacro.getToken( 0, '.', ++nIdx );
994 std::unique_ptr<weld::TreeIter> xIter = m_xTreeView->make_iterator();
995 if (!m_xTreeView->get_iter_first(*xIter))
996 return;
1000 OUString aEntryBas = m_xTreeView->get_text(*xIter);
1001 if (aEntryBas == aBasicName)
1003 m_xTreeView->expand_row(*xIter);
1004 std::unique_ptr<weld::TreeIter> xLibIter = m_xTreeView->make_iterator(xIter.get());
1005 if (m_xTreeView->get_iter_first(*xLibIter))
1009 OUString aEntryLib = m_xTreeView->get_text(*xLibIter);
1010 if (aEntryLib == aLib)
1012 m_xTreeView->expand_row(*xLibIter);
1013 std::unique_ptr<weld::TreeIter> xModIter = m_xTreeView->make_iterator(xLibIter.get());
1014 if (m_xTreeView->get_iter_first(*xModIter))
1018 OUString aEntryMod = m_xTreeView->get_text(*xModIter);
1019 if ( aEntryMod == aModule )
1021 m_xTreeView->expand_row(*xModIter);
1022 m_xTreeView->scroll_to_row(*xModIter);
1023 m_xTreeView->select(*xModIter);
1024 for (int i = 0, nCount = m_pFunctionListBox->n_children(); i < nCount; ++i)
1026 OUString aEntryMethod = m_pFunctionListBox->get_text(i);
1027 if (aEntryMethod == aMethod)
1029 m_pFunctionListBox->select(i);
1030 m_pFunctionListBox->scroll_to_row(i);
1031 return;
1035 } while (m_xTreeView->iter_next_sibling(*xModIter));
1038 } while (m_xTreeView->iter_next_sibling(*xLibIter));
1041 } while (m_xTreeView->iter_next_sibling(*xIter));
1045 * Implementation of SvxScriptSelectorDialog
1047 * This dialog is used for selecting Slot API commands
1048 * and Scripting Framework Scripts.
1051 SvxScriptSelectorDialog::SvxScriptSelectorDialog(
1052 weld::Window* pParent, bool bShowSlots, const css::uno::Reference< css::frame::XFrame >& xFrame)
1053 : GenericDialogController(pParent, "cui/ui/macroselectordialog.ui", "MacroSelectorDialog")
1054 , m_bShowSlots(bShowSlots)
1055 , m_xDialogDescription(m_xBuilder->weld_label(bShowSlots ? "helptoolbar" : "helpmacro"))
1056 , m_xCategories(new CuiConfigGroupListBox(m_xBuilder->weld_tree_view("categories")))
1057 , m_xCommands(new CuiConfigFunctionListBox(m_xBuilder->weld_tree_view("commands")))
1058 , m_xLibraryFT(m_xBuilder->weld_label("libraryft"))
1059 , m_xCategoryFT(m_xBuilder->weld_label("categoryft"))
1060 , m_xMacronameFT(m_xBuilder->weld_label("macronameft"))
1061 , m_xCommandsFT(m_xBuilder->weld_label("commandsft"))
1062 , m_xOKButton(m_xBuilder->weld_button(bShowSlots ? "add" : "ok"))
1063 , m_xCancelButton(m_xBuilder->weld_button(bShowSlots ? "close" : "cancel"))
1064 , m_xDescriptionText(m_xBuilder->weld_text_view("description"))
1066 if (m_bShowSlots)
1068 // If we are showing Slot API commands update labels in the UI
1069 m_xDialog->set_title(CuiResId(RID_SVXSTR_SELECTOR_ADD_COMMANDS));
1071 m_xCancelButton->show();
1072 m_xDialogDescription->show();
1073 m_xOKButton->show();
1075 m_xLibraryFT->set_visible(!m_bShowSlots);
1076 m_xCategoryFT->set_visible(m_bShowSlots);
1077 m_xMacronameFT->set_visible(!m_bShowSlots);
1078 m_xCommandsFT->set_visible(m_bShowSlots);
1080 const OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame));
1081 m_xCategories->SetFunctionListBox(m_xCommands.get());
1082 m_xCategories->Init(comphelper::getProcessComponentContext(), xFrame, aModuleName, bShowSlots);
1084 m_xCategories->connect_changed(
1085 LINK( this, SvxScriptSelectorDialog, SelectHdl ) );
1086 m_xCommands->connect_changed( LINK( this, SvxScriptSelectorDialog, SelectHdl ) );
1087 m_xCommands->connect_row_activated( LINK( this, SvxScriptSelectorDialog, FunctionDoubleClickHdl ) );
1089 m_xOKButton->connect_clicked( LINK( this, SvxScriptSelectorDialog, ClickHdl ) );
1090 m_xCancelButton->connect_clicked( LINK( this, SvxScriptSelectorDialog, ClickHdl ) );
1092 m_sDefaultDesc = m_xDescriptionText->get_text();
1094 // Support style commands
1095 uno::Reference<frame::XController> xController;
1096 uno::Reference<frame::XModel> xModel;
1097 if (xFrame.is())
1098 xController = xFrame->getController();
1099 if (xController.is())
1100 xModel = xController->getModel();
1102 m_aStylesInfo.init(aModuleName, xModel);
1103 m_xCategories->SetStylesInfo(&m_aStylesInfo);
1105 UpdateUI();
1108 SvxScriptSelectorDialog::~SvxScriptSelectorDialog()
1112 IMPL_LINK(SvxScriptSelectorDialog, SelectHdl, weld::TreeView&, rCtrl, void)
1114 if (&rCtrl == &m_xCategories->get_widget())
1116 m_xCategories->GroupSelected();
1118 UpdateUI();
1121 IMPL_LINK_NOARG(SvxScriptSelectorDialog, FunctionDoubleClickHdl, weld::TreeView&, bool)
1123 if (m_xOKButton->get_sensitive())
1124 ClickHdl(*m_xOKButton);
1125 return true;
1128 // Check if command is selected and enable the OK button accordingly
1129 // Grab the help text for this id if available and update the description field
1130 void
1131 SvxScriptSelectorDialog::UpdateUI()
1133 OUString url = GetScriptURL();
1134 if ( !url.isEmpty() )
1136 OUString sMessage = m_xCommands->GetHelpText();
1137 m_xDescriptionText->set_text(sMessage.isEmpty() ? m_sDefaultDesc : sMessage);
1139 m_xOKButton->set_sensitive(true);
1141 else
1143 m_xDescriptionText->set_text(m_sDefaultDesc);
1144 m_xOKButton->set_sensitive(false);
1148 IMPL_LINK(SvxScriptSelectorDialog, ClickHdl, weld::Button&, rButton, void)
1150 if (&rButton == m_xCancelButton.get())
1152 m_xDialog->response(RET_CANCEL);
1154 else if (&rButton == m_xOKButton.get())
1156 // If we are displaying Slot API commands then this the dialog is being
1157 // run from Tools/Configure and we should not close it
1158 if ( !m_bShowSlots )
1160 m_xDialog->response(RET_OK);
1162 else
1164 // Select the next entry in the list if possible
1165 std::unique_ptr<weld::TreeIter> xIter = m_xCommands->make_iterator();
1166 if (m_xCommands->get_selected(xIter.get()) && m_xCommands->iter_next_sibling(*xIter))
1167 m_xCommands->select(*xIter);
1172 void
1173 SvxScriptSelectorDialog::SetRunLabel()
1175 m_xOKButton->set_label(CuiResId(RID_SVXSTR_SELECTOR_RUN));
1178 OUString
1179 SvxScriptSelectorDialog::GetScriptURL() const
1181 OUString result;
1183 std::unique_ptr<weld::TreeIter> xIter = m_xCommands->make_iterator();
1184 if (m_xCommands->get_selected(xIter.get()))
1186 SfxGroupInfo_Impl *pData = reinterpret_cast<SfxGroupInfo_Impl*>(m_xCommands->get_id(*xIter).toInt64());
1187 if ( ( pData->nKind == SfxCfgKind::FUNCTION_SLOT )
1188 || ( pData->nKind == SfxCfgKind::FUNCTION_SCRIPT )
1189 || ( pData->nKind == SfxCfgKind::GROUP_STYLES )
1192 result = pData->sCommand;
1196 return result;
1199 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */