X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;ds=sidebyside;f=gotovienna-qml;h=4393d0e6eb27b506dea68ec26b0e97d810187bd6;hb=HEAD;hp=40e2793f23df20916549ed97a305dc56eabd601d;hpb=7403374b55d1ffeed1c3717c44ea9cc1472e3e74;p=pywienerlinien diff --git a/gotovienna-qml b/gotovienna-qml index 40e2793..4393d0e 100755 --- a/gotovienna-qml +++ b/gotovienna-qml @@ -1,60 +1,187 @@ -#!/usr/env/python +#!/usr/bin/env python """Public transport information for Vienna""" __author__ = 'kelvan ' -__version__ = '0.8.2' -__website__ = 'https://github.com/kelvan/gotoVienna/' +__version__ = '0.9.1' +__website__ = 'http://tinyurl.com/gotoVienna' __license__ = 'GNU General Public License v3 or later' from datetime import datetime -from PySide.QtCore import QAbstractListModel, QModelIndex, QObject, Slot, Signal -from PySide.QtGui import QApplication +from PySide.QtCore import QAbstractListModel, QModelIndex, QObject, Slot, Signal, Qt +from PySide.QtGui import QApplication, QTextItem from PySide.QtDeclarative import QDeclarativeView from gotovienna.utils import * from gotovienna.realtime import * from gotovienna.gps import * +from gotovienna.update import * +from gotovienna.config import config as conf + +from gotovienna import defaults import urllib2 import os import sys import threading +import json from datetime import time -class GotoViennaListModel(QAbstractListModel): - def __init__(self, objects=None): - QAbstractListModel.__init__(self) - if objects is None: - objects = [] - self._objects = objects - self.setRoleNames({0: 'modelData'}) +class Config(QObject): + def __init__(self): + QObject.__init__(self) + + @Slot(result=bool) + def getGpsEnabled(self): + return conf.getGpsEnabled() - def set_objects(self, objects): - self._objects = objects + @Slot(bool, result=unicode) + def setGpsEnabled(self, val): + # TODO + return conf.setGpsEnabled(val) - def get_objects(self): - return self._objects + @Slot(result=unicode) + def getLastUpdate(self): + # TODO + return conf.getLastStationsUpdate() - def get_object(self, index): - return self._objects[index.row()] + @Slot(result=unicode) + def updateStations(self): + # TODO + try: + update_stations() + return datetime.now().strftime('%c') + except Exception as e: + print e + return '' - def rowCount(self, parent=QModelIndex()): - return len(self._objects) + @Slot(result=bool) + def checkStationsUpdate(self): + # FIXME exception handling foo + try: + return check_stations_update() + except: + return False - def data(self, index, role): - if index.isValid(): - if role == 0: - return self.get_object(index) - return None +class AboutInfo(QObject): + def __init__(self): + QObject.__init__(self) + @Slot(result=unicode) + def getAppName(self): + return u'gotoVienna %s' % __version__ + + @Slot(result=unicode) + def getWebsiteURL(self): + return __website__ + + @Slot(result=unicode) + def getCopyright(self): + return 'Copyright 2011, 2012 %s' % __author__ + + @Slot(result=unicode) + def getLicense(self): + return __license__ + +class DepartureModel(QAbstractListModel): + LINE_ROLE = Qt.UserRole + 1 + DIRECTION_ROLE = Qt.UserRole + 2 + STATION_ROLE = Qt.UserRole + 3 + TIME_ROLE = Qt.UserRole + 4 + LOWFLOOR_ROLE = Qt.UserRole + 5 + + def __init__(self, parent=None): + super(DepartureModel, self).__init__(parent) + self._data = [] + + self.keys = {} + self.keys[DepartureModel.LINE_ROLE] = 'line' + self.keys[DepartureModel.DIRECTION_ROLE] = 'direction' + self.keys[DepartureModel.STATION_ROLE] = 'station' + self.keys[DepartureModel.TIME_ROLE] = 'time' + self.keys[DepartureModel.LOWFLOOR_ROLE] = 'lowfloor' + self.setRoleNames(self.keys) + + def rowCount(self, index): + return len(self._data) -class Gui(QObject): + def data(self, index, role): + if not index.isValid(): + return None + + if index.row() > len(self._data): + return None + + departure = self._data[index.row()] + + if self.keys.has_key(role): + return departure[self.keys[role]] + else: + return None + + def setDepartures(self, dep): + self.beginResetModel() + self._data = dep + self.endResetModel() + +class FavoriteManager(QObject): def __init__(self): QObject.__init__(self) + self._faves = [] + if os.path.exists(defaults.favorites_file): + try: + self._faves = json.load(open(defaults.favorites_file, 'r')) + self._faves = map(tuple, self._faves) + print 'faves loaded:', self._faves + except Exception, e: + print 'faves load error:', e + + @Slot(result=int) + def getCount(self): + result = len(self._faves) + print 'getCount->', result + return result + + @Slot(int, result=unicode) + def getItem(self, index): + keys = ['gline', 'gdirection', 'gstation', 'sourceurl', 'isstation'] + result = dict(zip(keys, self._faves[index])) + result['name'] = u'%(gline)s -> %(gdirection)s @ %(gstation)s' % result + result = json.dumps(result) + print 'getItem:', index, result + return result + + def _persist(self): + print 'persist:', self._faves, '->', defaults.favorites_file + try: + fp = open(defaults.favorites_file, 'w') + json.dump(self._faves, fp) + fp.close() + except Exception, e: + print 'faves save error:', e + + @Slot(unicode, unicode, unicode, unicode, bool, int, result=bool) + def isFavorite(self, gline, gdirection, gstation, sourceurl, isstation, x): + k = (gline, gdirection, gstation, sourceurl, isstation) + return (k in self._faves) + + @Slot(unicode, unicode, unicode, unicode, bool) + def toggleFavorite(self, gline, gdirection, gstation, sourceurl, isstation): + k = (gline, gdirection, gstation, sourceurl, isstation) + if k in self._faves: + self._faves.remove(k) + else: + self._faves.append(k) + + self._persist() + +class Gui(QObject): + def __init__(self, depModel): + QObject.__init__(self) self.itip = ITipParser() self.lines = [] + self.departureModel = depModel # Read line names in categorized/sorted order for _, lines in categorize_lines(self.itip.lines): @@ -92,19 +219,41 @@ class Gui(QObject): threading.Thread(target=load_async).start() - def map_departure(self, dep): - dep['lowfloor'] = 1 if dep['lowfloor'] else 0 - if type(dep['time']) == time: - dep['time'] = dep['time'].strftime('%H:%M') - return dep + #def map_departure(self, dep): + # """ prepare departure list for qml gui + # """ + # dep['lowfloor'] = 1 if dep['lowfloor'] else 0 + # dep['realtime'] = 1 if dep['realtime'] else 0 + # dep['time'] = dep['ftime'] + # return dep departuresLoaded = Signal() @Slot(str) + def load_departures_test(self, **args): + """ valid args combinations + station + line, station + """ + def load_async(): + if args.has_key('station'): + if args.has_key('line'): + self.current_departures = map(self.map_departure, \ + self.itip.get_departures(args['line'], args['station'])) + #print self.current_departures + self.departuresLoaded.emit() + else: + self.current_departures = map(self.map_departure, \ + sort_departures(self.itip.get_departures_by_station(station))) + else: + raise KeyError('Missing valid argument combination') + + threading.Thread(target=load_async).start() + + @Slot(str) def load_departures(self, url): def load_async(): - self.current_departures = map(self.map_departure, \ - self.itip.get_departures(url)) + self.departureModel.setDepartures(self.itip.get_departures(url)) #print self.current_departures self.departuresLoaded.emit() @@ -113,9 +262,7 @@ class Gui(QObject): @Slot(str) def load_station_departures(self, station): def load_async(): - self.current_departures = map(self.map_departure, \ - sort_departures(self.itip.get_departures_by_station(station))) - #print self.current_departures + self.departureModel.setDepartures(sort_departures(self.itip.get_departures_by_station(station))) self.departuresLoaded.emit() threading.Thread(target=load_async).start() @@ -152,51 +299,36 @@ class Gui(QObject): def get_lines(self): return self.lines - @Slot(result='QVariant') - def get_departures(self): - return self.current_departures - @Slot(float, float, result='QStringList') def get_nearby_stations(self, lat, lon): try: return get_nearby_stations(lat, lon) - except Exception as e: - print e.message + except BaseException as e: + # No/wrong stations.db file return [] - @Slot(str, str) - def search(self, line, station): - line = line.upper() - station = station.decode('utf-8') - print line, station - - if line not in self.lines: - return "Invalid line" - - try: - stations = sorted(self.itip.get_stations(line).items()) - print stations - headers, stations = zip(*stations) - print headers - print stations - details = [(direction, name, url) for direction, stops in stations - for name, url in stops if match_station(station, name)] - print details - except urllib2.URLError as e: - print e.message - return e.message if __name__ == '__main__': app = QApplication(sys.argv) view = QDeclarativeView() + aboutInfo = AboutInfo() + config = Config() + departureModel = DepartureModel() + # instantiate the Python object - itip = Gui() + itip = Gui(departureModel) + + favManager = FavoriteManager() # expose the object to QML context = view.rootContext() context.setContextProperty('itip', itip) + context.setContextProperty('aboutInfo', aboutInfo) + context.setContextProperty('config', config) + context.setContextProperty('resultModel', departureModel) + context.setContextProperty('favManager', favManager) if os.path.abspath(__file__).startswith('/usr/bin/'): # Assume system-wide installation, QML from /usr/share/