From fa246f93508147b4b2e582c61fbb60a0d7f881c3 Mon Sep 17 00:00:00 2001 From: Ariya Hidayat Date: Wed, 19 Aug 2009 13:24:05 +0200 Subject: 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 --- demos/embedded/embedded.pro | 1 + demos/embedded/flightinfo/aircraft.png | Bin 0 -> 28713 bytes demos/embedded/flightinfo/flightinfo.cpp | 415 +++++++++++++++++++++ demos/embedded/flightinfo/flightinfo.pro | 12 + demos/embedded/flightinfo/flightinfo.qrc | 5 + demos/embedded/flightinfo/form.ui | 226 +++++++++++ demos/embedded/fluidlauncher/config_s60/config.xml | 1 + .../fluidlauncher/screenshots/flightinfo_s60.png | Bin 0 -> 24473 bytes 8 files changed, 660 insertions(+) create mode 100644 demos/embedded/flightinfo/aircraft.png create mode 100644 demos/embedded/flightinfo/flightinfo.cpp create mode 100644 demos/embedded/flightinfo/flightinfo.pro create mode 100644 demos/embedded/flightinfo/flightinfo.qrc create mode 100644 demos/embedded/flightinfo/form.ui create mode 100644 demos/embedded/fluidlauncher/screenshots/flightinfo_s60.png diff --git a/demos/embedded/embedded.pro b/demos/embedded/embedded.pro index 2af64c7..3fa0e13 100644 --- a/demos/embedded/embedded.pro +++ b/demos/embedded/embedded.pro @@ -9,6 +9,7 @@ contains(QT_CONFIG, svg) { contains(QT_CONFIG, network) { SUBDIRS += lightmaps + SUBDIRS += flightinfo } contains(QT_CONFIG, webkit) { diff --git a/demos/embedded/flightinfo/aircraft.png b/demos/embedded/flightinfo/aircraft.png new file mode 100644 index 0000000..0845cb4 Binary files /dev/null and b/demos/embedded/flightinfo/aircraft.png differ 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 +#include +#include + +#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(" 0) + data.remove(0, i - 1); + + // everything inside the head tag + i = data.indexOf(" 0) + data.remove(i, data.indexOf("") - 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("") - 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("").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 += ""; + if (special) { + text += ""; + } else { + text += ""; + text += ""; + } + text += ""; + } + text += "
"; + text += "" + fv + ""; + text += ""; + text += fn; + text += " : "; + text += " "; + text += ""; + text += fv; + text += "
"; + 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 @@ + + + aircraft.png + + 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 @@ + + + Form + + + + 0 + 0 + 220 + 171 + + + + Form + + + + 0 + + + 0 + + + + + QFrame { +background-color: #45629a; +} + +QLabel { +color: white; +} + + + QFrame::NoFrame + + + QFrame::Raised + + + 0 + + + + 0 + + + 4 + + + + + + 0 + 0 + + + + Powered by FlightView + + + + + + + + 0 + 0 + + + + + 75 + true + + + + background-color: white; +color: #45629a; + + + 0 + + + Ready + + + Qt::AlignCenter + + + 4 + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 5 + + + + + color: black; +border: 1px solid black; +background: white; +selection-background-color: lightgray; + + + + + + + color: rgb(255, 255, 255); +background-color: rgb(85, 85, 255); +padding: 2px; +border: 2px solid rgb(0, 0, 127); + + + Search + + + Qt::ToolButtonTextBesideIcon + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 58 + + + + + + + + + 0 + 0 + + + + QFrame { border: 2px solid white; +border-radius: 10px; +margin: 5px; +background-color: rgba(69, 98, 154, 192); } + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 5 + + + + + + 0 + 0 + + + + color: white; +border: none; +background-color: none; + + + + + + Qt::RichText + + + true + + + Qt::NoTextInteraction + + + + + + + + + + + diff --git a/demos/embedded/fluidlauncher/config_s60/config.xml b/demos/embedded/fluidlauncher/config_s60/config.xml index be4f016..5957404 100644 --- a/demos/embedded/fluidlauncher/config_s60/config.xml +++ b/demos/embedded/fluidlauncher/config_s60/config.xml @@ -16,6 +16,7 @@ + diff --git a/demos/embedded/fluidlauncher/screenshots/flightinfo_s60.png b/demos/embedded/fluidlauncher/screenshots/flightinfo_s60.png new file mode 100644 index 0000000..8a304eb Binary files /dev/null and b/demos/embedded/fluidlauncher/screenshots/flightinfo_s60.png differ -- cgit v0.12