mirror of
https://github.com/lubosz/overte.git
synced 2025-08-08 04:08:13 +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)
|
endif (APPLE)
|
||||||
|
|
||||||
find_package(Qt4 REQUIRED QtCore QtGui QtNetwork QtOpenGL)
|
find_package(Qt4 REQUIRED QtCore QtGui QtNetwork QtOpenGL QtWebKit)
|
||||||
include(${QT_USE_FILE})
|
include(${QT_USE_FILE})
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}")
|
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
|
# run qt moc on qt-enabled headers
|
||||||
qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h src/Webcam.h)
|
qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h src/Webcam.h)
|
||||||
|
|
||||||
|
@ -108,7 +112,14 @@ include_directories(
|
||||||
${SPEEXDSP_INCLUDE_DIRS}
|
${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)
|
if (APPLE)
|
||||||
# link in required OS X frameworks and include the right GL headers
|
# 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 "Util.h"
|
||||||
#include "renderer/ProgramObject.h"
|
#include "renderer/ProgramObject.h"
|
||||||
#include "ui/TextRenderer.h"
|
#include "ui/TextRenderer.h"
|
||||||
|
#include "fvupdater.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -246,10 +247,28 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
|
|
||||||
_window->setCentralWidget(_glWidget);
|
_window->setCentralWidget(_glWidget);
|
||||||
|
|
||||||
// these are used, for example, to identify the application settings
|
#ifdef Q_WS_MAC
|
||||||
setApplicationName("Interface");
|
QString resourcesPath = QCoreApplication::applicationDirPath() + "/../Resources";
|
||||||
setOrganizationDomain("highfidelity.io");
|
#else
|
||||||
setOrganizationName("High Fidelity");
|
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();
|
initMenu();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue