5ae9447fca0722c2143c08487ca64d6802f79705
[masstransit] / src / opt / masstransit / masstransit.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 "affichage des horaires de train"
4
5
6
7 import urllib2
8 import HTMLParser
9 import ConfigParser
10 import errno
11 import conic
12
13
14 magic = 0xAA55
15
16 try:
17     import hildon
18 except ImportError: 
19     raise ImportError("erreur d'importation de hildon")
20
21 try :
22     from portrait import FremantleRotation
23 except ImportError: 
24     raise ImportError("erreur d'importation de portrait")
25
26 try :
27     import gtk
28 except ImportError: 
29     raise ImportError("erreur d'importation de gtk")
30
31 try : 
32     import pygtk
33 except ImportError: 
34     raise ImportError("erreur d'importation de pygtk")
35     
36 pygtk.require("2.0")
37
38 class LigneHoraire(object):
39     "une ligne code_mission | heure_de_passage"
40     def __init__(self, code_mission, heure_de_passage, destination, voie):
41         self.__code_mission = code_mission
42         self.__heure_de_passage = heure_de_passage
43         self.__destination = destination
44         self.__voie = voie
45     
46     def add_to_treestore(self, treestore):
47         "ajoute la ligne à un treestore"
48         treestore.append(None, [self.__code_mission, self.__heure_de_passage, self.__destination, self.__voie])
49     
50     
51
52 class TableParser(HTMLParser.HTMLParser):
53     "Parse les tableaux html contenant les horaires"
54     def __init__(self):
55         HTMLParser.HTMLParser.__init__(self)
56         self.__table_horaires3 = False
57         self.__code_de_mission = False
58         self.__a_code_de_mission = False
59         self.__heure_de_passage = False
60         self.__destination = False
61         self.__voie = False
62         self.__liste_train = []
63         self.__liste_horaire = []
64         self.__liste_destination = []
65         self.__liste_voie = []
66         
67         
68     def handle_starttag(self, tag, attrs):
69         "execute a chaque balise ouvrante"
70         if (tag == 'table' and (dict(attrs)['class'] == 'horaires3')):
71             self.__table_horaires3 = True
72         
73         elif self.__table_horaires3 and tag == 'td':
74             try:
75                 self.__code_de_mission = (
76                     dict(attrs)['headers'] == 'Code_de_mission')
77                 self.__heure_de_passage = (
78                     dict(attrs)['headers'] == 'Heure_de_passage')
79                 self.__destination = (
80                     dict(attrs)['headers'] == 'Destination')
81                 self.__voie = (
82                     dict(attrs)['headers'] == 'Voie')
83             except KeyError:
84                 if dict(attrs).has_key('headers'):
85                     raise
86                 else:
87                     pass
88         else:
89             self.__a_code_de_mission = (tag == 'a' and self.__code_de_mission)
90         
91     def handle_data(self, data):
92         "execute pour chaque contenu de balise"
93         if self.__a_code_de_mission:
94             self.__liste_train.append(data.strip())
95         if self.__heure_de_passage:
96             self.__liste_horaire.append(data.strip())
97         if self.__destination:
98             self.__liste_destination.append(data.strip())
99         if self.__voie:
100             self.__liste_voie.append(data.strip())
101             
102     def handle_endtag(self, tag):
103         "execute à chaque balise fermante"
104         self.__a_code_de_mission ^= (self.__a_code_de_mission and tag == 'a')
105         self.__heure_de_passage ^= (self.__heure_de_passage and tag == 'td')
106         self.__destination ^= (self.__destination and tag == 'td')
107         self.__voie ^= (self.__voie and tag == 'td')
108     
109     
110     @property
111     def __list_ligne_horaire(self):
112         "getter"
113         __list_ligne_horaire = []
114         __curseur_horaire = 0
115         for __i in self.__liste_train:
116             __list_ligne_horaire.append(LigneHoraire(
117                 code_mission=__i, 
118                 heure_de_passage=self.__liste_horaire[__curseur_horaire],
119                 destination=self.__liste_destination[__curseur_horaire],
120                 voie=self.__liste_voie[__curseur_horaire]
121                 ))
122             __curseur_horaire += 1
123         return __list_ligne_horaire
124
125     def fill_treestore(self, treestore):
126         "remlpli le treestore avec les resultats"
127         for __i in self.__list_ligne_horaire:
128             __i.add_to_treestore(treestore)
129
130 def connection_cb(connection, event, magic):
131     print "connection_cb(%s, %s, %x)" % (connection, event, magic)
132     print event.get_status()
133
134 class Trajet(object):
135     "trajet d'une gare source à une gare_dest"
136     def __init__(self, gare_source, gare_dest):
137         self.__gare_source = gare_source
138         self.__gare_dest = gare_dest
139         
140     def refresh_treestore(self, treestore):
141         "met à jour les horaires d'un trajet"
142         treestore.clear()
143         __parser = TableParser()
144         __parser.feed(urllib2.urlopen('http://www.transilien.com/web/ITProchainsTrainsAvecDest.do?codeTr3aDepart='+self.__gare_source.shortname+'&codeTr3aDest='+self.__gare_dest.shortname+'&urlModule=/site/pid/184&gareAcc=true').read())
145         __parser.fill_treestore(treestore)
146
147
148 class ConfFile(object):
149     "fichier contenant les gares"
150     def __init__(self, fichier):
151         self.config = ConfigParser.ConfigParser()
152         self.config.read(fichier)
153         
154
155 class LongNameGare(object):
156     "nom long d'une gare"
157     def __init__(self, longname):
158         self.__longname = longname
159     def get_gare(self, conffile):
160         "retourne une gare à partir d'un nom long"
161         return Gare(conffile.config.get('ListeDesGares', self.__longname))
162
163 class Gare(object):
164     "gare"
165     def __init__(self, shortname):
166         self.shortname = shortname
167
168 class TransilienUI:
169     "interface hildon"
170     def __init__(self):
171         self.main_window = hildon.Window()
172         self.main_window.set_title("Horaires des Prochains Trains")
173         self.main_window.connect("destroy", self.on_main_window_destroy)
174
175         rotation_object = FremantleRotation(
176             'NameOfYourApp', 
177             self.main_window, 
178             '1.0', 
179             FremantleRotation.AUTOMATIC
180             )
181         
182         refresh_button = hildon.Button(
183             gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, 
184             hildon.BUTTON_ARRANGEMENT_HORIZONTAL, 
185             "Actualiser"
186             )
187         retour_button = hildon.Button(
188             gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, 
189             hildon.BUTTON_ARRANGEMENT_HORIZONTAL, 
190             "Retour"
191             )
192         refresh_button.connect("clicked", self.on_refresh_button_clicked)
193         retour_button.connect("clicked", self.on_retour_button_clicked)
194
195         self.treestore = gtk.TreeStore(str, str, str, str)
196         self.treeview = gtk.TreeView(self.treestore)
197
198         self.treeview.append_column(
199             gtk.TreeViewColumn( 
200                 'Train', 
201                 gtk.CellRendererText(), 
202                 text=0
203             ))
204         
205         self.treeview.append_column(
206             gtk.TreeViewColumn(
207                 'Horaire', 
208                 gtk.CellRendererText(), 
209                 text=1
210             ))
211             
212         self.treeview.append_column(
213             gtk.TreeViewColumn(
214                 'Destination', 
215                 gtk.CellRendererText(), 
216                 text=2
217             ))
218         self.treeview.append_column(
219             gtk.TreeViewColumn(
220                 'Voie', 
221                 gtk.CellRendererText(), 
222                 text=3
223             ))
224
225
226         
227         
228         self.combo_source = hildon.TouchSelectorEntry(text=True)
229         self.combo_dest = hildon.TouchSelectorEntry(text=True)
230
231         liste = ConfFile('/opt/masstransit/masstransit.cfg').config.items('ListeDesGares')
232         liste.sort()
233         for i in liste:
234             self.combo_source.append_text(i[0].capitalize())
235             self.combo_dest.append_text(i[0].capitalize())
236         
237         picker_button_source = hildon.PickerButton(
238             gtk.HILDON_SIZE_AUTO, 
239             hildon.BUTTON_ARRANGEMENT_VERTICAL)
240         
241         picker_button_dest = hildon.PickerButton(
242             gtk.HILDON_SIZE_AUTO, 
243             hildon.BUTTON_ARRANGEMENT_VERTICAL
244             )
245         
246         picker_button_source.set_title("Gare de Depart")
247         picker_button_dest.set_title("Gare d'arrivee")
248         
249         picker_button_source.set_selector(self.combo_source)
250         picker_button_dest.set_selector(self.combo_dest)
251         
252         vertical_box = gtk.VBox()
253         horizontal_box = gtk.HBox()
254         vertical_box.pack_start(horizontal_box)
255         horizontal_box.pack_start(picker_button_source)
256         horizontal_box.pack_start(picker_button_dest)
257         horizontal_box.pack_start(retour_button)
258         vertical_box.pack_start(self.treeview)
259         vertical_box.pack_start(refresh_button)
260
261         self.main_window.add(vertical_box)
262         self.main_window.show_all()
263
264     def on_main_window_destroy(self, widget):
265         "quitte l'application à la fermeture de la fenetre"
266         gtk.main_quit()
267
268     
269     def on_retour_button_clicked(self, widget):
270         "le bouton retour est clicked"
271         col_source = self.combo_source.get_active(0)
272         col_dest = self.combo_dest.get_active(0)
273         self.combo_source.set_active(0, col_dest)
274         self.combo_dest.set_active(0, col_source)
275         self.refresh()
276     
277     def on_refresh_button_clicked(self, widget):
278         "le bouton refresh est clicked"
279         self.refresh()
280     
281     def refresh(self):
282         "met a jour les horaires"
283         conf = ConfFile('/opt/masstransit/masstransit.cfg')
284         try :
285             gare_source = LongNameGare(self.combo_source.get_current_text()).get_gare(conf)
286         except AttributeError:
287             if self.combo_source.get_current_text() is None:
288                 gtk.Dialog.run(hildon.hildon_note_new_information(self.main_window, "Vous devez remplir la gare source"))
289             else:
290                 raise
291         else:
292             try :
293                 gare_dest = LongNameGare(self.combo_dest.get_current_text()).get_gare(conf)     
294             except AttributeError:
295                 if self.combo_dest.get_current_text() is None:
296                     gtk.Dialog.run(hildon.hildon_note_new_information(self.main_window, "Vous devez remplir la gare de destination"))
297                 else:
298                     raise
299             else:
300                 trajet = Trajet(gare_source , gare_dest)
301                 try :
302                     trajet.refresh_treestore(self.treestore)
303                 except urllib2.URLError, e:
304                     global magic
305                     connection = conic.Connection()
306                     connection.connect("connection-event", connection_cb, magic)
307                     connection.request_connection(conic.CONNECT_FLAG_NONE)
308                     trajet.refresh_treestore(self.treestore)
309                     
310         
311 if __name__ == "__main__":
312     TransilienUI()
313     gtk.main()
314