diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h index 15e33c247cc98d14b1b33b0c8f0b82def7e1a01a..73544db89a21e46e4154d938ecbc343e890bcaac 100644 --- a/src/plugins/coreplugin/coreconstants.h +++ b/src/plugins/coreplugin/coreconstants.h @@ -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_SUPPORT[] = "QtCreator.Group.Help.Supprt"; 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_PLUS[] = ":/core/images/plus.png"; diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index a502b595a668d1de9a64f57021978194fcb97c6d..15d094bbfbe29ed929724f122f9cb2e34883c76d 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -453,6 +453,7 @@ void MainWindow::registerDefaultContainers() ac->appendGroup(Constants::G_HELP_HELP); ac->appendGroup(Constants::G_HELP_SUPPORT); ac->appendGroup(Constants::G_HELP_ABOUT); + ac->appendGroup(Constants::G_HELP_UPDATES); } void MainWindow::registerDefaultActions() diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index a610c7403b4ba19d05e8e41915efe92beb658ecf..b39c61e6b5e3c975b3ebd53d4a1d1795ea0b34d3 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -52,6 +52,7 @@ SUBDIRS = \ qmakeandroidsupport \ winrt \ qmlprofiler \ + updateinfo \ welcome DO_NOT_BUILD_QMLDESIGNER = $$(DO_NOT_BUILD_QMLDESIGNER) diff --git a/src/plugins/updateinfo/settingspage.cpp b/src/plugins/updateinfo/settingspage.cpp index 6565760dc033aa75eaf0a2392710c30e370589d9..291424fd415d24958ef408a897109087462c1baa 100644 --- a/src/plugins/updateinfo/settingspage.cpp +++ b/src/plugins/updateinfo/settingspage.cpp @@ -29,21 +29,31 @@ ****************************************************************************/ #include "settingspage.h" -#include "updateinfoplugin.h" #include <coreplugin/coreconstants.h> +#include <utils/qtcassert.h> +#include <utils/progressindicator.h> + +#include <QDate> using namespace UpdateInfo; 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) : m_widget(0) , m_plugin(plugin) { - setId(Constants::FILTER_OPTIONS_PAGE); + setId(FILTER_OPTIONS_PAGE_ID); setCategory(Core::Constants::SETTINGS_CATEGORY_CORE); 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)); } @@ -52,17 +62,116 @@ QWidget *SettingsPage::widget() if (!m_widget) { m_widget = new QWidget; m_ui.setupUi(m_widget); - m_ui.m_timeTable->setItemText(m_ui.m_timeTable->currentIndex(), QTime(m_plugin->scheduledUpdateTime()) - .toString(QLatin1String("hh:mm"))); + m_ui.m_checkIntervalComboBox->addItem(tr("Daily"), UpdateInfoPlugin::DailyCheck); + 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; } +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() { - m_plugin->setScheduledUpdateTime(QTime::fromString(m_ui.m_timeTable->currentText(), - QLatin1String("hh:mm"))); - m_plugin->saveSettings(); + if (!m_widget) + return; + + m_plugin->setCheckUpdateInterval(currentCheckInterval()); + m_plugin->setAutomaticCheck(m_ui.m_updatesGroupBox->isChecked()); } void SettingsPage::finish() diff --git a/src/plugins/updateinfo/settingspage.h b/src/plugins/updateinfo/settingspage.h index 43bdd0b533b7f1ac6646723e25aea7bd3236d38d..77cf685a89bf73f6a7c180945337b04f1bee238a 100644 --- a/src/plugins/updateinfo/settingspage.h +++ b/src/plugins/updateinfo/settingspage.h @@ -32,11 +32,14 @@ #define SETTINGSPAGE_H #include "ui_settingspage.h" +#include "updateinfoplugin.h" #include <coreplugin/dialogs/ioptionspage.h> #include <QPointer> +namespace Utils { class ProgressIndicator; } + namespace UpdateInfo { namespace Internal { @@ -54,7 +57,14 @@ public: void finish(); private: + void newUpdatesAvailable(bool available); + void checkRunningChanged(bool running); + void updateLastCheckDate(); + void updateNextCheckDate(); + UpdateInfoPlugin::CheckUpdateInterval currentCheckInterval() const; + QPointer<QWidget> m_widget; + QPointer<Utils::ProgressIndicator> m_progressIndicator; Ui::SettingsWidget m_ui; UpdateInfoPlugin *m_plugin; }; diff --git a/src/plugins/updateinfo/settingspage.ui b/src/plugins/updateinfo/settingspage.ui index fee80c0e944ccf1eb125a25dd1d3ecf4d2ab9527..d34ef304e60b1f84b5c57aae784e1a27620fd18a 100644 --- a/src/plugins/updateinfo/settingspage.ui +++ b/src/plugins/updateinfo/settingspage.ui @@ -7,21 +7,34 @@ <x>0</x> <y>0</y> <width>482</width> - <height>364</height> + <height>242</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"> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0" colspan="4"> + <widget class="QGroupBox" name="m_updatesGroupBox"> <property name="title"> - <string>Qt Creator Update Settings</string> + <string>Automatic Check for Updates</string> </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QLabel" name="m_info"> + <property name="checkable"> + <bool>true</bool> + </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"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -29,196 +42,107 @@ </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> + <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 name="wordWrap"> <bool>true</bool> </property> </widget> </item> - <item> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> + <item row="1" column="1"> + <widget class="QComboBox" name="m_checkIntervalComboBox"> + <property name="currentIndex"> + <number>-1</number> </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> + </widget> + </item> + <item row="1" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> - <width>20</width> + <width>171</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 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> - </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> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Next check date:</string> </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>253</height> - </size> + </widget> + </item> + <item row="2" column="1" colspan="2"> + <widget class="QLabel" name="m_nextCheckDateLabel"> + <property name="text"> + <string/> </property> - </spacer> + </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"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>233</height> + </size> + </property> + </spacer> + </item> </layout> </widget> <resources/> diff --git a/src/plugins/updateinfo/updateinfo.pro b/src/plugins/updateinfo/updateinfo.pro index 7654a4f6c537f92e268c1445018f2bf7d4d756db..8a66ba38981e8370151fed24d421adfff99c0637 100644 --- a/src/plugins/updateinfo/updateinfo.pro +++ b/src/plugins/updateinfo/updateinfo.pro @@ -1,10 +1,8 @@ QT += network xml HEADERS += updateinfoplugin.h \ - updateinfobutton.h \ settingspage.h SOURCES += updateinfoplugin.cpp \ - updateinfobutton.cpp \ settingspage.cpp FORMS += settingspage.ui RESOURCES += updateinfo.qrc diff --git a/src/plugins/updateinfo/updateinfo.qbs b/src/plugins/updateinfo/updateinfo.qbs index 02161420e302847979d79b43145004d04c824b90..2a875c4d7f42b75d2166f8e1bf022e2cd06077e2 100644 --- a/src/plugins/updateinfo/updateinfo.qbs +++ b/src/plugins/updateinfo/updateinfo.qbs @@ -14,8 +14,6 @@ QtcPlugin { pluginJsonReplacements: ({"UPDATEINFO_EXPERIMENTAL_STR": (enable ? "false": "true")}) files: [ - "updateinfobutton.cpp", - "updateinfobutton.h", "updateinfoplugin.cpp", "updateinfoplugin.h", "settingspage.cpp", diff --git a/src/plugins/updateinfo/updateinfobutton.cpp b/src/plugins/updateinfo/updateinfobutton.cpp deleted file mode 100644 index e049626923135c99fe4af47d7af542a866639067..0000000000000000000000000000000000000000 --- a/src/plugins/updateinfo/updateinfobutton.cpp +++ /dev/null @@ -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 diff --git a/src/plugins/updateinfo/updateinfobutton.h b/src/plugins/updateinfo/updateinfobutton.h deleted file mode 100644 index d99827ee4b59b7a2ff8e5d7dba572a4b31d109a9..0000000000000000000000000000000000000000 --- a/src/plugins/updateinfo/updateinfobutton.h +++ /dev/null @@ -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 diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index 1def9167f4ac0621712645be3d9e86263532e4cf..b327d2eb2eae386ce552f45658276e65ecd43638 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -30,28 +30,34 @@ #include "settingspage.h" #include "updateinfoplugin.h" -#include "updateinfobutton.h" #include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/coreconstants.h> #include <coreplugin/icore.h> -#include <coreplugin/progressmanager/progressmanager.h> -#include <coreplugin/progressmanager/futureprogress.h> #include <coreplugin/settingsdatabase.h> +#include <coreplugin/shellcommand.h> +#include <utils/fileutils.h> -#include <qtconcurrentrun.h> - -#include <QBasicTimer> +#include <QDate> #include <QDomDocument> #include <QFile> -#include <QFutureWatcher> +#include <QFileInfo> #include <QMenu> -#include <QProcess> +#include <QMessageBox> +#include <QMetaEnum> +#include <QProcessEnvironment> +#include <QTimer> #include <QtPlugin> 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 OneHour = 3600000; } using namespace Core; @@ -63,47 +69,120 @@ class UpdateInfoPluginPrivate { public: UpdateInfoPluginPrivate() - : progressUpdateInfoButton(0), - checkUpdateInfoWatcher(0), - m_settingsPage(0) - { - } + { } - QString updaterProgram; - QString updaterRunUiArgument; - QString updaterCheckOnlyArgument; + QString m_maintenanceTool; + ShellCommand *m_checkUpdatesCommand = 0; + QString m_collectedOutput; + QTimer *m_checkUpdatesTimer = 0; - QFuture<QDomDocument> lastCheckUpdateInfoTask; - QPointer<FutureProgress> updateInfoProgress; - UpdateInfoButton *progressUpdateInfoButton; - QFutureWatcher<QDomDocument> *checkUpdateInfoWatcher; - - QBasicTimer m_timer; - QDate m_lastDayChecked; - QTime m_scheduledUpdateTime; - SettingsPage *m_settingsPage; + bool m_automaticCheck = true; + UpdateInfoPlugin::CheckUpdateInterval m_checkInterval = UpdateInfoPlugin::WeeklyCheck; + QDate m_lastCheckDate; }; UpdateInfoPlugin::UpdateInfoPlugin() : 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() { - d->lastCheckUpdateInfoTask.cancel(); - d->lastCheckUpdateInfoTask.waitForFinished(); + stopCheckForUpdates(); + if (!d->m_maintenanceTool.isEmpty()) + saveSettings(); 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() { - d->checkUpdateInfoWatcher = new QFutureWatcher<QDomDocument>(this); - connect(d->checkUpdateInfoWatcher, SIGNAL(finished()), this, SLOT(parseUpdates())); + if (isAutomaticCheck()) + QTimer::singleShot(OneMinute, this, &UpdateInfoPlugin::startAutoCheckForUpdates); - d->m_timer.start(OneMinute, this); return true; } @@ -114,167 +193,132 @@ void UpdateInfoPlugin::extensionsInitialized() bool UpdateInfoPlugin::initialize(const QStringList & /* arguments */, QString *errorMessage) { loadSettings(); - if (d->updaterProgram.isEmpty()) { + + if (d->m_maintenanceTool.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); + if (!QFileInfo(d->m_maintenanceTool).isExecutable()) { + *errorMessage = tr("The maintenance tool at \"%1\" is not an executable. Check your installation.") + .arg(d->m_maintenanceTool); + d->m_maintenanceTool = QString(); return false; } - d->m_settingsPage = new SettingsPage(this); - addAutoReleasedObject(d->m_settingsPage); + connect(ICore::instance(), &ICore::saveSettingsRequested, + this, &UpdateInfoPlugin::saveSettings); + + addAutoReleasedObject(new SettingsPage(this)); - ActionContainer *const container = ActionManager::actionContainer(Core::Constants::M_HELP); - 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; } -void UpdateInfoPlugin::loadSettings() +void UpdateInfoPlugin::loadSettings() const { - 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()); + QSettings *settings = ICore::settings(); + const QString updaterKey = QLatin1String(UpdaterGroup) + QLatin1Char('/'); + d->m_maintenanceTool = settings->value(updaterKey + QLatin1String(MaintenanceToolKey)).toString(); + d->m_lastCheckDate = settings->value(updaterKey + QLatin1String(LastCheckDateKey), QDate()).toDate(); + d->m_automaticCheck = settings->value(updaterKey + QLatin1String(AutomaticCheckKey), true).toBool(); + const QString checkInterval = settings->value(updaterKey + QLatin1String(CheckIntervalKey)).toString(); + 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() { - SettingsDatabase *settings = ICore::settingsDatabase(); - if (settings) { - settings->beginTransaction(); - 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(); - settings->endTransaction(); - } + QSettings *settings = ICore::settings(); + settings->beginGroup(QLatin1String(UpdaterGroup)); + settings->setValue(QLatin1String(LastCheckDateKey), d->m_lastCheckDate); + settings->setValue(QLatin1String(AutomaticCheckKey), d->m_automaticCheck); + // Note: don't save MaintenanceToolKey on purpose! This setting may be set only by installer. + // If creator is run not from installed SDK, the setting can be manually created here: + // [CREATOR_INSTALLATION_LOCATION]/share/qtcreator/QtProject/QtCreator.ini or + // [CREATOR_INSTALLATION_LOCATION]/Qt Creator.app/Contents/Resources/QtProject/QtCreator.ini on OS X + const QMetaObject *mo = metaObject(); + const QMetaEnum me = mo->enumerator(mo->indexOfEnumerator(CheckIntervalKey)); + settings->setValue(QLatin1String(CheckIntervalKey), QLatin1String(me.valueToKey(d->m_checkInterval))); + settings->endGroup(); } -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) + return; -// -- protected + d->m_automaticCheck = on; + if (on) + startAutoCheckForUpdates(); + else + stopAutoCheckForUpdates(); +} -void UpdateInfoPlugin::timerEvent(QTimerEvent *event) +UpdateInfoPlugin::CheckUpdateInterval UpdateInfoPlugin::checkUpdateInterval() const { - 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); - } + return d->m_checkInterval; } -// -- private slots - -void UpdateInfoPlugin::parseUpdates() +void UpdateInfoPlugin::setCheckUpdateInterval(UpdateInfoPlugin::CheckUpdateInterval interval) { - QDomDocument updatesDomDocument = d->checkUpdateInfoWatcher->result(); - if (updatesDomDocument.isNull() || !updatesDomDocument.firstChildElement().hasChildNodes()) + if (d->m_checkInterval == interval) 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())); + d->m_checkInterval = interval; } -void UpdateInfoPlugin::startUpdaterUiApplication() +QDate UpdateInfoPlugin::lastCheckDate() const { - QProcess::startDetached(d->updaterProgram, QStringList() << d->updaterRunUiArgument); - if (!d->updateInfoProgress.isNull()) //this is fading out the last update info - d->updateInfoProgress->setKeepOnFinish(FutureProgress::HideOnFinish); + return d->m_lastCheckDate; } -// -- private - -QDomDocument UpdateInfoPlugin::update() +void UpdateInfoPlugin::setLastCheckDate(const QDate &date) { - 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); - 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."; - } + if (d->m_lastCheckDate == date) + return; - d->m_lastDayChecked = QDate::currentDate(); - return updates; + d->m_lastCheckDate = date; + emit lastCheckDateChanged(date); } -template <typename T> -void UpdateInfoPlugin::settingsHelper(T *settings) +QDate UpdateInfoPlugin::nextCheckDate() const { - settings->beginGroup(QLatin1String("Updater")); + return nextCheckDate(d->m_checkInterval); +} - 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(); +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); +} - settings->endGroup(); +void UpdateInfoPlugin::startUpdater() +{ + QProcess::startDetached(d->m_maintenanceTool, QStringList(QLatin1String("--updater"))); } } //namespace Internal diff --git a/src/plugins/updateinfo/updateinfoplugin.h b/src/plugins/updateinfo/updateinfoplugin.h index 6f4c0576cf9f8224067c3cff2288622cf9c24202..69862e1be5c574bb3ff8b8cc23b8234eb93c677f 100644 --- a/src/plugins/updateinfo/updateinfoplugin.h +++ b/src/plugins/updateinfo/updateinfoplugin.h @@ -33,26 +33,28 @@ #include <extensionsystem/iplugin.h> -#include <QTime> -#include <QDomDocument> +QT_BEGIN_NAMESPACE +class QDate; +QT_END_NAMESPACE 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 { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "UpdateInfo.json") - + Q_ENUMS(CheckUpdateInterval) public: + enum CheckUpdateInterval { + DailyCheck, + WeeklyCheck, + MonthlyCheck + }; + UpdateInfoPlugin(); virtual ~UpdateInfoPlugin(); @@ -60,22 +62,39 @@ public: void extensionsInitialized(); bool initialize(const QStringList &arguments, QString *errorMessage); - void loadSettings(); - void saveSettings(); + bool isAutomaticCheck() const; + void setAutomaticCheck(bool on); + + CheckUpdateInterval checkUpdateInterval() const; + void setCheckUpdateInterval(CheckUpdateInterval interval); - QTime scheduledUpdateTime() const; - void setScheduledUpdateTime(const QTime &time); + QDate lastCheckDate() const; + QDate nextCheckDate() const; + QDate nextCheckDate(CheckUpdateInterval interval) const; -protected: - void timerEvent(QTimerEvent *event); + bool isCheckForUpdatesRunning() const; + void startCheckForUpdates(); -private slots: - void parseUpdates(); - void startUpdaterUiApplication(); +signals: + void lastCheckDateChanged(const QDate &date); + void newUpdatesAvailable(bool available); + void checkForUpdatesRunningChanged(bool running); private: - QDomDocument update(); - template <typename T> void settingsHelper(T *settings); + void setLastCheckDate(const QDate &date); + + void startAutoCheckForUpdates(); + void stopAutoCheckForUpdates(); + void doAutoCheckForUpdates(); + + void startUpdater(); + void stopCheckForUpdates(); + + void collectCheckForUpdatesOutput(const QString &contents); + void checkForUpdatesFinished(); + + void loadSettings() const; + void saveSettings(); private: UpdateInfoPluginPrivate *d;