Moved AutoUpdater to main application.. (Still not ready yet)

This commit is contained in:
Mark Watkins 2011-12-17 02:31:58 +10:00
parent 68535c6d0e
commit 2d130f1e0c
32 changed files with 1243 additions and 21 deletions

View File

@ -69,11 +69,22 @@ SOURCES += main.cpp\
exportcsv.cpp \
common_gui.cpp \
SleepLib/loader_plugins/intellipap_loader.cpp \
SleepLib/calcs.cpp
SleepLib/calcs.cpp \
UpdateWindow.cpp \
updateparser.cpp \
quazip/zip.c \
quazip/unzip.c \
quazip/quazipnewinfo.cpp \
quazip/quazipfile.cpp \
quazip/quazip.cpp \
quazip/quacrc32.cpp \
quazip/quaadler32.cpp \
quazip/qioapi.cpp \
quazip/JlCompress.cpp
unix:SOURCES += qextserialport/posix_qextserialport.cpp
unix:!macx:SOURCES += qextserialport/qextserialenumerator_unix.cpp
unix:!macx:LIBS += -lX11
unix:!macx:LIBS += -lX11 -lz
macx {
SOURCES += qextserialport/qextserialenumerator_osx.cpp
@ -127,7 +138,22 @@ HEADERS += \
common_gui.h \
SleepLib/loader_plugins/intellipap_loader.h \
SleepLib/calcs.h \
version.h
version.h \
UpdateWindow.h \
updateparser.h \
quazip/zip.h \
quazip/unzip.h \
quazip/quazipnewinfo.h \
quazip/quazip_global.h \
quazip/quazipfileinfo.h \
quazip/quazipfile.h \
quazip/quazip.h \
quazip/quacrc32.h \
quazip/quachecksum32.h \
quazip/quaadler32.h \
quazip/JlCompress.h \
quazip/ioapi.h \
quazip/crypt.h
FORMS += \
@ -139,10 +165,12 @@ FORMS += \
report.ui \
profileselect.ui \
newprofile.ui \
exportcsv.ui
exportcsv.ui \
UpdateWindow.ui
RESOURCES += \
Resources.qrc
Resources.qrc \
resources.qrc
OTHER_FILES += \
docs/index.html \

527
UpdateWindow.cpp Normal file
View File

@ -0,0 +1,527 @@
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QMessageBox>
#include <QResource>
#include <QProgressBar>
#include <QTimer>
#include <QFile>
#include <QDir>
#include <QDate>
#include <QDebug>
#include <QXmlSimpleReader>
#include <QCryptographicHash>
#include <QDesktopWidget>
#include "SleepLib/preferences.h"
#include "quazip/quazip.h"
#include "quazip/quazipfile.h"
#include "UpdateWindow.h"
#include "ui_UpdateWindow.h"
#include "version.h"
#include "mainwindow.h"
#include "common_gui.h"
extern MainWindow * mainwin;
UpdateWindow::UpdateWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::UpdateWindow)
{
ui->setupUi(this);
QDesktopWidget *desktop = QApplication::desktop();
int screenWidth = desktop->width(); // get width of screen
int screenHeight = desktop->height(); // get height of screen
QSize windowSize = size(); // size of our application window
int width = windowSize.width();
int height = windowSize.height();
// little computations
int x = (screenWidth - width) / 2;
int y = (screenHeight - height) / 2;
y -= 50;
// move window to desired coordinates
move ( x, y );
requestmode=RM_None;
netmanager = new QNetworkAccessManager(this);
connect(netmanager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
update=NULL;
ui->stackedWidget->setCurrentIndex(0);
}
UpdateWindow::~UpdateWindow()
{
disconnect(netmanager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
delete ui;
}
void UpdateWindow::checkForUpdates()
{
QString filename=QApplication::applicationDirPath()+QDir::separator()+"update.xml";
qDebug() << filename;
// Check updates.xml file if it's still recent..
if (QFile::exists(filename)) {
QFileInfo fi(filename);
QDateTime created=fi.created();
int age=created.secsTo(QDateTime::currentDateTime());
if (age<7200) {
QFile file(filename);
file.open(QFile::ReadOnly);
ParseUpdateXML(&file);
file.close();
return;
}
}
mainwin->Notify("Checking for SleepyHead Updates");
requestmode=RM_CheckUpdates;
reply=netmanager->get(QNetworkRequest(QUrl("http://192.168.1.8/update.xml")));
ui->plainTextEdit->appendPlainText("Requesting "+reply->url().toString());
netmanager->connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this, SLOT(downloadProgress(qint64,qint64)));
dltime.start();
}
void UpdateWindow::dataReceived()
{
//HttpStatusCodeAttribute
QString rs=reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString();
if (rs!="200") return;
//QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
QByteArray read=reply->read(reply->bytesAvailable());
qDebug() << "Received" << read.size() << "bytes";
file.write(read);
}
void UpdateWindow::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
QString rs=reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString();
if (rs!="200") return;
if (ui->tableWidget->rowCount()>0) {
double f=(double(bytesReceived) / double(bytesTotal)) * 100.0;
QProgressBar *bar=qobject_cast<QProgressBar *>(ui->tableWidget->cellWidget(current_row,3));
if (bar)
bar->setValue(f);
ui->tableWidget->item(current_row,2)->setText(QString::number(bytesTotal/1048576.0,'f',3)+"MB");
}
//ui->progressBar->setValue(f);
int elapsed=dltime.elapsed();
}
void UpdateWindow::requestFile()
{
if (!update) return;
QProgressBar *bar=qobject_cast<QProgressBar *>(ui->tableWidget->cellWidget(current_row,3));
QString style="QProgressBar{\
border: 1px solid gray;\
border-radius: 3px;\
text-align: center;\
text-decoration: bold;\
color: yellow;\
}\
QProgressBar::chunk {\
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 \"light green\", stop: 1 green);\
width: 10px;\
margin: 0px;\
}";
if (bar)
bar->setStyleSheet(style);
QString filename=update->filename;
ui->plainTextEdit->appendPlainText("Requesting "+update->url);
requestmode=RM_GetFile;
QString path=QApplication::applicationDirPath()+QDir::separator()+"Download";
QDir().mkdir(path);
path+=QDir::separator()+filename;
ui->plainTextEdit->appendPlainText("Saving as "+path);
file.setFileName(path);
file.open(QFile::WriteOnly);
dltime.start();
QNetworkRequest req=QNetworkRequest(QUrl(update->url));
req.setRawHeader("User-Agent", "Wget/1.12 (linux-gnu)");
reply=netmanager->get(req);
connect(reply,SIGNAL(readyRead()),this, SLOT(dataReceived()));
connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this, SLOT(downloadProgress(qint64,qint64)));
}
void UpdateWindow::ParseUpdateXML(QIODevice * dev)
{
QXmlInputSource src(dev);
QXmlSimpleReader reader;
reader.setContentHandler(&updateparser);
if (reader.parse(src)) {
ui->plainTextEdit->appendPlainText("XML update structure parsed cleanly");
QStringList versions;
for (QHash<QString,Release>::iterator it=updateparser.releases.begin();it!=updateparser.releases.end();it++) {
versions.push_back(it.key());
}
qSort(versions);
QString platform=PlatformString.toLower();
release=NULL;
for (int i=versions.size()-1;i>=0;i--) {
QString verstr=versions[i];
release=&updateparser.releases[verstr];
if (release->updates.contains(platform)) {
break;
} else release=NULL;
}
if (!release || (VersionString() > release->version)) {
mainwin->Notify("No updates were found for your platform",5000,"SleepyHead Updates");
delay(4000);
close();
return;
}
qDebug() << "Version" << release->version << "has updates for" << platform;
QString latestapp="", latestqt="";
updates.clear();
Update *upd=NULL;
Update *upq=NULL;
for (int i=0;i<release->updates[platform].size();i++) {
update=&release->updates[platform][i];
if (update->type=="qtlibs") {
qDebug() << "QT Version" << update->version;
if (update->version > latestqt) {
latestqt=update->version;
upq=update;
}
} else if (update->type=="application") {
qDebug() << "Application Version" << update->version;
if (update->version > latestapp) {
latestapp=update->version;
upd=update;
}
}
}
if (upq && (upq->version > QT_VERSION_STR)) {
updates.push_back(upq);
}
if (upd && upd->version > VersionString()) {
updates.push_back(upd);
}
if (updates.size()>0) {
QString html="<html><h3>SleepyHead v"+release->version+" codename \""+release->codename+"\"</h3><p>"+release->notes[""]+"</p><b>";
html+=platform.left(1).toUpper()+platform.mid(1);
html+=" platform notes</b><p>"+release->notes[platform]+"</p></html>";
ui->webView->setHtml(html);
QString info;
if (VersionString()< release->version) {
ui->Title->setText("<font size=+1>A new version of SleepyHead is available!</font>");
info="Shiny new <b>v"+latestapp+"</b> is available. You're running old and busted v"+VersionString();
ui->notesTabWidget->setCurrentIndex(0);
} else {
ui->Title->setText("<font size=+1>An update for SleepyHead is available.</font>");
info="Version <b>"+latestapp+"</b> is available. You're currently running v"+VersionString();
ui->notesTabWidget->setCurrentIndex(1);
}
ui->versionInfo->setText(info);
QString notes;
for (int i=0;i<release->updates[platform].size();i++) {
update=&release->updates[platform][i];
if ((update->type=="application") && (update->version > VersionString())) {
notes+="<b>SleepyHead v"+update->version+" build notes</b><br/>"+update->notes.trimmed()+"<br/><br/>";
} else if ((update->type=="qtlibs") && (update->version > QT_VERSION_STR)) {
notes+="<b>Update to QtLibs (v"+update->version+")</b><br/>"+update->notes.trimmed();
}
}
ui->buildNotes->setText(notes);
setWindowModality(Qt::ApplicationModal);
show();
}
} else {
mainwin->Notify("There was an error parsing the XML Update file.");
}
}
void UpdateWindow::replyFinished(QNetworkReply * reply)
{
netmanager->disconnect(reply,SIGNAL(downloadProgress(qint64,qint64)),this, SLOT(downloadProgress(qint64,qint64)));
if (reply->error()==QNetworkReply::NoError) {
if (requestmode==RM_CheckUpdates) {
ui->plainTextEdit->appendPlainText(QString::number(reply->size())+" bytes received.");
QString filename=QApplication::applicationDirPath()+QDir::separator()+reply->url().toString().section("/",-1);
qDebug() << filename;
QFile file(filename);
file.open(QFile::WriteOnly);
file.write(reply->readAll());
file.close();
file.open(QFile::ReadOnly);
//QTextStream ts(&file);
ParseUpdateXML(&file);
file.close();
reply->deleteLater();
} else if (requestmode==RM_GetFile) {
disconnect(reply,SIGNAL(readyRead()),this, SLOT(dataReceived()));
file.close();
//HttpStatusCodeAttribute
QString rs=reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString();
bool failed=false;
if (rs=="404") {
qDebug() << "File not found";
failed=true;
} else {
qDebug() << "StatCodeAttr" << rs;
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
if (!redirectUrl.isEmpty() && (redirectUrl!=reply->url())) {
file.open(QFile::WriteOnly); //reopen file..
update->url=redirectUrl.toString();
ui->plainTextEdit->appendPlainText("Redirected to "+update->url);
QTimer::singleShot(100,this,SLOT(requestFile()));
reply->deleteLater();
return;
}
ui->plainTextEdit->appendPlainText("Received "+QString::number(file.size())+" bytes");
if (update->size>0) {
double s1=update->size/1048576.0;
double s2=ui->tableWidget->item(current_row,2)->text().toDouble();
if (s1!=s2) {
failed=true;
ui->plainTextEdit->appendPlainText("File size mismatch for "+update->filename);
}
} else {
QString path=QApplication::applicationDirPath()+QDir::separator()+"Download";
path+=QDir::separator()+update->filename;
QFile f(path);
f.open(QFile::ReadOnly);
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(f.readAll());
QString res=hash.result().toHex();
if (res!=update->hash) {
ui->plainTextEdit->appendPlainText("File integrity check failed for "+update->filename);
failed=true;
}
}
}
reply->deleteLater();
QProgressBar *bar=qobject_cast<QProgressBar *>(ui->tableWidget->cellWidget(current_row,3));
if (!failed) {
//file.open(QFile::ReadOnly);
QuaZip zip(&file);
if (!zip.open(QuaZip::mdUnzip)) {
failed=true;
} else {
QStringList files=zip.getFileNameList();
QFile f;
int errors=0;
int fsize=files.size();
QByteArray ba;
QStringList update_txt;
QStringList unzipped;
QStringList original;
for (int i=0;i<fsize;i++) {
ui->plainTextEdit->appendPlainText("Extracting "+files.at(i));
QuaZipFile qzf(file.fileName(),files.at(i));
qzf.open(QuaZipFile::ReadOnly);
QString path=QApplication::applicationDirPath()+QDir::separator()+"Download"+QDir::separator()+files.at(i);
if (path.endsWith(QDir::separator())) {
QDir().mkpath(path);
if (update->unzipped_path.isEmpty())
update->unzipped_path=path;
} else {
ba=qzf.readAll();
if (qzf.getZipError()) {
errors++;
} else if (files.at(i)=="update.txt") {
QTextStream ts(ba);
QString line;
do {
line=ts.readLine();
if (!line.isNull()) update_txt.append(line);
} while (!line.isNull());
} else {
unzipped.append(path);
original.append(QApplication::applicationDirPath()+QDir::separator()+files.at(i).section("/",-1));
f.setFileName(path);
f.open(QFile::WriteOnly);
f.write(ba);
f.close();
}
}
if (bar) {
bar->setValue((1.0/float(fsize)*float(i+1))*100.0);
QApplication::processEvents();
}
qzf.close();
}
zip.close();
if (!errors) {
for (int i=0;i<unzipped.size();i++) {
if (QFile::copy(unzipped[i],original[i])) {
ui->plainTextEdit->appendPlainText("Copied "+unzipped[i]+" to "+original[i]);
} else {
QFile f(original[i]);
if (f.exists()) {
if (!f.remove()) {
f.rename(original[i],original[i]+".bak");
ui->plainTextEdit->appendPlainText("Renaming "+original[i]);
} else {
ui->plainTextEdit->appendPlainText("Removing "+original[i]);
}
}
if (QFile::copy(unzipped[i],original[i])) {
ui->plainTextEdit->appendPlainText("Copied "+unzipped[i]+" to "+original[i]);
} else {
ui->plainTextEdit->appendPlainText("Copy Failed");
failed=true;
}
}
}
// Parse replacement instructions file? or just dump zip over the top?
// To clean up or not to clean up... is a reasonably valid question.
//file.remove();
}
}
}
ui->tableWidget->item(current_row,0)->setCheckState(Qt::Checked);
if (failed) {
qDebug() << "File is corrupted";
if (bar) {
bar->setFormat("Failed");
QString style="QProgressBar{\
border: 1px solid gray;\
border-radius: 3px;\
text-align: center;\
text-decoration: bold;\
color: yellow;\
}\
QProgressBar::chunk {\
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 \"dark red\", stop: 1 red);\
width: 10px;\
margin: 0px;\
}";
//: qlineargradient(x1: 0, y1: 0.5, x2: 1, y2: 0.5, stop: 0 red, stop: 1 white);
bar->setStyleSheet(style);
}
}
ui->tableWidget->item(current_row,0)->setData(Qt::UserRole+1,failed);
QTimer::singleShot(100,this,SLOT(upgradeNext()));
ui->plainTextEdit->appendPlainText("Download Complete");
} else if (requestmode==RM_UpdateQT) {
ui->plainTextEdit->appendPlainText("Received "+QString::number(reply->size())+" bytes");
}
} else {
mainwin->Notify("There was an error completing a network request:\n\n("+reply->errorString()+")");
}
}
void UpdateWindow::on_CloseButton_clicked()
{
close();
}
void UpdateWindow::upgradeNext()
{
QTableWidgetItem *item;
bool fnd=false;
for (current_row=0;current_row<ui->tableWidget->rowCount();current_row++) {
item=ui->tableWidget->item(current_row,0);
bool complete=item->checkState()==Qt::Checked;
if (complete)
continue;
update=item->data(Qt::UserRole).value<Update *>();
qDebug() << "Processing" << update->url;
fnd=true;
requestFile();
break;
}
if (!fnd) {
bool ok=true;
for (current_row=0;current_row<ui->tableWidget->rowCount();current_row++) {
bool failed=ui->tableWidget->item(current_row,0)->data(Qt::UserRole+1).toBool();
if (failed) {
ok=false;
break;
}
}
if (ok) {
success=true;
//QMessageBox::information(this,"Updates Complete","SleepyHead has been updated and needs to restart.",QMessageBox::Ok);
ui->downloadTitle->setText("Update Complete!");
ui->FinishedButton->setVisible(true);
ui->downloadLabel->setText("Updates Complete. SleepyHead needs to restart now, click Finished to do so.");
} else {
ui->downloadTitle->setText("Update Failed :(");
success=false;
ui->downloadLabel->setText("Download Error. Sorry, try again later.");
ui->FinishedButton->setVisible(true);
//QMessageBox::warning(this,"Download Error","Sorry, could not get all necessary files for upgrade.. Try again later.",QMessageBox::Ok);
//close();
}
}
}
void UpdateWindow::on_upgradeButton_clicked()
{
if (!updates.size()) return;
ui->tableWidget->clearContents();
ui->tableWidget->setColumnHidden(4,true);
ui->tableWidget->setColumnHidden(5,true);
ui->FinishedButton->setVisible(false);
ui->downloadLabel->setText("Downloading & Installing Updates...");
ui->downloadTitle->setText("Please wait while downloading and installing updates.");
success=false;
for (int i=0;i<updates.size();i++) {
update=updates.at(i);
ui->tableWidget->insertRow(i);
QTableWidgetItem *item=new QTableWidgetItem(update->type);
QVariant av;
av.setValue(update);
item->setData(Qt::UserRole,av);
item->setCheckState(Qt::Unchecked);
item->setFlags(Qt::ItemIsEnabled);
ui->tableWidget->setItem(i,0,item);
ui->tableWidget->setItem(i,1,new QTableWidgetItem(update->version));
ui->tableWidget->setItem(i,2,new QTableWidgetItem(QString::number(update->size/1048576.0,'f',3)+"MB"));
QProgressBar *bar=new QProgressBar(ui->tableWidget);
bar->setMaximum(100);
bar->setValue(0);
ui->tableWidget->setCellWidget(i,3,bar);
ui->tableWidget->setItem(i,4,new QTableWidgetItem(update->url));
}
ui->stackedWidget->setCurrentIndex(1);
upgradeNext();
}
void UpdateWindow::on_FinishedButton_clicked()
{
if (success)
mainwin->RestartApplication();
else close();
}

