1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version, but always including the *additional*
9 // restrictions defined in the "License.txt" file.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 // http://www.gnu.org/licenses/gpl-2.0.txt
21 ///////////////////////////////////////////////////////////////////////////////
23 #include "Dialog_Update.h"
26 #include "UIC_UpdateDialog.h"
30 #include "Dialog_LogView.h"
31 #include "Model_Settings.h"
32 #include "WinSevenTaskbar.h"
35 #include <MUtils/UpdateChecker.h>
36 #include <MUtils/Version.h>
40 #include <QFileDialog>
43 #include <QDesktopServices>
45 #include <QCloseEvent>
47 #include <QMessageBox>
49 ///////////////////////////////////////////////////////////////////////////////
53 T DO_ASYNC(T (*functionPointer)())
55 QFutureWatcher<T> watcher; QEventLoop loop;
56 QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
57 watcher.setFuture(QtConcurrent::run(functionPointer));
58 loop.exec(QEventLoop::ExcludeUserInputEvents);
59 return watcher.result();
63 #define SHOW_HINT(TEXT, ICON) do \
65 ui->hintLabel->setText((TEXT)); \
66 ui->hintIcon->setPixmap(QIcon((ICON)).pixmap(16,16)); \
67 ui->hintIcon->show(); \
68 ui->hintLabel->show(); \
72 #define UPDATE_TASKBAR(STATE, ICON) do \
74 WinSevenTaskbar::setTaskbarState(this->parentWidget(), (STATE)); \
75 WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon((ICON))); \
79 ///////////////////////////////////////////////////////////////////////////////
81 UpdateDialog::UpdateDialog(SettingsModel *settings, QWidget *parent)
84 ui(new Ui::UpdateDialog),
87 m_logFile(new QStringList()),
88 m_betaUpdates(settings ? (settings->autoUpdateCheckBeta() || lamexp_version_demo()) : lamexp_version_demo()),
91 m_updateReadyToInstall(false),
92 m_updaterProcess(NULL),
93 m_binaryUpdater(lamexp_lookup_tool("wupdate.exe")),
94 m_binaryWGet(lamexp_lookup_tool("wget.exe")),
95 m_binaryGnuPG(lamexp_lookup_tool("gpgv.exe")),
96 m_binaryKeys(lamexp_lookup_tool("gpgv.gpg"))
98 if(m_binaryUpdater.isEmpty())
100 THROW("Tools not initialized correctly!");
103 //Init the dialog, from the .ui file
105 setWindowFlags(windowFlags() ^ Qt::WindowContextHelpButtonHint);
108 lamexp_enable_close_button(this, false);
111 m_animator = new QMovie(":/images/Loading3.gif");
112 ui->labelAnimationCenter->setMovie(m_animator);
115 //Indicate beta updates
118 setWindowTitle(windowTitle().append(" [Beta]"));
122 connect(ui->retryButton, SIGNAL(clicked()), this, SLOT(checkForUpdates()));
123 connect(ui->installButton, SIGNAL(clicked()), this, SLOT(applyUpdate()));
124 connect(ui->infoLabel, SIGNAL(linkActivated(QString)), this, SLOT(linkActivated(QString)));
125 connect(ui->logButton, SIGNAL(clicked()), this, SLOT(logButtonClicked()));
127 //Enable progress bar
128 connect(ui->progressBar, SIGNAL(valueChanged(int)), this, SLOT(progressBarValueChanged(int)));
131 UpdateDialog::~UpdateDialog(void)
140 if(!m_thread->wait(1000))
142 m_thread->terminate();
147 MUTILS_DELETE(m_thread);
148 MUTILS_DELETE(m_logFile);
149 MUTILS_DELETE(m_animator);
151 WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarNoState);
152 WinSevenTaskbar::setOverlayIcon(this->parentWidget(), NULL);
157 void UpdateDialog::showEvent(QShowEvent *event)
159 QDialog::showEvent(event);
165 m_thread = new MUtils::UpdateChecker(m_binaryWGet, m_binaryGnuPG, m_binaryKeys, QLatin1String("LameXP"), lamexp_version_build(), m_betaUpdates);
166 connect(m_thread, SIGNAL(statusChanged(int)), this, SLOT(threadStatusChanged(int)));
167 connect(m_thread, SIGNAL(progressChanged(int)), this, SLOT(threadProgressChanged(int)));
168 connect(m_thread, SIGNAL(messageLogged(QString)), this, SLOT(threadMessageLogged(QString)));
169 connect(m_thread, SIGNAL(finished()), this, SLOT(threadFinished()));
170 connect(m_thread, SIGNAL(terminated()), this, SLOT(threadFinished()));
173 threadStatusChanged(m_thread->getUpdateStatus());
174 ui->labelVersionInstalled->setText(QString("%1 %2 (%3)").arg(tr("Build"), QString::number(lamexp_version_build()), MUtils::Version::build_date().toString(Qt::ISODate)));
175 ui->labelVersionLatest->setText(QString("(%1)").arg(tr("Unknown")));
177 ui->installButton->setEnabled(false);
178 ui->closeButton->setEnabled(false);
179 ui->retryButton->setEnabled(false);
180 ui->logButton->setEnabled(false);
181 ui->retryButton->hide();
182 ui->logButton->hide();
183 ui->infoLabel->hide();
184 ui->hintLabel->hide();
185 ui->hintIcon->hide();
186 ui->frameAnimation->hide();
188 ui->progressBar->setMaximum(m_thread->getMaximumProgress());
189 ui->progressBar->setValue(0);
191 m_updaterProcess = NULL;
193 QTimer::singleShot(0, this, SLOT(updateInit()));
198 void UpdateDialog::closeEvent(QCloseEvent *event)
200 if(!ui->closeButton->isEnabled())
206 WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarNoState);
207 WinSevenTaskbar::setOverlayIcon(this->parentWidget(), NULL);
211 void UpdateDialog::keyPressEvent(QKeyEvent *e)
213 if(e->key() == Qt::Key_F11)
215 if(ui->closeButton->isEnabled()) logButtonClicked();
217 else if((e->key() == Qt::Key_F12) && e->modifiers().testFlag(Qt::ControlModifier))
219 if(ui->closeButton->isEnabled()) testKnownHosts();
223 QDialog::keyPressEvent(e);
227 bool UpdateDialog::event(QEvent *e)
229 if((e->type() == QEvent::ActivationChange) && (m_updaterProcess != NULL))
231 lamexp_bring_process_to_front(m_updaterProcess);
233 return QDialog::event(e);
236 bool UpdateDialog::winEvent(MSG *message, long *result)
238 return WinSevenTaskbar::handleWinEvent(message, result);
241 void UpdateDialog::updateInit(void)
243 setMinimumSize(size());
244 setMaximumHeight(height());
245 QTimer::singleShot(0, this, SLOT(checkForUpdates()));
248 void UpdateDialog::checkForUpdates(void)
250 if(m_thread->isRunning())
252 qWarning("Update in progress, cannot check for updates now!");
255 if(!lamexp_user_is_admin())
257 qWarning("User is not in the \"admin\" group, cannot update!");
259 message += QString("<nobr>%1</nobr><br>").arg(tr("Sorry, but only users in the \"Administrators\" group can install updates."));
260 message += QString("<nobr>%1</nobr>").arg(tr("Please start application from an administrator account and try again!"));
261 if(QMessageBox::critical(this, this->windowTitle(), message, tr("Discard"), tr("Ignore")) != 1)
263 ui->closeButton->setEnabled(true);
268 WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarNormalState);
269 WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/transmit_blue.png"));
271 ui->progressBar->setValue(0);
272 ui->installButton->setEnabled(false);
273 ui->closeButton->setEnabled(false);
274 ui->retryButton->setEnabled(false);
275 ui->logButton->setEnabled(false);
276 if(ui->infoLabel->isVisible()) ui->infoLabel->hide();
277 if(ui->hintLabel->isVisible()) ui->hintLabel->hide();
278 if(ui->hintIcon->isVisible()) ui->hintIcon->hide();
279 ui->frameAnimation->show();
281 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
282 QApplication::setOverrideCursor(Qt::WaitCursor);
288 void UpdateDialog::threadStatusChanged(const int status)
292 case MUtils::UpdateChecker::UpdateStatus_NotStartedYet:
293 ui->statusLabel->setText(tr("Initializing, please wait..."));
295 case MUtils::UpdateChecker::UpdateStatus_CheckingConnection:
296 ui->statusLabel->setText(tr("Testing your internet connection, please wait..."));
298 case MUtils::UpdateChecker::UpdateStatus_FetchingUpdates:
299 ui->statusLabel->setText(tr("Checking for new updates online, please wait..."));
301 case MUtils::UpdateChecker::UpdateStatus_CompletedUpdateAvailable:
302 ui->statusLabel->setText(tr("A new version of LameXP is available!"));
303 SHOW_HINT(tr("We highly recommend all users to install this update as soon as possible."), ":/icons/shield_exclamation.png");
304 UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarNormalState, ":/icons/shield_exclamation.png");
306 case MUtils::UpdateChecker::UpdateStatus_CompletedNoUpdates:
307 ui->statusLabel->setText(tr("No new updates available at this time."));
308 SHOW_HINT(tr("Your version of LameXP is still up-to-date. Please check for updates regularly!"), ":/icons/shield_green.png");
309 UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarNormalState, ":/icons/shield_green.png");
311 case MUtils::UpdateChecker::UpdateStatus_CompletedNewVersionOlder:
312 ui->statusLabel->setText(tr("Your version appears to be newer than the latest release."));
313 SHOW_HINT(tr("This usually indicates your are currently using a pre-release version of LameXP."), ":/icons/shield_blue.png");
314 UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarNormalState, ":/icons/shield_error.png");
316 case MUtils::UpdateChecker::UpdateStatus_ErrorNoConnection:
317 ui->statusLabel->setText(tr("It appears that the computer currently is offline!"));
318 SHOW_HINT(tr("Please make sure your computer is connected to the internet and try again."), ":/icons/network_error.png");
319 UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarErrorState, ":/icons/exclamation.png");
321 case MUtils::UpdateChecker::UpdateStatus_ErrorConnectionTestFailed:
322 ui->statusLabel->setText(tr("Network connectivity test has failed!"));
323 SHOW_HINT(tr("Please make sure your computer is connected to the internet and try again."), ":/icons/network_error.png");
324 UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarErrorState, ":/icons/exclamation.png");
326 case MUtils::UpdateChecker::UpdateStatus_ErrorFetchUpdateInfo:
327 ui->statusLabel->setText(tr("Failed to fetch update information from server!"));
328 SHOW_HINT(tr("Sorry, the update server might be busy at this time. Plase try again later."), ":/icons/server_error.png");
329 UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarErrorState, ":/icons/exclamation.png");
332 qWarning("Unknown status %d !!!", int(status));
336 void UpdateDialog::threadProgressChanged(const int progress)
338 ui->progressBar->setValue(progress);
341 void UpdateDialog::threadMessageLogged(const QString &message)
343 (*m_logFile) << message;
346 void UpdateDialog::threadFinished(void)
348 const bool bSuccess = m_thread->getSuccess();
350 ui->closeButton->setEnabled(true);
351 if(ui->frameAnimation->isVisible()) ui->frameAnimation->hide();
352 ui->progressBar->setValue(ui->progressBar->maximum());
356 if(m_settings->soundsEnabled()) lamexp_play_sound("error", true);
360 const bool bHaveUpdate = (m_thread->getUpdateStatus() == MUtils::UpdateChecker::UpdateStatus_CompletedUpdateAvailable);
361 ui->installButton->setEnabled(bHaveUpdate);
362 lamexp_beep(bHaveUpdate ? lamexp_beep_info : lamexp_beep_warning);
364 if(const MUtils::UpdateCheckerInfo *const updateInfo = m_thread->getUpdateInfo())
366 ui->infoLabel->setText(QString("%1<br><a href=\"%2\">%2</a>").arg(tr("More information available at:"), updateInfo->getDownloadSite()));
367 ui->labelVersionLatest->setText(QString("%1 %2 (%3)").arg(tr("Build"), QString::number(updateInfo->getBuildNo()), updateInfo->getBuildDate().toString(Qt::ISODate)));
368 ui->infoLabel->show();
374 ui->retryButton->setVisible(!bSuccess);
375 ui->logButton->setVisible(!bSuccess);
376 ui->retryButton->setEnabled(!bSuccess);
377 ui->logButton->setEnabled(!bSuccess);
379 QApplication::restoreOverrideCursor();
382 void UpdateDialog::linkActivated(const QString &link)
384 QDesktopServices::openUrl(QUrl(link));
387 void UpdateDialog::applyUpdate(void)
389 ui->installButton->setEnabled(false);
390 ui->closeButton->setEnabled(false);
391 ui->retryButton->setEnabled(false);
393 if(const MUtils::UpdateCheckerInfo *updateInfo = m_thread->getUpdateInfo())
395 ui->statusLabel->setText(tr("Update is being downloaded, please be patient..."));
396 ui->frameAnimation->show();
397 if(ui->hintLabel->isVisible()) ui->hintLabel->hide();
398 if(ui->hintIcon->isVisible()) ui->hintIcon->hide();
399 int oldMax = ui->progressBar->maximum();
400 int oldMin = ui->progressBar->minimum();
401 ui->progressBar->setRange(0, 0);
402 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
408 MUtils::init_process(process, QFileInfo(m_binaryUpdater).absolutePath(), false);
410 connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
411 connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit()));
413 args << QString("/Location=%1").arg(updateInfo->getDownloadAddress());
414 args << QString("/Filename=%1").arg(updateInfo->getDownloadFilename());
415 args << QString("/TicketID=%1").arg(updateInfo->getDownloadFilecode());
416 args << QString("/ToFolder=%1").arg(QDir::toNativeSeparators(QDir(QApplication::applicationDirPath()).canonicalPath()));
417 args << QString("/ToExFile=%1.exe").arg(QFileInfo(QFileInfo(QApplication::applicationFilePath()).canonicalFilePath()).completeBaseName());
418 args << QString("/AppTitle=LameXP (Build #%1)").arg(QString::number(updateInfo->getBuildNo()));
420 QApplication::setOverrideCursor(Qt::WaitCursor);
421 UPDATE_TASKBAR(WinSevenTaskbar::WinSevenTaskbarIndeterminateState, ":/icons/transmit_blue.png");
423 process.start(m_binaryUpdater, args);
424 bool updateStarted = process.waitForStarted();
427 m_updaterProcess = lamexp_process_id(&process);
428 loop.exec(QEventLoop::ExcludeUserInputEvents);
431 m_updaterProcess = NULL;
432 QApplication::restoreOverrideCursor();
434 ui->hintLabel->show();
435 ui->hintIcon->show();
436 ui->progressBar->setRange(oldMin, oldMax);
437 ui->progressBar->setValue(oldMax);
438 ui->frameAnimation->hide();
440 if(updateStarted && (process.exitCode() == 0))
442 ui->statusLabel->setText(tr("Update ready to install. Applicaion will quit..."));
443 m_updateReadyToInstall = true;
444 WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarNoState);
445 WinSevenTaskbar::setOverlayIcon(this->parentWidget(), NULL);
450 ui->statusLabel->setText(tr("Update failed. Please try again or download manually!"));
451 WinSevenTaskbar::setTaskbarState(this->parentWidget(), WinSevenTaskbar::WinSevenTaskbarErrorState);
452 WinSevenTaskbar::setOverlayIcon(this->parentWidget(), &QIcon(":/icons/exclamation.png"));
453 WinSevenTaskbar::setTaskbarProgress(this->parentWidget(), 100, 100);
457 ui->installButton->setEnabled(true);
458 ui->closeButton->setEnabled(true);
461 void UpdateDialog::logButtonClicked(void)
463 LogViewDialog *logView = new LogViewDialog(this);
464 logView->exec(*m_logFile);
465 MUTILS_DELETE(logView);
468 void UpdateDialog::progressBarValueChanged(int value)
470 WinSevenTaskbar::setTaskbarProgress(this->parentWidget(), value, ui->progressBar->maximum());
473 void UpdateDialog::testKnownHosts(void)
475 ui->statusLabel->setText("Testing all known hosts, this may take a few minutes...");
477 if(MUtils::UpdateChecker *testThread = new MUtils::UpdateChecker(m_binaryWGet, m_binaryGnuPG, m_binaryKeys, QLatin1String("LameXP"), lamexp_version_build(), m_betaUpdates, true))
482 connect(testThread, SIGNAL(messageLogged(QString)), this, SLOT(threadMessageLogged(QString)));
483 connect(testThread, SIGNAL(finished()), &loop, SLOT(quit()));
484 connect(testThread, SIGNAL(terminated()), &loop, SLOT(quit()));
487 while(testThread->isRunning())
489 QTimer::singleShot(5000, &loop, SLOT(quit()));
490 loop.exec(QEventLoop::ExcludeUserInputEvents);
493 MUTILS_DELETE(testThread);
497 ui->statusLabel->setText("Test completed.");
498 lamexp_beep(lamexp_beep_info);