The Extension Core is a set of functions that every EOEC extension depends on. It provides the backbone of creating and registering an extension, the run-time development mechanism, debugging and a number of essential utilities.
A large part of the functionality is present in the ComponentBase class, and some parts that are not tied to an extension object are implemented as functions.
This is the base class from which extension classes are derived. ComponentBase itself is in turn derived from unohelper.Base, the base class provided by PyUNO.
The following interfaces are implemented:
The following methods can be overridden by subclasses to customize their behavior:
Runs at every time OpenOffice.org starts up. Subclasses may override it to do some kind of initialization here – the default implementation does not do anything.
Try to write your extension so that most of the heavy initialization only happens when it is needed. This way slowing down startup unnecessarily can be avoided.
Runs the first time OpenOffice.org starts up after the extension was installed. Subclasses may override it to do some kind of initialization here – the default implementation does not do anything.
This is the recommended place to create new menu items.
Runs when the user presses the Disable or Remove buttons on the extension in the Extension Manager dialog. Subclasses may override it to do some kind of clean up here – the default implementation does not do anything.
This is the recommended place to remove anything that was created in firstrun().
The following utility methods are provided:
Adds a new menu item to the OpenOffice.org menu system. This addition is permanent. The menu item can only be removed using removeMenuItem(). It is recommended to add menu items in the firstrun() method and remove all of them in the uninstall() method.
An example creating a new submenu with two menu items in the Insert menu:
self.addMenuItem('com.sun.star.text.TextDocument', '.uno:InsertMenu', self.localize('submenu'), 'mysubmenu', submenu=True) self.addMenuItem('com.sun.star.text.TextDocument', 'mysubmenu', self.localize('item-2'), 'method2') self.addMenuItem('com.sun.star.text.TextDocument', 'mysubmenu', self.localize('item-1'), 'method1')
The menu items are added in reverse order, so item-1 will be the top item and item-2 the bottom.
Icons can be assigned to menu items through the xml configuration file Addons.xcu.
Removes the menu item or submenu from the menu tree of the given document type.
Display a message box. Uses com.sun.star.awt.Toolkit.createMessageBox(), but saves a lot of the verbosity of the UNO API. The constants used come from the UNO API and are not validated by this method.
The infobox can only display an OK button, so if buttons is not 'OK', kind defaults to 'querybox' instead.
The result of the execute() call on the message box. Different values are returned depending on which button was pressed. The BOXCANCEL, BOXOK, BOXYES, BOXNO, BOXRETRY attributes can be used to distinguish. BOXCANCEL has a False truth value, so simple OK_CANCEL boxes can be evaluated without the use of these constants.
This method can be used in place of debugexception() where even in release mode the user should be alerted of the problem.
format can be used to customize the error message. By default it is
'An unexpected error (%(kind)s) occured at line %(linenumber)s of %(filename)s.'
The format string can contain insertion points for kind (the exception type), filename, linenumber, functionname and text (the message of the exception).
This method also calls debugexception() so in debug mode the entire stack trace is recorded.
It is recommended to add instructions for the user in the format string (such as “Please let us know about this problem at email@example.com.”).
Returns the com.sun.star.configuration.ConfigurationAccess object associated with the given node path.
See the config attribute.
|Parameter:||update – If True, a ConfigurationUpdateAccess object is instead returned, that can be used to change configuration settings.|
Returns the localized string associated with the internal string string.
If language is None, the language is automatically chosen based on the SUPPORTED_LANGUAGES attribute. If the current user interface language (as given by org.openoffice.Setup.L10N.ooLocale) is in the list of supported languages, it is used, otherwise the first element of the list (the fallback language) is used in its place.
If language is not None, it should be the two-letter code of a language to be used instead of the default.
The localizations are loaded from MyNameMyExtensionDialogs/DialogStrings_language.properties (with the two-letter code for the language). See the description of this file .
|Returns:||Normally the localized string is returned. However if there is no localization for the given string in any language, the string 'unlocalized: '+string' is returned and if there are localizations just not in the chosen language, the string 'unlocalized for %s: %s'%(language, string) is returned instead. These can be used to quickly spot missing translations on the user interface.|
Creates an instance of the given dialog using com.sun.star.awt.DialogProvider.createDialog().
For increased convenience, the dialog controls are accessible as attributes of the returned object. For example if the dialog Dialog1 has a button named Button1 adding an ActionListener can be done like this:
dlg = self.createdialog( 'Dialog1' ) dlg.Button1.addActionListener( self )
This is mostly equivalent to dlg.getControl( 'Button1' ).addActionListener( self ), but is more efficient when the control is accessed multiple times, because each time an UNO call is saved.
For technical reasons a wrapper object is created around the com.sun.star.awt.XDialog object to enable this convenient access. The original XDialog object can be accessed as the xdialog attribute of the wrapper. The wrapper forwards every attribute access to the XDialog object, so accessing the original object is practically never necessary.
To display a dialog, call its execute() method.
|Parameter:||dialogname – the name of the dialog that you have used in the OpenOffice.org dialog designer|
|Returns:||an instance of the given dialog|
The ComponentBase class also sets up a few attributes that can be useful:
Provides access to the persistent configuration of the extension. It is a com.sun.star.configuration.ConfigurationUpdateAccess object associated with the node my.prefix.MyExtensionSettings/ConfigNode.
Keep in mind that for the change to the configuration to be persistent, the commitChanges() method has to be called.
For example on the first start up (after firstrun() was called) the FirstRun configuration setting is updated like this:
self.config.FirstRun = False self.config.commitChanges()
The Extension Core provides a basic debugging framework. Since debugging is most important when things go wrong, and when things go wrong there is not much that can be relied on, debug messages are output to either stderr (on Linux) or to a debug file (c:\debug.txt on Windows and /tmp/debug.txt on Mac).
To provide some degree of convenience, the EOEC dialog displays the contents of the debug file (if there is one).
On platforms with debug files the debug file is truncated on startup and then on calls to the debug() function it is opened, appended and closed.
Note that all debug output is silently omitted if the extension is not in development mode.
The relevant functions are:
Writes the last exception (with stack trace) to the debug output.
You can notice in the source code of the Extension Core and the blank extension created by create.py that calls from the “outside” are wrapped in try-except-debugexception blocks. This is very useful for debugging, because otherwise the exception is propagated to OpenOffice.org and will most likely result in a crash that gives little information. It is recommended that in new methods that implement UNO interfaces extension developers follow the same convention even when the method does not appear to do anything “dangerous”.
An example of this important principle:
# XActionListener def actionPerformed(self, event): try: pass # suppose we do something... except: debugexception()
The Extension Core also includes a number of useful functions and constants that are used by ComponentBase and can also be useful to developers of extensions.
Normally extensions import * from extensioncore, so these utilities are conveniently available.
This base-class provides a modified __getattribute__ implementation that (when in development mode) checks if a newer version of the source file is available (based on file modification dates) and reloads it if necessary, modifying this instance and future instances of the class.
ComponentBase is derived from this class, but if other classes need this functionality they can derive from SelfUpdating too.
The UNO API often expects parameters to be com.sun.star.beans.PropertyValue arrays. This function makes it easy to create such arrays.
props can be called with either a single dictionary object as the parameter, or with keyword arguments. It will then turn the given dictionary or the keyword arguments into a com.sun.star.beans.PropertyValue array and return this array.
The UNO API often returns values as com.sun.star.beans.PropertyValue arrays. unprops unpacks these arrays into a more convenient format.
The class of the returned object is derived from dict, so the results are accessible as in a normal dictionary object. However for added convenience it is also possible to access the values as attributes of the returned object.
For example to access the command URL of the first menu item in some menu system:
settings = xUIMgr.getSettings('private:resource/menubar/menubar', True) menu = unprops(settings.getByIndex(0)) debug(menu.CommandURL)
This function also works with NamedValue arrays.
UNO Sequence objects are converted to tuples when they come to the Python side and are easy to work with. However the OpenOffice.org API has a number of different container types that are not automatically converted and can be less convenient to work with.
enumerate is a generator function for these container types. An example usage for relabeling footnotes:
for footnote in enumerate( self.getcomponent().Footnotes ): footnote.Label = 'Footnote ' + footnote.Label
The following kinds of objects are supported:
Evaluates a Python expression making sure it is safe.
The expression can contain only a very limited set of language elements, that are only sufficient for describing objects made up of basic Python types. This way a dictionary mapping strings to lists of integers for example can be simply stored by calling repr() on it, and can be loaded using this function.
This variable lists the possible document types (such as 'com.sun.star.text.TextDocument') in OpenOffice.org.
Note that not every build of OpenOffice.org has all of these document types!
This class is a lightweight implementation of com.sun.star.beans.XPropertySet and com.sun.star.lang.XServiceInfo. None of the methods in the XPropertySet interface are actually implemented except for getPropertyValue() and setPropertyValue(). This is appropriate for most purposes, such as for inserting a new item into a com.sun.star.ui.ActionTriggerContainer. Error handling is also not implemented.
Registers the given class in the OpenOffice.org type database for the given services. This function should not be called arbitrarily – it is a part of the extension initialization process. It is called in the last line of extensionname.py. Extensions automatically support the com.sun.star.task.Job service but if further services are needed to be registered for they can be added to this function call.
Of course the required interfaces should be implemented when registering for a service.