diff options
author | Ariya Hidayat <ariya.hidayat@nokia.com> | 2009-08-19 11:24:05 (GMT) |
---|---|---|
committer | Ariya Hidayat <ariya.hidayat@nokia.com> | 2009-08-19 12:08:13 (GMT) |
commit | fa246f93508147b4b2e582c61fbb60a0d7f881c3 (patch) | |
tree | 421ba0f15fd337749ff27bf3c66c516e81352b0b /demos/embedded/flightinfo | |
parent | a238c86219a2a16d1e417a4c75273c6d9c7faecc (diff) | |
download | Qt-fa246f93508147b4b2e582c61fbb60a0d7f881c3.zip Qt-fa246f93508147b4b2e582c61fbb60a0d7f881c3.tar.gz Qt-fa246f93508147b4b2e582c61fbb60a0d7f881c3.tar.bz2 |
Import the flight info example.
Originally it was published in Qt Labs:
http://labs.trolltech.com/blogs/2009/07/26/track-your-flight-with-qts60/
Reviewed-by: Jason Barron
Diffstat (limited to 'demos/embedded/flightinfo')
-rw-r--r-- | demos/embedded/flightinfo/aircraft.png | bin | 0 -> 28713 bytes | |||
-rw-r--r-- | demos/embedded/flightinfo/flightinfo.cpp | 415 | ||||
-rw-r--r-- | demos/embedded/flightinfo/flightinfo.pro | 12 | ||||
-rw-r--r-- | demos/embedded/flightinfo/flightinfo.qrc | 5 | ||||
-rw-r--r-- | demos/embedded/flightinfo/form.ui | 226 |
5 files changed, 658 insertions, 0 deletions
diff --git a/demos/embedded/flightinfo/aircraft.png b/demos/embedded/flightinfo/aircraft.png Binary files differnew file mode 100644 index 0000000..0845cb4 --- /dev/null +++ b/demos/embedded/flightinfo/aircraft.png diff --git a/demos/embedded/flightinfo/flightinfo.cpp b/demos/embedded/flightinfo/flightinfo.cpp new file mode 100644 index 0000000..de3a9e9 --- /dev/null +++ b/demos/embedded/flightinfo/flightinfo.cpp @@ -0,0 +1,415 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore> +#include <QtGui> +#include <QtNetwork> + +#if defined (Q_OS_SYMBIAN) +#include "sym_iap_util.h" +#endif + +#include "ui_form.h" + +#define FLIGHTVIEW_URL "http://mobile.flightview.com/TrackByFlight.aspx" +#define FLIGHTVIEW_RANDOM "http://mobile.flightview.com/TrackSampleFlight.aspx" + +// strips all invalid constructs that might trip QXmlStreamReader +static QString sanitized(const QString &xml) +{ + QString data = xml; + + // anything up to the html tag + int i = data.indexOf("<html"); + if (i > 0) + data.remove(0, i - 1); + + // everything inside the head tag + i = data.indexOf("<head"); + if (i > 0) + data.remove(i, data.indexOf("</head>") - i + 7); + + // invalid link for JavaScript code + while (true) { + i = data.indexOf("onclick=\"gotoUrl("); + if (i < 0) + break; + data.remove(i, data.indexOf('\"', i + 9) - i + 1); + } + + // all inline frames + while (true) { + i = data.indexOf("<iframe"); + if (i < 0) + break; + data.remove(i, data.indexOf("</iframe>") - i + 8); + } + + // entities + data.remove(" "); + data.remove("©"); + + return data; +} + +class FlightInfo : public QMainWindow +{ + Q_OBJECT + +private: + + Ui_Form ui; + QUrl m_url; + QDate m_searchDate; + QPixmap m_map; + +public: + + FlightInfo(QMainWindow *parent = 0): QMainWindow(parent) { + + QWidget *w = new QWidget(this); + ui.setupUi(w); + setCentralWidget(w); + + ui.searchBar->hide(); + ui.infoBox->hide(); + connect(ui.searchButton, SIGNAL(clicked()), SLOT(startSearch())); + connect(ui.flightEdit, SIGNAL(returnPressed()), SLOT(startSearch())); + + setWindowTitle("Flight Info"); + QTimer::singleShot(0, this, SLOT(delayedInit())); + + // Rendered from the public-domain vectorized aircraft + // http://openclipart.org/media/people/Jarno + m_map = QPixmap(":/aircraft.png"); + + QAction *searchTodayAction = new QAction("Today's Flight", this); + QAction *searchYesterdayAction = new QAction("Yesterday's Flight", this); + QAction *randomAction = new QAction("Random Flight", this); + connect(searchTodayAction, SIGNAL(triggered()), SLOT(today())); + connect(searchYesterdayAction, SIGNAL(triggered()), SLOT(yesterday())); + connect(randomAction, SIGNAL(triggered()), SLOT(randomFlight())); +#if defined(Q_OS_SYMBIAN) + menuBar()->addAction(searchTodayAction); + menuBar()->addAction(searchYesterdayAction); + menuBar()->addAction(randomAction); +#else + addAction(searchTodayAction); + addAction(searchYesterdayAction); + addAction(randomAction); + setContextMenuPolicy(Qt::ActionsContextMenu); +#endif + } + +private slots: + void delayedInit() { +#if defined(Q_OS_SYMBIAN) + qt_SetDefaultIap(); +#endif + } + + + void handleNetworkData(QNetworkReply *networkReply) { + if (!networkReply->error()) { + // Assume UTF-8 encoded + QByteArray data = networkReply->readAll(); + QString xml = QString::fromUtf8(data); + digest(xml); + } + networkReply->deleteLater(); + networkReply->manager()->deleteLater(); + } + + void handleMapData(QNetworkReply *networkReply) { + if (!networkReply->error()) { + m_map.loadFromData(networkReply->readAll()); + update(); + } + networkReply->deleteLater(); + networkReply->manager()->deleteLater(); + } + + void today() { + QDateTime timestamp = QDateTime::currentDateTime(); + m_searchDate = timestamp.date(); + searchFlight(); + } + + void yesterday() { + QDateTime timestamp = QDateTime::currentDateTime(); + timestamp = timestamp.addDays(-1); + m_searchDate = timestamp.date(); + searchFlight(); + } + + void searchFlight() { + ui.searchBar->show(); + ui.infoBox->hide(); + ui.flightStatus->hide(); + ui.flightName->setText("Enter flight number"); + m_map = QPixmap(); + update(); + } + + void startSearch() { + ui.searchBar->hide(); + QString flight = ui.flightEdit->text().simplified(); + if (!flight.isEmpty()) + request(flight, m_searchDate); + } + + void randomFlight() { + request(QString(), QDate::currentDate()); + } + +public slots: + + void request(const QString &flightCode, const QDate &date) { + + setWindowTitle("Loading..."); + + QString code = flightCode.simplified(); + QString airlineCode = code.left(2).toUpper(); + QString flightNumber = code.mid(2, code.length()); + + ui.flightName->setText("Searching for " + code); + + m_url = QUrl(FLIGHTVIEW_URL); + m_url.addEncodedQueryItem("view", "detail"); + m_url.addEncodedQueryItem("al", QUrl::toPercentEncoding(airlineCode)); + m_url.addEncodedQueryItem("fn", QUrl::toPercentEncoding(flightNumber)); + m_url.addEncodedQueryItem("dpdat", QUrl::toPercentEncoding(date.toString("yyyyMMdd"))); + + if (code.isEmpty()) { + // random flight as sample + m_url = QUrl(FLIGHTVIEW_RANDOM); + ui.flightName->setText("Getting a random flight..."); + } + + QNetworkAccessManager *manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)), + this, SLOT(handleNetworkData(QNetworkReply*))); + manager->get(QNetworkRequest(m_url)); + } + + +private: + + void digest(const QString &content) { + + setWindowTitle("Flight Info"); + QString data = sanitized(content); + + // do we only get the flight list? + // we grab the first leg in the flight list + // then fetch another URL for the real flight info + int i = data.indexOf("a href=\"?view=detail"); + if (i > 0) { + QString href = data.mid(i, data.indexOf('\"', i + 8) - i + 1); + QRegExp regex("dpap=([A-Za-z0-9]+)"); + regex.indexIn(href); + QString airport = regex.cap(1); + m_url.addEncodedQueryItem("dpap", QUrl::toPercentEncoding(airport)); + QNetworkAccessManager *manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)), + this, SLOT(handleNetworkData(QNetworkReply*))); + manager->get(QNetworkRequest(m_url)); + return; + } + + QXmlStreamReader xml(data); + bool inFlightName = false; + bool inFlightStatus = false; + bool inFlightMap = false; + bool inFieldName = false; + bool inFieldValue = false; + + QString flightName; + QString flightStatus; + QStringList fieldNames; + QStringList fieldValues; + + while (!xml.atEnd()) { + xml.readNext(); + + if (xml.tokenType() == QXmlStreamReader::StartElement) { + QStringRef className = xml.attributes().value("class"); + inFlightName |= xml.name() == "h1"; + inFlightStatus |= className == "FlightDetailHeaderStatus"; + inFlightMap |= className == "flightMap"; + if (xml.name() == "td" && !className.isEmpty()) { + QString cn = className.toString(); + if (cn.contains("fieldTitle")) { + inFieldName = true; + fieldNames += QString(); + fieldValues += QString(); + } + if (cn.contains("fieldValue")) + inFieldValue = true; + } + if (xml.name() == "img" && inFlightMap) { + QString src = xml.attributes().value("src").toString(); + src.prepend("http://mobile.flightview.com"); + QUrl url = QUrl::fromPercentEncoding(src.toAscii()); + QNetworkAccessManager *manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)), + this, SLOT(handleMapData(QNetworkReply*))); + manager->get(QNetworkRequest(url)); + } + } + + if (xml.tokenType() == QXmlStreamReader::EndElement) { + inFlightName &= xml.name() != "h1"; + inFlightStatus &= xml.name() != "div"; + inFlightMap &= xml.name() != "div"; + inFieldName &= xml.name() != "td"; + inFieldValue &= xml.name() != "td"; + } + + if (xml.tokenType() == QXmlStreamReader::Characters) { + if (inFlightName) + flightName += xml.text(); + if (inFlightStatus) + flightStatus += xml.text(); + if (inFieldName) + fieldNames.last() += xml.text(); + if (inFieldValue) + fieldValues.last() += xml.text(); + } + } + + if (fieldNames.isEmpty()) { + QString code = ui.flightEdit->text().simplified().left(10); + QString msg = QString("Flight %1 is not found").arg(code); + ui.flightName->setText(msg); + return; + } + + ui.flightName->setText(flightName); + flightStatus.remove("Status: "); + ui.flightStatus->setText(flightStatus); + ui.flightStatus->show(); + + QStringList whiteList; + whiteList << "Departure"; + whiteList << "Arrival"; + whiteList << "Scheduled"; + whiteList << "Takeoff"; + whiteList << "Estimated"; + whiteList << "Term-Gate"; + + QString text; + text = QString("<table width=%1>").arg(width() - 25); + for (int i = 0; i < fieldNames.count(); i++) { + QString fn = fieldNames[i].simplified(); + if (fn.endsWith(':')) + fn = fn.left(fn.length() - 1); + if (!whiteList.contains(fn)) + continue; + + QString fv = fieldValues[i].simplified(); + bool special = false; + special |= fn.startsWith("Departure"); + special |= fn.startsWith("Arrival"); + text += "<tr>"; + if (special) { + text += "<td align=center colspan=2>"; + text += "<b><font size=+1>" + fv + "</font></b>"; + text += "</td>"; + } else { + text += "<td align=right>"; + text += fn; + text += " : "; + text += " "; + text += "</td>"; + text += "<td>"; + text += fv; + text += "</td>"; + } + text += "</tr>"; + } + text += "</table>"; + ui.detailedInfo->setText(text); + ui.infoBox->show(); + } + + void resizeEvent(QResizeEvent *event) { + Q_UNUSED(event); + ui.detailedInfo->setMaximumWidth(width() - 25); + } + + void paintEvent(QPaintEvent *event) { + QMainWindow::paintEvent(event); + QPainter p(this); + p.fillRect(rect(), QColor(131, 171, 210)); + if (!m_map.isNull()) { + int x = (width() - m_map.width()) / 2; + int space = ui.infoBox->pos().y(); + if (!ui.infoBox->isVisible()) + space = height(); + int top = ui.titleBox->height(); + int y = qMax(top, (space - m_map.height()) / 2); + p.drawPixmap(x, y, m_map); + } + p.end(); + } + +}; + + +#include "flightinfo.moc" + +int main(int argc, char **argv) +{ + Q_INIT_RESOURCE(flightinfo); + + QApplication app(argc, argv); + + FlightInfo w; +#if defined(Q_OS_SYMBIAN) + w.showMaximized(); +#else + w.resize(360, 504); + w.show(); +#endif + + return app.exec(); +} diff --git a/demos/embedded/flightinfo/flightinfo.pro b/demos/embedded/flightinfo/flightinfo.pro new file mode 100644 index 0000000..5edb175 --- /dev/null +++ b/demos/embedded/flightinfo/flightinfo.pro @@ -0,0 +1,12 @@ +TEMPLATE = app +TARGET = flightinfo +SOURCES = flightinfo.cpp +FORMS += form.ui +RESOURCES = flightinfo.qrc +QT += network + +symbian { + HEADERS += $$QT_SOURCE_TREE/examples/network/ftp/sym_iap_util.h + LIBS += -lesock -lconnmon + TARGET.CAPABILITY = NetworkServices +} diff --git a/demos/embedded/flightinfo/flightinfo.qrc b/demos/embedded/flightinfo/flightinfo.qrc new file mode 100644 index 0000000..babea7e --- /dev/null +++ b/demos/embedded/flightinfo/flightinfo.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/" > + <file>aircraft.png</file> + </qresource> +</RCC> diff --git a/demos/embedded/flightinfo/form.ui b/demos/embedded/flightinfo/form.ui new file mode 100644 index 0000000..3a24c75 --- /dev/null +++ b/demos/embedded/flightinfo/form.ui @@ -0,0 +1,226 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Form</class> + <widget class="QWidget" name="Form"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>220</width> + <height>171</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QFrame" name="titleBox"> + <property name="styleSheet"> + <string>QFrame { +background-color: #45629a; +} + +QLabel { +color: white; +}</string> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="margin"> + <number>4</number> + </property> + <item> + <widget class="QLabel" name="flightName"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Powered by FlightView</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="flightStatus"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="styleSheet"> + <string>background-color: white; +color: #45629a;</string> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="text"> + <string>Ready</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="margin"> + <number>4</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QFrame" name="searchBar"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="margin"> + <number>5</number> + </property> + <item> + <widget class="QLineEdit" name="flightEdit"> + <property name="styleSheet"> + <string>color: black; +border: 1px solid black; +background: white; +selection-background-color: lightgray;</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="searchButton"> + <property name="styleSheet"> + <string>color: rgb(255, 255, 255); +background-color: rgb(85, 85, 255); +padding: 2px; +border: 2px solid rgb(0, 0, 127);</string> + </property> + <property name="text"> + <string>Search</string> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>58</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QFrame" name="infoBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string>QFrame { border: 2px solid white; +border-radius: 10px; +margin: 5px; +background-color: rgba(69, 98, 154, 192); }</string> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="spacing"> + <number>0</number> + </property> + <property name="margin"> + <number>5</number> + </property> + <item> + <widget class="QLabel" name="detailedInfo"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string>color: white; +border: none; +background-color: none;</string> + </property> + <property name="text"> + <string/> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::NoTextInteraction</set> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> |