Dialog (no longer overlay frame) for new DB data

* allows to select the entities
* allows to consolidate
This commit is contained in:
Klaus Basan
2018-04-02 02:25:41 +02:00
parent f8d16555aa
commit 9192d13a6c
6 changed files with 470 additions and 51 deletions

View File

@@ -0,0 +1,192 @@
/* Copyright (C) 2018
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "dbloaddatadialog.h"
#include "ui_dbloaddatadialog.h"
#include "blackgui/guiapplication.h"
#include "blackcore/webdataservices.h"
#include "blackcore/db/databaseutils.h"
#include "blackmisc/simulation/aircraftmodellist.h"
#include <QDialogButtonBox>
#include <QModelIndexList>
using namespace BlackMisc::Network;
using namespace BlackMisc::Simulation;
using namespace BlackMisc::Simulation::Data;
using namespace BlackCore;
using namespace BlackCore::Db;
namespace BlackGui
{
namespace Components
{
CDbLoadDataDialog::CDbLoadDataDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::CDbLoadDataDialog)
{
Q_ASSERT_X(sGui, Q_FUNC_INFO, "Need sGui");
ui->setupUi(this);
this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
QStringListModel *lvm = new QStringListModel(ui->lv_Entities);
ui->comp_SimulatorSelector->setMode(CSimulatorSelector::RadioButtons);
ui->lv_Entities->setModel(lvm);
ui->bb_loadDataDialog->button(QDialogButtonBox::Apply)->setText("Load");
ui->wi_WorkStatus->setVisible(false);
ui->wi_Consolidate->setVisible(false);
ui->comp_SimulatorSelector->setValue(m_sets.getCurrentSimulator());
connect(sGui->getWebDataServices(), &CWebDataServices::dataRead, this, &CDbLoadDataDialog::onDataRead, Qt::QueuedConnection);
connect(ui->bb_loadDataDialog, &QDialogButtonBox::clicked, this, &CDbLoadDataDialog::onButtonClicked);
connect(ui->pb_Consolidate, &QPushButton::clicked, this, &CDbLoadDataDialog::consolidate);
connect(this, &CDbLoadDataDialog::rejected, this, &CDbLoadDataDialog::onRejected);
connect(ui->comp_SimulatorSelector, &CSimulatorSelector::changed, &m_sets, &CModelSetCaches::setCurrentSimulator, Qt::QueuedConnection);
connect(ui->comp_SimulatorSelector, &CSimulatorSelector::changed, &m_models, &CModelCaches::setCurrentSimulator, Qt::QueuedConnection);
}
CDbLoadDataDialog::~CDbLoadDataDialog()
{ }
bool CDbLoadDataDialog::newerOrEmptyEntitiesDetected(CEntityFlags::Entity loadEntities)
{
this->show();
if (m_consolidating) { return false; }
if (m_pendingEntities != CEntityFlags::NoEntity) { return false; } // already loading
if (loadEntities == CEntityFlags::NoEntity) { return false; }
m_autoConsolidate = false;
const QStringList entitiesStringList = CEntityFlags::entitiesToStringList(loadEntities);
this->entitiesModel()->setStringList(entitiesStringList);
ui->lv_Entities->selectAll();
return true;
}
QStringListModel *CDbLoadDataDialog::entitiesModel() const
{
return qobject_cast<QStringListModel *>(ui->lv_Entities->model());
}
QStringList CDbLoadDataDialog::selectedEntities() const
{
const QModelIndexList indexes = ui->lv_Entities->selectionModel()->selectedIndexes();
QStringList entities;
for (const QModelIndex &index : indexes)
{
entities.append(index.data(Qt::DisplayRole).toString());
}
return entities;
}
void CDbLoadDataDialog::onButtonClicked(QAbstractButton *button)
{
if (!button) { return; }
if (button == ui->bb_loadDataDialog->button(QDialogButtonBox::Apply))
{
const QStringList entityList = this->selectedEntities();
if (entityList.isEmpty()) { return; }
const CEntityFlags::Entity loadEntities = CEntityFlags::multipleEntitiesByNames(entityList);
m_pendingEntities = sGui->getWebDataServices()->triggerLoadingDirectlyFromSharedFiles(loadEntities, false);
const int pending = CEntityFlags::numberOfEntities(m_pendingEntities);
m_pendingEntitiesCount = sGui->getWebDataServices()->getDbInfoObjectsCount(loadEntities);
ui->pb_Loading->setMaximum(m_pendingEntitiesCount > 0 ? m_pendingEntitiesCount : pending);
ui->pb_Loading->setValue(0);
ui->wi_WorkStatus->setVisible(pending > 0);
ui->wi_Consolidate->setVisible(false);
ui->le_Info->setText("Loading started ...");
}
}
void CDbLoadDataDialog::onDataRead(CEntityFlags::Entity entity, CEntityFlags::ReadState state, int number)
{
if (m_pendingEntities == CEntityFlags::NoEntity) { return; } // no triggered from here
if (state == CEntityFlags::StartRead) { return; }
if (!m_pendingEntities.testFlag(CEntityFlags::entityToEntityFlag(entity))) { return; }
m_pendingEntities &= ~entity;
const int pending = CEntityFlags::numberOfEntities(m_pendingEntities);
const int max = ui->pb_Loading->maximum();
if (m_pendingEntitiesCount < 0)
{
ui->pb_Loading->setValue(max - pending);
}
else
{
m_pendingEntitiesCount -= number;
ui->pb_Loading->setValue(max - m_pendingEntitiesCount);
}
const QString e = CEntityFlags::entitiesToString(entity);
ui->le_Info->setText(e);
if (pending < 1)
{
m_pendingEntitiesCount = -1;
const bool defaultConsolidate = !ui->cb_AllModels->isChecked() && ui->cb_ModelSet->isChecked();
QTimer::singleShot(2000, this, [ = ]
{
ui->wi_Consolidate->setVisible(true);
ui->wi_WorkStatus->setVisible(false);
if (defaultConsolidate)
{
m_autoConsolidate = true;
QTimer::singleShot(1000, this, &CDbLoadDataDialog::consolidate);
}
});
}
}
void CDbLoadDataDialog::onRejected()
{
m_pendingEntities = CEntityFlags::NoEntity;
m_pendingEntitiesCount = -1;
m_autoConsolidate = false;
ui->pb_Loading->setVisible(false);
}
void CDbLoadDataDialog::consolidate()
{
const bool set = ui->cb_ModelSet->isChecked();
const bool all = ui->cb_AllModels->isChecked();
if (m_consolidating) { return; }
if (!set && !all) { return; }
ui->wi_WorkStatus->setVisible(true);
ui->pb_Loading->setValue(0);
ui->pb_Loading->setMaximum(0); // 0/0 causing busy indicator
do
{
if (set)
{
ui->le_Info->setText("Model set");
CAircraftModelList models = m_sets.getCurrentCachedModels();
const int c = CDatabaseUtils::consolidateModelsWithDbDataAllowsGuiRefresh(models, true, true);
if (c > 0) { m_sets.setCachedModels(models, m_sets.getCurrentSimulator()); }
}
if (!this->isVisible()) { break; } // dialog closed?
if (all)
{
ui->le_Info->setText("All models");
CAircraftModelList models = m_models.getCurrentCachedModels();
const int c = CDatabaseUtils::consolidateModelsWithDbDataAllowsGuiRefresh(models, true, true);
if (c > 0) { m_models.setCachedModels(models, m_models.getCurrentSimulator()); }
}
}
while (false);
m_consolidating = false;
QTimer::singleShot(2000, this, [ = ]
{
ui->pb_Loading->setMaximum(100);
ui->wi_WorkStatus->setVisible(false);
if (m_autoConsolidate)
{
m_autoConsolidate = false;
this->accept();
}
});
}
} // ns
} // ns

View File

@@ -0,0 +1,75 @@
/* Copyright (C) 2018
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef DBLOADDATADIALOG_H
#define DBLOADDATADIALOG_H
#include "blackgui/blackguiexport.h"
#include "blackmisc/network/entityflags.h"
#include "blackmisc/simulation/data/modelcaches.h"
#include <QDialog>
#include <QScopedPointer>
#include <QStringListModel>
#include <QAbstractButton>
namespace Ui { class CDbLoadDataDialog; }
namespace BlackGui
{
namespace Components
{
/**
* Load data from DB as dialog
*/
class BLACKGUI_EXPORT CDbLoadDataDialog : public QDialog
{
Q_OBJECT
public:
//! Constructor
explicit CDbLoadDataDialog(QWidget *parent = nullptr);
//! Destructor
virtual ~CDbLoadDataDialog();
//! Newer or empty entities detected
bool newerOrEmptyEntitiesDetected(BlackMisc::Network::CEntityFlags::Entity loadEntities);
private:
QScopedPointer<Ui::CDbLoadDataDialog> ui;
BlackMisc::Network::CEntityFlags::Entity m_pendingEntities = BlackMisc::Network::CEntityFlags::NoEntity;
BlackMisc::Simulation::Data::CModelSetCaches m_sets { true, this }; //!< caches
BlackMisc::Simulation::Data::CModelCaches m_models { true, this }; //!< models
int m_pendingEntitiesCount = -1;
bool m_consolidating = false; //! currently consolidating
bool m_autoConsolidate = false;
//! The string list model
QStringListModel *entitiesModel() const;
//! All selected items
QStringList selectedEntities() const;
//! Button clicked
void onButtonClicked(QAbstractButton *button);
//! Data have been read
void onDataRead(BlackMisc::Network::CEntityFlags::Entity entity, BlackMisc::Network::CEntityFlags::ReadState state, int number);
//! Dialog rejected
void onRejected();
//! Consolidate
void consolidate();
};
} // ns
} // ns
#endif // guard

