Talk:Python as a macro language

From Apache OpenOffice Wiki
Jump to: navigation, search

I would like to improve some info on this page, but i have never edited a wiki before, so i'm discussing it here first.

Recently it took me 3 whole days to discover some very simple facts about writing a python macro, because they are not clear in the documentation.
Also, some things seem to have changed since the documentation was written.

Here is the information that i want to convey:

To write a simple macro:

  • in Python
  • stored in the document
  • called from a toolbar button (not a dialog)

this is what you need to know, that is different from the existing documentation:

  • your function must accept an argument
  • it does not need to import uno or unohelper (or anything at all)
  • you do not have to modify manifest.xml, it's done automatically

and this is what you need to know, that is hard discover in the existing documentation:
(it's there, but in a different context, so it's hard to know the relevance of it when you first see it)

Within your function, to get to the UNO API,
(like "ThisDocument" and "StarDesktop" in OO Basic)
use XSCRIPTCONTEXT, like this:
this_doc = XSCRIPTCONTEXT.getDocument()
desktop = XSCRIPTCONTEXT.getDesktop()

Code example:

def test_toolbar_button( *tpl_args ):
	"""Test of basic text insertion;
	prints whatever args are passed to this function."""

	this_doc = XSCRIPTCONTEXT.getDocument()
	doc_text = this_doc.Text
	cursor = text.createTextCursor()

	s_text_1 = 'These arguments were passed:\n%r\n\n' % ( tpl_args, )
	doc_text.insertString( cursor, s_text_1, 0 )

	return 0

The following aspects of the task were easy enough to understand from the documentation:

  • putting the script file into the document (unzip/zip)
  • making a toolbar button and connecting it to the function

Why was it so hard to find the clue about XSCRIPTCONTEXT?

The clue is given in HelloWorldPython(), but that example

  • is given in a context other than embedding in a document
  • does not run, so i ignored it. (it does not run because it does not accept an argument)

The example that is given in the context of embedding in the document (push_me_python4.odt) does not use XSCRIPTCONTEXT. (It runs from a dialog, so it gets an 'event' instance passed to it, and gets context from that; so this example is no use if you want to run from a toolbar button.)

I'm thinking of writing a separate page about "Simple Python macro", and linking to it from 'Python_as_a_macro_language'.

jim_hill_au 14:30, 8 June 2007 (CEST)

Contribute to the python samples

I would like if you help me build the Python-UNO page, I already have quite a bit, you might want to check one of the latest page I have been working at which are the Python_samples which is the ones that are included in the OOo distribution.

what i discovered so far

after many more hours of agony, i got the hang of it.

need to write more, will try to find time in a week or few.

for now, here's a sample that uses all the little tricks i've discovered. It's a bit messy, but i want to get it out, rather than wait until i can clean it.

This is for running INside the OO process, not connecting from outside.


## import time
## import pyuno
import uno 	# i use only getComponentContext()
import unohelper 	# i use only inspect()
from import PropertyValue
from pprint import pformat 	# saferepr

## from import PARAGRAPH_BREAK as PARA_BRK

doc0 = XSCRIPTCONTEXT.getDocument()
## dtop = XSCRIPTCONTEXT.getDesktop()

text0 = doc0.Text
cursor0 = text0.createTextCursor()

controller0 = doc0.getCurrentController()
frame0 = controller0.getFrame()
## model0 = controller0.Model
## assert model0 == doc0 	# it is
## assert model0 is doc0 	# it's not

## vw_cursr = controller0.ViewCursor 	# this is the Cursor the user sees
## vw_cursr.gotoEnd(0)

# this oContext is NOT the same as XSCRIPTCONTEXT
oContext = uno.getComponentContext()
oServiceManager = oContext.ServiceManager
dispatcher = oServiceManager.createInstanceWithContext( "", oContext )
## dispatcher = unohelper.createUnoService("")

s_file_notes = "./auto_notes.txt"
fil_notes = open(s_file_notes, 'w+', 0)

def _make_propval( name, value ):
	pv = PropertyValue()
	pv.Name = name
	pv.Value = value
	return pv
