Refactor UpdateInfo plugin

Change-Id: I63fc40b12e29204d9ecd4ed3fd33e7ad3171918d
Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com>
This commit is contained in:
Jarek Kobus
2015-05-19 15:15:15 +02:00
parent 41ea69248c
commit 13fcf5ad3c
12 changed files with 465 additions and 489 deletions

View File

@@ -182,6 +182,7 @@ const char G_WINDOW_OTHER[] = "QtCreator.Group.Window.Other";
const char G_HELP_HELP[] = "QtCreator.Group.Help.Help"; const char G_HELP_HELP[] = "QtCreator.Group.Help.Help";
const char G_HELP_SUPPORT[] = "QtCreator.Group.Help.Supprt"; const char G_HELP_SUPPORT[] = "QtCreator.Group.Help.Supprt";
const char G_HELP_ABOUT[] = "QtCreator.Group.Help.About"; const char G_HELP_ABOUT[] = "QtCreator.Group.Help.About";
const char G_HELP_UPDATES[] = "QtCreator.Group.Help.Updates";
const char ICON_MINUS[] = ":/core/images/minus.png"; const char ICON_MINUS[] = ":/core/images/minus.png";
const char ICON_PLUS[] = ":/core/images/plus.png"; const char ICON_PLUS[] = ":/core/images/plus.png";

View File

@@ -453,6 +453,7 @@ void MainWindow::registerDefaultContainers()
ac->appendGroup(Constants::G_HELP_HELP); ac->appendGroup(Constants::G_HELP_HELP);
ac->appendGroup(Constants::G_HELP_SUPPORT); ac->appendGroup(Constants::G_HELP_SUPPORT);
ac->appendGroup(Constants::G_HELP_ABOUT); ac->appendGroup(Constants::G_HELP_ABOUT);
ac->appendGroup(Constants::G_HELP_UPDATES);
} }
void MainWindow::registerDefaultActions() void MainWindow::registerDefaultActions()

View File

@@ -52,6 +52,7 @@ SUBDIRS = \
qmakeandroidsupport \ qmakeandroidsupport \
winrt \ winrt \
qmlprofiler \ qmlprofiler \
updateinfo \
welcome welcome
DO_NOT_BUILD_QMLDESIGNER = $$(DO_NOT_BUILD_QMLDESIGNER) DO_NOT_BUILD_QMLDESIGNER = $$(DO_NOT_BUILD_QMLDESIGNER)

View File

