From a94daf6834f11f6694e01c2f8d5822fd7c61f338 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Fri, 15 Jul 2016 12:00:00 +0300 Subject: [PATCH 1/8] First implementation of Update Notification. --HG-- branch : feature --- src/app/valentina/main.cpp | 8 + src/app/valentina/valentina.pro | 9 + src/libs/fervor/LICENSE | 7 + src/libs/fervor/fervor.pri | 15 + src/libs/fervor/fervor.pro | 107 +++++ src/libs/fervor/fvavailableupdate.cpp | 74 +++ src/libs/fervor/fvavailableupdate.h | 52 +++ src/libs/fervor/fvupdater.cpp | 589 ++++++++++++++++++++++++ src/libs/fervor/fvupdater.h | 128 +++++ src/libs/fervor/fvupdatewindow.cpp | 72 +++ src/libs/fervor/fvupdatewindow.h | 53 +++ src/libs/fervor/fvupdatewindow.ui | 98 ++++ src/libs/ifc/xml/vabstractconverter.cpp | 9 +- src/libs/ifc/xml/vabstractconverter.h | 5 +- src/libs/libs.pro | 3 +- src/libs/vmisc/vcommonsettings.cpp | 13 + src/libs/vmisc/vcommonsettings.h | 8 +- 17 files changed, 1241 insertions(+), 9 deletions(-) create mode 100644 src/libs/fervor/LICENSE create mode 100644 src/libs/fervor/fervor.pri create mode 100644 src/libs/fervor/fervor.pro create mode 100644 src/libs/fervor/fvavailableupdate.cpp create mode 100644 src/libs/fervor/fvavailableupdate.h create mode 100644 src/libs/fervor/fvupdater.cpp create mode 100644 src/libs/fervor/fvupdater.h create mode 100644 src/libs/fervor/fvupdatewindow.cpp create mode 100644 src/libs/fervor/fvupdatewindow.h create mode 100644 src/libs/fervor/fvupdatewindow.ui diff --git a/src/app/valentina/main.cpp b/src/app/valentina/main.cpp index bdc2b26d0..48c3fa982 100644 --- a/src/app/valentina/main.cpp +++ b/src/app/valentina/main.cpp @@ -28,6 +28,8 @@ #include "mainwindow.h" #include "core/vapplication.h" +#include "../fervor/fvupdater.h" + #include // For QT_REQUIRE_VERSION #include @@ -55,6 +57,12 @@ int main(int argc, char *argv[]) app.InitOptions(); + // Set feed URL before doing anything else + FvUpdater::sharedUpdater()->SetFeedURL("http://localhost/updateapp/Appcast.xml"); + + // Check for updates automatically + FvUpdater::sharedUpdater()->CheckForUpdatesSilent(); + MainWindow w; #if !defined(Q_OS_MAC) app.setWindowIcon(QIcon(":/icon/64x64/icon64x64.png")); diff --git a/src/app/valentina/valentina.pro b/src/app/valentina/valentina.pro index f1c0ba838..ede57e369 100644 --- a/src/app/valentina/valentina.pro +++ b/src/app/valentina/valentina.pro @@ -536,6 +536,15 @@ DEPENDPATH += $$PWD/../../libs/vgeometry win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vgeometry/$${DESTDIR}/vgeometry.lib else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vgeometry/$${DESTDIR}/libvgeometry.a +# Fervor static library (depend on VMisc, IFC) +unix|win32: LIBS += -L$$OUT_PWD/../../libs/fervor/$${DESTDIR}/ -lfervor + +INCLUDEPATH += $$PWD/../../libs/fervor +DEPENDPATH += $$PWD/../../libs/fervor + +win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/fervor/$${DESTDIR}/fervor.lib +else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/fervor/$${DESTDIR}/libfervor.a + # IFC static library (depend on QMuParser, VMisc) unix|win32: LIBS += -L$$OUT_PWD/../../libs/ifc/$${DESTDIR}/ -lifc diff --git a/src/libs/fervor/LICENSE b/src/libs/fervor/LICENSE new file mode 100644 index 000000000..d9c310de8 --- /dev/null +++ b/src/libs/fervor/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2012 Linas Valiukas and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/libs/fervor/fervor.pri b/src/libs/fervor/fervor.pri new file mode 100644 index 000000000..2cac3bc15 --- /dev/null +++ b/src/libs/fervor/fervor.pri @@ -0,0 +1,15 @@ +# ADD TO EACH PATH $$PWD VARIABLE!!!!!! +# This need for corect working file translations.pro + +SOURCES += \ + $$PWD/fvupdatewindow.cpp \ + $$PWD/fvupdater.cpp \ + $$PWD/fvavailableupdate.cpp + +HEADERS += \ + $$PWD/fvupdatewindow.h \ + $$PWD/fvupdater.h \ + $$PWD/fvavailableupdate.h + +FORMS += \ + $$PWD/fvupdatewindow.ui diff --git a/src/libs/fervor/fervor.pro b/src/libs/fervor/fervor.pro new file mode 100644 index 000000000..e6a45f916 --- /dev/null +++ b/src/libs/fervor/fervor.pro @@ -0,0 +1,107 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2016-07-14T11:55:03 +# +#------------------------------------------------- + +# File with common stuff for whole project +include(../../../common.pri) + +QT += network widgets + +# Name of library +TARGET = fervor + +# We want to create a library +TEMPLATE = lib + +CONFIG += \ + staticlib \# Making static library + c++11 # We use C++11 standard + +# Use out-of-source builds (shadow builds) +CONFIG -= debug_and_release debug_and_release_target + +# Since Qt 5.4.0 the source code location is recorded only in debug builds. +# We need this information also in release builds. For this need define QT_MESSAGELOGCONTEXT. +DEFINES += QT_MESSAGELOGCONTEXT + +include(fervor.pri) + +# This is static library so no need in "make install" + +# directory for executable file +DESTDIR = bin + +# files created moc +MOC_DIR = moc + +# objecs files +OBJECTS_DIR = obj + +# Directory for files created uic +UI_DIR = uic + +# Set using ccache. Function enable_ccache() defined in common.pri. +$$enable_ccache() + +CONFIG(debug, debug|release){ + # Debug mode + unix { + #Turn on compilers warnings. + *-g++{ + QMAKE_CXXFLAGS += \ + # Key -isystem disable checking errors in system headers. + -isystem "$${OUT_PWD}/$${MOC_DIR}" \ + -isystem "$${OUT_PWD}/$${UI_DIR}" \ + $$GCC_DEBUG_CXXFLAGS # See common.pri for more details. + + noAddressSanitizer{ # For enable run qmake with CONFIG+=noAddressSanitizer + # do nothing + } else { + #gcc’s 4.8.0 Address Sanitizer + #http://blog.qt.digia.com/blog/2013/04/17/using-gccs-4-8-0-address-sanitizer-with-qt/ + QMAKE_CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer + QMAKE_CFLAGS += -fsanitize=address -fno-omit-frame-pointer + QMAKE_LFLAGS += -fsanitize=address + } + } + clang*{ + QMAKE_CXXFLAGS += \ + # Key -isystem disable checking errors in system headers. + -isystem "$${OUT_PWD}/$${MOC_DIR}" \ + -isystem "$${OUT_PWD}/$${UI_DIR}" \ + $$CLANG_DEBUG_CXXFLAGS # See common.pri for more details. + } + *-icc-*{ + QMAKE_CXXFLAGS += \ + -isystem "$${OUT_PWD}/$${MOC_DIR}" \ + -isystem "$${OUT_PWD}/$${UI_DIR}" \ + $$ICC_DEBUG_CXXFLAGS + } + } else { + *-g++{ + QMAKE_CXXFLAGS += $$GCC_DEBUG_CXXFLAGS # See common.pri for more details. + } + } + +}else{ + # Release mode + !win32-msvc*:CONFIG += silent + DEFINES += V_NO_ASSERT + !unix:*-g++{ + QMAKE_CXXFLAGS += -fno-omit-frame-pointer # Need for exchndl.dll + } + + noDebugSymbols{ # For enable run qmake with CONFIG+=noDebugSymbols + # do nothing + } else { + !macx:!win32-msvc*{ + # Turn on debug symbols in release mode on Unix systems. + # On Mac OS X temporarily disabled. TODO: find way how to strip binary file. + QMAKE_CXXFLAGS_RELEASE += -g -gdwarf-3 + QMAKE_CFLAGS_RELEASE += -g -gdwarf-3 + QMAKE_LFLAGS_RELEASE = + } + } +} diff --git a/src/libs/fervor/fvavailableupdate.cpp b/src/libs/fervor/fvavailableupdate.cpp new file mode 100644 index 000000000..daf5e0997 --- /dev/null +++ b/src/libs/fervor/fvavailableupdate.cpp @@ -0,0 +1,74 @@ +/*************************************************************************************************** + ** + ** Copyright (c) 2012 Linas Valiukas and others. + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#include "fvavailableupdate.h" + +//--------------------------------------------------------------------------------------------------------------------- +FvAvailableUpdate::FvAvailableUpdate(QObject *parent) + : QObject(parent), + m_enclosureUrl(), + m_enclosureVersion(), + m_enclosurePlatform() +{ + // noop +} + +//--------------------------------------------------------------------------------------------------------------------- +QUrl FvAvailableUpdate::GetEnclosureUrl() const +{ + return m_enclosureUrl; +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvAvailableUpdate::SetEnclosureUrl(const QUrl &enclosureUrl) +{ + m_enclosureUrl = enclosureUrl; +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvAvailableUpdate::SetEnclosureUrl(const QString &enclosureUrl) +{ + SetEnclosureUrl(QUrl(enclosureUrl)); +} + +//--------------------------------------------------------------------------------------------------------------------- +QString FvAvailableUpdate::GetEnclosureVersion() const +{ + return m_enclosureVersion; +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvAvailableUpdate::SetEnclosureVersion(const QString &enclosureVersion) +{ + m_enclosureVersion = enclosureVersion; +} + +//--------------------------------------------------------------------------------------------------------------------- +QString FvAvailableUpdate::GetEnclosurePlatform() const +{ + return m_enclosurePlatform; +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvAvailableUpdate::SetEnclosurePlatform(const QString &enclosurePlatform) +{ + m_enclosurePlatform = enclosurePlatform; +} diff --git a/src/libs/fervor/fvavailableupdate.h b/src/libs/fervor/fvavailableupdate.h new file mode 100644 index 000000000..7192df064 --- /dev/null +++ b/src/libs/fervor/fvavailableupdate.h @@ -0,0 +1,52 @@ +/*************************************************************************************************** + ** + ** Copyright (c) 2012 Linas Valiukas and others. + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#ifndef FVAVAILABLEUPDATE_H +#define FVAVAILABLEUPDATE_H + +#include +#include + +class FvAvailableUpdate : public QObject +{ + Q_OBJECT +public: + explicit FvAvailableUpdate(QObject *parent = nullptr); + + QUrl GetEnclosureUrl() const; + void SetEnclosureUrl(const QUrl &enclosureUrl); + void SetEnclosureUrl(const QString &enclosureUrl); + + QString GetEnclosureVersion() const; + void SetEnclosureVersion(const QString &enclosureVersion); + + QString GetEnclosurePlatform() const; + void SetEnclosurePlatform(const QString &enclosurePlatform); + +private: + Q_DISABLE_COPY(FvAvailableUpdate) + + QUrl m_enclosureUrl; + QString m_enclosureVersion; + QString m_enclosurePlatform; +}; + +#endif // FVAVAILABLEUPDATE_H diff --git a/src/libs/fervor/fvupdater.cpp b/src/libs/fervor/fvupdater.cpp new file mode 100644 index 000000000..fd41e71e1 --- /dev/null +++ b/src/libs/fervor/fvupdater.cpp @@ -0,0 +1,589 @@ +/*************************************************************************************************** + ** + ** Copyright (c) 2012 Linas Valiukas and others. + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#include "fvupdater.h" +#include "../vmisc/projectversion.h" +#include "../vmisc/vabstractapplication.h" +#include "../ifc/xml/vabstractconverter.h" +#include "../ifc/exception/vexception.h" + +#include +#include +#include +#include + +QPointer FvUpdater::m_Instance; + +//--------------------------------------------------------------------------------------------------------------------- +FvUpdater* FvUpdater::sharedUpdater() +{ + static QMutex mutex; + if (m_Instance.isNull()) + { + mutex.lock(); + + if (m_Instance.isNull()) + { + m_Instance = new FvUpdater; + } + + mutex.unlock(); + } + + return m_Instance.data(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::drop() +{ + static QMutex mutex; + mutex.lock(); + delete m_Instance; + mutex.unlock(); +} + +//--------------------------------------------------------------------------------------------------------------------- +FvUpdater::FvUpdater() + : QObject(nullptr), + m_updaterWindow(nullptr), + m_proposedUpdate(nullptr), + m_silentAsMuchAsItCouldGet(true), + m_feedURL(), + m_qnam(), + m_reply(nullptr), + m_httpRequestAborted(false), + m_xml() +{ + // noop +} + +//--------------------------------------------------------------------------------------------------------------------- +FvUpdater::~FvUpdater() +{ + hideUpdaterWindow(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::showUpdaterWindowUpdatedWithCurrentUpdateProposal() +{ + // Destroy window if already exists + hideUpdaterWindow(); + + // Create a new window + m_updaterWindow = new FvUpdateWindow(qApp->getMainWindow()); + m_updaterWindow->UpdateWindowWithCurrentProposedUpdate(); + m_updaterWindow->show(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::hideUpdaterWindow() +{ + if (m_updaterWindow) + { + m_updaterWindow->close(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::SetFeedURL(const QUrl &feedURL) +{ + m_feedURL = feedURL; +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::SetFeedURL(const QString &feedURL) +{ + SetFeedURL(QUrl(feedURL)); +} + +//--------------------------------------------------------------------------------------------------------------------- +QString FvUpdater::GetFeedURL() const +{ + return m_feedURL.toString(); +} + +//--------------------------------------------------------------------------------------------------------------------- +QPointer FvUpdater::GetProposedUpdate() +{ + return m_proposedUpdate; +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::InstallUpdate() +{ + qDebug() << "Install update"; + + UpdateInstallationConfirmed(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::SkipUpdate() +{ + qDebug() << "Skip update"; + + FvAvailableUpdate* proposedUpdate = GetProposedUpdate(); + if (not proposedUpdate) + { + qWarning() << "Proposed update is NULL (shouldn't be at this point)"; + return; + } + + // Start ignoring this particular version + IgnoreVersion(proposedUpdate->GetEnclosureVersion()); + + hideUpdaterWindow(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::RemindMeLater() +{ + qDebug() << "Remind me later"; + + hideUpdaterWindow(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::UpdateInstallationConfirmed() +{ + qDebug() << "Confirm update installation"; + + QPointer proposedUpdate = GetProposedUpdate(); + if (proposedUpdate.isNull()) + { + qWarning() << "Proposed update is NULL (shouldn't be at this point)"; + return; + } + + // Open a link + if (not QDesktopServices::openUrl(proposedUpdate->GetEnclosureUrl())) + { + showErrorDialog(tr("Unable to open a browser."), true); + return; + } + + hideUpdaterWindow(); +} + +//--------------------------------------------------------------------------------------------------------------------- +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 (QApplication::organizationName().isEmpty()) + { + qCritical() << "QApplication::organizationName is not set. Please do that."; + return false; + } + if (QApplication::organizationDomain().isEmpty()) + { + qCritical() << "QApplication::organizationDomain is not set. Please do that."; + return false; + } + + // Set application name / version is not set yet + if (QApplication::applicationName().isEmpty()) + { + qCritical() << "QApplication::applicationName is not set. Please do that."; + return false; + } + + if (QApplication::applicationVersion().isEmpty()) + { + qCritical() << "QApplication::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(const QUrl &url) +{ + m_xml.clear(); + + QNetworkRequest request; + request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/xml")); + request.setHeader(QNetworkRequest::UserAgentHeader, QApplication::applicationName()); + request.setUrl(url); + + m_reply = m_qnam.get(request); + + connect(m_reply, &QNetworkReply::readyRead, this, &FvUpdater::httpFeedReadyRead); + connect(m_reply, &QNetworkReply::downloadProgress, this, &FvUpdater::httpFeedUpdateDataReadProgress); + connect(m_reply, &QNetworkReply::finished, this, &FvUpdater::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; + } + + const 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 (not redirectionTarget.isNull()) + { + const 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 xmlEnclosureUrl, xmlEnclosureVersion, xmlEnclosurePlatform; + + // Parse + while (not m_xml.atEnd()) + { + m_xml.readNext(); + + if (m_xml.isStartElement()) + { + if (m_xml.name() == QLatin1Literal("item")) + { + xmlEnclosureUrl.clear(); + xmlEnclosureVersion.clear(); + xmlEnclosurePlatform.clear(); + } + else if (m_xml.name() == QLatin1Literal("enclosure")) + { + const QXmlStreamAttributes attribs = m_xml.attributes(); + const QString fervorPlatform = QStringLiteral("fervor:platform"); + + if (attribs.hasAttribute(fervorPlatform)) + { + if (CurrentlyRunningOnPlatform(attribs.value(fervorPlatform).toString().trimmed())) + { + xmlEnclosurePlatform = attribs.value(fervorPlatform).toString().trimmed(); + + const QString attributeUrl = QStringLiteral("url"); + if (attribs.hasAttribute(attributeUrl)) + { + xmlEnclosureUrl = attribs.value(attributeUrl).toString().trimmed(); + } + else + { + xmlEnclosureUrl.clear(); + } + + const QString fervorVersion = QStringLiteral("fervor:version"); + if (attribs.hasAttribute(fervorVersion)) + { + const QString candidateVersion = attribs.value(fervorVersion).toString().trimmed(); + if (not candidateVersion.isEmpty()) + { + xmlEnclosureVersion = candidateVersion; + } + } + } + } + } + } + else if (m_xml.isEndElement()) + { + if (m_xml.name() == QLatin1Literal("item")) + { + // That's it - we have analyzed a single and we'll stop + // here (because the topmost is the most recent one, and thus + // the newest version. + + return searchDownloadedFeedForUpdates(xmlEnclosureUrl, + xmlEnclosureVersion, + xmlEnclosurePlatform); + } + } + + 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; + + } + } + + // No updates were found if we're at this point + // (not a single element found) + showInformationDialog(tr("No updates were found."), false); + + return false; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool FvUpdater::searchDownloadedFeedForUpdates(const QString &xmlEnclosureUrl, + const QString &xmlEnclosureVersion, + const QString &xmlEnclosurePlatform) +{ + qDebug() << "Enclosure URL:" << xmlEnclosureUrl; + qDebug() << "Enclosure version:" << xmlEnclosureVersion; + qDebug() << "Enclosure platform:" << xmlEnclosurePlatform; + + // Validate + if (xmlEnclosureUrl.isEmpty() || xmlEnclosureVersion.isEmpty() || xmlEnclosurePlatform.isEmpty()) + { + showErrorDialog(tr("Feed error: invalid \"enclosure\" with the download link"), false); + return false; + } + + // Relevant version? + if (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 = new FvAvailableUpdate(this); + m_proposedUpdate->SetEnclosureUrl(xmlEnclosureUrl); + m_proposedUpdate->SetEnclosureVersion(xmlEnclosureVersion); + m_proposedUpdate->SetEnclosurePlatform(xmlEnclosurePlatform); + + // Show "look, there's an update" window + showUpdaterWindowUpdatedWithCurrentUpdateProposal(); + + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool FvUpdater::VersionIsIgnored(const 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. + + int decVersion = 0x0; + try + { + decVersion = VAbstractConverter::GetVersion(version); + } + catch (const VException &e) + { + Q_UNUSED(e) + return true; // Ignore invalid version + } + + if (decVersion == APP_VERSION) + { + return true; + } + + const int lastSkippedVersion = qApp->Settings()->GetLatestSkippedVersion(); + if (lastSkippedVersion != 0x0) + { + if (decVersion == lastSkippedVersion) + { + // Implicitly skipped version - skip + return true; + } + } + + if (decVersion > APP_VERSION) + { + // Newer version - do not skip + return false; + } + + // Fallback - skip + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::IgnoreVersion(const QString &version) +{ + int decVersion = 0x0; + try + { + decVersion = VAbstractConverter::GetVersion(version); + } + catch (const VException &e) + { + Q_UNUSED(e) + return ; // Ignore invalid version + } + + if (decVersion == APP_VERSION) + { + // Don't ignore the current version + return; + } + + qApp->Settings()->SetLatestSkippedVersion(decVersion); +} + +//--------------------------------------------------------------------------------------------------------------------- +bool FvUpdater::CurrentlyRunningOnPlatform(const QString &platform) +{ + const QStringList platforms = QStringList() << "Q_OS_LINUX" + << "Q_OS_MAC" + << "Q_OS_WIN32"; + + switch (platforms.indexOf(platform.toUpper().trimmed())) + { + case 0: // Q_OS_LINUX +#ifdef Q_OS_LINUX // Defined on Linux. + return true; +#endif + break; + case 1: // Q_OS_MAC +#ifdef Q_OS_MAC // Defined on MAC OS (synonym for Darwin). + return true; +#endif + break; + case 2: // Q_OS_WIN32 +#ifdef Q_OS_WIN32 // Defined on all supported versions of Windows. + return true; +#endif + break; + default: + break; + } + + // Fallback + return false; +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::showErrorDialog(const QString &message, bool showEvenInSilentMode) +{ + if (m_silentAsMuchAsItCouldGet) + { + if (not showEvenInSilentMode) + { + // Don't show errors in the silent mode + return; + } + } + + QMessageBox dlFailedMsgBox; + dlFailedMsgBox.setIcon(QMessageBox::Critical); + dlFailedMsgBox.setText(tr("Error")); + dlFailedMsgBox.setInformativeText(message); + dlFailedMsgBox.exec(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void FvUpdater::showInformationDialog(const QString &message, bool showEvenInSilentMode) +{ + if (m_silentAsMuchAsItCouldGet) + { + if (not showEvenInSilentMode) + { + // Don't show information dialogs in the silent mode + return; + } + } + + QMessageBox dlInformationMsgBox; + dlInformationMsgBox.setIcon(QMessageBox::Information); + dlInformationMsgBox.setText(tr("Information")); + dlInformationMsgBox.setInformativeText(message); + dlInformationMsgBox.exec(); +} diff --git a/src/libs/fervor/fvupdater.h b/src/libs/fervor/fvupdater.h new file mode 100644 index 000000000..0191ae589 --- /dev/null +++ b/src/libs/fervor/fvupdater.h @@ -0,0 +1,128 @@ +/*************************************************************************************************** + ** + ** Copyright (c) 2012 Linas Valiukas and others. + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#ifndef FVUPDATER_H +#define FVUPDATER_H + +#include +#include +#include +#include +#include +#include + +#include "fvupdatewindow.h" +#include "fvavailableupdate.h" + +class FvUpdater : public QObject +{ + Q_OBJECT + +public: + // Singleton + static FvUpdater* sharedUpdater(); + static void drop(); + + // Set / get feed URL + void SetFeedURL(const QUrl &feedURL); + void SetFeedURL(const QString &feedURL); + QString GetFeedURL() const; + +public slots: + // Check for updates + bool CheckForUpdates(bool silentAsMuchAsItCouldGet = true); + + // Aliases + bool CheckForUpdatesSilent(); + bool CheckForUpdatesNotSilent(); + +protected: + friend class FvUpdateWindow; // Uses GetProposedUpdate() and others + QPointer GetProposedUpdate(); + +protected slots: + // Update window button slots + void InstallUpdate(); + void SkipUpdate(); + void RemindMeLater(); + + // Update confirmation dialog button slots + void UpdateInstallationConfirmed(); + +private slots: + void httpFeedReadyRead(); + void httpFeedUpdateDataReadProgress(qint64 bytesRead, qint64 totalBytes); + void httpFeedDownloadFinished(); + +private: + // + // Singleton business + // + Q_DISABLE_COPY(FvUpdater) + FvUpdater(); // Hide main constructor + virtual ~FvUpdater(); // Hide main destructor + + static QPointer m_Instance; // Singleton instance + + QPointer m_updaterWindow; // Updater window (NULL if not shown) + + // Available update (NULL if not fetched) + QPointer 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; + + // + // HTTP feed fetcher infrastructure + // + QUrl m_feedURL; // Feed URL that will be fetched + QNetworkAccessManager m_qnam; + QNetworkReply* m_reply; + bool m_httpRequestAborted; + + QXmlStreamReader m_xml; // XML data collector and parser + + void showUpdaterWindowUpdatedWithCurrentUpdateProposal(); // Show updater window + void hideUpdaterWindow(); // Hide + destroy m_updaterWindow + + void startDownloadFeed(const QUrl &url); // Start downloading feed + void cancelDownloadFeed(); // Stop downloading the current feed + + // Dialogs (notifications) + // Show an error message + void showErrorDialog(const QString &message, bool showEvenInSilentMode = false); + // Show an informational message + void showInformationDialog(const QString &message, bool showEvenInSilentMode = false); + + + bool xmlParseFeed(); // Parse feed in m_xml + bool searchDownloadedFeedForUpdates(const QString &xmlEnclosureUrl, + const QString &xmlEnclosureVersion, + const QString &xmlEnclosurePlatform); + + static bool VersionIsIgnored(const QString &version); + static void IgnoreVersion(const QString &version); + static bool CurrentlyRunningOnPlatform(const QString &platform); +}; + +#endif // FVUPDATER_H diff --git a/src/libs/fervor/fvupdatewindow.cpp b/src/libs/fervor/fvupdatewindow.cpp new file mode 100644 index 000000000..16525e05e --- /dev/null +++ b/src/libs/fervor/fvupdatewindow.cpp @@ -0,0 +1,72 @@ +/*************************************************************************************************** + ** + ** Copyright (c) 2012 Linas Valiukas and others. + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#include "fvupdatewindow.h" +#include "ui_fvupdatewindow.h" +#include "fvupdater.h" +#include "fvavailableupdate.h" + +#include +#include +#include + +//--------------------------------------------------------------------------------------------------------------------- +FvUpdateWindow::FvUpdateWindow(QWidget *parent) + : QDialog(parent), + m_ui(new Ui::FvUpdateWindow), + m_appIconScene(nullptr) +{ + m_ui->setupUi(this); + + // Delete on close + setAttribute(Qt::WA_DeleteOnClose, true); + + // Set the "new version is available" string + const QString newVersString = m_ui->newVersionIsAvailableLabel->text().arg(qApp->applicationDisplayName()); + m_ui->newVersionIsAvailableLabel->setText(newVersString); + + // Connect buttons + connect(m_ui->installUpdateButton, &QPushButton::clicked, FvUpdater::sharedUpdater(), &FvUpdater::InstallUpdate); + connect(m_ui->skipThisVersionButton, &QPushButton::clicked, FvUpdater::sharedUpdater(), &FvUpdater::SkipUpdate); + connect(m_ui->remindMeLaterButton, &QPushButton::clicked, FvUpdater::sharedUpdater(), &FvUpdater::RemindMeLater); +} + +//--------------------------------------------------------------------------------------------------------------------- +FvUpdateWindow::~FvUpdateWindow() +{ + delete m_ui; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool FvUpdateWindow::UpdateWindowWithCurrentProposedUpdate() +{ + QPointer proposedUpdate = FvUpdater::sharedUpdater()->GetProposedUpdate(); + if (proposedUpdate.isNull()) + { + return false; + } + + const QString downloadString = m_ui->wouldYouLikeToDownloadLabel->text() + .arg(qApp->applicationDisplayName(), proposedUpdate->GetEnclosureVersion(), qApp->applicationVersion()); + m_ui->wouldYouLikeToDownloadLabel->setText(downloadString); + + return true; +} diff --git a/src/libs/fervor/fvupdatewindow.h b/src/libs/fervor/fvupdatewindow.h new file mode 100644 index 000000000..37cbacd4c --- /dev/null +++ b/src/libs/fervor/fvupdatewindow.h @@ -0,0 +1,53 @@ +/*************************************************************************************************** + ** + ** Copyright (c) 2012 Linas Valiukas and others. + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#ifndef FVUPDATEWINDOW_H +#define FVUPDATEWINDOW_H + +#include + +class QGraphicsScene; + +namespace Ui +{ + class FvUpdateWindow; +} + +class FvUpdateWindow : public QDialog +{ + Q_OBJECT + +public: + explicit FvUpdateWindow(QWidget *parent = nullptr); + virtual ~FvUpdateWindow(); + + // Update the current update proposal from FvUpdater + bool UpdateWindowWithCurrentProposedUpdate(); + +private: + Q_DISABLE_COPY(FvUpdateWindow) + + Ui::FvUpdateWindow* m_ui; + QGraphicsScene* m_appIconScene; + +}; + +#endif // FVUPDATEWINDOW_H diff --git a/src/libs/fervor/fvupdatewindow.ui b/src/libs/fervor/fvupdatewindow.ui new file mode 100644 index 000000000..da38a53f5 --- /dev/null +++ b/src/libs/fervor/fvupdatewindow.ui @@ -0,0 +1,98 @@ + + + FvUpdateWindow + + + + 0 + 0 + 520 + 95 + + + + Software Update + + + + :/icon/64x64/icon64x64.png:/icon/64x64/icon64x64.png + + + + + + + + + 75 + true + + + + A new version of %1 is available! + + + + + + + %1 %2 is now available - you have %3. Would you like to download it now? + + + + + + + + + Skip This Version + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Remind Me Later + + + + + + + + + + Get Update + + + true + + + true + + + + + + + + + + + + + + diff --git a/src/libs/ifc/xml/vabstractconverter.cpp b/src/libs/ifc/xml/vabstractconverter.cpp index 2c89eda77..079da3610 100644 --- a/src/libs/ifc/xml/vabstractconverter.cpp +++ b/src/libs/ifc/xml/vabstractconverter.cpp @@ -33,6 +33,7 @@ #include #include #include +#include //--------------------------------------------------------------------------------------------------------------------- VAbstractConverter::VAbstractConverter(const QString &fileName) @@ -107,7 +108,7 @@ QString VAbstractConverter::GetVersionStr() const } //--------------------------------------------------------------------------------------------------------------------- -int VAbstractConverter::GetVersion(const QString &version) const +int VAbstractConverter::GetVersion(const QString &version) { ValidateVersion(version); @@ -138,11 +139,11 @@ int VAbstractConverter::GetVersion(const QString &version) const } //--------------------------------------------------------------------------------------------------------------------- -void VAbstractConverter::ValidateVersion(const QString &version) const +void VAbstractConverter::ValidateVersion(const QString &version) { - const QRegExp rx(QStringLiteral("^(0|([1-9][0-9]*)).(0|([1-9][0-9]*)).(0|([1-9][0-9]*))$")); + const QRegularExpression rx(QStringLiteral("^(0|([1-9][0-9]*)).(0|([1-9][0-9]*)).(0|([1-9][0-9]*))$")); - if (rx.exactMatch(version) == false) + if (rx.match(version).hasMatch() == false) { const QString errorMsg(tr("Version \"%1\" invalid.").arg(version)); throw VException(errorMsg); diff --git a/src/libs/ifc/xml/vabstractconverter.h b/src/libs/ifc/xml/vabstractconverter.h index 5a3060664..6a7a28992 100644 --- a/src/libs/ifc/xml/vabstractconverter.h +++ b/src/libs/ifc/xml/vabstractconverter.h @@ -43,12 +43,13 @@ public: void Convert(); virtual bool SaveDocument(const QString &fileName, QString &error) const Q_DECL_OVERRIDE; + static int GetVersion(const QString &version); + protected: int ver; QString fileName; void ValidateInputFile(const QString ¤tSchema) const; - int GetVersion(const QString &version) const; Q_NORETURN void InvalidVersion(int ver) const; void Save() const; void SetVersion(const QString &version); @@ -72,7 +73,7 @@ private: QString GetVersionStr() const; - void ValidateVersion(const QString &version) const; + static void ValidateVersion(const QString &version); void ReserveFile() const; }; diff --git a/src/libs/libs.pro b/src/libs/libs.pro index af365e150..334d77b84 100644 --- a/src/libs/libs.pro +++ b/src/libs/libs.pro @@ -11,4 +11,5 @@ SUBDIRS = \ vmisc \ vwidgets \ vtools \ - vformat + vformat \ + fervor diff --git a/src/libs/vmisc/vcommonsettings.cpp b/src/libs/vmisc/vcommonsettings.cpp index 82daa3b75..5c8686b78 100644 --- a/src/libs/vmisc/vcommonsettings.cpp +++ b/src/libs/vmisc/vcommonsettings.cpp @@ -65,6 +65,7 @@ const QString VCommonSettings::SettingGeneralGeometry = QString const QString VCommonSettings::SettingGeneralWindowState = QStringLiteral("windowState"); const QString VCommonSettings::SettingGeneralToolbarsState = QStringLiteral("toolbarsState"); const QString VCommonSettings::SettingPreferenceDialogSize = QStringLiteral("preferenceDialogSize"); +const QString VCommonSettings::SettingLatestSkippedVersion = QStringLiteral("lastestSkippedVersion"); static const QString commonIniFilename = QStringLiteral("common"); @@ -429,3 +430,15 @@ void VCommonSettings::SetPreferenceDialogSize(const QSize& sz) { setValue(SettingPreferenceDialogSize, sz); } + +//--------------------------------------------------------------------------------------------------------------------- +int VCommonSettings::GetLatestSkippedVersion() const +{ + return value(SettingLatestSkippedVersion, 0x0).toInt(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VCommonSettings::SetLatestSkippedVersion(int value) +{ + setValue(SettingLatestSkippedVersion, value); +} diff --git a/src/libs/vmisc/vcommonsettings.h b/src/libs/vmisc/vcommonsettings.h index d8e516282..42d954348 100644 --- a/src/libs/vmisc/vcommonsettings.h +++ b/src/libs/vmisc/vcommonsettings.h @@ -99,8 +99,11 @@ public: QByteArray GetToolbarsState() const; void SetToolbarsState(const QByteArray &value); - QSize GetPreferenceDialogSize() const; - void SetPreferenceDialogSize(const QSize& sz); + QSize GetPreferenceDialogSize() const; + void SetPreferenceDialogSize(const QSize& sz); + + int GetLatestSkippedVersion() const; + void SetLatestSkippedVersion(int value); private: Q_DISABLE_COPY(VCommonSettings) @@ -128,6 +131,7 @@ private: static const QString SettingGeneralWindowState; static const QString SettingGeneralToolbarsState; static const QString SettingPreferenceDialogSize; + static const QString SettingLatestSkippedVersion; }; #endif // VCOMMONSETTINGS_H From 1e6dc7c0a826522cf6c208e91c5a2bf66545ad5b Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Fri, 15 Jul 2016 12:03:19 +0300 Subject: [PATCH 2/8] Use QPointer class. --HG-- branch : feature --- src/libs/fervor/fvupdater.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/fervor/fvupdater.cpp b/src/libs/fervor/fvupdater.cpp index fd41e71e1..00a10f146 100644 --- a/src/libs/fervor/fvupdater.cpp +++ b/src/libs/fervor/fvupdater.cpp @@ -139,8 +139,8 @@ void FvUpdater::SkipUpdate() { qDebug() << "Skip update"; - FvAvailableUpdate* proposedUpdate = GetProposedUpdate(); - if (not proposedUpdate) + QPointer proposedUpdate = GetProposedUpdate(); + if (proposedUpdate.isNull()) { qWarning() << "Proposed update is NULL (shouldn't be at this point)"; return; From d61c1c13bfe39c4eadc03a40b09fe6c1c8fba797 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Fri, 15 Jul 2016 12:30:55 +0300 Subject: [PATCH 3/8] Check one day and try remind again. --HG-- branch : feature --- src/libs/fervor/fvupdater.cpp | 11 ++++++++++- src/libs/vmisc/vcommonsettings.cpp | 14 ++++++++++++++ src/libs/vmisc/vcommonsettings.h | 4 ++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/libs/fervor/fvupdater.cpp b/src/libs/fervor/fvupdater.cpp index 00a10f146..9e7f3adfd 100644 --- a/src/libs/fervor/fvupdater.cpp +++ b/src/libs/fervor/fvupdater.cpp @@ -157,6 +157,8 @@ void FvUpdater::RemindMeLater() { qDebug() << "Remind me later"; + qApp->Settings()->SetDateOfLastRemind(QDate::currentDate()); + hideUpdaterWindow(); } @@ -229,7 +231,14 @@ bool FvUpdater::CheckForUpdates(bool silentAsMuchAsItCouldGet) //--------------------------------------------------------------------------------------------------------------------- bool FvUpdater::CheckForUpdatesSilent() { - return CheckForUpdates(true); + if (qApp->Settings()->GetDateOfLastRemind().daysTo(QDate::currentDate()) >= 1) + { + return CheckForUpdates(true); + } + else + { + return true; + } } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/vmisc/vcommonsettings.cpp b/src/libs/vmisc/vcommonsettings.cpp index 5c8686b78..a21ded0e7 100644 --- a/src/libs/vmisc/vcommonsettings.cpp +++ b/src/libs/vmisc/vcommonsettings.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "../ifc/ifcdef.h" @@ -66,6 +67,7 @@ const QString VCommonSettings::SettingGeneralWindowState = QString const QString VCommonSettings::SettingGeneralToolbarsState = QStringLiteral("toolbarsState"); const QString VCommonSettings::SettingPreferenceDialogSize = QStringLiteral("preferenceDialogSize"); const QString VCommonSettings::SettingLatestSkippedVersion = QStringLiteral("lastestSkippedVersion"); +const QString VCommonSettings::SettingDateOfLastRemind = QStringLiteral("dateOfLastRemind"); static const QString commonIniFilename = QStringLiteral("common"); @@ -442,3 +444,15 @@ void VCommonSettings::SetLatestSkippedVersion(int value) { setValue(SettingLatestSkippedVersion, value); } + +//--------------------------------------------------------------------------------------------------------------------- +QDate VCommonSettings::GetDateOfLastRemind() const +{ + return value(SettingDateOfLastRemind, QDate(1900, 1, 1)).toDate(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VCommonSettings::SetDateOfLastRemind(const QDate &date) +{ + setValue(SettingDateOfLastRemind, date); +} diff --git a/src/libs/vmisc/vcommonsettings.h b/src/libs/vmisc/vcommonsettings.h index 42d954348..0755b11a1 100644 --- a/src/libs/vmisc/vcommonsettings.h +++ b/src/libs/vmisc/vcommonsettings.h @@ -105,6 +105,9 @@ public: int GetLatestSkippedVersion() const; void SetLatestSkippedVersion(int value); + QDate GetDateOfLastRemind() const; + void SetDateOfLastRemind(const QDate &date); + private: Q_DISABLE_COPY(VCommonSettings) @@ -132,6 +135,7 @@ private: static const QString SettingGeneralToolbarsState; static const QString SettingPreferenceDialogSize; static const QString SettingLatestSkippedVersion; + static const QString SettingDateOfLastRemind; }; #endif // VCOMMONSETTINGS_H From faae90363ebf260074f7ea409f5cd1aef13981ad Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Fri, 15 Jul 2016 13:14:48 +0300 Subject: [PATCH 4/8] Show button "Check For Updates" in dialogs about Valentina and Tape. Move settings to common file. --HG-- branch : feature --- src/app/tape/dialogs/dialogabouttape.cpp | 20 +++++----- src/app/tape/dialogs/dialogabouttape.h | 10 ++--- src/app/tape/dialogs/dialogabouttape.ui | 41 +++++++++++++------- src/app/tape/main.cpp | 4 ++ src/app/tape/tape.pro | 9 +++++ src/app/valentina/dialogs/dialogaboutapp.cpp | 25 ++++++------ src/app/valentina/dialogs/dialogaboutapp.h | 7 +--- src/app/valentina/dialogs/dialogaboutapp.ui | 39 ++++++++++++------- src/app/valentina/main.cpp | 11 ++++-- src/libs/fervor/fvupdater.cpp | 4 +- src/libs/fervor/fvupdater.h | 2 + src/libs/vmisc/vcommonsettings.cpp | 14 +++++-- 12 files changed, 113 insertions(+), 73 deletions(-) diff --git a/src/app/tape/dialogs/dialogabouttape.cpp b/src/app/tape/dialogs/dialogabouttape.cpp index 841d0c9f1..5c282bd9b 100644 --- a/src/app/tape/dialogs/dialogabouttape.cpp +++ b/src/app/tape/dialogs/dialogabouttape.cpp @@ -30,6 +30,7 @@ #include "ui_dialogabouttape.h" #include "../version.h" #include "../vmisc/def.h" +#include "../fervor/fvupdater.h" #include #include @@ -49,8 +50,16 @@ DialogAboutTape::DialogAboutTape(QWidget *parent) //mApp->Settings()->GetOsSeparator() ? setLocale(QLocale::system()) : setLocale(QLocale(QLocale::C)); RetranslateUi(); - connect(ui->pushButton_Web_Site, &QPushButton::clicked, this, &DialogAboutTape::WebButtonClicked); + connect(ui->pushButton_Web_Site, &QPushButton::clicked, [this](){ + if ( QDesktopServices::openUrl(QUrl(VER_COMPANYDOMAIN_STR)) == false) + { + qWarning() << tr("Cannot open your default browser"); + } + }); connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &DialogAboutTape::close); + connect(ui->pushButtonCheckUpdate, &QPushButton::clicked, [](){ + FvUpdater::sharedUpdater()->CheckForUpdatesNotSilent(); + }); // By default on Windows font point size 8 points we need 11 like on Linux. FontPointSize(ui->label_Legal_Stuff, 11); @@ -99,15 +108,6 @@ void DialogAboutTape::showEvent(QShowEvent *event) isInitialized = true;//first show windows are held } -//--------------------------------------------------------------------------------------------------------------------- -void DialogAboutTape::WebButtonClicked() -{ - if ( QDesktopServices::openUrl(QUrl(VER_COMPANYDOMAIN_STR)) == false) - { - qWarning() << tr("Cannot open your default browser"); - } -} - //--------------------------------------------------------------------------------------------------------------------- void DialogAboutTape::FontPointSize(QWidget *w, int pointSize) { diff --git a/src/app/tape/dialogs/dialogabouttape.h b/src/app/tape/dialogs/dialogabouttape.h index 64039ed04..286f7e2af 100644 --- a/src/app/tape/dialogs/dialogabouttape.h +++ b/src/app/tape/dialogs/dialogabouttape.h @@ -31,8 +31,9 @@ #include -namespace Ui { -class DialogAboutTape; +namespace Ui +{ + class DialogAboutTape; } class DialogAboutTape : public QDialog @@ -40,16 +41,13 @@ class DialogAboutTape : public QDialog Q_OBJECT public: - explicit DialogAboutTape(QWidget *parent = 0); + explicit DialogAboutTape(QWidget *parent = nullptr); virtual ~DialogAboutTape(); protected: virtual void changeEvent(QEvent* event) Q_DECL_OVERRIDE; virtual void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; -private slots: - void WebButtonClicked(); - private: Q_DISABLE_COPY(DialogAboutTape) Ui::DialogAboutTape *ui; diff --git a/src/app/tape/dialogs/dialogabouttape.ui b/src/app/tape/dialogs/dialogabouttape.ui index 5a00d3df0..e070f0d65 100644 --- a/src/app/tape/dialogs/dialogabouttape.ui +++ b/src/app/tape/dialogs/dialogabouttape.ui @@ -6,7 +6,7 @@ 0 0 - 559 + 376 320 @@ -248,20 +248,31 @@ - - - true - - - Qt::Horizontal - - - QDialogButtonBox::Ok - - - true - - + + + + + Check For Updates + + + + + + + true + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + false + + + + diff --git a/src/app/tape/main.cpp b/src/app/tape/main.cpp index d1ef6b158..42e1d5e4f 100644 --- a/src/app/tape/main.cpp +++ b/src/app/tape/main.cpp @@ -28,6 +28,7 @@ #include "tmainwindow.h" #include "mapplication.h" +#include "../fervor/fvupdater.h" #include // For QT_REQUIRE_VERSION #include @@ -51,6 +52,9 @@ int main(int argc, char *argv[]) MApplication app(argc, argv); app.InitOptions(); + // Set feed URL before doing anything else + FvUpdater::sharedUpdater()->SetFeedURL(defaultFeedURL); + QTimer::singleShot(0, &app, SLOT(ProcessCMD())); return app.exec(); diff --git a/src/app/tape/tape.pro b/src/app/tape/tape.pro index a04fbeb47..75325edc0 100644 --- a/src/app/tape/tape.pro +++ b/src/app/tape/tape.pro @@ -401,6 +401,15 @@ DEPENDPATH += $$PWD/../../libs/vpatterndb win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vpatterndb/$${DESTDIR}/vpatterndb.lib else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/vpatterndb/$${DESTDIR}/libvpatterndb.a +# Fervor static library (depend on VMisc, IFC) +unix|win32: LIBS += -L$$OUT_PWD/../../libs/fervor/$${DESTDIR}/ -lfervor + +INCLUDEPATH += $$PWD/../../libs/fervor +DEPENDPATH += $$PWD/../../libs/fervor + +win32:!win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/fervor/$${DESTDIR}/fervor.lib +else:unix|win32-g++: PRE_TARGETDEPS += $$OUT_PWD/../../libs/fervor/$${DESTDIR}/libfervor.a + #VMisc static library unix|win32: LIBS += -L$$OUT_PWD/../../libs/vmisc/$${DESTDIR}/ -lvmisc diff --git a/src/app/valentina/dialogs/dialogaboutapp.cpp b/src/app/valentina/dialogs/dialogaboutapp.cpp index 7081726ff..3379cafb3 100644 --- a/src/app/valentina/dialogs/dialogaboutapp.cpp +++ b/src/app/valentina/dialogs/dialogaboutapp.cpp @@ -35,6 +35,7 @@ #include #include "../options.h" #include "../core/vapplication.h" +#include "../fervor/fvupdater.h" //--------------------------------------------------------------------------------------------------------------------- DialogAboutApp::DialogAboutApp(QWidget *parent) : @@ -60,7 +61,16 @@ DialogAboutApp::DialogAboutApp(QWidget *parent) : ui->pushButton_Web_Site->setText(tr("Web site : %1").arg(VER_COMPANYDOMAIN_STR)); - connect(ui->pushButton_Web_Site, &QPushButton::clicked, this, &DialogAboutApp::webButtonClicked ); + connect(ui->pushButton_Web_Site, &QPushButton::clicked, [this](){ + if ( QDesktopServices::openUrl(QUrl(VER_COMPANYDOMAIN_STR)) == false) + { + qWarning() << tr("Cannot open your default browser"); + } + }); + + connect(ui->pushButtonCheckUpdate, &QPushButton::clicked, [](){ + FvUpdater::sharedUpdater()->CheckForUpdatesNotSilent(); + }); // By default on Windows font point size 8 points we need 11 like on Linux. FontPointSize(ui->label_Legal_Stuff, 11); @@ -105,16 +115,3 @@ void DialogAboutApp::FontPointSize(QWidget *w, int pointSize) font.setPointSize(pointSize); w->setFont(font); } - -//--------------------------------------------------------------------------------------------------------------------- -/** - * @brief Fake button clicked - */ -void DialogAboutApp::webButtonClicked() -{ - if ( QDesktopServices::openUrl(QUrl(VER_COMPANYDOMAIN_STR)) == false) - { - qWarning() << tr("Cannot open your default browser"); - } - -} diff --git a/src/app/valentina/dialogs/dialogaboutapp.h b/src/app/valentina/dialogs/dialogaboutapp.h index 5e8ce6b17..e635be942 100644 --- a/src/app/valentina/dialogs/dialogaboutapp.h +++ b/src/app/valentina/dialogs/dialogaboutapp.h @@ -41,8 +41,8 @@ class DialogAboutApp : public QDialog Q_OBJECT public: - explicit DialogAboutApp(QWidget *parent = 0); - ~DialogAboutApp(); + explicit DialogAboutApp(QWidget *parent = nullptr); + virtual ~DialogAboutApp(); protected: virtual void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; @@ -53,9 +53,6 @@ private: Q_DISABLE_COPY(DialogAboutApp) void FontPointSize(QWidget *w, int pointSize); - -private slots: - void webButtonClicked(); }; #endif // DIALOGABOUTAPP_H diff --git a/src/app/valentina/dialogs/dialogaboutapp.ui b/src/app/valentina/dialogs/dialogaboutapp.ui index 6b6ae2a24..dfa407174 100644 --- a/src/app/valentina/dialogs/dialogaboutapp.ui +++ b/src/app/valentina/dialogs/dialogaboutapp.ui @@ -294,20 +294,31 @@ Bettina Gatzlaff - - - true - - - Qt::Horizontal - - - QDialogButtonBox::Ok - - - true - - + + + + + Check For Updates + + + + + + + true + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + false + + + + diff --git a/src/app/valentina/main.cpp b/src/app/valentina/main.cpp index 48c3fa982..353e33aae 100644 --- a/src/app/valentina/main.cpp +++ b/src/app/valentina/main.cpp @@ -57,11 +57,14 @@ int main(int argc, char *argv[]) app.InitOptions(); - // Set feed URL before doing anything else - FvUpdater::sharedUpdater()->SetFeedURL("http://localhost/updateapp/Appcast.xml"); + if (VApplication::IsGUIMode()) + { + // Set feed URL before doing anything else + FvUpdater::sharedUpdater()->SetFeedURL(defaultFeedURL); - // Check for updates automatically - FvUpdater::sharedUpdater()->CheckForUpdatesSilent(); + // Check for updates automatically + FvUpdater::sharedUpdater()->CheckForUpdatesSilent(); + } MainWindow w; #if !defined(Q_OS_MAC) diff --git a/src/libs/fervor/fvupdater.cpp b/src/libs/fervor/fvupdater.cpp index 9e7f3adfd..b215a5957 100644 --- a/src/libs/fervor/fvupdater.cpp +++ b/src/libs/fervor/fvupdater.cpp @@ -30,6 +30,8 @@ #include #include +const QString defaultFeedURL = QStringLiteral("http://localhost/updateapp/Appcast.xml"); + QPointer FvUpdater::m_Instance; //--------------------------------------------------------------------------------------------------------------------- @@ -177,7 +179,7 @@ void FvUpdater::UpdateInstallationConfirmed() // Open a link if (not QDesktopServices::openUrl(proposedUpdate->GetEnclosureUrl())) { - showErrorDialog(tr("Unable to open a browser."), true); + showErrorDialog(tr("Cannot open your default browser."), true); return; } diff --git a/src/libs/fervor/fvupdater.h b/src/libs/fervor/fvupdater.h index 0191ae589..f6021f25b 100644 --- a/src/libs/fervor/fvupdater.h +++ b/src/libs/fervor/fvupdater.h @@ -32,6 +32,8 @@ #include "fvupdatewindow.h" #include "fvavailableupdate.h" +extern const QString defaultFeedURL; + class FvUpdater : public QObject { Q_OBJECT diff --git a/src/libs/vmisc/vcommonsettings.cpp b/src/libs/vmisc/vcommonsettings.cpp index a21ded0e7..179754b4e 100644 --- a/src/libs/vmisc/vcommonsettings.cpp +++ b/src/libs/vmisc/vcommonsettings.cpp @@ -436,23 +436,29 @@ void VCommonSettings::SetPreferenceDialogSize(const QSize& sz) //--------------------------------------------------------------------------------------------------------------------- int VCommonSettings::GetLatestSkippedVersion() const { - return value(SettingLatestSkippedVersion, 0x0).toInt(); + QSettings settings(this->format(), this->scope(), this->organizationName(), commonIniFilename); + return settings.value(SettingLatestSkippedVersion, 0x0).toInt(); } //--------------------------------------------------------------------------------------------------------------------- void VCommonSettings::SetLatestSkippedVersion(int value) { - setValue(SettingLatestSkippedVersion, value); + QSettings settings(this->format(), this->scope(), this->organizationName(), commonIniFilename); + settings.setValue(SettingLatestSkippedVersion, value); + settings.sync(); } //--------------------------------------------------------------------------------------------------------------------- QDate VCommonSettings::GetDateOfLastRemind() const { - return value(SettingDateOfLastRemind, QDate(1900, 1, 1)).toDate(); + QSettings settings(this->format(), this->scope(), this->organizationName(), commonIniFilename); + return settings.value(SettingDateOfLastRemind, QDate(1900, 1, 1)).toDate(); } //--------------------------------------------------------------------------------------------------------------------- void VCommonSettings::SetDateOfLastRemind(const QDate &date) { - setValue(SettingDateOfLastRemind, date); + QSettings settings(this->format(), this->scope(), this->organizationName(), commonIniFilename); + settings.setValue(SettingDateOfLastRemind, date); + settings.sync(); } From 0a1e89c8394d2972b9869cf5ae44cac698e029b0 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Fri, 15 Jul 2016 13:21:45 +0300 Subject: [PATCH 5/8] Updated default feed url. --HG-- branch : feature --- src/libs/fervor/fvupdater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/fervor/fvupdater.cpp b/src/libs/fervor/fvupdater.cpp index b215a5957..17a6bcef7 100644 --- a/src/libs/fervor/fvupdater.cpp +++ b/src/libs/fervor/fvupdater.cpp @@ -30,7 +30,7 @@ #include #include -const QString defaultFeedURL = QStringLiteral("http://localhost/updateapp/Appcast.xml"); +const QString defaultFeedURL = QStringLiteral("http://valentinaproject.bitbucket.org/Appcast.xml"); QPointer FvUpdater::m_Instance; From 83aeb00063f1c338261b11129119c46a046c48a9 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Fri, 15 Jul 2016 13:24:27 +0300 Subject: [PATCH 6/8] Added example of Appcast.xml. --HG-- branch : feature --- src/libs/fervor/data/Appcast.xml | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/libs/fervor/data/Appcast.xml diff --git a/src/libs/fervor/data/Appcast.xml b/src/libs/fervor/data/Appcast.xml new file mode 100644 index 000000000..5812aa0d8 --- /dev/null +++ b/src/libs/fervor/data/Appcast.xml @@ -0,0 +1,48 @@ + + + + + Valentina + http://valentina-project.org/ + Valentina is a cross-platform patternmaking program which allows designers +to create and model patterns of clothing. This software allows pattern +creation, using either standard sizing tables or an individual’s set of +measurements. It blends new technologies with traditional methods to create +a unique pattern making tool. + en + + + + Version 0.4.4 + https://bitbucket.org/dismine/valentina/raw/default/ChangeLog.txt + New minor release + + + + + + + + + + + + + + + From 0a58a27877890eb4127cf4d0f3fb606882410eef Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Fri, 15 Jul 2016 13:28:00 +0300 Subject: [PATCH 7/8] Updated Changelog.txt. --HG-- branch : feature --- ChangeLog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog.txt b/ChangeLog.txt index 780fa2465..e660ee814 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -34,6 +34,7 @@ - [#480] New tool: Midpoint between two points. - [#496] Selector for selecting which pieces to print. - [#520] Improve Union tool. An option to select about original pieces. +- [#262] Automatic Update notification. # Version 0.4.5 - [#435] Valentina doesn't change the cursor.