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

@@ -0,0 +1,74 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "settingspage.h"
#include "updateinfoplugin.h"
#include <coreplugin/coreconstants.h>
using namespace UpdateInfo;
using namespace UpdateInfo::Internal;
SettingsPage::SettingsPage(UpdateInfoPlugin *plugin)
: m_plugin(plugin)
, m_page(0)
{
setId(Constants::FILTER_OPTIONS_PAGE);
setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON));
setDisplayName(QCoreApplication::translate("Update", UpdateInfo::Constants::FILTER_OPTIONS_PAGE));
setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::SETTINGS_TR_CATEGORY_CORE));
}
QWidget *SettingsPage::createPage(QWidget *parent)
{
m_page = new QWidget(parent);
m_ui.setupUi(m_page);
if (m_searchKeywords.isEmpty())
m_searchKeywords = m_ui.m_info->text();
m_ui.m_timeTable->setCurrentText(QTime(m_plugin->scheduledUpdateTime())
.toString(QLatin1String("hh:mm")));
return m_page;
}
void SettingsPage::apply()
{
m_plugin->setScheduledUpdateTime(QTime::fromString(m_ui.m_timeTable->currentText(),
QLatin1String("hh:mm")));
m_plugin->saveSettings();
}
void SettingsPage::finish()
{
}
bool SettingsPage::matches(const QString &searchKey) const
{
return m_searchKeywords.contains(searchKey, Qt::CaseInsensitive);
}

View File

@@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef SETTINGSPAGE_H
#define SETTINGSPAGE_H
#include "ui_settingspage.h"
#include <coreplugin/dialogs/ioptionspage.h>
namespace UpdateInfo {
namespace Internal {
class UpdateInfoPlugin;
class SettingsPage : public Core::IOptionsPage
{
Q_OBJECT
public:
explicit SettingsPage(UpdateInfoPlugin *plugin);
QWidget *createPage(QWidget *parent);
void apply();
void finish();
bool matches(const QString &searchKey) const;
private:
QWidget *m_page;
Ui::SettingsWidget m_ui;
QString m_searchKeywords;
UpdateInfoPlugin *m_plugin;
};
} // namespace Internal
} // namespace UpdateInfo
#endif // SETTINGSPAGE_H

View File

@@ -0,0 +1,226 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UpdateInfo::Internal::SettingsWidget</class>
<widget class="QWidget" name="UpdateInfo::Internal::SettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>482</width>
<height>364</height>
</rect>
</property>
<property name="windowTitle">
<string>Configure Filters</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Qt Creator Update Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="m_info">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Qt Creator automatically runs a scheduled update check on a daily basis. If Qt Creator is not in use on the scheduled time or maintenance is behind schedule, the automatic update check will be run next time Qt Creator starts.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Run update check daily at:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="m_timeTable">
<property name="currentIndex">
<number>12</number>
</property>
<item>
<property name="text">
<string>00:00</string>
</property>
</item>
<item>
<property name="text">
<string>01:00</string>
</property>
</item>
<item>
<property name="text">
<string>02:00</string>
</property>
</item>
<item>
<property name="text">
<string>03:00</string>
</property>
</item>
<item>
<property name="text">
<string>04:00</string>
</property>
</item>
<item>
<property name="text">
<string>05:00</string>
</property>
</item>
<item>
<property name="text">
<string>06:00</string>
</property>
</item>
<item>
<property name="text">
<string>07:00</string>
</property>
</item>
<item>
<property name="text">
<string>08:00</string>
</property>
</item>
<item>
<property name="text">
<string>09:00</string>
</property>
</item>
<item>
<property name="text">
<string>10:00</string>
</property>
</item>
<item>
<property name="text">
<string>11:00</string>
</property>
</item>
<item>
<property name="text">
<string>12:00</string>
</property>
</item>
<item>
<property name="text">
<string>13:00</string>
</property>
</item>
<item>
<property name="text">
<string>14:00</string>
</property>
</item>
<item>
<property name="text">
<string>15:00</string>
</property>
</item>
<item>
<property name="text">
<string>16:00</string>
</property>
</item>
<item>
<property name="text">
<string>17:00</string>
</property>
</item>
<item>
<property name="text">
<string>18:00</string>
</property>
</item>
<item>
<property name="text">
<string>19:00</string>
</property>
</item>
<item>
<property name="text">
<string>20:00</string>
</property>
</item>
<item>
<property name="text">
<string>21:00</string>
</property>
</item>
<item>
<property name="text">
<string>22:00</string>
</property>
</item>
<item>
<property name="text">
<string>23:00</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>253</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,9 +1,12 @@
QT += network xml
HEADERS += updateinfoplugin.h \
updateinfobutton.h
updateinfobutton.h \
settingspage.h
SOURCES += updateinfoplugin.cpp \
updateinfobutton.cpp
updateinfobutton.cpp \
settingspage.cpp
FORMS += settingspage.ui
RESOURCES += updateinfo.qrc
isEmpty(UPDATEINFO_ENABLE):UPDATEINFO_EXPERIMENTAL_STR="true"

