|
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 Qt Mobility Components. |
|
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 #include <QtSvg> |
|
46 |
|
47 // QtMobility API headers |
|
48 #include <qmobilityglobal.h> |
|
49 #include <qgeopositioninfosource.h> |
|
50 #include <qgeosatelliteinfosource.h> |
|
51 #include <qnmeapositioninfosource.h> |
|
52 #include <qgeopositioninfo.h> |
|
53 #include <qnetworkconfigmanager.h> |
|
54 #include <qnetworksession.h> |
|
55 |
|
56 #include "satellitedialog.h" |
|
57 #include "connectivityhelper.h" |
|
58 |
|
59 // Use the QtMobility namespace |
|
60 QTM_USE_NAMESPACE |
|
61 |
|
62 class WeatherInfo: public QMainWindow |
|
63 { |
|
64 Q_OBJECT |
|
65 |
|
66 private: |
|
67 |
|
68 QGraphicsView *m_view; |
|
69 QGraphicsScene m_scene; |
|
70 QString city; |
|
71 QGraphicsRectItem *m_statusItem; |
|
72 QGraphicsTextItem *m_temperatureItem; |
|
73 QGraphicsTextItem *m_conditionItem; |
|
74 QGraphicsSvgItem *m_iconItem; |
|
75 QList<QGraphicsRectItem*> m_forecastItems; |
|
76 QList<QGraphicsTextItem*> m_dayItems; |
|
77 QList<QGraphicsSvgItem*> m_conditionItems; |
|
78 QList<QGraphicsTextItem*> m_rangeItems; |
|
79 QTimeLine m_timeLine; |
|
80 QHash<QString, QString> m_icons; |
|
81 QNetworkAccessManager* m_nam; |
|
82 |
|
83 bool m_usingLogFile; |
|
84 bool m_gpsWeather; |
|
85 QGeoPositionInfoSource* m_location; |
|
86 QNetworkSession* m_session; |
|
87 ConnectivityHelper* m_connectivityHelper; |
|
88 QGeoCoordinate m_coordinate; |
|
89 |
|
90 public: |
|
91 WeatherInfo(QWidget *parent = 0): QMainWindow(parent) { |
|
92 |
|
93 m_view = new QGraphicsView(this); |
|
94 setCentralWidget(m_view); |
|
95 |
|
96 setupScene(); |
|
97 m_view->setScene(&m_scene); |
|
98 m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
|
99 m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
|
100 |
|
101 m_view->setFrameShape(QFrame::NoFrame); |
|
102 setWindowTitle("Weather Info"); |
|
103 |
|
104 QAction *your = new QAction("Your weather", this); |
|
105 connect(your, SIGNAL(triggered()), SLOT(yourWeather())); |
|
106 addAction(your); |
|
107 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) |
|
108 menuBar()->addAction(your); |
|
109 #endif |
|
110 |
|
111 QStringList cities; |
|
112 cities << "Helsinki"; |
|
113 cities << "Oslo"; |
|
114 cities << "Berlin"; |
|
115 cities << "Brisbane"; |
|
116 cities << "San Diego"; |
|
117 for (int i = 0; i < cities.count(); ++i) { |
|
118 QAction *action = new QAction(cities[i], this); |
|
119 connect(action, SIGNAL(triggered()), SLOT(chooseCity())); |
|
120 addAction(action); |
|
121 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_WINCE) |
|
122 menuBar()->addAction(action); |
|
123 #endif |
|
124 } |
|
125 |
|
126 #if defined(Q_OS_WINCE) |
|
127 QAction *exitAction = new QAction(tr("Exit"), this); |
|
128 connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit())); |
|
129 addAction(exitAction); |
|
130 menuBar()->addAction(exitAction); |
|
131 #endif |
|
132 |
|
133 setContextMenuPolicy(Qt::ActionsContextMenu); |
|
134 |
|
135 // QNetworkAccessManager |
|
136 m_nam = new QNetworkAccessManager(this); |
|
137 connect(m_nam, SIGNAL(finished(QNetworkReply*)), |
|
138 this, SLOT(handleNetworkData(QNetworkReply*))); |
|
139 |
|
140 // Don't use the GPS until we need it |
|
141 m_location = 0; |
|
142 m_gpsWeather = false; |
|
143 m_usingLogFile = false; |
|
144 |
|
145 QTimer::singleShot(0, this, SLOT(delayedInit())); |
|
146 } |
|
147 |
|
148 ~WeatherInfo() { |
|
149 if (m_location) |
|
150 m_location->stopUpdates(); |
|
151 m_session->close(); |
|
152 } |
|
153 |
|
154 private slots: |
|
155 |
|
156 void delayedInit() { |
|
157 // Set Internet Access Point |
|
158 QNetworkConfigurationManager manager; |
|
159 const bool canStartIAP = (manager.capabilities() |
|
160 & QNetworkConfigurationManager::CanStartAndStopInterfaces); |
|
161 // Is there default access point, use it |
|
162 QNetworkConfiguration cfg = manager.defaultConfiguration(); |
|
163 if (!cfg.isValid() || (!canStartIAP && cfg.state() != QNetworkConfiguration::Active)) { |
|
164 QMessageBox::information(this, tr("Weather Info"), tr( |
|
165 "Available Access Points not found.")); |
|
166 return; |
|
167 } |
|
168 m_session = new QNetworkSession(cfg, this); |
|
169 m_connectivityHelper = new ConnectivityHelper(m_session, this); |
|
170 connect(m_session, SIGNAL(opened()), this, SLOT(networkSessionOpened())); |
|
171 connect(m_connectivityHelper, SIGNAL(networkingCancelled()), qApp, SLOT(quit())); |
|
172 |
|
173 m_session->open(); |
|
174 } |
|
175 |
|
176 void networkSessionOpened() { |
|
177 m_gpsWeather = false; |
|
178 request("Helsinki"); |
|
179 } |
|
180 |
|
181 void yourWeather() { |
|
182 m_gpsWeather = true; |
|
183 |
|
184 if (!m_location) { |
|
185 // QGeoPositionInfoSource |
|
186 m_location = QGeoPositionInfoSource::createDefaultSource(this); |
|
187 |
|
188 if (!m_location) { |
|
189 QNmeaPositionInfoSource *nmeaLocation = |
|
190 new QNmeaPositionInfoSource(QNmeaPositionInfoSource::SimulationMode, this); |
|
191 QFile *logFile = new QFile(QApplication::applicationDirPath() + QDir::separator() |
|
192 + "nmealog.txt", this); |
|
193 nmeaLocation->setDevice(logFile); |
|
194 m_location = nmeaLocation; |
|
195 |
|
196 m_usingLogFile = true; |
|
197 |
|
198 QMessageBox::information(this, tr("Weather Info"), |
|
199 tr("No GPS support detected, using GPS data from a sample log file instead.")); |
|
200 } |
|
201 } |
|
202 |
|
203 if (!m_usingLogFile) { |
|
204 QGeoSatelliteInfoSource *m_satellite = QGeoSatelliteInfoSource::createDefaultSource(this); |
|
205 |
|
206 if (m_satellite) { |
|
207 SatelliteDialog *dialog = new SatelliteDialog(this, |
|
208 30, |
|
209 SatelliteDialog::ExitOnFixOrCancel, |
|
210 SatelliteDialog::OrderByPrnNumber, |
|
211 SatelliteDialog::ScaleToMaxPossible); |
|
212 |
|
213 dialog->connectSources(m_location, m_satellite); |
|
214 |
|
215 m_location->startUpdates(); |
|
216 m_satellite->startUpdates(); |
|
217 |
|
218 dialog->exec(); |
|
219 |
|
220 m_location->stopUpdates(); |
|
221 m_satellite->stopUpdates(); |
|
222 } |
|
223 } |
|
224 |
|
225 // Listen gps position changes |
|
226 connect(m_location, SIGNAL(positionUpdated(QGeoPositionInfo)), this, |
|
227 SLOT(positionUpdated(QGeoPositionInfo))); |
|
228 |
|
229 // Start listening GPS position updates |
|
230 m_location->startUpdates(); |
|
231 } |
|
232 |
|
233 void positionUpdated(QGeoPositionInfo gpsPos) { |
|
234 if (m_gpsWeather) { |
|
235 m_coordinate = gpsPos.coordinate(); |
|
236 if (m_coordinate.isValid()) { |
|
237 QString longitude; |
|
238 longitude.setNum(m_coordinate.longitude()); |
|
239 QString latitude; |
|
240 latitude.setNum(m_coordinate.latitude()); |
|
241 requestTownName(longitude, latitude); |
|
242 m_gpsWeather = false; |
|
243 m_location->stopUpdates(); |
|
244 } else { |
|
245 QMessageBox::information(this, "Weather Info", "Waiting for your GPS position..."); |
|
246 } |
|
247 } |
|
248 } |
|
249 |
|
250 void chooseCity() { |
|
251 QAction *action = qobject_cast<QAction*>(sender()); |
|
252 if (action) { |
|
253 if (m_location) |
|
254 m_location->stopUpdates(); |
|
255 m_gpsWeather = false; |
|
256 request(action->text()); |
|
257 } |
|
258 } |
|
259 |
|
260 void handleNetworkData(QNetworkReply *networkReply) { |
|
261 QUrl url = networkReply->url(); |
|
262 if (!networkReply->error()) { |
|
263 QString data = QString::fromUtf8(networkReply->readAll()); |
|
264 qDebug() << data; |
|
265 if (data.contains("<LocalityName>", Qt::CaseInsensitive)) { |
|
266 requestWeatherOfTown(data); |
|
267 } else { |
|
268 digest(data); |
|
269 } |
|
270 } |
|
271 networkReply->deleteLater(); |
|
272 } |
|
273 |
|
274 void animate(int frame) { |
|
275 qreal progress = static_cast<qreal>(frame) / 100; |
|
276 #if QT_VERSION >= 0x040500 |
|
277 m_iconItem->setOpacity(progress); |
|
278 #endif |
|
279 qreal hw = width() / 2.0; |
|
280 m_statusItem->setPos(-hw + hw * progress, 0); |
|
281 for (int i = 0; i < m_forecastItems.count(); ++i) { |
|
282 qreal ofs = i * 0.5 / m_forecastItems.count(); |
|
283 qreal alpha = qBound(qreal(0), 2 * (progress - ofs), qreal(1)); |
|
284 #if QT_VERSION >= 0x040500 |
|
285 m_conditionItems[i]->setOpacity(alpha); |
|
286 #endif |
|
287 QPointF pos = m_forecastItems[i]->pos(); |
|
288 if (width() > height()) { |
|
289 qreal fx = width() - width() * 0.4 * alpha; |
|
290 m_forecastItems[i]->setPos(fx, pos.y()); |
|
291 } else { |
|
292 qreal fx = height() - height() * 0.5 * alpha; |
|
293 m_forecastItems[i]->setPos(pos.x(), fx); |
|
294 } |
|
295 } |
|
296 } |
|
297 |
|
298 private: |
|
299 |
|
300 void setupScene() { |
|
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) |
|
673 w.showMaximized(); |
|
674 #else |
|
675 w.resize(520, 288); |
|
676 w.show(); |
|
677 #endif |
|
678 |
|
679 return app.exec(); |
|
680 } |