Kaydet (Commit) c697ad1a authored tarafından Mike Kaganski's avatar Mike Kaganski Kaydeden (comit) Stephan Bergmann

tdf#100837: Support Office URI Schemes

This patch adds support for Office URI Schemes (see
https://msdn.microsoft.com/en-us/library/dn906146).
This will enable browser (non-CMIS) integration of LibreOffice
with MS SharePoint server (v.2013 tested).

In this patch, in addition to ms-* schemes, a new scheme is
introduced: vnd.libreoffice.command, which is analogous to ms-*.
Its purpose is to enable flexible configuration of server and
client, where some types of documents are declared as handled by
LibreOffice, and other are handled by other software. E.g., ODTs
may have "vnd.libreoffice.command" scheme, while DOCXs could be
"ms-word". Client may register LibreOffice to handle both, or to
handle only "vnd.libreoffice.command" scheme.

Unit test included.

TODO in a later patch: add a mechanism to register LibreOffice
to the schemes with OS.

Change-Id: I1c449a211102036f87163058a4c90a93eb32c948
Reviewed-on: https://gerrit.libreoffice.org/27094Reviewed-by: 's avatarStephan Bergmann <sbergman@redhat.com>
Tested-by: 's avatarJenkins <ci@libreoffice.org>
üst 4306e660
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# 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,desktop_app))
$(eval $(call gb_CppunitTest_add_exception_objects,desktop_app, \
desktop/qa/desktop_app/test_desktop_app \
))
$(eval $(call gb_CppunitTest_use_externals,desktop_app, \
dbus \
))
$(eval $(call gb_CppunitTest_use_libraries,desktop_app, \
comphelper \
cppu \
cppuhelper \
deploymentmisc \
editeng \
i18nlangtag \
$(if $(filter OPENCL,$(BUILD_TYPE)),opencl) \
sal \
salhelper \
sb \
sfx \
svl \
svxcore \
svt \
tk \
tl \
utl \
vcl \
))
ifeq ($(OS), $(filter LINUX %BSD SOLARIS, $(OS)))
$(eval $(call gb_CppunitTest_use_static_libraries,desktop_app,\
glxtest \
))
$(eval $(call gb_CppunitTest_add_libs,desktop_app,\
-lm $(DLOPEN_LIBS) \
-lpthread \
-lX11 \
))
endif
$(eval $(call gb_CppunitTest_use_library_objects,desktop_app, \
sofficeapp \
))
$(eval $(call gb_CppunitTest_use_external,desktop_app,boost_headers))
$(eval $(call gb_CppunitTest_use_sdk_api,desktop_app))
# vim: set noet sw=4 ts=4:
...@@ -131,6 +131,7 @@ $(eval $(call gb_Module_add_targets,desktop, \ ...@@ -131,6 +131,7 @@ $(eval $(call gb_Module_add_targets,desktop, \
endif endif
$(eval $(call gb_Module_add_check_targets,desktop, \ $(eval $(call gb_Module_add_check_targets,desktop, \
CppunitTest_desktop_app \
CppunitTest_desktop_version \ CppunitTest_desktop_version \
)) ))
......
/* -*- 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 <cstddef>
#include <sal/types.h>
#include "cppunit/TestAssert.h"
#include "cppunit/TestFixture.h"
#include "cppunit/extensions/HelperMacros.h"
#include "cppunit/plugin/TestPlugIn.h"
#include <rtl/ustring.h>
#include <rtl/ustring.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <comphelper/processfactory.hxx>
#include "../../source/app/cmdlineargs.hxx"
namespace {
class Test: public ::CppUnit::TestFixture {
public:
void testTdf100837();
CPPUNIT_TEST_SUITE(Test);
CPPUNIT_TEST(testTdf100837);
CPPUNIT_TEST_SUITE_END();
};
class TestSupplier : public desktop::CommandLineArgs::Supplier {
public:
virtual ~TestSupplier() {}
virtual boost::optional< OUString > getCwdUrl() override { return boost::optional< OUString >(); }
virtual bool next(OUString * argument) override {
CPPUNIT_ASSERT(argument != nullptr);
if (m_index < m_args.size()) {
*argument = m_args[m_index++];
return true;
}
else {
return false;
}
}
TestSupplier& operator << (const OUString& arg) { m_args.push_back(arg); return *this; }
private:
std::vector< OUString > m_args;
std::vector< OUString >::size_type m_index = 0;
};
// Test Office URI Schemes support
void Test::testTdf100837() {
auto xContext = ::cppu::defaultBootstrap_InitialComponentContext();
::css::uno::Reference<::css::lang::XMultiComponentFactory> xFactory(xContext->getServiceManager());
::css::uno::Reference<::css::lang::XMultiServiceFactory> xSM(xFactory, ::css::uno::UNO_QUERY_THROW);
// Without this we're crashing because callees are using getProcessServiceFactory
::comphelper::setProcessServiceFactory(xSM);
TestSupplier supplier;
supplier << "--view" << "foo" << "ms-word:ofe|u|bar1" << "ms-word:ofv|u|bar2" << "ms-word:nft|u|bar3" << "baz";
desktop::CommandLineArgs args(supplier);
auto vViewList = args.GetViewList();
auto vForceOpenList = args.GetForceOpenList();
auto vForceNewList = args.GetForceNewList();
// 3 documents go to View list: foo; bar2; baz
CPPUNIT_ASSERT_EQUAL(decltype(vViewList.size())(3), vViewList.size());
CPPUNIT_ASSERT_EQUAL(OUString("foo"), vViewList[0]);
CPPUNIT_ASSERT_EQUAL(OUString("bar2"), vViewList[1]);
CPPUNIT_ASSERT_EQUAL(OUString("baz"), vViewList[2]);
// 1 document goes to ForceOpen list: bar1
CPPUNIT_ASSERT_EQUAL(decltype(vForceOpenList.size())(1), vForceOpenList.size());
CPPUNIT_ASSERT_EQUAL(OUString("bar1"), vForceOpenList[0]);
// 1 document goes to ForceNew list: bar3
CPPUNIT_ASSERT_EQUAL(decltype(vForceNewList.size())(1), vForceNewList.size());
CPPUNIT_ASSERT_EQUAL(OUString("bar3"), vForceNewList[0]);
}
CPPUNIT_TEST_SUITE_REGISTRATION(Test);
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -102,6 +102,80 @@ private: ...@@ -102,6 +102,80 @@ private:
sal_uInt32 m_index; sal_uInt32 m_index;
}; };
// Office URI Schemes : see https://msdn.microsoft.com/en-us/library/dn906146
class OfficeURISchemeCommandLineSupplier : public CommandLineArgs::Supplier {
public:
static bool IsOfficeURI(const OUString& URI, OUString* rest = nullptr)
{
return ( URI.startsWithIgnoreAsciiCase("vnd.libreoffice.command:", rest) // Proposed extended schema
|| URI.startsWithIgnoreAsciiCase("ms-word:", rest)
|| URI.startsWithIgnoreAsciiCase("ms-powerpoint:", rest)
|| URI.startsWithIgnoreAsciiCase("ms-excel:", rest)
|| URI.startsWithIgnoreAsciiCase("ms-visio:", rest)
|| URI.startsWithIgnoreAsciiCase("ms-access:", rest));
}
OfficeURISchemeCommandLineSupplier(boost::optional< OUString > cwdUrl, const OUString& URI)
: m_cwdUrl(cwdUrl)
{
// 1. Strip the scheme name
OUString rest1;
bool isOfficeURI = IsOfficeURI(URI, &rest1);
assert(isOfficeURI);
(void) isOfficeURI;
OUString rest2;
long nURIlen = -1;
// 2. Discriminate by command name (incl. 1st command argument descriptor)
// Extract URI: everything up to possible next argument
if (rest1.startsWith("ofv|u|", &rest2))
{
// Open for view
m_args.push_back("--view");
nURIlen = rest2.indexOf("|");
}
else if (rest1.startsWith("ofe|u|", &rest2))
{
// Open for editing
m_args.push_back("-o");
nURIlen = rest2.indexOf("|");
}
else if (rest1.startsWith("nft|u|", &rest2))
{
// New from template
m_args.push_back("-n");
nURIlen = rest2.indexOf("|");
// TODO: process optional second argument (default save-to location)
// For now, we just ignore it
}
else
{
// Abbreviated schema: <scheme-name>:URI
// "ofv|u|" implied
rest2 = rest1;
m_args.push_back("--view");
}
if (nURIlen < 0)
nURIlen = rest2.getLength();
m_args.push_back(rest2.copy(0, nURIlen));
}
virtual ~OfficeURISchemeCommandLineSupplier() {}
virtual boost::optional< OUString > getCwdUrl() override { return m_cwdUrl; }
virtual bool next(OUString * argument) override {
assert(argument != nullptr);
if (m_index < m_args.size()) {
*argument = m_args[m_index++];
return true;
}
else {
return false;
}
}
private:
boost::optional< OUString > m_cwdUrl;
std::vector< OUString > m_args;
std::vector< OUString >::size_type m_index = 0;
};
} }
CommandLineArgs::Supplier::Exception::Exception() {} CommandLineArgs::Supplier::Exception::Exception() {}
...@@ -538,7 +612,15 @@ void CommandLineArgs::ParseCommandLine_Impl( Supplier& supplier ) ...@@ -538,7 +612,15 @@ void CommandLineArgs::ParseCommandLine_Impl( Supplier& supplier )
else else
{ {
// handle this argument as a filename // handle this argument as a filename
if ( bOpenEvent )
// 1. Check if this is an Office URI
if (!bDisplaySpec && OfficeURISchemeCommandLineSupplier::IsOfficeURI(aArg))
{
OfficeURISchemeCommandLineSupplier OfficeURISupplier(getCwdUrl(), aArg);
// Add the file according its command, ignore current event
ParseCommandLine_Impl(OfficeURISupplier);
}
else if ( bOpenEvent )
{ {
m_openlist.push_back(aArg); m_openlist.push_back(aArg);
bOpenDoc = true; bOpenDoc = true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment