newtaildialog.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. *openPilotLog - A FOSS Pilot Logbook Application
  3. *Copyright (C) 2020-2021 Felix Turowsky
  4. *
  5. *This program is free software: you can redistribute it and/or modify
  6. *it under the terms of the GNU General Public License as published by
  7. *the Free Software Foundation, either version 3 of the License, or
  8. *(at your option) any later version.
  9. *
  10. *This program is distributed in the hope that it will be useful,
  11. *but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. *GNU General Public License for more details.
  14. *
  15. *You should have received a copy of the GNU General Public License
  16. *along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. #include "newtaildialog.h"
  19. #include "ui_newtail.h"
  20. #include "src/functions/alog.h"
  21. #include "src/opl.h"
  22. static const auto REG_VALID = QPair<QString, QRegularExpression> {
  23. QStringLiteral("registrationLineEdit"), QRegularExpression("\\w+-\\w+")};
  24. static const auto MAKE_VALID = QPair<QString, QRegularExpression> {
  25. QStringLiteral("makeLineEdit"), QRegularExpression("[-a-zA-Z\\s]+")};
  26. static const auto MODEL_VALID = QPair<QString, QRegularExpression> {
  27. QStringLiteral("modelLineEdit"), QRegularExpression("[\\s\\w-]+")};
  28. static const auto VARIANT_VALID = QPair<QString, QRegularExpression> {
  29. QStringLiteral("variantLineEdit"), QRegularExpression("[\\s\\w-]+")};
  30. static const auto LINE_EDIT_VALIDATORS = QVector<QPair<QString, QRegularExpression>>{
  31. REG_VALID,
  32. MAKE_VALID,
  33. MODEL_VALID,
  34. VARIANT_VALID};
  35. NewTailDialog::NewTailDialog(QString new_registration, QWidget *parent) :
  36. QDialog(parent),
  37. ui(new Ui::NewTail)
  38. {
  39. DEB << "new NewTailDialog";
  40. ui->setupUi(this);
  41. setupCompleter();
  42. setupValidators();
  43. ui->registrationLineEdit->setText(new_registration);
  44. ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid blue"));
  45. ui->searchLineEdit->setFocus();
  46. entry = ATailEntry();
  47. }
  48. NewTailDialog::NewTailDialog(int row_id, QWidget *parent) :
  49. QDialog(parent),
  50. ui(new Ui::NewTail)
  51. {
  52. DEB << "New New Pilot Dialog (edit existing)";
  53. ui->setupUi(this);
  54. ui->searchLabel->hide();
  55. ui->searchLineEdit->hide();
  56. ui->line->hide();
  57. setupValidators();
  58. entry = aDB->getTailEntry(row_id);
  59. fillForm(entry, false);
  60. }
  61. NewTailDialog::~NewTailDialog()
  62. {
  63. DEB << "Deleting NewTailDialog\n";
  64. delete ui;
  65. }
  66. /// Functions
  67. /*!
  68. * \brief NewTail::setupCompleter obtains a QMap<QString searchstring, int aircaft_id> for auto completion
  69. * and obtains a QStringList for QCompleter. This function then sets up the search line edit where
  70. * the user can select a template from the aircraft database to pre-fill the form with the details
  71. * for the selected type.
  72. */
  73. void NewTailDialog::setupCompleter()
  74. {
  75. idMap = aDB->getIdMap(ADatabaseTarget::aircraft);
  76. aircraftList = aDB->getCompletionList(ADatabaseTarget::aircraft);
  77. QCompleter *completer = new QCompleter(aircraftList, ui->searchLineEdit);
  78. completer->setCaseSensitivity(Qt::CaseInsensitive);
  79. completer->setCompletionMode(QCompleter::PopupCompletion);
  80. completer->setFilterMode(Qt::MatchContains);
  81. ui->searchLineEdit->setCompleter(completer);
  82. QObject::connect(completer, static_cast<void(QCompleter::*)(const QString &)>(&QCompleter::activated),
  83. this, &NewTailDialog::onSearchCompleterActivated);
  84. QObject::connect(completer, static_cast<void(QCompleter::*)(const QString &)>(&QCompleter::highlighted),
  85. this, &NewTailDialog::onSearchCompleterActivated);
  86. }
  87. void NewTailDialog::setupValidators()
  88. {
  89. for(const auto& pair : LINE_EDIT_VALIDATORS){
  90. auto line_edit = this->findChild<QLineEdit*>(pair.first);
  91. auto validator = new QRegularExpressionValidator(pair.second, line_edit);
  92. line_edit->setValidator(validator);
  93. }
  94. }
  95. /*!
  96. * \brief NewTailDialog::fillForm populates the Dialog with the
  97. * information contained in an entry object. This can be either
  98. * a template (AAircraft, used when creating a new entry) or
  99. * a tail (ATail, used when editing an existing entry)
  100. * \param entry
  101. */
  102. void NewTailDialog::fillForm(AEntry entry, bool is_template)
  103. {
  104. DEB << "Filling Form for a/c" << entry.getPosition().tableName << entry.getPosition().rowId;
  105. //fill Line Edits
  106. auto line_edits = this->findChildren<QLineEdit *>();
  107. if (is_template)
  108. line_edits.removeOne(ui->registrationLineEdit);
  109. auto data = entry.getData();
  110. for (const auto &le : line_edits) {
  111. auto key = le->objectName().remove(QStringLiteral("LineEdit"));
  112. le->setText(data.value(key).toString());
  113. }
  114. ui->operationComboBox->setCurrentIndex(data.value(Opl::Db::TAILS_MULTIPILOT).toInt() + 1);
  115. ui->ppNumberComboBox ->setCurrentIndex(data.value(Opl::Db::TAILS_MULTIENGINE).toInt() + 1);
  116. ui->ppTypeComboBox->setCurrentIndex(data.value(Opl::Db::TAILS_ENGINETYPE).toInt() + 1);
  117. ui->weightComboBox->setCurrentIndex(data.value(Opl::Db::TAILS_WEIGHTCLASS).toInt() + 1);
  118. }
  119. /*!
  120. * \brief NewTail::verify A simple check for empty recommended fields in the form
  121. * \return true if all reconmmended fields are populated
  122. */
  123. bool NewTailDialog::verify()
  124. {
  125. auto recommended_line_edits = this->findChildren<QLineEdit *>(QStringLiteral("registrationLineEdit"));
  126. recommended_line_edits.append(this->findChild<QLineEdit *>(QStringLiteral("makeLineEdit")));
  127. recommended_line_edits.append(this->findChild<QLineEdit *>(QStringLiteral("modelLineEdit")));
  128. auto recommended_combo_boxes = this->findChildren<QComboBox *>(QStringLiteral("operationComboBox"));
  129. recommended_combo_boxes.append(this->findChild<QComboBox *>(QStringLiteral("ppNumberComboBox")));
  130. recommended_combo_boxes.append(this->findChild<QComboBox *>(QStringLiteral("ppTypeComboBox")));
  131. for (const auto &le : recommended_line_edits) {
  132. if (le->text() != "") {
  133. DEB << "Good: " << le;
  134. recommended_line_edits.removeOne(le);
  135. le->setStyleSheet("");
  136. } else {
  137. le->setStyleSheet(QStringLiteral("border: 1px solid red"));
  138. DEB << "Not Good: " << le;
  139. }
  140. }
  141. for (const auto &cb : recommended_combo_boxes) {
  142. if (cb->currentIndex() != 0) {
  143. recommended_combo_boxes.removeOne(cb);
  144. cb->setStyleSheet(QString());
  145. } else {
  146. cb->setStyleSheet(QStringLiteral("background: orange"));
  147. DEB << "Not Good: " << cb;
  148. }
  149. }
  150. if (recommended_line_edits.isEmpty() && recommended_combo_boxes.isEmpty()) {
  151. return true;
  152. } else {
  153. return false;
  154. }
  155. }
  156. /*!
  157. * \brief NewTail::submitForm collects input from Line Edits and creates
  158. * or updates a database entry and commits or updates the database
  159. * \param edRole editExisting or createNew
  160. */
  161. void NewTailDialog::submitForm()
  162. {
  163. DEB << "Creating Database Object...";
  164. RowData_T new_data;
  165. //retreive Line Edits
  166. auto line_edits = this->findChildren<QLineEdit *>();
  167. line_edits.removeOne(this->findChild<QLineEdit *>(QStringLiteral("searchLineEdit")));
  168. for (const auto &le : line_edits) {
  169. auto key = le->objectName().remove(QStringLiteral("LineEdit"));
  170. new_data.insert(key, le->text());
  171. }
  172. if (ui->operationComboBox->currentIndex() != 0) { // bool Multipilot
  173. new_data.insert(Opl::Db::TAILS_MULTIPILOT, ui->operationComboBox->currentIndex() - 1);
  174. }
  175. if (ui->ppNumberComboBox->currentIndex() != 0) { // bool MultiEngine
  176. new_data.insert(Opl::Db::TAILS_MULTIENGINE, ui->ppNumberComboBox->currentIndex() - 1);
  177. }
  178. if (ui->ppTypeComboBox->currentIndex() != 0) { // int 0=unpowered,....4=jet
  179. new_data.insert(Opl::Db::TAILS_ENGINETYPE, ui->ppTypeComboBox->currentIndex() - 1);
  180. }
  181. if (ui->weightComboBox->currentIndex() != 0) { // int 0=light...3=super
  182. new_data.insert(Opl::Db::TAILS_WEIGHTCLASS, ui->weightComboBox->currentIndex() - 1);
  183. }
  184. //create db object
  185. entry.setData(new_data);
  186. if (!aDB->commit(entry)) {
  187. QMessageBox message_box(this);
  188. message_box.setText(tr("The following error has ocurred:"
  189. "<br><br>%1<br><br>"
  190. "The entry has not been saved."
  191. ).arg(aDB->lastError.text()));
  192. message_box.exec();
  193. return;
  194. } else {
  195. if (entry.getPosition().rowId != 0)
  196. ACalc::updateAutoTimes(entry.getPosition().rowId);
  197. QDialog::accept();
  198. }
  199. }
  200. /// Slots
  201. void NewTailDialog::on_operationComboBox_currentIndexChanged(int index)
  202. {
  203. if (index != 0)
  204. ui->operationComboBox->setStyleSheet(QString());
  205. }
  206. void NewTailDialog::on_ppTypeComboBox_currentIndexChanged(int index)
  207. {
  208. if (index != 0)
  209. ui->ppTypeComboBox->setStyleSheet(QString());
  210. }
  211. void NewTailDialog::on_ppNumberComboBox_currentIndexChanged(int index)
  212. {
  213. if (index != 0)
  214. ui->ppNumberComboBox->setStyleSheet(QString());
  215. }
  216. void NewTailDialog::on_weightComboBox_currentIndexChanged(int index)
  217. {
  218. if (index != 0)
  219. ui->weightComboBox->setStyleSheet(QString());
  220. }
  221. void NewTailDialog::on_buttonBox_accepted()
  222. {
  223. DEB << "Button Box Accepted.";
  224. if (ui->registrationLineEdit->text().isEmpty()) {
  225. QMessageBox message_box(this);
  226. message_box.setText(tr("Registration cannot be empty."));
  227. message_box.exec();
  228. return;
  229. }
  230. if (!verify()) {
  231. QMessageBox message_box(this);
  232. message_box.setIcon(QMessageBox::Warning);
  233. message_box.setText(tr("Some or all recommended fields are empty.<br>"
  234. "Please fill out the mandatory fields. You can use "
  235. "the search function to automatically fill out all "
  236. "the required fields for a known aircraft type."));
  237. message_box.exec();
  238. return;
  239. }
  240. DEB << "Form verified";
  241. submitForm();
  242. }
  243. void NewTailDialog::onSearchCompleterActivated()
  244. {
  245. const auto &text = ui->searchLineEdit->text();
  246. if (aircraftList.contains(text)) {
  247. DEB << "Template Selected. aircraft_id is: " << idMap.value(text);
  248. //call autofiller for dialog
  249. fillForm(aDB->getAircraftEntry(idMap.value(text)), true);
  250. ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid green"));
  251. ui->searchLabel->setText(text);
  252. } else {
  253. //for example, editing finished without selecting a result from Qcompleter
  254. ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid orange"));
  255. }
  256. }
  257. void NewTailDialog::on_registrationLineEdit_textChanged(const QString &arg1)
  258. {
  259. ui->registrationLineEdit->setText(arg1.toUpper());
  260. }