Pencil2D Animation
Download Community News Docs Contribute
  • Overview
  • Articles
  • Code
  •  
  • Class List
  • Class Index
  • Class Hierarchy
  • Class Members
  • File List
Loading...
Searching...
No Matches
  • app
  • src
checkupdatesdialog.cpp
1/*
2
3Pencil2D - Traditional Animation Software
4Copyright (C) 2005-2007 Patrick Corrieri & Pascal Naidon
5Copyright (C) 2012-2020 Matthew Chiawen Chang
6
7This program is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public License
9as published by the Free Software Foundation; version 2 of the License.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16*/
17
18#include "checkupdatesdialog.h"
19#include <QDebug>
20#include <QNetworkReply>
21#include <QNetworkAccessManager>
22#include <QHBoxLayout>
23#include <QVBoxLayout>
24#include <QLabel>
25#include <QProgressBar>
26#include <QPushButton>
27#include <QDesktopServices>
28#include <QRegularExpression>
29#include <QVersionNumber>
30#include <QXmlStreamReader>
31
32#include "util.h"
33
34
35CheckUpdatesDialog::CheckUpdatesDialog()
36{
37 Qt::WindowFlags eFlags = Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint;
38 setWindowFlags(eFlags);
39 setMinimumSize(QSize(400, 150));
40
41 QLabel* logoLabel = new QLabel;
42 logoLabel->setPixmap(QPixmap(":/icons/logo.png"));
43 logoLabel->setFixedSize(QSize(72, 72));
44
45 mTitleLabel = new QLabel;
46 mTitleLabel->setText(tr("Checking for Updates...", "status description in the check-for-update dialog"));
47
48 mDetailLabel = new QLabel;
49 mDetailLabel->setWordWrap(true);
50
51 //If minimum and maximum both are set to 0, the bar shows a busy indicator instead of a percentage of steps.
52 mProgressBar = new QProgressBar;
53 mProgressBar->setMaximum(0);
54 mProgressBar->setMinimum(0);
55 mProgressBar->setValue(0);
56 mProgressBar->setTextVisible(false);
57
58 mDownloadButton = new QPushButton(tr("Download"));
59 mCloseButton = new QPushButton(tr("Close"));
60
61 QHBoxLayout* hButtonLayout = new QHBoxLayout;
62 hButtonLayout->addWidget(mDownloadButton);
63 hButtonLayout->addWidget(mCloseButton);
64
65 QVBoxLayout* vLayout = new QVBoxLayout;
66 vLayout->addWidget(mTitleLabel);
67 vLayout->addWidget(mDetailLabel);
68 vLayout->addWidget(mProgressBar);
69 vLayout->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
70 vLayout->addLayout(hButtonLayout);
71
72 QHBoxLayout* mainLayout = new QHBoxLayout;
73 mainLayout->addWidget(logoLabel);
74 mainLayout->addLayout(vLayout);
75 setLayout(mainLayout);
76
77 mDownloadButton->setDisabled(true);
78
79 connect(mDownloadButton, &QPushButton::clicked, this, &CheckUpdatesDialog::gotoDownloadPage);
80 connect(mCloseButton, &QPushButton::clicked, this, &CheckUpdatesDialog::closeDialog);
81}
82
83CheckUpdatesDialog::~CheckUpdatesDialog()
84{
85 mNetworkManager->deleteLater();
86}
87
88void CheckUpdatesDialog::startChecking()
89{
90#ifdef PENCIL2D_NIGHTLY_BUILD
91 nightlyBuildCheck();
92#else
93 regularBuildCheck();
94#endif
95}
96
97void CheckUpdatesDialog::regularBuildCheck()
98{
99 mNetworkManager = new QNetworkAccessManager(this);
100 QUrl url("https://github.com/pencil2d/pencil/releases.atom");
101
102 QNetworkRequest req;
103 req.setUrl(url);
104 req.setRawHeader("User-Agent", "Mozilla Firefox");
105
106 mNetworkManager->get(req);
107 connect(mNetworkManager, &QNetworkAccessManager::finished, this, &CheckUpdatesDialog::networkRequestFinished);
108}
109
110void CheckUpdatesDialog::nightlyBuildCheck()
111{
112 mTitleLabel->setText(tr("<b>You are using a Pencil2D nightly build</b>"));
113 mDetailLabel->setText(tr("Please go %1 here %2 to check new nightly builds.")
114 .arg("<a href=\"https://www.pencil2d.org/download/#nightlybuild\">", "</a>"));
115 mDetailLabel->setOpenExternalLinks(true);
116 mProgressBar->setRange(0, 1);
117 mProgressBar->setValue(1);
118 mDownloadButton->setEnabled(false);
119}
120
121void CheckUpdatesDialog::networkErrorHappened()
122{
123 mTitleLabel->setText(tr("<b>An error occurred while checking for updates</b>", "error msg of check-for-update"));
124 mDetailLabel->setText(tr("Please check your internet connection and try again later.", "error msg of check-for-update"));
125 mProgressBar->setRange(0, 1);
126 mProgressBar->setValue(1);
127 mDownloadButton->setEnabled(false);
128}
129
130void CheckUpdatesDialog::networkResponseIsEmpty()
131{
132 mTitleLabel->setText(tr("<b>An error occurred while checking for updates</b>", "error msg of check-for-update"));
133 mDetailLabel->setText(tr("Network response is empty", "error msg of check-for-update"));
134 mProgressBar->setRange(0, 1);
135 mProgressBar->setValue(1);
136 mDownloadButton->setEnabled(false);
137}
138
139void CheckUpdatesDialog::invalidReleaseXml()
140{
141 mTitleLabel->setText(tr("<b>An error occurred while checking for updates</b>", "error msg of check-for-update"));
142 mDetailLabel->setText(tr("Couldn't retrieve the version information", "error msg of check-for-update"));
143 mProgressBar->setRange(0, 1);
144 mProgressBar->setValue(1);
145 mDownloadButton->setEnabled(false);
146}
147
148void CheckUpdatesDialog::networkRequestFinished(QNetworkReply* reply)
149{
150 reply->deleteLater();
151
152 QNetworkReply::NetworkError errorCode = reply->error();
153 if (errorCode != QNetworkReply::NoError)
154 {
155 // show error message
156 qDebug() << reply->errorString();
157 networkErrorHappened();
158 return;
159 }
160
161 auto releasesAtom = QString::fromUtf8(reply->readAll()).trimmed();
162 if (releasesAtom.isEmpty())
163 {
164 networkResponseIsEmpty();
165 return;
166 }
167
168 QString latestVersionString = getVersionNumberFromXml(releasesAtom);
169 if (latestVersionString == "0.0.1")
170 {
171 invalidReleaseXml();
172 return;
173 }
174
175 bool isNewVersionAvailable = compareVersion(APP_VERSION, latestVersionString);
176 if (isNewVersionAvailable)
177 {
178 mTitleLabel->setText(tr("<b>A new version of Pencil2D is available!</b>"));
179 mDetailLabel->setText(tr("Pencil2D %1 is now available -- you have %2. Would you like to download it?")
180 .arg(latestVersionString, APP_VERSION));
181 mProgressBar->hide();
182 mDownloadButton->setEnabled(true);
183 }
184 else
185 {
186 mTitleLabel->setText(tr("<b>Pencil2D is up to date</b>"));
187 mDetailLabel->setText(tr("Version %1").arg(APP_VERSION));
188 mProgressBar->setRange(0, 1);
189 mProgressBar->setValue(1);
190 mDownloadButton->setEnabled(false);
191 }
192}
193
194bool CheckUpdatesDialog::compareVersion(QString currentVersion, QString latestVersion)
195{
196 return QVersionNumber::fromString(currentVersion) < QVersionNumber::fromString(latestVersion);
197}
198
199QString CheckUpdatesDialog::getVersionNumberFromXml(QString xml)
200{
201 // XML source: https://github.com/pencil2d/pencil/releases.atom
202
203 QXmlStreamReader xmlReader(xml);
204
205 while (!xmlReader.atEnd() && !xmlReader.hasError())
206 {
207 QXmlStreamReader::TokenType tokenType = xmlReader.readNext();
208 if (tokenType == QXmlStreamReader::StartElement && xmlReader.name() == QLatin1String("entry"))
209 {
210 while (!xmlReader.atEnd() && !xmlReader.hasError())
211 {
212 xmlReader.readNext();
213 if (xmlReader.name() == QLatin1String("title"))
214 {
215 QString titleTag = xmlReader.readElementText();
216 return titleTag.remove(QRegularExpression("^v")); // remove the leading 'v'
217 }
218 }
219 }
220 }
221 if (xmlReader.error() != QXmlStreamReader::NoError)
222 {
223 qDebug() << xmlReader.errorString();
224 return "0.0.1";
225 }
226 return "0.0.1";
227}
228
229void CheckUpdatesDialog::gotoDownloadPage()
230{
231 QString url = "https://pencil2d.org/download";
232 QDesktopServices::openUrl(QUrl(url));
233}
234
235void CheckUpdatesDialog::closeDialog()
236{
237 done(QDialog::Accepted);
238}
QAbstractButton::clicked
void clicked(bool checked)
QBoxLayout::addLayout
void addLayout(QLayout *layout, int stretch)
QBoxLayout::addSpacerItem
void addSpacerItem(QSpacerItem *spacerItem)
QBoxLayout::addWidget
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
QDesktopServices::openUrl
bool openUrl(const QUrl &url)
QDialog::Accepted
Accepted
QDialog::done
virtual void done(int r)
QHBoxLayout
QIODevice::errorString
QString errorString() const const
QIODevice::readAll
QByteArray readAll()
QLabel
QLabel::setOpenExternalLinks
void setOpenExternalLinks(bool open)
QLabel::setPixmap
void setPixmap(const QPixmap &)
QLabel::setText
void setText(const QString &)
QLabel::setWordWrap
void setWordWrap(bool on)
QLatin1String
QNetworkAccessManager
QNetworkAccessManager::finished
void finished(QNetworkReply *reply)
QNetworkAccessManager::get
QNetworkReply * get(const QNetworkRequest &request)
QNetworkReply
QNetworkReply::NetworkError
NetworkError
QNetworkReply::error
QNetworkReply::NetworkError error() const const
QNetworkRequest
QNetworkRequest::setRawHeader
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
QNetworkRequest::setUrl
void setUrl(const QUrl &url)
QObject::connect
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject::deleteLater
void deleteLater()
QObject::tr
QString tr(const char *sourceText, const char *disambiguation, int n)
QPixmap
QProgressBar
QProgressBar::setMaximum
void setMaximum(int maximum)
QProgressBar::setMinimum
void setMinimum(int minimum)
QProgressBar::setRange
void setRange(int minimum, int maximum)
QProgressBar::setTextVisible
void setTextVisible(bool visible)
QProgressBar::setValue
void setValue(int value)
QPushButton
QRegularExpression
QSize
QSizePolicy::Minimum
Minimum
QSpacerItem
QString
QString::fromUtf8
QString fromUtf8(const char *str, int size)
QString::remove
QString & remove(int position, int n)
QString::trimmed
QString trimmed() const const
Qt::WindowFlags
typedef WindowFlags
QUrl
QVBoxLayout
QVersionNumber::fromString
QVersionNumber fromString(const QString &string, int *suffixIndex)
QWidget::setEnabled
void setEnabled(bool)
QWidget::hide
void hide()
QWidget::setMinimumSize
void setMinimumSize(const QSize &)
QWidget::setDisabled
void setDisabled(bool disable)
QWidget::setFixedSize
void setFixedSize(const QSize &s)
QWidget::setLayout
void setLayout(QLayout *layout)
QWidget::setWindowFlags
void setWindowFlags(Qt::WindowFlags type)
QXmlStreamReader
QXmlStreamReader::NoError
NoError
QXmlStreamReader::TokenType
TokenType
Generated on Thu May 8 2025 04:47:53 for Pencil2D by doxygen 1.9.6 based on revision 4513250b1d5b1a3676ec0e67b06b7a885ceaae39