63
UpdateWindow.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef UPDATEWINDOW_H
#define UPDATEWINDOW_H
#include <QSystemTrayIcon>
#include <QNetworkAccessManager>
#include <QTableWidgetItem>
#include <QMenu>
#include <QMainWindow>
#include "version.h"
#include "updateparser.h"
namespace Ui {
class UpdateWindow;
}
enum RequestMode { RM_None, RM_CheckUpdates, RM_GetFile, RM_UpdateQT };
class UpdateWindow : public QMainWindow
{
Q_OBJECT
public:
explicit UpdateWindow(QWidget *parent = 0);
~UpdateWindow();
void checkForUpdates();
void ParseUpdateXML(QIODevice * dev);
protected slots:
void replyFinished(QNetworkReply * reply);
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void dataReceived();
void requestFile();
private slots:
void on_CloseButton_clicked();
void on_upgradeButton_clicked();
void upgradeNext();
void on_FinishedButton_clicked();
private:
UpdateParser updateparser;
Ui::UpdateWindow *ui;
QSystemTrayIcon *systray;
QMenu *systraymenu;
RequestMode requestmode;
QTime dltime;
QString needQtVersion;
Update *update;
Release *release;
QFile file;
QNetworkAccessManager *netmanager;
QNetworkReply * reply;
QList<Update *> updates;
int current_row;
bool success;
};
#endif // UPDATEWINDOW_H

