Add QML UI for displaying the overview
authorThomas Perl <m@thp.io>
Thu, 3 Mar 2011 11:54:33 +0000 (12:54 +0100)
committerThomas Perl <m@thp.io>
Thu, 3 Mar 2011 11:54:33 +0000 (12:54 +0100)
pyWienerLinien.py
ui/Overview.qml [new file with mode: 0644]
ui/OverviewItem.qml [new file with mode: 0644]
wlSearch.py

index 1c352b3..a91db68 100644 (file)
@@ -16,6 +16,10 @@ class WienerLinienQt(QMainWindow, Ui_MainWindow):
 
     def __init__(self):
         QMainWindow.__init__(self)
+        # _s is used to keep a reference to the Search object, so it does
+        # not get destroyed when it falls out of scope (the QML view is
+        # destroyed as soon as the Search object is destroyed!)
+        self._s = None
         self.setupUi(self)
         self.connect(self.btnSearch, SIGNAL("clicked()"), self.search)
 
@@ -41,15 +45,10 @@ class WienerLinienQt(QMainWindow, Ui_MainWindow):
         if not origin and destination:
             self.btnSearch.setText("Search - Missing input")
         else:
-            s = Search(origin, destination, \
+            self._s = Search(origin, destination, \
                        origin_type=self.types[self.comboOrigin.currentIndex()], \
                        destination_type=self.types[self.comboDestination.currentIndex()])
-            try:
-                s.open_browser()
-            except webbrowser.Error:
-                self.btnSearch.setText("Error starting webbrowser")
-                return False
-            self.btnSearch.setText("Search - Opening webbrowser")
+            self._s.open_qml()
             return True
 
 
diff --git a/ui/Overview.qml b/ui/Overview.qml
new file mode 100644 (file)
index 0000000..888d146
--- /dev/null
@@ -0,0 +1,71 @@
+
+import Qt 4.7
+
+ListView {
+    id: lv
+    width: 800
+    height: 400
+    delegate: OverviewItem {
+        onShowDetails: lv.showDetails(details)
+    }
+
+    states: [
+        State {
+            name: 'overview'
+        },
+        State {
+            name: 'details'
+            PropertyChanges {
+                target: detailsRect
+                opacity: 1
+                scale: 1
+            }
+        }
+    ]
+
+    Rectangle {
+        id: detailsRect
+        width: parent.width - 50
+        height: parent.height - 50
+        anchors.centerIn: parent
+        scale: 0
+        opacity: 0
+        color: '#aaa'
+
+        border {
+            color: '#888'
+            width: 10
+        }
+
+        Behavior on opacity { PropertyAnimation { duration: 250 }}
+
+        Behavior on scale {
+            PropertyAnimation {
+                duration: 500
+                easing.type: Easing.InCubic
+            }
+        }
+
+        Text {
+            id: detailsTitle
+
+            anchors.left: parent.left
+            anchors.right: parent.right
+            anchors.top: parent.top
+            horizontalAlignment: Text.AlignHCenter
+            anchors.topMargin: 20
+            font.pixelSize: 30
+        }
+
+        MouseArea {
+            anchors.fill: parent
+            onClicked: lv.state = 'overview'
+        }
+    }
+
+    function showDetails(details) {
+        detailsTitle.text = 'FIXME - show details for ' + details.time_from
+        lv.state = 'details'
+    }
+}
+
diff --git a/ui/OverviewItem.qml b/ui/OverviewItem.qml
new file mode 100644 (file)
index 0000000..945eadd
--- /dev/null
@@ -0,0 +1,72 @@
+import Qt 4.7
+
+Rectangle {
+    anchors.left: parent.left
+    anchors.right: parent.right
+    height: 70
+    color: (index%2)?'#eee':'#ddd'
+
+    signal showDetails(variant details)
+
+    Text {
+        id: datum
+        anchors.left: parent.left
+        anchors.top: parent.top
+        anchors.bottom: parent.bottom
+        verticalAlignment: Text.AlignVCenter
+        text: modelData.date
+        font.pixelSize: 20
+        anchors.leftMargin: 30
+        anchors.rightMargin: 30
+        width: parent.width * .2
+    }
+
+    Text {
+        id: time_from
+        anchors.left: datum.right
+        anchors.bottom: parent.verticalCenter
+        text: 'von ' + modelData.time_from
+        verticalAlignment: Text.AlignBottom
+        width: parent.width * .2
+        visible: modelData.time_from != '-'
+    }
+
+    Text {
+        id: time_to
+        anchors.left: datum.right
+        anchors.top: parent.verticalCenter
+        text: 'bis ' + modelData.time_to
+        anchors.rightMargin: 40
+        verticalAlignment: Text.AlignTop
+        width: time_from.width
+        visible: modelData.time_to != '-'
+    }
+
+    Text {
+        id: dauer
+        text: 'Dauer: ' + modelData.duration + ' (' + modelData.change + ' x umsteigen)'
+        font.pixelSize: 17
+        anchors.left: time_from.right
+        anchors.top: parent.top
+        anchors.bottom: parent.bottom
+        verticalAlignment: Text.AlignVCenter
+        width: parent.width * .3
+    }
+
+    Text {
+        id: price
+        text: 'EUR ' + modelData.price
+        anchors.right: parent.right
+        anchors.top: parent.top
+        anchors.bottom: parent.bottom
+        verticalAlignment: Text.AlignVCenter
+        width: parent.width * .1
+        horizontalAlignment: Text.AlignRight
+        anchors.rightMargin: 20
+    }
+
+    MouseArea {
+        anchors.fill: parent
+        onClicked: parent.showDetails(modelData)
+    }
+}
index 25c4581..bbf11b4 100644 (file)
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
 import urllib
 import sys
 from datetime import datetime
@@ -5,6 +7,33 @@ import settings
 import webbrowser
 import urllib2
 
+from parseHtml import Parser
+
+from PySide.QtDeclarative import QDeclarativeView
+
+def QMLModel(overview):
+    # Mapping from the "overview" data structure to a "plain" data
+    # structure to be used as model for the qml listview
+    r = []
+    for item in overview:
+        d = {
+                'date': item['date'].strftime('%d.%m.%Y') if item['date'] else u'Fußweg',
+                'duration': item['duration'].strftime('%H:%M'),
+                'price': item['price'],
+                'change': item['change'],
+        }
+
+        if len(item['time']) == 2 and all(x is not None for x in item['time']):
+            d.update({
+                'time_from': item['time'][0].strftime('%H:%M'),
+                'time_to': item['time'][1].strftime('%H:%M'),
+            })
+        else:
+            d.update({'time_from': '-', 'time_to': '-'})
+
+        r.append(d)
+    return r
+
 
 class Search:
 
@@ -13,6 +42,8 @@ class Search:
         self.destination = destination
         self.origin_type = origin_type
         self.destination_type = destination_type
+        self.view = None
+        self.qml_model = None
 
     def get_html(self, dtime=datetime.now()):
         return urllib2.urlopen('%s?%s' % (settings.action, self.get_parameter(dtime)))
@@ -20,6 +51,15 @@ class Search:
     def open_browser(self, dtime=datetime.now()):
         webbrowser.open('%s?%s' % (settings.action, self.get_parameter(dtime)))
 
+    def open_qml(self, dtime=datetime.now()):
+        p = Parser(self.get_html(dtime))
+        self.qml_model = QMLModel(p.overview)
+        self.view = QDeclarativeView()
+        self.view.setResizeMode(QDeclarativeView.SizeRootObjectToView)
+        self.view.setSource('ui/Overview.qml')
+        self.view.rootObject().setProperty('model', self.qml_model)
+        self.view.show()
+
     def get_datetime(self, dtime):
         return (dtime.strftime('%d.%m.%Y'), dtime.strftime('%H:%M'))