@@ -29,21 +29,31 @@
****************************************************************************/ ****************************************************************************/
#include "settingspage.h" #include "settingspage.h"
#include "updateinfoplugin.h"
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <utils/qtcassert.h>
#include <utils/progressindicator.h>
#include <QDate>
using namespace UpdateInfo; using namespace UpdateInfo;
using namespace UpdateInfo::Internal; using namespace UpdateInfo::Internal;
namespace {
static const char FILTER_OPTIONS_PAGE_ID[] = "Update";
static const char FILTER_OPTIONS_PAGE[] = QT_TRANSLATE_NOOP("Update", "Update");
}
SettingsPage::SettingsPage(UpdateInfoPlugin *plugin) SettingsPage::SettingsPage(UpdateInfoPlugin *plugin)
: m_widget(0) : m_widget(0)
, m_plugin(plugin) , m_plugin(plugin)
{ {
setId(Constants::FILTER_OPTIONS_PAGE); setId(FILTER_OPTIONS_PAGE_ID);
setCategory(Core::Constants::SETTINGS_CATEGORY_CORE); setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON)); setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON));
setDisplayName(QCoreApplication::translate("Update", UpdateInfo::Constants::FILTER_OPTIONS_PAGE)); setDisplayName(QCoreApplication::translate("Update", FILTER_OPTIONS_PAGE));
setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::SETTINGS_TR_CATEGORY_CORE)); setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::SETTINGS_TR_CATEGORY_CORE));
} }
@@ -52,17 +62,116 @@ QWidget *SettingsPage::widget()
if (!m_widget) { if (!m_widget) {
m_widget = new QWidget; m_widget = new QWidget;
m_ui.setupUi(m_widget); m_ui.setupUi(m_widget);
m_ui.m_timeTable->setItemText(m_ui.m_timeTable->currentIndex(), QTime(m_plugin->scheduledUpdateTime()) m_ui.m_checkIntervalComboBox->addItem(tr("Daily"), UpdateInfoPlugin::DailyCheck);
.toString(QLatin1String("hh:mm"))); m_ui.m_checkIntervalComboBox->addItem(tr("Weekly"), UpdateInfoPlugin::WeeklyCheck);
m_ui.m_checkIntervalComboBox->addItem(tr("Monthly"), UpdateInfoPlugin::MonthlyCheck);
UpdateInfoPlugin::CheckUpdateInterval interval = m_plugin->checkUpdateInterval();
for (int i = 0; i < m_ui.m_checkIntervalComboBox->count(); i++) {
if (m_ui.m_checkIntervalComboBox->itemData(i).toInt() == interval) {
m_ui.m_checkIntervalComboBox->setCurrentIndex(i);
break;
}
}
m_ui.m_updatesGroupBox->setChecked(m_plugin->isAutomaticCheck());
updateLastCheckDate();
checkRunningChanged(m_plugin->isCheckForUpdatesRunning());
connect(m_ui.m_checkNowButton, &QPushButton::clicked,
m_plugin, &UpdateInfoPlugin::startCheckForUpdates);
connect(m_ui.m_checkIntervalComboBox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &SettingsPage::updateNextCheckDate);
connect(m_plugin, &UpdateInfoPlugin::lastCheckDateChanged,
this, &SettingsPage::updateLastCheckDate);
connect(m_plugin, &UpdateInfoPlugin::checkForUpdatesRunningChanged,
this, &SettingsPage::checkRunningChanged);
connect(m_plugin, &UpdateInfoPlugin::newUpdatesAvailable,
this, &SettingsPage::newUpdatesAvailable);
} }
return m_widget; return m_widget;
} }
UpdateInfoPlugin::CheckUpdateInterval SettingsPage::currentCheckInterval() const
{
QTC_ASSERT(m_widget, return UpdateInfoPlugin::WeeklyCheck);
return static_cast<UpdateInfoPlugin::CheckUpdateInterval>
(m_ui.m_checkIntervalComboBox->itemData(m_ui.m_checkIntervalComboBox->currentIndex()).toInt());
}
void SettingsPage::newUpdatesAvailable(bool available)
{
if (!m_widget)
return;
const QString message = available
? tr("New updates are available.")
: tr("No new updates are available.");
m_ui.m_messageLabel->setText(message);
}
void SettingsPage::checkRunningChanged(bool running)
{
if (!m_widget)
return;
m_ui.m_checkNowButton->setDisabled(running);
if (running) {
if (!m_progressIndicator) {
m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicator::Large);
m_progressIndicator->attachToWidget(m_widget);
}
m_progressIndicator->show();
} else {
if (m_progressIndicator) {
delete m_progressIndicator;
}
}
const QString message = running
? tr("Checking for updates...") : QString();
m_ui.m_messageLabel->setText(message);
}
void SettingsPage::updateLastCheckDate()
{
if (!m_widget)
return;
const QDate date = m_plugin->lastCheckDate();
QString lastCheckDateString;
if (date.isValid())
lastCheckDateString = date.toString();
else
lastCheckDateString = tr("Not checked yet");
m_ui.m_lastCheckDateLabel->setText(lastCheckDateString);
updateNextCheckDate();
}
void SettingsPage::updateNextCheckDate()
{
if (!m_widget)
return;
QDate date = m_plugin->nextCheckDate(currentCheckInterval());
if (!date.isValid() || date < QDate::currentDate())
date = QDate::currentDate();
m_ui.m_nextCheckDateLabel->setText(date.toString());
}
void SettingsPage::apply() void SettingsPage::apply()
{ {
m_plugin->setScheduledUpdateTime(QTime::fromString(m_ui.m_timeTable->currentText(), if (!m_widget)
QLatin1String("hh:mm"))); return;
m_plugin->saveSettings();
m_plugin->setCheckUpdateInterval(currentCheckInterval());
m_plugin->setAutomaticCheck(m_ui.m_updatesGroupBox->isChecked());
} }
void SettingsPage::finish() void SettingsPage::finish()

View File

