xref: /core/cui/source/dialogs/scriptdlg.cxx (revision d628258f)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <memory>
21 #include <utility>
22 
23 #include <sal/log.hxx>
24 #include <sfx2/objsh.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/weld.hxx>
27 
28 #include <strings.hrc>
29 #include <bitmaps.hlst>
30 #include <scriptdlg.hxx>
31 #include <dialmgr.hxx>
32 
33 #include <com/sun/star/uno/XComponentContext.hpp>
34 #include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
35 #include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
36 #include <com/sun/star/script/provider/XScriptProvider.hpp>
37 #include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
38 #include <com/sun/star/script/browse/XBrowseNodeFactory.hpp>
39 #include <com/sun/star/script/browse/BrowseNodeFactoryViewTypes.hpp>
40 #include <com/sun/star/script/browse/theBrowseNodeFactory.hpp>
41 #include <com/sun/star/script/provider/ScriptErrorRaisedException.hpp>
42 #include <com/sun/star/script/provider/ScriptExceptionRaisedException.hpp>
43 #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
44 #include <com/sun/star/frame/Desktop.hpp>
45 #include <com/sun/star/frame/ModuleManager.hpp>
46 #include <com/sun/star/script/XInvocation.hpp>
47 #include <com/sun/star/document/XEmbeddedScripts.hpp>
48 
49 #include <comphelper/SetFlagContextHelper.hxx>
50 #include <comphelper/documentinfo.hxx>
51 #include <comphelper/processfactory.hxx>
52 
53 #include <svtools/imagemgr.hxx>
54 #include <tools/urlobj.hxx>
55 #include <tools/diagnose_ex.h>
56 
57 using namespace ::com::sun::star;
58 using namespace css::uno;
59 using namespace css::script;
60 using namespace css::frame;
61 using namespace css::document;
62 
63 static void ShowErrorDialog( const Any& aException )
64 {
65     ScopedVclPtrInstance<SvxScriptErrorDialog> pDlg( aException );
66     pDlg->Execute();
67 }
68 
69 void SvxScriptOrgDialog::delUserData(const weld::TreeIter& rIter)
70 {
71     SFEntry* pUserData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rIter).toInt64());
72     if (pUserData)
73     {
74         delete pUserData;
75         // TBD seem to get a Select event on node that is remove ( below )
76         // so need to be able to detect that this node is not to be
77         // processed in order to do this, setting userData to NULL ( must
78         // be a better way to do this )
79         m_xScriptsBox->set_id(rIter, OUString());
80     }
81 }
82 
83 void SvxScriptOrgDialog::deleteTree(weld::TreeIter& rIter)
84 {
85     delUserData(rIter);
86     std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator(&rIter);
87     if (!m_xScriptsBox->iter_children(*xIter))
88         return;
89 
90     std::unique_ptr<weld::TreeIter> xAltIter = m_xScriptsBox->make_iterator();
91     bool bNextEntry;
92     do
93     {
94         m_xScriptsBox->copy_iterator(*xIter, *xAltIter);
95         bNextEntry = m_xScriptsBox->iter_next_sibling(*xAltIter);
96         deleteTree(*xIter);
97         m_xScriptsBox->remove(*xIter);
98         m_xScriptsBox->copy_iterator(*xAltIter, *xIter);
99     }
100     while (bNextEntry);
101 }
102 
103 void SvxScriptOrgDialog::deleteAllTree()
104 {
105     std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
106     if (!m_xScriptsBox->get_iter_first(*xIter))
107         return;
108 
109     std::unique_ptr<weld::TreeIter> xAltIter = m_xScriptsBox->make_iterator();
110     // TBD - below is a candidate for a destroyAllTrees method
111     bool bNextEntry;
112     do
113     {
114         m_xScriptsBox->copy_iterator(*xIter, *xAltIter);
115         bNextEntry = m_xScriptsBox->iter_next_sibling(*xAltIter);
116         deleteTree(*xIter);
117         m_xScriptsBox->remove(*xIter);
118         m_xScriptsBox->copy_iterator(*xAltIter, *xIter);
119     }
120     while (bNextEntry);
121 }
122 
123 void SvxScriptOrgDialog::Init( const OUString& language  )
124 {
125     m_xScriptsBox->freeze();
126 
127     deleteAllTree();
128 
129     Reference< browse::XBrowseNode > rootNode;
130     Reference< XComponentContext > xCtx(
131         comphelper::getProcessComponentContext() );
132 
133     Sequence< Reference< browse::XBrowseNode > > children;
134 
135     OUString userStr("user");
136     OUString const shareStr("share");
137 
138     try
139     {
140         Reference< browse::XBrowseNodeFactory > xFac = browse::theBrowseNodeFactory::get(xCtx);
141 
142         rootNode.set( xFac->createView(
143             browse::BrowseNodeFactoryViewTypes::MACROORGANIZER ) );
144 
145         if (  rootNode.is() && rootNode->hasChildNodes() )
146         {
147             children = rootNode->getChildNodes();
148         }
149     }
150     catch( const Exception& )
151     {
152         TOOLS_WARN_EXCEPTION("cui.dialogs", "Exception getting root browse node from factory");
153         // TODO exception handling
154     }
155 
156     Reference<XModel> xDocumentModel;
157     for ( sal_Int32 n = 0; n < children.getLength(); n++ )
158     {
159         bool app = false;
160         OUString uiName = children[ n ]->getName();
161         OUString factoryURL;
162         if ( uiName == userStr || uiName == shareStr )
163         {
164             app = true;
165             if ( uiName == userStr )
166             {
167                 uiName = m_sMyMacros;
168             }
169             else
170             {
171                 uiName = m_sProdMacros;
172             }
173         }
174         else
175         {
176             xDocumentModel.set(getDocumentModel(xCtx, uiName ), UNO_QUERY);
177 
178             if ( xDocumentModel.is() )
179             {
180                 Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xCtx) );
181 
182                 // get the long name of the document:
183                 Sequence<beans::PropertyValue> moduleDescr;
184                 try{
185                     OUString appModule = xModuleManager->identify( xDocumentModel );
186                     xModuleManager->getByName(appModule) >>= moduleDescr;
187                 } catch(const uno::Exception&)
188                     {}
189 
190                 beans::PropertyValue const * pmoduleDescr =
191                     moduleDescr.getConstArray();
192                 for ( sal_Int32 pos = moduleDescr.getLength(); pos--; )
193                 {
194                     if ( pmoduleDescr[ pos ].Name == "ooSetupFactoryEmptyDocumentURL" )
195                     {
196                         pmoduleDescr[ pos ].Value >>= factoryURL;
197                         break;
198                     }
199                 }
200             }
201         }
202 
203         Reference< browse::XBrowseNode > langEntries =
204             getLangNodeFromRootNode( children[ n ], language );
205 
206         insertEntry( uiName, app ? OUStringLiteral(RID_CUIBMP_HARDDISK) : OUStringLiteral(RID_CUIBMP_DOC),
207             nullptr, true, std::make_unique< SFEntry >( langEntries, xDocumentModel ), factoryURL, false );
208     }
209 
210     m_xScriptsBox->thaw();
211 }
212 
213 Reference< XInterface  >
214 SvxScriptOrgDialog::getDocumentModel( Reference< XComponentContext > const & xCtx, OUString const & docName )
215 {
216     Reference< XInterface > xModel;
217     Reference< frame::XDesktop2 > desktop  = frame::Desktop::create(xCtx);
218 
219     Reference< container::XEnumerationAccess > componentsAccess =
220         desktop->getComponents();
221     Reference< container::XEnumeration > components =
222         componentsAccess->createEnumeration();
223     while (components->hasMoreElements())
224     {
225         Reference< frame::XModel > model(
226             components->nextElement(), UNO_QUERY );
227         if ( model.is() )
228         {
229             OUString sTdocUrl = ::comphelper::DocumentInfo::getDocumentTitle( model );
230             if( sTdocUrl == docName )
231             {
232                 xModel = model;
233                 break;
234             }
235         }
236     }
237     return xModel;
238 }
239 
240 Reference< browse::XBrowseNode >
241 SvxScriptOrgDialog::getLangNodeFromRootNode( Reference< browse::XBrowseNode > const & rootNode, OUString const & language )
242 {
243     Reference< browse::XBrowseNode > langNode;
244 
245     try
246     {
247         auto tryFind = [&] {
248             const Sequence<Reference<browse::XBrowseNode>> children = rootNode->getChildNodes();
249             const auto it = std::find_if(children.begin(), children.end(),
250                                          [&](const Reference<browse::XBrowseNode>& child) {
251                                              return child->getName() == language;
252                                          });
253             return (it != children.end()) ? *it : nullptr;
254         };
255         {
256             // First try without Java interaction, to avoid warnings for non-JRE-dependent providers
257             css::uno::ContextLayer layer(comphelper::NoEnableJavaInteractionContext());
258             langNode = tryFind();
259         }
260         if (!langNode)
261         {
262             // Now try with Java interaction enabled
263             langNode = tryFind();
264         }
265     }
266     catch ( Exception& )
267     {
268         // if getChildNodes() throws an exception we just return
269         // the empty Reference
270     }
271     return langNode;
272 }
273 
274 void SvxScriptOrgDialog::RequestSubEntries(const weld::TreeIter& rRootEntry, Reference< css::script::browse::XBrowseNode > const & node,
275                                            Reference< XModel >& model)
276 {
277     if (!node.is())
278     {
279         return;
280     }
281 
282     Sequence< Reference< browse::XBrowseNode > > children;
283     try
284     {
285         children = node->getChildNodes();
286     }
287     catch ( Exception& )
288     {
289         // if we catch an exception in getChildNodes then no entries are added
290     }
291 
292     for ( sal_Int32 n = 0; n < children.getLength(); n++ )
293     {
294         OUString name( children[ n ]->getName() );
295         if (  children[ n ]->getType() !=  browse::BrowseNodeTypes::SCRIPT)
296         {
297             insertEntry(name, RID_CUIBMP_LIB, &rRootEntry, true, std::make_unique<SFEntry>(children[n], model), false);
298         }
299         else
300         {
301             insertEntry(name, RID_CUIBMP_MACRO, &rRootEntry, false, std::make_unique<SFEntry>(children[n], model), false);
302         }
303     }
304 }
305 
306 void SvxScriptOrgDialog::insertEntry(const OUString& rText, const OUString& rBitmap,
307     const weld::TreeIter* pParent, bool bChildrenOnDemand, std::unique_ptr<SFEntry> && aUserData,
308     const OUString& factoryURL, bool bSelect)
309 {
310     if (rBitmap == RID_CUIBMP_DOC && !factoryURL.isEmpty())
311     {
312         OUString aImage = SvFileInformationManager::GetFileImageId(INetURLObject(factoryURL));
313         insertEntry(rText, aImage, pParent, bChildrenOnDemand, std::move(aUserData), bSelect);
314         return;
315     }
316     insertEntry(rText, rBitmap, pParent, bChildrenOnDemand, std::move(aUserData), bSelect);
317 }
318 
319 void SvxScriptOrgDialog::insertEntry(
320     const OUString& rText, const OUString& rBitmap, const weld::TreeIter* pParent,
321     bool bChildrenOnDemand, std::unique_ptr<SFEntry> && aUserData, bool bSelect)
322 {
323     std::unique_ptr<weld::TreeIter> xRetIter;
324     if (bSelect)
325         xRetIter = m_xScriptsBox->make_iterator();
326     OUString sId(OUString::number(reinterpret_cast<sal_Int64>(aUserData.release()))); // XXX possible leak
327     m_xScriptsBox->insert(pParent, -1, &rText, &sId, nullptr, nullptr, &rBitmap,
328                           bChildrenOnDemand, xRetIter.get());
329     if (bSelect)
330     {
331         m_xScriptsBox->set_cursor(*xRetIter);
332         m_xScriptsBox->select(*xRetIter);
333     }
334 }
335 
336 IMPL_LINK(SvxScriptOrgDialog, ExpandingHdl, const weld::TreeIter&, rIter, bool)
337 {
338     SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rIter).toInt64());
339 
340     Reference< browse::XBrowseNode > node;
341     Reference< XModel > model;
342     if ( userData && !userData->isLoaded() )
343     {
344         node = userData->GetNode();
345         model = userData->GetModel();
346         RequestSubEntries(rIter, node, model);
347         userData->setLoaded();
348     }
349 
350     return true;
351 }
352 
353 // CuiInputDialog ------------------------------------------------------------
354 CuiInputDialog::CuiInputDialog(weld::Window * pParent, InputDialogMode nMode)
355     : GenericDialogController(pParent, "cui/ui/newlibdialog.ui", "NewLibDialog")
356     , m_xEdit(m_xBuilder->weld_entry("entry"))
357 {
358     m_xEdit->grab_focus();
359 
360     std::unique_ptr<weld::Label> xNewLibFT(m_xBuilder->weld_label("newlibft"));
361 
362     if ( nMode == InputDialogMode::NEWMACRO )
363     {
364         xNewLibFT->hide();
365         std::unique_ptr<weld::Label> xNewMacroFT(m_xBuilder->weld_label("newmacroft"));
366         xNewMacroFT->show();
367         std::unique_ptr<weld::Label> xAltTitle(m_xBuilder->weld_label("altmacrotitle"));
368         m_xDialog->set_title(xAltTitle->get_label());
369     }
370     else if ( nMode == InputDialogMode::RENAME )
371     {
372         xNewLibFT->hide();
373         std::unique_ptr<weld::Label> xRenameFT(m_xBuilder->weld_label("renameft"));
374         xRenameFT->show();
375         std::unique_ptr<weld::Label> xAltTitle(m_xBuilder->weld_label("altrenametitle"));
376         m_xDialog->set_title(xAltTitle->get_label());
377     }
378 }
379 
380 // ScriptOrgDialog ------------------------------------------------------------
381 
382 SvxScriptOrgDialog::SvxScriptOrgDialog(weld::Window* pParent, const OUString& language)
383     : SfxDialogController(pParent, "cui/ui/scriptorganizer.ui", "ScriptOrganizerDialog")
384     , m_sLanguage(language)
385     , m_delErrStr(CuiResId(RID_SVXSTR_DELFAILED))
386     , m_delErrTitleStr(CuiResId(RID_SVXSTR_DELFAILED_TITLE))
387     , m_delQueryStr(CuiResId(RID_SVXSTR_DELQUERY))
388     , m_delQueryTitleStr(CuiResId(RID_SVXSTR_DELQUERY_TITLE))
389     , m_createErrStr(CuiResId(RID_SVXSTR_CREATEFAILED))
390     , m_createDupStr(CuiResId(RID_SVXSTR_CREATEFAILEDDUP))
391     , m_createErrTitleStr(CuiResId(RID_SVXSTR_CREATEFAILED_TITLE))
392     , m_renameErrStr(CuiResId(RID_SVXSTR_RENAMEFAILED))
393     , m_renameErrTitleStr(CuiResId(RID_SVXSTR_RENAMEFAILED_TITLE))
394     , m_sMyMacros(CuiResId(RID_SVXSTR_MYMACROS))
395     , m_sProdMacros(CuiResId(RID_SVXSTR_PRODMACROS))
396     , m_xScriptsBox(m_xBuilder->weld_tree_view("scripts"))
397     , m_xRunButton(m_xBuilder->weld_button("ok"))
398     , m_xCloseButton(m_xBuilder->weld_button("close"))
399     , m_xCreateButton(m_xBuilder->weld_button("create"))
400     , m_xEditButton(m_xBuilder->weld_button("edit"))
401     , m_xRenameButton(m_xBuilder->weld_button("rename"))
402     , m_xDelButton(m_xBuilder->weld_button("delete"))
403 {
404     // must be a neater way to deal with the strings than as above
405     // append the language to the dialog title
406     OUString winTitle(m_xDialog->get_title());
407     winTitle = winTitle.replaceFirst( "%MACROLANG", m_sLanguage );
408     m_xDialog->set_title(winTitle);
409 
410     m_xScriptsBox->set_size_request(m_xScriptsBox->get_approximate_digit_width() * 45,
411                                     m_xScriptsBox->get_height_rows(12));
412 
413     m_xScriptsBox->connect_changed( LINK( this, SvxScriptOrgDialog, ScriptSelectHdl ) );
414     m_xScriptsBox->connect_expanding(LINK( this, SvxScriptOrgDialog, ExpandingHdl ) );
415     m_xRunButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
416     m_xCloseButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
417     m_xRenameButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
418     m_xEditButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
419     m_xDelButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
420     m_xCreateButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
421 
422     m_xRunButton->set_sensitive(false);
423     m_xRenameButton->set_sensitive(false);
424     m_xEditButton->set_sensitive(false);
425     m_xDelButton->set_sensitive(false);
426     m_xCreateButton->set_sensitive(false);
427 
428     Init(m_sLanguage);
429     RestorePreviousSelection();
430 }
431 
432 SvxScriptOrgDialog::~SvxScriptOrgDialog()
433 {
434     deleteAllTree();
435 }
436 
437 short SvxScriptOrgDialog::run()
438 {
439     SfxObjectShell *pDoc = SfxObjectShell::GetFirst();
440 
441     // force load of MSPs for all documents
442     while ( pDoc )
443     {
444         Reference< provider::XScriptProviderSupplier > xSPS( pDoc->GetModel(), UNO_QUERY );
445         if ( xSPS.is() )
446         {
447             xSPS->getScriptProvider();
448         }
449 
450         pDoc = SfxObjectShell::GetNext(*pDoc);
451     }
452 
453     return SfxDialogController::run();
454 }
455 
456 void SvxScriptOrgDialog::CheckButtons( Reference< browse::XBrowseNode > const & node )
457 {
458     if ( node.is() )
459     {
460         if ( node->getType() == browse::BrowseNodeTypes::SCRIPT)
461         {
462             m_xRunButton->set_sensitive(true);
463         }
464         else
465         {
466             m_xRunButton->set_sensitive(false);
467         }
468         Reference< beans::XPropertySet > xProps( node, UNO_QUERY );
469 
470         if ( !xProps.is() )
471         {
472             m_xEditButton->set_sensitive(false);
473             m_xDelButton->set_sensitive(false);
474             m_xCreateButton->set_sensitive(false);
475             m_xRunButton->set_sensitive(false);
476             return;
477         }
478 
479         OUString sName("Editable");
480 
481         if ( getBoolProperty( xProps, sName ) )
482         {
483             m_xEditButton->set_sensitive(true);
484         }
485         else
486         {
487             m_xEditButton->set_sensitive(false);
488         }
489 
490         sName = "Deletable";
491 
492         if ( getBoolProperty( xProps, sName ) )
493         {
494             m_xDelButton->set_sensitive(true);
495         }
496         else
497         {
498             m_xDelButton->set_sensitive(false);
499         }
500 
501         sName = "Creatable";
502 
503         if ( getBoolProperty( xProps, sName ) )
504         {
505             m_xCreateButton->set_sensitive(true);
506         }
507         else
508         {
509             m_xCreateButton->set_sensitive(false);
510         }
511 
512         sName = "Renamable";
513 
514         if ( getBoolProperty( xProps, sName ) )
515         {
516             m_xRenameButton->set_sensitive(true);
517         }
518         else
519         {
520             m_xRenameButton->set_sensitive(false);
521         }
522     }
523     else
524     {
525         // no node info available, disable all configurable actions
526         m_xDelButton->set_sensitive(false);
527         m_xCreateButton->set_sensitive(false);
528         m_xEditButton->set_sensitive(false);
529         m_xRunButton->set_sensitive(false);
530         m_xRenameButton->set_sensitive(false);
531     }
532 }
533 
534 IMPL_LINK_NOARG(SvxScriptOrgDialog, ScriptSelectHdl, weld::TreeView&, void)
535 {
536     std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
537     if (!m_xScriptsBox->get_selected(xIter.get()))
538         return;
539 
540     SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(*xIter).toInt64());
541 
542     Reference< browse::XBrowseNode > node;
543     if (userData)
544     {
545         node = userData->GetNode();
546         CheckButtons(node);
547     }
548 }
549 
550 IMPL_LINK(SvxScriptOrgDialog, ButtonHdl, weld::Button&, rButton, void)
551 {
552     if ( &rButton == m_xCloseButton.get() )
553     {
554         StoreCurrentSelection();
555         m_xDialog->response(RET_CANCEL);
556     }
557     if (&rButton == m_xEditButton.get() ||
558         &rButton == m_xCreateButton.get() ||
559         &rButton == m_xDelButton.get() ||
560         &rButton == m_xRunButton.get() ||
561         &rButton == m_xRenameButton.get())
562 
563     {
564         std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
565         if (!m_xScriptsBox->get_selected(xIter.get()))
566             return;
567         SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(*xIter).toInt64());
568         if (!userData)
569             return;
570 
571         Reference< browse::XBrowseNode > node;
572         Reference< XModel > xModel;
573 
574         node = userData->GetNode();
575         xModel = userData->GetModel();
576 
577         if ( !node.is() )
578         {
579             return;
580         }
581 
582         if (&rButton == m_xRunButton.get())
583         {
584             OUString tmpString;
585             Reference< beans::XPropertySet > xProp( node, UNO_QUERY );
586             Reference< provider::XScriptProvider > mspNode;
587             if( !xProp.is() )
588             {
589                 return;
590             }
591 
592             if ( xModel.is() )
593             {
594                 Reference< XEmbeddedScripts >  xEmbeddedScripts( xModel, UNO_QUERY);
595                 if( !xEmbeddedScripts.is() )
596                 {
597                     return;
598                 }
599 
600                 if (!xEmbeddedScripts->getAllowMacroExecution())
601                 {
602                     // Please FIXME: Show a message box if AllowMacroExecution is false
603                     return;
604                 }
605             }
606 
607             std::unique_ptr<weld::TreeIter> xParentIter = m_xScriptsBox->make_iterator(xIter.get());
608             bool bParent = m_xScriptsBox->iter_parent(*xParentIter);
609             while (bParent && !mspNode.is() )
610             {
611                 SFEntry* mspUserData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(*xParentIter).toInt64());
612                 mspNode.set( mspUserData->GetNode() , UNO_QUERY );
613                 bParent = m_xScriptsBox->iter_parent(*xParentIter);
614             }
615             xProp->getPropertyValue("URI") >>= tmpString;
616             const OUString scriptURL( tmpString );
617 
618             if ( mspNode.is() )
619             {
620                 try
621                 {
622                     Reference< provider::XScript > xScript(
623                         mspNode->getScript( scriptURL ), UNO_SET_THROW );
624 
625                     const Sequence< Any > args(0);
626                     Sequence< sal_Int16 > outIndex;
627                     Sequence< Any > outArgs( 0 );
628                     xScript->invoke( args, outIndex, outArgs );
629                 }
630                 catch ( reflection::InvocationTargetException& ite )
631                 {
632                     ShowErrorDialog(css::uno::Any(ite));
633                 }
634                 catch ( provider::ScriptFrameworkErrorException& ite )
635                 {
636                     ShowErrorDialog(css::uno::Any(ite));
637                 }
638                 catch ( RuntimeException& re )
639                 {
640                     ShowErrorDialog(css::uno::Any(re));
641                 }
642                 catch ( Exception& e )
643                 {
644                     ShowErrorDialog(css::uno::Any(e));
645                 }
646             }
647             StoreCurrentSelection();
648             m_xDialog->response(RET_CANCEL);
649         }
650         else if ( &rButton == m_xEditButton.get() )
651         {
652             Reference< script::XInvocation > xInv( node, UNO_QUERY );
653             if ( xInv.is() )
654             {
655                 StoreCurrentSelection();
656                 m_xDialog->response(RET_CANCEL);
657                 Sequence< Any > args(0);
658                 Sequence< Any > outArgs( 0 );
659                 Sequence< sal_Int16 > outIndex;
660                 try
661                 {
662                     // ISSUE need code to run script here
663                     xInv->invoke( "Editable", args, outIndex, outArgs );
664                 }
665                 catch( Exception const & )
666                 {
667                     TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to invoke" );
668                 }
669             }
670         }
671         else if ( &rButton == m_xCreateButton.get() )
672         {
673             createEntry(*xIter);
674         }
675         else if ( &rButton == m_xDelButton.get() )
676         {
677             deleteEntry(*xIter);
678         }
679         else if ( &rButton == m_xRenameButton.get() )
680         {
681             renameEntry(*xIter);
682         }
683     }
684 }
685 
686 Reference< browse::XBrowseNode > SvxScriptOrgDialog::getBrowseNode(const weld::TreeIter& rEntry)
687 {
688     Reference< browse::XBrowseNode > node;
689     SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rEntry).toInt64());
690     if (userData)
691     {
692         node = userData->GetNode();
693     }
694     return node;
695 }
696 
697 Reference< XModel > SvxScriptOrgDialog::getModel(const weld::TreeIter& rEntry)
698 {
699     Reference< XModel > model;
700     SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rEntry).toInt64());
701     if ( userData )
702     {
703         model = userData->GetModel();
704     }
705     return model;
706 }
707 
708 void SvxScriptOrgDialog::createEntry(weld::TreeIter& rEntry)
709 {
710 
711     Reference< browse::XBrowseNode >  aChildNode;
712     Reference< browse::XBrowseNode > node = getBrowseNode( rEntry );
713     Reference< script::XInvocation > xInv( node, UNO_QUERY );
714 
715     if ( xInv.is() )
716     {
717         OUString aNewName;
718         OUString aNewStdName;
719         InputDialogMode nMode = InputDialogMode::NEWLIB;
720         if (m_xScriptsBox->get_iter_depth(rEntry) == 0)
721         {
722             aNewStdName = "Library" ;
723         }
724         else
725         {
726             aNewStdName = "Macro" ;
727             nMode = InputDialogMode::NEWMACRO;
728         }
729         //do we need L10N for this? ie something like:
730         //String aNewStdName( ResId( STR_STDMODULENAME ) );
731         bool bValid = false;
732         sal_Int32 i = 1;
733 
734         Sequence< Reference< browse::XBrowseNode > > childNodes;
735         // no children => ok to create Parcel1 or Script1 without checking
736         try
737         {
738             if( !node->hasChildNodes() )
739             {
740                 aNewName = aNewStdName + OUString::number(i);
741                 bValid = true;
742             }
743             else
744             {
745                 childNodes = node->getChildNodes();
746             }
747         }
748         catch ( Exception& )
749         {
750             // ignore, will continue on with empty sequence
751         }
752 
753         OUString extn;
754         while ( !bValid )
755         {
756             aNewName = aNewStdName + OUString::number(i);
757             bool bFound = false;
758             if(childNodes.hasElements() )
759             {
760                 OUString nodeName = childNodes[0]->getName();
761                 sal_Int32 extnPos = nodeName.lastIndexOf( '.' );
762                 if(extnPos>0)
763                     extn = nodeName.copy(extnPos);
764             }
765             for( sal_Int32 index = 0; index < childNodes.getLength(); index++ )
766             {
767                 if (aNewName+extn == childNodes[index]->getName())
768                 {
769                     bFound = true;
770                     break;
771                 }
772             }
773             if( bFound )
774             {
775                 i++;
776             }
777             else
778             {
779                 bValid = true;
780             }
781         }
782 
783         CuiInputDialog aNewDlg(m_xDialog.get(), nMode);
784         aNewDlg.SetObjectName(aNewName);
785 
786         do
787         {
788             if (aNewDlg.run() && !aNewDlg.GetObjectName().isEmpty())
789             {
790                 OUString aUserSuppliedName = aNewDlg.GetObjectName();
791                 bValid = true;
792                 for( sal_Int32 index = 0; index < childNodes.getLength(); index++ )
793                 {
794                     if (aUserSuppliedName+extn == childNodes[index]->getName())
795                     {
796                         bValid = false;
797                         OUString aError = m_createErrStr + m_createDupStr;
798 
799                         std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
800                                                                        VclMessageType::Warning, VclButtonsType::Ok, aError));
801                         xErrorBox->set_title(m_createErrTitleStr);
802                         xErrorBox->run();
803                         aNewDlg.SetObjectName(aNewName);
804                         break;
805                     }
806                 }
807                 if( bValid )
808                     aNewName = aUserSuppliedName;
809             }
810             else
811             {
812                 // user hit cancel or hit OK with nothing in the editbox
813 
814                 return;
815             }
816         }
817         while ( !bValid );
818 
819         // open up parent node (which ensures it's loaded)
820         m_xScriptsBox->expand_row(rEntry);
821 
822         Sequence< Any > args( 1 );
823         args[ 0 ] <<= aNewName;
824         Sequence< Any > outArgs( 0 );
825         Sequence< sal_Int16 > outIndex;
826         try
827         {
828             Any aResult = xInv->invoke( "Creatable", args, outIndex, outArgs );
829             Reference< browse::XBrowseNode > newNode( aResult, UNO_QUERY );
830             aChildNode = newNode;
831 
832         }
833         catch( Exception const & )
834         {
835             TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Create" );
836         }
837     }
838     if ( aChildNode.is() )
839     {
840         OUString aChildName = aChildNode->getName();
841 
842         Reference<XModel> xDocumentModel = getModel( rEntry );
843 
844         // ISSUE do we need to remove all entries for parent
845         // to achieve sort? Just need to determine position
846         // -- Basic doesn't do this on create.
847         // Suppose we could avoid this too. -> created nodes are
848         // not in alphabetical order
849         if ( aChildNode->getType() == browse::BrowseNodeTypes::SCRIPT )
850         {
851             insertEntry(aChildName, RID_CUIBMP_MACRO, &rEntry, false,
852                         std::make_unique<SFEntry>(aChildNode,xDocumentModel), true);
853         }
854         else
855         {
856             insertEntry(aChildName, RID_CUIBMP_LIB, &rEntry, false,
857                         std::make_unique<SFEntry>(aChildNode,xDocumentModel), true);
858 
859             // If the Parent is not loaded then set to
860             // loaded, this will prevent RequestingChildren ( called
861             // from vcl via RequestingChildren ) from
862             // creating new ( duplicate ) children
863             SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rEntry).toInt64());
864             if ( userData &&  !userData->isLoaded() )
865             {
866                 userData->setLoaded();
867             }
868         }
869     }
870     else
871     {
872         //ISSUE L10N & message from exception?
873         OUString aError( m_createErrStr );
874         std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
875                                                        VclMessageType::Warning, VclButtonsType::Ok, aError));
876         xErrorBox->set_title(m_createErrTitleStr);
877         xErrorBox->run();
878     }
879 }
880 
881 void SvxScriptOrgDialog::renameEntry(const weld::TreeIter& rEntry)
882 {
883 
884     Reference< browse::XBrowseNode >  aChildNode;
885     Reference< browse::XBrowseNode > node = getBrowseNode(rEntry);
886     Reference< script::XInvocation > xInv( node, UNO_QUERY );
887 
888     if ( xInv.is() )
889     {
890         OUString aNewName = node->getName();
891         sal_Int32 extnPos = aNewName.lastIndexOf( '.' );
892         if(extnPos>0)
893         {
894             aNewName = aNewName.copy(0,extnPos);
895         }
896         CuiInputDialog aNewDlg(m_xDialog.get(), InputDialogMode::RENAME);
897         aNewDlg.SetObjectName(aNewName);
898 
899         if (!aNewDlg.run() || aNewDlg.GetObjectName().isEmpty())
900             return; // user hit cancel or hit OK with nothing in the editbox
901 
902         aNewName = aNewDlg.GetObjectName();
903 
904         Sequence< Any > args( 1 );
905         args[ 0 ] <<= aNewName;
906         Sequence< Any > outArgs( 0 );
907         Sequence< sal_Int16 > outIndex;
908         try
909         {
910             Any aResult = xInv->invoke( "Renamable", args, outIndex, outArgs );
911             Reference< browse::XBrowseNode > newNode( aResult, UNO_QUERY );
912             aChildNode = newNode;
913 
914         }
915         catch( Exception const & )
916         {
917             TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Rename" );
918         }
919     }
920     if ( aChildNode.is() )
921     {
922         m_xScriptsBox->set_text(rEntry, aChildNode->getName());
923         m_xScriptsBox->set_cursor(rEntry);
924         m_xScriptsBox->select(rEntry);
925 
926     }
927     else
928     {
929         //ISSUE L10N & message from exception?
930         OUString aError( m_renameErrStr );
931         std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
932                                                        VclMessageType::Warning, VclButtonsType::Ok, aError));
933         xErrorBox->set_title(m_renameErrTitleStr);
934         xErrorBox->run();
935     }
936 }
937 
938 void SvxScriptOrgDialog::deleteEntry(weld::TreeIter& rEntry)
939 {
940     bool result = false;
941     Reference< browse::XBrowseNode > node = getBrowseNode(rEntry);
942     // ISSUE L10N string & can we centre list?
943     OUString aQuery = m_delQueryStr + getListOfChildren( node, 0 );
944     std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(),
945                                                    VclMessageType::Question, VclButtonsType::YesNo, aQuery));
946     xQueryBox->set_title(m_delQueryTitleStr);
947     if (xQueryBox->run() == RET_NO)
948     {
949         return;
950     }
951 
952     Reference< script::XInvocation > xInv( node, UNO_QUERY );
953     if ( xInv.is() )
954     {
955         Sequence< Any > args( 0 );
956         Sequence< Any > outArgs( 0 );
957         Sequence< sal_Int16 > outIndex;
958         try
959         {
960             Any aResult = xInv->invoke( "Deletable", args, outIndex, outArgs );
961             aResult >>= result; // or do we just assume true if no exception ?
962         }
963         catch( Exception const & )
964         {
965             TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to delete" );
966         }
967     }
968 
969     if ( result )
970     {
971         deleteTree(rEntry);
972         m_xScriptsBox->remove(rEntry);
973     }
974     else
975     {
976         //ISSUE L10N & message from exception?
977         std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
978                                                        VclMessageType::Warning, VclButtonsType::Ok, m_delErrStr));
979         xErrorBox->set_title(m_delErrTitleStr);
980         xErrorBox->run();
981     }
982 
983 }
984 
985 bool SvxScriptOrgDialog::getBoolProperty( Reference< beans::XPropertySet > const & xProps,
986                 OUString const & propName )
987 {
988     bool result = false;
989     try
990     {
991         xProps->getPropertyValue( propName ) >>= result;
992     }
993     catch ( Exception& )
994     {
995         return result;
996     }
997     return result;
998 }
999 
1000 OUString SvxScriptOrgDialog::getListOfChildren( const Reference< browse::XBrowseNode >& node, int depth )
1001 {
1002     OUStringBuffer result = "\n";
1003     for( int i=0;i<=depth;i++ )
1004     {
1005         result.append("\t");
1006     }
1007     result.append(node->getName());
1008 
1009     try
1010     {
1011         if ( node->hasChildNodes() )
1012         {
1013             Sequence< Reference< browse::XBrowseNode > > children
1014                 = node->getChildNodes();
1015             for ( sal_Int32 n = 0; n < children.getLength(); n++ )
1016             {
1017                 result.append( getListOfChildren( children[ n ] , depth+1 ) );
1018             }
1019         }
1020     }
1021     catch ( Exception& )
1022     {
1023         // ignore, will return an empty string
1024     }
1025 
1026     return result.makeStringAndClear();
1027 }
1028 
1029 Selection_hash SvxScriptOrgDialog::m_lastSelection;
1030 
1031 void SvxScriptOrgDialog::StoreCurrentSelection()
1032 {
1033     std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
1034     if (!m_xScriptsBox->get_selected(xIter.get()))
1035         return;
1036     OUString aDescription;
1037     bool bEntry;
1038     do
1039     {
1040         aDescription = m_xScriptsBox->get_text(*xIter) + aDescription;
1041         bEntry = m_xScriptsBox->iter_parent(*xIter);
1042         if (bEntry)
1043             aDescription = ";" + aDescription;
1044     }
1045     while (bEntry);
1046     OUString sDesc( aDescription );
1047     m_lastSelection[ m_sLanguage ] = sDesc;
1048 }
1049 
1050 void SvxScriptOrgDialog::RestorePreviousSelection()
1051 {
1052     OUString aStoredEntry = m_lastSelection[ m_sLanguage ];
1053     if( aStoredEntry.isEmpty() )
1054         return;
1055     std::unique_ptr<weld::TreeIter> xEntry;
1056     std::unique_ptr<weld::TreeIter> xTmpEntry(m_xScriptsBox->make_iterator());
1057     sal_Int32 nIndex = 0;
1058     while (nIndex != -1)
1059     {
1060         OUString aTmp( aStoredEntry.getToken( 0, ';', nIndex ) );
1061 
1062         bool bTmpEntry;
1063         if (!xEntry)
1064         {
1065             xEntry = m_xScriptsBox->make_iterator();
1066             bTmpEntry = m_xScriptsBox->get_iter_first(*xEntry);
1067             m_xScriptsBox->copy_iterator(*xEntry, *xTmpEntry);
1068         }
1069         else
1070         {
1071             m_xScriptsBox->copy_iterator(*xEntry, *xTmpEntry);
1072             bTmpEntry = m_xScriptsBox->iter_children(*xTmpEntry);
1073         }
1074 
1075         while (bTmpEntry)
1076         {
1077             if (m_xScriptsBox->get_text(*xTmpEntry) == aTmp)
1078             {
1079                 m_xScriptsBox->copy_iterator(*xTmpEntry, *xEntry);
1080                 break;
1081             }
1082             bTmpEntry = m_xScriptsBox->iter_next_sibling(*xTmpEntry);
1083         }
1084 
1085         if (!bTmpEntry)
1086             break;
1087 
1088         m_xScriptsBox->expand_row(*xEntry);
1089     }
1090 
1091     if (xEntry)
1092         m_xScriptsBox->set_cursor(*xEntry);
1093 }
1094 
1095 namespace {
1096 
1097 OUString ReplaceString(
1098     const OUString& source,
1099     const OUString& token,
1100     const OUString& value )
1101 {
1102     sal_Int32 pos = source.indexOf( token );
1103 
1104     if ( pos != -1 && !value.isEmpty() )
1105     {
1106         return source.replaceAt( pos, token.getLength(), value );
1107     }
1108     else
1109     {
1110         return source;
1111     }
1112 }
1113 
1114 OUString FormatErrorString(
1115     const OUString& unformatted,
1116     const OUString& language,
1117     const OUString& script,
1118     const OUString& line,
1119     const OUString& type,
1120     const OUString& message )
1121 {
1122     OUString result = unformatted.copy( 0 );
1123 
1124     result = ReplaceString(result, "%LANGUAGENAME", language );
1125     result = ReplaceString(result, "%SCRIPTNAME", script );
1126     result = ReplaceString(result, "%LINENUMBER", line );
1127 
1128     if ( !type.isEmpty() )
1129     {
1130         result += "\n\n" + CuiResId(RID_SVXSTR_ERROR_TYPE_LABEL) + " " + type;
1131     }
1132 
1133     if ( !message.isEmpty() )
1134     {
1135         result += "\n\n" + CuiResId(RID_SVXSTR_ERROR_MESSAGE_LABEL) + " " + message;
1136     }
1137 
1138     return result;
1139 }
1140 
1141 OUString GetErrorMessage(
1142     const provider::ScriptErrorRaisedException& eScriptError )
1143 {
1144     OUString unformatted = CuiResId( RID_SVXSTR_ERROR_AT_LINE );
1145 
1146     OUString unknown("UNKNOWN");
1147     OUString language = unknown;
1148     OUString script = unknown;
1149     OUString line = unknown;
1150     OUString type = "";
1151     OUString message = eScriptError.Message;
1152 
1153     if ( !eScriptError.language.isEmpty() )
1154     {
1155         language = eScriptError.language;
1156     }
1157 
1158     if ( !eScriptError.scriptName.isEmpty() )
1159     {
1160         script = eScriptError.scriptName;
1161     }
1162 
1163     if ( !eScriptError.Message.isEmpty() )
1164     {
1165         message = eScriptError.Message;
1166     }
1167     if ( eScriptError.lineNum != -1 )
1168     {
1169         line = OUString::number( eScriptError.lineNum );
1170         unformatted = CuiResId( RID_SVXSTR_ERROR_AT_LINE );
1171     }
1172     else
1173     {
1174         unformatted = CuiResId( RID_SVXSTR_ERROR_RUNNING );
1175     }
1176 
1177     return FormatErrorString(
1178         unformatted, language, script, line, type, message );
1179 }
1180 
1181 OUString GetErrorMessage(
1182     const provider::ScriptExceptionRaisedException& eScriptException )
1183 {
1184     OUString unformatted = CuiResId( RID_SVXSTR_EXCEPTION_AT_LINE );
1185 
1186     OUString unknown("UNKNOWN");
1187     OUString language = unknown;
1188     OUString script = unknown;
1189     OUString line = unknown;
1190     OUString type = unknown;
1191     OUString message = eScriptException.Message;
1192 
1193     if ( !eScriptException.language.isEmpty() )
1194     {
1195         language = eScriptException.language;
1196     }
1197     if ( !eScriptException.scriptName.isEmpty() )
1198     {
1199         script = eScriptException.scriptName;
1200     }
1201 
1202     if ( !eScriptException.Message.isEmpty() )
1203     {
1204         message = eScriptException.Message;
1205     }
1206 
1207     if ( eScriptException.lineNum != -1 )
1208     {
1209         line = OUString::number( eScriptException.lineNum );
1210         unformatted = CuiResId( RID_SVXSTR_EXCEPTION_AT_LINE );
1211     }
1212     else
1213     {
1214         unformatted = CuiResId( RID_SVXSTR_EXCEPTION_RUNNING );
1215     }
1216 
1217     if ( !eScriptException.exceptionType.isEmpty() )
1218     {
1219         type = eScriptException.exceptionType;
1220     }
1221 
1222     return FormatErrorString(
1223         unformatted, language, script, line, type, message );
1224 
1225 }
1226 OUString GetErrorMessage(
1227     const provider::ScriptFrameworkErrorException& sError )
1228 {
1229     OUString unformatted = CuiResId( RID_SVXSTR_FRAMEWORK_ERROR_RUNNING );
1230 
1231     OUString language("UNKNOWN");
1232 
1233     OUString script("UNKNOWN");
1234 
1235     OUString message;
1236 
1237     if ( !sError.scriptName.isEmpty() )
1238     {
1239         script = sError.scriptName;
1240     }
1241     if ( !sError.language.isEmpty() )
1242     {
1243         language = sError.language;
1244     }
1245     if ( sError.errorType == provider::ScriptFrameworkErrorType::NOTSUPPORTED )
1246     {
1247         message =
1248             CuiResId(  RID_SVXSTR_ERROR_LANG_NOT_SUPPORTED );
1249         message = ReplaceString(message, "%LANGUAGENAME", language );
1250 
1251     }
1252     else
1253     {
1254         message = sError.Message;
1255     }
1256     return FormatErrorString(
1257         unformatted, language, script, OUString(), OUString(), message );
1258 }
1259 
1260 OUString GetErrorMessage( const css::uno::Any& aException )
1261 {
1262     if ( aException.getValueType() ==
1263          cppu::UnoType<reflection::InvocationTargetException>::get())
1264     {
1265         reflection::InvocationTargetException ite;
1266         aException >>= ite;
1267         if ( ite.TargetException.getValueType() == cppu::UnoType<provider::ScriptErrorRaisedException>::get())
1268         {
1269             // Error raised by script
1270             provider::ScriptErrorRaisedException scriptError;
1271             ite.TargetException >>= scriptError;
1272             return GetErrorMessage( scriptError );
1273         }
1274         else if ( ite.TargetException.getValueType() == cppu::UnoType<provider::ScriptExceptionRaisedException>::get())
1275         {
1276             // Exception raised by script
1277             provider::ScriptExceptionRaisedException scriptException;
1278             ite.TargetException >>= scriptException;
1279             return GetErrorMessage( scriptException );
1280         }
1281         else
1282         {
1283             // Unknown error, shouldn't happen
1284             // OSL_ASSERT(...)
1285         }
1286 
1287     }
1288     else if ( aException.getValueType() == cppu::UnoType<provider::ScriptFrameworkErrorException>::get())
1289     {
1290         // A Script Framework error has occurred
1291         provider::ScriptFrameworkErrorException sfe;
1292         aException >>= sfe;
1293         return GetErrorMessage( sfe );
1294 
1295     }
1296     // unknown exception
1297     auto msg = aException.getValueTypeName();
1298     Exception e;
1299     if ( (aException >>= e) && !e.Message.isEmpty() )
1300     {
1301         msg += ": " + e.Message;
1302     }
1303     return msg;
1304 }
1305 
1306 }
1307 
1308 SvxScriptErrorDialog::SvxScriptErrorDialog( css::uno::Any const & aException )
1309     : m_sMessage()
1310 {
1311     SolarMutexGuard aGuard;
1312     m_sMessage = GetErrorMessage( aException );
1313 }
1314 
1315 SvxScriptErrorDialog::~SvxScriptErrorDialog()
1316 {
1317 }
1318 
1319 short SvxScriptErrorDialog::Execute()
1320 {
1321     // Show Error dialog asynchronously
1322 
1323     // Pass a copy of the message to the ShowDialog method as the
1324     // SvxScriptErrorDialog may be deleted before ShowDialog is called
1325     Application::PostUserEvent(
1326         LINK( this, SvxScriptErrorDialog, ShowDialog ),
1327         new OUString( m_sMessage ) );
1328 
1329     return 0;
1330 }
1331 
1332 IMPL_STATIC_LINK( SvxScriptErrorDialog, ShowDialog, void*, p, void )
1333 {
1334     OUString* pMessage = static_cast<OUString*>(p);
1335     OUString message;
1336 
1337     if ( pMessage && !pMessage->isEmpty() )
1338     {
1339         message = *pMessage;
1340     }
1341     else
1342     {
1343         message = CuiResId( RID_SVXSTR_ERROR_TITLE );
1344     }
1345 
1346     std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
1347                                               VclMessageType::Warning, VclButtonsType::Ok, message));
1348     xBox->set_title(CuiResId(RID_SVXSTR_ERROR_TITLE));
1349     xBox->run();
1350 
1351     delete pMessage;
1352 }
1353 
1354 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1355