370
UpdateWindow.ui Normal file
View File

@ -0,0 +1,370 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UpdateWindow</class>
<widget class="QMainWindow" name="UpdateWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>589</width>
<height>416</height>
</rect>
</property>
<property name="windowTitle">
<string>SleepyHead Updater</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>:/images/sheep.png</normaloff>:/images/sheep.png</iconset>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="frontPage">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="Title">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>A new version of $APP is available</string>
</property>
</widget>
</item>
<item row="0" column="1" rowspan="3">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="graphicLabel">
<property name="maximumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="Resources.qrc">:/docs/sheep.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="versionInfo">
<property name="text">
<string>Version Information</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QTabWidget" name="notesTabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="relNotesTab">
<attribute name="title">
<string>Release Notes</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_8">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QWebView" name="webView">
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="buildNotesTab">
<attribute name="title">
<string>Build Notes</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QTextEdit" name="buildNotes">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="CloseButton">
<property name="text">
<string>&amp;No Thanks</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="LaterButton">
<property name="text">
<string>&amp;Remind Me Later</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="upgradeButton">
<property name="text">
<string>&amp;Upgrade Now</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>4</number>
</property>
<property name="margin">
<number>4</number>
</property>
<item>
<widget class="QLabel" name="downloadTitle">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Please wait while updates are downloaded and installed...</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout"/>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabUpdates">
<attribute name="title">
<string>Updates</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QTableWidget" name="tableWidget">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Component</string>
</property>
</column>
<column>
<property name="text">
<string>Version</string>
</property>
</column>
<column>
<property name="text">
<string>Size</string>
</property>
</column>
<column>
<property name="text">
<string>Progress</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabLog">
<attribute name="title">
<string>Log</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QPlainTextEdit" name="plainTextEdit"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="downloadLabel">
<property name="text">
<string>Downloading &amp; Installing Updates</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="FinishedButton">
<property name="text">
<string>&amp;Finished</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QWebView</class>
<extends>QWidget</extends>
<header>QtWebKit/QWebView</header>
</customwidget>
</customwidgets>
<resources>
<include location="Resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -7,6 +7,16 @@
#include "common_gui.h"
#include "qglobal.h"
void delay(int ms)
{
#ifdef Q_WS_WIN32
delay(ms);
#else
sleep(ms/1000);
#endif
}
#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0))
// Qt 4.8 makes this a whole lot easier
Qt::DayOfWeek firstDayOfWeekFromLocale()
@ -28,6 +38,11 @@ Qt::DayOfWeek firstDayOfWeekFromLocale()
#endif
#ifdef Q_WS_WIN32
#include <dos.h>
#endif
// This function has been "borrowed".. Ahem..
Qt::DayOfWeek firstDayOfWeekFromLocale()
{

View File

@ -10,5 +10,6 @@
#include <QLocale>
Qt::DayOfWeek firstDayOfWeekFromLocale();
void delay(int ms);
#endif

View File

@ -30,6 +30,7 @@
#include "exportcsv.h"
#include "SleepLib/schema.h"
#include "Graphs/glcommon.h"
#include "UpdateWindow.h"
QProgressBar *qprogress;
QLabel *qstatus;
@ -189,10 +190,10 @@ MainWindow::~MainWindow()
mainwin=NULL;
delete ui;
}
void MainWindow::Notify(QString s,int ms)
void MainWindow::Notify(QString s,int ms,QString title)
{
if (systray) {
systray->showMessage("SleepyHead v"+PREF["VersionString"].toString(),s,QSystemTrayIcon::Information,ms);
systray->showMessage(title,s,QSystemTrayIcon::Information,ms);
} else {
ui->statusbar->showMessage(s,ms);
}
@ -200,7 +201,7 @@ void MainWindow::Notify(QString s,int ms)
void MainWindow::Startup()
{
qDebug() << PREF["AppName"].toString().toAscii()+" v"+PREF["VersionString"].toString().toAscii() << "built with Qt"<< QT_VERSION_STR << "on" << __DATE__ << __TIME__;
qDebug() << PREF["AppName"].toString().toAscii()+" v"+VersionString().toAscii() << "built with Qt"<< QT_VERSION_STR << "on" << __DATE__ << __TIME__;
qstatus->setText(tr("Loading Data"));
qprogress->show();
//qstatusbar->showMessage(tr("Loading Data"),0);
@ -510,22 +511,26 @@ void MainWindow::on_oximetryButton_clicked()
void MainWindow::CheckForUpdates()
{
QTimer::singleShot(100,this,SLOT(on_actionCheck_for_Updates_triggered()));
//on_actionCheck_for_Updates_triggered();
//QTimer::singleShot(100,this,SLOT(on_actionCheck_for_Updates_triggered()));
on_actionCheck_for_Updates_triggered();
}
void MainWindow::on_actionCheck_for_Updates_triggered()
{
if (PREF.Exists("Updates_LastChecked")) {
if (PREF["Updates_LastChecked"].toDateTime().secsTo(QDateTime::currentDateTime())<7200) {
// Instead of doing this, just use the cached crud
if (prefdialog) prefdialog->RefreshLastChecked();
mainwin->Notify("No New Updates - You already checked recently...");
return;
}
}
mainwin->Notify("Checking for Updates");
netmanager->get(QNetworkRequest(QUrl("http://sleepyhead.sourceforge.net/current_version.txt")));
UpdateWindow *w=new UpdateWindow(this);
w->checkForUpdates();
// if (PREF.Exists("Updates_LastChecked")) {
// if (PREF["Updates_LastChecked"].toDateTime().secsTo(QDateTime::currentDateTime())<7200) {
// // Instead of doing this, just use the cached crud
// if (prefdialog) prefdialog->RefreshLastChecked();
// mainwin->Notify("No New Updates - You already checked recently...");
// return;
// }
// }
// mainwin->Notify("Checking for Updates");
// netmanager->get(QNetworkRequest(QUrl("http://sleepyhead.sourceforge.net/current_version.txt")));
}
void MainWindow::replyFinished(QNetworkReply * reply)
{

View File

@ -40,7 +40,7 @@ public:
void Log(QString s);
QMenu * CreateMenu(QString title);
void CheckForUpdates();
void Notify(QString s,int ms=5000);
void Notify(QString s,int ms=5000, QString title="SleepyHead v"+VersionString());
gGraphView *snapshotGraph() { return SnapshotGraph; }
Daily *getDaily() { return daily; }
Overview *getOverview() { return overview; }

120
updateparser.cpp Normal file
View File

@ -0,0 +1,120 @@
#include <QDebug>
#include "updateparser.h"
bool UpdateParser::startDocument()
{
inRelease=false;
inUpdate=false;
inNotes=false;
inUpdateNotes=false;
release=NULL;
update=NULL;
return true;
}
bool UpdateParser::endElement(const QString &namespaceURI, const QString &localName, const QString &qName)
{
QString name=qName.toLower();
if (name=="release") {
inRelease=false;
release=NULL;
} else if (inRelease && name=="update") {
inUpdate=false;
update=NULL;
} else if (inUpdate && name=="notes")
inUpdateNotes=false;
else if (inRelease && name=="notes")
inNotes=false;
return true;
}
bool UpdateParser::characters(const QString &ch)
{
if (inUpdateNotes) {
update->notes=ch;
} else if (inNotes) {
release->notes[platform]=ch;
}
return true;
}
bool UpdateParser::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts)
{
QString name=qName.toLower();
if (inRelease && name=="update") {
QString ver, type;
for (int i=0;i<atts.count();i++) {
if (atts.localName(i)=="type")
type=atts.value(i).toLower();
if (atts.localName(i)=="version")
ver=atts.value(i).toLower();
if (atts.localName(i)=="platform")
platform=atts.value(i).toLower();
if (atts.localName(i)=="release_date")
release_date=atts.value(i);
}
QDate date=QDate::fromString(release_date,"yyyy-MM-dd");
if (!date.isValid()) date=QDate::currentDate();
release->updates[platform].push_back(Update(type,ver,platform,date));
update=&release->updates[platform][release->updates[platform].size()-1];
inUpdate=true;
} else if (inRelease && name=="info") {
QString tmp=atts.value("url");
if (tmp.isEmpty()) return false;
release->info_url=tmp;
} else if (inUpdate && name=="file") {
for (int i=0;i<atts.count();i++) {
if (atts.localName(i)=="name")
update->filename=atts.value(i);
if (atts.localName(i)=="size") {
bool ok;
update->size=atts.value(i).toLongLong(&ok);
//if (!ok) return false;
}
if (atts.localName(i)=="url")
update->url=atts.value(i);
if (atts.localName(i)=="hash")
update->hash=atts.value(i).toLower();
}
} else if (inUpdate && name=="notes") {
inUpdateNotes=true;
} else if (inRelease && name=="notes") {
platform="";
if (atts.count()>=1) {
if (atts.localName(0)=="platform") {
platform=atts.value(0);
}
}
inNotes=true;
} else if (name=="release") {
inRelease=true;
QString codename,status;
for (int i=0;i<atts.count();i++) {
if (atts.localName(i)=="version")
version=atts.value(i).toLower();
if (atts.localName(i)=="codename")
codename=atts.value(i);
if (atts.localName(i)=="status")
status=atts.value(i);
}
releases[version]=Release(version,codename,status);
release=&releases[version];
if (version>latest_version) latest_version=version;
}
return true;
}
bool UpdateParser::endDocument()
{
/*for (QHash<QString,Release>::iterator r=releases.begin();r!=releases.end();r++) {
Release & rel=r.value();
qDebug() << "New Version" << r.key() << rel.codename << rel.notes;
for (QHash<QString,Update>::iterator u=rel.files.begin();u!=rel.files.end();u++) {
Update & up=u.value();
qDebug() << "Platform:" << u.key() << up.filename << up.date;
}
}*/
return true;
}

93
updateparser.h Normal file
View File

@ -0,0 +1,93 @@
#ifndef UPDATEPARSER_H
#define UPDATEPARSER_H
#include <QXmlDefaultHandler>
#include <QMetaType>
#include <QDate>
struct Update
{
public:
explicit Update() { size=0;}
explicit Update(const Update & copy) {
type=copy.type;
version=copy.version;
platform=copy.platform;
date=copy.date;
filename=copy.filename;
url=copy.url;
hash=copy.hash;
size=copy.size;
notes=copy.notes;
unzipped_path=copy.unzipped_path;
}
Update(QString _type, QString _version, QString _platform, QDate _date)
{
type=_type;
version=_version;
platform=_platform;
date=_date;
size=0;
}
QString type;
QString version;
QString platform;
QDate date;
QString filename;
QString url;
QString hash;
qint64 size;
QString notes;
QString unzipped_path;
};
struct Release
{
Release() {}
Release(const Release & copy) {
version=copy.version;
codename=copy.version;
notes=copy.notes;
info_url=copy.info_url;
status=copy.status;
updates=copy.updates;
}
Release(QString ver, QString code, QString stat) { version=ver; codename=code; status=stat; }
QString version;
QString codename;
QString status;
QString info_url;
QHash<QString,QString> notes; // by platform
QHash<QString,QList<Update> > updates;
};
Q_DECLARE_METATYPE(Update *)
class UpdateParser:public QXmlDefaultHandler
{
public:
bool startDocument();
bool endElement(const QString &namespaceURI, const QString &localName, const QString &name);
bool characters(const QString &ch);
bool startElement(const QString &namespaceURI, const QString &localName, const QString &name, const QXmlAttributes &atts);
bool endDocument();
QString latest() { return latest_version; }
QHash<QString,Release> releases;
private:
Update * update;
Release * release;
QString version, platform;
QString release_date;
QString latest_version;
bool inRelease;
bool inUpdate;
bool inNotes;
bool inUpdateNotes;
};
#endif // UPDATEPARSER_H