fixed signature generation
[pywienerlinien] / gotovienna-qml
1 #!/usr/bin/env python
2
3 """Public transport information for Vienna"""
4
5 __author__ = 'kelvan <kelvan@logic.at>'
6 __version__ = '0.9.0'
7 __website__ = 'http://tinyurl.com/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 AboutInfo(QObject):
27     def __init__(self):
28         QObject.__init__(self)
29
30     @Slot(result=unicode)
31     def getAppName(self):
32         return u'gotoVienna %s' % __version__
33
34     @Slot(result=unicode)
35     def getWebsiteURL(self):
36         return __website__
37
38     @Slot(result=unicode)
39     def getCopyright(self):
40         return 'Copyright 2011, 2012 %s' % __author__
41
42     @Slot(result=unicode)
43     def getLicense(self):
44         return __license__
45
46 class GotoViennaListModel(QAbstractListModel):
47     def __init__(self, objects=None):
48         QAbstractListModel.__init__(self)
49         if objects is None:
50             objects = []
51         self._objects = objects
52         self.setRoleNames({0: 'modelData'})
53
54     def set_objects(self, objects):
55         self._objects = objects
56
57     def get_objects(self):
58         return self._objects
59
60     def get_object(self, index):
61         return self._objects[index.row()]
62
63     def rowCount(self, parent=QModelIndex()):
64         return len(self._objects)
65
66     def data(self, index, role):
67         if index.isValid():
68             if role == 0:
69                 return self.get_object(index)
70         return None
71
72
73 class Gui(QObject):
74     def __init__(self):
75         QObject.__init__(self)
76         self.itip = ITipParser()
77         self.lines = []
78
79         # Read line names in categorized/sorted order
80         for _, lines in categorize_lines(self.itip.lines):
81             self.lines.extend(lines)
82
83         self.current_line = ''
84         self.current_stations = []
85         self.current_departures = []
86
87     @Slot(int, result=str)
88     def get_direction(self, idx):
89         return self.current_stations[idx][0]
90
91     @Slot(str, str, result='QStringList')
92     def get_stations(self, line, direction):
93         print 'line:', line, 'current line:', self.current_line
94         for dx, stations in self.current_stations:
95             print 'dx:', dx, 'direction:', direction
96             if dx == direction:
97                 return [stationname for stationname, url in stations]
98
99         return ['no stations found']
100
101     directionsLoaded = Signal()
102
103     @Slot(str)
104     def load_directions(self, line):
105         def load_async():
106             stations = sorted(self.itip.get_stations(line).items())
107
108             self.current_line = line
109             self.current_stations = stations
110
111             self.directionsLoaded.emit()
112
113         threading.Thread(target=load_async).start()
114
115     def map_departure(self, dep):
116         dep['lowfloor'] = 1 if dep['lowfloor'] else 0
117         if type(dep['time']) == time:
118             dep['time'] = dep['time'].strftime('%H:%M')
119         return dep
120
121     departuresLoaded = Signal()
122
123     @Slot(str)
124     def load_departures(self, url):
125         def load_async():
126             self.current_departures = map(self.map_departure, \
127                                           self.itip.get_departures(url))
128             #print self.current_departures
129             self.departuresLoaded.emit()
130
131         threading.Thread(target=load_async).start()
132
133     @Slot(str)
134     def load_station_departures(self, station):
135         def load_async():
136             self.current_departures = map(self.map_departure, \
137                                           sort_departures(self.itip.get_departures_by_station(station)))
138             #print self.current_departures
139             self.departuresLoaded.emit()
140
141         threading.Thread(target=load_async).start()
142
143     @Slot(float, float)
144     def load_nearby_departures(self, lat, lon):
145         def load_async():
146             self.current_departures = []
147             try:
148                 stations = get_nearby_stations(lat, lon)
149                 print stations
150                 for station in stations:
151                     print station
152                     try:
153                         self.current_departures += self.itip.get_departures_by_station(station)
154                     except Exception as e:
155                         print e.message
156                 self.current_departures = map(self.map_departure, \
157                                               sort_departures(self.current_departures))
158                 #print self.current_departures
159             except Exception as e:
160                 print e.message
161
162             print 'loaded'
163             self.departuresLoaded.emit()
164
165         threading.Thread(target=load_async).start()
166
167     @Slot(str, str, str, result=str)
168     def get_directions_url(self, line, direction, station):
169         return self.itip.get_url_from_direction(line, direction, station)
170
171     @Slot(result='QStringList')
172     def get_lines(self):
173         return self.lines
174
175     @Slot(result='QVariant')
176     def get_departures(self):
177         return self.current_departures
178
179     @Slot(float, float, result='QStringList')
180     def get_nearby_stations(self, lat, lon):
181         try:
182             return get_nearby_stations(lat, lon)
183         except Exception as e:
184             print e.message
185             return []
186
187     @Slot(str, str)
188     def search(self, line, station):
189         line = line.upper()
190         station = station.decode('utf-8')
191         print line, station
192
193         if line not in self.lines:
194             return "Invalid line"
195
196         try:
197             stations = sorted(self.itip.get_stations(line).items())
198             print stations
199             headers, stations = zip(*stations)
200             print headers
201             print stations
202             details = [(direction, name, url) for direction, stops in stations
203                         for name, url in stops if match_station(station, name)]
204             print details
205         except urllib2.URLError as e:
206             print e.message
207             return e.message
208
209 if __name__ == '__main__':
210     app = QApplication(sys.argv)
211
212     view = QDeclarativeView()
213
214     aboutInfo = AboutInfo()
215
216     # instantiate the Python object
217     itip = Gui()
218
219     # expose the object to QML
220     context = view.rootContext()
221     context.setContextProperty('itip', itip)
222     context.setContextProperty('aboutInfo', aboutInfo)
223
224     if os.path.abspath(__file__).startswith('/usr/bin/'):
225         # Assume system-wide installation, QML from /usr/share/
226         view.setSource('/usr/share/gotovienna/qml/main.qml')
227     else:
228         # Assume test from source directory, use relative path
229         view.setSource(os.path.join(os.path.dirname(__file__), 'qml/main.qml'))
230
231     view.showFullScreen()
232
233     sys.exit(app.exec_())
234