Import Upstream version 3.2.0.3
|
@ -0,0 +1,281 @@
|
||||||
|
#ifndef INTERACTION_H
|
||||||
|
#define INTERACTION_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
#include "global/corevar.h"
|
||||||
|
#include <QPersistentModelIndex>
|
||||||
|
class coreinteraction;
|
||||||
|
|
||||||
|
class Interaction : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/*
|
||||||
|
* 接口功能:后端初始化后,初始化前端
|
||||||
|
* 接口场景:网络诊断完成后,初始化前端
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
void toStartView();
|
||||||
|
/*
|
||||||
|
* 接口功能:网络错误,给ui层传递无网络信息
|
||||||
|
* 接口场景:程序启动时,检测网络连接状况
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:QString
|
||||||
|
* 参数描述:返回网络错误信息
|
||||||
|
*/
|
||||||
|
void netUiShow(QString);
|
||||||
|
/*
|
||||||
|
* 接口功能:请求服务器错误
|
||||||
|
* 接口场景:访问服务器拿数据--目前返回的是code值
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:int
|
||||||
|
* 参数描述:返回访问服务器错误信息
|
||||||
|
*/
|
||||||
|
|
||||||
|
void serverUiShow(QString);
|
||||||
|
/*
|
||||||
|
* 接口功能:数据解析
|
||||||
|
* 接口场景:服务器返回数据为空或不全
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:QString
|
||||||
|
* 参数描述:返回数据解析错误信息
|
||||||
|
*/
|
||||||
|
void dataUiShow(QString);
|
||||||
|
/*
|
||||||
|
* 接口功能:定位失败
|
||||||
|
* 接口场景:定位时
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:QString
|
||||||
|
* 参数描述:返回定位失败
|
||||||
|
*/
|
||||||
|
void geoUiShow(QString);
|
||||||
|
/*
|
||||||
|
* 接口功能:网络超时
|
||||||
|
* 接口场景:各处需要检测超时的地方
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:bool
|
||||||
|
* 参数描述:网络超时
|
||||||
|
*/
|
||||||
|
void netTimeout(QString);
|
||||||
|
/*
|
||||||
|
* 接口功能:显示生活指数信息
|
||||||
|
* 接口场景:显示生活指数信息
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:struct
|
||||||
|
* 参数描述:生活指数信息
|
||||||
|
*/
|
||||||
|
void showLifeStyle(LifeStyle m_lifeStyle); //发送信号,显示生活指数信息
|
||||||
|
/*
|
||||||
|
* 接口功能:显示当前城市信息
|
||||||
|
* 接口场景:显示当前城市信息
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:struct
|
||||||
|
* 参数描述:当前城市信息
|
||||||
|
*/
|
||||||
|
void showCurrent(CurrentWeather m_currentWeather); //发送信号,显示当前城市信息
|
||||||
|
/*
|
||||||
|
* 接口功能:显示城市预测信息
|
||||||
|
* 接口场景:显示城市预测信息
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:struct
|
||||||
|
* 参数描述:当前城市信息
|
||||||
|
*/
|
||||||
|
void showForcast(ForecastWeather forecastWeather); //发送信号,显示城市预测信息
|
||||||
|
/*
|
||||||
|
* 接口功能:显示逐小时信息
|
||||||
|
* 接口场景:显示逐小时信息
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:QVariant
|
||||||
|
* 参数描述:逐小时信息
|
||||||
|
*/
|
||||||
|
void showHourly(QVariant var); //发送信号,显示逐小时信息
|
||||||
|
/*
|
||||||
|
* 接口功能:搜索错误,给ui层传递无搜索结果信息
|
||||||
|
* 接口场景:输入或不输入字符,无搜索内容
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:返回搜索错误信息
|
||||||
|
*/
|
||||||
|
void searchNull();
|
||||||
|
/*
|
||||||
|
* 接口功能:搜索结果,给ui层传递搜索结果信息
|
||||||
|
* 接口场景:输入或不输入字符,有/无搜索内容
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:bool
|
||||||
|
* 参数描述:返回有/无搜索结果
|
||||||
|
*/
|
||||||
|
void searchUiShow(bool hasCity);
|
||||||
|
/*
|
||||||
|
* 接口功能:收藏城市为空
|
||||||
|
* 接口场景:判断收藏城市是否为空
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
void collectNull();
|
||||||
|
/*
|
||||||
|
* 接口功能:收藏城市不为空
|
||||||
|
* 接口场景:判断收藏城市是否为空
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
void collectShow();
|
||||||
|
/*
|
||||||
|
* 接口功能:关闭程序
|
||||||
|
* 接口场景:点击关闭按钮和托盘退出选项
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
void closePro();
|
||||||
|
/*
|
||||||
|
* 接口功能:在屏幕中间显示
|
||||||
|
* 接口场景:显示
|
||||||
|
* 接口类型:信号,需要绑定
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
void showInCenter();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* 接口功能:单例取指针,供UI层实例化接口对象
|
||||||
|
* 接口场景:程序启动时,首次调用要放到主界面构造函数的第一行
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
* 返回类型:Interaction
|
||||||
|
* 返回描述:接口对象
|
||||||
|
*/
|
||||||
|
static Interaction *getInstance();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 接口功能:初始化核心模块
|
||||||
|
* 接口场景:程序启动时,放在主界面构造函数的第二行,只需调用这一次,多次调用无效果
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
* 参数类型:QStringList
|
||||||
|
* 参数描述:程序启动时传入的参数,一般来自QApplication::arguments()
|
||||||
|
*/
|
||||||
|
virtual void creatCore(const QStringList &list) = 0;
|
||||||
|
/*
|
||||||
|
* 接口功能:切换城市
|
||||||
|
* 接口场景:点击城市切换主界面城市
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
*/
|
||||||
|
virtual void changeCity(QString cityCode) = 0; //切换到目标城市
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 接口功能:搜索城市
|
||||||
|
* 接口场景:在搜索框输入字符
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
*/
|
||||||
|
virtual void searchResult(QString inputText) = 0; //切换到目标城市
|
||||||
|
/*
|
||||||
|
* 接口功能:获取model指针
|
||||||
|
* 接口场景:获取城市列表
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
* 备注:对应QTabelView
|
||||||
|
*/
|
||||||
|
virtual QStandardItemModel *getCityModel() = 0; //获取搜索model指针
|
||||||
|
/*
|
||||||
|
* 接口功能:获取收藏model指针
|
||||||
|
* 接口场景:获取城市列表
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
* 备注:对应QTabelView
|
||||||
|
*/
|
||||||
|
virtual QStandardItemModel *getCollectModel() = 0; //获取收藏model指针
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 接口功能:从搜索列表切换城市
|
||||||
|
* 接口场景:点击城市切换主界面城市
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
*/
|
||||||
|
virtual void changeCityFromSearch(QModelIndex index) = 0; //切换到目标城市
|
||||||
|
/*
|
||||||
|
* 接口功能:从搜索列表添加城市到收藏城市
|
||||||
|
* 接口场景:点击“+”号按钮添加城市
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
*/
|
||||||
|
virtual void addCollectCity(QModelIndex index) = 0; //切换到目标城市
|
||||||
|
/*
|
||||||
|
* 接口功能:从收藏城市列表切换城市
|
||||||
|
* 接口场景:点击城市切换主界面城市
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
*/
|
||||||
|
virtual void changeCityFromCollect(QModelIndex index) = 0; //切换到目标城市
|
||||||
|
/*
|
||||||
|
* 接口功能:删除收藏城市列表的城市
|
||||||
|
* 接口场景:点击删除按钮添加城市
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
*/
|
||||||
|
virtual void delCollectCity(QModelIndex index) = 0; //切换到目标城市
|
||||||
|
/*
|
||||||
|
* 接口功能:初始化核心模块
|
||||||
|
* 接口场景:程序启动时,放在主界面构造函数的第二行,只需调用这一次,多次调用无效果
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
* 参数类型:QStringList
|
||||||
|
* 参数描述:程序启动时传入的参数,一般来自QApplication::arguments()
|
||||||
|
*/
|
||||||
|
virtual void test() = 0;
|
||||||
|
/*
|
||||||
|
* 接口功能:加载收藏城市列表
|
||||||
|
* 接口场景:show收藏城市列表时,发送此信号
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
virtual void loadCollectCity() = 0;
|
||||||
|
/*
|
||||||
|
* 接口功能:加载收藏城市列表
|
||||||
|
* 接口场景:show收藏城市列表时,发送此信号
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
virtual void showCenterAfter() = 0;
|
||||||
|
/*
|
||||||
|
* 接口功能:退出程序
|
||||||
|
* 接口场景:点击关闭,退出等按键
|
||||||
|
* 接口类型:函数,可直接调用
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
virtual void closePrograme() = 0;
|
||||||
|
/*
|
||||||
|
* 接口功能:允许定位
|
||||||
|
* 接口场景:点击菜单栏定位选项的允许定位
|
||||||
|
* 接口类型:
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
virtual void allowLocationYes() = 0;
|
||||||
|
/*
|
||||||
|
* 接口功能:不允许定位
|
||||||
|
* 接口场景:点击菜单栏定位选项的不允许定位
|
||||||
|
* 接口类型:
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
virtual void allowLocationNo() = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 接口功能:重试刷新网络
|
||||||
|
* 接口场景:点击网络异常界面重试按钮
|
||||||
|
* 接口类型:
|
||||||
|
* 参数类型:无
|
||||||
|
* 参数描述:无
|
||||||
|
*/
|
||||||
|
virtual void refresh() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Interaction *m_interaction; //单例指针
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // INTERACTION_H
|
|
@ -0,0 +1,460 @@
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
Core::Core() {}
|
||||||
|
|
||||||
|
void Core::initCore()
|
||||||
|
{
|
||||||
|
//初始化各部分
|
||||||
|
// model/view
|
||||||
|
m_model = new QStandardItemModel();
|
||||||
|
m_collectModel = new QStandardItemModel();
|
||||||
|
// dbus接口用-暂时不用
|
||||||
|
// m_canProcess = new QTimer(this);
|
||||||
|
// m_canProcess->setSingleShot(true);
|
||||||
|
//网络模块
|
||||||
|
m_network = new Network;
|
||||||
|
// ip定位模块
|
||||||
|
m_ipLocation = new Iplocation;
|
||||||
|
//数据解析
|
||||||
|
m_dataParser = new DataParser;
|
||||||
|
//数据请求
|
||||||
|
m_dataRequest = new DataRequest;
|
||||||
|
//搜索模块
|
||||||
|
m_searchMarch = new SearchMarch;
|
||||||
|
//定时器-30分钟刷新
|
||||||
|
m_refreshweather = new QTimer(this); //定时更新主界面天气
|
||||||
|
m_refreshweather->setTimerType(Qt::PreciseTimer); //精密计时,保持毫秒精度
|
||||||
|
|
||||||
|
//自定义类型数据注册
|
||||||
|
qRegisterMetaType<LifeStyle>("LifeStyle");
|
||||||
|
qRegisterMetaType<CurrentWeather>("CurrentWeather");
|
||||||
|
qRegisterMetaType<ForecastWeather>("ForecastWeather");
|
||||||
|
qRegisterMetaType<LocationData>("LocationData");
|
||||||
|
qRegisterMetaType<ItemData>("ItemData");
|
||||||
|
qRegisterMetaType<QList<QPersistentModelIndex>>("QList<QPersistentModelIndex>");
|
||||||
|
qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>("QAbstractItemModel::LayoutChangeHint");
|
||||||
|
|
||||||
|
//初始化信号槽
|
||||||
|
initConnect();
|
||||||
|
//检查网络
|
||||||
|
m_network->checkNetWork();
|
||||||
|
}
|
||||||
|
//信号槽
|
||||||
|
void Core::initConnect()
|
||||||
|
{
|
||||||
|
connect(m_network, &Network::effectiveNetwork, this, &Core::networkState); //检查网络状态
|
||||||
|
connect(m_network, &Network::haveNet, this, &Core::refreshCity); //网络从无到有,开始重新请求
|
||||||
|
connect(m_dataRequest, &DataRequest::sendData, m_dataParser, &DataParser::dataReply); //数据reply
|
||||||
|
connect(m_dataRequest, &DataRequest::sendCollData, m_dataParser, &DataParser::dataReplyColl); //收藏城市数据reply
|
||||||
|
connect(m_dataParser, &DataParser::showCurrent, this, &Core::showCurrent); //发送信号,显示生活指数信息
|
||||||
|
connect(m_dataParser, &DataParser::showForcast, this, &Core::showForcast); //发送信号,显示当前城市信息
|
||||||
|
connect(m_dataParser, &DataParser::showLifeStyle, this, &Core::showLifeStyle); //发送信号,显示城市预测信息
|
||||||
|
connect(m_dataParser, &DataParser::showCollectCode, this, &Core::updateCollect); //更新收藏城市信息
|
||||||
|
connect(m_dataParser, &DataParser::showHourly, this, &Core::showHourly); //增加逐小时临时调试接口
|
||||||
|
connect(m_refreshweather, &QTimer::timeout, this, &Core::refreshCity); //设置定时器,每隔半小时刷新
|
||||||
|
m_refreshweather->start((60 * 60) * 1000); //定时器开启-60mim
|
||||||
|
}
|
||||||
|
//城市切换--收藏,搜索,热门
|
||||||
|
void Core::changeCity(QString cityId)
|
||||||
|
{
|
||||||
|
if (cityId == "") {
|
||||||
|
ErrorReact::getInstance()->collectAddError("切换城市为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//城市切换-埋点
|
||||||
|
kdk::kabase::BuriedPoint buriedPointChangeCity;
|
||||||
|
if (buriedPointChangeCity.functionBuriedPoint(kdk::kabase::AppName::KylinWeather,
|
||||||
|
kdk::kabase::BuriedPoint::PT::KylinWeatherChangeCity)) {
|
||||||
|
qCritical() << "Error : buried point fail ChangeCity!";
|
||||||
|
};
|
||||||
|
//获取城市数据
|
||||||
|
m_dataRequest->dataRequest(cityId);
|
||||||
|
}
|
||||||
|
//从搜索列表改变当前城市
|
||||||
|
void Core::changeCityFromSearch(QModelIndex index)
|
||||||
|
{
|
||||||
|
ItemData itemda = m_model->itemFromIndex(index)->data(Qt::UserRole).value<ItemData>();
|
||||||
|
if (itemda.cityId.isEmpty() || itemda.cityName.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
changeCity(itemda.cityId);
|
||||||
|
}
|
||||||
|
//加载收藏城市
|
||||||
|
void Core::loadCollectCity()
|
||||||
|
{
|
||||||
|
QString collectCity = CoreVar::getSettings("collect-city").toString();
|
||||||
|
QStringList listCollectCity = collectCity.split(",");
|
||||||
|
m_fullCityList = listCollectCity;
|
||||||
|
m_open = false;
|
||||||
|
//判断配置文件有内容,发信号给前端改变控件位置
|
||||||
|
if (collectCity != "") {
|
||||||
|
emit collectShow();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < listCollectCity.length(); i++) {
|
||||||
|
if (listCollectCity.at(i) != "") {
|
||||||
|
m_updateList = false; //--备用
|
||||||
|
m_itemIndex = i;
|
||||||
|
m_searchResultList = m_searchMarch->exactMatchCity(listCollectCity.at(i));
|
||||||
|
LocationData m_locationdata = (LocationData)m_searchResultList.at(0);
|
||||||
|
initCollectModel(listCollectCity.at(i), m_locationdata.city);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//暂时先一个一个访问
|
||||||
|
requestDataColl(collectCity);
|
||||||
|
}
|
||||||
|
//显示在屏幕中间
|
||||||
|
void Core::showInCenter()
|
||||||
|
{
|
||||||
|
emit showCenter();
|
||||||
|
}
|
||||||
|
//添加收藏城市
|
||||||
|
void Core::addCollectCity(QModelIndex index)
|
||||||
|
{
|
||||||
|
//获得点击的城市的cityId--不能用cityName来判断,会重名。
|
||||||
|
QStandardItem *item = m_model->itemFromIndex(index);
|
||||||
|
ItemData itemdata = item->data(Qt::UserRole).value<ItemData>();
|
||||||
|
|
||||||
|
if (itemdata.cityId.isEmpty() || itemdata.cityName.isEmpty() || itemdata.cityId == "") {
|
||||||
|
ErrorReact::getInstance()->collectAddError("添加收藏城市异常,数据为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//遍历收藏城市列表,不可重复添加
|
||||||
|
if (!m_fullCityList.isEmpty()) {
|
||||||
|
for (QStringList::iterator it = m_fullCityList.begin(); it != m_fullCityList.end(); ++it) {
|
||||||
|
if (*it == itemdata.cityId) { //若收藏城市列表中已有需要添加的城市,则返回
|
||||||
|
ErrorReact::getInstance()->collectAddError("收藏城市列表中已有需要添加的城市");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//设置将城市加入配置文件
|
||||||
|
QString fullCityID = itemdata.cityId;
|
||||||
|
m_fullCityList.append(fullCityID);
|
||||||
|
//更新配置文件
|
||||||
|
//重新将收藏城市列表写入配置文件
|
||||||
|
setCollectGsettings();
|
||||||
|
//更改状态
|
||||||
|
m_open = true;
|
||||||
|
m_updateList = true;
|
||||||
|
//设置item,model--用于界面显示
|
||||||
|
initCollectModel(itemdata.cityId, itemdata.cityName);
|
||||||
|
}
|
||||||
|
//从收藏城市切换城市
|
||||||
|
void Core::changeCityFromCollect(QModelIndex index)
|
||||||
|
{
|
||||||
|
CollectItemData itemda = m_collectModel->itemFromIndex(index)->data(Qt::UserRole).value<CollectItemData>();
|
||||||
|
if (itemda.cityId.isEmpty() || itemda.cityName.isEmpty()) {
|
||||||
|
ErrorReact::getInstance()->collectAddError("收藏城市切换主界面城市错误");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//切换城市
|
||||||
|
changeCity(itemda.cityId);
|
||||||
|
}
|
||||||
|
//删除收藏列表中的城市
|
||||||
|
void Core::delCollectCity(QModelIndex index)
|
||||||
|
{
|
||||||
|
//遍历列表,拿到需要删除的item对应的id值 -更新配置文件
|
||||||
|
QString sign;
|
||||||
|
if (m_collectModel != nullptr) {
|
||||||
|
//获取收藏列表中的cityId
|
||||||
|
sign = m_collectModel->item(index.row(), index.column())->data(Qt::UserRole).value<CollectItemData>().cityId;
|
||||||
|
}
|
||||||
|
//删除选中项--设置一个list存其余各项
|
||||||
|
QList<QStandardItem *> itemList;
|
||||||
|
//遍历当前整个model
|
||||||
|
for (int i = 0; i < m_collectModel->rowCount(); i++) {
|
||||||
|
for (int j = 0; j < m_collectModel->columnCount(); j++) {
|
||||||
|
//判断为删除项,跳出此次,继续遍历
|
||||||
|
if (index.row() == i && index.column() == j) {
|
||||||
|
//判断到最后一个item的时候,可以直接跳出循环。
|
||||||
|
if (m_collectModel->item(i, j)->data(Qt::UserRole).value<CollectItemData>().cityId
|
||||||
|
== m_fullCityList.at(m_fullCityList.length() - 1)) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//遍历到最后一行时,对于空item,continue--不然会发生闪退
|
||||||
|
if (i == m_collectModel->rowCount() - 1
|
||||||
|
&& i * m_collectModel->columnCount() + (j + 1) > m_fullCityList.length() - 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//将有效项加入qlist
|
||||||
|
itemList.append(m_collectModel->item(i, j)->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//清空model,重排整个model
|
||||||
|
m_collectModel->clear();
|
||||||
|
//遍历qlist,将有效item重新排列
|
||||||
|
for (int i = 0; i < itemList.length(); i++) {
|
||||||
|
m_collectModel->setItem(i / 3, i % 3, itemList.at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
//更新配置文件
|
||||||
|
if (!m_fullCityList.empty()) {
|
||||||
|
int cityIndex = m_fullCityList.indexOf(sign);
|
||||||
|
m_fullCityList.removeAt(cityIndex);
|
||||||
|
//判断配置文件为空,发送信号给前端
|
||||||
|
if (m_fullCityList.length() == 1) {
|
||||||
|
emit collectNull();
|
||||||
|
}
|
||||||
|
setCollectGsettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::allowLocationYes()
|
||||||
|
{
|
||||||
|
CoreVar::setSettings("allow-locate", "1"); //改变定位为允许定位
|
||||||
|
location();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::allowLocationNo()
|
||||||
|
{
|
||||||
|
CoreVar::setSettings("allow-locate", "0"); //不允许定位
|
||||||
|
}
|
||||||
|
|
||||||
|
//定位
|
||||||
|
void Core::location()
|
||||||
|
{
|
||||||
|
//判断是否允许定位----默认不允许定位
|
||||||
|
if ("1" == CoreVar::getSettings("allow-locate").toString()) {
|
||||||
|
//定位--地区名
|
||||||
|
QString cityName = m_ipLocation->gotoLocation();
|
||||||
|
//发现ipip定位偶尔会出现返回乱码--包含http字段
|
||||||
|
if (cityName.contains("http")) {
|
||||||
|
ErrorReact::getInstance()->geoFail(tr("Seek failed!"));
|
||||||
|
// cityName = m_ipLocation->gotoLocation();
|
||||||
|
}
|
||||||
|
//定位失败
|
||||||
|
if (cityName == "" || cityName.contains("http")) {
|
||||||
|
ErrorReact::getInstance()->geoFail(tr("Seek failed!"));
|
||||||
|
m_currentCityId = "";
|
||||||
|
refreshCity();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//搜索本地词库--地区id
|
||||||
|
QString cityId = m_searchMarch->setAutomaticCity(cityName);
|
||||||
|
m_dataRequest->dataRequest(cityId);
|
||||||
|
m_currentCityId = cityId;
|
||||||
|
} else if ("0" == CoreVar::getSettings("allow-locate").toString()) {
|
||||||
|
//不允许定位时
|
||||||
|
m_dataRequest->dataRequest(CoreVar::DEFAULT_CITYID);
|
||||||
|
m_currentCityId = CoreVar::DEFAULT_CITYID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//搜索城市
|
||||||
|
void Core::searchCity(QString inputText)
|
||||||
|
{
|
||||||
|
//清空模型-清空上次搜索结果
|
||||||
|
m_model->clear();
|
||||||
|
//去搜索模块获得搜索结果list
|
||||||
|
m_searchResultList = m_searchMarch->exactMatchCity(inputText);
|
||||||
|
if (inputText == "") {
|
||||||
|
//输入为空,发信号给前端进行处理
|
||||||
|
emit searchUiShow(false);
|
||||||
|
} else if (m_searchResultList.isEmpty()) {
|
||||||
|
//搜索为空,发信号给前端进行处理
|
||||||
|
emit searchNull();
|
||||||
|
} else {
|
||||||
|
emit searchUiShow(true);
|
||||||
|
//设置搜索模型
|
||||||
|
setModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//请求收藏数据
|
||||||
|
void Core::requestDataColl(QString cityIdList)
|
||||||
|
{
|
||||||
|
m_dataRequest->dataRequestCollect(cityIdList);
|
||||||
|
}
|
||||||
|
//刷新城市
|
||||||
|
void Core::refreshCity()
|
||||||
|
{
|
||||||
|
//拿配置文件数据去请求城市,没有就直接使用默认城市北京
|
||||||
|
// m_network->checkNetWork();
|
||||||
|
if (m_currentCityId == "") {
|
||||||
|
QString currentInfo = CoreVar::getSettings("weather").toString();
|
||||||
|
QStringList currentInfoList = currentInfo.split(",");
|
||||||
|
if (currentInfoList.length() >= 8) {
|
||||||
|
m_currentCityId = currentInfoList.at(1);
|
||||||
|
} else {
|
||||||
|
m_currentCityId = CoreVar::DEFAULT_CITYID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_dataRequest->dataRequest(m_currentCityId);
|
||||||
|
}
|
||||||
|
//搜索model
|
||||||
|
QStandardItemModel *Core::getCityModel()
|
||||||
|
{
|
||||||
|
return m_model;
|
||||||
|
}
|
||||||
|
//收藏model
|
||||||
|
QStandardItemModel *Core::getCollectModel()
|
||||||
|
{
|
||||||
|
return m_collectModel;
|
||||||
|
}
|
||||||
|
//设置搜索model数据
|
||||||
|
void Core::setModel()
|
||||||
|
{
|
||||||
|
//遍历整个搜索结果列表
|
||||||
|
for (int i = 0; i < m_searchResultList.size(); ++i) {
|
||||||
|
LocationData m_locationdata = (LocationData)m_searchResultList.at(i);
|
||||||
|
//设置模型item-构造搜索model
|
||||||
|
initModel(m_locationdata, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//构造搜索model
|
||||||
|
void Core::initModel(LocationData m_locationdata, int i)
|
||||||
|
{
|
||||||
|
// model数据
|
||||||
|
ItemData m_itemData;
|
||||||
|
//城市id
|
||||||
|
m_itemData.cityId = m_locationdata.id;
|
||||||
|
//城市名
|
||||||
|
m_itemData.cityName = m_locationdata.city;
|
||||||
|
//初始化item
|
||||||
|
QStandardItem *item = new QStandardItem;
|
||||||
|
//设置不可拖拽
|
||||||
|
item->setDragEnabled(false);
|
||||||
|
//整体存取
|
||||||
|
item->setData(QVariant::fromValue(m_itemData), Qt::UserRole);
|
||||||
|
//插入model
|
||||||
|
m_model->setItem(i / 3, i % 3, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
//构造搜索model
|
||||||
|
void Core::initCollectModel(QString cityId, QString cityName)
|
||||||
|
{
|
||||||
|
//判断是从搜索界面加入收藏城市,需要知道当前共有多少个城市
|
||||||
|
if (m_open) {
|
||||||
|
m_itemIndex = m_fullCityList.length() - 2;
|
||||||
|
}
|
||||||
|
// model数据
|
||||||
|
CollectItemData m_collectItemData;
|
||||||
|
//城市id
|
||||||
|
m_collectItemData.cityId = cityId;
|
||||||
|
//城市名
|
||||||
|
m_collectItemData.cityName = cityName;
|
||||||
|
//设置item
|
||||||
|
QStandardItem *item = new QStandardItem;
|
||||||
|
//设置item不可拖拽
|
||||||
|
item->setDragEnabled(false);
|
||||||
|
//整体存取
|
||||||
|
item->setData(QVariant::fromValue(m_collectItemData), Qt::UserRole);
|
||||||
|
item->setToolTip(cityName);
|
||||||
|
|
||||||
|
//设置model的行列
|
||||||
|
m_collectModel->setItem(m_itemIndex / 3, m_itemIndex % 3, item);
|
||||||
|
//请求数据---获取温度和阴晴
|
||||||
|
if (m_updateList) {
|
||||||
|
requestDataColl(m_collectItemData.cityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//初始化dbus
|
||||||
|
QString Core::initDbus(const QStringList &arguments)
|
||||||
|
{
|
||||||
|
// m_dbus = new Dbus;-------暂不需要
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::processingCommand(const QStringList &cmd)
|
||||||
|
{
|
||||||
|
if (coreOperateTooOften()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cmd[0] == "-change") {
|
||||||
|
//调用函数实现功能
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Core::processingApi(const QStringList &cmd) {}
|
||||||
|
|
||||||
|
void Core::progremExit()
|
||||||
|
{
|
||||||
|
this->deleteLater();
|
||||||
|
emit coreProgremExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::apiFunction() {}
|
||||||
|
|
||||||
|
//配置文件存收藏城市
|
||||||
|
void Core::setCollectGsettings()
|
||||||
|
{
|
||||||
|
QString newStrCityId = "";
|
||||||
|
foreach (QString str, m_fullCityList) {
|
||||||
|
if (str != "") {
|
||||||
|
newStrCityId.append(str);
|
||||||
|
newStrCityId.append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CoreVar::setSettings("collect-city", newStrCityId); //将更新后的列表写入配置文件
|
||||||
|
}
|
||||||
|
|
||||||
|
void Core::networkState(bool isOnline)
|
||||||
|
{
|
||||||
|
//启动
|
||||||
|
if (isOnline) {
|
||||||
|
//开始定位
|
||||||
|
location();
|
||||||
|
} else {
|
||||||
|
//无网络或其他错误
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//更新收藏城市列表
|
||||||
|
void Core::updateCollect(QList<CollectItemData> collectItemList)
|
||||||
|
{
|
||||||
|
if (m_updateList) {
|
||||||
|
//遍历当前整个model
|
||||||
|
for (int i = 0; i < m_collectModel->rowCount(); i++) {
|
||||||
|
for (int j = 0; j < m_collectModel->columnCount(); j++) {
|
||||||
|
//遍历到最后一行时,对于空item,跳出--不然会发生闪退
|
||||||
|
if (i == m_collectModel->rowCount() - 1
|
||||||
|
&& i * m_collectModel->columnCount() + (j + 1) > m_fullCityList.length() - 1) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
QStandardItem *item = m_collectModel->item(i, j);
|
||||||
|
if (item->data(Qt::UserRole).value<CollectItemData>().cityId == collectItemList.at(0).cityId) {
|
||||||
|
m_collectModel->item(i, j)->setData(QVariant::fromValue(collectItemList.at(0)), Qt::UserRole);
|
||||||
|
//备用--收藏列表最后一个加载完成--以后可能会需要这个完成的信号
|
||||||
|
// if (i == m_collectModel->rowCount() - 1 && i *m_collectModel->columnCount()
|
||||||
|
// + (j+1) == m_fullCityList.length() - 1) {
|
||||||
|
// qDebug()<<"最后一个加载完成";
|
||||||
|
// emit updateFinish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//遍历当前整个model
|
||||||
|
for (int i = 0; i < m_collectModel->rowCount(); i++) {
|
||||||
|
for (int j = 0; j < m_collectModel->columnCount(); j++) {
|
||||||
|
//遍历到最后一行时,对于空item,跳出--不然会发生闪退
|
||||||
|
if (i == m_collectModel->rowCount() - 1
|
||||||
|
&& i * m_collectModel->columnCount() + (j + 1) > m_fullCityList.length() - 1) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
QStandardItem *item = m_collectModel->item(i, j);
|
||||||
|
for (int k = 0; k < collectItemList.length(); k++) {
|
||||||
|
if (item->data(Qt::UserRole).value<CollectItemData>().cityId == collectItemList.at(k).cityId) {
|
||||||
|
m_collectModel->item(i, j)->setData(QVariant::fromValue(collectItemList.at(k)), Qt::UserRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::coreOperateTooOften()
|
||||||
|
{
|
||||||
|
if (m_canProcess->isActive()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
m_canProcess->start(CoreVar::REFRESH_RATE); //刷新间隔
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
#ifndef CORE_H
|
||||||
|
#define CORE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QGSettings>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QModelIndexList>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QFontMetrics>
|
||||||
|
#include "model/dbus.h"
|
||||||
|
#include "model/network.h"
|
||||||
|
#include "model/dataparser.h"
|
||||||
|
#include "controller/core/errorreact.h"
|
||||||
|
#include "model/iplocation.h"
|
||||||
|
#include "model/datarequest.h"
|
||||||
|
#include "model/searchmarch.h"
|
||||||
|
#include <QPersistentModelIndex>
|
||||||
|
#include <buried_point.hpp>
|
||||||
|
class Core : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void coreProgremExit(); //结束进程
|
||||||
|
void showCenter(); //显示在屏幕中间
|
||||||
|
void showLifeStyle(LifeStyle m_lifeStyle); //发送信号,显示生活指数信息
|
||||||
|
void showCurrent(CurrentWeather m_currentWeather); //发送信号,显示当前城市信息
|
||||||
|
void showForcast(ForecastWeather forecastWeather); //发送信号,显示城市预测信息
|
||||||
|
void showHourly(QVariant var); //发送信号,显示城市逐小时信息
|
||||||
|
void startView(); //开启前端
|
||||||
|
void collectNull(); //收藏城市为空--删光了
|
||||||
|
void collectShow(); //配置文件中收藏城市不为空
|
||||||
|
void searchUiShow(bool hasCity); //搜索有结果或搜索输入为空
|
||||||
|
void searchNull(); //搜索为空
|
||||||
|
void updateFinish(); //收藏城市最后一个加载完成
|
||||||
|
|
||||||
|
public:
|
||||||
|
Core();
|
||||||
|
QString initDbus(const QStringList &arguments); //初始化Dbus模块
|
||||||
|
void changeCity(QString cityId); //切换城市
|
||||||
|
void changeCityFromSearch(QModelIndex index); //切换到目标城市
|
||||||
|
void addCollectCity(QModelIndex index); //添加收藏城市
|
||||||
|
void changeCityFromCollect(QModelIndex index); //切换到目标城市
|
||||||
|
void delCollectCity(QModelIndex index); //添加收藏城市
|
||||||
|
void searchCity(QString inputText); //搜索本地词库表
|
||||||
|
void initCore(); //初始化核心
|
||||||
|
void loadCollectCity(); //加载收藏城市
|
||||||
|
void showInCenter(); //显示在屏幕中间
|
||||||
|
QStandardItemModel *getCityModel(); //获取搜索列表model指针
|
||||||
|
QStandardItemModel *getCollectModel(); //获取收藏城市model指针
|
||||||
|
void allowLocationYes();
|
||||||
|
void allowLocationNo();
|
||||||
|
void progremExit(); //结束进程
|
||||||
|
void refreshCity(); //刷新城市
|
||||||
|
|
||||||
|
private:
|
||||||
|
Dbus *m_dbus = nullptr; // DBus模块对象
|
||||||
|
Network *m_network = nullptr; //网络模块
|
||||||
|
DataParser *m_dataParser = nullptr; //数据解析模块
|
||||||
|
DataRequest *m_dataRequest = nullptr; //数据请求模块
|
||||||
|
Iplocation *m_ipLocation = nullptr; //初始化ip定位模块
|
||||||
|
SearchMarch *m_searchMarch = nullptr; //初始化搜索模块
|
||||||
|
QThread *m_ipThread = nullptr;
|
||||||
|
QThread *m_networkThread = nullptr;
|
||||||
|
bool m_isOnline = false; //网络是否有效--默认无效
|
||||||
|
bool m_isAllowLocate = false; //是否允许定位--默认不允许定位
|
||||||
|
void initConnect(); //初始化信号槽
|
||||||
|
void location(); //判断定位
|
||||||
|
void requestDataColl(QString cityIdList); //请求收藏数据
|
||||||
|
QStandardItemModel *m_model = nullptr;
|
||||||
|
QStandardItemModel *m_collectModel = nullptr;
|
||||||
|
QList<LocationData> m_searchResultList;
|
||||||
|
void setModel(); //设置model(7x3x2请求一次):一页21个城市,缓存两页;当鼠标滑动到某一个位置,再去请求下两页
|
||||||
|
void initModel(LocationData m_locationdata, int i); //设置搜索model
|
||||||
|
void initCollectModel(QString cityId, QString cityName); //设置收藏城市model
|
||||||
|
void processingCommand(const QStringList &cmd); //处理终端命令
|
||||||
|
QString processingApi(const QStringList &cmd); //处理外部命令
|
||||||
|
QTimer *m_canProcess = nullptr; //限制操作频率,降低cpu占用
|
||||||
|
bool coreOperateTooOften(); //操作过于频繁
|
||||||
|
bool apiFunction(); //处理api函数
|
||||||
|
int m_itemIndex = 0; //收藏城市model
|
||||||
|
QStringList m_fullCityList; //获取收藏城市列表
|
||||||
|
void setCollectGsettings(); //更新配置文件中的收藏城市
|
||||||
|
bool m_open = false; //判断是打开时,初始化model,还是从列表中添加的----默认为false:打开时初始化model。
|
||||||
|
QTimer *m_refreshweather;
|
||||||
|
bool m_updateList = false; //默认false时,不进行访问收藏城市数据--避免多次访问
|
||||||
|
QString m_currentCityId = "";
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void networkState(bool isOnline);
|
||||||
|
void updateCollect(QList<CollectItemData> collectItemList);
|
||||||
|
// void netTEst();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CORE_H
|
|
@ -0,0 +1,184 @@
|
||||||
|
#include "coreinteraction.h"
|
||||||
|
|
||||||
|
Interaction *Interaction::m_interaction(nullptr);
|
||||||
|
|
||||||
|
|
||||||
|
Interaction *Interaction::getInstance()
|
||||||
|
{
|
||||||
|
if (m_interaction == nullptr) {
|
||||||
|
m_interaction = new CoreInteraction;
|
||||||
|
}
|
||||||
|
return m_interaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreInteraction::CoreInteraction()
|
||||||
|
{
|
||||||
|
m_canProcess = new QTimer(this);
|
||||||
|
m_canProcess->setSingleShot(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::creatCore(const QStringList &list)
|
||||||
|
{
|
||||||
|
//防止多次初始化后端-默认false
|
||||||
|
if (m_isCoreInit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_core = new Core;
|
||||||
|
//线程
|
||||||
|
QThread *thread = new QThread();
|
||||||
|
//绑定信号和槽
|
||||||
|
initConnect();
|
||||||
|
//放到线程
|
||||||
|
m_core->moveToThread(thread);
|
||||||
|
thread->start();
|
||||||
|
emit coreInitCore(); //初始化core
|
||||||
|
emit toStartView(); //初始化界面
|
||||||
|
m_isCoreInit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::initConnect()
|
||||||
|
{
|
||||||
|
connect(this, &CoreInteraction::coreInitCore, m_core, &Core::initCore); //初始化core,不能跨线程调用,用信号槽实现
|
||||||
|
connect(ErrorReact::getInstance(), &ErrorReact::netUiShow, this,
|
||||||
|
&CoreInteraction::netUiShow); //返回网络错误,给UI发信号
|
||||||
|
connect(ErrorReact::getInstance(), &ErrorReact::serverUiShow, this,
|
||||||
|
&CoreInteraction::serverUiShow); //返回请求服务器错误,给UI发信号
|
||||||
|
connect(ErrorReact::getInstance(), &ErrorReact::dataUiShow, this,
|
||||||
|
&CoreInteraction::dataUiShow); //返回数据解析错误,给UI发信号
|
||||||
|
connect(ErrorReact::getInstance(), &ErrorReact::netTimeout, this, &CoreInteraction::netTimeout); //超时返回
|
||||||
|
connect(ErrorReact::getInstance(), &ErrorReact::geoUiShow, this, &CoreInteraction::geoUiShow); //定位失败
|
||||||
|
connect(m_core, &Core::searchNull, this, &CoreInteraction::searchNull); //返回搜索为无匹配城市,给UI发信号
|
||||||
|
connect(m_core, &Core::searchUiShow, this,
|
||||||
|
&CoreInteraction::searchUiShow); //返回搜索有/输入为空城市结果,给UI发信号
|
||||||
|
connect(m_core, &Core::startView, this,
|
||||||
|
&CoreInteraction::toStartView); //后端初始化之后,先进行网络诊断,之后初始化前端
|
||||||
|
// connect(m_core,&Core::showCenter,this,&CoreInteraction::showInCenter);//不起作用,有问题,带解决
|
||||||
|
connect(m_core, &Core::showCurrent, this, &CoreInteraction::showCurrent); //返回当前城市
|
||||||
|
connect(m_core, &Core::showForcast, this, &CoreInteraction::showForcast); //返回预测一周信息
|
||||||
|
connect(m_core, &Core::showHourly, this, &CoreInteraction::showHourly); //增加逐小时接口---临时用
|
||||||
|
connect(m_core, &Core::showLifeStyle, this, &CoreInteraction::showLifeStyle); //返回生活指数信息
|
||||||
|
connect(m_core, &Core::collectNull, this, &CoreInteraction::collectNull); //收藏城市为空
|
||||||
|
connect(m_core, &Core::collectShow, this, &CoreInteraction::collectShow); //收藏城市不为空---初始打开时进行发送
|
||||||
|
connect(m_core, &Core::coreProgremExit, this, &CoreInteraction::closePro); //关闭程序
|
||||||
|
connect(this, &CoreInteraction::coreChangeCity, m_core, &Core::changeCity); //切换城市
|
||||||
|
connect(this, &CoreInteraction::corechangeCityFromSearch, m_core, &Core::changeCityFromSearch); //从搜索界面切换城市
|
||||||
|
connect(this, &CoreInteraction::coreAddCollectCity, m_core, &Core::addCollectCity); //从搜索界面添加收藏城市
|
||||||
|
connect(this, &CoreInteraction::coreSearchResult, m_core, &Core::searchCity); //根据输入字符,匹配本地城市
|
||||||
|
connect(this, &CoreInteraction::coreGetCityModel, m_core, &Core::getCityModel,
|
||||||
|
Qt::BlockingQueuedConnection); //获取搜索model指针
|
||||||
|
connect(this, &CoreInteraction::coreGetCollectModel, m_core, &Core::getCollectModel,
|
||||||
|
Qt::BlockingQueuedConnection); //获取收藏model指针
|
||||||
|
connect(this, &CoreInteraction::corechangeCityFromCollect, m_core,
|
||||||
|
&Core::changeCityFromCollect); //从收藏列表切换城市
|
||||||
|
connect(this, &CoreInteraction::coreDelCollectCity, m_core, &Core::delCollectCity); //删除收藏城市列表中的城市
|
||||||
|
connect(this, &CoreInteraction::coreLoadCollect, m_core, &Core::loadCollectCity); //加载收藏城市列表
|
||||||
|
connect(this, &CoreInteraction::coreClosePro, m_core, &Core::progremExit); //项目退出
|
||||||
|
connect(this, &CoreInteraction::setAllowLocationYes, m_core, &Core::allowLocationYes); //允许定位-刷新
|
||||||
|
connect(this, &CoreInteraction::setAllowLocationNo, m_core, &Core::allowLocationNo); //不允许定位
|
||||||
|
connect(this, &CoreInteraction::refreshCity, m_core, &Core::refreshCity); //重试等刷新城市函数
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CoreInteraction::coreOperateTooOften()
|
||||||
|
{
|
||||||
|
if (m_canProcess->isActive()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
m_canProcess->start(CoreVar::REFRESH_RATE); //刷新间隔
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//在屏幕中间显示
|
||||||
|
void CoreInteraction::showCenterAfter()
|
||||||
|
{
|
||||||
|
emit showInCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::closePrograme()
|
||||||
|
{
|
||||||
|
if (coreOperateTooOften()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit coreClosePro();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::allowLocationYes()
|
||||||
|
{
|
||||||
|
emit setAllowLocationYes();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::allowLocationNo()
|
||||||
|
{
|
||||||
|
emit setAllowLocationNo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::refresh()
|
||||||
|
{
|
||||||
|
emit refreshCity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::test()
|
||||||
|
{
|
||||||
|
emit toStartView();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::changeCity(QString cityId)
|
||||||
|
{
|
||||||
|
if (coreOperateTooOften()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit coreChangeCity(cityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::searchResult(QString inputText)
|
||||||
|
{
|
||||||
|
emit coreSearchResult(inputText);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStandardItemModel *CoreInteraction::getCityModel()
|
||||||
|
{
|
||||||
|
return coreGetCityModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStandardItemModel *CoreInteraction::getCollectModel()
|
||||||
|
{
|
||||||
|
return coreGetCollectModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::changeCityFromSearch(QModelIndex index)
|
||||||
|
{
|
||||||
|
if (coreOperateTooOften()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit corechangeCityFromSearch(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::addCollectCity(QModelIndex index)
|
||||||
|
{
|
||||||
|
if (coreOperateTooOften()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit coreAddCollectCity(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::changeCityFromCollect(QModelIndex index)
|
||||||
|
{
|
||||||
|
if (coreOperateTooOften()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit corechangeCityFromCollect(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreInteraction::delCollectCity(QModelIndex index)
|
||||||
|
{
|
||||||
|
if (coreOperateTooOften()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit coreDelCollectCity(index);
|
||||||
|
}
|
||||||
|
void CoreInteraction::loadCollectCity()
|
||||||
|
{
|
||||||
|
if (coreOperateTooOften()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit coreLoadCollect();
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
#ifndef COREINTERACTION_H
|
||||||
|
#define COREINTERACTION_H
|
||||||
|
#include <QThread>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <global/corevar.h>
|
||||||
|
#include "controller/core/core.h"
|
||||||
|
#include "controller/core/errorreact.h"
|
||||||
|
#include "controller/Interaction.h"
|
||||||
|
#include <QPersistentModelIndex>
|
||||||
|
//实际实现功能
|
||||||
|
class CoreInteraction : public Interaction
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void coreChangeCity(QString cityId); //切换城市
|
||||||
|
void corechangeCityFromSearch(QModelIndex index); //从搜索城市列表切换到目标城市
|
||||||
|
void coreAddCollectCity(QModelIndex index); //添加收藏城市
|
||||||
|
void corechangeCityFromCollect(QModelIndex index); //从收藏城市切换到目标城市
|
||||||
|
void coreDelCollectCity(QModelIndex index); //删除收藏城市列表中的城市
|
||||||
|
void coreSearchResult(QString inputText); //根据输入,匹配本地城市
|
||||||
|
void coreInitCore(); //不能跨线程调用,线程中使用信号槽来实现调用
|
||||||
|
void coreLoadCollect(); //加载收藏城市列表
|
||||||
|
void coreshowInCenter();
|
||||||
|
void coreClosePro();
|
||||||
|
void setAllowLocationYes();
|
||||||
|
void setAllowLocationNo();
|
||||||
|
void refreshCity();
|
||||||
|
QStandardItemModel *coreGetCityModel(); //设置搜索城市列表model
|
||||||
|
QStandardItemModel *coreGetCollectModel(); //设置收藏城市列表model
|
||||||
|
|
||||||
|
public:
|
||||||
|
CoreInteraction();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void creatCore(const QStringList &list); //初始化核心模块
|
||||||
|
virtual void changeCity(QString cityId); //切换城市
|
||||||
|
virtual void searchResult(QString inputText); //搜索本地城市进行匹配
|
||||||
|
virtual QStandardItemModel *getCityModel(); //获取搜索model指针
|
||||||
|
virtual QStandardItemModel *getCollectModel(); //获取收藏model指针
|
||||||
|
virtual void changeCityFromSearch(QModelIndex index); //从搜索城市切换到目标城市
|
||||||
|
virtual void addCollectCity(QModelIndex index); //添加收藏城市
|
||||||
|
virtual void changeCityFromCollect(QModelIndex index); //从收藏城市切换到目标城市
|
||||||
|
virtual void delCollectCity(QModelIndex index); //删除收藏城市列表中的城市
|
||||||
|
virtual void loadCollectCity(); //加载收藏城市列表
|
||||||
|
virtual void showCenterAfter();
|
||||||
|
virtual void closePrograme();
|
||||||
|
virtual void allowLocationYes();
|
||||||
|
virtual void allowLocationNo();
|
||||||
|
virtual void refresh();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initConnect(); //初始化绑定
|
||||||
|
bool coreOperateTooOften(); //操作过于频繁
|
||||||
|
|
||||||
|
bool m_isCoreInit = false; //防止多次初始化核心
|
||||||
|
QTimer *m_canProcess = nullptr; //限制操作频率,降低cpu占用
|
||||||
|
Core *m_core = nullptr; //核心对象
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void test();
|
||||||
|
|
||||||
|
// QString m_needStartWithOpenImagePath =
|
||||||
|
// "";//UI未初始化时设置,使其初始化完成立即加载图片---可以改成立即加载天气信息
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CoreINTERACTIONCoreH
|
|
@ -0,0 +1,61 @@
|
||||||
|
#include "errorreact.h"
|
||||||
|
ErrorReact *ErrorReact::m_errorReact = nullptr;
|
||||||
|
ErrorReact *ErrorReact::getInstance()
|
||||||
|
{
|
||||||
|
if (m_errorReact == nullptr) {
|
||||||
|
m_errorReact = new ErrorReact;
|
||||||
|
}
|
||||||
|
return m_errorReact;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorReact::ErrorReact() {}
|
||||||
|
//网络错误
|
||||||
|
void ErrorReact::networkFeedBack(bool isOnline, QString errorString)
|
||||||
|
{
|
||||||
|
if ("无网络" == errorString) {
|
||||||
|
emit netUiShow(tr("Network not connected!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit netUiShow(tr("Network error!"));
|
||||||
|
}
|
||||||
|
//请求服务器模块
|
||||||
|
void ErrorReact::serverFeedBack(bool isGetData, QString stateCode)
|
||||||
|
{
|
||||||
|
qDebug() << "请求服务器返回错误:异常等状况" << isGetData << stateCode;
|
||||||
|
emit serverUiShow(tr("Abnormal access address!"));
|
||||||
|
}
|
||||||
|
//数据解析模块
|
||||||
|
void ErrorReact::dataFeedBack(bool isDataError, QString dataError)
|
||||||
|
{
|
||||||
|
qDebug() << "数据解析错误" << isDataError << dataError;
|
||||||
|
emit dataUiShow(tr("Data parsing error!"));
|
||||||
|
}
|
||||||
|
//搜索有关---暂时不用,在core里处理
|
||||||
|
void ErrorReact::searchFeedBack(bool hasCity)
|
||||||
|
{
|
||||||
|
qDebug() << "搜索问题" << hasCity;
|
||||||
|
// if (hasCity == false) {
|
||||||
|
// //给搜索列表显示两个控件的显隐
|
||||||
|
// emit searchNull();
|
||||||
|
// }
|
||||||
|
// //结果如何-传递给前端搜索-收藏界面进行界面的调整和显示
|
||||||
|
// emit searchUiShow(hasCity);
|
||||||
|
}
|
||||||
|
//网络超时部分
|
||||||
|
void ErrorReact::networkTimeout(QString Timeout)
|
||||||
|
{
|
||||||
|
qDebug() << "超时:";
|
||||||
|
// Timeout--true:为主界面或者切换主界面超时,--false:为搜索部分超时
|
||||||
|
emit netTimeout(tr("Network Timeout!"));
|
||||||
|
}
|
||||||
|
//定位失败
|
||||||
|
void ErrorReact::geoFail(QString geoError)
|
||||||
|
{
|
||||||
|
qDebug() << "定位失败";
|
||||||
|
emit geoUiShow(tr("Seek failed!"));
|
||||||
|
}
|
||||||
|
//添加收藏城市等暂时无需界面显示的错误
|
||||||
|
void ErrorReact::collectAddError(QString collectAdd)
|
||||||
|
{
|
||||||
|
qDebug() << collectAdd;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef ERRORREACT_H
|
||||||
|
#define ERRORREACT_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDebug>
|
||||||
|
class ErrorReact : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
void networkFeedBack(bool isOnline, QString errorString); //网络错误码
|
||||||
|
void serverFeedBack(bool isGetData, QString stateCode); //服务器错误码
|
||||||
|
void dataFeedBack(bool isDataError, QString dataError); //数据解析错误码
|
||||||
|
void searchFeedBack(bool hasCity); //本地搜索错误
|
||||||
|
void networkTimeout(QString Timeout); //超时
|
||||||
|
void geoFail(QString geoError); //定位失败
|
||||||
|
void collectAddError(QString collectAdd); //添加城市异常
|
||||||
|
/*
|
||||||
|
* 接口功能:单例取指针
|
||||||
|
* 接口场景:程序启动时,首次调用要放到主界面构造函数的第一行
|
||||||
|
* 接口类型:函数,直接调用
|
||||||
|
* 返回类型:ErrorReact
|
||||||
|
* 返回描述:接口对象
|
||||||
|
*/
|
||||||
|
static ErrorReact *getInstance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ErrorReact();
|
||||||
|
static ErrorReact *m_errorReact;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void netUiShow(QString errorString); //网络错误详情
|
||||||
|
void serverUiShow(QString stateCode); //服务器错误码
|
||||||
|
void dataUiShow(QString dataError); //数据解析错误码
|
||||||
|
void geoUiShow(QString geoError); //定位失败
|
||||||
|
// void searchUiShow(bool hasCity);//搜索结果
|
||||||
|
// void searchNull();//搜索为空或输入为空
|
||||||
|
void netTimeout(QString isTimeout); //超时
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ERROR_H
|
|
@ -0,0 +1,126 @@
|
||||||
|
#include "viewcontrol.h"
|
||||||
|
viewControl *viewControl::m_viewControl = nullptr;
|
||||||
|
viewControl *viewControl::getInstance()
|
||||||
|
{
|
||||||
|
if (m_viewControl == nullptr) {
|
||||||
|
m_viewControl = new viewControl;
|
||||||
|
}
|
||||||
|
return m_viewControl;
|
||||||
|
}
|
||||||
|
viewControl::viewControl()
|
||||||
|
{
|
||||||
|
initConnect();
|
||||||
|
}
|
||||||
|
//信号槽
|
||||||
|
void viewControl::initConnect()
|
||||||
|
{
|
||||||
|
connect(Interaction::getInstance(), &Interaction::toStartView, this, &viewControl::autoStart); //启动前端
|
||||||
|
connect(Interaction::getInstance(), &Interaction::showInCenter, this,
|
||||||
|
&viewControl::toShowView); //目前没有用到,但之后横竖屏需要此信号
|
||||||
|
}
|
||||||
|
|
||||||
|
//初始化界面
|
||||||
|
void viewControl::autoStart()
|
||||||
|
{
|
||||||
|
showView(m_isStart);
|
||||||
|
ViewVar::initGsetting();
|
||||||
|
ViewVar::initFontSize();
|
||||||
|
}
|
||||||
|
//界面已经初始化之后,显示在屏幕中央
|
||||||
|
void viewControl::toShowView()
|
||||||
|
{
|
||||||
|
if (m_screen == false) {
|
||||||
|
if (m_horscreen != nullptr) {
|
||||||
|
showInCenter(m_horscreen);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_verscreen != nullptr) {
|
||||||
|
showInCenter(m_verscreen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//后端初始化
|
||||||
|
void viewControl::initCore(const QStringList &list, bool isStart)
|
||||||
|
{
|
||||||
|
//带showmainwindow 或 不带参
|
||||||
|
m_isStart = isStart;
|
||||||
|
//初始化后端
|
||||||
|
Interaction::getInstance()->creatCore(list);
|
||||||
|
}
|
||||||
|
//返回已经存在的widget,给qsingleapplication激活
|
||||||
|
QWidget *viewControl::activeWindow()
|
||||||
|
{
|
||||||
|
if (m_screen == false && m_horscreen != nullptr) {
|
||||||
|
return m_horscreen;
|
||||||
|
} else if (m_screen == true && m_verscreen != nullptr) {
|
||||||
|
return m_verscreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//确定横竖屏
|
||||||
|
void viewControl::showView(bool isStart)
|
||||||
|
{
|
||||||
|
//获得横竖屏信号 m_screen暂时用来判断
|
||||||
|
//确定是什么屏幕
|
||||||
|
if (m_screen == false) {
|
||||||
|
if (m_horscreen == nullptr) {
|
||||||
|
m_horscreen = new horscreen();
|
||||||
|
}
|
||||||
|
//如果不是开机自启动,而是双击desktop启动,show主界面
|
||||||
|
if (isStart == false) {
|
||||||
|
showInCenter(m_horscreen); //展示在屏幕中央
|
||||||
|
emit setActiveWidow(m_horscreen);
|
||||||
|
}
|
||||||
|
//竖屏存在时,不起竖屏,且deleter
|
||||||
|
if (m_verscreen == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_verscreen->isHidden()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_verscreen->hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//竖屏模式
|
||||||
|
if (m_verscreen == nullptr) {
|
||||||
|
m_verscreen = new verscreen();
|
||||||
|
}
|
||||||
|
if (m_isStart == false) {
|
||||||
|
showInCenter(m_verscreen);
|
||||||
|
emit setActiveWidow(m_verscreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_horscreen == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_horscreen->isHidden()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_horscreen->hide();
|
||||||
|
}
|
||||||
|
//显示在屏幕中央
|
||||||
|
void viewControl::showInCenter(QWidget *w)
|
||||||
|
{
|
||||||
|
//计算将窗口移动到屏幕中间,并show出来
|
||||||
|
if (!w->isVisible()) {
|
||||||
|
QDesktopWidget *m = QApplication::desktop();
|
||||||
|
QRect desk_rect = m->screenGeometry(m->screenNumber(QCursor::pos()));
|
||||||
|
int desk_x = desk_rect.width();
|
||||||
|
int desk_y = desk_rect.height();
|
||||||
|
int x = w->width();
|
||||||
|
int y = w->height();
|
||||||
|
w->move(desk_x / 2 - x / 2 + desk_rect.left(), desk_y / 2 - y / 2 + desk_rect.top());
|
||||||
|
}
|
||||||
|
w->showNormal();
|
||||||
|
w->raise();
|
||||||
|
w->activateWindow();
|
||||||
|
//为解决点击托盘,界面show不出来的问题,推断是底层将此信号给拦截了
|
||||||
|
QTimer *timer = new QTimer(this);
|
||||||
|
timer->setSingleShot(true);
|
||||||
|
connect(timer, &QTimer::timeout, this, [=] {
|
||||||
|
w->showNormal();
|
||||||
|
w->raise();
|
||||||
|
w->activateWindow();
|
||||||
|
});
|
||||||
|
connect(timer, &QTimer::timeout, timer, &QTimer::deleteLater);
|
||||||
|
timer->start(500);
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef VIEWCONTROL_H
|
||||||
|
#define VIEWCONTROL_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include "controller/Interaction.h"
|
||||||
|
#include "view/horscreen/horscreen.h"
|
||||||
|
#include "view/verscreen/verscreen.h"
|
||||||
|
|
||||||
|
class viewControl : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
viewControl();
|
||||||
|
void initCore(const QStringList &list, bool isStart); //初始化后端
|
||||||
|
QWidget *activeWindow();
|
||||||
|
static viewControl *getInstance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
horscreen *m_horscreen = nullptr;
|
||||||
|
verscreen *m_verscreen = nullptr;
|
||||||
|
bool m_screen = false; // false-横屏,true-竖屏
|
||||||
|
bool m_autoStart = false; //默认为开机自启,不显示主界面
|
||||||
|
bool m_isStart = true; //默认为不带showmainwindow启动
|
||||||
|
void showView(bool isStart); //实例化前端
|
||||||
|
void showInCenter(QWidget *w); //显示在屏幕中央
|
||||||
|
void initConnect(); //信号槽
|
||||||
|
static viewControl *m_viewControl;
|
||||||
|
public slots:
|
||||||
|
void autoStart(); //通知实例化界面
|
||||||
|
void toShowView(); //在界面打开之后,将界面展示在屏幕中间---暂时没有用到,之后横竖屏会用到
|
||||||
|
signals:
|
||||||
|
void setActiveWidow(QWidget *w); //通知激活窗口
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VIEWCONTROL_H
|
|
@ -0,0 +1,5 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/data">
|
||||||
|
<file>data/china-city-list.csv</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 700 B |
After Width: | Height: | Size: 220 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 163 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 9.0 KiB |
|
@ -0,0 +1,28 @@
|
||||||
|
# Weather
|
||||||
|
## Summary
|
||||||
|
Weather is an app that provides weather and life index information. By obtaining the authoritative meteorological data, you can view the weather conditions and living index information (such as ultraviolet index, air index, etc.) of each city in the next week in real time. You can automatically locate the current city and add a city by yourself.
|
||||||
|
|
||||||
|
### Open mode
|
||||||
|
|
||||||
|
“open menu”![](image/1.png)>“weather” or “taskbar”>“search”![](image/2.png)>“weather”
|
||||||
|
|
||||||
|
![Fig 1 Eyes of Pictures-big](image/3.png)
|
||||||
|
|
||||||
|
### Basic Operation
|
||||||
|
|
||||||
|
Open the application for the first time, and automatically obtain and display the weather conditions and life index information of Beijing when the network is connected; If the system is not connected to the network, a pop-up prompt of "network error" will pop up after opening the application.
|
||||||
|
|
||||||
|
After selecting "switch" in the interface, you can select a city from the displayed popular cities to switch, or you can search any city in the country in the search bar and select "+" to add the city to the favorite city and click the city to switch.
|
||||||
|
|
||||||
|
![Fig 2 change city-big](image/4.png)
|
||||||
|
|
||||||
|
![Fig 3 search City-big](image/5.png)
|
||||||
|
|
||||||
|
Click the navigation bar of “![](image/6.png)”can open the weather menu bar。After you choice "Allow Locate">"Yes",the application can automatically locate the current city, obtain and display the weather conditions and life index information of the city.
|
||||||
|
|
||||||
|
After you click the menu bar of “help”,it will automatically jump to the user manual,and you can view the operating instructions of the application. Click "about" in the menu bar to view the current version information, and select "exit" to close the application.
|
||||||
|
|
||||||
|
![Fig 4 menu bar-big](image/7.png)
|
||||||
|
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 700 B |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 155 KiB |
After Width: | Height: | Size: 161 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 80 KiB |
|
@ -0,0 +1,26 @@
|
||||||
|
# 天气
|
||||||
|
## 概 述
|
||||||
|
天气是一款能获取天气及生活指数信息的应用软件。通过获取权威气象数据可以实时查看全国各城市未来一周的天气状况及生活指数信息(如紫外线指数、空气指数等),支持自动定位当前所在城市、自定义添加城市。
|
||||||
|
|
||||||
|
### 打开方式
|
||||||
|
|
||||||
|
“开始菜单”![](image/1.png)>“天气”或“任务栏”>“搜索”![](image/2.png)>“天气”
|
||||||
|
|
||||||
|
![图1 天气主界面-big](image/3.png)
|
||||||
|
|
||||||
|
### 基本操作
|
||||||
|
|
||||||
|
首次打开应用,在已连接网络的情况下,自动获取并显示北京的天气状况及生活指数信息;若系统未连接网络,打开应用后会弹出“网络错误”的弹窗提示。
|
||||||
|
|
||||||
|
在界面中选择“切换”后,可以在展示的热门城市中选择城市进行切换,也可以在搜索栏中搜索全国的任一城市并选择“+”将该城市添加到收藏城市后点击该城市进行切换。
|
||||||
|
|
||||||
|
![图2 切换城市-big](image/4.png)
|
||||||
|
|
||||||
|
![图3 搜索城市-big](image/5.png)
|
||||||
|
|
||||||
|
点击导航栏中的“![](image/6.png)”可打开天气菜单栏。选择“允许定位”> “是”后,应用可以自动定位当前所在城市,获取并显示所在城市的天气状况及生活指数信息。
|
||||||
|
|
||||||
|
点击菜单栏中的“帮助”将自动跳转至用户手册中,可查看该应用的操作说明。点击菜单栏中的“关于”可查看当前版本信息,选择“退出”可关闭应用。
|
||||||
|
|
||||||
|
![图4 天气下拉菜单-big](image/7.png)
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<schemalist gettext-domain="kylin-weather">
|
||||||
|
<schema id="org.kylin-weather.settings" path="/org/ukui/kylin-weather/">
|
||||||
|
<key name="collect-city" type="s">
|
||||||
|
<default>""</default>
|
||||||
|
<summary>collectcity</summary>
|
||||||
|
<description>collectCity</description>
|
||||||
|
</key>
|
||||||
|
<key name="weather" type="s">
|
||||||
|
<default>"1920-08-27 10:17:42,101010100,海淀,小雨,95%,25℃,北风,1级,北京,305"</default>
|
||||||
|
<summary>thisweather</summary>
|
||||||
|
<description>current weather of this city</description>
|
||||||
|
</key>
|
||||||
|
<key name="allow-locate" type="s">
|
||||||
|
<default>"0"</default>
|
||||||
|
<summary>allowlocate</summary>
|
||||||
|
<description>if user allow locate or not</description>
|
||||||
|
</key>
|
||||||
|
<key name="thememode" type="s">
|
||||||
|
<default>"auto"</default>
|
||||||
|
<summary>"record theme mode"</summary>
|
||||||
|
<description>record theme mode.there's three mode.auto,lightonly and darkonly</description>
|
||||||
|
</key>
|
||||||
|
<key name="locate-widget" type="s">
|
||||||
|
<default>"0"</default>
|
||||||
|
<summary>locatewidget</summary>
|
||||||
|
<description>if user allow locate or not</description>
|
||||||
|
</key>
|
||||||
|
<key name="ipkeypart" type="s">
|
||||||
|
<default>"ZWRkZWZmNCZ0eXBlPTQmaXA9"</default>
|
||||||
|
<summary>ipkey</summary>
|
||||||
|
<description>ipkey</description>
|
||||||
|
</key>
|
||||||
|
</schema>
|
||||||
|
</schemalist>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<schemalist gettext-domain="ukui-log4qt-kylin-weather">
|
||||||
|
<schema id="org.ukui.ukui-log4qt-kylin-weather" path="/org/ukui/ukui-log4qt-kylin-weather/">
|
||||||
|
<key type="s" name="log4j-handleqtmessages">
|
||||||
|
<default>"true"</default>
|
||||||
|
<summary>hook qt messages</summary>
|
||||||
|
<description>Control if hook qt messages</description>
|
||||||
|
</key>
|
||||||
|
<key type="s" name="log4j-rootlogger">
|
||||||
|
<default>"DEBUG,console,daily"</default>
|
||||||
|
<summary>config rootLogger's level and appenders</summary>
|
||||||
|
<description>config rootLogger's level and appenders:"level,appender"</description>
|
||||||
|
</key>
|
||||||
|
<key type="s" name="log4j-appender-daily-datepattern">
|
||||||
|
<default>".yyyy-MM-dd"</default>
|
||||||
|
<summary>daily log file pattern</summary>
|
||||||
|
<description>set daily log file pattern format:one day</description>
|
||||||
|
</key>
|
||||||
|
<key type="s" name="log4j-appender-daily-layout-conversionpattern">
|
||||||
|
<default>"%d{yyyy-MM-dd HH:mm:ss,zzz}(%-4r)[%t]|%-5p| - %m%n"</default>
|
||||||
|
<summary>set log message's format</summary>
|
||||||
|
<description>set log message's format</description>
|
||||||
|
</key>
|
||||||
|
<key type="i" name="delaytime">
|
||||||
|
<default>3600</default>
|
||||||
|
<summary>set check log files delay time</summary>
|
||||||
|
<description>set check log files delay time</description>
|
||||||
|
</key>
|
||||||
|
<key type="i" name="maxfilecount">
|
||||||
|
<default>7</default>
|
||||||
|
<summary>set log files count</summary>
|
||||||
|
<description>set log files count,unit s</description>
|
||||||
|
</key>
|
||||||
|
<key type="i" name="maxfilesize">
|
||||||
|
<default>512</default>
|
||||||
|
<summary>set log files total size</summary>
|
||||||
|
<description>set log files total size, unit M</description>
|
||||||
|
</key>
|
||||||
|
</schema>
|
||||||
|
</schemalist>
|
|
@ -0,0 +1,141 @@
|
||||||
|
#include "corevar.h"
|
||||||
|
|
||||||
|
//项目名称
|
||||||
|
const QString CoreVar::PROGRAM_NAME = QString("kylin-weather");
|
||||||
|
// DBUS服务名称
|
||||||
|
const QString CoreVar::WEATHER_DBUS_SERVICENAME = QString("org.ukui.kylin_weather");
|
||||||
|
// DBUS路径
|
||||||
|
const QString CoreVar::WEATHER_DBUS_PARH = QString("/");
|
||||||
|
// DBUS接口
|
||||||
|
const QString CoreVar::WEATHER_DBUS_INTERFACE = QString("kylin_weather.commands");
|
||||||
|
//高德定位url
|
||||||
|
const QString CoreVar::PCONLINEURL = QString("http://whois.pconline.com.cn/");
|
||||||
|
// ipip定位url
|
||||||
|
const QString CoreVar::IPIP = QString("http://myip.ipip.net");
|
||||||
|
//除ip外完整定位url
|
||||||
|
QString CoreVar::URLHEAD = QString("http://restapi.amap.com/v5/");
|
||||||
|
// url的key--需要申请
|
||||||
|
// const QString CoreVar::URLKEY = QString("faf8faad4c9c070879bebe615eddeff4");
|
||||||
|
//服务器url
|
||||||
|
const QString CoreVar::SERVICEREQUEST =
|
||||||
|
QString("http://weather.ubuntukylin.com:8001/weather/api/3.0/heweather_data_s6/%1/");
|
||||||
|
//收藏城市
|
||||||
|
const QString CoreVar::SERVICEREQUEST_COLLECT =
|
||||||
|
QString("http://weather.ubuntukylin.com:8001/weather/api/3.0/heweather_simple_s6/?cityids=");
|
||||||
|
|
||||||
|
//服务器url -intel
|
||||||
|
// const QString CoreVar::SERVICEREQUEST = QString("http://edu.kylinos.cn:8001/weather/api/3.0/heweather_data_s6/%1/");
|
||||||
|
//收藏城市
|
||||||
|
// const QString CoreVar::SERVICEREQUEST_COLLECT =
|
||||||
|
// QString("http://edu.kylinos.cn:8001/weather/api/3.0/heweather_simple_s6/?cityids=");
|
||||||
|
|
||||||
|
// QGSettings服务名称
|
||||||
|
const QString CoreVar::WEATHER_GSETTINGS_SERVICENAME = QString("org.kylin-weather.settings");
|
||||||
|
// GSettings
|
||||||
|
QGSettings *CoreVar::m_settings = CoreVar::getSettings();
|
||||||
|
//支持的命令列表
|
||||||
|
const QMap<QString, QString> CoreVar::SUPPORT_CMD = CoreVar::getSupportCmd();
|
||||||
|
const int CoreVar::REFRESH_RATE = 15; //刷新间隔
|
||||||
|
const int CoreVar::SEARCHCITYNUM = 42; //搜索城市列表2页的数量
|
||||||
|
const QSize CoreVar::CITYITEM = QSize(156, 36); //城市item的大小
|
||||||
|
const QString CoreVar::API_TYPE = QString("$api$"); //是否为外部作为API调用的标识
|
||||||
|
const QStringList CoreVar::WEATHER_CODE_TMP = CoreVar::temList();
|
||||||
|
const QString CoreVar::DEFAULT_CITYID = QString("101010100");
|
||||||
|
const int CoreVar::DEFAULT_TIMEOUT = 30000; // 30s
|
||||||
|
QGSettings *CoreVar::getSettings()
|
||||||
|
{
|
||||||
|
QGSettings *mysetting = nullptr;
|
||||||
|
if (QGSettings::isSchemaInstalled(WEATHER_GSETTINGS_SERVICENAME.toLocal8Bit())) {
|
||||||
|
mysetting = new QGSettings(WEATHER_GSETTINGS_SERVICENAME.toLocal8Bit());
|
||||||
|
}
|
||||||
|
return mysetting;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, QString> CoreVar::getSupportCmd()
|
||||||
|
{
|
||||||
|
QMap<QString, QString> cmds;
|
||||||
|
cmds.insert("-changeCity", "切换城市");
|
||||||
|
return cmds;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList CoreVar::temList()
|
||||||
|
{
|
||||||
|
QStringList tmp;
|
||||||
|
tmp << "100"
|
||||||
|
<< "101"
|
||||||
|
<< "102"
|
||||||
|
<< "103"
|
||||||
|
<< "104"
|
||||||
|
<< "150"
|
||||||
|
<< "153"
|
||||||
|
<< "154"
|
||||||
|
<< "300"
|
||||||
|
<< "301"
|
||||||
|
<< "302"
|
||||||
|
<< "303"
|
||||||
|
<< "304"
|
||||||
|
<< "305"
|
||||||
|
<< "306"
|
||||||
|
<< "307"
|
||||||
|
<< "308"
|
||||||
|
<< "309"
|
||||||
|
<< "310"
|
||||||
|
<< "311"
|
||||||
|
<< "312"
|
||||||
|
<< "313"
|
||||||
|
<< "314"
|
||||||
|
<< "315"
|
||||||
|
<< "316"
|
||||||
|
<< "317"
|
||||||
|
<< "318"
|
||||||
|
<< "399"
|
||||||
|
<< "350"
|
||||||
|
<< "351"
|
||||||
|
<< "400"
|
||||||
|
<< "401"
|
||||||
|
<< "402"
|
||||||
|
<< "403"
|
||||||
|
<< "404"
|
||||||
|
<< "405"
|
||||||
|
<< "406"
|
||||||
|
<< "407"
|
||||||
|
<< "408"
|
||||||
|
<< "409"
|
||||||
|
<< "410"
|
||||||
|
<< "499"
|
||||||
|
<< "456"
|
||||||
|
<< "457"
|
||||||
|
<< "500"
|
||||||
|
<< "501"
|
||||||
|
<< "502"
|
||||||
|
<< "503"
|
||||||
|
<< "504"
|
||||||
|
<< "507"
|
||||||
|
<< "508"
|
||||||
|
<< "509"
|
||||||
|
<< "510"
|
||||||
|
<< "511"
|
||||||
|
<< "512"
|
||||||
|
<< "513"
|
||||||
|
<< "514"
|
||||||
|
<< "515"
|
||||||
|
<< "900"
|
||||||
|
<< "901"
|
||||||
|
<< "101";
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//写入配置文件
|
||||||
|
void CoreVar::setSettings(const QString &key, const QVariant &value)
|
||||||
|
{
|
||||||
|
m_settings->set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//读取配置文件
|
||||||
|
QVariant CoreVar::getSettings(const QString &key)
|
||||||
|
{
|
||||||
|
QVariant setting;
|
||||||
|
setting = m_settings->get(key);
|
||||||
|
return setting;
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
#ifndef COREVAR_H
|
||||||
|
#define COREVAR_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QGSettings>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QSize>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <QTranslator>
|
||||||
|
|
||||||
|
//当前城市
|
||||||
|
struct CurrentWeather
|
||||||
|
{
|
||||||
|
QString id = "101010100"; //城市id
|
||||||
|
QString city = "N/A"; //城市名字
|
||||||
|
QString updatetime = "N/A"; //更新时间--服务器时间
|
||||||
|
QString cond_code = "999"; //实况天气状况代码 默认999
|
||||||
|
QString cond_txt = "N/A"; //实况天气状况描述 晴
|
||||||
|
QString hum = "N/A"; //相对湿度 40
|
||||||
|
QString tmp = "N/A"; //温度,默认单位:摄氏度℃ 21
|
||||||
|
QString wind_dir = "N/A"; //风向 西北
|
||||||
|
QString wind_sc = "N/A"; //风力 3 (0:静风 1:1级风)
|
||||||
|
QString serveTime = "N/A"; //天气信息的更新时间
|
||||||
|
};
|
||||||
|
//本地城市列表
|
||||||
|
struct LocationData
|
||||||
|
{
|
||||||
|
QString id; //城市id
|
||||||
|
QString city_en; //城市/县区-英文
|
||||||
|
QString city; //城市/县区-中文
|
||||||
|
QString country_en; //国家-中文
|
||||||
|
QString country; //国家-中文
|
||||||
|
QString province_en; //省-英文
|
||||||
|
QString province; //省-中文
|
||||||
|
QString admin_district_en; //市-英文
|
||||||
|
QString admin_district; //市-中文
|
||||||
|
QString shorthand; //首字母缩写
|
||||||
|
};
|
||||||
|
//每一个收藏列表item的信息
|
||||||
|
struct CollectItemData
|
||||||
|
{
|
||||||
|
QString cityId = "";
|
||||||
|
QString cityName = "";
|
||||||
|
QString cond_code = "999"; //实况天气状况代码--转换为icon
|
||||||
|
QString tmp = "-"; //温度
|
||||||
|
};
|
||||||
|
//每一个搜索列表item的信息
|
||||||
|
struct ItemData
|
||||||
|
{
|
||||||
|
QString cityId = "";
|
||||||
|
QString cityName = "";
|
||||||
|
};
|
||||||
|
//某一天的详细信息
|
||||||
|
struct oneDay
|
||||||
|
{
|
||||||
|
QString cond_code_d = "999"; //白天天气状况代码 默认999
|
||||||
|
QString cond_code_n = "999"; //晚间天气状况代码 默认999
|
||||||
|
QString cond_txt_d = "N/A"; //白天天气状况描述 晴
|
||||||
|
QString cond_txt_n = "N/A"; //晚间天气状况描述 晴
|
||||||
|
QString forcast_date = "N/A"; //预报日期 2013-12-30
|
||||||
|
QString wind_dir = "N/A"; //风向 西北风
|
||||||
|
QString wind_sc = "N/A"; //风力 1-2 (级风)
|
||||||
|
QString date = "N/A"; //日期
|
||||||
|
QString dateTime = "N/A"; //当前城市信息更新日期
|
||||||
|
QString tmp_max = "N/A"; //最高气温
|
||||||
|
QString tmp_min = "N/A"; //最低气温
|
||||||
|
};
|
||||||
|
|
||||||
|
//预测天气
|
||||||
|
struct ForecastWeather
|
||||||
|
{
|
||||||
|
oneDay first;
|
||||||
|
oneDay second;
|
||||||
|
oneDay third;
|
||||||
|
oneDay fourth;
|
||||||
|
oneDay fifth;
|
||||||
|
oneDay sixth;
|
||||||
|
oneDay seventh;
|
||||||
|
};
|
||||||
|
// QList<oneDay> ForecastWeather;
|
||||||
|
//逐小时天气
|
||||||
|
struct Hourly
|
||||||
|
{
|
||||||
|
QString cond_code = "999"; // "100" 默认999
|
||||||
|
QString cond_txt = "N/A"; // "晴"
|
||||||
|
QString time = "N/A"; // "2021-09-24 16:00"
|
||||||
|
QString tmp = "N/A"; // "36"
|
||||||
|
};
|
||||||
|
|
||||||
|
//生活指数
|
||||||
|
struct LifeStyle
|
||||||
|
{
|
||||||
|
QString air_brf = "N/A"; //空气指数
|
||||||
|
QString cw_brf = "N/A"; //洗车指数
|
||||||
|
QString drsg_brf = "N/A"; //穿衣指数
|
||||||
|
QString flu_brf = "N/A"; //感冒指数
|
||||||
|
QString sport_brf = "N/A"; //运动指数
|
||||||
|
QString uv_brf = "N/A"; //紫外线指数
|
||||||
|
};
|
||||||
|
// QMap <QString,ItemData>SearchList;
|
||||||
|
Q_DECLARE_METATYPE(CurrentWeather) // QVarant 注册自定义类型
|
||||||
|
Q_DECLARE_METATYPE(LocationData) // QVarant 注册自定义类型
|
||||||
|
Q_DECLARE_METATYPE(ForecastWeather) // QVarant 注册自定义类型
|
||||||
|
Q_DECLARE_METATYPE(LifeStyle) // QVarant 注册自定义类型
|
||||||
|
Q_DECLARE_METATYPE(ItemData) // QVarant 注册自定义类型
|
||||||
|
Q_DECLARE_METATYPE(CollectItemData) // QVarant 注册自定义类型
|
||||||
|
Q_DECLARE_METATYPE(oneDay) // QVarant 注册自定义类型
|
||||||
|
Q_DECLARE_METATYPE(Hourly) // QVarant 注册自定义类型
|
||||||
|
class CoreVar : public QObject
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const QString PROGRAM_NAME; //项目名称
|
||||||
|
static const QString WEATHER_DBUS_SERVICENAME; // DBUS服务名称
|
||||||
|
static const QString WEATHER_DBUS_PARH; // DBUS路径
|
||||||
|
static const QString WEATHER_DBUS_INTERFACE; // DBUS接口
|
||||||
|
static const QString WEATHER_GSETTINGS_SERVICENAME; // QGSettings服务名称
|
||||||
|
static const QString PCONLINEURL; //高德定位url---得到ip
|
||||||
|
static const QString IPIP; // ipip定位url---得到ip
|
||||||
|
static QString URLHEAD; //除ip外完整定位url
|
||||||
|
// static const QString URLKEY; // url的key--需要申请
|
||||||
|
static const QString SERVICEREQUEST; //服务器url
|
||||||
|
static const QString SERVICEREQUEST_COLLECT; //服务器收藏城市url
|
||||||
|
static const QMap<QString, QString> SUPPORT_CMD; //支持的命令列表
|
||||||
|
|
||||||
|
static const int REFRESH_RATE; //刷新间隔
|
||||||
|
|
||||||
|
|
||||||
|
static const QString API_TYPE;
|
||||||
|
static const int SEARCHCITYNUM; //搜索城市列表2页的数量
|
||||||
|
static const QSize CITYITEM; //城市item的大小
|
||||||
|
static void setSettings(const QString &key, const QVariant &value); //写入配置文件
|
||||||
|
static QVariant getSettings(const QString &key); //读取配置文件
|
||||||
|
static const QStringList WEATHER_CODE_TMP; //临时用--逐小时
|
||||||
|
static const QString DEFAULT_CITYID;
|
||||||
|
static const int DEFAULT_TIMEOUT; //刷新间隔
|
||||||
|
private:
|
||||||
|
static QGSettings *m_settings; //配置文件对象
|
||||||
|
static QGSettings *getSettings(); //初始化gsettings
|
||||||
|
static QMap<QString, QString> getSupportCmd(); //创建支持的命令列表
|
||||||
|
static QStringList temList(); //临时用--逐小时
|
||||||
|
};
|
||||||
|
#endif // VARIABLE_H
|
|
@ -0,0 +1,209 @@
|
||||||
|
#include "viewvar.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
ViewVar *ViewVar::m_viewVar(nullptr);
|
||||||
|
|
||||||
|
ViewVar *ViewVar::getInstance()
|
||||||
|
{
|
||||||
|
if (m_viewVar == nullptr) {
|
||||||
|
m_viewVar = new ViewVar;
|
||||||
|
}
|
||||||
|
return m_viewVar;
|
||||||
|
}
|
||||||
|
|
||||||
|
//热门城市列表
|
||||||
|
QMap<int, QStringList> ViewVar::HOTCITY_MAP = ViewVar::saveHotCity(); //热门城市列表
|
||||||
|
//城市item--收藏和搜索
|
||||||
|
QColor ViewVar::s_colorItem = QColor(120, 120, 120);
|
||||||
|
QColor ViewVar::s_colorWid = QColor(246, 246, 246, 0);
|
||||||
|
QColor ViewVar::s_colorSearch = QColor(246, 246, 246, 1);
|
||||||
|
const QSize ViewVar::COLLECT_BTNSIZE = QSize(36, 36); //收藏城市按钮大小
|
||||||
|
//按钮位置
|
||||||
|
const int ViewVar::COLLECT_BTNXL = 155;
|
||||||
|
const int ViewVar::COLLECT_BTNYL = 4;
|
||||||
|
const int ViewVar::COLLECT_BTNXR = -10;
|
||||||
|
const int ViewVar::COLLECT_BTNYR = -8;
|
||||||
|
//文字位置
|
||||||
|
const int ViewVar::COLLECT_NAMEXL = 4;
|
||||||
|
const int ViewVar::COLLECT_TMPXL = 120;
|
||||||
|
const int ViewVar::COLLECT_CODEXL = 65;
|
||||||
|
//文字位置-same
|
||||||
|
const int ViewVar::COLLECT_SAMEYL = 4;
|
||||||
|
const int ViewVar::COLLECT_SAMEXR = -4;
|
||||||
|
const int ViewVar::COLLECT_SAMEYR = -4;
|
||||||
|
//图标位置
|
||||||
|
const int ViewVar::COLLECT_ICONXL = 80;
|
||||||
|
const int ViewVar::COLLECT_ICONYL = 4;
|
||||||
|
const int ViewVar::COLLECT_ICONXR = -144;
|
||||||
|
const int ViewVar::COLLECT_ICONYR = -6;
|
||||||
|
//按钮位置
|
||||||
|
const int ViewVar::SEARCH_BTNXL = 120;
|
||||||
|
const int ViewVar::SEARCH_BTNYL = 4;
|
||||||
|
const int ViewVar::SEARCH_BTNXR = -10;
|
||||||
|
const int ViewVar::SEARCH_BTNYR = -10;
|
||||||
|
//文字位置
|
||||||
|
const int ViewVar::SEARCH_NAMEXL = 4;
|
||||||
|
const int ViewVar::SEARCH_NAMEYL = 4;
|
||||||
|
const int ViewVar::SEARCH_NAMEXR = -4;
|
||||||
|
const int ViewVar::SEARCH_NAMEYR = -4;
|
||||||
|
const QString ViewVar::COLLECT_ICONPATH = QString(":/res/weather-icon/PNG16/2x/");
|
||||||
|
const QString ViewVar::COLLECT_ICONSUFFIX = QString(".png"); //图标后缀
|
||||||
|
QPen ViewVar::m_collectPen = QPen(Qt::black);
|
||||||
|
|
||||||
|
const QRect ViewVar::COLLECT_ITEMRECT = QRect(0, 0, 170, 170); //收藏城市item位置
|
||||||
|
const QRect ViewVar::SEARCH_ITEMRECT = QRect(0, 0, 170, 170); //收藏城市item位置
|
||||||
|
const qreal ViewVar::SAME_ITEMRADIUS = 6; //收藏和搜索列表城市item圆角
|
||||||
|
//透明度设置
|
||||||
|
const qreal ViewVar::SAME_OPACITY_0 = 0;
|
||||||
|
const qreal ViewVar::SAME_OPACITY_1 = 0.2;
|
||||||
|
const qreal ViewVar::SAME_OPACITY_2 = 1;
|
||||||
|
|
||||||
|
bool ViewVar::s_themeStyle = true; //默认浅色
|
||||||
|
//收藏
|
||||||
|
const QSize ViewVar::COLLECT = QSize(595, 141);
|
||||||
|
const QSize ViewVar::COLLECT_LIST = QSize(580, 115);
|
||||||
|
const QPoint ViewVar::COLLECT_TITLE = QPoint(8, 0);
|
||||||
|
const int ViewVar::NONECITYX = 10;
|
||||||
|
const int ViewVar::CITYLISTX = 14;
|
||||||
|
const int ViewVar::COLLECT_ITEMH = 36;
|
||||||
|
const int ViewVar::COLLECT_ITEMW = 185;
|
||||||
|
//热门
|
||||||
|
const QSize ViewVar::HOT = QSize(595, 128); //热门
|
||||||
|
const QSize ViewVar::HOT_LIST = QSize(595, 98); //热门城市列表
|
||||||
|
const QPoint ViewVar::HOT_TITLE = QPoint(8, 0); //热门-title
|
||||||
|
const int ViewVar::HOTLISTX = 0; //热门城市list x值
|
||||||
|
const int ViewVar::ITEM_LENGTHM = 2; //热门城市文字长度最大值
|
||||||
|
const int ViewVar::ITEM_NUM = 8; //热门城市每行数量
|
||||||
|
const int ViewVar::ITEM_NUMM = 17; //热门城市每行数量
|
||||||
|
const int ViewVar::ITEM_POS = (46 + 17); //热门城市item的间隔值
|
||||||
|
const int ViewVar::ITEM_DIS0 = 9; //热门城市个数值-行1
|
||||||
|
const int ViewVar::ITEM_DIS2 = 18; //热门城市个数值-行2
|
||||||
|
//热门-按钮大小
|
||||||
|
const QSize ViewVar::HOT_BTN = QSize(79, 28);
|
||||||
|
//搜索框
|
||||||
|
const QSize ViewVar::SEARCH_BOX = QSize(244, 36);
|
||||||
|
//搜索框文本间距--左上右下
|
||||||
|
const QMargins ViewVar::SEARCH_MARGINS = QMargins(34, 0, 0, 0);
|
||||||
|
//搜索框-图标控件大小
|
||||||
|
const QSize ViewVar::SEARCH_ICON = QSize(16, 16);
|
||||||
|
//搜索框-图标位置-x
|
||||||
|
const int ViewVar::SEARCH_ICON_X0 = 97 - 8;
|
||||||
|
const int ViewVar::SEARCH_ICON_X1 = 9;
|
||||||
|
|
||||||
|
//搜索列表-个尺寸大小
|
||||||
|
const QSize ViewVar::SEARCH_LIST = QSize(538, 287);
|
||||||
|
const int ViewVar::SEARCH_ITEMH = 41; //搜索城市item height值
|
||||||
|
const int ViewVar::SEARCH_ITEMW = 170; //搜索城市item weight值
|
||||||
|
const int ViewVar::SEARCH_NONEW = 500; //搜索城市无city的控件宽度值
|
||||||
|
//搜索-收藏-总界面
|
||||||
|
const QSize ViewVar::SEARCH = QSize(610, 350);
|
||||||
|
//搜索框位置-y值
|
||||||
|
const int ViewVar::SEARCH_BOXY = 8;
|
||||||
|
const QPoint ViewVar::SEARCHLIST_POS = QPoint(46, 54); //搜索列表位置
|
||||||
|
const int ViewVar::SEARCH_CHANGECITYX = 8;
|
||||||
|
const int ViewVar::DISTANCE0 = 10; //间隔0--热门和收藏的相互间距
|
||||||
|
const int ViewVar::DISTANCE1 = 16; //间隔1--热门和收藏与搜索框的相互间距
|
||||||
|
QString ViewVar::icon_path = QString(":/res/weather-icon/PNG48/1x/");
|
||||||
|
QStringList ViewVar::platFormList = {"V10SP1-edu"};
|
||||||
|
QString ViewVar::platForm = ViewVar::platFormType();
|
||||||
|
QStringList ViewVar::hotMap(QString city, QString cityId)
|
||||||
|
{
|
||||||
|
QStringList hotcity;
|
||||||
|
hotcity.append(city);
|
||||||
|
hotcity.append(cityId);
|
||||||
|
return hotcity;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<int, QStringList> ViewVar::saveHotCity()
|
||||||
|
{
|
||||||
|
QMap<int, QStringList> hotcity;
|
||||||
|
|
||||||
|
hotcity.insert(0, hotMap(tr("Beijing"), "101010100"));
|
||||||
|
hotcity.insert(1, hotMap(tr("Shanghai"), "101020100"));
|
||||||
|
hotcity.insert(2, hotMap(tr("Guangzhou"), "101280101"));
|
||||||
|
hotcity.insert(3, hotMap(tr("Shenzhen"), "101280601"));
|
||||||
|
hotcity.insert(4, hotMap(tr("Chengdu"), "101270101"));
|
||||||
|
hotcity.insert(5, hotMap(tr("Wuhan"), "101200101"));
|
||||||
|
hotcity.insert(6, hotMap(tr("Chongqing"), "101040100"));
|
||||||
|
hotcity.insert(7, hotMap(tr("Hangzhou"), "101210101"));
|
||||||
|
hotcity.insert(8, hotMap(tr("Nanjing"), "101190101"));
|
||||||
|
hotcity.insert(9, hotMap(tr("Taibei"), "101340101"));
|
||||||
|
hotcity.insert(10, hotMap(tr("Suzhou"), "101190401"));
|
||||||
|
hotcity.insert(11, hotMap(tr("Tianjin"), "101030100"));
|
||||||
|
hotcity.insert(12, hotMap(tr("Qingdao"), "101120201"));
|
||||||
|
hotcity.insert(13, hotMap(tr("Changsha"), "101250101"));
|
||||||
|
hotcity.insert(14, hotMap(tr("Zhengzhou"), "101180101"));
|
||||||
|
hotcity.insert(15, hotMap(tr("Xian"), "101110101"));
|
||||||
|
hotcity.insert(16, hotMap(tr("Wuxi"), "101190201"));
|
||||||
|
hotcity.insert(17, hotMap(tr("Jinan"), "101120101"));
|
||||||
|
hotcity.insert(18, hotMap(tr("Hongkong"), "101320101"));
|
||||||
|
hotcity.insert(19, hotMap(tr("Macao"), "101330101")); // Macao
|
||||||
|
hotcity.insert(20, hotMap(tr("Lasa"), "101140101"));
|
||||||
|
hotcity.insert(21, hotMap(tr("Lijiang"), "101291401"));
|
||||||
|
return hotcity;
|
||||||
|
}
|
||||||
|
void ViewVar::initGsetting()
|
||||||
|
{
|
||||||
|
connect(kdk::kabase::Gsettings::getPoint(), &kdk::kabase::Gsettings::systemThemeChange, ViewVar::getInstance(),
|
||||||
|
[=]() {
|
||||||
|
monitorGsetting();
|
||||||
|
});
|
||||||
|
monitorGsetting();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewVar::initFontSize()
|
||||||
|
{
|
||||||
|
connect(kdk::kabase::Gsettings::getPoint(), &kdk::kabase::Gsettings::systemFontSizeChange, ViewVar::getInstance(),
|
||||||
|
[=]() {
|
||||||
|
//获取字号的值
|
||||||
|
int fontSizeKey = kdk::kabase::Gsettings::getSystemFontSize().toInt();
|
||||||
|
//发送改变信号
|
||||||
|
if (fontSizeKey > 0) {
|
||||||
|
if (fontSizeKey > 15) {
|
||||||
|
fontSizeKey = 15;
|
||||||
|
}
|
||||||
|
emit ViewVar::getInstance()->setFontSizeSignal(fontSizeKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//启动时设置字号
|
||||||
|
int fontSizeKey = 11; //系统默认字号
|
||||||
|
int fontSizeKeyTmp = kdk::kabase::Gsettings::getSystemFontSize().toInt();
|
||||||
|
if (fontSizeKeyTmp > 0) {
|
||||||
|
fontSizeKey = fontSizeKeyTmp;
|
||||||
|
}
|
||||||
|
if (fontSizeKey > 15) {
|
||||||
|
fontSizeKey = 15;
|
||||||
|
}
|
||||||
|
emit ViewVar::getInstance()->setFontSizeSignal(fontSizeKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
//监听主题配置文件
|
||||||
|
void ViewVar::monitorGsetting()
|
||||||
|
{
|
||||||
|
QString themeStyle = kdk::kabase::Gsettings::getSystemTheme().toString();
|
||||||
|
if ("ukui-dark" == themeStyle || "ukui-black" == themeStyle) {
|
||||||
|
ViewVar::s_colorItem = QColor(255, 255, 255, 255 * 0.6);
|
||||||
|
ViewVar::s_colorWid = QColor(0, 0, 0, 0);
|
||||||
|
ViewVar::s_colorSearch = QColor(0, 0, 0, 1);
|
||||||
|
ViewVar::m_collectPen = QPen(Qt::white);
|
||||||
|
s_themeStyle = false;
|
||||||
|
} else {
|
||||||
|
ViewVar::s_colorItem = QColor(120, 120, 120);
|
||||||
|
// ViewVar::s_colorWid = QColor(246,246,246,0);
|
||||||
|
// ViewVar::s_colorSearch = QColor(246,246,246,1);
|
||||||
|
ViewVar::s_colorWid = QColor(255, 255, 255, 0);
|
||||||
|
ViewVar::s_colorSearch = QColor(255, 255, 255, 1);
|
||||||
|
ViewVar::m_collectPen = QPen(Qt::black);
|
||||||
|
s_themeStyle = true;
|
||||||
|
}
|
||||||
|
emit ViewVar::getInstance()->monitorThemeChanged(themeStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ViewVar::platFormType()
|
||||||
|
{
|
||||||
|
QString platformName;
|
||||||
|
kdk::kabase::SystemInformation systemInformation;
|
||||||
|
platformName = systemInformation.getProjectCodeName();
|
||||||
|
return platformName;
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
#ifndef VIEWVAR_H
|
||||||
|
#define VIEWVAR_H
|
||||||
|
#define FITTHEMESTYLE "org.ukui.style"
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QGSettings>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QSize>
|
||||||
|
#include <QRect>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QPen>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <QTranslator>
|
||||||
|
#include <QMargins>
|
||||||
|
#include <gsettings.hpp>
|
||||||
|
#include <system_information.hpp>
|
||||||
|
class ViewVar : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
static QMap<int, QStringList> HOTCITY_MAP; //热门城市列表
|
||||||
|
static QColor s_colorItem; //收藏城市颜色
|
||||||
|
static QColor s_colorWid; //收藏城市颜色
|
||||||
|
static QColor s_colorSearch; //收藏城市颜色
|
||||||
|
static const QSize COLLECT_BTNSIZE; //收藏城市按钮大小
|
||||||
|
static QString icon_path; //主界面图标路径
|
||||||
|
//按钮位置-收藏
|
||||||
|
static const int COLLECT_BTNXL;
|
||||||
|
static const int COLLECT_BTNYL;
|
||||||
|
static const int COLLECT_BTNXR;
|
||||||
|
static const int COLLECT_BTNYR;
|
||||||
|
// pen
|
||||||
|
static QPen m_collectPen;
|
||||||
|
//文字位置-收藏
|
||||||
|
static const int COLLECT_NAMEXL;
|
||||||
|
static const int COLLECT_TMPXL;
|
||||||
|
static const int COLLECT_CODEXL;
|
||||||
|
//文字位置-same-收藏
|
||||||
|
static const int COLLECT_SAMEYL;
|
||||||
|
static const int COLLECT_SAMEXR;
|
||||||
|
static const int COLLECT_SAMEYR;
|
||||||
|
//图标位置-收藏
|
||||||
|
static const int COLLECT_ICONXL;
|
||||||
|
static const int COLLECT_ICONYL;
|
||||||
|
static const int COLLECT_ICONXR;
|
||||||
|
static const int COLLECT_ICONYR;
|
||||||
|
|
||||||
|
//按钮位置-搜索
|
||||||
|
static const int SEARCH_BTNXL;
|
||||||
|
static const int SEARCH_BTNYL;
|
||||||
|
static const int SEARCH_BTNXR;
|
||||||
|
static const int SEARCH_BTNYR;
|
||||||
|
//文字位置-搜索
|
||||||
|
static const int SEARCH_NAMEXL;
|
||||||
|
static const int SEARCH_NAMEYL;
|
||||||
|
static const int SEARCH_NAMEXR;
|
||||||
|
static const int SEARCH_NAMEYR;
|
||||||
|
static const QString COLLECT_ICONPATH; //图标路径
|
||||||
|
static const QString COLLECT_ICONSUFFIX; //图标后缀
|
||||||
|
static const QRect COLLECT_ITEMRECT; //收藏城市item
|
||||||
|
static const QRect SEARCH_ITEMRECT; //搜索城市item
|
||||||
|
static const qreal SAME_ITEMRADIUS; // item圆角
|
||||||
|
static const qreal SAME_OPACITY_0; //透明度-0
|
||||||
|
static const qreal SAME_OPACITY_1; //透明度-0.2
|
||||||
|
static const qreal SAME_OPACITY_2; //透明度-1
|
||||||
|
|
||||||
|
static bool s_themeStyle; //主题变化
|
||||||
|
//各窗口大小
|
||||||
|
//收藏
|
||||||
|
static const QSize COLLECT; //收藏
|
||||||
|
static const QSize COLLECT_LIST; //收藏
|
||||||
|
static const QPoint COLLECT_TITLE; //收藏-title
|
||||||
|
static const int NONECITYX; //无收藏城市x值
|
||||||
|
static const int CITYLISTX; //收藏城市list x值
|
||||||
|
static const int COLLECT_ITEMH; //收藏城市item height值
|
||||||
|
static const int COLLECT_ITEMW; //收藏城市item weight值
|
||||||
|
//热门
|
||||||
|
static const QSize HOT; //热门
|
||||||
|
static const QSize HOT_LIST; //热门城市列表
|
||||||
|
static const QPoint HOT_TITLE; //热门-title
|
||||||
|
static const int HOTLISTX; //热门城市list x值
|
||||||
|
static const int ITEM_LENGTHM; //热门城市文字长度最大值
|
||||||
|
static const int ITEM_NUM; //热门城市每行数量
|
||||||
|
static const int ITEM_NUMM; //热门城市2行数量
|
||||||
|
static const int ITEM_POS; //热门城市item的间隔值
|
||||||
|
static const int ITEM_DIS0; //热门城市个数值-行1
|
||||||
|
static const int ITEM_DIS2; //热门城市个数值-行2
|
||||||
|
//热门-按钮
|
||||||
|
static const QSize HOT_BTN; //热门-按钮
|
||||||
|
//搜索框
|
||||||
|
static const QSize SEARCH_BOX;
|
||||||
|
|
||||||
|
static const QMargins SEARCH_MARGINS; //搜索框文本间距--左上右下
|
||||||
|
static const QSize SEARCH_ICON; //搜索框-图标控件大小
|
||||||
|
static const int SEARCH_ICON_X0; //搜索框-图标位置-x
|
||||||
|
static const int SEARCH_ICON_X1;
|
||||||
|
//搜索列表-个尺寸大小
|
||||||
|
static const QSize SEARCH_LIST;
|
||||||
|
static const int SEARCH_ITEMH; //搜索城市item height值
|
||||||
|
static const int SEARCH_ITEMW; //搜索城市item weight值
|
||||||
|
static const int SEARCH_NONEW; //搜索城市无city的控件宽度值
|
||||||
|
|
||||||
|
|
||||||
|
//搜索-收藏-总界面
|
||||||
|
static const QSize SEARCH;
|
||||||
|
static const int SEARCH_BOXY; //搜索框位置-y值
|
||||||
|
static const QPoint SEARCHLIST_POS; //搜索列表位置
|
||||||
|
static const int SEARCH_CHANGECITYX; //交换位置的x值
|
||||||
|
static const int DISTANCE0; //间隔0--热门和收藏的相互间距
|
||||||
|
static const int DISTANCE1; //间隔1--热门和收藏与搜索框的相互间距
|
||||||
|
|
||||||
|
static void initGsetting();
|
||||||
|
static void initFontSize();
|
||||||
|
static QMap<int, QStringList> saveHotCity(); //存储热门城市
|
||||||
|
static ViewVar *getInstance(); //单例
|
||||||
|
static QStringList platFormList; //平台
|
||||||
|
static QString platForm; //平台
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QStringList hotMap(QString city, QString cityId);
|
||||||
|
|
||||||
|
static void monitorGsetting(); //主题gsettings监听
|
||||||
|
static ViewVar *m_viewVar; //单例指针
|
||||||
|
static QString platFormType(); //获得平台名字
|
||||||
|
signals:
|
||||||
|
void monitorThemeChanged(QString themeType);
|
||||||
|
void setFontSizeSignal(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VIEWVAR_H
|
|
@ -0,0 +1,17 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=Weather
|
||||||
|
Name[zh_CN]=天气
|
||||||
|
Name[bo_CN]=གནམ་གཤིས།
|
||||||
|
Comment[bo_CN]=ཀྲུང་གོའི་དུས་ལྟར་གནམ་གཤིས།
|
||||||
|
Comment=Indicator applet for current weather conditions in China
|
||||||
|
Comment[zh_CN]=中国实时天气
|
||||||
|
GenericName[bo_CN]=གནམ་གཤིས།
|
||||||
|
GenericName=China Weather Applet
|
||||||
|
Keywords=weather,china
|
||||||
|
Exec=/usr/bin/kylin-weather showmainwindow%u
|
||||||
|
Icon=kylin-weather
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
X-GNOME-Autostart-Delay=10
|
||||||
|
Categories=System;Utility;
|
||||||
|
X-UKUI-AutoRestart=true;
|
|
@ -0,0 +1,181 @@
|
||||||
|
QT += core gui dbus
|
||||||
|
QT += network
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
# 适配窗口管理器圆角阴影
|
||||||
|
QT += KWindowSystem dbus x11extras
|
||||||
|
|
||||||
|
# 适配窗口管理器圆角阴影
|
||||||
|
LIBS +=-lpthread
|
||||||
|
LIBS +=-lX11
|
||||||
|
#适配sdk
|
||||||
|
PKGCONFIG += kysdk-qtwidgets
|
||||||
|
|
||||||
|
TARGET = kylin-weather
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
#kysdk
|
||||||
|
PKGCONFIG += kysdk-kabase
|
||||||
|
LIBS += -L/usr/lib/kysdk/kysdk-base -lkylog -lkyconf
|
||||||
|
|
||||||
|
#sdk不一样的版本路径有更改
|
||||||
|
INCLUDEPATH += /usr/include/kabase/
|
||||||
|
INCLUDEPATH += /usr/include/kysdk/applications/kabase/kylin_system/
|
||||||
|
INCLUDEPATH += /usr/include/kabase/kylin_system/
|
||||||
|
INCLUDEPATH += /usr/include/kysdk/applications/kabase/
|
||||||
|
|
||||||
|
target.source += $$TARGET
|
||||||
|
target.path = /usr/bin
|
||||||
|
|
||||||
|
!system($$PWD/translations/generate_translations_pm.sh): error("Failed to generate pm")
|
||||||
|
qm_files.files = translations/*.qm
|
||||||
|
qm_files.path = /usr/share/kylin-weather/translations/
|
||||||
|
|
||||||
|
TRANSLATIONS += \
|
||||||
|
translations/kylin-weather_zh_CN.ts \
|
||||||
|
translations/kylin-weather_kk.ts \
|
||||||
|
translations/kylin-weather_ky.ts \
|
||||||
|
translations/kylin-weather_ug.ts \
|
||||||
|
translations/kylin-weather_bo_CN.ts
|
||||||
|
|
||||||
|
# 配置gsettings
|
||||||
|
CONFIG += link_pkgconfig
|
||||||
|
PKGCONFIG += gsettings-qt
|
||||||
|
#settings.files = data/org.kylin.weather.gschema.xml
|
||||||
|
settings.files += \
|
||||||
|
$$PWD/data/org.kylin.weather.gschema.xml \
|
||||||
|
$$PWD/data/org.ukui.log4qt.kylin-weather.gschema.xml
|
||||||
|
|
||||||
|
icons.files += res/kylin-weather.png
|
||||||
|
icons.path = /usr/share/pixmaps/
|
||||||
|
|
||||||
|
settings.path = /usr/share/glib-2.0/schemas/
|
||||||
|
|
||||||
|
appdesktop.files += kylin-weather.desktop
|
||||||
|
appdesktop.path = /usr/share/applications/
|
||||||
|
|
||||||
|
startdesktop.files += kylin-weather.desktop
|
||||||
|
startdesktop.path = /etc/xdg/autostart/
|
||||||
|
|
||||||
|
backgroundimages.files += res/background/*.png
|
||||||
|
backgroundimages.path = /usr/share/kylin-weather/background/
|
||||||
|
|
||||||
|
guide.files = data/guide/kylin-weather/
|
||||||
|
|
||||||
|
guide.path = /usr/share/kylin-user-guide/data/guide/
|
||||||
|
|
||||||
|
INSTALLS +=settings appdesktop startdesktop icons target qm_files guide
|
||||||
|
|
||||||
|
CONFIG += c++11
|
||||||
|
|
||||||
|
# The following define makes your compiler emit warnings if you use
|
||||||
|
# any Qt feature that has been marked deprecated (the exact warnings
|
||||||
|
# depend on your compiler). Please consult the documentation of the
|
||||||
|
# deprecated API in order to know how to port your code away from it.
|
||||||
|
DEFINES += QT_DEPRECATED_WARNINGS
|
||||||
|
|
||||||
|
# You can also make your code fail to compile if it uses deprecated APIs.
|
||||||
|
# In order to do so, uncomment the following line.
|
||||||
|
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||||
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
controller/core/core.cpp \
|
||||||
|
controller/core/coreinteraction.cpp \
|
||||||
|
controller/core/errorreact.cpp \
|
||||||
|
controller/core/viewcontrol.cpp \
|
||||||
|
global/corevar.cpp \
|
||||||
|
global/viewvar.cpp \
|
||||||
|
main.cpp \
|
||||||
|
model/dataparser.cpp \
|
||||||
|
model/datarequest.cpp \
|
||||||
|
model/dbus.cpp \
|
||||||
|
model/iplocation.cpp \
|
||||||
|
model/network.cpp \
|
||||||
|
model/searchmarch.cpp \
|
||||||
|
view/horscreen/air.cpp \
|
||||||
|
view/horscreen/allowlocation.cpp \
|
||||||
|
view/horscreen/city.cpp \
|
||||||
|
view/horscreen/clothe.cpp \
|
||||||
|
view/horscreen/empty.cpp \
|
||||||
|
view/horscreen/flu.cpp \
|
||||||
|
view/horscreen/horscreen.cpp \
|
||||||
|
view/horscreen/information.cpp \
|
||||||
|
view/horscreen/lifestyle.cpp \
|
||||||
|
view/horscreen/menumodule.cpp \
|
||||||
|
view/horscreen/onedayweather.cpp \
|
||||||
|
view/horscreen/onehourweather.cpp \
|
||||||
|
view/horscreen/perhour.cpp \
|
||||||
|
view/horscreen/promptwidget.cpp \
|
||||||
|
view/horscreen/splitline.cpp \
|
||||||
|
view/horscreen/sport.cpp \
|
||||||
|
view/horscreen/title.cpp \
|
||||||
|
view/horscreen/ultravioletrays.cpp \
|
||||||
|
view/horscreen/washcar.cpp \
|
||||||
|
view/horscreen/weekweather.cpp \
|
||||||
|
view/horscreen/xatom-helper.cpp \
|
||||||
|
view/search/collectcity.cpp \
|
||||||
|
view/search/collectitemdelegate.cpp \
|
||||||
|
view/search/hotcity.cpp \
|
||||||
|
view/search/hotcitybtn.cpp \
|
||||||
|
view/search/searchbox.cpp \
|
||||||
|
view/search/searchbtn.cpp \
|
||||||
|
view/search/searchcitylist.cpp \
|
||||||
|
view/search/searchdelegate.cpp \
|
||||||
|
view/search/searchview.cpp \
|
||||||
|
view/verscreen/verscreen.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
controller/Interaction.h \
|
||||||
|
controller/core/core.h \
|
||||||
|
controller/core/coreinteraction.h \
|
||||||
|
controller/core/errorreact.h \
|
||||||
|
controller/core/viewcontrol.h \
|
||||||
|
global/corevar.h \
|
||||||
|
global/viewvar.h \
|
||||||
|
model/dataparser.h \
|
||||||
|
model/datarequest.h \
|
||||||
|
model/dbus.h \
|
||||||
|
model/iplocation.h \
|
||||||
|
model/network.h \
|
||||||
|
model/searchmarch.h \
|
||||||
|
view/horscreen/air.h \
|
||||||
|
view/horscreen/allowlocation.h \
|
||||||
|
view/horscreen/city.h \
|
||||||
|
view/horscreen/clothe.h \
|
||||||
|
view/horscreen/empty.h \
|
||||||
|
view/horscreen/flu.h \
|
||||||
|
view/horscreen/horscreen.h \
|
||||||
|
view/horscreen/information.h \
|
||||||
|
view/horscreen/lifestyle.h \
|
||||||
|
view/horscreen/menumodule.h \
|
||||||
|
view/horscreen/onedayweather.h \
|
||||||
|
view/horscreen/onehourweather.h \
|
||||||
|
view/horscreen/perhour.h \
|
||||||
|
view/horscreen/promptwidget.h \
|
||||||
|
view/horscreen/splitline.h \
|
||||||
|
view/horscreen/sport.h \
|
||||||
|
view/horscreen/title.h \
|
||||||
|
view/horscreen/ultravioletrays.h \
|
||||||
|
view/horscreen/washcar.h \
|
||||||
|
view/horscreen/weekweather.h \
|
||||||
|
view/horscreen/xatom-helper.h \
|
||||||
|
view/search/collectcity.h \
|
||||||
|
view/search/collectitemdelegate.h \
|
||||||
|
view/search/hotcity.h \
|
||||||
|
view/search/hotcitybtn.h \
|
||||||
|
view/search/searchbox.h \
|
||||||
|
view/search/searchbtn.h \
|
||||||
|
view/search/searchcitylist.h \
|
||||||
|
view/search/searchdelegate.h \
|
||||||
|
view/search/searchview.h \
|
||||||
|
view/verscreen/verscreen.h
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
data/org.kylin.weather.gschema.xml \
|
||||||
|
data/org.ukui.log4qt.kylin-weather.gschema.xml \
|
||||||
|
translations/kylin-weather_bo_CN.ts \
|
||||||
|
translations/kylin-weather_zh_CN.ts
|
||||||
|
|
||||||
|
RESOURCES += \
|
||||||
|
data.qrc \
|
||||||
|
res.qrc
|
|
@ -0,0 +1,67 @@
|
||||||
|
#include "controller/core/viewcontrol.h"
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QObject>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
#include <single_application/single_application.hpp>
|
||||||
|
#include <window_management.hpp>
|
||||||
|
#include <log.hpp>
|
||||||
|
|
||||||
|
//初始化核心,初始化前端,启动时是否展示界面
|
||||||
|
void controlView(kdk::kabase::QtSingleApplication &a, const QStringList &args, bool isStart)
|
||||||
|
{
|
||||||
|
//实例化viewcontrol
|
||||||
|
|
||||||
|
viewControl::getInstance()->initCore(args, isStart);
|
||||||
|
QObject::connect(&a, &kdk::kabase::QtSingleApplication::messageReceived, viewControl::getInstance(),
|
||||||
|
&viewControl::toShowView);
|
||||||
|
//激活窗口
|
||||||
|
a.setActivationWindow(viewControl::getInstance()->activeWindow());
|
||||||
|
}
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
//适配4K屏以及分数缩放
|
||||||
|
kdk::kabase::WindowManagement::setScalingProperties();
|
||||||
|
//日志输出
|
||||||
|
qInstallMessageHandler(kdk::kabase::Log::logOutput);
|
||||||
|
kdk::kabase::QtSingleApplication a(argc, argv);
|
||||||
|
a.setWindowIcon(QIcon::fromTheme("kylin-weather"));
|
||||||
|
//单例
|
||||||
|
if (a.isRunning()) {
|
||||||
|
qDebug() << "is running";
|
||||||
|
a.sendMessage("running , 4000");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//翻译
|
||||||
|
QTranslator qt_trans;
|
||||||
|
QString locale = QLocale::system().name();
|
||||||
|
QString trans_path;
|
||||||
|
if (QDir("/usr/share/kylin-weather/translations").exists()) {
|
||||||
|
trans_path = "/usr/share/kylin-weather/translations";
|
||||||
|
} else {
|
||||||
|
trans_path = qApp->applicationDirPath() + "/translations";
|
||||||
|
}
|
||||||
|
QString qt_trans_path;
|
||||||
|
qt_trans_path = QLibraryInfo::location(QLibraryInfo::TranslationsPath); // /usr/share/qt5/translations
|
||||||
|
if (!qt_trans.load("qt_" + locale + ".qm", qt_trans_path)) {
|
||||||
|
qDebug() << "Load translation file:"
|
||||||
|
<< "qt_" + locale + ".qm from" << qt_trans_path << "failed!";
|
||||||
|
} else {
|
||||||
|
a.installTranslator(&qt_trans);
|
||||||
|
}
|
||||||
|
QTranslator sdk_trans;
|
||||||
|
if (sdk_trans.load(":/translations/gui_" + locale + ".qm")) {
|
||||||
|
a.installTranslator(&sdk_trans);
|
||||||
|
}
|
||||||
|
QTranslator app_trans;
|
||||||
|
if (!app_trans.load("kylin-weather_" + locale + ".qm", trans_path)) {
|
||||||
|
qDebug() << "Load translation file:"
|
||||||
|
<< "kylin-weather_" + locale + ".qm from" << trans_path << "failed!";
|
||||||
|
} else {
|
||||||
|
a.installTranslator(&app_trans);
|
||||||
|
}
|
||||||
|
//初始化后端前端,判断启动方式,是否带参
|
||||||
|
controlView(a, a.arguments(), !(argc == 2 && QLatin1String(argv[1]) == "showmainwindow"));
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
|
@ -0,0 +1,426 @@
|
||||||
|
#include "dataparser.h"
|
||||||
|
|
||||||
|
DataParser::DataParser() {}
|
||||||
|
|
||||||
|
//处理返回的网络数据
|
||||||
|
void DataParser::dataReply(QByteArray dataBa)
|
||||||
|
{
|
||||||
|
//数据异常
|
||||||
|
QJsonParseError jsonParserErr;
|
||||||
|
QJsonDocument jsonDocument = QJsonDocument::fromJson(dataBa, &jsonParserErr);
|
||||||
|
if (jsonParserErr.error != QJsonParseError::NoError) { // Json type error
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, jsonParserErr.errorString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (jsonDocument.isNull() || jsonDocument.isEmpty()) {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, "Json null or empty!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// jsonObject数据为空
|
||||||
|
QJsonObject jsonObject = jsonDocument.object();
|
||||||
|
if (jsonObject.isEmpty() || jsonObject.size() == 0) {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, "Json object null or empty!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//无KylinWeather
|
||||||
|
if (!jsonObject.contains("KylinWeather")) {
|
||||||
|
// ErrorReact::getInstance()->dataFeedBack(false,"服务器数据没有字段");
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("Data is empty"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject mainObj = jsonObject.value("KylinWeather").toObject();
|
||||||
|
if (mainObj.isEmpty() || mainObj.size() == 0) {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, "Json object null or empty!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//解析当前城市天气状况和一周预报天气
|
||||||
|
if (mainObj.contains("weather")) {
|
||||||
|
QJsonObject weatherObj = mainObj.value("weather").toObject();
|
||||||
|
if (!weatherObj.isEmpty() && weatherObj.size() > 0) {
|
||||||
|
CurrentWeather m_currentWeather;
|
||||||
|
currentWeather(weatherObj, m_currentWeather);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// ErrorReact::getInstance()->dataFeedBack(false,"无当前城市天气信息");
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("Data is empty"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//解析生活指数信息
|
||||||
|
if (mainObj.contains("lifestyle")) {
|
||||||
|
QJsonObject lifestyleObj = mainObj.value("lifestyle").toObject();
|
||||||
|
lifeStyle(lifestyleObj);
|
||||||
|
} else {
|
||||||
|
// ErrorReact::getInstance()->dataFeedBack(false,"无生活指数信息");
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("Data is empty"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// QJsonObject hourlyObj = mainObj.value("hourly").toObject();
|
||||||
|
// QList<Hourly>hourlist;
|
||||||
|
// tmphourlyWeather(hourlyObj,hourlist);
|
||||||
|
//随机生成逐小时的天气信息----备用,先模拟一个逐小时天气信息
|
||||||
|
if (mainObj.contains("hourly")) {
|
||||||
|
QJsonObject hourlyObj = mainObj.value("hourly").toObject();
|
||||||
|
QList<Hourly> hourlist;
|
||||||
|
hourlyWeather(hourlyObj, hourlist);
|
||||||
|
} else {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, "无逐小时信息");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataParser::dataReplyColl(QByteArray dataBa)
|
||||||
|
{
|
||||||
|
QJsonParseError jsonParserErr;
|
||||||
|
QJsonDocument jsonDocument = QJsonDocument::fromJson(dataBa, &jsonParserErr);
|
||||||
|
if (jsonParserErr.error != QJsonParseError::NoError) { // Json type error
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, jsonParserErr.errorString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (jsonDocument.isNull() || jsonDocument.isEmpty()) {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, "Json null or empty!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject jsonObject = jsonDocument.object();
|
||||||
|
if (jsonObject.isEmpty() || jsonObject.size() == 0) {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, "Json object null or empty!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (jsonObject.contains("KylinWeather")) {
|
||||||
|
QJsonObject mainObj = jsonObject.value("KylinWeather").toObject();
|
||||||
|
if (mainObj.isEmpty() || mainObj.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mainObj.contains("weather")) {
|
||||||
|
QString weather_msg = mainObj.value("weather").toString();
|
||||||
|
if (weather_msg != "") {
|
||||||
|
collectWeather(weather_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//解析生活指数信息
|
||||||
|
void DataParser::lifeStyle(QJsonObject lifestyleObj)
|
||||||
|
{
|
||||||
|
LifeStyle m_lifestyle;
|
||||||
|
if (!lifestyleObj.isEmpty() && lifestyleObj.size() > 0) {
|
||||||
|
m_lifestyle.air_brf = lifestyleObj.value("air_brf").toString();
|
||||||
|
m_lifestyle.cw_brf = lifestyleObj.value("cw_brf").toString();
|
||||||
|
m_lifestyle.drsg_brf = lifestyleObj.value("drsg_brf").toString();
|
||||||
|
m_lifestyle.flu_brf = lifestyleObj.value("flu_brf").toString();
|
||||||
|
m_lifestyle.sport_brf = lifestyleObj.value("sport_brf").toString();
|
||||||
|
m_lifestyle.uv_brf = lifestyleObj.value("uv_brf").toString();
|
||||||
|
} else {
|
||||||
|
m_lifestyle.air_brf = "N/A";
|
||||||
|
m_lifestyle.cw_brf = "N/A";
|
||||||
|
m_lifestyle.drsg_brf = "N/A";
|
||||||
|
m_lifestyle.flu_brf = "N/A";
|
||||||
|
m_lifestyle.sport_brf = "N/A";
|
||||||
|
m_lifestyle.uv_brf = "N/A";
|
||||||
|
// ErrorReact::getInstance()->dataFeedBack(false,"服务器返回数据为空或不全");
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("Data is empty"));
|
||||||
|
}
|
||||||
|
emit showLifeStyle(m_lifestyle);
|
||||||
|
}
|
||||||
|
//解析当前城市信息
|
||||||
|
void DataParser::currentWeather(QJsonObject weatherObj, CurrentWeather currentWeather)
|
||||||
|
{
|
||||||
|
//当前城市id
|
||||||
|
QString id_msg = weatherObj.value("id").toString();
|
||||||
|
if (id_msg != "") {
|
||||||
|
currentWeather.id = id_msg;
|
||||||
|
}
|
||||||
|
//当前城市名字
|
||||||
|
QString location_msg = weatherObj.value("location").toString();
|
||||||
|
if (location_msg != "") {
|
||||||
|
currentWeather.city = location_msg;
|
||||||
|
}
|
||||||
|
//当前城市需要显示的具体信息
|
||||||
|
QString now_msg = weatherObj.value("now").toString();
|
||||||
|
if (now_msg != "" && now_msg.contains(",", Qt::CaseInsensitive)) {
|
||||||
|
QStringList strList = now_msg.split(",");
|
||||||
|
QJsonObject m_json;
|
||||||
|
foreach (QString str, strList) {
|
||||||
|
if (str != "") {
|
||||||
|
m_json.insert(str.split("=").at(0), str.split("=").at(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentWeather.tmp = m_json.value("tmp").toString();
|
||||||
|
currentWeather.wind_sc = m_json.value("wind_sc").toString();
|
||||||
|
currentWeather.cond_txt = m_json.value("cond_txt").toString();
|
||||||
|
currentWeather.hum = m_json.value("hum").toString();
|
||||||
|
currentWeather.cond_code = m_json.value("cond_code").toString();
|
||||||
|
currentWeather.wind_dir = m_json.value("wind_dir").toString();
|
||||||
|
currentWeather.serveTime = weatherObj.value("update_time").toString();
|
||||||
|
|
||||||
|
//将当前城市信息存入配置文件
|
||||||
|
setGsettings(currentWeather);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
currentWeather.tmp = "N/A";
|
||||||
|
currentWeather.wind_sc = "N/A";
|
||||||
|
currentWeather.cond_txt = "N/A";
|
||||||
|
currentWeather.hum = "N/A";
|
||||||
|
currentWeather.cond_code = "999";
|
||||||
|
currentWeather.wind_dir = "N/A";
|
||||||
|
currentWeather.serveTime = "N/A";
|
||||||
|
setGsettings(currentWeather);
|
||||||
|
// ErrorReact::getInstance()->dataFeedBack(false,"服务器返回数据为空或不全");
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("Data is empty"));
|
||||||
|
}
|
||||||
|
emit showCurrent(currentWeather);
|
||||||
|
forcastWeather(weatherObj, currentWeather);
|
||||||
|
}
|
||||||
|
//解析预报天气信息
|
||||||
|
void DataParser::forcastWeather(QJsonObject weatherObj, CurrentWeather currentWeather)
|
||||||
|
{
|
||||||
|
ForecastWeather forecastWeather;
|
||||||
|
QStringList strList;
|
||||||
|
int i = 0;
|
||||||
|
//处理预报天气
|
||||||
|
QString forecast_msg = weatherObj.value("forecast").toString();
|
||||||
|
if (forecast_msg != "" && forecast_msg.contains(",", Qt::CaseInsensitive)) {
|
||||||
|
strList = forecast_msg.split(";");
|
||||||
|
foreach (QString strDay, strList) {
|
||||||
|
QStringList strListDaySub;
|
||||||
|
QJsonObject m_json;
|
||||||
|
if (strDay != "") {
|
||||||
|
strListDaySub = strDay.split(",");
|
||||||
|
|
||||||
|
foreach (QString str, strListDaySub) {
|
||||||
|
if (str != "") {
|
||||||
|
m_json.insert(str.split("=").at(0), str.split("=").at(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QString dateTime = currentWeather.serveTime.split(" ").first();
|
||||||
|
setCollectValue(i, m_json, forecastWeather, dateTime);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// ErrorReact::getInstance()->dataFeedBack(false,"服务器返回数据为空或不全");
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("Data is empty"));
|
||||||
|
}
|
||||||
|
emit showForcast(forecastWeather);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataParser::setGsettings(CurrentWeather currentWeather)
|
||||||
|
{
|
||||||
|
//存配置文件
|
||||||
|
QString weatherNow = "";
|
||||||
|
weatherNow.append(currentWeather.serveTime + ","); //时间
|
||||||
|
weatherNow.append(currentWeather.id + ","); //省市编码
|
||||||
|
weatherNow.append(currentWeather.city + ","); //城市名称
|
||||||
|
weatherNow.append(currentWeather.cond_txt + ","); //天气情况
|
||||||
|
weatherNow.append(currentWeather.hum + "%,"); //湿度
|
||||||
|
weatherNow.append(currentWeather.tmp + "°,"); //温度
|
||||||
|
weatherNow.append(currentWeather.wind_dir + ","); //风向
|
||||||
|
weatherNow.append(currentWeather.wind_sc + "级,"); //风力
|
||||||
|
// weatherNow.append(weatherObj.value("admin_area").toString()+",");//省份----暂时不需要
|
||||||
|
weatherNow.append(currentWeather.cond_code + ",");
|
||||||
|
CoreVar::setSettings("weather", weatherNow); //写入配置文件
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataParser::collectWeather(QString weatherList)
|
||||||
|
{
|
||||||
|
QList<CollectItemData> collectItemList;
|
||||||
|
if (weatherList == "")
|
||||||
|
return;
|
||||||
|
QStringList strList = weatherList.split(";");
|
||||||
|
QString weatherStr = "";
|
||||||
|
for (int i = 0; i <= strList.length() - 1; i++) {
|
||||||
|
weatherStr = strList.at(i);
|
||||||
|
CollectItemData collectItemData;
|
||||||
|
if (!weatherStr.isEmpty() && weatherStr.contains(",", Qt::CaseInsensitive)) {
|
||||||
|
QJsonObject m_json;
|
||||||
|
if (!weatherStr.isEmpty()) {
|
||||||
|
QStringList eachKeyList = weatherStr.split(",");
|
||||||
|
foreach (QString strKey, eachKeyList) {
|
||||||
|
if (!strKey.isEmpty()) {
|
||||||
|
//等号左边为键,右边为值
|
||||||
|
m_json.insert(strKey.split("=").at(0), strKey.split("=").at(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collectItemData.tmp = m_json.value("tmp").toString() + QString("°");
|
||||||
|
collectItemData.cond_code = m_json.value("cond_code").toString();
|
||||||
|
collectItemData.cityId = m_json.value("id").toString();
|
||||||
|
collectItemData.cityName = m_json.value("location").toString();
|
||||||
|
} else {
|
||||||
|
collectItemData.tmp = "-";
|
||||||
|
collectItemData.cond_code = "999";
|
||||||
|
collectItemData.cityId = "-";
|
||||||
|
collectItemData.cityName = "-";
|
||||||
|
// ErrorReact::getInstance()->dataFeedBack(false,"服务器返回数据为空或不全");
|
||||||
|
//返回的数据中带了一个空数据,所以将这一项去掉
|
||||||
|
if (i != strList.length() - 1) {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("Data is empty"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collectItemList.append(collectItemData);
|
||||||
|
}
|
||||||
|
emit showCollectCode(collectItemList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataParser::hourlyWeather(QJsonObject hourlyObj, QList<Hourly> hourlist)
|
||||||
|
{
|
||||||
|
if (hourlyObj.contains(QStringLiteral("hourly"))) {
|
||||||
|
QJsonValue arrayValue = hourlyObj.value(QStringLiteral("hourly"));
|
||||||
|
if (arrayValue.isArray()) {
|
||||||
|
QJsonArray array = arrayValue.toArray();
|
||||||
|
if (array.size() != 24) {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("hourly != 24"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < array.size(); i++) {
|
||||||
|
QJsonValue jsonArray = array.at(i);
|
||||||
|
QJsonObject m_json = jsonArray.toObject();
|
||||||
|
Hourly tmp_hour;
|
||||||
|
if (!(m_json.contains("icon") && m_json.contains("fxTime") && m_json.contains("temp"))) {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("hourly key is wrong"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_json.value("icon").toString() == "" || m_json.value("fxTime").toString() == ""
|
||||||
|
|| m_json.value("temp").toString() == "") {
|
||||||
|
tmp_hour.cond_code = "999";
|
||||||
|
tmp_hour.time = "-";
|
||||||
|
tmp_hour.tmp = "-";
|
||||||
|
} else {
|
||||||
|
tmp_hour.cond_code = m_json.value("icon").toString();
|
||||||
|
// tmp_hour.cond_txt = m_json.value("text").toString();
|
||||||
|
tmp_hour.time = m_json.value("fxTime").toString();
|
||||||
|
QString timeFormat = tmp_hour.time.mid(tmp_hour.time.indexOf("T"), 6);
|
||||||
|
timeFormat = timeFormat.replace("T", "");
|
||||||
|
tmp_hour.time = timeFormat;
|
||||||
|
tmp_hour.tmp = m_json.value("temp").toString() + QString("°");
|
||||||
|
}
|
||||||
|
hourlist.append(tmp_hour);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("Hourly is not array"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QVariant var;
|
||||||
|
var.setValue<QList<Hourly>>(hourlist);
|
||||||
|
emit showHourly(var);
|
||||||
|
} else {
|
||||||
|
ErrorReact::getInstance()->dataFeedBack(false, tr("Hourly is not exits"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//临时用
|
||||||
|
void DataParser::tmphourlyWeather(QJsonObject hourlyObj, QList<Hourly> hourlist)
|
||||||
|
{
|
||||||
|
QTime current_time = QTime::currentTime();
|
||||||
|
int hour = current_time.hour() + 1; //当前的小时
|
||||||
|
for (int i = 0; i < 24; i++) {
|
||||||
|
int num_code = qrand() % (1, 60);
|
||||||
|
int num_tmp = qrand() % (-10, 30);
|
||||||
|
QString tmpText = QString::number(num_tmp) + "°C";
|
||||||
|
Hourly tmp_hour;
|
||||||
|
QString hour_tmp = QString::number(hour + i) + ":00";
|
||||||
|
if (hour + i >= 24) {
|
||||||
|
hour_tmp = QString::number(hour + i - 24) + ":00";
|
||||||
|
if (hour + i - 24 < 10) {
|
||||||
|
hour_tmp = "0" + QString::number(hour + i - 24) + ":00";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp_hour.cond_code = CoreVar::WEATHER_CODE_TMP.at(num_code);
|
||||||
|
tmp_hour.time = hour_tmp;
|
||||||
|
tmp_hour.tmp = tmpText;
|
||||||
|
hourlist.append(tmp_hour);
|
||||||
|
}
|
||||||
|
QVariant var;
|
||||||
|
var.setValue<QList<Hourly>>(hourlist);
|
||||||
|
emit showHourly(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataParser::setCollectValue(int i, const QJsonObject &json, ForecastWeather &forecastweather,
|
||||||
|
const QString &dateTime)
|
||||||
|
{
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
forecastweather.first.cond_txt_d = json.value("cond_txt_d").toString();
|
||||||
|
forecastweather.first.cond_txt_n = json.value("cond_txt_n").toString();
|
||||||
|
forecastweather.first.cond_code_d = json.value("cond_code_d").toString();
|
||||||
|
forecastweather.first.cond_code_n = json.value("cond_code_n").toString();
|
||||||
|
forecastweather.first.wind_dir = json.value("wind_dir").toString();
|
||||||
|
forecastweather.first.wind_sc = json.value("wind_sc").toString();
|
||||||
|
forecastweather.first.tmp_max = json.value("tmp_max").toString();
|
||||||
|
forecastweather.first.tmp_min = json.value("tmp_min").toString();
|
||||||
|
forecastweather.first.date = json.value("date").toString();
|
||||||
|
forecastweather.first.dateTime = dateTime;
|
||||||
|
case 1:
|
||||||
|
forecastweather.second.cond_txt_d = json.value("cond_txt_d").toString();
|
||||||
|
forecastweather.second.cond_txt_n = json.value("cond_txt_n").toString();
|
||||||
|
forecastweather.second.cond_code_d = json.value("cond_code_d").toString();
|
||||||
|
forecastweather.second.cond_code_n = json.value("cond_code_n").toString();
|
||||||
|
forecastweather.second.wind_dir = json.value("wind_dir").toString();
|
||||||
|
forecastweather.second.wind_sc = json.value("wind_sc").toString();
|
||||||
|
forecastweather.second.tmp_max = json.value("tmp_max").toString();
|
||||||
|
forecastweather.second.tmp_min = json.value("tmp_min").toString();
|
||||||
|
forecastweather.second.date = json.value("date").toString();
|
||||||
|
forecastweather.second.dateTime = dateTime;
|
||||||
|
case 2:
|
||||||
|
forecastweather.third.cond_txt_d = json.value("cond_txt_d").toString();
|
||||||
|
forecastweather.third.cond_txt_n = json.value("cond_txt_n").toString();
|
||||||
|
forecastweather.third.cond_code_d = json.value("cond_code_d").toString();
|
||||||
|
forecastweather.third.cond_code_n = json.value("cond_code_n").toString();
|
||||||
|
forecastweather.third.wind_dir = json.value("wind_dir").toString();
|
||||||
|
forecastweather.third.wind_sc = json.value("wind_sc").toString();
|
||||||
|
forecastweather.third.tmp_max = json.value("tmp_max").toString();
|
||||||
|
forecastweather.third.tmp_min = json.value("tmp_min").toString();
|
||||||
|
forecastweather.third.date = json.value("date").toString();
|
||||||
|
forecastweather.third.dateTime = dateTime;
|
||||||
|
case 3:
|
||||||
|
forecastweather.fourth.cond_txt_d = json.value("cond_txt_d").toString();
|
||||||
|
forecastweather.fourth.cond_txt_n = json.value("cond_txt_n").toString();
|
||||||
|
forecastweather.fourth.cond_code_d = json.value("cond_code_d").toString();
|
||||||
|
forecastweather.fourth.cond_code_n = json.value("cond_code_n").toString();
|
||||||
|
forecastweather.fourth.wind_dir = json.value("wind_dir").toString();
|
||||||
|
forecastweather.fourth.wind_sc = json.value("wind_sc").toString();
|
||||||
|
forecastweather.fourth.tmp_max = json.value("tmp_max").toString();
|
||||||
|
forecastweather.fourth.tmp_min = json.value("tmp_min").toString();
|
||||||
|
forecastweather.fourth.date = json.value("date").toString();
|
||||||
|
forecastweather.fourth.dateTime = dateTime;
|
||||||
|
case 4:
|
||||||
|
forecastweather.fifth.cond_txt_d = json.value("cond_txt_d").toString();
|
||||||
|
forecastweather.fifth.cond_txt_n = json.value("cond_txt_n").toString();
|
||||||
|
forecastweather.fifth.cond_code_d = json.value("cond_code_d").toString();
|
||||||
|
forecastweather.fifth.cond_code_n = json.value("cond_code_n").toString();
|
||||||
|
forecastweather.fifth.wind_dir = json.value("wind_dir").toString();
|
||||||
|
forecastweather.fifth.wind_sc = json.value("wind_sc").toString();
|
||||||
|
forecastweather.fifth.tmp_max = json.value("tmp_max").toString();
|
||||||
|
forecastweather.fifth.tmp_min = json.value("tmp_min").toString();
|
||||||
|
forecastweather.fifth.date = json.value("date").toString();
|
||||||
|
forecastweather.fifth.dateTime = dateTime;
|
||||||
|
case 5:
|
||||||
|
forecastweather.sixth.cond_txt_d = json.value("cond_txt_d").toString();
|
||||||
|
forecastweather.sixth.cond_txt_n = json.value("cond_txt_n").toString();
|
||||||
|
forecastweather.sixth.cond_code_d = json.value("cond_code_d").toString();
|
||||||
|
forecastweather.sixth.cond_code_n = json.value("cond_code_n").toString();
|
||||||
|
forecastweather.sixth.wind_dir = json.value("wind_dir").toString();
|
||||||
|
forecastweather.sixth.wind_sc = json.value("wind_sc").toString();
|
||||||
|
forecastweather.sixth.tmp_max = json.value("tmp_max").toString();
|
||||||
|
forecastweather.sixth.tmp_min = json.value("tmp_min").toString();
|
||||||
|
forecastweather.sixth.date = json.value("date").toString();
|
||||||
|
forecastweather.sixth.dateTime = dateTime;
|
||||||
|
case 6:
|
||||||
|
forecastweather.seventh.cond_txt_d = json.value("cond_txt_d").toString();
|
||||||
|
forecastweather.seventh.cond_txt_n = json.value("cond_txt_n").toString();
|
||||||
|
forecastweather.seventh.cond_code_d = json.value("cond_code_d").toString();
|
||||||
|
forecastweather.seventh.cond_code_n = json.value("cond_code_n").toString();
|
||||||
|
forecastweather.seventh.wind_dir = json.value("wind_dir").toString();
|
||||||
|
forecastweather.seventh.wind_sc = json.value("wind_sc").toString();
|
||||||
|
forecastweather.seventh.tmp_max = json.value("tmp_max").toString();
|
||||||
|
forecastweather.seventh.tmp_min = json.value("tmp_min").toString();
|
||||||
|
forecastweather.seventh.date = json.value("date").toString();
|
||||||
|
forecastweather.seventh.dateTime = dateTime;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef DATAPARSER_H
|
||||||
|
#define DATAPARSER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QTime>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonValue>
|
||||||
|
#include "global/corevar.h"
|
||||||
|
#include "controller/core/errorreact.h"
|
||||||
|
class DataParser : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DataParser();
|
||||||
|
signals:
|
||||||
|
void showLifeStyle(LifeStyle lifeStyle); //发送信号,显示生活指数信息
|
||||||
|
void showCurrent(CurrentWeather currentWeather); //发送信号,显示当前城市信息
|
||||||
|
void showForcast(ForecastWeather forecastWeather); //发送信号,显示城市预测信息
|
||||||
|
// void showForcast(QString forecastWeather);//发送信号,显示城市预测信息
|
||||||
|
void showCollectCode(QList<CollectItemData> collectItemList); //发送信号,显示收藏城市信息
|
||||||
|
void showHourly(QVariant varHour); //逐小时天气信息
|
||||||
|
private:
|
||||||
|
void lifeStyle(QJsonObject lifestyleObj); //解析生活指数信息
|
||||||
|
void currentWeather(QJsonObject weatherObj, CurrentWeather currentWeather); //解析当前城市信息
|
||||||
|
void forcastWeather(QJsonObject weatherObj, CurrentWeather currentWeather); //解析预报天气信息
|
||||||
|
void setGsettings(CurrentWeather currentWeather); //存当前城市信息于配置文件
|
||||||
|
void collectWeather(QString weatherList); //解析当前城市信息
|
||||||
|
void hourlyWeather(QJsonObject hourlyObj, QList<Hourly> hourlist); //解析逐小时信息
|
||||||
|
void tmphourlyWeather(QJsonObject hourlyObj, QList<Hourly> hourlist); //解析逐小时信息
|
||||||
|
void setCollectValue(int i, const QJsonObject &json, ForecastWeather &forecastweather,
|
||||||
|
const QString &dateTime); //给预报天气的结构体的每一天赋值
|
||||||
|
public slots:
|
||||||
|
void dataReply(QByteArray dataBa); //对发送来的数据进行解析
|
||||||
|
void dataReplyColl(QByteArray dataBa); //对收藏城市数据进行解析
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DATAPARSER_H
|
|
@ -0,0 +1,131 @@
|
||||||
|
#include "datarequest.h"
|
||||||
|
|
||||||
|
DataRequest::DataRequest(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
m_networkManager = new QNetworkAccessManager(this);
|
||||||
|
m_timer.setSingleShot(true);
|
||||||
|
m_timerColl.setSingleShot(true);
|
||||||
|
}
|
||||||
|
DataRequest::~DataRequest()
|
||||||
|
{
|
||||||
|
m_networkManager->deleteLater();
|
||||||
|
m_reply->deleteLater();
|
||||||
|
m_replyCollect->deleteLater();
|
||||||
|
}
|
||||||
|
//利用连接请求网络数据
|
||||||
|
void DataRequest::dataRequest(const QString &cityId)
|
||||||
|
{
|
||||||
|
if (cityId.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString forecastUrl = CoreVar::SERVICEREQUEST.arg(cityId);
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setUrl(forecastUrl);
|
||||||
|
m_reply = m_networkManager->get(request);
|
||||||
|
QEventLoop eventLoop;
|
||||||
|
connect(&m_timer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); //定时器结束,循环断开
|
||||||
|
connect(m_reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
|
||||||
|
m_timer.start(CoreVar::DEFAULT_TIMEOUT); // 30s等待
|
||||||
|
eventLoop.exec();
|
||||||
|
//超时处理
|
||||||
|
if (!timeOut(&m_timer, m_reply, &eventLoop)) {
|
||||||
|
ErrorReact::getInstance()->networkTimeout("true"); //超时
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
//数据处理
|
||||||
|
dataReply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//处理返回的网络数据
|
||||||
|
void DataRequest::dataReply()
|
||||||
|
{
|
||||||
|
// QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
//状态码不为200时,异常
|
||||||
|
if (statusCode != 200) {
|
||||||
|
ErrorReact::getInstance()->serverFeedBack(false, QString::number(statusCode));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//网络层错误[与目标服务器有关]
|
||||||
|
if (m_reply->error() != QNetworkReply::NoError) {
|
||||||
|
ErrorReact::getInstance()->networkFeedBack(false, m_reply->errorString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//一切正常,进行数据解析
|
||||||
|
QByteArray dataBa = m_reply->readAll();
|
||||||
|
m_reply->abort();
|
||||||
|
emit sendData(dataBa);
|
||||||
|
}
|
||||||
|
//请求收藏城市数据
|
||||||
|
void DataRequest::dataRequestCollect(const QString &cityIdList)
|
||||||
|
{
|
||||||
|
if (cityIdList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//如果是搜藏城市列表加载城市
|
||||||
|
QString forecastUrl = CoreVar::SERVICEREQUEST_COLLECT;
|
||||||
|
QStringList cityList = cityIdList.split(","); // cityList最后一项为空字符
|
||||||
|
//访问要求为 : "11111"+ "22222"形式
|
||||||
|
for (int i = 0; i < cityList.size(); i++) {
|
||||||
|
if (i == cityList.size() - 1) {
|
||||||
|
forecastUrl.append(cityList.at(i));
|
||||||
|
} else {
|
||||||
|
forecastUrl.append(cityList.at(i));
|
||||||
|
forecastUrl.append("+");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setUrl(forecastUrl);
|
||||||
|
m_replyCollect = m_networkManager->get(request);
|
||||||
|
QEventLoop eventLoop;
|
||||||
|
connect(&m_timerColl, SIGNAL(timeout()), &eventLoop, SLOT(quit())); //定时器结束,循环断开
|
||||||
|
connect(m_replyCollect, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
|
||||||
|
m_timerColl.start(CoreVar::DEFAULT_TIMEOUT); // 30s等待
|
||||||
|
eventLoop.exec();
|
||||||
|
//超时处理
|
||||||
|
if (!timeOut(&m_timerColl, m_replyCollect, &eventLoop)) {
|
||||||
|
ErrorReact::getInstance()->networkTimeout("false"); //超时
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
//数据处理
|
||||||
|
dataReplyCollect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//处理收藏城市数据返回
|
||||||
|
void DataRequest::dataReplyCollect()
|
||||||
|
{
|
||||||
|
int statusCode = m_replyCollect->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
//状态码不为200时,异常
|
||||||
|
if (statusCode != 200) {
|
||||||
|
ErrorReact::getInstance()->serverFeedBack(false, QString::number(statusCode));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//网络层错误[与目标服务器有关]
|
||||||
|
if (m_replyCollect->error() != QNetworkReply::NoError) {
|
||||||
|
ErrorReact::getInstance()->networkFeedBack(false, m_replyCollect->errorString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QByteArray dataBaC = m_replyCollect->readAll();
|
||||||
|
m_replyCollect->abort();
|
||||||
|
emit sendCollData(dataBaC);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DataRequest::timeOut(QTimer *timer, QNetworkReply *reply, QEventLoop *eventloop)
|
||||||
|
{
|
||||||
|
//超时处理
|
||||||
|
if (timer->isActive()) {
|
||||||
|
//在设定的时间内没有超时,定时器关闭
|
||||||
|
timer->stop();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (reply == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//超时-断开访问连接
|
||||||
|
disconnect(reply, &QNetworkReply::finished, eventloop, &QEventLoop::quit);
|
||||||
|
reply->abort();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef DATAREQUEST_H
|
||||||
|
#define DATAREQUEST_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include "controller/core/errorreact.h"
|
||||||
|
#include "global/corevar.h"
|
||||||
|
class DataRequest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit DataRequest(QObject *parent = nullptr);
|
||||||
|
~DataRequest();
|
||||||
|
void dataRequest(const QString &cityId); //主界面城市数据请求
|
||||||
|
void dataRequestCollect(const QString &cityIdList); //收藏城市数据请求
|
||||||
|
private:
|
||||||
|
QNetworkAccessManager *m_networkManager = nullptr;
|
||||||
|
void dataReply(); //主界面城市网络返回
|
||||||
|
void dataReplyCollect(); //收藏界面网络返回
|
||||||
|
bool m_requsetWay = false; //默认为false,请求数据的方式,true代表是从搜索列表请求,false为其他
|
||||||
|
QTimer m_timer; //当前城市的定时器
|
||||||
|
QTimer m_timerColl; //收藏的定时器
|
||||||
|
QNetworkReply *m_reply = nullptr; //主界面城市网络reply
|
||||||
|
QNetworkReply *m_replyCollect = nullptr; //收藏城市界面网络reply
|
||||||
|
bool timeOut(QTimer *timer, QNetworkReply *reply, QEventLoop *eventloop); //主界面超时函数
|
||||||
|
signals:
|
||||||
|
void sendData(QByteArray dataBa); //主界面城市数据
|
||||||
|
void sendCollData(QByteArray dataBa); //收藏城市数据
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DATAREQUEST_H
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "dbus.h"
|
||||||
|
|
||||||
|
Dbus::Dbus() {}
|
||||||
|
|
||||||
|
void Dbus::argumentsCommand(const QStringList &arguments) {}
|
||||||
|
|
||||||
|
bool Dbus::getConnectSeccess() {}
|
||||||
|
|
||||||
|
void Dbus::getCmdFromOtherMe(const QStringList &cmd) {}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef DBUS_H
|
||||||
|
#define DBUS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusReply>
|
||||||
|
|
||||||
|
#include "global/corevar.h"
|
||||||
|
|
||||||
|
class Dbus : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void processingCommand(QStringList);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Dbus();
|
||||||
|
void argumentsCommand(const QStringList &arguments);
|
||||||
|
bool getConnectSeccess();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void getCmdFromOtherMe(const QStringList &cmd);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_connectSeccess = false; //注册DBus成功
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DBUS_H
|
|
@ -0,0 +1,166 @@
|
||||||
|
#include "iplocation.h"
|
||||||
|
const QString codeSecond = QString("YzljMDcwODc5YmViZTYxNQ=="); //第二段加密内容
|
||||||
|
Iplocation::Iplocation(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
m_timer.setSingleShot(true); //设置定时器单例--必须设置
|
||||||
|
m_timerGeo.setSingleShot(true);
|
||||||
|
m_timerIPIP.setSingleShot(true);
|
||||||
|
//超时逻辑
|
||||||
|
//使用 QTimer 启动一个单次定时器,并设置超时时间。
|
||||||
|
//在事件循环退出之后,判断定时器的状态,如果是激活状态,证明请求已经完成;否则,说明超时
|
||||||
|
}
|
||||||
|
const QString Iplocation::getCodeThird()
|
||||||
|
{
|
||||||
|
QString codeThird = "";
|
||||||
|
codeThird = CoreVar::getSettings("ipkeypart").toString();
|
||||||
|
return codeThird;
|
||||||
|
}
|
||||||
|
QString Iplocation::gotoLocation()
|
||||||
|
{
|
||||||
|
//{"status":"0","info":"USER_DAILY_QUERY_OVER_LIMIT","infocode":"10044"}
|
||||||
|
//高德api定位逻辑
|
||||||
|
QNetworkAccessManager *manager = new QNetworkAccessManager();
|
||||||
|
//获得ip
|
||||||
|
QString ip_str = pconlineLocation(CoreVar::PCONLINEURL);
|
||||||
|
|
||||||
|
QString str = CoreVar::URLHEAD + decodeToOrigin(codeFirst, codeSecond, getCodeThird());
|
||||||
|
//获得完整url
|
||||||
|
QString url_str = str.append(ip_str);
|
||||||
|
//获得返回数据:地址--精确到区
|
||||||
|
QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url_str)));
|
||||||
|
//返回数据解析
|
||||||
|
QString responeData;
|
||||||
|
//事件循环-做超时处理
|
||||||
|
QEventLoop eventLoop;
|
||||||
|
//定时器过期之后或者网络响应完成后事件循环得到退出,不至于一直处于阻塞状态
|
||||||
|
connect(&m_timer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); //定时器结束,循环断开
|
||||||
|
connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
|
||||||
|
m_timer.start(CoreVar::DEFAULT_TIMEOUT); // 30s等待
|
||||||
|
eventLoop.exec();
|
||||||
|
//超时处理
|
||||||
|
if (!timeOut(&m_timer, reply, &eventLoop)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
// ipip定位
|
||||||
|
if (reply == nullptr) {
|
||||||
|
return ipipLocation();
|
||||||
|
}
|
||||||
|
responeData = reply->readAll();
|
||||||
|
//数据解析
|
||||||
|
// 创建 QJsonParseError 对象,用来获取解析结果
|
||||||
|
QJsonParseError parseJsonError;
|
||||||
|
//使用静态函数获取 QJsonDocument 对象 读写json文档
|
||||||
|
QJsonDocument jsonDocument = QJsonDocument::fromJson(responeData.toUtf8(), &parseJsonError);
|
||||||
|
if (parseJsonError.error != QJsonParseError::NoError) {
|
||||||
|
return ipipLocation();
|
||||||
|
}
|
||||||
|
//将数据转换为QString 返回jsonDocument中的json对象。
|
||||||
|
QJsonObject jsonObject = jsonDocument.object();
|
||||||
|
if (jsonObject["status"].toString() == "1" && jsonObject["status"].toString() != "") {
|
||||||
|
return jsonObject["district"].toString();
|
||||||
|
} else {
|
||||||
|
return ipipLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QString Iplocation::decodeToOrigin(const QString &codeStr1, const QString &codeStr2, const QString &codeStr3)
|
||||||
|
{
|
||||||
|
QString finalStr = "";
|
||||||
|
QByteArray text1 = codeStr1.toLocal8Bit();
|
||||||
|
QByteArray by1 = text1.fromBase64(text1);
|
||||||
|
QString str1 = QString::fromLocal8Bit(by1);
|
||||||
|
|
||||||
|
QByteArray text2 = codeStr2.toLocal8Bit();
|
||||||
|
QByteArray by2 = text2.fromBase64(text2);
|
||||||
|
QString str2 = QString::fromLocal8Bit(by2);
|
||||||
|
|
||||||
|
QByteArray text3 = codeStr3.toLocal8Bit();
|
||||||
|
QByteArray by3 = text3.fromBase64(text3);
|
||||||
|
QString str3 = QString::fromLocal8Bit(by3);
|
||||||
|
|
||||||
|
finalStr.append(str1);
|
||||||
|
finalStr.append(str2);
|
||||||
|
finalStr.append(str3);
|
||||||
|
|
||||||
|
return finalStr;
|
||||||
|
}
|
||||||
|
//高德定位
|
||||||
|
QString Iplocation::pconlineLocation(const QString &url)
|
||||||
|
{
|
||||||
|
|
||||||
|
QNetworkAccessManager *manager = new QNetworkAccessManager();
|
||||||
|
QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
|
||||||
|
QEventLoop loop;
|
||||||
|
connect(&m_timerGeo, SIGNAL(timeout()), &loop, SLOT(quit())); //定时器结束,循环断开
|
||||||
|
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||||
|
m_timerGeo.start(CoreVar::DEFAULT_TIMEOUT); // 30s等待
|
||||||
|
loop.exec();
|
||||||
|
//超时处理
|
||||||
|
if (!timeOut(&m_timerGeo, reply, &loop)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
|
QByteArray ba = reply->readAll();
|
||||||
|
QString reply_content = QString::fromUtf8(ba);
|
||||||
|
reply->close();
|
||||||
|
reply->deleteLater();
|
||||||
|
manager->deleteLater();
|
||||||
|
if (!reply_content.isEmpty()) {
|
||||||
|
QString htmlStr = reply_content.replace(" ", "");
|
||||||
|
htmlStr = htmlStr.replace("\r", "");
|
||||||
|
htmlStr = htmlStr.replace("\n", "");
|
||||||
|
QStringList htmlList = htmlStr.split("<br/>");
|
||||||
|
if (htmlList.size() >= 4) {
|
||||||
|
QStringList ipList = htmlList.at(4).split("=");
|
||||||
|
if (ipList.count() > 1) {
|
||||||
|
if (ipList.at(1).contains(",")) {
|
||||||
|
ipList = ipList.at(1).split(",");
|
||||||
|
return ipList.at(0);
|
||||||
|
}
|
||||||
|
return ipList.at(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//无法定位,返回""
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
// ipip定位
|
||||||
|
QString Iplocation::ipipLocation()
|
||||||
|
{
|
||||||
|
//使用ipip.net的服务进行定位 "当前 IP:123.150.8.43 来自于:中国 天津 天津 电信\n"
|
||||||
|
QNetworkAccessManager *manager = new QNetworkAccessManager();
|
||||||
|
QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(CoreVar::IPIP)));
|
||||||
|
QByteArray responseData;
|
||||||
|
QEventLoop eventLoop;
|
||||||
|
connect(&m_timerIPIP, SIGNAL(timeout()), &eventLoop, SLOT(quit())); //定时器结束,循环断开
|
||||||
|
connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
|
||||||
|
m_timerIPIP.start(CoreVar::DEFAULT_TIMEOUT); // 30s等待
|
||||||
|
eventLoop.exec();
|
||||||
|
//超时处理
|
||||||
|
if (!timeOut(&m_timerIPIP, reply, &eventLoop)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
responseData = reply->readAll();
|
||||||
|
QString str = responseData;
|
||||||
|
|
||||||
|
QStringList respList = str.split(' ');
|
||||||
|
if (!(respList.size() >= 5))
|
||||||
|
return "";
|
||||||
|
return respList[5];
|
||||||
|
}
|
||||||
|
//网络超时处理
|
||||||
|
bool Iplocation::timeOut(QTimer *timer, QNetworkReply *reply, QEventLoop *eventloop)
|
||||||
|
{
|
||||||
|
//超时处理
|
||||||
|
if (timer->isActive()) {
|
||||||
|
//在设定的时间内没有超时,定时器关闭
|
||||||
|
timer->stop();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
//超时-断开访问连接
|
||||||
|
disconnect(reply, &QNetworkReply::finished, eventloop, &QEventLoop::quit);
|
||||||
|
reply->abort();
|
||||||
|
reply->deleteLater();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef IPLOCATION_H
|
||||||
|
#define IPLOCATION_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include "global/corevar.h"
|
||||||
|
class Iplocation : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Iplocation(QObject *parent = nullptr);
|
||||||
|
QString gotoLocation(); //去定位
|
||||||
|
private:
|
||||||
|
QString pconlineLocation(const QString &url); //高德定位
|
||||||
|
QString ipipLocation(); // ipip定位
|
||||||
|
QTimer m_timer; //超时处理--定位
|
||||||
|
QTimer m_timerGeo; //超时处理--高德
|
||||||
|
QTimer m_timerIPIP; //超时处理--ipip
|
||||||
|
bool timeOut(QTimer *timer, QNetworkReply *reply, QEventLoop *eventloop);
|
||||||
|
const QString codeFirst = QString("aXA/a2V5PWZhZjhmYWFkNA=="); //第一段加密内容
|
||||||
|
QString decodeToOrigin(const QString &codeStr1, const QString &codeStr2, const QString &codeStr3); //解密
|
||||||
|
const QString getCodeThird();
|
||||||
|
signals:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IPLOCATION_H
|
|
@ -0,0 +1,119 @@
|
||||||
|
#include "network.h"
|
||||||
|
|
||||||
|
Network::Network(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
initConnect();
|
||||||
|
//初始化dbus
|
||||||
|
initConnectionInfo();
|
||||||
|
}
|
||||||
|
//检查网络
|
||||||
|
void Network::checkNetWork()
|
||||||
|
{
|
||||||
|
QNetworkConfigurationManager mgr;
|
||||||
|
if (mgr.isOnline()) {
|
||||||
|
//判断网络是否有连接,不一定能上网,如果连接了,则开始检查互联网是否可以ping通
|
||||||
|
QHostInfo::lookupHost("www.gov.cn", this, SLOT(checkNetAvailable(QHostInfo)));
|
||||||
|
} else {
|
||||||
|
ErrorReact::getInstance()->networkFeedBack(false, "无网络");
|
||||||
|
emit effectiveNetwork(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//检查网络可用
|
||||||
|
void Network::checkNetAvailable(const QHostInfo &host)
|
||||||
|
{
|
||||||
|
//判断网络可用---返回错误原因
|
||||||
|
if (host.error() != QHostInfo::NoError) {
|
||||||
|
ErrorReact::getInstance()->networkFeedBack(false, host.errorString());
|
||||||
|
emit effectiveNetwork(false);
|
||||||
|
} else {
|
||||||
|
emit effectiveNetwork(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Network::initConnectionInfo()
|
||||||
|
{
|
||||||
|
// service名,path,interface;systemBus() or sessionBus()
|
||||||
|
QDBusInterface interface("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager",
|
||||||
|
"org.freedesktop.DBus.Properties", QDBusConnection::systemBus());
|
||||||
|
// method:get(接口名,属性名) ----返回值为:Variant-----返回当前的所有连接的网络
|
||||||
|
QDBusMessage result = interface.call("Get", "org.freedesktop.NetworkManager", "ActiveConnections");
|
||||||
|
// outArgs放返回的数据
|
||||||
|
QList<QVariant> outArgs = result.arguments();
|
||||||
|
QVariant first = outArgs.at(0);
|
||||||
|
QDBusVariant dbvFirst = first.value<QDBusVariant>();
|
||||||
|
QVariant vFirst = dbvFirst.variant();
|
||||||
|
QDBusArgument dbusArgs = vFirst.value<QDBusArgument>();
|
||||||
|
|
||||||
|
QDBusObjectPath objPath;
|
||||||
|
dbusArgs.beginArray();
|
||||||
|
//循环存
|
||||||
|
while (!dbusArgs.atEnd()) {
|
||||||
|
dbusArgs >> objPath;
|
||||||
|
m_oldPaths.append(objPath);
|
||||||
|
//目的可能是检测更换网络:更换网络---刷新
|
||||||
|
QDBusInterface interface("org.freedesktop.NetworkManager", objPath.path(), "org.freedesktop.DBus.Properties",
|
||||||
|
QDBusConnection::systemBus());
|
||||||
|
//获得网络类型--type是有线还是无线:802-3-ethernet,802-11-wireless
|
||||||
|
QDBusReply<QVariant> reply = interface.call("Get", "org.freedesktop.NetworkManager.Connection.Active", "Type");
|
||||||
|
m_oldPathInfo.append(reply.value().toString());
|
||||||
|
}
|
||||||
|
dbusArgs.endArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::onPropertiesChanged(QVariantMap qvm)
|
||||||
|
{
|
||||||
|
for (QString keyStr : qvm.keys()) {
|
||||||
|
if (keyStr == "ActiveConnections") {
|
||||||
|
const QDBusArgument &dbusArg = qvm.value(keyStr).value<QDBusArgument>();
|
||||||
|
QList<QDBusObjectPath> newPaths;
|
||||||
|
dbusArg >> newPaths;
|
||||||
|
QStringList newPathInfo;
|
||||||
|
foreach (QDBusObjectPath objPath, newPaths) {
|
||||||
|
QDBusInterface interface("org.freedesktop.NetworkManager", objPath.path(),
|
||||||
|
"org.freedesktop.DBus.Properties", QDBusConnection::systemBus());
|
||||||
|
|
||||||
|
QDBusReply<QVariant> reply =
|
||||||
|
interface.call("Get", "org.freedesktop.NetworkManager.Connection.Active", "Type");
|
||||||
|
|
||||||
|
if (reply.value().toString() == "") {
|
||||||
|
ErrorReact::getInstance()->networkFeedBack(false, "无网络");
|
||||||
|
emit effectiveNetwork(false);
|
||||||
|
}
|
||||||
|
newPathInfo.append(reply.value().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前的网络连接个数由0个增为1个时,触发天气界面更新
|
||||||
|
if (newPaths.size() == 1) {
|
||||||
|
if (m_oldPaths.size() == 0) {
|
||||||
|
//等待4s,开始发送刷新信号
|
||||||
|
QTimer::singleShot(4 * 1000, this, SLOT(onTimeFinished()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isChangeOldPathInfo = true;
|
||||||
|
for (int k = 0; k < newPathInfo.size(); k++) {
|
||||||
|
if (newPathInfo.at(k) == "") {
|
||||||
|
isChangeOldPathInfo = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isChangeOldPathInfo) {
|
||||||
|
m_oldPathInfo = newPathInfo;
|
||||||
|
}
|
||||||
|
m_oldPaths = newPaths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::initConnect()
|
||||||
|
{
|
||||||
|
// dbus-信号槽
|
||||||
|
QDBusConnection::systemBus().connect(QString("org.freedesktop.NetworkManager"),
|
||||||
|
QString("/org/freedesktop/NetworkManager"),
|
||||||
|
QString("org.freedesktop.NetworkManager"), QString("PropertiesChanged"), this,
|
||||||
|
SLOT(onPropertiesChanged(QVariantMap)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::onTimeFinished()
|
||||||
|
{
|
||||||
|
//发送信号--刷新界面
|
||||||
|
emit haveNet();
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef NETWORK_H
|
||||||
|
#define NETWORK_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QNetworkConfigurationManager>
|
||||||
|
#include <QtNetwork/QNetworkConfigurationManager>
|
||||||
|
#include <QHostInfo>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDBusArgument>
|
||||||
|
#include <QDBusObjectPath>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
#include <QDBusReply>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QTimer>
|
||||||
|
#include "controller/core/errorreact.h"
|
||||||
|
class Network : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Network(QObject *parent = 0);
|
||||||
|
void checkNetWork(); //检查网络
|
||||||
|
void initConnectionInfo(); //初始化网络dbus
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringList m_oldPathInfo;
|
||||||
|
QList<QDBusObjectPath> m_oldPaths;
|
||||||
|
|
||||||
|
void initConnect(); //初始化信号槽
|
||||||
|
private slots:
|
||||||
|
void checkNetAvailable(const QHostInfo &host); //检查网络可用
|
||||||
|
void onPropertiesChanged(QVariantMap qvm); //监听断网联网
|
||||||
|
void onTimeFinished(); //延时发送重新定位请求
|
||||||
|
signals:
|
||||||
|
void effectiveNetwork(bool isOnline); //网络连接正常
|
||||||
|
void haveNet(); //网络从无到有,开始刷新
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NETWORK_H
|
|
@ -0,0 +1,135 @@
|
||||||
|
#include "searchmarch.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
SearchThread::SearchThread(SearchMarch *parent) : QThread(parent) {}
|
||||||
|
|
||||||
|
void SearchThread::run()
|
||||||
|
{
|
||||||
|
SearchMarch *m_worker = qobject_cast<SearchMarch *>(parent());
|
||||||
|
if (!m_worker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// CN101250101,changsha,长沙,CN,China,中国,hunan,湖南,changsha,长沙,28.19409,112.98228,"430101,430100,430000",
|
||||||
|
//本地词表--存储各地区的中英文名称,对应的cityId,经纬度等信息
|
||||||
|
//在开始时,将本地词表中的所有的地区的信息m_locatonList列表中,元素为LocationData结构体
|
||||||
|
QFile file(":/data/data/china-city-list.csv");
|
||||||
|
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
//读取行
|
||||||
|
QString line = file.readLine();
|
||||||
|
line = line.replace("\n", "");
|
||||||
|
//去掉首行,没有数据的,遍历整个词表csv,将其存储在m_locatonList列表中
|
||||||
|
while (!line.isEmpty()) {
|
||||||
|
QStringList resultList = line.split(",");
|
||||||
|
if (resultList.length() < 10) {
|
||||||
|
line = file.readLine();
|
||||||
|
line = line.replace("\n", "");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString id = resultList.at(0);
|
||||||
|
if (!id.startsWith("CN")) {
|
||||||
|
line = file.readLine();
|
||||||
|
line = line.replace("\n", "");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationData data;
|
||||||
|
data.id = id.remove(0, 2); // remove "CN"
|
||||||
|
data.city_en = resultList.at(1);
|
||||||
|
data.city = resultList.at(2);
|
||||||
|
data.country_en = resultList.at(4);
|
||||||
|
data.country = resultList.at(5);
|
||||||
|
data.province_en = resultList.at(6);
|
||||||
|
data.province = resultList.at(7);
|
||||||
|
data.admin_district_en = resultList.at(8);
|
||||||
|
data.admin_district = resultList.at(9);
|
||||||
|
data.shorthand = resultList.at(10);
|
||||||
|
|
||||||
|
m_worker->m_locatonList << data; //将数据存入m_locatonList中
|
||||||
|
|
||||||
|
line = file.readLine();
|
||||||
|
line = line.replace("\n", "");
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SearchMarch::SearchMarch(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
m_workerThread = new SearchThread(this);
|
||||||
|
m_workerThread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchMarch::~SearchMarch()
|
||||||
|
{
|
||||||
|
m_workerThread->deleteLater();
|
||||||
|
}
|
||||||
|
//返回搜索结果
|
||||||
|
QList<LocationData> SearchMarch::exactMatchCity(const QString &inputText) const
|
||||||
|
{
|
||||||
|
QList<LocationData> searchedList;
|
||||||
|
//搜索匹配-遍历m_locatonList
|
||||||
|
for (const LocationData line : m_locatonList) {
|
||||||
|
if (line.shorthand == inputText || line.id == inputText || //拼音和ID
|
||||||
|
line.province == inputText || line.province_en == inputText || //省
|
||||||
|
line.city.contains(inputText) || line.city_en.contains(inputText) //县
|
||||||
|
) {
|
||||||
|
//保证完全匹配的字符串放在显示的第一个
|
||||||
|
if (inputText == line.city_en) {
|
||||||
|
searchedList.insert(0, line);
|
||||||
|
} else {
|
||||||
|
searchedList.append(line); //将数据加入列表
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return searchedList;
|
||||||
|
}
|
||||||
|
//自动定位-查找当前地区id
|
||||||
|
QString SearchMarch::setAutomaticCity(const QString &cityName)
|
||||||
|
{
|
||||||
|
QString cityId;
|
||||||
|
|
||||||
|
if (cityName.isEmpty()) {
|
||||||
|
return cityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(":/data/data/china-city-list.csv");
|
||||||
|
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
QString line = file.readLine();
|
||||||
|
|
||||||
|
line = line.replace("\n", "");
|
||||||
|
while (!line.isEmpty()) {
|
||||||
|
QStringList resultList = line.split(",");
|
||||||
|
if (resultList.length() < 10) {
|
||||||
|
line = file.readLine();
|
||||||
|
line = line.replace("\n", "");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//("CN101340406", "yunlin", "云林", "CN", "China", "中国", "taiwan", "台湾", "taizhong", "台中", "yl",
|
||||||
|
//"23.718", "120.538", "710000")
|
||||||
|
QString id = resultList.at(0);
|
||||||
|
if (!id.startsWith("CN")) {
|
||||||
|
line = file.readLine();
|
||||||
|
line = line.replace("\n", "");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//对比cityname和词表的city,拿id,去CN
|
||||||
|
if (resultList.at(1).compare(cityName, Qt::CaseInsensitive) == 0
|
||||||
|
|| resultList.at(2).compare(cityName, Qt::CaseInsensitive) == 0
|
||||||
|
|| QString(resultList.at(2) + "市").compare(cityName, Qt::CaseInsensitive) == 0
|
||||||
|
|| QString(resultList.at(2) + "区").compare(cityName, Qt::CaseInsensitive) == 0
|
||||||
|
|| QString(resultList.at(2) + "县").compare(cityName, Qt::CaseInsensitive) == 0) {
|
||||||
|
id.remove(0, 2); // remove "CN"
|
||||||
|
cityId = id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
line = file.readLine();
|
||||||
|
line = line.replace("\n", "");
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
return cityId;
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef SEARCHMARCH_H
|
||||||
|
#define SEARCHMARCH_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include "global/corevar.h"
|
||||||
|
#include "controller/core/errorreact.h"
|
||||||
|
class SearchMarch;
|
||||||
|
|
||||||
|
class SearchThread : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SearchThread(SearchMarch *parent);
|
||||||
|
~SearchThread() {}
|
||||||
|
|
||||||
|
//从文件china-city-list.csv中查找子串,并将城市数据保存在LocationData结构体中
|
||||||
|
void run() Q_DECL_OVERRIDE;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SearchMarch : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SearchMarch(QObject *parent = 0);
|
||||||
|
~SearchMarch();
|
||||||
|
QString setAutomaticCity(const QString &cityName); //定位当前城市
|
||||||
|
//将匹配到的每个城市加入一个列表中
|
||||||
|
QList<LocationData> exactMatchCity(const QString &inputText) const;
|
||||||
|
QList<LocationData> m_locatonList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class WorkerThread;
|
||||||
|
|
||||||
|
SearchThread *m_workerThread = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LOCATIONWORKER_H
|
|
@ -0,0 +1 @@
|
||||||
|
#include "qtlockedfile.h"
|
|
@ -0,0 +1 @@
|
||||||
|
#include "qtsingleapplication.h"
|
|
@ -0,0 +1,33 @@
|
||||||
|
Qt Solutions Component: Single Application
|
||||||
|
|
||||||
|
The QtSingleApplication component provides support for
|
||||||
|
applications that can be only started once per user.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Version history:
|
||||||
|
|
||||||
|
2.0: - Version 1.3 ported to Qt 4.
|
||||||
|
|
||||||
|
2.1: - Fix compilation problem on Mac.
|
||||||
|
|
||||||
|
2.2: - Really fix the Mac compilation problem.
|
||||||
|
- Mac: fix crash due to wrong object releasing.
|
||||||
|
- Mac: Fix memory leak.
|
||||||
|
|
||||||
|
2.3: - Windows: Force creation of internal widget to make it work
|
||||||
|
with Qt 4.2.
|
||||||
|
|
||||||
|
2.4: - Fix the system for automatic window raising on message
|
||||||
|
reception. NOTE: minor API change.
|
||||||
|
|
||||||
|
2.5: - Mac: Fix isRunning() to work and report correctly.
|
||||||
|
|
||||||
|
2.6: - - initialize() is now obsolete, no longer necessary to call
|
||||||
|
it
|
||||||
|
- - Fixed race condition where multiple instances migth be started
|
||||||
|
- - QtSingleCoreApplication variant provided for non-GUI (console)
|
||||||
|
usage
|
||||||
|
- Complete reimplementation. Visible changes:
|
||||||
|
- LGPL release.
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "qtlocalpeer.h"
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QTime>
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
#include <QLibrary>
|
||||||
|
#include <qt_windows.h>
|
||||||
|
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
|
||||||
|
static PProcessIdToSessionId pProcessIdToSessionId = 0;
|
||||||
|
#endif
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace QtLP_Private {
|
||||||
|
#include "qtlockedfile.cpp"
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
#include "qtlockedfile_win.cpp"
|
||||||
|
#else
|
||||||
|
#include "qtlockedfile_unix.cpp"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* QtLocalPeer::ack = "ack";
|
||||||
|
|
||||||
|
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
|
||||||
|
: QObject(parent), id(appId)
|
||||||
|
{
|
||||||
|
QString prefix = id;
|
||||||
|
if (id.isEmpty()) {
|
||||||
|
id = QCoreApplication::applicationFilePath();
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
id = id.toLower();
|
||||||
|
#endif
|
||||||
|
prefix = id.section(QLatin1Char('/'), -1);
|
||||||
|
}
|
||||||
|
prefix.remove(QRegExp("[^a-zA-Z]"));
|
||||||
|
prefix.truncate(6);
|
||||||
|
|
||||||
|
QByteArray idc = id.toUtf8();
|
||||||
|
quint16 idNum = qChecksum(idc.constData(), idc.size());
|
||||||
|
socketName = QLatin1String("qtsingleapp-") + prefix
|
||||||
|
+ QLatin1Char('-') + QString::number(idNum, 16);
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
if (!pProcessIdToSessionId) {
|
||||||
|
QLibrary lib("kernel32");
|
||||||
|
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
|
||||||
|
}
|
||||||
|
if (pProcessIdToSessionId) {
|
||||||
|
DWORD sessionId = 0;
|
||||||
|
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||||
|
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
server = new QLocalServer(this);
|
||||||
|
QString lockName = QDir(QDir::tempPath()).absolutePath()
|
||||||
|
+ QLatin1Char('/') + socketName
|
||||||
|
+ QLatin1String("-lockfile");
|
||||||
|
lockFile.setFileName(lockName);
|
||||||
|
lockFile.open(QIODevice::ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool QtLocalPeer::isClient()
|
||||||
|
{
|
||||||
|
if (lockFile.isLocked())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool res = server->listen(socketName);
|
||||||
|
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
|
||||||
|
// ### Workaround
|
||||||
|
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
|
||||||
|
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
|
||||||
|
res = server->listen(socketName);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!res)
|
||||||
|
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
|
||||||
|
QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
|
||||||
|
{
|
||||||
|
if (!isClient())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QLocalSocket socket;
|
||||||
|
bool connOk = false;
|
||||||
|
for(int i = 0; i < 2; i++) {
|
||||||
|
// Try twice, in case the other instance is just starting up
|
||||||
|
socket.connectToServer(socketName);
|
||||||
|
connOk = socket.waitForConnected(timeout/2);
|
||||||
|
if (connOk || i)
|
||||||
|
break;
|
||||||
|
int ms = 250;
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
Sleep(DWORD(ms));
|
||||||
|
#else
|
||||||
|
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (!connOk)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QByteArray uMsg(message.toUtf8());
|
||||||
|
QDataStream ds(&socket);
|
||||||
|
ds.writeBytes(uMsg.constData(), uMsg.size());
|
||||||
|
bool res = socket.waitForBytesWritten(timeout);
|
||||||
|
if (res) {
|
||||||
|
res &= socket.waitForReadyRead(timeout); // wait for ack
|
||||||
|
if (res)
|
||||||
|
res &= (socket.read(qstrlen(ack)) == ack);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QtLocalPeer::receiveConnection()
|
||||||
|
{
|
||||||
|
QLocalSocket* socket = server->nextPendingConnection();
|
||||||
|
if (!socket)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (socket->bytesAvailable() < (int)sizeof(quint32))
|
||||||
|
socket->waitForReadyRead();
|
||||||
|
QDataStream ds(socket);
|
||||||
|
QByteArray uMsg;
|
||||||
|
quint32 remaining;
|
||||||
|
ds >> remaining;
|
||||||
|
uMsg.resize(remaining);
|
||||||
|
int got = 0;
|
||||||
|
char* uMsgBuf = uMsg.data();
|
||||||
|
do {
|
||||||
|
got = ds.readRawData(uMsgBuf, remaining);
|
||||||
|
remaining -= got;
|
||||||
|
uMsgBuf += got;
|
||||||
|
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
|
||||||
|
if (got < 0) {
|
||||||
|
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
|
||||||
|
delete socket;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString message(QString::fromUtf8(uMsg));
|
||||||
|
socket->write(ack, qstrlen(ack));
|
||||||
|
socket->waitForBytesWritten(1000);
|
||||||
|
socket->waitForDisconnected(1000); // make sure client reads ack
|
||||||
|
delete socket;
|
||||||
|
emit messageReceived(message); //### (might take a long time to return)
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QTLOCALPEER_H
|
||||||
|
#define QTLOCALPEER_H
|
||||||
|
|
||||||
|
#include <QLocalServer>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#include "qtlockedfile.h"
|
||||||
|
|
||||||
|
class QtLocalPeer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
|
||||||
|
bool isClient();
|
||||||
|
bool sendMessage(const QString &message, int timeout);
|
||||||
|
QString applicationId() const
|
||||||
|
{ return id; }
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void messageReceived(const QString &message);
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
void receiveConnection();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QString id;
|
||||||
|
QString socketName;
|
||||||
|
QLocalServer* server;
|
||||||
|
QtLP_Private::QtLockedFile lockFile;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const char* ack;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QTLOCALPEER_H
|
|
@ -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 Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "qtlockedfile.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QtLockedFile
|
||||||
|
|
||||||
|
\brief The QtLockedFile class extends QFile with advisory locking
|
||||||
|
functions.
|
||||||
|
|
||||||
|
A file may be locked in read or write mode. Multiple instances of
|
||||||
|
\e QtLockedFile, created in multiple processes running on the same
|
||||||
|
machine, may have a file locked in read mode. Exactly one instance
|
||||||
|
may have it locked in write mode. A read and a write lock cannot
|
||||||
|
exist simultaneously on the same file.
|
||||||
|
|
||||||
|
The file locks are advisory. This means that nothing prevents
|
||||||
|
another process from manipulating a locked file using QFile or
|
||||||
|
file system functions offered by the OS. Serialization is only
|
||||||
|
guaranteed if all processes that access the file use
|
||||||
|
QLockedFile. Also, while holding a lock on a file, a process
|
||||||
|
must not open the same file again (through any API), or locks
|
||||||
|
can be unexpectedly lost.
|
||||||
|
|
||||||
|
The lock provided by an instance of \e QtLockedFile is released
|
||||||
|
whenever the program terminates. This is true even when the
|
||||||
|
program crashes and no destructors are called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \enum QtLockedFile::LockMode
|
||||||
|
|
||||||
|
This enum describes the available lock modes.
|
||||||
|
|
||||||
|
\value ReadLock A read lock.
|
||||||
|
\value WriteLock A write lock.
|
||||||
|
\value NoLock Neither a read lock nor a write lock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructs an unlocked \e QtLockedFile object. This constructor
|
||||||
|
behaves in the same way as \e QFile::QFile().
|
||||||
|
|
||||||
|
\sa QFile::QFile()
|
||||||
|
*/
|
||||||
|
QtLockedFile::QtLockedFile()
|
||||||
|
: QFile()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
wmutex = 0;
|
||||||
|
rmutex = 0;
|
||||||
|
#endif
|
||||||
|
m_lock_mode = NoLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructs an unlocked QtLockedFile object with file \a name. This
|
||||||
|
constructor behaves in the same way as \e QFile::QFile(const
|
||||||
|
QString&).
|
||||||
|
|
||||||
|
\sa QFile::QFile()
|
||||||
|
*/
|
||||||
|
QtLockedFile::QtLockedFile(const QString &name)
|
||||||
|
: QFile(name)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
wmutex = 0;
|
||||||
|
rmutex = 0;
|
||||||
|
#endif
|
||||||
|
m_lock_mode = NoLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Opens the file in OpenMode \a mode.
|
||||||
|
|
||||||
|
This is identical to QFile::open(), with the one exception that the
|
||||||
|
Truncate mode flag is disallowed. Truncation would conflict with the
|
||||||
|
advisory file locking, since the file would be modified before the
|
||||||
|
write lock is obtained. If truncation is required, use resize(0)
|
||||||
|
after obtaining the write lock.
|
||||||
|
|
||||||
|
Returns true if successful; otherwise false.
|
||||||
|
|
||||||
|
\sa QFile::open(), QFile::resize()
|
||||||
|
*/
|
||||||
|
bool QtLockedFile::open(OpenMode mode)
|
||||||
|
{
|
||||||
|
if (mode & QIODevice::Truncate) {
|
||||||
|
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return QFile::open(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns \e true if this object has a in read or write lock;
|
||||||
|
otherwise returns \e false.
|
||||||
|
|
||||||
|
\sa lockMode()
|
||||||
|
*/
|
||||||
|
bool QtLockedFile::isLocked() const
|
||||||
|
{
|
||||||
|
return m_lock_mode != NoLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the type of lock currently held by this object, or \e
|
||||||
|
QtLockedFile::NoLock.
|
||||||
|
|
||||||
|
\sa isLocked()
|
||||||
|
*/
|
||||||
|
QtLockedFile::LockMode QtLockedFile::lockMode() const
|
||||||
|
{
|
||||||
|
return m_lock_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
|
||||||
|
|
||||||
|
Obtains a lock of type \a mode. The file must be opened before it
|
||||||
|
can be locked.
|
||||||
|
|
||||||
|
If \a block is true, this function will block until the lock is
|
||||||
|
aquired. If \a block is false, this function returns \e false
|
||||||
|
immediately if the lock cannot be aquired.
|
||||||
|
|
||||||
|
If this object already has a lock of type \a mode, this function
|
||||||
|
returns \e true immediately. If this object has a lock of a
|
||||||
|
different type than \a mode, the lock is first released and then a
|
||||||
|
new lock is obtained.
|
||||||
|
|
||||||
|
This function returns \e true if, after it executes, the file is
|
||||||
|
locked by this object, and \e false otherwise.
|
||||||
|
|
||||||
|
\sa unlock(), isLocked(), lockMode()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn bool QtLockedFile::unlock()
|
||||||
|
|
||||||
|
Releases a lock.
|
||||||
|
|
||||||
|
If the object has no lock, this function returns immediately.
|
||||||
|
|
||||||
|
This function returns \e true if, after it executes, the file is
|
||||||
|
not locked by this object, and \e false otherwise.
|
||||||
|
|
||||||
|
\sa lock(), isLocked(), lockMode()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn QtLockedFile::~QtLockedFile()
|
||||||
|
|
||||||
|
Destroys the \e QtLockedFile object. If any locks were held, they
|
||||||
|
are released.
|
||||||
|
*/
|
|
@ -0,0 +1,97 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QTLOCKEDFILE_H
|
||||||
|
#define QTLOCKEDFILE_H
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include <QVector>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
|
||||||
|
# define QT_QTLOCKEDFILE_EXPORT
|
||||||
|
# elif defined(QT_QTLOCKEDFILE_IMPORT)
|
||||||
|
# if defined(QT_QTLOCKEDFILE_EXPORT)
|
||||||
|
# undef QT_QTLOCKEDFILE_EXPORT
|
||||||
|
# endif
|
||||||
|
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
|
||||||
|
# elif defined(QT_QTLOCKEDFILE_EXPORT)
|
||||||
|
# undef QT_QTLOCKEDFILE_EXPORT
|
||||||
|
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QT_QTLOCKEDFILE_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace QtLP_Private {
|
||||||
|
|
||||||
|
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum LockMode { NoLock = 0, ReadLock, WriteLock };
|
||||||
|
|
||||||
|
QtLockedFile();
|
||||||
|
QtLockedFile(const QString &name);
|
||||||
|
~QtLockedFile();
|
||||||
|
|
||||||
|
bool open(OpenMode mode);
|
||||||
|
|
||||||
|
bool lock(LockMode mode, bool block = true);
|
||||||
|
bool unlock();
|
||||||
|
bool isLocked() const;
|
||||||
|
LockMode lockMode() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
Qt::HANDLE wmutex;
|
||||||
|
Qt::HANDLE rmutex;
|
||||||
|
QVector<Qt::HANDLE> rmutexes;
|
||||||
|
QString mutexname;
|
||||||
|
|
||||||
|
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
|
||||||
|
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
LockMode m_lock_mode;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,115 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "qtlockedfile.h"
|
||||||
|
|
||||||
|
bool QtLockedFile::lock(LockMode mode, bool block)
|
||||||
|
{
|
||||||
|
if (!isOpen()) {
|
||||||
|
qWarning("QtLockedFile::lock(): file is not opened");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == NoLock)
|
||||||
|
return unlock();
|
||||||
|
|
||||||
|
if (mode == m_lock_mode)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (m_lock_mode != NoLock)
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
struct flock fl;
|
||||||
|
fl.l_whence = SEEK_SET;
|
||||||
|
fl.l_start = 0;
|
||||||
|
fl.l_len = 0;
|
||||||
|
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
|
||||||
|
int cmd = block ? F_SETLKW : F_SETLK;
|
||||||
|
int ret = fcntl(handle(), cmd, &fl);
|
||||||
|
|
||||||
|
if (ret == -1) {
|
||||||
|
if (errno != EINTR && errno != EAGAIN)
|
||||||
|
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
m_lock_mode = mode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool QtLockedFile::unlock()
|
||||||
|
{
|
||||||
|
if (!isOpen()) {
|
||||||
|
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLocked())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
struct flock fl;
|
||||||
|
fl.l_whence = SEEK_SET;
|
||||||
|
fl.l_start = 0;
|
||||||
|
fl.l_len = 0;
|
||||||
|
fl.l_type = F_UNLCK;
|
||||||
|
int ret = fcntl(handle(), F_SETLKW, &fl);
|
||||||
|
|
||||||
|
if (ret == -1) {
|
||||||
|
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lock_mode = NoLock;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QtLockedFile::~QtLockedFile()
|
||||||
|
{
|
||||||
|
if (isOpen())
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "qtlockedfile.h"
|
||||||
|
#include <qt_windows.h>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
#define MUTEX_PREFIX "QtLockedFile mutex "
|
||||||
|
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
|
||||||
|
#define MAX_READERS MAXIMUM_WAIT_OBJECTS
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
#define QT_WA(unicode, ansi) unicode
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
|
||||||
|
{
|
||||||
|
if (mutexname.isEmpty()) {
|
||||||
|
QFileInfo fi(*this);
|
||||||
|
mutexname = QString::fromLatin1(MUTEX_PREFIX)
|
||||||
|
+ fi.absoluteFilePath().toLower();
|
||||||
|
}
|
||||||
|
QString mname(mutexname);
|
||||||
|
if (idx >= 0)
|
||||||
|
mname += QString::number(idx);
|
||||||
|
|
||||||
|
Qt::HANDLE mutex;
|
||||||
|
if (doCreate) {
|
||||||
|
QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); },
|
||||||
|
{ mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
|
||||||
|
if (!mutex) {
|
||||||
|
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); },
|
||||||
|
{ mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
|
||||||
|
if (!mutex) {
|
||||||
|
if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
||||||
|
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
|
||||||
|
{
|
||||||
|
Q_ASSERT(mutex);
|
||||||
|
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
|
||||||
|
switch (res) {
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
case WAIT_ABANDONED:
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool QtLockedFile::lock(LockMode mode, bool block)
|
||||||
|
{
|
||||||
|
if (!isOpen()) {
|
||||||
|
qWarning("QtLockedFile::lock(): file is not opened");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == NoLock)
|
||||||
|
return unlock();
|
||||||
|
|
||||||
|
if (mode == m_lock_mode)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (m_lock_mode != NoLock)
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!waitMutex(wmutex, block))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mode == ReadLock) {
|
||||||
|
int idx = 0;
|
||||||
|
for (; idx < MAX_READERS; idx++) {
|
||||||
|
rmutex = getMutexHandle(idx, false);
|
||||||
|
if (!rmutex || waitMutex(rmutex, false))
|
||||||
|
break;
|
||||||
|
CloseHandle(rmutex);
|
||||||
|
}
|
||||||
|
bool ok = true;
|
||||||
|
if (idx >= MAX_READERS) {
|
||||||
|
qWarning("QtLockedFile::lock(): too many readers");
|
||||||
|
rmutex = 0;
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
else if (!rmutex) {
|
||||||
|
rmutex = getMutexHandle(idx, true);
|
||||||
|
if (!rmutex || !waitMutex(rmutex, false))
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
if (!ok && rmutex) {
|
||||||
|
CloseHandle(rmutex);
|
||||||
|
rmutex = 0;
|
||||||
|
}
|
||||||
|
ReleaseMutex(wmutex);
|
||||||
|
if (!ok)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Q_ASSERT(rmutexes.isEmpty());
|
||||||
|
for (int i = 0; i < MAX_READERS; i++) {
|
||||||
|
Qt::HANDLE mutex = getMutexHandle(i, false);
|
||||||
|
if (mutex)
|
||||||
|
rmutexes.append(mutex);
|
||||||
|
}
|
||||||
|
if (rmutexes.size()) {
|
||||||
|
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
|
||||||
|
TRUE, block ? INFINITE : 0);
|
||||||
|
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
|
||||||
|
if (res != WAIT_TIMEOUT)
|
||||||
|
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
|
||||||
|
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
|
||||||
|
unlock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lock_mode = mode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QtLockedFile::unlock()
|
||||||
|
{
|
||||||
|
if (!isOpen()) {
|
||||||
|
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLocked())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (m_lock_mode == ReadLock) {
|
||||||
|
ReleaseMutex(rmutex);
|
||||||
|
CloseHandle(rmutex);
|
||||||
|
rmutex = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach(Qt::HANDLE mutex, rmutexes) {
|
||||||
|
ReleaseMutex(mutex);
|
||||||
|
CloseHandle(mutex);
|
||||||
|
}
|
||||||
|
rmutexes.clear();
|
||||||
|
ReleaseMutex(wmutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lock_mode = QtLockedFile::NoLock;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QtLockedFile::~QtLockedFile()
|
||||||
|
{
|
||||||
|
if (isOpen())
|
||||||
|
unlock();
|
||||||
|
if (wmutex)
|
||||||
|
CloseHandle(wmutex);
|
||||||
|
}
|
|
@ -0,0 +1,350 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "qtsingleapplication.h"
|
||||||
|
#include "qtlocalpeer.h"
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QtSingleApplication qtsingleapplication.h
|
||||||
|
\brief The QtSingleApplication class provides an API to detect and
|
||||||
|
communicate with running instances of an application.
|
||||||
|
|
||||||
|
This class allows you to create applications where only one
|
||||||
|
instance should be running at a time. I.e., if the user tries to
|
||||||
|
launch another instance, the already running instance will be
|
||||||
|
activated instead. Another usecase is a client-server system,
|
||||||
|
where the first started instance will assume the role of server,
|
||||||
|
and the later instances will act as clients of that server.
|
||||||
|
|
||||||
|
By default, the full path of the executable file is used to
|
||||||
|
determine whether two processes are instances of the same
|
||||||
|
application. You can also provide an explicit identifier string
|
||||||
|
that will be compared instead.
|
||||||
|
|
||||||
|
The application should create the QtSingleApplication object early
|
||||||
|
in the startup phase, and call isRunning() to find out if another
|
||||||
|
instance of this application is already running. If isRunning()
|
||||||
|
returns false, it means that no other instance is running, and
|
||||||
|
this instance has assumed the role as the running instance. In
|
||||||
|
this case, the application should continue with the initialization
|
||||||
|
of the application user interface before entering the event loop
|
||||||
|
with exec(), as normal.
|
||||||
|
|
||||||
|
The messageReceived() signal will be emitted when the running
|
||||||
|
application receives messages from another instance of the same
|
||||||
|
application. When a message is received it might be helpful to the
|
||||||
|
user to raise the application so that it becomes visible. To
|
||||||
|
facilitate this, QtSingleApplication provides the
|
||||||
|
setActivationWindow() function and the activateWindow() slot.
|
||||||
|
|
||||||
|
If isRunning() returns true, another instance is already
|
||||||
|
running. It may be alerted to the fact that another instance has
|
||||||
|
started by using the sendMessage() function. Also data such as
|
||||||
|
startup parameters (e.g. the name of the file the user wanted this
|
||||||
|
new instance to open) can be passed to the running instance with
|
||||||
|
this function. Then, the application should terminate (or enter
|
||||||
|
client mode).
|
||||||
|
|
||||||
|
If isRunning() returns true, but sendMessage() fails, that is an
|
||||||
|
indication that the running instance is frozen.
|
||||||
|
|
||||||
|
Here's an example that shows how to convert an existing
|
||||||
|
application to use QtSingleApplication. It is very simple and does
|
||||||
|
not make use of all QtSingleApplication's functionality (see the
|
||||||
|
examples for that).
|
||||||
|
|
||||||
|
\code
|
||||||
|
// Original
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
MyMainWidget mmw;
|
||||||
|
mmw.show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single instance
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
QtSingleApplication app(argc, argv);
|
||||||
|
|
||||||
|
if (app.isRunning())
|
||||||
|
return !app.sendMessage(someDataString);
|
||||||
|
|
||||||
|
MyMainWidget mmw;
|
||||||
|
app.setActivationWindow(&mmw);
|
||||||
|
mmw.show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Once this QtSingleApplication instance is destroyed (normally when
|
||||||
|
the process exits or crashes), when the user next attempts to run the
|
||||||
|
application this instance will not, of course, be encountered. The
|
||||||
|
next instance to call isRunning() or sendMessage() will assume the
|
||||||
|
role as the new running instance.
|
||||||
|
|
||||||
|
For console (non-GUI) applications, QtSingleCoreApplication may be
|
||||||
|
used instead of this class, to avoid the dependency on the QtGui
|
||||||
|
library.
|
||||||
|
|
||||||
|
\sa QtSingleCoreApplication
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void QtSingleApplication::sysInit(const QString &appId)
|
||||||
|
{
|
||||||
|
actWin = 0;
|
||||||
|
peer = new QtLocalPeer(this, appId);
|
||||||
|
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a QtSingleApplication object. The application identifier
|
||||||
|
will be QCoreApplication::applicationFilePath(). \a argc, \a
|
||||||
|
argv, and \a GUIenabled are passed on to the QAppliation constructor.
|
||||||
|
|
||||||
|
If you are creating a console application (i.e. setting \a
|
||||||
|
GUIenabled to false), you may consider using
|
||||||
|
QtSingleCoreApplication instead.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
|
||||||
|
: QApplication(argc, argv, GUIenabled)
|
||||||
|
{
|
||||||
|
sysInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a QtSingleApplication object with the application
|
||||||
|
identifier \a appId. \a argc and \a argv are passed on to the
|
||||||
|
QAppliation constructor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
|
||||||
|
: QApplication(argc, argv)
|
||||||
|
{
|
||||||
|
sysInit(appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION < 0x050000
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a QtSingleApplication object. The application identifier
|
||||||
|
will be QCoreApplication::applicationFilePath(). \a argc, \a
|
||||||
|
argv, and \a type are passed on to the QAppliation constructor.
|
||||||
|
*/
|
||||||
|
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
|
||||||
|
: QApplication(argc, argv, type)
|
||||||
|
{
|
||||||
|
sysInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# if defined(Q_WS_X11)
|
||||||
|
/*!
|
||||||
|
Special constructor for X11, ref. the documentation of
|
||||||
|
QApplication's corresponding constructor. The application identifier
|
||||||
|
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
|
||||||
|
and \a cmap are passed on to the QApplication constructor.
|
||||||
|
*/
|
||||||
|
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||||
|
: QApplication(dpy, visual, cmap)
|
||||||
|
{
|
||||||
|
sysInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Special constructor for X11, ref. the documentation of
|
||||||
|
QApplication's corresponding constructor. The application identifier
|
||||||
|
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
|
||||||
|
argv, \a visual, and \a cmap are passed on to the QApplication
|
||||||
|
constructor.
|
||||||
|
*/
|
||||||
|
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||||
|
: QApplication(dpy, argc, argv, visual, cmap)
|
||||||
|
{
|
||||||
|
sysInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Special constructor for X11, ref. the documentation of
|
||||||
|
QApplication's corresponding constructor. The application identifier
|
||||||
|
will be \a appId. \a dpy, \a argc, \a
|
||||||
|
argv, \a visual, and \a cmap are passed on to the QApplication
|
||||||
|
constructor.
|
||||||
|
*/
|
||||||
|
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||||
|
: QApplication(dpy, argc, argv, visual, cmap)
|
||||||
|
{
|
||||||
|
sysInit(appId);
|
||||||
|
}
|
||||||
|
# endif // Q_WS_X11
|
||||||
|
#endif // QT_VERSION < 0x050000
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns true if another instance of this application is running;
|
||||||
|
otherwise false.
|
||||||
|
|
||||||
|
This function does not find instances of this application that are
|
||||||
|
being run by a different user (on Windows: that are running in
|
||||||
|
another session).
|
||||||
|
|
||||||
|
\sa sendMessage()
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool QtSingleApplication::isRunning()
|
||||||
|
{
|
||||||
|
return peer->isClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tries to send the text \a message to the currently running
|
||||||
|
instance. The QtSingleApplication object in the running instance
|
||||||
|
will emit the messageReceived() signal when it receives the
|
||||||
|
message.
|
||||||
|
|
||||||
|
This function returns true if the message has been sent to, and
|
||||||
|
processed by, the current instance. If there is no instance
|
||||||
|
currently running, or if the running instance fails to process the
|
||||||
|
message within \a timeout milliseconds, this function return false.
|
||||||
|
|
||||||
|
\sa isRunning(), messageReceived()
|
||||||
|
*/
|
||||||
|
bool QtSingleApplication::sendMessage(const QString &message, int timeout)
|
||||||
|
{
|
||||||
|
return peer->sendMessage(message, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the application identifier. Two processes with the same
|
||||||
|
identifier will be regarded as instances of the same application.
|
||||||
|
*/
|
||||||
|
QString QtSingleApplication::id() const
|
||||||
|
{
|
||||||
|
return peer->applicationId();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the activation window of this application to \a aw. The
|
||||||
|
activation window is the widget that will be activated by
|
||||||
|
activateWindow(). This is typically the application's main window.
|
||||||
|
|
||||||
|
If \a activateOnMessage is true (the default), the window will be
|
||||||
|
activated automatically every time a message is received, just prior
|
||||||
|
to the messageReceived() signal being emitted.
|
||||||
|
|
||||||
|
\sa activateWindow(), messageReceived()
|
||||||
|
*/
|
||||||
|
|
||||||
|
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage)
|
||||||
|
{
|
||||||
|
actWin = aw;
|
||||||
|
if (activateOnMessage)
|
||||||
|
connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
|
||||||
|
else
|
||||||
|
disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the applications activation window if one has been set by
|
||||||
|
calling setActivationWindow(), otherwise returns 0.
|
||||||
|
|
||||||
|
\sa setActivationWindow()
|
||||||
|
*/
|
||||||
|
QWidget* QtSingleApplication::activationWindow() const
|
||||||
|
{
|
||||||
|
return actWin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
De-minimizes, raises, and activates this application's activation window.
|
||||||
|
This function does nothing if no activation window has been set.
|
||||||
|
|
||||||
|
This is a convenience function to show the user that this
|
||||||
|
application instance has been activated when he has tried to start
|
||||||
|
another instance.
|
||||||
|
|
||||||
|
This function should typically be called in response to the
|
||||||
|
messageReceived() signal. By default, that will happen
|
||||||
|
automatically, if an activation window has been set.
|
||||||
|
|
||||||
|
\sa setActivationWindow(), messageReceived(), initialize()
|
||||||
|
*/
|
||||||
|
void QtSingleApplication::activateWindow()
|
||||||
|
{
|
||||||
|
if (actWin) {
|
||||||
|
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
|
||||||
|
if(!actWin->isActiveWindow())
|
||||||
|
actWin->hide();
|
||||||
|
actWin->show(); // 解决了vnc远程时应用窗口不显示的问题
|
||||||
|
actWin->raise();
|
||||||
|
actWin->activateWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void QtSingleApplication::messageReceived(const QString& message)
|
||||||
|
|
||||||
|
This signal is emitted when the current instance receives a \a
|
||||||
|
message from another instance of this application.
|
||||||
|
|
||||||
|
\sa sendMessage(), setActivationWindow(), activateWindow()
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void QtSingleApplication::initialize(bool dummy = true)
|
||||||
|
|
||||||
|
\obsolete
|
||||||
|
*/
|
|
@ -0,0 +1,106 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QTSINGLEAPPLICATION_H
|
||||||
|
#define QTSINGLEAPPLICATION_H
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
class QtLocalPeer;
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT)
|
||||||
|
# define QT_QTSINGLEAPPLICATION_EXPORT
|
||||||
|
# elif defined(QT_QTSINGLEAPPLICATION_IMPORT)
|
||||||
|
# if defined(QT_QTSINGLEAPPLICATION_EXPORT)
|
||||||
|
# undef QT_QTSINGLEAPPLICATION_EXPORT
|
||||||
|
# endif
|
||||||
|
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport)
|
||||||
|
# elif defined(QT_QTSINGLEAPPLICATION_EXPORT)
|
||||||
|
# undef QT_QTSINGLEAPPLICATION_EXPORT
|
||||||
|
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QT_QTSINGLEAPPLICATION_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
|
||||||
|
QtSingleApplication(const QString &id, int &argc, char **argv);
|
||||||
|
#if QT_VERSION < 0x050000
|
||||||
|
QtSingleApplication(int &argc, char **argv, Type type);
|
||||||
|
# if defined(Q_WS_X11)
|
||||||
|
QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
||||||
|
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
|
||||||
|
QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
||||||
|
# endif // Q_WS_X11
|
||||||
|
#endif // QT_VERSION < 0x050000
|
||||||
|
|
||||||
|
bool isRunning();
|
||||||
|
QString id() const;
|
||||||
|
|
||||||
|
|
||||||
|
QWidget* activationWindow() const;
|
||||||
|
|
||||||
|
// Obsolete:
|
||||||
|
void initialize(bool dummy = true)
|
||||||
|
{ isRunning(); Q_UNUSED(dummy) }
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
bool sendMessage(const QString &message, int timeout = 5000);
|
||||||
|
void activateWindow();
|
||||||
|
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
|
||||||
|
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void messageReceived(const QString &message);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sysInit(const QString &appId = QString());
|
||||||
|
QtLocalPeer *peer;
|
||||||
|
QWidget *actWin;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QTSINGLEAPPLICATION_H
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include(../common.pri)
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
DEPENDPATH += $$PWD
|
||||||
|
QT *= network
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets
|
||||||
|
|
||||||
|
qtsingleapplication-uselib:!qtsingleapplication-buildlib {
|
||||||
|
LIBS += -L$$QTSINGLEAPPLICATION_LIBDIR -l$$QTSINGLEAPPLICATION_LIBNAME
|
||||||
|
} else {
|
||||||
|
SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp
|
||||||
|
HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h
|
||||||
|
}
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTSINGLEAPPLICATION_EXPORT
|
||||||
|
else:qtsingleapplication-uselib:DEFINES += QT_QTSINGLEAPPLICATION_IMPORT
|
||||||
|
}
|
|
@ -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 Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "qtsinglecoreapplication.h"
|
||||||
|
#include "qtlocalpeer.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QtSingleCoreApplication qtsinglecoreapplication.h
|
||||||
|
\brief A variant of the QtSingleApplication class for non-GUI applications.
|
||||||
|
|
||||||
|
This class is a variant of QtSingleApplication suited for use in
|
||||||
|
console (non-GUI) applications. It is an extension of
|
||||||
|
QCoreApplication (instead of QApplication). It does not require
|
||||||
|
the QtGui library.
|
||||||
|
|
||||||
|
The API and usage is identical to QtSingleApplication, except that
|
||||||
|
functions relating to the "activation window" are not present, for
|
||||||
|
obvious reasons. Please refer to the QtSingleApplication
|
||||||
|
documentation for explanation of the usage.
|
||||||
|
|
||||||
|
A QtSingleCoreApplication instance can communicate to a
|
||||||
|
QtSingleApplication instance if they share the same application
|
||||||
|
id. Hence, this class can be used to create a light-weight
|
||||||
|
command-line tool that sends commands to a GUI application.
|
||||||
|
|
||||||
|
\sa QtSingleApplication
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a QtSingleCoreApplication object. The application identifier
|
||||||
|
will be QCoreApplication::applicationFilePath(). \a argc and \a
|
||||||
|
argv are passed on to the QCoreAppliation constructor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
|
||||||
|
: QCoreApplication(argc, argv)
|
||||||
|
{
|
||||||
|
peer = new QtLocalPeer(this);
|
||||||
|
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a QtSingleCoreApplication object with the application
|
||||||
|
identifier \a appId. \a argc and \a argv are passed on to the
|
||||||
|
QCoreAppliation constructor.
|
||||||
|
*/
|
||||||
|
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
|
||||||
|
: QCoreApplication(argc, argv)
|
||||||
|
{
|
||||||
|
peer = new QtLocalPeer(this, appId);
|
||||||
|
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns true if another instance of this application is running;
|
||||||
|
otherwise false.
|
||||||
|
|
||||||
|
This function does not find instances of this application that are
|
||||||
|
being run by a different user (on Windows: that are running in
|
||||||
|
another session).
|
||||||
|
|
||||||
|
\sa sendMessage()
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool QtSingleCoreApplication::isRunning()
|
||||||
|
{
|
||||||
|
return peer->isClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tries to send the text \a message to the currently running
|
||||||
|
instance. The QtSingleCoreApplication object in the running instance
|
||||||
|
will emit the messageReceived() signal when it receives the
|
||||||
|
message.
|
||||||
|
|
||||||
|
This function returns true if the message has been sent to, and
|
||||||
|
processed by, the current instance. If there is no instance
|
||||||
|
currently running, or if the running instance fails to process the
|
||||||
|
message within \a timeout milliseconds, this function return false.
|
||||||
|
|
||||||
|
\sa isRunning(), messageReceived()
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
|
||||||
|
{
|
||||||
|
return peer->sendMessage(message, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the application identifier. Two processes with the same
|
||||||
|
identifier will be regarded as instances of the same application.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QString QtSingleCoreApplication::id() const
|
||||||
|
{
|
||||||
|
return peer->applicationId();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void QtSingleCoreApplication::messageReceived(const QString& message)
|
||||||
|
|
||||||
|
This signal is emitted when the current instance receives a \a
|
||||||
|
message from another instance of this application.
|
||||||
|
|
||||||
|
\sa sendMessage()
|
||||||
|
*/
|
|
@ -0,0 +1,71 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QTSINGLECOREAPPLICATION_H
|
||||||
|
#define QTSINGLECOREAPPLICATION_H
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
class QtLocalPeer;
|
||||||
|
|
||||||
|
class QtSingleCoreApplication : public QCoreApplication
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QtSingleCoreApplication(int &argc, char **argv);
|
||||||
|
QtSingleCoreApplication(const QString &id, int &argc, char **argv);
|
||||||
|
|
||||||
|
bool isRunning();
|
||||||
|
QString id() const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
bool sendMessage(const QString &message, int timeout = 5000);
|
||||||
|
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void messageReceived(const QString &message);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
QtLocalPeer* peer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QTSINGLECOREAPPLICATION_H
|
|
@ -0,0 +1,234 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>res/contorl_icons/999.png</file>
|
||||||
|
<file>res/contorl_icons/close_white.png</file>
|
||||||
|
<file>res/contorl_icons/icon.png</file>
|
||||||
|
<file>res/contorl_icons/index_air.png</file>
|
||||||
|
<file>res/contorl_icons/index_cash_wash.png</file>
|
||||||
|
<file>res/contorl_icons/index_clothe.png</file>
|
||||||
|
<file>res/contorl_icons/index_flu.png</file>
|
||||||
|
<file>res/contorl_icons/index_sport.png</file>
|
||||||
|
<file>res/contorl_icons/index_uv.png</file>
|
||||||
|
<file>res/contorl_icons/left.png</file>
|
||||||
|
<file>res/contorl_icons/menu.png</file>
|
||||||
|
<file>res/contorl_icons/min_normal_btn.png</file>
|
||||||
|
<file>res/contorl_icons/right.png</file>
|
||||||
|
<file>res/forecast-icons/1x/300-2x.png</file>
|
||||||
|
<file>res/forecast-icons/1x/300.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/100.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/101.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/102.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/103.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/104.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/200.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/201.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/202.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/203.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/204.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/205.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/206.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/207.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/208.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/209.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/210.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/211.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/212.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/213.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/300.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/301.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/302.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/303.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/304.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/305.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/306.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/307.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/308.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/309.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/310.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/311.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/312.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/313.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/314.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/315.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/316.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/317.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/318.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/399.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/400.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/401.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/402.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/403.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/404.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/405.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/406.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/407.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/408.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/409.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/410.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/499.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/500.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/501.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/502.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/503.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/504.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/507.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/508.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/509.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/510.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/511.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/512.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/513.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/514.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/515.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/900.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/901.png</file>
|
||||||
|
<file>res/weather-icon/PNG16/2x/999.png</file>
|
||||||
|
<file>res/background/100.png</file>
|
||||||
|
<file>res/background/101.png</file>
|
||||||
|
<file>res/background/102.png</file>
|
||||||
|
<file>res/background/104.png</file>
|
||||||
|
<file>res/background/200.png</file>
|
||||||
|
<file>res/background/201.png</file>
|
||||||
|
<file>res/background/202.png</file>
|
||||||
|
<file>res/background/203.png</file>
|
||||||
|
<file>res/background/204.png</file>
|
||||||
|
<file>res/background/205.png</file>
|
||||||
|
<file>res/background/206.png</file>
|
||||||
|
<file>res/background/207.png</file>
|
||||||
|
<file>res/background/208.png</file>
|
||||||
|
<file>res/background/209.png</file>
|
||||||
|
<file>res/background/210.png</file>
|
||||||
|
<file>res/background/211.png</file>
|
||||||
|
<file>res/background/212.png</file>
|
||||||
|
<file>res/background/213.png</file>
|
||||||
|
<file>res/background/300.png</file>
|
||||||
|
<file>res/background/301.png</file>
|
||||||
|
<file>res/background/302.png</file>
|
||||||
|
<file>res/background/303.png</file>
|
||||||
|
<file>res/background/304.png</file>
|
||||||
|
<file>res/background/305.png</file>
|
||||||
|
<file>res/background/306.png</file>
|
||||||
|
<file>res/background/307.png</file>
|
||||||
|
<file>res/background/308.png</file>
|
||||||
|
<file>res/background/309.png</file>
|
||||||
|
<file>res/background/310.png</file>
|
||||||
|
<file>res/background/311.png</file>
|
||||||
|
<file>res/background/312.png</file>
|
||||||
|
<file>res/background/313.png</file>
|
||||||
|
<file>res/background/314.png</file>
|
||||||
|
<file>res/background/315.png</file>
|
||||||
|
<file>res/background/316.png</file>
|
||||||
|
<file>res/background/317.png</file>
|
||||||
|
<file>res/background/318.png</file>
|
||||||
|
<file>res/background/399.png</file>
|
||||||
|
<file>res/background/400.png</file>
|
||||||
|
<file>res/background/401.png</file>
|
||||||
|
<file>res/background/402.png</file>
|
||||||
|
<file>res/background/403.png</file>
|
||||||
|
<file>res/background/404.png</file>
|
||||||
|
<file>res/background/405.png</file>
|
||||||
|
<file>res/background/406.png</file>
|
||||||
|
<file>res/background/407.png</file>
|
||||||
|
<file>res/background/408.png</file>
|
||||||
|
<file>res/background/409.png</file>
|
||||||
|
<file>res/background/410.png</file>
|
||||||
|
<file>res/background/499.png</file>
|
||||||
|
<file>res/background/500.png</file>
|
||||||
|
<file>res/background/501.png</file>
|
||||||
|
<file>res/background/502.png</file>
|
||||||
|
<file>res/background/503.png</file>
|
||||||
|
<file>res/background/504.png</file>
|
||||||
|
<file>res/background/507.png</file>
|
||||||
|
<file>res/background/508.png</file>
|
||||||
|
<file>res/background/509.png</file>
|
||||||
|
<file>res/background/510.png</file>
|
||||||
|
<file>res/background/511.png</file>
|
||||||
|
<file>res/background/512.png</file>
|
||||||
|
<file>res/background/513.png</file>
|
||||||
|
<file>res/background/514.png</file>
|
||||||
|
<file>res/background/515.png</file>
|
||||||
|
<file>res/background/900.png</file>
|
||||||
|
<file>res/background/901.png</file>
|
||||||
|
<file>res/contorl_icons/loding_dark.png</file>
|
||||||
|
<file>res/contorl_icons/loding_normal.png</file>
|
||||||
|
<file>res/contorl_icons/network_warn_dark.png</file>
|
||||||
|
<file>res/contorl_icons/network_warn_normal.png</file>
|
||||||
|
<file>res/contorl_icons/retry_dark.png</file>
|
||||||
|
<file>res/contorl_icons/retry_normal.png</file>
|
||||||
|
<file>res/contorl_icons/location_doubt.png</file>
|
||||||
|
<file>res/contorl_icons/delete_light.png</file>
|
||||||
|
<file>res/contorl_icons/delete_dark.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/101.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/102.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/103.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/104.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/200.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/201.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/202.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/203.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/204.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/205.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/206.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/207.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/208.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/209.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/210.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/211.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/212.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/213.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/300.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/301.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/302.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/303.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/304.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/305.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/306.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/307.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/308.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/309.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/310.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/311.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/312.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/313.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/314.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/315.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/316.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/317.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/318.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/399.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/400.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/401.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/402.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/403.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/404.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/405.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/406.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/407.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/408.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/409.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/410.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/499.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/500.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/501.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/502.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/503.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/504.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/507.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/508.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/509.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/510.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/511.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/512.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/513.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/514.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/515.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/900.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/901.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/999.png</file>
|
||||||
|
<file>res/weather-icon/PNG48/1x/100.png</file>
|
||||||
|
<file>res/contorl_icons/search_dark.png</file>
|
||||||
|
<file>res/contorl_icons/search_light.png</file>
|
||||||
|
<file>res/contorl_icons/selected_normal.png</file>
|
||||||
|
<file>res/contorl_icons/selected_dark.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 100 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 42 KiB |