forked from qt-creator/qt-creator
Implement settings page for updater plugin.
Change-Id: I32cf1cd03413d59da99e99d0d6c19f6ba2bcc52f Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
@@ -27,31 +27,25 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "settingspage.h"
|
||||
#include "updateinfoplugin.h"
|
||||
#include "updateinfobutton.h"
|
||||
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/actionmanager/actioncontainer.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/modemanager.h>
|
||||
#include <coreplugin/progressmanager/progressmanager.h>
|
||||
#include <coreplugin/progressmanager/futureprogress.h>
|
||||
#include <coreplugin/settingsdatabase.h>
|
||||
|
||||
#include <qtconcurrentrun.h>
|
||||
|
||||
#include <QtPlugin>
|
||||
#include <QProcess>
|
||||
#include <QTimer>
|
||||
#include <QTimerEvent>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QThread>
|
||||
#include <QCoreApplication>
|
||||
#include <QDomDocument>
|
||||
#include <QMessageBox>
|
||||
#include <QMenu>
|
||||
#include <QFile>
|
||||
#include <QFutureWatcher>
|
||||
#include <QMenu>
|
||||
#include <QProcess>
|
||||
|
||||
namespace {
|
||||
static const quint32 OneMinute = 60000;
|
||||
@@ -66,24 +60,29 @@ class UpdateInfoPluginPrivate
|
||||
{
|
||||
public:
|
||||
UpdateInfoPluginPrivate()
|
||||
: startUpdaterAction(0),
|
||||
currentTimerId(0),
|
||||
progressUpdateInfoButton(0),
|
||||
checkUpdateInfoWatcher(0)
|
||||
{}
|
||||
~UpdateInfoPluginPrivate()
|
||||
: progressUpdateInfoButton(0),
|
||||
checkUpdateInfoWatcher(0),
|
||||
m_settingsPage(0)
|
||||
{
|
||||
}
|
||||
~UpdateInfoPluginPrivate()
|
||||
{
|
||||
delete m_settingsPage;
|
||||
}
|
||||
|
||||
QAction *startUpdaterAction;
|
||||
QString updaterProgram;
|
||||
QString updaterCheckOnlyArgument;
|
||||
QString updaterRunUiArgument;
|
||||
int currentTimerId;
|
||||
QString updaterCheckOnlyArgument;
|
||||
|
||||
QFuture<QDomDocument> lastCheckUpdateInfoTask;
|
||||
QPointer<FutureProgress> updateInfoProgress;
|
||||
UpdateInfoButton *progressUpdateInfoButton;
|
||||
QFutureWatcher<QDomDocument> *checkUpdateInfoWatcher;
|
||||
|
||||
QBasicTimer m_timer;
|
||||
QDate m_lastDayChecked;
|
||||
QTime m_scheduledUpdateTime;
|
||||
SettingsPage *m_settingsPage;
|
||||
};
|
||||
|
||||
|
||||
@@ -94,133 +93,178 @@ UpdateInfoPlugin::UpdateInfoPlugin()
|
||||
|
||||
UpdateInfoPlugin::~UpdateInfoPlugin()
|
||||
{
|
||||
removeObject(d->m_settingsPage);
|
||||
delete d;
|
||||
}
|
||||
|
||||
void UpdateInfoPlugin::startCheckTimer(uint milliseconds)
|
||||
{
|
||||
if (d->currentTimerId != 0)
|
||||
stopCurrentCheckTimer();
|
||||
d->currentTimerId = startTimer(milliseconds);
|
||||
}
|
||||
|
||||
void UpdateInfoPlugin::stopCurrentCheckTimer()
|
||||
{
|
||||
killTimer(d->currentTimerId);
|
||||
d->currentTimerId = 0;
|
||||
}
|
||||
|
||||
|
||||
/*! Initializes the plugin. Returns true on success.
|
||||
Plugins want to register objects with the plugin manager here.
|
||||
|
||||
\a errorMessage can be used to pass an error message to the plugin system,
|
||||
if there was any.
|
||||
*/
|
||||
bool UpdateInfoPlugin::initialize(const QStringList & /* arguments */, QString *errorMessage)
|
||||
bool UpdateInfoPlugin::delayedInitialize()
|
||||
{
|
||||
d->checkUpdateInfoWatcher = new QFutureWatcher<QDomDocument>(this);
|
||||
connect(d->checkUpdateInfoWatcher, SIGNAL(finished()), this, SLOT(reactOnUpdaterOutput()));
|
||||
|
||||
QSettings *settings = ICore::settings();
|
||||
d->updaterProgram = settings->value(QLatin1String("Updater/Application")).toString();
|
||||
d->updaterCheckOnlyArgument = settings->value(QLatin1String("Updater/CheckOnlyArgument")).toString();
|
||||
d->updaterRunUiArgument = settings->value(QLatin1String("Updater/RunUiArgument")).toString();
|
||||
|
||||
if (d->updaterProgram.isEmpty()) {
|
||||
*errorMessage = tr("Could not determine location of maintenance tool. Please check "
|
||||
"your installation if you did not enable this plugin manually.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!QFile::exists(d->updaterProgram)) {
|
||||
*errorMessage = tr("Could not find maintenance tool at '%1'. Check your installation.")
|
||||
.arg(d->updaterProgram);
|
||||
return false;
|
||||
}
|
||||
|
||||
ActionContainer *const helpActionContainer = ActionManager::actionContainer(Core::Constants::M_HELP);
|
||||
helpActionContainer->menu()->addAction(tr("Start Updater"), this, SLOT(startUpdaterUiApplication()));
|
||||
|
||||
//wait some time before we want to have the first check
|
||||
startCheckTimer(OneMinute / 10);
|
||||
connect(d->checkUpdateInfoWatcher, SIGNAL(finished()), this, SLOT(parseUpdates()));
|
||||
|
||||
d->m_timer.start(OneMinute, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
QDomDocument UpdateInfoPlugin::checkForUpdates()
|
||||
{
|
||||
if (QThread::currentThread() == QCoreApplication::instance()->thread())
|
||||
qWarning() << Q_FUNC_INFO << " Was not designed to run in main/gui thread -> it is using updaterProcess.waitForFinished()";
|
||||
|
||||
//starting
|
||||
QProcess updaterProcess;
|
||||
|
||||
updaterProcess.start(d->updaterProgram,
|
||||
QStringList() << d->updaterCheckOnlyArgument);
|
||||
updaterProcess.waitForFinished();
|
||||
|
||||
//process return value
|
||||
if (updaterProcess.exitStatus() == QProcess::CrashExit) {
|
||||
qWarning() << "Get update info application crashed.";
|
||||
//return; //maybe there is some output
|
||||
}
|
||||
QByteArray updaterOutput = updaterProcess.readAllStandardOutput();
|
||||
QDomDocument updatesDomDocument;
|
||||
updatesDomDocument.setContent(updaterOutput);
|
||||
|
||||
return updatesDomDocument;
|
||||
}
|
||||
|
||||
|
||||
void UpdateInfoPlugin::reactOnUpdaterOutput()
|
||||
{
|
||||
QDomDocument updatesDomDocument = d->checkUpdateInfoWatcher->result();
|
||||
|
||||
if (updatesDomDocument.isNull() ||
|
||||
!updatesDomDocument.firstChildElement().hasChildNodes())
|
||||
{ // no updates are available
|
||||
startCheckTimer(60 * OneMinute);
|
||||
} else {
|
||||
//added the current almost finished task to the progressmanager
|
||||
d->updateInfoProgress = ProgressManager::addTask(
|
||||
d->lastCheckUpdateInfoTask, tr("Update"), "Update.GetInfo", ProgressManager::KeepOnFinish);
|
||||
|
||||
d->updateInfoProgress->setKeepOnFinish(FutureProgress::KeepOnFinish);
|
||||
|
||||
d->progressUpdateInfoButton = new UpdateInfoButton();
|
||||
//the old widget is deleted inside this function
|
||||
//and the current widget becomes a child of updateInfoProgress
|
||||
d->updateInfoProgress->setWidget(d->progressUpdateInfoButton);
|
||||
|
||||
//d->progressUpdateInfoButton->setText(tr("Update")); //we have this information over the progressbar
|
||||
connect(d->progressUpdateInfoButton, SIGNAL(released()),
|
||||
this, SLOT(startUpdaterUiApplication()));
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInfoPlugin::startUpdaterUiApplication()
|
||||
{
|
||||
QProcess::startDetached(d->updaterProgram, QStringList() << d->updaterRunUiArgument);
|
||||
if (!d->updateInfoProgress.isNull())
|
||||
d->updateInfoProgress->setKeepOnFinish(FutureProgress::HideOnFinish); //this is fading out the last updateinfo
|
||||
startCheckTimer(OneMinute);
|
||||
}
|
||||
|
||||
void UpdateInfoPlugin::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == d->currentTimerId && !d->lastCheckUpdateInfoTask.isRunning())
|
||||
{
|
||||
stopCurrentCheckTimer();
|
||||
d->lastCheckUpdateInfoTask = QtConcurrent::run(this, &UpdateInfoPlugin::checkForUpdates);
|
||||
d->checkUpdateInfoWatcher->setFuture(d->lastCheckUpdateInfoTask);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInfoPlugin::extensionsInitialized()
|
||||
{
|
||||
}
|
||||
|
||||
bool UpdateInfoPlugin::initialize(const QStringList & /* arguments */, QString *errorMessage)
|
||||
{
|
||||
loadSettings();
|
||||
if (d->updaterProgram.isEmpty()) {
|
||||
*errorMessage = tr("Could not determine location of maintenance tool. Please check "
|
||||
"your installation if you did not enable this plugin manually.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!QFile::exists(d->updaterProgram)) {
|
||||
*errorMessage = tr("Could not find maintenance tool at '%1'. Check your installation.")
|
||||
.arg(d->updaterProgram);
|
||||
return false;
|
||||
}
|
||||
|
||||
d->m_settingsPage = new SettingsPage(this);
|
||||
addObject(d->m_settingsPage);
|
||||
|
||||
ActionContainer *const container = ActionManager::actionContainer(Core::Constants::M_HELP);
|
||||
container->menu()->addAction(tr("Start Updater"), this, SLOT(startUpdaterUiApplication()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateInfoPlugin::loadSettings()
|
||||
{
|
||||
QSettings *qs = ICore::settings();
|
||||
if (qs->contains(QLatin1String("Updater/Application"))) {
|
||||
settingsHelper(qs);
|
||||
qs->remove(QLatin1String("Updater"));
|
||||
saveSettings(); // update to the new settings location
|
||||
} else {
|
||||
settingsHelper(ICore::settingsDatabase());
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateInfoPlugin::saveSettings()
|
||||
{
|
||||
SettingsDatabase *settings = ICore::settingsDatabase();
|
||||
if (settings) {
|
||||
settings->beginGroup(QLatin1String("Updater"));
|
||||
settings->setValue(QLatin1String("Application"), d->updaterProgram);
|
||||
settings->setValue(QLatin1String("LastDayChecked"), d->m_lastDayChecked);
|
||||
settings->setValue(QLatin1String("RunUiArgument"), d->updaterRunUiArgument);
|
||||
settings->setValue(QLatin1String("CheckOnlyArgument"), d->updaterCheckOnlyArgument);
|
||||
settings->setValue(QLatin1String("ScheduledUpdateTime"), d->m_scheduledUpdateTime);
|
||||
settings->endGroup();
|
||||
}
|
||||
}
|
||||
|
||||
QTime UpdateInfoPlugin::scheduledUpdateTime() const
|
||||
{
|
||||
return d->m_scheduledUpdateTime;
|
||||
}
|
||||
|
||||
void UpdateInfoPlugin::setScheduledUpdateTime(const QTime &time)
|
||||
{
|
||||
d->m_scheduledUpdateTime = time;
|
||||
}
|
||||
|
||||
// -- protected
|
||||
|
||||
void UpdateInfoPlugin::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == d->m_timer.timerId()) {
|
||||
const QDate today = QDate::currentDate();
|
||||
if ((d->m_lastDayChecked == today) || (d->lastCheckUpdateInfoTask.isRunning()))
|
||||
return; // we checked already or the update task is still running
|
||||
|
||||
bool check = false;
|
||||
if (d->m_lastDayChecked <= today.addDays(-2))
|
||||
check = true; // we haven't checked since some days, force check
|
||||
|
||||
if (QTime::currentTime() > d->m_scheduledUpdateTime)
|
||||
check = true; // we are behind schedule, force check
|
||||
|
||||
if (check) {
|
||||
d->lastCheckUpdateInfoTask = QtConcurrent::run(this, &UpdateInfoPlugin::update);
|
||||
d->checkUpdateInfoWatcher->setFuture(d->lastCheckUpdateInfoTask);
|
||||
}
|
||||
} else {
|
||||
// not triggered from our timer
|
||||
ExtensionSystem::IPlugin::timerEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
// -- private slots
|
||||
|
||||
void UpdateInfoPlugin::parseUpdates()
|
||||
{
|
||||
QDomDocument updatesDomDocument = d->checkUpdateInfoWatcher->result();
|
||||
if (updatesDomDocument.isNull() || !updatesDomDocument.firstChildElement().hasChildNodes())
|
||||
return;
|
||||
|
||||
// add the finished task to the progress manager
|
||||
d->updateInfoProgress = ProgressManager::addTask(d->lastCheckUpdateInfoTask, tr("Updates "
|
||||
"available"), "Update.GetInfo", ProgressManager::KeepOnFinish);
|
||||
d->updateInfoProgress->setKeepOnFinish(FutureProgress::KeepOnFinish);
|
||||
|
||||
d->progressUpdateInfoButton = new UpdateInfoButton();
|
||||
d->updateInfoProgress->setWidget(d->progressUpdateInfoButton);
|
||||
connect(d->progressUpdateInfoButton, SIGNAL(released()), this, SLOT(startUpdaterUiApplication()));
|
||||
}
|
||||
|
||||
void UpdateInfoPlugin::startUpdaterUiApplication()
|
||||
{
|
||||
QProcess::startDetached(d->updaterProgram, QStringList() << d->updaterRunUiArgument);
|
||||
if (!d->updateInfoProgress.isNull()) //this is fading out the last update info
|
||||
d->updateInfoProgress->setKeepOnFinish(FutureProgress::HideOnFinish);
|
||||
}
|
||||
|
||||
// -- private
|
||||
|
||||
QDomDocument UpdateInfoPlugin::update()
|
||||
{
|
||||
if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
|
||||
qWarning() << Q_FUNC_INFO << " was not designed to run in main/ gui thread, it is using "
|
||||
"QProcess::waitForFinished()";
|
||||
}
|
||||
|
||||
// start
|
||||
QProcess updater;
|
||||
updater.start(d->updaterProgram, QStringList() << d->updaterCheckOnlyArgument);
|
||||
updater.waitForFinished();
|
||||
|
||||
// process return value
|
||||
QDomDocument updates;
|
||||
if (updater.exitStatus() != QProcess::CrashExit) {
|
||||
d->m_timer.stop();
|
||||
d->m_lastDayChecked = QDate::currentDate();
|
||||
updates.setContent(updater.readAllStandardOutput());
|
||||
saveSettings(); // force writing out the last update date
|
||||
} else {
|
||||
qWarning() << "Updater application crashed.";
|
||||
}
|
||||
return updates;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void UpdateInfoPlugin::settingsHelper(T *settings)
|
||||
{
|
||||
settings->beginGroup(QLatin1String("Updater"));
|
||||
|
||||
d->updaterProgram = settings->value(QLatin1String("Application")).toString();
|
||||
d->m_lastDayChecked = settings->value(QLatin1String("LastDayChecked"), QDate()).toDate();
|
||||
d->updaterRunUiArgument = settings->value(QLatin1String("RunUiArgument"),
|
||||
QLatin1String("--updater")).toString();
|
||||
d->updaterCheckOnlyArgument = settings->value(QLatin1String("CheckOnlyArgument"),
|
||||
QLatin1String("--checkupdates")).toString();
|
||||
d->m_scheduledUpdateTime = settings->value(QLatin1String("ScheduledUpdateTime"), QTime(12, 0))
|
||||
.toTime();
|
||||
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
} //namespace Internal
|
||||
} //namespace UpdateInfo
|
||||
|
||||
|
||||
Reference in New Issue
Block a user