ui: Show news sent with update check on start screen
* News are passed as JSON string, containing an array of news items. * Each news item has version and content (html). * Items can be filtered by min/max version, OS and license. The first item that fits is used. * Items can be important, which highlights the news box. * News are not shown if older than 5 days. fortune cookie message = You will be financially successful in case your actions are well planned.
This commit is contained in:
@@ -29,19 +29,38 @@
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#recentLabel {
|
#titleLabel {
|
||||||
color: black;
|
color: black;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#versionLabel {
|
#textLabel {
|
||||||
|
color: black;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#boldLabel {
|
||||||
color: black;
|
color: black;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#textField {
|
||||||
|
background: white;
|
||||||
|
border: 1px solid lightgray;
|
||||||
|
border-radius: 12px;
|
||||||
|
color: black;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 5px;
|
||||||
|
min-width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#textField[important=true] {
|
||||||
|
border: 2px solid #007ac3;
|
||||||
|
}
|
||||||
|
|
||||||
#updateButton, #upgradeButton {
|
#updateButton, #upgradeButton {
|
||||||
margin: 1px 0 3px;
|
margin: 1px 0 3px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -57,19 +76,3 @@
|
|||||||
color: black;
|
color: black;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#licenseHeaderLabel {
|
|
||||||
color: black;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#licenseLabel {
|
|
||||||
color: black;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#welcomeLabel {
|
|
||||||
color: black;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -97,6 +97,7 @@
|
|||||||
<skip_version><!-- VERSION: version to skip for update --></skip_version>
|
<skip_version><!-- VERSION: version to skip for update --></skip_version>
|
||||||
<update_url><!-- STRING: url to new version download --></update_url>
|
<update_url><!-- STRING: url to new version download --></update_url>
|
||||||
<update_version><!-- VERSION: version of last check --></update_version>
|
<update_version><!-- VERSION: version of last check --></update_version>
|
||||||
|
<news><!-- STRING: news in last update check --></news>
|
||||||
</update_check>
|
</update_check>
|
||||||
|
|
||||||
<seen_error_help_message><!-- BOOL: whether user has been shown help message on errors after indexing --></seen_error_help_message>
|
<seen_error_help_message><!-- BOOL: whether user has been shown help message on errors after indexing --></seen_error_help_message>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ std::shared_ptr<LicenseChecker> LicenseChecker::getInstance()
|
|||||||
return s_instance;
|
return s_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LicenseChecker::getCurrentLicenseString() const
|
std::string LicenseChecker::getCurrentLicenseString()
|
||||||
{
|
{
|
||||||
License license;
|
License license;
|
||||||
bool isLoaded = license.loadFromEncodedString(
|
bool isLoaded = license.loadFromEncodedString(
|
||||||
@@ -38,7 +38,7 @@ std::string LicenseChecker::getCurrentLicenseString() const
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void LicenseChecker::saveCurrentLicenseString(const std::string& licenseString) const
|
void LicenseChecker::saveCurrentLicenseString(const std::string& licenseString)
|
||||||
{
|
{
|
||||||
License license;
|
License license;
|
||||||
bool isLoaded = license.loadFromString(licenseString);
|
bool isLoaded = license.loadFromString(licenseString);
|
||||||
@@ -55,7 +55,7 @@ bool LicenseChecker::isCurrentLicenseValid()
|
|||||||
return checkCurrentLicense() == LICENSE_VALID;
|
return checkCurrentLicense() == LICENSE_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
LicenseChecker::LicenseState LicenseChecker::checkCurrentLicense() const
|
LicenseChecker::LicenseState LicenseChecker::checkCurrentLicense()
|
||||||
{
|
{
|
||||||
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
||||||
if (appSettings == nullptr)
|
if (appSettings == nullptr)
|
||||||
@@ -96,7 +96,7 @@ LicenseChecker::LicenseState LicenseChecker::checkCurrentLicense() const
|
|||||||
return checkLicense(license);
|
return checkLicense(license);
|
||||||
}
|
}
|
||||||
|
|
||||||
LicenseChecker::LicenseState LicenseChecker::checkLicenseString(const std::string& licenseString) const
|
LicenseChecker::LicenseState LicenseChecker::checkLicenseString(const std::string& licenseString)
|
||||||
{
|
{
|
||||||
if (licenseString.size() == 0)
|
if (licenseString.size() == 0)
|
||||||
{
|
{
|
||||||
@@ -115,7 +115,7 @@ LicenseChecker::LicenseState LicenseChecker::checkLicenseString(const std::strin
|
|||||||
return checkLicense(license);
|
return checkLicense(license);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageEnteredLicense::LicenseType LicenseChecker::getCurrentLicenseType() const
|
MessageEnteredLicense::LicenseType LicenseChecker::getCurrentLicenseType()
|
||||||
{
|
{
|
||||||
License license;
|
License license;
|
||||||
bool isLoaded = license.loadFromEncodedString(
|
bool isLoaded = license.loadFromEncodedString(
|
||||||
@@ -143,7 +143,7 @@ MessageEnteredLicense::LicenseType LicenseChecker::getCurrentLicenseType() const
|
|||||||
return MessageEnteredLicense::LICENSE_COMMERCIAL;
|
return MessageEnteredLicense::LICENSE_COMMERCIAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageEnteredLicense::LicenseType LicenseChecker::getLicenseType(const std::string& licenseString) const
|
MessageEnteredLicense::LicenseType LicenseChecker::getLicenseType(const std::string& licenseString)
|
||||||
{
|
{
|
||||||
if (licenseString.size() == 0)
|
if (licenseString.size() == 0)
|
||||||
{
|
{
|
||||||
@@ -174,11 +174,28 @@ MessageEnteredLicense::LicenseType LicenseChecker::getLicenseType(const std::str
|
|||||||
return MessageEnteredLicense::LICENSE_COMMERCIAL;
|
return MessageEnteredLicense::LICENSE_COMMERCIAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string LicenseChecker::getCurrentLicenseTypeString()
|
||||||
|
{
|
||||||
|
// WARNING: Don't change these string. The server API relies on them.
|
||||||
|
switch (getCurrentLicenseType())
|
||||||
|
{
|
||||||
|
case MessageEnteredLicense::LICENSE_NONE:
|
||||||
|
case MessageEnteredLicense::LICENSE_NON_COMMERCIAL:
|
||||||
|
return "private";
|
||||||
|
case MessageEnteredLicense::LICENSE_TEST:
|
||||||
|
return "test";
|
||||||
|
case MessageEnteredLicense::LICENSE_COMMERCIAL:
|
||||||
|
return "commercial";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "private";
|
||||||
|
}
|
||||||
|
|
||||||
LicenseChecker::LicenseChecker()
|
LicenseChecker::LicenseChecker()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
LicenseChecker::LicenseState LicenseChecker::checkLicense(License& license) const
|
LicenseChecker::LicenseState LicenseChecker::checkLicense(License& license)
|
||||||
{
|
{
|
||||||
if (license.isExpired())
|
if (license.isExpired())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,22 +23,24 @@ public:
|
|||||||
|
|
||||||
~LicenseChecker() = default;
|
~LicenseChecker() = default;
|
||||||
|
|
||||||
std::string getCurrentLicenseString() const;
|
static std::string getCurrentLicenseString();
|
||||||
void saveCurrentLicenseString(const std::string& licenseString) const;
|
static void saveCurrentLicenseString(const std::string& licenseString);
|
||||||
|
|
||||||
bool isCurrentLicenseValid();
|
static bool isCurrentLicenseValid();
|
||||||
LicenseState checkCurrentLicense() const;
|
static LicenseState checkCurrentLicense();
|
||||||
LicenseState checkLicenseString(const std::string& licenseString) const;
|
static LicenseState checkLicenseString(const std::string& licenseString);
|
||||||
|
|
||||||
MessageEnteredLicense::LicenseType getCurrentLicenseType() const;
|
static MessageEnteredLicense::LicenseType getCurrentLicenseType();
|
||||||
MessageEnteredLicense::LicenseType getLicenseType(const std::string& licenseString) const;
|
static MessageEnteredLicense::LicenseType getLicenseType(const std::string& licenseString);
|
||||||
|
|
||||||
|
static std::string getCurrentLicenseTypeString();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LicenseChecker();
|
LicenseChecker();
|
||||||
LicenseChecker(const LicenseChecker&) = delete;
|
LicenseChecker(const LicenseChecker&) = delete;
|
||||||
void operator=(const LicenseChecker&) = delete;
|
void operator=(const LicenseChecker&) = delete;
|
||||||
|
|
||||||
LicenseState checkLicense(License& license) const;
|
static LicenseState checkLicense(License& license);
|
||||||
|
|
||||||
static std::shared_ptr<LicenseChecker> s_instance;
|
static std::shared_ptr<LicenseChecker> s_instance;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -597,6 +597,16 @@ Version ApplicationSettings::getUpdateVersion() const
|
|||||||
return Version::fromString(getValue<std::string>("user/update_check/update_version", "2017.1.0"));
|
return Version::fromString(getValue<std::string>("user/update_check/update_version", "2017.1.0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ApplicationSettings::getUpdateNews() const
|
||||||
|
{
|
||||||
|
return getValue<std::string>("user/update_check/news", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplicationSettings::setUpdateNews(const std::string& news)
|
||||||
|
{
|
||||||
|
setValue<std::string>("user/update_check/news", news);
|
||||||
|
}
|
||||||
|
|
||||||
void ApplicationSettings::setUpdateVersion(const Version& version)
|
void ApplicationSettings::setUpdateVersion(const Version& version)
|
||||||
{
|
{
|
||||||
if (version.isValid())
|
if (version.isValid())
|
||||||
|
|||||||
@@ -167,6 +167,9 @@ public:
|
|||||||
Version getUpdateVersion() const;
|
Version getUpdateVersion() const;
|
||||||
void setUpdateVersion(const Version& version);
|
void setUpdateVersion(const Version& version);
|
||||||
|
|
||||||
|
std::string getUpdateNews() const;
|
||||||
|
void setUpdateNews(const std::string& news);
|
||||||
|
|
||||||
bool getSeenErrorHelpMessage() const;
|
bool getSeenErrorHelpMessage() const;
|
||||||
void setSeenErrorHelpMessage(bool seen);
|
void setSeenErrorHelpMessage(bool seen);
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ add_files(
|
|||||||
qt/element/QtListBoxItem.h
|
qt/element/QtListBoxItem.h
|
||||||
qt/element/QtLocationPicker.cpp
|
qt/element/QtLocationPicker.cpp
|
||||||
qt/element/QtLocationPicker.h
|
qt/element/QtLocationPicker.h
|
||||||
|
qt/element/QtNewsWidget.cpp
|
||||||
|
qt/element/QtNewsWidget.h
|
||||||
qt/element/QtPathListBox.cpp
|
qt/element/QtPathListBox.cpp
|
||||||
qt/element/QtPathListBox.h
|
qt/element/QtPathListBox.h
|
||||||
qt/element/QtPathListBoxItem.cpp
|
qt/element/QtPathListBoxItem.cpp
|
||||||
@@ -67,6 +69,8 @@ add_files(
|
|||||||
qt/element/QtStatusBar.h
|
qt/element/QtStatusBar.h
|
||||||
qt/element/QtTable.cpp
|
qt/element/QtTable.cpp
|
||||||
qt/element/QtTable.h
|
qt/element/QtTable.h
|
||||||
|
qt/element/QtTextEdit.cpp
|
||||||
|
qt/element/QtTextEdit.h
|
||||||
qt/element/QtTooltip.cpp
|
qt/element/QtTooltip.cpp
|
||||||
qt/element/QtTooltip.h
|
qt/element/QtTooltip.h
|
||||||
qt/element/QtUndoRedo.cpp
|
qt/element/QtUndoRedo.cpp
|
||||||
|
|||||||
@@ -0,0 +1,227 @@
|
|||||||
|
#include "QtNewsWidget.h"
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QStyle>
|
||||||
|
|
||||||
|
#include "ApplicationSettings.h"
|
||||||
|
#include "LicenseChecker.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "QtTextEdit.h"
|
||||||
|
#include "TimeStamp.h"
|
||||||
|
#include "utilityApp.h"
|
||||||
|
#include "Version.h"
|
||||||
|
|
||||||
|
QtNewsWidget::QtNewsWidget(QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
|
||||||
|
m_text = new QtTextEdit();
|
||||||
|
m_text->setObjectName("textField");
|
||||||
|
m_text->setReadOnly(true);
|
||||||
|
m_text->setTabStopWidth(8 * m_text->fontMetrics().width('9'));
|
||||||
|
m_text->setViewportMargins(6, 4, 16, 4);
|
||||||
|
m_text->setOpenExternalLinks(true);
|
||||||
|
layout->addWidget(m_text);
|
||||||
|
|
||||||
|
QString placeholder = "No news available";
|
||||||
|
if (!ApplicationSettings::getInstance()->getAutomaticUpdateCheck())
|
||||||
|
{
|
||||||
|
placeholder += "\n(Enable update check)";
|
||||||
|
}
|
||||||
|
m_text->setPlaceholderText(placeholder);
|
||||||
|
|
||||||
|
updateNews();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
syntax:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
// required
|
||||||
|
"version": 1,
|
||||||
|
"content": "<b>Hello World!</b>",
|
||||||
|
|
||||||
|
// optional
|
||||||
|
"conditions":
|
||||||
|
{
|
||||||
|
"license": ["test", "private", "commercial"],
|
||||||
|
"os": ["windows", "macOS", "linux"],
|
||||||
|
"min_version": "2017.2.0",
|
||||||
|
"max_version": "2018.4.2",
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional
|
||||||
|
"flags":
|
||||||
|
{
|
||||||
|
"important": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
|
||||||
|
void QtNewsWidget::updateNews()
|
||||||
|
{
|
||||||
|
const int supportedNewsItemVersion = 1;
|
||||||
|
|
||||||
|
resetFlags();
|
||||||
|
|
||||||
|
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
||||||
|
std::string newsRaw = appSettings->getUpdateNews();
|
||||||
|
if (!newsRaw.size())
|
||||||
|
{
|
||||||
|
setNews("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TimeStamp::now().deltaHours(appSettings->getLastUpdateCheck()) >= 120)
|
||||||
|
{
|
||||||
|
LOG_INFO_STREAM(<< "Ignore news string, because older than 5 days.");
|
||||||
|
setNews("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO_STREAM(<< "Process news string: " << newsRaw);
|
||||||
|
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(QString::fromStdString(newsRaw).toUtf8(), &error);
|
||||||
|
if (doc.isNull() || !doc.isArray())
|
||||||
|
{
|
||||||
|
LOG_ERROR_STREAM(<< "News string couldn't be parsed as JSON: " << error.errorString().toStdString()
|
||||||
|
<< "\nJSON: " << newsRaw);
|
||||||
|
setNews("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t itemNum = 0;
|
||||||
|
for (QJsonValueRef value : doc.array())
|
||||||
|
{
|
||||||
|
itemNum++;
|
||||||
|
QJsonObject newsItem = value.toObject();
|
||||||
|
|
||||||
|
int version = newsItem.value("version").toInt();
|
||||||
|
if (version > supportedNewsItemVersion)
|
||||||
|
{
|
||||||
|
LOG_INFO_STREAM(<< "News item " << itemNum << " version " << version << " is not supported.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkConditions(newsItem.value("conditions").toObject()))
|
||||||
|
{
|
||||||
|
LOG_INFO_STREAM(<< "News item " << itemNum << " conditions failed.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
processFlags(newsItem.value("flags").toObject());
|
||||||
|
setNews(newsItem.value("content").toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNews("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtNewsWidget::resetFlags()
|
||||||
|
{
|
||||||
|
setImportant(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtNewsWidget::setNews(const QString& news)
|
||||||
|
{
|
||||||
|
m_text->setHtml(news);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtNewsWidget::setImportant(bool important)
|
||||||
|
{
|
||||||
|
m_text->setProperty("important", important);
|
||||||
|
m_text->style()->unpolish(m_text);
|
||||||
|
m_text->style()->polish(m_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QtNewsWidget::checkConditions(const QJsonObject& conditions) const
|
||||||
|
{
|
||||||
|
if (conditions.isEmpty())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// min_version
|
||||||
|
{
|
||||||
|
QString minVersionString = conditions.value("min_version").toString();
|
||||||
|
if (!minVersionString.isEmpty())
|
||||||
|
{
|
||||||
|
Version minVersion = Version::fromString(minVersionString.toStdString());
|
||||||
|
if (minVersion.isValid() && minVersion > Version::getApplicationVersion())
|
||||||
|
{
|
||||||
|
LOG_INFO_STREAM(<< "Failed condition min_version.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// max_version
|
||||||
|
{
|
||||||
|
QString maxVersionString = conditions.value("max_version").toString();
|
||||||
|
if (!maxVersionString.isEmpty())
|
||||||
|
{
|
||||||
|
Version maxVersion = Version::fromString(maxVersionString.toStdString());
|
||||||
|
if (maxVersion.isValid() && maxVersion < Version::getApplicationVersion())
|
||||||
|
{
|
||||||
|
LOG_INFO_STREAM(<< "Failed condition max_version.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// license
|
||||||
|
{
|
||||||
|
QJsonArray licenseStrings = conditions.value("license").toArray();
|
||||||
|
if (!licenseStrings.isEmpty())
|
||||||
|
{
|
||||||
|
QString licenseString = QString::fromStdString(LicenseChecker::getCurrentLicenseTypeString());
|
||||||
|
if (!licenseStrings.contains(QJsonValue(licenseString)))
|
||||||
|
{
|
||||||
|
LOG_INFO_STREAM(<< "Failed condition license.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OS
|
||||||
|
{
|
||||||
|
QJsonArray osStrings = conditions.value("os").toArray();
|
||||||
|
if (!osStrings.isEmpty())
|
||||||
|
{
|
||||||
|
QString osString = QString::fromStdString(utility::getOsTypeString());
|
||||||
|
if (!osStrings.contains(QJsonValue(osString)))
|
||||||
|
{
|
||||||
|
LOG_INFO_STREAM(<< "Failed condition os.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtNewsWidget::processFlags(const QJsonObject& flags)
|
||||||
|
{
|
||||||
|
if (flags.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// important
|
||||||
|
{
|
||||||
|
bool important = flags.value("important").toBool();
|
||||||
|
if (important)
|
||||||
|
{
|
||||||
|
LOG_INFO_STREAM(<< "Flag important enabled.");
|
||||||
|
setImportant(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef QT_NEWS_WIDGET_H
|
||||||
|
#define QT_NEWS_WIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class QtTextEdit;
|
||||||
|
class QJsonObject;
|
||||||
|
|
||||||
|
class QtNewsWidget
|
||||||
|
: public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QtNewsWidget(QWidget* parent = nullptr);
|
||||||
|
virtual ~QtNewsWidget() = default;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void updateNews();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void resetFlags();
|
||||||
|
|
||||||
|
void setNews(const QString& news);
|
||||||
|
void setImportant(bool important);
|
||||||
|
|
||||||
|
bool checkConditions(const QJsonObject& conditions) const;
|
||||||
|
void processFlags(const QJsonObject& flags);
|
||||||
|
|
||||||
|
QtTextEdit* m_text;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QT_NEWS_WIDGET_H
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#include "QtTextEdit.h"
|
||||||
|
|
||||||
|
QtTextEdit::QtTextEdit(QWidget* parent)
|
||||||
|
: QTextBrowser(parent)
|
||||||
|
{
|
||||||
|
document()->setDefaultStyleSheet("a { color: #007AC2; }");
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtTextEdit::setViewportMargins(int left, int top, int right, int bottom)
|
||||||
|
{
|
||||||
|
QAbstractScrollArea::setViewportMargins(left, top, right, bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtTextEdit::focusInEvent(QFocusEvent* event)
|
||||||
|
{
|
||||||
|
emit focus();
|
||||||
|
QTextBrowser::focusInEvent(event);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef QT_TEXT_EDIT_H
|
||||||
|
#define QT_TEXT_EDIT_H
|
||||||
|
|
||||||
|
#include <QTextBrowser>
|
||||||
|
|
||||||
|
class QtTextEdit
|
||||||
|
: public QTextBrowser
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QtTextEdit(QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
void setViewportMargins(int left, int top, int right, int bottom);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void focus();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void focusInEvent(QFocusEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QT_TEXT_EDIT_H
|
||||||
@@ -99,6 +99,8 @@ void QtUpdateCheckerWidget::checkUpdate(bool force)
|
|||||||
{
|
{
|
||||||
setDownloadUrl(result.url);
|
setDownloadUrl(result.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit updateReceived();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,15 @@ class QPushButton;
|
|||||||
class QtUpdateCheckerWidget
|
class QtUpdateCheckerWidget
|
||||||
: public QWidget
|
: public QWidget
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QtUpdateCheckerWidget(QWidget* parent = nullptr);
|
QtUpdateCheckerWidget(QWidget* parent = nullptr);
|
||||||
virtual ~QtUpdateCheckerWidget();
|
virtual ~QtUpdateCheckerWidget();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void updateReceived();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void checkUpdate(bool force);
|
void checkUpdate(bool force);
|
||||||
void setDownloadUrl(QString url);
|
void setDownloadUrl(QString url);
|
||||||
|
|||||||
@@ -36,27 +36,10 @@ void QtUpdateChecker::check(bool force, std::function<void(Result)> callback)
|
|||||||
appSettings->setUpdateDownloadUrl("");
|
appSettings->setUpdateDownloadUrl("");
|
||||||
appSettings->save();
|
appSettings->save();
|
||||||
|
|
||||||
QString urlString = "https://www.sourcetrail.com/api/v1/versions/latest";
|
QString urlString = "https://www.sourcetrail.com/api/v2/versions/latest";
|
||||||
|
|
||||||
// OS
|
// OS
|
||||||
std::string osString;
|
std::string osString = utility::getOsTypeString();
|
||||||
|
|
||||||
switch (utility::getOsType())
|
|
||||||
{
|
|
||||||
case OS_WINDOWS:
|
|
||||||
osString = "windows";
|
|
||||||
break;
|
|
||||||
case OS_MAC:
|
|
||||||
osString = "macOS";
|
|
||||||
break;
|
|
||||||
case OS_LINUX:
|
|
||||||
osString = "linux";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
callback(result);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
urlString += ("?os=" + osString).c_str();
|
urlString += ("?os=" + osString).c_str();
|
||||||
|
|
||||||
// architecture
|
// architecture
|
||||||
@@ -68,21 +51,7 @@ void QtUpdateChecker::check(bool force, std::function<void(Result)> callback)
|
|||||||
urlString += ("&version=" + Version::getApplicationVersion().toDisplayString()).c_str();
|
urlString += ("&version=" + Version::getApplicationVersion().toDisplayString()).c_str();
|
||||||
|
|
||||||
// license
|
// license
|
||||||
std::string licenseString;
|
std::string licenseString = LicenseChecker::getCurrentLicenseTypeString();
|
||||||
switch (LicenseChecker::getInstance()->getCurrentLicenseType())
|
|
||||||
{
|
|
||||||
case MessageEnteredLicense::LICENSE_NONE:
|
|
||||||
case MessageEnteredLicense::LICENSE_NON_COMMERCIAL:
|
|
||||||
licenseString = "private";
|
|
||||||
break;
|
|
||||||
case MessageEnteredLicense::LICENSE_TEST:
|
|
||||||
licenseString = "test";
|
|
||||||
break;
|
|
||||||
case MessageEnteredLicense::LICENSE_COMMERCIAL:
|
|
||||||
licenseString = "commercial";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
urlString += ("&license=" + licenseString).c_str();
|
urlString += ("&license=" + licenseString).c_str();
|
||||||
|
|
||||||
// user token
|
// user token
|
||||||
@@ -103,15 +72,27 @@ void QtUpdateChecker::check(bool force, std::function<void(Result)> callback)
|
|||||||
{
|
{
|
||||||
Result result;
|
Result result;
|
||||||
|
|
||||||
|
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
||||||
|
bool saveAppSettings = false;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(bytes);
|
QJsonParseError error;
|
||||||
if (!doc.isObject())
|
QJsonDocument doc = QJsonDocument::fromJson(bytes, &error);
|
||||||
|
if (doc.isNull() || !doc.isObject())
|
||||||
{
|
{
|
||||||
LOG_ERROR_STREAM(<< "Update response couldn't be parsed as JSON");
|
LOG_ERROR_STREAM(<< "Update response couldn't be parsed as JSON: " << error.errorString().toStdString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString news = doc.object().find("news")->toString();
|
||||||
|
if (news.toStdString() != appSettings->getUpdateNews())
|
||||||
|
{
|
||||||
|
appSettings->setUpdateNews(news.toStdString());
|
||||||
|
saveAppSettings = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QString version = doc.object().find("version")->toString();
|
QString version = doc.object().find("version")->toString();
|
||||||
QString url = doc.object().find("url")->toString();
|
QString url = doc.object().find("url")->toString();
|
||||||
|
|
||||||
@@ -129,10 +110,9 @@ void QtUpdateChecker::check(bool force, std::function<void(Result)> callback)
|
|||||||
result.version = updateVersion;
|
result.version = updateVersion;
|
||||||
result.url = url;
|
result.url = url;
|
||||||
|
|
||||||
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
|
||||||
appSettings->setUpdateVersion(updateVersion);
|
appSettings->setUpdateVersion(updateVersion);
|
||||||
appSettings->setUpdateDownloadUrl(url.toStdString());
|
appSettings->setUpdateDownloadUrl(url.toStdString());
|
||||||
appSettings->save();
|
saveAppSettings = true;
|
||||||
|
|
||||||
if (!force && appSettings->getSkipUpdateForVersion() == updateVersion)
|
if (!force && appSettings->getSkipUpdateForVersion() == updateVersion)
|
||||||
{
|
{
|
||||||
@@ -153,7 +133,6 @@ void QtUpdateChecker::check(bool force, std::function<void(Result)> callback)
|
|||||||
if (val == 1)
|
if (val == 1)
|
||||||
{
|
{
|
||||||
appSettings->setSkipUpdateForVersion(updateVersion);
|
appSettings->setSkipUpdateForVersion(updateVersion);
|
||||||
appSettings->save();
|
|
||||||
}
|
}
|
||||||
else if (val == 2)
|
else if (val == 2)
|
||||||
{
|
{
|
||||||
@@ -163,6 +142,11 @@ void QtUpdateChecker::check(bool force, std::function<void(Result)> callback)
|
|||||||
}
|
}
|
||||||
while (false);
|
while (false);
|
||||||
|
|
||||||
|
if (saveAppSettings)
|
||||||
|
{
|
||||||
|
appSettings->save();
|
||||||
|
}
|
||||||
|
|
||||||
request->deleteLater();
|
request->deleteLater();
|
||||||
|
|
||||||
callback(result);
|
callback(result);
|
||||||
|
|||||||
@@ -7,17 +7,17 @@
|
|||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "ApplicationSettings.h"
|
||||||
#include "AppPath.h"
|
#include "AppPath.h"
|
||||||
#include "MessageLoadProject.h"
|
|
||||||
#include "ResourcePaths.h"
|
|
||||||
#include "Version.h"
|
|
||||||
|
|
||||||
#include "License.h"
|
#include "License.h"
|
||||||
|
#include "MessageLoadProject.h"
|
||||||
|
#include "ProjectSettings.h"
|
||||||
#include "PublicKey.h"
|
#include "PublicKey.h"
|
||||||
#include "QtUpdateCheckerWidget.h"
|
#include "QtUpdateCheckerWidget.h"
|
||||||
|
#include "QtNewsWidget.h"
|
||||||
|
#include "ResourcePaths.h"
|
||||||
#include "utilityQt.h"
|
#include "utilityQt.h"
|
||||||
#include "ApplicationSettings.h"
|
#include "Version.h"
|
||||||
#include "ProjectSettings.h"
|
|
||||||
|
|
||||||
QtRecentProjectButton::QtRecentProjectButton(QWidget* parent)
|
QtRecentProjectButton::QtRecentProjectButton(QWidget* parent)
|
||||||
: QPushButton(parent)
|
: QPushButton(parent)
|
||||||
@@ -93,7 +93,7 @@ QtStartScreen::QtStartScreen(QWidget *parent)
|
|||||||
|
|
||||||
QSize QtStartScreen::sizeHint() const
|
QSize QtStartScreen::sizeHint() const
|
||||||
{
|
{
|
||||||
return QSize(570, 600);
|
return QSize(570, 630);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtStartScreen::updateButtons()
|
void QtStartScreen::updateButtons()
|
||||||
@@ -153,39 +153,39 @@ void QtStartScreen::setupStartScreen()
|
|||||||
addLogo();
|
addLogo();
|
||||||
|
|
||||||
QHBoxLayout* layout = new QHBoxLayout();
|
QHBoxLayout* layout = new QHBoxLayout();
|
||||||
layout->setContentsMargins(15, 170, 15, 10);
|
layout->setContentsMargins(15, 170, 15, 0);
|
||||||
layout->setSpacing(1);
|
layout->setSpacing(1);
|
||||||
m_content->setLayout(layout);
|
m_content->setLayout(layout);
|
||||||
|
|
||||||
{
|
{
|
||||||
QVBoxLayout* col = new QVBoxLayout();
|
QVBoxLayout* col = new QVBoxLayout();
|
||||||
layout->addLayout(col, 2);
|
layout->addLayout(col, 3);
|
||||||
|
|
||||||
QLabel* versionLabel = new QLabel(("Version " + Version::getApplicationVersion().toDisplayString()).c_str(), this);
|
QLabel* versionLabel = new QLabel(("Version " + Version::getApplicationVersion().toDisplayString()).c_str(), this);
|
||||||
versionLabel->setObjectName("versionLabel");
|
versionLabel->setObjectName("boldLabel");
|
||||||
col->addWidget(versionLabel);
|
col->addWidget(versionLabel);
|
||||||
|
|
||||||
QtUpdateCheckerWidget* checker = new QtUpdateCheckerWidget(this);
|
QtUpdateCheckerWidget* checker = new QtUpdateCheckerWidget(this);
|
||||||
col->addWidget(checker);
|
col->addWidget(checker);
|
||||||
|
|
||||||
col->addSpacing(30);
|
col->addSpacing(15);
|
||||||
|
|
||||||
if (license.isValid())
|
if (license.isValid())
|
||||||
{
|
{
|
||||||
std::string licenseString = license.getLicenseInfo();
|
std::string licenseString = license.getLicenseInfo();
|
||||||
|
|
||||||
QLabel* licenseHeader = new QLabel("Licensed to:");
|
QLabel* licenseHeader = new QLabel("Licensed to:");
|
||||||
licenseHeader->setObjectName("licenseHeaderLabel");
|
licenseHeader->setObjectName("boldLabel");
|
||||||
col->addWidget(licenseHeader);
|
col->addWidget(licenseHeader);
|
||||||
col->addSpacing(2);
|
col->addSpacing(2);
|
||||||
QLabel* licenseLabel = new QLabel(licenseString.c_str());
|
QLabel* licenseLabel = new QLabel(licenseString.c_str());
|
||||||
licenseLabel->setObjectName("licenseLabel");
|
licenseLabel->setObjectName("textLabel");
|
||||||
col->addWidget(licenseLabel);
|
col->addWidget(licenseLabel);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QLabel* licenseHeader = new QLabel("Not licensed for<br />commercial use.");
|
QLabel* licenseHeader = new QLabel("Not licensed for<br />commercial use.");
|
||||||
licenseHeader->setObjectName("licenseHeaderLabel");
|
licenseHeader->setObjectName("boldLabel");
|
||||||
col->addWidget(licenseHeader);
|
col->addWidget(licenseHeader);
|
||||||
|
|
||||||
QPushButton* upgradeButton = new QPushButton("upgrade");
|
QPushButton* upgradeButton = new QPushButton("upgrade");
|
||||||
@@ -195,6 +195,20 @@ void QtStartScreen::setupStartScreen()
|
|||||||
connect(upgradeButton, &QPushButton::clicked, [this](){ emit openEnterLicenseDialog(); });
|
connect(upgradeButton, &QPushButton::clicked, [this](){ emit openEnterLicenseDialog(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
col->addSpacing(15);
|
||||||
|
|
||||||
|
{
|
||||||
|
QLabel* newsHeader = new QLabel("News:");
|
||||||
|
newsHeader->setObjectName("boldLabel");
|
||||||
|
col->addWidget(newsHeader);
|
||||||
|
|
||||||
|
QtNewsWidget* newsWidget = new QtNewsWidget(this);
|
||||||
|
col->addWidget(newsWidget);
|
||||||
|
|
||||||
|
connect(checker, &QtUpdateCheckerWidget::updateReceived, newsWidget, &QtNewsWidget::updateNews);
|
||||||
|
}
|
||||||
|
|
||||||
|
col->addSpacing(15);
|
||||||
col->addStretch();
|
col->addStretch();
|
||||||
|
|
||||||
QPushButton* newProjectButton = new QPushButton("New Project", this);
|
QPushButton* newProjectButton = new QPushButton("New Project", this);
|
||||||
@@ -212,23 +226,21 @@ void QtStartScreen::setupStartScreen()
|
|||||||
openProjectButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
openProjectButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
connect(openProjectButton, &QPushButton::clicked, this, &QtStartScreen::handleOpenProjectButton);
|
connect(openProjectButton, &QPushButton::clicked, this, &QtStartScreen::handleOpenProjectButton);
|
||||||
col->addWidget(openProjectButton);
|
col->addWidget(openProjectButton);
|
||||||
|
|
||||||
layout->addStretch(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layout->addSpacing(50);
|
||||||
|
|
||||||
{
|
{
|
||||||
QVBoxLayout* col = new QVBoxLayout();
|
QVBoxLayout* col = new QVBoxLayout();
|
||||||
layout->addLayout(col, 1);
|
layout->addLayout(col, 1);
|
||||||
|
|
||||||
QLabel* recentProjectsLabel = new QLabel("Recent Projects: ", this);
|
QLabel* recentProjectsLabel = new QLabel("Recent Projects: ", this);
|
||||||
recentProjectsLabel->setObjectName("recentLabel");
|
recentProjectsLabel->setObjectName("titleLabel");
|
||||||
col->addWidget(recentProjectsLabel);
|
col->addWidget(recentProjectsLabel);
|
||||||
|
|
||||||
col->addSpacing(20);
|
col->addSpacing(20);
|
||||||
|
|
||||||
for (int i = 0
|
for (int i = 0; i < ApplicationSettings::getInstance()->getMaxRecentProjectsCount(); i++)
|
||||||
; i < ApplicationSettings::getInstance()->getMaxRecentProjectsCount()
|
|
||||||
; i++)
|
|
||||||
{
|
{
|
||||||
QtRecentProjectButton* button = new QtRecentProjectButton(this);
|
QtRecentProjectButton* button = new QtRecentProjectButton(this);
|
||||||
button->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
|
button->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac
|
||||||
|
|||||||
@@ -137,6 +137,16 @@ void utility::killRunningProcesses()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int utility::getIdealThreadCount()
|
||||||
|
{
|
||||||
|
int threadCount = QThread::idealThreadCount();
|
||||||
|
if (getOsType() == OS_WINDOWS)
|
||||||
|
{
|
||||||
|
threadCount -= 1;
|
||||||
|
}
|
||||||
|
return std::max(1, threadCount);
|
||||||
|
}
|
||||||
|
|
||||||
OsType utility::getOsType()
|
OsType utility::getOsType()
|
||||||
{
|
{
|
||||||
if (QSysInfo::windowsVersion() != QSysInfo::WV_None)
|
if (QSysInfo::windowsVersion() != QSysInfo::WV_None)
|
||||||
@@ -154,14 +164,21 @@ OsType utility::getOsType()
|
|||||||
return OS_UNKNOWN;
|
return OS_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
int utility::getIdealThreadCount()
|
std::string utility::getOsTypeString()
|
||||||
{
|
{
|
||||||
int threadCount = QThread::idealThreadCount();
|
// WARNING: Don't change these string. The server API relies on them.
|
||||||
if (getOsType() == OS_WINDOWS)
|
switch (utility::getOsType())
|
||||||
{
|
{
|
||||||
threadCount -= 1;
|
case OS_WINDOWS:
|
||||||
|
return "windows";
|
||||||
|
case OS_MAC:
|
||||||
|
return "macOS";
|
||||||
|
case OS_LINUX:
|
||||||
|
return "linux";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return std::max(1, threadCount);
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool utility::saveLicense(const License* license)
|
bool utility::saveLicense(const License* license)
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ namespace utility
|
|||||||
);
|
);
|
||||||
|
|
||||||
void killRunningProcesses();
|
void killRunningProcesses();
|
||||||
|
|
||||||
int getIdealThreadCount();
|
int getIdealThreadCount();
|
||||||
|
|
||||||
OsType getOsType();
|
OsType getOsType();
|
||||||
|
std::string getOsTypeString();
|
||||||
|
|
||||||
bool saveLicense(const License* license);
|
bool saveLicense(const License* license);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user