Top > OOo > Ext > MRI > Documentation > Macros

Macros Edit

Introduced on MRI 1.0.0.

MRI has macro function to control MRI itself. They can be written by users in Python.

The macros are allowed to access to all functions of MRI and they might be crash your office. However MRI is not for general use, it does not serious problem.

MRI macro is highly depends on MRI implementation, so it is hard to write your macro without knowledge of the MRI internal structure. In this document, only important parts are described, see source code of the MRI for more detail.

Macros menu entry Edit

Open MRI window, Macros menu entry is there on the main menu of the window. The entries of the menu are created dynamically.

Macros should be stored under following directory.

  • Extension's repository, which is come with MRI.
  • User's repository, it can be set in Tools - Configuration... entry of the main menu.

For user's repository, you can choose any directory which you have access right. MRI suppose to use $(user)/Scripts/python/mri_macros directory or something else.

Import macros Edit

If you have a file which includes MRI macros, there is an easy way to put it into your macros directory. Choose Macros - bundle.py - Import Macros entry in the main menu, selected files are copied to user's directory of MRI macros.

If macro files are archived into ZIP, tar.gz or tar.bz2 archive, import function unpack it and it's contents are imported. And if README file is there in the archive, its content is shown in license dialog to confirm before importing its contents.

Reload macros entries Edit

The Macros menu is created dynamically but it is static after the first loading. If you have changes in your macros repository, try to reload it. Choose Macros - bundle.py - Reload Macros Menu entry. Which erase loaded entries and a flag inhibit to load.

File type of macros Edit

Macros have to be written in Python language and stored with ".py" file extension under user's repository. See above section about repositories.

Types of Macro Edit

There are two kind of macros which can be executed on MRI. First one is simple code which extends MRI itself. Another one is record-able macro, processing by macros on the entries are recorded as generated code. In this document, first type is called "Normal Macro" and second type is called "Action Macro".

Normal Macro Edit

Here is an example of normal macro.

# # hello.py example
# Entries of __all__ are shown in Macros menu.
# The order in the list is kept in the menu and empty items 
# are converted into separator of menu entries.
__all__ = ["hello_world", "", "another_function"]

def hello_world(mri):
    """ Greeting
        Description of this method """
    # The document string of the function is used to specify 
    # its title and description. First line is used for title of it 
    # and second line is used for description of the function.
    mri.message("Hello World!")

def another_function(mri):
    pass

def private_function(mri):
   """ This function is not shown in the list of function. """

Your macro file is loaded as a module by imp.load_source function. Your function should be take an argument, which is mri object. Any MRI functions are accessible though it, see following sections described about them.

The doc string of the function is used for the title and the tool tip text of the entry in the menu or other place.

__all__ variable is used to get list of functions exported by the file. In the above example, hello_world and another_function are shown in the sub menu entries of hello.py entry, they are separated with a separator which is specified by the entry of empty string.

Here is an another example working with current target but API calls are not recorded by the code generator.

def another_example(mri):
   target = mri.current.target # real value of the current target 
   sheets = target.getSheets()
   sheet = sheets.getSheets()
   # To do something

Action Macro Edit

Aciton macro allows to generate code for API calls. It is the same as normal macro except for working with Entry instances. If you work with an entry which does not have its position in the history, register it to the history by generator statement.

Here is an simple example.

def action_macro(mri):
    current = mri.current # current is a Writer document object
    text = current.getText()
    cursor = text.createTextCursor()

Calling getText and createTextCursor methods are recorded automatically and return value of each methods is being entries of the history.

When you work with new instance like a service instance, register it to the history.

def macro_test(mri):
    current = mri.current
    transformer = mri.create_service(
        "com.sun.star.util.URLTransformer")
    yield current, transformer

The generator have to return tuple of a parent entry and an entry to register as history entry. The first element, a parent entry should be registered in the history.

There are some restrictions on action macros and code generation with it. For example, a listener like custom UNO component can not be used with it.

MRI object Edit

All macro takes current MRI instance as first argument, which is core program of MRI. The instance of MRI does not support any user interface, the window of MRI can be accessed though ui instance variable of it.

Instance variables Edit

MRI instance keeps something in its instance variables.

VariableTypeDescription
ctxpyunoThe component context.
configmytools_Mri.config.ConfigSettings
webmytools_Mri.web.IDLClass for web-browser to open web pages.
enginemytools_Mri.engine.EngineIntrospection and reflection.
historymytools_Mri.node.RootHistory hierarch.
currentmytools_Mri.engine.EntryCurrent entry.
cgmytools_Mri.cg.CodeGeneratorManages code generators.
modeboolTrue for normal mode, otherwise macro mode.
open_newboolIf True, next target is opened in new MRI.
macrosmytools_Mri.macros.MacrosManages macros.
uimytools_Mri.ui.MRIUiUI instance.

