|
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 Qt Mobility Components. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:BSD$ |
|
10 ** You may use this file under the terms of the BSD license as follows: |
|
11 ** |
|
12 ** "Redistribution and use in source and binary forms, with or without |
|
13 ** modification, are permitted provided that the following conditions are |
|
14 ** met: |
|
15 ** * Redistributions of source code must retain the above copyright |
|
16 ** notice, this list of conditions and the following disclaimer. |
|
17 ** * Redistributions in binary form must reproduce the above copyright |
|
18 ** notice, this list of conditions and the following disclaimer in |
|
19 ** the documentation and/or other materials provided with the |
|
20 ** distribution. |
|
21 ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor |
|
22 ** the names of its contributors may be used to endorse or promote |
|
23 ** products derived from this software without specific prior written |
|
24 ** permission. |
|
25 ** |
|
26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
28 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
29 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
30 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
36 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
|
37 ** $QT_END_LICENSE$ |
|
38 ** |
|
39 ****************************************************************************/ |
|
40 |
|
41 #include <QtCore> |
|
42 #include <QtGui> |
|
43 #include <QtNetwork> |
|
44 #include <QtSvg> |
|
45 |
|
46 // QtMobility API headers |
|
47 #include <qmobilityglobal.h> |
|
48 #include <qgeopositioninfosource.h> |
|
49 #include <qgeosatelliteinfosource.h> |
|
50 #include <qnmeapositioninfosource.h> |
|
51 #include <qgeopositioninfo.h> |
|
52 #include <qnetworkconfigmanager.h> |
|
53 #include <qnetworksession.h> |
|
54 |
|
55 #include "satellitedialog.h" |
|
56 #include "connectivityhelper.h" |
|
57 |
|
58 // Use the QtMobility namespace |
|
59 QTM_USE_NAMESPACE |
|
60 |
|
61 class WeatherInfo: public QMainWindow |
|
62 { |
|
63 Q_OBJECT |
|
64 |
|
65 private: |
|
66 |
|
67 QGraphicsView *m_view; |
|
68 QGraphicsScene m_scene; |
|
69 QString city; |
|
70 QGraphicsRectItem *m_statusItem; |
|
71 QGraphicsTextItem *m_temperatureItem; |
|
72 QGraphicsTextItem *m_conditionItem; |
|
73 QGraphicsSvgItem *m_iconItem; |
|
74 QList<QGraphicsRectItem*> m_forecastItems; |
|
75 QList<QGraphicsTextItem*> m_dayItems; |
|
76 QList<QGraphicsSvgItem*> m_conditionItems; |
|
77 QList<QGraphicsTextItem*> m_rangeItems; |
|
78 QTimeLine m_timeLine; |
|
79 QHash<QString, QString> m_icons; |
|
80 QNetworkAccessManager* m_nam; |
|
81 |
|
82 bool m_usingLogFile; |
|
83 bool m_gpsWeather; |
|
84 QGeoPositionInfoSource* m_location; |
|
85 QNetworkSession* m_session; |
|
86 ConnectivityHelper* m_connectivityHelper; |
|
87 QGeoCoordinate m_coordinate; |
|
88 |
|
89 public: |
|
90 WeatherInfo(QWidget *parent = 0): QMainWindow(parent) { |
|
91 |
|
92 m_view = new QGraphicsView(this); |
|
93 setCentralWidget(m_view); |
|
94 |
|
95 setupScene(); |
|
96 m_view->setScene(&m_scene); |
|
97 m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
|
98 m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
|
99 |
|
100 m_view->setFrameShape(QFrame::NoFrame); |
|
101 setWindowTitle("Weather Info"); |
|
102 |
|
103 QAction *your = new QAction("Your weather", this); |
|
104 connect(your, SIGNAL(triggered()), SLOT(yourWeather())); |
|
105 addAction(your); |
|
106 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) |
|
107 menuBar()->addAction(your); |
|
108 #endif |
|
109 |
|
110 QStringList cities; |
|
111 cities << "Helsinki"; |
|
112 cities << "Oslo"; |
|
113 cities << "Berlin"; |
|
114 cities << "Brisbane"; |
|
115 cities << "San Diego"; |
|
116 for (int i = 0; i < cities.count(); ++i) { |
|
117 QAction *action = new QAction(cities[i], this); |
|
118 connect(action, SIGNAL(triggered()), SLOT(chooseCity())); |
|
119 addAction(action); |
|
120 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) |
|
121 menuBar()->addAction(action); |
|
122 #endif |
|
123 } |
|
124 |
|
125 #if defined(Q_OS_WINCE) |
|
126 QAction *exitAction = new QAction(tr("Exit"), this); |
|
127 connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit())); |
|
128 addAction(exitAction); |
|
129 menuBar()->addAction(exitAction); |
|
130 #endif |
|
131 |
|
132 setContextMenuPolicy(Qt::ActionsContextMenu); |
|
133 |
|
134 // QNetworkAccessManager |
|
135 m_nam = new QNetworkAccessManager(this); |
|
136 connect(m_nam, SIGNAL(finished(QNetworkReply*)), |
|
137 this, SLOT(handleNetworkData(QNetworkReply*))); |
|
138 |
|
139 // Don't use the GPS until we need it |
|
140 m_location = 0; |
|
141 m_gpsWeather = false; |
|
142 m_usingLogFile = false; |
|
143 |
|
144 QTimer::singleShot(0, this, SLOT(delayedInit())); |
|
145 } |
|
146 |
|
147 ~WeatherInfo() { |
|
148 if (m_location) |
|
149 m_location->stopUpdates(); |
|
150 m_session->close(); |
|
151 } |
|
152 |
|
153 private slots: |
|
154 |
|
155 void delayedInit() { |
|
156 // Set Internet Access Point |
|
157 QNetworkConfigurationManager manager; |
|
158 const bool canStartIAP = (manager.capabilities() |
|
159 & QNetworkConfigurationManager::CanStartAndStopInterfaces); |
|
160 // Is there default access point, use it |
|
161 QTM_PREPEND_NAMESPACE(QNetworkConfiguration) cfg = manager.defaultConfiguration(); |
|
162 if (!cfg.isValid() || (!canStartIAP && cfg.state() != QTM_PREPEND_NAMESPACE(QNetworkConfiguration)::Active)) { |
|
163 QMessageBox::information(this, tr("Weather Info"), tr( |
|
164 "Available Access Points not found.")); |
|
165 return; |
|
166 } |
|
167 m_session = new QNetworkSession(cfg, this); |
|
168 m_connectivityHelper = new ConnectivityHelper(m_session, this); |
|
169 connect(m_session, SIGNAL(opened()), this, SLOT(networkSessionOpened())); |
|
170 connect(m_connectivityHelper, SIGNAL(networkingCancelled()), qApp, SLOT(quit())); |
|
171 |
|
172 m_session->open(); |
|
173 } |
|
174 |
|
175 void networkSessionOpened() { |
|
176 m_gpsWeather = false; |
|
177 request("Helsinki"); |
|
178 } |
|
179 |
|
180 void yourWeather() { |
|
181 m_gpsWeather = true; |
|
182 |
|
183 if (!m_location) { |
|
184 // QGeoPositionInfoSource |
|
185 m_location = QGeoPositionInfoSource::createDefaultSource(this); |
|
186 |
|
187 if (!m_location) { |
|
188 QNmeaPositionInfoSource *nmeaLocation = |
|
189 new QNmeaPositionInfoSource(QNmeaPositionInfoSource::SimulationMode, this); |
|
190 QFile *logFile = new QFile(QApplication::applicationDirPath() + QDir::separator() |
|
191 + "nmealog.txt", this); |
|
192 nmeaLocation->setDevice(logFile); |
|
193 m_location = nmeaLocation; |
|
194 |
|
195 m_usingLogFile = true; |
|
196 |
|
197 QMessageBox::information(this, tr("Weather Info"), |
|
198 tr("No GPS support detected, using GPS data from a sample log file instead.")); |
|
199 } |
|
200 } |
|
201 |
|
202 if (!m_usingLogFile) { |
|
203 QGeoSatelliteInfoSource *m_satellite = QGeoSatelliteInfoSource::createDefaultSource(this); |
|
204 |
|
205 if (m_satellite) { |
|
206 SatelliteDialog *dialog = new SatelliteDialog(this, |
|
207 30, |
|
208 SatelliteDialog::ExitOnFixOrCancel, |
|
209 SatelliteDialog::OrderByPrnNumber, |
|
210 SatelliteDialog::ScaleToMaxPossible); |
|
211 |
|
212 dialog->connectSources(m_location, m_satellite); |
|
213 |
|
214 m_location->startUpdates(); |
|
215 m_satellite->startUpdates(); |
|
216 |
|
217 dialog->exec(); |
|
218 |
|
219 m_location->stopUpdates(); |
|
220 m_satellite->stopUpdates(); |
|
221 } |
|
222 } |
|
223 |
|
224 // Listen gps position changes |
|
225 connect(m_location, SIGNAL(positionUpdated(QGeoPositionInfo)), this, |
|
226 SLOT(positionUpdated(QGeoPositionInfo))); |
|
227 |
|
228 // Start listening GPS position updates |
|
229 m_location->startUpdates(); |
|
230 } |
|
231 |
|
232 void positionUpdated(QGeoPositionInfo gpsPos) { |
|
233 if (m_gpsWeather) { |
|
234 m_coordinate = gpsPos.coordinate(); |
|
235 if (m_coordinate.isValid()) { |
|
236 QString longitude; |
|
237 longitude.setNum(m_coordinate.longitude()); |
|
238 QString latitude; |
|
239 latitude.setNum(m_coordinate.latitude()); |
|
240 requestTownName(longitude, latitude); |
|
241 m_gpsWeather = false; |
|
242 m_location->stopUpdates(); |
|
243 } else { |
|
244 QMessageBox::information(this, "Weather Info", "Waiting for your GPS position..."); |
|
245 } |
|
246 } |
|
247 } |
|
248 |
|
249 void chooseCity() { |
|
250 QAction *action = qobject_cast<QAction*>(sender()); |
|
251 if (action) { |
|
252 if (m_location) |
|
253 m_location->stopUpdates(); |
|
254 m_gpsWeather = false; |
|
255 request(action->text()); |
|
256 } |
|
257 } |
|
258 |
|
259 void handleNetworkData(QNetworkReply *networkReply) { |
|
260 QUrl url = networkReply->url(); |
|
261 if (!networkReply->error()) { |
|
262 QString data = QString::fromUtf8(networkReply->readAll()); |
|
263 if (data.contains("<LocalityName>", Qt::CaseInsensitive)) { |
|
264 requestWeatherOfTown(data); |
|
265 } else { |
|
266 digest(data); |
|
267 } |
|
268 } |
|
269 networkReply->deleteLater(); |
|
270 } |
|
271 |
|
272 void animate(int frame) { |
|
273 qreal progress = static_cast<qreal>(frame) / 100; |
|
274 #if QT_VERSION >= 0x040500 |
|
275 m_iconItem->setOpacity(progress); |
|
276 #endif |
|
277 qreal hw = width() / 2.0; |
|
278 m_statusItem->setPos(-hw + hw * progress, 0); |
|
279 for (int i = 0; i < m_forecastItems.count(); ++i) { |
|
280 qreal ofs = i * 0.5 / m_forecastItems.count(); |
|
281 qreal alpha = qBound(qreal(0), 2 * (progress - ofs), qreal(1)); |
|
282 #if QT_VERSION >= 0x040500 |
|
283 m_conditionItems[i]->setOpacity(alpha); |
|
284 #endif |
|
285 QPointF pos = m_forecastItems[i]->pos(); |
|
286 if (width() > height()) { |
|
287 qreal fx = width() - width() * 0.4 * alpha; |
|
288 m_forecastItems[i]->setPos(fx, pos.y()); |
|
289 } else { |
|
290 qreal fx = height() - height() * 0.5 * alpha; |
|
291 m_forecastItems[i]->setPos(pos.x(), fx); |
|
292 } |
|
293 } |
|
294 } |
|
295 |
|
296 private: |
|
297 |
|
298 void setupScene() { |
|
299 |
|
300 m_scene.setBackgroundBrush(QBrush(palette().color(QPalette::Base))); |
|
301 |
|
302 QColor textColor = palette().color(QPalette::WindowText); |
|
303 QFont textFont = font(); |
|
304 textFont.setBold(true); |
|
305 textFont.setPointSize(textFont.pointSize() * 2); |
|
306 |
|
307 m_temperatureItem = m_scene.addText(QString(), textFont); |
|
308 m_temperatureItem->setDefaultTextColor(textColor); |
|
309 |
|
310 m_conditionItem = m_scene.addText(QString(), textFont); |
|
311 m_conditionItem->setDefaultTextColor(textColor); |
|
312 |
|
313 m_iconItem = new QGraphicsSvgItem; |
|
314 m_scene.addItem(m_iconItem); |
|
315 |
|
316 m_statusItem = m_scene.addRect(0, 0, 10, 10); |
|
317 m_statusItem->setPen(Qt::NoPen); |
|
318 m_statusItem->setBrush(Qt::NoBrush); |
|
319 m_temperatureItem->setParentItem(m_statusItem); |
|
320 m_conditionItem->setParentItem(m_statusItem); |
|
321 m_iconItem->setParentItem(m_statusItem); |
|
322 |
|
323 connect(&m_timeLine, SIGNAL(frameChanged(int)), SLOT(animate(int))); |
|
324 m_timeLine.setDuration(1100); |
|
325 m_timeLine.setFrameRange(0, 100); |
|
326 m_timeLine.setCurveShape(QTimeLine::EaseInCurve); |
|
327 } |
|
328 |
|
329 void requestTownName(QString longitude, QString latitude) { |
|
330 // http://code.google.com/intl/en/apis/maps/documentation/geocoding/index.html#ReverseGeocoding |
|
331 QUrl url("http://maps.google.com/maps/geo"); |
|
332 url.addEncodedQueryItem("q", QUrl::toPercentEncoding(latitude + "," + longitude)); |
|
333 url.addEncodedQueryItem("output", QUrl::toPercentEncoding("xml")); |
|
334 |
|
335 m_nam->get(QNetworkRequest(url)); |
|
336 |
|
337 city = QString(); |
|
338 setWindowTitle("Loading..."); |
|
339 } |
|
340 |
|
341 void requestWeatherOfTown(QString xml) { |
|
342 // Try to find <LocalityName>xxxxxx</LocalityName> |
|
343 int start = xml.indexOf("<LocalityName>"); |
|
344 int end = xml.indexOf("</LocalityName>", start); |
|
345 QString town = xml.mid(start + 14, end - start - 14); |
|
346 request(town); |
|
347 } |
|
348 |
|
349 void request(const QString &location) { |
|
350 QUrl url("http://www.google.com/ig/api"); |
|
351 url.addEncodedQueryItem("hl", "en"); |
|
352 url.addEncodedQueryItem("weather", QUrl::toPercentEncoding(location)); |
|
353 |
|
354 m_nam->get(QNetworkRequest(url)); |
|
355 |
|
356 city = QString(); |
|
357 setWindowTitle("Loading..."); |
|
358 } |
|
359 |
|
360 QString extractIcon(const QString &data) { |
|
361 if (m_icons.isEmpty()) { |
|
362 m_icons["mostly_cloudy"] = "weather-few-clouds"; |
|
363 m_icons["cloudy"] = "weather-overcast"; |
|
364 m_icons["mostly_sunny"] = "weather-sunny-very-few-clouds"; |
|
365 m_icons["partly_cloudy"] = "weather-sunny-very-few-clouds"; |
|
366 m_icons["sunny"] = "weather-sunny"; |
|
367 m_icons["flurries"] = "weather-snow"; |
|
368 m_icons["fog"] = "weather-fog"; |
|
369 m_icons["haze"] = "weather-haze"; |
|
370 m_icons["icy"] = "weather-icy"; |
|
371 m_icons["sleet"] = "weather-sleet"; |
|
372 m_icons["chance_of_sleet"] = "weather-sleet"; |
|
373 m_icons["snow"] = "weather-snow"; |
|
374 m_icons["chance_of_snow"] = "weather-snow"; |
|
375 m_icons["mist"] = "weather-showers"; |
|
376 m_icons["rain"] = "weather-showers"; |
|
377 m_icons["chance_of_rain"] = "weather-showers"; |
|
378 m_icons["storm"] = "weather-storm"; |
|
379 m_icons["chance_of_storm"] = "weather-storm"; |
|
380 m_icons["thunderstorm"] = "weather-thundershower"; |
|
381 m_icons["chance_of_tstorm"] = "weather-thundershower"; |
|
382 } |
|
383 QRegExp regex("([\\w]+).gif$"); |
|
384 if (regex.indexIn(data) != -1) { |
|
385 QString i = regex.cap(); |
|
386 i = i.left(i.length() - 4); |
|
387 QString name = m_icons.value(i); |
|
388 if (!name.isEmpty()) { |
|
389 name.prepend(":/icons/"); |
|
390 name.append(".svg"); |
|
391 return name; |
|
392 } |
|
393 } |
|
394 return QString(); |
|
395 } |
|
396 |
|
397 static QString toCelcius(QString t, QString unit) { |
|
398 bool ok = false; |
|
399 int degree = t.toInt(&ok); |
|
400 if (!ok) |
|
401 return QString(); |
|
402 if (unit != "SI") |
|
403 degree = ((degree - 32) * 5 + 8) / 9; |
|
404 return QString::number(degree) + QChar(176); |
|
405 } |
|
406 |
|
407 |
|
408 #define GET_DATA_ATTR xml.attributes().value("data").toString() |
|
409 |
|
410 void digest(const QString &data) { |
|
411 |
|
412 if (data.contains("<problem_cause")) { |
|
413 setWindowTitle("Weather Info"); |
|
414 QMessageBox::information(this, "Weather Info", "Could not find weather info"); |
|
415 return; |
|
416 } |
|
417 |
|
418 |
|
419 QColor textColor = palette().color(QPalette::WindowText); |
|
420 QString unitSystem; |
|
421 |
|
422 delete m_iconItem; |
|
423 m_iconItem = new QGraphicsSvgItem(); |
|
424 m_scene.addItem(m_iconItem); |
|
425 m_iconItem->setParentItem(m_statusItem); |
|
426 qDeleteAll(m_dayItems); |
|
427 qDeleteAll(m_conditionItems); |
|
428 qDeleteAll(m_rangeItems); |
|
429 qDeleteAll(m_forecastItems); |
|
430 m_dayItems.clear(); |
|
431 m_conditionItems.clear(); |
|
432 m_rangeItems.clear(); |
|
433 m_forecastItems.clear(); |
|
434 |
|
435 QXmlStreamReader xml(data); |
|
436 while (!xml.atEnd()) { |
|
437 xml.readNext(); |
|
438 if (xml.tokenType() == QXmlStreamReader::StartElement) { |
|
439 if (xml.name() == "city") { |
|
440 city = GET_DATA_ATTR; |
|
441 setWindowTitle(city); |
|
442 } |
|
443 if (xml.name() == "unit_system") |
|
444 unitSystem = xml.attributes().value("data").toString(); |
|
445 // Parse current weather conditions |
|
446 if (xml.name() == "current_conditions") { |
|
447 while (!xml.atEnd()) { |
|
448 xml.readNext(); |
|
449 if (xml.name() == "current_conditions") |
|
450 break; |
|
451 if (xml.tokenType() == QXmlStreamReader::StartElement) { |
|
452 if (xml.name() == "condition") { |
|
453 m_conditionItem->setPlainText(GET_DATA_ATTR); |
|
454 } |
|
455 if (xml.name() == "icon") { |
|
456 QString name = extractIcon(GET_DATA_ATTR); |
|
457 if (!name.isEmpty()) { |
|
458 delete m_iconItem; |
|
459 m_iconItem = new QGraphicsSvgItem(name); |
|
460 m_scene.addItem(m_iconItem); |
|
461 m_iconItem->setParentItem(m_statusItem); |
|
462 } |
|
463 } |
|
464 if (xml.name() == "temp_c") { |
|
465 QString s = GET_DATA_ATTR + QChar(176); |
|
466 m_temperatureItem->setPlainText(s); |
|
467 } |
|
468 } |
|
469 } |
|
470 } |
|
471 // Parse and collect the forecast conditions |
|
472 if (xml.name() == "forecast_conditions") { |
|
473 QGraphicsTextItem *dayItem = 0; |
|
474 QGraphicsSvgItem *statusItem = 0; |
|
475 QString lowT, highT; |
|
476 while (!xml.atEnd()) { |
|
477 xml.readNext(); |
|
478 if (xml.name() == "forecast_conditions") { |
|
479 if (dayItem && statusItem && |
|
480 !lowT.isEmpty() && !highT.isEmpty()) { |
|
481 m_dayItems << dayItem; |
|
482 m_conditionItems << statusItem; |
|
483 QString txt = highT + '/' + lowT; |
|
484 QGraphicsTextItem* rangeItem; |
|
485 rangeItem = m_scene.addText(txt); |
|
486 rangeItem->setDefaultTextColor(textColor); |
|
487 m_rangeItems << rangeItem; |
|
488 QGraphicsRectItem *box; |
|
489 box = m_scene.addRect(0, 0, 10, 10); |
|
490 box->setPen(Qt::NoPen); |
|
491 box->setBrush(Qt::NoBrush); |
|
492 m_forecastItems << box; |
|
493 dayItem->setParentItem(box); |
|
494 statusItem->setParentItem(box); |
|
495 rangeItem->setParentItem(box); |
|
496 } else { |
|
497 delete dayItem; |
|
498 delete statusItem; |
|
499 } |
|
500 break; |
|
501 } |
|
502 if (xml.tokenType() == QXmlStreamReader::StartElement) { |
|
503 if (xml.name() == "day_of_week") { |
|
504 QString s = GET_DATA_ATTR; |
|
505 dayItem = m_scene.addText(s.left(3)); |
|
506 dayItem->setDefaultTextColor(textColor); |
|
507 } |
|
508 if (xml.name() == "icon") { |
|
509 QString name = extractIcon(GET_DATA_ATTR); |
|
510 if (!name.isEmpty()) { |
|
511 statusItem = new QGraphicsSvgItem(name); |
|
512 m_scene.addItem(statusItem); |
|
513 } |
|
514 } |
|
515 if (xml.name() == "low") |
|
516 lowT = toCelcius(GET_DATA_ATTR, unitSystem); |
|
517 if (xml.name() == "high") |
|
518 highT = toCelcius(GET_DATA_ATTR, unitSystem); |
|
519 } |
|
520 } |
|
521 } |
|
522 |
|
523 } |
|
524 } |
|
525 |
|
526 m_timeLine.stop(); |
|
527 layoutItems(); |
|
528 animate(0); |
|
529 m_timeLine.start(); |
|
530 } |
|
531 |
|
532 void layoutItems() { |
|
533 m_scene.setSceneRect(0, 0, width() - 1, height() - 1); |
|
534 m_view->centerOn(width() / 2, height() / 2); |
|
535 if (width() > height()) |
|
536 layoutItemsLandscape(); |
|
537 else |
|
538 layoutItemsPortrait(); |
|
539 } |
|
540 |
|
541 void layoutItemsLandscape() { |
|
542 m_statusItem->setRect(0, 0, width() / 2 - 1, height() - 1); |
|
543 |
|
544 if (!m_iconItem->boundingRect().isEmpty()) { |
|
545 qreal dim = qMin(width() * 0.6, height() * 0.8); |
|
546 qreal pad = (height() - dim) / 2; |
|
547 qreal sw = dim / m_iconItem->boundingRect().width(); |
|
548 qreal sh = dim / m_iconItem->boundingRect().height(); |
|
549 m_iconItem->setTransform(QTransform().scale(sw, sh)); |
|
550 m_iconItem->setPos(1, pad); |
|
551 } |
|
552 |
|
553 m_temperatureItem->setPos(2, 2); |
|
554 qreal h = m_conditionItem->boundingRect().height(); |
|
555 m_conditionItem->setPos(10, height() - h); |
|
556 |
|
557 if (m_dayItems.count()) { |
|
558 qreal left = width() * 0.6; |
|
559 qreal h = height() / m_dayItems.count(); |
|
560 QFont textFont = font(); |
|
561 textFont.setPixelSize(static_cast<int>(h * 0.3)); |
|
562 qreal statusWidth = 0; |
|
563 qreal rangeWidth = 0; |
|
564 for (int i = 0; i < m_dayItems.count(); ++i) { |
|
565 m_dayItems[i]->setFont(textFont); |
|
566 QRectF brect = m_dayItems[i]->boundingRect(); |
|
567 statusWidth = qMax(statusWidth, brect.width()); |
|
568 brect = m_rangeItems[i]->boundingRect(); |
|
569 rangeWidth = qMax(rangeWidth, brect.width()); |
|
570 } |
|
571 qreal space = width() - left - statusWidth - rangeWidth; |
|
572 qreal dim = qMin(h, space); |
|
573 qreal pad = statusWidth + (space - dim) / 2; |
|
574 for (int i = 0; i < m_dayItems.count(); ++i) { |
|
575 qreal base = h * i; |
|
576 m_forecastItems[i]->setPos(left, base); |
|
577 m_forecastItems[i]->setRect(0, 0, width() - left, h); |
|
578 QRectF brect = m_dayItems[i]->boundingRect(); |
|
579 qreal ofs = (h - brect.height()) / 2; |
|
580 m_dayItems[i]->setPos(0, ofs); |
|
581 brect = m_rangeItems[i]->boundingRect(); |
|
582 ofs = (h - brect.height()) / 2; |
|
583 m_rangeItems[i]->setPos(width() - rangeWidth - left, ofs); |
|
584 brect = m_conditionItems[i]->boundingRect(); |
|
585 ofs = (h - dim) / 2; |
|
586 m_conditionItems[i]->setPos(pad, ofs); |
|
587 if (brect.isEmpty()) |
|
588 continue; |
|
589 qreal sw = dim / brect.width(); |
|
590 qreal sh = dim / brect.height(); |
|
591 m_conditionItems[i]->setTransform(QTransform().scale(sw, sh)); |
|
592 } |
|
593 } |
|
594 } |
|
595 |
|
596 void layoutItemsPortrait() { |
|
597 |
|
598 m_statusItem->setRect(0, 0, width() - 1, height() / 2 - 1); |
|
599 |
|
600 if (!m_iconItem->boundingRect().isEmpty()) { |
|
601 qreal dim = qMin(width() * 0.8, height() * 0.4); |
|
602 qreal ofsy = (height() / 2 - dim) / 2; |
|
603 qreal ofsx = (width() - dim) / 3; |
|
604 qreal sw = dim / m_iconItem->boundingRect().width(); |
|
605 qreal sh = dim / m_iconItem->boundingRect().height(); |
|
606 m_iconItem->setTransform(QTransform().scale(sw, sh)); |
|
607 m_iconItem->setPos(ofsx, ofsy); |
|
608 } |
|
609 |
|
610 m_temperatureItem->setPos(2, 2); |
|
611 qreal ch = m_conditionItem->boundingRect().height(); |
|
612 qreal cw = m_conditionItem->boundingRect().width(); |
|
613 m_conditionItem->setPos(width() - cw , height() / 2 - ch - 20); |
|
614 |
|
615 if (m_dayItems.count()) { |
|
616 qreal top = height() * 0.5; |
|
617 qreal w = width() / m_dayItems.count(); |
|
618 qreal statusHeight = 0; |
|
619 qreal rangeHeight = 0; |
|
620 for (int i = 0; i < m_dayItems.count(); ++i) { |
|
621 m_dayItems[i]->setFont(font()); |
|
622 QRectF brect = m_dayItems[i]->boundingRect(); |
|
623 statusHeight = qMax(statusHeight, brect.height()); |
|
624 brect = m_rangeItems[i]->boundingRect(); |
|
625 rangeHeight = qMax(rangeHeight, brect.height()); |
|
626 } |
|
627 qreal space = height() - top - statusHeight - rangeHeight; |
|
628 qreal dim = qMin(w, space); |
|
629 |
|
630 qreal boxh = statusHeight + rangeHeight + dim; |
|
631 qreal pad = (height() - top - boxh) / 2; |
|
632 |
|
633 for (int i = 0; i < m_dayItems.count(); ++i) { |
|
634 qreal base = w * i; |
|
635 m_forecastItems[i]->setPos(base, top); |
|
636 m_forecastItems[i]->setRect(0, 0, w, boxh); |
|
637 QRectF brect = m_dayItems[i]->boundingRect(); |
|
638 qreal ofs = (w - brect.width()) / 2; |
|
639 m_dayItems[i]->setPos(ofs, pad); |
|
640 |
|
641 brect = m_rangeItems[i]->boundingRect(); |
|
642 ofs = (w - brect.width()) / 2; |
|
643 m_rangeItems[i]->setPos(ofs, pad + statusHeight + dim); |
|
644 |
|
645 brect = m_conditionItems[i]->boundingRect(); |
|
646 ofs = (w - dim) / 2; |
|
647 m_conditionItems[i]->setPos(ofs, pad + statusHeight); |
|
648 if (brect.isEmpty()) |
|
649 continue; |
|
650 qreal sw = dim / brect.width(); |
|
651 qreal sh = dim / brect.height(); |
|
652 m_conditionItems[i]->setTransform(QTransform().scale(sw, sh)); |
|
653 } |
|
654 } |
|
655 } |
|
656 |
|
657 |
|
658 void resizeEvent(QResizeEvent *event) { |
|
659 Q_UNUSED(event); |
|
660 layoutItems(); |
|
661 } |
|
662 |
|
663 }; |
|
664 |
|
665 #include "weatherinfo.moc" |
|
666 |
|
667 int main(int argc, char *argv[]) |
|
668 { |
|
669 QApplication app(argc, argv); |
|
670 |
|
671 WeatherInfo w; |
|
672 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) |
|
673 w.showMaximized(); |
|
674 #else |
|
675 w.resize(520, 288); |
|
676 w.show(); |
|
677 #endif |
|
678 |
|
679 return app.exec(); |
|
680 } |