From e1cf3423a505fe9eb65f0c043416c60aa131c6a4 Mon Sep 17 00:00:00 2001
From: James Turner <zakalawe@mac.com>
Date: Mon, 7 Nov 2016 20:49:33 +0100
Subject: [PATCH] =?UTF-8?q?=E2=80=98Update=20all=20aircraft=E2=80=99=20UI?=
 =?UTF-8?q?=20overlay.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

WIP, but basics should be there.
---
 src/GUI/AircraftItemDelegate.cxx |  4 +-
 src/GUI/AircraftModel.cxx        | 21 +++++-----
 src/GUI/AircraftModel.hxx        | 17 ++++----
 src/GUI/CMakeLists.txt           |  1 +
 src/GUI/QtLauncher.cxx           | 70 +++++++++++++++++++++++++++++---
 src/GUI/QtLauncher_private.hxx   |  6 +++
 src/GUI/UpdateAllAircraft.ui     | 44 ++++++++++++++++++++
 7 files changed, 136 insertions(+), 27 deletions(-)
 create mode 100644 src/GUI/UpdateAllAircraft.ui

diff --git a/src/GUI/AircraftItemDelegate.cxx b/src/GUI/AircraftItemDelegate.cxx
index 12bce2651..41bd4865b 100644
--- a/src/GUI/AircraftItemDelegate.cxx
+++ b/src/GUI/AircraftItemDelegate.cxx
@@ -47,7 +47,7 @@ void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem
 
     QVariant v = index.data(AircraftPackageStatusRole);
     const AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