View File

@@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CDbLoadDataDialog</class>
<widget class="QDialog" name="CDbLoadDataDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>300</height>
</size>
</property>
<property name="windowTitle">
<string>Load new DB data?</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="gb_Entities">
<property name="title">
<string>Entities</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="lbl_Load">
<property name="text">
<string>New DB data. Load the given entities?</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="lv_Entities">
<property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="selectionRectVisible">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="wi_WorkStatus" native="true">
<layout class="QHBoxLayout" name="hl_LoadStatus" stretch="1,3">
<item>
<widget class="QLineEdit" name="le_Info">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="pb_Loading">
<property name="value">
<number>50</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="wi_Consolidate" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="BlackGui::Components::CSimulatorSelector" name="comp_SimulatorSelector">
<property name="minimumSize">
<size>
<width>125</width>
<height>0</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item>
<spacer name="hs_Consolidate">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="cb_ModelSet">
<property name="toolTip">
<string>Model set</string>
</property>
<property name="text">
<string>Set</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cb_AllModels">
<property name="toolTip">
<string>all models</string>
</property>
<property name="text">
<string>All</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pb_Consolidate">
<property name="text">
<string>consolidate</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="bb_loadDataDialog">
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>BlackGui::Components::CSimulatorSelector</class>
<extends>QFrame</extends>
<header>blackgui/components/simulatorselector.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>bb_loadDataDialog</sender>
<signal>accepted()</signal>
<receiver>CDbLoadDataDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>bb_loadDataDialog</sender>
<signal>rejected()</signal>
<receiver>CDbLoadDataDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -417,7 +417,8 @@ QMenuBar::item {
border-radius: 4px; border-radius: 4px;
} }
QMenuBar::item:selected { /* when selected using mouse or keyboard */ /* when selected using mouse or keyboard */
QMenuBar::item:selected {
background: black; background: black;
} }
@@ -588,6 +589,11 @@ QTableView::item:selected {
color: white; color: white;
} }
QListView::item:selected {
background-color: blue;
color: white;
}
QTreeView { QTreeView {
show-decoration-selected: 1; show-decoration-selected: 1;
} }

