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 dep['lowfloor'] = 1 if dep['lowfloor'] else 0
155 if type(dep['time']) == time:
156 dep['time'] = dep['time'].strftime('%H:%M')
159 departuresLoaded = Signal()
162 def load_departures(self, url):
164 self.current_departures = map(self.map_departure, \
165 self.itip.get_departures(url))
166 #print self.current_departures
167 self.departuresLoaded.emit()
169 threading.Thread(target=load_async).start()
172 def load_station_departures(self, station):
174 self.current_departures = map(self.map_departure, \
175 sort_departures(self.itip.get_departures_by_station(station)))
176 #print self.current_departures
177 self.departuresLoaded.emit()
179 threading.Thread(target=load_async).start()
182 def load_nearby_departures(self, lat, lon):
184 self.current_departures = []
186 stations = get_nearby_stations(lat, lon)
188 for station in stations:
191 self.current_departures += self.itip.get_departures_by_station(station)
192 except Exception as e:
194 self.current_departures = map(self.map_departure, \
195 sort_departures(self.current_departures))
196 #print self.current_departures
197 except Exception as e:
201 self.departuresLoaded.emit()
203 threading.Thread(target=load_async).start()
205 @Slot(str, str, str, result=str)
206 def get_directions_url(self, line, direction, station):
207 return self.itip.get_url_from_direction(line, direction, station)
209 @Slot(result='QStringList')
213 @Slot(result='QVariant')
214 def get_departures(self):
215 return self.current_departures
217 @Slot(float, float, result='QStringList')
218 def get_nearby_stations(self, lat, lon):
220 return get_nearby_stations(lat, lon)
221 except BaseException as e:
222 # No/wrong stations.db file
226 def search(self, line, station):
228 station = station.decode('utf-8')
231 if line not in self.lines:
232 return "Invalid line"
235 stations = sorted(self.itip.get_stations(line).items())
237 headers, stations = zip(*stations)
240 details = [(direction, name, url) for direction, stops in stations
241 for name, url in stops if match_station(station, name)]
243 except urllib2.URLError as e:
247 if __name__ == '__main__':
248 app = QApplication(sys.argv)
250 view = QDeclarativeView()
252 aboutInfo = AboutInfo()
255 # instantiate the Python object
258 # expose the object to QML
259 context = view.rootContext()
260 context.setContextProperty('itip', itip)
261 context.setContextProperty('aboutInfo', aboutInfo)
262 context.setContextProperty('config', config)
264 if os.path.abspath(__file__).startswith('/usr/bin/'):
265 # Assume system-wide installation, QML from /usr/share/
266 view.setSource('/usr/share/gotovienna/qml/main.qml')
268 # Assume test from source directory, use relative path
269 view.setSource(os.path.join(os.path.dirname(__file__), 'qml/main.qml'))
271 view.showFullScreen()
273 sys.exit(app.exec_())