diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/applicationinfo.cpp | 193 | ||||
-rw-r--r-- | src/applicationinfo.h | 139 | ||||
-rw-r--r-- | src/applicationpaths.h | 75 | ||||
-rw-r--r-- | src/cities.cpp | 164 | ||||
-rw-r--r-- | src/cities.h | 92 | ||||
-rw-r--r-- | src/citieslistmodel.cpp | 125 | ||||
-rw-r--r-- | src/citieslistmodel.h | 84 | ||||
-rw-r--r-- | src/citymodel.cpp | 302 | ||||
-rw-r--r-- | src/citymodel.h | 138 | ||||
-rw-r--r-- | src/daymodel.cpp | 149 | ||||
-rw-r--r-- | src/daymodel.h | 116 | ||||
-rw-r--r-- | src/main.cpp | 138 | ||||
-rw-r--r-- | src/src.pri | 16 | ||||
-rw-r--r-- | src/weatherimageprovider.h | 72 |
14 files changed, 1803 insertions, 0 deletions
diff --git a/src/applicationinfo.cpp b/src/applicationinfo.cpp new file mode 100644 index 0000000..dcbc54f --- /dev/null +++ b/src/applicationinfo.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QFile> +#include <QtCore/qmath.h> +#include <QtCore/QRegExp> +#include <QtCore/QUrl> +#include <QtCore/QUrlQuery> +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> +#include <QtNetwork/QNetworkReply> +#include <QtNetwork/QNetworkRequest> + +#include "applicationinfo.h" +#include "weatherimageprovider.h" +#include <QDebug> + +ApplicationInfo::ApplicationInfo(WeatherImageProvider *provider) + : imageProvider(provider) +{ + + m_isMobile = false; +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_BLACKBERRY) + m_isMobile = true; +#endif + + m_colors = new QQmlPropertyMap(this); + m_colors->insert(QLatin1String("white"), QVariant("#ffffff")); + m_colors->insert(QLatin1String("smokeGray"), QVariant("#eeeeee")); + m_colors->insert(QLatin1String("paleGray"), QVariant("#d7d6d5")); + m_colors->insert(QLatin1String("lightGray"), QVariant("#aeadac")); + m_colors->insert(QLatin1String("darkGray"), QVariant("#35322f")); + m_colors->insert(QLatin1String("mediumGray"), QVariant("#5d5b59")); + m_colors->insert(QLatin1String("doubleDarkGray"), QVariant("#1e1b18")); + m_colors->insert(QLatin1String("blue"), QVariant("#14aaff")); + m_colors->insert(QLatin1String("darkBlue"), QVariant("#14148c")); + + m_constants = new QQmlPropertyMap(this); + m_constants->insert(QLatin1String("isMobile"), QVariant(m_isMobile)); + m_constants->insert(QLatin1String("errorLoadingImage"), QVariant(tr("Error loading image - Host not found or unreachable"))); + + manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); + m_citiesFound = new CitiesListModel(this); + + QRect rect = qApp->primaryScreen()->geometry(); + m_ratio = m_isMobile ? qMin(qMax(rect.width(), rect.height())/1136. , qMin(rect.width(), rect.height())/640.) : 1; + m_sliderHandleWidth = getSizeWithRatio(70); + m_sliderHandleHeight = getSizeWithRatio(87); + m_sliderGapWidth = getSizeWithRatio(100); + m_isPortraitMode = m_isMobile ? rect.height() > rect.width() : false; + m_hMargin = m_isPortraitMode ? 20 * ratio() : 50 * ratio(); + m_applicationWidth = m_isMobile ? rect.width() : 1120; + + m_currentIndexDay = -1; + + if (m_isMobile) + connect(qApp->primaryScreen(), SIGNAL(physicalSizeChanged(QSizeF)), this, SLOT(notifyPortraitMode())); + + // Search in English + // In order to use yr.no weather data service, refer to their terms + // and conditions of use. http://om.yr.no/verdata/free-weather-data/ + QUrl searchUrl2("http://www.yr.no/_/settspr.aspx"); + QUrlQuery query2; + query2.addQueryItem("spr", "eng"); + query2.addQueryItem("redir", "/"); + searchUrl2.setQuery(query2); + manager->get(QNetworkRequest(searchUrl2)); +} + +void ApplicationInfo::setCurrentCityModel(CityModel *model) +{ + if (model != m_currentCityModel) + { + m_currentCityModel = model; + emit currentCityModelChanged(); + } +} + +void ApplicationInfo::setCurrentIndexDay(const int index) +{ + if (index != m_currentIndexDay) { + m_currentIndexDay = index; + emit currentIndexDayChanged(); + } +} + +void ApplicationInfo::setApplicationWidth(const int newWidth) +{ + if (newWidth != m_applicationWidth) { + m_applicationWidth = newWidth; + emit applicationWidthChanged(); + } +} + +QString ApplicationInfo::getImagePath(const QString image) +{ + return QString("qrc:/weatherapp/qml/touch/images/%1").arg(image); +} + +void ApplicationInfo::notifyPortraitMode() +{ + int width = qApp->primaryScreen()->geometry().width(); + int height = qApp->primaryScreen()->geometry().height(); + setIsPortraitMode(height > width); +} + +void ApplicationInfo::setIsPortraitMode(const bool newMode) +{ + if (m_isPortraitMode != newMode) { + m_isPortraitMode = newMode; + m_hMargin = m_isPortraitMode ? 20 * ratio() : 50 * ratio(); + emit portraitModeChanged(); + emit hMarginChanged(); + } +} + +void ApplicationInfo::queryCities(const QString input) +{ + if (input.isEmpty()) + return; + // In order to use yr.no weather data service, refer to their terms + // and conditions of use. http://om.yr.no/verdata/free-weather-data/ + QUrl searchUrl("http://www.yr.no/_/websvc/jsonforslagsboks.aspx"); + QUrlQuery query; + query.addQueryItem("s", input); + searchUrl.setQuery(query); + manager->get(QNetworkRequest(searchUrl)); + m_citiesFound->clear(); + waitForCitiesQueryReply(tr("Waiting for cities, network may be slow...")); +} + +void ApplicationInfo::replyFinished(QNetworkReply *reply) +{ + waitForCitiesQueryReply(""); + if (reply->request().url().query() != "spr=eng&redir=/" ) { + if (reply->error() != QNetworkReply::NoError) { + emit(errorOnQueryCities(tr("Network error: %1").arg(reply->errorString()))); + m_citiesFound->addCities(); + } else { + QString data = reply->readAll(); + QRegExp regExp; + regExp.setPattern("^\\[\\[.*\\],\\[\\[(.*)\\]\\]\\]$"); + regExp.exactMatch(data); + QString foundCities = regExp.capturedTexts().at(1); + QStringList citiesFound = foundCities.split(QRegExp("\\],\\["), QString::SkipEmptyParts); + m_citiesFound->addCities(citiesFound); + } + } + if (reply) { + reply->deleteLater(); + reply = 0; + } +} + diff --git a/src/applicationinfo.h b/src/applicationinfo.h new file mode 100644 index 0000000..4e001dd --- /dev/null +++ b/src/applicationinfo.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef APPLICATIONINFO_H +#define APPLICATIONINFO_H + +#include <QtCore/QObject> +#include <QtQml/QQmlPropertyMap> + +QT_BEGIN_NAMESPACE +class QNetworkAccessManager; +class QNetworkReply; +QT_END_NAMESPACE + +class WeatherImageProvider; + +#include "citymodel.h" +#include "citieslistmodel.h" + +class ApplicationInfo : public QObject +{ + Q_OBJECT + Q_PROPERTY(int applicationWidth READ applicationWidth WRITE setApplicationWidth NOTIFY applicationWidthChanged) + Q_PROPERTY(QObject *colors READ colors CONSTANT) + Q_PROPERTY(QObject *constants READ constants CONSTANT) + Q_PROPERTY(bool isPortraitMode READ isPortraitMode WRITE setIsPortraitMode NOTIFY portraitModeChanged) + Q_PROPERTY(int currentIndexDay READ currentIndexDay WRITE setCurrentIndexDay NOTIFY currentIndexDayChanged) + Q_PROPERTY(CityModel *currentCityModel READ currentCityModel WRITE setCurrentCityModel NOTIFY currentCityModelChanged) + Q_PROPERTY(CitiesListModel *foundCities READ foundCities NOTIFY foundCitiesChanged) + Q_PROPERTY(qreal ratio READ ratio NOTIFY ratioChanged) + Q_PROPERTY(qreal hMargin READ hMargin NOTIFY hMarginChanged) + Q_PROPERTY(qreal sliderHandleWidth READ sliderHandleWidth NOTIFY ratioChanged) + Q_PROPERTY(qreal sliderHandleHeight READ sliderHandleHeight NOTIFY ratioChanged) + Q_PROPERTY(qreal sliderGapWidth READ sliderGapWidth NOTIFY ratioChanged) + +public: + ApplicationInfo(WeatherImageProvider *provider); + + QQmlPropertyMap *colors() const { return m_colors; } + QQmlPropertyMap *constants() const { return m_constants; } + + CityModel *currentCityModel() const { return m_currentCityModel; } + void setCurrentCityModel(CityModel *model); + + int applicationWidth() const { return m_applicationWidth; } + void setApplicationWidth(const int newWidth); + + int currentIndexDay() const { return m_currentIndexDay; } + void setCurrentIndexDay(const int index); + + bool isPortraitMode() const { return m_isPortraitMode; } + void setIsPortraitMode(const bool newMode); + + CitiesListModel *foundCities() { return m_citiesFound; } + + qreal hMargin() const { return m_hMargin; } + qreal ratio() const { return m_ratio; } + qreal sliderHandleHeight() { return m_sliderHandleHeight; } + qreal sliderGapWidth() { return m_sliderGapWidth; } + qreal sliderHandleWidth() { return m_sliderHandleWidth; } + + Q_INVOKABLE QString getImagePath(const QString image); + Q_INVOKABLE void queryCities(const QString input); + +protected slots: + void notifyPortraitMode(); + +private slots: + void replyFinished(QNetworkReply *reply); + +protected: + qreal getSizeWithRatio(const qreal height) { return ratio() * height; } + +signals: + void applicationWidthChanged(); + void portraitModeChanged(); + void hMarginChanged(); + void currentCityModelChanged(); + void currentIndexDayChanged(); + void foundCitiesChanged(); + void ratioChanged(); + void waitForCitiesQueryReply(const QString message); + void errorOnQueryCities(const QString errorMessage); + +private: + int m_applicationWidth; + QQmlPropertyMap *m_colors; + QQmlPropertyMap *m_constants; + CityModel *m_currentCityModel; + bool m_isPortraitMode; + int m_currentIndexDay; + QNetworkAccessManager *manager; + CitiesListModel *m_citiesFound; + bool m_isMobile; + qreal m_ratio; + qreal m_hMargin; + qreal m_sliderHandleHeight, m_sliderHandleWidth, m_sliderGapWidth; + WeatherImageProvider *imageProvider; +}; + +#endif // APPLICATIONINFO_H diff --git a/src/applicationpaths.h b/src/applicationpaths.h new file mode 100644 index 0000000..efce270 --- /dev/null +++ b/src/applicationpaths.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef APPLICATIONPATHS_H +#define APPLICATIONPATHS_H + +#include <QtCore/QDir> +#include <QtCore/QStandardPaths> +#include <QtCore/QStringList> +#include <QDebug> + +class ApplicationPaths +{ +public: + inline static QString settingsPath() + { + return getPath(QStandardPaths::DataLocation); + } + inline static QString dowloadedFilesPath() + { + return getPath(QStandardPaths::CacheLocation); + } +protected: + + inline static QString getPath(QStandardPaths::StandardLocation location) + { + QString path = QStandardPaths::standardLocations(location).value(0); + QDir dir(path); + if (!dir.exists()) + dir.mkpath(path); + if (!path.isEmpty() && !path.endsWith("/")) + path += "/"; + return path; + } +}; + +#endif // APPLICATIONPATHS_H diff --git a/src/cities.cpp b/src/cities.cpp new file mode 100644 index 0000000..b91c276 --- /dev/null +++ b/src/cities.cpp @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QCoreApplication> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QIODevice> +#include <QtCore/QTextStream> +#include <QtGlobal> + +#include "cities.h" +#include "citymodel.h" +#include "applicationpaths.h" +#include <QDebug> + +Cities::Cities(QObject *parent) : + QAbstractListModel(parent) +{ + m_citiesFileName = QString("%1cities.settings").arg(ApplicationPaths::settingsPath()); + readCities(); +} + +Cities::~Cities() +{ + saveCities(); +} + +CityModel* Cities::getCityModel(int index) +{ + Q_ASSERT(index > -1); + Q_ASSERT(index < m_cityMap.count()); + return m_cityMap.at(index).second; +} + +void Cities::removeCityModel(int index) +{ + if (index < m_cityMap.count() && index >=0 ) + { + beginRemoveRows(QModelIndex(), index, index); + CityModel *modelToDelete = m_cityMap.at(index).second; + modelToDelete->cleanAll(); + modelToDelete->deleteLater(); + m_cityMap.removeAt(index); + endRemoveRows(); + } +} + +int Cities::addCityModel(CityModel *model) +{ + CityModelPair pair = qMakePair(model->sourceXml(), model); + int modelIndex = m_cityMap.indexOf(pair); + if (modelIndex == -1) { + m_cityMap.prepend(pair); + connect(model, SIGNAL(contentXmlChanged()), this, SIGNAL(cityModelReady())); + if (m_cityMap.count() > 15) + removeCityModel(m_cityMap.count() - 1); + return 0; + } + return modelIndex; +} + +void Cities::readCities() +{ + QFile file(m_citiesFileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + QTextStream in(&file); + while (!in.atEnd()) { + QString sourceXml = in.readLine().trimmed(); + processSourceXml(sourceXml); + } + file.close(); +} + +int Cities::processSourceXml(const QString sourceXml) +{ + // Dont add save town/identical sourceXml twice + for (int i = 0; i <m_cityMap.count(); i++) { + if (m_cityMap.at(i).first == sourceXml) + return i; + } + CityModel *model = new CityModel(this); + if (model->setSourceXml(sourceXml)) + return addCityModel(model); + + model->deleteLater(); + return -1; +} + +void Cities::saveCities() +{ + QFile file(m_citiesFileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return; + QTextStream out(&file); + for (int index = m_cityMap.count()-1; index >= 0; index--) + out << m_cityMap.at(index).first << endl; + file.close(); +} + +QVariant Cities::data(const QModelIndex & index, int role) const +{ + CityModel *model = m_cityMap.at(index.row()).second; + if (model) { + switch (role) { + case CityNameRole: + return model->cityNameDisplay().replace("_", " "); + case CountryRole: + return model->countryName().replace("_", " "); + } + } + return QVariant(); +} + +int Cities::rowCount(const QModelIndex & /*parent*/) const +{ + return m_cityMap.count(); +} + +QHash<int, QByteArray> Cities::roleNames() const +{ + QHash<int, QByteArray> rn; + rn[CityNameRole] = "name"; + rn[CountryRole] = "country"; + return rn; +} diff --git a/src/cities.h b/src/cities.h new file mode 100644 index 0000000..6839074 --- /dev/null +++ b/src/cities.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CITIES_H +#define CITIES_H + +#include <QtCore/QAbstractListModel> +#include <QtCore/QList> +#include <QtCore/QPair> +#include <QtQml/qqml.h> + +class CityModel; + +typedef QPair<QString, CityModel*> CityModelPair; + +class Cities : public QAbstractListModel +{ + Q_OBJECT +public: + enum { + CityNameRole = Qt::UserRole + 1, + CountryRole = Qt::UserRole + 2 + }; + + Cities(QObject *parent = 0); + ~Cities(); + + Q_INVOKABLE CityModel* getCityModel(const int index); + Q_INVOKABLE void removeCityModel(const int index); + int addCityModel(CityModel *model); + Q_INVOKABLE int processSourceXml(const QString sourceXml); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QHash<int, QByteArray> roleNames() const; + int rowCount(const QModelIndex & parent = QModelIndex()) const; + Q_INVOKABLE void saveCities(); + +protected: + void readCities(); + +signals: + void cityModelReady(); + void modelChanged(const int index); + +private: + QString m_wantedCity; + QString m_citiesFileName; + QString m_cachePath; + QList<CityModelPair> m_cityMap; +}; + +QML_DECLARE_TYPE(Cities) + +#endif // CITIES_H diff --git a/src/citieslistmodel.cpp b/src/citieslistmodel.cpp new file mode 100644 index 0000000..e86bd0d --- /dev/null +++ b/src/citieslistmodel.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "citieslistmodel.h" +#include <QDebug> + +CitiesListModel::CitiesListModel(QObject *parent) : + QAbstractListModel(parent), m_isEmpty(true) +{ +} + +QVariant CitiesListModel::data(const QModelIndex & index, int role) const +{ + Q_ASSERT(index.row() < m_foundCities.count()); + if (role == CountryRole) + return QString(m_foundCities.at(index.row()).first).replace("_", " "); + else + return QVariant(""); +} + +int CitiesListModel::rowCount(const QModelIndex & /*parent*/) const +{ + return m_foundCities.count(); +} + +QString CitiesListModel::getCitySourceXml(const int index) +{ + Q_ASSERT(index > -1); + Q_ASSERT(index < m_foundCities.count()); + CityXmlPair pair = m_foundCities.at(index); + // In order to use yr.no weather data service, refer to their terms + // and conditions of use. http://om.yr.no/verdata/free-weather-data/ + return QString("http://www.yr.no%1forecast.xml").arg(pair.second); +} + +void CitiesListModel::addCities(QStringList listCities) +{ + clear(); + QList<CityXmlPair> temp; + if (!listCities.empty()) { + for (int i = 0; i < listCities.count(); i++) + { + QRegExp regExp2; + regExp2.setPattern("^\"(.*)\",\"(.*)\",\"(.*)\",\"(.*)\"$"); + regExp2.exactMatch(listCities.at(i)); + QString cityName = regExp2.capturedTexts().at(1); + QString countryName = regExp2.capturedTexts().at(3); + QString xml = regExp2.capturedTexts().at(2); + QRegExp regExp3; + regExp3.setPattern("^/place/.*/.*/.*/$"); + if (countryName.isEmpty() || countryName.contains("Municipality") || !regExp3.exactMatch(xml)) + continue; // We want cities forecast only + QString name = cityName + " - " + countryName; + temp.append(qMakePair(name, xml)); + } + } + + if (!temp.isEmpty()) { + beginInsertRows(QModelIndex(), 0, temp.count() - 1); + m_foundCities.append(temp); + m_isEmpty = false; + } else { + beginInsertRows(QModelIndex(), 0, 0); + m_foundCities.append(qMakePair(tr("no city found"), QString(""))); + } + + endInsertRows(); +} + +void CitiesListModel::clear() +{ + m_isEmpty = true; + if (m_foundCities.count() > 0) { + beginRemoveRows(QModelIndex(), 0, m_foundCities.count() - 1); + m_foundCities.clear(); + endRemoveRows(); + } +} + +QHash<int, QByteArray> CitiesListModel::roleNames() const +{ + QHash<int, QByteArray> rn; + rn[CountryRole] = "country"; + rn[NameRole] = "name"; // needed to use in delegate that read both roles (country and name) + return rn; +} + diff --git a/src/citieslistmodel.h b/src/citieslistmodel.h new file mode 100644 index 0000000..7120620 --- /dev/null +++ b/src/citieslistmodel.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CITIESLISTMODEL_H +#define CITIESLISTMODEL_H + +#include <QtCore/QAbstractListModel> +#include <QtCore/QList> +#include <QtCore/QPair> +#include <QtCore/QStringList> +#include <QtQml/qqml.h> + +typedef QPair<QString, QString> CityXmlPair; + +class CitiesListModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(bool isEmpty READ isEmpty NOTIFY isEmptyChanged) +public: + enum { + NameRole = Qt::UserRole + 1, + CountryRole = Qt::UserRole + 2 + }; + CitiesListModel(QObject *parent = 0); + + Q_INVOKABLE QString getCitySourceXml(const int index); + void addCities(QStringList listCities = QStringList()); + + bool isEmpty() const { return m_isEmpty; } + + void clear(); + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + Q_INVOKABLE int rowCount(const QModelIndex & parent = QModelIndex()) const; + QHash<int, QByteArray> roleNames() const; + +signals: + void isEmptyChanged(); + +private: + QList<CityXmlPair> m_foundCities; + bool m_isEmpty; +}; + +QML_DECLARE_TYPE(CitiesListModel) + +#endif // CITIESLISTMODEL_H diff --git a/src/citymodel.cpp b/src/citymodel.cpp new file mode 100644 index 0000000..9056398 --- /dev/null +++ b/src/citymodel.cpp @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QDateTime> +#include <QtCore/QFile> +#include <QtCore/QIODevice> +#include <QtCore/QRegExp> +#include <QtCore/QStringList> +#include <QtNetwork/QNetworkRequest> +#include <QtNetwork/QNetworkReply> +#include <QtNetwork/QNetworkAccessManager> + +#include "citymodel.h" +#include "applicationpaths.h" +#include <QDebug> + +CityModel::CityModel(QObject *parent) : + QObject(parent), m_timeStamp(0) +{ + manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)), + this, SLOT(replyFinished(QNetworkReply*))); + connect(this, SIGNAL(ready()), this, SLOT(readXml())); +} + +void CityModel::setCopyright(const QString copyright) +{ + if (copyright != m_copyright) { + m_copyright = copyright; + emit copyrightChanged(); + } +} + +bool CityModel::setSourceXml(const QString xml) +{ + if (xml != m_sourceXml) { + QRegExp regExp; + // will reject invalid xml string + regExp.setPattern("^http://www\\.yr\\.no/place/(([^/]*)/.*/([^/]*))/forecast\\.xml$"); + if (!regExp.exactMatch(xml)) + return false; + m_sourceXml = xml; + + // get city name, country and filename from sourceXml + QStringList list = regExp.capturedTexts(); + setCityNameDisplay(list.at(3)); + setCountryName(list.at(2)); + QString tempFileName = regExp.capturedTexts().at(1); + tempFileName = tempFileName.replace(QString("/"), QString("_")); + m_filename = QString("%1%2.wa").arg(ApplicationPaths::dowloadedFilesPath()).arg(tempFileName); + emit sourceXmlChanged(); + } + return true; +} + +void CityModel::setCityNameDisplay(QString name) +{ + int pos = name.indexOf("~"); + if ( pos > 0) + name.truncate(pos); + + if (name != m_cityNameDisplay) { + m_cityNameDisplay = name; + emit cityNameDisplayChanged(); + } +} + +QString CityModel::cityNameDisplay() const +{ + QString cityName = m_cityNameDisplay; + return cityName.replace("_", " "); +} + +void CityModel::setCountryName(const QString name) +{ + if (name != m_countryName) { + m_countryName = name; + emit countryNameChanged(); + } +} + +QString CityModel::countryName() const +{ + QString countryName = m_countryName; + return countryName.replace("_", " "); +} + +void CityModel::setError(const QString errorMessage) +{ + // Always emit error message + emit error(tr("Network error: ") + errorMessage); +} + +QVariant CityModel::data(const QModelIndex & /*index*/, int role) const +{ + if (role == CityNameDisplayRole) + return m_cityNameDisplay; + return QVariant(); +} + +QHash<int, QByteArray> CityModel::roleNames() const +{ + QHash<int, QByteArray> rn; + rn[CityNameDisplayRole] = "name"; + return rn; +} + +void CityModel::clear() +{ + m_copyright = QString(); + m_timeStamp = 0; + for (int i = 0; i < m_citydata.count(); i++) { + DayModel *temp = m_citydata.takeAt(i); + temp->clear(); + temp->deleteLater(); + } + m_citydata.clear(); +} + +void CityModel::cleanAll() +{ + clear(); + // Clear eventual cached file + QFile file(m_filename); + if (file.exists()) + file.remove(); +} + +void CityModel::addDayModel(DayModel *newDayModel) +{ + m_citydata.append(newDayModel); + connect(newDayModel, SIGNAL(addedImages(QStringList)), this, SLOT(addImages(QStringList))); +} + +void CityModel::addImages(const QStringList images) +{ + for (int i = 0; i < images.count(); i++) + downloadImage(images.at(i)); +} + +DayModel* CityModel::getDayModel(QString date) +{ + for (int i = 0; i < m_citydata.count(); i++) { + if ( m_citydata.at(i)->getDate() == date ) + return m_citydata.at(i); + } + return 0; +} + +DayModel* CityModel::getDayModel(int indexDay) +{ + Q_ASSERT(indexDay > -1); + Q_ASSERT(indexDay < m_citydata.count()); + return m_citydata.at(indexDay); +} + +void CityModel::refreshData() +{ + if (sourceXml() == QString()) { + qWarning("Warning: source xml not set"); + return; + } + QNetworkRequest request; + request.setUrl(QUrl(sourceXml())); + request.setRawHeader("Accept", "application/xml,*/*"); + manager->get(request); +} + +void CityModel::loadData() +{ + Q_ASSERT(!m_filename.isEmpty()); + QFile file(m_filename); + m_timeStamp = 0; + if (file.exists() && file.open(QIODevice::ReadOnly)) { + m_timeStamp = QString(file.readLine().trimmed()).toLongLong(); + file.close(); + } + if (dataExpired(m_timeStamp)) + refreshData(); + else + emit ready(); +} + +bool CityModel::dataExpired(qint64 timeStamp) { + // 10 minutes caching + qint64 tenMinutesMSecs = 10 * 60 * 1000; + qint64 timeElapsed = QDateTime::currentMSecsSinceEpoch() - timeStamp; + return timeStamp == 0 || timeElapsed > tenMinutesMSecs; +} + +void CityModel::replyFinished(QNetworkReply *reply) +{ + if (reply->error() != QNetworkReply::NoError) { + setError(reply->errorString()); + } else { + QString requestUrl = reply->request().url().toString(); + if (requestUrl.endsWith(".xml")) { + QByteArray data = reply->readAll(); + if (!data.isEmpty()) { + data.prepend("\n"); + data.prepend(QByteArray::number(QDateTime::currentMSecsSinceEpoch(), 'f', 0)); + QFile file(m_filename); + if (file.open(QIODevice::WriteOnly)) { + file.write(data); + file.close(); + emit ready(); + } else { + setError(file.errorString()); + } + } else { + setError(tr("No data at given url")); + } + } else { // download image + QString filename = getImageFileName(reply->url().toString()); + QByteArray data = reply->readAll(); + if (!data.isEmpty()) { + QFile file(filename); + if (!file.exists() && file.open(QIODevice::WriteOnly)) { + file.write(data); + file.close(); + } + } + } + } + if (reply) { + reply->deleteLater(); + reply = 0; + } +} + +void CityModel::downloadImage(const QString imageUrl) +{ + QString filename = getImageFileName(imageUrl); + QFile file(filename); + if (!file.exists()) { + QNetworkRequest request; + request.setUrl(QUrl(imageUrl)); + manager->get(request); + } +} + +QString CityModel::getImageFileName(const QString url) +{ + bool isLargeImage = url.contains("b200"); + QString filename = url.right(url.length() - url.lastIndexOf("/") - 1); + if (isLargeImage) + filename.prepend("large_"); + filename = QString("%1%2").arg(ApplicationPaths::dowloadedFilesPath()).arg(filename); + return filename; +} + +void CityModel::readXml() +{ + QFile file(m_filename); + QString content; + if (file.open(QIODevice::ReadOnly)) { + m_timeStamp = QString(file.readLine().trimmed()).toLongLong(); + m_contentXml = QString(file.readAll()); + emit contentXmlChanged(); // always emit this signal + file.close(); + } else { + setError(file.errorString()); + } +} diff --git a/src/citymodel.h b/src/citymodel.h new file mode 100644 index 0000000..34d40ec --- /dev/null +++ b/src/citymodel.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CITYMODEL_H +#define CITYMODEL_H + +#include <QtCore/QModelIndex> +#include <QtCore/QObject> +#include <QtQml/qqml.h> +#include <QDebug> + +#include "daymodel.h" + +QT_BEGIN_NAMESPACE +class QNetworkAccessManager; +class QNetworkReply; +QT_END_NAMESPACE + +class CityModel : public QObject +{ + Q_OBJECT + Q_ENUMS(Status) + Q_PROPERTY(QString copyright READ copyright WRITE setCopyright NOTIFY copyrightChanged) + Q_PROPERTY(QString cityNameDisplay READ cityNameDisplay NOTIFY cityNameDisplayChanged) + Q_PROPERTY(QString countryName READ countryName NOTIFY countryNameChanged) + Q_PROPERTY(QString sourceXml READ sourceXml NOTIFY sourceXmlChanged) + Q_PROPERTY(QString contentXml READ contentXml NOTIFY contentXmlChanged) + +public: + enum { + CityNameDisplayRole = Qt::UserRole + 1 + }; + + CityModel(QObject *parent = 0); + + void setError(const QString msg); + + QString copyright() const { return m_copyright;} + void setCopyright(const QString copyright); + + QString cityNameDisplay() const; + void setCityNameDisplay(QString name); + + QString countryName() const; + void setCountryName(const QString name); + + QString sourceXml() const { return m_sourceXml; } + bool setSourceXml(const QString xml); + + QString contentXml() const { return m_contentXml; } + + QVariant data(const QModelIndex &index, int role) const; + QHash<int, QByteArray> roleNames() const; + + Q_INVOKABLE int daysCount() const { return m_citydata.count(); } + Q_INVOKABLE void loadData(); + Q_INVOKABLE void clear(); + Q_INVOKABLE void addDayModel(DayModel *newDayModel); + Q_INVOKABLE DayModel* getDayModel(QString dayName); + Q_INVOKABLE DayModel* getDayModel(int indexDay); + + void cleanAll(); + + void downloadImage(const QString imageUrl); + +private: + void refreshData(); + bool dataExpired(qint64 timeStamp); + QString getImageFileName(const QString url); + +private Q_SLOTS: + void replyFinished(QNetworkReply*); + void readXml(); + void addImages(const QStringList images); + +Q_SIGNALS: + void copyrightChanged(); + void countryNameChanged(); + void error(const QString errorMessage); + void sourceXmlChanged(); + void contentXmlChanged(); + void cityNameDisplayChanged(); + void fileNameChanged(); + void ready(); + +private: + QString m_copyright; + QString m_countryName, m_contentXml; + qreal m_timeStamp; + QList<DayModel*> m_citydata; + QNetworkAccessManager *manager; + QString m_filename; + QString m_url; + QString m_sourceXml; + QString m_cityNameDisplay; +}; + +QML_DECLARE_TYPE(CityModel) + +#endif // CITYMODEL_H diff --git a/src/daymodel.cpp b/src/daymodel.cpp new file mode 100644 index 0000000..a0ae9ac --- /dev/null +++ b/src/daymodel.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QDir> +#include <QtCore/QCoreApplication> +#include <QtNetwork/QNetworkRequest> +#include <QtNetwork/QNetworkReply> +#include <QtNetwork/QNetworkAccessManager> + +#include "daymodel.h" +#include "applicationpaths.h" +#include <QDebug> + +DayModel::DayModel() + : QObject(), m_afternoonindex(0) { +} + +QVariant DayModel::data(const QModelIndex &index, int role) const +{ + if (role == DayRole) + return m_data.at(index.row()).day; + if (role == WeatherUrlRole) + return m_data.at(index.row()).weatherUrl; + if (role == TimeRangeRole) + return m_data.at(index.row()).timeRange; + if (role == TemperatureRole) + return m_data.at(index.row()).temperature; + if (role == WindSpeedRole) + return m_data.at(index.row()).windSpeed; + if (role == WindUrlRole) + return m_data.at(index.row()).windUrl; + if (role == RainRole) + return m_data.at(index.row()).rain; + return QVariant(); +} + +QHash<int, QByteArray> DayModel::roleNames() const +{ + QHash<int, QByteArray> rn; + rn[DayRole] = "day"; + rn[WeatherUrlRole] = "weatherUrl"; + rn[TimeRangeRole] = "timeRange"; + rn[TemperatureRole] = "temperature"; + rn[WindSpeedRole] = "windSpeed"; + rn[WindUrlRole] = "windUrl"; + rn[RainRole] = "rain"; + return rn; +} + +void DayModel::clear() +{ + m_date = QString(); + m_afternoonindex = 0; + m_data.clear(); +} + +void DayModel::addRow(QString day, QString weatherUrl, QString timeRange, QString temperature, QString windSpeed, QString windUrl, QString rain) { + QStringList m_images; + DayModelStructure temp; + temp.day = day; + temp.weatherUrl = weatherUrl; + m_images.append(weatherUrl); + QString largeWeatherIconUrl = weatherUrl; + m_images.append(largeWeatherIconUrl.replace("b100", "b200")); + temp.timeRange = timeRange; + temp.temperature = temperature; + temp.windSpeed = windSpeed; + temp.windUrl = windUrl; + m_images.append(windUrl); + temp.rain = rain; + m_data.append(temp); + emit addedImages(m_images); +} + +QUrl DayModel::getCachedImageFile(const QString url) +{ + bool isLargeImage = url.contains("b200"); + QString filename = url.right(url.length() - url.lastIndexOf("/") - 1); + if (isLargeImage) + filename.prepend("large_"); + filename = QString("%1%2").arg(ApplicationPaths::dowloadedFilesPath()).arg(filename); + QFile file(filename); + if (file.exists()) + return QUrl(QString("image://weatherImages/%1").arg(filename)); + else + return QUrl(url); +} + +QString DayModel::getDayDetails(int index, QString prop) const +{ + if (index == -1) + index = 0; + if (index < m_data.count()) { + DayModelStructure temp = m_data.at(index); + if (prop == "day") + return temp.day; + if (prop == "weatherUrl") + return temp.weatherUrl; + if (prop == "timeRange") + return temp.timeRange; + if (prop == "temperature") + return temp.temperature; + if (prop == "windSpeed") + return temp.windSpeed; + if (prop == "windUrl") + return temp.windUrl; + if (prop == "rain") + return temp.rain; + } + return QString(); +} diff --git a/src/daymodel.h b/src/daymodel.h new file mode 100644 index 0000000..d93e905 --- /dev/null +++ b/src/daymodel.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DAYMODEL_H +#define DAYMODEL_H + +#include <QtCore/QModelIndex> + +#include <QtCore/QObject> +#include <QtCore/QStringList> +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE +class QNetworkAccessManager; +class QNetworkReply; +QT_END_NAMESPACE + +class DayModel : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString date READ getDate WRITE setDate NOTIFY dateChanged) + Q_PROPERTY(int afternoonIndex READ getAfternoonIndex WRITE setAfternoonIndex NOTIFY afternoonIndexChanged) + +public: + + struct DayModelStructure { + QString day; + QString weatherUrl; + QString timeRange; + QString temperature; + QString windSpeed; + QString windUrl; + QString rain; + }; + + enum { + DayRole = Qt::UserRole + 1, + WeatherUrlRole = Qt::UserRole + 2, + TimeRangeRole = Qt::UserRole + 3, + TemperatureRole = Qt::UserRole + 4, + WindSpeedRole = Qt::UserRole + 5, + WindUrlRole = Qt::UserRole + 6, + RainRole = Qt::UserRole + 7 + }; + + DayModel(); + + QString getDate() const { return m_date;} + void setDate(QString date) { m_date = date; } + + int getAfternoonIndex() const { return m_afternoonindex;} + void setAfternoonIndex(int index) { m_afternoonindex = index; } + + void clear(); + + QVariant data(const QModelIndex &index, int role) const; + QHash<int, QByteArray> roleNames() const; + + Q_INVOKABLE void addRow(QString day, QString weatherUrl, QString timeRange, QString temperature, QString windSpeed, QString windUrl, QString rain); + Q_INVOKABLE QString getDayDetails(int index, QString prop) const; + Q_INVOKABLE int periodCount() const { return m_data.count(); } + + Q_INVOKABLE QUrl getCachedImageFile(const QString url); + +Q_SIGNALS: + void dateChanged(); + void afternoonIndexChanged(); + void addedImages(const QStringList images); + +private: + QString m_date; + int m_afternoonindex; + QList<DayModelStructure> m_data; +}; + +QML_DECLARE_TYPE(DayModel) + +#endif // DAYMODEL_H diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..1704fe2 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QString> +#include <QtGui/QFont> +#include <QtGui/QFontDatabase> +#include <QtGui/QGuiApplication> +#include <QtQuick/QQuickWindow> +#include <QtQml> + +#include "daymodel.h" +#include "citymodel.h" +#include "cities.h" +#include "applicationinfo.h" +#include "weatherimageprovider.h" + +static const struct { + const char *type; + int major, minor; +} qmldir_touch [] = { + { "TouchSlider", 1, 0 }, + { "TouchScrollView", 1, 0 }, + { "TouchLabel", 1, 0 }, + { "TouchTextField", 1, 0 }, + { "ListViewDelegate", 1, 0 }, + { "ListViewDelegateLoading", 1, 0 }, +}; + +static const struct { + const char *type; + int major, minor; +} qmldir_models [] = { + { "CitiesModel", 1, 0 }, + { "WeatherModel", 1, 0 }, +}; + +static const struct { + const char *type; + int major, minor; +} qmldir_pages [] = { + { "CitiesPage", 1, 0 }, + { "LongTermPage", 1, 0 }, + { "OneDayPage", 1, 0 }, +}; + +static QObject *systeminfo_provider(QQmlEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + WeatherImageProvider *provider = new WeatherImageProvider(); + engine->addImageProvider(QLatin1String("weatherImages"), provider); + return new ApplicationInfo(provider); +} + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + app.setOrganizationName("Digia"); + app.setApplicationName("QuickForecast"); + +#ifndef Q_OS_IOS //QTBUG-34490 + QFontDatabase::addApplicationFont(":/weatherapp/fonts/OpenSans-Bold.ttf"); + QFontDatabase::addApplicationFont(":/weatherapp/fonts/OpenSans-Semibold.ttf"); + int openSansID = QFontDatabase::addApplicationFont(":/weatherapp/fonts/OpenSans-Regular.ttf"); + QStringList loadedFontFamilies = QFontDatabase::applicationFontFamilies(openSansID); + if (!loadedFontFamilies.empty()) { + QString fontName = loadedFontFamilies.at(0); + QGuiApplication::setFont(QFont(fontName)); + } else { + qWarning("Error: fail to load Open Sans font"); + } +#endif + + const char *uri = "org.qtproject.demo.weather"; + qmlRegisterType<DayModel>(uri, 1, 0, "DayModel"); + qmlRegisterType<CityModel>(uri, 1, 0, "CityModel"); + qmlRegisterType<Cities>(uri, 1, 0, "Cities"); + qmlRegisterType<CitiesListModel>(uri, 1, 0, "CitiesListModel"); + qmlRegisterSingletonType<ApplicationInfo>(uri, 1, 0, "ApplicationInfo", systeminfo_provider); + + for (int i = 0; i < int(sizeof(qmldir_touch)/sizeof(qmldir_touch[0])); i++) + qmlRegisterType(QUrl(QString("qrc:/weatherapp/qml/touch/%1.qml").arg(qmldir_touch[i].type)), uri, qmldir_touch[i].major, qmldir_touch[i].minor, qmldir_touch[i].type); + + for (int i = 0; i < int(sizeof(qmldir_models)/sizeof(qmldir_models[0])); i++) + qmlRegisterType(QUrl(QString("qrc:/weatherapp/qml/models/%1.qml").arg(qmldir_models[i].type)), uri, qmldir_models[i].major, qmldir_models[i].minor, qmldir_models[i].type); + + for (int i = 0; i < int(sizeof(qmldir_pages)/sizeof(qmldir_pages[0])); i++) + qmlRegisterType(QUrl(QString("qrc:/weatherapp/qml/pages/%1.qml").arg(qmldir_pages[i].type)), uri, qmldir_pages[i].major, qmldir_pages[i].minor, qmldir_pages[i].type); + + QQmlApplicationEngine engine(QUrl("qrc:/weatherapp/qml/main.qml")); + QObject *topLevel = engine.rootObjects().value(0); + + QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel); + if ( !window ) { + qWarning("Error: Your root item has to be a Window."); + return -1; + } + window->show(); + return app.exec(); +} diff --git a/src/src.pri b/src/src.pri new file mode 100644 index 0000000..5a3bbdf --- /dev/null +++ b/src/src.pri @@ -0,0 +1,16 @@ +SOURCES += \ + $$PWD/main.cpp \ + $$PWD/citymodel.cpp \ + $$PWD/daymodel.cpp \ + $$PWD/cities.cpp \ + $$PWD/applicationinfo.cpp \ + $$PWD/citieslistmodel.cpp + +HEADERS += \ + $$PWD/citymodel.h \ + $$PWD/daymodel.h \ + $$PWD/cities.h \ + $$PWD/applicationinfo.h \ + $$PWD/citieslistmodel.h \ + $$PWD/weatherimageprovider.h \ + $$PWD/applicationpaths.h diff --git a/src/weatherimageprovider.h b/src/weatherimageprovider.h new file mode 100644 index 0000000..59fcbcc --- /dev/null +++ b/src/weatherimageprovider.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WEATHERIMAGEPROVIDER_H +#define WEATHERIMAGEPROVIDER_H + +#include <QtQuick/QQuickImageProvider> +#include <QtGui/QImage> +#include <QtCore/QSize> + +class WeatherImageProvider : public QQuickImageProvider +{ +public: + WeatherImageProvider() + : QQuickImageProvider(QQuickImageProvider::Image) + { + } + + QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) + { + int width = 50; + int height = 50; + + if (size) + *size = QSize(width, height); + QImage image(requestedSize.width() > 0 ? requestedSize.width() : width, + requestedSize.height() > 0 ? requestedSize.height() : height, + QImage::Format_ARGB32); + image.load(id); + return image; + } +}; + +#endif // WEATHERIMAGEPROVIDER_H |