Added the ability to store and retrieve macros in the document macro storage.
This commit is contained in:
parent
763703b96a
commit
a47e65a50c
@ -256,6 +256,13 @@ LIBRARY The name of the Basic library. Default to the same
|
|||||||
Run he specific macro after synchronization, for
|
Run he specific macro after synchronization, for
|
||||||
convenience.
|
convenience.
|
||||||
|
|
||||||
|
--user Store the macros in the user macro storage. (default)
|
||||||
|
|
||||||
|
--doc Store the macros in the document macro storage.
|
||||||
|
|
||||||
|
--target TARGET The target storage document if there are more than one
|
||||||
|
opened documents. A partial path is OK.
|
||||||
|
|
||||||
-h, --help Show the help message and exit
|
-h, --help Show the help message and exit
|
||||||
|
|
||||||
-v, --version Show program’s version number and exit
|
-v, --version Show program’s version number and exit
|
||||||
@ -264,7 +271,7 @@ LIBRARY The name of the Basic library. Default to the same
|
|||||||
COPYRIGHT
|
COPYRIGHT
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Copyright (c) 2016 imacat.
|
Copyright (c) 2016-2017 imacat.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
248
bin/obasync
248
bin/obasync
@ -3,7 +3,7 @@
|
|||||||
# Office Basic macro source synchronizer.
|
# Office Basic macro source synchronizer.
|
||||||
# by imacat <imacat@mail.imacat.idv.tw>, 2016-08-31
|
# by imacat <imacat@mail.imacat.idv.tw>, 2016-08-31
|
||||||
|
|
||||||
# Copyright (c) 2016 imacat.
|
# Copyright (c) 2016-2017 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@ -70,7 +70,7 @@ LIBRARY The name of the Basic library. Default to the same
|
|||||||
OpenOffice/LibreOffice. The default is 2002. You can
|
OpenOffice/LibreOffice. The default is 2002. You can
|
||||||
change it if port 2002 is already in use.
|
change it if port 2002 is already in use.
|
||||||
|
|
||||||
-x, --ext .EXT The file name extension of the source files. The
|
-x, --ext .EXT The file name extension of the source files. The
|
||||||
default is ".vb". This may be used for your
|
default is ".vb". This may be used for your
|
||||||
convenience of editor syntax highlighting.
|
convenience of editor syntax highlighting.
|
||||||
|
|
||||||
@ -86,6 +86,13 @@ LIBRARY The name of the Basic library. Default to the same
|
|||||||
Run he specific macro after synchronization, for
|
Run he specific macro after synchronization, for
|
||||||
convenience.
|
convenience.
|
||||||
|
|
||||||
|
--user Store the macros in the user macro storage. (default)
|
||||||
|
|
||||||
|
--doc Store the macros in the document macro storage.
|
||||||
|
|
||||||
|
--target TARGET The target storage document if there are more than one
|
||||||
|
opened documents. A partial path is OK.
|
||||||
|
|
||||||
-h, --help Show the help message and exit
|
-h, --help Show the help message and exit
|
||||||
|
|
||||||
-v, --version Show program’s version number and exit
|
-v, --version Show program’s version number and exit
|
||||||
@ -133,9 +140,8 @@ def main():
|
|||||||
# Downloads the macros from OpenOffice/LibreOffice Basic
|
# Downloads the macros from OpenOffice/LibreOffice Basic
|
||||||
if args.get:
|
if args.get:
|
||||||
oo = Office(args.port)
|
oo = Office(args.port)
|
||||||
libraries = oo.service_manager.createInstance(
|
storage = find_storage(oo, args.storage_type, args.target)
|
||||||
"com.sun.star.script.ApplicationScriptLibraryContainer")
|
modules = read_basic_modules(storage, args.library)
|
||||||
modules = read_basic_modules(libraries, args.library)
|
|
||||||
if len(modules) == 0:
|
if len(modules) == 0:
|
||||||
print("ERROR: Library %s does not exist" % args.library,
|
print("ERROR: Library %s does not exist" % args.library,
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
@ -153,19 +159,10 @@ def main():
|
|||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
return
|
return
|
||||||
oo = Office(args.port)
|
oo = Office(args.port)
|
||||||
libraries = oo.service_manager.createInstance(
|
storage = find_storage(oo, args.storage_type, args.target)
|
||||||
"com.sun.star.script.ApplicationScriptLibraryContainer")
|
update_basic_modules(storage, args.library, modules)
|
||||||
update_basic_modules(libraries, args.library, modules, oo)
|
|
||||||
if args.run is not None:
|
if args.run is not None:
|
||||||
factory = oo.service_manager.DefaultContext.getByName(
|
run_macro(storage, args.library, args.run)
|
||||||
"/singletons/com.sun.star.script.provider."
|
|
||||||
"theMasterScriptProviderFactory")
|
|
||||||
provider = factory.createScriptProvider("")
|
|
||||||
script = provider.getScript(
|
|
||||||
"vnd.sun.star.script:%s.%s"
|
|
||||||
"?language=Basic&location=application" %
|
|
||||||
(args.library, args.run))
|
|
||||||
script.invoke((), (), ())
|
|
||||||
|
|
||||||
print("Done. %02d:%02d elapsed." %
|
print("Done. %02d:%02d elapsed." %
|
||||||
(int((time.time() - t_start) / 60),
|
(int((time.time() - t_start) / 60),
|
||||||
@ -206,6 +203,18 @@ def parse_args():
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-r", "--run", metavar="MODULE.MACRO",
|
"-r", "--run", metavar="MODULE.MACRO",
|
||||||
help="The macro to run after the upload, if any.")
|
help="The macro to run after the upload, if any.")
|
||||||
|
parser.add_argument(
|
||||||
|
"--user", dest="storage_type",
|
||||||
|
action="store_const", const="user",
|
||||||
|
help="Store the macros in the user macro storage. (default)")
|
||||||
|
parser.add_argument(
|
||||||
|
"--doc", dest="storage_type",
|
||||||
|
action="store_const", const="doc",
|
||||||
|
help="Store the macros in the document macro storage.")
|
||||||
|
parser.add_argument(
|
||||||
|
"--target", metavar="TARGET",
|
||||||
|
help=("The target storage document if there are more than one"
|
||||||
|
" opened documents. A partial path is OK."))
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-v", "--version", action="version", version="%(prog)s 0.4")
|
"-v", "--version", action="version", version="%(prog)s 0.4")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
@ -219,9 +228,117 @@ def parse_args():
|
|||||||
if args.ext[0] != ".":
|
if args.ext[0] != ".":
|
||||||
args.ext = "." + args.ext
|
args.ext = "." + args.ext
|
||||||
|
|
||||||
|
if args.storage_type is None:
|
||||||
|
args.storage_type = "user"
|
||||||
|
# Paths are understood locally, despite of the content encoding.
|
||||||
|
if args.target is not None:
|
||||||
|
args.target = args.target.decode(locale.getpreferredencoding())
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def find_storage(oo, type, target):
|
||||||
|
"""Finds the macro storage to store the macros.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
type: The storage type, either "user" or "doc".
|
||||||
|
target: The file path to locate the storing document if there
|
||||||
|
are more than one opened documents. A partial path
|
||||||
|
is OK.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The storage to save the macros, as a Storage object.
|
||||||
|
"""
|
||||||
|
if type == "user":
|
||||||
|
storage = Storage()
|
||||||
|
storage.type = type
|
||||||
|
storage.oo = oo
|
||||||
|
storage.doc = None
|
||||||
|
storage.libs = oo.service_manager.createInstance(
|
||||||
|
"com.sun.star.script.ApplicationScriptLibraryContainer")
|
||||||
|
return storage
|
||||||
|
elif type == "doc":
|
||||||
|
storage = Storage()
|
||||||
|
storage.type = type
|
||||||
|
storage.oo = oo
|
||||||
|
storage.doc = find_doc(oo, target)
|
||||||
|
storage.libs = storage.doc.getPropertyValue("BasicLibraries")
|
||||||
|
return storage
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def find_doc(oo, target):
|
||||||
|
"""Find the target opened document by a partial path.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
target: A partial path of the document.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
If there is only one opened document, it is returned. If
|
||||||
|
there are more than one opened document, the document whose
|
||||||
|
file path matches the "target" is returned. Otherwise, if
|
||||||
|
no matching document or more than one matching document are
|
||||||
|
found, the program exists with an error.
|
||||||
|
"""
|
||||||
|
# Checks the opened documents
|
||||||
|
enum = oo.desktop.getComponents().createEnumeration()
|
||||||
|
opened = []
|
||||||
|
while enum.hasMoreElements():
|
||||||
|
component = enum.nextElement()
|
||||||
|
if component.supportsService(
|
||||||
|
"com.sun.star.document.OfficeDocument"):
|
||||||
|
opened.append(component)
|
||||||
|
if len(opened) == 0:
|
||||||
|
print("ERROR: Found no opened document to store the macros",
|
||||||
|
file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
# There are opened documents.
|
||||||
|
if target is None:
|
||||||
|
if len(opened) == 1:
|
||||||
|
return opened[0]
|
||||||
|
print("ERROR: There are more than one opened documens."
|
||||||
|
" Please specify the file path.",
|
||||||
|
file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
file_content_provider = oo.service_manager.createInstance(
|
||||||
|
"com.sun.star.ucb.FileContentProvider")
|
||||||
|
matched = []
|
||||||
|
for doc in opened:
|
||||||
|
if doc.hasLocation():
|
||||||
|
path = file_content_provider.getSystemPathFromFileURL(
|
||||||
|
doc.getLocation())
|
||||||
|
else:
|
||||||
|
path = doc.getTitle()
|
||||||
|
if path.find(target) >= 0:
|
||||||
|
matched.append(doc)
|
||||||
|
if len(matched) == 1:
|
||||||
|
return matched[0]
|
||||||
|
elif len(matched) == 0:
|
||||||
|
print("ERROR: Found no matching document to store the macros.",
|
||||||
|
file=sys.stderr)
|
||||||
|
print("Opened documents:", file=sys.stderr)
|
||||||
|
for doc in opened:
|
||||||
|
if doc.hasLocation():
|
||||||
|
path = file_content_provider.getSystemPathFromFileURL(
|
||||||
|
doc.getLocation())
|
||||||
|
else:
|
||||||
|
path = doc.getTitle()
|
||||||
|
print("* %s" % path, file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("ERROR: There are more than one matching documents.",
|
||||||
|
file=sys.stderr)
|
||||||
|
print("Matching documents:", file=sys.stderr)
|
||||||
|
for doc in matched:
|
||||||
|
if doc.hasLocation():
|
||||||
|
path = file_content_provider.getSystemPathFromFileURL(
|
||||||
|
doc.getLocation())
|
||||||
|
else:
|
||||||
|
path = doc.getTitle()
|
||||||
|
print("* %s" % path, file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def read_in_source_dir(projdir, ext, encoding):
|
def read_in_source_dir(projdir, ext, encoding):
|
||||||
"""Read-in the source files.
|
"""Read-in the source files.
|
||||||
|
|
||||||
@ -289,15 +406,13 @@ def update_source_dir(projdir, modules, ext, encoding):
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def read_basic_modules(libraries, libname):
|
def read_basic_modules(storage, libname):
|
||||||
"""
|
"""
|
||||||
Read the OpenOffice/LibreOffice Basic macros from the macro
|
Read the OpenOffice/LibreOffice Basic macros from the macro
|
||||||
storage.
|
storage.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
libraries: The Basic library storage, as a
|
storage: The Basic macro storage, as a Storage object.
|
||||||
com.sun.star.script.ApplicationScriptLibraryContainer
|
|
||||||
service object.
|
|
||||||
libname: The name of the Basic library.
|
libname: The name of the Basic library.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -306,41 +421,44 @@ def read_basic_modules(libraries, libname):
|
|||||||
dictionary are the module contents.
|
dictionary are the module contents.
|
||||||
"""
|
"""
|
||||||
modules = {}
|
modules = {}
|
||||||
if not libraries.hasByName(libname):
|
if not storage.libs.hasByName(libname):
|
||||||
return modules
|
return modules
|
||||||
libraries.loadLibrary(libname)
|
storage.libs.loadLibrary(libname)
|
||||||
library = libraries.getByName(libname)
|
library = storage.libs.getByName(libname)
|
||||||
for modname in library.getElementNames():
|
for modname in library.getElementNames():
|
||||||
modules[modname] = library.getByName(modname)
|
modules[modname] = library.getByName(modname)
|
||||||
return modules
|
return modules
|
||||||
|
|
||||||
|
|
||||||
def update_basic_modules(libraries, libname, modules, oo):
|
def update_basic_modules(storage, libname, modules):
|
||||||
"""Update the OpenOffice/LibreOffice Basic macro storage.
|
"""Update the OpenOffice/LibreOffice Basic macro storage.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
libraries: The Basic library storage, as a
|
storage: The Basic macro storage, as a Storage object.
|
||||||
com.sun.star.script.ApplicationScriptLibraryContainer
|
|
||||||
service object.
|
|
||||||
libname: The name of the Basic library.
|
libname: The name of the Basic library.
|
||||||
modules: The Basic modules, as a dictionary. The keys of
|
modules: The Basic modules, as a dictionary. The keys of
|
||||||
the dictionary are the module names, and the values of
|
the dictionary are the module names, and the values of
|
||||||
the dictionary are the module contents.
|
the dictionary are the module contents.
|
||||||
oo: The OpenOffice/LibreOffice connection, as an Office
|
|
||||||
object.
|
|
||||||
"""
|
"""
|
||||||
if not libraries.hasByName(libname):
|
if not storage.libs.hasByName(libname):
|
||||||
libraries.createLibrary(libname)
|
storage.libs.createLibrary(libname)
|
||||||
print("Script library %s created." % libname, file=sys.stderr)
|
print("Script library %s created." % libname, file=sys.stderr)
|
||||||
create_dialog_library(oo, libname)
|
create_dialog_library(storage, libname)
|
||||||
library = libraries.getByName(libname)
|
library = storage.libs.getByName(libname)
|
||||||
for modname in sorted(modules.keys()):
|
for modname in sorted(modules.keys()):
|
||||||
library.insertByName(modname, modules[modname])
|
library.insertByName(modname, modules[modname])
|
||||||
print("Module %s added." % modname, file=sys.stderr)
|
print("Module %s added." % modname, file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
libraries.loadLibrary(libname)
|
storage.libs.loadLibrary(libname)
|
||||||
library = libraries.getByName(libname)
|
library = storage.libs.getByName(libname)
|
||||||
curmods = sorted(library.getElementNames())
|
# As of OpenOffice 4.1.3, when there is no modules in the
|
||||||
|
# document storage, it returns a zero-length byte sequence
|
||||||
|
# instead of an empty string list.
|
||||||
|
# The byte sequence cannot be sorted directly.
|
||||||
|
curmods = library.getElementNames()
|
||||||
|
if len(curmods) == 0:
|
||||||
|
curmods = []
|
||||||
|
curmods = sorted(curmods)
|
||||||
for modname in sorted(modules.keys()):
|
for modname in sorted(modules.keys()):
|
||||||
if modname not in curmods:
|
if modname not in curmods:
|
||||||
library.insertByName(modname, modules[modname])
|
library.insertByName(modname, modules[modname])
|
||||||
@ -352,28 +470,57 @@ def update_basic_modules(libraries, libname, modules, oo):
|
|||||||
if modname not in modules:
|
if modname not in modules:
|
||||||
library.removeByName(modname)
|
library.removeByName(modname)
|
||||||
print("Module %s removed." % modname, file=sys.stderr)
|
print("Module %s removed." % modname, file=sys.stderr)
|
||||||
if libraries.isModified():
|
if storage.libs.isModified():
|
||||||
libraries.storeLibraries()
|
storage.libs.storeLibraries()
|
||||||
else:
|
else:
|
||||||
print("Everything is in sync.", file=sys.stderr)
|
print("Everything is in sync.", file=sys.stderr)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def create_dialog_library(oo, libname):
|
def create_dialog_library(storage, libname):
|
||||||
"""Create the dialog library.
|
"""Create the dialog library.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
oo: The OpenOffice/LibreOffice connection, as an Office
|
storage: The Basic macro storage, as a Storage object.
|
||||||
object.
|
|
||||||
libname: The name of the dialog library.
|
libname: The name of the dialog library.
|
||||||
"""
|
"""
|
||||||
libraries = oo.service_manager.createInstance(
|
if storage.type is "user":
|
||||||
"com.sun.star.script.ApplicationDialogLibraryContainer")
|
libraries = storage.oo.service_manager.createInstance(
|
||||||
|
"com.sun.star.script.ApplicationDialogLibraryContainer")
|
||||||
|
else:
|
||||||
|
libraries = storage.doc.getPropertyValue("DialogLibraries")
|
||||||
libraries.createLibrary(libname)
|
libraries.createLibrary(libname)
|
||||||
print("Dialog library %s created." % libname, file=sys.stderr)
|
print("Dialog library %s created." % libname, file=sys.stderr)
|
||||||
libraries.storeLibraries()
|
libraries.storeLibraries()
|
||||||
|
|
||||||
|
|
||||||
|
def run_macro(storage, libname, macro):
|
||||||
|
"""Run a Basic macro.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
storage: The Basic macro storage, as a Storage object.
|
||||||
|
libname: The name of the dialog library.
|
||||||
|
macro: The The macro to run.
|
||||||
|
"""
|
||||||
|
if storage.type is "user":
|
||||||
|
factory = storage.oo.service_manager.DefaultContext.getByName(
|
||||||
|
"/singletons/com.sun.star.script.provider."
|
||||||
|
"theMasterScriptProviderFactory")
|
||||||
|
provider = factory.createScriptProvider("")
|
||||||
|
script = provider.getScript(
|
||||||
|
"vnd.sun.star.script:%s.%s"
|
||||||
|
"?language=Basic&location=application" %
|
||||||
|
(args.library, args.run))
|
||||||
|
script.invoke((), (), ())
|
||||||
|
else:
|
||||||
|
provider = storage.doc.getScriptProvider()
|
||||||
|
script = provider.getScript(
|
||||||
|
"vnd.sun.star.script:%s.%s"
|
||||||
|
"?language=Basic&location=document" %
|
||||||
|
(args.library, args.run))
|
||||||
|
script.invoke((), (), ())
|
||||||
|
|
||||||
|
|
||||||
def read_file(path, encoding):
|
def read_file(path, encoding):
|
||||||
"""Read a file, and deals with Python 3 / 2 compatibility.
|
"""Read a file, and deals with Python 3 / 2 compatibility.
|
||||||
|
|
||||||
@ -448,6 +595,17 @@ def update_file(path, content, encoding):
|
|||||||
return is_updated
|
return is_updated
|
||||||
|
|
||||||
|
|
||||||
|
class Storage:
|
||||||
|
"""A Basic macro storage.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
oo: The office connection, as an Office() object.
|
||||||
|
doc: The office document component to store the macros.
|
||||||
|
libs: The Basic macro storage of the document.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Office:
|
class Office:
|
||||||
"""The OpenOffice/LibreOffice connection.
|
"""The OpenOffice/LibreOffice connection.
|
||||||
|
|
||||||
@ -588,7 +746,7 @@ class Office:
|
|||||||
|
|
||||||
LibreOffice on POSIX systems accepts "--accept" instead of
|
LibreOffice on POSIX systems accepts "--accept" instead of
|
||||||
"-accept" now.
|
"-accept" now.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if soffice is LibreOffice, or False otherwise.
|
True if soffice is LibreOffice, or False otherwise.
|
||||||
"""
|
"""
|
||||||
|
2
setup.py
2
setup.py
@ -3,7 +3,7 @@
|
|||||||
# Python setuptools installer for the obasync project.
|
# Python setuptools installer for the obasync project.
|
||||||
# by imacat <imacat@mail.imacat.idv.tw>, 2016-12-20
|
# by imacat <imacat@mail.imacat.idv.tw>, 2016-12-20
|
||||||
|
|
||||||
# Copyright (c) 2016 imacat.
|
# Copyright (c) 2016-2017 imacat.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
|
Loading…
Reference in New Issue
Block a user