View File

@@ -16,5 +16,8 @@ QtcPlugin {
"updateinfobutton.h",
"updateinfoplugin.cpp",
"updateinfoplugin.h",
"settingspage.cpp",
"settingspage.h",
"settingspage.ui",
]
}

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,39 +93,26 @@ 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()));
connect(d->checkUpdateInfoWatcher, SIGNAL(finished()), this, SLOT(parseUpdates()));
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();
d->m_timer.start(OneMinute, this);
return true;
}
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.");
@@ -139,86 +125,144 @@ bool UpdateInfoPlugin::initialize(const QStringList & /* arguments */, QString *
return false;
}
ActionContainer *const helpActionContainer = ActionManager::actionContainer(Core::Constants::M_HELP);
helpActionContainer->menu()->addAction(tr("Start Updater"), this, SLOT(startUpdaterUiApplication()));
d->m_settingsPage = new SettingsPage(this);
addObject(d->m_settingsPage);
//wait some time before we want to have the first check
startCheckTimer(OneMinute / 10);
ActionContainer *const container = ActionManager::actionContainer(Core::Constants::M_HELP);
container->menu()->addAction(tr("Start Updater"), this, SLOT(startUpdaterUiApplication()));
return true;
}
QDomDocument UpdateInfoPlugin::checkForUpdates()
void UpdateInfoPlugin::loadSettings()
{
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
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());
}
QByteArray updaterOutput = updaterProcess.readAllStandardOutput();
QDomDocument updatesDomDocument;
updatesDomDocument.setContent(updaterOutput);
return updatesDomDocument;
}
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();
}
}
void UpdateInfoPlugin::reactOnUpdaterOutput()
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;
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);
// 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();
//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()));
}
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);
if (!d->updateInfoProgress.isNull()) //this is fading out the last update info
d->updateInfoProgress->setKeepOnFinish(FutureProgress::HideOnFinish);
}
void UpdateInfoPlugin::timerEvent(QTimerEvent *event)
// -- private
QDomDocument UpdateInfoPlugin::update()
{
if (event->timerId() == d->currentTimerId && !d->lastCheckUpdateInfoTask.isRunning())
{
stopCurrentCheckTimer();
d->lastCheckUpdateInfoTask = QtConcurrent::run(this, &UpdateInfoPlugin::checkForUpdates);
d->checkUpdateInfoWatcher->setFuture(d->lastCheckUpdateInfoTask);
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;
}
void UpdateInfoPlugin::extensionsInitialized()
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

View File

@@ -32,11 +32,18 @@
#include <extensionsystem/iplugin.h>
#include <QTime>
#include <QDomDocument>
namespace UpdateInfo {
namespace Constants {
const char FILTER_OPTIONS_PAGE[] = QT_TRANSLATE_NOOP("Update", "Update");
} // namespace Constants
namespace Internal {
class SettingsPage;
class UpdateInfoPluginPrivate;
class UpdateInfoPlugin : public ExtensionSystem::IPlugin
@@ -48,21 +55,28 @@ public:
UpdateInfoPlugin();
virtual ~UpdateInfoPlugin();
virtual bool initialize(const QStringList &arguments, QString *errorMessage);
bool delayedInitialize();
void extensionsInitialized();
bool initialize(const QStringList &arguments, QString *errorMessage);
virtual void extensionsInitialized();
void loadSettings();
void saveSettings();
private slots:
void startUpdaterUiApplication();
void reactOnUpdaterOutput();
QTime scheduledUpdateTime() const;
void setScheduledUpdateTime(const QTime &time);
protected:
void timerEvent(QTimerEvent *event);
private slots:
void parseUpdates();
void startUpdaterUiApplication();
private:
QDomDocument update();
template <typename T> void settingsHelper(T *settings);
private:
void startCheckTimer(uint milliseconds);
void stopCurrentCheckTimer();
QDomDocument checkForUpdates();
UpdateInfoPluginPrivate *d;
};