Page 1 sur 1

[Résolu][Python] Ajout d'entrée au menu contextuel

Publié : 03 août 2010 21:11
par OlivierR
Bonjour à tous,

But
J’essaie d’ajouter des entrées au menu contextuel. Je parviens à ajouter un séparateur et une entrée au menu, mais impossible d’y mettre un texte. Une image s’y trouve par défaut, je ne l’y ai pas ajoutée. Voilà ce que ça donne :
xMenu.png
Le code
Voici le code épuré de ce qui n’est pas utile :

Code : Tout sélectionner

import uno
import unohelper

def writeLog (s):
    log = codecs.open("C:\_log.txt", "a", "utf-8")
    log.write(s+"\n")
    log.close()

from com.sun.star.task import XJob
from com.sun.star.ui import XContextMenuInterceptor
from com.sun.star.lang import XMultiServiceFactory
from com.sun.star.beans import XPropertySet
from com.sun.star.container import XIndexContainer
from com.sun.star.uno import Exception as UnoException
from com.sun.star.beans import UnknownPropertyException
from com.sun.star.lang import IllegalArgumentException

def analyzeWord (word):
    [ écrit l’analyse de word dans le fichier de log et renvoie un tableau de chaînes comme résultat ]

class MyContextMenuInterceptor (XContextMenuInterceptor, unohelper.Base):
    def __init__ (self, ctx):
        self.ctx = ctx
        writeLog('Init menu interceptor!')

    def notifyContextMenuExecute (self, event):
        try:
            writeLog(' >begin menu')
            # Retrieve context menu container and query for service factory to create sub menus, menu entries and separators
            xContextMenu = event.ActionTriggerContainer
            xMenuElementFactory = xContextMenu 
            #xray(xMenuElementFactory)
            if (xMenuElementFactory):
                # create a line separator
                xSeparator = xMenuElementFactory.createInstance("com.sun.star.ui.ActionTriggerSeparator")
                xSeparator.SeparatorType = uno.getConstantByName("com.sun.star.ui.ActionTriggerSeparatorType.LINE")
                writeLog(' >1')
                
                # create root menu entry
                xRootMenuEntry = xMenuElementFactory.createInstance("com.sun.star.ui.ActionTrigger")
                xray(xRootMenuEntry)
                lMorphWord = analyzeWord('m**de')
                writeLog(' >2')
                # query sub menu for index container to get access
                xSubMenuContainer = xMenuElementFactory.createInstance("com.sun.star.ui.ActionTriggerContainer")
                writeLog(' >3')
                # intialize root menu entry "Help"
                #xRootMenuEntry.setPropertyValue('Text', 'Grammalecte')
                #xRootMenuEntry.Text = "Grammalecte"
                xRootMenuEntry.CommandURL = "slot:5410"
                xRootMenuEntry.HelpURL = "5410"
                #xRootMenuEntry.SubContainer = xSubMenuContainer
                #xray(xSubMenuContainer)
                writeLog(' >4')
                # create menu entries for the new sub menu

                [ création des éléments du sous-menu ]
                
                # add separator into the given context menu
                xContextMenu.insertByIndex(0, xSeparator)
                # add new sub menu into the given context menu
                xContextMenu.insertByIndex(0, xRootMenuEntry)
                writeLog(' >end menu')
                
                # The controller should execute the modified context menu and stop notifying other interceptors.
                return uno.getConstantByName("com.sun.star.ui.ContextMenuInterceptorAction.EXECUTE_MODIFIED")
        except:
            writeLog('ERREUR!')

        return uno.getConstantByName("com.sun.star.ui.ContextMenuInterceptorAction.IGNORED")

class JobExecutor (XJob, unohelper.Base):
    def __init__ (self, ctx):
        self.ctx = ctx
        [ initialisation du correcteur orthographique ]
        
    def execute (self, args):
        [ initialisation du MyContextMenuInterceptor ]

g_ImplementationHelper = unohelper.ImplementationHelper()
g_ImplementationHelper.addImplementation(JobExecutor, "grammalecte.by.OlivierR.ContextMenuHandler", ("grammalecte.by.OlivierR.ContextMenuHandler",),)
Ceci est une transcription du code en Java.


Focus sur le problème
En regardant l’objet avec xray, je constate que deux propriétés de cet élément de menu ne sont pas conformes à l’API et que l’objet est d’un type inconnu de xray. Apparemment donc, si je comprends bien, c’est la commande createInstance n’est pas faite correctement.

Avec

Code : Tout sélectionner

                xRootMenuEntry = xMenuElementFactory.createInstance("com.sun.star.ui.ActionTrigger")
                xray(xRootMenuEntry)
xray affiche:
xRootMenuEntry.png
Ce qui n’est pas conforme avec ce que dit l’API sur cet objet : ActionTrigger

C’est pourquoi les lignes ici commentées

Code : Tout sélectionner

                #xRootMenuEntry.setPropertyValue('Text', 'Grammalecte')
                #xRootMenuEntry.Text = "Grammalecte"
                xRootMenuEntry.CommandURL = "slot:5410"
                xRootMenuEntry.HelpURL = "5410"
                #xRootMenuEntry.SubContainer = xSubMenuContainer
soulèvent immanquablement une erreur (si elles sont décommentées bien sûr). Le type des propriétés n’est pas conforme à ce que je suis censé y écrire! Du reste, sur SubContainer et Text, xray déclare lui-même que le type des données n’est pas cohérent.


Analyse
Le souci vient certainement de ma compréhension du sac de nœuds services/interfaces/structures qui est assez embrouillée. J’ai probablement mal traduit de Java à Python. Alors je reprends ligne par ligne sur le passage délicat :

En Java :

Code : Tout sélectionner

