/*
*openPilotLog - A FOSS Pilot Logbook Application
*Copyright (C) 2020-2021 Felix Turowsky
*
*This program is free software: you can redistribute it and/or modify
*it under the terms of the GNU General Public License as published by
*the Free Software Foundation, either version 3 of the License, or
*(at your option) any later version.
*
*This program is distributed in the hope that it will be useful,
*but WITHOUT ANY WARRANTY; without even the implied warranty of
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*GNU General Public License for more details.
*
*You should have received a copy of the GNU General Public License
*along with this program. If not, see .
*/
#include "pilotswidget.h"
#include "ui_pilotswidget.h"
#include "src/opl.h"
#include "src/functions/alog.h"
#include "src/database/adatabase.h"
#include "src/classes/apilotentry.h"
PilotsWidget::PilotsWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::PilotsWidget)
{
ui->setupUi(this);
ui->tableView->setMinimumWidth(this->width()/2);
ui->stackedWidget->setMinimumWidth(this->width()/2);
setupModelAndView();
}
PilotsWidget::~PilotsWidget()
{
delete ui;
}
void PilotsWidget::setupModelAndView()
{
model = new QSqlTableModel(this);
model->setTable(QStringLiteral("viewPilots"));
model->setFilter(QStringLiteral("ID > 1")); // Don't show self
model->select();
view = ui->tableView;
view->setModel(model);
view->setSelectionBehavior(QAbstractItemView::SelectRows);
view->setSelectionMode(QAbstractItemView::SingleSelection);
view->setEditTriggers(QAbstractItemView::NoEditTriggers);
view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
view->hideColumn(0);
view->resizeColumnsToContents();
view->verticalHeader()->hide();
view->setAlternatingRowColors(true);
view->setSortingEnabled(true);
sortColumn = ASettings::read(ASettings::UserData::PilotSortColumn).toInt();
view->sortByColumn(sortColumn, Qt::AscendingOrder);
view->show();
selectionModel = view->selectionModel();
connectSignalsAndSlots();
}
void PilotsWidget::connectSignalsAndSlots()
{
QObject::connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &PilotsWidget::tableView_selectionChanged);
QObject::connect(ui->tableView->horizontalHeader(), &QHeaderView::sectionClicked,
this, &PilotsWidget::tableView_headerClicked);
}
void PilotsWidget::changeEvent(QEvent *event)
{
if (event != nullptr)
if(event->type() == QEvent::LanguageChange)
ui->retranslateUi(this);
}
void PilotsWidget::onPilotsWidget_settingChanged(SettingsWidget::SettingSignal signal)
{
if (signal == SettingsWidget::PilotsWidget)
setupModelAndView();
}
void PilotsWidget::onPilotsWidget_databaseUpdated()
{
refreshView();
}
void PilotsWidget::onNewPilotDialog_editingFinished()
{
refreshView();
}
void PilotsWidget::on_pilotSearchLineEdit_textChanged(const QString &arg1)
{
model->setFilter(QLatin1Char('\"') + ui->pilotsSearchComboBox->currentText()
+ QLatin1String("\" LIKE '%") + arg1
+ QLatin1String("%' AND ID > 1"));
}
void PilotsWidget::tableView_selectionChanged()
{
if (this->findChild() != nullptr) {
delete this->findChild();
}
auto *selection = ui->tableView->selectionModel();
selectedPilots.clear();
for (const auto& row : selection->selectedRows()) {
selectedPilots.append(row.data().toInt());
DEB << "Selected Tails(s) with ID: " << selectedPilots;
}
if(selectedPilots.length() == 1) {
NewPilotDialog* np = new NewPilotDialog(selectedPilots.first(), this);
QObject::connect(np, &QDialog::accepted,
this, &PilotsWidget::onNewPilotDialog_editingFinished);
QObject::connect(np, &QDialog::rejected,
this, &PilotsWidget::onNewPilotDialog_editingFinished);
np->setWindowFlag(Qt::Widget);
np->setAttribute(Qt::WA_DeleteOnClose);
ui->stackedWidget->addWidget(np);
ui->stackedWidget->setCurrentWidget(np);
np->exec();
}
}
void PilotsWidget::tableView_headerClicked(int column)
{
sortColumn = column;
ASettings::write(ASettings::UserData::PilotSortColumn, column);
}
void PilotsWidget::on_newPilotButton_clicked()
{
NewPilotDialog* np = new NewPilotDialog(this);
QObject::connect(np, &QDialog::accepted,
this, &PilotsWidget::onNewPilotDialog_editingFinished);
QObject::connect(np, &QDialog::rejected,
this, &PilotsWidget::onNewPilotDialog_editingFinished);
np->setAttribute(Qt::WA_DeleteOnClose);
np->exec();
}
void PilotsWidget::on_deletePilotButton_clicked()
{
if (selectedPilots.length() == 0) {
INFO(tr("No Pilot selected."));
} else if (selectedPilots.length() > 1) {
WARN(tr("Deleting multiple entries is currently not supported"));
/// [F] to do: for (const auto& row_id : selectedPilots) { do batchDelete }
/// I am not sure if enabling this functionality for this widget is a good idea.
/// On the one hand, deleting many entries could be useful in a scenario where
/// for example, the user has changed airlines and does not want to have his 'old'
/// colleagues polluting his logbook anymore.
/// On the other hand we could run into issues with foreign key constraints on the
/// flights table (see on_delete_unsuccessful) below.
/// I think batch-editing should be implemented at some point, but batch-deleting should not.
} else if (selectedPilots.length() == 1) {
auto entry = aDB->getPilotEntry(selectedPilots.first());
QMessageBox confirm(this);
confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
confirm.setDefaultButton(QMessageBox::No);
confirm.setIcon(QMessageBox::Question);
confirm.setWindowTitle(tr("Delete Pilot"));
confirm.setText(tr("You are deleting the following pilot:
"
"%1
Are you sure?").arg(entry.name()));
if (confirm.exec() == QMessageBox::Yes) {
if(!aDB->remove(entry))
onDeleteUnsuccessful();
}
}
refreshView();
}
/*!
* \brief Informs the user that deleting a database entry has been unsuccessful
*
* \details Normally, when one of these entries can not be deleted, it is because of
* a [foreign key constraint](https://sqlite.org/foreignkeys.html), meaning that a flight
* is associated with the Pilot that was supposed to be deleted as Pilot-in-command.
*
* This function is used to inform the user and give hints on how to solve the problem.
*/
void PilotsWidget::onDeleteUnsuccessful()
{
const QList foreign_key_constraints = aDB->getForeignKeyConstraints(selectedPilots.first(),
ADatabaseTable::pilots);
QList constrained_flights;
for (const auto &row_id : foreign_key_constraints) {
constrained_flights.append(aDB->getFlightEntry(row_id));
}
if (constrained_flights.isEmpty()) {
WARN(tr("
Unable to delete.
The following error has ocurred:
%1"
).arg(aDB->lastError.text()));
return;
} else {
QString constrained_flights_string;
for (int i=0; i"));
if (i>10) {
constrained_flights_string.append("
[...]
");
break;
}
}
WARN(tr("Unable to delete.
"
"This is most likely the case because a flight exists with the Pilot "
"you are trying to delete as PIC.
"
"%1 flight(s) with this pilot have been found:
"
"%2"
"
You have to change or remove the conflicting flight(s) "
"before removing this pilot from the database.
"
).arg(QString::number(constrained_flights.length()),
constrained_flights_string));
}
}
void PilotsWidget::repopulateModel()
{
// unset the current model and delete it to avoid leak
view->setModel(nullptr);
delete model;
// create a new model and populate it
model = new QSqlTableModel(this);
setupModelAndView();
connectSignalsAndSlots();
}