Methods Edit

The following methods return Entry instance and calling them makes code entry according to the method.

get_component_context() -> Entry

Returns the component context.

assign_element(k, value, append=False) -> None

Assign an element to current sequence. This is called by the Entry instance of [] method.

create_service(name, *args, **kwds) -> Enry | pyuno

Returns new instance of a service specified by its name. If nocode=True is specified, the pyuno object of the service instance is returned.

create_struct(name, *args, **kwds) -> Entry | pyuno

Returns new instance of a struct specified by its name. If nocode=True is specified, the object of the struct instance is returned.

create_sequence(type_name, length, var=None) -> Entry

Returns new sequence of with its content type and length.

declare_variable(type_name, value) -> Entry

Make an entry into the code generated with specific variable name.

ComponentContext Edit

MRI keeps css.uno.XComponentContext interface in ctx instance variable. It can be used to make new instances of UNO services.

Current entry Edit

MRI keeps current target in current instance variable, which is instance of mytools_Mri.engine.Entry class.

Engine object Edit

The engine is the core object to get object information of UNO objects. It uses css.beans.Introspection, css.reflection.CoreReflection and css.reflection.TypeDescription services, implemented in mytools_Mri.engine.Engine class. And the instance of the engine can be taken from engine instance variable of MRI.

def use_engine(mri):
    """ Shows type name of the current target. """
    engine = mri.engine
    current = mri.current
    mri.ui.message(engine.get_type_name(current))

Web object Edit

The web object helps you to open web page in user's web browser which specified in the configuration. It is implemented in mytools_Mri.web.IDL class.

def open_url(mri):
    """ Allows to open any URL in your web browser. """
    url = "http://example.com/"
    mri.web.open_url(url)

def open_ref(mri):
    """ Open IDL reference with its name, 
        second argument is optional. """
    idl = "com.sun.star.awt.Rectangle"
    name = "X"
    mri.web.open_idl_reference(idl, name)

MRI UI object Edit

The mytools_Mri.ui.MRIUi class manages the window of MRI.

VariableTypeDescription
ctxpyunoThe component context.
mainmytools_Mri.MRIMRI instance.
desktoppyunoThe desktop instance.
listenersdictListener isntances.
property_modeboolTrue for getting property value otherwise set.
treemytools_Mri.ui.pages.HistoryTreeUiSub window for tree history.
dlgsmytools_Mri.ui.dialogs.DialogsProvides dialogs.
status_eraserthreading.TimerTo delete status line.
framepyunoFrame of the MRI window.
contpyunoContainer window of the MRI window.
pagesmytools_Mri.ui.pages.InfoUi/GridUiProvides access to contents of controls.

Dialogs Edit

There are some dialog in the mytools_Mri.ui.dialogs.Dialogs class which can be used though dlgs instance variable of MRIUi instance.

def dialog_select(mri):
    items = ("Item 1", "Item 2", "Item 3", "Item 1")
    item = mri.ui.dlgs.dialog_select(items, "Title")
    mri.ui.dlgs.dialog_info("%s is selected. " % item)

Second argument of dialog_select method specifies title of the dialog. In the above case, two Item 1 entries, if you want to know which one is selected, pass True for third argument, it makes return value to index of the selected value. None is returned if canceled.

If you want to get text input by users, use dialog_input method to execute input dialog.

def dialog_input(mri):
    text = mri.ui.dlgs.dialog_input(
          "Service Name", "Input a service name.", 
          "com.sun.star.awt.")
    mri.ui.message(text)

All arguments can be omitted.

There is a dialog which allows to choose an entry from the history.

def history_selector(mri):
    entry = mri.ui.dlgs.history_selector("Select Entry")
    if entry:
        mri.ui.message(entry.name)

Return value of the method is an instance of mytools_Mri.engine.Entry class.

If you want to use dialog box to show something or query for user, message method is provided for this task. Which provides shortcut to css.awt.XMessageBoxFactory, see reference for more information. The definition of the method is like the following:

def message(self, message, title="", type="messbox", buttons=1):

Entry Edit

Entry class is used to keep current and other target to inspect by MRI. For example, the current target can be accessed through current instance variable of MRI instance. Entry class is defined in mytools_Mri.engine module and here is its inheritance structure.

mytools_Mri.engine.Entry < 
  (mytools_Mri.engine.EntryBase, mytools_Mri.node.Node)

Entry class inherits two parent classes but there is not additional method defined itself. Node class provides functions to construct hierarch of history structure. EntryBase provides important methods to write macros with its instances.

The following table describes instance variables of Entry class.

VariableTypeDescription
targetobjectReal value wrapped by this instance.
inspectedpyunocss.beans.XIntrospectionAccess interface.
typepyunoIDL type by css.reflection.CoreReflection.
mrimytools_Mri.MRIReference to living MRI.
code_entrymytools_Mri.cg.CodeEntryKeeps informations for code generation.

