bump product version to 6.4.0.3
[LibreOffice.git] / cui / source / dialogs / scriptdlg.cxx
blob12da15e0c2b622d3f3b61a660dec905688739928
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 <memory>
21 #include <utility>
23 #include <sal/log.hxx>
24 #include <sfx2/objsh.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/weld.hxx>
28 #include <strings.hrc>
29 #include <bitmaps.hlst>
30 #include <scriptdlg.hxx>
31 #include <dialmgr.hxx>
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>
49 #include <comphelper/SetFlagContextHelper.hxx>
50 #include <comphelper/documentinfo.hxx>
51 #include <comphelper/processfactory.hxx>
53 #include <svtools/imagemgr.hxx>
54 #include <tools/urlobj.hxx>
55 #include <tools/diagnose_ex.h>
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;
63 static void ShowErrorDialog( const Any& aException )
65 ScopedVclPtrInstance<SvxScriptErrorDialog> pDlg( aException );
66 pDlg->Execute();
69 void SvxScriptOrgDialog::delUserData(const weld::TreeIter& rIter)
71 SFEntry* pUserData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rIter).toInt64());
72 if (pUserData)
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());
83 void SvxScriptOrgDialog::deleteTree(weld::TreeIter& rIter)
85 delUserData(rIter);
86 std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator(&rIter);
87 if (!m_xScriptsBox->iter_children(*xIter))
88 return;
90 std::unique_ptr<weld::TreeIter> xAltIter = m_xScriptsBox->make_iterator();
91 bool bNextEntry;
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);
100 while (bNextEntry);
103 void SvxScriptOrgDialog::deleteAllTree()
105 std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
106 if (!m_xScriptsBox->get_iter_first(*xIter))
107 return;
109 std::unique_ptr<weld::TreeIter> xAltIter = m_xScriptsBox->make_iterator();
110 // TBD - below is a candidate for a destroyAllTrees method
111 bool bNextEntry;
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);
120 while (bNextEntry);
123 void SvxScriptOrgDialog::Init( const OUString& language )
125 m_xScriptsBox->freeze();
127 deleteAllTree();
129 Reference< browse::XBrowseNode > rootNode;
130 Reference< XComponentContext > xCtx(
131 comphelper::getProcessComponentContext() );
133 Sequence< Reference< browse::XBrowseNode > > children;
135 OUString userStr("user");
136 OUString const shareStr("share");
140 Reference< browse::XBrowseNodeFactory > xFac = browse::theBrowseNodeFactory::get(xCtx);
142 rootNode.set( xFac->createView(
143 browse::BrowseNodeFactoryViewTypes::MACROORGANIZER ) );
145 if ( rootNode.is() && rootNode->hasChildNodes() )
147 children = rootNode->getChildNodes();
150 catch( const Exception& )
152 TOOLS_WARN_EXCEPTION("cui.dialogs", "Exception getting root browse node from factory");
153 // TODO exception handling
156 Reference<XModel> xDocumentModel;
157 for ( sal_Int32 n = 0; n < children.getLength(); n++ )
159 bool app = false;
160 OUString uiName = children[ n ]->getName();
161 OUString factoryURL;
162 if ( uiName == userStr || uiName == shareStr )
164 app = true;
165 if ( uiName == userStr )
167 uiName = m_sMyMacros;
169 else
171 uiName = m_sProdMacros;
174 else
176 xDocumentModel.set(getDocumentModel(xCtx, uiName ), UNO_QUERY);
178 if ( xDocumentModel.is() )
180 Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xCtx) );
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&)
190 beans::PropertyValue const * pmoduleDescr =
191 moduleDescr.getConstArray();
192 for ( sal_Int32 pos = moduleDescr.getLength(); pos--; )
194 if ( pmoduleDescr[ pos ].Name == "ooSetupFactoryEmptyDocumentURL" )
196 pmoduleDescr[ pos ].Value >>= factoryURL;
197 break;
203 Reference< browse::XBrowseNode > langEntries =
204 getLangNodeFromRootNode( children[ n ], language );
206 insertEntry( uiName, app ? OUStringLiteral(RID_CUIBMP_HARDDISK) : OUStringLiteral(RID_CUIBMP_DOC),
207 nullptr, true, std::make_unique< SFEntry >( langEntries, xDocumentModel ), factoryURL, false );
210 m_xScriptsBox->thaw();
213 Reference< XInterface >
214 SvxScriptOrgDialog::getDocumentModel( Reference< XComponentContext > const & xCtx, OUString const & docName )
216 Reference< XInterface > xModel;
217 Reference< frame::XDesktop2 > desktop = frame::Desktop::create(xCtx);
219 Reference< container::XEnumerationAccess > componentsAccess =
220 desktop->getComponents();
221 Reference< container::XEnumeration > components =
222 componentsAccess->createEnumeration();
223 while (components->hasMoreElements())
225 Reference< frame::XModel > model(
226 components->nextElement(), UNO_QUERY );
227 if ( model.is() )
229 OUString sTdocUrl = ::comphelper::DocumentInfo::getDocumentTitle( model );
230 if( sTdocUrl == docName )
232 xModel = model;
233 break;
237 return xModel;
240 Reference< browse::XBrowseNode >
241 SvxScriptOrgDialog::getLangNodeFromRootNode( Reference< browse::XBrowseNode > const & rootNode, OUString const & language )
243 Reference< browse::XBrowseNode > langNode;
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;
253 return (it != children.end()) ? *it : nullptr;
256 // First try without Java interaction, to avoid warnings for non-JRE-dependent providers
257 css::uno::ContextLayer layer(comphelper::NoEnableJavaInteractionContext());
258 langNode = tryFind();
260 if (!langNode)
262 // Now try with Java interaction enabled
263 langNode = tryFind();
266 catch ( Exception& )
268 // if getChildNodes() throws an exception we just return
269 // the empty Reference
271 return langNode;
274 void SvxScriptOrgDialog::RequestSubEntries(const weld::TreeIter& rRootEntry, Reference< css::script::browse::XBrowseNode > const & node,
275 Reference< XModel >& model)
277 if (!node.is())
279 return;
282 Sequence< Reference< browse::XBrowseNode > > children;
285 children = node->getChildNodes();
287 catch ( Exception& )
289 // if we catch an exception in getChildNodes then no entries are added
292 for ( sal_Int32 n = 0; n < children.getLength(); n++ )
294 OUString name( children[ n ]->getName() );
295 if ( children[ n ]->getType() != browse::BrowseNodeTypes::SCRIPT)
297 insertEntry(name, RID_CUIBMP_LIB, &rRootEntry, true, std::make_unique<SFEntry>(children[n], model), false);
299 else
301 insertEntry(name, RID_CUIBMP_MACRO, &rRootEntry, false, std::make_unique<SFEntry>(children[n], model), false);
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)
310 if (rBitmap == RID_CUIBMP_DOC && !factoryURL.isEmpty())
312 OUString aImage = SvFileInformationManager::GetFileImageId(INetURLObject(factoryURL));
313 insertEntry(rText, aImage, pParent, bChildrenOnDemand, std::move(aUserData), bSelect);
314 return;
316 insertEntry(rText, rBitmap, pParent, bChildrenOnDemand, std::move(aUserData), bSelect);
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)
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)
331 m_xScriptsBox->set_cursor(*xRetIter);
332 m_xScriptsBox->select(*xRetIter);
336 IMPL_LINK(SvxScriptOrgDialog, ExpandingHdl, const weld::TreeIter&, rIter, bool)
338 SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rIter).toInt64());
340 Reference< browse::XBrowseNode > node;
341 Reference< XModel > model;
342 if ( userData && !userData->isLoaded() )
344 node = userData->GetNode();
345 model = userData->GetModel();
346 RequestSubEntries(rIter, node, model);
347 userData->setLoaded();
350 return true;
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"))
358 m_xEdit->grab_focus();
360 std::unique_ptr<weld::Label> xNewLibFT(m_xBuilder->weld_label("newlibft"));
362 if ( nMode == InputDialogMode::NEWMACRO )
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());
370 else if ( nMode == InputDialogMode::RENAME )
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());
380 // ScriptOrgDialog ------------------------------------------------------------
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"))
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);
410 m_xScriptsBox->set_size_request(m_xScriptsBox->get_approximate_digit_width() * 45,
411 m_xScriptsBox->get_height_rows(12));
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 ) );
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);
428 Init(m_sLanguage);
429 RestorePreviousSelection();
432 SvxScriptOrgDialog::~SvxScriptOrgDialog()
434 deleteAllTree();
437 short SvxScriptOrgDialog::run()
439 SfxObjectShell *pDoc = SfxObjectShell::GetFirst();
441 // force load of MSPs for all documents
442 while ( pDoc )
444 Reference< provider::XScriptProviderSupplier > xSPS( pDoc->GetModel(), UNO_QUERY );
445 if ( xSPS.is() )
447 xSPS->getScriptProvider();
450 pDoc = SfxObjectShell::GetNext(*pDoc);
453 return SfxDialogController::run();
456 void SvxScriptOrgDialog::CheckButtons( Reference< browse::XBrowseNode > const & node )
458 if ( node.is() )
460 if ( node->getType() == browse::BrowseNodeTypes::SCRIPT)
462 m_xRunButton->set_sensitive(true);
464 else
466 m_xRunButton->set_sensitive(false);
468 Reference< beans::XPropertySet > xProps( node, UNO_QUERY );
470 if ( !xProps.is() )
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;
479 OUString sName("Editable");
481 if ( getBoolProperty( xProps, sName ) )
483 m_xEditButton->set_sensitive(true);
485 else
487 m_xEditButton->set_sensitive(false);
490 sName = "Deletable";
492 if ( getBoolProperty( xProps, sName ) )
494 m_xDelButton->set_sensitive(true);
496 else
498 m_xDelButton->set_sensitive(false);
501 sName = "Creatable";
503 if ( getBoolProperty( xProps, sName ) )
505 m_xCreateButton->set_sensitive(true);
507 else
509 m_xCreateButton->set_sensitive(false);
512 sName = "Renamable";
514 if ( getBoolProperty( xProps, sName ) )
516 m_xRenameButton->set_sensitive(true);
518 else
520 m_xRenameButton->set_sensitive(false);
523 else
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);
534 IMPL_LINK_NOARG(SvxScriptOrgDialog, ScriptSelectHdl, weld::TreeView&, void)
536 std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
537 if (!m_xScriptsBox->get_selected(xIter.get()))
538 return;
540 SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(*xIter).toInt64());
542 Reference< browse::XBrowseNode > node;
543 if (userData)
545 node = userData->GetNode();
546 CheckButtons(node);
550 IMPL_LINK(SvxScriptOrgDialog, ButtonHdl, weld::Button&, rButton, void)
552 if ( &rButton == m_xCloseButton.get() )
554 StoreCurrentSelection();
555 m_xDialog->response(RET_CANCEL);
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())
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;
571 Reference< browse::XBrowseNode > node;
572 Reference< XModel > xModel;
574 node = userData->GetNode();
575 xModel = userData->GetModel();
577 if ( !node.is() )
579 return;
582 if (&rButton == m_xRunButton.get())
584 OUString tmpString;
585 Reference< beans::XPropertySet > xProp( node, UNO_QUERY );
586 Reference< provider::XScriptProvider > mspNode;
587 if( !xProp.is() )
589 return;
592 if ( xModel.is() )
594 Reference< XEmbeddedScripts > xEmbeddedScripts( xModel, UNO_QUERY);
595 if( !xEmbeddedScripts.is() )
597 return;
600 if (!xEmbeddedScripts->getAllowMacroExecution())
602 // Please FIXME: Show a message box if AllowMacroExecution is false
603 return;
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() )
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);
615 xProp->getPropertyValue("URI") >>= tmpString;
616 const OUString scriptURL( tmpString );
618 if ( mspNode.is() )
622 Reference< provider::XScript > xScript(
623 mspNode->getScript( scriptURL ), UNO_SET_THROW );
625 const Sequence< Any > args(0);
626 Sequence< sal_Int16 > outIndex;
627 Sequence< Any > outArgs( 0 );
628 xScript->invoke( args, outIndex, outArgs );
630 catch ( reflection::InvocationTargetException& ite )
632 ShowErrorDialog(css::uno::Any(ite));
634 catch ( provider::ScriptFrameworkErrorException& ite )
636 ShowErrorDialog(css::uno::Any(ite));
638 catch ( RuntimeException& re )
640 ShowErrorDialog(css::uno::Any(re));
642 catch ( Exception& e )
644 ShowErrorDialog(css::uno::Any(e));
647 StoreCurrentSelection();
648 m_xDialog->response(RET_CANCEL);
650 else if ( &rButton == m_xEditButton.get() )
652 Reference< script::XInvocation > xInv( node, UNO_QUERY );
653 if ( xInv.is() )
655 StoreCurrentSelection();
656 m_xDialog->response(RET_CANCEL);
657 Sequence< Any > args(0);
658 Sequence< Any > outArgs( 0 );
659 Sequence< sal_Int16 > outIndex;
662 // ISSUE need code to run script here
663 xInv->invoke( "Editable", args, outIndex, outArgs );
665 catch( Exception const & )
667 TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to invoke" );
671 else if ( &rButton == m_xCreateButton.get() )
673 createEntry(*xIter);
675 else if ( &rButton == m_xDelButton.get() )
677 deleteEntry(*xIter);
679 else if ( &rButton == m_xRenameButton.get() )
681 renameEntry(*xIter);
686 Reference< browse::XBrowseNode > SvxScriptOrgDialog::getBrowseNode(const weld::TreeIter& rEntry)
688 Reference< browse::XBrowseNode > node;
689 SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rEntry).toInt64());
690 if (userData)
692 node = userData->GetNode();
694 return node;
697 Reference< XModel > SvxScriptOrgDialog::getModel(const weld::TreeIter& rEntry)
699 Reference< XModel > model;
700 SFEntry* userData = reinterpret_cast<SFEntry*>(m_xScriptsBox->get_id(rEntry).toInt64());
701 if ( userData )
703 model = userData->GetModel();
705 return model;
708 void SvxScriptOrgDialog::createEntry(weld::TreeIter& rEntry)
711 Reference< browse::XBrowseNode > aChildNode;
712 Reference< browse::XBrowseNode > node = getBrowseNode( rEntry );
713 Reference< script::XInvocation > xInv( node, UNO_QUERY );
715 if ( xInv.is() )
717 OUString aNewName;
718 OUString aNewStdName;
719 InputDialogMode nMode = InputDialogMode::NEWLIB;
720 if (m_xScriptsBox->get_iter_depth(rEntry) == 0)
722 aNewStdName = "Library" ;
724 else
726 aNewStdName = "Macro" ;
727 nMode = InputDialogMode::NEWMACRO;
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;
734 Sequence< Reference< browse::XBrowseNode > > childNodes;
735 // no children => ok to create Parcel1 or Script1 without checking
738 if( !node->hasChildNodes() )
740 aNewName = aNewStdName + OUString::number(i);
741 bValid = true;
743 else
745 childNodes = node->getChildNodes();
748 catch ( Exception& )
750 // ignore, will continue on with empty sequence
753 OUString extn;
754 while ( !bValid )
756 aNewName = aNewStdName + OUString::number(i);
757 bool bFound = false;
758 if(childNodes.hasElements() )
760 OUString nodeName = childNodes[0]->getName();
761 sal_Int32 extnPos = nodeName.lastIndexOf( '.' );
762 if(extnPos>0)
763 extn = nodeName.copy(extnPos);
765 for( sal_Int32 index = 0; index < childNodes.getLength(); index++ )
767 if (aNewName+extn == childNodes[index]->getName())
769 bFound = true;
770 break;
773 if( bFound )
775 i++;
777 else
779 bValid = true;
783 CuiInputDialog aNewDlg(m_xDialog.get(), nMode);
784 aNewDlg.SetObjectName(aNewName);
788 if (aNewDlg.run() && !aNewDlg.GetObjectName().isEmpty())
790 OUString aUserSuppliedName = aNewDlg.GetObjectName();
791 bValid = true;
792 for( sal_Int32 index = 0; index < childNodes.getLength(); index++ )
794 if (aUserSuppliedName+extn == childNodes[index]->getName())
796 bValid = false;
797 OUString aError = m_createErrStr + m_createDupStr;
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;
807 if( bValid )
808 aNewName = aUserSuppliedName;
810 else
812 // user hit cancel or hit OK with nothing in the editbox
814 return;
817 while ( !bValid );
819 // open up parent node (which ensures it's loaded)
820 m_xScriptsBox->expand_row(rEntry);
822 Sequence< Any > args( 1 );
823 args[ 0 ] <<= aNewName;
824 Sequence< Any > outArgs( 0 );
825 Sequence< sal_Int16 > outIndex;
828 Any aResult = xInv->invoke( "Creatable", args, outIndex, outArgs );
829 Reference< browse::XBrowseNode > newNode( aResult, UNO_QUERY );
830 aChildNode = newNode;
833 catch( Exception const & )
835 TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Create" );
838 if ( aChildNode.is() )
840 OUString aChildName = aChildNode->getName();
842 Reference<XModel> xDocumentModel = getModel( rEntry );
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 )
851 insertEntry(aChildName, RID_CUIBMP_MACRO, &rEntry, false,
852 std::make_unique<SFEntry>(aChildNode,xDocumentModel), true);
854 else
856 insertEntry(aChildName, RID_CUIBMP_LIB, &rEntry, false,
857 std::make_unique<SFEntry>(aChildNode,xDocumentModel), true);
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() )
866 userData->setLoaded();
870 else
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();
881 void SvxScriptOrgDialog::renameEntry(const weld::TreeIter& rEntry)
884 Reference< browse::XBrowseNode > aChildNode;
885 Reference< browse::XBrowseNode > node = getBrowseNode(rEntry);
886 Reference< script::XInvocation > xInv( node, UNO_QUERY );
888 if ( xInv.is() )
890 OUString aNewName = node->getName();
891 sal_Int32 extnPos = aNewName.lastIndexOf( '.' );
892 if(extnPos>0)
894 aNewName = aNewName.copy(0,extnPos);
896 CuiInputDialog aNewDlg(m_xDialog.get(), InputDialogMode::RENAME);
897 aNewDlg.SetObjectName(aNewName);
899 if (!aNewDlg.run() || aNewDlg.GetObjectName().isEmpty())
900 return; // user hit cancel or hit OK with nothing in the editbox
902 aNewName = aNewDlg.GetObjectName();
904 Sequence< Any > args( 1 );
905 args[ 0 ] <<= aNewName;
906 Sequence< Any > outArgs( 0 );
907 Sequence< sal_Int16 > outIndex;
910 Any aResult = xInv->invoke( "Renamable", args, outIndex, outArgs );
911 Reference< browse::XBrowseNode > newNode( aResult, UNO_QUERY );
912 aChildNode = newNode;
915 catch( Exception const & )
917 TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Rename" );
920 if ( aChildNode.is() )
922 m_xScriptsBox->set_text(rEntry, aChildNode->getName());
923 m_xScriptsBox->set_cursor(rEntry);
924 m_xScriptsBox->select(rEntry);
927 else
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();
938 void SvxScriptOrgDialog::deleteEntry(weld::TreeIter& rEntry)
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)
949 return;
952 Reference< script::XInvocation > xInv( node, UNO_QUERY );
953 if ( xInv.is() )
955 Sequence< Any > args( 0 );
956 Sequence< Any > outArgs( 0 );
957 Sequence< sal_Int16 > outIndex;
960 Any aResult = xInv->invoke( "Deletable", args, outIndex, outArgs );
961 aResult >>= result; // or do we just assume true if no exception ?
963 catch( Exception const & )
965 TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to delete" );
969 if ( result )
971 deleteTree(rEntry);
972 m_xScriptsBox->remove(rEntry);
974 else
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();
985 bool SvxScriptOrgDialog::getBoolProperty( Reference< beans::XPropertySet > const & xProps,
986 OUString const & propName )
988 bool result = false;
991 xProps->getPropertyValue( propName ) >>= result;
993 catch ( Exception& )
995 return result;
997 return result;
1000 OUString SvxScriptOrgDialog::getListOfChildren( const Reference< browse::XBrowseNode >& node, int depth )
1002 OUStringBuffer result = "\n";
1003 for( int i=0;i<=depth;i++ )
1005 result.append("\t");
1007 result.append(node->getName());
1011 if ( node->hasChildNodes() )
1013 Sequence< Reference< browse::XBrowseNode > > children
1014 = node->getChildNodes();
1015 for ( sal_Int32 n = 0; n < children.getLength(); n++ )
1017 result.append( getListOfChildren( children[ n ] , depth+1 ) );
1021 catch ( Exception& )
1023 // ignore, will return an empty string
1026 return result.makeStringAndClear();
1029 Selection_hash SvxScriptOrgDialog::m_lastSelection;
1031 void SvxScriptOrgDialog::StoreCurrentSelection()
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;
1040 aDescription = m_xScriptsBox->get_text(*xIter) + aDescription;
1041 bEntry = m_xScriptsBox->iter_parent(*xIter);
1042 if (bEntry)
1043 aDescription = ";" + aDescription;
1045 while (bEntry);
1046 OUString sDesc( aDescription );
1047 m_lastSelection[ m_sLanguage ] = sDesc;
1050 void SvxScriptOrgDialog::RestorePreviousSelection()
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)
1060 OUString aTmp( aStoredEntry.getToken( 0, ';', nIndex ) );
1062 bool bTmpEntry;
1063 if (!xEntry)
1065 xEntry = m_xScriptsBox->make_iterator();
1066 bTmpEntry = m_xScriptsBox->get_iter_first(*xEntry);
1067 m_xScriptsBox->copy_iterator(*xEntry, *xTmpEntry);
1069 else
1071 m_xScriptsBox->copy_iterator(*xEntry, *xTmpEntry);
1072 bTmpEntry = m_xScriptsBox->iter_children(*xTmpEntry);
1075 while (bTmpEntry)
1077 if (m_xScriptsBox->get_text(*xTmpEntry) == aTmp)
1079 m_xScriptsBox->copy_iterator(*xTmpEntry, *xEntry);
1080 break;
1082 bTmpEntry = m_xScriptsBox->iter_next_sibling(*xTmpEntry);
1085 if (!bTmpEntry)
1086 break;
1088 m_xScriptsBox->expand_row(*xEntry);
1091 if (xEntry)
1092 m_xScriptsBox->set_cursor(*xEntry);
1095 namespace {
1097 OUString ReplaceString(
1098 const OUString& source,
1099 const OUString& token,
1100 const OUString& value )
1102 sal_Int32 pos = source.indexOf( token );
1104 if ( pos != -1 && !value.isEmpty() )
1106 return source.replaceAt( pos, token.getLength(), value );
1108 else
1110 return source;
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 )
1122 OUString result = unformatted.copy( 0 );
1124 result = ReplaceString(result, "%LANGUAGENAME", language );
1125 result = ReplaceString(result, "%SCRIPTNAME", script );
1126 result = ReplaceString(result, "%LINENUMBER", line );
1128 if ( !type.isEmpty() )
1130 result += "\n\n" + CuiResId(RID_SVXSTR_ERROR_TYPE_LABEL) + " " + type;
1133 if ( !message.isEmpty() )
1135 result += "\n\n" + CuiResId(RID_SVXSTR_ERROR_MESSAGE_LABEL) + " " + message;
1138 return result;
1141 OUString GetErrorMessage(
1142 const provider::ScriptErrorRaisedException& eScriptError )
1144 OUString unformatted = CuiResId( RID_SVXSTR_ERROR_AT_LINE );
1146 OUString unknown("UNKNOWN");
1147 OUString language = unknown;
1148 OUString script = unknown;
1149 OUString line = unknown;
1150 OUString type = "";
1151 OUString message = eScriptError.Message;
1153 if ( !eScriptError.language.isEmpty() )
1155 language = eScriptError.language;
1158 if ( !eScriptError.scriptName.isEmpty() )
1160 script = eScriptError.scriptName;
1163 if ( !eScriptError.Message.isEmpty() )
1165 message = eScriptError.Message;
1167 if ( eScriptError.lineNum != -1 )
1169 line = OUString::number( eScriptError.lineNum );
1170 unformatted = CuiResId( RID_SVXSTR_ERROR_AT_LINE );
1172 else
1174 unformatted = CuiResId( RID_SVXSTR_ERROR_RUNNING );
1177 return FormatErrorString(
1178 unformatted, language, script, line, type, message );
1181 OUString GetErrorMessage(
1182 const provider::ScriptExceptionRaisedException& eScriptException )
1184 OUString unformatted = CuiResId( RID_SVXSTR_EXCEPTION_AT_LINE );
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;
1193 if ( !eScriptException.language.isEmpty() )
1195 language = eScriptException.language;
1197 if ( !eScriptException.scriptName.isEmpty() )
1199 script = eScriptException.scriptName;
1202 if ( !eScriptException.Message.isEmpty() )
1204 message = eScriptException.Message;
1207 if ( eScriptException.lineNum != -1 )
1209 line = OUString::number( eScriptException.lineNum );
1210 unformatted = CuiResId( RID_SVXSTR_EXCEPTION_AT_LINE );
1212 else
1214 unformatted = CuiResId( RID_SVXSTR_EXCEPTION_RUNNING );
1217 if ( !eScriptException.exceptionType.isEmpty() )
1219 type = eScriptException.exceptionType;
1222 return FormatErrorString(
1223 unformatted, language, script, line, type, message );
1226 OUString GetErrorMessage(
1227 const provider::ScriptFrameworkErrorException& sError )
1229 OUString unformatted = CuiResId( RID_SVXSTR_FRAMEWORK_ERROR_RUNNING );
1231 OUString language("UNKNOWN");
1233 OUString script("UNKNOWN");
1235 OUString message;
1237 if ( !sError.scriptName.isEmpty() )
1239 script = sError.scriptName;
1241 if ( !sError.language.isEmpty() )
1243 language = sError.language;
1245 if ( sError.errorType == provider::ScriptFrameworkErrorType::NOTSUPPORTED )
1247 message =
1248 CuiResId( RID_SVXSTR_ERROR_LANG_NOT_SUPPORTED );
1249 message = ReplaceString(message, "%LANGUAGENAME", language );
1252 else
1254 message = sError.Message;
1256 return FormatErrorString(
1257 unformatted, language, script, OUString(), OUString(), message );
1260 OUString GetErrorMessage( const css::uno::Any& aException )
1262 if ( aException.getValueType() ==
1263 cppu::UnoType<reflection::InvocationTargetException>::get())
1265 reflection::InvocationTargetException ite;
1266 aException >>= ite;
1267 if ( ite.TargetException.getValueType() == cppu::UnoType<provider::ScriptErrorRaisedException>::get())
1269 // Error raised by script
1270 provider::ScriptErrorRaisedException scriptError;
1271 ite.TargetException >>= scriptError;
1272 return GetErrorMessage( scriptError );
1274 else if ( ite.TargetException.getValueType() == cppu::UnoType<provider::ScriptExceptionRaisedException>::get())
1276 // Exception raised by script
1277 provider::ScriptExceptionRaisedException scriptException;
1278 ite.TargetException >>= scriptException;
1279 return GetErrorMessage( scriptException );
1281 else
1283 // Unknown error, shouldn't happen
1284 // OSL_ASSERT(...)
1288 else if ( aException.getValueType() == cppu::UnoType<provider::ScriptFrameworkErrorException>::get())
1290 // A Script Framework error has occurred
1291 provider::ScriptFrameworkErrorException sfe;
1292 aException >>= sfe;
1293 return GetErrorMessage( sfe );
1296 // unknown exception
1297 auto msg = aException.getValueTypeName();
1298 Exception e;
1299 if ( (aException >>= e) && !e.Message.isEmpty() )
1301 msg += ": " + e.Message;
1303 return msg;
1308 SvxScriptErrorDialog::SvxScriptErrorDialog( css::uno::Any const & aException )
1309 : m_sMessage()
1311 SolarMutexGuard aGuard;
1312 m_sMessage = GetErrorMessage( aException );
1315 SvxScriptErrorDialog::~SvxScriptErrorDialog()
1319 short SvxScriptErrorDialog::Execute()
1321 // Show Error dialog asynchronously
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 ) );
1329 return 0;
1332 IMPL_STATIC_LINK( SvxScriptErrorDialog, ShowDialog, void*, p, void )
1334 OUString* pMessage = static_cast<OUString*>(p);
1335 OUString message;
1337 if ( pMessage && !pMessage->isEmpty() )
1339 message = *pMessage;
1341 else
1343 message = CuiResId( RID_SVXSTR_ERROR_TITLE );
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();
1351 delete pMessage;
1354 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */