Ever wondered how to create a LibreOffice extension? Here I discuss how to do that via Python programming language. We also discuss how to debug the code in an external IDE like PyCharm.
LibreOffice Extensions with Python
If you have used LibreOffice extensions, you know that many exciting things can be done with extensions. Extensions can open LibreOffice applications, create new documents, read and write text and images inside the documents, and convert them to all possible formats. They can have their own menus and toolbar buttons, and have nice looking GUIs to interact with the users.
To write an extension, the easiest way is to use LibreOffice BASIC language. You can refer to this tutorial for such an approach here:
But with Python, you will have access to a big set of packages, that is one of the many strengths of the Python programming language. You can do almost anything possible with a software with those packages. Furthermore, LibreOffice has its own Python interpreter! In this way, installing and using a Python extension would be much easier.
Handling Context in LibreOffice Extensions
First of all, you should know about context, and you should be able to have that variable to be able to use LibreOffice API.
There can be at least 3 different possibilities for running a Python program with LibreOffice:
- Running the Python program with APSO inside LibreOffice
- Running the Python program as an extension inside LibreOffice
- Running the Python program as a process outside LibreOffice
In each of these possibilities, the way to get the context and use them is different.
Structure of a LibreOffice Extension
Extensions are essentially zip files that have specific files known to LibreOffice inside them. This is the structure of a Python extension:
META-INF/: required folder
META-INF/manifest.xml: Specification of the script(s), menu/toolbar and language files
- pkg-description/ : required folder
pkg-description/pkg-description.en: Description of the extension in text, which can be also in languages other than English
registration/: required folder
registration/license.txt: License of the extension
description.xml: Description of the extension in XML format, as displayed in the extension manager
main.py: The main script. Then name can be anything but it should
be specified in the
Contents of the Files
Most of the contents of the files are re-usable, so you can use the skeleton extension, and build your extension around that. But, the Python script is important and we will talk about it here.
From the above 3 possible situations for LibreOffice, in order to be able to use the code as extension, you should add these this 2 lines should be in the Python file
g_ImplementationHelper = unohelper.ImplementationHelper() g_ImplementationHelper.addImplementation(MainJob, "org.extension.sample.do",("com.sun.star.task.Job",), )
In addition, this import is also required:
from com.sun.star.task import XJobExecutor
Then, a Python class with this definition is needed:
class MainJob(unohelper.Base, XjobExecutor)
The program should have this method:
def trigger(self, args):
To be able to debug the program, the
main function should be defined as something like this:
def main(): try: ctx = XSCRIPTCONTEXT except NameError: ctx = officehelper.bootstrap() if ctx is None: print("ERROR: Could not bootstrap default Office.") sys.exit(1) job = MainJob(ctx) job.trigger("keywords") if __name__ == "__main__": main()
This is a sample implementation of the MainJob class:
class MainJob(unohelper.Base, XJobExecutor): def __init__(self, ctx): self.ctx = ctx # handling different situations (inside LibreOffice / different process) try: self.sm = ctx.getServiceManager() self.desktop = XSCRIPTCONTEXT.getDesktop() except NameError: self.sm = ctx.ServiceManager self.desktop = self.ctx.getServiceManager().createInstanceWithContext( "com.sun.star.frame.Desktop", self.ctx)
And this is a sample
trigger() function that opens Writer, and write a sample text consisting of the argument passed to it.
def trigger(self, args): desktop = self.ctx.ServiceManager.createInstanceWithContext( "com.sun.star.frame.Desktop", self.ctx) model = desktop.getCurrentComponent() if not hasattr(model, "Text"): model = self.desktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, ()) text = model.Text cursor = text.createTextCursor() text.insertString(cursor, "Hello Extension argument -> " + args + "\n", 0)
You can use this structure to create Python extension that you want to create.
A complete extension with the above files is available here, and the plan is to make it available among the other LibreOffice SDK examples:
This year we had an extensive workshop on LibreOffice development in LibreOffice conference 2023. If you want to know more about using LibreOffice API in Python, you can refer to the presentation: