summaryrefslogtreecommitdiffstats
path: root/cui/source/dialogs/scriptdlg.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--cui/source/dialogs/scriptdlg.cxx1338
1 files changed, 1338 insertions, 0 deletions
diff --git a/cui/source/dialogs/scriptdlg.cxx b/cui/source/dialogs/scriptdlg.cxx
new file mode 100644
index 000000000..8e787e8d1
--- /dev/null
+++ b/cui/source/dialogs/scriptdlg.cxx
@@ -0,0 +1,1338 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <string_view>
+#include <utility>
+
+#include <sfx2/objsh.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <scriptdlg.hxx>
+#include <dialmgr.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
+#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+#include <com/sun/star/script/browse/XBrowseNodeFactory.hpp>
+#include <com/sun/star/script/browse/BrowseNodeFactoryViewTypes.hpp>
+#include <com/sun/star/script/browse/theBrowseNodeFactory.hpp>
+#include <com/sun/star/script/provider/ScriptErrorRaisedException.hpp>
+#include <com/sun/star/script/provider/ScriptExceptionRaisedException.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+
+#include <comphelper/lok.hxx>
+#include <comphelper/SetFlagContextHelper.hxx>
+#include <comphelper/documentinfo.hxx>
+#include <comphelper/processfactory.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <svtools/imagemgr.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+using namespace css::uno;
+using namespace css::script;
+using namespace css::frame;
+using namespace css::document;
+
+void SvxScriptOrgDialog::delUserData(const weld::TreeIter& rIter)
+{
+ SFEntry* pUserData = weld::fromId<SFEntry*>(m_xScriptsBox->get_id(rIter));
+ if (pUserData)
+ {
+ delete pUserData;
+ // TBD seem to get a Select event on node that is remove ( below )
+ // so need to be able to detect that this node is not to be
+ // processed in order to do this, setting userData to NULL ( must
+ // be a better way to do this )
+ m_xScriptsBox->set_id(rIter, OUString());
+ }
+}
+
+void SvxScriptOrgDialog::deleteTree(const weld::TreeIter& rIter)
+{
+ delUserData(rIter);
+ std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator(&rIter);
+ if (!m_xScriptsBox->iter_children(*xIter))
+ return;
+
+ std::unique_ptr<weld::TreeIter> xAltIter = m_xScriptsBox->make_iterator();
+ bool bNextEntry;
+ do
+ {
+ m_xScriptsBox->copy_iterator(*xIter, *xAltIter);
+ bNextEntry = m_xScriptsBox->iter_next_sibling(*xAltIter);
+ deleteTree(*xIter);
+ m_xScriptsBox->remove(*xIter);
+ m_xScriptsBox->copy_iterator(*xAltIter, *xIter);
+ }
+ while (bNextEntry);
+}
+
+void SvxScriptOrgDialog::deleteAllTree()
+{
+ std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
+ if (!m_xScriptsBox->get_iter_first(*xIter))
+ return;
+
+ std::unique_ptr<weld::TreeIter> xAltIter = m_xScriptsBox->make_iterator();
+ // TBD - below is a candidate for a destroyAllTrees method
+ bool bNextEntry;
+ do
+ {
+ m_xScriptsBox->copy_iterator(*xIter, *xAltIter);
+ bNextEntry = m_xScriptsBox->iter_next_sibling(*xAltIter);
+ deleteTree(*xIter);
+ m_xScriptsBox->remove(*xIter);
+ m_xScriptsBox->copy_iterator(*xAltIter, *xIter);
+ }
+ while (bNextEntry);
+}
+
+void SvxScriptOrgDialog::Init( std::u16string_view language )
+{
+ m_xScriptsBox->freeze();
+
+ deleteAllTree();
+
+ Reference< browse::XBrowseNode > rootNode;
+ Reference< XComponentContext > xCtx(
+ comphelper::getProcessComponentContext() );
+
+ Sequence< Reference< browse::XBrowseNode > > children;
+
+ OUString userStr("user");
+ OUString const shareStr("share");
+
+ try
+ {
+ Reference< browse::XBrowseNodeFactory > xFac = browse::theBrowseNodeFactory::get(xCtx);
+
+ rootNode.set( xFac->createView(
+ browse::BrowseNodeFactoryViewTypes::MACROORGANIZER ) );
+
+ if ( rootNode.is() && rootNode->hasChildNodes() )
+ {
+ children = rootNode->getChildNodes();
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "Exception getting root browse node from factory");
+ // TODO exception handling
+ }
+
+ Reference<XModel> xDocumentModel;
+ for ( const Reference< browse::XBrowseNode >& childNode : std::as_const(children) )
+ {
+ bool app = false;
+ OUString uiName = childNode->getName();
+ OUString factoryURL;
+ if ( uiName == userStr || uiName == shareStr )
+ {
+ app = true;
+ if ( uiName == userStr )
+ {
+ uiName = m_sMyMacros;
+ }
+ else
+ {
+ uiName = m_sProdMacros;
+ }
+ }
+ else
+ {
+ xDocumentModel.set(getDocumentModel(xCtx, uiName ), UNO_QUERY);
+
+ if ( xDocumentModel.is() )
+ {
+ Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xCtx) );
+
+ // get the long name of the document:
+ Sequence<beans::PropertyValue> moduleDescr;
+ try{
+ OUString appModule = xModuleManager->identify( xDocumentModel );
+ xModuleManager->getByName(appModule) >>= moduleDescr;
+ } catch(const uno::Exception&)
+ {}
+
+ for ( const beans::PropertyValue& prop : std::as_const(moduleDescr))
+ {
+ if ( prop.Name == "ooSetupFactoryEmptyDocumentURL" )
+ {
+ prop.Value >>= factoryURL;
+ break;
+ }
+ }
+ }
+ }
+
+ Reference< browse::XBrowseNode > langEntries =
+ getLangNodeFromRootNode( childNode, language );
+
+ insertEntry( uiName, app ? OUString(RID_CUIBMP_HARDDISK) : OUString(RID_CUIBMP_DOC),
+ nullptr, true, std::make_unique< SFEntry >( langEntries, xDocumentModel ), factoryURL, false );
+ }
+
+ m_xScriptsBox->thaw();
+}
+
+Reference< XInterface >
+SvxScriptOrgDialog::getDocumentModel( Reference< XComponentContext > const & xCtx, std::u16string_view docName )
+{
+ Reference< XInterface > xModel;
+ Reference< frame::XDesktop2 > desktop = frame::Desktop::create(xCtx);
+
+ Reference< container::XEnumerationAccess > componentsAccess =
+ desktop->getComponents();
+ Reference< container::XEnumeration > components =
+ componentsAccess->createEnumeration();
+ while (components->hasMoreElements())
+ {
+ Reference< frame::XModel > model(
+ components->nextElement(), UNO_QUERY );
+ if ( model.is() )
+ {
+ OUString sTdocUrl = ::comphelper::DocumentInfo::getDocumentTitle( model );
+ if( sTdocUrl == docName )
+ {
+ xModel = model;
+ break;
+ }
+ }
+ }
+ return xModel;
+}
+
+Reference< browse::XBrowseNode >
+SvxScriptOrgDialog::getLangNodeFromRootNode( Reference< browse::XBrowseNode > const & rootNode, std::u16string_view language )
+{
+ Reference< browse::XBrowseNode > langNode;
+
+ try
+ {
+ auto tryFind = [&] {
+ const Sequence<Reference<browse::XBrowseNode>> children = rootNode->getChildNodes();
+ const auto it = std::find_if(children.begin(), children.end(),
+ [&](const Reference<browse::XBrowseNode>& child) {
+ return child->getName() == language;
+ });
+ return (it != children.end()) ? *it : nullptr;
+ };
+ {
+ // First try without Java interaction, to avoid warnings for non-JRE-dependent providers
+ css::uno::ContextLayer layer(comphelper::NoEnableJavaInteractionContext());
+ langNode = tryFind();
+ }
+ if (!langNode)
+ {
+ // Now try with Java interaction enabled
+ langNode = tryFind();
+ }
+ }
+ catch ( Exception& )
+ {
+ // if getChildNodes() throws an exception we just return
+ // the empty Reference
+ }
+ return langNode;
+}
+
+void SvxScriptOrgDialog::RequestSubEntries(const weld::TreeIter& rRootEntry, Reference< css::script::browse::XBrowseNode > const & node,
+ Reference< XModel >& model)
+{
+ if (!node.is())
+ {
+ return;
+ }
+
+ Sequence< Reference< browse::XBrowseNode > > children;
+ try
+ {
+ children = node->getChildNodes();
+ }
+ catch ( Exception& )
+ {
+ // if we catch an exception in getChildNodes then no entries are added
+ }
+
+ for ( const Reference< browse::XBrowseNode >& childNode : std::as_const(children) )
+ {
+ OUString name( childNode->getName() );
+ if ( childNode->getType() != browse::BrowseNodeTypes::SCRIPT)
+ {
+ insertEntry(name, RID_CUIBMP_LIB, &rRootEntry, true, std::make_unique<SFEntry>(childNode, model), false);
+ }
+ else
+ {
+ insertEntry(name, RID_CUIBMP_MACRO, &rRootEntry, false, std::make_unique<SFEntry>(childNode, model), false);
+ }
+ }
+}
+
+void SvxScriptOrgDialog::insertEntry(const OUString& rText, const OUString& rBitmap,
+ const weld::TreeIter* pParent, bool bChildrenOnDemand, std::unique_ptr<SFEntry> && aUserData,
+ std::u16string_view factoryURL, bool bSelect)
+{
+ if (rBitmap == RID_CUIBMP_DOC && !factoryURL.empty())
+ {
+ OUString aImage = SvFileInformationManager::GetFileImageId(INetURLObject(factoryURL));
+ insertEntry(rText, aImage, pParent, bChildrenOnDemand, std::move(aUserData), bSelect);
+ return;
+ }
+ insertEntry(rText, rBitmap, pParent, bChildrenOnDemand, std::move(aUserData), bSelect);
+}
+
+void SvxScriptOrgDialog::insertEntry(
+ const OUString& rText, const OUString& rBitmap, const weld::TreeIter* pParent,
+ bool bChildrenOnDemand, std::unique_ptr<SFEntry> && aUserData, bool bSelect)
+{
+ OUString sId(weld::toId(aUserData.release())); // XXX possible leak
+ m_xScriptsBox->insert(pParent, -1, &rText, &sId, nullptr, nullptr,
+ bChildrenOnDemand, m_xScratchIter.get());
+ m_xScriptsBox->set_image(*m_xScratchIter, rBitmap);
+ if (bSelect)
+ {
+ m_xScriptsBox->set_cursor(*m_xScratchIter);
+ m_xScriptsBox->select(*m_xScratchIter);
+ }
+}
+
+IMPL_LINK(SvxScriptOrgDialog, ExpandingHdl, const weld::TreeIter&, rIter, bool)
+{
+ SFEntry* userData = weld::fromId<SFEntry*>(m_xScriptsBox->get_id(rIter));
+
+ Reference< browse::XBrowseNode > node;
+ Reference< XModel > model;
+ if ( userData && !userData->isLoaded() )
+ {
+ node = userData->GetNode();
+ model = userData->GetModel();
+ RequestSubEntries(rIter, node, model);
+ userData->setLoaded();
+ }
+
+ return true;
+}
+
+// CuiInputDialog ------------------------------------------------------------
+CuiInputDialog::CuiInputDialog(weld::Window * pParent, InputDialogMode nMode)
+ : GenericDialogController(pParent, "cui/ui/newlibdialog.ui", "NewLibDialog")
+ , m_xEdit(m_xBuilder->weld_entry("entry"))
+{
+ m_xEdit->grab_focus();
+
+ std::unique_ptr<weld::Label> xNewLibFT(m_xBuilder->weld_label("newlibft"));
+
+ if ( nMode == InputDialogMode::NEWMACRO )
+ {
+ xNewLibFT->hide();
+ std::unique_ptr<weld::Label> xNewMacroFT(m_xBuilder->weld_label("newmacroft"));
+ xNewMacroFT->show();
+ std::unique_ptr<weld::Label> xAltTitle(m_xBuilder->weld_label("altmacrotitle"));
+ m_xDialog->set_title(xAltTitle->get_label());
+ }
+ else if ( nMode == InputDialogMode::RENAME )
+ {
+ xNewLibFT->hide();
+ std::unique_ptr<weld::Label> xRenameFT(m_xBuilder->weld_label("renameft"));
+ xRenameFT->show();
+ std::unique_ptr<weld::Label> xAltTitle(m_xBuilder->weld_label("altrenametitle"));
+ m_xDialog->set_title(xAltTitle->get_label());
+ }
+}
+
+// ScriptOrgDialog ------------------------------------------------------------
+
+SvxScriptOrgDialog::SvxScriptOrgDialog(weld::Window* pParent, OUString language)
+ : SfxDialogController(pParent, "cui/ui/scriptorganizer.ui", "ScriptOrganizerDialog")
+ , m_pParent(pParent)
+ , m_sLanguage(std::move(language))
+ , m_delErrStr(CuiResId(RID_CUISTR_DELFAILED))
+ , m_delErrTitleStr(CuiResId(RID_CUISTR_DELFAILED_TITLE))
+ , m_delQueryStr(CuiResId(RID_CUISTR_DELQUERY))
+ , m_delQueryTitleStr(CuiResId(RID_CUISTR_DELQUERY_TITLE))
+ , m_createErrStr(CuiResId(RID_CUISTR_CREATEFAILED))
+ , m_createDupStr(CuiResId(RID_CUISTR_CREATEFAILEDDUP))
+ , m_createErrTitleStr(CuiResId(RID_CUISTR_CREATEFAILED_TITLE))
+ , m_renameErrStr(CuiResId(RID_CUISTR_RENAMEFAILED))
+ , m_renameErrTitleStr(CuiResId(RID_CUISTR_RENAMEFAILED_TITLE))
+ , m_sMyMacros(CuiResId(RID_CUISTR_MYMACROS))
+ , m_sProdMacros(CuiResId(RID_CUISTR_PRODMACROS))
+ , m_xScriptsBox(m_xBuilder->weld_tree_view("scripts"))
+ , m_xScratchIter(m_xScriptsBox->make_iterator())
+ , m_xRunButton(m_xBuilder->weld_button("ok"))
+ , m_xCloseButton(m_xBuilder->weld_button("close"))
+ , m_xCreateButton(m_xBuilder->weld_button("create"))
+ , m_xEditButton(m_xBuilder->weld_button("edit"))
+ , m_xRenameButton(m_xBuilder->weld_button("rename"))
+ , m_xDelButton(m_xBuilder->weld_button("delete"))
+{
+ // must be a neater way to deal with the strings than as above
+ // append the language to the dialog title
+ OUString winTitle(m_xDialog->get_title());
+ winTitle = winTitle.replaceFirst( "%MACROLANG", m_sLanguage );
+ m_xDialog->set_title(winTitle);
+
+ m_xScriptsBox->set_size_request(m_xScriptsBox->get_approximate_digit_width() * 45,
+ m_xScriptsBox->get_height_rows(12));
+
+ m_xScriptsBox->connect_changed( LINK( this, SvxScriptOrgDialog, ScriptSelectHdl ) );
+ m_xScriptsBox->connect_expanding(LINK( this, SvxScriptOrgDialog, ExpandingHdl ) );
+ m_xRunButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+ m_xCloseButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+ m_xRenameButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+ m_xEditButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+ m_xDelButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+ m_xCreateButton->connect_clicked( LINK( this, SvxScriptOrgDialog, ButtonHdl ) );
+
+ m_xRunButton->set_sensitive(false);
+ m_xRenameButton->set_sensitive(false);
+ m_xEditButton->set_sensitive(false);
+ m_xDelButton->set_sensitive(false);
+ m_xCreateButton->set_sensitive(false);
+
+ Init(m_sLanguage);
+ RestorePreviousSelection();
+}
+
+SvxScriptOrgDialog::~SvxScriptOrgDialog()
+{
+ deleteAllTree();
+}
+
+short SvxScriptOrgDialog::run()
+{
+ SfxObjectShell *pDoc = SfxObjectShell::GetFirst();
+
+ // force load of MSPs for all documents
+ while ( pDoc )
+ {
+ Reference< provider::XScriptProviderSupplier > xSPS( pDoc->GetModel(), UNO_QUERY );
+ if ( xSPS.is() )
+ {
+ xSPS->getScriptProvider();
+ }
+
+ pDoc = SfxObjectShell::GetNext(*pDoc);
+ }
+
+ return SfxDialogController::run();
+}
+
+void SvxScriptOrgDialog::CheckButtons( Reference< browse::XBrowseNode > const & node )
+{
+ if ( node.is() )
+ {
+ if ( node->getType() == browse::BrowseNodeTypes::SCRIPT)
+ {
+ m_xRunButton->set_sensitive(true);
+ }
+ else
+ {
+ m_xRunButton->set_sensitive(false);
+ }
+ Reference< beans::XPropertySet > xProps( node, UNO_QUERY );
+
+ if ( !xProps.is() )
+ {
+ m_xEditButton->set_sensitive(false);
+ m_xDelButton->set_sensitive(false);
+ m_xCreateButton->set_sensitive(false);
+ m_xRunButton->set_sensitive(false);
+ return;
+ }
+
+ OUString sName("Editable");
+
+ if ( getBoolProperty( xProps, sName ) )
+ {
+ m_xEditButton->set_sensitive(true);
+ }
+ else
+ {
+ m_xEditButton->set_sensitive(false);
+ }
+
+ sName = "Deletable";
+
+ if ( getBoolProperty( xProps, sName ) )
+ {
+ m_xDelButton->set_sensitive(true);
+ }
+ else
+ {
+ m_xDelButton->set_sensitive(false);
+ }
+
+ sName = "Creatable";
+
+ if ( getBoolProperty( xProps, sName ) )
+ {
+ m_xCreateButton->set_sensitive(true);
+ }
+ else
+ {
+ m_xCreateButton->set_sensitive(false);
+ }
+
+ sName = "Renamable";
+
+ if ( getBoolProperty( xProps, sName ) )
+ {
+ m_xRenameButton->set_sensitive(true);
+ }
+ else
+ {
+ m_xRenameButton->set_sensitive(false);
+ }
+ }
+ else
+ {
+ // no node info available, disable all configurable actions
+ m_xDelButton->set_sensitive(false);
+ m_xCreateButton->set_sensitive(false);
+ m_xEditButton->set_sensitive(false);
+ m_xRunButton->set_sensitive(false);
+ m_xRenameButton->set_sensitive(false);
+ }
+}
+
+IMPL_LINK_NOARG(SvxScriptOrgDialog, ScriptSelectHdl, weld::TreeView&, void)
+{
+ std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
+ if (!m_xScriptsBox->get_selected(xIter.get()))
+ return;
+
+ SFEntry* userData = weld::fromId<SFEntry*>(m_xScriptsBox->get_id(*xIter));
+
+ Reference< browse::XBrowseNode > node;
+ if (userData)
+ {
+ node = userData->GetNode();
+ CheckButtons(node);
+ }
+}
+
+IMPL_LINK(SvxScriptOrgDialog, ButtonHdl, weld::Button&, rButton, void)
+{
+ if ( &rButton == m_xCloseButton.get() )
+ {
+ StoreCurrentSelection();
+ m_xDialog->response(RET_CANCEL);
+ }
+ if (!(&rButton == m_xEditButton.get() ||
+ &rButton == m_xCreateButton.get() ||
+ &rButton == m_xDelButton.get() ||
+ &rButton == m_xRunButton.get() ||
+ &rButton == m_xRenameButton.get()))
+
+ return;
+
+ std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
+ if (!m_xScriptsBox->get_selected(xIter.get()))
+ return;
+ SFEntry* userData = weld::fromId<SFEntry*>(m_xScriptsBox->get_id(*xIter));
+ if (!userData)
+ return;
+
+ Reference< browse::XBrowseNode > node;
+ Reference< XModel > xModel;
+
+ node = userData->GetNode();
+ xModel = userData->GetModel();
+
+ if ( !node.is() )
+ {
+ return;
+ }
+
+ if (&rButton == m_xRunButton.get())
+ {
+ OUString tmpString;
+ Reference< beans::XPropertySet > xProp( node, UNO_QUERY );
+ Reference< provider::XScriptProvider > mspNode;
+ if( !xProp.is() )
+ {
+ return;
+ }
+
+ if ( xModel.is() )
+ {
+ Reference< XEmbeddedScripts > xEmbeddedScripts( xModel, UNO_QUERY);
+ if( !xEmbeddedScripts.is() )
+ {
+ return;
+ }
+
+ if (!xEmbeddedScripts->getAllowMacroExecution())
+ {
+ // Please FIXME: Show a message box if AllowMacroExecution is false
+ return;
+ }
+ }
+
+ std::unique_ptr<weld::TreeIter> xParentIter = m_xScriptsBox->make_iterator(xIter.get());
+ bool bParent = m_xScriptsBox->iter_parent(*xParentIter);
+ while (bParent && !mspNode.is() )
+ {
+ SFEntry* mspUserData = weld::fromId<SFEntry*>(m_xScriptsBox->get_id(*xParentIter));
+ mspNode.set( mspUserData->GetNode() , UNO_QUERY );
+ bParent = m_xScriptsBox->iter_parent(*xParentIter);
+ }
+ xProp->getPropertyValue("URI") >>= tmpString;
+ const OUString scriptURL( tmpString );
+
+ if ( mspNode.is() )
+ {
+ try
+ {
+ Reference< provider::XScript > xScript(
+ mspNode->getScript( scriptURL ), UNO_SET_THROW );
+
+ const Sequence< Any > args(0);
+ Sequence< sal_Int16 > outIndex;
+ Sequence< Any > outArgs( 0 );
+ xScript->invoke( args, outIndex, outArgs );
+ }
+ catch ( reflection::InvocationTargetException& ite )
+ {
+ SvxScriptErrorDialog::ShowAsyncErrorDialog(m_pParent, css::uno::Any(ite));
+ }
+ catch ( provider::ScriptFrameworkErrorException& ite )
+ {
+ SvxScriptErrorDialog::ShowAsyncErrorDialog(m_pParent, css::uno::Any(ite));
+ }
+ catch ( RuntimeException& re )
+ {
+ SvxScriptErrorDialog::ShowAsyncErrorDialog(m_pParent, css::uno::Any(re));
+ }
+ catch ( Exception& e )
+ {
+ SvxScriptErrorDialog::ShowAsyncErrorDialog(m_pParent, css::uno::Any(e));
+ }
+ }
+ StoreCurrentSelection();
+ m_xDialog->response(RET_CANCEL);
+ }
+ else if ( &rButton == m_xEditButton.get() )
+ {
+ Reference< script::XInvocation > xInv( node, UNO_QUERY );
+ if ( xInv.is() )
+ {
+ StoreCurrentSelection();
+ m_xDialog->response(RET_CANCEL);
+ Sequence< Any > args(0);
+ Sequence< Any > outArgs( 0 );
+ Sequence< sal_Int16 > outIndex;
+ try
+ {
+ // ISSUE need code to run script here
+ xInv->invoke( "Editable", args, outIndex, outArgs );
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to invoke" );
+ }
+ }
+ }
+ else if ( &rButton == m_xCreateButton.get() )
+ {
+ createEntry(*xIter);
+ }
+ else if ( &rButton == m_xDelButton.get() )
+ {
+ deleteEntry(*xIter);
+ }
+ else if ( &rButton == m_xRenameButton.get() )
+ {
+ renameEntry(*xIter);
+ }
+}
+
+Reference< browse::XBrowseNode > SvxScriptOrgDialog::getBrowseNode(const weld::TreeIter& rEntry)
+{
+ Reference< browse::XBrowseNode > node;
+ SFEntry* userData = weld::fromId<SFEntry*>(m_xScriptsBox->get_id(rEntry));
+ if (userData)
+ {
+ node = userData->GetNode();
+ }
+ return node;
+}
+
+Reference< XModel > SvxScriptOrgDialog::getModel(const weld::TreeIter& rEntry)
+{
+ Reference< XModel > model;
+ SFEntry* userData = weld::fromId<SFEntry*>(m_xScriptsBox->get_id(rEntry));
+ if ( userData )
+ {
+ model = userData->GetModel();
+ }
+ return model;
+}
+
+void SvxScriptOrgDialog::createEntry(const weld::TreeIter& rEntry)
+{
+
+ Reference< browse::XBrowseNode > aChildNode;
+ Reference< browse::XBrowseNode > node = getBrowseNode( rEntry );
+ Reference< script::XInvocation > xInv( node, UNO_QUERY );
+
+ if ( xInv.is() )
+ {
+ OUString aNewName;
+ OUString aNewStdName;
+ InputDialogMode nMode = InputDialogMode::NEWLIB;
+ if (m_xScriptsBox->get_iter_depth(rEntry) == 0)
+ {
+ aNewStdName = "Library" ;
+ }
+ else
+ {
+ aNewStdName = "Macro" ;
+ nMode = InputDialogMode::NEWMACRO;
+ }
+ //do we need L10N for this? ie something like:
+ //String aNewStdName( ResId( STR_STDMODULENAME ) );
+ bool bValid = false;
+ sal_Int32 i = 1;
+
+ Sequence< Reference< browse::XBrowseNode > > childNodes;
+ // no children => ok to create Parcel1 or Script1 without checking
+ try
+ {
+ if( !node->hasChildNodes() )
+ {
+ aNewName = aNewStdName + OUString::number(i);
+ bValid = true;
+ }
+ else
+ {
+ childNodes = node->getChildNodes();
+ }
+ }
+ catch ( Exception& )
+ {
+ // ignore, will continue on with empty sequence
+ }
+
+ OUString extn;
+ while ( !bValid )
+ {
+ aNewName = aNewStdName + OUString::number(i);
+ bool bFound = false;
+ if(childNodes.hasElements() )
+ {
+ OUString nodeName = childNodes[0]->getName();
+ sal_Int32 extnPos = nodeName.lastIndexOf( '.' );
+ if(extnPos>0)
+ extn = nodeName.copy(extnPos);
+ }
+ for( const Reference< browse::XBrowseNode >& n : std::as_const(childNodes) )
+ {
+ if (OUStringConcatenation(aNewName+extn) == n->getName())
+ {
+ bFound = true;
+ break;
+ }
+ }
+ if( bFound )
+ {
+ i++;
+ }
+ else
+ {
+ bValid = true;
+ }
+ }
+
+ CuiInputDialog aNewDlg(m_xDialog.get(), nMode);
+ aNewDlg.SetObjectName(aNewName);
+
+ do
+ {
+ if (aNewDlg.run() && !aNewDlg.GetObjectName().isEmpty())
+ {
+ OUString aUserSuppliedName = aNewDlg.GetObjectName();
+ bValid = true;
+ for( const Reference< browse::XBrowseNode >& n : std::as_const(childNodes) )
+ {
+ if (OUStringConcatenation(aUserSuppliedName+extn) == n->getName())
+ {
+ bValid = false;
+ OUString aError = m_createErrStr + m_createDupStr;
+
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, aError));
+ xErrorBox->set_title(m_createErrTitleStr);
+ xErrorBox->run();
+ aNewDlg.SetObjectName(aNewName);
+ break;
+ }
+ }
+ if( bValid )
+ aNewName = aUserSuppliedName;
+ }
+ else
+ {
+ // user hit cancel or hit OK with nothing in the editbox
+
+ return;
+ }
+ }
+ while ( !bValid );
+
+ // open up parent node (which ensures it's loaded)
+ m_xScriptsBox->expand_row(rEntry);
+
+ Sequence< Any > args{ Any(aNewName) };
+ Sequence< Any > outArgs;
+ Sequence< sal_Int16 > outIndex;
+ try
+ {
+ Any aResult = xInv->invoke( "Creatable", args, outIndex, outArgs );
+ Reference< browse::XBrowseNode > newNode( aResult, UNO_QUERY );
+ aChildNode = newNode;
+
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Create" );
+ }
+ }
+ if ( aChildNode.is() )
+ {
+ OUString aChildName = aChildNode->getName();
+
+ Reference<XModel> xDocumentModel = getModel( rEntry );
+
+ // ISSUE do we need to remove all entries for parent
+ // to achieve sort? Just need to determine position
+ // -- Basic doesn't do this on create.
+ // Suppose we could avoid this too. -> created nodes are
+ // not in alphabetical order
+ if ( aChildNode->getType() == browse::BrowseNodeTypes::SCRIPT )
+ {
+ insertEntry(aChildName, RID_CUIBMP_MACRO, &rEntry, false,
+ std::make_unique<SFEntry>(aChildNode,xDocumentModel), true);
+ }
+ else
+ {
+ insertEntry(aChildName, RID_CUIBMP_LIB, &rEntry, false,
+ std::make_unique<SFEntry>(aChildNode,xDocumentModel), true);
+
+ // If the Parent is not loaded then set to
+ // loaded, this will prevent RequestingChildren ( called
+ // from vcl via RequestingChildren ) from
+ // creating new ( duplicate ) children
+ SFEntry* userData = weld::fromId<SFEntry*>(m_xScriptsBox->get_id(rEntry));
+ if ( userData && !userData->isLoaded() )
+ {
+ userData->setLoaded();
+ }
+ }
+ }
+ else
+ {
+ //ISSUE L10N & message from exception?
+ OUString aError( m_createErrStr );
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, aError));
+ xErrorBox->set_title(m_createErrTitleStr);
+ xErrorBox->run();
+ }
+}
+
+void SvxScriptOrgDialog::renameEntry(const weld::TreeIter& rEntry)
+{
+
+ Reference< browse::XBrowseNode > aChildNode;
+ Reference< browse::XBrowseNode > node = getBrowseNode(rEntry);
+ Reference< script::XInvocation > xInv( node, UNO_QUERY );
+
+ if ( xInv.is() )
+ {
+ OUString aNewName = node->getName();
+ sal_Int32 extnPos = aNewName.lastIndexOf( '.' );
+ if(extnPos>0)
+ {
+ aNewName = aNewName.copy(0,extnPos);
+ }
+ CuiInputDialog aNewDlg(m_xDialog.get(), InputDialogMode::RENAME);
+ aNewDlg.SetObjectName(aNewName);
+
+ if (!aNewDlg.run() || aNewDlg.GetObjectName().isEmpty())
+ return; // user hit cancel or hit OK with nothing in the editbox
+
+ aNewName = aNewDlg.GetObjectName();
+
+ Sequence< Any > args{ Any(aNewName) };
+ Sequence< Any > outArgs;
+ Sequence< sal_Int16 > outIndex;
+ try
+ {
+ Any aResult = xInv->invoke( "Renamable", args, outIndex, outArgs );
+ Reference< browse::XBrowseNode > newNode( aResult, UNO_QUERY );
+ aChildNode = newNode;
+
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to Rename" );
+ }
+ }
+ if ( aChildNode.is() )
+ {
+ m_xScriptsBox->set_text(rEntry, aChildNode->getName());
+ m_xScriptsBox->set_cursor(rEntry);
+ m_xScriptsBox->select(rEntry);
+
+ }
+ else
+ {
+ //ISSUE L10N & message from exception?
+ OUString aError( m_renameErrStr );
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, aError));
+ xErrorBox->set_title(m_renameErrTitleStr);
+ xErrorBox->run();
+ }
+}
+
+void SvxScriptOrgDialog::deleteEntry(const weld::TreeIter& rEntry)
+{
+ bool result = false;
+ Reference< browse::XBrowseNode > node = getBrowseNode(rEntry);
+ // ISSUE L10N string & can we center list?
+ OUString aQuery = m_delQueryStr + getListOfChildren( node, 0 );
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Question, VclButtonsType::YesNo, aQuery));
+ xQueryBox->set_title(m_delQueryTitleStr);
+ if (xQueryBox->run() == RET_NO)
+ {
+ return;
+ }
+
+ Reference< script::XInvocation > xInv( node, UNO_QUERY );
+ if ( xInv.is() )
+ {
+ Sequence< Any > args( 0 );
+ Sequence< Any > outArgs( 0 );
+ Sequence< sal_Int16 > outIndex;
+ try
+ {
+ Any aResult = xInv->invoke( "Deletable", args, outIndex, outArgs );
+ aResult >>= result; // or do we just assume true if no exception ?
+ }
+ catch( Exception const & )
+ {
+ TOOLS_WARN_EXCEPTION("cui.dialogs", "Caught exception trying to delete" );
+ }
+ }
+
+ if ( result )
+ {
+ deleteTree(rEntry);
+ m_xScriptsBox->remove(rEntry);
+ }
+ else
+ {
+ //ISSUE L10N & message from exception?
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok, m_delErrStr));
+ xErrorBox->set_title(m_delErrTitleStr);
+ xErrorBox->run();
+ }
+
+}
+
+bool SvxScriptOrgDialog::getBoolProperty( Reference< beans::XPropertySet > const & xProps,
+ OUString const & propName )
+{
+ bool result = false;
+ try
+ {
+ xProps->getPropertyValue( propName ) >>= result;
+ }
+ catch ( Exception& )
+ {
+ return result;
+ }
+ return result;
+}
+
+OUString SvxScriptOrgDialog::getListOfChildren( const Reference< browse::XBrowseNode >& node, int depth )
+{
+ OUStringBuffer result = "\n";
+ for( int i=0;i<=depth;i++ )
+ {
+ result.append("\t");
+ }
+ result.append(node->getName());
+
+ try
+ {
+ if ( node->hasChildNodes() )
+ {
+ const Sequence< Reference< browse::XBrowseNode > > children
+ = node->getChildNodes();
+ for( const Reference< browse::XBrowseNode >& n : children )
+ {
+ result.append( getListOfChildren( n , depth+1 ) );
+ }
+ }
+ }
+ catch ( Exception& )
+ {
+ // ignore, will return an empty string
+ }
+
+ return result.makeStringAndClear();
+}
+
+Selection_hash SvxScriptOrgDialog::m_lastSelection;
+
+void SvxScriptOrgDialog::StoreCurrentSelection()
+{
+ std::unique_ptr<weld::TreeIter> xIter = m_xScriptsBox->make_iterator();
+ if (!m_xScriptsBox->get_selected(xIter.get()))
+ return;
+ OUString aDescription;
+ bool bEntry;
+ do
+ {
+ aDescription = m_xScriptsBox->get_text(*xIter) + aDescription;
+ bEntry = m_xScriptsBox->iter_parent(*xIter);
+ if (bEntry)
+ aDescription = ";" + aDescription;
+ }
+ while (bEntry);
+ OUString sDesc( aDescription );
+ m_lastSelection[ m_sLanguage ] = sDesc;
+}
+
+void SvxScriptOrgDialog::RestorePreviousSelection()
+{
+ OUString aStoredEntry = m_lastSelection[ m_sLanguage ];
+ if( aStoredEntry.isEmpty() )
+ return;
+ std::unique_ptr<weld::TreeIter> xEntry;
+ std::unique_ptr<weld::TreeIter> xTmpEntry(m_xScriptsBox->make_iterator());
+ sal_Int32 nIndex = 0;
+ while (nIndex != -1)
+ {
+ std::u16string_view aTmp( o3tl::getToken(aStoredEntry, 0, ';', nIndex ) );
+
+ bool bTmpEntry;
+ if (!xEntry)
+ {
+ xEntry = m_xScriptsBox->make_iterator();
+ bTmpEntry = m_xScriptsBox->get_iter_first(*xEntry);
+ m_xScriptsBox->copy_iterator(*xEntry, *xTmpEntry);
+ }
+ else
+ {
+ m_xScriptsBox->copy_iterator(*xEntry, *xTmpEntry);
+ bTmpEntry = m_xScriptsBox->iter_children(*xTmpEntry);
+ }
+
+ while (bTmpEntry)
+ {
+ if (m_xScriptsBox->get_text(*xTmpEntry) == aTmp)
+ {
+ m_xScriptsBox->copy_iterator(*xTmpEntry, *xEntry);
+ break;
+ }
+ bTmpEntry = m_xScriptsBox->iter_next_sibling(*xTmpEntry);
+ }
+
+ if (!bTmpEntry)
+ break;
+
+ m_xScriptsBox->expand_row(*xEntry);
+ }
+
+ if (xEntry)
+ {
+ m_xScriptsBox->set_cursor(*xEntry);
+ ScriptSelectHdl(*m_xScriptsBox);
+ }
+}
+
+namespace {
+
+OUString ReplaceString(
+ const OUString& source,
+ const OUString& token,
+ std::u16string_view value )
+{
+ sal_Int32 pos = source.indexOf( token );
+
+ if ( pos != -1 && !value.empty() )
+ {
+ return source.replaceAt( pos, token.getLength(), value );
+ }
+ else
+ {
+ return source;
+ }
+}
+
+OUString FormatErrorString(
+ const OUString& unformatted,
+ std::u16string_view language,
+ std::u16string_view script,
+ std::u16string_view line,
+ std::u16string_view type,
+ std::u16string_view message )
+{
+ OUString result = unformatted;
+
+ result = ReplaceString(result, "%LANGUAGENAME", language );
+ result = ReplaceString(result, "%SCRIPTNAME", script );
+ result = ReplaceString(result, "%LINENUMBER", line );
+
+ if ( !type.empty() )
+ {
+ result += "\n\n" + CuiResId(RID_CUISTR_ERROR_TYPE_LABEL) + " " + type;
+ }
+
+ if ( !message.empty() )
+ {
+ result += "\n\n" + CuiResId(RID_CUISTR_ERROR_MESSAGE_LABEL) + " " + message;
+ }
+
+ return result;
+}
+
+OUString GetErrorMessage(
+ const provider::ScriptErrorRaisedException& eScriptError )
+{
+ OUString unformatted = CuiResId( RID_CUISTR_ERROR_AT_LINE );
+
+ OUString unknown("UNKNOWN");
+ OUString language = unknown;
+ OUString script = unknown;
+ OUString line = unknown;
+ OUString message = eScriptError.Message;
+
+ if ( !eScriptError.language.isEmpty() )
+ {
+ language = eScriptError.language;
+ }
+
+ if ( !eScriptError.scriptName.isEmpty() )
+ {
+ script = eScriptError.scriptName;
+ }
+
+ if ( !eScriptError.Message.isEmpty() )
+ {
+ message = eScriptError.Message;
+ }
+ if ( eScriptError.lineNum != -1 )
+ {
+ line = OUString::number( eScriptError.lineNum );
+ unformatted = CuiResId( RID_CUISTR_ERROR_AT_LINE );
+ }
+ else
+ {
+ unformatted = CuiResId( RID_CUISTR_ERROR_RUNNING );
+ }
+
+ return FormatErrorString(
+ unformatted, language, script, line, u"", message );
+}
+
+OUString GetErrorMessage(
+ const provider::ScriptExceptionRaisedException& eScriptException )
+{
+ OUString unformatted = CuiResId( RID_CUISTR_EXCEPTION_AT_LINE );
+
+ OUString unknown("UNKNOWN");
+ OUString language = unknown;
+ OUString script = unknown;
+ OUString line = unknown;
+ OUString type = unknown;
+ OUString message = eScriptException.Message;
+
+ if ( !eScriptException.language.isEmpty() )
+ {
+ language = eScriptException.language;
+ }
+ if ( !eScriptException.scriptName.isEmpty() )
+ {
+ script = eScriptException.scriptName;
+ }
+
+ if ( !eScriptException.Message.isEmpty() )
+ {
+ message = eScriptException.Message;
+ }
+
+ if ( eScriptException.lineNum != -1 )
+ {
+ line = OUString::number( eScriptException.lineNum );
+ unformatted = CuiResId( RID_CUISTR_EXCEPTION_AT_LINE );
+ }
+ else
+ {
+ unformatted = CuiResId( RID_CUISTR_EXCEPTION_RUNNING );
+ }
+
+ if ( !eScriptException.exceptionType.isEmpty() )
+ {
+ type = eScriptException.exceptionType;
+ }
+
+ return FormatErrorString(
+ unformatted, language, script, line, type, message );
+
+}
+OUString GetErrorMessage(
+ const provider::ScriptFrameworkErrorException& sError )
+{
+ OUString unformatted = CuiResId( RID_CUISTR_FRAMEWORK_ERROR_RUNNING );
+
+ OUString language("UNKNOWN");
+
+ OUString script("UNKNOWN");
+
+ OUString message;
+
+ if ( !sError.scriptName.isEmpty() )
+ {
+ script = sError.scriptName;
+ }
+ if ( !sError.language.isEmpty() )
+ {
+ language = sError.language;
+ }
+ if ( sError.errorType == provider::ScriptFrameworkErrorType::NOTSUPPORTED )
+ {
+ message = CuiResId(RID_CUISTR_ERROR_LANG_NOT_SUPPORTED);
+ message = ReplaceString(message, "%LANGUAGENAME", language );
+
+ }
+ else
+ {
+ message = sError.Message;
+ }
+ return FormatErrorString(
+ unformatted, language, script, u"", std::u16string_view(), message );
+}
+
+OUString GetErrorMessage( const css::uno::Any& aException )
+{
+ if ( aException.getValueType() ==
+ cppu::UnoType<reflection::InvocationTargetException>::get())
+ {
+ reflection::InvocationTargetException ite;
+ aException >>= ite;
+ if ( ite.TargetException.getValueType() == cppu::UnoType<provider::ScriptErrorRaisedException>::get())
+ {
+ // Error raised by script
+ provider::ScriptErrorRaisedException scriptError;
+ ite.TargetException >>= scriptError;
+ return GetErrorMessage( scriptError );
+ }
+ else if ( ite.TargetException.getValueType() == cppu::UnoType<provider::ScriptExceptionRaisedException>::get())
+ {
+ // Exception raised by script
+ provider::ScriptExceptionRaisedException scriptException;
+ ite.TargetException >>= scriptException;
+ return GetErrorMessage( scriptException );
+ }
+ else
+ {
+ // Unknown error, shouldn't happen
+ // OSL_ASSERT(...)
+ }
+
+ }
+ else if ( aException.getValueType() == cppu::UnoType<provider::ScriptFrameworkErrorException>::get())
+ {
+ // A Script Framework error has occurred
+ provider::ScriptFrameworkErrorException sfe;
+ aException >>= sfe;
+ return GetErrorMessage( sfe );
+
+ }
+ // unknown exception
+ auto msg = aException.getValueTypeName();
+ Exception e;
+ if ( (aException >>= e) && !e.Message.isEmpty() )
+ {
+ msg += ": " + e.Message;
+ }
+ return msg;
+}
+
+}
+
+// Show Error dialog asynchronously
+void SvxScriptErrorDialog::ShowAsyncErrorDialog( weld::Window* pParent, css::uno::Any const & aException )
+{
+ SolarMutexGuard aGuard;
+ OUString sMessage = GetErrorMessage( aException );
+
+ // Pass a copy of the message to the ShowDialog method as the
+ // SvxScriptErrorDialog may be deleted before ShowDialog is called
+ DialogData* pData = new DialogData;
+ pData->sMessage = sMessage;
+ pData->pParent = pParent;
+ Application::PostUserEvent(
+ LINK( nullptr, SvxScriptErrorDialog, ShowDialog ),
+ pData );
+}
+
+IMPL_STATIC_LINK( SvxScriptErrorDialog, ShowDialog, void*, p, void )
+{
+ std::unique_ptr<DialogData> xData(static_cast<DialogData*>(p));
+ OUString message = xData->sMessage;
+
+ if ( message.isEmpty() )
+ message = CuiResId( RID_CUISTR_ERROR_TITLE );
+
+ std::shared_ptr<weld::MessageDialog> xBox;
+ xBox.reset(Application::CreateMessageDialog(
+ xData->pParent,
+ VclMessageType::Warning,
+ VclButtonsType::Ok,
+ message,
+ comphelper::LibreOfficeKit::isActive()));
+
+ xBox->set_title(CuiResId(RID_CUISTR_ERROR_TITLE));
+
+ xBox->runAsync(xBox, [](sal_Int32 /*nResult*/) {});
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */