source: trunk/demos/embedded/flightinfo/flightinfo.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 13.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
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
56static 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
93class FlightInfo : public QMainWindow
94{
95 Q_OBJECT
96
97private:
98
99 Ui_Form ui;
100 QUrl m_url;
101 QDate m_searchDate;
102 QPixmap m_map;
103
104public:
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
142private 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
203public 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
234private:
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
400int 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}
Note: See TracBrowser for help on using the repository browser.