demos/embedded/weatherinfo/weatherinfo.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
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 #include <QtSvg>
       
    46 
       
    47 #if defined (Q_OS_SYMBIAN)
       
    48 #include "sym_iap_util.h"
       
    49 #endif
       
    50 
       
    51 class WeatherInfo: public QMainWindow
       
    52 {
       
    53     Q_OBJECT
       
    54 
       
    55 private:
       
    56 
       
    57     QGraphicsView *m_view;
       
    58     QGraphicsScene m_scene;
       
    59     QString city;
       
    60     QGraphicsRectItem *m_statusItem;
       
    61     QGraphicsTextItem *m_temperatureItem;
       
    62     QGraphicsTextItem *m_conditionItem;
       
    63     QGraphicsSvgItem *m_iconItem;
       
    64     QList<QGraphicsRectItem*> m_forecastItems;
       
    65     QList<QGraphicsTextItem*> m_dayItems;
       
    66     QList<QGraphicsSvgItem*> m_conditionItems;
       
    67     QList<QGraphicsTextItem*> m_rangeItems;
       
    68     QTimeLine m_timeLine;
       
    69     QHash<QString, QString> m_icons;
       
    70 
       
    71 public:
       
    72     WeatherInfo(QWidget *parent = 0): QMainWindow(parent) {
       
    73 
       
    74         m_view = new QGraphicsView(this);
       
    75         setCentralWidget(m_view);
       
    76 
       
    77         setupScene();
       
    78         m_view->setScene(&m_scene);
       
    79         m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
       
    80         m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
       
    81 
       
    82         m_view->setFrameShape(QFrame::NoFrame);
       
    83         setWindowTitle("Weather Info");
       
    84 
       
    85         QStringList cities;
       
    86         cities << "Oslo";
       
    87         cities << "Berlin";
       
    88         cities << "Brisbane";
       
    89         cities << "Helsinki";
       
    90         cities << "San Diego";
       
    91         for (int i = 0; i < cities.count(); ++i) {
       
    92             QAction *action = new QAction(cities[i], this);
       
    93             connect(action, SIGNAL(triggered()), SLOT(chooseCity()));
       
    94             addAction(action);
       
    95 #if defined(Q_OS_SYMBIAN)
       
    96             menuBar()->addAction(action);
       
    97 #endif
       
    98         }
       
    99         setContextMenuPolicy(Qt::ActionsContextMenu);
       
   100 
       
   101         QTimer::singleShot(0, this, SLOT(delayedInit()));
       
   102     }
       
   103 
       
   104 private slots:
       
   105     void delayedInit() {
       
   106 #if defined(Q_OS_SYMBIAN)
       
   107         qt_SetDefaultIap();
       
   108 #else
       
   109         request("Oslo");
       
   110 #endif
       
   111     }
       
   112 
       
   113 private slots:
       
   114 
       
   115     void chooseCity() {
       
   116         QAction *action = qobject_cast<QAction*>(sender());
       
   117         if (action)
       
   118             request(action->text());
       
   119     }
       
   120 
       
   121     void handleNetworkData(QNetworkReply *networkReply) {
       
   122         QUrl url = networkReply->url();
       
   123         if (!networkReply->error())
       
   124             digest(QString::fromUtf8(networkReply->readAll()));
       
   125         networkReply->deleteLater();
       
   126         networkReply->manager()->deleteLater();
       
   127     }
       
   128 
       
   129     void animate(int frame) {
       
   130         qreal progress = static_cast<qreal>(frame) / 100;
       
   131 #if QT_VERSION >= 0x040500
       
   132         m_iconItem->setOpacity(progress);
       
   133 #endif
       
   134         qreal hw = width() / 2.0;
       
   135         m_statusItem->setPos(-hw + hw * progress, 0);
       
   136         for (int i = 0; i < m_forecastItems.count(); ++i) {
       
   137             qreal ofs = i * 0.5 / m_forecastItems.count();
       
   138             qreal alpha = qBound(qreal(0), 2 * (progress - ofs), qreal(1));
       
   139 #if QT_VERSION >= 0x040500
       
   140             m_conditionItems[i]->setOpacity(alpha);
       
   141 #endif
       
   142             QPointF pos = m_forecastItems[i]->pos();
       
   143             if (width() > height()) {
       
   144                 qreal fx = width() - width() * 0.4 * alpha;
       
   145                 m_forecastItems[i]->setPos(fx, pos.y());
       
   146             } else {
       
   147                 qreal fx = height() - height() * 0.5 * alpha;
       
   148                 m_forecastItems[i]->setPos(pos.x(), fx);
       
   149             }
       
   150         }
       
   151     }
       
   152 
       
   153 private:
       
   154 
       
   155     void setupScene() {
       
   156 
       
   157         QColor textColor = palette().color(QPalette::WindowText);
       
   158         QFont textFont = font();
       
   159         textFont.setBold(true);
       
   160         textFont.setPointSize(textFont.pointSize() * 2);
       
   161 
       
   162         m_temperatureItem = m_scene.addText(QString(), textFont);
       
   163         m_temperatureItem->setDefaultTextColor(textColor);
       
   164 
       
   165         m_conditionItem = m_scene.addText(QString(), textFont);
       
   166         m_conditionItem->setDefaultTextColor(textColor);
       
   167 
       
   168         m_iconItem = new QGraphicsSvgItem;
       
   169         m_scene.addItem(m_iconItem);
       
   170 
       
   171         m_statusItem = m_scene.addRect(0, 0, 10, 10);
       
   172         m_statusItem->setPen(Qt::NoPen);
       
   173         m_statusItem->setBrush(Qt::NoBrush);
       
   174         m_temperatureItem->setParentItem(m_statusItem);
       
   175         m_conditionItem->setParentItem(m_statusItem);
       
   176         m_iconItem->setParentItem(m_statusItem);
       
   177 
       
   178         connect(&m_timeLine, SIGNAL(frameChanged(int)), SLOT(animate(int)));
       
   179         m_timeLine.setDuration(1100);
       
   180         m_timeLine.setFrameRange(0, 100);
       
   181         m_timeLine.setCurveShape(QTimeLine::EaseInCurve);
       
   182     }
       
   183 
       
   184     void request(const QString &location) {
       
   185         QUrl url("http://www.google.com/ig/api");
       
   186         url.addEncodedQueryItem("hl", "en");
       
   187         url.addEncodedQueryItem("weather", QUrl::toPercentEncoding(location));
       
   188 
       
   189         QNetworkAccessManager *manager = new QNetworkAccessManager(this);
       
   190         connect(manager, SIGNAL(finished(QNetworkReply*)),
       
   191                 this, SLOT(handleNetworkData(QNetworkReply*)));
       
   192         manager->get(QNetworkRequest(url));
       
   193 
       
   194         city = QString();
       
   195         setWindowTitle("Loading...");
       
   196     }
       
   197 
       
   198     QString extractIcon(const QString &data) {
       
   199         if (m_icons.isEmpty()) {
       
   200             m_icons["mostly_cloudy"]    = "weather-few-clouds";
       
   201             m_icons["cloudy"]           = "weather-overcast";
       
   202             m_icons["mostly_sunny"]     = "weather-sunny-very-few-clouds";
       
   203             m_icons["partly_cloudy"]    = "weather-sunny-very-few-clouds";
       
   204             m_icons["sunny"]            = "weather-sunny";
       
   205             m_icons["flurries"]         = "weather-snow";
       
   206             m_icons["fog"]              = "weather-fog";
       
   207             m_icons["haze"]             = "weather-haze";
       
   208             m_icons["icy"]              = "weather-icy";
       
   209             m_icons["sleet"]            = "weather-sleet";
       
   210             m_icons["chance_of_sleet"]  = "weather-sleet";
       
   211             m_icons["snow"]             = "weather-snow";
       
   212             m_icons["chance_of_snow"]   = "weather-snow";
       
   213             m_icons["mist"]             = "weather-showers";
       
   214             m_icons["rain"]             = "weather-showers";
       
   215             m_icons["chance_of_rain"]   = "weather-showers";
       
   216             m_icons["storm"]            = "weather-storm";
       
   217             m_icons["chance_of_storm"]  = "weather-storm";
       
   218             m_icons["thunderstorm"]     = "weather-thundershower";
       
   219             m_icons["chance_of_tstorm"] = "weather-thundershower";
       
   220         }
       
   221         QRegExp regex("([\\w]+).gif$");
       
   222         if (regex.indexIn(data) != -1) {
       
   223             QString i = regex.cap();
       
   224             i = i.left(i.length() - 4);
       
   225             QString name = m_icons.value(i);
       
   226             if (!name.isEmpty()) {
       
   227                 name.prepend(":/icons/");
       
   228                 name.append(".svg");
       
   229                 return name;
       
   230             }
       
   231         }
       
   232         return QString();
       
   233     }
       
   234 
       
   235     static QString toCelcius(QString t, QString unit) {
       
   236         bool ok = false;
       
   237         int degree = t.toInt(&ok);
       
   238         if (!ok)
       
   239             return QString();
       
   240         if (unit != "SI")
       
   241             degree = ((degree - 32) * 5 + 8)/ 9;
       
   242         return QString::number(degree) + QChar(176);
       
   243     }
       
   244 
       
   245 
       
   246 #define GET_DATA_ATTR xml.attributes().value("data").toString()
       
   247 
       
   248     void digest(const QString &data) {
       
   249 
       
   250         QColor textColor = palette().color(QPalette::WindowText);
       
   251         QString unitSystem;
       
   252 
       
   253         delete m_iconItem;
       
   254         m_iconItem = new QGraphicsSvgItem();
       
   255         m_scene.addItem(m_iconItem);
       
   256         m_iconItem->setParentItem(m_statusItem);
       
   257         qDeleteAll(m_dayItems);
       
   258         qDeleteAll(m_conditionItems);
       
   259         qDeleteAll(m_rangeItems);
       
   260         qDeleteAll(m_forecastItems);
       
   261         m_dayItems.clear();
       
   262         m_conditionItems.clear();
       
   263         m_rangeItems.clear();
       
   264         m_forecastItems.clear();
       
   265 
       
   266         QXmlStreamReader xml(data);
       
   267         while (!xml.atEnd()) {
       
   268             xml.readNext();
       
   269             if (xml.tokenType() == QXmlStreamReader::StartElement) {
       
   270                 if (xml.name() == "city") {
       
   271                     city = GET_DATA_ATTR;
       
   272                     setWindowTitle(city);
       
   273                 }
       
   274                 if (xml.name() == "unit_system")
       
   275                     unitSystem = xml.attributes().value("data").toString();
       
   276                 // Parse current weather conditions
       
   277                 if (xml.name() == "current_conditions") {
       
   278                     while (!xml.atEnd()) {
       
   279                         xml.readNext();
       
   280                         if (xml.name() == "current_conditions")
       
   281                             break;
       
   282                         if (xml.tokenType() == QXmlStreamReader::StartElement) {
       
   283                             if (xml.name() == "condition") {
       
   284                                 m_conditionItem->setPlainText(GET_DATA_ATTR);
       
   285                             }
       
   286                             if (xml.name() == "icon") {
       
   287                                 QString name = extractIcon(GET_DATA_ATTR);
       
   288                                 if (!name.isEmpty()) {
       
   289                                     delete m_iconItem;
       
   290                                     m_iconItem = new QGraphicsSvgItem(name);
       
   291                                     m_scene.addItem(m_iconItem);
       
   292                                     m_iconItem->setParentItem(m_statusItem);
       
   293                                 }
       
   294                             }
       
   295                             if (xml.name() == "temp_c") {
       
   296                                 QString s = GET_DATA_ATTR + QChar(176);
       
   297                                 m_temperatureItem->setPlainText(s);
       
   298                             }
       
   299                         }
       
   300                     }
       
   301                 }
       
   302                 // Parse and collect the forecast conditions
       
   303                 if (xml.name() == "forecast_conditions") {
       
   304                     QGraphicsTextItem *dayItem  = 0;
       
   305                     QGraphicsSvgItem *statusItem = 0;
       
   306                     QString lowT, highT;
       
   307                     while (!xml.atEnd()) {
       
   308                         xml.readNext();
       
   309                         if (xml.name() == "forecast_conditions") {
       
   310                             if (dayItem && statusItem &&
       
   311                                 !lowT.isEmpty() && !highT.isEmpty()) {
       
   312                                 m_dayItems << dayItem;
       
   313                                 m_conditionItems << statusItem;
       
   314                                 QString txt = highT + '/' + lowT;
       
   315                                 QGraphicsTextItem* rangeItem;
       
   316                                 rangeItem = m_scene.addText(txt);
       
   317                                 rangeItem->setDefaultTextColor(textColor);
       
   318                                 m_rangeItems << rangeItem;
       
   319                                 QGraphicsRectItem *box;
       
   320                                 box = m_scene.addRect(0, 0, 10, 10);
       
   321                                 box->setPen(Qt::NoPen);
       
   322                                 box->setBrush(Qt::NoBrush);
       
   323                                 m_forecastItems << box;
       
   324                                 dayItem->setParentItem(box);
       
   325                                 statusItem->setParentItem(box);
       
   326                                 rangeItem->setParentItem(box);
       
   327                             } else {
       
   328                                 delete dayItem;
       
   329                                 delete statusItem;
       
   330                             }
       
   331                             break;
       
   332                         }
       
   333                         if (xml.tokenType() == QXmlStreamReader::StartElement) {
       
   334                             if (xml.name() == "day_of_week") {
       
   335                                 QString s = GET_DATA_ATTR;
       
   336                                 dayItem = m_scene.addText(s.left(3));
       
   337                                 dayItem->setDefaultTextColor(textColor);
       
   338                             }
       
   339                             if (xml.name() == "icon") {
       
   340                                 QString name = extractIcon(GET_DATA_ATTR);
       
   341                                 if (!name.isEmpty()) {
       
   342                                     statusItem = new QGraphicsSvgItem(name);
       
   343                                     m_scene.addItem(statusItem);
       
   344                                 }
       
   345                             }
       
   346                             if (xml.name() == "low")
       
   347                                 lowT = toCelcius(GET_DATA_ATTR, unitSystem);
       
   348                             if (xml.name() == "high")
       
   349                                 highT = toCelcius(GET_DATA_ATTR, unitSystem);
       
   350                         }
       
   351                     }
       
   352                 }
       
   353 
       
   354             }
       
   355         }
       
   356 
       
   357         m_timeLine.stop();
       
   358         layoutItems();
       
   359         animate(0);
       
   360         m_timeLine.start();
       
   361     }
       
   362 
       
   363     void layoutItems() {
       
   364         m_scene.setSceneRect(0, 0, width() - 1, height() - 1);
       
   365         m_view->centerOn(width() / 2, height() / 2);
       
   366         if (width() > height())
       
   367             layoutItemsLandscape();
       
   368         else
       
   369             layoutItemsPortrait();
       
   370     }
       
   371 
       
   372     void layoutItemsLandscape() {
       
   373         m_statusItem->setRect(0, 0, width() / 2 - 1, height() - 1);
       
   374 
       
   375         if (!m_iconItem->boundingRect().isEmpty()) {
       
   376             qreal dim = qMin(width() * 0.6, height() * 0.8);
       
   377             qreal pad = (height()  - dim) / 2;
       
   378             qreal sw = dim / m_iconItem->boundingRect().width();
       
   379             qreal sh = dim / m_iconItem->boundingRect().height();
       
   380             m_iconItem->setTransform(QTransform().scale(sw, sh));
       
   381             m_iconItem->setPos(1, pad);
       
   382         }
       
   383 
       
   384         m_temperatureItem->setPos(2, 2);
       
   385         qreal h = m_conditionItem->boundingRect().height();
       
   386         m_conditionItem->setPos(10, height() - h);
       
   387 
       
   388         if (m_dayItems.count()) {
       
   389             qreal left = width() * 0.6;
       
   390             qreal h = height() / m_dayItems.count();
       
   391             QFont textFont = font();
       
   392             textFont.setPixelSize(static_cast<int>(h * 0.3));
       
   393             qreal statusWidth = 0;
       
   394             qreal rangeWidth = 0;
       
   395             for (int i = 0; i < m_dayItems.count(); ++i) {
       
   396                 m_dayItems[i]->setFont(textFont);
       
   397                 QRectF brect = m_dayItems[i]->boundingRect();
       
   398                 statusWidth = qMax(statusWidth, brect.width());
       
   399                 brect = m_rangeItems[i]->boundingRect();
       
   400                 rangeWidth = qMax(rangeWidth, brect.width());
       
   401             }
       
   402             qreal space = width() - left - statusWidth - rangeWidth;
       
   403             qreal dim = qMin(h, space);
       
   404             qreal pad = statusWidth + (space  - dim) / 2;
       
   405             for (int i = 0; i < m_dayItems.count(); ++i) {
       
   406                 qreal base = h * i;
       
   407                 m_forecastItems[i]->setPos(left, base);
       
   408                 m_forecastItems[i]->setRect(0, 0, width() - left, h);
       
   409                 QRectF brect = m_dayItems[i]->boundingRect();
       
   410                 qreal ofs = (h - brect.height()) / 2;
       
   411                 m_dayItems[i]->setPos(0, ofs);
       
   412                 brect = m_rangeItems[i]->boundingRect();
       
   413                 ofs = (h - brect.height()) / 2;
       
   414                 m_rangeItems[i]->setPos(width() - rangeWidth - left, ofs);
       
   415                 brect = m_conditionItems[i]->boundingRect();
       
   416                 ofs = (h - dim) / 2;
       
   417                 m_conditionItems[i]->setPos(pad, ofs);
       
   418                 if (brect.isEmpty())
       
   419                     continue;
       
   420                 qreal sw = dim / brect.width();
       
   421                 qreal sh = dim / brect.height();
       
   422                 m_conditionItems[i]->setTransform(QTransform().scale(sw, sh));
       
   423             }
       
   424         }
       
   425     }
       
   426 
       
   427     void layoutItemsPortrait() {
       
   428 
       
   429         m_statusItem->setRect(0, 0, width() - 1, height() / 2 - 1);
       
   430 
       
   431         if (!m_iconItem->boundingRect().isEmpty()) {
       
   432             qreal dim = qMin(width() * 0.8, height() * 0.4);
       
   433             qreal ofsy = (height() / 2  - dim) / 2;
       
   434             qreal ofsx = (width() - dim) / 3;
       
   435             qreal sw = dim / m_iconItem->boundingRect().width();
       
   436             qreal sh = dim / m_iconItem->boundingRect().height();
       
   437             m_iconItem->setTransform(QTransform().scale(sw, sh));
       
   438             m_iconItem->setPos(ofsx, ofsy);
       
   439         }
       
   440 
       
   441         m_temperatureItem->setPos(2, 2);
       
   442         qreal ch = m_conditionItem->boundingRect().height();
       
   443         qreal cw = m_conditionItem->boundingRect().width();
       
   444         m_conditionItem->setPos(width() - cw , height() / 2 - ch - 20);
       
   445 
       
   446         if (m_dayItems.count()) {
       
   447             qreal top = height() * 0.5;
       
   448             qreal w = width() / m_dayItems.count();
       
   449             qreal statusHeight = 0;
       
   450             qreal rangeHeight = 0;
       
   451             for (int i = 0; i < m_dayItems.count(); ++i) {
       
   452                 m_dayItems[i]->setFont(font());
       
   453                 QRectF brect = m_dayItems[i]->boundingRect();
       
   454                 statusHeight = qMax(statusHeight, brect.height());
       
   455                 brect = m_rangeItems[i]->boundingRect();
       
   456                 rangeHeight = qMax(rangeHeight, brect.height());
       
   457             }
       
   458             qreal space = height() - top - statusHeight - rangeHeight;
       
   459             qreal dim = qMin(w, space);
       
   460 
       
   461             qreal boxh = statusHeight + rangeHeight + dim;
       
   462             qreal pad = (height() - top - boxh) / 2;
       
   463 
       
   464             for (int i = 0; i < m_dayItems.count(); ++i) {
       
   465                 qreal base = w * i;
       
   466                 m_forecastItems[i]->setPos(base, top);
       
   467                 m_forecastItems[i]->setRect(0, 0, w, boxh);
       
   468                 QRectF brect = m_dayItems[i]->boundingRect();
       
   469                 qreal ofs = (w - brect.width()) / 2;
       
   470                 m_dayItems[i]->setPos(ofs, pad);
       
   471 
       
   472                 brect = m_rangeItems[i]->boundingRect();
       
   473                 ofs = (w - brect.width()) / 2;
       
   474                 m_rangeItems[i]->setPos(ofs, pad + statusHeight + dim);
       
   475 
       
   476                 brect = m_conditionItems[i]->boundingRect();
       
   477                 ofs = (w - dim) / 2;
       
   478                 m_conditionItems[i]->setPos(ofs, pad + statusHeight);
       
   479                 if (brect.isEmpty())
       
   480                     continue;
       
   481                 qreal sw = dim / brect.width();
       
   482                 qreal sh = dim / brect.height();
       
   483                 m_conditionItems[i]->setTransform(QTransform().scale(sw, sh));
       
   484             }
       
   485         }
       
   486     }
       
   487 
       
   488 
       
   489     void resizeEvent(QResizeEvent *event) {
       
   490         Q_UNUSED(event);
       
   491         layoutItems();
       
   492     }
       
   493 
       
   494 };
       
   495 
       
   496 #include "weatherinfo.moc"
       
   497 
       
   498 int main(int argc, char *argv[])
       
   499 {
       
   500     QApplication app(argc, argv);
       
   501 
       
   502     WeatherInfo w;
       
   503 #if defined(Q_OS_SYMBIAN)
       
   504     w.showMaximized();
       
   505 #else
       
   506     w.resize(520, 288);
       
   507     w.show();
       
   508 #endif
       
   509 
       
   510     return app.exec();
       
   511 }