Ref T42, application classes

* GUI classes allow retry
* longer timeouts
* accept unknow accessibility (QAM)
* QAM now as pointer, which would allow to replace QAM

When QAM becomes disconnected, then connect again it is in unknown state
This commit is contained in:
Klaus Basan
2017-04-28 02:42:50 +02:00
committed by Mathew Sutcliffe
parent 212bb6b485
commit 74e0bf397f
5 changed files with 90 additions and 66 deletions

View File

@@ -96,7 +96,8 @@ namespace BlackCore
{ } { }
CApplication::CApplication(const QString &applicationName, CApplicationInfo::Application application, bool init) : CApplication::CApplication(const QString &applicationName, CApplicationInfo::Application application, bool init) :
m_cookieManager( {}, this), m_applicationName(applicationName), m_application(application), m_coreFacadeConfig(CCoreFacadeConfig::allEmpty()) m_accessManager(new QNetworkAccessManager(this)),
m_application(application), m_cookieManager( {}, this), m_applicationName(applicationName), m_coreFacadeConfig(CCoreFacadeConfig::allEmpty())
{ {
Q_ASSERT_X(!sApp, Q_FUNC_INFO, "already initialized"); Q_ASSERT_X(!sApp, Q_FUNC_INFO, "already initialized");
Q_ASSERT_X(QCoreApplication::instance(), Q_FUNC_INFO, "no application object"); Q_ASSERT_X(QCoreApplication::instance(), Q_FUNC_INFO, "no application object");
@@ -139,9 +140,11 @@ namespace BlackCore
QCoreApplication::instance()->installTranslator(&translator); QCoreApplication::instance()->installTranslator(&translator);
// Init network // Init network
this->m_cookieManager.setParent(&this->m_accessManager); Q_ASSERT_X(m_accessManager, Q_FUNC_INFO, "Need QAM");
this->m_accessManager.setCookieJar(&this->m_cookieManager); this->m_cookieManager.setParent(this->m_accessManager);
connect(&this->m_accessManager, &QNetworkAccessManager::networkAccessibleChanged, this, &CApplication::ps_networkAccessibleChanged); this->m_accessManager->setCookieJar(&this->m_cookieManager);
connect(this->m_accessManager, &QNetworkAccessManager::networkAccessibleChanged, this, &CApplication::ps_networkAccessibleChanged);
CLogMessage::preformatted(CNetworkUtils::createNetworkReport(this->m_accessManager));
// global setup // global setup
sApp = this; sApp = this;
@@ -149,7 +152,7 @@ namespace BlackCore
connect(this->m_setupReader.data(), &CSetupReader::setupHandlingCompleted, this, &CApplication::ps_setupHandlingCompleted); connect(this->m_setupReader.data(), &CSetupReader::setupHandlingCompleted, this, &CApplication::ps_setupHandlingCompleted);
connect(this->m_setupReader.data(), &CSetupReader::distributionInfoAvailable, this, &CApplication::distributionInfoAvailable); connect(this->m_setupReader.data(), &CSetupReader::distributionInfoAvailable, this, &CApplication::distributionInfoAvailable);
this->m_parser.addOptions(this->m_setupReader->getCmdLineOptions()); this->m_parser.addOptions(this->m_setupReader->getCmdLineOptions()); // add options from reader
// startup done // startup done
connect(this, &CApplication::startUpCompleted, this, &CApplication::ps_startupCompleted); connect(this, &CApplication::startUpCompleted, this, &CApplication::ps_startupCompleted);
@@ -176,6 +179,15 @@ namespace BlackCore
return QCoreApplication::exec(); return QCoreApplication::exec();
} }
void CApplication::restartApplication()
{
this->gracefulShutdown();
const QString prg = QCoreApplication::applicationFilePath();
const QStringList args = CApplication::arguments();
QProcess::startDetached(prg, args);
this->exit(0);
}
CApplication::~CApplication() CApplication::~CApplication()
{ {
this->gracefulShutdown(); this->gracefulShutdown();
@@ -380,7 +392,7 @@ namespace BlackCore
CStatusMessageList CApplication::waitForSetup() CStatusMessageList CApplication::waitForSetup()
{ {
if (!this->m_setupReader) { return CStatusMessage(this).error("No setup reader"); } if (!this->m_setupReader) { return CStatusMessage(this).error("No setup reader"); }
CEventLoop::processEventsUntil(this, &CApplication::setupHandlingCompleted, 5000, [this] CEventLoop::processEventsUntil(this, &CApplication::setupHandlingCompleted, CNetworkUtils::getLongTimeoutMs(), [this]
{ {
return this->m_setupReader->isSetupAvailable(); return this->m_setupReader->isSetupAvailable();
}); });
@@ -567,9 +579,9 @@ namespace BlackCore
QNetworkReply *CApplication::postToNetwork(const QNetworkRequest &request, QHttpMultiPart *multiPart, const CSlot<void(QNetworkReply *)> &callback) QNetworkReply *CApplication::postToNetwork(const QNetworkRequest &request, QHttpMultiPart *multiPart, const CSlot<void(QNetworkReply *)> &callback)
{ {
if (!this->isNetworkAccessible()) { return nullptr; } if (!this->isNetworkAccessible()) { return nullptr; }
if (QThread::currentThread() != this->m_accessManager.thread()) if (QThread::currentThread() != this->m_accessManager->thread())
{ {
multiPart->moveToThread(this->m_accessManager.thread()); multiPart->moveToThread(this->m_accessManager->thread());
} }
return httpRequestImpl(request, callback, -1, [ this, multiPart ](QNetworkAccessManager & nam, const QNetworkRequest & request) return httpRequestImpl(request, callback, -1, [ this, multiPart ](QNetworkAccessManager & nam, const QNetworkRequest & request)
@@ -598,7 +610,12 @@ namespace BlackCore
bool CApplication::isNetworkAccessible() const bool CApplication::isNetworkAccessible() const
{ {
return this->m_accessManager.networkAccessible() == QNetworkAccessManager::Accessible; if (!this->m_accessManager) return false;
const QNetworkAccessManager::NetworkAccessibility a = this->m_accessManager->networkAccessible();
if (a == QNetworkAccessManager::Accessible) return true;
// currently I also accept unknown
return a == QNetworkAccessManager::UnknownAccessibility;
} }
bool CApplication::hasSetupReader() const bool CApplication::hasSetupReader() const
@@ -847,6 +864,7 @@ namespace BlackCore
switch (accessible) switch (accessible)
{ {
case QNetworkAccessManager::Accessible: case QNetworkAccessManager::Accessible:
this->m_accessManager->setNetworkAccessible(accessible); // for some reasons the queried value still is unknown
CLogMessage(this).info("Network is accessible"); CLogMessage(this).info("Network is accessible");
break; break;
case QNetworkAccessManager::NotAccessible: case QNetworkAccessManager::NotAccessible:
@@ -947,6 +965,11 @@ namespace BlackCore
return this->m_parser.isSet(option); return this->m_parser.isSet(option);
} }
bool CApplication::isInstallerOptionSet() const
{
return this->isParserOptionSet("installer");
}
bool CApplication::isParserOptionSet(const QCommandLineOption &option) const bool CApplication::isParserOptionSet(const QCommandLineOption &option) const
{ {
return this->m_parser.isSet(option); return this->m_parser.isSet(option);
@@ -1011,20 +1034,24 @@ namespace BlackCore
return true; return true;
} }
void CApplication::cmdLineErrorMessage(const QString &errorMessage) const bool CApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const
{ {
Q_UNUSED(retry); // onyl works with UI version
fputs(qPrintable(errorMessage), stderr); fputs(qPrintable(errorMessage), stderr);
fputs("\n\n", stderr); fputs("\n\n", stderr);
fputs(qPrintable(this->m_parser.helpText()), stderr); fputs(qPrintable(this->m_parser.helpText()), stderr);
return false;
} }
void CApplication::cmdLineErrorMessage(const CStatusMessageList &msgs) const bool CApplication::cmdLineErrorMessage(const CStatusMessageList &msgs, bool retry) const
{ {
if (msgs.isEmpty()) { return; } Q_UNUSED(retry); // onyl works with UI version
if (!msgs.hasErrorMessages()) { return; } if (msgs.isEmpty()) { return false; }
if (!msgs.hasErrorMessages()) { return false; }
CApplication::cmdLineErrorMessage( CApplication::cmdLineErrorMessage(
msgs.toFormattedQString(true) msgs.toFormattedQString(true)
); );
return false;
} }
void CApplication::cmdLineHelpMessage() void CApplication::cmdLineHelpMessage()
@@ -1206,14 +1233,14 @@ namespace BlackCore
if (this->m_shutdown) { return nullptr; } if (this->m_shutdown) { return nullptr; }
if (!this->isNetworkAccessible()) { return nullptr; } if (!this->isNetworkAccessible()) { return nullptr; }
QWriteLocker locker(&m_accessManagerLock); QWriteLocker locker(&m_accessManagerLock);
Q_ASSERT_X(QCoreApplication::instance()->thread() == m_accessManager.thread(), Q_FUNC_INFO, "Network manager supposed to be in main thread"); Q_ASSERT_X(QCoreApplication::instance()->thread() == m_accessManager->thread(), Q_FUNC_INFO, "Network manager supposed to be in main thread");
if (QThread::currentThread() != this->m_accessManager.thread()) if (QThread::currentThread() != this->m_accessManager->thread())
{ {
QTimer::singleShot(0, this, std::bind(&CApplication::httpRequestImpl, this, request, callback, maxRedirects, requestOrPostMethod)); QTimer::singleShot(0, this, std::bind(&CApplication::httpRequestImpl, this, request, callback, maxRedirects, requestOrPostMethod));
return nullptr; // not yet started return nullptr; // not yet started
} }
Q_ASSERT_X(QThread::currentThread() == m_accessManager.thread(), Q_FUNC_INFO, "Network manager thread mismatch"); Q_ASSERT_X(QThread::currentThread() == m_accessManager->thread(), Q_FUNC_INFO, "Network manager thread mismatch");
QNetworkRequest copiedRequest(request); // no QObject QNetworkRequest copiedRequest(request); // no QObject
CNetworkUtils::ignoreSslVerification(copiedRequest); CNetworkUtils::ignoreSslVerification(copiedRequest);
CNetworkUtils::setSwiftUserAgent(copiedRequest); CNetworkUtils::setSwiftUserAgent(copiedRequest);
@@ -1221,7 +1248,7 @@ namespace BlackCore
// If URL is one of the shared urls, add swift client SSL certificate // If URL is one of the shared urls, add swift client SSL certificate
CNetworkUtils::setSwiftClientSslCertificate(copiedRequest, getGlobalSetup().getSwiftSharedUrls()); CNetworkUtils::setSwiftClientSslCertificate(copiedRequest, getGlobalSetup().getSwiftSharedUrls());
QNetworkReply *reply = requestOrPostMethod(this->m_accessManager, copiedRequest); QNetworkReply *reply = requestOrPostMethod(*this->m_accessManager, copiedRequest);
reply->setProperty("started", QVariant(QDateTime::currentMSecsSinceEpoch())); reply->setProperty("started", QVariant(QDateTime::currentMSecsSinceEpoch()));
if (callback) if (callback)
{ {

View File

@@ -12,19 +12,6 @@
#ifndef BLACKCORE_APPLICATION_H #ifndef BLACKCORE_APPLICATION_H
#define BLACKCORE_APPLICATION_H #define BLACKCORE_APPLICATION_H
#include <QByteArray>
#include <QCommandLineOption>
#include <QCommandLineParser>
#include <QList>
#include <QNetworkAccessManager>
#include <QObject>
#include <QReadWriteLock>
#include <QScopedPointer>
#include <QString>
#include <QStringList>
#include <atomic>
#include <functional>
#include "blackcore/blackcoreexport.h" #include "blackcore/blackcoreexport.h"
#include "blackcore/cookiemanager.h" #include "blackcore/cookiemanager.h"
#include "blackcore/corefacadeconfig.h" #include "blackcore/corefacadeconfig.h"
@@ -38,6 +25,19 @@
#include "blackmisc/applicationinfolist.h" #include "blackmisc/applicationinfolist.h"
#include "blackmisc/statusmessagelist.h" #include "blackmisc/statusmessagelist.h"
#include <QByteArray>
#include <QCommandLineOption>
#include <QCommandLineParser>
#include <QList>
#include <QNetworkAccessManager>
#include <QObject>
#include <QReadWriteLock>
#include <QScopedPointer>
#include <QString>
#include <QStringList>
#include <atomic>
#include <functional>
#if defined(Q_CC_MSVC) || defined(Q_OS_OSX) // Crashpad only supported on MSVC and MacOS/X #if defined(Q_CC_MSVC) || defined(Q_OS_OSX) // Crashpad only supported on MSVC and MacOS/X
#define BLACK_USE_CRASHPAD #define BLACK_USE_CRASHPAD
#endif #endif
@@ -159,6 +159,9 @@ namespace BlackCore
//! Network accessible? //! Network accessible?
bool isNetworkAccessible() const; bool isNetworkAccessible() const;
//! Access to access manager
const QNetworkAccessManager *getNetworkAccessManager() const { return m_accessManager; }
//! Setup reader? //! Setup reader?
bool hasSetupReader() const; bool hasSetupReader() const;
@@ -221,6 +224,9 @@ namespace BlackCore
//! Directory for temporary files //! Directory for temporary files
QString getTemporaryDirectory() const; QString getTemporaryDirectory() const;
//! Stop and restart application
void restartApplication();
//! Register as running //! Register as running
//! \note Normally done automatically when CApplication::exec is called //! \note Normally done automatically when CApplication::exec is called
static bool registerAsRunning(); static bool registerAsRunning();
@@ -268,6 +274,9 @@ namespace BlackCore
//! Delegates to QCommandLineParser::isSet //! Delegates to QCommandLineParser::isSet
bool isParserOptionSet(const QString &option) const; bool isParserOptionSet(const QString &option) const;
//! Installer called?
bool isInstallerOptionSet() const;
//! Delegates to QCommandLineParser::isSet //! Delegates to QCommandLineParser::isSet
bool isParserOptionSet(const QCommandLineOption &option) const; bool isParserOptionSet(const QCommandLineOption &option) const;
@@ -285,10 +294,10 @@ namespace BlackCore
//! @} //! @}
//! Display error message //! Display error message
virtual void cmdLineErrorMessage(const QString &cmdLineErrorMessage) const; virtual bool cmdLineErrorMessage(const QString &cmdLineErrorMessage, bool retry = false) const;
//! Display error message //! Display error message
virtual void cmdLineErrorMessage(const BlackMisc::CStatusMessageList &msgs) const; virtual bool cmdLineErrorMessage(const BlackMisc::CStatusMessageList &msgs, bool retry = false) const;
// ----------------------- contexts ---------------------------------------- // ----------------------- contexts ----------------------------------------
@@ -479,14 +488,14 @@ namespace BlackCore
int maxRedirects, int maxRedirects,
std::function<QNetworkReply *(QNetworkAccessManager &, const QNetworkRequest &)> requestOrPostMethod); std::function<QNetworkReply *(QNetworkAccessManager &, const QNetworkRequest &)> requestOrPostMethod);
QNetworkAccessManager *m_accessManager = nullptr; //!< single network access manager
BlackMisc::CApplicationInfo::Application m_application = BlackMisc::CApplicationInfo::Unknown; //!< Application if specified
QScopedPointer<CCoreFacade> m_coreFacade; //!< core facade if any QScopedPointer<CCoreFacade> m_coreFacade; //!< core facade if any
QScopedPointer<CSetupReader> m_setupReader; //!< setup reader QScopedPointer<CSetupReader> m_setupReader; //!< setup reader
QScopedPointer<CWebDataServices> m_webDataServices; //!< web data services QScopedPointer<CWebDataServices> m_webDataServices; //!< web data services
QScopedPointer<BlackMisc::CFileLogger> m_fileLogger; //!< file logger QScopedPointer<BlackMisc::CFileLogger> m_fileLogger; //!< file logger
QNetworkAccessManager m_accessManager { this }; //!< single network access manager
CCookieManager m_cookieManager; //!< single cookie manager for our access manager CCookieManager m_cookieManager; //!< single cookie manager for our access manager
QString m_applicationName; //!< application name QString m_applicationName; //!< application name
BlackMisc::CApplicationInfo::Application m_application = BlackMisc::CApplicationInfo::Unknown; //!< Application if specified
QReadWriteLock m_accessManagerLock; //!< lock to make access manager access threadsafe QReadWriteLock m_accessManagerLock; //!< lock to make access manager access threadsafe
CCoreFacadeConfig m_coreFacadeConfig; //!< Core facade config if any CCoreFacadeConfig m_coreFacadeConfig; //!< Core facade config if any
CWebReaderFlags::WebReader m_webReadersUsed; //!< Readers to be used CWebReaderFlags::WebReader m_webReadersUsed; //!< Readers to be used

View File

@@ -259,39 +259,27 @@ namespace BlackGui
return html; return html;
} }
void CGuiApplication::cmdLineErrorMessage(const QString &errorMessage) const bool CGuiApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const
{ {
if (CBuildConfig::isRunningOnWindowsNtPlatform()) const QString helpText(beautifyHelpMessage(this->m_parser.helpText()));
{ const int r = QMessageBox::warning(nullptr,
const QString helpText(beautifyHelpMessage(this->m_parser.helpText())); QGuiApplication::applicationDisplayName(),
QMessageBox::warning(nullptr, "<html><head/><body><h2>" + errorMessage + "</h2><br>" + helpText + "</body></html>", QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton);
QGuiApplication::applicationDisplayName(), return (r == QMessageBox::Retry);
"<html><head/><body><h2>" + errorMessage + "</h2><br>" + helpText + "</body></html>");
}
else
{
CApplication::cmdLineErrorMessage(errorMessage);
}
} }
void CGuiApplication::cmdLineErrorMessage(const CStatusMessageList &msgs) const bool CGuiApplication::cmdLineErrorMessage(const CStatusMessageList &msgs, bool retry) const
{ {
if (msgs.isEmpty()) { return; } if (msgs.isEmpty()) { return false; }
if (!msgs.hasErrorMessages()) { return; } if (!msgs.hasErrorMessages()) { return false; }
if (CBuildConfig::isRunningOnWindowsNtPlatform()) static const CPropertyIndexList propertiesSingle({ CStatusMessage::IndexMessage });
{ static const CPropertyIndexList propertiesMulti({ CStatusMessage::IndexSeverityAsString, CStatusMessage::IndexMessage });
static const CPropertyIndexList propertiesSingle({ CStatusMessage::IndexMessage }); const QString helpText(CGuiApplication::beautifyHelpMessage(this->m_parser.helpText()));
static const CPropertyIndexList propertiesMulti({ CStatusMessage::IndexSeverityAsString, CStatusMessage::IndexMessage }); const QString msgsHtml = msgs.toHtml(msgs.size() > 1 ? propertiesMulti : propertiesSingle);
const QString helpText(CGuiApplication::beautifyHelpMessage(this->m_parser.helpText())); const int r = QMessageBox::critical(nullptr,
const QString msgsHtml = msgs.toHtml(msgs.size() > 1 ? propertiesMulti : propertiesSingle); QGuiApplication::applicationDisplayName(),
QMessageBox::critical(nullptr, "<html><head/><body>" + msgsHtml + "<br><br>" + helpText + "</body></html>", QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton);
QGuiApplication::applicationDisplayName(), return (r == QMessageBox::Retry);
"<html><head/><body>" + msgsHtml + "<br><br>" + helpText + "</body></html>");
}
else
{
CApplication::cmdLineErrorMessage(msgs);
}
} }
bool CGuiApplication::displayInStatusBar(const CStatusMessage &message) bool CGuiApplication::displayInStatusBar(const CStatusMessage &message)

View File

@@ -111,8 +111,8 @@ namespace BlackGui
//! \name print messages generated during parsing / cmd handling //! \name print messages generated during parsing / cmd handling
//! @{ //! @{
virtual void cmdLineErrorMessage(const QString &cmdLineErrorMessage) const override; virtual bool cmdLineErrorMessage(const QString &cmdLineErrorMessage, bool retry = false) const override;
virtual void cmdLineErrorMessage(const BlackMisc::CStatusMessageList &msgs) const override; virtual bool cmdLineErrorMessage(const BlackMisc::CStatusMessageList &msgs, bool retry = false) const override;
//! @} //! @}
//! \name direct access to main application window //! \name direct access to main application window

View File

@@ -70,7 +70,7 @@ CSwiftLauncher::CSwiftLauncher(QWidget *parent) :
m_checkTimer.start(); m_checkTimer.start();
// auto launch wizard // auto launch wizard
if (sGui->isParserOptionSet("installer")) if (sGui->isInstallerOptionSet())
{ {
QTimer::singleShot(2500, this, &CSwiftLauncher::ps_startWizard); QTimer::singleShot(2500, this, &CSwiftLauncher::ps_startWizard);
} }