Added the ability to store and retrieve macros in the document macro storage.
This commit is contained in:
		| @@ -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. | ||||||
|   | |||||||
							
								
								
									
										242
									
								
								bin/obasync
									
									
									
									
									
								
							
							
						
						
									
										242
									
								
								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. | ||||||
| @@ -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": | ||||||
|  |         libraries = storage.oo.service_manager.createInstance( | ||||||
|             "com.sun.star.script.ApplicationDialogLibraryContainer") |             "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. | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										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. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user