@@ -32,11 +32,14 @@
#define SETTINGSPAGE_H #define SETTINGSPAGE_H
#include "ui_settingspage.h" #include "ui_settingspage.h"
#include "updateinfoplugin.h"
#include <coreplugin/dialogs/ioptionspage.h> #include <coreplugin/dialogs/ioptionspage.h>
#include <QPointer> #include <QPointer>
namespace Utils { class ProgressIndicator; }
namespace UpdateInfo { namespace UpdateInfo {
namespace Internal { namespace Internal {
@@ -54,7 +57,14 @@ public:
void finish(); void finish();
private: private:
void newUpdatesAvailable(bool available);
void checkRunningChanged(bool running);
void updateLastCheckDate();
void updateNextCheckDate();
UpdateInfoPlugin::CheckUpdateInterval currentCheckInterval() const;
QPointer<QWidget> m_widget; QPointer<QWidget> m_widget;
QPointer<Utils::ProgressIndicator> m_progressIndicator;
Ui::SettingsWidget m_ui; Ui::SettingsWidget m_ui;
UpdateInfoPlugin *m_plugin; UpdateInfoPlugin *m_plugin;
}; };

View File

@@ -7,21 +7,34 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>482</width> <width>482</width>
<height>364</height> <height>242</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Configure Filters</string> <string>Configure Filters</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0"> <item row="0" column="0" colspan="4">
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="m_updatesGroupBox">
<property name="title"> <property name="title">
<string>Qt Creator Update Settings</string> <string>Automatic Check for Updates</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <property name="checkable">
<item> <bool>true</bool>
<widget class="QLabel" name="m_info"> </property>
<property name="checked">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Check interval basis:</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="m_infoLabel">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@@ -29,181 +42,95 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <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> <string>Qt Creator automatically runs a scheduled check for updates on a time interval basis. If Qt Creator is not in use on the scheduled date, the automatic check for updates will be performed next time Qt Creator starts.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item row="1" column="1">
<spacer name="verticalSpacer_2"> <widget class="QComboBox" name="m_checkIntervalComboBox">
<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"> <property name="currentIndex">
<number>12</number> <number>-1</number>
</property> </property>
<item>
<property name="text">
<string notr="true">00:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">01:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">02:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">03:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">04:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">05:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">06:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">07:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">08:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">09:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">10:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">11:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">12:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">13:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">14:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">15:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">16:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">17:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">18:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">19:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">20:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">21:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">22:00</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">23:00</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item> <item row="1" column="2">
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>40</width> <width>171</width>
<height>20</height> <height>20</height>
</size> </size>
</property> </property>
</spacer> </spacer>
</item> </item>
</layout> <item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Next check date:</string>
</property>
</widget>
</item> </item>
<item> <item row="2" column="1" colspan="2">
<widget class="QLabel" name="m_nextCheckDateLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Last check date:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="m_lastCheckDateLabel">
<property name="text">
<string>Not checked yet</string>
</property>
</widget>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>167</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="m_checkNowButton">
<property name="text">
<string>Check Now</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QLabel" name="m_messageLabel">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="0" colspan="4">
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
@@ -211,16 +138,13 @@
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>20</width>
<height>253</height> <height>233</height>
</size> </size>
</property> </property>
</spacer> </spacer>
</item> </item>
</layout> </layout>
</widget> </widget>
</item>
</layout>
</widget>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>

View File

@@ -1,10 +1,8 @@
QT += network xml QT += network xml
HEADERS += updateinfoplugin.h \ HEADERS += updateinfoplugin.h \
updateinfobutton.h \
settingspage.h settingspage.h
SOURCES += updateinfoplugin.cpp \ SOURCES += updateinfoplugin.cpp \
updateinfobutton.cpp \
settingspage.cpp settingspage.cpp
FORMS += settingspage.ui FORMS += settingspage.ui
RESOURCES += updateinfo.qrc RESOURCES += updateinfo.qrc

View File

@@ -14,8 +14,6 @@ QtcPlugin {
pluginJsonReplacements: ({"UPDATEINFO_EXPERIMENTAL_STR": (enable ? "false": "true")}) pluginJsonReplacements: ({"UPDATEINFO_EXPERIMENTAL_STR": (enable ? "false": "true")})
files: [ files: [
"updateinfobutton.cpp",
"updateinfobutton.h",
"updateinfoplugin.cpp", "updateinfoplugin.cpp",
"updateinfoplugin.h", "updateinfoplugin.h",
"settingspage.cpp", "settingspage.cpp",

View File

@@ -1,77 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** 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 The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "updateinfobutton.h"
#include <coreplugin/coreconstants.h>
#include <utils/stylehelper.h>
#include <QIcon>
#include <QPainter>
namespace UpdateInfo {
namespace Internal {
UpdateInfoButton::UpdateInfoButton(QWidget *parent) :
QAbstractButton(parent)
{
setIcon(QIcon(QLatin1String(":/updateinfo/images/update_available_logo.png")));
}
//copied from fancytoolbutton
QSize UpdateInfoButton::minimumSizeHint() const
{
return QSize(8, 8);
}
//copied from fancytoolbutton
QSize UpdateInfoButton::sizeHint() const
{
return iconSize().expandedTo(QSize(64, 38));
}
//copied from fancytoolbutton and removed unused things
void UpdateInfoButton::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
QPainter painter(this);
QRect iconRect(0, 0, Core::Constants::TARGET_ICON_SIZE, Core::Constants::TARGET_ICON_SIZE);
iconRect.moveCenter(rect().center());
Utils::StyleHelper::drawIconWithShadow(icon(), iconRect, &painter, isEnabled() ? QIcon::Normal : QIcon::Disabled);
}
} //Internal
} //namespace UpdateInfo

View File

@@ -1,52 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** 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 The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef UPDATEINFOBUTTON_H
#define UPDATEINFOBUTTON_H
#include <QAbstractButton>
namespace UpdateInfo {
namespace Internal {
class UpdateInfoButton : public QAbstractButton
{
Q_OBJECT
public:
explicit UpdateInfoButton(QWidget *parent = 0);
void paintEvent(QPaintEvent *event);
QSize sizeHint() const;
QSize minimumSizeHint() const;
};
} //namespace Internal
} //namespace UpdateInfo
#endif // UPDATEINFOBUTTON_H

View File

@@ -30,28 +30,34 @@
#include "settingspage.h" #include "settingspage.h"
#include "updateinfoplugin.h" #include "updateinfoplugin.h"
#include "updateinfobutton.h"
#include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
#include <coreplugin/settingsdatabase.h> #include <coreplugin/settingsdatabase.h>
#include <coreplugin/shellcommand.h>
#include <utils/fileutils.h>
#include <qtconcurrentrun.h> #include <QDate>
#include <QBasicTimer>
#include <QDomDocument> #include <QDomDocument>
#include <QFile> #include <QFile>
#include <QFutureWatcher> #include <QFileInfo>
#include <QMenu> #include <QMenu>
#include <QProcess> #include <QMessageBox>
#include <QMetaEnum>
#include <QProcessEnvironment>
#include <QTimer>
#include <QtPlugin> #include <QtPlugin>
namespace { namespace {
static const char UpdaterGroup[] = "Updater";
static const char MaintenanceToolKey[] = "MaintenanceTool";
static const char AutomaticCheckKey[] = "AutomaticCheck";
static const char CheckIntervalKey[] = "CheckUpdateInterval";
static const char LastCheckDateKey[] = "LastCheckDate";
static const quint32 OneMinute = 60000; static const quint32 OneMinute = 60000;
static const quint32 OneHour = 3600000;
} }
using namespace Core; using namespace Core;
@@ -63,47 +69,120 @@ class UpdateInfoPluginPrivate
{ {
public: public:
UpdateInfoPluginPrivate() UpdateInfoPluginPrivate()
: progressUpdateInfoButton(0), { }
checkUpdateInfoWatcher(0),
m_settingsPage(0)
{
}
QString updaterProgram; QString m_maintenanceTool;
QString updaterRunUiArgument; ShellCommand *m_checkUpdatesCommand = 0;
QString updaterCheckOnlyArgument; QString m_collectedOutput;
QTimer *m_checkUpdatesTimer = 0;
QFuture<QDomDocument> lastCheckUpdateInfoTask; bool m_automaticCheck = true;
QPointer<FutureProgress> updateInfoProgress; UpdateInfoPlugin::CheckUpdateInterval m_checkInterval = UpdateInfoPlugin::WeeklyCheck;
UpdateInfoButton *progressUpdateInfoButton; QDate m_lastCheckDate;
QFutureWatcher<QDomDocument> *checkUpdateInfoWatcher;
QBasicTimer m_timer;
QDate m_lastDayChecked;
QTime m_scheduledUpdateTime;
SettingsPage *m_settingsPage;
}; };
UpdateInfoPlugin::UpdateInfoPlugin() UpdateInfoPlugin::UpdateInfoPlugin()
: d(new UpdateInfoPluginPrivate) : d(new UpdateInfoPluginPrivate)
{ {
d->m_checkUpdatesTimer = new QTimer(this);
d->m_checkUpdatesTimer->setTimerType(Qt::VeryCoarseTimer);
d->m_checkUpdatesTimer->setInterval(OneHour);
connect(d->m_checkUpdatesTimer, &QTimer::timeout,
this, &UpdateInfoPlugin::doAutoCheckForUpdates);
} }
UpdateInfoPlugin::~UpdateInfoPlugin() UpdateInfoPlugin::~UpdateInfoPlugin()
{ {
d->lastCheckUpdateInfoTask.cancel(); stopCheckForUpdates();
d->lastCheckUpdateInfoTask.waitForFinished(); if (!d->m_maintenanceTool.isEmpty())
saveSettings();
delete d; delete d;
} }
void UpdateInfoPlugin::startAutoCheckForUpdates()
{
doAutoCheckForUpdates();
d->m_checkUpdatesTimer->start();
}
void UpdateInfoPlugin::stopAutoCheckForUpdates()
{
d->m_checkUpdatesTimer->stop();
}
void UpdateInfoPlugin::doAutoCheckForUpdates()
{
if (d->m_checkUpdatesCommand)
return; // update task is still running (might have been run manually just before)
if (nextCheckDate().isValid() && nextCheckDate() > QDate::currentDate())
return; // not a time for check yet
startCheckForUpdates();
}
void UpdateInfoPlugin::startCheckForUpdates()
{
stopCheckForUpdates();
d->m_checkUpdatesCommand = new ShellCommand(QString(), QProcessEnvironment());
connect(d->m_checkUpdatesCommand, &ShellCommand::stdOutText, this, &UpdateInfoPlugin::collectCheckForUpdatesOutput);
connect(d->m_checkUpdatesCommand, &ShellCommand::finished, this, &UpdateInfoPlugin::checkForUpdatesFinished);
d->m_checkUpdatesCommand->addJob(Utils::FileName(QFileInfo(d->m_maintenanceTool)), QStringList(QLatin1String("--checkupdates")));
d->m_checkUpdatesCommand->execute();
emit checkForUpdatesRunningChanged(true);
}
void UpdateInfoPlugin::stopCheckForUpdates()
{
if (!d->m_checkUpdatesCommand)
return;
d->m_collectedOutput = QString();
d->m_checkUpdatesCommand->disconnect();
d->m_checkUpdatesCommand->cancel();
d->m_checkUpdatesCommand = 0;
emit checkForUpdatesRunningChanged(false);
}
void UpdateInfoPlugin::collectCheckForUpdatesOutput(const QString &contents)
{
d->m_collectedOutput += contents;
}
void UpdateInfoPlugin::checkForUpdatesFinished()
{
setLastCheckDate(QDate::currentDate());
QDomDocument document;
document.setContent(d->m_collectedOutput);
stopCheckForUpdates();
if (!document.isNull() && document.firstChildElement().hasChildNodes()) {
emit newUpdatesAvailable(true);
if (QMessageBox::question(0, tr("Updater"),
tr("New updates are available. Do you want to start update?"))
== QMessageBox::Yes)
startUpdater();
} else {
emit newUpdatesAvailable(false);
}
}
bool UpdateInfoPlugin::isCheckForUpdatesRunning() const
{
return d->m_checkUpdatesCommand;
}
bool UpdateInfoPlugin::delayedInitialize() bool UpdateInfoPlugin::delayedInitialize()
{ {
d->checkUpdateInfoWatcher = new QFutureWatcher<QDomDocument>(this); if (isAutomaticCheck())
connect(d->checkUpdateInfoWatcher, SIGNAL(finished()), this, SLOT(parseUpdates())); QTimer::singleShot(OneMinute, this, &UpdateInfoPlugin::startAutoCheckForUpdates);
d->m_timer.start(OneMinute, this);
return true; return true;
} }
@@ -114,167 +193,132 @@ void UpdateInfoPlugin::extensionsInitialized()
bool UpdateInfoPlugin::initialize(const QStringList & /* arguments */, QString *errorMessage) bool UpdateInfoPlugin::initialize(const QStringList & /* arguments */, QString *errorMessage)
{ {
loadSettings(); loadSettings();
if (d->updaterProgram.isEmpty()) {
if (d->m_maintenanceTool.isEmpty()) {
*errorMessage = tr("Could not determine location of maintenance tool. Please check " *errorMessage = tr("Could not determine location of maintenance tool. Please check "
"your installation if you did not enable this plugin manually."); "your installation if you did not enable this plugin manually.");
return false; return false;
} }
if (!QFile::exists(d->updaterProgram)) { if (!QFileInfo(d->m_maintenanceTool).isExecutable()) {
*errorMessage = tr("Could not find maintenance tool at \"%1\". Check your installation.") *errorMessage = tr("The maintenance tool at \"%1\" is not an executable. Check your installation.")
.arg(d->updaterProgram); .arg(d->m_maintenanceTool);
d->m_maintenanceTool = QString();
return false; return false;
} }
d->m_settingsPage = new SettingsPage(this); connect(ICore::instance(), &ICore::saveSettingsRequested,
addAutoReleasedObject(d->m_settingsPage); this, &UpdateInfoPlugin::saveSettings);
ActionContainer *const container = ActionManager::actionContainer(Core::Constants::M_HELP); addAutoReleasedObject(new SettingsPage(this));
container->menu()->addAction(tr("Start Updater"), this, SLOT(startUpdaterUiApplication()));
QAction *checkForUpdatesAction = new QAction(tr("Check for Updates"), this);
Core::Command *checkForUpdatesCommand = Core::ActionManager::registerAction(checkForUpdatesAction, "Updates.CheckForUpdates");
connect(checkForUpdatesAction, &QAction::triggered, this, &UpdateInfoPlugin::startCheckForUpdates);
ActionContainer *const helpContainer = ActionManager::actionContainer(Core::Constants::M_HELP);
helpContainer->addAction(checkForUpdatesCommand, Constants::G_HELP_UPDATES);
return true; return true;
} }
void UpdateInfoPlugin::loadSettings() void UpdateInfoPlugin::loadSettings() const
{ {
QSettings *qs = ICore::settings(); QSettings *settings = ICore::settings();
if (qs->contains(QLatin1String("Updater/Application"))) { const QString updaterKey = QLatin1String(UpdaterGroup) + QLatin1Char('/');
settingsHelper(qs); d->m_maintenanceTool = settings->value(updaterKey + QLatin1String(MaintenanceToolKey)).toString();
qs->remove(QLatin1String("Updater")); d->m_lastCheckDate = settings->value(updaterKey + QLatin1String(LastCheckDateKey), QDate()).toDate();
saveSettings(); // update to the new settings location d->m_automaticCheck = settings->value(updaterKey + QLatin1String(AutomaticCheckKey), true).toBool();
} else { const QString checkInterval = settings->value(updaterKey + QLatin1String(CheckIntervalKey)).toString();
settingsHelper(ICore::settingsDatabase()); const QMetaObject *mo = metaObject();
const QMetaEnum me = mo->enumerator(mo->indexOfEnumerator(CheckIntervalKey));
if (me.isValid()) {
bool ok = false;
const int newValue = me.keyToValue(checkInterval.toUtf8(), &ok);
if (ok)
d->m_checkInterval = static_cast<CheckUpdateInterval>(newValue);
} }
} }
void UpdateInfoPlugin::saveSettings() void UpdateInfoPlugin::saveSettings()
{ {
SettingsDatabase *settings = ICore::settingsDatabase(); QSettings *settings = ICore::settings();
if (settings) { settings->beginGroup(QLatin1String(UpdaterGroup));
settings->beginTransaction(); settings->setValue(QLatin1String(LastCheckDateKey), d->m_lastCheckDate);
settings->beginGroup(QLatin1String("Updater")); settings->setValue(QLatin1String(AutomaticCheckKey), d->m_automaticCheck);
settings->setValue(QLatin1String("Application"), d->updaterProgram); // Note: don't save MaintenanceToolKey on purpose! This setting may be set only by installer.
settings->setValue(QLatin1String("LastDayChecked"), d->m_lastDayChecked); // If creator is run not from installed SDK, the setting can be manually created here:
settings->setValue(QLatin1String("RunUiArgument"), d->updaterRunUiArgument); // [CREATOR_INSTALLATION_LOCATION]/share/qtcreator/QtProject/QtCreator.ini or
settings->setValue(QLatin1String("CheckOnlyArgument"), d->updaterCheckOnlyArgument); // [CREATOR_INSTALLATION_LOCATION]/Qt Creator.app/Contents/Resources/QtProject/QtCreator.ini on OS X
settings->setValue(QLatin1String("ScheduledUpdateTime"), d->m_scheduledUpdateTime); const QMetaObject *mo = metaObject();
const QMetaEnum me = mo->enumerator(mo->indexOfEnumerator(CheckIntervalKey));
settings->setValue(QLatin1String(CheckIntervalKey), QLatin1String(me.valueToKey(d->m_checkInterval)));
settings->endGroup(); settings->endGroup();
settings->endTransaction();
}
} }
QTime UpdateInfoPlugin::scheduledUpdateTime() const bool UpdateInfoPlugin::isAutomaticCheck() const
{ {
return d->m_scheduledUpdateTime; return d->m_automaticCheck;
} }
void UpdateInfoPlugin::setScheduledUpdateTime(const QTime &time) void UpdateInfoPlugin::setAutomaticCheck(bool on)
{ {
d->m_scheduledUpdateTime = time; if (d->m_automaticCheck == on)
}
// -- 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; return;
// add the finished task to the progress manager d->m_automaticCheck = on;
d->updateInfoProgress if (on)
= ProgressManager::addTask(d->lastCheckUpdateInfoTask, tr("Updates Available"), startAutoCheckForUpdates();
"Update.GetInfo", ProgressManager::KeepOnFinish); else
d->updateInfoProgress->setKeepOnFinish(FutureProgress::KeepOnFinish); stopAutoCheckForUpdates();
d->progressUpdateInfoButton = new UpdateInfoButton();
d->updateInfoProgress->setWidget(d->progressUpdateInfoButton);
connect(d->progressUpdateInfoButton, SIGNAL(released()), this, SLOT(startUpdaterUiApplication()));
} }
void UpdateInfoPlugin::startUpdaterUiApplication() UpdateInfoPlugin::CheckUpdateInterval UpdateInfoPlugin::checkUpdateInterval() const
{ {
QProcess::startDetached(d->updaterProgram, QStringList() << d->updaterRunUiArgument); return d->m_checkInterval;
if (!d->updateInfoProgress.isNull()) //this is fading out the last update info
d->updateInfoProgress->setKeepOnFinish(FutureProgress::HideOnFinish);
} }
// -- private void UpdateInfoPlugin::setCheckUpdateInterval(UpdateInfoPlugin::CheckUpdateInterval interval)
QDomDocument UpdateInfoPlugin::update()
{ {
if (QThread::currentThread() == QCoreApplication::instance()->thread()) { if (d->m_checkInterval == interval)
qWarning() << Q_FUNC_INFO << " was not designed to run in main/ gui thread, it is using " return;
"QProcess::waitForFinished()";
}
// start d->m_checkInterval = interval;
QProcess updater;
updater.start(d->updaterProgram, QStringList() << d->updaterCheckOnlyArgument);
while (updater.state() != QProcess::NotRunning) {
if (!updater.waitForFinished(1000)
&& d->lastCheckUpdateInfoTask.isCanceled()) {
updater.kill();
updater.waitForFinished(-1);
return QDomDocument();
}
}
// process return value
QDomDocument updates;
if (updater.exitStatus() != QProcess::CrashExit) {
d->m_timer.stop();
updates.setContent(updater.readAllStandardOutput());
saveSettings(); // force writing out the last update date
} else {
qWarning() << "Updater application crashed.";
}
d->m_lastDayChecked = QDate::currentDate();
return updates;
} }
template <typename T> QDate UpdateInfoPlugin::lastCheckDate() const
void UpdateInfoPlugin::settingsHelper(T *settings)
{ {
settings->beginGroup(QLatin1String("Updater")); return d->m_lastCheckDate;
}
d->updaterProgram = settings->value(QLatin1String("Application")).toString(); void UpdateInfoPlugin::setLastCheckDate(const QDate &date)
d->m_lastDayChecked = settings->value(QLatin1String("LastDayChecked"), QDate()).toDate(); {
d->updaterRunUiArgument = settings->value(QLatin1String("RunUiArgument"), if (d->m_lastCheckDate == date)
QLatin1String("--updater")).toString(); return;
d->updaterCheckOnlyArgument = settings->value(QLatin1String("CheckOnlyArgument"),
QLatin1String("--checkupdates")).toString();
d->m_scheduledUpdateTime = settings->value(QLatin1String("ScheduledUpdateTime"), QTime(12, 0))
.toTime();
settings->endGroup(); d->m_lastCheckDate = date;
emit lastCheckDateChanged(date);
}
QDate UpdateInfoPlugin::nextCheckDate() const
{
return nextCheckDate(d->m_checkInterval);
}
QDate UpdateInfoPlugin::nextCheckDate(CheckUpdateInterval interval) const
{
if (!d->m_lastCheckDate.isValid())
return QDate();
if (interval == DailyCheck)
return d->m_lastCheckDate.addDays(1);
if (interval == WeeklyCheck)
return d->m_lastCheckDate.addDays(7);
return d->m_lastCheckDate.addMonths(1);
}
void UpdateInfoPlugin::startUpdater()
{
QProcess::startDetached(d->m_maintenanceTool, QStringList(QLatin1String("--updater")));
} }
} //namespace Internal } //namespace Internal

View File

@@ -33,26 +33,28 @@
#include <extensionsystem/iplugin.h> #include <extensionsystem/iplugin.h>
#include <QTime> QT_BEGIN_NAMESPACE
#include <QDomDocument> class QDate;
QT_END_NAMESPACE
namespace UpdateInfo { namespace UpdateInfo {
namespace Constants {
const char FILTER_OPTIONS_PAGE[] = QT_TRANSLATE_NOOP("Update", "Update");
} // namespace Constants
namespace Internal { namespace Internal {
class SettingsPage;
class UpdateInfoPluginPrivate; class UpdateInfoPluginPrivate;
class UpdateInfoPlugin : public ExtensionSystem::IPlugin class UpdateInfoPlugin : public ExtensionSystem::IPlugin
{ {
Q_OBJECT Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "UpdateInfo.json") Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "UpdateInfo.json")
Q_ENUMS(CheckUpdateInterval)
public: public:
enum CheckUpdateInterval {
DailyCheck,
WeeklyCheck,
MonthlyCheck
};
UpdateInfoPlugin(); UpdateInfoPlugin();
virtual ~UpdateInfoPlugin(); virtual ~UpdateInfoPlugin();
@@ -60,22 +62,39 @@ public:
void extensionsInitialized(); void extensionsInitialized();
bool initialize(const QStringList &arguments, QString *errorMessage); bool initialize(const QStringList &arguments, QString *errorMessage);
void loadSettings(); bool isAutomaticCheck() const;
void saveSettings(); void setAutomaticCheck(bool on);
QTime scheduledUpdateTime() const; CheckUpdateInterval checkUpdateInterval() const;
void setScheduledUpdateTime(const QTime &time); void setCheckUpdateInterval(CheckUpdateInterval interval);
protected: QDate lastCheckDate() const;
void timerEvent(QTimerEvent *event); QDate nextCheckDate() const;
QDate nextCheckDate(CheckUpdateInterval interval) const;
private slots: bool isCheckForUpdatesRunning() const;
void parseUpdates(); void startCheckForUpdates();
void startUpdaterUiApplication();
signals:
void lastCheckDateChanged(const QDate &date);
void newUpdatesAvailable(bool available);
void checkForUpdatesRunningChanged(bool running);
private: private:
QDomDocument update(); void setLastCheckDate(const QDate &date);
template <typename T> void settingsHelper(T *settings);
void startAutoCheckForUpdates();
void stopAutoCheckForUpdates();
void doAutoCheckForUpdates();
void startUpdater();
void stopCheckForUpdates();
void collectCheckForUpdatesOutput(const QString &contents);
void checkForUpdatesFinished();
void loadSettings() const;
void saveSettings();
private: private:
UpdateInfoPluginPrivate *d; UpdateInfoPluginPrivate *d;