def _make_props_tuple( d_props ):
	props = []
	for k, v in d_props.items():
		props.append( _make_propval( k, v ) )
	return tuple(props)

def _write_seq( seq1, cursor=cursor0  ):
	for v in seq1:
		v2 = '%s\n' % v
		text0.insertString( cursor, v2, 0 )
	return 0
def _write( v1, cursor=cursor0  ):
## def _write( v1, cursor=vw_cursr  ):
	## if type(v1) ==
	## text0.insertString( cursor, type(v1), 0 )
	## text0.insertString( cursor, v1, 0 )
	## v2 = '%s' % v1
	## v2 = unicode(v1)
	v2 = '%s\r' % v1
	## v2 = '%r\r' % v1
	text0.insertString( cursor, v2, 0 )
	return 0

def _introspect_py_object(o):
	s_type = type(o)
	s_dict = pformat(o.__dict__)
	s_string = pformat(str(o))
	return s_type, s_dict, s_string
def _write_py_object_info(o, s_name="no_name" ):
	s_type, s_dict, s_string = _introspect_py_object(o)
	s_info = "name: \t%s\ntype: \t%s\ndict:\n%s\nstring:\n%s\n" \
		% ( s_name, s_type, s_dict, s_string, )
	_write( s_info )
	return 0
def _object_info_to_file(o, s_name, file1=fil_notes ):
	file1.write('\n%s\n' % s_name)
	unohelper.inspect(o, file1 )
	return 0

def TableToText( *tpl_args ):
	# manually put the cursor in a table before you run this
	t_props = _make_props_tuple( { "Delimiter":chr(9), } )
	dispatcher.executeDispatch( frame0, ".uno:ConvertTableToText", "", 0, t_props )
def export( *tpl_args ):

	d_props = {
	"FilterName":"Text (encoded)",
	## "FilterName":"writer_pdf_Export",
	## "SelectionOnly":True, 	# has no effect
	## "SelectionOnly":1, 	# has no effect
	t_props = _make_props_tuple( d_props )

	file_url = "file://....../save_test.txt" #XXX write your own
	# at this point u could get doc0.URL, extract the path from it,
	# and use that as the location for the text file.
	doc0.storeToURL(file_url, t_props)

	# this is no good, it brings up the ui dialog
	## dispatcher.executeDispatch( frame0, ".uno:SaveAs", "", 0, props )

def replace( *tpl_args ):

	xRD = doc0.createReplaceDescriptor()

	## s_find = '$'
	## s_repl = '|'

	## s_find = '\|'
	## s_repl = '\n'

	## xRD.SearchRegularExpression = True

	s_find = 'g'
	s_repl = 'z'

	xRD.SearchString = s_find
	xRD.ReplaceString = s_repl
	n_found = doc0.replaceAll( xRD )
	_write( 'n_found a: %s\n' % n_found )

	# use undo to put it back the way it was, so you can run the test again

	return 0
def test( *tpl_args ):
	## _write_py_object_info(oContext, "oContext")
	## _write_py_object_info(XSCRIPTCONTEXT, 'XSCRIPTCONTEXT')
	## _write( doc0.Location, )
	## _write( doc0.URL, )
	## _write( doc0.DocumentSubStoragesNames, )
	## _object_info_to_file( doc0.DocumentStorage, 'doc0.DocumentStorage')
	## tpl1 = doc0.DocumentStorage.getElementNames()
	## _write_seq( tpl1, 'Storage ElementNames')
	## x= doc0.Parent; _write(type(x))
	## _object_info_to_file( doc0.Parent, 'doc0.Parent')
	## _object_info_to_file( doc0, 'doc0' )
	## TableToText()
	## export()
	return 0

## s_test = "\nThis text is set, and written, outside of any function.\n\n"
## text0.insertString( cursor0, s_test, 0 )

# end

- jim_hill_au 2007-07-06 16h AEST

forgot to mention -- i set a toolbar button to run test(), and the script is in my OO user area, so i can easily edit it in between clicks of the button. the reason for all the ## lines in test() is they're the things i've been trying out.

- jh

Personal tools