Change QStringList to QVariant for Departures
[pywienerlinien] / gotovienna-qml
1 #!/usr/env/python
2
3 """Public transport information for Vienna"""
4
5 __author__ = 'kelvan <kelvan@logic.at>'
6 __version__ = '0.8.2'
7 __website__ = 'https://github.com/kelvan/gotoVienna/'
8 __license__ = 'GNU General Public License v3 or later'
9
10 from datetime import datetime
11
12 from PySide.QtCore import QAbstractListModel, QModelIndex, QObject, Slot, Signal
13 from PySide.QtGui import QApplication
14 from PySide.QtDeclarative import QDeclarativeView
15
16 from gotovienna.utils import *
17 from gotovienna.realtime import *
18 from gotovienna.gps import *
19
20 import urllib2
21 import os
22 import sys
23 import threading
24 from datetime import time
25
26 class GotoViennaListModel(QAbstractListModel):
27     def __init__(self, objects=None):
28         QAbstractListModel.__init__(self)
29         if objects is None:
30             objects = []
31         self._objects = objects
32         self.setRoleNames({0: 'modelData'})
33
34     def set_objects(self, objects):
35         self._objects = objects
36
37     def get_objects(self):
38         return self._objects
39
40     def get_object(self, index):
41         return self._objects[index.row()]
42
43     def rowCount(self, parent=QModelIndex()):
44         return len(self._objects)
45
46     def data(self, index, role):
47         if index.isValid():
48             if role == 0:
49                 return self.get_object(index)
50         return None
51
52
53 class Gui(QObject):
54     def __init__(self):
55         QObject.__init__(self)
56         self.itip = ITipParser()
57         self.lines = []
58
59         # Read line names in categorized/sorted order
60         for _, lines in categorize_lines(self.itip.lines):
61             self.lines.extend(lines)
62
63         self.current_line = ''
64         self.current_stations = []
65         self.current_departures = []
66
67     @Slot(int, result=str)
68     def get_direction(self, idx):
69         return self.current_stations[idx][0]
70
71     @Slot(str, str, result='QStringList')
72     def get_stations(self, line, direction):
73         print 'line:', line, 'current line:', self.current_line
74         for dx, stations in self.current_stations:
75             print 'dx:', dx, 'direction:', direction
76             if dx == direction:
77                 return [stationname for stationname, url in stations]
78
79         return ['no stations found']
80
81     directionsLoaded = Signal()
82
83     @Slot(str)
84     def load_directions(self, line):
85         def load_async():
86             stations = sorted(self.itip.get_stations(line).items())
87
88             self.current_line = line
89             self.current_stations = stations
90
91             self.directionsLoaded.emit()
92
93         threading.Thread(target=load_async).start()
94
95     departuresLoaded = Signal()
96
97     @Slot(str)
98     def load_departures(self, url):
99         def load_async():
100             def map_departure(dep):
101                 dep['lowfloor'] = 1 if dep['lowfloor'] else 0
102                 if type(dep['time']) == time:
103                     dep['time'] = dep['time'].strftime('%H:%M')
104                 return dep
105                 
106             self.current_departures = map(map_departure, self.itip.get_departures(url))
107             print self.current_departures
108             self.departuresLoaded.emit()
109
110         threading.Thread(target=load_async).start()
111
112     @Slot(str, str, str, result=str)
113     def get_directions_url(self, line, direction, station):
114         return self.itip.get_url_from_direction(line, direction, station)
115
116     @Slot(result='QStringList')
117     def get_lines(self):
118         return self.lines
119
120     @Slot(result='QVariant')
121     def get_departures(self):
122         return self.current_departures
123
124     @Slot(float, float, result=str)
125     def get_nearby_stations(self, lat, lon):
126         try:
127             return ', '.join(get_nearby_stations(lat, lon))
128         except Exception as e:
129             print e.message
130             return ''
131
132     @Slot(str, str)
133     def search(self, line, station):
134         line = line.upper()
135         station = station.decode('utf-8')
136         print line, station
137
138         if line not in self.lines:
139             return "Invalid line"
140
141         try:
142             stations = sorted(self.itip.get_stations(line).items())
143             print stations
144             headers, stations = zip(*stations)
145             print headers
146             print stations
147             details = [(direction, name, url) for direction, stops in stations
148                         for name, url in stops if match_station(station, name)]
149             print details
150         except urllib2.URLError as e:
151             print e.message
152             return e.message
153
154 if __name__ == '__main__':
155     app = QApplication(sys.argv)
156
157     view = QDeclarativeView()
158
159     # instantiate the Python object
160     itip = Gui()
161
162     # expose the object to QML
163     context = view.rootContext()
164     context.setContextProperty('itip', itip)
165
166     if os.path.abspath(__file__).startswith('/usr/bin/'):
167         # Assume system-wide installation, QML from /usr/share/
168         view.setSource('/usr/share/gotovienna/qml/main.qml')
169     else:
170         # Assume test from source directory, use relative path
171         view.setSource(os.path.join(os.path.dirname(__file__), 'qml/main.qml'))
172
173     view.showFullScreen()
174
175     sys.exit(app.exec_())
176