1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the demonstration applications of the Qt Toolkit.
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
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
48 #define FLIGHTVIEW_URL "http://mobile.flightview.com/TrackByFlight.aspx"
49 #define FLIGHTVIEW_RANDOM "http://mobile.flightview.com/TrackSampleFlight.aspx"
51 // strips all invalid constructs that might trip QXmlStreamReader
52 static QString sanitized(const QString &xml)
56 // anything up to the html tag
57 int i = data.indexOf("<html");
59 data.remove(0, i - 1);
61 // everything inside the head tag
62 i = data.indexOf("<head");
64 data.remove(i, data.indexOf("</head>") - i + 7);
66 // invalid link for JavaScript code
68 i = data.indexOf("onclick=\"gotoUrl(");
71 data.remove(i, data.indexOf('\"', i + 9) - i + 1);
76 i = data.indexOf("<iframe");
79 data.remove(i, data.indexOf("</iframe>") - i + 8);
83 data.remove(" ");
84 data.remove("©");
89 class FlightInfo : public QMainWindow
99 QNetworkAccessManager m_manager;
100 QList<QNetworkReply *> mapReplies;
104 FlightInfo(QMainWindow *parent = 0): QMainWindow(parent) {
106 QWidget *w = new QWidget(this);
110 ui.searchBar->hide();
112 connect(ui.searchButton, SIGNAL(clicked()), SLOT(startSearch()));
113 connect(ui.flightEdit, SIGNAL(returnPressed()), SLOT(startSearch()));
115 setWindowTitle("Flight Info");
117 // Rendered from the public-domain vectorized aircraft
118 // http://openclipart.org/media/people/Jarno
119 m_map = QPixmap(":/aircraft.png");
121 QAction *searchTodayAction = new QAction("Today's Flight", this);
122 QAction *searchYesterdayAction = new QAction("Yesterday's Flight", this);
123 QAction *randomAction = new QAction("Random Flight", this);
124 connect(searchTodayAction, SIGNAL(triggered()), SLOT(today()));
125 connect(searchYesterdayAction, SIGNAL(triggered()), SLOT(yesterday()));
126 connect(randomAction, SIGNAL(triggered()), SLOT(randomFlight()));
127 connect(&m_manager, SIGNAL(finished(QNetworkReply*)),
128 this, SLOT(handleNetworkData(QNetworkReply*)));
129 #if defined(Q_OS_SYMBIAN)
130 menuBar()->addAction(searchTodayAction);
131 menuBar()->addAction(searchYesterdayAction);
132 menuBar()->addAction(randomAction);
134 addAction(searchTodayAction);
135 addAction(searchYesterdayAction);
136 addAction(randomAction);
137 setContextMenuPolicy(Qt::ActionsContextMenu);
143 void handleNetworkData(QNetworkReply *networkReply) {
144 if (!networkReply->error()) {
145 if (!mapReplies.contains(networkReply)) {
146 // Assume UTF-8 encoded
147 QByteArray data = networkReply->readAll();
148 QString xml = QString::fromUtf8(data);
151 mapReplies.removeOne(networkReply);
152 m_map.loadFromData(networkReply->readAll());
156 networkReply->deleteLater();
160 QDateTime timestamp = QDateTime::currentDateTime();
161 m_searchDate = timestamp.date();
166 QDateTime timestamp = QDateTime::currentDateTime();
167 timestamp = timestamp.addDays(-1);
168 m_searchDate = timestamp.date();
172 void searchFlight() {
173 ui.searchBar->show();
175 ui.flightStatus->hide();
176 ui.flightName->setText("Enter flight number");
177 ui.flightEdit->setFocus();
178 #ifdef QT_KEYPAD_NAVIGATION
179 ui.flightEdit->setEditFocus(true);
186 ui.searchBar->hide();
187 QString flight = ui.flightEdit->text().simplified();
188 if (!flight.isEmpty())
189 request(flight, m_searchDate);
192 void randomFlight() {
193 request(QString(), QDate::currentDate());
198 void request(const QString &flightCode, const QDate &date) {
200 setWindowTitle("Loading...");
202 QString code = flightCode.simplified();
203 QString airlineCode = code.left(2).toUpper();
204 QString flightNumber = code.mid(2, code.length());
206 ui.flightName->setText("Searching for " + code);
208 m_url = QUrl(FLIGHTVIEW_URL);
209 m_url.addEncodedQueryItem("view", "detail");
210 m_url.addEncodedQueryItem("al", QUrl::toPercentEncoding(airlineCode));
211 m_url.addEncodedQueryItem("fn", QUrl::toPercentEncoding(flightNumber));
212 m_url.addEncodedQueryItem("dpdat", QUrl::toPercentEncoding(date.toString("yyyyMMdd")));
214 if (code.isEmpty()) {
215 // random flight as sample
216 m_url = QUrl(FLIGHTVIEW_RANDOM);
217 ui.flightName->setText("Getting a random flight...");
220 m_manager.get(QNetworkRequest(m_url));
226 void digest(const QString &content) {
228 setWindowTitle("Flight Info");
229 QString data = sanitized(content);
231 // do we only get the flight list?
232 // we grab the first leg in the flight list
233 // then fetch another URL for the real flight info
234 int i = data.indexOf("a href=\"?view=detail");
236 QString href = data.mid(i, data.indexOf('\"', i + 8) - i + 1);
237 QRegExp regex("dpap=([A-Za-z0-9]+)");
239 QString airport = regex.cap(1);
240 m_url.addEncodedQueryItem("dpap", QUrl::toPercentEncoding(airport));
241 m_manager.get(QNetworkRequest(m_url));
245 QXmlStreamReader xml(data);
246 bool inFlightName = false;
247 bool inFlightStatus = false;
248 bool inFlightMap = false;
249 bool inFieldName = false;
250 bool inFieldValue = false;
253 QString flightStatus;
254 QStringList fieldNames;
255 QStringList fieldValues;
257 while (!xml.atEnd()) {
260 if (xml.tokenType() == QXmlStreamReader::StartElement) {
261 QStringRef className = xml.attributes().value("class");
262 inFlightName |= xml.name() == "h1";
263 inFlightStatus |= className == "FlightDetailHeaderStatus";
264 inFlightMap |= className == "flightMap";
265 if (xml.name() == "td" && !className.isEmpty()) {
266 QString cn = className.toString();
267 if (cn.contains("fieldTitle")) {
269 fieldNames += QString();
270 fieldValues += QString();
272 if (cn.contains("fieldValue"))
275 if (xml.name() == "img" && inFlightMap) {
276 QString src = xml.attributes().value("src").toString();
277 src.prepend("http://mobile.flightview.com/");
278 QUrl url = QUrl::fromPercentEncoding(src.toAscii());
279 mapReplies.append(m_manager.get(QNetworkRequest(url)));
283 if (xml.tokenType() == QXmlStreamReader::EndElement) {
284 inFlightName &= xml.name() != "h1";
285 inFlightStatus &= xml.name() != "div";
286 inFlightMap &= xml.name() != "div";
287 inFieldName &= xml.name() != "td";
288 inFieldValue &= xml.name() != "td";
291 if (xml.tokenType() == QXmlStreamReader::Characters) {
293 flightName += xml.text();
295 flightStatus += xml.text();
297 fieldNames.last() += xml.text();
299 fieldValues.last() += xml.text();
303 if (fieldNames.isEmpty()) {
304 QString code = ui.flightEdit->text().simplified().left(10);
305 QString msg = QString("Flight %1 is not found").arg(code);
306 ui.flightName->setText(msg);
310 ui.flightName->setText(flightName);
311 flightStatus.remove("Status: ");
312 ui.flightStatus->setText(flightStatus);
313 ui.flightStatus->show();
315 QStringList whiteList;
316 whiteList << "Departure";
317 whiteList << "Arrival";
318 whiteList << "Scheduled";
319 whiteList << "Takeoff";
320 whiteList << "Estimated";
321 whiteList << "Term-Gate";
324 text = QString("<table width=%1>").arg(width() - 25);
325 for (int i = 0; i < fieldNames.count(); i++) {
326 QString fn = fieldNames[i].simplified();
327 if (fn.endsWith(':'))
328 fn = fn.left(fn.length() - 1);
329 if (!whiteList.contains(fn))
332 QString fv = fieldValues[i].simplified();
333 bool special = false;
334 special |= fn.startsWith("Departure");
335 special |= fn.startsWith("Arrival");
338 text += "<td align=center colspan=2>";
339 text += "<b><font size=+1>" + fv + "</font></b>";
342 text += "<td align=right>";
354 ui.detailedInfo->setText(text);
358 void resizeEvent(QResizeEvent *event) {
360 ui.detailedInfo->setMaximumWidth(width() - 25);
363 void paintEvent(QPaintEvent *event) {
364 QMainWindow::paintEvent(event);
366 p.fillRect(rect(), QColor(131, 171, 210));
367 if (!m_map.isNull()) {
368 int x = (width() - m_map.width()) / 2;
369 int space = ui.infoBox->pos().y();
370 if (!ui.infoBox->isVisible())
372 int top = ui.titleBox->height();
373 int y = qMax(top, (space - m_map.height()) / 2);
374 p.drawPixmap(x, y, m_map);
382 #include "flightinfo.moc"
384 int main(int argc, char **argv)
386 Q_INIT_RESOURCE(flightinfo);
388 QApplication app(argc, argv);
391 #if defined(Q_OS_SYMBIAN)