Ajout d'un exercice de programmation Python+Gtk+Thread+Xmpp.
[progfou.git] / pygtranslator / pygtranslator.py
CommitLineData
e603e417
P
1#!/usr/bin/env python2.5
2# -*- coding: utf-8 -*-
3"""
4PygTranslator - pas de doc cette fois-ci... :-P
5
6Copyright : Agence universitaire de la Francophonie
7Licence : GNU General Public Licence, version 2
8Auteur : Jean Christophe André
9Date de création : 28 septembre 2009
10"""
11
12from threading import Thread
13from Queue import Queue
14import xmpp
15
16import pygtk
17pygtk.require('2.0')
18import gtk, gobject
19
20def DEBUG(message):
21 #print "\x1b[31;1mDEBUG\x1b[m:", message
22 return
23
24class XmppTranslator(Thread):
25
26 def __init__(self, jid, password):
27 Thread.__init__(self)
28 self.setDaemon(True)
29 self._input_queue = Queue(0)
30 self._output_queue = Queue(0)
31 self._quit = False
32
33 self._jid = xmpp.JID(jid)
34 self._password = password
35 if self._jid.getResource() == '':
36 self._jid.setResource('translator')
37
38 self._client = xmpp.Client(self._jid.getDomain(), debug=[])
39
40 def __del__(self):
41 if self._client and not self._client.isConnected():
42 return
43 self._client.sendPresence(typ='unavailable')
44 self._client.disconnect()
45
46 def _connect(self):
47 try:
48 if not self._client.connect():
49 raise IOError
50 except IOError:
51 raise IOError, "can't connect to '%s'" % self._jid.getDomain()
52 self._client.RegisterHandler('message', self._messageHandler)
53
54 auth = self._client.auth(self._jid.getNode(), self._password,
55 self._jid.getResource())
56 if not auth:
57 raise IOError, "unable to authenticate '%s'" % self._jid.getNode()
58 self._client.sendInitPresence(requestRoster=0)
59
60 def _messageHandler(self, client, message):
61 if message.getType() == 'error':
62 return
63 translation_path = message.getFrom().getNode()
64 text = message.getBody()
65 self._output_queue.put( (translation_path, text) )
66 raise xmpp.NodeProcessed
67
68 def _process_input_queue(self):
69 if self._input_queue.empty():
70 return
71 # process pending translation job
72 translation_path, text = self._input_queue.get()
73 jid = '%s@bot.talk.google.com' % translation_path
74 message = xmpp.Message(to=jid, typ='chat', body=text)
75 self._client.send(message)
76 DEBUG("sent [%s] to '%s'." % (text, jid))
77 self._input_queue.task_done()
78
79 def run(self):
80 self._connect()
81 self._client.Process(1)
82 while not self._quit:
83 self._process_input_queue()
84 self._client.Process(1)
85
86 def request_translation(self, translation_path, text):
87 # remove any pending translation job
88 while not self._input_queue.empty():
89 self._input_queue.get()
90 DEBUG("removed a pending translation job")
91 self._input_queue.task_done()
92 # put a new translation job
93 self._input_queue.put( (translation_path, text) )
94
95 def translation_result(self):
96 if self._output_queue.empty():
97 return None
98 translation_path, text = self._output_queue.get()
99 return translation_path, text
100
101 def translation_done(self):
102 self._output_queue.task_done()
103
104class GtkTranslator(object):
105
106 def __init__(self, translator):
107 self._translator = translator
108
109 self._textbuf = {}
110
111 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
112 self.window.set_title(u"PygTranslator")
113 self.window.set_border_width(0)
114 self.window.connect("destroy", lambda w: gtk.main_quit())
115 self.window.connect("delete_event", self.delete_event)
116
117 vbox = gtk.VBox(True, 0)
118 vbox.show()
119
120 textview = gtk.TextView()
121 textview.set_size_request(400, 100)
122 textview.set_wrap_mode(gtk.WRAP_WORD)
123 textview.show()
124 scroll = gtk.ScrolledWindow()
125 scroll.add(textview)
126 scroll.show()
127 frame = gtk.Frame(u"Texte en français")
128 frame.connect("key_release_event", self.key_release_event, 'fr')
129 frame.add(scroll)
130 frame.show()
131 vbox.pack_start(frame, True, True, 0)
132 self._textbuf['fr'] = textview.get_buffer()
133
134 textview = gtk.TextView()
135 textview.set_size_request(400, 100)
136 textview.set_wrap_mode(gtk.WRAP_WORD)
137 textview.show()
138 scroll = gtk.ScrolledWindow()
139 scroll.add(textview)
140 scroll.show()
141 frame = gtk.Frame(u"Text in English")
142 frame.connect("key_release_event", self.key_release_event, 'en')
143 frame.add(scroll)
144 frame.show()
145 vbox.pack_start(frame, True, True, 0)
146 self._textbuf['en'] = textview.get_buffer()
147
148 self.window.add(vbox)
149 self.window.show()
150
151 def run(self):
152 DEBUG("running graphic interface")
153 gobject.timeout_add(100, self.process_translation_result)
154 gtk.gdk.threads_init()
155 gtk.main()
156
157 def delete_event(self, widget, event, data=None):
158 DEBUG("caught delete event")
159 gtk.main_quit()
160 return False
161
162 def key_release_event(self, widget, event, lang):
163 start, end = self._textbuf[lang].get_bounds()
164 text = self._textbuf[lang].get_text(start, end)
165 other_lang = (set(self._textbuf.keys()) - set((lang,))).pop()
166 translation_path = lang + '2' + other_lang
167 self._translator.request_translation(translation_path, text)
168
169 def process_translation_result(self):
170 result = {}
171 # FIXME: to transform into an iterator...
172 while True:
173 r = self._translator.translation_result()
174 if r is None:
175 break
176 translation_path, text = r
177 lang = translation_path[3:]
178 if lang in self._textbuf:
179 result[lang] = text
180 else:
181 DEBUG("unknown destination language '%s'" % lang)
182 self._translator.translation_done()
183 for lang, text in result.items():
184 self._textbuf[lang].set_text(text)
185 gobject.timeout_add(100, self.process_translation_result)
186
187if __name__ == "__main__":
188 import sys
189 if len(sys.argv) != 3:
190 print "Usage: %s <jid> <password>" % sys.argv[0]
191 sys.exit(1)
192
193 translator = XmppTranslator(sys.argv[1], sys.argv[2])
194 translator.start()
195
196 pygtranslator = GtkTranslator(translator)
197 try:
198 pygtranslator.run()
199 except KeyboardInterrupt:
200 pass
201
202 translator._quit = True
203 translator.join()
204
205 sys.exit(0)
206