Will Pittenger wrote:No, I'm I working on a Writer doc.
I'll use that in my example.
Will Pittenger wrote:
Charlie Young wrote:If you want the sort of thing that is a called from the menus or a toolbar button, that is called an add-on, and my knowledge of that is sketchy.
A button would be handy, but I just want a way to trigger the code's execution.
What I'm going to suggest should work from a button.
Will Pittenger wrote:
Charlie Young wrote:You can also write routines, then call them from say, Basic, Python, or Javascript, and this is sometimes nice, especially to get something that runs faster than interpreted code. Sometimes here you need to have Office running in listening mode.
This is what I have in mind, although I don't know what you mean by listening mode.
Listening mode refers to having an Office process running in the background which enables communication with an external program. It is necessary if the program needs to directly manipulate the UNO objects in the document. It is started from the command line with either
Code: Select all
soffice -invisible -accept=pipe,name=mypipe;urp;StarOffice.ServiceManager
or
Code: Select all
soffice -invisible -accept=socket,host=localhost,port=2083;urp;StarOffice.ServiceManager
The pipe method is usually the one used on a local machine, and as I will discuss, can be automatically done by a program.
I needed some example of something to do with a Writer document, so I went back to
this silly thing of mine, which just colors all the words in a document in a cycle.
I translated that into javascript to see how it would work that way.
Code: Select all
// Color words
importClass(Packages.com.sun.star.uno.UnoRuntime);
importClass(Packages.com.sun.star.text.XTextDocument);
importClass(Packages.com.sun.star.text.XText);
importClass(Packages.com.sun.star.text.XTextCursor);
importClass(Packages.com.sun.star.text.XWordCursor);
importClass(Packages.com.sun.star.frame.XModel);
importClass(Packages.com.sun.star.beans.XPropertySet);
importClass(java.awt.Color);
WordColor = new Array();
WordColor[0] = Color(1,0,0); //red
WordColor[1] = Color(1,165/255,0); //orange
WordColor[2] = Color(1,1,0); //yellow
WordColor[3] = Color(0,1,0); //green
WordColor[4] = Color(0,0,1); //blue
WordColor[5] = Color(75/255,0,130/255); //indigo
WordColor[6] = Color(223/255,130/255,238/255); //violet
n = WordColor.length;
oDoc = UnoRuntime.queryInterface(XModel,XSCRIPTCONTEXT.getInvocationContext());
if ( !oDoc )
oDoc = XSCRIPTCONTEXT.getDocument();
xTextDoc = UnoRuntime.queryInterface(XTextDocument,oDoc);
xText = xTextDoc.getText();
nCursor = xText.createTextCursor();
wCursor = UnoRuntime.queryInterface(XWordCursor, nCursor);
nCursor.gotoStart(false);
MoreText = true;
c = 0;
while(MoreText)
{
wCursor.gotoEndOfWord(true);
colorer = UnoRuntime.queryInterface(XPropertySet, nCursor);
w = WordColor[c].getRGB();
colorer.setPropertyValue("CharColor",new java.lang.Integer(w));
c = (c + 1) % n;
MoreText = wCursor.gotoNextWord(false);
}
Next, I wrote a c++ program to do the coloring, the point being that one can then call the .exe file from a macro. The program, whatever language it is in, has to establish a pipe or socket connection. In older Office versions it was necessary to start the listening process as discussed earlier, then have a special routine in the program to fetch the process. Nowadays the bootstrap for the ServiceManager automatically gets a pipe connection.
In c++, that looks like this:
Code: Select all
// Creates a simple registry service instance.
Reference< XSimpleRegistry > xSimpleRegistry(
::cppu::createSimpleRegistry() );
// Connects the registry to a persistent data source represented by a URL.
xSimpleRegistry->open( OUString::createFromAscii("C:\\Documents and Settings\\Charlie\\My Documents\\Visual Studio 2010\\Projects\\ColorWords\\ColorWords.rdb"), sal_True, sal_False );
Reference< XComponentContext > xComponentContext(::cppu::bootstrap_InitialComponentContext( xSimpleRegistry ) );
Reference<XComponentContext> rComponentContext = ::cppu::bootstrap ();
Reference<XMultiComponentFactory> xServiceManager = rComponentContext->getServiceManager ();
Reference< XMultiServiceFactory > rOfficeServiceManager (xServiceManager,UNO_QUERY);
The SDK includes Java examples illustrating the same process.
Having gotten the ServiceManager above, we can use it to get the Desktop's CurrentComponent, which here we assume is going to be a text document:
Code: Select all
Reference < XInterface > Desktop = rOfficeServiceManager->createInstance(OUString::createFromAscii( "com.sun.star.frame.Desktop" ));
Reference< XDesktop > xDesktop(Desktop, UNO_QUERY);
Reference< XComponent > xcomponent = xDesktop->getCurrentComponent();
Reference< XTextDocument > xTextDoc (xcomponent, UNO_QUERY);
Reference< XText > oText = xTextDoc->getText();
It should be similar in Java, and then you can use the xTextDoc to do whatever you want (like color the words).
Once you have the .exe, written in whatever language, you can call it from a javascript macro like so:
Code: Select all
importClass(Packages.com.sun.star.uno.UnoRuntime);
importClass(Packages.com.sun.star.system.XSystemShellExecute);
xCompCont = XSCRIPTCONTEXT.getComponentContext();
xMultiComponentFactory = xCompCont.getServiceManager();
shell = xMultiComponentFactory.createInstanceWithContext('com.sun.star.system.SystemShellExecute', xCompCont);
xshell = UnoRuntime.queryInterface(XSystemShellExecute, shell);
xshell.execute("C:\\...path...\\ColorWords.exe","",0);
If you do this in a jscript macro, you can attach that macro to a button or a menu item as easily as you could a Basic macro. There is no need to call Java from basic, though that is possible.