diff --git a/bin/app/data/gui/startscreen/startscreen.css b/bin/app/data/gui/startscreen/startscreen.css index 6b3cff93..35d47fdc 100644 --- a/bin/app/data/gui/startscreen/startscreen.css +++ b/bin/app/data/gui/startscreen/startscreen.css @@ -29,19 +29,38 @@ border-radius: 10px; } -#recentLabel { +#titleLabel { color: black; font-size: 16px; font-weight: bold; margin-left: 6px; } -#versionLabel { +#textLabel { + color: black; + font-size: 12px; +} + +#boldLabel { color: black; font-size: 12px; 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 { margin: 1px 0 3px; text-align: left; @@ -57,19 +76,3 @@ color: black; text-decoration: none; } - -#licenseHeaderLabel { - color: black; - font-size: 12px; - font-weight: bold; -} - -#licenseLabel { - color: black; - font-size: 12px; -} - -#welcomeLabel { - color: black; - font-size: 12px; -} diff --git a/bin/app/user/ApplicationSettings_template.xml b/bin/app/user/ApplicationSettings_template.xml index cede33f6..7ad86d6a 100644 --- a/bin/app/user/ApplicationSettings_template.xml +++ b/bin/app/user/ApplicationSettings_template.xml @@ -97,6 +97,7 @@ + diff --git a/src/lib/LicenseChecker.cpp b/src/lib/LicenseChecker.cpp index 976ce5d1..322bd963 100644 --- a/src/lib/LicenseChecker.cpp +++ b/src/lib/LicenseChecker.cpp @@ -24,7 +24,7 @@ std::shared_ptr LicenseChecker::getInstance() return s_instance; } -std::string LicenseChecker::getCurrentLicenseString() const +std::string LicenseChecker::getCurrentLicenseString() { License license; bool isLoaded = license.loadFromEncodedString( @@ -38,7 +38,7 @@ std::string LicenseChecker::getCurrentLicenseString() const return ""; } -void LicenseChecker::saveCurrentLicenseString(const std::string& licenseString) const +void LicenseChecker::saveCurrentLicenseString(const std::string& licenseString) { License license; bool isLoaded = license.loadFromString(licenseString); @@ -55,7 +55,7 @@ bool LicenseChecker::isCurrentLicenseValid() return checkCurrentLicense() == LICENSE_VALID; } -LicenseChecker::LicenseState LicenseChecker::checkCurrentLicense() const +LicenseChecker::LicenseState LicenseChecker::checkCurrentLicense() { ApplicationSettings* appSettings = ApplicationSettings::getInstance().get(); if (appSettings == nullptr) @@ -96,7 +96,7 @@ LicenseChecker::LicenseState LicenseChecker::checkCurrentLicense() const return checkLicense(license); } -LicenseChecker::LicenseState LicenseChecker::checkLicenseString(const std::string& licenseString) const +LicenseChecker::LicenseState LicenseChecker::checkLicenseString(const std::string& licenseString) { if (licenseString.size() == 0) { @@ -115,7 +115,7 @@ LicenseChecker::LicenseState LicenseChecker::checkLicenseString(const std::strin return checkLicense(license); } -MessageEnteredLicense::LicenseType LicenseChecker::getCurrentLicenseType() const +MessageEnteredLicense::LicenseType LicenseChecker::getCurrentLicenseType() { License license; bool isLoaded = license.loadFromEncodedString( @@ -143,7 +143,7 @@ MessageEnteredLicense::LicenseType LicenseChecker::getCurrentLicenseType() const 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) { @@ -174,11 +174,28 @@ MessageEnteredLicense::LicenseType LicenseChecker::getLicenseType(const std::str 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::LicenseState LicenseChecker::checkLicense(License& license) const +LicenseChecker::LicenseState LicenseChecker::checkLicense(License& license) { if (license.isExpired()) { diff --git a/src/lib/LicenseChecker.h b/src/lib/LicenseChecker.h index d16a2f88..e97cf21f 100644 --- a/src/lib/LicenseChecker.h +++ b/src/lib/LicenseChecker.h @@ -23,22 +23,24 @@ public: ~LicenseChecker() = default; - std::string getCurrentLicenseString() const; - void saveCurrentLicenseString(const std::string& licenseString) const; + static std::string getCurrentLicenseString(); + static void saveCurrentLicenseString(const std::string& licenseString); - bool isCurrentLicenseValid(); - LicenseState checkCurrentLicense() const; - LicenseState checkLicenseString(const std::string& licenseString) const; + static bool isCurrentLicenseValid(); + static LicenseState checkCurrentLicense(); + static LicenseState checkLicenseString(const std::string& licenseString); - MessageEnteredLicense::LicenseType getCurrentLicenseType() const; - MessageEnteredLicense::LicenseType getLicenseType(const std::string& licenseString) const; + static MessageEnteredLicense::LicenseType getCurrentLicenseType(); + static MessageEnteredLicense::LicenseType getLicenseType(const std::string& licenseString); + + static std::string getCurrentLicenseTypeString(); private: LicenseChecker(); LicenseChecker(const LicenseChecker&) = delete; void operator=(const LicenseChecker&) = delete; - LicenseState checkLicense(License& license) const; + static LicenseState checkLicense(License& license); static std::shared_ptr s_instance; }; diff --git a/src/lib/settings/ApplicationSettings.cpp b/src/lib/settings/ApplicationSettings.cpp index e343eb7b..26fb7191 100644 --- a/src/lib/settings/ApplicationSettings.cpp +++ b/src/lib/settings/ApplicationSettings.cpp @@ -597,6 +597,16 @@ Version ApplicationSettings::getUpdateVersion() const return Version::fromString(getValue("user/update_check/update_version", "2017.1.0")); } +std::string ApplicationSettings::getUpdateNews() const +{ + return getValue("user/update_check/news", ""); +} + +void ApplicationSettings::setUpdateNews(const std::string& news) +{ + setValue("user/update_check/news", news); +} + void ApplicationSettings::setUpdateVersion(const Version& version) { if (version.isValid()) diff --git a/src/lib/settings/ApplicationSettings.h b/src/lib/settings/ApplicationSettings.h index 7ae192a8..b7283f3c 100644 --- a/src/lib/settings/ApplicationSettings.h +++ b/src/lib/settings/ApplicationSettings.h @@ -167,6 +167,9 @@ public: Version getUpdateVersion() const; void setUpdateVersion(const Version& version); + std::string getUpdateNews() const; + void setUpdateNews(const std::string& news); + bool getSeenErrorHelpMessage() const; void setSeenErrorHelpMessage(bool seen); diff --git a/src/lib_gui/CMakeLists.txt b/src/lib_gui/CMakeLists.txt index d5ee7d39..eab2dc79 100644 --- a/src/lib_gui/CMakeLists.txt +++ b/src/lib_gui/CMakeLists.txt @@ -45,6 +45,8 @@ add_files( qt/element/QtListBoxItem.h qt/element/QtLocationPicker.cpp qt/element/QtLocationPicker.h + qt/element/QtNewsWidget.cpp + qt/element/QtNewsWidget.h qt/element/QtPathListBox.cpp qt/element/QtPathListBox.h qt/element/QtPathListBoxItem.cpp @@ -67,6 +69,8 @@ add_files( qt/element/QtStatusBar.h qt/element/QtTable.cpp qt/element/QtTable.h + qt/element/QtTextEdit.cpp + qt/element/QtTextEdit.h qt/element/QtTooltip.cpp qt/element/QtTooltip.h qt/element/QtUndoRedo.cpp diff --git a/src/lib_gui/qt/element/QtNewsWidget.cpp b/src/lib_gui/qt/element/QtNewsWidget.cpp new file mode 100644 index 00000000..dbd3f0e6 --- /dev/null +++ b/src/lib_gui/qt/element/QtNewsWidget.cpp @@ -0,0 +1,227 @@ +#include "QtNewsWidget.h" + +#include +#include +#include +#include +#include + +#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": "Hello World!", + + // 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); + } + } +} diff --git a/src/lib_gui/qt/element/QtNewsWidget.h b/src/lib_gui/qt/element/QtNewsWidget.h new file mode 100644 index 00000000..a92d657a --- /dev/null +++ b/src/lib_gui/qt/element/QtNewsWidget.h @@ -0,0 +1,33 @@ +#ifndef QT_NEWS_WIDGET_H +#define QT_NEWS_WIDGET_H + +#include + +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 diff --git a/src/lib_gui/qt/element/QtTextEdit.cpp b/src/lib_gui/qt/element/QtTextEdit.cpp new file mode 100644 index 00000000..1be11982 --- /dev/null +++ b/src/lib_gui/qt/element/QtTextEdit.cpp @@ -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); +} diff --git a/src/lib_gui/qt/element/QtTextEdit.h b/src/lib_gui/qt/element/QtTextEdit.h new file mode 100644 index 00000000..a9ae8bae --- /dev/null +++ b/src/lib_gui/qt/element/QtTextEdit.h @@ -0,0 +1,23 @@ +#ifndef QT_TEXT_EDIT_H +#define QT_TEXT_EDIT_H + +#include + +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 diff --git a/src/lib_gui/qt/element/QtUpdateCheckerWidget.cpp b/src/lib_gui/qt/element/QtUpdateCheckerWidget.cpp index 306b6220..2425e7fd 100644 --- a/src/lib_gui/qt/element/QtUpdateCheckerWidget.cpp +++ b/src/lib_gui/qt/element/QtUpdateCheckerWidget.cpp @@ -99,6 +99,8 @@ void QtUpdateCheckerWidget::checkUpdate(bool force) { setDownloadUrl(result.url); } + + emit updateReceived(); } ); } diff --git a/src/lib_gui/qt/element/QtUpdateCheckerWidget.h b/src/lib_gui/qt/element/QtUpdateCheckerWidget.h index ff9db513..6c3ffdb2 100644 --- a/src/lib_gui/qt/element/QtUpdateCheckerWidget.h +++ b/src/lib_gui/qt/element/QtUpdateCheckerWidget.h @@ -10,10 +10,15 @@ class QPushButton; class QtUpdateCheckerWidget : public QWidget { + Q_OBJECT + public: QtUpdateCheckerWidget(QWidget* parent = nullptr); virtual ~QtUpdateCheckerWidget(); +signals: + void updateReceived(); + private: void checkUpdate(bool force); void setDownloadUrl(QString url); diff --git a/src/lib_gui/qt/network/QtUpdateChecker.cpp b/src/lib_gui/qt/network/QtUpdateChecker.cpp index ed3d8a74..844522a8 100644 --- a/src/lib_gui/qt/network/QtUpdateChecker.cpp +++ b/src/lib_gui/qt/network/QtUpdateChecker.cpp @@ -36,27 +36,10 @@ void QtUpdateChecker::check(bool force, std::function callback) appSettings->setUpdateDownloadUrl(""); appSettings->save(); - QString urlString = "https://www.sourcetrail.com/api/v1/versions/latest"; + QString urlString = "https://www.sourcetrail.com/api/v2/versions/latest"; // OS - std::string osString; - - 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; - } - + std::string osString = utility::getOsTypeString(); urlString += ("?os=" + osString).c_str(); // architecture @@ -68,21 +51,7 @@ void QtUpdateChecker::check(bool force, std::function callback) urlString += ("&version=" + Version::getApplicationVersion().toDisplayString()).c_str(); // license - std::string licenseString; - 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; - } - + std::string licenseString = LicenseChecker::getCurrentLicenseTypeString(); urlString += ("&license=" + licenseString).c_str(); // user token @@ -103,15 +72,27 @@ void QtUpdateChecker::check(bool force, std::function callback) { Result result; + ApplicationSettings* appSettings = ApplicationSettings::getInstance().get(); + bool saveAppSettings = false; + do { - QJsonDocument doc = QJsonDocument::fromJson(bytes); - if (!doc.isObject()) + QJsonParseError error; + 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; } + 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 url = doc.object().find("url")->toString(); @@ -129,10 +110,9 @@ void QtUpdateChecker::check(bool force, std::function callback) result.version = updateVersion; result.url = url; - ApplicationSettings* appSettings = ApplicationSettings::getInstance().get(); appSettings->setUpdateVersion(updateVersion); appSettings->setUpdateDownloadUrl(url.toStdString()); - appSettings->save(); + saveAppSettings = true; if (!force && appSettings->getSkipUpdateForVersion() == updateVersion) { @@ -153,7 +133,6 @@ void QtUpdateChecker::check(bool force, std::function callback) if (val == 1) { appSettings->setSkipUpdateForVersion(updateVersion); - appSettings->save(); } else if (val == 2) { @@ -163,6 +142,11 @@ void QtUpdateChecker::check(bool force, std::function callback) } while (false); + if (saveAppSettings) + { + appSettings->save(); + } + request->deleteLater(); callback(result); diff --git a/src/lib_gui/qt/window/QtStartScreen.cpp b/src/lib_gui/qt/window/QtStartScreen.cpp index 1bcb56a2..b56f609e 100644 --- a/src/lib_gui/qt/window/QtStartScreen.cpp +++ b/src/lib_gui/qt/window/QtStartScreen.cpp @@ -7,17 +7,17 @@ #include #include +#include "ApplicationSettings.h" #include "AppPath.h" -#include "MessageLoadProject.h" -#include "ResourcePaths.h" -#include "Version.h" - #include "License.h" +#include "MessageLoadProject.h" +#include "ProjectSettings.h" #include "PublicKey.h" #include "QtUpdateCheckerWidget.h" +#include "QtNewsWidget.h" +#include "ResourcePaths.h" #include "utilityQt.h" -#include "ApplicationSettings.h" -#include "ProjectSettings.h" +#include "Version.h" QtRecentProjectButton::QtRecentProjectButton(QWidget* parent) : QPushButton(parent) @@ -93,7 +93,7 @@ QtStartScreen::QtStartScreen(QWidget *parent) QSize QtStartScreen::sizeHint() const { - return QSize(570, 600); + return QSize(570, 630); } void QtStartScreen::updateButtons() @@ -153,39 +153,39 @@ void QtStartScreen::setupStartScreen() addLogo(); QHBoxLayout* layout = new QHBoxLayout(); - layout->setContentsMargins(15, 170, 15, 10); + layout->setContentsMargins(15, 170, 15, 0); layout->setSpacing(1); m_content->setLayout(layout); { QVBoxLayout* col = new QVBoxLayout(); - layout->addLayout(col, 2); + layout->addLayout(col, 3); QLabel* versionLabel = new QLabel(("Version " + Version::getApplicationVersion().toDisplayString()).c_str(), this); - versionLabel->setObjectName("versionLabel"); + versionLabel->setObjectName("boldLabel"); col->addWidget(versionLabel); QtUpdateCheckerWidget* checker = new QtUpdateCheckerWidget(this); col->addWidget(checker); - col->addSpacing(30); + col->addSpacing(15); if (license.isValid()) { std::string licenseString = license.getLicenseInfo(); QLabel* licenseHeader = new QLabel("Licensed to:"); - licenseHeader->setObjectName("licenseHeaderLabel"); + licenseHeader->setObjectName("boldLabel"); col->addWidget(licenseHeader); col->addSpacing(2); QLabel* licenseLabel = new QLabel(licenseString.c_str()); - licenseLabel->setObjectName("licenseLabel"); + licenseLabel->setObjectName("textLabel"); col->addWidget(licenseLabel); } else { QLabel* licenseHeader = new QLabel("Not licensed for
commercial use."); - licenseHeader->setObjectName("licenseHeaderLabel"); + licenseHeader->setObjectName("boldLabel"); col->addWidget(licenseHeader); QPushButton* upgradeButton = new QPushButton("upgrade"); @@ -195,6 +195,20 @@ void QtStartScreen::setupStartScreen() 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(); QPushButton* newProjectButton = new QPushButton("New Project", this); @@ -212,23 +226,21 @@ void QtStartScreen::setupStartScreen() openProjectButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(openProjectButton, &QPushButton::clicked, this, &QtStartScreen::handleOpenProjectButton); col->addWidget(openProjectButton); - - layout->addStretch(2); } + layout->addSpacing(50); + { QVBoxLayout* col = new QVBoxLayout(); layout->addLayout(col, 1); QLabel* recentProjectsLabel = new QLabel("Recent Projects: ", this); - recentProjectsLabel->setObjectName("recentLabel"); + recentProjectsLabel->setObjectName("titleLabel"); col->addWidget(recentProjectsLabel); col->addSpacing(20); - for (int i = 0 - ; i < ApplicationSettings::getInstance()->getMaxRecentProjectsCount() - ; i++) + for (int i = 0; i < ApplicationSettings::getInstance()->getMaxRecentProjectsCount(); i++) { QtRecentProjectButton* button = new QtRecentProjectButton(this); button->setAttribute(Qt::WA_LayoutUsesWidgetRect); // fixes layouting on Mac diff --git a/src/lib_gui/utility/utilityApp.cpp b/src/lib_gui/utility/utilityApp.cpp index ff09d610..f2c477c3 100644 --- a/src/lib_gui/utility/utilityApp.cpp +++ b/src/lib_gui/utility/utilityApp.cpp @@ -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() { if (QSysInfo::windowsVersion() != QSysInfo::WV_None) @@ -154,14 +164,21 @@ OsType utility::getOsType() return OS_UNKNOWN; } -int utility::getIdealThreadCount() +std::string utility::getOsTypeString() { - int threadCount = QThread::idealThreadCount(); - if (getOsType() == OS_WINDOWS) + // WARNING: Don't change these string. The server API relies on them. + 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) diff --git a/src/lib_gui/utility/utilityApp.h b/src/lib_gui/utility/utilityApp.h index 9ab8376a..9a33c03c 100644 --- a/src/lib_gui/utility/utilityApp.h +++ b/src/lib_gui/utility/utilityApp.h @@ -15,17 +15,17 @@ namespace utility std::string executeProcess(const std::string& command, const FilePath& workingDirectory = FilePath(), const int timeout = 30000); std::string executeProcessUntilNoOutput(const std::string& command, const FilePath& workingDirectory, int waitTime = 10000); int executeProcessAndGetExitCode( - const std::wstring& commandPath, - const std::vector& commandArguments, - const FilePath& workingDirectory = FilePath(), + const std::wstring& commandPath, + const std::vector& commandArguments, + const FilePath& workingDirectory = FilePath(), const int timeout = 30000 ); void killRunningProcesses(); - int getIdealThreadCount(); OsType getOsType(); + std::string getOsTypeString(); bool saveLicense(const License* license); }