/* -*- 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 <comphelper/diagnose_ex.hxx>
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;
const Reference< XComponentContext >& xCtx(
comphelper::getProcessComponentContext() );
Sequence< Reference< browse::XBrowseNode > > children;
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 : children)
{
bool app = false;
OUString uiName = childNode->getName();
OUString factoryURL;
if (uiName == "user")
{
app = true;
uiName = m_sMyMacros;
}
else if (uiName == "share")
{
app = true;
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 : moduleDescr)
{
if ( prop.Name == "ooSetupFactoryEmptyDocumentURL" )
{
prop.Value >>= factoryURL;
break;
}
}
}
}
Reference< browse::XBrowseNode > langEntries =
getLangNodeFromRootNode( childNode, language );
insertEntry( uiName, app ? RID_CUIBMP_HARDDISK : 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 : 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, u"cui/ui/newlibdialog.ui"_ustr, u"NewLibDialog"_ustr)
, m_xEdit(m_xBuilder->weld_entry(u"entry"_ustr))
{
m_xEdit->grab_focus();
std::unique_ptr<weld::Label> xNewLibFT(m_xBuilder->weld_label(u"newlibft"_ustr));
if ( nMode == InputDialogMode::NEWMACRO )
{
xNewLibFT->hide();
std::unique_ptr<weld::Label> xNewMacroFT(m_xBuilder->weld_label(u"newmacroft"_ustr));
xNewMacroFT->show();
std::unique_ptr<weld::Label> xAltTitle(m_xBuilder->weld_label(u"altmacrotitle"_ustr));
m_xDialog->set_title(xAltTitle->get_label());
}
else if ( nMode == InputDialogMode::RENAME )
{
xNewLibFT->hide();
std::unique_ptr<weld::Label> xRenameFT(m_xBuilder->weld_label(u"renameft"_ustr));
xRenameFT->show();
std::unique_ptr<weld::Label> xAltTitle(m_xBuilder->weld_label(u"altrenametitle"_ustr));
m_xDialog->set_title(xAltTitle->get_label());
}
}
// ScriptOrgDialog ------------------------------------------------------------
SvxScriptOrgDialog::SvxScriptOrgDialog(weld::Window* pParent, OUString language)
: SfxDialogController(pParent, u"cui/ui/scriptorganizer.ui"_ustr, u"ScriptOrganizerDialog"_ustr)
, 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(u"scripts"_ustr))
, m_xScratchIter(m_xScriptsBox->make_iterator())
, m_xRunButton(m_xBuilder->weld_button(u"ok"_ustr))
, m_xCloseButton(m_xBuilder->weld_button(u"close"_ustr))
, m_xCreateButton(m_xBuilder->weld_button(u"create"_ustr))
, m_xEditButton(m_xBuilder->weld_button(u"edit"_ustr))
, m_xRenameButton(m_xBuilder->weld_button(u"rename"_ustr))
, m_xDelButton(m_xBuilder->weld_button(u"delete"_ustr))
{
// 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(u"Editable"_ustr);
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(u"URI"_ustr) >>= 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( u"Editable"_ustr, 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 : childNodes)
{
if (Concat2View(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 : childNodes)
{
if (Concat2View(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( u"Creatable"_ustr, args, outIndex, outArgs );
aChildNode.set(aResult, UNO_QUERY);
}
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( u"Renamable"_ustr, args, outIndex, outArgs );
aChildNode.set(aResult, UNO_QUERY);
}
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( u"Deletable"_ustr, 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);
m_lastSelection[m_sLanguage] = aDescription;
}
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,
std::u16string_view token,
std::u16string_view value )
{
sal_Int32 pos = source.indexOf( token );
if ( pos != -1 && !value.empty() )
{
return source.replaceAt( pos, token.size(), 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, u"%LANGUAGENAME", language );
result = ReplaceString(result, u"%SCRIPTNAME", script );
result = ReplaceString(result, u"%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(u"UNKNOWN"_ustr);
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(u"UNKNOWN"_ustr);
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(u"UNKNOWN"_ustr);
OUString script(u"UNKNOWN"_ustr);
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, u"%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;
// 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 = GetErrorMessage(aException);
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));
xBox->set_title(CuiResId(RID_CUISTR_ERROR_TITLE));
xBox->runAsync(xBox, [](sal_Int32 /*nResult*/) {});
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V547 Expression 'result' is always false.