demos/embedded/flightinfo/flightinfo.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the demonstration applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QtCore>
       
    43 #include <QtGui>
       
    44 #include <QtNetwork>
       
    45 
       
    46 #if defined (Q_OS_SYMBIAN)
       
    47 #include "sym_iap_util.h"
       
    48 #endif
       
    49 
       
    50 #include "ui_form.h"
       
    51 
       
    52 #define FLIGHTVIEW_URL "http://mobile.flightview.com/TrackByFlight.aspx"
       
    53 #define FLIGHTVIEW_RANDOM "http://mobile.flightview.com/TrackSampleFlight.aspx"
       
    54 
       
    55 // strips all invalid constructs that might trip QXmlStreamReader
       
    56 static QString sanitized(const QString &xml)
       
    57 {
       
    58     QString data = xml;
       
    59 
       
    60     // anything up to the html tag
       
    61     int i = data.indexOf("<html");
       
    62     if (i > 0)
       
    63         data.remove(0, i - 1);
       
    64 
       
    65     // everything inside the head tag
       
    66     i = data.indexOf("<head");
       
    67     if (i > 0)
       
    68         data.remove(i, data.indexOf("</head>") - i + 7);
       
    69 
       
    70     // invalid link for JavaScript code
       
    71     while (true) {
       
    72         i  = data.indexOf("onclick=\"gotoUrl(");
       
    73         if (i < 0)
       
    74             break;
       
    75         data.remove(i, data.indexOf('\"', i + 9) - i + 1);
       
    76     }
       
    77 
       
    78     // all inline frames
       
    79     while (true) {
       
    80         i  = data.indexOf("<iframe");
       
    81         if (i < 0)
       
    82             break;
       
    83         data.remove(i, data.indexOf("</iframe>") - i + 8);
       
    84     }
       
    85 
       
    86     // entities
       
    87     data.remove("&nbsp;");
       
    88     data.remove("&copy;");
       
    89 
       
    90     return data;
       
    91 }
       
    92 
       
    93 class FlightInfo : public QMainWindow
       
    94 {
       
    95     Q_OBJECT
       
    96 
       
    97 private:
       
    98 
       
    99     Ui_Form ui;
       
   100     QUrl m_url;
       
   101     QDate m_searchDate;
       
   102     QPixmap m_map;
       
   103 
       
   104 public:
       
   105 
       
   106     FlightInfo(QMainWindow *parent = 0): QMainWindow(parent) {
       
   107 
       
   108         QWidget *w = new QWidget(this);
       
   109         ui.setupUi(w);
       
   110         setCentralWidget(w);
       
   111 
       
   112         ui.searchBar->hide();
       
   113         ui.infoBox->hide();
       
   114         connect(ui.searchButton, SIGNAL(clicked()), SLOT(startSearch()));
       
   115         connect(ui.flightEdit, SIGNAL(returnPressed()), SLOT(startSearch()));
       
   116 
       
   117         setWindowTitle("Flight Info");
       
   118         QTimer::singleShot(0, this, SLOT(delayedInit()));
       
   119 
       
   120         // Rendered from the public-domain vectorized aircraft
       
   121         // http://openclipart.org/media/people/Jarno
       
   122         m_map = QPixmap(":/aircraft.png");
       
   123 
       
   124         QAction *searchTodayAction = new QAction("Today's Flight", this);
       
   125         QAction *searchYesterdayAction = new QAction("Yesterday's Flight", this);
       
   126         QAction *randomAction = new QAction("Random Flight", this);
       
   127         connect(searchTodayAction, SIGNAL(triggered()), SLOT(today()));
       
   128         connect(searchYesterdayAction, SIGNAL(triggered()), SLOT(yesterday()));
       
   129         connect(randomAction, SIGNAL(triggered()), SLOT(randomFlight()));
       
   130 #if defined(Q_OS_SYMBIAN)
       
   131         menuBar()->addAction(searchTodayAction);
       
   132         menuBar()->addAction(searchYesterdayAction);
       
   133         menuBar()->addAction(randomAction);
       
   134 #else
       
   135         addAction(searchTodayAction);
       
   136         addAction(searchYesterdayAction);
       
   137         addAction(randomAction);
       
   138         setContextMenuPolicy(Qt::ActionsContextMenu);
       
   139 #endif
       
   140     }
       
   141 
       
   142 private slots:
       
   143     void delayedInit() {
       
   144 #if defined(Q_OS_SYMBIAN)
       
   145         qt_SetDefaultIap();
       
   146 #endif
       
   147     }
       
   148 
       
   149 
       
   150     void handleNetworkData(QNetworkReply *networkReply) {
       
   151         if (!networkReply->error()) {
       
   152             // Assume UTF-8 encoded
       
   153             QByteArray data = networkReply->readAll();
       
   154             QString xml = QString::fromUtf8(data);
       
   155             digest(xml);
       
   156         }
       
   157         networkReply->deleteLater();
       
   158         networkReply->manager()->deleteLater();
       
   159     }
       
   160 
       
   161     void handleMapData(QNetworkReply *networkReply) {
       
   162         if (!networkReply->error()) {
       
   163             m_map.loadFromData(networkReply->readAll());
       
   164             update();
       
   165         }
       
   166         networkReply->deleteLater();
       
   167         networkReply->manager()->deleteLater();
       
   168     }
       
   169 
       
   170     void today() {
       
   171         QDateTime timestamp = QDateTime::currentDateTime();
       
   172         m_searchDate = timestamp.date();
       
   173         searchFlight();
       
   174     }
       
   175 
       
   176     void yesterday() {
       
   177         QDateTime timestamp = QDateTime::currentDateTime();
       
   178         timestamp = timestamp.addDays(-1);
       
   179         m_searchDate = timestamp.date();
       
   180         searchFlight();
       
   181     }
       
   182 
       
   183     void searchFlight() {
       
   184         ui.searchBar->show();
       
   185         ui.infoBox->hide();
       
   186         ui.flightStatus->hide();
       
   187         ui.flightName->setText("Enter flight number");
       
   188         m_map = QPixmap();
       
   189         update();
       
   190     }
       
   191 
       
   192     void startSearch() {
       
   193         ui.searchBar->hide();
       
   194         QString flight = ui.flightEdit->text().simplified();
       
   195         if (!flight.isEmpty())
       
   196             request(flight, m_searchDate);
       
   197     }
       
   198 
       
   199     void randomFlight() {
       
   200         request(QString(), QDate::currentDate());
       
   201     }
       
   202 
       
   203 public slots:
       
   204 
       
   205     void request(const QString &flightCode, const QDate &date) {
       
   206 
       
   207         setWindowTitle("Loading...");
       
   208 
       
   209         QString code = flightCode.simplified();
       
   210         QString airlineCode = code.left(2).toUpper();
       
   211         QString flightNumber = code.mid(2, code.length());
       
   212 
       
   213         ui.flightName->setText("Searching for " + code);
       
   214 
       
   215         m_url = QUrl(FLIGHTVIEW_URL);
       
   216         m_url.addEncodedQueryItem("view", "detail");
       
   217         m_url.addEncodedQueryItem("al", QUrl::toPercentEncoding(airlineCode));
       
   218         m_url.addEncodedQueryItem("fn", QUrl::toPercentEncoding(flightNumber));
       
   219         m_url.addEncodedQueryItem("dpdat", QUrl::toPercentEncoding(date.toString("yyyyMMdd")));
       
   220 
       
   221         if (code.isEmpty()) {
       
   222             // random flight as sample
       
   223             m_url = QUrl(FLIGHTVIEW_RANDOM);
       
   224             ui.flightName->setText("Getting a random flight...");
       
   225         }
       
   226 
       
   227         QNetworkAccessManager *manager = new QNetworkAccessManager(this);
       
   228         connect(manager, SIGNAL(finished(QNetworkReply*)),
       
   229                 this, SLOT(handleNetworkData(QNetworkReply*)));
       
   230         manager->get(QNetworkRequest(m_url));
       
   231     }
       
   232 
       
   233 
       
   234 private:
       
   235 
       
   236     void digest(const QString &content) {
       
   237 
       
   238         setWindowTitle("Flight Info");
       
   239         QString data = sanitized(content);
       
   240 
       
   241         // do we only get the flight list?
       
   242         // we grab the first leg in the flight list
       
   243         // then fetch another URL for the real flight info
       
   244         int i = data.indexOf("a href=\"?view=detail");
       
   245         if (i > 0) {
       
   246             QString href = data.mid(i, data.indexOf('\"', i + 8) - i + 1);
       
   247             QRegExp regex("dpap=([A-Za-z0-9]+)");
       
   248             regex.indexIn(href);
       
   249             QString airport = regex.cap(1);
       
   250             m_url.addEncodedQueryItem("dpap", QUrl::toPercentEncoding(airport));
       
   251             QNetworkAccessManager *manager = new QNetworkAccessManager(this);
       
   252             connect(manager, SIGNAL(finished(QNetworkReply*)),
       
   253                     this, SLOT(handleNetworkData(QNetworkReply*)));
       
   254             manager->get(QNetworkRequest(m_url));
       
   255             return;
       
   256         }
       
   257 
       
   258         QXmlStreamReader xml(data);
       
   259         bool inFlightName = false;
       
   260         bool inFlightStatus = false;
       
   261         bool inFlightMap = false;
       
   262         bool inFieldName = false;
       
   263         bool inFieldValue = false;
       
   264 
       
   265         QString flightName;
       
   266         QString flightStatus;
       
   267         QStringList fieldNames;
       
   268         QStringList fieldValues;
       
   269 
       
   270         while (!xml.atEnd()) {
       
   271             xml.readNext();
       
   272 
       
   273             if (xml.tokenType() == QXmlStreamReader::StartElement) {
       
   274                 QStringRef className = xml.attributes().value("class");
       
   275                 inFlightName |= xml.name() == "h1";
       
   276                 inFlightStatus |= className == "FlightDetailHeaderStatus";
       
   277                 inFlightMap |= className == "flightMap";
       
   278                 if (xml.name() == "td" && !className.isEmpty()) {
       
   279                     QString cn = className.toString();
       
   280                     if (cn.contains("fieldTitle")) {
       
   281                         inFieldName = true;
       
   282                         fieldNames += QString();
       
   283                         fieldValues += QString();
       
   284                     }
       
   285                     if (cn.contains("fieldValue"))
       
   286                         inFieldValue = true;
       
   287                 }
       
   288                 if (xml.name() == "img" && inFlightMap) {
       
   289                     QString src = xml.attributes().value("src").toString();
       
   290                     src.prepend("http://mobile.flightview.com");
       
   291                     QUrl url = QUrl::fromPercentEncoding(src.toAscii());
       
   292                     QNetworkAccessManager *manager = new QNetworkAccessManager(this);
       
   293                     connect(manager, SIGNAL(finished(QNetworkReply*)),
       
   294                             this, SLOT(handleMapData(QNetworkReply*)));
       
   295                     manager->get(QNetworkRequest(url));
       
   296                 }
       
   297             }
       
   298 
       
   299             if (xml.tokenType() == QXmlStreamReader::EndElement) {
       
   300                 inFlightName &= xml.name() != "h1";
       
   301                 inFlightStatus &= xml.name() != "div";
       
   302                 inFlightMap &= xml.name() != "div";
       
   303                 inFieldName &= xml.name() != "td";
       
   304                 inFieldValue &= xml.name() != "td";
       
   305             }
       
   306 
       
   307             if (xml.tokenType() == QXmlStreamReader::Characters) {
       
   308                 if (inFlightName)
       
   309                     flightName += xml.text();
       
   310                 if (inFlightStatus)
       
   311                     flightStatus += xml.text();
       
   312                 if (inFieldName)
       
   313                     fieldNames.last() += xml.text();
       
   314                 if (inFieldValue)
       
   315                     fieldValues.last() += xml.text();
       
   316             }
       
   317         }
       
   318 
       
   319         if (fieldNames.isEmpty()) {
       
   320             QString code = ui.flightEdit->text().simplified().left(10);
       
   321             QString msg = QString("Flight %1 is not found").arg(code);
       
   322             ui.flightName->setText(msg);
       
   323             return;
       
   324         }
       
   325 
       
   326         ui.flightName->setText(flightName);
       
   327         flightStatus.remove("Status: ");
       
   328         ui.flightStatus->setText(flightStatus);
       
   329         ui.flightStatus->show();
       
   330 
       
   331         QStringList whiteList;
       
   332         whiteList << "Departure";
       
   333         whiteList << "Arrival";
       
   334         whiteList << "Scheduled";
       
   335         whiteList << "Takeoff";
       
   336         whiteList << "Estimated";
       
   337         whiteList << "Term-Gate";
       
   338 
       
   339         QString text;
       
   340         text = QString("<table width=%1>").arg(width() - 25);
       
   341         for (int i = 0; i < fieldNames.count(); i++) {
       
   342             QString fn = fieldNames[i].simplified();
       
   343             if (fn.endsWith(':'))
       
   344                 fn = fn.left(fn.length() - 1);
       
   345             if (!whiteList.contains(fn))
       
   346                 continue;
       
   347 
       
   348             QString fv = fieldValues[i].simplified();
       
   349             bool special = false;
       
   350             special |= fn.startsWith("Departure");
       
   351             special |= fn.startsWith("Arrival");
       
   352             text += "<tr>";
       
   353             if (special) {
       
   354                 text += "<td align=center colspan=2>";
       
   355                 text += "<b><font size=+1>" + fv + "</font></b>";
       
   356                 text += "</td>";
       
   357             } else {
       
   358                 text += "<td align=right>";
       
   359                 text += fn;
       
   360                 text += " : ";
       
   361                 text += "&nbsp;";
       
   362                 text += "</td>";
       
   363                 text += "<td>";
       
   364                 text += fv;
       
   365                 text += "</td>";
       
   366             }
       
   367             text += "</tr>";
       
   368         }
       
   369         text += "</table>";
       
   370         ui.detailedInfo->setText(text);
       
   371         ui.infoBox->show();
       
   372     }
       
   373 
       
   374     void resizeEvent(QResizeEvent *event) {
       
   375         Q_UNUSED(event);
       
   376         ui.detailedInfo->setMaximumWidth(width() - 25);
       
   377     }
       
   378 
       
   379     void paintEvent(QPaintEvent *event) {
       
   380         QMainWindow::paintEvent(event);
       
   381         QPainter p(this);
       
   382         p.fillRect(rect(), QColor(131, 171, 210));
       
   383         if (!m_map.isNull()) {
       
   384             int x = (width() - m_map.width()) / 2;
       
   385             int space = ui.infoBox->pos().y();
       
   386             if (!ui.infoBox->isVisible())
       
   387                 space = height();
       
   388             int top = ui.titleBox->height();
       
   389             int y = qMax(top, (space - m_map.height()) / 2);
       
   390             p.drawPixmap(x, y, m_map);
       
   391         }
       
   392         p.end();
       
   393     }
       
   394 
       
   395 };
       
   396 
       
   397 
       
   398 #include "flightinfo.moc"
       
   399 
       
   400 int main(int argc, char **argv)
       
   401 {
       
   402     Q_INIT_RESOURCE(flightinfo);
       
   403 
       
   404     QApplication app(argc, argv);
       
   405 
       
   406     FlightInfo w;
       
   407 #if defined(Q_OS_SYMBIAN)
       
   408     w.showMaximized();
       
   409 #else
       
   410     w.resize(360, 504);
       
   411     w.show();
       
   412 #endif
       
   413 
       
   414     return app.exec();
       
   415 }