Chapter 1. Libreoffice Api Concepts: Part 1: Basics
Chapter 1. Libreoffice Api Concepts: Part 1: Basics
Part 1: Basics
Chapter 1. LibreOffice API Concepts Topics: Some History;
Help and Rxamples for
the LibreOffice SDK
(lodoc, loguide); Office
as a Process; Common
This chapter describes LibreOffice API concepts without Structures (Interface,
resorting to code (that comes along in the next chapter). Property, Service, and
These concepts include Office as a (possibly networked) Component); Service
and Interface Inheritance
process, the interface, property, service, and component Hierarchies; the Frame-
structures, the two API inheritance hierarchies, and the Controller-Model (FCM)
Frame-Controller-Model (FCM) relationship. Relationship;
Extensions; Comparison
LibreOffice is an open source, cross-platform, office suite, with Basic
made up of six main applications, and lots of other useful
stuff. The applications are: Writer (a word processor),
Draw (vector graphics drawing), Impress (for slide Example folder: "Utils"
presentations), Calc (spreadsheets), Base (a database front-
end), and Math (for writing formulae). Some of the lesser-
known features include a charting library, spell checker, forms designer, thesaurus, e-
mail package, and support for extensions (e.g. new menu items and libraries). Aside
from Open Document Format (ODF) files, LibreOffice can import, convert, and
export a vast number of text, graphic, and other formats, including Microsoft Office
documents, PDF, HTML, SWF (Flash), and SQL databases.
LibreOffice is managed and developed by The Document Foundation
(https://www.libreoffice.org/), and was first released in 2010. However, earlier Office
versions date back to the 1980's, and traces of this heritage are visible in many parts
of its API. Figure 1 shows a simplified timeline of how StarOffice begat OpenOffice,
and so on to LibreOffice.
This book is not about how to use LibreOffice's GUI (e.g. where to find the menu
item for italicizing text). I'm also not going to discuss how to compile the LibreOffice
<OFFICE> is my way of writing the path to the LibreOffice directory, which for
example is "C:\Program Files\LibreOffice 5" on my 32-bit test machine.
You should also browse the LibreOffice development forums
(http://www.imaccanici.org/en.libreofficeforum.org/) and the corresponding ones for
OpenOffice (https://forum.openoffice.org/en/forum/). Look for the sub-forums that
talk about the UNO API and/or macros. Sadly, imaccanici.org is an archive of the
defunct http://en.libreofficeforum.org/ site, but the OpenOffice forum is still going
strong, and very relevant. LibreOffice has a question-posing page, at
https://ask.libreoffice.org/en/questions/, which is a good source of information.
http://www.oooforum.org/ is an older forum site, which has the unfortunate habit of
periodically disappearing from the Web. Often the only way to access one of its posts
or threads is via cached pages maintained by Google.
The Office API has been ported to many programming languages. The API was first
coded in C++, and later converted to Java, Basic, Python, C#, Perl, JavaScript,
OORexx, and many more. The most popular language is probably Basic, which is
principally used for writing macros (also called scripts) embedded in Office
documents, or in the Office application. A big advantage of Basic is its lack of typing,
which simplifies its version of the API. Basic macros utilize a similar set of Office
API functions as Java, so can be a useful source of ideas.
Perhaps the best place for learning about Office macro programming is Andrew
Pitonyak's website (http://www.pitonyak.org/), which includes an excellent free-to-
download book: "OpenOffice.org Macros Explained", a macros cookbook, and a
document focusing on database macros.
Another great site is http://openoffice3.web.fc2.com/, which is mostly written in
Japanese. This shouldn't put off non-Japanese readers since Google is quite happy to
translate the pages for you, and the code examples are mostly ASCII.
lodoc.bat is 'almost' always returns the right page, mainly because Office interfaces,
and many of its services, have long unique names. (I'll explain what a service is
shortly.)
loDoc.bat can be found in the Utils/ folder listed at the start of this chapter, and its
also included in every example folder used in later chapters.
Service names are less unusual, and so you should probably add the word "service" to
your search. For instance, if you're looking for the Text service, type:
lodoc text service
Module names are also quite common words, so add "module" to the search. If you
want to reach the "text" module (which implements most of Writer), search for:
lodoc text module
You can call lodoc with Office application names, which are mapped to API module
names. For instance:
lodoc Impress
brings up the "presentation" module page.
You may be wondering why I chose to implement this script using DuckDuckGo
rather than Google? Google doesn't seem to like me querying it from the command
line. It periodically keeps asking me to type in a captcha string when I call it from
lodoc.bat. Another problem is that Google likes to replace my search strings with
'more likely' strings.
loguide writer
opens the guide at the start of the "Text Documents" chapter.
Calling loGuide.bat with no arguments, makes the browser load the first page of the
guide.
2. Office as a Process
Office is started as an OS process, and a Java program communicates with it via a
socket or named pipe. This necessarily complicates the Java/Office link, which is
illustrated in Figure 2.
The invocation of Office and the setup of a named pipe link can be achieved with a
single call to the SDK's Bootstrap.bootstrap() method. Its source code is available
online, and makes for interesting reading. (Probably the most reliable way of finding
it is to google using the terms Bootstrap libreoffice filetype:java.)
bootstrap() starts the Office executable (called soffice.exe) with several command line
arguments, the most important being "-accept" which specifies the use of pipes or
sockets for the interprocess link.
A call to XUnoUrlResolver.resolve() inside bootstrap() creates a remote component
context, which acts as proxy for the 'real' component context over in the Office
process (see Figure 2). The context is a container/environment for components and
UNO objects which I'll explain below. When a Java program refers to components
and UNO objects in the remote component context, the interprocess bridge maps
those references across the process boundaries to the corresponding components and
objects on the Office side.
Underpinning this mapping is the Universal Network Object (UNO) model which
links objects in different environments using the UNO remote protocol (URP). For
example, a method call is converted into a byte stream, sent across the bridge and
reconstructed. Method results are returned in the same way.
Thankfully, this network communication is hidden by the Office API. The only place
a beginner might encounter UNO mechanisms is when loading or saving documents.
Every document (more generally called a resource) is referred to using a Uniform
Resource Identifier (URI); URIs are employed by Office’s Universal Content Broker
(UCB) and Universal Content Providers (UCPs) to load and save a wide range of data
formats.
Bootstrap.bootstrap() sets up a remote component context based on named pipes, but
if you want to utilize sockets, then the coding is left to you. My Lo utility class
contains a socketContext() method that does the necessary work, and I'll show some
examples of its use in the next chapter.
Obtaining a remote component context is not the end of Office’s initialization.
Typically, at least three UNO objects are needed over on the Java side for most
programming tasks: a service manager, a Desktop object, and a component loader.
The service manager is used to load additional services into Office at runtime. The
Desktop object has nothing to do with the OS'es desktop – it refers to the top-level of
the Office application, particularly to its GUI. The component loader is used to load
or create Office documents.
Other UNO objects might be more useful depending on your programming task. For
example, for historical reasons, Office supports two slightly different service
managers (one that requires an explicit component context argument, and an older one
that doesn't). I've chosen to add both of them to the component context, as a
convenience to the programmer; this detail is hidden by my Lo util class.
The Office documentation often talks about property structs (e.g. the Point and
KeyEvent structs). These are coded in Java as classes, and their names often clash
with classes in the standard JDK which can complicate their usage.
Since interfaces contain no code, a service is a specification for an Office feature.
When a service is implemented (i.e. its interfaces are implemented), it becomes a
component. This distinction means that the Office API can be implemented in
different languages (as components) but always employs the same specifications
(services), as represented in Figure 4.
The developer's guide uses a notation like that shown in Figure 5 to draw a service
and its interfaces.
I haven't drawn all the interfaces for OfficeDocument, since they're quite numerous,
and I haven’t listed the methods defined by each interface.
The developer's guide drawing for the SpellChecker service is shown in Figure 6.
The two figures illustrate a useful naming convention: all interface names start with
the letter "X".
The developer's guide notation leaves out information about the properties managed
by the services. Also, the services webpages at the LibreOffice site don't use the
guide’s notation.
The URLs for these pages are somewhat difficult to remember. The best thing is to
use my loDoc.bat tool to find them. For instance, you can access the office document
and spell checker services with:
lodoc officedocument service
and
lodoc spellchecker service
Note that the "officedocument" search result isn't ideal – it takes you to the IDL page
for the service. You need to click on the "OfficeDocument" link under the "Classes"
heading to get to the actual service details.
The LibreOffice service webpages usually list properties, but sometimes refer to them
as 'attributes'. If the service documentation doesn't describe the properties, then they're
probably being managed by a separate “Supplier” interface (e.g.
XDocumentPropertiesSupplier for OfficeDocument in Figure 5). The supplier will
include methods for accessing the properties as an XPropertySet object.
One great feature of the LibreOffice webpages is the inheritance diagrams on each
service and interface page. Part of the diagram for the OfficeDocument service is
shown in Figure 7.
Each box in the diagram can be clicked upon to jump to the documentation for that
subclass or superclass.
For example, OfficeDocument is the superclass service of all other document formats,
as illustrated in Figure 9.
The LibreOffice documentation graphically displays these hierarchies (e.g. see Figure
7), but makes no visual distinction between the service and interface hierarchies. It
also represents the "contains" relationship between services and interfaces as
inheritance, rather than as lines with circles as in the developer's guide (e.g. see
Figures 5 and 6).
Every Office document inherits the OfficeDocument service (see Figure 9), and
Figure 5 shows that OfficeDocument supports the XModel interface. This means that
every document will include XModel methods for accessing the document's
resources, such as its URL, file name, type, and meta information. Via
XModel.getCurrentController(), a document's controller can be accessed.
A controller manages the visual presentation of a document. For instance, the Office
GUI interacts with the controller to position the cursor in a document, to control
which page is displayed, and to highlight selections. The XController interface
belongs to the Controller service, which is a superclass for viewing documents;
subclasses include TextDocumentView, DrawingDocumentDrawView, and
PresentationView.
From XController, it's possible to reach XFrame, which contains information about
the document's display window. A document utilizes two XWindow objects, called
the component and container windows. The component window represents the
rectangular area on screen that displays the document. It also handles GUI events,
such as window activation or minimization. The container window is the component's
parent. For example, a component window displaying a chart might be contained
within a spreadsheet window
A frame can contain child frames, allowing the Office GUI to be thought of as a tree
of frames. The root frame of this tree is the Desktop object, which you may recall is
one of the first three objects stored in the remote component context when we start
Office. This means that we can move around the frames in the Office GUI starting
from the loaded document, or from the root frame referred to from XDesktop. For
example, XDesktop provides getCurrentFrame() to access the currently active frame.
6. Components Again
A knowledge of the FCM relationship, and its XFrame, XController, and XModel
interfaces, lets me give a more detailed definition of a component. Back in section 3
(and in Figure 4), I said a component was an implemented service. Another way of
understanding a component is in terms of how much of the FCM relationship it
supports, which allows the 'component' idea to be divided into three:
1. A component that supports both the XModel and XController interfaces is usually
an Office document.
2. A component with a controller but no model is typically used to implement library
functionality that doesn't need to load data. Examples include the spell checker,
and Office tools for creating database forms.
3. A component with no model or controller (i.e. just an XWindow object) is used
for simple GUI elements, such as Office's help windows.
Of these three types, the component-as-document (number 1) is the most important
for our needs. In particular, I'll be using the component loader in the remote
component context to load Office documents.
7. What's an Extension?
The Office developer's guide often uses the words 'extension', 'add-on', and 'add-in'.
I'll be spending four chapters on these features in Part 8 (along with macro
programming in Java), but it's worth briefly explaining them now.
An extension is a code library that extends Office's functionality. For Java
programmers, an extension usually takes the form of a JAR file containing a service,
its interfaces, properties, and their implementations. Since an extension implements
the service, it may also be referred to as a component.
An add-on is an extension with additional XML files defining a GUI for the extension
(e.g. a menu bar, menu item, or toolbar icon). An add-on is rendered in Office's GUI
in the same way as standard Office elements.
An add-in or, to use its full name, a Calc Add-in, is an extension that adds a new
function to Calc.
been written about programming the Office API have all used Basic (e.g. Pitonyak's
"OpenOffice.org Macros Explained" at http://www.pitonyak.org/book/).
There are two styles of Basic macro programming – scripts can be attached to specific
documents, or to the Office application. In a document, a macro can respond to Office
events, such as the loading of the document, or its modification. The macro can
monitor the user's key presses or menu button presses, and can utilize Office dialogs.
This isn't the place for a language war between Java and Basic, but it's fair to say that
the Basic Office API is simpler than the Java version! This is partly due to the fact
that Basic has a weaker typing system than Java, but also that the Office abstractions
used by Basic are simpler than those in Java.
The main difference is that the Basic API doesn't use interfaces. Instead of a service
containing a collection of interfaces, each of which has methods, a Basic service
directly contains all the methods. This means that an Office service can be understood
as a plain-old object containing methods and data (in the form of properties).
I'm at a loss why this abstraction wasn't used in Java. One use of interfaces is to
employ interface typing, but most of the typing protection is applied at runtime when
one interface is cast to another. This means that one of the big benefits of typing
(compile-time error detection) is lost.
Another advantage of Basic is its hiding of the complexities of accessing Office at
start-up, and for requesting services. In comparison, for many years, there was no
Bootstrap class in the Java Office API. This meant that every Java programmer had to
grapple with difficult code for linking to Office and obtaining a remote component
context.
In the Basic API, there's no remote component context since the macros run inside
Office or inside a document that is loaded into Office. Incidentally, this means that
Basic code doesn't need those few extra microseconds for every operation to
communicate across process boundaries.
The Basic programmer still utilizes a service manager, Desktop object, and perhaps a
loader. This means that the first few lines of a macro might be:
Also, Office's Basic runtime environment automatically creates a service manager and
Desktop object, so it's unnecessary to create them explicitly. This reduces the code to
a one-liner:
Set oDoc = StarDesktop.CurrentComponent
or even:
Set oDoc = ThisComponent
If other services are needed, Basic programmers call the createUnoService() function
which transparently requests the named service from the service manager. For
instance:
Recall that a Basic service contains all the methods from its interfaces, so once the
service reference has been obtained, methods can be called directly.
One of the aims of my utilities is to hide as much of the complexity of Office as the
Basic version of the API.
Having just reread this section, I may have just convinced myself to become a Basic
programmer . The reason I'm going to stick with Java is that it's a full-featured
language, with massive numbers of standard and third-part APIs which can augment
the Office API.