Ajout d'un exercice de programmation Python+Gtk+Thread+Xmpp.
authorProgfou <jean-christophe.andre@auf.org>
Sun, 27 Sep 2009 22:31:02 +0000 (05:31 +0700)
committerProgfou <jean-christophe.andre@auf.org>
Sun, 27 Sep 2009 22:31:02 +0000 (05:31 +0700)
pygtranslator/pygtranslator.py [new file with mode: 0755]

diff --git a/pygtranslator/pygtranslator.py b/pygtranslator/pygtranslator.py
new file mode 100755 (executable)
index 0000000..ae77618
--- /dev/null
@@ -0,0 +1,206 @@
+#!/usr/bin/env python2.5
+# -*- coding: utf-8 -*-
+"""
+PygTranslator - pas de doc cette fois-ci... :-P
+
+Copyright : Agence universitaire de la Francophonie
+Licence : GNU General Public Licence, version 2
+Auteur : Jean Christophe André
+Date de création : 28 septembre 2009
+"""
+
+from threading import Thread
+from Queue import Queue
+import xmpp
+
+import pygtk
+pygtk.require('2.0')
+import gtk, gobject
+
+def DEBUG(message):
+    #print "\x1b[31;1mDEBUG\x1b[m:", message
+    return
+
+class XmppTranslator(Thread):
+
+    def __init__(self, jid, password):
+        Thread.__init__(self)
+        self.setDaemon(True)
+        self._input_queue = Queue(0)
+        self._output_queue = Queue(0)
+        self._quit = False
+
+        self._jid = xmpp.JID(jid)
+        self._password = password
+        if self._jid.getResource() == '':
+            self._jid.setResource('translator')
+
+        self._client = xmpp.Client(self._jid.getDomain(), debug=[])
+
+    def __del__(self):
+        if self._client and not self._client.isConnected():
+            return
+        self._client.sendPresence(typ='unavailable')
+        self._client.disconnect()
+
+    def _connect(self):
+        try:
+            if not self._client.connect():
+                raise IOError
+        except IOError:
+            raise IOError, "can't connect to '%s'" % self._jid.getDomain()
+        self._client.RegisterHandler('message', self._messageHandler)
+
+        auth = self._client.auth(self._jid.getNode(), self._password,
+                                                self._jid.getResource())
+        if not auth:
+            raise IOError, "unable to authenticate '%s'" % self._jid.getNode()
+        self._client.sendInitPresence(requestRoster=0)
+
+    def _messageHandler(self, client, message):
+        if message.getType() == 'error':
+            return
+        translation_path = message.getFrom().getNode()
+        text = message.getBody()
+        self._output_queue.put( (translation_path, text) )
+        raise xmpp.NodeProcessed
+
+    def _process_input_queue(self):
+        if self._input_queue.empty():
+            return
+        # process pending translation job
+        translation_path, text = self._input_queue.get()
+        jid = '%s@bot.talk.google.com' % translation_path
+        message = xmpp.Message(to=jid, typ='chat', body=text)
+        self._client.send(message)
+        DEBUG("sent [%s] to '%s'." % (text, jid))
+        self._input_queue.task_done()
+
+    def run(self):
+        self._connect()
+        self._client.Process(1)
+        while not self._quit:
+            self._process_input_queue()
+            self._client.Process(1)
+
+    def request_translation(self, translation_path, text):
+        # remove any pending translation job
+        while not self._input_queue.empty():
+            self._input_queue.get()
+            DEBUG("removed a pending translation job")
+            self._input_queue.task_done()
+        # put a new translation job
+        self._input_queue.put( (translation_path, text) )
+
+    def translation_result(self):
+        if self._output_queue.empty():
+            return None
+        translation_path, text = self._output_queue.get()
+        return translation_path, text
+
+    def translation_done(self):
+        self._output_queue.task_done()
+
+class GtkTranslator(object):
+
+    def __init__(self, translator):
+        self._translator = translator
+
+        self._textbuf = {}
+
+        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+        self.window.set_title(u"PygTranslator")
+        self.window.set_border_width(0)
+        self.window.connect("destroy", lambda w: gtk.main_quit())
+        self.window.connect("delete_event", self.delete_event)
+
+        vbox = gtk.VBox(True, 0)
+        vbox.show()
+
+        textview = gtk.TextView()
+        textview.set_size_request(400, 100)
+        textview.set_wrap_mode(gtk.WRAP_WORD)
+        textview.show()
+        scroll = gtk.ScrolledWindow()
+        scroll.add(textview)
+        scroll.show()
+        frame = gtk.Frame(u"Texte en français")
+        frame.connect("key_release_event", self.key_release_event, 'fr')
+        frame.add(scroll)
+        frame.show()
+        vbox.pack_start(frame, True, True, 0)
+        self._textbuf['fr'] = textview.get_buffer()
+
+        textview = gtk.TextView()
+        textview.set_size_request(400, 100)
+        textview.set_wrap_mode(gtk.WRAP_WORD)
+        textview.show()
+        scroll = gtk.ScrolledWindow()
+        scroll.add(textview)
+        scroll.show()
+        frame = gtk.Frame(u"Text in English")
+        frame.connect("key_release_event", self.key_release_event, 'en')
+        frame.add(scroll)
+        frame.show()
+        vbox.pack_start(frame, True, True, 0)
+        self._textbuf['en'] = textview.get_buffer()
+
+        self.window.add(vbox)
+        self.window.show()
+
+    def run(self):
+        DEBUG("running graphic interface")
+        gobject.timeout_add(100, self.process_translation_result)
+        gtk.gdk.threads_init()
+        gtk.main()
+
+    def delete_event(self, widget, event, data=None):
+        DEBUG("caught delete event")
+        gtk.main_quit()
+        return False
+
+    def key_release_event(self, widget, event, lang):
+        start, end = self._textbuf[lang].get_bounds()
+        text = self._textbuf[lang].get_text(start, end)
+        other_lang = (set(self._textbuf.keys()) - set((lang,))).pop()
+        translation_path = lang + '2' + other_lang
+        self._translator.request_translation(translation_path, text)
+
+    def process_translation_result(self):
+        result = {}
+        # FIXME: to transform into an iterator...
+        while True:
+            r = self._translator.translation_result()
+            if r is None:
+                break
+            translation_path, text = r
+            lang = translation_path[3:]
+            if lang in self._textbuf:
+                result[lang] = text
+            else:
+                DEBUG("unknown destination language '%s'" % lang)
+            self._translator.translation_done()
+        for lang, text in result.items():
+            self._textbuf[lang].set_text(text)
+        gobject.timeout_add(100, self.process_translation_result)
+
+if __name__ == "__main__":
+    import sys
+    if len(sys.argv) != 3:
+        print "Usage: %s <jid> <password>" % sys.argv[0]
+        sys.exit(1)
+
+    translator = XmppTranslator(sys.argv[1], sys.argv[2])
+    translator.start()
+
+    pygtranslator = GtkTranslator(translator)
+    try:
+        pygtranslator.run()
+    except KeyboardInterrupt:
+        pass
+
+    translator._quit = True
+    translator.join()
+
+    sys.exit(0)
+