Implement settings page for updater plugin.

Change-Id: I32cf1cd03413d59da99e99d0d6c19f6ba2bcc52f
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
kh1
2013-11-11 14:58:17 +01:00
committed by Kai Koehne
parent 2dd9e781ec
commit 65c60ce4ce
7 changed files with 573 additions and 145 deletions

View File

@@ -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