3 """Public transport information for Vienna"""
5 __author__ = 'kelvan <kelvan@logic.at>'
7 __website__ = 'http://tinyurl.com/gotoVienna'
8 __license__ = 'GNU General Public License v3 or later'
10 from datetime import datetime
12 from PySide.QtCore import QAbstractListModel, QModelIndex, QObject, Slot, Signal
13 from PySide.QtGui import QApplication
14 from PySide.QtDeclarative import QDeclarativeView
16 from gotovienna.utils import *
17 from gotovienna.realtime import *
18 from gotovienna.gps import *
19 from gotovienna.update import *
20 from gotovienna.config import config as conf
26 from datetime import time
28 class Config(QObject):
30 QObject.__init__(self)
33 def getGpsEnabled(self):
34 return conf.getGpsEnabled()
36 @Slot(bool, result=unicode)
37 def setGpsEnabled(self, val):
39 return conf.setGpsEnabled(val)
42 def getLastUpdate(self):
44 return conf.getLastStationsUpdate()
47 def updateStations(self):
51 return datetime.now().strftime('%c')
52 except Exception as e:
57 def checkStationsUpdate(self):
58 # FIXME exception handling foo
60 return check_stations_update()
64 class AboutInfo(QObject):
66 QObject.__init__(self)
70 return u'gotoVienna %s' % __version__
73 def getWebsiteURL(self):
77 def getCopyright(self):
78 return 'Copyright 2011, 2012 %s' % __author__
84 class GotoViennaListModel(QAbstractListModel):
85 def __init__(self, objects=None):
86 QAbstractListModel.__init__(self)
89 self._objects = objects
90 self.setRoleNames({0: 'modelData'})
92 def set_objects(self, objects):
93 self._objects = objects
95 def get_objects(self):
98 def get_object(self, index):
99 return self._objects[index.row()]
101 def rowCount(self, parent=QModelIndex()):
102 return len(self._objects)
104 def data(self, index, role):
107 return self.get_object(index)
113 QObject.__init__(self)
114 self.itip = ITipParser()
117 # Read line names in categorized/sorted order
118 for _, lines in categorize_lines(self.itip.lines):
119 self.lines.extend(lines)
121 self.current_line = ''
122 self.current_stations = []
123 self.current_departures = []
125 @Slot(int, result=str)
126 def get_direction(self, idx):
127 return self.current_stations[idx][0]
129 @Slot(str, str, result='QStringList')
130 def get_stations(self, line, direction):
131 print 'line:', line, 'current line:', self.current_line
132 for dx, stations in self.current_stations:
133 print 'dx:', dx, 'direction:', direction
135 return [stationname for stationname, url in stations]
137 return ['no stations found']
139 directionsLoaded = Signal()
142 def load_directions(self, line):
144 stations = sorted(self.itip.get_stations(line).items())
146 self.current_line = line
147 self.current_stations = stations
149 self.directionsLoaded.emit()
151 threading.Thread(target=load_async).start()
153 def map_departure(self, dep):
154 """ prepare departure list for qml gui
156 dep['lowfloor'] = 1 if dep['lowfloor'] else 0
157 dep['realtime'] = 1 if dep['realtime'] else 0
158 dep['time'] = dep['ftime']
161 departuresLoaded = Signal()
164 def load_departures_test(self, **args):
165 """ valid args combinations
170 if args.has_key('station'):
171 if args.has_key('line'):
172 self.current_departures = map(self.map_departure, \
173 self.itip.get_departures(args['line'], args['station']))
174 #print self.current_departures
175 self.departuresLoaded.emit()
177 self.current_departures = map(self.map_departure, \
178 sort_departures(self.itip.get_departures_by_station(station)))
180 raise KeyError('Missing valid argument combination')
182 threading.Thread(target=load_async).start()
185 def load_departures(self, url):
187 self.current_departures = map(self.map_departure, \
188 self.itip.get_departures(url))
189 #print self.current_departures
190 self.departuresLoaded.emit()
192 threading.Thread(target=load_async).start()
195 def load_station_departures(self, station):
197 self.current_departures = map(self.map_departure, \
198 sort_departures(self.itip.get_departures_by_station(station)))
199 #print self.current_departures
200 self.departuresLoaded.emit()
202 threading.Thread(target=load_async).start()
205 def load_nearby_departures(self, lat, lon):
207 self.current_departures = []
209 stations = get_nearby_stations(lat, lon)
211 for station in stations:
214 self.current_departures += self.itip.get_departures_by_station(station)
215 except Exception as e:
217 self.current_departures = map(self.map_departure, \
218 sort_departures(self.current_departures))
219 #print self.current_departures
220 except Exception as e:
224 self.departuresLoaded.emit()
226 threading.Thread(target=load_async).start()
228 @Slot(str, str, str, result=str)
229 def get_directions_url(self, line, direction, station):
230 return self.itip.get_url_from_direction(line, direction, station)
232 @Slot(result='QStringList')
236 @Slot(result='QVariant')
237 def get_departures(self):
238 return self.current_departures
240 @Slot(float, float, result='QStringList')
241 def get_nearby_stations(self, lat, lon):
243 return get_nearby_stations(lat, lon)
244 except BaseException as e:
245 # No/wrong stations.db file
249 def search(self, line, station):
251 station = station.decode('utf-8')
254 if line not in self.lines:
255 return "Invalid line"
258 stations = sorted(self.itip.get_stations(line).items())
260 headers, stations = zip(*stations)
263 details = [(direction, name, url) for direction, stops in stations
264 for name, url in stops if match_station(station, name)]
266 except urllib2.URLError as e:
270 if __name__ == '__main__':
271 app = QApplication(sys.argv)
273 view = QDeclarativeView()
275 aboutInfo = AboutInfo()
278 # instantiate the Python object
281 # expose the object to QML
282 context = view.rootContext()
283 context.setContextProperty('itip', itip)
284 context.setContextProperty('aboutInfo', aboutInfo)
285 context.setContextProperty('config', config)
287 if os.path.abspath(__file__).startswith('/usr/bin/'):
288 # Assume system-wide installation, QML from /usr/share/
289 view.setSource('/usr/share/gotovienna/qml/main.qml')
291 # Assume test from source directory, use relative path
292 view.setSource(os.path.join(os.path.dirname(__file__), 'qml/main.qml'))
294 view.showFullScreen()
296 sys.exit(app.exec_())