mirror of
https://github.com/lubosz/overte.git
synced 2025-04-17 02:16:42 +02:00
add fervor updater and run during launch if OS X release
This commit is contained in:
parent
800bfd097b
commit
0b243ec881
20 changed files with 2199 additions and 6 deletions
|
@ -65,10 +65,14 @@ if (APPLE)
|
|||
|
||||
endif (APPLE)
|
||||
|
||||
find_package(Qt4 REQUIRED QtCore QtGui QtNetwork QtOpenGL)
|
||||
find_package(Qt4 REQUIRED QtCore QtGui QtNetwork QtOpenGL QtWebKit)
|
||||
include(${QT_USE_FILE})
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}")
|
||||
|
||||
set(QUAZIP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/quazip)
|
||||
add_subdirectory(external/fervor/)
|
||||
include_directories(external/fervor/)
|
||||
|
||||
# run qt moc on qt-enabled headers
|
||||
qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h src/Webcam.h)
|
||||
|
||||
|
@ -108,7 +112,14 @@ include_directories(
|
|||
${SPEEXDSP_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${QT_LIBRARIES} ${OPENCV_LIBRARIES} ${ZLIB_LIBRARIES} ${SPEEXDSP_LIBRARIES})
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
${QT_LIBRARIES}
|
||||
${OPENCV_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${SPEEXDSP_LIBRARIES}
|
||||
fervor
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
# link in required OS X frameworks and include the right GL headers
|
||||
|
|
23
interface/external/fervor/CMakeLists.txt
vendored
Normal file
23
interface/external/fervor/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
project(Fervor)
|
||||
find_package(Qt4 REQUIRED)
|
||||
|
||||
add_definitions(-DFV_GUI)
|
||||
|
||||
file(GLOB FERVOR_SOURCES *.cpp)
|
||||
file(GLOB FERVOR_HEADERS *.h)
|
||||
file(GLOB FERVOR_UI *.ui)
|
||||
|
||||
qt4_wrap_ui(FERVOR_WRAPPED_UI ${FERVOR_UI})
|
||||
qt4_wrap_cpp(FERVOR_MOC_SOURCES ${FERVOR_HEADERS})
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
|
||||
find_package(Quazip REQUIRED)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${QUAZIP_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_library(fervor ${FERVOR_SOURCES} ${FERVOR_HEADERS} ${FERVOR_MOC_SOURCES} ${FERVOR_WRAPPED_UI})
|
||||
target_link_libraries(fervor ${QUAZIP_LIBRARIES})
|
97
interface/external/fervor/fvavailableupdate.cpp
vendored
Executable file
97
interface/external/fervor/fvavailableupdate.cpp
vendored
Executable file
|
@ -0,0 +1,97 @@
|
|||
#include "fvavailableupdate.h"
|
||||
|
||||
FvAvailableUpdate::FvAvailableUpdate(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
QString FvAvailableUpdate::GetTitle()
|
||||
{
|
||||
return m_title;
|
||||
}
|
||||
|
||||
void FvAvailableUpdate::SetTitle(QString title)
|
||||
{
|
||||
m_title = title;
|
||||
}
|
||||
|
||||
QUrl FvAvailableUpdate::GetReleaseNotesLink()
|
||||
{
|
||||
return m_releaseNotesLink;
|
||||
}
|
||||
|
||||
void FvAvailableUpdate::SetReleaseNotesLink(QUrl releaseNotesLink)
|
||||
{
|
||||
m_releaseNotesLink = releaseNotesLink;
|
||||
}
|
||||
|
||||
void FvAvailableUpdate::SetReleaseNotesLink(QString releaseNotesLink)
|
||||
{
|
||||
SetReleaseNotesLink(QUrl(releaseNotesLink));
|
||||
}
|
||||
|
||||
QString FvAvailableUpdate::GetPubDate()
|
||||
{
|
||||
return m_pubDate;
|
||||
}
|
||||
|
||||
void FvAvailableUpdate::SetPubDate(QString pubDate)
|
||||
{
|
||||
m_pubDate = pubDate;
|
||||
}
|
||||
|
||||
QUrl FvAvailableUpdate::GetEnclosureUrl()
|
||||
{
|
||||
return m_enclosureUrl;
|
||||
}
|
||||
|
||||
void FvAvailableUpdate::SetEnclosureUrl(QUrl enclosureUrl)
|
||||
{
|
||||
m_enclosureUrl = enclosureUrl;
|
||||
}
|
||||
|
||||
void FvAvailableUpdate::SetEnclosureUrl(QString enclosureUrl)
|
||||
{
|
||||
SetEnclosureUrl(QUrl(enclosureUrl));
|
||||
}
|
||||
|
||||
QString FvAvailableUpdate::GetEnclosureVersion()
|
||||
{
|
||||
return m_enclosureVersion;
|
||||
}
|
||||
|
||||
void FvAvailableUpdate::SetEnclosureVersion(QString enclosureVersion)
|
||||
{
|
||||
m_enclosureVersion = enclosureVersion;
|
||||
}
|
||||
|
||||
QString FvAvailableUpdate::GetEnclosurePlatform()
|
||||
{
|
||||
return m_enclosurePlatform;
|
||||
}
|
||||
|
||||
void FvAvailableUpdate::SetEnclosurePlatform(QString enclosurePlatform)
|
||||
{
|
||||
m_enclosurePlatform = enclosurePlatform;
|
||||
}
|
||||
|
||||
unsigned long FvAvailableUpdate::GetEnclosureLength()
|
||||
{
|
||||
return m_enclosureLength;
|
||||
}
|
||||
|
||||
void FvAvailableUpdate::SetEnclosureLength(unsigned long enclosureLength)
|
||||
{
|
||||
m_enclosureLength = enclosureLength;
|
||||
}
|
||||
|
||||
QString FvAvailableUpdate::GetEnclosureType()
|
||||
{
|
||||
return m_enclosureType;
|
||||
}
|
||||
|
||||
void FvAvailableUpdate::SetEnclosureType(QString enclosureType)
|
||||
{
|
||||
m_enclosureType = enclosureType;
|
||||
}
|
51
interface/external/fervor/fvavailableupdate.h
vendored
Executable file
51
interface/external/fervor/fvavailableupdate.h
vendored
Executable file
|
@ -0,0 +1,51 @@
|
|||
#ifndef FVAVAILABLEUPDATE_H
|
||||
#define FVAVAILABLEUPDATE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
|
||||
class FvAvailableUpdate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FvAvailableUpdate(QObject *parent = 0);
|
||||
|
||||
QString GetTitle();
|
||||
void SetTitle(QString title);
|
||||
|
||||
QUrl GetReleaseNotesLink();
|
||||
void SetReleaseNotesLink(QUrl releaseNotesLink);
|
||||
void SetReleaseNotesLink(QString releaseNotesLink);
|
||||
|
||||
QString GetPubDate();
|
||||
void SetPubDate(QString pubDate);
|
||||
|
||||
QUrl GetEnclosureUrl();
|
||||
void SetEnclosureUrl(QUrl enclosureUrl);
|
||||
void SetEnclosureUrl(QString enclosureUrl);
|
||||
|
||||
QString GetEnclosureVersion();
|
||||
void SetEnclosureVersion(QString enclosureVersion);
|
||||
|
||||
QString GetEnclosurePlatform();
|
||||
void SetEnclosurePlatform(QString enclosurePlatform);
|
||||
|
||||
unsigned long GetEnclosureLength();
|
||||
void SetEnclosureLength(unsigned long enclosureLength);
|
||||
|
||||
QString GetEnclosureType();
|
||||
void SetEnclosureType(QString enclosureType);
|
||||
|
||||
private:
|
||||
QString m_title;
|
||||
QUrl m_releaseNotesLink;
|
||||
QString m_pubDate;
|
||||
QUrl m_enclosureUrl;
|
||||
QString m_enclosureVersion;
|
||||
QString m_enclosurePlatform;
|
||||
unsigned long m_enclosureLength;
|
||||
QString m_enclosureType;
|
||||
|
||||
};
|
||||
|
||||
#endif // FVAVAILABLEUPDATE_H
|
74
interface/external/fervor/fvignoredversions.cpp
vendored
Executable file
74
interface/external/fervor/fvignoredversions.cpp
vendored
Executable file
|
@ -0,0 +1,74 @@
|
|||
#include "fvignoredversions.h"
|
||||
#include "fvversioncomparator.h"
|
||||
#include <QSettings>
|
||||
#include <QCoreApplication>
|
||||
#include <string>
|
||||
|
||||
// QSettings key for the latest skipped version
|
||||
#define FV_IGNORED_VERSIONS_LATEST_SKIPPED_VERSION_KEY "FVLatestSkippedVersion"
|
||||
|
||||
|
||||
FVIgnoredVersions::FVIgnoredVersions(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
bool FVIgnoredVersions::VersionIsIgnored(QString version)
|
||||
{
|
||||
// We assume that variable 'version' contains either:
|
||||
// 1) The current version of the application (ignore)
|
||||
// 2) The version that was skipped before and thus stored in QSettings (ignore)
|
||||
// 3) A newer version (don't ignore)
|
||||
// 'version' is not likely to contain an older version in any case.
|
||||
|
||||
if (version == QCoreApplication::applicationVersion()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QSettings settings(QSettings::NativeFormat,
|
||||
QSettings::UserScope,
|
||||
QCoreApplication::organizationDomain(),
|
||||
QCoreApplication::applicationName());
|
||||
|
||||
//QSettings settings;
|
||||
if (settings.contains(FV_IGNORED_VERSIONS_LATEST_SKIPPED_VERSION_KEY)) {
|
||||
QString lastSkippedVersion = settings.value(FV_IGNORED_VERSIONS_LATEST_SKIPPED_VERSION_KEY).toString();
|
||||
if (version == lastSkippedVersion) {
|
||||
// Implicitly skipped version - skip
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::string currentAppVersion = QCoreApplication::applicationVersion().toStdString();
|
||||
std::string suggestedVersion = std::string(version.toStdString());
|
||||
if (FvVersionComparator::CompareVersions(currentAppVersion, suggestedVersion) == FvVersionComparator::kAscending) {
|
||||
// Newer version - do not skip
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fallback - skip
|
||||
return true;
|
||||
}
|
||||
|
||||
void FVIgnoredVersions::IgnoreVersion(QString version)
|
||||
{
|
||||
if (version == QCoreApplication::applicationVersion()) {
|
||||
// Don't ignore the current version
|
||||
return;
|
||||
}
|
||||
|
||||
if (version.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QSettings settings(QSettings::NativeFormat,
|
||||
QSettings::UserScope,
|
||||
QCoreApplication::organizationDomain(),
|
||||
QCoreApplication::applicationName());
|
||||
|
||||
|
||||
settings.setValue(FV_IGNORED_VERSIONS_LATEST_SKIPPED_VERSION_KEY, version);
|
||||
|
||||
return;
|
||||
}
|
19
interface/external/fervor/fvignoredversions.h
vendored
Executable file
19
interface/external/fervor/fvignoredversions.h
vendored
Executable file
|
@ -0,0 +1,19 @@
|
|||
#ifndef FVIGNOREDVERSIONS_H
|
||||
#define FVIGNOREDVERSIONS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class FVIgnoredVersions : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static bool VersionIsIgnored(QString version);
|
||||
static void IgnoreVersion(QString version);
|
||||
|
||||
private:
|
||||
explicit FVIgnoredVersions(QObject *parent = 0);
|
||||
|
||||
};
|
||||
|
||||
#endif // FVIGNOREDVERSIONS_H
|
210
interface/external/fervor/fvplatform.cpp
vendored
Executable file
210
interface/external/fervor/fvplatform.cpp
vendored
Executable file
|
@ -0,0 +1,210 @@
|
|||
#include "fvplatform.h"
|
||||
#include <QtGlobal>
|
||||
#include <QDebug>
|
||||
|
||||
FvPlatform::FvPlatform(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
bool FvPlatform::CurrentlyRunningOnPlatform(QString platform)
|
||||
{
|
||||
platform = platform.toUpper().trimmed();
|
||||
if (platform.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Defined on AIX.
|
||||
#ifdef Q_OS_AIX
|
||||
if (platform == "Q_OS_AIX") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Q_OS_BSD4 ("Defined on Any BSD 4.4 system") intentionally skipped.
|
||||
|
||||
// Defined on BSD/OS.
|
||||
#ifdef Q_OS_BSDI
|
||||
if (platform == "Q_OS_BSDI") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on Cygwin.
|
||||
#ifdef Q_OS_CYGWIN
|
||||
if (platform == "Q_OS_CYGWIN") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Q_OS_DARWIN ("Defined on Darwin OS (synonym for Q_OS_MAC)") intentionally skipped.
|
||||
|
||||
// Defined on DG/UX.
|
||||
#ifdef Q_OS_DGUX
|
||||
if (platform == "Q_OS_DGUX") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on DYNIX/ptx.
|
||||
#ifdef Q_OS_DYNIX
|
||||
if (platform == "Q_OS_DYNIX") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on FreeBSD.
|
||||
#ifdef Q_OS_FREEBSD
|
||||
if (platform == "Q_OS_FREEBSD") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on HP-UX.
|
||||
#ifdef Q_OS_HPUX
|
||||
if (platform == "Q_OS_HPUX") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on GNU Hurd.
|
||||
#ifdef Q_OS_HURD
|
||||
if (platform == "Q_OS_HURD") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on SGI Irix.
|
||||
#ifdef Q_OS_IRIX
|
||||
if (platform == "Q_OS_IRIX") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on Linux.
|
||||
#ifdef Q_OS_LINUX
|
||||
if (platform == "Q_OS_LINUX") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on LynxOS.
|
||||
#ifdef Q_OS_LYNX
|
||||
if (platform == "Q_OS_LYNX") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on MAC OS (synonym for Darwin).
|
||||
#ifdef Q_OS_MAC
|
||||
if (platform == "Q_OS_MAC") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Q_OS_MSDOS ("Defined on MS-DOS and Windows") intentionally skipped.
|
||||
|
||||
// Defined on NetBSD.
|
||||
#ifdef Q_OS_NETBSD
|
||||
if (platform == "Q_OS_NETBSD") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on OS/2.
|
||||
#ifdef Q_OS_OS2
|
||||
if (platform == "Q_OS_OS2") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on OpenBSD.
|
||||
#ifdef Q_OS_OPENBSD
|
||||
if (platform == "Q_OS_OPENBSD") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on XFree86 on OS/2 (not PM).
|
||||
#ifdef Q_OS_OS2EMX
|
||||
if (platform == "Q_OS_OS2EMX") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on HP Tru64 UNIX.
|
||||
#ifdef Q_OS_OSF
|
||||
if (platform == "Q_OS_OSF") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on QNX Neutrino.
|
||||
#ifdef Q_OS_QNX
|
||||
if (platform == "Q_OS_QNX") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on Reliant UNIX.
|
||||
#ifdef Q_OS_RELIANT
|
||||
if (platform == "Q_OS_RELIANT") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on SCO OpenServer 5.
|
||||
#ifdef Q_OS_SCO
|
||||
if (platform == "Q_OS_SCO") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on Sun Solaris.
|
||||
#ifdef Q_OS_SOLARIS
|
||||
if (platform == "Q_OS_SOLARIS") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on Symbian.
|
||||
#ifdef Q_OS_SYMBIAN
|
||||
if (platform == "Q_OS_SYMBIAN") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on DEC Ultrix.
|
||||
#ifdef Q_OS_ULTRIX
|
||||
if (platform == "Q_OS_ULTRIX") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Q_OS_UNIX ("Defined on Any UNIX BSD/SYSV system") intentionally skipped.
|
||||
|
||||
// Defined on UnixWare 7, Open UNIX 8.
|
||||
#ifdef Q_OS_UNIXWARE
|
||||
if (platform == "Q_OS_UNIXWARE") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on Windows CE (note: goes before Q_OS_WIN32)
|
||||
#ifdef Q_OS_WINCE
|
||||
if (platform == "Q_OS_WINCE") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defined on all supported versions of Windows.
|
||||
#ifdef Q_OS_WIN32
|
||||
if (platform == "Q_OS_WIN32") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fallback
|
||||
return false;
|
||||
}
|
18
interface/external/fervor/fvplatform.h
vendored
Executable file
18
interface/external/fervor/fvplatform.h
vendored
Executable file
|
@ -0,0 +1,18 @@
|
|||
#ifndef FVPLATFORM_H
|
||||
#define FVPLATFORM_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class FvPlatform : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static bool CurrentlyRunningOnPlatform(QString platform);
|
||||
|
||||
private:
|
||||
explicit FvPlatform(QObject *parent = 0);
|
||||
|
||||
};
|
||||
|
||||
#endif // FVPLATFORM_H
|
26
interface/external/fervor/fvupdatedownloadprogress.cpp
vendored
Executable file
26
interface/external/fervor/fvupdatedownloadprogress.cpp
vendored
Executable file
|
@ -0,0 +1,26 @@
|
|||
#include "fvupdatedownloadprogress.h"
|
||||
|
||||
FvUpdateDownloadProgress::FvUpdateDownloadProgress(QWidget *parent)
|
||||
: QWidget(parent, Qt::SplashScreen)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
ui.progress->setValue(0);
|
||||
|
||||
}
|
||||
|
||||
FvUpdateDownloadProgress::~FvUpdateDownloadProgress()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FvUpdateDownloadProgress::downloadProgress ( qint64 bytesReceived, qint64 bytesTotal )
|
||||
{
|
||||
ui.progress->setValue( ((float)bytesReceived / (float)bytesTotal) * 100 );
|
||||
}
|
||||
|
||||
void FvUpdateDownloadProgress::close()
|
||||
{
|
||||
this->deleteLater();
|
||||
QWidget::close();
|
||||
}
|
23
interface/external/fervor/fvupdatedownloadprogress.h
vendored
Executable file
23
interface/external/fervor/fvupdatedownloadprogress.h
vendored
Executable file
|
@ -0,0 +1,23 @@
|
|||
#ifndef FVUPDATEDOWNLOADPROGRESS_H
|
||||
#define FVUPDATEDOWNLOADPROGRESS_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "ui_fvupdatedownloadprogress.h"
|
||||
|
||||
class FvUpdateDownloadProgress : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FvUpdateDownloadProgress(QWidget *parent = 0);
|
||||
~FvUpdateDownloadProgress();
|
||||
|
||||
public slots:
|
||||
void downloadProgress ( qint64 bytesReceived, qint64 bytesTotal );
|
||||
void close();
|
||||
|
||||
private:
|
||||
Ui::FvUpdateDownloadProgress ui;
|
||||
};
|
||||
|
||||
#endif // FVUPDATEDOWNLOADPROGRESS_H
|
94
interface/external/fervor/fvupdatedownloadprogress.ui
vendored
Executable file
94
interface/external/fervor/fvupdatedownloadprogress.ui
vendored
Executable file
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FvUpdateDownloadProgress</class>
|
||||
<widget class="QWidget" name="FvUpdateDownloadProgress">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>558</width>
|
||||
<height>70</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>FvUpdateDownloadProgress</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::WinPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Downloading Update...</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progress">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
<property name="textVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="invertedAppearance">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
908
interface/external/fervor/fvupdater.cpp
vendored
Executable file
908
interface/external/fervor/fvupdater.cpp
vendored
Executable file
|
@ -0,0 +1,908 @@
|
|||
#include "fvupdater.h"
|
||||
#include "fvplatform.h"
|
||||
#include "fvignoredversions.h"
|
||||
#include "fvavailableupdate.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QtNetwork>
|
||||
#include <QDebug>
|
||||
#include <QSettings>
|
||||
#include "quazip.h"
|
||||
#include "quazipfile.h"
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
#include "CoreFoundation/CoreFoundation.h"
|
||||
#endif
|
||||
|
||||
#ifdef FV_GUI
|
||||
#include "fvupdatewindow.h"
|
||||
#include "fvupdatedownloadprogress.h"
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
#else
|
||||
// QSettings key for automatic update installation
|
||||
#define FV_NEW_VERSION_POLICY_KEY "FVNewVersionPolicy"
|
||||
#endif
|
||||
|
||||
#ifdef FV_DEBUG
|
||||
// Unit tests
|
||||
# include "fvversioncomparatortest.h"
|
||||
#endif
|
||||
|
||||
extern QSettings* settings;
|
||||
|
||||
FvUpdater* FvUpdater::m_Instance = 0;
|
||||
|
||||
|
||||
FvUpdater* FvUpdater::sharedUpdater()
|
||||
{
|
||||
static QMutex mutex;
|
||||
if (! m_Instance) {
|
||||
mutex.lock();
|
||||
|
||||
if (! m_Instance) {
|
||||
m_Instance = new FvUpdater;
|
||||
}
|
||||
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
return m_Instance;
|
||||
}
|
||||
|
||||
void FvUpdater::drop()
|
||||
{
|
||||
static QMutex mutex;
|
||||
mutex.lock();
|
||||
delete m_Instance;
|
||||
m_Instance = 0;
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
FvUpdater::FvUpdater() : QObject(0)
|
||||
{
|
||||
m_reply = 0;
|
||||
#ifdef FV_GUI
|
||||
m_updaterWindow = 0;
|
||||
#endif
|
||||
m_proposedUpdate = 0;
|
||||
m_requiredSslFingerprint = "";
|
||||
htAuthUsername = "";
|
||||
htAuthPassword = "";
|
||||
skipVersionAllowed = true;
|
||||
remindLaterAllowed = true;
|
||||
|
||||
connect(&m_qnam, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),this, SLOT(authenticationRequired(QNetworkReply*, QAuthenticator*)));
|
||||
|
||||
// Translation mechanism
|
||||
installTranslator();
|
||||
|
||||
#ifdef FV_DEBUG
|
||||
// Unit tests
|
||||
FvVersionComparatorTest* test = new FvVersionComparatorTest();
|
||||
test->runAll();
|
||||
delete test;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
FvUpdater::~FvUpdater()
|
||||
{
|
||||
if (m_proposedUpdate) {
|
||||
delete m_proposedUpdate;
|
||||
m_proposedUpdate = 0;
|
||||
}
|
||||
|
||||
#ifdef FV_GUI
|
||||
hideUpdaterWindow();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FvUpdater::installTranslator()
|
||||
{
|
||||
QTranslator translator;
|
||||
QString locale = QLocale::system().name();
|
||||
translator.load(QString("fervor_") + locale);
|
||||
|
||||
#if QT_VERSION < 0x050000
|
||||
QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));
|
||||
#endif
|
||||
|
||||
qApp->installTranslator(&translator);
|
||||
}
|
||||
|
||||
#ifdef FV_GUI
|
||||
void FvUpdater::showUpdaterWindowUpdatedWithCurrentUpdateProposal()
|
||||
{
|
||||
// Destroy window if already exists
|
||||
hideUpdaterWindow();
|
||||
|
||||
// Create a new window
|
||||
m_updaterWindow = new FvUpdateWindow(NULL, skipVersionAllowed, remindLaterAllowed);
|
||||
m_updaterWindow->UpdateWindowWithCurrentProposedUpdate();
|
||||
m_updaterWindow->show();
|
||||
}
|
||||
|
||||
void FvUpdater::hideUpdaterWindow()
|
||||
{
|
||||
if (m_updaterWindow) {
|
||||
if (! m_updaterWindow->close()) {
|
||||
qWarning() << "Update window didn't close, leaking memory from now on";
|
||||
}
|
||||
|
||||
// not deleting because of Qt::WA_DeleteOnClose
|
||||
|
||||
m_updaterWindow = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FvUpdater::updaterWindowWasClosed()
|
||||
{
|
||||
// (Re-)nullify a pointer to a destroyed QWidget or you're going to have a bad time.
|
||||
m_updaterWindow = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void FvUpdater::SetFeedURL(QUrl feedURL)
|
||||
{
|
||||
m_feedURL = feedURL;
|
||||
}
|
||||
|
||||
void FvUpdater::SetFeedURL(QString feedURL)
|
||||
{
|
||||
SetFeedURL(QUrl(feedURL));
|
||||
}
|
||||
|
||||
QString FvUpdater::GetFeedURL()
|
||||
{
|
||||
return m_feedURL.toString();
|
||||
}
|
||||
|
||||
FvAvailableUpdate* FvUpdater::GetProposedUpdate()
|
||||
{
|
||||
return m_proposedUpdate;
|
||||
}
|
||||
|
||||
|
||||
void FvUpdater::InstallUpdate()
|
||||
{
|
||||
if(m_proposedUpdate==NULL)
|
||||
{
|
||||
qWarning() << "Abort Update: No update prososed! This should not happen.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare download
|
||||
QUrl url = m_proposedUpdate->GetEnclosureUrl();
|
||||
|
||||
// Check SSL Fingerprint if required
|
||||
if(url.scheme()=="https" && !m_requiredSslFingerprint.isEmpty())
|
||||
if( !checkSslFingerPrint(url) ) // check failed
|
||||
{
|
||||
qWarning() << "Update aborted.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Start Download
|
||||
QNetworkReply* reply = m_qnam.get(QNetworkRequest(url));
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(httpUpdateDownloadFinished()));
|
||||
|
||||
// Maybe Check request 's return value
|
||||
if (reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
qDebug()<<"Unable to download the update: "<<reply->errorString();
|
||||
return;
|
||||
}
|
||||
else
|
||||
qDebug()<<"OK";
|
||||
|
||||
// Show download Window
|
||||
#ifdef FV_GUI
|
||||
FvUpdateDownloadProgress* dlwindow = new FvUpdateDownloadProgress(NULL);
|
||||
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), dlwindow, SLOT(downloadProgress(qint64, qint64) ));
|
||||
connect(&m_qnam, SIGNAL(finished(QNetworkReply*)), dlwindow, SLOT(close()));
|
||||
dlwindow->show();
|
||||
#endif
|
||||
|
||||
emit (updatedFinishedSuccessfully());
|
||||
|
||||
#ifdef FV_GUI
|
||||
hideUpdaterWindow();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FvUpdater::httpUpdateDownloadFinished()
|
||||
{
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||
if(reply==NULL)
|
||||
{
|
||||
qWarning()<<"The slot httpUpdateDownloadFinished() should only be invoked by S&S.";
|
||||
return;
|
||||
}
|
||||
|
||||
if(reply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
int httpstatuscode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toUInt();
|
||||
|
||||
// no error received?
|
||||
if (reply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
if (reply->isReadable())
|
||||
{
|
||||
#ifdef Q_WS_MAC
|
||||
CFURLRef appURLRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
||||
char path[PATH_MAX];
|
||||
if (!CFURLGetFileSystemRepresentation(appURLRef, TRUE, (UInt8 *)path, PATH_MAX)) {
|
||||
// error!
|
||||
}
|
||||
|
||||
CFRelease(appURLRef);
|
||||
QString filePath = QString(path);
|
||||
QString rootDirectory = filePath.left(filePath.lastIndexOf("/"));
|
||||
#else
|
||||
QString rootDirectory = QCoreApplication::applicationDirPath() + "/";
|
||||
#endif
|
||||
|
||||
// Write download into File
|
||||
QFileInfo fileInfo=reply->url().path();
|
||||
QString fileName = rootDirectory + fileInfo.fileName();
|
||||
//qDebug()<<"Writing downloaded file into "<<fileName;
|
||||
|
||||
QFile file(fileName);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.write(reply->readAll());
|
||||
file.close();
|
||||
|
||||
// Retrieve List of updated files (Placed in an extra scope to avoid QuaZIP handles the archive permanently and thus avoids the deletion.)
|
||||
{
|
||||
QuaZip zip(fileName);
|
||||
if (!zip.open(QuaZip::mdUnzip)) {
|
||||
qWarning("testRead(): zip.open(): %d", zip.getZipError());
|
||||
return;
|
||||
}
|
||||
zip.setFileNameCodec("IBM866");
|
||||
QList<QuaZipFileInfo> updateFiles = zip.getFileInfoList();
|
||||
|
||||
// Rename all current files with available update.
|
||||
for (int i=0;i<updateFiles.size();i++)
|
||||
{
|
||||
QString sourceFilePath = rootDirectory + "\\" + updateFiles[i].name;
|
||||
QDir appDir( QCoreApplication::applicationDirPath() );
|
||||
|
||||
QFileInfo file( sourceFilePath );
|
||||
if(file.exists())
|
||||
{
|
||||
//qDebug()<<tr("Moving file %1 to %2").arg(sourceFilePath).arg(sourceFilePath+".oldversion");
|
||||
appDir.rename( sourceFilePath, sourceFilePath+".oldversion" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Install updated Files
|
||||
unzipUpdate(fileName, rootDirectory);
|
||||
|
||||
// Delete update archive
|
||||
while(QFile::remove(fileName) )
|
||||
{
|
||||
};
|
||||
|
||||
// Restart ap to clean up and start usual business
|
||||
restartApplication();
|
||||
|
||||
}
|
||||
else qDebug()<<"Error: QNetworkReply is not readable!";
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug()<<"Download errors ocurred! HTTP Error Code:"<<httpstatuscode;
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
} // If !reply->error END
|
||||
} // httpUpdateDownloadFinished END
|
||||
|
||||
bool FvUpdater::unzipUpdate(const QString & filePath, const QString & extDirPath, const QString & singleFileName )
|
||||
{
|
||||
QuaZip zip(filePath);
|
||||
|
||||
if (!zip.open(QuaZip::mdUnzip)) {
|
||||
qWarning()<<tr("Error: Unable to open zip archive %1 for unzipping: %2").arg(filePath).arg(zip.getZipError());
|
||||
return false;
|
||||
}
|
||||
|
||||
zip.setFileNameCodec("IBM866");
|
||||
|
||||
//qWarning("Update contains %d files\n", zip.getEntriesCount());
|
||||
|
||||
QuaZipFileInfo info;
|
||||
QuaZipFile file(&zip);
|
||||
QFile out;
|
||||
QString name;
|
||||
QDir appDir(extDirPath);
|
||||
for (bool more = zip.goToFirstFile(); more; more = zip.goToNextFile())
|
||||
{
|
||||
if (!zip.getCurrentFileInfo(&info)) {
|
||||
qWarning()<<tr("Error: Unable to retrieve fileInfo about the file to extract: %2").arg(zip.getZipError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!singleFileName.isEmpty())
|
||||
if (!info.name.contains(singleFileName))
|
||||
continue;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qWarning()<<tr("Error: Unable to open file %1 for unzipping: %2").arg(filePath).arg(file.getZipError());
|
||||
return false;
|
||||
}
|
||||
|
||||
name = QString("%1/%2").arg(extDirPath).arg(file.getActualFileName());
|
||||
|
||||
if (file.getZipError() != UNZ_OK) {
|
||||
qWarning()<<tr("Error: Unable to retrieve zipped filename to unzip from %1: %2").arg(filePath).arg(file.getZipError());
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo fi(name);
|
||||
appDir.mkpath(fi.absolutePath() ); // Ensure that subdirectories - if required - exist
|
||||
out.setFileName(name);
|
||||
out.open(QIODevice::WriteOnly);
|
||||
out.write( file.readAll() );
|
||||
out.close();
|
||||
|
||||
if (file.getZipError() != UNZ_OK) {
|
||||
qWarning()<<tr("Error: Unable to unzip file %1: %2").arg(name).arg(file.getZipError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file.atEnd()) {
|
||||
qWarning()<<tr("Error: Have read all available bytes, but pointer still does not show EOF: %1").arg(file.getZipError());
|
||||
return false;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
if (file.getZipError() != UNZ_OK) {
|
||||
qWarning()<<tr("Error: Unable to close zipped file %1: %2").arg(name).arg(file.getZipError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
zip.close();
|
||||
|
||||
if (zip.getZipError() != UNZ_OK) {
|
||||
qWarning()<<tr("Error: Unable to close zip archive file %1: %2").arg(filePath).arg(file.getZipError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void FvUpdater::SkipUpdate()
|
||||
{
|
||||
qDebug() << "Skip update";
|
||||
|
||||
FvAvailableUpdate* proposedUpdate = GetProposedUpdate();
|
||||
if (! proposedUpdate) {
|
||||
qWarning() << "Proposed update is NULL (shouldn't be at this point)";
|
||||
return;
|
||||
}
|
||||
|
||||
// Start ignoring this particular version
|
||||
FVIgnoredVersions::IgnoreVersion(proposedUpdate->GetEnclosureVersion());
|
||||
|
||||
#ifdef FV_GUI
|
||||
hideUpdaterWindow();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FvUpdater::RemindMeLater()
|
||||
{
|
||||
//qDebug() << "Remind me later";
|
||||
|
||||
#ifdef FV_GUI
|
||||
hideUpdaterWindow();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FvUpdater::CheckForUpdates(bool silentAsMuchAsItCouldGet)
|
||||
{
|
||||
if (m_feedURL.isEmpty()) {
|
||||
qCritical() << "Please set feed URL via setFeedURL() before calling CheckForUpdates().";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_silentAsMuchAsItCouldGet = silentAsMuchAsItCouldGet;
|
||||
|
||||
// Check if application's organization name and domain are set, fail otherwise
|
||||
// (nowhere to store QSettings to)
|
||||
if (QCoreApplication::organizationName().isEmpty()) {
|
||||
qCritical() << "QCoreApplication::organizationName is not set. Please do that.";
|
||||
return false;
|
||||
}
|
||||
if (QCoreApplication::organizationDomain().isEmpty()) {
|
||||
qCritical() << "QCoreApplication::organizationDomain is not set. Please do that.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(QCoreApplication::applicationName().isEmpty()) {
|
||||
qCritical() << "QCoreApplication::applicationName is not set. Please do that.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set application version is not set yet
|
||||
if (QCoreApplication::applicationVersion().isEmpty()) {
|
||||
qCritical() << "QCoreApplication::applicationVersion is not set. Please do that.";
|
||||
return false;
|
||||
}
|
||||
|
||||
cancelDownloadFeed();
|
||||
m_httpRequestAborted = false;
|
||||
startDownloadFeed(m_feedURL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FvUpdater::CheckForUpdatesSilent()
|
||||
{
|
||||
return CheckForUpdates(true);
|
||||
}
|
||||
|
||||
bool FvUpdater::CheckForUpdatesNotSilent()
|
||||
{
|
||||
return CheckForUpdates(false);
|
||||
}
|
||||
|
||||
|
||||
void FvUpdater::startDownloadFeed(QUrl url)
|
||||
{
|
||||
m_xml.clear();
|
||||
|
||||
// Check SSL Fingerprint if required
|
||||
if(url.scheme()=="https" && !m_requiredSslFingerprint.isEmpty())
|
||||
if( !checkSslFingerPrint(url) ) // check failed
|
||||
{
|
||||
qWarning() << "Update aborted.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_reply = m_qnam.get(QNetworkRequest(url));
|
||||
|
||||
connect(m_reply, SIGNAL(readyRead()), this, SLOT(httpFeedReadyRead()));
|
||||
connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(httpFeedUpdateDataReadProgress(qint64, qint64)));
|
||||
connect(m_reply, SIGNAL(finished()), this, SLOT(httpFeedDownloadFinished()));
|
||||
}
|
||||
|
||||
void FvUpdater::cancelDownloadFeed()
|
||||
{
|
||||
if (m_reply) {
|
||||
m_httpRequestAborted = true;
|
||||
m_reply->abort();
|
||||
}
|
||||
}
|
||||
|
||||
void FvUpdater::httpFeedReadyRead()
|
||||
{
|
||||
// this slot gets called every time the QNetworkReply has new data.
|
||||
// We read all of its new data and write it into the file.
|
||||
// That way we use less RAM than when reading it at the finished()
|
||||
// signal of the QNetworkReply
|
||||
m_xml.addData(m_reply->readAll());
|
||||
}
|
||||
|
||||
void FvUpdater::httpFeedUpdateDataReadProgress(qint64 bytesRead,
|
||||
qint64 totalBytes)
|
||||
{
|
||||
Q_UNUSED(bytesRead);
|
||||
Q_UNUSED(totalBytes);
|
||||
|
||||
if (m_httpRequestAborted) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void FvUpdater::httpFeedDownloadFinished()
|
||||
{
|
||||
if (m_httpRequestAborted) {
|
||||
m_reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
if (m_reply->error()) {
|
||||
|
||||
// Error.
|
||||
showErrorDialog(tr("Feed download failed: %1.").arg(m_reply->errorString()), false);
|
||||
|
||||
} else if (! redirectionTarget.isNull()) {
|
||||
QUrl newUrl = m_feedURL.resolved(redirectionTarget.toUrl());
|
||||
|
||||
m_feedURL = newUrl;
|
||||
m_reply->deleteLater();
|
||||
|
||||
startDownloadFeed(m_feedURL);
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
// Done.
|
||||
xmlParseFeed();
|
||||
|
||||
}
|
||||
|
||||
m_reply->deleteLater();
|
||||
m_reply = 0;
|
||||
}
|
||||
|
||||
bool FvUpdater::xmlParseFeed()
|
||||
{
|
||||
QString currentTag, currentQualifiedTag;
|
||||
|
||||
QString xmlTitle, xmlLink, xmlReleaseNotesLink, xmlPubDate, xmlEnclosureUrl,
|
||||
xmlEnclosureVersion, xmlEnclosurePlatform, xmlEnclosureType;
|
||||
unsigned long xmlEnclosureLength;
|
||||
|
||||
// Parse
|
||||
while (! m_xml.atEnd()) {
|
||||
|
||||
m_xml.readNext();
|
||||
|
||||
if (m_xml.isStartElement()) {
|
||||
|
||||
currentTag = m_xml.name().toString();
|
||||
currentQualifiedTag = m_xml.qualifiedName().toString();
|
||||
|
||||
if (m_xml.name() == "item") {
|
||||
|
||||
xmlTitle.clear();
|
||||
xmlLink.clear();
|
||||
xmlReleaseNotesLink.clear();
|
||||
xmlPubDate.clear();
|
||||
xmlEnclosureUrl.clear();
|
||||
xmlEnclosureVersion.clear();
|
||||
xmlEnclosurePlatform.clear();
|
||||
xmlEnclosureLength = 0;
|
||||
xmlEnclosureType.clear();
|
||||
|
||||
} else if (m_xml.name() == "enclosure") {
|
||||
|
||||
QXmlStreamAttributes attribs = m_xml.attributes();
|
||||
|
||||
if (attribs.hasAttribute("fervor:platform"))
|
||||
{
|
||||
xmlEnclosurePlatform = attribs.value("fervor:platform").toString().trimmed();
|
||||
|
||||
if (FvPlatform::CurrentlyRunningOnPlatform(xmlEnclosurePlatform))
|
||||
{
|
||||
xmlEnclosureUrl = attribs.hasAttribute("url") ? attribs.value("url").toString().trimmed() : "";
|
||||
|
||||
xmlEnclosureVersion = "";
|
||||
if (attribs.hasAttribute("fervor:version"))
|
||||
xmlEnclosureVersion = attribs.value("fervor:version").toString().trimmed();
|
||||
if (attribs.hasAttribute("sparkle:version"))
|
||||
xmlEnclosureVersion = attribs.value("sparkle:version").toString().trimmed();
|
||||
|
||||
xmlEnclosureLength = attribs.hasAttribute("length") ? attribs.value("length").toString().toLong() : 0;
|
||||
|
||||
xmlEnclosureType = attribs.hasAttribute("type") ? attribs.value("type").toString().trimmed() : "";
|
||||
}
|
||||
|
||||
} // if hasAttribute flevor:platform END
|
||||
|
||||
} // IF encosure END
|
||||
|
||||
} else if (m_xml.isEndElement()) {
|
||||
|
||||
if (m_xml.name() == "item") {
|
||||
|
||||
// That's it - we have analyzed a single <item> and we'll stop
|
||||
// here (because the topmost is the most recent one, and thus
|
||||
// the newest version.
|
||||
|
||||
return searchDownloadedFeedForUpdates(xmlTitle,
|
||||
xmlLink,
|
||||
xmlReleaseNotesLink,
|
||||
xmlPubDate,
|
||||
xmlEnclosureUrl,
|
||||
xmlEnclosureVersion,
|
||||
xmlEnclosurePlatform,
|
||||
xmlEnclosureLength,
|
||||
xmlEnclosureType);
|
||||
|
||||
}
|
||||
|
||||
} else if (m_xml.isCharacters() && ! m_xml.isWhitespace()) {
|
||||
|
||||
if (currentTag == "title") {
|
||||
xmlTitle += m_xml.text().toString().trimmed();
|
||||
|
||||
} else if (currentTag == "link") {
|
||||
xmlLink += m_xml.text().toString().trimmed();
|
||||
|
||||
} else if (currentQualifiedTag == "sparkle:releaseNotesLink") {
|
||||
xmlReleaseNotesLink += m_xml.text().toString().trimmed();
|
||||
|
||||
} else if (currentTag == "pubDate") {
|
||||
xmlPubDate += m_xml.text().toString().trimmed();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (m_xml.error() && m_xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
|
||||
|
||||
showErrorDialog(tr("Feed parsing failed: %1 %2.").arg(QString::number(m_xml.lineNumber()), m_xml.errorString()), false);
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FvUpdater::searchDownloadedFeedForUpdates(QString xmlTitle,
|
||||
QString xmlLink,
|
||||
QString xmlReleaseNotesLink,
|
||||
QString xmlPubDate,
|
||||
QString xmlEnclosureUrl,
|
||||
QString xmlEnclosureVersion,
|
||||
QString xmlEnclosurePlatform,
|
||||
unsigned long xmlEnclosureLength,
|
||||
QString xmlEnclosureType)
|
||||
{
|
||||
Q_UNUSED(xmlTitle);
|
||||
Q_UNUSED(xmlPubDate);
|
||||
Q_UNUSED(xmlEnclosureLength);
|
||||
Q_UNUSED(xmlEnclosureType);
|
||||
|
||||
// Validate
|
||||
if (xmlReleaseNotesLink.isEmpty()) {
|
||||
if (xmlLink.isEmpty()) {
|
||||
showErrorDialog(tr("Feed error: \"release notes\" link is empty"), false);
|
||||
return false;
|
||||
} else {
|
||||
xmlReleaseNotesLink = xmlLink;
|
||||
}
|
||||
} else {
|
||||
xmlLink = xmlReleaseNotesLink;
|
||||
}
|
||||
if (! (xmlLink.startsWith("http://") || xmlLink.startsWith("https://"))) {
|
||||
showErrorDialog(tr("Feed error: invalid \"release notes\" link"), false);
|
||||
return false;
|
||||
}
|
||||
if (xmlEnclosureUrl.isEmpty() || xmlEnclosureVersion.isEmpty() || xmlEnclosurePlatform.isEmpty()) {
|
||||
showErrorDialog(tr("Feed error: invalid \"enclosure\" with the download link"), false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Relevant version?
|
||||
if (FVIgnoredVersions::VersionIsIgnored(xmlEnclosureVersion)) {
|
||||
qDebug() << "Version '" << xmlEnclosureVersion << "' is ignored, too old or something like that.";
|
||||
|
||||
showInformationDialog(tr("No updates were found."), false);
|
||||
|
||||
return true; // Things have succeeded when you think of it.
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Success! At this point, we have found an update that can be proposed
|
||||
// to the user.
|
||||
//
|
||||
|
||||
if (m_proposedUpdate) {
|
||||
delete m_proposedUpdate; m_proposedUpdate = 0;
|
||||
}
|
||||
m_proposedUpdate = new FvAvailableUpdate();
|
||||
m_proposedUpdate->SetTitle(xmlTitle);
|
||||
m_proposedUpdate->SetReleaseNotesLink(xmlReleaseNotesLink);
|
||||
m_proposedUpdate->SetPubDate(xmlPubDate);
|
||||
m_proposedUpdate->SetEnclosureUrl(xmlEnclosureUrl);
|
||||
m_proposedUpdate->SetEnclosureVersion(xmlEnclosureVersion);
|
||||
m_proposedUpdate->SetEnclosurePlatform(xmlEnclosurePlatform);
|
||||
m_proposedUpdate->SetEnclosureLength(xmlEnclosureLength);
|
||||
m_proposedUpdate->SetEnclosureType(xmlEnclosureType);
|
||||
|
||||
#ifdef FV_GUI
|
||||
// Show "look, there's an update" window
|
||||
showUpdaterWindowUpdatedWithCurrentUpdateProposal();
|
||||
#else
|
||||
// Decide ourselves what to do
|
||||
decideWhatToDoWithCurrentUpdateProposal();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void FvUpdater::showErrorDialog(QString message, bool showEvenInSilentMode)
|
||||
{
|
||||
if (m_silentAsMuchAsItCouldGet) {
|
||||
if (! showEvenInSilentMode) {
|
||||
// Don't show errors in the silent mode
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FV_GUI
|
||||
QMessageBox dlFailedMsgBox;
|
||||
dlFailedMsgBox.setIcon(QMessageBox::Critical);
|
||||
dlFailedMsgBox.setText(tr("Error"));
|
||||
dlFailedMsgBox.setInformativeText(message);
|
||||
dlFailedMsgBox.exec();
|
||||
#else
|
||||
qCritical() << message;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FvUpdater::showInformationDialog(QString message, bool showEvenInSilentMode)
|
||||
{
|
||||
if (m_silentAsMuchAsItCouldGet) {
|
||||
if (! showEvenInSilentMode) {
|
||||
// Don't show information dialogs in the silent mode
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FV_GUI
|
||||
QMessageBox dlInformationMsgBox;
|
||||
dlInformationMsgBox.setIcon(QMessageBox::Information);
|
||||
dlInformationMsgBox.setText(tr("Information"));
|
||||
dlInformationMsgBox.setInformativeText(message);
|
||||
dlInformationMsgBox.exec();
|
||||
#else
|
||||
qDebug() << message;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FvUpdater::finishUpdate(QString pathToFinish)
|
||||
{
|
||||
pathToFinish = pathToFinish.isEmpty() ? QCoreApplication::applicationDirPath() : pathToFinish;
|
||||
QDir appDir(pathToFinish);
|
||||
appDir.setFilter( QDir::Files | QDir::Dirs );
|
||||
|
||||
QFileInfoList dirEntries = appDir.entryInfoList();
|
||||
foreach (QFileInfo fi, dirEntries)
|
||||
{
|
||||
if ( fi.isDir() )
|
||||
{
|
||||
QString dirname = fi.fileName();
|
||||
if ((dirname==".") || (dirname == ".."))
|
||||
continue;
|
||||
|
||||
// recursive clean up subdirectory
|
||||
finishUpdate(fi.filePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(fi.suffix()=="oldversion")
|
||||
if( !appDir.remove( fi.absoluteFilePath() ) )
|
||||
qDebug()<<"Error: Unable to clean up file: "<<fi.absoluteFilePath();
|
||||
|
||||
}
|
||||
} // For each dir entry END
|
||||
}
|
||||
|
||||
void FvUpdater::restartApplication()
|
||||
{
|
||||
// Spawn a new instance of myApplication:
|
||||
QString app = QApplication::applicationFilePath();
|
||||
QStringList arguments = QApplication::arguments();
|
||||
QString wd = QDir::currentPath();
|
||||
qDebug() << app << arguments << wd;
|
||||
QProcess::startDetached(app, arguments, wd);
|
||||
QApplication::exit();
|
||||
}
|
||||
|
||||
void FvUpdater::setRequiredSslFingerPrint(QString md5)
|
||||
{
|
||||
m_requiredSslFingerprint = md5.remove(":");
|
||||
}
|
||||
|
||||
QString FvUpdater::getRequiredSslFingerPrint()
|
||||
{
|
||||
return m_requiredSslFingerprint;
|
||||
}
|
||||
|
||||
bool FvUpdater::checkSslFingerPrint(QUrl urltoCheck)
|
||||
{
|
||||
if(urltoCheck.scheme()!="https")
|
||||
{
|
||||
qWarning()<<tr("SSL fingerprint check: The url %1 is not a ssl connection!").arg(urltoCheck.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
QSslSocket *socket = new QSslSocket(this);
|
||||
socket->connectToHostEncrypted(urltoCheck.host(), 443);
|
||||
if( !socket->waitForEncrypted(1000)) // waits until ssl emits encrypted(), max 1000msecs
|
||||
{
|
||||
qWarning()<<"SSL fingerprint check: Unable to connect SSL server: "<<socket->sslErrors();
|
||||
return false;
|
||||
}
|
||||
|
||||
QSslCertificate cert = socket->peerCertificate();
|
||||
|
||||
if(cert.isNull())
|
||||
{
|
||||
qWarning()<<"SSL fingerprint check: Unable to retrieve SSL server certificate.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// COmpare digests
|
||||
if(cert.digest().toHex() != m_requiredSslFingerprint)
|
||||
{
|
||||
qWarning()<<"SSL fingerprint check: FINGERPRINT MISMATCH! Server digest="<<cert.digest().toHex()<<", requiered ssl digest="<<m_requiredSslFingerprint;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FvUpdater::authenticationRequired ( QNetworkReply * reply, QAuthenticator * authenticator )
|
||||
{
|
||||
if(reply==NULL || authenticator==NULL)
|
||||
return;
|
||||
|
||||
if(!authenticator->user().isEmpty()) // If there is already a login user set but an authentication is still required: credentials must be wrong -> abort
|
||||
{
|
||||
reply->abort();
|
||||
qWarning()<<"Http authentication: Wrong credentials!";
|
||||
return;
|
||||
}
|
||||
|
||||
authenticator->setUser(htAuthUsername);
|
||||
authenticator->setPassword(htAuthPassword);
|
||||
}
|
||||
|
||||
void FvUpdater::setHtAuthCredentials(QString user, QString pass)
|
||||
{
|
||||
htAuthUsername = user;
|
||||
htAuthPassword = pass;
|
||||
}
|
||||
|
||||
void FvUpdater::setHtAuthUsername(QString user)
|
||||
{
|
||||
htAuthUsername = user;
|
||||
}
|
||||
|
||||
void FvUpdater::setHtAuthPassword(QString pass)
|
||||
{
|
||||
htAuthPassword = pass;
|
||||
}
|
||||
|
||||
void FvUpdater::setSkipVersionAllowed(bool allowed)
|
||||
{
|
||||
skipVersionAllowed = allowed;
|
||||
}
|
||||
|
||||
void FvUpdater::setRemindLaterAllowed(bool allowed)
|
||||
{
|
||||
remindLaterAllowed = allowed;
|
||||
}
|
||||
|
||||
bool FvUpdater::getSkipVersionAllowed()
|
||||
{
|
||||
return skipVersionAllowed;
|
||||
}
|
||||
|
||||
bool FvUpdater::getRemindLaterAllowed()
|
||||
{
|
||||
return remindLaterAllowed;
|
||||
}
|
||||
|
||||
#ifndef FV_GUI
|
||||
|
||||
void FvUpdater::decideWhatToDoWithCurrentUpdateProposal()
|
||||
{
|
||||
QString policy = settings->value(FV_NEW_VERSION_POLICY_KEY).toString();
|
||||
if(policy == "install")
|
||||
InstallUpdate();
|
||||
else if(policy == "skip")
|
||||
SkipUpdate();
|
||||
else
|
||||
RemindMeLater();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
183
interface/external/fervor/fvupdater.h
vendored
Executable file
183
interface/external/fervor/fvupdater.h
vendored
Executable file
|
@ -0,0 +1,183 @@
|
|||
#ifndef FVUPDATER_H
|
||||
#define FVUPDATER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QUrl>
|
||||
#include <QXmlStreamReader>
|
||||
class QNetworkReply;
|
||||
class FvUpdateWindow;
|
||||
class FvUpdateConfirmDialog;
|
||||
class FvAvailableUpdate;
|
||||
|
||||
|
||||
class FvUpdater : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
// Singleton
|
||||
static FvUpdater* sharedUpdater();
|
||||
static void drop();
|
||||
|
||||
// Set / get feed URL
|
||||
void SetFeedURL(QUrl feedURL);
|
||||
void SetFeedURL(QString feedURL);
|
||||
QString GetFeedURL();
|
||||
void finishUpdate(QString pathToFinish = "");
|
||||
void setRequiredSslFingerPrint(QString md5);
|
||||
QString getRequiredSslFingerPrint(); // returns md5!
|
||||
// HTTP Authentuication - for security reasons no getters are provided, only a setter
|
||||
void setHtAuthCredentials(QString user, QString pass);
|
||||
void setHtAuthUsername(QString user);
|
||||
void setHtAuthPassword(QString pass);
|
||||
void setSkipVersionAllowed(bool allowed);
|
||||
void setRemindLaterAllowed(bool allowed);
|
||||
bool getSkipVersionAllowed();
|
||||
bool getRemindLaterAllowed();
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
// Check for updates
|
||||
bool CheckForUpdates(bool silentAsMuchAsItCouldGet = true);
|
||||
|
||||
// Aliases
|
||||
bool CheckForUpdatesSilent();
|
||||
bool CheckForUpdatesNotSilent();
|
||||
|
||||
|
||||
//
|
||||
// ---------------------------------------------------
|
||||
// ---------------------------------------------------
|
||||
// ---------------------------------------------------
|
||||
// ---------------------------------------------------
|
||||
//
|
||||
|
||||
protected:
|
||||
|
||||
friend class FvUpdateWindow; // Uses GetProposedUpdate() and others
|
||||
friend class FvUpdateConfirmDialog; // Uses GetProposedUpdate() and others
|
||||
FvAvailableUpdate* GetProposedUpdate();
|
||||
|
||||
|
||||
protected slots:
|
||||
|
||||
// Update window button slots
|
||||
void InstallUpdate();
|
||||
void SkipUpdate();
|
||||
void RemindMeLater();
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Singleton business
|
||||
//
|
||||
// (we leave just the declarations, so the compiler will warn us if we try
|
||||
// to use those two functions by accident)
|
||||
FvUpdater(); // Hide main constructor
|
||||
~FvUpdater(); // Hide main destructor
|
||||
FvUpdater(const FvUpdater&); // Hide copy constructor
|
||||
FvUpdater& operator=(const FvUpdater&); // Hide assign op
|
||||
|
||||
static FvUpdater* m_Instance; // Singleton instance
|
||||
|
||||
|
||||
//
|
||||
// Windows / dialogs
|
||||
//
|
||||
#ifdef FV_GUI
|
||||
FvUpdateWindow* m_updaterWindow; // Updater window (NULL if not shown)
|
||||
void showUpdaterWindowUpdatedWithCurrentUpdateProposal(); // Show updater window
|
||||
void hideUpdaterWindow(); // Hide + destroy m_updaterWindow
|
||||
void updaterWindowWasClosed(); // Sent by the updater window when it gets closed
|
||||
#else
|
||||
void decideWhatToDoWithCurrentUpdateProposal(); // Perform an action which is configured in settings
|
||||
#endif
|
||||
|
||||
// Available update (NULL if not fetched)
|
||||
FvAvailableUpdate* m_proposedUpdate;
|
||||
|
||||
// If true, don't show the error dialogs and the "no updates." dialog
|
||||
// (silentAsMuchAsItCouldGet from CheckForUpdates() goes here)
|
||||
// Useful for automatic update checking upon application startup.
|
||||
bool m_silentAsMuchAsItCouldGet;
|
||||
|
||||
// Dialogs (notifications)
|
||||
bool skipVersionAllowed;
|
||||
bool remindLaterAllowed;
|
||||
|
||||
void showErrorDialog(QString message, bool showEvenInSilentMode = false); // Show an error message
|
||||
void showInformationDialog(QString message, bool showEvenInSilentMode = false); // Show an informational message
|
||||
|
||||
|
||||
//
|
||||
// HTTP feed fetcher infrastructure
|
||||
//
|
||||
QUrl m_feedURL; // Feed URL that will be fetched
|
||||
QNetworkAccessManager m_qnam;
|
||||
QNetworkReply* m_reply;
|
||||
int m_httpGetId;
|
||||
bool m_httpRequestAborted;
|
||||
|
||||
void startDownloadFeed(QUrl url); // Start downloading feed
|
||||
void cancelDownloadFeed(); // Stop downloading the current feed
|
||||
|
||||
//
|
||||
// SSL Fingerprint Check infrastructure
|
||||
//
|
||||
QString m_requiredSslFingerprint;
|
||||
|
||||
bool checkSslFingerPrint(QUrl urltoCheck); // true=ssl Fingerprint accepted, false= ssl Fingerprint NOT accepted
|
||||
|
||||
//
|
||||
// Htauth-Infrastructure
|
||||
//
|
||||
QString htAuthUsername;
|
||||
QString htAuthPassword;
|
||||
|
||||
|
||||
//
|
||||
// XML parser
|
||||
//
|
||||
QXmlStreamReader m_xml; // XML data collector and parser
|
||||
bool xmlParseFeed(); // Parse feed in m_xml
|
||||
bool searchDownloadedFeedForUpdates(QString xmlTitle,
|
||||
QString xmlLink,
|
||||
QString xmlReleaseNotesLink,
|
||||
QString xmlPubDate,
|
||||
QString xmlEnclosureUrl,
|
||||
QString xmlEnclosureVersion,
|
||||
QString xmlEnclosurePlatform,
|
||||
unsigned long xmlEnclosureLength,
|
||||
QString xmlEnclosureType);
|
||||
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
void installTranslator(); // Initialize translation mechanism
|
||||
void restartApplication(); // Restarts application after update
|
||||
|
||||
private slots:
|
||||
|
||||
void authenticationRequired ( QNetworkReply * reply, QAuthenticator * authenticator );
|
||||
void httpFeedReadyRead();
|
||||
void httpFeedUpdateDataReadProgress(qint64 bytesRead,
|
||||
qint64 totalBytes);
|
||||
void httpFeedDownloadFinished();
|
||||
|
||||
//
|
||||
// Download and install Update infrastructure
|
||||
//
|
||||
void httpUpdateDownloadFinished();
|
||||
bool unzipUpdate(const QString & filePath, const QString & extDirPath, const QString & singleFileName = QString("")); // returns true on success
|
||||
|
||||
signals:
|
||||
void updatedFinishedSuccessfully();
|
||||
|
||||
};
|
||||
|
||||
#endif // FVUPDATER_H
|
66
interface/external/fervor/fvupdatewindow.cpp
vendored
Executable file
66
interface/external/fervor/fvupdatewindow.cpp
vendored
Executable file
|
@ -0,0 +1,66 @@
|
|||
#include "fvupdatewindow.h"
|
||||
#include "ui_fvupdatewindow.h"
|
||||
#include "fvupdater.h"
|
||||
#include "fvavailableupdate.h"
|
||||
#include <QApplication>
|
||||
#include <QCloseEvent>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
FvUpdateWindow::FvUpdateWindow(QWidget *parent, bool skipVersionAllowed, bool remindLaterAllowed) :
|
||||
QWidget(parent, Qt::CustomizeWindowHint),
|
||||
m_ui(new Ui::FvUpdateWindow)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
m_appIconScene = 0;
|
||||
|
||||
if(!skipVersionAllowed)
|
||||
m_ui->skipThisVersionButton->hide();
|
||||
if(!remindLaterAllowed)
|
||||
m_ui->remindMeLaterButton->hide();
|
||||
|
||||
// Delete on close
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
// Set the "new version is available" string
|
||||
QString newVersString = m_ui->newVersionIsAvailableLabel->text().arg(QApplication::applicationName());
|
||||
m_ui->newVersionIsAvailableLabel->setText(newVersString);
|
||||
|
||||
// Connect buttons
|
||||
connect(m_ui->installUpdateButton, SIGNAL(clicked()),
|
||||
FvUpdater::sharedUpdater(), SLOT(InstallUpdate()));
|
||||
connect(m_ui->skipThisVersionButton, SIGNAL(clicked()),
|
||||
FvUpdater::sharedUpdater(), SLOT(SkipUpdate()));
|
||||
connect(m_ui->remindMeLaterButton, SIGNAL(clicked()),
|
||||
FvUpdater::sharedUpdater(), SLOT(RemindMeLater()));
|
||||
}
|
||||
|
||||
FvUpdateWindow::~FvUpdateWindow()
|
||||
{
|
||||
m_ui->releaseNotesWebView->stop();
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
bool FvUpdateWindow::UpdateWindowWithCurrentProposedUpdate()
|
||||
{
|
||||
FvAvailableUpdate* proposedUpdate = FvUpdater::sharedUpdater()->GetProposedUpdate();
|
||||
if (! proposedUpdate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QString downloadString = m_ui->wouldYouLikeToDownloadLabel->text()
|
||||
.arg(QApplication::applicationName(), proposedUpdate->GetEnclosureVersion(), QApplication::applicationVersion());
|
||||
m_ui->wouldYouLikeToDownloadLabel->setText(downloadString);
|
||||
|
||||
m_ui->releaseNotesWebView->stop();
|
||||
m_ui->releaseNotesWebView->load(proposedUpdate->GetReleaseNotesLink());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FvUpdateWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
FvUpdater::sharedUpdater()->updaterWindowWasClosed();
|
||||
event->accept();
|
||||
}
|
37
interface/external/fervor/fvupdatewindow.h
vendored
Executable file
37
interface/external/fervor/fvupdatewindow.h
vendored
Executable file
|
@ -0,0 +1,37 @@
|
|||
#ifndef FVUPDATEWINDOW_H
|
||||
#define FVUPDATEWINDOW_H
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QtWidgets/QWidget>
|
||||
#else
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
class QGraphicsScene;
|
||||
|
||||
namespace Ui {
|
||||
class FvUpdateWindow;
|
||||
}
|
||||
|
||||
class FvUpdateWindow : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FvUpdateWindow(QWidget *parent, bool skipVersionAllowed, bool remindLaterAllowed);
|
||||
~FvUpdateWindow();
|
||||
|
||||
// Update the current update proposal from FvUpdater
|
||||
bool UpdateWindowWithCurrentProposedUpdate();
|
||||
|
||||
void closeEvent(QCloseEvent* event);
|
||||
|
||||
private:
|
||||
Ui::FvUpdateWindow* m_ui;
|
||||
QGraphicsScene* m_appIconScene;
|
||||
|
||||
};
|
||||
|
||||
#endif // FVUPDATEWINDOW_H
|
||||
|
||||
|
129
interface/external/fervor/fvupdatewindow.ui
vendored
Executable file
129
interface/external/fervor/fvupdatewindow.ui
vendored
Executable file
|
@ -0,0 +1,129 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FvUpdateWindow</class>
|
||||
<widget class="QWidget" name="FvUpdateWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>640</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Software Update</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="newVersionIsAvailableLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>A new version of %1 is available!</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="wouldYouLikeToDownloadLabel">
|
||||
<property name="text">
|
||||
<string>%1 %2 is now available - you have %3. Would you like to download it now?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Release Notes:</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QWebView" name="releaseNotesWebView">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>160</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="url">
|
||||
<url>
|
||||
<string>about:blank</string>
|
||||
</url>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="skipThisVersionButton">
|
||||
<property name="text">
|
||||
<string>Skip This Version</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="remindMeLaterButton">
|
||||
<property name="text">
|
||||
<string>Remind Me Later</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="installUpdateButton">
|
||||
<property name="text">
|
||||
<string>Install Update</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QWebView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>QtWebKit/QWebView</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
164
interface/external/fervor/fvversioncomparator.cpp
vendored
Executable file
164
interface/external/fervor/fvversioncomparator.cpp
vendored
Executable file
|
@ -0,0 +1,164 @@
|
|||
#include "fvversioncomparator.h"
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
//
|
||||
// Clone of Sparkle's SUStandardVersionComparator.m, so here's original author's
|
||||
// copyright too:
|
||||
//
|
||||
// Copyright 2007 Andy Matuschak. All rights reserved.
|
||||
//
|
||||
// Everything's the same except for TypeOfCharacter()
|
||||
// (because who knows how Foundation does isdigit() and such.)
|
||||
//
|
||||
|
||||
|
||||
FvVersionComparator::FvVersionComparator()
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
FvVersionComparator::CharacterType FvVersionComparator::TypeOfCharacter(std::string character)
|
||||
{
|
||||
if (character == ".") {
|
||||
return kSeparatorType;
|
||||
} else if (isdigit(character[0])) {
|
||||
return kNumberType;
|
||||
} else if (isspace(character[0])) {
|
||||
return kSeparatorType;
|
||||
} else if (ispunct(character[0])) {
|
||||
return kSeparatorType;
|
||||
} else {
|
||||
return kStringType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::string> FvVersionComparator::SplitVersionString(std::string version)
|
||||
{
|
||||
std::string character;
|
||||
std::string s;
|
||||
unsigned long i = 0, n = 0;
|
||||
CharacterType oldType, newType;
|
||||
std::vector<std::string> parts;
|
||||
|
||||
if (version.length() == 0) {
|
||||
// Nothing to do here
|
||||
return parts;
|
||||
}
|
||||
|
||||
s = version.substr(0, 1);
|
||||
oldType = TypeOfCharacter(s);
|
||||
n = version.length() - 1;
|
||||
for (i = 1; i <= n; ++i) {
|
||||
character = version.substr(i, 1)[0];
|
||||
newType = TypeOfCharacter(character);
|
||||
if (oldType != newType || oldType == kSeparatorType) {
|
||||
// We've reached a new segment
|
||||
std::string aPart = s;
|
||||
parts.push_back(aPart);
|
||||
s = character;
|
||||
} else {
|
||||
// Add character to string and continue
|
||||
s.append(character);
|
||||
}
|
||||
oldType = newType;
|
||||
}
|
||||
|
||||
// Add the last part onto the array
|
||||
parts.push_back(s);
|
||||
return parts;
|
||||
}
|
||||
|
||||
|
||||
FvVersionComparator::ComparatorResult FvVersionComparator::CompareVersions(std::string versionA,
|
||||
std::string versionB)
|
||||
{
|
||||
std::vector<std::string> partsA = SplitVersionString(versionA);
|
||||
std::vector<std::string> partsB = SplitVersionString(versionB);
|
||||
|
||||
std::string partA = std::string(""), partB = std::string("");
|
||||
unsigned long i = 0, n = 0;
|
||||
int intA, intB;
|
||||
CharacterType typeA, typeB;
|
||||
|
||||
n = std::min(partsA.size(), partsB.size());
|
||||
for (i = 0; i < n; ++i) {
|
||||
partA = partsA.at(i);
|
||||
partB = partsB.at(i);
|
||||
|
||||
typeA = TypeOfCharacter(partA);
|
||||
typeB = TypeOfCharacter(partB);
|
||||
|
||||
// Compare types
|
||||
if (typeA == typeB) {
|
||||
// Same type; we can compare
|
||||
if (typeA == kNumberType) {
|
||||
intA = atoi(partA.c_str());
|
||||
intB = atoi(partB.c_str());
|
||||
|
||||
if (intA > intB) {
|
||||
return kDescending;
|
||||
} else if (intA < intB) {
|
||||
return kAscending;
|
||||
}
|
||||
} else if (typeA == kStringType) {
|
||||
short result = partA.compare(partB);
|
||||
switch (result) {
|
||||
case -1: return kAscending; break;
|
||||
case 1: return kDescending; break;
|
||||
case 0: /* do nothing */ break;
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// Not the same type? Now we have to do some validity checking
|
||||
if (typeA != kStringType && typeB == kStringType) {
|
||||
// typeA wins
|
||||
return kDescending;
|
||||
} else if (typeA == kStringType && typeB != kStringType) {
|
||||
// typeB wins
|
||||
return kAscending;
|
||||
} else {
|
||||
// One is a number and the other is a period. The period is invalid
|
||||
if (typeA == kNumberType) {
|
||||
return kDescending;
|
||||
} else {
|
||||
return kAscending;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The versions are equal up to the point where they both still have parts
|
||||
// Lets check to see if one is larger than the other
|
||||
if (partsA.size() != partsB.size()) {
|
||||
// Yep. Lets get the next part of the larger
|
||||
// n holds the index of the part we want.
|
||||
std::string missingPart = std::string("");
|
||||
CharacterType missingType;
|
||||
ComparatorResult shorterResult, largerResult;
|
||||
|
||||
if (partsA.size() > partsB.size()) {
|
||||
missingPart = partsA.at(n);
|
||||
shorterResult = kAscending;
|
||||
largerResult = kDescending;
|
||||
} else {
|
||||
missingPart = partsB.at(n);
|
||||
shorterResult = kDescending;
|
||||
largerResult = kAscending;
|
||||
}
|
||||
|
||||
missingType = TypeOfCharacter(missingPart);
|
||||
// Check the type
|
||||
if (missingType == kStringType) {
|
||||
// It's a string. Shorter version wins
|
||||
return shorterResult;
|
||||
} else {
|
||||
// It's a number/period. Larger version wins
|
||||
return largerResult;
|
||||
}
|
||||
}
|
||||
|
||||
// The 2 strings are identical
|
||||
return kSame;
|
||||
}
|
36
interface/external/fervor/fvversioncomparator.h
vendored
Executable file
36
interface/external/fervor/fvversioncomparator.h
vendored
Executable file
|
@ -0,0 +1,36 @@
|
|||
#ifndef FVVERSIONCOMPARATOR_H
|
||||
#define FVVERSIONCOMPARATOR_H
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class FvVersionComparator
|
||||
{
|
||||
public:
|
||||
|
||||
typedef enum {
|
||||
kSame = 0,
|
||||
kDescending = 1,
|
||||
kAscending = -1
|
||||
} ComparatorResult;
|
||||
|
||||
static ComparatorResult CompareVersions(std::string versionA,
|
||||
std::string versionB);
|
||||
|
||||
private:
|
||||
|
||||
FvVersionComparator();
|
||||
|
||||
typedef enum {
|
||||
kNumberType,
|
||||
kStringType,
|
||||
kSeparatorType
|
||||
} CharacterType;
|
||||
|
||||
static CharacterType TypeOfCharacter(std::string character);
|
||||
static std::vector<std::string> SplitVersionString(std::string version);
|
||||
|
||||
};
|
||||
|
||||
#endif // FVVERSIONCOMPARATOR_H
|
5
interface/resources/info/ApplicationInfo.ini
Normal file
5
interface/resources/info/ApplicationInfo.ini
Normal file
|
@ -0,0 +1,5 @@
|
|||
[INFO]
|
||||
name=interface
|
||||
version=0.0.1
|
||||
organizationName=High Fidelity
|
||||
organizationDomain=highfidelity.io
|
|
@ -61,6 +61,7 @@
|
|||
#include "Util.h"
|
||||
#include "renderer/ProgramObject.h"
|
||||
#include "ui/TextRenderer.h"
|
||||
#include "fvupdater.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -246,10 +247,28 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
|
||||
_window->setCentralWidget(_glWidget);
|
||||
|
||||
// these are used, for example, to identify the application settings
|
||||
setApplicationName("Interface");
|
||||
setOrganizationDomain("highfidelity.io");
|
||||
setOrganizationName("High Fidelity");
|
||||
#ifdef Q_WS_MAC
|
||||
QString resourcesPath = QCoreApplication::applicationDirPath() + "/../Resources";
|
||||
#else
|
||||
QString resourcesPath = QCoreApplication::applicationDirPath() + "/resources";
|
||||
#endif
|
||||
|
||||
// read the ApplicationInfo.ini file for Name/Version/Domain information
|
||||
QSettings applicationInfo(resourcesPath + "/info/ApplicationInfo.ini", QSettings::IniFormat);
|
||||
|
||||
// set the associated application properties
|
||||
applicationInfo.beginGroup("INFO");
|
||||
|
||||
setApplicationName(applicationInfo.value("name").toString());
|
||||
setApplicationVersion(applicationInfo.value("version").toString());
|
||||
setOrganizationName(applicationInfo.value("organizationName").toString());
|
||||
setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
|
||||
|
||||
#if defined(Q_WS_MAC) && defined(QT_NO_DEBUG)
|
||||
// if this is a release OS X build use fervor to check for an update
|
||||
FvUpdater::sharedUpdater()->SetFeedURL("file:///Users/birarda/Desktop/Appcast.xml");
|
||||
FvUpdater::sharedUpdater()->CheckForUpdatesNotSilent();
|
||||
#endif
|
||||
|
||||
initMenu();
|
||||
|
||||
|
|
Loading…
Reference in a new issue