From 13fcf5ad3c3705ae87556b2072889daa519ff1b3 Mon Sep 17 00:00:00 2001
From: Jarek Kobus <jaroslaw.kobus@theqtcompany.com>
Date: Tue, 19 May 2015 15:15:15 +0200
Subject: [PATCH] Refactor UpdateInfo plugin

Change-Id: I63fc40b12e29204d9ecd4ed3fd33e7ad3171918d
Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com>
---
 src/plugins/coreplugin/coreconstants.h      |   1 +
 src/plugins/coreplugin/mainwindow.cpp       |   1 +
 src/plugins/plugins.pro                     |   1 +
 src/plugins/updateinfo/settingspage.cpp     | 125 +++++++-
 src/plugins/updateinfo/settingspage.h       |  10 +
 src/plugins/updateinfo/settingspage.ui      | 278 ++++++----------
 src/plugins/updateinfo/updateinfo.pro       |   2 -
 src/plugins/updateinfo/updateinfo.qbs       |   2 -
 src/plugins/updateinfo/updateinfobutton.cpp |  77 -----
 src/plugins/updateinfo/updateinfobutton.h   |  52 ---
 src/plugins/updateinfo/updateinfoplugin.cpp | 336 +++++++++++---------
 src/plugins/updateinfo/updateinfoplugin.h   |  57 ++--
 12 files changed, 459 insertions(+), 483 deletions(-)
 delete mode 100644 src/plugins/updateinfo/updateinfobutton.cpp
 delete mode 100644 src/plugins/updateinfo/updateinfobutton.h

diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h
index 15e33c247cc..73544db89a2 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 a502b595a66..15d094bbfbe 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 a610c7403b4..b39c61e6b5e 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 6565760dc03..291424fd415 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 43bdd0b533b..77cf685a89b 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 fee80c0e944..d34ef304e60 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 7654a4f6c53..8a66ba38981 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 02161420e30..2a875c4d7f4 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 e0496269231..00000000000
--- 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 d99827ee4b5..00000000000
--- 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 1def9167f4a..b327d2eb2ea 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 6f4c0576cf9..69862e1be5c 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;
-- 
GitLab