View File

@@ -16,6 +16,7 @@
#include "blackcore/corefacadeconfig.h" #include "blackcore/corefacadeconfig.h"
#include "blackgui/components/infobarstatuscomponent.h" #include "blackgui/components/infobarstatuscomponent.h"
#include "blackgui/components/logcomponent.h" #include "blackgui/components/logcomponent.h"
#include "blackgui/components/dbloaddatadialog.h"
#include "blackgui/components/settingscomponent.h" #include "blackgui/components/settingscomponent.h"
#include "blackgui/copyxswiftbusdialog.h" #include "blackgui/copyxswiftbusdialog.h"
#include "blackgui/guiapplication.h" #include "blackgui/guiapplication.h"
@@ -440,61 +441,15 @@ void SwiftGuiStd::checkDbDataLoaded()
if (!sGui || sGui->isShuttingDown()) { return; } if (!sGui || sGui->isShuttingDown()) { return; }
Q_ASSERT_X(sGui->hasWebDataServices(), Q_FUNC_INFO, "Missing web services"); Q_ASSERT_X(sGui->hasWebDataServices(), Q_FUNC_INFO, "Missing web services");
Q_ASSERT_X(CThreadUtils::isCurrentThreadApplicationThread(), Q_FUNC_INFO, "Wrong thread, needs to run in main thread"); Q_ASSERT_X(CThreadUtils::isCurrentThreadApplicationThread(), Q_FUNC_INFO, "Wrong thread, needs to run in main thread");
CEntityFlags::Entity loadEntities = sGui->getWebDataServices()->getEntitiesWithNewerSharedFile(CEntityFlags::AllDbEntities); CEntityFlags::Entity loadEntities = sGui->getWebDataServices()->getSychronizedEntitiesWithNewerSharedFileOrEmpty(!m_dbDataLoading);
const CEntityFlags::Entity checkForEmpty = CEntityFlags::entityFlagToEntity(CEntityFlags::AllDbEntitiesNoInfoObjects) & ~loadEntities;
// it can happen the timestamps are not newer, but the data are empty
// - can happen if caches are copied and the TS does not represent the DB timestamp
// - cache files have been deleted
// - sync all DB entities
// - fast if there are no data
// - no impact if already synced
// - slow if newer synced before and all has to be done now
if (!m_dbDataLoading) { sGui->getWebDataServices()->synchronizeDbCaches(checkForEmpty); }
// we have no newer timestamps, but incomplete data
loadEntities |= sGui->getWebDataServices()->getEmptyEntities();
if (loadEntities == CEntityFlags::NoEntity) if (loadEntities == CEntityFlags::NoEntity)
{ {
m_dbDataLoading = false; m_dbDataLoading = false;
return; return;
} }
CStatusMessage sm = m_dbDataLoading ? if (!m_dbLoadDialog) { m_dbLoadDialog.reset(new CDbLoadDataDialog(this)); }
CStatusMessage(this).info("Loading in progress:") : m_dbLoadDialog->newerOrEmptyEntitiesDetected(loadEntities);
CStatusMessage(this).info("New data for shared files:");
CStatusMessageList sms(sm);
const QSet<CEntityFlags::Entity> newSingleEntities = CEntityFlags::asSingleEntities(loadEntities);
const QString m = m_dbDataLoading ? QStringLiteral("Loading data for '%1'") : QStringLiteral("Load data for '%1'?");
for (CEntityFlags::Entity newSingleEntity : newSingleEntities)
{
sm = CStatusMessage(this).info(m) << CEntityFlags::flagToString(newSingleEntity);
sms.push_back(sm);
}
constexpr int checkAgain = 5000;
if (m_dbDataLoading)
{
// already loading
ui->fr_CentralFrameInside->showOverlayMessages(sms, false, 1.2 * checkAgain);
return;
}
// data need to be loaded
constexpr int delay = 2500; // allow to init GUI completely before showing overlays
QTimer::singleShot(delay, this, [ = ]
{
// delayed call
auto lambda = [ = ]()
{
sGui->getWebDataServices()->triggerLoadingDirectlyFromSharedFiles(loadEntities, false);
m_dbDataLoading = true;
// re-check
QTimer::singleShot(checkAgain, this, &SwiftGuiStd::checkDbDataLoaded);
};
ui->fr_CentralFrameInside->showOverlayMessagesWithConfirmation(sms, false, "Load DB data?", lambda);
});
} }
void SwiftGuiStd::playNotifcationSound(CNotificationSounds::Notification notification) const void SwiftGuiStd::playNotifcationSound(CNotificationSounds::Notification notification) const

View File

@@ -44,6 +44,7 @@ class QTimer;
class QWidget; class QWidget;
namespace BlackMisc { namespace Aviation { class CAltitude; } } namespace BlackMisc { namespace Aviation { class CAltitude; } }
namespace BlackGui { namespace Components { class CDbLoadDataDialog; }}
namespace Ui { class SwiftGuiStd; } namespace Ui { class SwiftGuiStd; }
//! swift GUI //! swift GUI
@@ -101,7 +102,8 @@ protected:
private: private:
QScopedPointer<Ui::SwiftGuiStd> ui; QScopedPointer<Ui::SwiftGuiStd> ui;
QScopedPointer<BlackGui::Components::CNavigatorDialog> m_navigator{new BlackGui::Components::CNavigatorDialog()}; // if I pass the parent, the dialog is always centered over the parent QScopedPointer<BlackGui::Components::CNavigatorDialog> m_navigator{ new BlackGui::Components::CNavigatorDialog() }; //!< navigator dialog bar, if I pass the parent, the dialog is always centered over the parent
QScopedPointer<BlackGui::Components::CDbLoadDataDialog> m_dbLoadDialog; //!< load DB data, lazy init UI component
BlackCore::CActionBindings m_menuHotkeyHandlers; BlackCore::CActionBindings m_menuHotkeyHandlers;
BlackGui::CManagedStatusBar m_statusBar; BlackGui::CManagedStatusBar m_statusBar;
BlackMisc::CLogSubscriber m_logSubscriber { this, &SwiftGuiStd::displayStatusMessageInGui }; BlackMisc::CLogSubscriber m_logSubscriber { this, &SwiftGuiStd::displayStatusMessageInGui };