com.sun.star.container.XIndexContainer xContextMenu = aEvent.ActionTriggerContainer;
devient en Python :

Code : Tout sélectionner

xContextMenu = event.ActionTriggerContainer
En Java :

Code : Tout sélectionner

com.sun.star.lang.XMultiServiceFactory xMenuElementFactory = (com.sun.star.lang.XMultiServiceFactory) UnoRuntime.queryInterface ( com.sun.star.lang.XMultiServiceFactory.class, xContextMenu );
com.sun.star.beans.XPropertySet xRootMenuEntry = (XPropertySet)UnoRuntime.queryInterface ( com.sun.star.beans.XPropertySet.class, xMenuElementFactory.createInstance ( "com.sun.star.ui.ActionTrigger" ));
devient en Python :

Code : Tout sélectionner

xMenuElementFactory = xContextMenu
xRootMenuEntry = xMenuElementFactory.createInstance("com.sun.star.ui.ActionTrigger")
La ligne [xMenuElementFactory = xContextMenu] ne sert évidemment à rien, hormis me rappeler qu’en Java, il faut explicitement appeler une interface dont les méthodes sont directement disponibles par l’objet en Python (si je ne m’abuse, mais mon erreur est peut-être là?).


Extension fournie
Je vous joins l’extension qui fait tout ça. Il suffit d’installer.
[[ lien supprimé ]]
:!: Si vous êtes sous Linux, avant de relancer OOo, éditez le fichier grammalecte.py et modifiez la méthode writeLog :

Code : Tout sélectionner

def writeLog (s):
    log = codecs.open("C:\_log.txt", "a", "utf-8")
    log.write(s+"\n")
    log.close()
Modifiez le chemin d’écriture du log.

Le log renvoie quelque chose comme ceci :

Code : Tout sélectionner

====== Init job! ======
Hunspell & Locale FR!
execute job
Init menu interceptor!
job done
 >begin menu
 >1
 st:m**de po:interj
 st:m**de po:nom is:fem
 st:merder po:verb is:spré is:3sg
 st:merder po:verb is:spré is:1sg
 st:merder po:verb is:ipré is:3sg
 st:merder po:verb is:ipré is:1sg
 >2
 >3
 >4
 >5
 >6
 >7
 >end menu

Re: [Python] un service renvoie un objet inconnu de xray

Publié : 04 août 2010 07:26
par bm92
Bonjour,
Je n'ai pas vu d'erreur dans le (trans)codage, je penche plutôt pour une erreur de l'API, qui renvoie un objet incorrect.

Xray retransmet le message d'erreur de Basic quand il essaie de lire la propriété Text avec .getPropertyValue()
Or cette propriété existe, car elle est listée grâce à l'introspection. Ton erreur signifie que .setPropertyValue() ne marche pas non plus.

Plus bizarre : les propriétés CommandURL et HelpURL fonctionnent pour toi (car non commentées) alors que Xray voit la même erreur. Cela semble dire que .getPropertyValue() ne marche pas, mais .setPropertyValue() marche pour ces deux propriétés. Tu pourrais le vérifier en essayant de lire les propriétés, avant de les modifier.

Si tu fais un rapport d'anomalie, ou si tu poses la question dans la liste de diffusion dev@api (s'incrire avec un message à dev_subscribe@api.openoffice.org ), il faudrait réduire le codage à une tentative d'écriture sur cette propriété Text de xRootMenuEntry, qui déclenche une erreur.
Inutile de parler de Xray, les développeurs Sun ne connaissent pas :mrgreen:

Re: [Python] un service renvoie un objet inconnu de xray

Publié : 04 août 2010 07:50
par jjk
Bonjour à tous
bm92 a écrit :Inutile de parler de Xray, les développeurs Sun ne connaissent pas
Non ? j'y crois pas :fou:
Et ceux d'Oracle alors ?

Re: [Python] un service renvoie un objet inconnu de Xray

Publié : 27 juil. 2011 14:31
par adibe
Bonjour!

Avez-vous résoudre le problème d'affichage de texte? Je rencontre le même problème.

Merci,
Adrian.

Re: [Python] un service renvoie un objet inconnu de Xray

Publié : 27 juil. 2011 14:45
par Don Corleone
Bonjour,

Nous vous rappelons les règles de ce forum et notamment la n° 7
Un sujet = le problème d'une seule personne
Vous ne devez pas poser une question dans le fil d'un autre. Celle-ci ne fait qu'interférer et les réponses éventuellement postées ne feront qu'embrouiller la lecture du problème initial. Vous ne pourrez pas ajouter [Résolu] car vous n'êtes pas l'auteur de la première question.
Donc dans tous les cas, vous devez ouvrir un nouveau sujet pour votre question en rappelant que vous avez le même problème que dans ce fil.

Merci de votre collaboration.

Re: [Python] un service renvoie un objet inconnu de Xray

Publié : 27 juil. 2011 17:54
par OlivierR
Bonjour,

(J’avais oublié que j’avais posté ce sujet.)

Le bogue reste d’actualité. Il faudrait que je pense à faire un rapport digne de ce nom. Les dévs de LibO connaissent-ils XRay ? :mrgreen:

J’ai résolu l’affaire en contournant le problème il y a assez longtemps. J’ai repris la méthode d’une extension écrite en Basic, mais j’ai oublié laquelle.
ctxmenu.png
Je vous livre l’extension telle quelle, avec plein de lignes de code inutiles. Je vous laisse faire le nettoyage. Je n’ai pas le temps de m’en occuper pour l’instant. Je m’en sers surtout pour déboguer le correcteur grammatical, pour vérifier l’étiquetage des mots. Ça fonctionne.
ContextualMenu.oxt
Je ne sais pas trop s’il faut que je tague [issue] ou [résolu]. :wink: