Hi

Our Python script/macro integration is the worst of all our scripting
languages. While StarBasic, BeanShell and Javascript can be created, edited
and debugged within OpenOffice, Python can only be run. Python scripts can
only be embedded into documents manually, by unzipping the OpenDocument
file, copying in the scripts, and then zipping it back up (
https://wiki.openoffice.org/wiki/Python_as_a_macro_language).

Also Python works as badly in LO as it does with us.

On bugs 60849 and 75132 I started trying to improve that, so Python scripts
can be embedded into documents, and created/deleted/renamed within
OpenOffice, and have made considerable progress.

The ScriptProvider implementations for Java, Javascript, and BeanShell are
within main/scripting/java/org, while Python one is in
main/scripting/source/pyprov/pythonscript.py. The fact that Java
implementation had much more code, including UI dialogs, first led me to
try adding a script provider for Python in there. But when I did, I
realized that won't work well, as invoke() is called in Java but must reach
Python, requiring a double UNO call: C++ -> Java -> Python, which would be
bad for performance. Also further investigation led me to realize the UI
dialogs in the Java code are unused, all the UI elements come from
main/cui/source/dialogs/scriptdlg.cxx instead.

What finally convinced me to go back to improving the Python ScriptProvider
is that the scripting framework specifications (
https://www.openoffice.org/specs/scripting_framework/index.html) explained
how each language ScriptProvider is supposed to operate independently, and
can nest its XBrowseNodes in whatever way best represents that language's
scripts. The Java/JavaScript/BeanShell ScriptProviders uses
parcel-descriptor.xml files to define the scripts, using an entire file as
a script, and have a nesting of root -> library -> macro. Python is
completely different, with no parcel-descriptor.xml, instead of complete
files it is the functions in the .py files that are scripts, and the
nesting is root -> library -> macro -> function.

Eventually by comparing Java's XBrowseNode implementations with Python's, I
saw Java's XBrowseNode was implementing XPropertySet and XInvocation on
some of its nodes, while Python wasn't. When I added those to Python, and
handled the "Creatable", "Editable" and other properties, the macro dialog
started enabling buttons that were previously greyed out, but only on
existing libraries, I couldn't create new libraries from root sources like
the document, and really struggled to understand why.

I thought it was a lost cause and was about to give up, but then an idea
came to me. I realized that PythonScriptProvider itself implement
XBrowseNode, and forwards method calls to XBrowseNode methods to its
DirBrowseNode field, and reasoned that just like XPropertySet and
XInvocation had to be added to DirBrowseNode, they might have to be added
to the PythonScriptProvider too, and also forwarded to that DirBrowseNode
field. When I did that, top-level sources like the document started
allowing creation of libraries within them :-).

Implementing XPropertySet and XInvocation on FileBrowseNode even got macro
creation to work, successfully embedding (admittedly empty) .py files into
documents :-) :-).

A number of issues however were discovered:
- All macro operations (creating, renaming, deleting) give false errors
saying they failed, but actually succeed, you need to close and re-open the
macro dialog to see the changes. I suspect this is a bug in the Python UNO
bridge.
- Creating libraries inside documents is completely broken on Windows, the
UI buttons stay greyed out. This is some kind of a permission issue when
calling isReadOnly() on the SimpleFileAccess interface for the document.
- The documentation for Python development leaves a lot to be desired. It
took me forever to find how to create the UNO Any type. Handling "out"
parameters is completely different to other languages. The best document is
actually https://www.openoffice.org/udk/python/python-bridge.html which is
also completely hidden and I only found it by accident.

Apart from those issues, we now need to add Python editing in OpenOffice
for it to be really useful. Still considering what to do there. The scripts
embedded in documents especially, need to be accessed through a custom URL
and our UCB system, and won't be easily accessible to external
applications. There is some code in main/scripting/java that allows
NetBeans to edit BeanShell files, but might require OpenOffice to be
started with an UNO listening port
(scripting/java/org/openoffice/idesupport/localoffice/LocalOfficeImpl.java),
something that won't fly in production.

Developing OpenOffice in Python is actually remarkably simple and pleasant,
It is a first-class UNO language, capable of both consuming UNO components,
and implementing them. Python is probably too slow for serious development,
but given how Python components don't need compiling to redeploy changes,
just OpenOffice restart, it is much faster to develop with.

My preliminary changes have been pushed to the python-editing-embedding
branch. There is no need to build, you can just copy
main/scripting/source/pyprov/pythonscript.py over the one in an existing
OpenOffice instance, it's in the same directory as the main soffice[.exe]
executable. Then start OpenOffice, create or open a document, and compare
Tools -> Macros -> Organize Macros -> Python before and after. Creating,
renaming, and deleting Python libraries and macros should work (to some
degree, on *nix at least), although with false errors afterwards (close and
reopen the dialog to see the changes).

You can also run OpenOffice with the environment
variables PYSCRIPT_LOG_LEVEL=DEBUG PYSCRIPT_LOG_STDOUT=1 set, so that the
Python ScriptProvider logs debugging info to standard output. (It would be
best to change this to the XLogger logging framework eventually.)

Regards
Damjan

Reply via email to