And there are methods provides functions described in the following table:

MethodDescription
get_target()Use target instance variable to get its real value.
has_interface(name)Check the target exports the interface.
supports_service(name)Check the target supports the service.
append(obj)Append obj to the list, works only on an entry created by create_sequence method of MRI instance.

Pages Edit

The pages instance variable of MRIUi keeps mytools_Mri.pages.InfoUi or GridUi instance depends on the controls shown on the MRI window, which provides access to contents of controls. Their class inheritance is little bit complicated. Here are inheritance structure of them and all classes are defined in mytools_Mri.ui.pages module.

InfoUi < (Ui, PageStatus, 
   Pages < PagesBase)
GridUi < (Ui, PageStatus, 
   GridPages < GridPagesBase < PagesBase)

Ui class provides access to type, implementation name, search edit and history list box controls. The following table describes important methods defined by the Ui class.

MethodDescription
get_type_name()Returns type name.
set_type_name(name)Sets type name.
get_imple_name()Returns implementation name.
set_imple_name(name)Sets implementation name.
get_code()Get current code text.
set_code(txt)Sets current code text.

PageStatus class manages updated status of information pages.

PagesBase class defines group of methods should be provided by its child class, they provides access to information controls. These methods needs index as an argument. They are bound like Properties: 0, Methods: 1, Interfaces: 2, Services 3.

MethodDescription
get_selected(index=None)Get selected text.
get_current_line(index=None)Get text of current line.
get_first_word(index=None)Get head word in the current line.
activate(index)Set active page index.
get_active()Get active page index.
search(search_text, index=None)Search inside.

Keep in mind, the content of their controls are updated at first time which is activated.

Controller of MRI Window Edit

MRI uses custom controller which is bound to frame of windows. It is written in Python and it allows to access an instance of MRI. All MRI windows are registerd on the desktop frame and they can be taken though css.frame.XFrame interface.

def do_something_with(mri):
    # find MRI window from the desktop
    found = None
    frames = mri.ui.desktop.getFrames()
    for i in range(frames.getCount()):
        frame = frames.getByIndex(i)
        if frame.getTitle() == "MRI":
            found = frame
            break
    if found:
        controller = found.getController()
        # MRIUi instance of another MRI
        ui = controller.ui
        mri2 = ui.main # instance of mytools_Mri.MRI

This way can be used in any Python code working on the same Python instance of the office. The bundle.py - Diff macro uses this way to get an entry from the another MRI.

Structure of the MRI Window Edit

Here is hierarch of the MRI window.

frame: css.frame.Frame
  - Controller: mytools_Mri.ui.controller.Controller
    - Model: always None
  - Container Window: general window
  - Component Window: css.awt.UnoControlContainer
    - splitter: does not added in the container
    - label_status: FixedText keeps status text.
    - edit_type: Edit shows type information.
    - edit_in: Edit shows implementation name.
    - list_hist: List of history.
    - btn_back: Back button.
    - btn_forward: Forward button.
    - edit_search: Search edit.
    - btn_search: Search Button.
    - btn_tree: Open tree button.
    - btn_index_acc: Index button.
    - btn_name_acc: Name button.
    - subcont: css.awt.UnoControlContainer (without tab)
      - info_0: 
      - info_1: 
      - info_2: 
      - info_3: 
   - subcont: css.awt.UnoControlContainer (with tab)
      - page_0
        - info_0
      - page_1
        - info_1
      - page_2
        - info_2
      - page_3
        - info_3

The structure of subcont is changed depending of using tab control on the window. The pages instance variable of the MRIUi class provides access to their content simply.

Examples Edit

There are examples in bundle.py placed under Macros directory of the extension package.

Example 1 Edit

Here is a piece of code to inspect child shapes of the current shape collection.

def inspect_shapes(mri):
    """ Inspect Shapes
        Inspect all shapes in this container. """
    shape = mri.current # current target
    # check current shape is correct type
    if shape.supports_service("com.sun.star.drawing.ShapeCollection"):
        # getCount call is not collected to code
        for i in range(shape.target.getCount()):
             child = shape.getByIndex(i)

The supports_service method of Entry class is used to check the current target is correct type. If the target does not support css.lang.XServiceInfo interface, False is returned. If you want to warn for user about it, raise an exception or show message with mri.message method.

Example 2 Edit

The Entry instance wraps its real value in target instance variable. If you need real value of the target, please refer it.

def show_property_value(mri):
    current = mri.current
    ui = mri.ui
    ui.message(current.target)

Reload   New Lower page making Edit Freeze Diff Upload Copy Rename   Front page List of pages Search Recent changes Backup   Help   RSS of recent changes