<fix, feature>(core, ui): version system upgrade.
1. can notice user withdraw version now. 2. fix software not restart when signal caught. 3. improve ui.
This commit is contained in:
parent
5cc72a35de
commit
2f64e4300b
@ -177,6 +177,7 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
QApplication::exit(RESTART_CODE);
|
||||||
QMessageBox::information(
|
QMessageBox::information(
|
||||||
nullptr, _("A serious error has occurred"),
|
nullptr, _("A serious error has occurred"),
|
||||||
_("Oh no! GpgFrontend caught a serious error in the software, so it "
|
_("Oh no! GpgFrontend caught a serious error in the software, so it "
|
||||||
|
@ -8,6 +8,7 @@ aux_source_directory(./help UI_SOURCE)
|
|||||||
aux_source_directory(./settings UI_SOURCE)
|
aux_source_directory(./settings UI_SOURCE)
|
||||||
aux_source_directory(./function UI_SOURCE)
|
aux_source_directory(./function UI_SOURCE)
|
||||||
aux_source_directory(./details UI_SOURCE)
|
aux_source_directory(./details UI_SOURCE)
|
||||||
|
aux_source_directory(./data_struct UI_SOURCE)
|
||||||
|
|
||||||
if (SMTP_SUPPORT)
|
if (SMTP_SUPPORT)
|
||||||
aux_source_directory(./smtp UI_SOURCE)
|
aux_source_directory(./smtp UI_SOURCE)
|
||||||
|
@ -371,8 +371,16 @@ void KeyMgmt::slotExportKeyToKeyPackage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KeyMgmt::slotExportKeyToClipboard() {
|
void KeyMgmt::slotExportKeyToClipboard() {
|
||||||
ByteArrayPtr key_export_data = nullptr;
|
|
||||||
auto keys_checked = key_list_->getChecked();
|
auto keys_checked = key_list_->getChecked();
|
||||||
|
if (keys_checked->empty()) {
|
||||||
|
QMessageBox::critical(
|
||||||
|
this, _("Forbidden"),
|
||||||
|
_("Please check some keys before doing this operation."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArrayPtr key_export_data = nullptr;
|
||||||
if (!GpgKeyImportExporter::GetInstance().ExportKeys(keys_checked,
|
if (!GpgKeyImportExporter::GetInstance().ExportKeys(keys_checked,
|
||||||
key_export_data)) {
|
key_export_data)) {
|
||||||
return;
|
return;
|
||||||
|
@ -117,12 +117,7 @@ void MainWindow::init() noexcept {
|
|||||||
emit loaded();
|
emit loaded();
|
||||||
|
|
||||||
#ifdef RELEASE
|
#ifdef RELEASE
|
||||||
QString baseUrl =
|
auto version_thread = new VersionCheckThread();
|
||||||
"https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
|
|
||||||
QNetworkRequest request;
|
|
||||||
request.setUrl(QUrl(baseUrl));
|
|
||||||
auto* replay = networkAccessManager->get(request);
|
|
||||||
auto version_thread = new VersionCheckThread(replay);
|
|
||||||
|
|
||||||
connect(version_thread, SIGNAL(finished()), version_thread,
|
connect(version_thread, SIGNAL(finished()), version_thread,
|
||||||
SLOT(deleteLater()));
|
SLOT(deleteLater()));
|
||||||
|
@ -244,8 +244,7 @@ class MainWindow : public QMainWindow {
|
|||||||
/**
|
/**
|
||||||
* @details called when need to upgrade.
|
* @details called when need to upgrade.
|
||||||
*/
|
*/
|
||||||
void slotVersionUpgrade(const QString& currentVersion,
|
void slotVersionUpgrade(const SoftwareVersion& version);
|
||||||
const QString& latestVersion);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
25
src/ui/data_struct/SoftwareVersion.cpp
Normal file
25
src/ui/data_struct/SoftwareVersion.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of GpgFrontend.
|
||||||
|
*
|
||||||
|
* GpgFrontend is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Foobar is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* The initial version of the source code is inherited from gpg4usb-team.
|
||||||
|
* Their source code version also complies with GNU General Public License.
|
||||||
|
*
|
||||||
|
* The source code version of this software was modified and released
|
||||||
|
* by Saturneric<eric@bktus.com> starting on May 12, 2021.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SoftwareVersion.h"
|
53
src/ui/data_struct/SoftwareVersion.h
Normal file
53
src/ui/data_struct/SoftwareVersion.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* This file is part of GpgFrontend.
|
||||||
|
*
|
||||||
|
* GpgFrontend is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Foobar is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* The initial version of the source code is inherited from gpg4usb-team.
|
||||||
|
* Their source code version also complies with GNU General Public License.
|
||||||
|
*
|
||||||
|
* The source code version of this software was modified and released
|
||||||
|
* by Saturneric<eric@bktus.com> starting on May 12, 2021.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GPGFRONTEND_SOFTWAREVERSION_H
|
||||||
|
#define GPGFRONTEND_SOFTWAREVERSION_H
|
||||||
|
|
||||||
|
#include <boost/date_time.hpp>
|
||||||
|
|
||||||
|
namespace GpgFrontend::UI {
|
||||||
|
struct SoftwareVersion {
|
||||||
|
std::string latest_version;
|
||||||
|
std::string current_version;
|
||||||
|
bool latest_prerelease = false;
|
||||||
|
bool latest_draft = false;
|
||||||
|
bool current_prerelease = false;
|
||||||
|
bool current_draft = false;
|
||||||
|
bool load_info_done = false;
|
||||||
|
std::string publish_date;
|
||||||
|
std::string release_note;
|
||||||
|
|
||||||
|
[[nodiscard]] bool NeedUpgrade() const {
|
||||||
|
return load_info_done && !latest_prerelease && !latest_draft &&
|
||||||
|
current_version < latest_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool VersionWithDrawn() const {
|
||||||
|
return load_info_done && current_prerelease && !current_draft;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace GpgFrontend::UI
|
||||||
|
|
||||||
|
#endif // GPGFRONTEND_SOFTWAREVERSION_H
|
@ -24,8 +24,7 @@
|
|||||||
|
|
||||||
#include "VersionCheckThread.h"
|
#include "VersionCheckThread.h"
|
||||||
|
|
||||||
#include <iterator>
|
#include <QMetaType>
|
||||||
#include <regex>
|
|
||||||
|
|
||||||
#include "GpgFrontendBuildInfo.h"
|
#include "GpgFrontendBuildInfo.h"
|
||||||
#include "json/json.hpp"
|
#include "json/json.hpp"
|
||||||
@ -33,45 +32,97 @@
|
|||||||
namespace GpgFrontend::UI {
|
namespace GpgFrontend::UI {
|
||||||
|
|
||||||
void VersionCheckThread::run() {
|
void VersionCheckThread::run() {
|
||||||
using namespace nlohmann;
|
|
||||||
|
|
||||||
LOG(INFO) << "get latest version from Github";
|
|
||||||
|
|
||||||
auto current_version = std::string("v") + std::to_string(VERSION_MAJOR) +
|
auto current_version = std::string("v") + std::to_string(VERSION_MAJOR) +
|
||||||
"." + std::to_string(VERSION_MINOR) + "." +
|
"." + std::to_string(VERSION_MINOR) + "." +
|
||||||
std::to_string(VERSION_PATCH);
|
std::to_string(VERSION_PATCH);
|
||||||
|
|
||||||
while (mNetworkReply->isRunning()) {
|
auto manager = new QNetworkAccessManager(nullptr);
|
||||||
QApplication::processEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mNetworkReply->error() != QNetworkReply::NoError) {
|
LOG(INFO) << "current version" << current_version;
|
||||||
|
|
||||||
|
std::string latest_version_url =
|
||||||
|
"https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
|
||||||
|
|
||||||
|
std::string current_version_url =
|
||||||
|
"https://api.github.com/repos/saturneric/gpgfrontend/releases/tags/" +
|
||||||
|
current_version;
|
||||||
|
|
||||||
|
QNetworkRequest latest_request, current_request;
|
||||||
|
latest_request.setUrl(QUrl(latest_version_url.c_str()));
|
||||||
|
current_request.setUrl(QUrl(current_version_url.c_str()));
|
||||||
|
auto reply = manager->get(latest_request);
|
||||||
|
while (reply->isRunning()) QApplication::processEvents();
|
||||||
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
LOG(ERROR) << "network error";
|
LOG(ERROR) << "network error";
|
||||||
|
manager->deleteLater();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bytes = mNetworkReply->readAll();
|
latest_reply_bytes_ = reply->readAll();
|
||||||
|
reply = manager->get(current_request);
|
||||||
auto reply_json = nlohmann::json::parse(bytes.toStdString());
|
while (reply->isRunning()) QApplication::processEvents();
|
||||||
|
current_reply_bytes_ = reply->readAll();
|
||||||
std::string latest_version = reply_json["tag_name"];
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
|
LOG(ERROR) << "network error";
|
||||||
LOG(INFO) << "latest version from Github" << latest_version;
|
manager->deleteLater();
|
||||||
|
return;
|
||||||
QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))");
|
|
||||||
auto version_match = re.match(latest_version.c_str());
|
|
||||||
if (version_match.hasMatch()) {
|
|
||||||
latest_version = version_match.captured(0).toStdString();
|
|
||||||
LOG(INFO) << "latest version matched" << latest_version;
|
|
||||||
} else {
|
|
||||||
latest_version = current_version;
|
|
||||||
LOG(WARNING) << "latest version unknown";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emit upgradeVersion(current_version.c_str(), latest_version.c_str());
|
SoftwareVersion version;
|
||||||
|
version.current_version = current_version;
|
||||||
|
|
||||||
|
try {
|
||||||
|
using namespace nlohmann;
|
||||||
|
|
||||||
|
auto latest_reply_json =
|
||||||
|
nlohmann::json::parse(latest_reply_bytes_.toStdString());
|
||||||
|
auto current_reply_json =
|
||||||
|
nlohmann::json::parse(current_reply_bytes_.toStdString());
|
||||||
|
|
||||||
|
std::string latest_version = latest_reply_json["tag_name"];
|
||||||
|
|
||||||
|
LOG(INFO) << "latest version from Github" << latest_version;
|
||||||
|
|
||||||
|
QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))");
|
||||||
|
auto version_match = re.match(latest_version.c_str());
|
||||||
|
if (version_match.hasMatch()) {
|
||||||
|
latest_version = version_match.captured(0).toStdString();
|
||||||
|
LOG(INFO) << "latest version matched" << latest_version;
|
||||||
|
} else {
|
||||||
|
latest_version = current_version;
|
||||||
|
LOG(WARNING) << "latest version unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool prerelease = latest_reply_json["prerelease"],
|
||||||
|
draft = latest_reply_json["draft"];
|
||||||
|
std::string publish_date = latest_reply_json["published_at"];
|
||||||
|
std::string release_note = latest_reply_json["body"];
|
||||||
|
version.latest_version = latest_version;
|
||||||
|
version.latest_prerelease = prerelease;
|
||||||
|
version.latest_draft = draft;
|
||||||
|
version.publish_date = publish_date;
|
||||||
|
version.release_note = release_note;
|
||||||
|
|
||||||
|
bool current_prerelease = current_reply_json["prerelease"],
|
||||||
|
current_draft = current_reply_json["draft"];
|
||||||
|
version.latest_prerelease = current_prerelease;
|
||||||
|
version.latest_draft = current_draft;
|
||||||
|
|
||||||
|
// loading done
|
||||||
|
version.load_info_done = true;
|
||||||
|
|
||||||
|
} catch (...) {
|
||||||
|
LOG(INFO) << "error occurred";
|
||||||
|
version.load_info_done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager->deleteLater();
|
||||||
|
|
||||||
|
emit upgradeVersion(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionCheckThread::VersionCheckThread(QNetworkReply* networkReply)
|
VersionCheckThread::VersionCheckThread() : QThread(nullptr) {
|
||||||
: mNetworkReply(networkReply) {}
|
qRegisterMetaType<SoftwareVersion>("SoftwareVersion");
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace GpgFrontend::UI
|
} // namespace GpgFrontend::UI
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#define GPGFRONTEND_VERSIONCHECKTHREAD_H
|
#define GPGFRONTEND_VERSIONCHECKTHREAD_H
|
||||||
|
|
||||||
#include "ui/GpgFrontendUI.h"
|
#include "ui/GpgFrontendUI.h"
|
||||||
|
#include "ui/data_struct/SoftwareVersion.h"
|
||||||
|
|
||||||
namespace GpgFrontend::UI {
|
namespace GpgFrontend::UI {
|
||||||
|
|
||||||
@ -33,18 +34,17 @@ class VersionCheckThread : public QThread {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit VersionCheckThread(QNetworkReply* networkReply);
|
explicit VersionCheckThread();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void upgradeVersion(const QString& currentVersion,
|
void upgradeVersion(SoftwareVersion version);
|
||||||
const QString& latestVersion);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void run() override;
|
void run() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QNetworkReply* mNetworkReply;
|
QByteArray latest_reply_bytes_, current_reply_bytes_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace GpgFrontend::UI
|
} // namespace GpgFrontend::UI
|
||||||
|
@ -163,14 +163,6 @@ UpdateTab::UpdateTab(QWidget* parent) : QWidget(parent) {
|
|||||||
latestVersionLabel->setWordWrap(true);
|
latestVersionLabel->setWordWrap(true);
|
||||||
|
|
||||||
upgradeLabel = new QLabel();
|
upgradeLabel = new QLabel();
|
||||||
upgradeLabel->setText(
|
|
||||||
"<center>" +
|
|
||||||
QString(_("The current version is less than the latest version on "
|
|
||||||
"github.")) +
|
|
||||||
"</center><center>" + _("Please click") +
|
|
||||||
" <a "
|
|
||||||
"href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
|
|
||||||
_("Here") + "</a> " + _("to download the latest version.") + "</center>");
|
|
||||||
upgradeLabel->setWordWrap(true);
|
upgradeLabel->setWordWrap(true);
|
||||||
upgradeLabel->setOpenExternalLinks(true);
|
upgradeLabel->setOpenExternalLinks(true);
|
||||||
upgradeLabel->setHidden(true);
|
upgradeLabel->setHidden(true);
|
||||||
@ -196,11 +188,7 @@ void UpdateTab::getLatestVersion() {
|
|||||||
|
|
||||||
LOG(INFO) << _("try to get latest version");
|
LOG(INFO) << _("try to get latest version");
|
||||||
|
|
||||||
QString base_url =
|
auto version_thread = new VersionCheckThread();
|
||||||
"https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
|
|
||||||
QNetworkRequest request;
|
|
||||||
request.setUrl(QUrl(base_url));
|
|
||||||
auto version_thread = new VersionCheckThread(manager->get(request));
|
|
||||||
|
|
||||||
connect(version_thread, SIGNAL(finished()), version_thread,
|
connect(version_thread, SIGNAL(finished()), version_thread,
|
||||||
SLOT(deleteLater()));
|
SLOT(deleteLater()));
|
||||||
@ -210,16 +198,33 @@ void UpdateTab::getLatestVersion() {
|
|||||||
version_thread->start();
|
version_thread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateTab::slotShowVersionStatus(const QString& current,
|
void UpdateTab::slotShowVersionStatus(const SoftwareVersion& version) {
|
||||||
const QString& server) {
|
|
||||||
this->pb->setHidden(true);
|
this->pb->setHidden(true);
|
||||||
|
|
||||||
latestVersionLabel->setText("<center><b>" +
|
latestVersionLabel->setText("<center><b>" +
|
||||||
QString(_("Latest Version From Github")) + ": " +
|
QString(_("Latest Version From Github")) + ": " +
|
||||||
server + "</b></center>");
|
version.latest_version.c_str() + "</b></center>");
|
||||||
|
|
||||||
if (current < server) {
|
if (version.NeedUpgrade()) {
|
||||||
|
upgradeLabel->setText(
|
||||||
|
"<center>" +
|
||||||
|
QString(_("The current version is less than the latest version on "
|
||||||
|
"github.")) +
|
||||||
|
"</center><center>" + _("Please click") +
|
||||||
|
" <a "
|
||||||
|
"href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
|
||||||
|
_("Here") + "</a> " + _("to download the latest stable version.") +
|
||||||
|
"</center>");
|
||||||
upgradeLabel->show();
|
upgradeLabel->show();
|
||||||
|
} else if (version.VersionWithDrawn()) {
|
||||||
|
upgradeLabel->setText(
|
||||||
|
"<center>" +
|
||||||
|
QString(_("This version has serious problems and has been withdrawn. "
|
||||||
|
"Please stop using it immediately.")) +
|
||||||
|
"</center><center>" + _("Please click") +
|
||||||
|
" <a "
|
||||||
|
"href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
|
||||||
|
_("Here") + "</a> " + _("to download the latest stable version.") +
|
||||||
|
"</center>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include "gpg/GpgContext.h"
|
#include "gpg/GpgContext.h"
|
||||||
#include "ui/GpgFrontendUI.h"
|
#include "ui/GpgFrontendUI.h"
|
||||||
|
#include "ui/data_struct/SoftwareVersion.h"
|
||||||
|
|
||||||
namespace GpgFrontend::UI {
|
namespace GpgFrontend::UI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,7 +75,7 @@ class UpdateTab : public QWidget {
|
|||||||
void getLatestVersion();
|
void getLatestVersion();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotShowVersionStatus(const QString& current, const QString& server);
|
void slotShowVersionStatus(const SoftwareVersion& version);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void replyFromUpdateServer(QByteArray data);
|
void replyFromUpdateServer(QByteArray data);
|
||||||
|
@ -499,13 +499,12 @@ void MainWindow::uploadKeyToServer() {
|
|||||||
|
|
||||||
void MainWindow::slotOpenFile(QString& path) { edit->slotOpenFile(path); }
|
void MainWindow::slotOpenFile(QString& path) { edit->slotOpenFile(path); }
|
||||||
|
|
||||||
void MainWindow::slotVersionUpgrade(const QString& currentVersion,
|
void MainWindow::slotVersionUpgrade(const SoftwareVersion& version) {
|
||||||
const QString& latestVersion) {
|
|
||||||
LOG(INFO) << _("called");
|
LOG(INFO) << _("called");
|
||||||
if (currentVersion < latestVersion) {
|
if (version.NeedUpgrade()) {
|
||||||
statusBar()->showMessage(
|
statusBar()->showMessage(
|
||||||
QString(_("GpgFrontend Upgradeable (New Version: %1)."))
|
QString(_("GpgFrontend Upgradeable (New Version: %1)."))
|
||||||
.arg(latestVersion),
|
.arg(version.latest_version.c_str()),
|
||||||
30000);
|
30000);
|
||||||
auto update_button = new QPushButton("Update GpgFrontend", this);
|
auto update_button = new QPushButton("Update GpgFrontend", this);
|
||||||
connect(update_button, &QPushButton::clicked, [=]() {
|
connect(update_button, &QPushButton::clicked, [=]() {
|
||||||
@ -513,17 +512,19 @@ void MainWindow::slotVersionUpgrade(const QString& currentVersion,
|
|||||||
about_dialog->show();
|
about_dialog->show();
|
||||||
});
|
});
|
||||||
statusBar()->addPermanentWidget(update_button, 0);
|
statusBar()->addPermanentWidget(update_button, 0);
|
||||||
} else if (currentVersion > latestVersion) {
|
} else if (version.VersionWithDrawn()) {
|
||||||
QMessageBox::warning(
|
QMessageBox::warning(
|
||||||
this, _("Unreleased Version"),
|
this, _("Withdrawn Version"),
|
||||||
QString(
|
QString(
|
||||||
_("This version(%1) has not been officially released and is not "
|
_("This version(%1) may have been withdrawn by the developer due "
|
||||||
"recommended for use in a production environment. <br/>"))
|
"to serious problems. Please stop using this version "
|
||||||
.arg(currentVersion) +
|
"immediately and use the latest stable version."))
|
||||||
QString(
|
.arg(version.current_version.c_str()) +
|
||||||
_("You can download the latest version(%1) on Github Releases "
|
"<br/>" +
|
||||||
"Page.<br/>"))
|
QString(_("You can download the latest stable version(%1) on "
|
||||||
.arg(latestVersion));
|
"Github Releases "
|
||||||
|
"Page.<br/>"))
|
||||||
|
.arg(version.latest_version.c_str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,16 +451,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="saveDraftButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Save Draft</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item alignment="Qt::AlignRight">
|
<item alignment="Qt::AlignRight">
|
||||||
<widget class="QPushButton" name="sendMailButton">
|
<widget class="QPushButton" name="sendMailButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user