Page 1 of 1

[Solved] Auto execute BASIC macro from python

Posted: Mon Aug 03, 2015 11:25 am
by sng
Hi all,

This is my situation:

I have a BASIC macro which adds an icon on the main toolbar (let's call it addIcon).
I would like this macro to be automatically executed whenever a new writer document is created or opened.

The way I do it right now is by manually assigning it to the open and create events of writer. The thing is that i have to do that every time i make a new LOO/AOO installation.

So, I would like this to be done by code.

I think this cannot be done with BASIC; I've read somewhere that it can be done with JAVA, but found no code.

Does anyone has such a code or point me to some resource?

Thanks
Spiros

Re: Writer: Auto execute BASIC macro by code

Posted: Mon Aug 03, 2015 11:59 am
by RoryOF

Re: Writer: Auto execute BASIC macro by code

Posted: Mon Aug 03, 2015 12:44 pm
by sng
Thanks for that

But I do have some questions on this one...
Python loader

The Python loader is not able load classes that are not it its own path. Thus it's necessary to copy any classes or modules you will use into the OPenOffice Python lib directory, and it may be necessary to restart OOo before they are picked up.
I wonder what this means when installing on Windows, Mac OS and Linux. Is this handled by the installer? (I mean the "Extension Manager")

The test program (which actually triggers the class) is, as far as I can understand, executed when the program is explicitly executed (/opt/openoffice.org1.9.103/program/python ./Wavelet.py). Furthermore, it should also be removed before packaging the extension.

If this part is removed, how will the class get automatically triggered?
Is it enough to register is as com.sun.star.task.Job?

Sorry for the "stupid" questions, but this is all new to me...

Spiros

Re: Writer: Auto execute BASIC macro by code

Posted: Mon Aug 03, 2015 3:28 pm
by sng
Ok, I did some reading...

It seems that I need to have this py file (shicon.py)

Code: Select all

import uno
import unohelper
from com.sun.star.task import XJobExecutor
from com.sun.star.uno import RuntimeException
 
class ShowIcon( unohelper.Base, XJobExecutor ):

    def __init__( self, ctx ):
        self.ctx = ctx

    def createUnoService(serviceName):
        """ gets a service from Uno """
        sm = uno.getComponentContext().ServiceManager
        result = sm.createInstance(serviceName)
        if not result:
            raise RuntimeException("\nService not available :\n" + serviceName, uno.getComponentContext())
        return result

    def trigger( self, args ):
        _mspf = createUnoService("com.sun.star.script.provider.MasterScriptProviderFactory")
        scriptPro = _mspf.createScriptProvider("") 
        try:
            Xscript = scriptPro.getScript("vnd.sun.star.script:myLibrary.myModule.addIcon?language=Basic&location=application") 
            Xscript.invoke( ( (), ), (), () )
        except:
            pass
            """ sys.exc_clear() """


g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(
        ShowIcon,
        "my.extension.id.oxt",
        ("com.sun.star.task.Job",),)
I also have to create a Jobs.xcu file

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE oor:component-data SYSTEM "../../../../component-update.dtd">
  <oor:component-data oor:name="Jobs" 
                      oor:package="org.openoffice.Office" 
                      xmlns:oor="http://openoffice.org/2001/registry" 
                      xmlns:xs="http://www.w3.org/2001/XMLSchema" 
                      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <node oor:name="Jobs">
          <node oor:name="ShowIcon" oor:op="replace">
              <prop oor:name="Service">
                  <value>vnd.sun.star.jobs.ShowIcon</value>
              </prop>
          </node>
      </node>
      <node oor:name="Events">
          <node oor:name="onNew" oor:op="fuse">
              <node oor:name="JobList">
                  <node oor:name="ShowIcon" oor:op="replace"/>
              </node>
          <node oor:name="onLoad" oor:op="fuse">
              <node oor:name="JobList">
                  <node oor:name="ShowIcon" oor:op="replace"/>
              </node>
          </node>
          </node>
      </node>
  </oor:component-data>
And probably add a couple of lines in manifest.xml

Code: Select all

<manifest:file-entry manifest:media-type="application/vnd.sun.star.configuration-data" manifest:full-path="Jobs.xcu"/> 
<manifest:file-entry manifest:media-type="application/vnd.sun.star.uno-component;type=Python" manifest:full-path="shicon.py"/> 
Did I get it right?
Do you see anything wrong so far?

Spiros

Re: Writer: Auto execute BASIC macro by code

Posted: Mon Aug 03, 2015 3:38 pm
by RoryOF
This is not my area of expertise, so I can make no comment.

Re: Writer: Auto execute BASIC macro by code

Posted: Mon Aug 03, 2015 3:44 pm
by sng
RoryOF wrote:This is not my area of expertise, so I can make no comment.
Well, thank you anyway for your help so far.
I will start testing and report back...

Spiros

Re: Writer: Auto execute BASIC macro by code

Posted: Mon Aug 03, 2015 6:07 pm
by hanya
The way I do it right now is by manually assigning it to the open and create events of writer. The thing is that i have to do that every time i make a new LOO/AOO installation.
It can have only an assignment for each event. It seems I have wrote the code to execute some macros from the job events: http://hermione.s41.xrea.com/pukiwiki/i ... obbs3%2F60

- You have some problems in your Python code. The local variable can not be refered inside another method.
- "invoke" function to execute the macro require three arguments.
The Python loader is not able load classes that are not it its own path. Thus it's necessary to copy any classes or modules you will use into the OPenOffice Python lib directory, and it may be necessary to restart OOo before they are picked up.
This description is little bit old.
See "Implementing UNO components with multiple source files" section in http://www.openoffice.org/udk/python/python-bridge.html

Re: Writer: Auto execute BASIC macro by code

Posted: Tue Aug 04, 2015 9:47 am
by sng
hanya wrote:
The way I do it right now is by manually assigning it to the open and create events of writer. The thing is that i have to do that every time i make a new LOO/AOO installation.
It can have only an assignment for each event. It seems I have wrote the code to execute some macros from the job events: http://hermione.s41.xrea.com/pukiwiki/i ... obbs3%2F60
This is great, but

I have tried it and this is what the Extension Manager reports:

Code: Select all

(com.sun.star.uno.RuntimeException) { { Message = "unknown entity reference in file:///Users/spiros/Library/Application%20Support/LibreOffice/4/user/uno_packages/cache/uno_packages/lux0y7m5.tmp_/myPlugin.oxt/Jobs.xcu", Context = (com.sun.star.uno.XInterface) @0 } }
The only way to make it work was to change the URL so that
?language=Basic&location=application
becomes
?language=Basic&location=application

But then again, it does not run my BASIC code.

Then I enabled a print("Valid") statement in the PY file, but I still do not see anything.
Am I doing something wrong?
hanya wrote: - You have some problems in your Python code. The local variable can not be refered inside another method.
- "invoke" function to execute the macro require three arguments.
Yes, of course, you are right
I have already edited the code...

Since I pass no parameters to BASIC, I have used invoke( ( (), ), (), () )
Hope this works (haven't tested it yet...)
hanya wrote:
The Python loader is not able load classes that are not it its own path. Thus it's necessary to copy any classes or modules you will use into the OPenOffice Python lib directory, and it may be necessary to restart OOo before they are picked up.
This description is little bit old.
See "Implementing UNO components with multiple source files" section in http://www.openoffice.org/udk/python/python-bridge.html
Thanks for this one

Spiros

Re: Writer: Auto execute BASIC macro by code

Posted: Tue Aug 04, 2015 4:12 pm
by Arineckaig
I have a BASIC macro which adds an icon on the main toolbar (let's call it addIcon).
I would like this macro to be automatically executed whenever a new writer document is created or opened.
The way I do it right now is by manually assigning it to the open and create events of writer. The thing is that i have to do that every time i make a new LOO/AOO installation.

Does anyone has such a code or point me to some resource?
Many apologies for my interference if I have misuderstood the requirement.

It can perhaps be done without a macro by adding the icon to the standard toolbar using the Tools>>Customise...>>Toolbars tab routine. The added icon can be for all new Writer documents, for any specific Writer Template(s) or even just for Base Form documents that are essentially Writer documents.

Re: Writer: Auto execute BASIC macro by code

Posted: Tue Aug 04, 2015 4:27 pm
by sng
Arineckaig wrote:
I have a BASIC macro which adds an icon on the main toolbar (let's call it addIcon).
I would like this macro to be automatically executed whenever a new writer document is created or opened.
The way I do it right now is by manually assigning it to the open and create events of writer. The thing is that i have to do that every time i make a new LOO/AOO installation.

Does anyone has such a code or point me to some resource?
Many apologies for my interference if I have misuderstood the requirement.

It can perhaps be done without a macro by adding the icon to the standard toolbar using the Tools>>Customise...>>Toolbars tab routine. The added icon can be for all new Writer documents, for any specific Writer Template(s) or even just for Base Form documents that are essentially Writer documents.


Well, I suppose you've missed this spot...
So, I would like this to be done by code.

I think this cannot be done with BASIC; I've read somewhere that it can be done with JAVA, but found no code.
But that's all right, being eager to help is enough :D

Kind regards,
Spiros

Re: Writer: Auto execute BASIC macro by code

Posted: Tue Aug 04, 2015 4:54 pm
by Arineckaig
So, I would like this to be done by code.
I did not miss that sentence, but in my, admittedly limited, experience resort to macros in AOO is seldom productive when coding can be avoided.

As this thread may well be read by other visitors to the forum there may well be some merit in suggesting there are simply ways to skin this particular cat.

Re: Writer: Auto execute BASIC macro by code

Posted: Tue Aug 04, 2015 6:57 pm
by sng
Arineckaig wrote:
So, I would like this to be done by code.
I did not miss that sentence, but in my, admittedly limited, experience resort to macros in AOO is seldom productive when coding can be avoided.

As this thread may well be read by other visitors to the forum there may well be some merit in suggesting there are simply ways to skin this particular cat.
This is off topic (both for me and the question I asked when I posted here).

Please do read the title

Re: Writer: Auto execute BASIC macro by code

Posted: Tue Aug 04, 2015 7:16 pm
by Villeroy
Basically your question is about how to let OpenOffice run any code automatically which potentially is a question about malware.
You can customize your own installation packages to include your GUI element.
You can customize your own installation packages to run your macro automatically.
You can work with your own default templates including GUI elements macros, stlyes, auto-text and what else.
But you have to do some kind of customization without hoping for auto-run magic that could be misused for anything.

Re: Writer: Auto execute BASIC macro by code

Posted: Tue Aug 04, 2015 10:00 pm
by sng
Basically you are wrong
Villeroy wrote:Basically your question is about how to let OpenOffice run any code automatically...
Not just any code, my code
Villeroy wrote:...which potentially is a question about malware.
This is insulting and I would expect an apology
Villeroy wrote:But you have to do some kind of customization without hoping for auto-run magic that could be misused for anything.
You couldn't be more mistaken.
The mechanism is already there.
What I'm asking is the way to use it

Re: Writer: Auto execute BASIC macro by code

Posted: Tue Aug 04, 2015 10:37 pm
by RoryOF
This extension adds a button to the toolbar; once installed the button is present on every instance of Writer
http://en.ooo-info.org/documentation/an ... _tool.html

The code is readily accessible from the downloaded extension.

Re: Writer: Auto execute BASIC macro by code

Posted: Tue Aug 04, 2015 10:42 pm
by sng
RoryOF wrote:This extension adds a button to the toolbar; once installed the button is present on every instance of Writer
http://en.ooo-info.org/documentation/an ... _tool.html

The code is readily accessible from the downloaded extension.
Thank you very much
I will look into it


EDIT
----------------
I'm afraid it does not display an icon... just a menu structure...

Re: Writer: Auto execute BASIC macro by code

Posted: Wed Aug 05, 2015 9:42 am
by RoryOF
Try this one:
http://aoo-extensions.sourceforge.net/e ... -ide-tools

It certainly adds buttons to its interface.

Re: Writer: Auto execute BASIC macro by code

Posted: Wed Aug 05, 2015 12:02 pm
by sng
RoryOF wrote:Try this one:
http://aoo-extensions.sourceforge.net/e ... -ide-tools

It certainly adds buttons to its interface.
Yes, it does, but these are static buttons and the extension does not implement auto execution


In the meantime I have tried any combination of PY and Jobs.xcu implementation I could think of, but no result :cry:
I give up.

If anybody can help in the future, please do

Spiros

Re: Writer: Auto execute BASIC macro by code

Posted: Wed Aug 05, 2015 3:00 pm
by sng
Here I am again... (I just can't let it go :lol: )

It seems to there are two problems here:

1. Running a BASIC Sub from python
2. Making it auto execute

Since I do not know which one fails, I decided to split the post

If you are interested, I've posted this: Python crashing on loading BASIC script

Spiros

Re: Writer: Auto execute BASIC macro by code

Posted: Sat Aug 08, 2015 2:22 am
by sng
Ok, it's done!!!

I will post here the way I did it:

I took another of hanya's examples, called InterceptContextMenu and tested it. I found out that it worked for the part that interested me (auto-load)

Then I changed it, combining code from OOobbs3/60 and ended up with a working python component!!!

Through a painful trial and error procedure, I found out that:
  • The order of base classes seems to be important. I think unohelper.Base must be the last one
  • LibreOffice does not provide the Config part, so URL was always empty (this is why it always failed...). So the URL must be hard-coded
  • The event list should be limited to the ones I actually worked with. So for me it's: onLoad, onNew, onCreate.
  • Even thought all this is done, my Windows tests were a total disaster (getting messages from BASIC that the argument is wrong, etc.). So I enclosed the Sub in a On Error goto structure. (Linux and Mac OS did not complain :super: )
These are the files

1. PY file (cmi.py)

Code: Select all

# coding: utf-8
import uno
import unohelper

from com.sun.star.task import XJob
from com.sun.star.document import DocumentEvent
from com.sun.star.lang import XServiceInfo
IMPLE_NAME = "mytools.ContextMenuHandler"

class JobExecutor(XJob, XServiceInfo, unohelper.Base):
    DOCUMENT_EVENTS = ("OnCreate", "OnNew", "OnLoad") 
    """ DOCUMENT_EVENTS = ("OnCreate", 
        "OnLoadFinished", "OnNew", "OnLoad", 
        "OnSave", "OnSaveAs", "OnSaveAsDone", 
        "OnPrepareunload", "OnFocus", "OnUnfocus", 
        "OnPrint", "OnModifyChanged", 
        "OnCopyTo", "OnCopyToDone", 
        "OnViewCreated", "OnPrepareViewClosing", 
        "OnVisAreaChanged", "OnCreate", "OnLoadFinished", 
        "OnSaveAsFailed", "OnSaveFailed", "OnCopyToFailed", 
        "TitleChanged", "OnMailMerge", "OnPageCountChange") """
    APPLICATION_EVENTS = ("OnStartApp", "OnCloseApp", 
        "OnUnload", "OnViewClosed")
    
    def __init__(self, ctx, *args):
        self.ctx = ctx
    # XServiceInfo
    def getImplementationName(self):
        return IMPLE_NAME
    def supportsService(self, name):
        return name == IMPLE_NAME
    def getSupportedServiceNames(self):
        return IMPLE_NAME, 
    def check_context(self, doc, context):
        if len(context) == 0:
            return True
        
        mod_manager = self.ctx.getServiceManager().createInstanceWithContext(
            "com.sun.star.frame.ModuleManager", self.ctx)
        identifier = mod_manager.identify(doc)
        return identifier in context
    
    def execute(self, args):
        """ Event executed. """
        event_name = ""
        doc = None
        url = ""
        context = []
        
        for arg in args:
            name = arg.Name
            #print(name)
            if name == "JobConfig": # Arguments
                options = arg.Value
                for option in options:
                    name = option.Name
                    if name == "URL":
                        url = option.Value
                        url.replace("&","&")
                    elif name == "Context":
                        context = option.Value.split(",")
            elif name == "Environment":
                envs = arg.Value
                #print(envs)
                for env in envs:
                    name = env.Name
                    if name == "EnvType" and env.Value == "DOCUMENTEVENT":
                        pass#print(env.Value)
                    elif name == "Model":
                        doc = env.Value
                    elif name == "EventName":
                        event_name = env.Value
        #
        valid = True
        if event_name in self.DOCUMENT_EVENTS:
            if not self.check_context(doc, context):
                valid = False
        else:
            # elif event_name in self.APPLICATION_EVENTS:
            doc = None
            
        if valid:
            # execute macro
            url = "vnd.sun.star.script:AncientGreek.IbycusIcon.AddIbycusIcon?language=Basic&location=application"
            sp = doc.getScriptProvider()
            script = sp.getScript(url)
            #if not script:
            #    print("no script")
            ev = DocumentEvent(doc, event_name, None, None)
            a=None
            b=None
            script.invoke((ev,), a, b)

g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(
	JobExecutor,
	"mytools.ContextMenuHandler", ("mytools.ContextMenuHandler",),)
2. jobs.xcu

Code: Select all

<?xml version="1.0"?>
<oor:component-data xmlns:oor="http://openoffice.org/2001/registry" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:install="http://openoffice.org/2004/installation" oor:name="Jobs" 
oor:package="org.openoffice.Office">
<node oor:name="Jobs">
	<node oor:name="StartIA" oor:op="replace">
		<prop oor:name="Service">
			<value>mytools.ContextMenuHandler</value>
		</prop>
	</node>
</node>
<node oor:name="Events">
	<node oor:name="OnNew" oor:op="fuse">
		<node oor:name="JobList">
			<node oor:name="StartIA" oor:op="replace"/>
		</node>
	</node>
	<node oor:name="OnLoad" oor:op="fuse">
		<node oor:name="JobList">
			<node oor:name="StartIA" oor:op="replace"/>
		</node>
	</node>
	<node oor:name="OnCreate" oor:op="fuse">
		<node oor:name="JobList">
			<node oor:name="StartIA" oor:op="replace"/>
		</node>
	</node>
</node>
</oor:component-data>
3. META-INF/manifest.xml

Code: Select all

   	<manifest:file-entry manifest:media-type="application/vnd.sun.star.configuration-data" manifest:full-path="jobs.xcu"/>
  	<manifest:file-entry manifest:media-type="application/vnd.sun.star.uno-component;type=Python" manifest:full-path="cmi.py"/>-->
If you are combining the autoload component with an existing extension, you will just have to add these line to whatever is in manifest.xml

4. The BASIC Sub

Code: Select all

Sub AddIbycusIcon
    On Error Goto xxxOut

    ***   Any code here   ***

    xxxOut:
        On Error GoTo 0
End Sub
That's it...

hanya thank you very much for the wonderful examples. :bravo: :bravo: :bravo:

And thank you all for helping out!!! :D

Marking it as Solved and changing the title of my first post in order to be accurate (hope this does not break any rule :alarm: )

Spiros