-    if (status == NoOfficialCatalogMessage) {
+    if (status == MessageWidget) {
         painter->setPen(QColor(0x7f, 0x7f, 0x7f));
         painter->setBrush(Qt::NoBrush);
 
@@ -236,7 +236,7 @@ QSize AircraftItemDelegate::sizeHint(const QStyleOptionViewItem & option, const
     QVariant v = index.data(AircraftPackageStatusRole);
     const AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
 
-    if (status == NoOfficialCatalogMessage) {
+    if (status == MessageWidget) {
         QSize r = option.rect.size();
         r.setHeight(100);
         return r;
diff --git a/src/GUI/AircraftModel.cxx b/src/GUI/AircraftModel.cxx
index b0369b7eb..a6c4d5ac6 100644
--- a/src/GUI/AircraftModel.cxx
+++ b/src/GUI/AircraftModel.cxx
@@ -438,9 +438,7 @@ private:
 };
 
 AircraftItemModel::AircraftItemModel(QObject* pr ) :
-    QAbstractListModel(pr),
-    m_scanThread(NULL),
-    m_showOfficialHangarMessage(false)
+    QAbstractListModel(pr)
 {
 }
 
@@ -471,13 +469,13 @@ void AircraftItemModel::setPaths(QStringList paths)
     m_paths = paths;
 }
 
-void AircraftItemModel::setOfficialHangarMessageVisible(bool vis)
+void AircraftItemModel::setMessageWidgetVisible(bool vis)
 {
-    if (m_showOfficialHangarMessage == vis) {
+    if (m_showMessageWidget == vis) {
         return;
     }
 
-    m_showOfficialHangarMessage = vis;
+    m_showMessageWidget = vis;
 
     if (vis) {
         beginInsertRows(QModelIndex(), 0, 0);
@@ -492,9 +490,9 @@ void AircraftItemModel::setOfficialHangarMessageVisible(bool vis)
     }
 }
 
-QModelIndex AircraftItemModel::officialHangarMessageIndex() const
+QModelIndex AircraftItemModel::messageWidgetIndex() const
 {
-    if (!m_showOfficialHangarMessage) {
+    if (!m_showMessageWidget) {
         return QModelIndex();
     }
 
@@ -505,7 +503,7 @@ void AircraftItemModel::scanDirs()
 {
 	abandonCurrentScan();
 
-	int firstRow = (m_showOfficialHangarMessage ? 1 : 0);
+    int firstRow = (m_showMessageWidget ? 1 : 0);
 	int numToRemove = m_items.size() - firstRow;
 	if (numToRemove > 0) {
 		int lastRow = firstRow + numToRemove - 1;
@@ -574,6 +572,7 @@ void AircraftItemModel::refreshPackages()
     }
 
     emit dataChanged(index(firstRow), index(firstRow + newSize - 1));
+    emit packagesNeedUpdating(!m_packageRoot->packagesNeedingUpdate().empty());
 }
 
 int AircraftItemModel::rowCount(const QModelIndex& parent) const
@@ -584,10 +583,10 @@ int AircraftItemModel::rowCount(const QModelIndex& parent) const
 QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
 {
     int row = index.row();
-    if (m_showOfficialHangarMessage) {
+    if (m_showMessageWidget) {
         if (row == 0) {
             if (role == AircraftPackageStatusRole) {
-                return NoOfficialCatalogMessage;
+                return MessageWidget;
             }
 
             return QVariant();
diff --git a/src/GUI/AircraftModel.hxx b/src/GUI/AircraftModel.hxx
index 401a6b6a2..5499f19d0 100644
--- a/src/GUI/AircraftModel.hxx
+++ b/src/GUI/AircraftModel.hxx
@@ -96,7 +96,7 @@ enum AircraftItemStatus {
     PackageUpdateAvailable,
     PackageQueued,
     PackageDownloading,
-    NoOfficialCatalogMessage
+    MessageWidget
 };
 
 class AircraftItemModel : public QAbstractListModel
@@ -133,12 +133,12 @@ public:
     bool isIndexRunnable(const QModelIndex& index) const;
 
     /**
-     * should we show the prompt about the official hangar not being installed
-     * or not?
+     * should we show reserve index 0 for a message widget? Which is set
+     * by the layer above via setIndexWidget
      */
-    void setOfficialHangarMessageVisible(bool vis);
+    void setMessageWidgetVisible(bool vis);
 
-    QModelIndex officialHangarMessageIndex() const;
+    QModelIndex messageWidgetIndex() const;
 
     /**
      * @helper to determine if a particular path is likely to contain
@@ -153,6 +153,7 @@ signals:
     
     void scanCompleted();
 
+    void packagesNeedUpdating(bool yes);
 private slots:
     void onScanResults();
     
@@ -175,10 +176,10 @@ private:
     void installFailed(QModelIndex index, simgear::pkg::Delegate::StatusCode reason);
     
     QStringList m_paths;
-    AircraftScanThread* m_scanThread;
+    AircraftScanThread* m_scanThread = nullptr;
     QVector<AircraftItemPtr> m_items;
-    PackageDelegate* m_delegate;
-    bool m_showOfficialHangarMessage;
+    PackageDelegate* m_delegate = nullptr;
+    bool m_showMessageWidget = false;
 
     QVector<quint32> m_activeVariant;
     QVector<quint32> m_packageVariant;
diff --git a/src/GUI/CMakeLists.txt b/src/GUI/CMakeLists.txt
index 87ccb8d09..aedf62068 100644
--- a/src/GUI/CMakeLists.txt
+++ b/src/GUI/CMakeLists.txt
@@ -79,6 +79,7 @@ if (HAVE_QT)
                             NoOfficialHangar.ui
                             InstallSceneryDialog.ui
                             EditCustomMPServerDialog.ui
+                            UpdateAllAircraft.ui
                             )
     qt5_add_resources(qrc_sources resources.qrc)
 
diff --git a/src/GUI/QtLauncher.cxx b/src/GUI/QtLauncher.cxx
index 04a08194c..b1ce55061 100644
--- a/src/GUI/QtLauncher.cxx
+++ b/src/GUI/QtLauncher.cxx
@@ -61,6 +61,7 @@
 
 #include "ui_Launcher.h"
 #include "ui_NoOfficialHangar.h"
+#include "ui_UpdateAllAircraft.h"
 
 #include "EditRatingsFilterDialog.hxx"
 #include "AircraftItemDelegate.hxx"
@@ -375,7 +376,7 @@ protected:
         QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
         QVariant v = index.data(AircraftPackageStatusRole);
         AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
-        if (status == NoOfficialCatalogMessage) {
+        if (status == MessageWidget) {
             return true;
         }
 
@@ -428,6 +429,27 @@ private:
     Ui::NoOfficialHangarMessage* m_ui;
 };
 
+class UpdateAllAircraftMessage : public QWidget
+{
+    Q_OBJECT
+public:
+    UpdateAllAircraftMessage() :
+        m_ui(new Ui::UpdateAllAircraftMessage)
+    {
+        m_ui->setupUi(this);
+        // proxy this signal upwards
+        connect(m_ui->label, &QLabel::linkActivated, this, &UpdateAllAircraftMessage::linkActivated);
+        connect(m_ui->updateAllButton, &QPushButton::clicked, this, &UpdateAllAircraftMessage::updateAll);
+    }
+
+Q_SIGNALS:
+    void linkActivated(QUrl link);
+    void updateAll();
+private:
+    Ui::UpdateAllAircraftMessage* m_ui;
+};
+
+
 static void initQtResources()
 {
     Q_INIT_RESOURCE(resources);
@@ -1238,6 +1260,20 @@ void QtLauncher::updateSelectedAircraft()
     }
 }
 
+void QtLauncher::onUpdateAllAircraft()
+{
+    const PackageList& toBeUpdated = globals->packageRoot()->packagesNeedingUpdate();
+    std::for_each(toBeUpdated.begin(), toBeUpdated.end(), [](PackageRef pkg) {
+        globals->packageRoot()->scheduleToUpdate(pkg->install());
+    });
+}
+
+void QtLauncher::onPackagesNeedUpdate(bool yes)
+{
+    Q_UNUSED(yes);
+    checkUpdateAircraft();
+}
+
 QModelIndex QtLauncher::proxyIndexForAircraftURI(QUrl uri) const
 {
   return m_aircraftProxy->mapFromSource(sourceIndexForAircraftURI(uri));
@@ -1397,21 +1433,25 @@ void QtLauncher::onDownloadDirChanged()
     setSceneryPaths();
 }
 
-void QtLauncher::checkOfficialCatalogMessage()
+bool QtLauncher::shouldShowOfficialCatalogMessage() const
 {
     QSettings settings;
     bool showOfficialCatalogMesssage = !globals->get_subsystem<FGHTTPClient>()->isDefaultCatalogInstalled();
     if (settings.value("hide-official-catalog-message").toBool()) {
         showOfficialCatalogMesssage = false;
     }
-
-    m_aircraftModel->setOfficialHangarMessageVisible(showOfficialCatalogMesssage);
-    if (showOfficialCatalogMesssage) {
+    return showOfficialCatalogMesssage;
+}
+void QtLauncher::checkOfficialCatalogMessage()
+{
+    const bool show = shouldShowOfficialCatalogMessage();
+    m_aircraftModel->setMessageWidgetVisible(show);
+    if (show) {
         NoOfficialHangarMessage* messageWidget = new NoOfficialHangarMessage;
         connect(messageWidget, &NoOfficialHangarMessage::linkActivated,
                 this, &QtLauncher::onOfficialCatalogMessageLink);
 
-        QModelIndex index = m_aircraftProxy->mapFromSource(m_aircraftModel->officialHangarMessageIndex());
+        QModelIndex index = m_aircraftProxy->mapFromSource(m_aircraftModel->messageWidgetIndex());
         m_ui->aircraftList->setIndexWidget(index, messageWidget);
     }
 }
@@ -1429,6 +1469,24 @@ void QtLauncher::onOfficialCatalogMessageLink(QUrl link)
     checkOfficialCatalogMessage();
 }
 
+void QtLauncher::checkUpdateAircraft()
+{
+    if (shouldShowOfficialCatalogMessage()) {
+        return; // don't interfere
+    }
+
+    const bool showUpdateMessage = !globals->packageRoot()->packagesNeedingUpdate().empty();
+    m_aircraftModel->setMessageWidgetVisible(showUpdateMessage);
+    if (showUpdateMessage) {
+        UpdateAllAircraftMessage* messageWidget = new UpdateAllAircraftMessage;
+       // connect(messageWidget, &UpdateAllAircraftMessage::linkActivated,
+      //        this, &QtLauncher::onMessageLink);
+        connect(messageWidget, &UpdateAllAircraftMessage::updateAll, this, &QtLauncher::onUpdateAllAircraft);
+        QModelIndex index = m_aircraftProxy->mapFromSource(m_aircraftModel->messageWidgetIndex());
+        m_ui->aircraftList->setIndexWidget(index, messageWidget);
+    }
+}
+
 void QtLauncher::onRefreshMPServers()
 {
     if (m_mpServerRequest.get()) {
diff --git a/src/GUI/QtLauncher_private.hxx b/src/GUI/QtLauncher_private.hxx
index b6357ae34..b3405d22c 100644
--- a/src/GUI/QtLauncher_private.hxx
+++ b/src/GUI/QtLauncher_private.hxx
@@ -104,6 +104,9 @@ private slots:
     void onRefreshMPServers();
     void onMPServerActivated(int index);
 
+    void onUpdateAllAircraft();
+
+    void onPackagesNeedUpdate(bool yes);
 
 private:
 
@@ -127,6 +130,8 @@ private:
     void checkOfficialCatalogMessage();
     void onOfficialCatalogMessageLink(QUrl link);
 
+    void checkUpdateAircraft();
+
     void onRefreshMPServersDone(simgear::HTTP::Request*);
     void onRefreshMPServersFailed(simgear::HTTP::Request*);
     int findMPServerPort(const std::string& host);
@@ -138,6 +143,7 @@ private:
     void onRatingsFilterToggled();
 
     void updateLocationHistory();
+    bool shouldShowOfficialCatalogMessage() const;
 
     QScopedPointer<Ui::Launcher> m_ui;
     AircraftProxyModel* m_aircraftProxy;
diff --git a/src/GUI/UpdateAllAircraft.ui b/src/GUI/UpdateAllAircraft.ui
new file mode 100644
index 000000000..602019d58
--- /dev/null
+++ b/src/GUI/UpdateAllAircraft.ui
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UpdateAllAircraftMessage</class>
+ <widget class="QWidget" name="UpdateAllAircraftMessage">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>607</width>
+    <height>44</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="autoFillBackground">
+   <bool>false</bool>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 aircraft have updates available. (&lt;a href=&quot;action:hide&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Click&lt;/span&gt;&lt;/a&gt; to hide this)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+     <property name="textFormat">
+      <enum>Qt::RichText</enum>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="updateAllButton">
+     <property name="text">
+      <string>Update all</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>