pythonscript: Implement the XCopyableBrowseNode interface
Implements the XCopyableBrowseNode interface on the Python script provider. Change-Id: I17c6916567518fd9f28d11724def4a0d98f53ed9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207737 Tested-by: Jenkins Reviewed-by: Neil Roberts <nroberts@libreoffice.org>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
|
||||
#
|
||||
# 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/.
|
||||
#
|
||||
|
||||
$(eval $(call gb_CppunitTest_CppunitTest,scripting_pythonscript))
|
||||
|
||||
$(eval $(call gb_CppunitTest_add_exception_objects,scripting_pythonscript, \
|
||||
scripting/qa/cppunit/pythonscript/PythonScriptTest \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_libraries,scripting_pythonscript, \
|
||||
cppu \
|
||||
cppuhelper \
|
||||
pythonloader \
|
||||
pyuno \
|
||||
sal \
|
||||
subsequenttest \
|
||||
test \
|
||||
unotest \
|
||||
utl \
|
||||
tl \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_externals,scripting_pythonscript,\
|
||||
boost_headers \
|
||||
libxml2 \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_api,scripting_pythonscript,\
|
||||
udkapi \
|
||||
offapi \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_packages,scripting_pythonscript,scripting_scriptproviderforpython))
|
||||
$(call gb_CppunitTest_get_target,scripting_pythonscript): \
|
||||
UNO_SERVICES += $(SRCDIR)/scripting/source/pyprov/scriptproviderforpython.rdb
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_components,scripting_pythonscript,\
|
||||
pyuno/source/loader/pythonloader \
|
||||
))
|
||||
|
||||
$(eval $(call gb_CppunitTest_use_ure,scripting_pythonscript))
|
||||
$(eval $(call gb_CppunitTest_use_vcl,scripting_pythonscript))
|
||||
$(eval $(call gb_CppunitTest_use_rdb,scripting_pythonscript,services))
|
||||
$(eval $(call gb_CppunitTest_use_configuration,scripting_pythonscript))
|
||||
|
||||
# vim: set noet sw=4 ts=4:
|
||||
@@ -50,6 +50,7 @@ $(eval $(call gb_Module_add_targets,scripting,\
|
||||
$(eval $(call gb_Module_add_check_targets,scripting,\
|
||||
$(if $(ENABLE_QUICKJS),CppunitTest_scripting_jsprov) \
|
||||
$(if $(ENABLE_SCRIPTING_BEANSHELL),CppunitTest_scripting_beanshell) \
|
||||
$(if $(DISABLE_PYTHON),,CppunitTest_scripting_pythonscript) \
|
||||
))
|
||||
|
||||
$(eval $(call gb_Module_add_subsequentcheck_targets,scripting,\
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
||||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
#include <sal/config.h>
|
||||
|
||||
#include <test/unoapi_test.hxx>
|
||||
|
||||
#include <com/sun/star/beans/XPropertySet.hpp>
|
||||
#include <com/sun/star/io/TextOutputStream.hpp>
|
||||
#include <com/sun/star/io/XActiveDataSource.hpp>
|
||||
#include <com/sun/star/lang/XSingleComponentFactory.hpp>
|
||||
#include <com/sun/star/script/browse/XBrowseNode.hpp>
|
||||
#include <com/sun/star/script/browse/XCopyableBrowseNode.hpp>
|
||||
#include <com/sun/star/script/provider/ScriptURIHelper.hpp>
|
||||
#include <com/sun/star/script/provider/XScriptProvider.hpp>
|
||||
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
|
||||
#include <com/sun/star/ucb/UniversalContentBroker.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
class PythonScriptTest : public UnoApiTest
|
||||
{
|
||||
public:
|
||||
PythonScriptTest()
|
||||
: UnoApiTest(u"/scripting/qa/extras"_ustr)
|
||||
{
|
||||
}
|
||||
|
||||
void setUp() override;
|
||||
void tearDown() override;
|
||||
|
||||
private:
|
||||
css::uno::Reference<css::ucb::XSimpleFileAccess3> m_xFileAccess;
|
||||
css::uno::Reference<css::script::provider::XScriptURIHelper> m_xUriHelper;
|
||||
css::uno::Reference<css::script::provider::XScriptProvider> m_xScriptProvider;
|
||||
|
||||
void createDummyMacro();
|
||||
|
||||
void testCopyable();
|
||||
|
||||
CPPUNIT_TEST_SUITE(PythonScriptTest);
|
||||
CPPUNIT_TEST(testCopyable);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
};
|
||||
|
||||
void PythonScriptTest::setUp()
|
||||
{
|
||||
UnoApiTest::setUp();
|
||||
|
||||
m_xFileAccess = css::ucb::SimpleFileAccess::create(m_xContext);
|
||||
|
||||
// The ExpandContentProvider is needed for ScriptURIHelper to work
|
||||
css::uno::Reference<css::ucb::XUniversalContentBroker> xUcb
|
||||
= css::ucb::UniversalContentBroker::create(m_xContext);
|
||||
css::uno::Reference<css::ucb::XContentProvider> xExpandProvider(
|
||||
m_xSFactory->createInstance(u"com.sun.star.ucb.ExpandContentProvider"_ustr),
|
||||
css::uno::UNO_QUERY_THROW);
|
||||
xUcb->registerContentProvider(xExpandProvider, u"vnd.sun.star.expand"_ustr, true);
|
||||
|
||||
m_xUriHelper = css::script::provider::ScriptURIHelper::create(getComponentContext(),
|
||||
u"Python"_ustr, u"user"_ustr);
|
||||
|
||||
css::uno::Sequence<css::uno::Any> aArgs(1);
|
||||
aArgs.getArray()[0] <<= u"user"_ustr;
|
||||
|
||||
m_xScriptProvider.set(
|
||||
m_xFactory->createInstanceWithArgumentsAndContext(
|
||||
"com.sun.star.script.provider.ScriptProviderForPython", aArgs, m_xContext),
|
||||
css::uno::UNO_QUERY_THROW);
|
||||
}
|
||||
|
||||
void PythonScriptTest::tearDown()
|
||||
{
|
||||
m_xScriptProvider.clear();
|
||||
|
||||
// Delete the Python scripting directory so that each test can have a clean slate
|
||||
if (m_xFileAccess->isFolder(m_xUriHelper->getRootStorageURI()))
|
||||
m_xFileAccess->kill(m_xUriHelper->getRootStorageURI());
|
||||
|
||||
m_xFileAccess.clear();
|
||||
m_xUriHelper.clear();
|
||||
|
||||
UnoApiTest::tearDown();
|
||||
}
|
||||
|
||||
void PythonScriptTest::createDummyMacro()
|
||||
{
|
||||
// Create a dummy macro in the script directory
|
||||
css::uno::Reference<css::io::XOutputStream> xOutput = m_xFileAccess->openFileWrite(
|
||||
m_xUriHelper->getRootStorageURI() + "/MyLibrary/MyScript.py");
|
||||
css::uno::Reference<css::io::XTextOutputStream> xTextOutput
|
||||
= css::io::TextOutputStream::create(m_xContext);
|
||||
xTextOutput->setEncoding(u"UTF-8"_ustr);
|
||||
|
||||
css::uno::Reference<css::io::XActiveDataSource> xActiveDataSource(xTextOutput,
|
||||
css::uno::UNO_QUERY_THROW);
|
||||
xActiveDataSource->setOutputStream(xOutput);
|
||||
|
||||
xTextOutput->writeString(u"def MyMacro():\n pass\n"_ustr);
|
||||
xTextOutput->closeOutput();
|
||||
}
|
||||
|
||||
bool isCopyableNode(const css::uno::Reference<css::script::browse::XBrowseNode>& xNode)
|
||||
{
|
||||
css::uno::Reference<css::script::browse::XCopyableBrowseNode> xCopyable(xNode,
|
||||
css::uno::UNO_QUERY);
|
||||
|
||||
return xCopyable.is() && xCopyable->isCopyableNode();
|
||||
}
|
||||
|
||||
void PythonScriptTest::testCopyable()
|
||||
{
|
||||
createDummyMacro();
|
||||
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xRootNode(m_xScriptProvider,
|
||||
css::uno::UNO_QUERY_THROW);
|
||||
|
||||
// The root node shouldn’t be copyable
|
||||
CPPUNIT_ASSERT(!isCopyableNode(xRootNode));
|
||||
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xLibrary = xRootNode->getChildNodes()[0];
|
||||
CPPUNIT_ASSERT_EQUAL(u"MyLibrary"_ustr, xLibrary->getName());
|
||||
|
||||
// The library shouldn’t be copyable
|
||||
CPPUNIT_ASSERT(!isCopyableNode(xLibrary));
|
||||
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xFile = xLibrary->getChildNodes()[0];
|
||||
CPPUNIT_ASSERT_EQUAL(u"MyScript"_ustr, xFile->getName());
|
||||
|
||||
// File nodes are copyable
|
||||
CPPUNIT_ASSERT(isCopyableNode(xFile));
|
||||
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xMacro = xFile->getChildNodes()[0];
|
||||
CPPUNIT_ASSERT_EQUAL(u"MyMacro"_ustr, xMacro->getName());
|
||||
|
||||
// Macro nodes are not copyable
|
||||
CPPUNIT_ASSERT(!isCopyableNode(xMacro));
|
||||
|
||||
css::uno::Reference<css::script::browse::XCopyableBrowseNode> xCopyable(
|
||||
xFile, css::uno::UNO_QUERY_THROW);
|
||||
|
||||
// We can copy to the root level of the Python hierarchy
|
||||
CPPUNIT_ASSERT(xCopyable->nodeCanBeCopiedTo(xRootNode));
|
||||
// We can’t copy to the same directory that the file is already in
|
||||
CPPUNIT_ASSERT(!xCopyable->nodeCanBeCopiedTo(xLibrary));
|
||||
// We can’t copy to a file
|
||||
CPPUNIT_ASSERT(!xCopyable->nodeCanBeCopiedTo(xFile));
|
||||
// or a macro
|
||||
CPPUNIT_ASSERT(!xCopyable->nodeCanBeCopiedTo(xMacro));
|
||||
|
||||
// Make a new library that we can copy to
|
||||
m_xFileAccess->createFolder(m_xUriHelper->getRootStorageURI() + "/MyOtherLibrary");
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xOtherLibrary;
|
||||
for (const auto& xChild : xRootNode->getChildNodes())
|
||||
{
|
||||
if (xChild->getName() == u"MyOtherLibrary"_ustr)
|
||||
{
|
||||
xOtherLibrary = xChild;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CPPUNIT_ASSERT(xOtherLibrary.is());
|
||||
|
||||
// We should be able to copy into the new library
|
||||
CPPUNIT_ASSERT(xCopyable->nodeCanBeCopiedTo(xOtherLibrary));
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xCopiedNode
|
||||
= xCopyable->copyNode(xOtherLibrary);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(u"MyScript"_ustr, xCopiedNode->getName());
|
||||
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xCopiedMacro
|
||||
= xCopiedNode->getChildNodes()[0];
|
||||
CPPUNIT_ASSERT_EQUAL(u"MyMacro"_ustr, xCopiedMacro->getName());
|
||||
|
||||
// Get the URI of the copied macro
|
||||
css::uno::Reference<css::beans::XPropertySet> xPropertySet(xCopiedMacro,
|
||||
css::uno::UNO_QUERY_THROW);
|
||||
css::uno::Any xURI = xPropertySet->getPropertyValue(u"URI"_ustr);
|
||||
OUString sURI;
|
||||
CPPUNIT_ASSERT(xURI >>= sURI);
|
||||
|
||||
// The URI should contain the new library name
|
||||
CPPUNIT_ASSERT(sURI.indexOf(":MyOtherLibrary|") != -1);
|
||||
|
||||
// Check that we can load the script. This should also end up checking that the contents of the
|
||||
// file contains the macro.
|
||||
CPPUNIT_ASSERT(m_xScriptProvider->getScript(sURI).is());
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(PythonScriptTest);
|
||||
|
||||
} // namespace
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
||||
@@ -42,7 +42,8 @@ from com.sun.star.uno import Exception as UnoException
|
||||
from com.sun.star.awt import XActionListener
|
||||
|
||||
from com.sun.star.script.provider import XScriptProvider, XScript, ScriptFrameworkErrorException
|
||||
from com.sun.star.script.browse import XBrowseNode, XCreatableBrowseNode, XEditableBrowseNode
|
||||
from com.sun.star.script.browse import XBrowseNode, XCreatableBrowseNode, XCopyableBrowseNode
|
||||
from com.sun.star.script.browse import XEditableBrowseNode
|
||||
from com.sun.star.script.browse.BrowseNodeTypes import SCRIPT, CONTAINER
|
||||
from com.sun.star.system import SystemShellExecuteFlags
|
||||
|
||||
@@ -715,7 +716,7 @@ class ScriptBrowseNode(unohelper.Base, XBrowseNode, XPropertySet, EditableNode):
|
||||
|
||||
|
||||
# -------------------------------------------------------
|
||||
class FileBrowseNode(unohelper.Base, XBrowseNode, EditableNode):
|
||||
class FileBrowseNode(unohelper.Base, XBrowseNode, XCopyableBrowseNode, EditableNode):
|
||||
def __init__(self, provCtx, uri, name):
|
||||
self.provCtx = provCtx
|
||||
self.uri = uri
|
||||
@@ -750,6 +751,36 @@ class FileBrowseNode(unohelper.Base, XBrowseNode, EditableNode):
|
||||
def getType(self):
|
||||
return CONTAINER
|
||||
|
||||
def isCopyableNode(self):
|
||||
return True
|
||||
|
||||
def getCopyDestinationUrl(self, xDest):
|
||||
if isinstance(xDest, PythonScriptProvider):
|
||||
xDest = xDest.dirBrowseNode
|
||||
if not isinstance(xDest, DirBrowseNode):
|
||||
return None
|
||||
|
||||
# Don’t allow copying into the same directory
|
||||
if xDest.rootUrl == self.uri[0:self.uri.rfind('/')]:
|
||||
return None
|
||||
|
||||
return xDest.rootUrl
|
||||
|
||||
def nodeCanBeCopiedTo(self, parentNode):
|
||||
return self.getCopyDestinationUrl(parentNode) != None
|
||||
|
||||
def copyNode(self, parentNode):
|
||||
dest_dir_url = self.getCopyDestinationUrl(parentNode)
|
||||
if dest_dir_url is None:
|
||||
raise IllegalArgumentException("Invalid parent node passed to copyNode", self, 0)
|
||||
|
||||
self.provCtx.sfa.createFolder(dest_dir_url)
|
||||
|
||||
target_url = f"{dest_dir_url}/{self.uri[self.uri.rfind('/') + 1:]}"
|
||||
self.provCtx.sfa.copy(self.uri, target_url)
|
||||
|
||||
return FileBrowseNode(self.provCtx, target_url, self.name)
|
||||
|
||||
|
||||
class DirBrowseNode(unohelper.Base, XBrowseNode, XCreatableBrowseNode):
|
||||
def __init__(self, provCtx, name, rootUrl):
|
||||
|
||||
Reference in New Issue
Block a user