singleprov/ScriptFile: Implement XCopyableBrowseNode
Implements XCopyableBrowseNode on the ScriptFile class so that all script providers based on the single-file provider can support copying. Change-Id: I14aa057ac432ff80e4a4841fbe5c19be082aa099 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/208161 Tested-by: Jenkins Reviewed-by: Neil Roberts <nroberts@libreoffice.org>
This commit is contained in:
@@ -12,10 +12,12 @@
|
||||
#include <com/sun/star/lang/XSingleComponentFactory.hpp>
|
||||
#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
|
||||
#include <com/sun/star/script/browse/XBrowseNode.hpp>
|
||||
#include <com/sun/star/script/browse/XCopyableBrowseNode.hpp>
|
||||
#include <com/sun/star/script/browse/XCreatableBrowseNode.hpp>
|
||||
#include <com/sun/star/script/browse/XEditableBrowseNode.hpp>
|
||||
#include <com/sun/star/script/provider/ScriptURIHelper.hpp>
|
||||
#include <com/sun/star/script/provider/XScriptProvider.hpp>
|
||||
#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
|
||||
#include <com/sun/star/text/XText.hpp>
|
||||
#include <com/sun/star/text/XTextDocument.hpp>
|
||||
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
|
||||
@@ -41,12 +43,14 @@ private:
|
||||
css::uno::Reference<css::script::provider::XScriptProvider> m_xScriptProvider;
|
||||
|
||||
css::uno::Reference<css::script::provider::XScriptProvider> createScriptProvider();
|
||||
void createDummyMacro(const OUString& sDirectoryUri);
|
||||
|
||||
void testEditableCreatable();
|
||||
void testCreate();
|
||||
void testRun();
|
||||
void testUnrelatedFile();
|
||||
void testFolder();
|
||||
void testCopyable();
|
||||
|
||||
CPPUNIT_TEST_SUITE(JsProvTest);
|
||||
CPPUNIT_TEST(testEditableCreatable);
|
||||
@@ -54,6 +58,7 @@ private:
|
||||
CPPUNIT_TEST(testRun);
|
||||
CPPUNIT_TEST(testUnrelatedFile);
|
||||
CPPUNIT_TEST(testFolder);
|
||||
CPPUNIT_TEST(testCopyable);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
};
|
||||
|
||||
@@ -144,7 +149,7 @@ bool isCreatable(const css::uno::Reference<css::script::browse::XBrowseNode>& xN
|
||||
void JsProvTest::testEditableCreatable()
|
||||
{
|
||||
// Create a dummy macro in the script directory
|
||||
m_xFileAccess->openFileWrite(m_xUriHelper->getRootStorageURI() + "/MyScript.js");
|
||||
createDummyMacro(m_xUriHelper->getRootStorageURI() + "/MyScript.js");
|
||||
|
||||
// The root node should be creatable but not editable
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xRootNode(m_xScriptProvider,
|
||||
@@ -229,11 +234,11 @@ void JsProvTest::testCreate()
|
||||
CPPUNIT_ASSERT_EQUAL(u"My Script"_ustr, xBrowseNode->getChildNodes()[0]->getName());
|
||||
}
|
||||
|
||||
void JsProvTest::testRun()
|
||||
void JsProvTest::createDummyMacro(const OUString& sDirectoryUri)
|
||||
{
|
||||
// Create a dummy macro in the script directory
|
||||
// Create a dummy macro in the given directory
|
||||
css::uno::Reference<css::io::XOutputStream> xOutput
|
||||
= m_xFileAccess->openFileWrite(m_xUriHelper->getRootStorageURI() + "/MyScript.js");
|
||||
= m_xFileAccess->openFileWrite(sDirectoryUri);
|
||||
|
||||
// Make the script insert some text in all of the writer documents
|
||||
static constexpr OString sSource
|
||||
@@ -251,6 +256,11 @@ void JsProvTest::testRun()
|
||||
xOutput->writeBytes(aSource);
|
||||
|
||||
xOutput->closeOutput();
|
||||
}
|
||||
|
||||
void JsProvTest::testRun()
|
||||
{
|
||||
createDummyMacro(m_xUriHelper->getRootStorageURI() + "/MyScript.js");
|
||||
|
||||
// Get the macro as a property set
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xBrowseNode(m_xScriptProvider,
|
||||
@@ -326,6 +336,118 @@ void JsProvTest::testFolder()
|
||||
CPPUNIT_ASSERT_EQUAL(u"MyScript"_ustr, xBrowseNode->getName());
|
||||
}
|
||||
|
||||
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 JsProvTest::testCopyable()
|
||||
{
|
||||
// Create a dummy macro in a subfolder of the script directory
|
||||
m_xFileAccess->createFolder(m_xUriHelper->getRootStorageURI() + "/SrcDir");
|
||||
createDummyMacro(m_xUriHelper->getRootStorageURI() + "/SrcDir/MyScript.js");
|
||||
|
||||
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"SrcDir"_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"MyScript"_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 JavaScript 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));
|
||||
|
||||
// We shouldn’t be able to copy to any other language providers
|
||||
css::uno::Reference<css::script::provider::XScriptProviderFactory> xMasterProviderFactory
|
||||
= css::script::provider::theMasterScriptProviderFactory::get(m_xContext);
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xMasterProvider(
|
||||
xMasterProviderFactory->createScriptProvider(css::uno::Any(u"user"_ustr)),
|
||||
css::uno::UNO_QUERY_THROW);
|
||||
for (const auto& xChild : xMasterProvider->getChildNodes())
|
||||
{
|
||||
if (xChild->getName() == u"JavaScript"_ustr)
|
||||
continue;
|
||||
CPPUNIT_ASSERT(!xCopyable->nodeCanBeCopiedTo(xChild));
|
||||
}
|
||||
|
||||
// Make a new library that we can copy to
|
||||
m_xFileAccess->createFolder(m_xUriHelper->getRootStorageURI() + "/DestDir");
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> xOtherLibrary;
|
||||
for (const auto& xChild : xRootNode->getChildNodes())
|
||||
{
|
||||
if (xChild->getName() == u"DestDir"_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"MyScript"_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(":DestDir|") != -1);
|
||||
|
||||
// Create a document to run the script on
|
||||
loadFromURL(u"private:factory/swriter"_ustr);
|
||||
|
||||
// Execute it
|
||||
css::uno::Sequence<css::uno::Any> aScriptParams;
|
||||
css::uno::Sequence<sal_Int16> aOutParamIndex;
|
||||
css::uno::Sequence<css::uno::Any> aOutParam;
|
||||
m_xScriptProvider->getScript(sURI)->invoke(aScriptParams, aOutParamIndex, aOutParam);
|
||||
|
||||
// Check that the text was inserted into our test document
|
||||
css::uno::Reference<css::text::XTextDocument> xTextDocument(mxComponent,
|
||||
css::uno::UNO_QUERY_THROW);
|
||||
CPPUNIT_ASSERT_EQUAL(u"jsprovtest"_ustr, xTextDocument->getText()->getString());
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(JsProvTest);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/* -*- 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/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <rtl/ustring.hxx>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace singleprovider
|
||||
{
|
||||
class SingleScriptFactory;
|
||||
|
||||
class SAL_LOPLUGIN_ANNOTATE("crosscast") DirectoryNode
|
||||
{
|
||||
public:
|
||||
virtual std::shared_ptr<SingleScriptFactory> getScriptFactory() const = 0;
|
||||
virtual std::optional<OUString> getDirectoryUri() const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <singleprov/directorynode.hxx>
|
||||
|
||||
#include <com/sun/star/beans/XPropertySet.hpp>
|
||||
#include <com/sun/star/script/browse/XBrowseNode.hpp>
|
||||
#include <com/sun/star/script/browse/XCreatableBrowseNode.hpp>
|
||||
@@ -27,10 +29,12 @@ class ScriptBrowser;
|
||||
class SingleScriptFactory;
|
||||
|
||||
class ScriptProvider
|
||||
: public cppu::WeakImplHelper<
|
||||
css::lang::XInitialization, css::script::browse::XBrowseNode,
|
||||
css::script::browse::XCreatableBrowseNode, css::script::browse::XEditableBrowseNode,
|
||||
css::beans::XPropertySet, css::script::provider::XScriptProvider, css::lang::XServiceInfo>
|
||||
: public cppu::WeakImplHelper<css::lang::XInitialization, css::script::browse::XBrowseNode,
|
||||
css::script::browse::XCreatableBrowseNode,
|
||||
css::script::browse::XEditableBrowseNode,
|
||||
css::beans::XPropertySet, css::script::provider::XScriptProvider,
|
||||
css::lang::XServiceInfo>,
|
||||
public DirectoryNode
|
||||
{
|
||||
public:
|
||||
// XInitialization
|
||||
@@ -79,6 +83,10 @@ public:
|
||||
const OUString& PropertyName,
|
||||
const css::uno::Reference<css::beans::XVetoableChangeListener>& aListener) override;
|
||||
|
||||
// DirectoryNode
|
||||
std::shared_ptr<SingleScriptFactory> getScriptFactory() const override;
|
||||
std::optional<OUString> getDirectoryUri() const override;
|
||||
|
||||
static SAL_DLLPUBLIC_EXPORT OUString
|
||||
getImplementationNameStatic(std::u16string_view sLanguageName);
|
||||
static SAL_DLLPUBLIC_EXPORT css::uno::Sequence<OUString>
|
||||
|
||||
@@ -134,6 +134,16 @@ css::uno::Reference<css::script::browse::XBrowseNode>
|
||||
|
||||
return new ScriptFile(m_pProviderContext, sMacroName, sUrl);
|
||||
}
|
||||
|
||||
std::shared_ptr<SingleScriptFactory> ScriptDir::getScriptFactory() const
|
||||
{
|
||||
return m_pProviderContext->m_pSingleScriptFactory;
|
||||
}
|
||||
|
||||
std::optional<OUString> ScriptDir::getDirectoryUri() const
|
||||
{
|
||||
return std::make_optional(m_sBaseUri);
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <singleprov/directorynode.hxx>
|
||||
|
||||
#include <com/sun/star/script/browse/XBrowseNode.hpp>
|
||||
#include <com/sun/star/script/browse/XCreatableBrowseNode.hpp>
|
||||
#include <cppuhelper/implbase.hxx>
|
||||
@@ -19,7 +21,8 @@ namespace singleprovider
|
||||
class ProviderContext;
|
||||
|
||||
class ScriptDir : public cppu::WeakImplHelper<css::script::browse::XBrowseNode,
|
||||
css::script::browse::XCreatableBrowseNode>
|
||||
css::script::browse::XCreatableBrowseNode>,
|
||||
public DirectoryNode
|
||||
{
|
||||
public:
|
||||
ScriptDir(const std::shared_ptr<ProviderContext>& pProviderContext);
|
||||
@@ -38,6 +41,10 @@ public:
|
||||
css::uno::Reference<css::script::browse::XBrowseNode>
|
||||
SAL_CALL createNode(const OUString& sName) override;
|
||||
|
||||
// DirectoryNode
|
||||
std::shared_ptr<SingleScriptFactory> getScriptFactory() const override;
|
||||
std::optional<OUString> getDirectoryUri() const override;
|
||||
|
||||
private:
|
||||
OUString nameFromUrl(const OUString& sUrl);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
|
||||
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
|
||||
|
||||
#include <singleprov/directorynode.hxx>
|
||||
#include <singleprov/singlescriptfactory.hxx>
|
||||
|
||||
#include "externaledit.hxx"
|
||||
@@ -45,6 +46,67 @@ sal_Bool SAL_CALL ScriptFile::hasChildNodes() { return true; }
|
||||
|
||||
sal_Int16 SAL_CALL ScriptFile::getType() { return css::script::browse::BrowseNodeTypes::CONTAINER; }
|
||||
|
||||
sal_Bool SAL_CALL ScriptFile::isCopyableNode() { return true; }
|
||||
|
||||
std::optional<OUString> ScriptFile::getCopyDestinationUri(
|
||||
const css::uno::Reference<css::script::browse::XBrowseNode>& xDest) const
|
||||
{
|
||||
const DirectoryNode* pDirectoryNode = dynamic_cast<const DirectoryNode*>(xDest.get());
|
||||
|
||||
if (!pDirectoryNode)
|
||||
return std::nullopt;
|
||||
|
||||
// Don’t allow copying into providers for other languages
|
||||
if (pDirectoryNode->getScriptFactory()->getLanguageName()
|
||||
!= m_pProviderContext->m_pSingleScriptFactory->getLanguageName())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<OUString> sDirectoryUri = pDirectoryNode->getDirectoryUri();
|
||||
|
||||
// Don’t allow copying into the same directory
|
||||
if (sDirectoryUri)
|
||||
{
|
||||
sal_Int32 nDirEnd = m_sBaseUri.lastIndexOf(u'/');
|
||||
|
||||
if (sDirectoryUri.value() == (nDirEnd == -1 ? m_sBaseUri : m_sBaseUri.copy(0, nDirEnd)))
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return sDirectoryUri;
|
||||
}
|
||||
|
||||
sal_Bool SAL_CALL ScriptFile::nodeCanBeCopiedTo(
|
||||
const css::uno::Reference<css::script::browse::XBrowseNode>& xParentNode)
|
||||
{
|
||||
return getCopyDestinationUri(xParentNode).has_value();
|
||||
}
|
||||
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> SAL_CALL
|
||||
ScriptFile::copyNode(const css::uno::Reference<css::script::browse::XBrowseNode>& xParentNode)
|
||||
{
|
||||
std::optional<OUString> sDirectoryUri = getCopyDestinationUri(xParentNode);
|
||||
|
||||
if (!sDirectoryUri)
|
||||
{
|
||||
throw css::lang::IllegalArgumentException(u"Invalid parent node passed to copyNode"_ustr,
|
||||
getXWeak(), 0);
|
||||
}
|
||||
|
||||
const css::uno::Reference<css::ucb::XSimpleFileAccess3>& xFileAccess
|
||||
= m_pProviderContext->m_xFileAccess;
|
||||
|
||||
xFileAccess->createFolder(sDirectoryUri.value());
|
||||
|
||||
std::u16string_view sBaseName = m_sBaseUri.subView(m_sBaseUri.lastIndexOf(u'/') + 1);
|
||||
OUString sTargetUri = sDirectoryUri.value() + OUStringChar('/') + sBaseName;
|
||||
|
||||
xFileAccess->copy(m_sBaseUri, sTargetUri);
|
||||
|
||||
return new ScriptFile(m_pProviderContext, m_sName, sTargetUri);
|
||||
}
|
||||
|
||||
sal_Bool SAL_CALL ScriptFile::isEditableNode()
|
||||
{
|
||||
return isEditable(m_pProviderContext, m_sBaseUri);
|
||||
|
||||
@@ -10,15 +10,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <com/sun/star/script/browse/XBrowseNode.hpp>
|
||||
#include <com/sun/star/script/browse/XCopyableBrowseNode.hpp>
|
||||
#include <com/sun/star/script/browse/XEditableBrowseNode.hpp>
|
||||
#include <cppuhelper/implbase.hxx>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace singleprovider
|
||||
{
|
||||
class ProviderContext;
|
||||
|
||||
class ScriptFile : public cppu::WeakImplHelper<css::script::browse::XBrowseNode,
|
||||
css::script::browse::XCopyableBrowseNode,
|
||||
css::script::browse::XEditableBrowseNode>
|
||||
{
|
||||
public:
|
||||
@@ -32,6 +35,13 @@ public:
|
||||
sal_Bool SAL_CALL hasChildNodes() override;
|
||||
sal_Int16 SAL_CALL getType() override;
|
||||
|
||||
// XCopyableBrowseNode
|
||||
sal_Bool SAL_CALL isCopyableNode() override;
|
||||
sal_Bool SAL_CALL nodeCanBeCopiedTo(
|
||||
const css::uno::Reference<css::script::browse::XBrowseNode>& xParentNode) override;
|
||||
css::uno::Reference<css::script::browse::XBrowseNode> SAL_CALL
|
||||
copyNode(const css::uno::Reference<css::script::browse::XBrowseNode>& xParentNode) override;
|
||||
|
||||
// XEditableBrowseNode
|
||||
sal_Bool SAL_CALL isEditableNode() override;
|
||||
sal_Bool SAL_CALL editNode() override;
|
||||
@@ -41,6 +51,9 @@ private:
|
||||
|
||||
OUString m_sName;
|
||||
OUString m_sBaseUri;
|
||||
|
||||
std::optional<OUString>
|
||||
getCopyDestinationUri(const css::uno::Reference<css::script::browse::XBrowseNode>& xDest) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -203,6 +203,20 @@ sal_Bool SAL_CALL ScriptProvider::editNode()
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<SingleScriptFactory> ScriptProvider::getScriptFactory() const
|
||||
{
|
||||
return m_pProviderContext->m_pSingleScriptFactory;
|
||||
}
|
||||
|
||||
std::optional<OUString> ScriptProvider::getDirectoryUri() const
|
||||
{
|
||||
if (const DirectoryNode* pDirectoryNode
|
||||
= dynamic_cast<const DirectoryNode*>(m_xRootBrowser.get()))
|
||||
return pDirectoryNode->getDirectoryUri();
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
OUString SAL_CALL ScriptProvider::getImplementationName()
|
||||
{
|
||||
return getImplementationNameStatic(
|
||||
|
||||
Reference in New Issue
Block a user