/*
*openPilot Log - A FOSS Pilot Logbook Application
*Copyright (C) 2020 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 "newtail.h"
#include "ui_newtail.h"
// Debug Makro
#define DEB(expr) \
qDebug() << __PRETTY_FUNCTION__<< "\t" << expr
const auto MAKE_VALID = QPair {
"makeLineEdit", QRegularExpression("[a-zA-Z]+")};
const auto MODEL_VALID = QPair {
"modelLineEdit", QRegularExpression("\\w+")};
const auto VARIANT_VALID = QPair {
"variantLineEdit", QRegularExpression("\\w+")};
const auto LINE_EDIT_VALIDATORS = QVector({MAKE_VALID, MODEL_VALID, VARIANT_VALID});
//Dialog to be used to create a new tail
NewTail::NewTail(QString newreg, Db::editRole edRole, QWidget *parent) :
QDialog(parent),
ui(new Ui::NewTail)
{
ui->setupUi(this);
role = edRole;
setupCompleter();
setupValidators();
ui->editLabel->hide();
ui->registrationLineEdit->setText(newreg);
ui->searchLineEdit->setStyleSheet("border: 1px solid blue");
ui->searchLineEdit->setFocus();
}
//Dialog to be used to edit an existing tail
NewTail::NewTail(Aircraft dbentry, Db::editRole edRole, QWidget *parent) :
QDialog(parent),
ui(new Ui::NewTail)
{
oldEntry = dbentry;
role = edRole;
ui->setupUi(this);
ui->searchLabel->hide();
ui->searchLineEdit->hide();
ui->line->hide();
setupValidators();
formFiller(oldEntry);
}
NewTail::~NewTail()
{
delete ui;
}
/// Functions
/*!
* \brief NewTail::setupCompleter creates a QMap for auto completion,
* obtains a QStringList for QCompleter and sets up search line edit accordingly
*/
void NewTail::setupCompleter()
{
auto query = QLatin1String("SELECT make||' '||model||'-'||variant, aircraft_id FROM aircraft");
auto vector = Db::customQuery(query, 2);
QMap map;
for (int i = 0; i < vector.length() - 2 ; i += 2) {
if (vector[i] != QLatin1String("")) {
map.insert(vector[i], vector[i + 1].toInt());
}
}
//creating QStringlist for QCompleter. This list is identical to a list of map,
//but creating it like this is faster.
auto cl = new CompletionList(CompleterTarget::aircraft);
aircraftlist = cl->list;
idMap = map;
QCompleter *completer = new QCompleter(aircraftlist, ui->searchLineEdit);
completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->setCompletionMode(QCompleter::PopupCompletion);
completer->setFilterMode(Qt::MatchContains);
ui->searchLineEdit->setCompleter(completer);
}
void NewTail::setupValidators()
{
for(const auto& pair : LINE_EDIT_VALIDATORS){
auto line_edit = parent()->findChild(pair.first);
auto validator = new QRegularExpressionValidator(pair.second,line_edit);
line_edit->setValidator(validator);
}
}
/*!
* \brief NewTail::formFiller populates the Dialog with the
* information contained in an aircraft object.
* \param db - entry retreived from database
*/
void NewTail::formFiller(Aircraft entry)
{
DEB("Filling Form for a/c" << entry);
//fill Line Edits
auto line_edits = parent()->findChildren();
for (const auto &le : line_edits) {
QString name = le->objectName();
name.chop(8);//remove "LineEdit"
QString value = entry.data.value(name);
if (!value.isEmpty()) {
le->setText(value);
};
}
//select comboboxes
QVector operation = {entry.data.value("singleengine"), entry.data.value("multiengine")};
QVector ppNumber = {entry.data.value("singlepilot"), entry.data.value("multipilot")};
QVector ppType = {entry.data.value("unpowered"), entry.data.value("piston"),
entry.data.value("turboprop"), entry.data.value("jet")
};
QVector weight = {entry.data.value("light"), entry.data.value("medium"),
entry.data.value("heavy"), entry.data.value("super")
};
ui->operationComboBox->setCurrentIndex(operation.indexOf("1") + 1);
ui->ppNumberComboBox->setCurrentIndex(ppNumber.indexOf("1") + 1);
ui->ppTypeComboBox->setCurrentIndex(ppType.indexOf("1") + 1);
ui->weightComboBox->setCurrentIndex(weight.indexOf("1") + 1);
}
/*!
* \brief NewTail::verify A simple check for empty recommended fields in the form
* \return true if all reconmmended fields are populated
*/
bool NewTail::verify()
{
auto recommended_line_edits = parent()->findChildren("registrationLineEdit");
recommended_line_edits.append(parent()->findChild("makeLineEdit"));
recommended_line_edits.append(parent()->findChild("modelLineEdit"));
auto recommended_combo_boxes = parent()->findChildren("operationComboBox");
recommended_combo_boxes.append(parent()->findChild("ppNumberComboBox"));
recommended_combo_boxes.append(parent()->findChild("ppTypeComboBox"));
for (const auto le : recommended_line_edits) {
if (le->text() != "") {
DEB("Good: " << le);
recommended_line_edits.removeOne(le);
le->setStyleSheet("");
} else {
le->setStyleSheet("border: 1px solid red");
DEB("Not Good: " << le);
}
}
for (const auto cb : recommended_combo_boxes) {
if (cb->currentIndex() != 0) {
recommended_combo_boxes.removeOne(cb);
cb->setStyleSheet("");
} else {
cb->setStyleSheet("background: orange");
DEB("Not Good: " << cb);
}
}
if (recommended_line_edits.isEmpty() && recommended_combo_boxes.isEmpty()) {
return true;
} else {
return false;
}
}
/*!
* \brief NewTail::submitForm collects input from Line Edits and creates
* or updates a database entry and commits or updates the database
* \param edRole editExisting or createNew
*/
void NewTail::submitForm(Db::editRole edRole)
{
DEB("Creating Database Object...");
QMap newData;
//retreive Line Edits
auto line_edits = parent()->findChildren();
for (const auto &le : line_edits) {
QString name = le->objectName();
name.chop(8);//remove "LineEdit"
if (!le->text().isEmpty()) {
newData.insert(name, le->text());
}
}
//prepare comboboxes
QVector operation = {"singlepilot", "multipilot"};
QVector ppNumber = {"singleengine", "multiengine"};
QVector ppType = {"unpowered", "piston",
"turboprop", "jet"
};
QVector weight = {"light", "medium",
"heavy", "super"
};
if (ui->operationComboBox->currentIndex() != 0) {
newData.insert(operation[ui->operationComboBox->currentIndex() - 1], QLatin1String("1"));
}
if (ui->ppNumberComboBox->currentIndex() != 0) {
newData.insert(ppNumber[ui->ppNumberComboBox->currentIndex() - 1], QLatin1String("1"));
}
if (ui->ppTypeComboBox->currentIndex() != 0) {
newData.insert(ppType[ui->ppTypeComboBox->currentIndex() - 1], QLatin1String("1"));
}
if (ui->weightComboBox->currentIndex() != 0) {
newData.insert(weight[ui->weightComboBox->currentIndex() - 1], QLatin1String("1"));
}
//create db object
switch (edRole) {
case Db::createNew: {
auto newEntry = Aircraft("tails", newData);;
newEntry.commit();
break;
}
case Db::editExisting:
oldEntry.setData(newData);
oldEntry.commit();
Calc::updateAutoTimes(oldEntry.position.second);
break;
}
}
/// Slots
void NewTail::on_searchLineEdit_textChanged(const QString &arg1)
{
if (aircraftlist.contains(
arg1)) { //equivalent to editing finished for this purpose. todo: consider connecing qcompleter activated signal with editing finished slot.
DEB("Template Selected. aircraft_id is: " << idMap.value(arg1));
//call autofiller for dialog
formFiller(Aircraft("aircraft", idMap.value(arg1)));
ui->searchLineEdit->setStyleSheet("border: 1px solid green");
} else {
//for example, editing finished without selecting a result from Qcompleter
ui->searchLineEdit->setStyleSheet("border: 1px solid orange");
}
}
void NewTail::on_operationComboBox_currentIndexChanged(int index)
{
if (index != 0) {
ui->operationComboBox->setStyleSheet("");
}
}
void NewTail::on_ppTypeComboBox_currentIndexChanged(int index)
{
if (index != 0) {
ui->ppTypeComboBox->setStyleSheet("");
}
}
void NewTail::on_ppNumberComboBox_currentIndexChanged(int index)
{
if (index != 0) {
ui->ppNumberComboBox->setStyleSheet("");
}
}
void NewTail::on_weightComboBox_currentIndexChanged(int index)
{
if (index != 0) {
ui->weightComboBox->setStyleSheet("");
}
}
void NewTail::on_buttonBox_accepted()
{
DEB("Button Box Accepted.");
if (ui->registrationLineEdit->text().isEmpty()) {
auto nope = new QMessageBox(this);
nope->setText("Registration cannot be empty.");
nope->show();
} else {
if (verify()) {
DEB("Form verified");
submitForm(role);
accept();
} else {
QSettings setting;
if (!setting.value("userdata/acAllowIncomplete").toInt()) {
auto nope = new QMessageBox(this);
nope->setText("Some or all fields are empty.\nPlease go back and "
"complete the form.\n\nYou can allow logging incomplete entries on the settings page.");
nope->show();
} else {
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "Warning",
"Some recommended fields are empty.\n\n"
"If you do not fill out the aircraft details, "
"it will be impossible to automatically determine Single/Multi Pilot Times or Single/Multi Engine Time."
"This will also impact statistics and auto-logging capabilites.\n\n"
"It is highly recommended to fill in all the details.\n\n"
"Are you sure you want to proceed?",
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
submitForm(role);
accept();
}
}
}
}
}